Commit graph

7 commits

Author SHA1 Message Date
Erik
d53891557d feat(phys L.2g slice 1): ShadowObjectRegistry.UpdatePhysicsState
New mutator that overwrites cached PhysicsState bits on every shadow copy
of the named entity. The existing CollisionExemption.ShouldSkip(...) check
(acclient_2013_pseudo_c.txt:276782) reads the same cached field, so a
post-spawn ETHEREAL flip is now honored on the next resolver tick without
any resolver-path change.

Retail anchor: CPhysicsObj::set_state at acclient_2013_pseudo_c.txt:283044.
Slice 1 scopes to the bare state-write — retail's cosmetic side-effect
handlers (0x800 lighting, 0x20 nodraw, 0x4000 hidden) don't fire for the
ETHEREAL bit and stay deferred.

Three TDD tests cover: ETHEREAL flip from 0->0x4; unregistered-entity
no-op; entity spanning multiple cells gets all copies updated.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 22:22:32 +02:00
Erik
ffefc6977f feat(physics): live-entity collision plumbing (Commit A)
Plumbing-only foundation for the upcoming live-entity (NPC / monster
/ player) collision port. No behavior change — the new fields default
to zero/None so the 5 existing static-entity Register call sites in
GameWindow.cs are untouched.

Wire layer:
- CreateObject parser now surfaces PhysicsState (acclient.h:2815 —
  ETHEREAL_PS=0x4, IGNORE_COLLISIONS_PS=0x10, HAS_PHYSICS_BSP_PS=0x10000,
  ...) which the parser previously dropped at line ~337 with a bare
  `pos += 4`.
- CreateObject parser now surfaces ObjectDescriptionFlags (the retail
  PWD._bitfield trailer per acclient.h:6431-6463), where
  acclient_2013_pseudo_c.txt:406898-406918 ACCWeenieObject::IsPK /
  IsPKLite / IsImpenetrable read bits 5 / 25 / 21 directly. Previously
  read-and-discarded.
- WorldSession.EntitySpawn carries both new fields through to subscribers.

Physics layer:
- New `EntityCollisionFlags` enum (IsPlayer / IsCreature / IsPK /
  IsPKLite / IsImpenetrable) + `FromPwdBitfield` helper. Bit
  positions verified against retail's SetPlayerKillerStatus (
  acclient_2013_pseudo_c.txt:441868-441890) which maps
  PKStatusEnum→bitfield exactly: PK=0x4→bit5, PKLite=0x40→bit25,
  Free=0x20→bit21.
- `ShadowEntry` extended with `State` (raw PhysicsState bits) +
  `Flags` (decoded EntityCollisionFlags). Backward-compatible — all
  five existing landblock-entity Register call sites omit them.
- `ShadowObjectRegistry.UpdatePosition(entityId, pos, rot, ...)` —
  fast-path for the 5–10 Hz UpdatePosition (0xF748) stream the server
  emits per visible entity. Reuses the entry's existing shape +
  state + flags. Mirrors retail's CPhysicsObj::SetPosition
  (acclient_2013_pseudo_c.txt:284276) which keeps the same shape and
  re-registers cell membership.
- `ObjectInfoState` adds `IsPK = 0x800` and `IsPKLite = 0x1000`
  matching retail's OBJECTINFO::state bits (acclient.h:6190-6194).
  Used by Commit C's PvP exemption gate.

Tests:
- `EntityCollisionFlagsTests` — 7 tests covering empty / each bit
  alone / PK+player combo / unrelated-bit ignore.
- `ShadowObjectRegistryTests` — 5 new tests: UpdatePosition moves
  entry to new cell, preserves State/Flags, unregistered no-op,
  Register stores State/Flags, defaults are zero/None.
- `CreateObjectTests` — 3 new tests verifying PhysicsState + PWD
  bitfield (with PK / PKLite bit cases) parse and surface.

1454 → 1454 + 15 = covered by suite. dotnet build + dotnet test
green.

Foundation for Commit B (live-entity registration) and Commit C
(PvP exemption block in FindObjCollisions).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 13:12:56 +02:00
Erik
ff325abd7b feat(ui): debug overlay + refined input controls
Adds the first on-screen HUD for the dev client plus today's mouse-control
refinements. Also lands yesterday's scenery-alignment changes that were
left uncommitted in the working tree.

Overlay:
- BitmapFont rasterizes a system TTF via StbTrueTypeSharp into a 512x512
  R8 atlas at startup (Consolas on Windows, DejaVu/Menlo fallbacks)
- TextRenderer batches 2D quads in screen-space with ortho projection;
  one shader + two draw calls (rect then text) for panel backgrounds
  under glyphs
- DebugOverlay composes info / stats / compass / help panels on top of
  the 3D scene; toggles via F1/F4/F5/F6; transient toasts for key events
- DebugLineRenderer and its shaders (carried over from the scenery work)
  are properly committed in this commit

Controls:
- Per-mode mouse sensitivity (Chase 0.15, Fly 1.0, Orbit 1.0); F8/F9 to
  adjust the active mode multiplicatively (x1.2)
- Hold RMB to free-orbit the chase camera around the player; release
  stays at the new angle (no snap-back)
- Mouse-wheel zooms chase distance between 2m and 40m
- Chase pitch widened to [-0.7, 1.4] so mouse-Y tilts both ways from
  the default neutral angle

Scenery alignment (carried from yesterday's session):
- ShadowObjectRegistry AllEntriesForDebug + Scale field
- SceneryGenerator uses ACViewer's OnRoad polygon test + baseLoc +
  set_heading rotation
- BSPQuery dispatchers accept localToWorld so normals/offsets transform
  correctly per part
- TransitionTypes.CylinderCollision rewritten with wall-slide + push-out
- PhysicsDataCache caches visual-mesh AABB for scenery that lacks
  physics Setup bounds
2026-04-17 18:45:38 +02:00
Erik
efd6a06c7d fix(physics): search adjacent landblocks for collision objects
GetNearbyObjects now searches the player's landblock plus all 8
neighbors. Previously only searched one landblock, missing objects
near landblock boundaries — which includes most trees/rocks since
scenery is placed across the full streaming window.

Also added diagnostic logging (will strip after verification).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 12:44:50 +02:00
Erik
14b0a6e2b8 feat(physics): CylSphere collision for trees, rocks, NPCs
Most scenery objects (trees, rocks) use CylSphere collision from
their Setup, not PhysicsBSP. Register these in ShadowObjectRegistry
with a Cylinder collision type. FindObjCollisions now handles both:
- BSP: full polygon collision via BSPQuery (buildings, stabs)
- Cylinder: radial + vertical cylinder-sphere test (trees, NPCs)

Diagnostics showed 170 CylSphere entities vs 278 BSP entities in
the Holtburg landblock alone — this roughly doubles collision coverage.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 12:14:28 +02:00
Erik
e12d255d2e feat(physics): port full CTransition collision response from pseudocode
Replace simplified push-out with retail-faithful SlideSphere and
AdjustOffset from transition_pseudocode.md. Crease-projection between
collision normal and contact plane produces smooth wall-sliding.
Object collision uses proper rotation transform to object-local space.

SlideSphere (section 6): computes crease direction via cross product
of collision normal and contact plane normal, projects displacement
onto the crease, then applies the correction offset. Handles three
cases: crease exists, parallel same-direction, parallel opposing.

AdjustOffset (section 6): adds safety check to keep sphere above
contact plane by computing signed distance and pushing up along Z
when the sphere dips below.

FindObjCollisions: removes ad-hoc penetration push-out, now calls
SlideSphere after BSP hit detection for proper wall-slide behavior.

Also fixes: ShadowEntry gains Rotation field, tests updated to match
Register signature, unused variables removed from GameWindow.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 11:17:45 +02:00
Erik
e2f0c8580e feat(physics): cell-based ShadowObject collision
Register static entities into terrain cells during streaming.
Transition system queries nearby objects and runs BSP collision.
Player can no longer walk through trees and buildings.

- ShadowObjectRegistry: 24m×24m cell index, Register/Deregister/
  RemoveLandblock/GetNearbyObjects matching retail AC's approach
- PhysicsEngine: ShadowObjects property + DataCache wiring point;
  RemoveLandblock now also clears shadow objects; TryGetLandblockContext
  helper lets Transition resolve landblock id+offset for a world pos
- Transition.FindObjCollisions: queries registry, broad-phase sphere test,
  narrow-phase BSPQuery.SphereIntersectsPoly in object-local space,
  returns Slid on hit to redirect movement along the surface
- GameWindow.ApplyLoadedTerrainLocked: registers each static entity after
  physics BSP data is cached; selects radius from BSP bounding sphere or
  Setup.Radius; wires PhysicsDataCache into engine on OnLoad
- 16 new ShadowObjectRegistry unit tests, all 361 tests green

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 11:05:09 +02:00