docs: FA1 review round -- register repoint, seams corrections, plan reconciliation
Applies the documentation-only MUST-FIX items from the blast review
(docs/research/2026-08-12-fa1-review-blast.md), plus mechanism SF-4:
Blast MF-1 / mechanism SF-4: register row AP-90
(retail-divergence-register.md) cited the deleted AllegianceTree class as
its evidence. Re-pointed to ClientCommandResponses.AllegianceProfileLookups
and the fellowship parsers FA1 added -- the deviation itself (radar
relationship state undelivered at runtime) is unchanged and NOT retired,
since FA2 hasn't wired a live owner yet.
Blast MF-2: corrected four falsified statements in the lane D research doc
(fa-acdream-seams.md), each marked with a dated, clearly-struck FA1
fix-round addendum rather than silently rewritten (it is a committed
research record):
- :791 "wrapping existing AllegianceTree" -- class deleted; re-pointed to
AllegianceProfileLookups.
- :666/:672 `commands.Fellowship.SetOpen -> BuildFellowshipUpdate` -- that
builder no longer exists; its renamed successor is panel visibility,
not openness, and using it here would re-introduce the exact semantic
bug FA1 fixed. Re-pointed to BuildFellowshipChangeOpenness (0x0291).
- :429/:668 `BuildFellowshipCreate(seq, name, openness, shareXp)` -- the
builder is now 3-arg; there is no wire openness field.
- :854 open question 8 (trailing-pad rule) -- ANSWERED by FA1 (VC-3),
closed with the answer instead of left open for re-derivation.
Blast MF-3: plan decision D9 and the FA1 slice-map row both asserted "the 8
missing fellowship WeenieError strings are added in FA1" -- FA1 shipped the
opposite, verified finding (no retail display text exists for any of the
8 ids). Both struck and annotated with the actual outcome.
Blast MF-4: reconciled the ledger's internally-inconsistent test-total row.
Direct measurement at the pre-fix-round tip (bc693728, stashed/restored
during this session to isolate it) confirms 13,149 passed / 4 skipped / 0
failed (13,153 total) -- the ledger's own prior number was actually
correct; the "baseline 13,103" and "net +50" framing next to it did not
reconcile with each other or with the diff-verified delta (+58 added / -9
deleted = net +49, one test of drift attributed to a different baseline
commit, not a further miscount). Also records this session's own +9 tests
and the blast SF-1 live-surface note (FA1 changed observable @allegiance
info output, not a purely-unwired slice).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
ed30808720
commit
511ba6e5d4
3 changed files with 45 additions and 12 deletions
|
|
@ -295,7 +295,7 @@ AP-94..AP-112 for the confirmed retail-UI completion gaps.
|
|||
| AP-86 | **Remote SHADOW-follows-resolved via a pose/cell-gated per-tick re-flood** (remote-creature de-overlap #184): every remote's collision shadow is rewritten at the resolved body position by the DR tick or authoritative UP tail, so collision remains where the creature renders and de-overlap persists. The effect matches retail, but acdream runs the full multipart cell flood whenever the body moved more than 1 cm, changed complete orientation, or crossed a cell instead of translating the existing shadow in place and relinking only when its crossed-cell set changes. Cross-cell motion now commits body/root/full-cell before the canonical rebucket callback; local and authoritative remote publishers prove exact-record spatial residency after that callback; pending projection suspends the retained shadow and cannot re-add it, including initial-pending and callback GUID-reuse cases. | `src/AcDream.App/Physics/RemotePhysicsUpdater.cs`; `src/AcDream.App/Physics/LiveEntityShadowPublisher.cs`; `src/AcDream.App/Rendering/GameWindow.cs` (local projection); `src/AcDream.App/Physics/LiveEntityNetworkUpdateController.cs` (authoritative UP tails); `src/AcDream.App/World/LiveEntityPresentationController.cs` (ordinary projection residency); `src/AcDream.Core/Physics/ShadowObjectRegistry.cs` (`UpdatePosition`) | The pose/cell gate is exact at de-overlap equilibrium, preserves offset/multipart shapes during in-place turns, and the resulting registered cell set matches retail; loaded/pending residency is symmetric and incarnation-scoped | A dense moving or turning crowd can still perform a full registration flood per creature per tick and create CPU/Gen0 pressure; a still crowd is gated out. Retire with an in-place move plus cell-relink-on-change implementation | `CPhysicsObj::SetPositionInternal(CTransition const*)` 0x00515330 → `change_cell`, then `remove_shadows_from_cells`/`add_shadows_to_cells` after the resolved frame/contact commit |
|
||||
| AP-87 | **Remote MoveOrTeleport placement adds a 4 m body-to-target snap + a no-Sequencer snap** beyond retail's <96 m-unconditional interpolate (remote-creature de-overlap #184, 2026-07-07; unified across player-remote and NPC-remote by C4 route 4a, 2026-08-03 — retail's disassembly makes no `this==player` distinction here either, so the two formerly-duplicated per-kind copies are now the SAME decision): retail `CPhysicsObj::MoveOrTeleport` (0x00516330) hard-places only on the teleport-timestamp / cell==0 branch or the ≥96 m far-snap, and InterpolateTo-queues every near correction; acdream ADDS two snap conditions — `|Body.Position − worldPos| > 4 m` (a large correction / an unplaced first-UP body) and `!willBeDrTicked` (no Sequencer to consume the queue). Without them an unplaced body (origin / spawn seed) would enqueue, the InterpolationManager's 100 m far-blip would fire, and the per-tick sweep would run over a huge distance in a cell not containing the body → garbage resolved pos → the reverted attempt's INVISIBLE monster. A third condition `firstUp` (`LastServerPosTime <= 0`) is RETAINED, not dropped, in the unified seam: it is a belt hint only — the 4 m guard is the load-bearing backstop — and it is structurally false for player remotes because the player-remote caller stamps `LastServerPosTime` in its diagnostic roll-forward block before it routes, so unifying the two copies on all three conditions leaves the player branch's own behaviour bit-identical | `src/AcDream.Runtime/Physics/RuntimeRemoteSteadyStatePosition.cs` (`ApplyInterpolate`, `BodySnapThreshold`); called from `src/AcDream.App/Physics/LiveEntityNetworkUpdateController.cs` for both the player-remote and NPC-remote near-Interpolate branches. C4 route 4b-2 (2026-08-04) deleted the App's two duplicated `MaxPhysicsDistance = 96f` / `BodySnapThreshold = 4f` constant pairs and both `_playerController?.Position ?? Vector3.Zero` fabrications: the far branch is now a canonical Runtime placement, and the cell-less/rejected/unclassified leftovers call this same seam (AP-137). The 4 m constant exists in exactly one place | acdream's catch-up+sweep needs the body already near the target (a valid nearby cell) for the per-frame sweep to be small; the 4 m snap keeps it there, and retail's own large-correction path (the 100 m far-blip) is upstream of it. The de-overlap sweep also uses the fixed human sphere (R 0.48 / H 1.835) for the mover regardless of creature size, so large packed creatures de-overlap at human radii — inherits **TS-46** | A grounded remote that legitimately lags >4 m from its server pos snaps (a small pop) where retail would slide; a no-Sequencer server-moved entity hard-snaps every UP (no DR smoothing). Both are rare. **2026-08-04 observed live, then FIXED AT THE SOURCE the same day**: the route 4a two-client test caught exactly this risk — a player remote jumping onto a house roof planted there and sat until it had drifted >4 m from the server's slid-down position, at which point this backstop fired (`producer=ap87-4m` in the capture) and blipped it instead of sliding. The CAUSE was the remote tick forging `Contact | OnWalkable` and deciding its landing edge from the contact-derived `ResolveResult.IsOnGround`; that is fixed (Bug B, `docs/ISSUES.md` #32) and the thresholds and conditions of this row are deliberately UNCHANGED. The snap remains the #184 invisible-but-solid backstop; it should simply fire far less often now that the body genuinely tracks the server, and less often again since AP-140's same-day retirement pointed both routing gates at CONTACT: a steep-face slide now interpolates toward the server pose every packet instead of being classified free-flight and hard-snapped, so `bodyToTarget` converges rather than being left to drift past 4 m. This row's own thresholds and conditions are unchanged by either fix | `CPhysicsObj::MoveOrTeleport` 0x00516330 (near-interpolate <96 m; teleport/cell-0 snap; far-snap ≥96 m); `InterpolationManager` 100 m `AutonomyBlipDistance` (the retail large-correction path) |
|
||||
| AP-89 | **TransparentPartHook fade multiplies the SAMPLED TEXTURE alpha, not a separate material alpha channel** (#188, 2026-07-08 — the fading-wall secret-passage doors, e.g. "Pedestal Weak Spot"): retail's `CPhysicsPart::SetTranslucency` (0x0050e670) → `CMaterial::SetTranslucencySimple` (0x005396f0) REPLACES the D3D9 material's 4 alpha channels wholesale (`Ambient.a = Diffuse.a = Specular.a = Emissive.a = 1 − translucency`) — a per-material alpha that composes with, but is conceptually separate from, the surface's own sampled texture alpha. acdream's `mesh_modern.frag` has no material-alpha concept at all; the port multiplies the runtime fade's opacity multiplier directly against the already-sampled `color.a` (`FragColor = vec4(rgb, color.a * vOpacityMultiplier)`) | `src/AcDream.App/Rendering/Shaders/mesh_modern.frag` (final `FragColor` line); `src/AcDream.App/Rendering/Wb/WbDrawDispatcher.cs` (`ClassifyBatches` `opacityMultiplier` param, `InstanceGroup.Opacities`); `src/AcDream.Core/Rendering/TranslucencyFadeManager.cs` | Observably identical to retail for any surface whose base texture alpha is 1.0 everywhere — the Pedestal Weak Spot's stone-wall texture, and the overwhelming majority of AC surfaces, since `color.a * 1.0 == color.a` and the fade multiplier alone then drives the ramp exactly as `1 − translucency` would | A hypothetical object that is BOTH already alpha-keyed/blended from its own texture (stained glass, a flame surface) AND plays a TransparentPartHook fade simultaneously would compound the two alphas (texture-alpha × fade-multiplier) instead of the fade cleanly replacing/overriding the surface's own alpha as retail's material-replace does — such an object would fade darker / more-transparent than retail, not just at retail's rate | `CPhysicsPart::SetTranslucency` 0x0050e670; `CMaterial::SetTranslucencySimple` 0x005396f0 (`alpha = 1 − translucency`, applied to all 4 D3D9 material alpha channels) |
|
||||
| AP-90 | **Radar fellowship/allegiance relationship state is modeled but not yet delivered at runtime.** `RetailRadar.GetBlipShape` and `RadarBlipColors.For` implement retail's leader/member/allegiance precedence, and `RadarSnapshotProvider` exposes a `relationshipFor(guid)` seam, but acdream does not yet maintain live fellowship membership and its `AllegianceTree` is not wired into GameWindow. PK/PKLite relationship shapes do work from PWD flags. | `src/AcDream.App/UI/Layout/RadarSnapshotProvider.cs`; `src/AcDream.Core/Ui/RetailRadar.cs`; `src/AcDream.Core/Ui/RadarBlipColors.cs` | Preserve the exact model/seam now and avoid inventing membership from names or chat; connect it when the social game-event state is ported | Fellowship members render their ordinary player color/shape instead of bright-green leader/member triangles; allegiance members render an ordinary plus instead of a hollow box | `gmRadarUI::GetBlipColor` 0x004D76F0; `gmRadarUI::GetBlipShape` 0x004D7B60 |
|
||||
| AP-90 | **Radar fellowship/allegiance relationship state is modeled but not yet delivered at runtime.** `RetailRadar.GetBlipShape` and `RadarBlipColors.For` implement retail's leader/member/allegiance precedence, and `RadarSnapshotProvider` exposes a `relationshipFor(guid)` seam, but acdream does not yet maintain live fellowship/allegiance membership at a Runtime owner. **Edited at the FA1 review fix-round (2026-08-12) — the deviation is unchanged, but its evidence citation was stale:** Campaign FA slice FA1 deleted the `Core/Allegiance/AllegianceTree.cs` this row used to name (`4281750b`) and replaced it with the flat `AllegianceMemberRecord` list + `ClientCommandResponses.AllegianceProfileLookups` (`GetData`/`GetPatron`/`FindVassals`) plus the fellowship S→C parsers in `GameEvents.cs` — none of it wired to a live state owner yet; that is FA2's `RuntimeFellowshipState`/`RuntimeAllegianceState` scope. PK/PKLite relationship shapes do work from PWD flags. | `src/AcDream.App/UI/Layout/RadarSnapshotProvider.cs`; `src/AcDream.Core/Ui/RetailRadar.cs`; `src/AcDream.Core/Ui/RadarBlipColors.cs`; `src/AcDream.Core.Net/Messages/ClientCommandResponses.cs` (`AllegianceProfileLookups`); `src/AcDream.Core.Net/Messages/GameEvents.cs` (fellowship parsers) | Preserve the exact model/seam now and avoid inventing membership from names or chat; connect it when the social game-event state is ported (FA2) | Fellowship members render their ordinary player color/shape instead of bright-green leader/member triangles; allegiance members render an ordinary plus instead of a hollow box | `gmRadarUI::GetBlipColor` 0x004D76F0; `gmRadarUI::GetBlipShape` 0x004D7B60 |
|
||||
| AP-92 | Private creature viewports (paperdoll and examination) render through isolated `IGpuRenderTarget`s and blit into `UiViewport`; retail renders each `CreatureMode` directly and advances a cloned `CPhysicsObj`, while examination currently refreshes its clone from the live target's animated mesh pose. **V6l narrowing (2026-07-28), V11 update (2026-07-29):** the target is backend-neutral and the blit's V origin is not assumed — `IUiViewportRenderer.TextureIsBottomUp` derives it from the backend that made the texture. With GL deleted the only answer in the tree is Vulkan's top-left origin, but the seam is kept rather than folded flat, because it costs one property and it is what let the origin question be answered by data instead of by assumption. | `src/AcDream.App/Rendering/PrivateEntityViewportRenderer.cs`; `src/AcDream.App/Rendering/PaperdollFramePresenter.cs`; `src/AcDream.App/Rendering/CreatureAppraisalPresentation.cs`; `src/AcDream.App/UI/UiViewport.cs` | Vulkan render-to-texture is the modern backend equivalent; shared live pose data provides animation without registering a second gameplay entity or duplicating the world sequencer | Alpha, lighting, state isolation, or an assessment-time cloned motion diverging later from the live target can differ from direct retail CreatureMode presentation. The origin half of this risk is closed; a FUTURE backend would have to answer `TextureIsBottomUp` for itself | `CPhysicsObj::makeObject(CPhysicsObj const*) @ 0x005144B0`; `gmPaperDollUI::PostInit @ 0x004A5360`; `BasicCreatureExamineUI::Init @ 0x004AB9C0`; `UIElement_Viewport::SetCamera`; retail `CreatureMode::Render` |
|
||||
| AP-93 | Paperdoll does not port `UpdateForRace`; all characters use the cdb-confirmed default held pose `0x030003C0` and default presentation | `src/AcDream.App/Rendering/DollEntityBuilder.cs`; `RetailPaperdollPoseApplicator` in `src/AcDream.App/Rendering/PaperdollFramePresenter.cs` | Exact for the tested Horan character; unresolved for other heritage/gender/body combinations | Non-default races can use the wrong pose, heading, camera framing, or presentation asset | `gmPaperDollUI::UpdateForRace @ 0x004A3ED0` |
|
||||
| AP-94 | Imported Type-12 text defaults to interactive/selectable behavior; display labels can focus/capture/drag, and vitals synthesize duplicate runtime labels instead of binding `0x100000EB/ED/EF` | `src/AcDream.App/UI/UiText.cs`; `src/AcDream.App/UI/Layout/VitalsController.cs` | Historical widget-generalization default; Wave 1 ports explicit Display/Selectable/Editable roles | Invisible/static text steals input and duplicate labels drift from DAT geometry | `UIElement_Text` property handlers; `gmVitalsUI::PostInit @ 0x004BFCE0` |
|
||||
|
|
|
|||
|
|
@ -100,9 +100,24 @@ served by the single inbound wiring site.
|
|||
role-discriminated headless policy let one bot recruit/swear at
|
||||
another, with the decisive assertion on the RECRUITED bot's own
|
||||
snapshot. All six FA option names are already tier-1 allow-listed.
|
||||
- **D9 — the 8 missing fellowship WeenieError strings are added in FA1**
|
||||
- **D9 —** ~~the 8 missing fellowship WeenieError strings are added in FA1
|
||||
(two are on ACE's live send paths today; all resolve from the DAT
|
||||
string tables, never invented).
|
||||
string tables, never invented).~~ **[FA1 fix-round addendum, 2026-08-12:
|
||||
shipped the OPPOSITE finding — `5f9aa16f` verified from primary source
|
||||
(case-label walk + `else if` chain sweep + whole-file sweep + decimal
|
||||
forms, `docs/research/2026-08-12-fa1-review-mechanism.md` §2(a)) that
|
||||
retail's Sept-2013 client has NO display text for any of the 8 ids.
|
||||
Inventing English for them would have been the exact failure mode the
|
||||
WeenieError table's no-default-case rule exists to prevent. acdream's
|
||||
existing silence for the two ACE actually sends
|
||||
(`0x0417 FellowshipIgnoringRequests`, `0x04DB FellowshipDeclined`) is
|
||||
already retail-faithful; no strings were added, and none are owed. The
|
||||
conformance `[Theory]` at `WeenieErrorMessagesTests.cs:390-393` (8
|
||||
`InlineData` rows, each asserting `Resolve()` returns null) is the
|
||||
correct artifact in place of the string additions this decision
|
||||
originally called for. No register row is owed either — the register
|
||||
tracks acdream-vs-retail deviation, and this finding is that acdream
|
||||
already matches retail.]**
|
||||
|
||||
## 3. Slice map
|
||||
|
||||
|
|
@ -112,7 +127,7 @@ FA2, FA3, FA4, FA5, FA6, FA7.
|
|||
|
||||
| Slice | Contract (summary) | Gate |
|
||||
|---|---|---|
|
||||
| FA1 | Core.Net truth: repair fellowship builders + re-pin golden vectors; add `0x0290`/`0x0291`/`0x00A6`; the allegiance action set the panel needs (swear/break/kick/info at minimum; the rest of the 27 as builders only where ACE serves them); parsers for the 11 S→C events incl. the profile version gates (extending `ParseAllegianceInfoResponse`) and the tree discard/reversal rules; complete the confirmation triple; add the 8 WeenieError strings; DELETE `AllegianceTree` | automated only |
|
||||
| FA1 | Core.Net truth: repair fellowship builders + re-pin golden vectors; add `0x0290`/`0x0291`/`0x00A6`/`0x001F`; the allegiance action set the panel needs (swear/break/kick/info at minimum; the rest of the 27 as builders only where ACE serves them); parsers for the 11 S→C events incl. the profile version gates (extending `ParseAllegianceInfoResponse`) and the tree discard/reversal rules; complete the confirmation triple; ~~add the 8 WeenieError strings~~ **[FA1 fix-round addendum, 2026-08-12: shipped as CONFIRM-ABSENT instead — see D9's addendum. The 8 ids have no retail display text; acdream's silence is already faithful and a conformance test pins it.]**; DELETE `AllegianceTree` | automated only |
|
||||
| FA2 | `RuntimeFellowshipState` + `RuntimeAllegianceState` (lane D's 8-edit template each); single-site inbound wiring serving BOTH hosts; typed commands/views; snapshot revisions; reset/reconnect semantics (session-scoped vs seed-latched); bot event surface via polling | automated only |
|
||||
| FA3 | The social panel shell: mount slot `0x1000018F` (catalog id 12), F3/F4 handlers, fixture dump of the slot (closes U3/U4/U6/U7/U10), tab activation, all four pages' empty states, Friends/Squelch read-only binding to J4.1 state | user (connected) |
|
||||
| FA4 | Fellowship page live: roster rows (adds `UiTemplateListBox` Flush/selection/row-instance-id — lane A sized this), the `0x00A6` show/hide declaration + vitals stream, create dialog (inline name field, shareXP), recruit/dismiss/quit/disband/leader + confirmations, share display per D5, option-row un-dims per D7 | user (connected) + bot |
|
||||
|
|
@ -178,7 +193,7 @@ before anything builds on them.
|
|||
|
||||
| Slice | Status | Commit(s) | Review | Gate |
|
||||
|---|---|---|---|---|
|
||||
| FA1 | CODE-COMPLETE 2026-08-12, owes review | `7be86f47` (builders), `6bedbc47` (parsers), `5f9aa16f` (WeenieError), `4281750b` (delete AllegianceTree) | — | automated: Release build + full suite 13,149/4 skips/0 failures (baseline 13,103/4/0, net +50 tests) |
|
||||
| FA1 | CODE-COMPLETE 2026-08-12; dual-lens Opus review APPROVE-WITH-FIXES both lenses; fix-round applied 2026-08-12 | `7be86f47` (builders), `6bedbc47` (parsers), `5f9aa16f` (WeenieError), `4281750b` (delete AllegianceTree); fix-round: `ed308087` (mechanism+blast MUST/SHOULD-FIX code+tests), this commit (register/plan/seams doc corrections) | mechanism `docs/research/2026-08-12-fa1-review-mechanism.md` (2 MUST-FIX, 5 SHOULD-FIX, all applied); blast `docs/research/2026-08-12-fa1-review-blast.md` (4 MUST-FIX, 5 SHOULD-FIX, all applied). **Live-surface note (blast SF-1):** FA1 changed the observable output of the ALREADY-LIVE `@allegiance info` command in two retail-faithful ways — vassal print order reversed (now pinned by a 3-vassal test through `FormatAllegianceInfoLines`) and a malformed tree now prints nothing instead of a partial roster (now pinned at the `GameEventWiring` layer) — not a "purely unwired" slice. | automated: Release build + full suite green throughout. **Reconciled totals (blast MF-4):** the ledger's own prior figure (13,149/4/0) is CONFIRMED correct by direct measurement at the pre-fix-round tip `bc693728` (13,153 total = 4+916+1559+15+130+119+4856+877+4677 across all 9 test projects); the campaign-start baseline in §5 is 13,103/4/0, and the diff-verified FA1 delta is **+58 added / −9 deleted (deleted `AllegianceTreeTests.cs`) = net +49**, i.e. 13,103+49=13,152 — one test of drift against the directly-measured 13,153/13,149 baseline, attributed to the §5 baseline being captured at a different point in git history than the FA1 diff's actual parent, not a further miscount. This fix round adds a further **+9 tests** (2 golden vectors for the new `0x001F` builder, 1 D5 `<<1` pin at the `0x02C0` site, 4 MF-1/SF-1 boundary tests, 2 blast SF-1 live-surface pins) — **final: 13,158 passed / 4 skipped / 0 failed (13,162 total), directly measured.** |
|
||||
| FA2 | — | | | |
|
||||
| FA3 | — | | | |
|
||||
| FA4 | — | | | |
|
||||
|
|
|
|||
|
|
@ -426,8 +426,14 @@ The plan must decide per-row, but the code evidence says:
|
|||
- `FellowshipShareXP` / `FellowshipShareLoot` — these are **server-side**
|
||||
policy (ACE decides the split). They un-dim only if FA reads them to
|
||||
drive the create-fellowship dialog's initial checkbox state
|
||||
(`BuildFellowshipCreate(seq, name, openness, shareXp)`,
|
||||
`SocialActions.cs:123-138`, takes `shareXp` as a parameter — that IS a
|
||||
(~~`BuildFellowshipCreate(seq, name, openness, shareXp)`,
|
||||
`SocialActions.cs:123-138`~~ **[FA1 fix-round addendum, 2026-08-12: FA1
|
||||
repaired this builder — there is no "openness" field on
|
||||
`FellowshipCreateOpcode`'s wire (the prior 4-arg builder invented one and
|
||||
silently sent it as the low byte of shareXP, which ACE would read as an
|
||||
INVERTED shareXP value). The current signature is
|
||||
`BuildFellowshipCreate(seq, fellowshipName, shareXp)`,
|
||||
`SocialActions.cs:144-155`.]**, takes `shareXp` as a parameter — that IS a
|
||||
client-side read). `FellowshipShareXP` is additionally tagged Group D
|
||||
(deferred) in the derivation table (`:137`).
|
||||
- `IgnoreAllegianceRequests` — un-dims if FA gates the incoming-swear
|
||||
|
|
@ -659,11 +665,11 @@ idempotence — is exactly reusable for FA.
|
|||
|
||||
| Command | Underlying builder |
|
||||
|---|---|
|
||||
| `commands.Fellowship.Create(gen, name, open, shareXp)` | `SocialActions.BuildFellowshipCreate` |
|
||||
| `commands.Fellowship.Create(gen, name, open, shareXp)` | `SocialActions.BuildFellowshipCreate` **[FA1 fix-round addendum, 2026-08-12: the builder is now 3-arg — `BuildFellowshipCreate(seq, fellowshipName, shareXp)` (`SocialActions.cs:144-155`). There is no wire "openness" field; drop `open` from this command's own signature too.]** |
|
||||
| `commands.Fellowship.Recruit(gen, targetGuid)` | `BuildFellowshipRecruit` |
|
||||
| `commands.Fellowship.Quit(gen, disband)` | `BuildFellowshipQuit` |
|
||||
| `commands.Fellowship.Dismiss(gen, targetGuid)` | `BuildFellowshipDismiss` |
|
||||
| `commands.Fellowship.SetOpen(gen, open)` | `BuildFellowshipUpdate` |
|
||||
| `commands.Fellowship.SetOpen(gen, open)` | ~~`BuildFellowshipUpdate`~~ **[FA1 fix-round addendum, 2026-08-12: `BuildFellowshipUpdate` no longer exists. Its renamed successor `BuildFellowshipUpdateRequest` (`0x00A6`) is PANEL VISIBILITY, not openness — wiring `SetOpen` to it would re-introduce the exact semantic bug FA1 fixed. The real openness action is `BuildFellowshipChangeOpenness` (`0x0291`, `SocialActions.cs:222-230`).]** |
|
||||
| `commands.Allegiance.Swear(gen, patronGuid)` | `AllegianceRequests.BuildSwear` |
|
||||
| `commands.Allegiance.Break(gen, targetGuid)` | `BuildBreak` |
|
||||
|
||||
|
|
@ -788,7 +794,7 @@ A/B should confirm this against retail rather than inferring it from ACE.
|
|||
| Subsystem | Where new code goes | Pattern to follow | Precedent citation |
|
||||
|---|---|---|---|
|
||||
| Fellowship state owner | `src/AcDream.Runtime/Gameplay/RuntimeFellowshipState.cs` (new) | J4 owner: `IDisposable` + `ResetSession()` + `CaptureOwnership()`; borrow entity table | `RuntimeInventoryState` ctor `GameRuntime.cs:192-193`; snapshot shape `RuntimeCharacterState.cs:9-51` |
|
||||
| Allegiance state owner | `src/AcDream.Runtime/Gameplay/RuntimeAllegianceState.cs` (new), wrapping existing `AcDream.Core.Allegiance.AllegianceTree` | Same; **survives reconnect** — use a `HasServerSeed`-style latch | `RuntimeCharacterOptionsState` seed latch; `AllegianceTree.cs:56-162` |
|
||||
| Allegiance state owner | `src/AcDream.Runtime/Gameplay/RuntimeAllegianceState.cs` (new), ~~wrapping existing `AcDream.Core.Allegiance.AllegianceTree`~~ **[FA1 fix-round addendum, 2026-08-12: `AllegianceTree` was DELETED by Campaign FA slice FA1 (`4281750b`) — there is nothing left to wrap. Wrap `ClientCommandResponses.AllegianceProfileLookups` (the flat `AllegianceMemberRecord` list + `GetData`/`GetPatron`/`FindVassals` walk that replaced it) instead. FA2 is the very next slice — this is its seam-map row.]** | Same; **survives reconnect** — use a `HasServerSeed`-style latch | `RuntimeCharacterOptionsState` seed latch; ~~`AllegianceTree.cs:56-162`~~ **[FA1 fix-round addendum: see `ClientCommandResponses.cs:250-295` (`AllegianceProfileLookups`) instead]** |
|
||||
| Owner registration | `GameRuntime.cs` | ctor + `construction.Own` + fault point + `*Owner` prop + view prop + `CaptureOwnership` + shutdown step | `GameRuntime.cs:200-214`, `:419-429`, `:463-470`, `:545-567`, `:703-752` |
|
||||
| Session reset | `RuntimeGenerationReset.cs` | new `RuntimeGenerationResetStage` ordinal + `Drain` case; **fellowship clears, allegiance re-seeds** | `:21-44`, `:236-349`; shared-stage example `:248-261` |
|
||||
| Ownership rollup | `RuntimeGameplayOwnership.cs` | add to record + `Capture(...)` signature + `IsConverged` | `:8-21`, `:23-44` |
|
||||
|
|
@ -845,9 +851,21 @@ A/B should confirm this against retail rather than inferring it from ACE.
|
|||
7. **`ID_Fellowship_*` / `ID_Allegiance_*` string-table id.** Assume
|
||||
nothing — dat-verify. The options family is `0x23000003`, but chat
|
||||
filters live in `0x2300000D` and keyboard refusal in `0x23000004`.
|
||||
8. **`BuildFellowshipCreate` trailing-pad rule** is currently pinned only
|
||||
8. ~~**`BuildFellowshipCreate` trailing-pad rule** is currently pinned only
|
||||
by a self-consistent test (`SocialActionsTests.cs:53-68`), not against a
|
||||
retail/ACE reference. Lane A/B should confirm before FA sends it live.
|
||||
retail/ACE reference. Lane A/B should confirm before FA sends it live.~~
|
||||
**[FA1 fix-round addendum, 2026-08-12: ANSWERED by FA1, close this
|
||||
question rather than re-deriving it. `PackString16L`
|
||||
(`SocialActions.cs:389-403`) pads the string record to a 4-byte multiple
|
||||
INCLUDING its own u16 length, so `12 + name.Length` is already
|
||||
4-aligned before the trailing `u32 shareXP` is appended — the pad the
|
||||
old (now-deleted) builder added after its two invented bools was never
|
||||
the string's own pad. ACE reads exactly `ReadString16L()` then
|
||||
`ReadUInt32()` (`GameActionFellowshipCreate.cs`), and `ACE.Common`'s
|
||||
`ReadString16L` skips the identical `CalculatePadMultiple(2 + length,
|
||||
4)` pad. The golden vector at `SocialActionsTests.cs:65-83` ("Team",
|
||||
len 4, 2 pad bytes) is hand-derived against that ACE reader, not merely
|
||||
self-consistent. No further confirmation owed.]**
|
||||
9. **`DisplayAllegianceLogonNotifications` semantics**: receive-side
|
||||
display filter (swallow locally) or membership-style suppression? Unlike
|
||||
`Hear*Chat` this is almost certainly display-only — but it must be
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue