@kradle/challenges-sdk 0.19.1 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -17,6 +17,32 @@ also hand-edit this file or the [Unreleased] section at any time.
17
17
 
18
18
  ## [Unreleased]
19
19
 
20
+ ## [0.21.0] - 2026-10-09
21
+
22
+ ### Added
23
+
24
+ - Status facts on a player and an entity. A player (`g.players[i]`) carries `effects` (the effect id to `{ level, duration }`, the duration in ticks, `-1` with no end), `fire`, `absorption`, `pose` (`sneaking`, `swimming`, `fall_flying`, `sleeping`...), `xp`, `air`, `sprinting` and `blocking`; an entity (`g.entities()`) carries `effects`, `fire`, `absorption`, `pose` and, for a mob that has them, `baby`, `tamed`, `owner`, `sitting` and `color`. Each field is present only while away from its default, and leaves the record when it is back at it (no effect, no fire, no absorption, `pose: "standing"`, no experience level, full air, a wild or untamed mob), so a rule reads `p.fire === true` or `"pose" in p`. No declaration is needed: the fields ride the samples the engine already sends.
25
+ - An inventory slot (`p.slots[i]`) and an equipped item (`p.equipment.main`) carry `components`: the command syntax of every component the stack changes from its item's defaults (`[minecraft:enchantments={minecraft:fire_aspect:2},minecraft:damage=12]`), the same string `g.give` accepts. An equipped item now carries the metadata of an inventory slot too (`name`, `lore`, `enchantments`, `damage`) beside `item`, `count` and the dyed `color`.
26
+ - In a test, `game.sample`, `game.other`, `game.spawnEntity` and `game.changeEntity` take the status fields of a player or a mob, and the metadata of `player.setInventory` takes `components`.
27
+
28
+ ### Changed
29
+
30
+ - `LLM_README.md` lists the status fields of a player and of an entity, and the metadata an inventory slot and an equipped item carry.
31
+ - The reference of `g.command` says that a relative coordinate (`~`) resolves from the server console's position, not from a player, so absolute coordinates stay the advice, and that under `execute as <player>` the `by` of a block change names that player. The 0.20.0 entry below says the same.
32
+
33
+ ## [0.20.0] - 2026-10-08
34
+
35
+ ### Added
36
+
37
+ - `g.clone(from, to, dest, { mode? })`: copies a box so that its low corner lands at `dest`, with the vanilla clone. `mode` is `replace` (the default), `masked` (the air of the source is skipped, cave air and void air included) or `move` (the source is left as air). The mirror copies the states it holds from the source to the destination, and `on.blocksChanged` gets one entry with the destination `box`, the source `from` and `cause: "clone"` (a move adds the source box as air, first, as the vanilla command clears it first). When a source block changed in the same tick, or the mirror does not hold the source, the change arrives block by block with `cause: "effect"` instead. The volume cap of a fill applies (32,768 blocks), and a move counts both boxes. `replace` and `masked` refuse an overlap of the two boxes; `move` accepts it and ends with the moved blocks.
38
+ - The clone entry of a `blocksChanged` payload declares `block` as `undefined`, so a handler that reads `c.block` on every entry still compiles.
39
+ - `g.command(cmd)` may run `fill`, `setblock` and `clone` with absolute coordinates (the engine reads the blocks a command names before it runs, so the mirror sees the change, one entry per block with `cause: "command"`; use absolute coordinates, because a `~` resolves from the server console's position, not from a player; under `execute as <player>`, the change's `by` names that player), `forceload` (a loaded chunk arrives as a fact) and `fillbiome` (the mirror holds no biome). `place`, `data` and `item ... block` stay refused.
40
+ - In a test, `game.cloneBlocks(from, to, dest, mode?)` reports a clone to the challenge.
41
+
42
+ ### Changed
43
+
44
+ - `LLM_README.md` names `g.clone` among the effects, records which commands `g.command` accepts, and says how a clone reaches `blocksChanged`; `README.md` names a clone beside a fill in the handler list.
45
+
20
46
  ## [0.19.1] - 2026-10-08
21
47
 
22
48
  ### Changed
@@ -301,7 +327,9 @@ also hand-edit this file or the [Unreleased] section at any time.
301
327
  - Voting primitives (`votedFor`, `promptVote`, `allVotesIn`, `assignDefaultVotes`) for challenges that use discuss-then-vote-then-act phases as an alternative to pad-based voting.
302
328
  - Build-time validation of vote IDs and options against `KRADLE_CHALLENGE_VOTING_OPTIONS` (when set), matching the existing `getLocation`/`setEndState` pattern. `promptVote` also validates each announced option against the declared `votingOptions`.
303
329
 
304
- [Unreleased]: https://github.com/Kradle-ai/challenges-sdk/compare/v0.19.1...HEAD
330
+ [Unreleased]: https://github.com/Kradle-ai/challenges-sdk/compare/v0.21.0...HEAD
331
+ [0.21.0]: https://github.com/Kradle-ai/challenges-sdk/compare/v0.20.0...v0.21.0
332
+ [0.20.0]: https://github.com/Kradle-ai/challenges-sdk/compare/v0.19.1...v0.20.0
305
333
  [0.19.1]: https://github.com/Kradle-ai/challenges-sdk/compare/v0.19.0...v0.19.1
306
334
  [0.19.0]: https://github.com/Kradle-ai/challenges-sdk/compare/v0.18.0...v0.19.0
307
335
  [0.18.0]: https://github.com/Kradle-ai/challenges-sdk/compare/v0.17.0...v0.18.0
package/LLM_README.md CHANGED
@@ -157,7 +157,7 @@ The steps register behavior and return the same challenge object. Use one chain
157
157
  | `pickup` | `{ player, item, count, at }` |
158
158
  | `inventory` | `{ player, item, count }`: a count changed. |
159
159
  | `blockPlaced`, `blockBroken`, `blockUsed` | `{ player, at, block: { id, props } }`; the mirror already shows the new state. |
160
- | `blocksChanged` | `{ changes }`: every block that changed this tick; a fill is one entry with its `box`. |
160
+ | `blocksChanged` | `{ changes }`: every block that changed this tick; a fill is one entry with its `box` and `block`, a clone one entry with its destination `box` and the source `from`. |
161
161
  | `container` | `{ at, block, items, changes, by?, removed }`: a container's contents changed. |
162
162
  | `zoneEntered`, `zoneLeft` | `{ player, zone }` |
163
163
  | `chat` | `{ player, text }` |
@@ -210,7 +210,7 @@ not in `say` or `tell`.
210
210
 
211
211
  **Scores and roster.** `g.setScore(player, n)`, `g.addScore(player, delta)` (refused when `outcome.scores` exists), `g.eliminate(player)`, `g.random.int(lo, hi)`, `g.random.pick(items)`, `g.random.shuffle(items)`, `g.random.weighted(items)`.
212
212
 
213
- **Effects.** `g.give(player, item, count?)` (`item` is an id or `{ id, count?, name?, lore?, enchantments?, damage?, components? }`; `components` is the raw item argument suffix such as `[enchantments={sharpness:1}]`, and a metadata field wins over the same component), `g.clear(player, item?, count?)`, `g.effect(player, { id, duration, amplifier? })`, `g.teleport(player, to)`, `g.kill(player)`, `g.gamemode(player, mode)`, `g.attribute(player, attribute, value)` (e.g. `minecraft:max_health`; no `generic.` prefix since Minecraft 1.21.2), `g.fill(from, to, block)`, `g.setBlock(at, block)` (`block` is an id or `{ id, props?, blockEntity? }`), `g.summon(entity, at, { nbt? })`, `g.killEntities(types?)`, `g.time(value)`, `g.gamerule(rule, value)` (`rule` is a Minecraft 1.21.11+ id such as `minecraft:keep_inventory`; the old camelCase names are refused), `g.setSpawn(at)`, `g.worldBorder({ center?, size?, over? })`, `g.container(at, items)`, `g.command(cmd)` (the escape hatch: gameplay commands only).
213
+ **Effects.** `g.give(player, item, count?)` (`item` is an id or `{ id, count?, name?, lore?, enchantments?, damage?, components? }`; `components` is the raw item argument suffix such as `[enchantments={sharpness:1}]`, and a metadata field wins over the same component), `g.clear(player, item?, count?)`, `g.effect(player, { id, duration, amplifier? })`, `g.teleport(player, to)`, `g.kill(player)`, `g.gamemode(player, mode)`, `g.attribute(player, attribute, value)` (e.g. `minecraft:max_health`; no `generic.` prefix since Minecraft 1.21.2), `g.fill(from, to, block)`, `g.setBlock(at, block)` (`block` is an id or `{ id, props?, blockEntity? }`), `g.clone(from, to, dest, { mode? })` (copies the box so that its low corner lands at `dest`; `mode` is `replace`, `masked` or `move`; at most 32,768 blocks; `replace` and `masked` refuse an overlap, `move` accepts it), `g.summon(entity, at, { nbt? })`, `g.killEntities(types?)`, `g.time(value)`, `g.gamerule(rule, value)` (`rule` is a Minecraft 1.21.11+ id such as `minecraft:keep_inventory`; the old camelCase names are refused), `g.setSpawn(at)`, `g.worldBorder({ center?, size?, over? })`, `g.container(at, items)`, `g.command(cmd)` (the escape hatch: gameplay commands, and `fill`, `setblock`, `clone` with absolute coordinates, `forceload`, `fillbiome`; the mirror reports what a world command changed, one entry per block).
214
214
 
215
215
  **Flow.** `g.startPhase(name)`, `g.endPhase()`, `g.endGame(endState?)`, `g.schedule(timer, after)`, `g.cancel(timer)`, `g.walk(player, to, { fallback? })`, `g.batch(name, fn)` (the effects inside `fn` go out as one named batch; `on.batchDone` reports).
216
216
 
@@ -220,13 +220,13 @@ Durations are `"35s"`, `"2m"`, `"40t"` or `seconds(35)` / `minutes(2)` / `ticks(
220
220
 
221
221
  ## Players and Entities
222
222
 
223
- A player (`g.players[i]`) carries the roster (`name`, `role`, `seatNumber`, `human`), the observations (`connected`, `alive`, `eliminated`, `isActive`, `deaths`, `kills`, `score`, `achievements`, `pos`, `yaw`, `pitch`, `headYaw`, `health`, `food`, `gamemode`, `held`, `slots`, `inventory`, `equipment`, `invisible`, `zones`) and its own `state`. The observations are read-only for a rule; `p.state` is the challenge's; the score changes through `g.setScore` / `g.addScore` or `outcome.scores`. `p.pos` is set from the initializers onward: a disconnected player keeps the last position.
223
+ A player (`g.players[i]`) carries the roster (`name`, `role`, `seatNumber`, `human`), the observations (`connected`, `alive`, `eliminated`, `isActive`, `deaths`, `kills`, `score`, `achievements`, `pos`, `yaw`, `pitch`, `headYaw`, `health`, `food`, `gamemode`, `held`, `slots`, `inventory`, `equipment`, `invisible`, `zones`, and the status fields that are present only while not at their default: `effects` (id to `{ level, duration }`, ticks, -1 no end), `fire`, `absorption`, `pose`, `xp`, `air`, `sprinting`, `blocking`) and its own `state`. A slot (`p.slots[i]`) and an equipped item (`p.equipment.main`) carry `id`/`item`, `count`, and the metadata that is set: `name`, `lore`, `enchantments`, `damage`, and `components`, the command syntax of every component the stack changes from its item's defaults (`[minecraft:potion_contents={potion:"minecraft:speed"}]`), the same string `g.give` accepts. The observations are read-only for a rule; `p.state` is the challenge's; the score changes through `g.setScore` / `g.addScore` or `outcome.scores`. `p.pos` is set from the initializers onward: a disconnected player keeps the last position.
224
224
 
225
225
  `p.role === "seeker"` narrows the player to that role's state. `g.playersWithRole("seeker")` is typed the same way.
226
226
 
227
227
  All non-player entities in the chunks Minecraft loads are available before setup. No tracking declaration is needed. Use `g.entities({ tag: "kradle.spawn" })` to find tagged entities and read their `pos`. The SDK does not load chunks for observation. Minecraft controls when entities enter and leave the mirror. Keep entities needed for setup in spawn chunks or near the players' initial positions. Distant entities appear only after Minecraft loads their chunks.
228
228
 
229
- Entities (`g.entities()`) carry `id`, `type`, `pos`, `tags`, `name?`, `health?`, `item?`, `count?`, `uuid?`, `yaw?`, `pitch?`, `headYaw?`, `equipment?`, `invisible?`, `villager?`. They are read-only through every level; copy what you keep (`{ ...e.pos }`).
229
+ Entities (`g.entities()`) carry `id`, `type`, `pos`, `tags`, `name?`, `health?`, `item?`, `count?`, `uuid?`, `yaw?`, `pitch?`, `headYaw?`, `equipment?`, `invisible?`, `villager?`, and, only while not at their default, `effects?`, `fire?`, `absorption?`, `pose?`, `baby?`, `tamed?`, `owner?`, `sitting?`, `color?`. They are read-only through every level; copy what you keep (`{ ...e.pos }`).
230
230
 
231
231
  ---
232
232
 
package/README.md CHANGED
@@ -149,7 +149,7 @@ the state; the SDK answers from that mirror:
149
149
  - `p.pos`, `p.inventory`, `p.zones`; `g.inZone(p, zone)`, `g.countItems(p, item)`
150
150
 
151
151
  The handlers report the changes: `blockPlaced`, `blockBroken`, `blocksChanged`
152
- (every cause, a fill as one entry), `container`, `inventory`, `move`,
152
+ (every cause, a fill or a clone as one entry), `container`, `inventory`, `move`,
153
153
  `zoneEntered`, `zoneLeft`, `entitySpawned`, `entityChanged`, `entityRemoved`.
154
154
 
155
155
  ### Structures
@@ -79,6 +79,18 @@ interface StatePlayer {
79
79
  slots: Record<number, ItemStack>;
80
80
  inventory: Record<string, number>;
81
81
  zones: string[];
82
+ /** The status fields the engine reports; absent while at their default (`fire: false`, no effects, standing). */
83
+ effects?: Record<string, {
84
+ level: number;
85
+ duration: number;
86
+ }>;
87
+ fire?: boolean;
88
+ absorption?: number;
89
+ pose?: string;
90
+ xp?: number;
91
+ air?: number;
92
+ sprinting?: boolean;
93
+ blocking?: boolean;
82
94
  /** Achievement ids granted so far, in the order earned, each once. */
83
95
  achievements: string[];
84
96
  state: Record<string, unknown>;
@@ -1 +1 @@
1
- {"version":3,"file":"reducer.d.ts","sourceRoot":"","sources":["../../src/runtime/reducer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"reducer.d.ts","sourceRoot":"","sources":["../../src/runtime/reducer.ts"],"names":[],"mappings":"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"}
@@ -38,6 +38,15 @@ const SETUP_BATCH_TIMEOUT_TICKS = 30 * 20;
38
38
  /** The bound Kradle applies to a result's achievements; mirrored here so the harness reports it. */
39
39
  exports.MAX_ACHIEVEMENTS = 64;
40
40
  // ---------------------------------------------------------------- small helpers
41
+ /** The air a player has at the surface, in seconds. */
42
+ const FULL_AIR = 15;
43
+ /** A copy of an effects map, entry by entry: the mirror never shares an object with the event. */
44
+ function copyEffects(effects) {
45
+ const out = {};
46
+ for (const [id, e] of Object.entries(effects))
47
+ out[id] = { level: e.level, duration: e.duration };
48
+ return out;
49
+ }
41
50
  /** Drops undefined-valued keys: wire objects carry only what JSON would carry. */
42
51
  function compact(o) {
43
52
  for (const k of Object.keys(o))
@@ -163,6 +172,7 @@ function stackOf(sl) {
163
172
  lore: sl.lore ? [...sl.lore] : undefined,
164
173
  enchantments: sl.enchantments ? { ...sl.enchantments } : undefined,
165
174
  damage: sl.damage,
175
+ components: sl.components,
166
176
  });
167
177
  }
168
178
  function countsOf(slots) {
@@ -171,11 +181,13 @@ function countsOf(slots) {
171
181
  counts[st.id] = (counts[st.id] ?? 0) + st.count;
172
182
  return counts;
173
183
  }
184
+ /** The blocks a fill or a clone changes (a move changes both boxes); 0 for any other effect. */
174
185
  function fillVolume(e) {
175
- if (e.kind !== "fill")
186
+ if (e.kind !== "fill" && e.kind !== "clone")
176
187
  return 0;
177
188
  const { lo, hi } = (0, world_js_1.bounds)({ from: e.from, to: e.to });
178
- return (hi.x - lo.x + 1) * (hi.y - lo.y + 1) * (hi.z - lo.z + 1);
189
+ const volume = (hi.x - lo.x + 1) * (hi.y - lo.y + 1) * (hi.z - lo.z + 1);
190
+ return e.kind === "clone" && e.mode === "move" ? volume * 2 : volume;
179
191
  }
180
192
  /** Splits the setup effects into batches under the engine's limits, in order. */
181
193
  function splitBatches(effects) {
@@ -185,7 +197,7 @@ function splitBatches(effects) {
185
197
  for (const e of effects) {
186
198
  const v = fillVolume(e);
187
199
  if (v > exports.MAX_FILL_VOLUME) {
188
- throw (0, errors_js_1.apiError)("fill_too_large", `a fill of ${v} blocks exceeds ${exports.MAX_FILL_VOLUME}; split it`, { path: "setup" });
200
+ throw (0, errors_js_1.apiError)("fill_too_large", `a ${e.kind} of ${v} blocks exceeds ${exports.MAX_FILL_VOLUME}; split it`, { path: "setup" });
189
201
  }
190
202
  if (current.length >= exports.MAX_BATCH_EFFECTS || volume + v > exports.MAX_FILL_VOLUME) {
191
203
  out.push(current);
@@ -765,6 +777,10 @@ function createReducer(def) {
765
777
  write("fill");
766
778
  push({ kind: "fill", from: { ...from }, to: { ...to }, block: blockSpecString(block) });
767
779
  },
780
+ clone(from, to, dest, opts) {
781
+ write("clone");
782
+ push({ kind: "clone", from: { ...from }, to: { ...to }, dest: { ...dest }, mode: opts?.mode });
783
+ },
768
784
  setBlock(at, block) {
769
785
  write("setBlock");
770
786
  const nbt = typeof block === "string" ? undefined : block.blockEntity;
@@ -1449,8 +1465,117 @@ function createReducer(def) {
1449
1465
  p.gamemode = d.gamemode;
1450
1466
  if (d.held !== undefined)
1451
1467
  p.held = d.held;
1468
+ applyStatus(p, d);
1452
1469
  return move;
1453
1470
  }
1471
+ /** Folds the status fields of a sample into a player: a field at its default leaves the record. */
1472
+ function applyStatus(p, d) {
1473
+ if (d.effects !== undefined) {
1474
+ if (Object.keys(d.effects).length)
1475
+ p.effects = copyEffects(d.effects);
1476
+ else
1477
+ delete p.effects;
1478
+ }
1479
+ if (d.fire !== undefined) {
1480
+ if (d.fire)
1481
+ p.fire = true;
1482
+ else
1483
+ delete p.fire;
1484
+ }
1485
+ if (d.absorption !== undefined) {
1486
+ if (d.absorption > 0)
1487
+ p.absorption = d.absorption;
1488
+ else
1489
+ delete p.absorption;
1490
+ }
1491
+ if (d.pose !== undefined) {
1492
+ if (d.pose !== "standing")
1493
+ p.pose = d.pose;
1494
+ else
1495
+ delete p.pose;
1496
+ }
1497
+ if (d.xp !== undefined) {
1498
+ if (d.xp > 0)
1499
+ p.xp = d.xp;
1500
+ else
1501
+ delete p.xp;
1502
+ }
1503
+ if (d.air !== undefined) {
1504
+ if (d.air < FULL_AIR)
1505
+ p.air = d.air;
1506
+ else
1507
+ delete p.air;
1508
+ }
1509
+ if (d.sprinting !== undefined) {
1510
+ if (d.sprinting)
1511
+ p.sprinting = true;
1512
+ else
1513
+ delete p.sprinting;
1514
+ }
1515
+ if (d.blocking !== undefined) {
1516
+ if (d.blocking)
1517
+ p.blocking = true;
1518
+ else
1519
+ delete p.blocking;
1520
+ }
1521
+ }
1522
+ /** Folds a mob's status fields into an entity: a field at its default leaves the record. */
1523
+ function applyMobStatus(entity, d) {
1524
+ if (d.effects !== undefined) {
1525
+ if (Object.keys(d.effects).length)
1526
+ entity.effects = copyEffects(d.effects);
1527
+ else
1528
+ delete entity.effects;
1529
+ }
1530
+ if (d.fire !== undefined) {
1531
+ if (d.fire)
1532
+ entity.fire = true;
1533
+ else
1534
+ delete entity.fire;
1535
+ }
1536
+ if (d.absorption !== undefined) {
1537
+ if (d.absorption > 0)
1538
+ entity.absorption = d.absorption;
1539
+ else
1540
+ delete entity.absorption;
1541
+ }
1542
+ if (d.pose !== undefined) {
1543
+ if (d.pose !== "standing")
1544
+ entity.pose = d.pose;
1545
+ else
1546
+ delete entity.pose;
1547
+ }
1548
+ if (d.baby !== undefined) {
1549
+ if (d.baby)
1550
+ entity.baby = true;
1551
+ else
1552
+ delete entity.baby;
1553
+ }
1554
+ if (d.tamed !== undefined) {
1555
+ if (d.tamed)
1556
+ entity.tamed = true;
1557
+ else
1558
+ delete entity.tamed;
1559
+ }
1560
+ if (d.owner !== undefined) {
1561
+ if (d.owner)
1562
+ entity.owner = d.owner;
1563
+ else
1564
+ delete entity.owner;
1565
+ }
1566
+ if (d.sitting !== undefined) {
1567
+ if (d.sitting)
1568
+ entity.sitting = true;
1569
+ else
1570
+ delete entity.sitting;
1571
+ }
1572
+ if (d.color !== undefined) {
1573
+ if (d.color)
1574
+ entity.color = d.color;
1575
+ else
1576
+ delete entity.color;
1577
+ }
1578
+ }
1454
1579
  function zonesAt(pos) {
1455
1580
  if (!pos)
1456
1581
  return [];
@@ -1480,7 +1605,7 @@ function createReducer(def) {
1480
1605
  }
1481
1606
  function sampleOther(s, d) {
1482
1607
  const prev = s.world.others[d.name];
1483
- s.world = (0, world_js_1.putOther)(s.world, compact({
1608
+ const next = compact({
1484
1609
  name: d.name,
1485
1610
  pos: d.pos ? { ...d.pos } : (prev?.pos ?? null),
1486
1611
  health: d.health ?? prev?.health ?? 20,
@@ -1494,7 +1619,18 @@ function createReducer(def) {
1494
1619
  headYaw: d.headYaw ?? prev?.headYaw,
1495
1620
  equipment: d.equipment ? (0, world_js_1.applyEquipment)(prev?.equipment, d.equipment) : prev?.equipment,
1496
1621
  invisible: d.invisible ?? prev?.invisible,
1497
- }));
1622
+ effects: prev?.effects,
1623
+ fire: prev?.fire,
1624
+ absorption: prev?.absorption,
1625
+ pose: prev?.pose,
1626
+ xp: prev?.xp,
1627
+ air: prev?.air,
1628
+ sprinting: prev?.sprinting,
1629
+ blocking: prev?.blocking,
1630
+ });
1631
+ // Before the store freezes the record: a status write on a frozen object throws.
1632
+ applyStatus(next, d);
1633
+ s.world = (0, world_js_1.putOther)(s.world, next);
1498
1634
  }
1499
1635
  function applyContainer(r, e) {
1500
1636
  const s = r.s;
@@ -1727,7 +1863,12 @@ function createReducer(def) {
1727
1863
  const p = resolve(e.name);
1728
1864
  if (!p || !playing())
1729
1865
  return;
1730
- fire(r, "damaged", { player: viewOf(r, p), amount: e.amount, cause: e.cause, attacker: viewOf(r, resolve(e.attacker)) });
1866
+ fire(r, "damaged", {
1867
+ player: viewOf(r, p),
1868
+ amount: e.amount,
1869
+ cause: e.cause,
1870
+ attacker: viewOf(r, resolve(e.attacker)),
1871
+ });
1731
1872
  break;
1732
1873
  }
1733
1874
  case "player_died": {
@@ -1809,6 +1950,7 @@ function createReducer(def) {
1809
1950
  invisible: e.invisible,
1810
1951
  villager: e.villager ? { ...e.villager } : undefined,
1811
1952
  });
1953
+ applyMobStatus(entity, e);
1812
1954
  s.world = (0, world_js_1.putEntity)(s.world, entity);
1813
1955
  if (playing())
1814
1956
  fire(r, "entitySpawned", { entity: (0, world_js_1.freezeObservation)(entity) });
@@ -1835,6 +1977,7 @@ function createReducer(def) {
1835
1977
  next.invisible = e.invisible;
1836
1978
  if (e.villager)
1837
1979
  next.villager = { ...e.villager };
1980
+ applyMobStatus(next, e);
1838
1981
  s.world = (0, world_js_1.putEntity)(s.world, next);
1839
1982
  if (playing())
1840
1983
  fire(r, "entityChanged", { entity: (0, world_js_1.freezeObservation)(next), was: (0, world_js_1.freezeObservation)(prev) });
@@ -1846,7 +1989,11 @@ function createReducer(def) {
1846
1989
  return;
1847
1990
  s.world = (0, world_js_1.removeEntity)(s.world, e.id);
1848
1991
  if (playing())
1849
- fire(r, "entityRemoved", { entity: (0, world_js_1.freezeObservation)(prev), cause: e.cause, killer: viewOf(r, resolve(e.killer)) });
1992
+ fire(r, "entityRemoved", {
1993
+ entity: (0, world_js_1.freezeObservation)(prev),
1994
+ cause: e.cause,
1995
+ killer: viewOf(r, resolve(e.killer)),
1996
+ });
1850
1997
  break;
1851
1998
  }
1852
1999
  case "chunk":
@@ -1866,7 +2013,15 @@ function createReducer(def) {
1866
2013
  s.world = (0, world_js_1.setBlocks)(s.world, e.changes);
1867
2014
  if (playing()) {
1868
2015
  fire(r, "blocksChanged", () => ({
1869
- changes: e.changes.map((c) => compact({ x: c.x, y: c.y, z: c.z, block: c.block, was: c.was, cause: c.cause, by: viewOf(r, resolve(c.by)) })),
2016
+ changes: e.changes.map((c) => compact({
2017
+ x: c.x,
2018
+ y: c.y,
2019
+ z: c.z,
2020
+ block: c.block,
2021
+ was: c.was,
2022
+ cause: c.cause,
2023
+ by: viewOf(r, resolve(c.by)),
2024
+ })),
1870
2025
  }));
1871
2026
  }
1872
2027
  break;
@@ -1879,6 +2034,26 @@ function createReducer(def) {
1879
2034
  });
1880
2035
  }
1881
2036
  break;
2037
+ case "blocks_cloned": {
2038
+ const from = { ...e.from };
2039
+ const to = { ...e.to };
2040
+ const { lo, hi } = (0, world_js_1.bounds)({ from, to });
2041
+ const dest = { x: Math.floor(e.dest.x), y: Math.floor(e.dest.y), z: Math.floor(e.dest.z) };
2042
+ s.world = (0, world_js_1.cloneBlocks)(s.world, { from, to }, dest, e.mode);
2043
+ if (playing()) {
2044
+ const box = { from: dest, to: { x: dest.x + hi.x - lo.x, y: dest.y + hi.y - lo.y, z: dest.z + hi.z - lo.z } };
2045
+ // A move clears the source first: an author who applies the entries in order gets the vanilla result on an overlap.
2046
+ fire(r, "blocksChanged", {
2047
+ changes: e.mode === "move"
2048
+ ? [
2049
+ { box: { from, to }, block: world_js_1.AIR, cause: "clone" },
2050
+ { box, from: { from, to }, cause: "clone" },
2051
+ ]
2052
+ : [{ box, from: { from, to }, cause: "clone" }],
2053
+ });
2054
+ }
2055
+ break;
2056
+ }
1882
2057
  case "block_broken": {
1883
2058
  s.world = (0, world_js_1.setBlocks)(s.world, [{ ...e.at, block: e.after ?? world_js_1.AIR }]);
1884
2059
  const p = resolve(e.name);
@@ -1897,7 +2072,12 @@ function createReducer(def) {
1897
2072
  case "block_used": {
1898
2073
  const p = resolve(e.name);
1899
2074
  if (p && playing())
1900
- fire(r, "blockUsed", { player: viewOf(r, p), at: { ...e.at }, block: parseBlockState(e.block), item: e.item });
2075
+ fire(r, "blockUsed", {
2076
+ player: viewOf(r, p),
2077
+ at: { ...e.at },
2078
+ block: parseBlockState(e.block),
2079
+ item: e.item,
2080
+ });
1901
2081
  break;
1902
2082
  }
1903
2083
  case "chat": {