feat(sdk): migrate to EventBus 2.0

Replace the legacy EventBase runtime with generated multi-bus bindings and explicit scheduling. Migrate app, data, network, demo, and mod consumers; add generated network-event registration and owner-scoped mod content overrides.
This commit is contained in:
2026-08-26 01:15:48 +08:00
parent 67d32795c4
commit ad5a7b68a3
129 changed files with 5071 additions and 5584 deletions
@@ -18,6 +18,91 @@ namespace ShrinkModFramework.Tests
{
public sealed class ShrinkModContextHostTests
{
[Test]
public void RegistryNamespacedRegistration_BuildsOwnedKeyAndRejectsAmbiguousLocalKeys()
{
var registry = new ShrinkModRegistryManager().GetOrCreateMutableRegistry<string>("items");
var key = registry.RegisterNamespaced("example.mod", "iron_hammer", "Iron Hammer");
Assert.AreEqual("example.mod:iron_hammer", key);
Assert.IsTrue(registry.TryGet(key, out var value));
Assert.AreEqual("Iron Hammer", value);
Assert.Throws<ArgumentException>(() =>
registry.RegisterNamespaced("example.mod", "other:key", "invalid"));
Assert.Throws<ArgumentException>(() =>
registry.RegisterNamespaced("invalid:owner", "key", "invalid"));
}
[Test]
public void RegistryOverrides_HighestPriorityWinsAndOwnerRemovalRestoresPreviousValue()
{
var manager = new ShrinkModRegistryManager();
var registry = manager.GetOrCreateMutableRegistry<string>("items");
registry.RegisterNamespaced("core", "iron_hammer", "Core");
registry.RegisterOverride("mod.low", "core:iron_hammer", 10, "Low");
registry.RegisterOverride("mod.high", "core:iron_hammer", 20, "High");
Assert.IsTrue(registry.TryGetEntry("core:iron_hammer", out var high));
Assert.AreEqual("High", high.Value);
Assert.AreEqual("mod.high", high.OwnerModId);
Assert.IsTrue(high.IsOverride);
Assert.AreEqual(20, high.Priority);
Assert.AreEqual("mod.high", registry.Entries.Single().OwnerModId);
manager.RemoveOwnedEntries("mod.high");
Assert.IsTrue(registry.TryGetEntry("core:iron_hammer", out var low));
Assert.AreEqual("Low", low.Value);
Assert.AreEqual("mod.low", low.OwnerModId);
manager.RemoveOwnedEntries("mod.low");
Assert.IsTrue(registry.TryGetEntry("core:iron_hammer", out var original));
Assert.AreEqual("Core", original.Value);
Assert.AreEqual("core", original.OwnerModId);
Assert.IsFalse(original.IsOverride);
manager.RemoveOwnedEntries("core");
Assert.IsFalse(registry.Contains("core:iron_hammer"));
Assert.IsFalse(registry.TryGet("core:iron_hammer", out _));
}
[Test]
public void RegistryOverrides_RejectMissingTargetsAndSamePriorityConflicts()
{
var registry = new ShrinkModRegistryManager().GetOrCreateMutableRegistry<string>("items");
Assert.Throws<InvalidOperationException>(() =>
registry.RegisterOverride("mod.one", "core:missing", 10, "missing"));
registry.RegisterNamespaced("core", "iron_hammer", "Core");
registry.RegisterOverride("mod.one", "core:iron_hammer", 10, "One");
Assert.Throws<InvalidOperationException>(() =>
registry.RegisterOverride("mod.two", "core:iron_hammer", 10, "Two"));
Assert.That(registry.GetOverrideCandidates("core:iron_hammer").Select(entry => entry.OwnerModId),
Is.EqualTo(new[] { "mod.one" }));
}
[Test]
public void ModContext_ExposesReadOnlyRegistryAndOwnedWriteCommands()
{
var getRegistry = typeof(ShrinkModContext).GetMethod(nameof(ShrinkModContext.GetRegistry));
Assert.IsNotNull(getRegistry);
Assert.IsTrue(getRegistry!.ReturnType.IsGenericType);
Assert.AreEqual(typeof(IReadOnlyShrinkModRegistry<>),
getRegistry.ReturnType.GetGenericTypeDefinition());
var readMethods = typeof(IReadOnlyShrinkModRegistry<string>)
.GetMethods()
.Select(method => method.Name)
.ToArray();
Assert.That(readMethods, Does.Not.Contain("Register"));
Assert.That(readMethods, Does.Not.Contain("RegisterNamespaced"));
Assert.That(readMethods, Does.Not.Contain("RegisterOverride"));
Assert.IsNotNull(typeof(ShrinkModContext).GetMethod(nameof(ShrinkModContext.RegisterContent)));
Assert.IsNotNull(typeof(ShrinkModContext).GetMethod(nameof(ShrinkModContext.OverrideContent)));
}
[Test]
public void FailedReplacement_RestoresPreviousModEffectsAndRegistryContent()
{
@@ -34,8 +119,7 @@ namespace ShrinkModFramework.Tests
() => activeEffects.Remove("old"));
},
onRegisterContent: context =>
context.GetRegistry<string>("items")
.Register(context.ModInfo.ModId, "test:item", "old")));
context.RegisterContent("items", "item", "old")));
var failingSource = Source("test.transaction", "2.0.0", "broken", () =>
new DelegateMod(
@@ -43,8 +127,7 @@ namespace ShrinkModFramework.Tests
() => activeEffects.Add("new-partial"),
() => activeEffects.Remove("new-partial")),
onRegisterContent: context =>
context.GetRegistry<string>("items")
.Register(context.ModInfo.ModId, "test:item", "new"),
context.RegisterContent("items", "item", "new"),
onInitialize: _ => throw new InvalidOperationException("new mod failed")));
try
@@ -73,7 +156,7 @@ namespace ShrinkModFramework.Tests
Assert.IsEmpty(activeEffects);
Assert.IsEmpty(host.Mods);
Assert.IsFalse(host.GetOrCreateRegistry<string>("items").Contains("test:item"));
Assert.IsFalse(host.GetOrCreateRegistry<string>("items").Contains("test.transaction:item"));
}
[Test]
@@ -365,7 +448,7 @@ namespace ShrinkModFramework.Tests
private static void AssertRegistryValue(ShrinkModContextHost host, string expected)
{
var registry = host.GetOrCreateRegistry<string>("items");
Assert.IsTrue(registry.TryGet("test:item", out var value));
Assert.IsTrue(registry.TryGet("test.transaction:item", out var value));
Assert.AreEqual(expected, value);
}
@@ -420,10 +503,18 @@ namespace ShrinkModFramework.Tests
{
var package = UnityEditor.PackageManager.PackageInfo.FindForAssembly(
typeof(ShrinkModContextHostTests).Assembly);
if (package == null || string.IsNullOrWhiteSpace(package.resolvedPath))
throw new InvalidOperationException("Could not resolve the ShrinkModFramework package path.");
var testsRoot = package != null && !string.IsNullOrWhiteSpace(package.resolvedPath)
? Path.Combine(package.resolvedPath, "Tests")
: UnityEditor.AssetDatabase.FindAssets("ShrinkModFramework.Tests t:asmdef")
.Select(UnityEditor.AssetDatabase.GUIDToAssetPath)
.Where(path => string.Equals(Path.GetFileName(path),
"ShrinkModFramework.Tests.asmdef", StringComparison.Ordinal))
.Select(Path.GetDirectoryName)
.FirstOrDefault(path => !string.IsNullOrWhiteSpace(path));
if (string.IsNullOrWhiteSpace(testsRoot))
throw new InvalidOperationException("Could not resolve the ShrinkModFramework tests path.");
var fixturePath = Path.Combine(package.resolvedPath, "Tests", "Fixtures", fixtureName);
var fixturePath = Path.Combine(testsRoot, "Fixtures", fixtureName);
File.Copy(fixturePath, targetPath, true);
}