@kradle/challenges-sdk 0.23.0 → 0.24.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.
Files changed (43) hide show
  1. package/CHANGELOG.md +22 -1
  2. package/LLM_README.md +34 -11
  3. package/README.md +14 -0
  4. package/dist/engine.d.ts +2 -1
  5. package/dist/engine.d.ts.map +1 -1
  6. package/dist/engine.js +4 -1
  7. package/dist/engine.js.map +1 -1
  8. package/dist/index.d.ts +1 -0
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +4 -1
  11. package/dist/index.js.map +1 -1
  12. package/dist/runtime/builder.d.ts.map +1 -1
  13. package/dist/runtime/builder.js +25 -6
  14. package/dist/runtime/builder.js.map +1 -1
  15. package/dist/runtime/dimensions.d.ts +24 -0
  16. package/dist/runtime/dimensions.d.ts.map +1 -0
  17. package/dist/runtime/dimensions.js +47 -0
  18. package/dist/runtime/dimensions.js.map +1 -0
  19. package/dist/runtime/reducer.d.ts.map +1 -1
  20. package/dist/runtime/reducer.js +65 -28
  21. package/dist/runtime/reducer.js.map +1 -1
  22. package/dist/runtime/types.d.ts +22 -4
  23. package/dist/runtime/types.d.ts.map +1 -1
  24. package/dist/runtime/types.js.map +1 -1
  25. package/dist/runtime/wire.d.ts +20 -1
  26. package/dist/runtime/wire.d.ts.map +1 -1
  27. package/dist/runtime/wire.js +1 -0
  28. package/dist/runtime/wire.js.map +1 -1
  29. package/dist/runtime/world.d.ts +13 -4
  30. package/dist/runtime/world.d.ts.map +1 -1
  31. package/dist/runtime/world.js +40 -25
  32. package/dist/runtime/world.js.map +1 -1
  33. package/dist/structures.d.ts.map +1 -1
  34. package/dist/structures.js +3 -1
  35. package/dist/structures.js.map +1 -1
  36. package/dist/test/harness.d.ts +3 -2
  37. package/dist/test/harness.d.ts.map +1 -1
  38. package/dist/test/harness.js +18 -10
  39. package/dist/test/harness.js.map +1 -1
  40. package/dist/test/helpers.d.ts.map +1 -1
  41. package/dist/test/helpers.js +2 -1
  42. package/dist/test/helpers.js.map +1 -1
  43. package/package.json +1 -1
@@ -1,4 +1,12 @@
1
1
  "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MAX_ACHIEVEMENTS = exports.MAX_TRANSITIONS_PER_EVENT = exports.MAX_FILL_VOLUME = exports.MAX_BATCH_EFFECTS = void 0;
4
+ exports.assertJson = assertJson;
5
+ exports.parseBlockState = parseBlockState;
6
+ exports.blockSpecString = blockSpecString;
7
+ exports.splitBatches = splitBatches;
8
+ exports.createReducer = createReducer;
9
+ const dimensions_js_1 = require("./dimensions.js");
2
10
  // The reducer: one locked definition, one `init()` per run, one `reduce(state,
3
11
  // event)` per engine event. Everything a rule sees comes through a context
4
12
  // built for the reduction; everything a rule asks for leaves as actions.
@@ -15,15 +23,8 @@
15
23
  // the game-over hook, the judge data, `game_over`.
16
24
  // - An author error rolls the reduction back and ends the run as
17
25
  // `error_challenge` without another author callback.
18
- Object.defineProperty(exports, "__esModule", { value: true });
19
- exports.MAX_ACHIEVEMENTS = exports.MAX_TRANSITIONS_PER_EVENT = exports.MAX_FILL_VOLUME = exports.MAX_BATCH_EFFECTS = void 0;
20
- exports.assertJson = assertJson;
21
- exports.parseBlockState = parseBlockState;
22
- exports.blockSpecString = blockSpecString;
23
- exports.splitBatches = splitBatches;
24
- exports.createReducer = createReducer;
25
- const dialog_js_1 = require("./dialog.js");
26
26
  const chat_js_1 = require("./chat.js");
27
+ const dialog_js_1 = require("./dialog.js");
27
28
  const errors_js_1 = require("./errors.js");
28
29
  const time_js_1 = require("./time.js");
29
30
  const types_js_1 = require("./types.js");
@@ -103,7 +104,7 @@ function deepFreeze(value, seen = new WeakSet()) {
103
104
  for (const x of Object.values(value))
104
105
  deepFreeze(x, seen);
105
106
  }
106
- const posKey = (at) => `${Math.floor(at.x)},${Math.floor(at.y)},${Math.floor(at.z)}`;
107
+ const posKey = dimensions_js_1.positionKey;
107
108
  /** `minecraft:oak_stairs[facing=east,half=bottom]` -> `{ id, props }`. */
108
109
  function parseBlockState(state) {
109
110
  const i = state.indexOf("[");
@@ -338,6 +339,7 @@ function viewOf(r, p) {
338
339
  }
339
340
  function createReducer(def) {
340
341
  const config = def.config;
342
+ const dimensions = (0, dimensions_js_1.enabledDimensions)(config.challengeConfig?.dimensions);
341
343
  const roleNames = Object.keys(config.roles);
342
344
  const declaredZones = Object.keys(def.zones);
343
345
  const derivedScores = def.outcome.scores !== undefined;
@@ -488,6 +490,21 @@ function createReducer(def) {
488
490
  }
489
491
  };
490
492
  const push = (raw) => {
493
+ for (const value of [
494
+ raw,
495
+ ...["at", "from", "to", "dest"].map((key) => raw[key]),
496
+ ]) {
497
+ if (value &&
498
+ typeof value === "object" &&
499
+ "dimension" in value &&
500
+ value.dimension !== undefined &&
501
+ !dimensions.includes(value.dimension))
502
+ throw (0, errors_js_1.apiError)("invalid_value", "The target dimension is disabled");
503
+ }
504
+ if (raw.kind === "fill" || raw.kind === "clone")
505
+ (0, world_js_1.bounds)({ from: raw.from, to: raw.to });
506
+ if (raw.kind === "clone" && (0, dimensions_js_1.dimensionOf)(raw.from) !== (0, dimensions_js_1.dimensionOf)(raw.dest))
507
+ throw (0, errors_js_1.apiError)("invalid_value", "A clone cannot cross dimensions");
491
508
  // A plain copy: an author's argument may be a view (`p.pos`, `g.params.box`).
492
509
  const effect = compact(snapshot(raw));
493
510
  if (r.batch)
@@ -580,6 +597,7 @@ function createReducer(def) {
580
597
  throw (0, errors_js_1.notDeclared)("zones", zone, declaredZones);
581
598
  return p.zones.includes(zone);
582
599
  }
600
+ (0, world_js_1.bounds)(zone);
583
601
  return p.pos !== null && (0, world_js_1.inBox)(p.pos, zone);
584
602
  },
585
603
  countItems(p, match) {
@@ -617,6 +635,7 @@ function createReducer(def) {
617
635
  get worldTime() {
618
636
  return s.world.time;
619
637
  },
638
+ dimensionTime: (dimension) => (dimension === dimensions_js_1.OVERWORLD ? s.world.time : s.world.times?.[dimension]),
620
639
  entities: (filter) => (0, world_js_1.entitiesIn)(s.world, filter).map(world_js_1.freezeObservation),
621
640
  entity(id) {
622
641
  const e = s.world.entities[id];
@@ -826,17 +845,17 @@ function createReducer(def) {
826
845
  write("summon");
827
846
  push({ kind: "summon", entity, at: { ...at }, nbt: opts?.nbt });
828
847
  },
829
- killEntities(entities) {
848
+ killEntities(entities, dimension) {
830
849
  write("killEntities");
831
- push({ kind: "kill_entities", entities });
850
+ push({ kind: "kill_entities", entities, dimension });
832
851
  },
833
- time(value) {
852
+ time(value, dimension) {
834
853
  write("time");
835
- push({ kind: "time", value });
854
+ push({ kind: "time", value, dimension });
836
855
  },
837
- gamerule(rule, value) {
856
+ gamerule(rule, value, dimension) {
838
857
  write("gamerule");
839
- push({ kind: "gamerule", rule, value });
858
+ push({ kind: "gamerule", rule, value, dimension });
840
859
  },
841
860
  setSpawn(at) {
842
861
  write("setSpawn");
@@ -846,6 +865,7 @@ function createReducer(def) {
846
865
  write("worldBorder");
847
866
  push({
848
867
  kind: "worldborder",
868
+ dimension: opts.dimension,
849
869
  center: opts.center,
850
870
  size: opts.size,
851
871
  seconds: opts.over === undefined ? undefined : (0, time_js_1.toTicks)(opts.over) / 20,
@@ -866,11 +886,11 @@ function createReducer(def) {
866
886
  }));
867
887
  push({ kind: "container", at: { ...at }, items: out });
868
888
  },
869
- command(cmd, name) {
889
+ command(cmd, name, dimension) {
870
890
  write("command");
871
891
  r.actions.push({ type: "log", message: `raw command: ${cmd}` });
872
892
  if (name === undefined) {
873
- push({ kind: "command", cmd });
893
+ push({ kind: "command", cmd, dimension });
874
894
  return;
875
895
  }
876
896
  if (typeof name !== "string")
@@ -879,7 +899,7 @@ function createReducer(def) {
879
899
  throw (0, errors_js_1.apiError)("lifecycle", `command("${cmd}", "${name}"): a result needs a running game, not .setup (status ${s.status})`);
880
900
  const id = `cmd:${s.nextId++}`;
881
901
  s.commands[id] = { name };
882
- push({ kind: "command", cmd, id });
902
+ push({ kind: "command", cmd, id, dimension });
883
903
  },
884
904
  // ---- flow
885
905
  startPhase(name) {
@@ -1283,11 +1303,19 @@ function createReducer(def) {
1283
1303
  const out = [];
1284
1304
  if (w.spawn)
1285
1305
  out.push({ kind: "spawn", at: { ...w.spawn } });
1286
- if (w.time !== false)
1287
- out.push({ kind: "time", value: w.time });
1288
- out.push({ kind: "gamerule", rule: "minecraft:advance_time", value: w.daylightCycle });
1289
- out.push({ kind: "gamerule", rule: "minecraft:spawn_mobs", value: w.mobSpawning });
1290
- out.push({ kind: "gamerule", rule: "minecraft:natural_health_regeneration", value: w.naturalRegeneration });
1306
+ for (const dimension of dimensions) {
1307
+ const scope = dimension === dimensions_js_1.OVERWORLD ? {} : { dimension };
1308
+ if (w.time !== false)
1309
+ out.push({ kind: "time", value: w.time, ...scope });
1310
+ out.push({ kind: "gamerule", rule: "minecraft:advance_time", value: w.daylightCycle, ...scope });
1311
+ out.push({ kind: "gamerule", rule: "minecraft:spawn_mobs", value: w.mobSpawning, ...scope });
1312
+ out.push({
1313
+ kind: "gamerule",
1314
+ rule: "minecraft:natural_health_regeneration",
1315
+ value: w.naturalRegeneration,
1316
+ ...scope,
1317
+ });
1318
+ }
1291
1319
  return out;
1292
1320
  }
1293
1321
  function worldPlayers(s) {
@@ -1665,6 +1693,8 @@ function createReducer(def) {
1665
1693
  if (r.s.status !== "PLAYING")
1666
1694
  return;
1667
1695
  for (const { m, before, after } of edges) {
1696
+ if ((0, dimensions_js_1.dimensionOf)(m.from) !== (0, dimensions_js_1.dimensionOf)(m.to))
1697
+ fire(r, "dimensionChanged", { player: viewOf(r, m.p), from: m.from, to: { ...m.to } });
1668
1698
  for (const zone of after)
1669
1699
  if (!before.includes(zone))
1670
1700
  fire(r, "zoneEntered", { player: viewOf(r, m.p), zone });
@@ -1789,6 +1819,8 @@ function createReducer(def) {
1789
1819
  return;
1790
1820
  }
1791
1821
  const missing = missingCapabilities(e.capabilities);
1822
+ if (dimensions.length > 1 && !e.capabilities.includes("dimensions"))
1823
+ missing.push("dimensions");
1792
1824
  if (def.setup && !e.capabilities.includes("batch"))
1793
1825
  missing.push("batch");
1794
1826
  if (missing.length > 0) {
@@ -1849,6 +1881,8 @@ function createReducer(def) {
1849
1881
  delete s.dialogs[player];
1850
1882
  r.actions.push({ type: "effect", effect: { kind: "clear_dialog", player } });
1851
1883
  }
1884
+ if (e.times)
1885
+ s.world = { ...s.world, times: { ...s.world.times, ...e.times } };
1852
1886
  if (e.entities)
1853
1887
  s.world = (0, world_js_1.moveEntities)(s.world, e.entities);
1854
1888
  if (e.time !== undefined && e.time !== s.world.time)
@@ -2127,11 +2161,10 @@ function createReducer(def) {
2127
2161
  s.world = (0, world_js_1.applyChunk)(s.world, e);
2128
2162
  break;
2129
2163
  case "chunk_unloaded": {
2130
- s.world = (0, world_js_1.removeChunk)(s.world, e.x, e.z);
2164
+ s.world = (0, world_js_1.removeChunk)(s.world, e.x, e.z, e.dimension);
2131
2165
  // The containers of the chunk are unknown now.
2132
2166
  for (const key of Object.keys(s.containers)) {
2133
- const [x, , z] = key.split(",").map(Number);
2134
- if (x >> 4 === e.x && z >> 4 === e.z)
2167
+ if ((0, dimensions_js_1.keyInChunk)(key, e.x, e.z, e.dimension))
2135
2168
  delete s.containers[key];
2136
2169
  }
2137
2170
  break;
@@ -2141,6 +2174,7 @@ function createReducer(def) {
2141
2174
  if (playing()) {
2142
2175
  fire(r, "blocksChanged", () => ({
2143
2176
  changes: e.changes.map((c) => compact({
2177
+ dimension: c.dimension,
2144
2178
  x: c.x,
2145
2179
  y: c.y,
2146
2180
  z: c.z,
@@ -2165,10 +2199,13 @@ function createReducer(def) {
2165
2199
  const from = { ...e.from };
2166
2200
  const to = { ...e.to };
2167
2201
  const { lo, hi } = (0, world_js_1.bounds)({ from, to });
2168
- const dest = { x: Math.floor(e.dest.x), y: Math.floor(e.dest.y), z: Math.floor(e.dest.z) };
2202
+ const dest = { ...e.dest, x: Math.floor(e.dest.x), y: Math.floor(e.dest.y), z: Math.floor(e.dest.z) };
2169
2203
  s.world = (0, world_js_1.cloneBlocks)(s.world, { from, to }, dest, e.mode);
2170
2204
  if (playing()) {
2171
- 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 } };
2205
+ const box = {
2206
+ from: dest,
2207
+ to: { ...dest, x: dest.x + hi.x - lo.x, y: dest.y + hi.y - lo.y, z: dest.z + hi.z - lo.z },
2208
+ };
2172
2209
  // A move clears the source first: an author who applies the entries in order gets the vanilla result on an overlap.
2173
2210
  fire(r, "blocksChanged", {
2174
2211
  changes: e.mode === "move"