using ProjectM.Simulation;
using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.NetCode;
namespace ProjectM.Server
{
///
/// Server-authoritative handler for RPCs: moves items from the
/// sender's PERSONAL inventory into the shared base stockpile (the global
/// the build/upgrade/automation economy spends from). Resolves the sender's
/// player (SourceConnection -> NetworkId -> GhostOwner) via the AbilityUpgradeSystem owner-map idiom,
/// then withdraws from the player's inventory and deposits into the ledger IN-PLACE (buffer mutation is not
/// a structural change). ItemId == 0 ("deposit all") is handled BEFORE any per-item withdraw and
/// never writes a 0-id row. Resolves the ledger via GetSingletonEntity<ResourceLedger>() then
/// GetBuffer<StorageEntry>() — NEVER GetSingleton<StorageEntry> (the base
/// container owns a second StorageEntry buffer). Plain server SimulationSystemGroup (not predicted, so the
/// effect applies exactly once — no rollback double-apply).
///
[BurstCompile]
[WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)]
public partial struct InventoryDepositSystem : ISystem
{
[BurstCompile]
public void OnCreate(ref SystemState state)
{
state.RequireForUpdate();
var builder = new EntityQueryBuilder(Allocator.Temp)
.WithAll();
state.RequireForUpdate(state.GetEntityQuery(builder));
}
[BurstCompile]
public void OnUpdate(ref SystemState state)
{
var ledger = SystemAPI.GetBuffer(SystemAPI.GetSingletonEntity());
var playerByConn = new NativeHashMap(8, Allocator.Temp);
foreach (var (owner, entity) in
SystemAPI.Query>().WithAll().WithEntityAccess())
playerByConn[owner.ValueRO.NetworkId] = entity;
var ecb = new EntityCommandBuffer(Allocator.Temp);
foreach (var (request, receive, requestEntity) in
SystemAPI.Query, RefRO>().WithEntityAccess())
{
var conn = receive.ValueRO.SourceConnection;
if (SystemAPI.HasComponent(conn)
&& playerByConn.TryGetValue(SystemAPI.GetComponent(conn).Value, out var player))
{
var inv = SystemAPI.GetBuffer(player);
var req = request.ValueRO;
if (req.ItemId == 0)
{
// Deposit EVERYTHING: drain each non-empty stack into the ledger, then clear the bag.
for (int i = 0; i < inv.Length; i++)
{
var slot = inv[i];
if (slot.ItemId != 0 && slot.Count > 0)
StorageMath.Deposit(ledger, slot.ItemId, slot.Count);
}
inv.Clear();
}
else
{
// Count <= 0 means "all of that item"; Withdraw clamps to what is available.
int want = req.Count <= 0 ? int.MaxValue : req.Count;
int moved = InventoryMath.Withdraw(inv, req.ItemId, want);
if (moved > 0)
StorageMath.Deposit(ledger, req.ItemId, moved);
}
}
ecb.DestroyEntity(requestEntity);
}
ecb.Playback(state.EntityManager);
playerByConn.Dispose();
}
}
}