115 lines
5.7 KiB
Go
115 lines
5.7 KiB
Go
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"`
|
|||
|
|
}
|
|||
|
|
|