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 PlaceBuildingRpc — validates and spawns building entities. /// [BurstCompile] [WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)] public partial struct PlaceBuildingCommandSystem : ISystem { [BurstCompile] public void OnUpdate(ref SystemState state) { var ecb = new EntityCommandBuffer(Allocator.Temp); foreach (var (cmd, source, entity) in SystemAPI.Query, RefRO>() .WithEntityAccess()) { // TODO: Validate resources, territory, collision // TODO: Lookup building prefab entity from BuildingType // TODO: Instantiate the prefab and place it // For now just log UnityEngine.Debug.Log($"[Server] PlaceBuilding request: {cmd.ValueRO.Type} at {cmd.ValueRO.Position}"); ecb.DestroyEntity(entity); } ecb.Playback(state.EntityManager); ecb.Dispose(); } } /// /// Server-side: processes BuildRepairCommandRpc — assigns citizens to build/repair buildings. /// [BurstCompile] [WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)] public partial struct BuildRepairCommandSystem : 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 building = cmd.ValueRO.BuildingEntity; if (state.EntityManager.Exists(citizen) && state.EntityManager.Exists(building) && state.EntityManager.HasComponent(citizen)) { state.EntityManager.SetComponentData(citizen, new BuildTarget { Target = building }); state.EntityManager.SetComponentData(citizen, new CitizenStateComponent { Value = CitizenState.MovingToBuild }); var buildingPos = state.EntityManager.GetComponentData(building).Position; state.EntityManager.SetComponentData(citizen, new MoveTarget { Position = buildingPos, IsActive = true }); } ecb.DestroyEntity(entity); } ecb.Playback(state.EntityManager); ecb.Dispose(); } } /// /// Server-side: ticks construction progress for buildings with assigned citizens. /// [BurstCompile] [WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)] [UpdateAfter(typeof(BuildRepairCommandSystem))] public partial struct ConstructionSystem : ISystem { private float _timer; public void OnCreate(ref SystemState state) { _timer = 0f; } [BurstCompile] public void OnUpdate(ref SystemState state) { float dt = SystemAPI.Time.DeltaTime; _timer += dt; if (_timer < GameConstants.ConstructionTickInterval) return; _timer -= GameConstants.ConstructionTickInterval; var ecb = new EntityCommandBuffer(Allocator.Temp); // Count builders per building // Simple approach: iterate citizens in Building state foreach (var (citizenState, buildTarget, transform, moveTarget) in SystemAPI.Query, RefRO, RefRO, RefRO>() .WithAll()) { if (citizenState.ValueRO.Value == CitizenState.MovingToBuild && !moveTarget.ValueRO.IsActive) { citizenState.ValueRW.Value = CitizenState.Building; } if (citizenState.ValueRO.Value != CitizenState.Building) continue; var buildingEntity = buildTarget.ValueRO.Target; if (buildingEntity == Entity.Null || !state.EntityManager.Exists(buildingEntity)) continue; if (!state.EntityManager.HasComponent(buildingEntity)) continue; var progress = state.EntityManager.GetComponentData(buildingEntity); float increment = GameConstants.ConstructionTickInterval / progress.BuildTime; progress.Progress = math.min(progress.Progress + increment, 1f); state.EntityManager.SetComponentData(buildingEntity, progress); // Complete construction if (progress.Progress >= 1f) { ecb.RemoveComponent(buildingEntity); ecb.RemoveComponent(buildingEntity); // Set health to max var health = state.EntityManager.GetComponentData(buildingEntity); health.Current = health.Max; ecb.SetComponent(buildingEntity, health); // Citizen becomes idle citizenState.ValueRW.Value = CitizenState.Idle; } } ecb.Playback(state.EntityManager); ecb.Dispose(); } } /// /// Server-side: processes production queues on buildings and spawns units. /// [BurstCompile] [WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)] public partial struct ProductionSystem : ISystem { [BurstCompile] public void OnUpdate(ref SystemState state) { float dt = SystemAPI.Time.DeltaTime; var ecb = new EntityCommandBuffer(Allocator.Temp); foreach (var (productionQueue, rallyPoint, owner, transform, entity) in SystemAPI.Query, RefRO, RefRO, RefRO>() .WithAll() .WithNone() .WithEntityAccess()) { if (productionQueue.Length == 0) continue; var front = productionQueue[0]; front.TimeRemaining -= dt; if (front.TimeRemaining <= 0) { // TODO: Instantiate unit prefab based on front.UnitDataId // For now just log UnityEngine.Debug.Log($"[Server] Unit produced: DataId={front.UnitDataId} at {rallyPoint.ValueRO.Position}"); productionQueue.RemoveAt(0); } else { productionQueue[0] = front; } } ecb.Playback(state.EntityManager); ecb.Dispose(); } } }