using System.Collections.Generic;
using System.Numerics;
using DatReaderWriter.Enums;
namespace AcDream.Core.Physics;
///
/// Indoor walking Phase 2 (2026-05-19). Cached building portal data
/// for outdoor→indoor cell entry. One per outdoor landcell that contains
/// a building stab. Mirrors retail's BuildingObj.Portals array
/// (per the pseudocode doc §"LandCell.find_transit_cells").
///
public sealed class BuildingPhysics
{
public required Matrix4x4 WorldTransform { get; init; }
public required Matrix4x4 InverseWorldTransform { get; init; }
public required IReadOnlyList Portals { get; init; }
///
/// BR-7 / A6.P4 (2026-06-11): the building's shell part-0 GfxObj id.
/// 0x01 BuildingInfo.ModelId values are stored verbatim; 0x02 Setup
/// models are resolved to their FIRST part at cache time (the
/// CacheBuilding call site reads the dat). Drives the retail building
/// collision channel (CBuildingObj::find_building_collisions,
/// Ghidra 0x006b5300: one BSP test on part_array->parts[0]).
/// 0 = unknown (legacy cache entries / tests) — the channel is inert.
///
public uint ModelId { get; init; }
}
///
/// One building portal: the connection from a SortCell's BuildingObj to
/// an interior EnvCell. ExactMatch is decoded from
/// bit 0 (PortalFlags.ExactMatch = 0x0001).
///
public readonly struct BldPortalInfo
{
public BldPortalInfo(uint otherCellId, short otherPortalId, ushort flags)
{
OtherCellId = otherCellId;
OtherPortalId = otherPortalId;
Flags = flags;
}
/// Full id of the interior EnvCell this portal connects to.
public uint OtherCellId { get; }
///
/// The portal id within the destination EnvCell — SIGNED, like retail's
/// CBldPortal.other_portal_id (int, acclient.h:32098,
/// sign-extended from the dat's 16-bit field). -1 (wire
/// 0xFFFF) means "no reciprocal portal"; retail's
/// CEnvCell::check_building_transit (Ghidra 0x0052c5d0) rejects
/// the whole transit when this is negative — the arg2 >= 0
/// gate is the first instruction. BN's pseudo-C renders the comparison
/// unsigned (wrong); the sign-extension is Ghidra-proven
/// (wf1-interior-collision.md, BR-7 verified corrections).
/// DatReaderWriter parses the field as ushort; construction
/// sites reinterpret via unchecked((short)value).
///
public short OtherPortalId { get; }
public ushort Flags { get; }
///
/// Bit 0 of (DatReaderWriter.Enums.PortalFlags.ExactMatch).
///
///
/// Reserved per retail's CBldPortal::exact_match. NOT currently
/// consumed by — every
/// portal overlap is treated as a valid entry trigger. If a future
/// regression surfaces (e.g., a building entered by overlapping a
/// non-exact-match portal), wire this into the entry test.
///
///
public bool ExactMatch => (Flags & (ushort)PortalFlags.ExactMatch) != 0;
}