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/gameserver/routers/game_router_functional_npc.go
T

121 lines
5.9 KiB
Go
Raw Normal View History

package routers
import (
"context"
"sync"
)
var _ = sync.Mutex{}
var _ = context.Background
//
// Fifth entity channel: functional NPCs at fixed city spots (shop clerks, ticket sellers, ...).
// Same four-step announce sequence as the citizen channels — this file does not invent a spawn
// path, it only supplies different coordinates. Instead of "a plot's pavement spots, how many
// decided by the hour" the positions are固定的: one per venue, already snapped onto pavement by
// the generator, so a shop clerk ends up where the shop actually is.
// What the NPC *does* is not our problem here: F-key behaviour (open a shop panel, buy a ticket,
// start a mahjong match) is driven entirely by the client's own lua through
// AgentConfig.InteractSetting. The server just has to put a body there. That is deliberate — it
// is the whole reason this card is cheap.
// Two ways in, sharing one placement helper so they can never disagree:
// • the follow loop (EnsureFunctionalNpcs) — how they normally appear: walk up to
// a shop and its clerk is standing there;
// • the panel button (SpawnFunctionalNpcsAsync) — "put them all down now".
//
func GameRouter_FunctionalNpc_FunctionalNpcStateOf(ctx context.Context, session *GameSession) any {
// Router implementation for GameRouter_FunctionalNpc_FunctionalNpcStateOf
var zero any; return zero
}
// World-ready hook: start the follow loop. Idempotent; no-op when disabled.
func GameRouter_FunctionalNpc_EnsureFunctionalNpcs(ctx context.Context, session *GameSession) any {
// Router implementation for GameRouter_FunctionalNpc_EnsureFunctionalNpcs
var zero any; return zero
}
// Disconnect / scene switch: stop the loop. The client clears the entities itself.
func GameRouter_FunctionalNpc_StopFunctionalNpcs(ctx context.Context, session *GameSession) any {
// Router implementation for GameRouter_FunctionalNpc_StopFunctionalNpcs
var zero any; return zero
}
// How many the follow loop currently has standing. Panel display only.
func GameRouter_FunctionalNpc_FunctionalNpcActiveCount(ctx context.Context, session *GameSession) int32 {
// Router implementation for GameRouter_FunctionalNpc_FunctionalNpcActiveCount
return 0
}
func GameRouter_FunctionalNpc_RunFunctionalNpcLoopAsync(ctx context.Context, session *GameSession, owner any, token context.Context) any {
// Router implementation for GameRouter_FunctionalNpc_RunFunctionalNpcLoopAsync
var zero any; return zero
}
func GameRouter_FunctionalNpc_TickFunctionalNpcsAsync(ctx context.Context, session *GameSession, owner any, cfg any) any {
// Router implementation for GameRouter_FunctionalNpc_TickFunctionalNpcsAsync
var zero any; return zero
}
func GameRouter_FunctionalNpc_RemoveFunctionalNpcAsync(ctx context.Context, session *GameSession, state any, owner any, id uint64, spot any) any {
// Router implementation for GameRouter_FunctionalNpc_RemoveFunctionalNpcAsync
var zero any; return zero
}
//
// ★★★ R93(2026-09-27)—— **落脚高度吸附**:把点位声明的 Y 换成「该 XZ 上真实地面/物件的高度」。
// 为什么必须做:FunctionalNpcSpots.json 的 Y 是用 CivilianDistricts 人行道点
// 反向找的(见该文件 note)。那套人行道点只在**主城平地**有数据,一旦点位的 XZ 落在
// **高台/庙会/室内**,找出来的就是别处(常常是 y≈0/2 那一层)的 Y。
// 实测标本(2026-09-27):Tea Shop Owner(40954014)/Tea Stall Owner(40954022) 声明 Y=2.00,
// 而同 XZ 上 2528 件场景物一律 **y≈166~172** ⇒ NPC 被生成在**地下 167 m**,
// 现象 = 用户所说的「摊位的npc呢」(看着像根本没刷,其实刷了、埋了)。
// 数据源 = config/scene_item_placements.json(mtime 热重载,4877 件带真实 y)。
// 取点位 XZ **半径 内最近的若干件**的 y 中位数当落脚高度:
// 中位数对「同一点位旁边既有台面又有地面」的情况比最近邻稳。
// 命中不到(荒地/新点位)⇒ **原样返回**,绝不猜。
//
func GameRouter_FunctionalNpc_SnapGroundY(ctx context.Context, x float32, y float32, z float32, samples int32, snapped float32, radius float32) float32 {
// Router implementation for GameRouter_FunctionalNpc_SnapGroundY
return 0
}
//
// One placement: announce + remember. Returns the entity id, or 0 when the spot's ids are not
// in the catalogs (a bad row in the json must not kill the batch).
//
func GameRouter_FunctionalNpc_PlaceFunctionalNpcAsync(ctx context.Context, session *GameSession, state any, owner any, spot any) uint64 {
// Router implementation for GameRouter_FunctionalNpc_PlaceFunctionalNpcAsync
return 0
}
//
// Panel button: place every functional NPC of the current scene (nearest first when a radius
// is given, radius <= 0 = the whole scene). Anything already standing is skipped.
//
func GameRouter_FunctionalNpc_SpawnFunctionalNpcsAsync(ctx context.Context, session *GameSession, radius float32, includeSemantic bool) any {
// Router implementation for GameRouter_FunctionalNpc_SpawnFunctionalNpcsAsync
var zero any; return zero
}
func GameRouter_FunctionalNpc_Distance2(ctx context.Context, spot any, x float32, z float32) float32 {
// Router implementation for GameRouter_FunctionalNpc_Distance2
return 0
}
type FunctionalNpcSessionState struct {
SyncRoot any `json:"syncRoot"`
Cts *context.CancelFunc `json:"cts"`
Loop *any `json:"loop"`
// entityId -> the spot it was placed for. Doubles as the "already placed" set.
Active map[uint64]FunctionalNpcSpot4229938 `json:"active"`
//
// Formwork ids whose placement has been started but not finished yet.
// ⛑ Placement awaits several network writes and happens OUTSIDE the lock, so a tick that
// starts while the previous batch is still in flight cannot see it in Active
// and would place the same clerk again — two identical NPCs stacked on one spot.
//
Pending []uint32 `json:"pending"`
// Scene the Active entries belong to; a change wipes them.
Raid uint32 `json:"raid"`
}