From baa93ce92c439527ac2ae01db9726d53a225490a Mon Sep 17 00:00:00 2001 From: wtclaude Date: Mon, 5 Oct 2026 19:51:19 -0500 Subject: [PATCH] docs(runicnpc): stage 7 spike, measured on both rigs The corpse is filled in OnCorpsePopulate (ApplyLoot is protected on Oxide and public on Carbon, so no one override fits both); Rust's crates spawn empty with their loot off; a locked crate's timer is its starting count; a corpse's time is ResetRemovalTime. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY --- runicnpc/PLAN.md | 51 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/runicnpc/PLAN.md b/runicnpc/PLAN.md index c01da08..8066751 100644 --- a/runicnpc/PLAN.md +++ b/runicnpc/PLAN.md @@ -1356,6 +1356,57 @@ The org lead's answers on 2026-10-05 are D290–D299. **It is one stage, opening **Tested by** harness kills whose corpses and crates are read back, 100 times each, against the table's chances and the pool's cap; and a walk on both rigs. +**Measured (2026-10-05, `tools/RunicNpcTest.cs`: `rnt.spike7`).** Both rigs, on Rust 2634.289.1 (buildid +25681086), Oxide 2.0.7801 and Carbon 2.0.262, each checked against the latest first. 13 of 14 checks passed on each +rig; the fourteenth could not be run from outside our NPC (below). + +**1. The corpse (D290).** + +- **Today's corpse holds Rust's scientist loot, and the kit's clothing.** The main container gets the prefab's loot + slots (for example a salvaged hammer, tech parts, pistol and rifle ammunition and a bandage; on another kill only 12 + rifle ammunition). The clothing container holds what the NPC wore (the kit's burlap and boonie). Its belt and main + items (the revolver and its ammunition) are not in the corpse. Rust removes the corpse after **600 s**. +- **Both frameworks raise `OnCorpsePopulate(npc, corpse)` for our NPC**, once, after Rust filled the corpse. +- **A subclass cannot fill its own corpse on both frameworks.** Rust's `HumanNPC.ApplyLoot` is `protected` in + Oxide's assembly and `public` in Carbon's (Carbon publicises Rust's assembly), and an override cannot change a + member's access, so one source file cannot override it for both. `CopyInventoryToCorpse` is a read-only virtual + property, with the same risk. **So the build fills the corpse in `OnCorpsePopulate`:** it keeps or empties Rust's + loot, adds the kit's belt and main items for a kit start, then rolls the table. Emptying a corpse and filling it + there worked on both rigs (`scrap×150` alone). +- The kit start could not be measured from the harness, which cannot switch the property from outside. It is built + and tested in the build. + +**2. The crates (D292).** Each of Rust's four crates was spawned at a death spot with Rust's own loot switched off +before it spawned (`initialLootSpawn` false, no refresh), then filled: + +| Crate | Prefab | Slots | Rust's loot at spawn | Ours after | Refills | Gone when emptied | +|---|---|---|---|---|---|---| +| Wooden box | `crate_normal_2` | 6 | none | scrap×200 | no | yes | +| Military crate | `crate_normal` | 6 | none | scrap×200 | no | yes | +| Elite crate | `crate_elite` | 12 | none | scrap×200 | no | yes | +| Locked crate | `codelockedhackablecrate` | 24 | none | scrap×200 | no | yes | + +A table larger than the crate's slots will not fit; the build says so on the profile. + +**3. The locked crate's timer (D297).** Rust's is one server-wide setting, `hackablelockedcrate.requiredhackseconds` +(900 s), and each crate counts its own seconds up to it. **Starting a crate's count where the profile's time +remains gives each crate its own timer:** asked 10 s, it unlocked after 11.5–12.1 s; asked 20 s, after +21.1–22.4 s (Rust ticks once a second). Asked longer than Rust's 900 s (1,800), the count starts below zero +(−898 after 3 s) and still unlocks on time; **what a player's screen shows for a count below zero is not known** +without a client, so the walk checks it. An unhacked locked crate is removed after Rust's own `decaySeconds` +(7,200 s). + +**4. Removing the corpse (D294).** `ResetRemovalTime(5)` removed it after 5.1–5.3 s; a corpse killed at once is gone. + +**What this sets for the build, with nothing to decide:** + +- The corpse is filled in `OnCorpsePopulate`, not by overriding Rust's members. +- A crate spawns with Rust's loot off and no refresh, and is filled with the table. +- The locked crate's timer is its starting count. +- A corpse's time is `ResetRemovalTime`, or it is killed at once. + +**Open for the walk:** a locked crate set longer than 15 minutes, as a player's screen shows it. + ### Stage 8 — On the map and in the app Event NPCs and bosses on the live map (protocol 11's `map.live`), a live "left: 3/8" on the event page, and the same