using ProjectM.Simulation;
using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.NetCode;
namespace ProjectM.Server
{
///
/// Server-authoritative ability-damage upgrade (handles RPCs). Resolves
/// the sender's player (SourceConnection -> NetworkId -> GhostOwner) and, if the global ledger affords the
/// Aether cost, withdraws it IN-PLACE and grows a single damage on the player
/// (replace-by-SourceId so the [InternalBufferCapacity(8)] buffer stays bounded — repeated upgrades grow one
/// row's percent rather than appending). StatRecomputeSystem folds it into EffectiveAbilityStats.Damage on
/// both worlds. Plain server SimulationSystemGroup (not predicted → applied once).
///
[BurstCompile]
[WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)]
public partial struct AbilityUpgradeSystem : ISystem
{
const uint UpgradeSourceId = Tuning.AbilityUpgradeSourceId; // distinct sentinel so the upgrade modifier is found + grown
const float TierStep = Tuning.AbilityUpgradeTierStep; // +25% damage per tier
const int CostAmount = Tuning.AbilityUpgradeCostAmount; // Aether per tier
[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 (receive, requestEntity) in
SystemAPI.Query>().WithAll().WithEntityAccess())
{
var conn = receive.ValueRO.SourceConnection;
if (SystemAPI.HasComponent(conn)
&& playerByConn.TryGetValue(SystemAPI.GetComponent(conn).Value, out var player))
{
int have = 0;
for (int i = 0; i < ledger.Length; i++)
if (ledger[i].ItemId == ResourceId.Aether) { have = ledger[i].Count; break; }
if (have >= CostAmount)
{
StorageMath.Withdraw(ledger, ResourceId.Aether, CostAmount);
var mods = SystemAPI.GetBuffer(player);
bool grown = false;
for (int i = 0; i < mods.Length; i++)
{
if (mods[i].SourceId == UpgradeSourceId && mods[i].Target == (byte)StatTarget.Damage)
{
var m = mods[i];
m.Value += TierStep;
mods[i] = m;
grown = true;
break;
}
}
if (!grown)
mods.Add(new StatModifier
{
Target = (byte)StatTarget.Damage,
Op = (byte)ModOp.PercentAdd,
Value = TierStep,
SourceId = UpgradeSourceId,
});
}
}
ecb.DestroyEntity(requestEntity);
}
ecb.Playback(state.EntityManager);
playerByConn.Dispose();
}
}
}