diff --git a/docs/ISSUES.md b/docs/ISSUES.md index 408fcb49..e5fe597b 100644 --- a/docs/ISSUES.md +++ b/docs/ISSUES.md @@ -5482,6 +5482,28 @@ outdoors at the angle that previously erased it. # Recently closed +## #149 — BSP-less landblock statics (torches/braziers/lamp-posts) were walk-through + +**Status:** DONE (2026-06-25, `4cf6eeb`) — town props placed as landblock stabs +whose ONLY collision is a Setup CylSphere/Sphere (no physics BSP) had ZERO collision +shapes registered → walk-through. Root: the ISSUES #83 / A1.6 gate `!_isLandblockStab` +skipped Setup cyl/sphere for ALL stabs, on the false assumption *"landblock stabs +collide via BSP only (retail CBuildingObj)."* Confirmed end-to-end via live retail +cdb: the Holtburg torch (Setup `0x020005D8`, world (105.99,17.17)) hits +`CPhysicsObj::FindObjCollisions` with `num_cylsphere=1`, cyl h=2.2 — a cylsphere, +matching the dat (cylSphere r=0.2 h=2.2) exactly; the StabList confirms stab[95]= +`0x020005D8` at that position. Fix: gate the Setup cyl/sphere registration on +`entityBsp == 0` (retail's binary dispatch — BSP if the object has one, ELSE +cyl/sphere; see `feedback_retail_binary_dispatch`) instead of stab-ness — preserves +#83's anti-doubling (stab WITH a BSP → BSP-only) while restoring collision for +BSP-less stabs. Live-verified (torch + candle/brazier family block now; ~115 +cyl/sphere Setups register across streamed landblocks). The earlier selection-sphere +hypothesis was WRONG and reverted — the cdb's r=0.48 sphere was the player/NPC body +(every body sphere is ~0.48), not the torch; capturing the *target* at +`FindObjCollisions` (not `this` in `intersects_sphere`) + confirming by position + +Setup-id is the correct cdb method. `GameWindow.cs:7281`. Core suite green (1595/0). +(Numbered #149 to stay clear of main's #148; worktree branched before #145–148.) + ## Dense-town (Arwic) FPS deep-dive — 75 → ~165 fps **Status:** DONE (2026-06-24) — `290e731` (cell-object draw batching) + `9f51a4d` diff --git a/src/AcDream.App/Rendering/GameWindow.cs b/src/AcDream.App/Rendering/GameWindow.cs index eefa3325..c5ffc098 100644 --- a/src/AcDream.App/Rendering/GameWindow.cs +++ b/src/AcDream.App/Rendering/GameWindow.cs @@ -3830,7 +3830,8 @@ public sealed class GameWindow : IDisposable CylHeight: (setup.Height > 0 ? setup.Height : setup.Radius * 2f) * entScale)); } - if (shapes.Count == 0) return; + if (shapes.Count == 0) + return; // Decode PvP / Player / Impenetrable from PWD._bitfield. // IsCreature comes from the spawn's ItemType (server-known type). @@ -7265,17 +7266,28 @@ public sealed class GameWindow : IDisposable // clobber entries via Deregister. { var setup = _physicsDataCache.GetSetup(entity.SourceGfxObjOrSetupId); - // ISSUES #83 / Phase A1.6 (2026-05-21): landblock stabs use BSP - // collision exclusively (retail CBuildingObj). Skip Setup-derived - // CylSphere/Sphere/Radius shadow registrations for stabs to - // prevent the same doubled-collision bug A1 fixed for the - // mesh-AABB-fallback — but on the Setup path instead. Without - // this gate, a stab whose source is 0x02xxxxxx (Setup) with - // defined CylSpheres registers BOTH per-part BSP shadows AND a - // CylSphere shadow with id = entity.Id, producing an invisible - // collision cylinder at the stab origin alongside the correct - // BSP walls. - if (setup is not null && !_isLandblockStab) + // Retail binary collision dispatch (CPhysicsObj::FindObjCollisions + // @0x0050f050, see feedback_retail_binary_dispatch): an object uses + // its physics BSP if it HAS one (HAS_PHYSICS_BSP_PS 0x10000), ELSE + // its CSetup CylSpheres/Spheres — never both. The per-part BSP loop + // above already registered every BSP-bearing part (entityBsp counts + // them). So register the Setup's CylSpheres/Spheres ONLY when no BSP + // claimed this object (entityBsp == 0). + // + // This supersedes the ISSUES #83 / A1.6 (2026-05-21) gate that + // skipped Setup cyl/sphere for ALL landblock stabs to stop a + // BSP+cylinder doubled-collision. That gate over-broadened: it also + // killed collision for BSP-LESS stabs whose ONLY shape is a Setup + // CylSphere — e.g. the Holtburg town torch (stab Setup 0x020005D8, + // part 0x01001774 HasPhysics=False/BSP=null, cylSphere r=0.2 h=2.2). + // Retail collides with it via that cylsphere (live cdb 2026-06-25: + // FindObjCollisions target ncyl=1, cyl h=2.2 at world (105.99,17.17)); + // acdream walked straight through. Gating on entityBsp==0 keeps #83's + // anti-doubling (stab WITH a BSP → BSP-only) while restoring cyl + // collision for BSP-less stabs. Other landblock entities on this path + // (scenery — tree-trunk cylspheres etc.) are unaffected: with no BSP + // they still register cyl/sphere exactly as before. + if (setup is not null && entityBsp == 0) { float entScale = entity.Scale > 0f ? entity.Scale : 1f; uint shapeIndex = 0;