@bloopjs/bloop 0.0.21 → 0.0.22

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/dist/bloop.d.ts CHANGED
@@ -1,8 +1,7 @@
1
- import { type EnginePointer } from "@bloopjs/engine";
2
1
  import type { Context } from "./context";
3
2
  import type { Bag } from "./data/bag";
4
3
  import type { BloopSchema } from "./data/schema";
5
- import type { DeserializeFn, SerializeFn } from "./runtime";
4
+ import type { EngineHooks } from "./runtime";
6
5
  import type { System } from "./system";
7
6
  export type BloopOpts<B extends Bag> = {
8
7
  /** defaults to "Game" */
@@ -27,26 +26,26 @@ export declare class Bloop<GS extends BloopSchema> {
27
26
  * Bloop.create() is the way to create a new bloop instance.
28
27
  */
29
28
  static create<B extends Bag>(opts?: BloopOpts<B>): Bloop<MakeGS<B>>;
29
+ /**
30
+ * DO NOT USE `new Bloop` - use `Bloop.create()` instead for proper type hints.
31
+ */
30
32
  constructor(opts: BloopOpts<GS["B"]> | undefined, dontCallMeDirectly: string);
31
- get bag(): GS["B"];
32
- get context(): Readonly<Context<GS>>;
33
33
  /**
34
- * Take a snapshot of the game state outside the engine
35
- * @returns linear memory representation of the game state that the engine is unaware of
34
+ * Read the game singleton bag
36
35
  */
37
- serialize: () => ReturnType<SerializeFn>;
36
+ get bag(): GS["B"];
38
37
  /**
39
- * Restore a snapshot of the game state outside the engine
40
- * @returns linear memory representation of the game state that the engine is unaware of
38
+ * Read the game context object
41
39
  */
42
- deserialize: DeserializeFn;
40
+ get context(): Readonly<Context<GS>>;
43
41
  /**
44
42
  * Register a system with the game loop.
45
- *
46
43
  */
47
44
  system(label: string, system: System<GS>): number;
48
- systemsCallback(system_handle: number, ptr: EnginePointer): void;
49
- setBuffer(buffer: ArrayBuffer): void;
45
+ /**
46
+ * Low level hooks to engine functionality. Editing these is for advanced use cases, defaults should usually work.
47
+ */
48
+ hooks: EngineHooks;
50
49
  }
51
50
  type MakeGS<B extends Bag> = BloopSchema<B>;
52
51
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"bloop.d.ts","sourceRoot":"","sources":["../src/bloop.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,aAAa,EAWnB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAQjD,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC5D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC,MAAM,MAAM,SAAS,CAAC,CAAC,SAAS,GAAG,IAAI;IACrC,yBAAyB;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;OAIG;IAEH;;OAEG;IAEH;;;OAGG;IACH,GAAG,CAAC,EAAE,CAAC,CAAC;CAET,CAAC;AAEF,qBAAa,KAAK,CAAC,EAAE,SAAS,WAAW;;IAKvC;;OAEG;IACH,MAAM,CAAC,MAAM,CAGX,CAAC,SAAS,GAAG,EAGb,IAAI,GAAE,SAAS,CAAC,CAAC,CAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;gBAIhC,IAAI,EAAE,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,YAAK,EAAE,kBAAkB,EAAE,MAAM;IAerE,IAAI,GAAG,IAAI,EAAE,CAAC,GAAG,CAAC,CAEjB;IAED,IAAI,OAAO,IAAI,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAEnC;IAED;;;OAGG;IACH,SAAS,QAAO,UAAU,CAAC,WAAW,CAAC,CAYrC;IAEF;;;OAGG;IACH,WAAW,EAAE,aAAa,CAUxB;IAEF;;;OAGG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,GAAG,MAAM;IAMjD,eAAe,CAAC,aAAa,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa;IA6FzD,SAAS,CAAC,MAAM,EAAE,WAAW;CAG9B;AAUD,KAAK,MAAM,CAAC,CAAC,SAAS,GAAG,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"bloop.d.ts","sourceRoot":"","sources":["../src/bloop.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAQjD,OAAO,KAAK,EAAiB,WAAW,EAAe,MAAM,WAAW,CAAC;AACzE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC,MAAM,MAAM,SAAS,CAAC,CAAC,SAAS,GAAG,IAAI;IACrC,yBAAyB;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;OAIG;IAEH;;OAEG;IAEH;;;OAGG;IACH,GAAG,CAAC,EAAE,CAAC,CAAC;CAET,CAAC;AAEF,qBAAa,KAAK,CAAC,EAAE,SAAS,WAAW;;IAKvC;;OAEG;IACH,MAAM,CAAC,MAAM,CAGX,CAAC,SAAS,GAAG,EAGb,IAAI,GAAE,SAAS,CAAC,CAAC,CAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAI5C;;OAEG;gBACS,IAAI,EAAE,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,YAAK,EAAE,kBAAkB,EAAE,MAAM;IAerE;;OAEG;IACH,IAAI,GAAG,IAAI,EAAE,CAAC,GAAG,CAAC,CAEjB;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAEnC;IAED;;OAEG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,GAAG,MAAM;IAMjD;;OAEG;IACH,KAAK,EAAE,WAAW,CAsIhB;CACH;AAUD,KAAK,MAAM,CAAC,CAAC,SAAS,GAAG,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC"}
package/dist/mod.d.ts CHANGED
@@ -1,4 +1,8 @@
1
- export * from "./runtime";
2
- export * from "./bloop";
1
+ export type * as typesRuntime from "./runtime";
2
+ export type * as typesMount from "./mount";
3
+ export type * as typesBloop from "./bloop";
4
+ export type * as typesContext from "./context";
3
5
  export * as Util from "./util";
6
+ export { mount } from "./mount";
7
+ export { Bloop } from "./bloop";
4
8
  //# sourceMappingURL=mod.d.ts.map
package/dist/mod.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAA;AACzB,cAAc,SAAS,CAAA;AAEvB,OAAO,KAAK,IAAI,MAAM,QAAQ,CAAC"}
1
+ {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA,YAAY,KAAK,YAAY,MAAM,WAAW,CAAA;AAC9C,YAAY,KAAK,UAAU,MAAM,SAAS,CAAA;AAC1C,YAAY,KAAK,UAAU,MAAM,SAAS,CAAA;AAC1C,YAAY,KAAK,YAAY,MAAM,WAAW,CAAA;AAE9C,OAAO,KAAK,IAAI,MAAM,QAAQ,CAAC;AAE/B,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA"}
package/dist/mod.js CHANGED
@@ -9,6 +9,31 @@ var __export = (target, all) => {
9
9
  });
10
10
  };
11
11
 
12
+ // src/util.ts
13
+ var exports_util = {};
14
+ __export(exports_util, {
15
+ unwrap: () => unwrap,
16
+ toHexString: () => toHexString,
17
+ assert: () => assert
18
+ });
19
+ function toHexString(dataView, length) {
20
+ length ??= dataView.byteLength;
21
+ let hexString = "";
22
+ for (let i = 0;i < length; i++) {
23
+ const byte = dataView.getUint8(i);
24
+ hexString += `${byte.toString(16).padStart(2, "0")} `;
25
+ }
26
+ return hexString.trim();
27
+ }
28
+ function assert(condition, message) {
29
+ if (condition == null || condition === false) {
30
+ throw new Error(message ?? "Assertion failed");
31
+ }
32
+ }
33
+ function unwrap(value, message) {
34
+ assert(value != null, message ?? `Unwrap failed: value is ${value}`);
35
+ return value;
36
+ }
12
37
  // ../engine/dist/engine.js
13
38
  var __defProp2 = Object.defineProperty;
14
39
  var __export2 = (target, all) => {
@@ -991,32 +1016,6 @@ var EVENTS_OFFSET = INPUT_CTX_OFFSET + 4;
991
1016
  var SNAPSHOT_HEADER_USER_LEN_OFFSET = 4;
992
1017
  var SNAPSHOT_HEADER_ENGINE_LEN_OFFSET = 8;
993
1018
 
994
- // src/util.ts
995
- var exports_util = {};
996
- __export(exports_util, {
997
- unwrap: () => unwrap,
998
- toHexString: () => toHexString,
999
- assert: () => assert
1000
- });
1001
- function toHexString(dataView, length) {
1002
- length ??= dataView.byteLength;
1003
- let hexString = "";
1004
- for (let i = 0;i < length; i++) {
1005
- const byte = dataView.getUint8(i);
1006
- hexString += `${byte.toString(16).padStart(2, "0")} `;
1007
- }
1008
- return hexString.trim();
1009
- }
1010
- function assert(condition, message) {
1011
- if (condition == null || condition === false) {
1012
- throw new Error(message ?? "Assertion failed");
1013
- }
1014
- }
1015
- function unwrap(value, message) {
1016
- assert(value != null, message ?? `Unwrap failed: value is ${value}`);
1017
- return value;
1018
- }
1019
-
1020
1019
  // src/runtime.ts
1021
1020
  class Runtime {
1022
1021
  wasm;
@@ -1109,18 +1108,20 @@ class Runtime {
1109
1108
  }
1110
1109
  };
1111
1110
  }
1111
+
1112
+ // src/mount.ts
1112
1113
  async function mount(opts) {
1113
- if (opts.serialize && !opts.deserialize || !opts.serialize && opts.deserialize) {
1114
- throw new Error("Snapshot and restore hooks must be provided together");
1115
- }
1116
- const bytes = await Bun.file(opts.wasmUrl ?? DEFAULT_WASM_URL).arrayBuffer();
1114
+ const bytes = await fetch(opts.wasmUrl ?? DEFAULT_WASM_URL).then((res) => res.arrayBuffer()).catch((e) => {
1115
+ console.error(`Failed to fetch wasm at ${opts.wasmUrl ?? DEFAULT_WASM_URL}`, e);
1116
+ throw e;
1117
+ });
1117
1118
  const memory = new WebAssembly.Memory({ initial: 17, maximum: 1000 });
1118
1119
  const wasmInstantiatedSource = await WebAssembly.instantiate(bytes, {
1119
1120
  env: {
1120
1121
  memory,
1121
1122
  __cb: function(system_handle, ptr) {
1122
- opts.setBuffer(memory.buffer);
1123
- opts.systemsCallback(system_handle, ptr);
1123
+ opts.hooks.setBuffer(memory.buffer);
1124
+ opts.hooks.systemsCallback(system_handle, ptr);
1124
1125
  },
1125
1126
  console_log: function(ptr, len) {
1126
1127
  const bytes2 = new Uint8Array(memory.buffer, ptr, len);
@@ -1128,31 +1129,23 @@ async function mount(opts) {
1128
1129
  console.log(string);
1129
1130
  },
1130
1131
  user_data_len: function() {
1131
- const serializer = opts.serialize ? opts.serialize() : null;
1132
+ const serializer = opts.hooks.serialize();
1132
1133
  return serializer ? serializer.size : 0;
1133
1134
  },
1134
1135
  user_data_serialize: function(ptr, len) {
1135
- if (!opts.serialize) {
1136
- return;
1137
- }
1138
- const serializer = opts.serialize();
1139
- if (len !== serializer.size) {
1140
- throw new Error(`user_data_write length mismatch, expected=${serializer.size} got=${len}`);
1141
- }
1136
+ const serializer = opts.hooks.serialize();
1137
+ assert(len === serializer.size, `user_data_serialize length mismatch, expected=${serializer.size} got=${len}`);
1142
1138
  serializer.write(memory.buffer, ptr);
1143
1139
  },
1144
1140
  user_data_deserialize: function(ptr, len) {
1145
- if (!opts.deserialize) {
1146
- return;
1147
- }
1148
- opts.deserialize(memory.buffer, ptr, len);
1141
+ opts.hooks.deserialize(memory.buffer, ptr, len);
1149
1142
  }
1150
1143
  }
1151
1144
  });
1152
1145
  const wasm = wasmInstantiatedSource.instance.exports;
1153
1146
  wasm.initialize();
1154
1147
  const runtime = new Runtime(wasm, memory, {
1155
- serialize: opts.serialize
1148
+ serialize: opts.hooks.serialize
1156
1149
  });
1157
1150
  if (opts.startRecording ?? true) {
1158
1151
  runtime.record();
@@ -1187,99 +1180,101 @@ class Bloop {
1187
1180
  get context() {
1188
1181
  return this.#context;
1189
1182
  }
1190
- serialize = () => {
1191
- const str = JSON.stringify(this.#context.bag);
1192
- const encoder = new TextEncoder;
1193
- const textBytes = encoder.encode(str);
1194
- return {
1195
- size: textBytes.byteLength,
1196
- write: (buffer, ptr) => {
1197
- const memoryView = new Uint8Array(buffer, ptr, textBytes.byteLength);
1198
- memoryView.set(textBytes);
1199
- }
1200
- };
1201
- };
1202
- deserialize = (buffer, ptr, len) => {
1203
- const bagBytes = new Uint8Array(buffer, ptr, len);
1204
- const decoder = new TextDecoder;
1205
- const str = decoder.decode(bagBytes);
1206
- try {
1207
- this.#context.bag = JSON.parse(str);
1208
- } catch (e) {
1209
- console.error("failed to deserialize bag", { json: str, error: e });
1210
- }
1211
- };
1212
1183
  system(label, system) {
1213
1184
  system.label ??= label;
1214
1185
  this.#systems.push(system);
1215
1186
  return this.#systems.length;
1216
1187
  }
1217
- systemsCallback(system_handle, ptr) {
1218
- const dv = new DataView(this.#engineBuffer, ptr);
1219
- const timeCtxPtr = dv.getUint32(TIME_CTX_OFFSET, true);
1220
- const inputCtxPtr = dv.getUint32(INPUT_CTX_OFFSET, true);
1221
- const eventsPtr = dv.getUint32(EVENTS_OFFSET, true);
1222
- this.#context.rawPointer = ptr;
1223
- this.#context.inputs.dataView = new DataView(this.#engineBuffer, inputCtxPtr);
1224
- this.#context.time.dataView = new DataView(this.#engineBuffer, timeCtxPtr);
1225
- const eventsDataView = new DataView(this.#engineBuffer, eventsPtr);
1226
- for (const system of this.#systems) {
1227
- system.update?.(this.#context);
1228
- const eventCount = eventsDataView.getUint32(0, true);
1229
- let offset = Uint32Array.BYTES_PER_ELEMENT;
1230
- for (let i = 0;i < eventCount; i++) {
1231
- const eventType = eventsDataView.getUint8(offset);
1232
- const payloadSize = EVENT_PAYLOAD_SIZE;
1233
- const payloadByte = eventsDataView.getUint8(offset + EVENT_PAYLOAD_ALIGN);
1234
- const payloadVec2 = {
1235
- x: eventsDataView.getFloat32(offset + EVENT_PAYLOAD_ALIGN, true),
1236
- y: eventsDataView.getFloat32(offset + EVENT_PAYLOAD_ALIGN + Float32Array.BYTES_PER_ELEMENT, true)
1237
- };
1238
- switch (eventType) {
1239
- case exports_enums.EventType.KeyDown: {
1240
- system.keydown?.(attachEvent(this.#context, {
1241
- key: keyCodeToKey(payloadByte)
1242
- }));
1243
- break;
1188
+ hooks = {
1189
+ serialize: () => {
1190
+ const str = JSON.stringify(this.#context.bag);
1191
+ const encoder = new TextEncoder;
1192
+ const textBytes = encoder.encode(str);
1193
+ return {
1194
+ size: textBytes.byteLength,
1195
+ write: (buffer, ptr) => {
1196
+ const memoryView = new Uint8Array(buffer, ptr, textBytes.byteLength);
1197
+ memoryView.set(textBytes);
1198
+ }
1199
+ };
1200
+ },
1201
+ deserialize: (buffer, ptr, len) => {
1202
+ const bagBytes = new Uint8Array(buffer, ptr, len);
1203
+ const decoder = new TextDecoder;
1204
+ const str = decoder.decode(bagBytes);
1205
+ try {
1206
+ this.#context.bag = JSON.parse(str);
1207
+ } catch (e) {
1208
+ console.error("failed to deserialize bag", { json: str, error: e });
1209
+ }
1210
+ },
1211
+ setBuffer: (buffer) => {
1212
+ this.#engineBuffer = buffer;
1213
+ },
1214
+ systemsCallback: (system_handle, ptr) => {
1215
+ const dv = new DataView(this.#engineBuffer, ptr);
1216
+ const timeCtxPtr = dv.getUint32(TIME_CTX_OFFSET, true);
1217
+ const inputCtxPtr = dv.getUint32(INPUT_CTX_OFFSET, true);
1218
+ const eventsPtr = dv.getUint32(EVENTS_OFFSET, true);
1219
+ this.#context.rawPointer = ptr;
1220
+ this.#context.inputs.dataView = new DataView(this.#engineBuffer, inputCtxPtr);
1221
+ this.#context.time.dataView = new DataView(this.#engineBuffer, timeCtxPtr);
1222
+ const eventsDataView = new DataView(this.#engineBuffer, eventsPtr);
1223
+ for (const system of this.#systems) {
1224
+ system.update?.(this.#context);
1225
+ const eventCount = eventsDataView.getUint32(0, true);
1226
+ let offset = Uint32Array.BYTES_PER_ELEMENT;
1227
+ for (let i = 0;i < eventCount; i++) {
1228
+ const eventType = eventsDataView.getUint8(offset);
1229
+ const payloadSize = EVENT_PAYLOAD_SIZE;
1230
+ const payloadByte = eventsDataView.getUint8(offset + EVENT_PAYLOAD_ALIGN);
1231
+ const payloadVec2 = {
1232
+ x: eventsDataView.getFloat32(offset + EVENT_PAYLOAD_ALIGN, true),
1233
+ y: eventsDataView.getFloat32(offset + EVENT_PAYLOAD_ALIGN + Float32Array.BYTES_PER_ELEMENT, true)
1234
+ };
1235
+ switch (eventType) {
1236
+ case exports_enums.EventType.KeyDown: {
1237
+ system.keydown?.(attachEvent(this.#context, {
1238
+ key: keyCodeToKey(payloadByte)
1239
+ }));
1240
+ break;
1241
+ }
1242
+ case exports_enums.EventType.KeyUp:
1243
+ system.keyup?.(attachEvent(this.#context, {
1244
+ key: keyCodeToKey(payloadByte)
1245
+ }));
1246
+ break;
1247
+ case exports_enums.EventType.MouseDown:
1248
+ system.mousedown?.(attachEvent(this.#context, {
1249
+ button: mouseButtonCodeToMouseButton(payloadByte)
1250
+ }));
1251
+ break;
1252
+ case exports_enums.EventType.MouseUp:
1253
+ system.mouseup?.(attachEvent(this.#context, {
1254
+ button: mouseButtonCodeToMouseButton(payloadByte)
1255
+ }));
1256
+ break;
1257
+ case exports_enums.EventType.MouseMove:
1258
+ system.mousemove?.(attachEvent(this.#context, {
1259
+ x: payloadVec2.x,
1260
+ y: payloadVec2.y
1261
+ }));
1262
+ break;
1263
+ case exports_enums.EventType.MouseWheel:
1264
+ system.mousewheel?.(attachEvent(this.#context, {
1265
+ x: payloadVec2.x,
1266
+ y: payloadVec2.y
1267
+ }));
1268
+ break;
1269
+ default:
1270
+ throw new Error(`Unknown event type: ${eventType}`);
1244
1271
  }
1245
- case exports_enums.EventType.KeyUp:
1246
- system.keyup?.(attachEvent(this.#context, {
1247
- key: keyCodeToKey(payloadByte)
1248
- }));
1249
- break;
1250
- case exports_enums.EventType.MouseDown:
1251
- system.mousedown?.(attachEvent(this.#context, {
1252
- button: mouseButtonCodeToMouseButton(payloadByte)
1253
- }));
1254
- break;
1255
- case exports_enums.EventType.MouseUp:
1256
- system.mouseup?.(attachEvent(this.#context, {
1257
- button: mouseButtonCodeToMouseButton(payloadByte)
1258
- }));
1259
- break;
1260
- case exports_enums.EventType.MouseMove:
1261
- system.mousemove?.(attachEvent(this.#context, {
1262
- x: payloadVec2.x,
1263
- y: payloadVec2.y
1264
- }));
1265
- break;
1266
- case exports_enums.EventType.MouseWheel:
1267
- system.mousewheel?.(attachEvent(this.#context, {
1268
- x: payloadVec2.x,
1269
- y: payloadVec2.y
1270
- }));
1271
- break;
1272
- default:
1273
- throw new Error(`Unknown event type: ${eventType}`);
1272
+ offset += EVENT_PAYLOAD_ALIGN + EVENT_PAYLOAD_SIZE;
1274
1273
  }
1275
- offset += EVENT_PAYLOAD_ALIGN + EVENT_PAYLOAD_SIZE;
1274
+ this.#context.event = undefined;
1276
1275
  }
1277
- this.#context.event = undefined;
1278
1276
  }
1279
- }
1280
- setBuffer(buffer) {
1281
- this.#engineBuffer = buffer;
1282
- }
1277
+ };
1283
1278
  }
1284
1279
  function attachEvent(context, event) {
1285
1280
  context.event = event;
@@ -1288,9 +1283,8 @@ function attachEvent(context, event) {
1288
1283
  export {
1289
1284
  mount,
1290
1285
  exports_util as Util,
1291
- Runtime,
1292
1286
  Bloop
1293
1287
  };
1294
1288
 
1295
- //# debugId=586D28D5F65F094D64756E2164756E21
1289
+ //# debugId=43C3568B8A190DC064756E2164756E21
1296
1290
  //# sourceMappingURL=mod.js.map