Initial import
This commit is contained in:
197
Assets/Scripts/Systems/BuildingSystems.cs
Normal file
197
Assets/Scripts/Systems/BuildingSystems.cs
Normal file
@@ -0,0 +1,197 @@
|
||||
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
|
||||
{
|
||||
/// <summary>
|
||||
/// Server-side: processes PlaceBuildingRpc — validates and spawns building entities.
|
||||
/// </summary>
|
||||
[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<PlaceBuildingRpc>, RefRO<ReceiveRpcCommandRequest>>()
|
||||
.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();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Server-side: processes BuildRepairCommandRpc — assigns citizens to build/repair buildings.
|
||||
/// </summary>
|
||||
[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<BuildRepairCommandRpc>, RefRO<ReceiveRpcCommandRequest>>()
|
||||
.WithEntityAccess())
|
||||
{
|
||||
var citizen = cmd.ValueRO.CitizenEntity;
|
||||
var building = cmd.ValueRO.BuildingEntity;
|
||||
|
||||
if (state.EntityManager.Exists(citizen) && state.EntityManager.Exists(building) &&
|
||||
state.EntityManager.HasComponent<CitizenStateComponent>(citizen))
|
||||
{
|
||||
state.EntityManager.SetComponentData(citizen, new BuildTarget { Target = building });
|
||||
state.EntityManager.SetComponentData(citizen, new CitizenStateComponent { Value = CitizenState.MovingToBuild });
|
||||
|
||||
var buildingPos = state.EntityManager.GetComponentData<LocalTransform>(building).Position;
|
||||
state.EntityManager.SetComponentData(citizen, new MoveTarget
|
||||
{
|
||||
Position = buildingPos,
|
||||
IsActive = true
|
||||
});
|
||||
}
|
||||
|
||||
ecb.DestroyEntity(entity);
|
||||
}
|
||||
|
||||
ecb.Playback(state.EntityManager);
|
||||
ecb.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Server-side: ticks construction progress for buildings with assigned citizens.
|
||||
/// </summary>
|
||||
[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<RefRW<CitizenStateComponent>, RefRO<BuildTarget>,
|
||||
RefRO<LocalTransform>, RefRO<MoveTarget>>()
|
||||
.WithAll<CitizenTag>())
|
||||
{
|
||||
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<ConstructionProgress>(buildingEntity)) continue;
|
||||
|
||||
var progress = state.EntityManager.GetComponentData<ConstructionProgress>(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<UnderConstructionTag>(buildingEntity);
|
||||
ecb.RemoveComponent<ConstructionProgress>(buildingEntity);
|
||||
|
||||
// Set health to max
|
||||
var health = state.EntityManager.GetComponentData<Health>(buildingEntity);
|
||||
health.Current = health.Max;
|
||||
ecb.SetComponent(buildingEntity, health);
|
||||
|
||||
// Citizen becomes idle
|
||||
citizenState.ValueRW.Value = CitizenState.Idle;
|
||||
}
|
||||
}
|
||||
|
||||
ecb.Playback(state.EntityManager);
|
||||
ecb.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Server-side: processes production queues on buildings and spawns units.
|
||||
/// </summary>
|
||||
[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<DynamicBuffer<ProductionQueueElement>, RefRO<RallyPoint>,
|
||||
RefRO<OwnerPlayer>, RefRO<LocalTransform>>()
|
||||
.WithAll<BuildingTag>()
|
||||
.WithNone<UnderConstructionTag>()
|
||||
.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();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user