package catalogs import ( "encoding/json" "os" "path/filepath" "sync" ) var _ = json.RawMessage{} var _ = sync.Mutex{} var _ = os.ReadFile var _ = filepath.Join // One indoor venue the client can stream as sector_high_indoor_<Id>. // MiniMapPos 矩形的最小 x(HasRect=false 时无意义)。 // MiniMapPos 矩形的最小 z。 // MiniMapPos 矩形的最大 x。 // MiniMapPos 矩形的最大 z。 // true = 有矩形(MiniMapPos 给了 4 个数),判距离时按「点到矩形」算。 type IndoorVenue4229938 struct { Id uint32 `json:"id"` Name string `json:"name"` NameTag string `json:"nameTag"` Raid uint32 `json:"raid"` X float32 `json:"x"` Z float32 `json:"z"` FromMiniMap bool `json:"fromMiniMap"` MinX float32 `json:"minX"` MinZ float32 `json:"minZ"` MaxX float32 `json:"maxX"` MaxZ float32 `json:"maxZ"` HasRect bool `json:"hasRect"` } // // Reads Configs/IndoorConfig.json — the official indoor-venue table. Its Id is // exactly the number the client prints in Enter GpsBound: RaidId …, IndoorId N and the // suffix of the scene root sector_high_indoor_<N>. // // // ★ 为什么服务端能自己算出 IndoorId(2026-09-27 取证): // · 客户端日志 Enter GpsBound: RaidId 23300888, IndoorId 61; // · IndoorConfig.Id = 61 = "WowDonald's"(麦当劳),Coordinate = [859.34, 1.32, 1846.84]; // · 玩家当时在 (866, 1840),直线距离 9.5 m —— 完全吻合。 // ⇒ 不需要客户端上报,也不需要 frida 导出 WorldStateIndoorSectorConfig; // 服务端按「最近的 IndoorConfig 条目」即可推出玩家在哪个室内。 // ⛔ 坐标有两个来源,别只认一个: // 1. Coordinate(3D,[x,y,z])—— 新启 153 条里只有 54 条有; // 2. MiniMapPos(2D,[x0,z0,x1,z1,…])—— 其余 99 条 Coordinate 是空数组,只能靠它。 // FromMiniMap=true 的条目精度差一档(小地图锚点,不是门口坐标),半径要放宽。 // ⛔⛔ MiniMapPos 是矩形(建筑在小地图上的轮廓),前两个数是一个角 // —— 早期代码直接拿它当场馆坐标,导致「站在场馆正中央却被判成室外」 // (Spiko Hotel 矩形 [2515,1162,2610,1285],站中心 (2559,1217) 距角点 70.7 m > 60 m)。 // 2026-09-27 21:5x 已改成「取矩形中心 + 按点到矩形判距离(矩形内 = 0)」。 // ⛔ RelatedSector 字段基本没用:770 条里只有 1 条非空 // (Id=74 → "proxy_high_niu_employmentagency",是个场景对象名,不是扇区号)。别拿它当映射表。 // var ( IndoorCatalog4229938_cacheLock sync.RWMutex IndoorCatalog4229938_cached = false IndoorCatalog4229938_entries []any ) // LoadIndoorCatalog4229938 loads catalog records from client config directory func LoadIndoorCatalog4229938(configDir string) ([]any, error) { IndoorCatalog4229938_cacheLock.RLock() if IndoorCatalog4229938_cached { defer IndoorCatalog4229938_cacheLock.RUnlock() return IndoorCatalog4229938_entries, nil } IndoorCatalog4229938_cacheLock.RUnlock() IndoorCatalog4229938_cacheLock.Lock() defer IndoorCatalog4229938_cacheLock.Unlock() if IndoorCatalog4229938_cached { return IndoorCatalog4229938_entries, nil } filePath := filepath.Join(configDir, "IndoorCatalog.json.json") data, err := os.ReadFile(filePath) if err != nil { return nil, err } var raw struct { Records []json.RawMessage `json:"records"` } if err := json.Unmarshal(data, &raw); err != nil { return nil, err } var result []any for _, item := range raw.Records { var m map[string]any if err := json.Unmarshal(item, &m); err == nil { result = append(result, m) } } IndoorCatalog4229938_entries = result IndoorCatalog4229938_cached = true return result, nil } // How many venues the table has for one map (0 = that map has no usable rows). func IndoorCatalog4229938_CountForRaid(raid uint32) int32 { // Catalog helper IndoorCatalog4229938_CountForRaid return 0 } // // Nearest venue of within of (x,z). // Returns null when nothing is close enough — "the player is outdoors" is a normal answer. // func IndoorCatalog4229938_Nearest(raid uint32, x float32, z float32, radiusMeters float32) *IndoorVenue4229938 { // Catalog helper IndoorCatalog4229938_Nearest return nil } // 点到场馆中心(Coordinate 只有单点时用它)。 func IndoorCatalog4229938_DistanceToPoint(vx float32, vz float32, x float32, z float32) float64 { // Catalog helper IndoorCatalog4229938_DistanceToPoint return 0 } // // 点到 MiniMapPos 矩形的距离:在矩形内(含边界)= 0,否则到最近边/角的距离。 // ★ 2026-09-27 21:5x 修正:以前把 MiniMapPos[0],[1] 当成场馆坐标 —— 那是矩形的 // 第一个角,不是中心。后果:Spiko Hotel([2515,1162,2610,1285]) 的角点在 // (2515,1162),玩家站在矩形正中的 (2559,1217) 反而算出 70.7 m,超过 60 m 半径 ⇒ // 站在场馆正中间却被判成室外;而 ACD 因为角点恰好离玩家近才误打误撞判对。 // func IndoorCatalog4229938_DistanceToRect(v IndoorVenue4229938, x float32, z float32) float64 { // Catalog helper IndoorCatalog4229938_DistanceToRect return 0 } // Lookup by id (panel / diagnostics). func IndoorCatalog4229938_ById(raid uint32, id uint32) *IndoorVenue4229938 { // Catalog helper IndoorCatalog4229938_ById return nil } func IndoorCatalog4229938_LoadPair() any { // Catalog helper IndoorCatalog4229938_LoadPair var zero any; return zero } func IndoorCatalog4229938_TryRead(node any, venue *IndoorVenue4229938) bool { // Catalog helper IndoorCatalog4229938_TryRead return false } func IndoorCatalog4229938_U32(source any, name string) uint32 { // Catalog helper IndoorCatalog4229938_U32 return 0 } func IndoorCatalog4229938_Str(source any, name string) string { // Catalog helper IndoorCatalog4229938_Str return "" } func IndoorCatalog4229938_Floats(array any, take int32) []float32 { // Catalog helper IndoorCatalog4229938_Floats return nil }