Expose live mod actors and difficulty and support dense event queries
This commit is contained in:
1 parent
287b324e62
commit
93ea7064ba
10 files changed
+302
-11
No files matched your search
+2
-2
@@ -159,7 +159,7 @@ fn on_fire(event, state, random) {
|
||||
| `on_mission_start` | Mission: `tick = 0`. Runs when the first simulation step dispatches events. |
|
||||
| `on_mission_end` | Mission: `success`, `tick`. |
|
||||
|
||||
Every dispatched event also includes `tick`, `player`, `entities`, `projectiles`, `pickups` and `objectives`. `player` is a snapshot including position, velocity, shields, credits, inventory and selected equipment. `entities` is the current enemy array; each entry includes `entity`, `definition`, position, `width`, `height`, health, animation, movement state and the definition's `ground` boolean. Filter on `ground` when an attack affects only airborne or ground targets. Projectiles and pickups likewise carry stable entity IDs. These are read-only snapshots: return commands to change the simulation. Later callbacks in a tick can observe commands committed by earlier callbacks. Events raised by commands, such as a spawned enemy, are dispatched in subsequent batches of the same tick, within the 8,192-event limit. Rejected command batches report the mod, script path and callback, and roll back that simulation step and script state.
|
||||
Every World-dispatched event also includes `tick`, `difficulty`, `actor`, `player`, `entities`, `projectiles`, `pickups` and `objectives`. `difficulty` is the active World difficulty as an integer: `0` Training, `1` Rookie, `2` Veteran, `3` Elite. It is supplied centrally at dispatch for every hook, including events raised by commands; scripts can use it to select their own patterns. It does not change spawn difficulty gates or add a command that changes difficulty. Pilot saves retain difficulty alongside script state and RNG; recreating a mission from that pilot supplies the restored difficulty to its callbacks. `actor` is the addressed enemy's current snapshot, with exactly the same fields as its `entities` entry, including `ground`. It is `null` for mission callbacks, player entity `0`, nonenemy addresses and enemies already removed. A zero-health enemy still present in the World has an actor snapshot with `health = 0`; scripts should check presence and health before issuing commands. The actor is resolved when the callback dispatches, so it reflects movement, damage or removal committed by earlier callbacks; event-local `x`, `y` or `health` can still describe the earlier queued event. Scripts can read `event.actor` directly instead of scanning `event.entities` for themselves. This reuses the existing enemy-snapshot traversal and does not add another enemy scan or change the cost of constructing `entities`. `player` is a snapshot including position, velocity, shields, credits, inventory and selected equipment. `entities` is the current enemy array; each entry includes `entity`, `definition`, position, `width`, `height`, health, animation, movement state and the definition's `ground` boolean. Filter on `ground` when an attack affects only airborne or ground targets. Projectiles and pickups likewise carry stable entity IDs. These are read-only snapshots: return commands to change the simulation. Later callbacks in a tick can observe commands committed by earlier callbacks. Events raised by commands, such as a spawned enemy, are dispatched in subsequent batches of the same tick, within the 8,192-event limit. Rejected command batches report the mod, script path and callback, and roll back that simulation step and script state.
|
||||
|
||||
Use `behavior: "scripted"` for hitscan, chain lightning, proximity zaps or other attacks implemented entirely with commands. Player selection, firing input and weapon cooldowns still apply. An owned item with `special: false` fires its weapon alongside other ordinary equipment when Fire is held; `special: true` makes it selectable. Neither player nor enemy scripted weapons receive a default engine projectile. A script may explicitly emit `projectile`, or pair `damage` with `arc` for an immediate visible discharge. `target` describes the weapon's capability for the shop and governs explicit projectiles; scripts must enforce the intended targets and range for their own `damage` commands.
|
||||
|
||||
@@ -216,7 +216,7 @@ Lightning arcs render in both SD and HD using irregular fractal channels, thin t
|
||||
|
||||
`anchor` attaches the starting endpoint, and `to_anchor` independently attaches the destination. Supply absolute world coordinates at creation; each endpoint preserves its offset from the anchor's top-left `x/y` origin as the ship moves. Omitting an anchor keeps that endpoint fixed. Both anchors may be `0` to make a ring segment follow the player, or use `anchor: 0` and `to_anchor: enemy.entity` for a ship-to-ship bolt. Anchor IDs must exist when the command runs; a missing anchor rejects the batch. Endpoints update after simulation movement and API movement commands, and freeze at their last position when the anchored enemy disappears. Cosmetic coordinates clamp to ±32,768 when an attached ship moves beyond those bounds.
|
||||
|
||||
Rhai uses an explicit package allowlist for arithmetic, strings, collections, iteration and function helpers. The default language/time packages are excluded, so wall-clock timestamps and native `sleep` cannot be reached, including through function pointers. There are no exposed filesystem, network or OS interfaces. Dynamic `eval` and imports are disabled. Limits are 100,000 operations per callback and a shared 500,000-operation budget per simulation tick; 32 call levels; expression depths of 64/32; arrays of 4,096 entries; maps of 1,024 entries; strings of 16 KiB; 256 commands per callback; and 64 KiB of serialized state per script. See the [Rhai execution-limit API](https://docs.rs/rhai/latest/rhai/struct.Engine.html) for the underlying engine controls. Scripts cannot increase these limits.
|
||||
Rhai uses an explicit package allowlist for arithmetic, strings, collections, iteration and function helpers. The default language/time packages are excluded, so wall-clock timestamps and native `sleep` cannot be reached, including through function pointers. There are no exposed filesystem, network or OS interfaces. Dynamic `eval` and imports are disabled. Limits are 100,000 operations per callback and a shared 500,000-operation budget per simulation tick; 32 call levels; expression depths of 64/32; arrays of 4,096 entries; object maps with at most 16,384 aggregate properties across their nested map tree; strings of 16 KiB; 256 commands per callback; and 64 KiB of serialized state per script. See the [Rhai execution-limit API](https://docs.rs/rhai/latest/rhai/struct.Engine.html) for the underlying engine controls. [Rhai counts nested properties recursively](https://rhai.rs/book/safety/max-map-size.html), so the map bound accommodates complete enemy/projectile snapshots rather than only a map's top-level fields. The separate 64 KiB serialized callback-state and command/operation bounds remain unchanged. Scripts cannot increase these limits.
|
||||
|
||||
## Saves and compatibility
|
||||
|
||||
|
||||
@@ -15,6 +15,14 @@ Receipts for this one-picture append are in
|
||||
`.reference/hd-root-next-publication-after5339/`; immutable intake is
|
||||
`handoff-5340-20261017`.
|
||||
|
||||
The included Linux and Windows runtimes now expose active script difficulty and
|
||||
current enemy snapshots. A finite 16,384-property Rhai map limit fixes documented
|
||||
queries failing on ordinary enemy groups; operation, command and 64 KiB saved-state
|
||||
limits remain unchanged. All 45 modding regression tests pass. Three actual 1080p
|
||||
SDL captures (menu, S1 Wave 7, S3 Wave 9) match the previous binary byte for byte.
|
||||
Windows cross-build, PE imports and shared-data verification pass; this source
|
||||
revision still needs its own native Windows CI result.
|
||||
|
||||
Iron Coast retuning is active in `.reference/campaign-retune-20261017/`.
|
||||
The baseline covers all 27 original and 14 mod missions at all four difficulties.
|
||||
Mission waves, enemy movement, bosses and weapon presentation are being validated
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
# Rust engine and validation
|
||||
|
||||
## 17 October 2026: live mod snapshots and dense-event queries
|
||||
|
||||
World callbacks now receive `difficulty` and the addressed enemy's current `actor`
|
||||
snapshot, including damage, movement and removal committed by earlier callbacks.
|
||||
Dense enemy snapshots exposed Rhai's recursive map limit: even an ordinary query
|
||||
could reject a 24-enemy event. The bounded limit is now 16,384 properties; existing
|
||||
operation, command and serialized-state limits remain unchanged.
|
||||
|
||||
All 45 modding tests pass, including all four difficulties, save/RNG continuation,
|
||||
stale callbacks, 64-enemy queries and oversized intermediate/output rejection.
|
||||
Linux and Windows executables are rebuilt. Menu and two original-mission 1080p
|
||||
SDL captures are byte-identical across the change (6,220,800 pixels compared).
|
||||
Windows execution is verified separately by the post-push native workflow.
|
||||
|
||||
Rust is the default engine. The Rust binary never calls or embeds the C++ engine. SDL2 provides window/input/controller/audio services. Simulation and the validation CLI build without SDL2. The retained C++ checkout is optional reference material.
|
||||
|
||||
| Module | Responsibility |
|
||||
|
||||
Reference in new issue
Block a user