using System.Collections.Frozen; using System.Collections.Generic; namespace AcDream.Core.Items; /// /// AP-129 (Campaign P Slice P4 review fix, 2026-07-30). Retail /// RestrictionDB — the access-control list carried on a house/dwelling /// object's PublicWeenieDesc (WeenieHeaderFlag.HouseRestrictions, /// 0x04000000) and refreshed live via House_UpdateRestrictions (0x0248). /// Wire shape confirmed verbatim against /// references/Chorizite.ACProtocol/Chorizite.ACProtocol/Types/RestrictionDB.generated.cs /// and protocol.xml:6270-6275: uint Version, uint Flags (0=private, /// 1=open), ObjectId MonarchId, PHashTable<ObjectId,uint> Permissions. /// /// Wire Flags != 0 — retail's _bitmask /// & 1. When true, every mover is admitted regardless of the guest /// list. /// Wire MonarchId — retail /// _monarch_iid. A mover whose own monarch matches this id is admitted /// (allegiance-wide access), independent of the guest list. /// Wire Permissions — guid to permission value /// (0 = dwelling access only, 1 = storage access also). Retail's /// IsAllowedIn only consults key membership for entry; the permission /// value is preserved for wire fidelity but not consulted here. public sealed record HouseRestrictionRecord { public HouseRestrictionRecord( bool OpenToPublic, uint AllegianceMonarchId, IReadOnlyDictionary Guests) { ArgumentNullException.ThrowIfNull(Guests); this.OpenToPublic = OpenToPublic; this.AllegianceMonarchId = AllegianceMonarchId; this.Guests = Guests.ToFrozenDictionary(); } public bool OpenToPublic { get; } public uint AllegianceMonarchId { get; } /// /// Immutable snapshot of the wire permission table. The parser's mutable /// dictionary must never remain an untracked mutation path into live /// collision-entry authority. /// public IReadOnlyDictionary Guests { get; } /// /// Verbatim port of retail RestrictionDB::IsAllowedIn /// (named-retail pc:444493-444516, 0x005ae8f0): /// if ((_bitmask & 1) == 0) { if (_monarch_iid == 0 || arg3 != /// _monarch_iid) { if (arg2 == 0) return 0; if (!table.find(arg2)) return /// 0; } } return 1; — open bit set, OR mover shares the house's /// allegiance monarch, OR mover's own guid is a table member. /// public bool IsAllowedIn(uint moverId, uint moverMonarchId) { if (OpenToPublic) return true; if (AllegianceMonarchId != 0 && moverMonarchId == AllegianceMonarchId) return true; return moverId != 0 && Guests.ContainsKey(moverId); } }