Move character options and movement skills into the Runtime-owned character graph, expose borrowed inventory, character, and social views, and route retained UI state commands through generation-gated typed Runtime contracts. Preserve the existing synchronous wire path while deleting the App-owned option and skill mirrors and extending normalized parity checkpoints. Co-authored-by: Codex <codex@openai.com>
157 lines
6 KiB
C#
157 lines
6 KiB
C#
using AcDream.Core.Items;
|
|
using AcDream.Runtime.Entities;
|
|
using AcDream.Runtime.Gameplay;
|
|
|
|
namespace AcDream.Runtime.Tests.Gameplay;
|
|
|
|
public sealed class RuntimeInventoryStateTests
|
|
{
|
|
[Fact]
|
|
public void ViewBorrowsTransactionShortcutAndManaOwners()
|
|
{
|
|
using var entities = new RuntimeEntityObjectLifetime();
|
|
using var inventory = new RuntimeInventoryState(entities);
|
|
inventory.Shortcuts.Replace(
|
|
[
|
|
new AcDream.Core.Items.ShortcutEntry(3, 0x80000001u, 0u),
|
|
new AcDream.Core.Items.ShortcutEntry(4, 0u, 42u),
|
|
]);
|
|
inventory.ItemMana.OnQueryItemManaResponse(
|
|
0x80000001u,
|
|
0.75f,
|
|
valid: true);
|
|
inventory.Transactions.IncrementBusyCount();
|
|
|
|
RuntimeInventoryStateSnapshot snapshot = inventory.View.Snapshot;
|
|
|
|
Assert.Equal(2, snapshot.ShortcutCount);
|
|
Assert.Equal(1, snapshot.ItemManaCount);
|
|
Assert.Equal(1, snapshot.BusyCount);
|
|
Assert.False(snapshot.CanBeginRequest);
|
|
Assert.True(inventory.View.TryGetShortcut(
|
|
3,
|
|
out RuntimeShortcutSnapshot itemShortcut));
|
|
Assert.Equal(
|
|
new RuntimeShortcutSnapshot(3, 0x80000001u, 0u),
|
|
itemShortcut);
|
|
Assert.True(inventory.View.TryGetShortcut(
|
|
4,
|
|
out RuntimeShortcutSnapshot spellShortcut));
|
|
Assert.Equal(new RuntimeShortcutSnapshot(4, 0u, 42u), spellShortcut);
|
|
Assert.True(inventory.View.TryGetItemMana(
|
|
itemShortcut.ObjectId,
|
|
out float fraction));
|
|
Assert.Equal(0.75f, fraction);
|
|
}
|
|
|
|
[Fact]
|
|
public void OwnsOneGameplayGraphOverExactEntityObjectTable()
|
|
{
|
|
using var entities = new RuntimeEntityObjectLifetime();
|
|
using var inventory = new RuntimeInventoryState(entities);
|
|
IReadOnlyList<ShortcutEntry> shortcuts =
|
|
[new ShortcutEntry(2, 0x50000001u, 0u)];
|
|
|
|
inventory.ExternalContainers.RequestOpen(0x70000001u);
|
|
inventory.ExternalContainers.ApplyViewContents(0x70000001u);
|
|
inventory.ItemMana.OnQueryItemManaResponse(0x50000001u, 0.75f, true);
|
|
inventory.Shortcuts.Replace(shortcuts);
|
|
|
|
Assert.Same(entities.Objects, inventory.Objects);
|
|
Assert.Equal(0x70000001u, inventory.ExternalContainers.CurrentContainerId);
|
|
Assert.Equal(0.75f, inventory.ItemMana.GetManaPercent(0x50000001u));
|
|
Assert.Same(shortcuts, inventory.Shortcuts.Items);
|
|
Assert.Equal(1, inventory.Shortcuts.Revision);
|
|
}
|
|
|
|
[Fact]
|
|
public void ResetOperationsClearOnlyTheirOwnedLifetimeGroup()
|
|
{
|
|
using var entities = new RuntimeEntityObjectLifetime();
|
|
using var inventory = new RuntimeInventoryState(entities);
|
|
inventory.ExternalContainers.RequestOpen(0x70000001u);
|
|
inventory.ExternalContainers.ApplyViewContents(0x70000001u);
|
|
inventory.ItemMana.OnQueryItemManaResponse(0x50000001u, 0.75f, true);
|
|
inventory.Shortcuts.Replace([new ShortcutEntry(1, 2u, 3u)]);
|
|
inventory.Transactions.IncrementBusyCount();
|
|
|
|
inventory.ResetExternalContainer();
|
|
Assert.Equal(0u, inventory.ExternalContainers.CurrentContainerId);
|
|
Assert.True(inventory.ItemMana.HasMana(0x50000001u));
|
|
Assert.NotEmpty(inventory.Shortcuts.Items);
|
|
Assert.Equal(1, inventory.Transactions.BusyCount);
|
|
|
|
inventory.ResetTransactions();
|
|
inventory.ResetItemMana();
|
|
inventory.ResetPlayerSnapshots();
|
|
|
|
Assert.Equal(0, inventory.Transactions.BusyCount);
|
|
Assert.False(inventory.ItemMana.HasMana(0x50000001u));
|
|
Assert.Empty(inventory.Shortcuts.Items);
|
|
}
|
|
|
|
[Fact]
|
|
public void IndependentRuntimeInstancesNeverShareState()
|
|
{
|
|
using var firstEntities = new RuntimeEntityObjectLifetime();
|
|
using var secondEntities = new RuntimeEntityObjectLifetime();
|
|
using var first = new RuntimeInventoryState(firstEntities);
|
|
using var second = new RuntimeInventoryState(secondEntities);
|
|
|
|
first.Shortcuts.Replace([new ShortcutEntry(1, 2u, 3u)]);
|
|
first.Transactions.IncrementBusyCount();
|
|
|
|
Assert.NotSame(first.Objects, second.Objects);
|
|
Assert.Single(first.Shortcuts.Items);
|
|
Assert.Empty(second.Shortcuts.Items);
|
|
Assert.Equal(1, first.Transactions.BusyCount);
|
|
Assert.Equal(0, second.Transactions.BusyCount);
|
|
}
|
|
|
|
[Fact]
|
|
public void DisposeDetachesTransactionsAndClearsOwnedState()
|
|
{
|
|
using var entities = new RuntimeEntityObjectLifetime();
|
|
var inventory = new RuntimeInventoryState(entities);
|
|
inventory.ExternalContainers.RequestOpen(0x70000001u);
|
|
inventory.ExternalContainers.ApplyViewContents(0x70000001u);
|
|
inventory.ItemMana.OnQueryItemManaResponse(0x50000001u, 0.5f, true);
|
|
inventory.Shortcuts.Replace([new ShortcutEntry(1, 2u, 3u)]);
|
|
|
|
inventory.Dispose();
|
|
inventory.Dispose();
|
|
|
|
Assert.True(inventory.IsDisposed);
|
|
Assert.True(inventory.Transactions.IsDisposed);
|
|
Assert.Equal(0u, inventory.ExternalContainers.CurrentContainerId);
|
|
Assert.False(inventory.ItemMana.HasMana(0x50000001u));
|
|
Assert.Empty(inventory.Shortcuts.Items);
|
|
}
|
|
|
|
[Fact]
|
|
public void DisposalRetriesATransientOwnerObserverFailureToConvergence()
|
|
{
|
|
using var entities = new RuntimeEntityObjectLifetime();
|
|
var inventory = new RuntimeInventoryState(entities);
|
|
inventory.ExternalContainers.RequestOpen(0x70000001u);
|
|
inventory.ExternalContainers.ApplyViewContents(0x70000001u);
|
|
bool fail = true;
|
|
inventory.ExternalContainers.Changed += _ =>
|
|
{
|
|
if (fail)
|
|
{
|
|
fail = false;
|
|
throw new InvalidOperationException("transient");
|
|
}
|
|
};
|
|
|
|
Assert.Throws<AggregateException>(inventory.Dispose);
|
|
Assert.False(inventory.IsDisposed);
|
|
Assert.True(inventory.Transactions.IsDisposed);
|
|
|
|
inventory.Dispose();
|
|
|
|
Assert.True(inventory.IsDisposed);
|
|
Assert.Equal(0u, inventory.ExternalContainers.CurrentContainerId);
|
|
}
|
|
}
|