Hygiene B2: dead-code removal
Delete (unreferenced in any scene, per operator decision):
- TrainingDummy* chain (authoring/spawner/system/components/prefab) + UpgradePickup* chain (authoring/spawner/systems/components/prefab); remove TrainingDummyTag from the 3 live combat queries (AbilityFire/Melee/HealthApplyDamage now key on EnemyTag) and repoint HealthApplyDamageSystemTests to EnemyTag.
- Dead RPC RegionTransitSystem + RegionTransitRequest (no sender, ungated) + its test.
- Heartbeat + HeartbeatSystem (no WorldSystemFilter, ran no-op every tick) + its test.
- BuildSendSystem dead conveyor/pylon dev hooks (s_ConveyorDir, [/] rotation, Place{Pylon,Harvester,Conveyor} statics).
- Deprecated CyclePhase alias consts (Expedition/Defend/Build/*Ticks); repoint WaveSystemTests to Siege/Calm.
- Unread FeelConfig fields (HitFlashDurationMs, RumbleHeavy) + dangling HudUi doc-comments + stale crefs.
451/451 EditMode tests pass. CLAUDE.md HeartbeatSystemTests example ref to be repointed in B7.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -13,7 +13,7 @@ namespace ProjectM.Server
|
||||
/// this tick), subtracts the summed amount from <see cref="Health"/>, then clears the buffer so
|
||||
/// each hit is applied exactly once. Entities that carry character stats (players) clamp to their
|
||||
/// data-driven <see cref="EffectiveCharacterStats.MaxHealth"/> ceiling; others (training dummies)
|
||||
/// clamp at zero. A dead <see cref="TrainingDummyTag"/> is destroyed; player death is deferred.
|
||||
/// clamp at zero. A dead <see cref="EnemyTag"/> is destroyed; player death is deferred.
|
||||
/// Health.Current is a <c>[GhostField]</c>, so the new value replicates to clients for display.
|
||||
///
|
||||
/// Runs server-only (<see cref="WorldSystemFilterFlags.ServerSimulation"/>) inside the prediction
|
||||
@@ -156,7 +156,7 @@ namespace ProjectM.Server
|
||||
if (SystemAPI.HasComponent<IsLunging>(entity)) SystemAPI.SetComponentEnabled<IsLunging>(entity, false);
|
||||
}
|
||||
}
|
||||
else if (SystemAPI.HasComponent<TrainingDummyTag>(entity) || SystemAPI.HasComponent<EnemyTag>(entity) || SystemAPI.HasComponent<Destructible>(entity))
|
||||
else if (SystemAPI.HasComponent<EnemyTag>(entity) || SystemAPI.HasComponent<Destructible>(entity))
|
||||
ecb.DestroyEntity(entity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
using ProjectM.Simulation;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Entities;
|
||||
using Unity.Mathematics;
|
||||
using Unity.Transforms;
|
||||
|
||||
namespace ProjectM.Server
|
||||
{
|
||||
/// <summary>
|
||||
/// Server-only, one-shot dummy spawner. On its first update it reads the baked
|
||||
/// <see cref="TrainingDummySpawner"/> singleton and instantiates <c>Count</c> training-dummy
|
||||
/// ghosts in a row, spaced <c>Spacing</c> world-units apart along +X starting at <c>Origin</c>.
|
||||
/// It then destroys the spawner singleton entity so <c>RequireForUpdate<TrainingDummySpawner></c>
|
||||
/// is no longer satisfied and the system stops running (idempotent: dummies are spawned exactly once).
|
||||
/// Runs in the default <see cref="SimulationSystemGroup"/> (NOT the prediction loop) since spawning is
|
||||
/// a non-predicted, server-authoritative event; the dummies replicate to clients as interpolated ghosts.
|
||||
/// All structural changes are batched through an <see cref="EntityCommandBuffer"/>.
|
||||
/// </summary>
|
||||
[BurstCompile]
|
||||
[WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)]
|
||||
public partial struct TrainingDummySpawnSystem : ISystem
|
||||
{
|
||||
[BurstCompile]
|
||||
public void OnCreate(ref SystemState state)
|
||||
{
|
||||
state.RequireForUpdate<TrainingDummySpawner>();
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public void OnUpdate(ref SystemState state)
|
||||
{
|
||||
// Grab both the singleton entity (to destroy when done) and its baked config.
|
||||
var spawnerEntity = SystemAPI.GetSingletonEntity<TrainingDummySpawner>();
|
||||
var spawner = SystemAPI.GetComponent<TrainingDummySpawner>(spawnerEntity);
|
||||
|
||||
var ecb = new EntityCommandBuffer(Allocator.Temp);
|
||||
|
||||
for (int i = 0; i < spawner.Count; i++)
|
||||
{
|
||||
var dummy = ecb.Instantiate(spawner.Prefab);
|
||||
var position = spawner.Origin + new float3(i * spawner.Spacing, 0f, 0f);
|
||||
ecb.SetComponent(dummy, LocalTransform.FromPosition(position));
|
||||
}
|
||||
|
||||
// One-shot: remove the spawner so RequireForUpdate fails and the system idles.
|
||||
ecb.DestroyEntity(spawnerEntity);
|
||||
|
||||
ecb.Playback(state.EntityManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7673acbc74f7a4bddbca0679122511ea
|
||||
@@ -1,56 +0,0 @@
|
||||
using ProjectM.Simulation;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Entities;
|
||||
using Unity.Mathematics;
|
||||
using Unity.Transforms;
|
||||
|
||||
namespace ProjectM.Server
|
||||
{
|
||||
/// <summary>
|
||||
/// Server-only, one-shot upgrade-pickup spawner (mirrors TrainingDummySpawnSystem). On its first
|
||||
/// update it reads the baked <see cref="UpgradePickupSpawner"/> singleton and instantiates
|
||||
/// <c>Count</c> pickup ghosts in a row, spaced <c>Spacing</c> world-units apart along +X starting at
|
||||
/// <c>Origin</c>, then destroys the singleton so the system idles (spawned exactly once). Runs in the
|
||||
/// default <see cref="SimulationSystemGroup"/> (NOT the prediction loop); pickups replicate to clients
|
||||
/// as interpolated ghosts. Structural changes are batched through an <see cref="EntityCommandBuffer"/>.
|
||||
/// </summary>
|
||||
[BurstCompile]
|
||||
[WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)]
|
||||
public partial struct UpgradePickupSpawnSystem : ISystem
|
||||
{
|
||||
[BurstCompile]
|
||||
public void OnCreate(ref SystemState state)
|
||||
{
|
||||
state.RequireForUpdate<UpgradePickupSpawner>();
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public void OnUpdate(ref SystemState state)
|
||||
{
|
||||
var spawnerEntity = SystemAPI.GetSingletonEntity<UpgradePickupSpawner>();
|
||||
var spawner = SystemAPI.GetComponent<UpgradePickupSpawner>(spawnerEntity);
|
||||
|
||||
var ecb = new EntityCommandBuffer(Allocator.Temp);
|
||||
|
||||
if (spawner.Prefab != Entity.Null)
|
||||
{
|
||||
// Preserve the prefab's baked scale/rotation (FromPosition would reset Scale to 1).
|
||||
var baseXform = SystemAPI.GetComponent<LocalTransform>(spawner.Prefab);
|
||||
for (int i = 0; i < spawner.Count; i++)
|
||||
{
|
||||
var pickup = ecb.Instantiate(spawner.Prefab);
|
||||
var position = spawner.Origin + new float3(i * spawner.Spacing, 0f, 0f);
|
||||
var xform = baseXform;
|
||||
xform.Position = position;
|
||||
ecb.SetComponent(pickup, xform);
|
||||
}
|
||||
}
|
||||
|
||||
// One-shot: remove the spawner so RequireForUpdate fails and the system idles.
|
||||
ecb.DestroyEntity(spawnerEntity);
|
||||
|
||||
ecb.Playback(state.EntityManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 602544c80ca5649258a9d6ca9ad74f79
|
||||
@@ -1,78 +0,0 @@
|
||||
using ProjectM.Simulation;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Entities;
|
||||
using Unity.Mathematics;
|
||||
using Unity.Transforms;
|
||||
|
||||
namespace ProjectM.Server
|
||||
{
|
||||
/// <summary>
|
||||
/// Server-authoritative upgrade pickup grant. When a player overlaps an <see cref="UpgradePickup"/>
|
||||
/// (planar XZ distance within the pickup's <see cref="HitRadius"/>), appends the pickup's modifier to
|
||||
/// the player's replicated <see cref="StatModifier"/> buffer (which replicates to the predicting
|
||||
/// owner, so StatRecomputeSystem folds identical effective stats on both worlds) and destroys the
|
||||
/// pickup. Runs in the default <see cref="SimulationSystemGroup"/> (NOT the prediction loop) since the
|
||||
/// grant is a non-predicted server event. The buffer append + pickup destroy are batched through an
|
||||
/// <see cref="EntityCommandBuffer"/> played back immediately — so a plain-world EditMode test needs no
|
||||
/// separate ECB system.
|
||||
/// </summary>
|
||||
[BurstCompile]
|
||||
[WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)]
|
||||
public partial struct UpgradePickupSystem : ISystem
|
||||
{
|
||||
[BurstCompile]
|
||||
public void OnCreate(ref SystemState state)
|
||||
{
|
||||
state.RequireForUpdate<UpgradePickup>();
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public void OnUpdate(ref SystemState state)
|
||||
{
|
||||
// Snapshot modifiable players (carrying the modifier buffer + a transform) once this tick.
|
||||
var playerEntities = new NativeList<Entity>(Allocator.Temp);
|
||||
var playerPositions = new NativeList<float3>(Allocator.Temp);
|
||||
foreach (var (xform, e) in
|
||||
SystemAPI.Query<RefRO<LocalTransform>>()
|
||||
.WithAll<PlayerTag, StatModifier>()
|
||||
.WithEntityAccess())
|
||||
{
|
||||
playerEntities.Add(e);
|
||||
playerPositions.Add(xform.ValueRO.Position);
|
||||
}
|
||||
|
||||
var ecb = new EntityCommandBuffer(Allocator.Temp);
|
||||
|
||||
foreach (var (xform, radius, pickup, pickupEntity) in
|
||||
SystemAPI.Query<RefRO<LocalTransform>, RefRO<HitRadius>, RefRO<UpgradePickup>>()
|
||||
.WithEntityAccess())
|
||||
{
|
||||
float2 pp = new float2(xform.ValueRO.Position.x, xform.ValueRO.Position.z);
|
||||
float r = radius.ValueRO.Value;
|
||||
|
||||
for (int i = 0; i < playerEntities.Length; i++)
|
||||
{
|
||||
float2 cp = new float2(playerPositions[i].x, playerPositions[i].z);
|
||||
if (math.distancesq(pp, cp) > r * r)
|
||||
continue;
|
||||
|
||||
ecb.AppendToBuffer(playerEntities[i], new StatModifier
|
||||
{
|
||||
Target = pickup.ValueRO.Target,
|
||||
Op = pickup.ValueRO.Op,
|
||||
Value = pickup.ValueRO.Value,
|
||||
SourceId = pickup.ValueRO.SourceId,
|
||||
});
|
||||
ecb.DestroyEntity(pickupEntity);
|
||||
break; // granted to the first overlapping player, then despawns
|
||||
}
|
||||
}
|
||||
|
||||
ecb.Playback(state.EntityManager);
|
||||
ecb.Dispose();
|
||||
playerEntities.Dispose();
|
||||
playerPositions.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c3d9ef25fbc464e52aa342b531d6f35e
|
||||
@@ -1,71 +0,0 @@
|
||||
using ProjectM.Simulation;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Entities;
|
||||
using Unity.NetCode;
|
||||
using Unity.Transforms;
|
||||
|
||||
namespace ProjectM.Server
|
||||
{
|
||||
/// <summary>
|
||||
/// Server-authoritative handler for <see cref="RegionTransitRequest"/> RPCs. Resolves the sender's player
|
||||
/// (via the source connection's <see cref="NetworkId"/> -> <see cref="GhostOwner"/>), flips its
|
||||
/// <see cref="RegionTag"/> to the requested region, and teleports it to that region's origin
|
||||
/// (<see cref="RegionMath.RegionOrigin"/>, centered on the base via <see cref="BaseGridMath.PlotCenter"/>).
|
||||
/// Runs in the default server SimulationSystemGroup (NOT the prediction loop) so the transit applies once;
|
||||
/// the next snapshot reconciles the owner-predicted client and <see cref="RegionRelevancySystem"/> re-scopes
|
||||
/// which region's ghosts the connection receives. Mirrors the <see cref="StorageOpReceiveSystem"/> RPC shape.
|
||||
/// </summary>
|
||||
[BurstCompile]
|
||||
[WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)]
|
||||
public partial struct RegionTransitSystem : ISystem
|
||||
{
|
||||
[BurstCompile]
|
||||
public void OnCreate(ref SystemState state)
|
||||
{
|
||||
state.RequireForUpdate<BaseAnchor>();
|
||||
|
||||
var builder = new EntityQueryBuilder(Allocator.Temp)
|
||||
.WithAll<RegionTransitRequest, ReceiveRpcCommandRequest>();
|
||||
state.RequireForUpdate(state.GetEntityQuery(builder));
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public void OnUpdate(ref SystemState state)
|
||||
{
|
||||
var baseCenter = BaseGridMath.PlotCenter(SystemAPI.GetSingleton<BaseAnchor>());
|
||||
|
||||
// Map connection NetworkId -> player entity.
|
||||
var playerByConn = new NativeHashMap<int, Entity>(8, Allocator.Temp);
|
||||
foreach (var (owner, entity) in
|
||||
SystemAPI.Query<RefRO<GhostOwner>>().WithAll<PlayerTag, RegionTag>().WithEntityAccess())
|
||||
{
|
||||
playerByConn[owner.ValueRO.NetworkId] = entity;
|
||||
}
|
||||
|
||||
var ecb = new EntityCommandBuffer(Allocator.Temp);
|
||||
|
||||
foreach (var (request, receive, requestEntity) in
|
||||
SystemAPI.Query<RefRO<RegionTransitRequest>, RefRO<ReceiveRpcCommandRequest>>().WithEntityAccess())
|
||||
{
|
||||
var connEntity = receive.ValueRO.SourceConnection;
|
||||
if (SystemAPI.HasComponent<NetworkId>(connEntity))
|
||||
{
|
||||
int connId = SystemAPI.GetComponent<NetworkId>(connEntity).Value;
|
||||
if (playerByConn.TryGetValue(connId, out var player))
|
||||
{
|
||||
byte target = request.ValueRO.TargetRegion;
|
||||
SystemAPI.GetComponentRW<RegionTag>(player).ValueRW.Region = target;
|
||||
SystemAPI.GetComponentRW<LocalTransform>(player).ValueRW.Position =
|
||||
RegionMath.RegionOrigin(target, baseCenter);
|
||||
}
|
||||
}
|
||||
|
||||
ecb.DestroyEntity(requestEntity);
|
||||
}
|
||||
|
||||
ecb.Playback(state.EntityManager);
|
||||
playerByConn.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 44d6ce89f189d984c83cd213d86d4b02
|
||||
Reference in New Issue
Block a user