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); } } } }