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

@ -104,10 +104,19 @@ public class KeyBindingsJsonTests
var path = TempFile();
try
{
// User customizes ONE action — replace MovementForward with Q.
var custom = new KeyBindings();
custom.Add(new(new KeyChord(Key.Q, ModifierMask.None), InputAction.MovementForward));
custom.SaveToFile(path);
// A pre-v7 partial file customizes ONE action. Missing actions in
// those schemas mean "not stored yet", so they default-merge.
const string legacyJson = """
{
"version": 6,
"actions": {
"MovementForward": [
{ "key": "Q" }
]
}
}
""";
File.WriteAllText(path, legacyJson);
var loaded = KeyBindings.LoadOrDefault(path);
@ -128,6 +137,32 @@ public class KeyBindingsJsonTests
}
}
[Fact]
public void Roundtrip_preserves_explicitly_unbound_retail_action()
{
var path = TempFile();
try
{
KeyBindings defaults = KeyBindings.RetailDefaults();
var customized = new KeyBindings();
foreach (Binding binding in defaults.All)
{
if (binding.Action != InputAction.ToggleHelp)
customized.Add(binding);
}
customized.SaveToFile(path);
KeyBindings loaded = KeyBindings.LoadOrDefault(path);
Assert.Empty(loaded.ForAction(InputAction.ToggleHelp));
Assert.NotEmpty(loaded.ForAction(InputAction.ToggleOptionsPanel));
}
finally
{
if (File.Exists(path)) File.Delete(path);
}
}
[Fact]
public void LoadOrDefault_handles_version_zero_legacy_file()
{
@ -193,17 +228,16 @@ public class KeyBindingsJsonTests
}
[Fact]
public void LoadOrDefault_migratesV1CtrlNumberQuickSlotFromUseToSelect()
public void LoadOrDefault_migratesV5CtrlNumberQuickSlotFromSelectBackToRetailUse()
{
var path = TempFile();
try
{
const string json = """
{
"version": 1,
"version": 5,
"actions": {
"UseQuickSlot_5": [
{ "key": "Number5" },
"SelectQuickSlot_5": [
{ "key": "Number5", "mod": "Ctrl" }
]
}
@ -214,9 +248,8 @@ public class KeyBindingsJsonTests
var loaded = KeyBindings.LoadOrDefault(path);
Assert.Equal(InputAction.UseQuickSlot_5,
loaded.Find(new KeyChord(Key.Number5, ModifierMask.None), ActivationType.Press)?.Action);
Assert.Equal(InputAction.SelectQuickSlot_5,
loaded.Find(new KeyChord(Key.Number5, ModifierMask.Ctrl), ActivationType.Press)?.Action);
Assert.Empty(loaded.ForAction(InputAction.SelectQuickSlot_5));
}
finally
{