Hygiene B4d: PlayerResolve dedup + explicit Temp-ECB Dispose tail
- New Server/PlayerResolve.TryResolve single-sources the RPC SourceConnection -> NetworkId -> conn->player map resolve (3 sites: ClassSelectReceive, PrepPurchase, DebugCommandReceive); EntityManager reads keep it source-gen-safe from Bursted receivers. - ecb.Dispose() after Playback in 9 Temp-ECB systems (explicit-lifetime hygiene). - The TuningConfig.GetOrDefault(ref state) variant of this tail was REVERTED: state.GetEntityQuery in OnUpdate trips the Entities "creates a query during OnUpdate" diagnostic per system per world (caught in Play smoke) - the SystemAPI.TryGetSingleton idiom is already source-gen-optimal, confirming the original B4 deferral. Verified: 466/466 EditMode green on the final tree, console clean, Play smoke 0 errors. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -54,6 +54,7 @@ namespace ProjectM.Client
|
|||||||
}
|
}
|
||||||
|
|
||||||
ecb.Playback(state.EntityManager);
|
ecb.Playback(state.EntityManager);
|
||||||
|
ecb.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,6 +129,7 @@ namespace ProjectM.Server
|
|||||||
}
|
}
|
||||||
|
|
||||||
ecb.Playback(state.EntityManager);
|
ecb.Playback(state.EntityManager);
|
||||||
|
ecb.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ namespace ProjectM.Server
|
|||||||
}
|
}
|
||||||
|
|
||||||
ecb.Playback(state.EntityManager);
|
ecb.Playback(state.EntityManager);
|
||||||
|
ecb.Dispose();
|
||||||
occupied.Dispose();
|
occupied.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,8 +48,7 @@ namespace ProjectM.Server
|
|||||||
if (!accept) continue;
|
if (!accept) continue;
|
||||||
|
|
||||||
var conn = receive.ValueRO.SourceConnection;
|
var conn = receive.ValueRO.SourceConnection;
|
||||||
if (!SystemAPI.HasComponent<NetworkId>(conn)
|
if (!PlayerResolve.TryResolve(ref state, playerByConn, conn, out var player))
|
||||||
|| !playerByConn.TryGetValue(SystemAPI.GetComponent<NetworkId>(conn).Value, out var player))
|
|
||||||
continue;
|
continue;
|
||||||
if (!SystemAPI.HasComponent<AbilityRef>(player)) continue;
|
if (!SystemAPI.HasComponent<AbilityRef>(player)) continue;
|
||||||
|
|
||||||
|
|||||||
@@ -46,8 +46,7 @@ namespace ProjectM.Server
|
|||||||
if (!accept) continue;
|
if (!accept) continue;
|
||||||
|
|
||||||
var conn = receive.ValueRO.SourceConnection;
|
var conn = receive.ValueRO.SourceConnection;
|
||||||
if (!SystemAPI.HasComponent<NetworkId>(conn)
|
if (!PlayerResolve.TryResolve(ref state, playerByConn, conn, out var buyer))
|
||||||
|| !playerByConn.TryGetValue(SystemAPI.GetComponent<NetworkId>(conn).Value, out var buyer))
|
|
||||||
continue;
|
continue;
|
||||||
if (!PrepCatalog.TryGet(req.ValueRO.OptionId, out var row)) continue; // unknown id -> drop
|
if (!PrepCatalog.TryGet(req.ValueRO.OptionId, out var row)) continue; // unknown id -> drop
|
||||||
|
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ namespace ProjectM.Server
|
|||||||
}
|
}
|
||||||
|
|
||||||
ecb.Playback(state.EntityManager);
|
ecb.Playback(state.EntityManager);
|
||||||
|
ecb.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,8 +50,7 @@ namespace ProjectM.Server
|
|||||||
|
|
||||||
Entity sender = Entity.Null;
|
Entity sender = Entity.Null;
|
||||||
var connEntity = receive.ValueRO.SourceConnection;
|
var connEntity = receive.ValueRO.SourceConnection;
|
||||||
if (SystemAPI.HasComponent<NetworkId>(connEntity))
|
PlayerResolve.TryResolve(ref state, playerByConn, connEntity, out sender);
|
||||||
playerByConn.TryGetValue(SystemAPI.GetComponent<NetworkId>(connEntity).Value, out sender);
|
|
||||||
|
|
||||||
switch (cmd.Op)
|
switch (cmd.Op)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -141,6 +141,7 @@ namespace ProjectM.Server
|
|||||||
}
|
}
|
||||||
|
|
||||||
ecb.Playback(state.EntityManager);
|
ecb.Playback(state.EntityManager);
|
||||||
|
ecb.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ namespace ProjectM.Server
|
|||||||
ecb.DestroyEntity(spawnerEntity);
|
ecb.DestroyEntity(spawnerEntity);
|
||||||
|
|
||||||
ecb.Playback(state.EntityManager);
|
ecb.Playback(state.EntityManager);
|
||||||
|
ecb.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ namespace ProjectM.Server
|
|||||||
}
|
}
|
||||||
|
|
||||||
ecb.Playback(state.EntityManager);
|
ecb.Playback(state.EntityManager);
|
||||||
|
ecb.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
using Unity.Collections;
|
||||||
|
using Unity.Entities;
|
||||||
|
using Unity.NetCode;
|
||||||
|
|
||||||
|
namespace ProjectM.Server
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Shared server-side RPC sender resolution: a request's <c>ReceiveRpcCommandRequest.SourceConnection</c> →
|
||||||
|
/// its <see cref="NetworkId"/> → the conn→player map that every RPC-receive system builds (the
|
||||||
|
/// AbilityUpgradeSystem / ReadyToggle idiom). The MAP BUILD stays per-caller — each system's player query
|
||||||
|
/// carries different extra required components (InventorySlot / EquipmentSlot / StatModifier / BoonOffer /
|
||||||
|
/// PlayerReady / …) — but the RESOLVE step is byte-for-byte identical across sites, so it lives here once.
|
||||||
|
/// Burst-safe (plain <see cref="EntityManager"/> reads; called from <c>[BurstCompile]</c> receivers).
|
||||||
|
/// </summary>
|
||||||
|
public static class PlayerResolve
|
||||||
|
{
|
||||||
|
/// <summary>True (with <paramref name="player"/> set) iff <paramref name="conn"/> has a
|
||||||
|
/// <see cref="NetworkId"/> present in <paramref name="map"/>. Behaviour-identical to the inline
|
||||||
|
/// <c>HasComponent<NetworkId>(conn) && map.TryGetValue(GetComponent<NetworkId>(conn).Value, out player)</c>.</summary>
|
||||||
|
public static bool TryResolve(ref SystemState state, NativeHashMap<int, Entity> map, Entity conn, out Entity player)
|
||||||
|
{
|
||||||
|
player = Entity.Null;
|
||||||
|
return state.EntityManager.HasComponent<NetworkId>(conn)
|
||||||
|
&& map.TryGetValue(state.EntityManager.GetComponentData<NetworkId>(conn).Value, out player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 5e602229d090fee489d063aebece5da2
|
||||||
@@ -154,6 +154,7 @@ namespace ProjectM.Server
|
|||||||
ecb.DestroyEntity(spawnerEntity);
|
ecb.DestroyEntity(spawnerEntity);
|
||||||
|
|
||||||
ecb.Playback(state.EntityManager);
|
ecb.Playback(state.EntityManager);
|
||||||
|
ecb.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ namespace ProjectM.Server
|
|||||||
ecb.DestroyEntity(requestEntity);
|
ecb.DestroyEntity(requestEntity);
|
||||||
}
|
}
|
||||||
ecb.Playback(state.EntityManager);
|
ecb.Playback(state.EntityManager);
|
||||||
|
ecb.Dispose();
|
||||||
regionByConn.Dispose();
|
regionByConn.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user