Files
Workspace/Assets/Demos/Demo2/ECS/Demo2Systems.cs
T
2026-08-18 02:03:34 +08:00

539 lines
28 KiB
C#

#nullable enable
using System;
using Demo2.Domain;
using Unity.Collections;
using Unity.Entities;
namespace Demo2.ECS
{
[DisableAutoCreation]
public sealed partial class Demo2SimulationSystemGroup : ComponentSystemGroup { }
[DisableAutoCreation]
public sealed partial class Demo2BuildCommandSystem : SystemBase
{
protected override void OnUpdate()
{
var singletonQuery = GetEntityQuery(typeof(Demo2SimulationState), typeof(Demo2EconomyState), typeof(Demo2BuildCommandElement), typeof(Demo2ProcessedCommandToken));
if (singletonQuery.IsEmptyIgnoreFilter) return;
var singleton = singletonQuery.GetSingletonEntity();
var simulation = EntityManager.GetComponentData<Demo2SimulationState>(singleton);
if (simulation.Phase != Demo2Phase.Build) return;
var economy = EntityManager.GetComponentData<Demo2EconomyState>(singleton);
var commands = EntityManager.GetBuffer<Demo2BuildCommandElement>(singleton);
var tokens = EntityManager.GetBuffer<Demo2ProcessedCommandToken>(singleton);
var pending = commands.ToNativeArray(Allocator.Temp);
var knownTokens = new NativeArray<FixedString64Bytes>(tokens.Length + pending.Length, Allocator.Temp);
var knownCount = tokens.Length;
for (var i = 0; i < tokens.Length; i++) knownTokens[i] = tokens[i].Value;
commands.Clear();
for (var index = 0; index < pending.Length; index++)
{
var command = pending[index];
if (Contains(knownTokens, knownCount, command.IdempotencyToken)) continue;
knownTokens[knownCount++] = command.IdempotencyToken;
if (command.X < 0 || command.X >= Demo2Protocol.GridWidth || command.Y < 0 || command.Y >= Demo2Protocol.GridHeight) continue;
var existing = FindMachine(command.X, command.Y);
if (command.Remove != 0)
{
if (existing != Entity.Null)
{
var machine = EntityManager.GetComponentData<Demo2MachineState>(existing);
economy.Money = SaturatingMath.Add(economy.Money, Cost(machine.Kind));
EntityManager.DestroyEntity(existing);
}
continue;
}
var cost = Cost(command.Kind);
if (existing != Entity.Null || economy.Money < cost) continue;
economy.Money -= cost;
simulation.NextStableId++;
Demo2EcsFactory.CreateMachine(EntityManager, simulation.NextStableId, command.Kind, command.X, command.Y, command.Rotation, command.RecipeId);
}
tokens = EntityManager.GetBuffer<Demo2ProcessedCommandToken>(singleton);
tokens.Clear();
for (var i = Math.Max(0, knownCount - 256); i < knownCount; i++)
tokens.Add(new Demo2ProcessedCommandToken { Value = knownTokens[i] });
pending.Dispose();
knownTokens.Dispose();
EntityManager.SetComponentData(singleton, simulation);
EntityManager.SetComponentData(singleton, economy);
}
private Entity FindMachine(int x, int y)
{
var query = GetEntityQuery(typeof(Demo2GridPosition), typeof(Demo2MachineState));
using var entities = query.ToEntityArray(Allocator.Temp);
using var positions = query.ToComponentDataArray<Demo2GridPosition>(Allocator.Temp);
for (var i = 0; i < entities.Length; i++)
if (positions[i].X == x && positions[i].Y == y) return entities[i];
return Entity.Null;
}
private static bool Contains(NativeArray<FixedString64Bytes> tokens, int count, FixedString64Bytes token)
{
for (var i = 0; i < count; i++) if (tokens[i].Equals(token)) return true;
return false;
}
public static int Cost(Demo2MachineKind kind) => kind switch
{
Demo2MachineKind.Miner => 40,
Demo2MachineKind.Conveyor => 5,
Demo2MachineKind.Splitter => 15,
Demo2MachineKind.Smelter => 80,
Demo2MachineKind.Assembler => 110,
Demo2MachineKind.Loader => 70,
Demo2MachineKind.Turret => 150,
Demo2MachineKind.Generator => 60,
Demo2MachineKind.NightShiftSmelter => 95,
_ => 0
};
}
[DisableAutoCreation]
public sealed partial class Demo2ExtractionSystem : SystemBase
{
protected override void OnUpdate()
{
if (!Demo2SystemUtility.TryGetProductionState(EntityManager, out var singleton, out var simulation)) return;
var stats = EntityManager.GetComponentData<Demo2CycleStats>(singleton);
var query = GetEntityQuery(typeof(Demo2StableId), typeof(Demo2GridPosition), typeof(Demo2MachineState), typeof(Demo2RecipeState));
using var entities = query.ToEntityArray(Allocator.Temp);
using var positions = query.ToComponentDataArray<Demo2GridPosition>(Allocator.Temp);
for (var i = 0; i < entities.Length; i++)
{
var machine = EntityManager.GetComponentData<Demo2MachineState>(entities[i]);
if (machine.Enabled == 0 || (machine.Kind != Demo2MachineKind.Miner && machine.Kind != Demo2MachineKind.Generator)) continue;
machine.ProgressTicks++;
if (machine.ProgressTicks < Math.Max(1, machine.ProcessTicks))
{
EntityManager.SetComponentData(entities[i], machine);
continue;
}
machine.ProgressTicks = 0;
var recipe = EntityManager.GetComponentData<Demo2RecipeState>(entities[i]);
simulation.NextStableId++;
Demo2EcsFactory.CreateMaterial(EntityManager, simulation.NextStableId, recipe.Output, positions[i].X, positions[i].Y, machine.Rotation, Math.Max(1, recipe.OutputCount));
stats.Extracted = SaturatingMath.Add(stats.Extracted, recipe.OutputCount);
if (recipe.Output == Demo2MaterialKind.Energy)
{
var economy = EntityManager.GetComponentData<Demo2EconomyState>(singleton);
economy.Energy = SaturatingMath.Add(economy.Energy, recipe.OutputCount);
EntityManager.SetComponentData(singleton, economy);
}
EntityManager.SetComponentData(entities[i], machine);
}
EntityManager.SetComponentData(singleton, simulation);
EntityManager.SetComponentData(singleton, stats);
}
}
[DisableAutoCreation]
public sealed partial class Demo2ConveyorSystem : SystemBase
{
protected override void OnUpdate()
{
if (!Demo2SystemUtility.TryGetProductionState(EntityManager, out var singleton, out _)) return;
var stats = EntityManager.GetComponentData<Demo2CycleStats>(singleton);
stats.BeltOccupancy = 0;
stats.BeltCapacity = 0;
var beltQuery = GetEntityQuery(typeof(Demo2ConveyorState));
using (var belts = beltQuery.ToComponentDataArray<Demo2ConveyorState>(Allocator.Temp))
for (var i = 0; i < belts.Length; i++) stats.BeltCapacity += Math.Max(1, belts[i].Capacity);
var query = GetEntityQuery(typeof(Demo2GridPosition), typeof(Demo2MaterialState));
using var entities = query.ToEntityArray(Allocator.Temp);
for (var i = 0; i < entities.Length; i++)
{
var position = EntityManager.GetComponentData<Demo2GridPosition>(entities[i]);
var material = EntityManager.GetComponentData<Demo2MaterialState>(entities[i]);
material.SubCellProgress += 250;
stats.BeltOccupancy += material.Quantity;
if (material.SubCellProgress >= 1000)
{
material.SubCellProgress -= 1000;
Demo2SystemUtility.Move(ref position, material.Direction);
stats.Transported = SaturatingMath.Add(stats.Transported, material.Quantity);
}
EntityManager.SetComponentData(entities[i], position);
EntityManager.SetComponentData(entities[i], material);
}
EntityManager.SetComponentData(singleton, stats);
}
}
[DisableAutoCreation]
public sealed partial class Demo2InputAllocationSystem : SystemBase
{
protected override void OnUpdate()
{
if (!Demo2SystemUtility.TryGetProductionState(EntityManager, out var singleton, out _)) return;
var stats = EntityManager.GetComponentData<Demo2CycleStats>(singleton);
var materialQuery = GetEntityQuery(typeof(Demo2GridPosition), typeof(Demo2MaterialState));
var machineQuery = GetEntityQuery(typeof(Demo2GridPosition), typeof(Demo2MachineState));
using var materials = materialQuery.ToEntityArray(Allocator.Temp);
using var materialPositions = materialQuery.ToComponentDataArray<Demo2GridPosition>(Allocator.Temp);
using var materialStates = materialQuery.ToComponentDataArray<Demo2MaterialState>(Allocator.Temp);
using var machines = machineQuery.ToEntityArray(Allocator.Temp);
using var machinePositions = machineQuery.ToComponentDataArray<Demo2GridPosition>(Allocator.Temp);
for (var m = 0; m < materials.Length; m++)
{
if (!EntityManager.Exists(materials[m])) continue;
for (var i = 0; i < machines.Length; i++)
{
if (materialPositions[m].X != machinePositions[i].X || materialPositions[m].Y != machinePositions[i].Y) continue;
var machine = EntityManager.GetComponentData<Demo2MachineState>(machines[i]);
if (machine.Kind is Demo2MachineKind.Conveyor or Demo2MachineKind.Splitter or Demo2MachineKind.Miner or Demo2MachineKind.Generator or Demo2MachineKind.Turret) continue;
if (machine.StoredInput + materialStates[m].Quantity > machine.Capacity) continue;
machine.StoredInput += materialStates[m].Quantity;
EntityManager.SetComponentData(machines[i], machine);
EntityManager.DestroyEntity(materials[m]);
break;
}
}
stats.IronFuelAdjacent = HasAdjacentMaterial(materialPositions, materialStates, Demo2MaterialKind.IronOre, Demo2MaterialKind.Fuel) ? (byte)1 : (byte)0;
EntityManager.SetComponentData(singleton, stats);
}
private static bool HasAdjacentMaterial(NativeArray<Demo2GridPosition> positions, NativeArray<Demo2MaterialState> materials, Demo2MaterialKind a, Demo2MaterialKind b)
{
for (var i = 0; i < positions.Length; i++)
for (var j = i + 1; j < positions.Length; j++)
if (((materials[i].Kind == a && materials[j].Kind == b) || (materials[i].Kind == b && materials[j].Kind == a)) &&
Math.Abs(positions[i].X - positions[j].X) + Math.Abs(positions[i].Y - positions[j].Y) == 1) return true;
return false;
}
}
[DisableAutoCreation]
public sealed partial class Demo2ProcessingSystem : SystemBase
{
protected override void OnUpdate()
{
if (!Demo2SystemUtility.TryGetProductionState(EntityManager, out var singleton, out _)) return;
var stats = EntityManager.GetComponentData<Demo2CycleStats>(singleton);
stats.Faults = 0;
var query = GetEntityQuery(typeof(Demo2MachineState), typeof(Demo2RecipeState));
using var entities = query.ToEntityArray(Allocator.Temp);
for (var i = 0; i < entities.Length; i++)
{
var machine = EntityManager.GetComponentData<Demo2MachineState>(entities[i]);
if (machine.Kind is Demo2MachineKind.Miner or Demo2MachineKind.Generator or Demo2MachineKind.Conveyor or Demo2MachineKind.Splitter or Demo2MachineKind.Turret) continue;
var recipe = EntityManager.GetComponentData<Demo2RecipeState>(entities[i]);
var needed = Math.Max(1, recipe.InputCountA + recipe.InputCountB);
if (machine.StoredInput < needed) continue;
machine.ProgressTicks++;
if (machine.ProgressTicks >= Math.Max(1, machine.ProcessTicks))
{
machine.ProgressTicks = 0;
machine.StoredInput -= needed;
machine.PendingOutputs += Math.Max(1, recipe.OutputCount);
stats.Processed = SaturatingMath.Add(stats.Processed, 1);
stats.FirstBatch = stats.Processed == 1 ? (byte)1 : stats.FirstBatch;
if (stats.LastRecipeId == machine.RecipeId) stats.CompletedSameRecipeStreak++;
else { stats.LastRecipeId = machine.RecipeId; stats.CompletedSameRecipeStreak = 1; }
}
stats.Faults += machine.Faults;
EntityManager.SetComponentData(entities[i], machine);
}
EntityManager.SetComponentData(singleton, stats);
}
}
[DisableAutoCreation]
public sealed partial class Demo2OutputSystem : SystemBase
{
protected override void OnUpdate()
{
if (!Demo2SystemUtility.TryGetProductionState(EntityManager, out var singleton, out var simulation)) return;
var stats = EntityManager.GetComponentData<Demo2CycleStats>(singleton);
var query = GetEntityQuery(typeof(Demo2GridPosition), typeof(Demo2MachineState), typeof(Demo2RecipeState));
using var entities = query.ToEntityArray(Allocator.Temp);
using var positions = query.ToComponentDataArray<Demo2GridPosition>(Allocator.Temp);
for (var i = 0; i < entities.Length; i++)
{
var machine = EntityManager.GetComponentData<Demo2MachineState>(entities[i]);
if (machine.PendingOutputs <= 0) continue;
var recipe = EntityManager.GetComponentData<Demo2RecipeState>(entities[i]);
var quantity = machine.PendingOutputs;
if (stats.DuplicateNextOutputs > 0) { quantity *= 2; stats.DuplicateNextOutputs--; }
simulation.NextStableId++;
Demo2EcsFactory.CreateMaterial(EntityManager, simulation.NextStableId, recipe.Output, positions[i].X, positions[i].Y, machine.Rotation, quantity);
if (recipe.Output == Demo2MaterialKind.Ammo) stats.AmmoProduced = SaturatingMath.Add(stats.AmmoProduced, quantity);
machine.PendingOutputs = 0;
EntityManager.SetComponentData(entities[i], machine);
}
EntityManager.SetComponentData(singleton, simulation);
EntityManager.SetComponentData(singleton, stats);
}
}
[DisableAutoCreation]
public sealed partial class Demo2RuleTriggerSystem : SystemBase
{
protected override void OnUpdate()
{
var query = GetEntityQuery(typeof(Demo2SimulationState), typeof(Demo2EconomyState), typeof(Demo2CycleStats), typeof(Demo2RuleInstruction));
if (query.IsEmptyIgnoreFilter) return;
var singleton = query.GetSingletonEntity();
var simulation = EntityManager.GetComponentData<Demo2SimulationState>(singleton);
if (simulation.Phase != Demo2Phase.Defense || simulation.RuleAppliedCycle == simulation.Cycle) return;
var economy = EntityManager.GetComponentData<Demo2EconomyState>(singleton);
var stats = EntityManager.GetComponentData<Demo2CycleStats>(singleton);
var context = new Demo2RuleContext
{
Payload = economy.Payload,
MultiplierMilli = economy.MultiplierMilli,
Energy = economy.Energy,
Money = economy.Money,
ExcessFirepower = economy.ExcessFirepower,
Faults = stats.Faults,
ThreeSameRecipes = stats.CompletedSameRecipeStreak >= 3,
IronFuelAdjacent = stats.IronFuelAdjacent != 0,
BeltBelowEightyPercent = stats.BeltCapacity <= 0 || stats.BeltOccupancy * 100 < stats.BeltCapacity * 80,
FirstBatch = stats.FirstBatch != 0,
CoreAtRisk = EntityManager.GetComponentData<Demo2CoreHealth>(singleton).Value <= 1,
DuplicatedOutputs = stats.DuplicateNextOutputs
};
var instructions = EntityManager.GetBuffer<Demo2RuleInstruction>(singleton);
for (var i = 0; i < instructions.Length; i++)
{
var instruction = instructions[i];
var data = new Demo2RuleInstructionData { Opcode = instruction.Opcode, Condition = instruction.Condition, Operand = instruction.Operand };
if (Demo2RuleEngine.Matches(data.Condition, context)) Demo2RuleEngine.Apply(ref context, data);
}
economy.Payload = context.Payload;
economy.MultiplierMilli = context.MultiplierMilli;
economy.Energy = context.Energy;
economy.Money = context.Money;
stats.Faults = context.Faults;
stats.DuplicateNextOutputs = context.DuplicatedOutputs;
simulation.RuleAppliedCycle = simulation.Cycle;
EntityManager.SetComponentData(singleton, simulation);
EntityManager.SetComponentData(singleton, economy);
EntityManager.SetComponentData(singleton, stats);
}
}
[DisableAutoCreation]
public sealed partial class Demo2TurretLoadingSystem : SystemBase
{
protected override void OnUpdate()
{
if (!Demo2SystemUtility.TryGetProductionState(EntityManager, out _, out _)) return;
var materialQuery = GetEntityQuery(typeof(Demo2MaterialState));
var turretQuery = GetEntityQuery(typeof(Demo2TurretAmmo), typeof(Demo2StableId));
if (turretQuery.IsEmptyIgnoreFilter) return;
using var turretEntities = turretQuery.ToEntityArray(Allocator.Temp);
using var turretIds = turretQuery.ToComponentDataArray<Demo2StableId>(Allocator.Temp);
var turret = turretEntities[0];
var lowestId = turretIds[0].Value;
for (var i = 1; i < turretEntities.Length; i++)
if (turretIds[i].Value < lowestId)
{
turret = turretEntities[i];
lowestId = turretIds[i].Value;
}
var ammo = EntityManager.GetComponentData<Demo2TurretAmmo>(turret);
using var entities = materialQuery.ToEntityArray(Allocator.Temp);
using var materials = materialQuery.ToComponentDataArray<Demo2MaterialState>(Allocator.Temp);
for (var i = 0; i < entities.Length; i++)
{
if (materials[i].Kind != Demo2MaterialKind.Ammo || !EntityManager.Exists(entities[i])) continue;
ammo.Value = SaturatingMath.Add(ammo.Value, materials[i].Quantity);
EntityManager.DestroyEntity(entities[i]);
}
EntityManager.SetComponentData(turret, ammo);
}
}
[DisableAutoCreation]
public sealed partial class Demo2CycleStatisticsSystem : SystemBase
{
protected override void OnUpdate()
{
var query = GetEntityQuery(typeof(Demo2SimulationState), typeof(Demo2EconomyState), typeof(Demo2CycleStats));
if (query.IsEmptyIgnoreFilter) return;
var singleton = query.GetSingletonEntity();
var simulation = EntityManager.GetComponentData<Demo2SimulationState>(singleton);
if (simulation.Phase != Demo2Phase.Production) return;
simulation.Tick++;
var stats = EntityManager.GetComponentData<Demo2CycleStats>(singleton);
var economy = EntityManager.GetComponentData<Demo2EconomyState>(singleton);
economy.Payload = SaturatingMath.Add(economy.Payload, stats.AmmoProduced);
stats.AmmoProduced = 0;
EntityManager.SetComponentData(singleton, simulation);
EntityManager.SetComponentData(singleton, stats);
EntityManager.SetComponentData(singleton, economy);
}
}
[DisableAutoCreation]
public sealed partial class Demo2StateHashSystem : SystemBase
{
protected override void OnUpdate()
{
var singletonQuery = GetEntityQuery(typeof(Demo2SimulationState), typeof(Demo2EconomyState), typeof(Demo2CoreHealth));
if (singletonQuery.IsEmptyIgnoreFilter) return;
var singleton = singletonQuery.GetSingletonEntity();
var simulation = EntityManager.GetComponentData<Demo2SimulationState>(singleton);
var economy = EntityManager.GetComponentData<Demo2EconomyState>(singleton);
var core = EntityManager.GetComponentData<Demo2CoreHealth>(singleton);
var stats = EntityManager.GetComponentData<Demo2CycleStats>(singleton);
var hash = Demo2Hash.Offset;
Demo2Hash.Add(ref hash, simulation.Tick);
Demo2Hash.Add(ref hash, simulation.Seed);
Demo2Hash.Add(ref hash, (int)simulation.Phase);
Demo2Hash.Add(ref hash, simulation.Cycle);
Demo2Hash.Add(ref hash, simulation.RuleAppliedCycle);
Demo2Hash.Add(ref hash, simulation.SpeedMultiplier);
Demo2Hash.Add(ref hash, economy.Money);
Demo2Hash.Add(ref hash, economy.Payload);
Demo2Hash.Add(ref hash, economy.MultiplierMilli);
Demo2Hash.Add(ref hash, economy.Energy);
Demo2Hash.Add(ref hash, economy.ExcessFirepower);
Demo2Hash.Add(ref hash, core.Value);
Demo2Hash.Add(ref hash, stats.Extracted);
Demo2Hash.Add(ref hash, stats.Transported);
Demo2Hash.Add(ref hash, stats.Processed);
Demo2Hash.Add(ref hash, stats.AmmoProduced);
Demo2Hash.Add(ref hash, stats.CompletedSameRecipeStreak);
Demo2Hash.Add(ref hash, stats.LastRecipeId);
Demo2Hash.Add(ref hash, stats.Faults);
Demo2Hash.Add(ref hash, stats.BeltOccupancy);
Demo2Hash.Add(ref hash, stats.BeltCapacity);
Demo2Hash.Add(ref hash, stats.IronFuelAdjacent);
Demo2Hash.Add(ref hash, stats.FirstBatch);
Demo2Hash.Add(ref hash, stats.DuplicateNextOutputs);
var query = GetEntityQuery(typeof(Demo2StableId));
using var entities = query.ToEntityArray(Allocator.Temp);
using var ids = query.ToComponentDataArray<Demo2StableId>(Allocator.Temp);
var rows = new NativeArray<Demo2HashRow>(entities.Length, Allocator.Temp);
for (var i = 0; i < entities.Length; i++)
{
var row = new Demo2HashRow { StableId = ids[i].Value };
if (EntityManager.HasComponent<Demo2GridPosition>(entities[i]))
{
var position = EntityManager.GetComponentData<Demo2GridPosition>(entities[i]);
row.X = position.X;
row.Y = position.Y;
}
if (EntityManager.HasComponent<Demo2MachineState>(entities[i]))
{
var machine = EntityManager.GetComponentData<Demo2MachineState>(entities[i]);
row.Kind = (int)machine.Kind;
row.Rotation = machine.Rotation;
row.Enabled = machine.Enabled;
row.RecipeId = machine.RecipeId;
row.StoredInput = machine.StoredInput;
row.ProgressTicks = machine.ProgressTicks;
row.ProcessTicks = machine.ProcessTicks;
row.Capacity = machine.Capacity;
row.PendingOutputs = machine.PendingOutputs;
row.Faults = machine.Faults;
if (EntityManager.HasComponent<Demo2TurretAmmo>(entities[i]))
row.TurretAmmo = EntityManager.GetComponentData<Demo2TurretAmmo>(entities[i]).Value;
}
if (EntityManager.HasComponent<Demo2MaterialState>(entities[i]))
{
var material = EntityManager.GetComponentData<Demo2MaterialState>(entities[i]);
row.Kind = (int)material.Kind;
row.Quantity = material.Quantity;
row.SubCellProgress = material.SubCellProgress;
row.Rotation = material.Direction;
}
rows[i] = row;
}
rows.Sort();
for (var i = 0; i < rows.Length; i++)
{
var row = rows[i];
Demo2Hash.Add(ref hash, row.StableId);
Demo2Hash.Add(ref hash, row.X);
Demo2Hash.Add(ref hash, row.Y);
Demo2Hash.Add(ref hash, row.Kind);
Demo2Hash.Add(ref hash, row.Rotation);
Demo2Hash.Add(ref hash, row.Enabled);
Demo2Hash.Add(ref hash, row.RecipeId);
Demo2Hash.Add(ref hash, row.StoredInput);
Demo2Hash.Add(ref hash, row.ProgressTicks);
Demo2Hash.Add(ref hash, row.ProcessTicks);
Demo2Hash.Add(ref hash, row.Capacity);
Demo2Hash.Add(ref hash, row.PendingOutputs);
Demo2Hash.Add(ref hash, row.Faults);
Demo2Hash.Add(ref hash, row.Quantity);
Demo2Hash.Add(ref hash, row.SubCellProgress);
Demo2Hash.Add(ref hash, row.TurretAmmo);
}
rows.Dispose();
simulation.StateHash = hash;
EntityManager.SetComponentData(singleton, simulation);
}
private struct Demo2HashRow : IComparable<Demo2HashRow>
{
public int StableId;
public int X;
public int Y;
public int Kind;
public int Rotation;
public int Enabled;
public int RecipeId;
public int StoredInput;
public int ProgressTicks;
public int ProcessTicks;
public int Capacity;
public int PendingOutputs;
public int Faults;
public int Quantity;
public int SubCellProgress;
public long TurretAmmo;
public int CompareTo(Demo2HashRow other) => StableId.CompareTo(other.StableId);
}
}
internal static class Demo2SystemUtility
{
public static bool TryGetProductionState(EntityManager manager, out Entity singleton, out Demo2SimulationState simulation)
{
var query = manager.CreateEntityQuery(typeof(Demo2SimulationState));
if (query.IsEmptyIgnoreFilter) { singleton = Entity.Null; simulation = default; return false; }
singleton = query.GetSingletonEntity();
simulation = manager.GetComponentData<Demo2SimulationState>(singleton);
return simulation.Phase == Demo2Phase.Production;
}
public static void Move(ref Demo2GridPosition position, byte direction)
{
switch (direction & 3)
{
case 0: position.X++; break;
case 1: position.Y--; break;
case 2: position.X--; break;
case 3: position.Y++; break;
}
if (position.X < 0) position.X = 0;
if (position.X >= Demo2Protocol.GridWidth) position.X = Demo2Protocol.GridWidth - 1;
if (position.Y < 0) position.Y = 0;
if (position.Y >= Demo2Protocol.GridHeight) position.Y = Demo2Protocol.GridHeight - 1;
}
}
internal static class Demo2Hash
{
public const ulong Offset = 14695981039346656037UL;
private const ulong Prime = 1099511628211UL;
public static void Add(ref ulong hash, long value) { unchecked { hash ^= (ulong)value; hash *= Prime; } }
public static void Add(ref ulong hash, ulong value) { unchecked { hash ^= value; hash *= Prime; } }
public static void Add(ref ulong hash, int value) => Add(ref hash, (long)value);
}
}