using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;
using Unity.Collections;
using Unity.Physics;
using UnityEngine;
using EE2Clone.Components;
using EE2Clone.NetCode;
namespace EE2Clone.Hybrid
{
///
/// Processes right-click context commands: move, attack, gather, build/repair.
/// Sends the appropriate RPC to the server based on what was right-clicked.
/// Client-side MonoBehaviour.
///
public class CommandDispatcher : MonoBehaviour
{
private Camera _mainCamera;
private void Start()
{
_mainCamera = Camera.main;
}
private void Update()
{
var input = RTSInputActions.Instance;
if (input == null || _mainCamera == null) return;
if (input.RightClickPressed)
HandleRightClick(input.MousePosition);
if (input.StopPressed)
HandleStop();
}
private void HandleRightClick(Vector2 screenPos)
{
var selection = SelectionManager.Instance;
if (selection == null || selection.SelectedEntities.Count == 0) return;
var world = World.DefaultGameObjectInjectionWorld;
if (world == null || !world.IsCreated) return;
var em = world.EntityManager;
var ray = _mainCamera.ScreenPointToRay(new Vector3(screenPos.x, screenPos.y, 0));
// Raycast to find what was clicked
var physicsWorldQuery = em.CreateEntityQuery(typeof(PhysicsWorldSingleton));
if (physicsWorldQuery.IsEmpty) return;
var physicsWorld = physicsWorldQuery.GetSingleton();
var rayInput = new RaycastInput
{
Start = ray.origin,
End = ray.origin + ray.direction * 500f,
Filter = new CollisionFilter
{
BelongsTo = ~0u,
CollidesWith = ~0u,
GroupIndex = 0
}
};
Entity hitEntity = Entity.Null;
float3 hitPosition = float3.zero;
if (physicsWorld.CastRay(rayInput, out var hit))
{
hitEntity = physicsWorld.Bodies[hit.RigidBodyIndex].Entity;
hitPosition = hit.Position;
}
else
{
// No hit — use ground plane intersection
if (ray.direction.y != 0)
{
float t = -ray.origin.y / ray.direction.y;
if (t > 0)
hitPosition = new float3(ray.origin.x + ray.direction.x * t, 0, ray.origin.z + ray.direction.z * t);
}
return; // Only move command if no entity hit
}
// Determine command type based on what was clicked
if (hitEntity != Entity.Null && em.Exists(hitEntity))
{
if (em.HasComponent(hitEntity))
{
// Gather command for citizens
SendGatherCommands(hitEntity);
return;
}
if (em.HasComponent(hitEntity) || em.HasComponent(hitEntity))
{
if (em.HasComponent(hitEntity))
{
var owner = em.GetComponentData(hitEntity);
// TODO: compare with local player id
// For now, treat as enemy → attack
SendAttackCommands(hitEntity);
return;
}
}
if (em.HasComponent(hitEntity) && em.HasComponent(hitEntity))
{
// Build/repair command for citizens
SendBuildRepairCommands(hitEntity);
return;
}
}
// Default: move command
SendMoveCommands(hitPosition);
}
private void SendMoveCommands(float3 position)
{
var world = World.DefaultGameObjectInjectionWorld;
if (world == null) return;
var em = world.EntityManager;
foreach (var unit in SelectionManager.Instance.SelectedEntities)
{
if (!em.Exists(unit) || !em.HasComponent(unit)) continue;
var rpcEntity = em.CreateEntity();
em.AddComponentData(rpcEntity, new MoveCommandRpc
{
UnitEntity = unit,
TargetPosition = position
});
em.AddComponent(rpcEntity);
}
}
private void SendAttackCommands(Entity target)
{
var world = World.DefaultGameObjectInjectionWorld;
if (world == null) return;
var em = world.EntityManager;
foreach (var unit in SelectionManager.Instance.SelectedEntities)
{
if (!em.Exists(unit) || !em.HasComponent(unit)) continue;
var rpcEntity = em.CreateEntity();
em.AddComponentData(rpcEntity, new AttackCommandRpc
{
AttackerEntity = unit,
TargetEntity = target
});
em.AddComponent(rpcEntity);
}
}
private void SendGatherCommands(Entity resourceNode)
{
var world = World.DefaultGameObjectInjectionWorld;
if (world == null) return;
var em = world.EntityManager;
foreach (var unit in SelectionManager.Instance.SelectedEntities)
{
if (!em.Exists(unit) || !em.HasComponent(unit)) continue;
var rpcEntity = em.CreateEntity();
em.AddComponentData(rpcEntity, new GatherCommandRpc
{
CitizenEntity = unit,
ResourceNodeEntity = resourceNode
});
em.AddComponent(rpcEntity);
}
}
private void SendBuildRepairCommands(Entity building)
{
var world = World.DefaultGameObjectInjectionWorld;
if (world == null) return;
var em = world.EntityManager;
foreach (var unit in SelectionManager.Instance.SelectedEntities)
{
if (!em.Exists(unit) || !em.HasComponent(unit)) continue;
var rpcEntity = em.CreateEntity();
em.AddComponentData(rpcEntity, new BuildRepairCommandRpc
{
CitizenEntity = unit,
BuildingEntity = building
});
em.AddComponent(rpcEntity);
}
}
private void HandleStop()
{
var world = World.DefaultGameObjectInjectionWorld;
if (world == null) return;
var em = world.EntityManager;
foreach (var unit in SelectionManager.Instance.SelectedEntities)
{
if (!em.Exists(unit) || !em.HasComponent(unit)) continue;
var rpcEntity = em.CreateEntity();
em.AddComponentData(rpcEntity, new StopCommandRpc
{
UnitEntity = unit
});
em.AddComponent(rpcEntity);
}
}
}
}