package routers import ( "context" "sync" ) var _ = sync.Mutex{} var _ = context.Background // // Gang territory enemies at their authored city corners — the enemy counterpart of // GameRouter.FunctionalNpc (which does the same follow loop for shop clerks). // Where the positions come from is the interesting part, because the enemy tables have none: // EnemyCatalog.json is a pure template table. The only authored enemy coordinates in the // whole dump live in the faction influence system — FactionInfluenceAreaConfig (24 turfs, // each a FactionId plus the point ids it owns) × FactionAreaPointConfig (85 points, 2D). // Together they answer "which gang stands on which street corner", which is exactly the "put // bodies where they belong" placement. See EnemyTerritorySpotCatalog4229938. // What they DO once they exist is not decided here. The spawn goes through // GameAdminBridge.SpawnAgentAsync, the same path the admin panel's 生成敌人 button uses: // it sets forbidAetherAI = true, so the client's own behaviour tree takes the unit over the // moment it appears — idle, then whatever its tree does when the player gets close. That is why // they do NOT stroll along the pavement like ambient peds (which the server drives with // SyncLogicAgentCommand): this path has no server-side walking at all. // Two ways in, one placement helper: // • the follow loop (EnsureEnemyTerritory) — walk into a turf and its gang is // already standing there; // • the panel button (SpawnEnemyTerritoryAsync) — "put the nearby ones down now". // func GameRouter_EnemyTerritory_EnemyTerritoryStateOf(ctx context.Context, session *GameSession) any { // Router implementation for GameRouter_EnemyTerritory_EnemyTerritoryStateOf var zero any; return zero } // World-ready hook: start the follow loop. Idempotent; no-op when disabled. func GameRouter_EnemyTerritory_EnsureEnemyTerritory(ctx context.Context, session *GameSession) any { // Router implementation for GameRouter_EnemyTerritory_EnsureEnemyTerritory var zero any; return zero } // Disconnect / scene switch: stop the loop. The client clears the entities itself. func GameRouter_EnemyTerritory_StopEnemyTerritory(ctx context.Context, session *GameSession) any { // Router implementation for GameRouter_EnemyTerritory_StopEnemyTerritory var zero any; return zero } // How many territory enemies the follow loop currently has standing. Panel display only. func GameRouter_EnemyTerritory_EnemyTerritoryActiveCount(ctx context.Context, session *GameSession) int32 { // Router implementation for GameRouter_EnemyTerritory_EnemyTerritoryActiveCount return 0 } func GameRouter_EnemyTerritory_RunEnemyTerritoryLoopAsync(ctx context.Context, session *GameSession, owner any, token context.Context) any { // Router implementation for GameRouter_EnemyTerritory_RunEnemyTerritoryLoopAsync var zero any; return zero } func GameRouter_EnemyTerritory_TickEnemyTerritoryAsync(ctx context.Context, session *GameSession, owner any, cfg any) any { // Router implementation for GameRouter_EnemyTerritory_TickEnemyTerritoryAsync var zero any; return zero } // // Puts <count> members of one turf on the ground. // Where they go comes from EnemyTerritorySpot4229938.Members, and that list is // the whole point of the 2026-09-24 rework: the authored turf point is the corner of the // influence polygon, i.e. the middle of the intersection (measured: median 12.0 m from the // nearest pavement spot). Standing bodies there read as "traffic cone". The generator now // moves the whole group onto CivilianDistricts pavement spots near the turf point, preferring // the ones with 2-4 neighbours (an alley edge) over 7+ (a plaza/crossroads), and the members // face the group centroid so they read as a knot of people rather than a firing line. // The old ring-around-the-point placement is kept as a fallback for a JSON without "members" // — it is worse, but it is better than standing on the road. // func GameRouter_EnemyTerritory_PlaceTerritoryGroupAsync(ctx context.Context, session *GameSession, owner any, spot any, count int32, engage bool) any { // Router implementation for GameRouter_EnemyTerritory_PlaceTerritoryGroupAsync var zero any; return zero } func GameRouter_EnemyTerritory_RemoveTerritoryEnemyAsync(ctx context.Context, session *GameSession, owner any, id uint64) any { // Router implementation for GameRouter_EnemyTerritory_RemoveTerritoryEnemyAsync var zero any; return zero } // // Drops a retired unit out of the enemy ledger. SpawnAgentAsync registered it so its hits are // settled; leaving the entry behind would keep the attack AI driving a unit that no longer // exists, and the death-clear / groggy timers would fire into the void. // func GameRouter_EnemyTerritory_ForgetTerritoryEnemy(ctx context.Context, session *GameSession, uid uint64) any { // Router implementation for GameRouter_EnemyTerritory_ForgetTerritoryEnemy var zero any; return zero } // // Panel button: stock every turf within <radius> of the player (radius <= 0 = a 90 m // default), nearest first. Turfs already stocked are skipped. // func GameRouter_EnemyTerritory_SpawnEnemyTerritoryAsync(ctx context.Context, session *GameSession, radius float32) any { // Router implementation for GameRouter_EnemyTerritory_SpawnEnemyTerritoryAsync var zero any; return zero } type EnemyTerritorySessionState 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]EnemyTerritorySpot4229938 `json:"active"` // Point ids already stocked this scene; a change of raid wipes them. Stocked []uint32 `json:"stocked"` Raid uint32 `json:"raid"` }