f3f65bccbf
Server-only production chains (never predicted): components + server systems + pure byte-only math (ProductionMath/ConveyorMath/MachineSlotMath), authoring + 3 machine prefabs wired into the Gameplay subscene, StructureCatalog rows, BuildPlace Direction/RuntimePlacedTag, Tuning, and 35 EditMode tests (catch-up gating, conveyor shuffle-invariance, SaveData v2 round-trip). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
72 lines
3.3 KiB
C#
72 lines
3.3 KiB
C#
using NUnit.Framework;
|
|
using ProjectM.Simulation;
|
|
using UnityEngine;
|
|
|
|
namespace ProjectM.Tests
|
|
{
|
|
/// <summary>
|
|
/// Tests the SaveData v2 structure-persistence schema (M7): a player-built structure set + the flat machine-I/O
|
|
/// table round-trip through JsonUtility with fields intact; the REMAINING-ticks cooldown survives an epoch reset
|
|
/// (RemainingTicks/RestoreNextTick); and a save JSON lacking the v2 arrays deserializes without throwing (degrades
|
|
/// to no structures). The deeper instantiate-from-catalog restore is covered by the Play-mode validation pass.
|
|
/// </summary>
|
|
public class AutomationSaveRoundTripTests
|
|
{
|
|
[Test]
|
|
public void StructuresAndIo_RoundTrip_PreservesFields()
|
|
{
|
|
var data = new SaveData
|
|
{
|
|
GoalCharge = 3,
|
|
GoalTarget = 10,
|
|
Structures = new[]
|
|
{
|
|
new StructureSave { Type = StructureType.Harvester, CellX = 4, CellZ = -2, RemainingTicks = 12 },
|
|
new StructureSave { Type = StructureType.Conveyor, CellX = 5, CellZ = -2, Direction = 2, RemainingTicks = 3, ConveyorResId = ResourceId.Ore, ConveyorCount = 1 },
|
|
new StructureSave { Type = StructureType.Fabricator, CellX = 6, CellZ = -2, RemainingTicks = 40 },
|
|
},
|
|
StructureIo = new[]
|
|
{
|
|
new StructureIoRow { StructureIndex = 0, Slot = 1, ResourceId = ResourceId.Ore, Count = 7 },
|
|
new StructureIoRow { StructureIndex = 2, Slot = 0, ResourceId = ResourceId.Ore, Count = 5 },
|
|
},
|
|
};
|
|
|
|
var back = JsonUtility.FromJson<SaveData>(JsonUtility.ToJson(data));
|
|
|
|
Assert.AreEqual(SaveData.CurrentVersion, back.Version);
|
|
Assert.AreEqual(3, back.Structures.Length);
|
|
Assert.AreEqual(StructureType.Conveyor, back.Structures[1].Type);
|
|
Assert.AreEqual(2, back.Structures[1].Direction);
|
|
Assert.AreEqual(ResourceId.Ore, back.Structures[1].ConveyorResId);
|
|
Assert.AreEqual(1, back.Structures[1].ConveyorCount);
|
|
Assert.AreEqual(12u, back.Structures[0].RemainingTicks);
|
|
Assert.AreEqual(2, back.StructureIo.Length);
|
|
Assert.AreEqual(2, back.StructureIo[1].StructureIndex);
|
|
Assert.AreEqual(0, back.StructureIo[1].Slot);
|
|
Assert.AreEqual(5, back.StructureIo[1].Count);
|
|
}
|
|
|
|
[Test]
|
|
public void RemainingTicks_RestoreNextTick_PreservesCooldownGap_AcrossEpochs()
|
|
{
|
|
uint saveNow = 5000u, savedNext = 5037u;
|
|
uint remaining = ProductionMath.RemainingTicks(savedNext, saveNow);
|
|
Assert.AreEqual(37u, remaining);
|
|
|
|
uint restoreNow = 11u;
|
|
uint restoredNext = ProductionMath.RestoreNextTick(restoreNow, remaining);
|
|
Assert.AreEqual(48u, restoredNext);
|
|
}
|
|
|
|
[Test]
|
|
public void Save_Lacking_V2_Arrays_DeserializesWithoutThrowing()
|
|
{
|
|
SaveData back = null;
|
|
Assert.DoesNotThrow(() => back = JsonUtility.FromJson<SaveData>("{\"Version\":2,\"GoalCharge\":1,\"GoalTarget\":10}"));
|
|
Assert.IsNotNull(back);
|
|
Assert.IsTrue(back.Structures == null || back.Structures.Length == 0);
|
|
}
|
|
}
|
|
}
|