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

143 lines
7.9 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package routers
import (
"context"
"sync"
)
var _ = sync.Mutex{}
var _ = context.Background
//
// 房产(House)所有权 —— 2026-09-30。用户报的症状:
// 「手机 app 里买房产会播动画 + 显示已购买,但实际走到那栋房子显示未购买」。
// <para>根因(一句话):客户端判断「这套房是不是我的」只有一条路径 ——
// gBuyHouseUtils.CheckHasBuyTheHouse(houseId) →
// gPlayerManager.infoMinor.bindData.housesInfo.HouseInfoList →
// PlayerInfoMinorData.lua:54 的 t.housesInfo = info.InfoMinor.housesInfo。
// 也就是说所有权完全由登录包决定,而服务端从来没往里写过。
// 手机里那套「已购买」是 BuyHouseUtils.BuyTheHouse 拿到 error=0 之后的
// 本地乐观行为(自己 SendMessage(ON_BUY_HOUSE_SUCCESS) + 开
// HOUSE_REWARD_PANEL 播 HouseConfig.GameVideo),
// 服务端当时既不记账也不推包 —— 所以面板一关 / 一重登 / 一开大地图,客户端重算一次就翻回「未购买」。</para>
// <para>本文件负责三件事:</para>
// <list type="number">
// <item>记账:GrantHouseOwnershipAsync —— 写
// WorldEntryState.Progress.OwnedHouseIds(PlayerProgressStore 落盘),
// 并推一次 SyncAddHouse(64459483) 让本次会话立刻生效
// (登录包里没有它,客户端得靠这条增量补上)。</item>
// <item>推送:PushSyncAddHouseAsync —— 线格式见
// HouseOwnershipWire4229938。</item>
// <item>读房:AskLoadHouseData(63109556) —— 客户端 C# 侧
// AskLoadHouseData(uint houseId) : UXRPCTask&lt;HouseBuildingClientData&gt;
// 唯一的用途是拿「这栋房子的装修内容」。2026-09-30 起这里还负责下发
// 「房子自带的家具」(gameplay.houseFurniture,见
// HouseFurnitureTemplateCatalog4229938)—— 在此之前一律回 57 字节空房,
// 那就是玩家看到的毛坯房。同时保证 OwnerPid 是自己而不是 0
// (兜底表给的是 0)。</item>
// </list>
// <para>本轮明确不做(用户拍板「只做所有权落地」+「自带家具」):
// 车库 / 停车(SyncHouseParking)、家具编辑 / 购买 / 摆放
// (AskAddBuildHouseIndoor / AskSaveHouseConfiguration / AskModifyHouse /
// 墙体编辑 / livehouse)、鱼缸与收藏品的运行时数据(FurnitureGadgetDataDict)、
// 访客与点赞、以及真实扣款(保持免费)。</para>
// <para>配置依赖:Configs/HouseConfig.json(5 条,见
// HouseCatalog4229938)。商店侧 NpcShopCatalog.json 早已含 94100080
// 「新启房产」,5 件商品齐全,所以 AskNpcShopCommodityInfo 不用改。</para>
//
//
// 购买落地:记所有权 + 落盘 + 推 SyncAddHouse。
// <para>⛔ 只在「第一次拿到」时推。BuyHouseUtils.SyncAddHouse 是
// table.insert(不是 set),同一套房推两次客户端列表里就有两条重复项。
// 已拥有时静默返回 —— 登录包已经把这条给过客户端了。</para>
// 写进日志的结果串(granted / already-owned / no-world)。
//
func GameRouter_House_GrantHouseOwnershipAsync(ctx context.Context, session *GameSession, houseId uint32, log any) string {
// Router implementation for GameRouter_House_GrantHouseOwnershipAsync
return ""
}
//
// 推 SyncAddHouse(64459483):payload 是**单个** HouseBaseInfo 的 complex。
// <para>⛔ 直接把 HouseActiveInfo 交给 NotifyAsync&lt;T&gt; ——
// UxSerializer 对非 Inline 的 [UxContract] 类型会自己写那一个 0xFF 包装,
// 正好对上客户端的 Base.ReadComplex(reader, Auto.Reader[368])。
// **不要**再包一层 Inline 壳(多一个 0xFF ⇒ 整包错位)。</para>
//
func GameRouter_House_PushSyncAddHouseAsync(ctx context.Context, session *GameSession, houseId uint32, log any) any {
// Router implementation for GameRouter_House_PushSyncAddHouseAsync
var zero any; return zero
}
//
// 63109556 — 客户端 C# 侧唯一调用点:
// UXRPCTask&lt;HouseBuildingClientData&gt; AskLoadHouseData(uint houseId)。
// 入参就是一个裸 u32(ClientToGameDelegate.lua 的
// AskLoadHouseData_Serializer 只写一个 primitive),返回一个 complex(590)。
// <para>2026-09-30 起这条路要下发「房子自带的家具」。在此之前我们一律回
// 权威兜底表那份 57 字节全空 HouseBuildingClientData
// (DefaultReturnCatalog4229938 的 case 63109556u,逐字节由
// Auto.Reader[590] 推出)—— 只把 OwnerPid 换成自己的 pid,
// 因为兜底给的是 0(「无主」),跟所有权落地直接冲突。
// 空 FloorBuildInfoDict 就是毛坯房的直接原因。</para>
// <para>现在:houseId → HouseConfig.BuildId → HouseBuildConfig.IndoorId /
// Floors / FurnitureTemplateIds → HouseFurnitureTemplateConfig,
// 把模板树翻成 PlacedFurnitureInfo 树塞进 FloorBuildInfoDict。
// 详见 HouseFurnitureTree4229938 与
// HouseBuildingClientData4229938(线格式逐字对照在那儿)。</para>
// <para>兜底仍然保留:关掉开关 / houseId 查不到 / 房子没有可装修体
// (岸北悠居公寓 BuildId = 0)/ 模板树为空 —— 任一条命中就回 57 字节空房,
// 和改动前逐字节一致。</para>
//
func GameRouter_House_AskLoadHouseData(ctx context.Context, conn any, msg any) any {
// Router implementation for GameRouter_House_AskLoadHouseData
var zero any; return zero
}
//
// 「自带家具」下发分支。true = 已经回过包,调用方直接 return。
// <para>任何一步查不到都返回 false,让调用方走 57 字节兜底 —— 这样出问题时的表现
// 和改动前一模一样(毛坯),不会退化成半截包 / 空包。</para>
//
func GameRouter_House_TryReturnHouseFurnitureAsync(ctx context.Context, conn any, msg any, houseId uint32, owned bool) bool {
// Router implementation for GameRouter_House_TryReturnHouseFurnitureAsync
return true
}
//
// FloorBuildInfoDict 的键。
// <para>结论(2026-09-30 取证):键 = 楼层号,<u>1 基</u>,地面层 = 1,取值 1..Floors。
// 所以默认 floor 就是正解。</para>
// <para>证据链(全部来自客户端自己的文件,不是推测):</para>
// <list type="number">
// <item>HouseBuildConfig.FloorsName = [{floor:1,__RAW__name:"1F"}];
// 素光小筑 [{1,"1F"},{2,"2F"}],且长度恰好等于 Floors。</item>
// <item>HouseBuildConfig.BuildBound / CameraBound / CameraTopViewPoint
// 一律用 floor: 1,2(同时带 IndoorBoundId: 1,2,数值与 floor 相同)。</item>
// <item>HomeBuildPanelStore_Floor.lua:SelectOption(initFloor - 1)、
// houseCamera.floor = index + 1 ⇒ 游戏侧 floor 是 1 基、只有 UI 选项是 0 基;
// GetFloorByPlayerPosition 两处兜底都 return 1。</item>
// <item>LuaGmUtils.lua:166 的
// for floorKey, indoorBuildInfo in pairs(buildData.FloorBuildInfoDict) —— 变量名就叫
// floorKey;而且它对每个键都加载一遍家具(去重表 loadedFurnitureIds 建在
// 键循环体内部)⇒ 多写键 = 家具被创建多遍。所以默认绝不能「把所有候选键都写上碰运气」。</item>
// <item>HouseUtils.lua 三个函数(Add/Remove/ModifyOneFurnitureInfo)里的
// floor = floor or 0 只是「参数缺失」的兜底;0 本身是非法值(会走
// "无法找到楼层[0]的家具信息" 的 warn 分支)。</item>
// </list>
// <para>indoor / all 保留为诊断开关:GmSyncHouseIndoorBuildInfo(houseId,
// indoorId, …) 那条 GM 链路确实按 indoorId 组织,万一登录链路将来被证伪可立刻切过去验证。
// all 会同时写 1..Floors 与 IndoorId,一定产生重复家具,只用于确认
// 「客户端到底取哪个键」。</para>
//
func GameRouter_House_ResolveFurnitureFloorKeys(ctx context.Context, mode any, build any) []any {
// Router implementation for GameRouter_House_ResolveFurnitureFloorKeys
return nil
}
func GameRouter_House_LogFurnitureTree(ctx context.Context, log any, houseId uint32, nodes []any, depth int32) any {
// Router implementation for GameRouter_House_LogFurnitureTree
var zero any; return zero
}