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
|
|
@ -4,6 +4,7 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using DatReaderWriter;
|
||||
using DatReaderWriter.DBObjs;
|
||||
using DatReaderWriter.Types;
|
||||
|
||||
// Dumps the retail-default keymap (gmDefaultMap @ 0x14000000) from
|
||||
// client_portal.dat. Used for the Phase K control overhaul — extracts
|
||||
|
|
@ -74,8 +75,57 @@ foreach (uint id in new uint[] { 0x14000000u, 0x14000002u })
|
|||
}
|
||||
}
|
||||
|
||||
// The Configure Keyboard contract is wider than the default map: the
|
||||
// ActionMap contains every user-bindable row, including initially-unbound
|
||||
// emotes and character-option toggles. Dump it in stable, machine-readable
|
||||
// order so conformance work never infers the 306-row universe from the much
|
||||
// smaller set of actions that happen to have default chords.
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("## ActionMap 0x26000000 user-bindable rows");
|
||||
var actionMap = dat.Get<ActionMap>(0x26000000u);
|
||||
var actionStrings = dat.Get<StringTable>(0x23000005u);
|
||||
if (actionMap is null)
|
||||
{
|
||||
Console.WriteLine(" (not found)");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine(" InputMap|Action|Class|LabelHash|Label|TooltipHash|Tooltip");
|
||||
foreach ((uint inputMapId, Dictionary<uint, ActionMapValue> actions) in
|
||||
actionMap.InputMaps.OrderBy(entry => entry.Key))
|
||||
{
|
||||
foreach ((uint actionId, ActionMapValue value) in
|
||||
actions.OrderBy(entry => entry.Key))
|
||||
{
|
||||
UserBindingData? binding = value.UserBinding;
|
||||
if (binding is null || binding.ActionClass == 0u)
|
||||
continue;
|
||||
|
||||
Console.WriteLine(
|
||||
$" 0x{inputMapId:X8}|0x{actionId:X8}|{binding.ActionClass}|"
|
||||
+ $"0x{binding.ActionName:X8}|{Resolve(binding.ActionName)}|"
|
||||
+ $"0x{binding.ActionDescription:X8}|{Resolve(binding.ActionDescription)}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
string Resolve(uint hash)
|
||||
{
|
||||
if (actionStrings is null
|
||||
|| !actionStrings.Strings.TryGetValue(hash, out var entry)
|
||||
|| entry.Strings.Count == 0)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return entry.Strings[0].Value
|
||||
.Replace("\r", "\\r", StringComparison.Ordinal)
|
||||
.Replace("\n", "\\n", StringComparison.Ordinal)
|
||||
.Replace("|", "\\|", StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
// ── Key decoding (scan code in high word, device id in low word) ──────
|
||||
static (uint scan, uint dev) SplitKey(uint key) => ((key >> 16) & 0xFFFFu, key & 0xFFFFu);
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@
|
|||
Runs the complete portable Release gate with bounded child processes.
|
||||
|
||||
.DESCRIPTION
|
||||
Verifies that AcDream.slnx owns every project under src/, tests/, and tools/;
|
||||
Verifies that AcDream.slnx owns every product project under src/, tests/,
|
||||
and tools/ (deployment-only ACE server mods are intentionally separate);
|
||||
performs a locked restore; builds that complete supported graph; discovers
|
||||
every test project under tests/ that declares itself through
|
||||
Microsoft.NET.Test.Sdk or IsTestProject; and then runs each test assembly in
|
||||
|
|
@ -199,7 +200,13 @@ function Get-SolutionProjects {
|
|||
foreach ($directoryName in @('src', 'tests', 'tools')) {
|
||||
Get-ChildItem -LiteralPath (Join-Path $repoRoot $directoryName) -Recurse -Filter '*.csproj' -File
|
||||
}
|
||||
)
|
||||
) | Where-Object {
|
||||
# tools/ace-mods projects compile against a separately installed ACE
|
||||
# server and are deployed into that server, not shipped as part of the
|
||||
# portable acdream product graph.
|
||||
$relative = [IO.Path]::GetRelativePath($repoRoot, $_.FullName).Replace('\', '/')
|
||||
-not $relative.StartsWith('tools/ace-mods/', [StringComparison]::OrdinalIgnoreCase)
|
||||
}
|
||||
$solutionSet = [Collections.Generic.HashSet[string]]::new(
|
||||
[StringComparer]::OrdinalIgnoreCase)
|
||||
foreach ($project in $projects) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue