package catalogs import ( "encoding/json" "os" "path/filepath" "sync" ) var _ = json.RawMessage{} var _ = sync.Mutex{} var _ = os.ReadFile var _ = filepath.Join // // One place the player can invade: an enemy faction's influence area, with the world position of // the event that belongs to it. // // // Data comes from three official tables joined offline (_build_invasion_spots.py): // FactionInfluenceAreaConfig — the turf itself, and whether it is invadable at all // (CanInvasionArea; the player's own turf 犬魔社 is not); // FactionInfluenceEventConfig — what sits on that turf (HQ / Camp / Kingpin / Skirmish); // TaskEventConfig.CenterPos — where it actually is. // ⛑ Three rows are HQ (type=1) and their CenterPos is (0,0,0) in the official data — those // are not teleport targets. HasPosition exists so callers can skip them instead of // walking the player to the origin. // type FactionInvasionSpot4229938 struct { EventId int32 `json:"eventId"` AreaId int32 `json:"areaId"` AreaName string `json:"areaName"` EventName string `json:"eventName"` Type int32 `json:"type"` TypeName string `json:"typeName"` FactionId uint32 `json:"factionId"` Raid uint32 `json:"raid"` X float32 `json:"x"` Y float32 `json:"y"` Z float32 `json:"z"` HasPosition bool `json:"hasPosition"` } // // Reads Configs/FactionInvasionSpots.json. Parsed once behind a Lazy{T}; a // missing or malformed file is not fatal — the catalog goes empty and LoadError // explains why so the panel can say so. // var ( FactionInvasionSpotCatalog4229938_cacheLock sync.RWMutex FactionInvasionSpotCatalog4229938_cached = false FactionInvasionSpotCatalog4229938_entries []any ) // LoadFactionInvasionSpotCatalog4229938 loads catalog records from client config directory func LoadFactionInvasionSpotCatalog4229938(configDir string) ([]any, error) { FactionInvasionSpotCatalog4229938_cacheLock.RLock() if FactionInvasionSpotCatalog4229938_cached { defer FactionInvasionSpotCatalog4229938_cacheLock.RUnlock() return FactionInvasionSpotCatalog4229938_entries, nil } FactionInvasionSpotCatalog4229938_cacheLock.RUnlock() FactionInvasionSpotCatalog4229938_cacheLock.Lock() defer FactionInvasionSpotCatalog4229938_cacheLock.Unlock() if FactionInvasionSpotCatalog4229938_cached { return FactionInvasionSpotCatalog4229938_entries, nil } filePath := filepath.Join(configDir, "FactionInvasionSpotCatalog.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) } } FactionInvasionSpotCatalog4229938_entries = result FactionInvasionSpotCatalog4229938_cached = true return result, nil } // Every spot that has a real world position, ordered by area then event. func FactionInvasionSpotCatalog4229938_Placeable() []FactionInvasionSpot4229938 { // Catalog helper FactionInvasionSpotCatalog4229938_Placeable return nil } func FactionInvasionSpotCatalog4229938_ByEventId(eventId int32) *FactionInvasionSpot4229938 { // Catalog helper FactionInvasionSpotCatalog4229938_ByEventId return nil }