Frontend menu + settings + saves foundation
Netcode frontend pattern: UITK main menu / pause / settings (MenuUi + controllers), on-demand world lifecycle (WorldLauncher/SessionRunner), GameBootstrap menu branch; Graphics/Audio settings (SettingsService/GameVolume); single-slot save foundation (SaveData/SaveService, born-correct load at director spawn, autosave on Siege->Calm + quit); RuntimePanelSettings + theme; BuildTool menu; 10 EditMode tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
using NUnit.Framework;
|
||||
using ProjectM.Simulation;
|
||||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ProjectM.Tests
|
||||
{
|
||||
/// <summary>
|
||||
/// Pure tests for the save FOUNDATION: the JSON schema round-trips (JsonUtility), version handling is safe,
|
||||
/// and the born-correct ledger apply (<see cref="SaveApply.WriteLedger"/>) the server spawn system uses to
|
||||
/// overwrite a director's StorageEntry buffer from a staged PendingSave.
|
||||
/// </summary>
|
||||
public class SavePersistenceTests
|
||||
{
|
||||
[Test]
|
||||
public void SaveData_Json_RoundTrip_PreservesFields()
|
||||
{
|
||||
var data = new SaveData
|
||||
{
|
||||
GoalCharge = 42,
|
||||
GoalTarget = 10,
|
||||
Ledger = new[]
|
||||
{
|
||||
new LedgerRow { ItemId = 1, Count = 5 },
|
||||
new LedgerRow { ItemId = 2, Count = 9 },
|
||||
},
|
||||
SavedAtMs = 1234567890123L,
|
||||
};
|
||||
|
||||
var json = JsonUtility.ToJson(data);
|
||||
var back = JsonUtility.FromJson<SaveData>(json);
|
||||
|
||||
Assert.AreEqual(SaveData.CurrentVersion, back.Version);
|
||||
Assert.AreEqual(42, back.GoalCharge);
|
||||
Assert.AreEqual(10, back.GoalTarget);
|
||||
Assert.AreEqual(2, back.Ledger.Length);
|
||||
Assert.AreEqual(1, back.Ledger[0].ItemId);
|
||||
Assert.AreEqual(5, back.Ledger[0].Count);
|
||||
Assert.AreEqual(2, back.Ledger[1].ItemId);
|
||||
Assert.AreEqual(9, back.Ledger[1].Count);
|
||||
Assert.AreEqual(1234567890123L, back.SavedAtMs);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SaveData_EmptyJson_DoesNotThrow_And_EmptyLedgerRoundTrips()
|
||||
{
|
||||
Assert.DoesNotThrow(() => JsonUtility.FromJson<SaveData>("{}"));
|
||||
|
||||
var empty = new SaveData { GoalCharge = 0, GoalTarget = 10 };
|
||||
var back = JsonUtility.FromJson<SaveData>(JsonUtility.ToJson(empty));
|
||||
Assert.IsNotNull(back.Ledger);
|
||||
Assert.AreEqual(0, back.Ledger.Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SaveData_OldVersion_IsDetectable()
|
||||
{
|
||||
// A stale-version blob round-trips with its Version intact, so SaveService.Load rejects it (-> New Game).
|
||||
var old = new SaveData { Version = 0, GoalCharge = 7 };
|
||||
var back = JsonUtility.FromJson<SaveData>(JsonUtility.ToJson(old));
|
||||
Assert.AreEqual(0, back.Version);
|
||||
Assert.AreNotEqual(SaveData.CurrentVersion, back.Version);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WriteLedger_Overwrites_Destination_From_Staged_Rows()
|
||||
{
|
||||
using var world = new World("SaveApplyTest");
|
||||
var em = world.EntityManager;
|
||||
var e = em.CreateEntity();
|
||||
em.AddBuffer<PendingSaveLedgerRow>(e);
|
||||
em.AddBuffer<StorageEntry>(e);
|
||||
|
||||
var src = em.GetBuffer<PendingSaveLedgerRow>(e);
|
||||
src.Add(new PendingSaveLedgerRow { ItemId = 3, Count = 7 });
|
||||
src.Add(new PendingSaveLedgerRow { ItemId = 5, Count = 12 });
|
||||
|
||||
var dest = em.GetBuffer<StorageEntry>(e);
|
||||
dest.Add(new StorageEntry { ItemId = 99, Count = 1 }); // pre-existing junk that must be cleared
|
||||
|
||||
SaveApply.WriteLedger(em.GetBuffer<PendingSaveLedgerRow>(e), em.GetBuffer<StorageEntry>(e));
|
||||
|
||||
var result = em.GetBuffer<StorageEntry>(e);
|
||||
Assert.AreEqual(2, result.Length);
|
||||
Assert.AreEqual(3, result[0].ItemId);
|
||||
Assert.AreEqual(7, result[0].Count);
|
||||
Assert.AreEqual(5, result[1].ItemId);
|
||||
Assert.AreEqual(12, result[1].Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WriteLedger_EmptySource_ClearsDestination()
|
||||
{
|
||||
using var world = new World("SaveApplyEmptyTest");
|
||||
var em = world.EntityManager;
|
||||
var e = em.CreateEntity();
|
||||
em.AddBuffer<PendingSaveLedgerRow>(e);
|
||||
em.AddBuffer<StorageEntry>(e);
|
||||
var dest = em.GetBuffer<StorageEntry>(e);
|
||||
dest.Add(new StorageEntry { ItemId = 1, Count = 1 });
|
||||
|
||||
SaveApply.WriteLedger(em.GetBuffer<PendingSaveLedgerRow>(e), em.GetBuffer<StorageEntry>(e));
|
||||
|
||||
Assert.AreEqual(0, em.GetBuffer<StorageEntry>(e).Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user