fix(client): restore retail interaction parity
All checks were successful
CI / linux-portable (push) Successful in 3m27s
CI / windows-gate (push) Successful in 6m42s
CI / release (push) Successful in 2m12s

Harden keyboard and camera routing, inventory and vendor interactions, chat/emotes, relog portal flow, and paperdoll rendering. Add retail research, connected gate coverage, and release-gate validation.
This commit is contained in:
Erik 2026-08-26 20:45:11 +02:00
parent 0c699240e0
commit f6fe0f2a4f
151 changed files with 10162 additions and 1211 deletions

View file

@ -55,6 +55,42 @@ public sealed class RetailDialogFactoryTests
Assert.False(factory.IsOpen);
}
[Fact]
public void ConfirmationMenu_ReturnsSelectedIndex_AndRejectReturnsMinusOne()
{
var root = new UiRoot { Width = 800f, Height = 600f };
var layouts = new List<ImportedLayout>();
var factory = new RetailDialogFactory(root, type =>
{
ImportedLayout layout = BuildDialogLayout(type);
layouts.Add(layout);
return layout;
});
int? result = null;
factory.MakeConfirmationMenu(
new[] { "acdream.keymap", "friends.keymap" },
selectedIndex: 1,
data => result = data.GetInt32(RetailDialogProperty.MenuSelection));
ImportedLayout first = Assert.Single(layouts);
UiMenu menu = Assert.IsType<UiMenu>(
first.FindElement(RetailConfirmationMenuDialogView.MenuElementId));
Assert.Equal(1, menu.Selected);
menu.Selected = 0;
Button(first, RetailConfirmationMenuDialogView.AcceptButtonId).OnClick!();
Assert.Equal(0, result);
result = null;
factory.MakeConfirmationMenu(
new[] { "acdream.keymap" },
selectedIndex: 0,
data => result = data.GetInt32(RetailDialogProperty.MenuSelection));
ImportedLayout second = layouts[^1];
Button(second, RetailConfirmationMenuDialogView.RejectButtonId).OnClick!();
Assert.Equal(-1, result);
}
[Fact]
public void SameQueuePresentsFifoUsingFreshLiveRoots()
{
@ -691,6 +727,7 @@ public sealed class RetailDialogFactoryTests
{
RetailDialogType.Message => 0x17u,
RetailDialogType.ConfirmationTextInput => 0x15u,
RetailDialogType.ConfirmationMenu => 0x14u,
RetailDialogType.Wait => 0x19u,
_ => 0x13u,
};
@ -708,15 +745,18 @@ public sealed class RetailDialogFactoryTests
Width = 400f,
Height = type == RetailDialogType.ConfirmationTextInput ? 125f : 95f,
};
popup.Children.Add(new ElementInfo
if (type != RetailDialogType.ConfirmationMenu)
{
Id = 0x3Eu,
Type = 12u,
X = 15f,
Y = 15f,
Width = 370f,
Height = 18f,
});
popup.Children.Add(new ElementInfo
{
Id = 0x3Eu,
Type = 12u,
X = 15f,
Y = 15f,
Width = 370f,
Height = 18f,
});
}
if (type == RetailDialogType.Message)
{
popup.Children.Add(new ElementInfo
@ -793,6 +833,36 @@ public sealed class RetailDialogFactoryTests
Height = 32f,
});
}
else if (type == RetailDialogType.ConfirmationMenu)
{
popup.Children.Add(new ElementInfo
{
Id = RetailConfirmationMenuDialogView.MenuElementId,
Type = 6u,
X = 80f,
Y = 15f,
Width = 240f,
Height = 24f,
});
popup.Children.Add(new ElementInfo
{
Id = RetailConfirmationMenuDialogView.AcceptButtonId,
Type = 1u,
X = 80f,
Y = 48f,
Width = 80f,
Height = 32f,
});
popup.Children.Add(new ElementInfo
{
Id = RetailConfirmationMenuDialogView.RejectButtonId,
Type = 1u,
X = 240f,
Y = 48f,
Width = 80f,
Height = 32f,
});
}
root.Children.Add(popup);
return LayoutImporter.Build(root, _ => (0u, 0, 0), null);
}