feat(rust): NPC profile and placement routes, the event picker, triggers and titles (runicnpc stage 4)
Admin: /admin/rust/npcs for profiles (create, change, delete, restore a replaced one, push now) and each server's placements (list, add from a map point, change, remove, rename, respawn). Public: the profiles a leaderboard ranks by, one profile's ranking counted as the profile says (D247, D250), and one player's kills by profile (D252). Player: your own kills by profile. The Place NPCs step offers the site's profiles first, then Rust's own (D243). rust.npc.died and rust.npc.health are triggers a phase can wait on. A title rule can rank a profile's kills. Swagger fragment, engagement and route manifests regenerated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
@@ -1114,6 +1114,140 @@ module.exports = {
|
||||
presets: { type: 'array', items: { $ref: '#/components/schemas/RustZonePreset' } },
|
||||
},
|
||||
},
|
||||
RustNpcProfileBody: {
|
||||
type: 'object',
|
||||
description: 'A RunicNPC profile as RunicNPC reads it (docs/runicnpc/API.md, D238). Anything left out takes RunicNPC’s default.',
|
||||
properties: {
|
||||
names: { type: 'array', items: { type: 'string' }, example: ['Warden', 'Old Warden'] },
|
||||
kits: { type: 'array', items: { type: 'string' }, example: ['warden_rifle'] },
|
||||
prefab: { type: 'string', example: 'scientistnpc_roam' },
|
||||
role: { type: 'string', enum: ['roamer', 'sentry'], example: 'roamer' },
|
||||
movement: { type: 'object', example: { mode: 'wander', radius: 20 } },
|
||||
health: { type: 'number', example: 250 },
|
||||
damageDealt: { type: 'number', example: 1 },
|
||||
damageTaken: { type: 'object', example: { head: 1, body: 1, legs: 1 } },
|
||||
aimCone: { type: 'number', example: 2 },
|
||||
ranges: { type: 'object', example: { sense: 30, loseTarget: 40, chase: 40, attack: 30 } },
|
||||
visionCone: { type: 'number', example: -0.8 },
|
||||
sleepDistance: { type: 'number', example: 160 },
|
||||
healthThresholds: { type: 'array', items: { type: 'number' }, example: [0.5] },
|
||||
},
|
||||
},
|
||||
RustNpcProfile: {
|
||||
type: 'object',
|
||||
description: 'A site NPC profile (docs/runicnpc/PLAN.md stage 4) for one server, several, or every server. `adoptedFrom` names the server it was read from on the site’s first push there (D244); `replaced` marks one kept aside because a site profile of its name was already on that server (D251). `killsScope` is how its kills are counted (D247).',
|
||||
properties: {
|
||||
id: { type: 'integer', example: 4 },
|
||||
name: { type: 'string', example: 'warden' },
|
||||
label: { type: 'string', example: 'Warden' },
|
||||
body: { $ref: '#/components/schemas/RustNpcProfileBody' },
|
||||
allServers: { type: 'boolean', example: false },
|
||||
servers: { type: 'array', items: { type: 'string' }, example: ['main'] },
|
||||
killsScope: { type: 'string', enum: ['server', 'name', 'profile'], example: 'server' },
|
||||
adoptedFrom: { type: 'string', nullable: true, example: null },
|
||||
replaced: { type: 'boolean', example: false },
|
||||
updatedAt: { type: 'string', format: 'date-time', nullable: true },
|
||||
},
|
||||
},
|
||||
RustNpcProfileInput: {
|
||||
type: 'object',
|
||||
required: ['name', 'body'],
|
||||
description: 'A profile to save. `servers` is required unless `allServers` is true. The name is RunicNPC’s: 1 to 40 of a-z, 0-9, _ and -.',
|
||||
properties: {
|
||||
name: { type: 'string', example: 'warden' },
|
||||
body: { $ref: '#/components/schemas/RustNpcProfileBody' },
|
||||
allServers: { type: 'boolean', example: false },
|
||||
servers: { type: 'array', items: { type: 'string' }, example: ['main'] },
|
||||
killsScope: { type: 'string', enum: ['server', 'name', 'profile'], example: 'server' },
|
||||
},
|
||||
},
|
||||
RustNpcs: {
|
||||
type: 'object',
|
||||
description: 'The NPC profiles page: each server with what it said about RunicNPC and what the last push did, every profile, the prefabs the form offers, the kill-counting scopes, and RunicNPC’s defaults.',
|
||||
properties: {
|
||||
servers: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string', example: 'main' },
|
||||
name: { type: 'string', example: 'Main · Vanilla' },
|
||||
enabled: { type: 'boolean', example: true },
|
||||
online: { type: 'boolean', nullable: true, example: true },
|
||||
runicNpc: { type: 'object', nullable: true, example: { loaded: true, version: '0.2.0', api: 3 } },
|
||||
ready: { type: 'boolean', example: true },
|
||||
absence: { type: 'string', nullable: true, example: null },
|
||||
sync: { type: 'object', nullable: true, example: { state: 'ok', adoptedAt: '2026-09-30T10:00:00.000Z', syncedAt: '2026-09-30T10:00:01.000Z', refused: {}, error: null } },
|
||||
},
|
||||
},
|
||||
},
|
||||
profiles: { type: 'array', items: { $ref: '#/components/schemas/RustNpcProfile' } },
|
||||
prefabs: { type: 'array', items: { type: 'string' }, example: ['scientistnpc_roam'] },
|
||||
killsScopes: { type: 'array', items: { type: 'string' }, example: ['server', 'name', 'profile'] },
|
||||
defaults: { $ref: '#/components/schemas/RustNpcProfileBody' },
|
||||
},
|
||||
},
|
||||
RustNpcPlacements: {
|
||||
type: 'object',
|
||||
description: 'One server’s placements, read live from it (D222), with the routes one may walk and the cost warning (D227).',
|
||||
properties: {
|
||||
placements: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string', example: 'warden-2' },
|
||||
placement: { type: 'object', example: { profile: 'warden', position: { x: 100, y: 12.5, z: -340 }, yaw: 90, count: 3, respawn: 300, respawnMode: 'each' } },
|
||||
alive: { type: 'integer', example: 3 },
|
||||
waiting: { type: 'string', nullable: true, example: null },
|
||||
note: { type: 'string', nullable: true, example: null },
|
||||
lastError: { type: 'string', nullable: true, example: null },
|
||||
},
|
||||
},
|
||||
},
|
||||
routes: { type: 'array', items: { type: 'string' }, example: ['gate'] },
|
||||
cost: { type: 'string', nullable: true, example: 'RunicNPC: 12 NPC(s) on this server…' },
|
||||
},
|
||||
},
|
||||
RustNpcPlacementInput: {
|
||||
type: 'object',
|
||||
required: ['profile'],
|
||||
description: '`/rnpc place`’s options (D246). To create, `position` is the clicked point, x and z only; to change, a whole x, y, z moves it, and none keeps its spot.',
|
||||
properties: {
|
||||
profile: { type: 'string', example: 'warden' },
|
||||
position: { type: 'object', example: { x: 100, z: -340 } },
|
||||
count: { type: 'integer', example: 3 },
|
||||
respawn: { type: 'number', example: 300 },
|
||||
respawnMode: { type: 'string', enum: ['each', 'group'], example: 'each' },
|
||||
movement: { type: 'object', nullable: true, example: { mode: 'route:gate', radius: 0 } },
|
||||
},
|
||||
},
|
||||
RustNpcBoardProfiles: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
profiles: { type: 'array', items: { type: 'object' }, example: [{ id: 4, name: 'warden', label: 'Warden', killsScope: 'server' }] },
|
||||
},
|
||||
},
|
||||
RustNpcLeaderboard: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
profile: { type: 'object', example: { id: 4, name: 'warden', label: 'Warden', killsScope: 'server' } },
|
||||
leaderboard: { type: 'array', items: { type: 'object' }, example: [{ steamId: '76561198000000002', name: 'Marisol', kills: 12, titles: [] }] },
|
||||
},
|
||||
},
|
||||
RustNpcPlayerKills: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
steamId: { type: 'string', example: '76561198000000002' },
|
||||
kills: { type: 'array', items: { type: 'object' }, example: [{ profile: 'warden', label: 'Warden', kills: 3 }] },
|
||||
},
|
||||
},
|
||||
RustNpcOwnKills: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
kills: { type: 'array', items: { type: 'object' }, example: [{ serverId: 'main', profile: 'warden', label: 'Warden', kills: 3 }] },
|
||||
},
|
||||
},
|
||||
RustVisibilityUpdate: {
|
||||
type: 'object',
|
||||
description: 'A change to who may see who is online. Either part may be omitted; a server set to null follows the fleet default again.',
|
||||
|
||||
Reference in New Issue
Block a user