7c1fee097e
- The center-top phase banner read the CyclePhase label ("AT BASE") inside
expedition rooms - now shows ON EXPEDITION whenever a run is past Staging.
- The location-line switch had no RoomExplore case, so "choose your boon"
stuck through the whole loot window - added the portal-steer line.
- Storage crate floated 1u: GridOrigin.y=1 is the CC capsule-CENTER plane;
CellToWorld returns it, and the crate's mesh pivot is at its base (Turret/
Wall pivots are centered, which is why structures look grounded). The
container now sits on the terrain; same grounding for the portal beacon,
whose pos.y was the capsule plane too.
- Beacon HDR 2.6/3.4 bloomed into a white egg that swallowed the prompt -
tamed to 1.2/1.55 + slimmed the pillar.
456/456 EditMode before and after; Play smoke: crate at y=0, banner correct
at Staging.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
61 lines
2.7 KiB
C#
61 lines
2.7 KiB
C#
using ProjectM.Simulation;
|
|
using Unity.Burst;
|
|
using Unity.Collections;
|
|
using Unity.Entities;
|
|
using Unity.Transforms;
|
|
|
|
namespace ProjectM.Server
|
|
{
|
|
/// <summary>
|
|
/// Server-only, one-shot spawner for the shared home-base storage container (mirrors
|
|
/// UpgradePickupSpawnSystem). On its first update it reads the baked <see cref="StorageSpawner"/>
|
|
/// singleton and the <see cref="BaseAnchor"/>, instantiates the container ghost at the cell center
|
|
/// (<see cref="BaseGridMath.CellToWorld"/>), then destroys the spawner singleton so the system idles
|
|
/// (spawned exactly once). Runs in the default SimulationSystemGroup (NOT the prediction loop); the
|
|
/// container replicates to clients as an ownerless interpolated ghost. The container is intentionally
|
|
/// NOT linked to any connection's LinkedEntityGroup, so it persists across player disconnects.
|
|
/// </summary>
|
|
[BurstCompile]
|
|
[WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)]
|
|
public partial struct SharedStorageSpawnSystem : ISystem
|
|
{
|
|
[BurstCompile]
|
|
public void OnCreate(ref SystemState state)
|
|
{
|
|
state.RequireForUpdate<StorageSpawner>();
|
|
state.RequireForUpdate<BaseAnchor>();
|
|
}
|
|
|
|
[BurstCompile]
|
|
public void OnUpdate(ref SystemState state)
|
|
{
|
|
var spawnerEntity = SystemAPI.GetSingletonEntity<StorageSpawner>();
|
|
var spawner = SystemAPI.GetComponent<StorageSpawner>(spawnerEntity);
|
|
var anchor = SystemAPI.GetSingleton<BaseAnchor>();
|
|
|
|
var ecb = new EntityCommandBuffer(Allocator.Temp);
|
|
|
|
if (spawner.Prefab != Entity.Null)
|
|
{
|
|
var container = ecb.Instantiate(spawner.Prefab);
|
|
var position = BaseGridMath.CellToWorld(anchor, spawner.Cell);
|
|
// Phase 0: the grid Y (GridOrigin.y=1) is the CC capsule-CENTER plane; center-pivot structure
|
|
// meshes look grounded there, but the crate's pivot is at its base -> it floated 1 u. Sit it on
|
|
// the terrain surface instead.
|
|
position.y = 0f;
|
|
// Preserve the prefab's baked scale/rotation (FromPosition would reset Scale to 1).
|
|
var xform = SystemAPI.GetComponent<LocalTransform>(spawner.Prefab);
|
|
xform.Position = position;
|
|
ecb.SetComponent(container, xform);
|
|
// M6: scope the shared storage to the base region for ghost relevancy.
|
|
ecb.AddComponent(container, new RegionTag { Region = RegionId.Base });
|
|
}
|
|
|
|
// One-shot: remove the spawner so RequireForUpdate fails and the system idles.
|
|
ecb.DestroyEntity(spawnerEntity);
|
|
|
|
ecb.Playback(state.EntityManager);
|
|
}
|
|
}
|
|
}
|