package models import ( "encoding/json" "sync" ) var _ = json.RawMessage{} var _ = sync.Mutex{} // // AskLoadHouseData(63109556) 的返回体 —— 2026-09-30「自带家具」。 // ⛔ 先纠正一个编号坑:客户端有两套互不相通的 Auto.Reader 编号, // 千万别混用: // // Lua 侧(S2C 推送):LuaGen/AutoGen/RPCDeserializeAuto.lua,定义 // Auto.Reader[N] + midToReader[mid] + midToName[mid](833 条)。 // AskLoadHouseData 不在这张表里(它是 C# 侧请求/应答链路)⇒ // 拿 Lua 的编号去指这条返回体是错的。 // C# 侧(请求/应答):在 Assembly-CSharp 里,本仓库读不到。 // // 本 DTO 的字段顺序/编码不是靠编号推的,是逐字节验出来的(一次性探针 // %TEMP%\houseprobe,反射调 UxSerializer.Serialize 再和权威兜底表比): // // 空 payload(OwnerPid = 0)与 DefaultReturnCatalog4229938 里 // case 63109556u 的 57 字节模板 MATCH ⇒ 字段顺序 + 三个计数编码全对。 // 四套房的非空 payload 被按 Lua Auto.Reader[321]/[1010]/[390] 手写的解析器 // 完整吃掉(remain = 0),家具件数与模板一致。 // // 下面这套 Lua 编号是亲自读过、可信的(用于对照字段顺序): // // Auto.Reader[321] = HouseInfo { HouseId, ParkingSpaceVehicleIdDict, FloorBuildInfoDict, // CurPlacedFurnitureInstanceId, WallInfo, Configuration, // FashionShowcaseDict, PlacementStatistics } // Auto.Reader[1010] = IndoorBuildInfo { Root = ReadComplex(390) } // Auto.Reader[390] = PlacedFurnitureInfo // // 本返回体(HouseBuildingClientData,dump TypeDefIndex 33347,7 个 FieldIndex)逐字: // // OwnerPid u64 // FloorBuildInfoDict ReadDict7Bit(u32 → complex) ← ★ 家具树宿主;键 = 楼层号(1 基,见下) // WallInfo complex HouseWallInfo // FashionShowcaseDict ReadDict7Bit(u64 → complex) // Configuration complex PlayerSingleHouseConfiguration // FurnitureGadgetDataDict ReadDict7Bit(u64 → complex) // DisabledFurniturePlacedIds ReadList7Bit(u64) (带 UXRPCParameterLengthLimit(1024)) // // ⚠️ FloorBuildInfoDict 的键是 楼层号,1 基,地面层 = 1,取值 1..Floors // —— 不是 indoorId。取证链见 PrivateServerConfig.HouseFurnitureSettings.KeyMode // 与 GameRouter.House.cs 的 ResolveFurnitureFloorKeys。 // ⛔⛔ 三个 ReadDict7Bit 不能用 Auto.Reader[321](HouseInfo)那套 Int32 计数。 // Base.ReadDict7Bit(LX6/Service/RPCDeserializeBase.lua)是 // 「0xFF 标记 + 偏置 varint(线上写 count+1)」,而 Base.ReadDict 是 // 「0xFF + Int32 计数」。UxSerializer.WriteDictionary 的默认计数编码是 // Int32 ⇒ 这里每个 7bit 字段都必须显式写 // [UxCollection(Count = UxCountEncoding.Int7)],否则空表会写成 // FF 00 00 00 00(客户端读到 count=0 但多吞 3 个字节 ⇒ 整包错位)。 // 判据:权威兜底表 DefaultReturnCatalog4229938 里这条 57 字节的 // FloorBuildInfoDict 段就是 FF 01,不是 FF 00 00 00 00。 // ⛔ Root.ChildrenDict 反过来是 Base.ReadDict // (Auto.Reader[390] 里 ChildrenDict = Base.ReadDict(r:ReadUInt64, ReadComplex(390))) // ⇒ 那里必须用 Int32 计数(空表 FF 00 00 00 00)。两个字段编码不一样, // 别顺手统一。 // type HouseBuildingClientData4229938 struct { OwnerPid uint64 `json:"ownerPid"` FloorBuildInfoDict map[uint32]IndoorBuildInfo `json:"floorBuildInfoDict"` WallInfo HouseWallInfo `json:"wallInfo"` FashionShowcaseDict map[uint64]HouseFashionShowcaseData `json:"fashionShowcaseDict"` Configuration PlayerSingleHouseConfiguration `json:"configuration"` FurnitureGadgetDataDict map[uint64]HouseFurnitureGadgetData4229938 `json:"furnitureGadgetDataDict"` DisabledFurniturePlacedIds []uint64 `json:"disabledFurniturePlacedIds"` } // // HouseBuildingClientData.FurnitureGadgetDataDict 的 value 类型(FurnitureGadgetData)。 // ⛔ 下面这一族 Auto.Reader[N] 编号(1088 / 1073 / 932 / 1133 / 289 / 1089) // 属于 C# 侧编号空间,本仓库读不到那张表 ⇒ 只当形状备忘,别拿它去 Lua 的 // RPCDeserializeAuto.lua 里查(那边的编号完全不同)。已亲自验证过的 Lua 编号只有 // [321] HouseInfo / [1010] IndoorBuildInfo / [390] PlacedFurnitureInfo。 // 形状逐字抄自客户端 reader,但本轮永远不下发(FurnitureGadgetDataDict 恒为空字典)—— // 鱼缸 / 收藏品是「家具运行时数据」,不在「房子自带家具」范围内。 // 保留完整字段只是为了让这个类型将来真被填上时字节是对的,而不是个只会写 0xFF 的空壳。 // type HouseFurnitureGadgetData4229938 struct { FishTank *HouseFishTankGadgetData4229938 `json:"fishTank"` Collectible *HouseCollectibleGadgetData4229938 `json:"collectible"` } // Auto.Reader[1073]:{ SlotFish: Dict7Bit<u32, complex(1133)> }。 type HouseFishTankGadgetData4229938 struct { SlotFish map[uint32]HouseFishInfo4229938 `json:"slotFish"` } // Auto.Reader[932]。 type HouseCollectibleGadgetData4229938 struct { LootConfigId uint32 `json:"lootConfigId"` ItemUniqueId uint64 `json:"itemUniqueId"` } // Auto.Reader[1133](HouseFishInfo)。 type HouseFishInfo4229938 struct { UniqueId uint32 `json:"uniqueId"` TemplateId uint32 `json:"templateId"` Weight float32 `json:"weight"` Length float32 `json:"length"` PlacedInfo *HouseFishPlacedInfo4229938 `json:"placedInfo"` } // Auto.Reader[289]:{ Furniture: complex(1089) }。 type HouseFishPlacedInfo4229938 struct { Furniture *HouseFishPlacedFurnitureInfo4229938 `json:"furniture"` } // Auto.Reader[1089]。 type HouseFishPlacedFurnitureInfo4229938 struct { HouseId uint32 `json:"houseId"` FurniturePlacedId uint64 `json:"furniturePlacedId"` FurnitureSlotId uint32 `json:"furnitureSlotId"` } // // 把 ClientData.Client4229938.HouseFurnitureTemplateNode4229938 模板树 // 翻译成客户端认识的 PlacedFurnitureInfo 树。 // 关键点: // // Position/Rotation 直接搬模板里的**绝对世界坐标**,不做任何变换 // —— 模板叶子本来就落在房子所在的真实坐标上(绿屿公馆 14001 → 约 (2254..2294, 160.72, 1394..1404))。 // PlacedInstanceId 必须**全局唯一且非 0**:客户端的 // gFurnitureUIDManager.uid2FurnitureGoDict 是**跨房子**的全局表, // 四套房共用一套小 id 会让「先去 A 再去 B」互相踩。这里用 // houseId * 100000 + 模板节点号(节点号 ≤ 14150 < 100000 ⇒ 房内不撞; // houseId ≥ 11200003 ⇒ 跨房不撞;最大值 ≈ 1.12e12 < 2^53 ⇒ Lua number 也能精确表示)。 // GadgetInstanceId 恒 0 —— 家具本体是客户端按 FurnitureId 自己实例化的, // 机关(鱼缸/电视…)才需要 gadget,那是另一条链路。 // 父子关系照抄模板树(绿屿公馆的模板有 9 个「桌上的小物件」是挂在桌子下面的), // 客户端用 ChildrenDict 表达父子,没有 ParentPlacedInstanceId 字段。 // // type HouseFurnitureTree4229938 struct { } const ( HouseFurnitureTree4229938_PlacedIdStride uint64 = 100000 )