@patterkit/runtime 0.7.0 → 0.8.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
@@ -33,6 +33,42 @@ version number always means the same runtime behaviour. This package is versione
33
33
 
34
34
  ## [Unreleased]
35
35
 
36
+ ## [0.8.0] - 2026-09-01
37
+
38
+ ### Changed
39
+
40
+ - **`rngState` is now written UNSIGNED in a save.** It was accumulated with
41
+ `| 0`, so more than half of all saves carried a negative number where the
42
+ schema says uint32. The draws were unaffected (signed and unsigned
43
+ accumulation produce bit-identical draws), but the native ports could not read
44
+ those saves back: Unity threw, and C++ read them through undefined behaviour.
45
+
46
+ Old saves still load here, because restore already coerced, and the native
47
+ ports now coerce too. No gameplay changes.
48
+
49
+ - **Flags compare as a SET.** `==` and `!=` on a flags value now ignore order.
50
+ They are compared as multisets, so a duplicated flag still counts. A flags
51
+ value IS a set, and its stored order was an artefact of the order somebody
52
+ happened to add things in: `set_flags(@f, +red)` then `+blue` compared UNEQUAL
53
+ to the same two flags added the other way round. An expression that relied on
54
+ that will change answer.
55
+
56
+ - The PRNG is now `@wildwinter/expr`'s `makePrng` rather than a copy inline here.
57
+ Same algorithm, same draws; mulberry32 existed thirteen times across the two
58
+ product families and is a fixed published algorithm neither owns.
59
+
60
+
61
+ ## [0.7.1] - 2026-08-30
62
+
63
+ ### Fixed
64
+
65
+ - **A flow you forgot to announce still shows up in Patterpad's debug link.** `flowOpened` was the
66
+ host's job and nothing could check it, so a game that opened a flow and did not announce it left
67
+ the editor's follow list short - and the omission outlived a reconnect, because the link's hello
68
+ carries that list. A flow now announces itself the first time it is observed; `flowOpened` remains
69
+ worth calling for a flow that exists before it says anything. Reported from the Storylet Studio
70
+ side, 2026-08-29. (Same fix in all four runtimes.)
71
+
36
72
  ## [0.7.0] - 2026-08-29
37
73
 
38
74
  ### Changed
package/dist/index.cjs CHANGED
@@ -647,7 +647,7 @@ var Flow = class {
647
647
  constructor(id, host, seed) {
648
648
  this.id = id;
649
649
  this.host = host;
650
- this.rngState = seed >>> 0;
650
+ this.rngState = (0, import_expr.toUint32)(seed);
651
651
  this.local = this.freshLocal();
652
652
  const scopes = { ...host.shared.toEvalContext().scopes };
653
653
  scopes["patter"] = this.patterResolver;
@@ -945,7 +945,7 @@ var Flow = class {
945
945
  }
946
946
  /** @internal Restore this flow from a snapshot. */
947
947
  restore(snap) {
948
- this.rngState = snap.rngState >>> 0;
948
+ this.rngState = (0, import_expr.toUint32)(snap.rngState);
949
949
  this.visitCounts = new Map(Object.entries(snap.visits ?? {}));
950
950
  const c = snap.cursor;
951
951
  this.started = true;
@@ -1260,14 +1260,19 @@ var Flow = class {
1260
1260
  this.visitCounts.set(id, (this.visitCounts.get(id) ?? 0) + 1);
1261
1261
  this.host.sharedVisits.set(id, (this.host.sharedVisits.get(id) ?? 0) + 1);
1262
1262
  }
1263
- /** Next float in [0, 1): the shared custom PRNG, or this flow's serialisable mulberry32. */
1263
+ /** Next float in [0, 1): the shared custom PRNG, or this flow's serialisable mulberry32.
1264
+ *
1265
+ * The mixing is @wildwinter/expr's makePrng, not a copy inline here. It is a
1266
+ * fixed published algorithm that both product families need and neither
1267
+ * owns, and it existed thirteen times across the two of them. `rngState` is
1268
+ * still the serialisable position, so saves are unaffected: a generator is
1269
+ * made from it, drawn once, and the new state written back. */
1264
1270
  rng = () => {
1265
1271
  if (this.host.customRng) return this.host.customRng();
1266
- const a = this.rngState + 1831565813 | 0;
1267
- this.rngState = a;
1268
- let t = Math.imul(a ^ a >>> 15, 1 | a);
1269
- t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
1270
- return ((t ^ t >>> 14) >>> 0) / 4294967296;
1272
+ const prng = (0, import_expr.makePrng)(this.rngState);
1273
+ const draw = prng.next();
1274
+ this.rngState = prng.state();
1275
+ return draw;
1271
1276
  };
1272
1277
  // -- Strings / beats ------------------------------------------------------
1273
1278
  beatResult(beat) {