T6 (BR-7) C1: signed OtherPortalId + the >=0 building-transit gate
Retail CEnvCell::check_building_transit (Ghidra 0x0052c5d0) opens with `if (other_portal_id >= 0)` on the SIGNED sign-extended portal id (CBldPortal.other_portal_id is int, acclient.h:32098). Our BldPortalInfo carried the dat reader's raw ushort and CheckBuildingTransit had no gate at all, so a portal whose dat value is 0xFFFF (-1, "no reciprocal portal") could admit its interior cell. BN's pseudo-C renders the comparison unsigned - the sign-extension is Ghidra-proven (BR-7 verified corrections, wf1-interior-collision.md). - BldPortalInfo.OtherPortalId: ushort -> short; GameWindow construction reinterprets the dat ushort via unchecked((short)). - CheckBuildingTransit: negative-id portals rejected before any sphere test; new multi-sphere overload matching retail's per-sphere loop (0052c5fe, first-hit admits) with the hits_interior_cell output (0052c650) the BR-7 building channel consumes next. - Tests: negative-id skip vs positive-id admit on a leaf-root CellBSP; multi-sphere plumbing + zero-sphere no-op. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
85fe20f51d
commit
6ec4cde9a4
4 changed files with 192 additions and 14 deletions
|
|
@ -5967,7 +5967,12 @@ public sealed class GameWindow : IDisposable
|
|||
{
|
||||
bldPortals.Add(new AcDream.Core.Physics.BldPortalInfo(
|
||||
otherCellId: lbPrefix | (uint)bp.OtherCellId,
|
||||
otherPortalId: bp.OtherPortalId,
|
||||
// DatReaderWriter parses the dat's 16-bit field as
|
||||
// ushort; retail sign-extends it to a SIGNED int
|
||||
// (CBldPortal.other_portal_id, acclient.h:32098) and
|
||||
// check_building_transit gates on `>= 0`
|
||||
// (Ghidra 0x0052c5dc). 0xFFFF → -1 = no reciprocal.
|
||||
otherPortalId: unchecked((short)bp.OtherPortalId),
|
||||
flags: (ushort)bp.Flags));
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue