This repository has been archived on 2026-10-31. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files

146 lines
7.4 KiB
Go
Raw Permalink Normal View History

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