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