fix(client): restore retail interaction parity
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:
parent
0c699240e0
commit
f6fe0f2a4f
151 changed files with 10162 additions and 1211 deletions
113
tests/AcDream.App.Tests/Input/RetailKeymapFileTests.cs
Normal file
113
tests/AcDream.App.Tests/Input/RetailKeymapFileTests.cs
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
using AcDream.App.Input;
|
||||
using AcDream.UI.Abstractions.Input;
|
||||
using Silk.NET.Input;
|
||||
|
||||
namespace AcDream.App.Tests.Input;
|
||||
|
||||
public sealed class RetailKeymapFileTests
|
||||
{
|
||||
[Fact]
|
||||
public void Parse_CommittedRetailFile_ReproducesEveryUserBindableDefault()
|
||||
{
|
||||
string text = File.ReadAllText(Path.Combine(
|
||||
FindRepoRoot(), "docs", "research", "named-retail",
|
||||
"retail-default.keymap.txt"));
|
||||
KeyBindings expected = KeyBindings.RetailDefaults();
|
||||
KeyBindings actual = RetailKeymapFile.Parse(text, expected);
|
||||
|
||||
Assert.Equal(
|
||||
expected.ForAction(InputAction.MovementForward).ToArray(),
|
||||
actual.ForAction(InputAction.MovementForward).ToArray());
|
||||
Assert.Equal(
|
||||
expected.ForAction(InputAction.MovementWalkMode).ToArray(),
|
||||
actual.ForAction(InputAction.MovementWalkMode).ToArray());
|
||||
Assert.Equal(
|
||||
expected.ForAction(InputAction.ToggleInventoryPanel).ToArray(),
|
||||
actual.ForAction(InputAction.ToggleInventoryPanel).ToArray());
|
||||
Assert.Equal(
|
||||
expected.ForAction(InputAction.CameraAlternateRotateLeft).ToArray(),
|
||||
actual.ForAction(InputAction.CameraAlternateRotateLeft).ToArray());
|
||||
// The user's captured retail file omits slots 10-13; omission means
|
||||
// unbound rather than "inherit a compiled default".
|
||||
Assert.Empty(actual.ForAction(InputAction.UseQuickSlot_10));
|
||||
|
||||
// Host-only actions are outside retail's fourteen editable maps and survive.
|
||||
Assert.Equal(
|
||||
expected.ForAction(InputAction.AcdreamToggleAudioMute).ToArray(),
|
||||
actual.ForAction(InputAction.AcdreamToggleAudioMute).ToArray());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteThenParse_RoundTripsAll306RetailActionIdentities()
|
||||
{
|
||||
var source = new KeyBindings();
|
||||
foreach (((uint inputMapId, uint actionId), InputAction action) in
|
||||
RetailActionIdentityTable.Map)
|
||||
{
|
||||
source.Add(new Binding(
|
||||
new KeyChord(
|
||||
Key.SuperRight,
|
||||
ModifierMask.Shift | ModifierMask.Ctrl | ModifierMask.Win),
|
||||
action,
|
||||
RetailActionIdentityTable.ActivationFor(inputMapId, actionId),
|
||||
RetailActionIdentityTable.ScopeForInputMap(inputMapId)));
|
||||
}
|
||||
|
||||
string text = RetailKeymapFile.Write(source);
|
||||
KeyBindings loaded = RetailKeymapFile.Parse(text, new KeyBindings());
|
||||
|
||||
Assert.Equal(306, loaded.All.Count);
|
||||
foreach (Binding expected in source.All)
|
||||
Assert.Contains(expected, loaded.All);
|
||||
Assert.Contains("CharacterOptionCommands", text, StringComparison.Ordinal);
|
||||
Assert.Contains("AutoRepeatAttacks", text, StringComparison.Ordinal);
|
||||
Assert.Contains("AFKState", text, StringComparison.Ordinal);
|
||||
Assert.Contains("DIK_RWIN", text, StringComparison.Ordinal);
|
||||
Assert.Contains("EscapeKey [ \"\" [ 0 DIK_ESCAPE ] ]", text, StringComparison.Ordinal);
|
||||
Assert.Contains("TargetedUsage", text, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ProfileStore_SaveAsSelectsProfile_AndLoadReplacesRetailRows()
|
||||
{
|
||||
string root = Path.Combine(Path.GetTempPath(), "acdream-keymap-" + Guid.NewGuid().ToString("N"));
|
||||
string config = Path.Combine(root, "config");
|
||||
string documents = Path.Combine(root, "documents", "Asheron's Call");
|
||||
string json = Path.Combine(config, "keybinds.json");
|
||||
try
|
||||
{
|
||||
var source = KeyBindings.RetailDefaults();
|
||||
var store = new RetailKeymapProfileStore(json, documents);
|
||||
RetailKeymapSaveResult saved = store.Save("friends", source, overwrite: false);
|
||||
|
||||
Assert.Equal(RetailKeymapSaveStatus.Saved, saved.Status);
|
||||
Assert.Equal("friends.keymap", store.CurrentFileName);
|
||||
Assert.Equal(new[] { "friends.keymap" }, store.ListFiles());
|
||||
Assert.True(store.TryLoad(
|
||||
"friends.keymap", new KeyBindings(), out KeyBindings loaded, out string? error),
|
||||
error);
|
||||
Assert.Equal(
|
||||
source.ForAction(InputAction.MovementForward).ToArray(),
|
||||
loaded.ForAction(InputAction.MovementForward).ToArray());
|
||||
Assert.Equal(
|
||||
RetailKeymapSaveStatus.Exists,
|
||||
store.Save("friends", source, overwrite: false).Status);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (Directory.Exists(root)) Directory.Delete(root, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
private static string FindRepoRoot()
|
||||
{
|
||||
string? directory = AppContext.BaseDirectory;
|
||||
while (directory is not null)
|
||||
{
|
||||
if (File.Exists(Path.Combine(directory, "AcDream.slnx")))
|
||||
return directory;
|
||||
directory = Directory.GetParent(directory)?.FullName;
|
||||
}
|
||||
throw new DirectoryNotFoundException("Could not locate acdream.sln.");
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue