539 lines
28 KiB
C#
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);
|
|
}
|
|
}
|