feat(items): port retail external-container looting
Add the ClientUISystem ground-object lifecycle, authoritative root and nested ViewContents projections, replacement and close semantics, and the DAT-authored gmExternalContainerUI strip for chests and corpses. Route double-click loot and full or partial drag transfers through the shared retail item policy without optimistic external ownership. Remove the incorrect NoLongerViewingContents behavior from owned side packs and retire AP-106/#196. Release build succeeds and all 5,875 tests pass with five intentional skips. Co-authored-by: OpenAI Codex <codex@openai.com>
This commit is contained in:
parent
48a118db91
commit
20ce67b625
27 changed files with 1750 additions and 45 deletions
|
|
@ -0,0 +1,70 @@
|
|||
using AcDream.Core.Items;
|
||||
|
||||
namespace AcDream.Core.Tests.Items;
|
||||
|
||||
public sealed class ExternalContainerStateTests
|
||||
{
|
||||
[Fact]
|
||||
public void ViewContents_onlyCommitsTheExpectedRoot()
|
||||
{
|
||||
var state = new ExternalContainerState();
|
||||
state.RequestOpen(0x70000001u);
|
||||
|
||||
Assert.False(state.ApplyViewContents(0x70000002u));
|
||||
Assert.Equal(0u, state.CurrentContainerId);
|
||||
Assert.True(state.ApplyViewContents(0x70000001u));
|
||||
Assert.Equal(0x70000001u, state.CurrentContainerId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReplacementPublishesOldAndNewExactlyOnce()
|
||||
{
|
||||
var state = new ExternalContainerState();
|
||||
var changes = new List<ExternalContainerTransition>();
|
||||
state.Changed += changes.Add;
|
||||
state.RequestOpen(1u);
|
||||
state.ApplyViewContents(1u);
|
||||
state.RequestOpen(2u);
|
||||
state.ApplyViewContents(2u);
|
||||
state.ApplyViewContents(2u);
|
||||
|
||||
Assert.Equal(2, changes.Count);
|
||||
Assert.Equal(ExternalContainerTransitionKind.Opened, changes[0].Kind);
|
||||
Assert.Equal(
|
||||
new ExternalContainerTransition(
|
||||
ExternalContainerTransitionKind.Replaced, 1u, 2u),
|
||||
changes[1]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CloseIgnoresStaleContainerAndClosesCurrent()
|
||||
{
|
||||
var state = Open(2u);
|
||||
|
||||
Assert.False(state.ApplyClose(1u));
|
||||
Assert.Equal(2u, state.CurrentContainerId);
|
||||
Assert.True(state.ApplyClose(2u));
|
||||
Assert.Equal(0u, state.CurrentContainerId);
|
||||
Assert.Equal(0u, state.RequestedContainerId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RefusedReplacementRestoresCurrentAsExpectedRoot()
|
||||
{
|
||||
var state = Open(1u);
|
||||
state.RequestOpen(2u);
|
||||
|
||||
Assert.True(state.ApplyUseDone(0x550u));
|
||||
Assert.Equal(1u, state.CurrentContainerId);
|
||||
Assert.Equal(1u, state.RequestedContainerId);
|
||||
Assert.False(state.ApplyViewContents(2u));
|
||||
}
|
||||
|
||||
private static ExternalContainerState Open(uint id)
|
||||
{
|
||||
var state = new ExternalContainerState();
|
||||
state.RequestOpen(id);
|
||||
state.ApplyViewContents(id);
|
||||
return state;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue