docs(runicnpc): stage 7 spike, measured on both rigs; D300–D301 #319
@@ -120,6 +120,8 @@ architectural or design decision is implemented.
|
||||
| **D297** | **The locked crate's hack timer is the profile's**, Rust's own 15 minutes by default (stage 7). | Always Rust's 15 minutes. |
|
||||
| **D298** | **On a server with no website, a loot table is edited in the data file** (`data/RunicNPC/profiles.json`) and read again with `rnpc.reload`. No new in-game commands (stage 7). | `rnpc.loot` verbs; JSON through `rnpc.profile set`. |
|
||||
| **D299** | **Stage 7 is one stage, opening with a spike on both rigs, walked once end to end**, as stages 5 and 6 were (D253, D282) (stage 7). | 7a (the table and corpse) and 7b (the crates), each walked and merged before the next. |
|
||||
| **D300** | **A corpse that starts with "nothing" (D290) is truly empty:** the clothes the NPC wore come off too, so it lies unclothed and holds nothing until its table is added (stage 7 build). | Keep the worn clothes, as on any Rust corpse. |
|
||||
| **D301** | **A dropped crate stays until it is emptied**, as Rust's own crates do. The locked crate still removes itself after Rust's own time unhacked (7,200 s) (stage 7 build). | The profile sets how long an unopened crate stays, 30 minutes by default. |
|
||||
|
||||
**Borrowing, not copying.** NpcSpawn states no licence at all, so its source grants us nothing and is read only as a
|
||||
description of *what* can be done in Rust. HumanNPC is MIT on uMod, which is GPL-compatible, but §1.2 rules out its
|
||||
@@ -1356,6 +1358,62 @@ 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.
|
||||
|
||||
**The build's own questions, answered by the org lead on 2026-10-05 (D300, D301):**
|
||||
|
||||
1. **A "nothing" corpse and the clothes it wore. → D300:** truly empty, clothes too.
|
||||
2. **How long an unopened crate lasts. → D301:** until it is emptied, as Rust's crates do.
|
||||
|
||||
### 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
|
||||
|
||||
Reference in New Issue
Block a user