108 lines
4.8 KiB
C#
108 lines
4.8 KiB
C#
using ProjectM.Simulation;
|
|
using Unity.Entities;
|
|
using Unity.Mathematics;
|
|
using Unity.NetCode;
|
|
using Unity.Transforms;
|
|
|
|
namespace ProjectM.Client
|
|
{
|
|
/// <summary>
|
|
/// Client-only sender for build + upgrade RPCs. Keyboard: B builds a Turret at the local player's current
|
|
/// grid cell; U upgrades ability damage. Editor-only statics (PlaceStructure / PlaceTurret / UpgradeAbility)
|
|
/// drive the same path from execute_code for headless validation (a one-shot key can't be injected on an
|
|
/// unfocused editor — the StorageOpSendSystem idiom). Managed SystemBase (reads the Input System);
|
|
/// UnityEngine.InputSystem is fully qualified to avoid the ProjectM.Simulation.PlayerInput name collision.
|
|
/// The server re-validates legality + cost authoritatively; this only sends a hint.
|
|
/// </summary>
|
|
[WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation)]
|
|
public partial class BuildSendSystem : SystemBase
|
|
{
|
|
#if UNITY_EDITOR
|
|
struct PendingBuild { public byte Type; public int CellX; public int CellZ; }
|
|
static readonly System.Collections.Generic.Queue<PendingBuild> s_PendingBuild =
|
|
new System.Collections.Generic.Queue<PendingBuild>();
|
|
static int s_PendingUpgrades = 0;
|
|
|
|
/// <summary>EDITOR / execute_code hook: queue a structure placement at a specific cell.</summary>
|
|
public static void PlaceStructure(byte type, int cellX, int cellZ) =>
|
|
s_PendingBuild.Enqueue(new PendingBuild { Type = type, CellX = cellX, CellZ = cellZ });
|
|
|
|
/// <summary>EDITOR / execute_code hook: queue a turret placement at a specific cell.</summary>
|
|
public static void PlaceTurret(int cellX, int cellZ) => PlaceStructure(StructureType.Turret, cellX, cellZ);
|
|
|
|
/// <summary>EDITOR / execute_code hook: queue a wall placement at a specific cell.</summary>
|
|
public static void PlaceWall(int cellX, int cellZ) => PlaceStructure(StructureType.Wall, cellX, cellZ);
|
|
|
|
/// <summary>EDITOR / execute_code hook: queue a pylon placement at a specific cell.</summary>
|
|
public static void PlacePylon(int cellX, int cellZ) => PlaceStructure(StructureType.Pylon, cellX, cellZ);
|
|
|
|
/// <summary>EDITOR / execute_code hook: queue an ability-damage upgrade.</summary>
|
|
public static void UpgradeAbility() => s_PendingUpgrades++;
|
|
#endif
|
|
|
|
protected override void OnCreate()
|
|
{
|
|
RequireForUpdate<NetworkId>();
|
|
}
|
|
|
|
protected override void OnUpdate()
|
|
{
|
|
if (!SystemAPI.TryGetSingletonEntity<NetworkId>(out var connection))
|
|
return;
|
|
|
|
var keyboard = UnityEngine.InputSystem.Keyboard.current;
|
|
if (keyboard != null)
|
|
{
|
|
if (keyboard.bKey.wasPressedThisFrame && TryGetLocalPlayerCell(out int2 cell))
|
|
SendBuild(connection, StructureType.Turret, cell.x, cell.y);
|
|
if (keyboard.vKey.wasPressedThisFrame && TryGetLocalPlayerCell(out int2 wcell))
|
|
SendBuild(connection, StructureType.Wall, wcell.x, wcell.y);
|
|
if (keyboard.nKey.wasPressedThisFrame && TryGetLocalPlayerCell(out int2 pcell))
|
|
SendBuild(connection, StructureType.Pylon, pcell.x, pcell.y);
|
|
if (keyboard.uKey.wasPressedThisFrame)
|
|
SendUpgrade(connection);
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
while (s_PendingBuild.Count > 0)
|
|
{
|
|
var b = s_PendingBuild.Dequeue();
|
|
SendBuild(connection, b.Type, b.CellX, b.CellZ);
|
|
}
|
|
while (s_PendingUpgrades > 0)
|
|
{
|
|
s_PendingUpgrades--;
|
|
SendUpgrade(connection);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
bool TryGetLocalPlayerCell(out int2 cell)
|
|
{
|
|
cell = default;
|
|
if (!SystemAPI.TryGetSingleton<BaseAnchor>(out var anchor))
|
|
return false;
|
|
foreach (var xform in SystemAPI.Query<RefRO<LocalTransform>>().WithAll<GhostOwnerIsLocal, PlayerTag>())
|
|
{
|
|
cell = BaseGridMath.WorldToCell(anchor, xform.ValueRO.Position);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void SendBuild(Entity connection, byte type, int cellX, int cellZ)
|
|
{
|
|
var e = EntityManager.CreateEntity();
|
|
EntityManager.AddComponentData(e, new BuildPlaceRequest { StructureType = type, CellX = cellX, CellZ = cellZ });
|
|
EntityManager.AddComponentData(e, new SendRpcCommandRequest { TargetConnection = connection });
|
|
}
|
|
|
|
void SendUpgrade(Entity connection)
|
|
{
|
|
var e = EntityManager.CreateEntity();
|
|
EntityManager.AddComponentData(e, new AbilityUpgradeRequest());
|
|
EntityManager.AddComponentData(e, new SendRpcCommandRequest { TargetConnection = connection });
|
|
}
|
|
}
|
|
}
|