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
Ananta-ps/internal/catalogs/metro_carriage_catalog4229938.go
T

93 lines
3.5 KiB
Go

package catalogs
import (
"encoding/json"
"os"
"path/filepath"
"sync"
)
var _ = json.RawMessage{}
var _ = sync.Mutex{}
var _ = os.ReadFile
var _ = filepath.Join
//
// Reads the carriage composition of every metro train out of the two rail config tables the
// client already ships: RailLineConfig.json (lineId -> TrainTemplateId) and
// RailTrainConfig.json (templateId -> CarriageIds).
// Why the server needs this at all — see GameRouter's OnAskMetroGadgetIds: the client
// builds each LightRail prefab itself (LightRail_4_405/carriage0|1|2/Seats/Gadgets_888_LightRailChair*)
// and then asks the server which gadget instance ids belong to that train. Verified 2026-09-23 by
// frida dump of a live train:
// carriage0 = 4 seats, carriage1 = 6 seats (the injected ids only stuck on carriage1 back when we
// answered one flat count for every carriage) — the client matches InnerGadgetIds index-for-index
// against the carriage's own seat slots, so the answer must be one entry per carriage, each with
// exactly that carriage's seat count.
// The mapping metroId -> line comes from the ids the client asks with: 103/104/105 are line 1 trains,
// 205/206/207 are line 2, 304 line 3, 400/405 line 4 — i.e. lineId = metroId / 100.
// Composition per line (build 4229938):
// line 1/2 (Bayshore, template 1 LightRailVehicle01) -> [10, 2, 2, 2, 3]
// line 3 (Central, template 2 LightRailVehicle01) -> [11, 7, 7, 7, 8]
// line 4 (East, template 3 LightRailVehicle03) -> [4, 5, 9] <- the one we dumped
// line 5-8 (test) template 4 LightRailVehicle01 -> [10]
// line 9-14 (1/2/3号线 上下行, template 5 CX01) -> [12, 13, 13, 13, 14]
// line 15 (画舫 TourBoat01, template 6) -> [15]
// Seat counts per carriage template are NOT in any config (they live in the prefab), so they are a
// knob on MetroGadgetSettings — seed it from the in-game dump.
//
var (
MetroCarriageCatalog4229938_cacheLock sync.RWMutex
MetroCarriageCatalog4229938_cached = false
MetroCarriageCatalog4229938_entries []any
)
// LoadMetroCarriageCatalog4229938 loads catalog records from client config directory
func LoadMetroCarriageCatalog4229938(configDir string) ([]any, error) {
MetroCarriageCatalog4229938_cacheLock.RLock()
if MetroCarriageCatalog4229938_cached {
defer MetroCarriageCatalog4229938_cacheLock.RUnlock()
return MetroCarriageCatalog4229938_entries, nil
}
MetroCarriageCatalog4229938_cacheLock.RUnlock()
MetroCarriageCatalog4229938_cacheLock.Lock()
defer MetroCarriageCatalog4229938_cacheLock.Unlock()
if MetroCarriageCatalog4229938_cached { return MetroCarriageCatalog4229938_entries, nil }
filePath := filepath.Join(configDir, "MetroCarriageCatalog.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)
}
}
MetroCarriageCatalog4229938_entries = result
MetroCarriageCatalog4229938_cached = true
return result, nil
}
//
// Carriage template ids of one train, in carriage order (index 0 = the client's carriage0).
// False when the metroId does not resolve to a known line/template.
//
func MetroCarriageCatalog4229938_TryGetCarriageTemplates(metroId int32, carriageTemplates []int32) bool {
// Catalog helper MetroCarriageCatalog4229938_TryGetCarriageTemplates
return false
}