127 lines
5.6 KiB
Go
127 lines
5.6 KiB
Go
package routers
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
)
|
|
|
|
var _ = sync.Mutex{}
|
|
var _ = context.Background
|
|
|
|
//
|
|
// Playable characters standing in the city, each at whatever their own daily schedule says they
|
|
// are doing right now — Richie on the treadmill, Garm at the claw machine, and so on.
|
|
// Two reasons this file exists:
|
|
// 1. Official has them roaming from the start (the 趴卜 schedule tab and the big-map markers exist
|
|
// precisely so the player can go find them). We only ever materialised one at the moment the
|
|
// player switched <em>away</em> from that character, so walking to a schedule coordinate found
|
|
// nobody — which is exactly what the player reported on 09-25.
|
|
// 2. The client unloads distant units and never re-adds them by itself: coming back to a spot from
|
|
// far away shows an empty pavement until you switch the character away and back. So the server
|
|
// has to own the distance bookkeeping — place on enter, retire on exit, place again on return.
|
|
// That is not a new idea; it is the same follow-loop + hysteresis shape as
|
|
// GameRouter.EnsureFunctionalNpcs, only with different coordinates.
|
|
// Coordinates and the activity id come straight from the client's own tables
|
|
// (see NpcActivityCatalog4229938): nothing here is invented.
|
|
//
|
|
func GameRouter_RosterNpc_RosterNpcStateOf(ctx context.Context, session *GameSession) any {
|
|
// Router implementation for GameRouter_RosterNpc_RosterNpcStateOf
|
|
var zero any; return zero
|
|
}
|
|
|
|
// World-ready hook: start the follow loop. Idempotent; no-op when disabled.
|
|
func GameRouter_RosterNpc_EnsureRosterNpcs(ctx context.Context, session *GameSession) any {
|
|
// Router implementation for GameRouter_RosterNpc_EnsureRosterNpcs
|
|
var zero any; return zero
|
|
}
|
|
|
|
// Disconnect / scene switch: stop the loop. The client clears the entities itself.
|
|
func GameRouter_RosterNpc_StopRosterNpcs(ctx context.Context, session *GameSession) any {
|
|
// Router implementation for GameRouter_RosterNpc_StopRosterNpcs
|
|
var zero any; return zero
|
|
}
|
|
|
|
// How many are currently standing. Panel display only.
|
|
func GameRouter_RosterNpc_RosterNpcActiveCount(ctx context.Context, session *GameSession) int32 {
|
|
// Router implementation for GameRouter_RosterNpc_RosterNpcActiveCount
|
|
return 0
|
|
}
|
|
|
|
//
|
|
// ★ 切人接管时**立即**撤掉常驻摆在日程点上的那具身体(09-26 00:4x 加)。
|
|
// ⛑⛑ 为什么必须同步做:开了 SwitchToScheduleSpot 之后,玩家会直接瞬移到
|
|
// 角色的日程点位。而那个点位上常驻化很可能已经摆了一具同样的身体
|
|
// (他本来就「在城里过日子」)⇒ 瞬移过去就是「两个里希重叠」的老毛病(规则 166)。
|
|
// 常驻循环 1.5 秒才跳一次,等它自己撤(spirit == activeSpirit)中间那一秒玩家
|
|
// 就盯着两个自己 —— 所以切人时主动撤一次。
|
|
// ⛑ 撤不掉也不至于更糟:RemoveRosterNpcAsync 已经是 Leave+Aether 双发(规则 166)。
|
|
//
|
|
func GameRouter_RosterNpc_RetireRosterNpcForSwitchAsync(ctx context.Context, session *GameSession, spiritId uint32) bool {
|
|
// Router implementation for GameRouter_RosterNpc_RetireRosterNpcForSwitchAsync
|
|
return true
|
|
}
|
|
|
|
//
|
|
// spiritId -> unitId for everything currently on the field. The GM panel uses it to mark
|
|
// which rows are actually standing in the world right now (as opposed to merely scheduled).
|
|
//
|
|
func GameRouter_RosterNpc_RosterNpcPlacements(ctx context.Context, session *GameSession) map[string]any {
|
|
// Router implementation for GameRouter_RosterNpc_RosterNpcPlacements
|
|
return nil
|
|
}
|
|
|
|
func GameRouter_RosterNpc_RunRosterNpcLoopAsync(ctx context.Context, session *GameSession, owner any, token context.Context) any {
|
|
// Router implementation for GameRouter_RosterNpc_RunRosterNpcLoopAsync
|
|
var zero any; return zero
|
|
}
|
|
|
|
func GameRouter_RosterNpc_TickRosterNpcsAsync(ctx context.Context, session *GameSession, owner any, cfg any) any {
|
|
// Router implementation for GameRouter_RosterNpc_TickRosterNpcsAsync
|
|
var zero any; return zero
|
|
}
|
|
|
|
func GameRouter_RosterNpc_PlaceRosterNpcAsync(ctx context.Context, session *GameSession, state any, owner any, spiritId uint32, choice any, cfg any, mode string) any {
|
|
// Router implementation for GameRouter_RosterNpc_PlaceRosterNpcAsync
|
|
var zero any; return zero
|
|
}
|
|
|
|
func GameRouter_RosterNpc_RemoveRosterNpcAsync(ctx context.Context, session *GameSession, state any, owner any, spiritId uint32) any {
|
|
// Router implementation for GameRouter_RosterNpc_RemoveRosterNpcAsync
|
|
var zero any; return zero
|
|
}
|
|
|
|
func GameRouter_RosterNpc_Dist2(ctx context.Context, x float32, z float32, px float32, pz float32) float32 {
|
|
// Router implementation for GameRouter_RosterNpc_Dist2
|
|
return 0
|
|
}
|
|
|
|
//
|
|
// 目标点位 米内(3D)是否已经站着别的 NPC。
|
|
// 用 3D 是为了让「同一栋楼 1 楼和 2 楼各站一个」这种正常情况不误判 —— 只有真的贴在一起才算冲突。
|
|
//
|
|
func GameRouter_RosterNpc_Taken(ctx context.Context, x float32, y float32, z float32, poses []any, separation float32) bool {
|
|
// Router implementation for GameRouter_RosterNpc_Taken
|
|
return true
|
|
}
|
|
|
|
type RosterNpcSessionState struct {
|
|
SyncRoot any `json:"syncRoot"`
|
|
Cts *context.CancelFunc `json:"cts"`
|
|
Loop *any `json:"loop"`
|
|
// spiritId -> what was placed for it. Doubles as the "already placed" set.
|
|
Active map[uint32]RosterNpcPlacement `json:"active"`
|
|
// Scene the Active entries belong to; a change wipes them.
|
|
Raid uint32 `json:"raid"`
|
|
// 是否已经打过一次「名册里有多少人没有可落地活动」的诊断行(只打一次,别刷屏)。
|
|
Diagnosed bool `json:"diagnosed"`
|
|
}
|
|
|
|
type RosterNpcPlacement struct {
|
|
UnitId uint64 `json:"unitId"`
|
|
X float32 `json:"x"`
|
|
Y float32 `json:"y"`
|
|
Z float32 `json:"z"`
|
|
ActivityId uint32 `json:"activityId"`
|
|
}
|
|
|