@kradle/challenges-sdk 0.20.0 → 0.21.1
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 +28 -2
- package/LLM_README.md +14 -3
- package/README.md +13 -0
- package/dist/runtime/reducer.d.ts +12 -0
- package/dist/runtime/reducer.d.ts.map +1 -1
- package/dist/runtime/reducer.js +160 -6
- package/dist/runtime/reducer.js.map +1 -1
- package/dist/runtime/types.d.ts +31 -9
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime/types.js.map +1 -1
- package/dist/runtime/wire.d.ts +54 -8
- package/dist/runtime/wire.d.ts.map +1 -1
- package/dist/runtime/wire.js.map +1 -1
- package/dist/runtime/world.d.ts +43 -4
- package/dist/runtime/world.d.ts.map +1 -1
- package/dist/runtime/world.js +21 -3
- package/dist/runtime/world.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -17,13 +17,37 @@ also hand-edit this file or the [Unreleased] section at any time.
|
|
|
17
17
|
|
|
18
18
|
## [Unreleased]
|
|
19
19
|
|
|
20
|
+
## [0.21.1] - 2026-10-14
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
|
|
24
|
+
- The command reference lists support for `data`, `dialog`, `difficulty`, `item`, `loot`, `rotate`, `swing`, `waypoint`, `spectate`, `seed`, `list`, `help`, and `version`.
|
|
25
|
+
- Native Minecraft clients show dialogs. Dialog input does not create challenge events or text-agent messages.
|
|
26
|
+
- The reference describes block and container observations. These include closed containers, jukeboxes, lecterns, chiseled bookshelves, and decorated pots.
|
|
27
|
+
- World observations do not expose arbitrary NBT or command storage. Console output does not return to challenge code.
|
|
28
|
+
- The `g.container` reference states its limits for jukeboxes, lecterns, chiseled bookshelves, and decorated pots.
|
|
29
|
+
- `place`, `tick`, and server control commands remain unavailable.
|
|
30
|
+
|
|
31
|
+
## [0.21.0] - 2026-10-09
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
|
|
35
|
+
- 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.
|
|
36
|
+
- 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`.
|
|
37
|
+
- 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`.
|
|
38
|
+
|
|
39
|
+
### Changed
|
|
40
|
+
|
|
41
|
+
- `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.
|
|
42
|
+
- 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.
|
|
43
|
+
|
|
20
44
|
## [0.20.0] - 2026-10-08
|
|
21
45
|
|
|
22
46
|
### Added
|
|
23
47
|
|
|
24
48
|
- `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.
|
|
25
49
|
- The clone entry of a `blocksChanged` payload declares `block` as `undefined`, so a handler that reads `c.block` on every entry still compiles.
|
|
26
|
-
- `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"`;
|
|
50
|
+
- `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.
|
|
27
51
|
- In a test, `game.cloneBlocks(from, to, dest, mode?)` reports a clone to the challenge.
|
|
28
52
|
|
|
29
53
|
### Changed
|
|
@@ -314,7 +338,9 @@ also hand-edit this file or the [Unreleased] section at any time.
|
|
|
314
338
|
- Voting primitives (`votedFor`, `promptVote`, `allVotesIn`, `assignDefaultVotes`) for challenges that use discuss-then-vote-then-act phases as an alternative to pad-based voting.
|
|
315
339
|
- 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`.
|
|
316
340
|
|
|
317
|
-
[Unreleased]: https://github.com/Kradle-ai/challenges-sdk/compare/v0.
|
|
341
|
+
[Unreleased]: https://github.com/Kradle-ai/challenges-sdk/compare/v0.21.1...HEAD
|
|
342
|
+
[0.21.1]: https://github.com/Kradle-ai/challenges-sdk/compare/v0.21.0...v0.21.1
|
|
343
|
+
[0.21.0]: https://github.com/Kradle-ai/challenges-sdk/compare/v0.20.0...v0.21.0
|
|
318
344
|
[0.20.0]: https://github.com/Kradle-ai/challenges-sdk/compare/v0.19.1...v0.20.0
|
|
319
345
|
[0.19.1]: https://github.com/Kradle-ai/challenges-sdk/compare/v0.19.0...v0.19.1
|
|
320
346
|
[0.19.0]: https://github.com/Kradle-ai/challenges-sdk/compare/v0.18.0...v0.19.0
|
package/LLM_README.md
CHANGED
|
@@ -210,7 +210,18 @@ 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.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)` (
|
|
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)` (runs a supported Minecraft command; see the command scope and limits below).
|
|
214
|
+
|
|
215
|
+
`g.command(cmd)` supports `data`, `dialog`, `difficulty`, `item`, `loot`, `rotate`, `swing`, `waypoint`, `spectate`, `seed`, `list`, `help`, and `version`.
|
|
216
|
+
It also supports the existing gameplay and block commands.
|
|
217
|
+
Vanilla command syntax and rules still apply.
|
|
218
|
+
Block and container changes reach the world observations, including closed containers, jukeboxes, lecterns, chiseled bookshelves, and decorated pots.
|
|
219
|
+
The typed `g.container` method does not accept jukeboxes, lecterns, chiseled bookshelves, or decorated pots.
|
|
220
|
+
The observations do not expose arbitrary NBT or command storage.
|
|
221
|
+
Native Minecraft clients show dialogs. Dialog input does not create challenge events or text-agent messages.
|
|
222
|
+
Console output does not return to the challenge, including output from `data get`, `seed`, `list`, `help`, and `version`.
|
|
223
|
+
Use absolute coordinates, or `execute at` for a position relative to an entity.
|
|
224
|
+
`place`, `tick`, and server control commands remain unavailable.
|
|
214
225
|
|
|
215
226
|
**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
227
|
|
|
@@ -220,13 +231,13 @@ Durations are `"35s"`, `"2m"`, `"40t"` or `seconds(35)` / `minutes(2)` / `ticks(
|
|
|
220
231
|
|
|
221
232
|
## Players and Entities
|
|
222
233
|
|
|
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.
|
|
234
|
+
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
235
|
|
|
225
236
|
`p.role === "seeker"` narrows the player to that role's state. `g.playersWithRole("seeker")` is typed the same way.
|
|
226
237
|
|
|
227
238
|
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
239
|
|
|
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 }`).
|
|
240
|
+
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
241
|
|
|
231
242
|
---
|
|
232
243
|
|
package/README.md
CHANGED
|
@@ -207,3 +207,16 @@ configuration. The run's event log is uploaded as the `runtime` recording.
|
|
|
207
207
|
The wire contract (`Event`, `Effect`, `Action`) is the
|
|
208
208
|
`@kradle/challenges-sdk/engine` entry; `test/types/` shows what the types
|
|
209
209
|
catch.
|
|
210
|
+
|
|
211
|
+
## Minecraft commands
|
|
212
|
+
|
|
213
|
+
`g.command(cmd)` supports `data`, `dialog`, `difficulty`, `item`, `loot`, `rotate`, `swing`, `waypoint`, `spectate`, `seed`, `list`, `help`, and `version`.
|
|
214
|
+
It also supports the existing gameplay and block commands.
|
|
215
|
+
Vanilla command syntax and rules still apply.
|
|
216
|
+
Block and container changes reach the world observations, including closed containers, jukeboxes, lecterns, chiseled bookshelves, and decorated pots.
|
|
217
|
+
The typed `g.container` method does not accept jukeboxes, lecterns, chiseled bookshelves, or decorated pots.
|
|
218
|
+
The observations do not expose arbitrary NBT or command storage.
|
|
219
|
+
Native Minecraft clients show dialogs. Dialog input does not create challenge events or text-agent messages.
|
|
220
|
+
Console output does not return to the challenge, including output from `data get`, `seed`, `list`, `help`, and `version`.
|
|
221
|
+
Use absolute coordinates, or `execute at` for a position relative to an entity.
|
|
222
|
+
`place`, `tick`, and server control commands remain unavailable.
|
|
@@ -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":"AAmBA,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,KAAK,EAAW,MAAM,WAAW,CAAC;AAC/D,OAAO,KAAK,EAEX,SAAS,EACT,UAAU,EACV,eAAe,EAGf,QAAQ,EAIR,OAAO,EACP,SAAS,EAGT,SAAS,EAET,KAAK,EACL,MAAM,YAAY,CAAC;AAEpB,OAAO,KAAK,EACX,MAAM,EACN,OAAO,EACP,GAAG,EACH,UAAU,EAIV,MAAM,EACN,SAAS,EACT,KAAK,EACL,MAAM,EACN,SAAS,EACT,IAAI,
|
|
1
|
+
{"version":3,"file":"reducer.d.ts","sourceRoot":"","sources":["../../src/runtime/reducer.ts"],"names":[],"mappings":"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"}
|
package/dist/runtime/reducer.js
CHANGED
|
@@ -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) {
|
|
@@ -1455,8 +1465,117 @@ function createReducer(def) {
|
|
|
1455
1465
|
p.gamemode = d.gamemode;
|
|
1456
1466
|
if (d.held !== undefined)
|
|
1457
1467
|
p.held = d.held;
|
|
1468
|
+
applyStatus(p, d);
|
|
1458
1469
|
return move;
|
|
1459
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
|
+
}
|
|
1460
1579
|
function zonesAt(pos) {
|
|
1461
1580
|
if (!pos)
|
|
1462
1581
|
return [];
|
|
@@ -1486,7 +1605,7 @@ function createReducer(def) {
|
|
|
1486
1605
|
}
|
|
1487
1606
|
function sampleOther(s, d) {
|
|
1488
1607
|
const prev = s.world.others[d.name];
|
|
1489
|
-
|
|
1608
|
+
const next = compact({
|
|
1490
1609
|
name: d.name,
|
|
1491
1610
|
pos: d.pos ? { ...d.pos } : (prev?.pos ?? null),
|
|
1492
1611
|
health: d.health ?? prev?.health ?? 20,
|
|
@@ -1500,7 +1619,18 @@ function createReducer(def) {
|
|
|
1500
1619
|
headYaw: d.headYaw ?? prev?.headYaw,
|
|
1501
1620
|
equipment: d.equipment ? (0, world_js_1.applyEquipment)(prev?.equipment, d.equipment) : prev?.equipment,
|
|
1502
1621
|
invisible: d.invisible ?? prev?.invisible,
|
|
1503
|
-
|
|
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);
|
|
1504
1634
|
}
|
|
1505
1635
|
function applyContainer(r, e) {
|
|
1506
1636
|
const s = r.s;
|
|
@@ -1733,7 +1863,12 @@ function createReducer(def) {
|
|
|
1733
1863
|
const p = resolve(e.name);
|
|
1734
1864
|
if (!p || !playing())
|
|
1735
1865
|
return;
|
|
1736
|
-
fire(r, "damaged", {
|
|
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
|
+
});
|
|
1737
1872
|
break;
|
|
1738
1873
|
}
|
|
1739
1874
|
case "player_died": {
|
|
@@ -1815,6 +1950,7 @@ function createReducer(def) {
|
|
|
1815
1950
|
invisible: e.invisible,
|
|
1816
1951
|
villager: e.villager ? { ...e.villager } : undefined,
|
|
1817
1952
|
});
|
|
1953
|
+
applyMobStatus(entity, e);
|
|
1818
1954
|
s.world = (0, world_js_1.putEntity)(s.world, entity);
|
|
1819
1955
|
if (playing())
|
|
1820
1956
|
fire(r, "entitySpawned", { entity: (0, world_js_1.freezeObservation)(entity) });
|
|
@@ -1841,6 +1977,7 @@ function createReducer(def) {
|
|
|
1841
1977
|
next.invisible = e.invisible;
|
|
1842
1978
|
if (e.villager)
|
|
1843
1979
|
next.villager = { ...e.villager };
|
|
1980
|
+
applyMobStatus(next, e);
|
|
1844
1981
|
s.world = (0, world_js_1.putEntity)(s.world, next);
|
|
1845
1982
|
if (playing())
|
|
1846
1983
|
fire(r, "entityChanged", { entity: (0, world_js_1.freezeObservation)(next), was: (0, world_js_1.freezeObservation)(prev) });
|
|
@@ -1852,7 +1989,11 @@ function createReducer(def) {
|
|
|
1852
1989
|
return;
|
|
1853
1990
|
s.world = (0, world_js_1.removeEntity)(s.world, e.id);
|
|
1854
1991
|
if (playing())
|
|
1855
|
-
fire(r, "entityRemoved", {
|
|
1992
|
+
fire(r, "entityRemoved", {
|
|
1993
|
+
entity: (0, world_js_1.freezeObservation)(prev),
|
|
1994
|
+
cause: e.cause,
|
|
1995
|
+
killer: viewOf(r, resolve(e.killer)),
|
|
1996
|
+
});
|
|
1856
1997
|
break;
|
|
1857
1998
|
}
|
|
1858
1999
|
case "chunk":
|
|
@@ -1872,7 +2013,15 @@ function createReducer(def) {
|
|
|
1872
2013
|
s.world = (0, world_js_1.setBlocks)(s.world, e.changes);
|
|
1873
2014
|
if (playing()) {
|
|
1874
2015
|
fire(r, "blocksChanged", () => ({
|
|
1875
|
-
changes: e.changes.map((c) => compact({
|
|
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
|
+
})),
|
|
1876
2025
|
}));
|
|
1877
2026
|
}
|
|
1878
2027
|
break;
|
|
@@ -1923,7 +2072,12 @@ function createReducer(def) {
|
|
|
1923
2072
|
case "block_used": {
|
|
1924
2073
|
const p = resolve(e.name);
|
|
1925
2074
|
if (p && playing())
|
|
1926
|
-
fire(r, "blockUsed", {
|
|
2075
|
+
fire(r, "blockUsed", {
|
|
2076
|
+
player: viewOf(r, p),
|
|
2077
|
+
at: { ...e.at },
|
|
2078
|
+
block: parseBlockState(e.block),
|
|
2079
|
+
item: e.item,
|
|
2080
|
+
});
|
|
1927
2081
|
break;
|
|
1928
2082
|
}
|
|
1929
2083
|
case "chat": {
|