using Unity.Burst; using Unity.Collections; using Unity.Entities; using Unity.Mathematics; using Unity.Transforms; using Unity.NetCode; using EE2Clone.Components; using EE2Clone.Core; namespace EE2Clone.Systems { /// /// Server-side: processes GatherCommandRpc — assigns a gather target to citizens. /// [BurstCompile] [WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)] public partial struct GatherCommandSystem : ISystem { [BurstCompile] public void OnUpdate(ref SystemState state) { var ecb = new EntityCommandBuffer(Allocator.Temp); foreach (var (cmd, source, entity) in SystemAPI.Query, RefRO>() .WithEntityAccess()) { var citizen = cmd.ValueRO.CitizenEntity; var node = cmd.ValueRO.ResourceNodeEntity; if (state.EntityManager.Exists(citizen) && state.EntityManager.Exists(node) && state.EntityManager.HasComponent(citizen) && state.EntityManager.HasComponent(node)) { state.EntityManager.SetComponentData(citizen, new GatherTarget { Target = node }); state.EntityManager.SetComponentData(citizen, new CitizenStateComponent { Value = CitizenState.MovingToGather }); // Set move target to the resource node's position var nodePos = state.EntityManager.GetComponentData(node).Position; state.EntityManager.SetComponentData(citizen, new MoveTarget { Position = nodePos, IsActive = true }); } ecb.DestroyEntity(entity); } ecb.Playback(state.EntityManager); ecb.Dispose(); } } /// /// Server-side: citizen gathering state machine. /// Handles: MovingToGather → Gathering → MovingToDropoff → Depositing → repeat. /// [BurstCompile] [WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)] [UpdateAfter(typeof(GatherCommandSystem))] public partial struct GatheringSystem : ISystem { private float _gatherTimer; public void OnCreate(ref SystemState state) { _gatherTimer = 0f; } [BurstCompile] public void OnUpdate(ref SystemState state) { float dt = SystemAPI.Time.DeltaTime; _gatherTimer += dt; bool gatherTick = _gatherTimer >= GameConstants.GatherTickInterval; if (gatherTick) _gatherTimer -= GameConstants.GatherTickInterval; foreach (var (citizenState, gatherTarget, carried, transform, moveTarget, owner) in SystemAPI.Query, RefRW, RefRW, RefRO, RefRW, RefRO>() .WithAll()) { switch (citizenState.ValueRO.Value) { case CitizenState.MovingToGather: // Check if arrived (MoveTarget will be deactivated by movement system) if (!moveTarget.ValueRO.IsActive) { citizenState.ValueRW.Value = CitizenState.Gathering; } break; case CitizenState.Gathering: if (!gatherTick) break; var targetEntity = gatherTarget.ValueRO.Target; if (targetEntity == Entity.Null || !state.EntityManager.Exists(targetEntity)) { citizenState.ValueRW.Value = CitizenState.Idle; break; } var node = state.EntityManager.GetComponentData(targetEntity); if (node.RemainingAmount <= 0) { citizenState.ValueRW.Value = CitizenState.Idle; gatherTarget.ValueRW.Target = Entity.Null; break; } // Gather one unit int gatherAmount = math.min(1, node.RemainingAmount); gatherAmount = math.min(gatherAmount, carried.ValueRO.MaxCarryCapacity - carried.ValueRO.Amount); if (gatherAmount > 0) { node.RemainingAmount -= gatherAmount; state.EntityManager.SetComponentData(targetEntity, node); carried.ValueRW.Amount += gatherAmount; carried.ValueRW.Type = node.Type; } // If carrying capacity full, go to dropoff if (carried.ValueRO.Amount >= carried.ValueRO.MaxCarryCapacity) { citizenState.ValueRW.Value = CitizenState.MovingToDropoff; // TODO: Find nearest dropoff building and set as move target // For now, move back toward origin as placeholder moveTarget.ValueRW = new MoveTarget { Position = float3.zero, IsActive = true }; } break; case CitizenState.MovingToDropoff: if (!moveTarget.ValueRO.IsActive) { citizenState.ValueRW.Value = CitizenState.Depositing; } break; case CitizenState.Depositing: // Deposit resources into player economy // TODO: Find PlayerResourcesComponent for this owner and add resources carried.ValueRW.Amount = 0; // Go back to gather if the node still exists if (gatherTarget.ValueRO.Target != Entity.Null && state.EntityManager.Exists(gatherTarget.ValueRO.Target)) { var nodePos = state.EntityManager.GetComponentData(gatherTarget.ValueRO.Target).Position; moveTarget.ValueRW = new MoveTarget { Position = nodePos, IsActive = true }; citizenState.ValueRW.Value = CitizenState.MovingToGather; } else { citizenState.ValueRW.Value = CitizenState.Idle; } break; } } } } }