using Auto = Ananta.Server.RpcTypes.Client4229938.Auto; namespace Ananta.Server.Protocol.Client4229938; /// /// 「已拥有哪几套房」→ 客户端认识的线格式 —— 2026-09-30。 /// /// 两个消费点,必须字节一致: /// /// 登录包 PlayerClientInfoMinor.housesInfo.HouseInfoList /// (RuntimePayloadFactory.SeedOwnedHouses4229938)—— 决定「重登后房子还在不在」。 /// 购买瞬间的 SyncAddHouse(64459483) 推送 /// (GameRouter.House.cs 的 PushSyncAddHouseAsync)—— /// payload 就是**单个** HouseBaseInfo 的 complex,不是列表。 /// 客户端 Lua BuyHouseUtils.SyncAddHouse 拿到之后自己 /// table.insert 进上面那个 HouseInfoList。 /// /// 所以两边都走 ,避免同一个结构手抄两遍抄岔。 /// /// 线格式(LuaGen/AutoGen/RPCDeserializeAuto.lua 的 /// Auto.Reader[368] 逐字对照,2026-09-30 核对): /// /// HouseId u32 /// ParkingSpaceVehicleIdDict Dict<i32,u32> ← Base.ReadDict = marker 0xFF + Int32 计数 /// Version u32 /// SocialInfo complex(1143) /// FurnitureIndex u32 /// /// 注意 SyncAddHouse 的客户端 reader 是 /// Base.ReadComplex(reader, Auto.Reader[368]) —— 整包只有**一个** complex 包装, /// 所以推送时直接把 HouseActiveInfo 交给 NotifyAsync<T> 即可 /// (UxSerializer 对非 Inline 的 [UxContract] 类型会自动写那一个 0xFF), /// **不要**再包一层 Inline 壳 —— 那会多出一个 0xFF 把整包错位。 /// /// ⛔⛔ SocialInfo 绝对不能给 null。 /// 判据:客户端自己的 UX.Game.HouseBaseInfo 类上**没有** [NullableContext], /// 而同一个 namespace 下的 HouseSocialInfo 有 [NullableContext(2)] /// (dump.cs TypeDefIndex 33341 / 33342);Lua 侧 Auto.WriteHouseBaseInfo 里这个字段的 /// nullable 标记也是 false(对照 HouseAddFurnitureResult.PlacedFurnitureInfo 是 /// true,那个类确实带 [NullableContext(2)])⇒ 客户端按**非空**读。 /// 给 null 会让 UxSerializer 只写一个 0x00,后面的 FurnitureIndex 整体错位。 /// 正确默认是空对象(两个空串)。 /// internal static class HouseOwnershipWire4229938 { /// /// 一套房 → 一个 HouseBaseInfo。 /// Version / FurnitureIndex 恒 0 —— 这一轮只做所有权 + 车库指派,不碰装修。 /// /// 2026-09-30 起 ParkingSpaceVehicleIdDict 不再留空: /// 客户端 GarageManager.CheckHouseInfo 读的就是登录包这一份 /// (housesInfo.HouseInfoList[i].ParkingSpaceVehicleIdDict), /// 键 = 车位号 0 基,值 = 车辆 configId。重登后车库「哪个车位有车」靠它恢复。 /// /// /// 这套房的车位指派(车位号 0 基 → 车辆 configId);null / 空 = 车库全空 /// (与改动前的空字典逐字节一致)。 internal static Auto.HouseActiveInfo ToWire(uint houseId, IReadOnlyDictionary? parking = null) => new() { HouseId = houseId, ParkingSpaceVehicleIdDict = parking is null || parking.Count == 0 ? new Dictionary() : new Dictionary(parking), Version = 0u, SocialInfo = new Auto.HouseSocialInfo { PromoImageUrl = string.Empty, WelcomeText = string.Empty, }, FurnitureIndex = 0u, }; }