package routers import ( "context" "sync" "time" ) var _ = sync.Mutex{} var _ = context.Background var _ = time.Now // // Light rail / metro scheduling. // The client owns the whole carriage simulation: MetroManager builds the carriages, drives them // along the baked MetroPath of a line and plays the gate/door animation. All the server has to do is // answer AskGetAllMetroInfos and then keep telling the client "train X of line Y has been running for // Z seconds" through SyncRunningMetroInfos - MetroClientInfo has no position field at all // (Id, LineId, ElapsedTime, IsFinalTrain). That is why this feature needs no client patch. // The schedule comes straight out of the client's own Rail*Config tables (RailLineConfig / // RailStopConfig / RailStationConfig), which the panel exposes as "where is the train, which stop is // it at, how long / how far until the next one". // Round 54 got the scheduling right but not the clock: see MetroDefaultTimeFactor for the round-55 fix. // // // 当前 raid 该推哪几条线。取 RaidConfig.LightRailLineIds // (23300888 = 1–4,23300999 = 9–14 + 15,23301227 = 5–8,23301271 = 1–4), // 取不到就落回 MetroDefaultLines。 // func GameRouter_Metro_MetroLinesForRaid(ctx context.Context, session *GameSession) []any { // Router implementation for GameRouter_Metro_MetroLinesForRaid return nil } // // raid 变了就把自动选的线换掉。手动模式(MetroSessionState.AutoRaidLines = false, // 即面板显式下发过 lines)**一个字都不动**,免得和用户手选打架。 // 返回 true = 这次真的换过了,调用方负责打日志。 // func GameRouter_Metro_SyncMetroLinesToRaid(ctx context.Context, session *GameSession, owner any, force bool) bool { // Router implementation for GameRouter_Metro_SyncMetroLinesToRaid return true } // ---------------------------------------------------------------- state func GameRouter_Metro_TryGetMetroState(ctx context.Context, session *GameSession) any { // Router implementation for GameRouter_Metro_TryGetMetroState var zero any; return zero } func GameRouter_Metro_GetMetroState(ctx context.Context, session *GameSession) any { // Router implementation for GameRouter_Metro_GetMetroState var zero any; return zero } func GameRouter_Metro_EnsureMetroLoop(ctx context.Context, session *GameSession, owner any) any { // Router implementation for GameRouter_Metro_EnsureMetroLoop var zero any; return zero } // ---------------------------------------------------------------- protocol // // The scene asks once per load, with no arguments, and expects the list of metros currently // running. Everything before round 54 answered with the typed-default empty list, which is why no // carriage ever appeared. // func GameRouter_Metro_AskGetAllMetroInfos(ctx context.Context, conn any, msg any) any { // Router implementation for GameRouter_Metro_AskGetAllMetroInfos var zero any; return zero } func GameRouter_Metro_BuildMetroInfos(ctx context.Context, owner any) []any { // Router implementation for GameRouter_Metro_BuildMetroInfos return nil } func GameRouter_Metro_BuildMetroTrackSegments(ctx context.Context, ) []any { // Router implementation for GameRouter_Metro_BuildMetroTrackSegments return nil } // 点到轨道折线的最近距离(米)。段数为几十,每拍算一次开销可忽略。 func GameRouter_Metro_DistanceToMetroTrack(ctx context.Context, px float64, py float64, pz float64) float64 { // Router implementation for GameRouter_Metro_DistanceToMetroTrack return 0 } // // 玩家是否看得见列车。拿不到坐标时返回 true(按近处处理),宁可多推也不牺牲画面。 // func GameRouter_Metro_IsPlayerNearMetroTrack(ctx context.Context, session *GameSession, metres float64) bool { // Router implementation for GameRouter_Metro_IsPlayerNearMetroTrack return true } func GameRouter_Metro_MetroLineSummary(ctx context.Context, owner any) string { // Router implementation for GameRouter_Metro_MetroLineSummary return "" } // ---------------------------------------------------------------- the loop func GameRouter_Metro_RunMetroLoopAsync(ctx context.Context, session *GameSession, owner any, token context.Context) any { // Router implementation for GameRouter_Metro_RunMetroLoopAsync var zero any; return zero } func GameRouter_Metro_TickMetroAsync(ctx context.Context, session *GameSession, owner any, token context.Context) any { // Router implementation for GameRouter_Metro_TickMetroAsync var zero any; return zero } // ---------------------------------------------------------------- panel API // // Read-only snapshot for the web panel: the whole catalog plus, for every running train, the stop // it is calling at, the next stop, and the remaining time / straight-line distance to it. // func GameRouter_Metro_MetroStatus(ctx context.Context, session any) any { // Router implementation for GameRouter_Metro_MetroStatus var zero any; return zero } func GameRouter_Metro_MetroCatalogView(ctx context.Context, enabled []any) []any { // Router implementation for GameRouter_Metro_MetroCatalogView return nil } func GameRouter_Metro_MetroTrainView(ctx context.Context, owner any, stoppedSeconds int32) []any { // Router implementation for GameRouter_Metro_MetroTrainView return nil } func GameRouter_Metro_StopName(ctx context.Context, stop any) string { // Router implementation for GameRouter_Metro_StopName return "" } // // Where the train is between two platforms. The stop tables only carry arrival times, so the fill // is a straight line between the two station anchors scaled by the remaining fraction of the leg - // good enough for a status readout, and it is the same information the client itself animates from. // Null when the line has no station anchors (the depot ends of the ring, or the test paths). // func GameRouter_Metro_MetroInterpolate(ctx context.Context, progress any) any { // Router implementation for GameRouter_Metro_MetroInterpolate var zero any; return zero } func GameRouter_Metro_SetMetroEnabled(ctx context.Context, session any, enabled bool) any { // Router implementation for GameRouter_Metro_SetMetroEnabled var zero any; return zero } // // Panel update of the dispatcher. null keeps the current selection (that is // how the panel changes only the push period or the time factor), an empty list turns every line off. // func GameRouter_Metro_ConfigureMetroLines(ctx context.Context, session any, lines []any, pushMs any, timeFactor any, auto any) any { // Router implementation for GameRouter_Metro_ConfigureMetroLines var zero any; return zero } func GameRouter_Metro_StopMetro(ctx context.Context, session any) any { // Router implementation for GameRouter_Metro_StopMetro var zero any; return zero } type MetroSessionState struct { SyncRoot any `json:"syncRoot"` // Master switch. When false the loop idles without stopping, so nothing has to restart. Enabled bool `json:"enabled"` // Push cadence in milliseconds. PushMs int32 `json:"pushMs"` // Multiplier applied to the timetable second before it goes out as ElapsedTime (see MetroDefaultTimeFactor). TimeFactor float64 `json:"timeFactor"` // Lines currently being pushed. Lines []uint32 `json:"lines"` // // 线路跟随当前 raid(RaidConfig.LightRailLineIds)自动切换。 // 面板一旦显式下发 lines 就置 false —— 之后不再自动改,避免和用户手选打架; // 要切回自动,面板走 auto: true。 // AutoRaidLines bool `json:"autoRaidLines"` // 上次自动选线时用的 raid。只在它变化时才重建 Lines。 AutoRaidId uint32 `json:"autoRaidId"` // // The scene has actually asked for the metro list at least once. Pushes stay silent until then: // the client only has its MetroPaths after it has loaded the scene, so an early // SyncRunningMetroInfos could reach a half-built MetroManager. // Requested bool `json:"requested"` // // 上一拍玩家是否处在轨道附近。只用来在切换时打一条日志,避免在控制台刷屏。 // 初值 true = 还没拿到玩家坐标时按"近处"处理,不牺牲画面。 // NearTrack bool `json:"nearTrack"` // Seconds of service folded away by a previous stop, so a restart does not jump the trains. OffsetSeconds float64 `json:"offsetSeconds"` StartedUtc time.Time `json:"startedUtc"` Cts *context.CancelFunc `json:"cts"` Loop *any `json:"loop"` Ticks int64 `json:"ticks"` Pushes int64 `json:"pushes"` TrainsSent int64 `json:"trainsSent"` LastPushUtc time.Time `json:"lastPushUtc"` LastError *string `json:"lastError"` ElapsedSeconds float64 `json:"elapsedSeconds"` } type MetroPoint struct { X float64 `json:"x"` Y float64 `json:"y"` Z float64 `json:"z"` }