feat(core): adopt retail's SoundType catalog; retire AC2D
SoundId was not a subset of retail's table, the way its comment claimed. It was an invention: 23 acdream-local names on acdream-local values, and the values were wrong in the way that matters. FootstepDefault = 0x02 is retail's Random. SwingSword = 0x10 is retail's Death2. Death = 0x60 is retail's Explode. Anyone who reached for one of those names to compare against a wire or dat value would have got a different sound. Nothing referenced any of them by name -- grep for `SoundId.` across src and tests returns nothing -- so this was a trap rather than a live defect, the same shape the enum campaign found in DamageType. All 22 invented names are deleted and retail's 205 replace them. Three oracles agree exactly, on every name and every value: retail acclient.h:4569 enum SoundType, ACE's Sound, and DatReaderWriter's Sound. The third matters most. AudioHookSink already resolves SoundTable lookups through DatReaderWriter.Enums.Sound, so that is the enum acdream actually reads at runtime; our catalog now agrees with the values already flowing through the dat path, and a conformance test pins the two so they cannot drift apart. On the "206 sounds" figure: retail's block holds 207 entries, being 205 sounds followed by NUM_SOUND_TYPES = 0xCD and FORCE_SoundType_32_BIT. The first is a count and the second a width pin. Counting the former is where 206 came from. Neither is a member here, matching how the campaign treated NUM_ATTACK_HEIGHTS and Num_HoldKeys -- a count is not a value the wire can carry. Behaviour is unchanged and could not be otherwise: the enum had no consumers. IAudioEngine's three SoundId overloads are no-op stubs and the live path takes wave ids and DatReaderWriter values. The user's separate report that sound is "not working that good" is a triggering, selection and attenuation question rather than a catalog one, and is filed as its own Bucket B row in the post-Vulkan intake. Also in this commit, by user decision: AC2D is retired as a reference. Its clone and directory are gone and it must not be re-cloned. Everything we took from it still stands and is written down -- the FSplitNESW terrain split constants, the 0xF61C movement packet layout, the finding that a client need not compute terrain Z itself -- so CLAUDE.md's reference list, its hierarchy table, and the architecture doc's protocol row now point at docs/research/2026-04-12-movement-deep-dive.md rather than erasing the history. The reference count drops from six to five. Core tests 3907 passed / 2 skipped. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
f27ad9ee43
commit
39c1737bda
7 changed files with 601 additions and 58 deletions
|
|
@ -1135,7 +1135,7 @@ For acdream-specific code (renderer, plugin API, streaming):
|
|||
| Animation | `docs/research/named-retail/` + ACE Animation/ | — |
|
||||
| Terrain | ACME ClientReference.cs | named retail / older decompiled chunks |
|
||||
| Rendering | WorldBuilder (Silk.NET; its GL calls now read as RHI intent) | ACViewer |
|
||||
| Protocol | holtburger | AC2D |
|
||||
| Protocol | holtburger | `docs/research/named-retail/` (AC2D was the secondary until 2026-07-29 — retired reference; historical analysis remains in `docs/research/2026-04-12-movement-deep-dive.md`) |
|
||||
| Server behavior | ACE | — |
|
||||
|
||||
---
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ once Campaign V closes.
|
|||
| **VERIFY all enums** — **DONE 2026-07-29**, see [`docs/research/2026-07-29-enum-verification-campaign.md`](../research/2026-07-29-enum-verification-campaign.md) | The 2026-06-04 divergence note turned out to be missing from the repo entirely (open question 1 in the successor), so the sweep was regenerated from scratch. | Seven `Property*` tables created (864 members); `DamageType` and `ItemType` value bugs fixed; equipment/physics/item families closed against retail. Twelve open questions remain, headed by five empty `references/` repos. |
|
||||
| **Verify networking stack** | `docs/research/2026-06-04-wire-message-catalog.md`: 256 opcodes catalogued, 114 parsed. | Audit parsed-vs-stub-vs-missing against the catalog; prioritize by what live servers actually send (Coldeve session logs are now a real corpus); holtburger remains the client-side oracle. |
|
||||
| **Physics review — retail landing bounce et al.** | The named-retail decomp workflow; carried debt #116 (slide response), TS-50/51/53 in the divergence register. | A focused fidelity pass: start with the user's observed case — long-jump landing should bounce/recoil as retail does (grep `named-retail` for the landing/impact path in `MovementManager`/`SetMotion` land states before writing anything). Each fix follows grep→decompile→pseudocode→port→conformance. |
|
||||
| **Audio fidelity review** — user-sourced, 2026-07-29 | User reports sound "not working that good" generally. `AudioHookSink` + `OpenAlAudioEngine` are the current path; `SoundId` now carries retail's full 205-entry `SoundType` table (adopted 2026-07-29), so the catalog is no longer the gap. | Scope: sound *triggering*, *selection*, and *attenuation* versus retail — which hooks fire, how a SoundTable entry is chosen among its probability-weighted alternatives, and the falloff/pan curve. Separate from the `SoundId` catalog adoption, which was naming only. Oracles: named-retail's sound path, ACE, and the DAT SoundTable. |
|
||||
|
||||
## C. New feature bodies — milestone candidates, no existing spec
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,10 @@ empty directories** (`references/*` is gitignored; only WorldBuilder is checked
|
|||
in). The campaign therefore re-anchored on the oracles that *are* present, which
|
||||
is no loss of rigour — CLAUDE.md ranks the first of them above ACE anyway:
|
||||
|
||||
> This paragraph describes the environment the campaign *ran in*, later the same
|
||||
> day. It is no longer current: §7 records the restore, and AC2D was retired, so
|
||||
> CLAUDE.md now names five vendored repos rather than six.
|
||||
|
||||
| # | Oracle | What it is | Weight |
|
||||
|---|---|---|---|
|
||||
| 1 | `docs/research/named-retail/acclient.h` | The Sept 2013 EoR retail header, verbatim. 348 parseable `enum` blocks. | **Decides.** CLAUDE.md: "beats every other reference for what the real client does." |
|
||||
|
|
@ -201,11 +205,8 @@ CLAUDE.md these are recorded rather than guessed.
|
|||
`PublicWeenieDescPackHeader` (34), which is the *pack-header* bitfield — a
|
||||
different thing. `PublicWeenieDesc::BitfieldIndex` (31 members) is the likely
|
||||
real counterpart. **Blocker:** pairing unconfirmed; not diffed.
|
||||
7. **`SoundId` is a curated 23-member local subset** of retail's `SoundType`
|
||||
(206), with acdream-local names (`FootstepGrass`, `BuffApplied`) that do not
|
||||
correspond 1:1 to retail members. **Blocker:** needs a decision — adopt
|
||||
retail's table wholesale, or record the subset as an intentional divergence
|
||||
with a register row. Neither was done.
|
||||
7. ~~**`SoundId` is a curated 23-member local subset**~~ **RESOLVED 2026-07-29**
|
||||
by user decision: retail's table adopted wholesale. See §8.2.
|
||||
8. **`ChatType` / `BlobType` / `DispatchType`** (TurbineChat) share no members
|
||||
with retail's `eChatTypes` (26) or `ChatTypeEnum` (12); they describe chat
|
||||
*channels*, not text-display types. **Blocker:** correct counterpart not
|
||||
|
|
@ -261,11 +262,19 @@ absolute paths into `references/`). The method, in order:
|
|||
|
||||
## 7. The reference tree, restored (2026-07-29)
|
||||
|
||||
Open question 2 is closed. All six vendored repos were re-cloned from their
|
||||
upstreams into the main checkout at
|
||||
`C:\Users\erikn\source\repos\acdream\references\`, which every worktree shares.
|
||||
`references/*` is gitignored (only `WorldBuilder` is checked in as a gitlink), so
|
||||
none of this enters our history.
|
||||
Open question 2 is closed. The vendored repos were re-cloned from their upstreams
|
||||
into the main checkout at `C:\Users\erikn\source\repos\acdream\references\`, which
|
||||
every worktree shares. `references/*` is gitignored (only `WorldBuilder` is
|
||||
checked in as a gitlink), so none of this enters our history.
|
||||
|
||||
**AC2D was cloned, then dropped by user decision the same day and deleted along
|
||||
with its directory.** It is a retired reference: do not re-clone it. What we took
|
||||
from it — the `FSplitNESW` terrain split constants, the `0xF61C` movement packet
|
||||
layout, and the finding that a client need not compute terrain Z itself — is
|
||||
already written down in `docs/research/2026-04-12-movement-deep-dive.md` and the
|
||||
`docs/research/retail-ui/` dat-id work, and those citations stand. CLAUDE.md's
|
||||
reference list and hierarchy table, and the architecture doc's protocol row, were
|
||||
updated to say so rather than to erase the history.
|
||||
|
||||
Each candidate URL was cross-checked against the description in CLAUDE.md and
|
||||
`memory/reference_repos.md` before cloning, and the clone was verified to contain
|
||||
|
|
@ -277,7 +286,7 @@ the files those descriptions name.
|
|||
| ACViewer | `https://github.com/ACEmulator/ACViewer.git` | `c5c54fb3` | 97 MB | cited by URL in `docs/research/2026-07-13-retail-projectile-vfx-pseudocode.md`; also the remote of `repos/ACViewer`. Cloned `--recurse-submodules`, so its `ACE.DatLoader` submodule (`382edb23`) is present as the docs describe |
|
||||
| Chorizite.ACProtocol | `https://github.com/Chorizite/Chorizite.ACProtocol` | `ff7dffd6` | 4.5 MB | Chorizite org + exact repo name; contains the `Chorizite.ACProtocol` + `.SourceGen` projects CLAUDE.md describes as XML-generated |
|
||||
| holtburger | `https://github.com/merklejerk/holtburger` | `a7e806cb` | 25 MB | named by URL in `docs/research/2026-05-10-holtburger-network-stack-study.md`; also the remote of `repos/holtburger` |
|
||||
| AC2D | `https://github.com/deregtd/AC2D` | `3451f0d2` | 17 MB | no URL was recorded anywhere in the repo, so the candidate was verified by content: it is C++, and it holds `cNetwork.cpp`, `cInterface.cpp`, `cPictureBox.h`/`cStaticText.h`/`cEditBox.h`, and `FSplitNESW` in `Landblocks.cpp` — every file the docs attribute to AC2D |
|
||||
| ~~AC2D~~ | ~~`https://github.com/deregtd/AC2D`~~ | ~~`3451f0d2`~~ | — | **Retired 2026-07-29, deleted.** No URL was recorded anywhere in the repo, so the candidate had been verified by content: C++, holding `cNetwork.cpp`, `cInterface.cpp`, `cPictureBox.h`/`cStaticText.h`/`cEditBox.h`, and `FSplitNESW` in `Landblocks.cpp` — every file the docs attributed to AC2D. Identification was sound; the reference is simply no longer kept |
|
||||
| DatReaderWriter | `https://github.com/Chorizite/DatReaderWriter` | `c5359870` | 4.2 MB | cited by URL in `docs/research/2026-04-26-datreaderwriter-reference.md`. Not on the restore list, but it was empty for the same reason and is unambiguously identified |
|
||||
|
||||
---
|
||||
|
|
@ -329,3 +338,50 @@ naming a code does not make it render. The only site touched is
|
|||
|
||||
The enum also moved out of `MotionInterpreter.cs` into its own file at the same
|
||||
namespace; at 372 members it no longer belongs inside a physics class file.
|
||||
|
||||
### 8.2 `SoundId` — retail's full `SoundType` catalog
|
||||
|
||||
Open question 7, closed by user decision. This one was not a subset; it was an
|
||||
invention. The 23 members were acdream-local names on acdream-local values, and
|
||||
the values were wrong in the way that matters: the old `FootstepDefault = 0x02`
|
||||
is retail's `Random`, `SwingSword = 0x10` is retail's `Death2`, `Death = 0x60` is
|
||||
retail's `Explode`. The header comment called it "a sparse subset of retail
|
||||
enums", which it never was.
|
||||
|
||||
Nothing referenced any of the 23 by name — `grep` for `SoundId.` across `src/`
|
||||
and `tests/` returns nothing — so this was a trap rather than a live defect,
|
||||
exactly the shape the campaign found in `DamageType` (§2.1). All 22 invented
|
||||
names are deleted; retail's 205 replace them.
|
||||
|
||||
Three oracles agree exactly, on every name and every value:
|
||||
|
||||
| oracle | members | agreement |
|
||||
|---|---|---|
|
||||
| retail `acclient.h:4569 enum SoundType` | 205 named sounds | decides |
|
||||
| ACE `ACE.Entity.Enum.Sound` | 205 | identical names and values to retail |
|
||||
| DatReaderWriter `DatReaderWriter.Enums.Sound` | 205 | identical names and values to retail |
|
||||
|
||||
The third is the interesting one. `AudioHookSink` already resolves SoundTable
|
||||
lookups through `DatReaderWriter.Enums.Sound`, so that enum is what acdream
|
||||
actually reads at runtime — the adoption makes our own catalog agree with the
|
||||
values already flowing through the dat path, and a conformance test pins the two
|
||||
together so they cannot drift.
|
||||
|
||||
**On "206".** Retail's block holds 207 entries: 205 sounds, then
|
||||
`NUM_SOUND_TYPES = 0xCD` and `FORCE_SoundType_32_BIT`. The first is a count and
|
||||
the second a width pin. Counting `NUM_SOUND_TYPES` is where the 206 figure in
|
||||
open question 7 came from. Neither is a member here, matching how §3.2 treated
|
||||
`NUM_ATTACK_HEIGHTS` and `Num_HoldKeys` — a count is not a value the wire can
|
||||
carry.
|
||||
|
||||
**Behaviour: unchanged**, for the same reason as §8.1 and more strongly — the
|
||||
enum had no consumers at all. `IAudioEngine`'s three `SoundId` overloads
|
||||
(`PlayUi`, `Play3D`, `StartAmbient`) are no-op stubs; the live audio path takes
|
||||
wave ids and `DatReaderWriter.Enums.Sound` values, not this type.
|
||||
|
||||
The enum moved out of `AudioModel.cs` into its own file at the same namespace.
|
||||
|
||||
**Follow-up filed.** The user reports sound "not working that good" generally.
|
||||
That is a triggering/selection/attenuation question, not a catalog question, and
|
||||
is now a Bucket B row in
|
||||
[`docs/plans/2026-07-29-post-vulkan-work-intake.md`](../plans/2026-07-29-post-vulkan-work-intake.md).
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue