168 lines
5.9 KiB
Go
168 lines
5.9 KiB
Go
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
|
||
}
|
||
|