feat: stage 2, the NPC and its API (API 2)
All checks were successful
PR Checks / plugin-checks (pull_request) Successful in -1m38s
All checks were successful
PR Checks / plugin-checks (pull_request) Successful in -1m38s
RunicNPC now spawns its own NPC: Rust's scientist with its ScientistNPC and ScientistBrain swapped for ours, copying a fixed field list generated from Rust's unmodified assembly (D232, tools/fieldlist). Profiles live in data/RunicNPC/profiles.json in the approved shape (D238); placements persist with each/group respawn (D236) and wait for a missing profile or route (D237); roamers wander, follow Rust's monument paths, or walk a route (D233, D234), with our own chase where Rust's needs an AI zone; sentries hold their spot; NPCs walk home and sleep past 160 m of any player (D235). Spawns wait for the navmesh and are spread over frames; caps are off by default and the cost warning is shown instead (D227). The whole PLAN.md section 4 API and its hooks are in, documented in docs/runicnpc/API.md. tools/RunicNpcTest.cs is the stage 2 harness; every group passed on both rigs, and after a plugin reload and a server restart. checkPlugin no longer counts an override (RunicNpcPlayer.OnDied) as a hook. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
@@ -126,6 +126,25 @@ test('a method that is not shaped like a hook is left alone', () => {
|
||||
assert.ok(HOOK_NAME.test('CanBeTargeted'))
|
||||
})
|
||||
|
||||
test('an override shaped like a hook belongs to the NPC classes, not the framework, and is left alone', () => {
|
||||
const methods = ` private void OnServerInitialized()
|
||||
{
|
||||
}
|
||||
|
||||
public class RunicNpcPlayer : ScientistNPC
|
||||
{
|
||||
public override void OnDied(HitInfo info)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnStateChanged()
|
||||
{
|
||||
}
|
||||
}`
|
||||
|
||||
assert.deepEqual(check(source({ methods }), toml()), [])
|
||||
})
|
||||
|
||||
// ── The API ────────────────────────────────────────────────────────────────
|
||||
|
||||
test('a public API call without [HookMethod] is caught, because Call cannot reach it', () => {
|
||||
@@ -287,12 +306,13 @@ test('the parser actually reads the real plugin, rather than quietly matching no
|
||||
|
||||
// Raise these floors as the plugin grows; they are what stops a regex that
|
||||
// matches nothing from passing every case above.
|
||||
assert.ok(methods.length >= 5, `only found ${methods.length} methods in the real plugin`)
|
||||
assert.ok(methods.length >= 40, `only found ${methods.length} methods in the real plugin`)
|
||||
assert.ok(names.has('OnServerInitialized'), 'OnServerInitialized was not found by the method parser')
|
||||
assert.ok(names.has('CmdStatus'), 'CmdStatus (under an attribute) was not found by the method parser')
|
||||
|
||||
const api = methods.filter((m) => API_NAME.test(m.name)).map((m) => m.name)
|
||||
assert.ok(api.includes('RunicNpc_ApiVersion'), 'RunicNpc_ApiVersion was not found as an API call')
|
||||
assert.ok(api.includes('RunicNpc_Spawn'), 'RunicNpc_Spawn was not found as an API call')
|
||||
|
||||
assert.ok(readExpectedHooks(real).length >= 1)
|
||||
assert.deepEqual(readRequires(real), ['Kits'])
|
||||
|
||||
Reference in New Issue
Block a user