Initial import

This commit is contained in:
ldbetteridge
2026-03-31 15:59:23 +01:00
commit 58da5d1d71
136 changed files with 10922 additions and 0 deletions

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