@react-text-game/core 0.1.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 (178) hide show
  1. package/README.md +744 -0
  2. package/dist/baseGameObject.d.ts +90 -0
  3. package/dist/baseGameObject.d.ts.map +1 -0
  4. package/dist/baseGameObject.js +109 -0
  5. package/dist/baseGameObject.js.map +1 -0
  6. package/dist/constants.d.ts +12 -0
  7. package/dist/constants.d.ts.map +1 -0
  8. package/dist/constants.js +12 -0
  9. package/dist/constants.js.map +1 -0
  10. package/dist/game.d.ts +294 -0
  11. package/dist/game.d.ts.map +1 -0
  12. package/dist/game.js +489 -0
  13. package/dist/game.js.map +1 -0
  14. package/dist/helpers.d.ts +2 -0
  15. package/dist/helpers.d.ts.map +1 -0
  16. package/dist/helpers.js +6 -0
  17. package/dist/helpers.js.map +1 -0
  18. package/dist/hooks/index.d.ts +4 -0
  19. package/dist/hooks/index.d.ts.map +1 -0
  20. package/dist/hooks/index.js +4 -0
  21. package/dist/hooks/index.js.map +1 -0
  22. package/dist/hooks/useCurrentPassage.d.ts +10 -0
  23. package/dist/hooks/useCurrentPassage.d.ts.map +1 -0
  24. package/dist/hooks/useCurrentPassage.js +17 -0
  25. package/dist/hooks/useCurrentPassage.js.map +1 -0
  26. package/dist/hooks/useGameEntity.d.ts +21 -0
  27. package/dist/hooks/useGameEntity.d.ts.map +1 -0
  28. package/dist/hooks/useGameEntity.js +70 -0
  29. package/dist/hooks/useGameEntity.js.map +1 -0
  30. package/dist/hooks/useGameIsStarted.d.ts +12 -0
  31. package/dist/hooks/useGameIsStarted.d.ts.map +1 -0
  32. package/dist/hooks/useGameIsStarted.js +18 -0
  33. package/dist/hooks/useGameIsStarted.js.map +1 -0
  34. package/dist/index.d.ts +12 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +10 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/logger.d.ts +8 -0
  39. package/dist/logger.d.ts.map +1 -0
  40. package/dist/logger.js +36 -0
  41. package/dist/logger.js.map +1 -0
  42. package/dist/options.d.ts +13 -0
  43. package/dist/options.d.ts.map +1 -0
  44. package/dist/options.js +15 -0
  45. package/dist/options.js.map +1 -0
  46. package/dist/passages/interactiveMap/fabric.d.ts +4 -0
  47. package/dist/passages/interactiveMap/fabric.d.ts.map +1 -0
  48. package/dist/passages/interactiveMap/fabric.js +3 -0
  49. package/dist/passages/interactiveMap/fabric.js.map +1 -0
  50. package/dist/passages/interactiveMap/index.d.ts +4 -0
  51. package/dist/passages/interactiveMap/index.d.ts.map +1 -0
  52. package/dist/passages/interactiveMap/index.js +4 -0
  53. package/dist/passages/interactiveMap/index.js.map +1 -0
  54. package/dist/passages/interactiveMap/interactiveMap.d.ts +89 -0
  55. package/dist/passages/interactiveMap/interactiveMap.d.ts.map +1 -0
  56. package/dist/passages/interactiveMap/interactiveMap.js +103 -0
  57. package/dist/passages/interactiveMap/interactiveMap.js.map +1 -0
  58. package/dist/passages/interactiveMap/types.d.ts +822 -0
  59. package/dist/passages/interactiveMap/types.d.ts.map +1 -0
  60. package/dist/passages/interactiveMap/types.js +2 -0
  61. package/dist/passages/interactiveMap/types.js.map +1 -0
  62. package/dist/passages/passage.d.ts +57 -0
  63. package/dist/passages/passage.d.ts.map +1 -0
  64. package/dist/passages/passage.js +64 -0
  65. package/dist/passages/passage.js.map +1 -0
  66. package/dist/passages/story/fabric.d.ts +4 -0
  67. package/dist/passages/story/fabric.d.ts.map +1 -0
  68. package/dist/passages/story/fabric.js +3 -0
  69. package/dist/passages/story/fabric.js.map +1 -0
  70. package/dist/passages/story/index.d.ts +5 -0
  71. package/dist/passages/story/index.d.ts.map +1 -0
  72. package/dist/passages/story/index.js +5 -0
  73. package/dist/passages/story/index.js.map +1 -0
  74. package/dist/passages/story/start.d.ts +14 -0
  75. package/dist/passages/story/start.d.ts.map +1 -0
  76. package/dist/passages/story/start.js +22 -0
  77. package/dist/passages/story/start.js.map +1 -0
  78. package/dist/passages/story/story.d.ts +84 -0
  79. package/dist/passages/story/story.d.ts.map +1 -0
  80. package/dist/passages/story/story.js +88 -0
  81. package/dist/passages/story/story.js.map +1 -0
  82. package/dist/passages/story/types.d.ts +911 -0
  83. package/dist/passages/story/types.d.ts.map +1 -0
  84. package/dist/passages/story/types.js +2 -0
  85. package/dist/passages/story/types.js.map +1 -0
  86. package/dist/passages/types/index.d.ts +3 -0
  87. package/dist/passages/types/index.d.ts.map +1 -0
  88. package/dist/passages/types/index.js +2 -0
  89. package/dist/passages/types/index.js.map +1 -0
  90. package/dist/passages/widget.d.ts +62 -0
  91. package/dist/passages/widget.d.ts.map +1 -0
  92. package/dist/passages/widget.js +66 -0
  93. package/dist/passages/widget.js.map +1 -0
  94. package/dist/saves/constants.d.ts +17 -0
  95. package/dist/saves/constants.d.ts.map +1 -0
  96. package/dist/saves/constants.js +17 -0
  97. package/dist/saves/constants.js.map +1 -0
  98. package/dist/saves/db.d.ts +119 -0
  99. package/dist/saves/db.d.ts.map +1 -0
  100. package/dist/saves/db.js +231 -0
  101. package/dist/saves/db.js.map +1 -0
  102. package/dist/saves/helpers.d.ts +28 -0
  103. package/dist/saves/helpers.d.ts.map +1 -0
  104. package/dist/saves/helpers.js +84 -0
  105. package/dist/saves/helpers.js.map +1 -0
  106. package/dist/saves/hooks/index.d.ts +10 -0
  107. package/dist/saves/hooks/index.d.ts.map +1 -0
  108. package/dist/saves/hooks/index.js +10 -0
  109. package/dist/saves/hooks/index.js.map +1 -0
  110. package/dist/saves/hooks/useDeleteAllSlots.d.ts +18 -0
  111. package/dist/saves/hooks/useDeleteAllSlots.d.ts.map +1 -0
  112. package/dist/saves/hooks/useDeleteAllSlots.js +18 -0
  113. package/dist/saves/hooks/useDeleteAllSlots.js.map +1 -0
  114. package/dist/saves/hooks/useDeleteGame.d.ts +22 -0
  115. package/dist/saves/hooks/useDeleteGame.d.ts.map +1 -0
  116. package/dist/saves/hooks/useDeleteGame.js +33 -0
  117. package/dist/saves/hooks/useDeleteGame.js.map +1 -0
  118. package/dist/saves/hooks/useExportSaves.d.ts +27 -0
  119. package/dist/saves/hooks/useExportSaves.d.ts.map +1 -0
  120. package/dist/saves/hooks/useExportSaves.js +54 -0
  121. package/dist/saves/hooks/useExportSaves.js.map +1 -0
  122. package/dist/saves/hooks/useImportSaves.d.ts +29 -0
  123. package/dist/saves/hooks/useImportSaves.d.ts.map +1 -0
  124. package/dist/saves/hooks/useImportSaves.js +108 -0
  125. package/dist/saves/hooks/useImportSaves.js.map +1 -0
  126. package/dist/saves/hooks/useLastLoadGame.d.ts +39 -0
  127. package/dist/saves/hooks/useLastLoadGame.d.ts.map +1 -0
  128. package/dist/saves/hooks/useLastLoadGame.js +72 -0
  129. package/dist/saves/hooks/useLastLoadGame.js.map +1 -0
  130. package/dist/saves/hooks/useLoadGame.d.ts +22 -0
  131. package/dist/saves/hooks/useLoadGame.d.ts.map +1 -0
  132. package/dist/saves/hooks/useLoadGame.js +40 -0
  133. package/dist/saves/hooks/useLoadGame.js.map +1 -0
  134. package/dist/saves/hooks/useRestartGame.d.ts +20 -0
  135. package/dist/saves/hooks/useRestartGame.d.ts.map +1 -0
  136. package/dist/saves/hooks/useRestartGame.js +29 -0
  137. package/dist/saves/hooks/useRestartGame.js.map +1 -0
  138. package/dist/saves/hooks/useSaveGame.d.ts +22 -0
  139. package/dist/saves/hooks/useSaveGame.d.ts.map +1 -0
  140. package/dist/saves/hooks/useSaveGame.js +34 -0
  141. package/dist/saves/hooks/useSaveGame.js.map +1 -0
  142. package/dist/saves/hooks/useSaveSlots.d.ts +45 -0
  143. package/dist/saves/hooks/useSaveSlots.d.ts.map +1 -0
  144. package/dist/saves/hooks/useSaveSlots.js +42 -0
  145. package/dist/saves/hooks/useSaveSlots.js.map +1 -0
  146. package/dist/saves/index.d.ts +4 -0
  147. package/dist/saves/index.d.ts.map +1 -0
  148. package/dist/saves/index.js +3 -0
  149. package/dist/saves/index.js.map +1 -0
  150. package/dist/saves/types.d.ts +52 -0
  151. package/dist/saves/types.d.ts.map +1 -0
  152. package/dist/saves/types.js +2 -0
  153. package/dist/saves/types.js.map +1 -0
  154. package/dist/storage.d.ts +124 -0
  155. package/dist/storage.d.ts.map +1 -0
  156. package/dist/storage.js +229 -0
  157. package/dist/storage.js.map +1 -0
  158. package/dist/tests/game.test.d.ts +2 -0
  159. package/dist/tests/game.test.d.ts.map +1 -0
  160. package/dist/tests/game.test.js +602 -0
  161. package/dist/tests/game.test.js.map +1 -0
  162. package/dist/tests/interactiveMap.test.d.ts +2 -0
  163. package/dist/tests/interactiveMap.test.d.ts.map +1 -0
  164. package/dist/tests/interactiveMap.test.js +1003 -0
  165. package/dist/tests/interactiveMap.test.js.map +1 -0
  166. package/dist/tests/storage.test.d.ts +2 -0
  167. package/dist/tests/storage.test.d.ts.map +1 -0
  168. package/dist/tests/storage.test.js +328 -0
  169. package/dist/tests/storage.test.js.map +1 -0
  170. package/dist/tests/story.test.d.ts +2 -0
  171. package/dist/tests/story.test.d.ts.map +1 -0
  172. package/dist/tests/story.test.js +698 -0
  173. package/dist/tests/story.test.js.map +1 -0
  174. package/dist/types.d.ts +19 -0
  175. package/dist/types.d.ts.map +1 -0
  176. package/dist/types.js +2 -0
  177. package/dist/types.js.map +1 -0
  178. package/package.json +60 -0
package/dist/game.js ADDED
@@ -0,0 +1,489 @@
1
+ import { proxy, subscribe } from "valtio";
2
+ import { STORAGE_SYSTEM_PATH, SYSTEM_PASSAGE_NAMES } from "./constants";
3
+ import { logger } from "./logger";
4
+ import { _getOptions, newOptions } from "./options";
5
+ import { createOrUpdateSystemSave } from "./saves";
6
+ import { Storage } from "./storage";
7
+ const objectRegistry = new Map();
8
+ const passagesRegistry = new Map();
9
+ const jsonPath = `${STORAGE_SYSTEM_PATH}.game`;
10
+ /**
11
+ * Central orchestrator for the text game engine.
12
+ *
13
+ * The `Game` class manages all core game functionality including:
14
+ * - Entity registration and proxying with Valtio for reactive state
15
+ * - Passage registration and navigation
16
+ * - State serialization and persistence
17
+ * - Auto-save to session storage with debouncing
18
+ *
19
+ * All entities and passages are automatically registered through their constructors,
20
+ * and the Game provides static methods for navigation and state management.
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * // Create entities and passages (auto-registered)
25
+ * const player = new Player();
26
+ * const intro = newStory('intro', () => [...]);
27
+ *
28
+ * // Navigate
29
+ * Game.jumpTo('intro');
30
+ *
31
+ * // Save/Load
32
+ * const state = Game.getState();
33
+ * Game.setState(state);
34
+ *
35
+ * // Auto-save
36
+ * Game.enableAutoSave();
37
+ * Game.loadFromSessionStorage();
38
+ * ```
39
+ */
40
+ export class Game {
41
+ static state = proxy({
42
+ currentPassageId: null,
43
+ });
44
+ static initialized = false;
45
+ static autoSaveEnabled = false;
46
+ static saveTimer = null;
47
+ static unsubscribeFunctions = [];
48
+ static AUTO_SAVE_KEY = "gameAutoSave";
49
+ static SAVE_DEBOUNCE_MS = 500;
50
+ /**
51
+ * Ensures the game has been initialized before allowing method calls.
52
+ *
53
+ * @private
54
+ * @throws Error if Game.init() has not been called
55
+ */
56
+ static ensureInitialized() {
57
+ if (!Game.initialized) {
58
+ throw new Error("Game not initialized. Please call Game.init() before using the game engine.");
59
+ }
60
+ }
61
+ /**
62
+ * Registers and proxies the provided game objects for further use by adding them to the object registry.
63
+ *
64
+ * @param {...BaseGameObject[]} objects - The array of BaseGameObject instances to be registered.
65
+ * @return {void} This method does not return a value.
66
+ */
67
+ static registerEntity(...objects) {
68
+ objects.forEach((object) => {
69
+ if (objectRegistry.has(object.id)) {
70
+ throw new Error(`Object "${object.id}" is already registered.`);
71
+ }
72
+ const proxiedObject = proxy(object);
73
+ objectRegistry.set(object.id, proxiedObject);
74
+ logger.log(`Registered entity: ${object.id}`);
75
+ });
76
+ }
77
+ /**
78
+ * Registers one or more passages into the passage registry. Each passage must have a unique identifier.
79
+ * Throws an error if a passage with the same id is already registered.
80
+ *
81
+ * @param {...Passage} passages The passages to be registered. Each passage should be an object containing an `id` property.
82
+ * @return {void} Does not return a value.
83
+ * @throws Error if Game.init() has not been called
84
+ */
85
+ static registerPassage(...passages) {
86
+ const systemPassages = Object.values(SYSTEM_PASSAGE_NAMES);
87
+ passages.forEach((passage) => {
88
+ if (passagesRegistry.has(passage.id) &&
89
+ // letting user to re-register system passages
90
+ !systemPassages.includes(passage.id)) {
91
+ throw new Error(`Passage "${passage.id}" is already registered.`);
92
+ }
93
+ passagesRegistry.set(passage.id, passage);
94
+ logger.log(`Registered passage: ${passage.id}`);
95
+ });
96
+ }
97
+ /**
98
+ * Retrieves all registered passages from the passage registry.
99
+ *
100
+ * @return {IterableIterator<Passage>} An iterator containing all the Passage objects.
101
+ * @throws Error if Game.init() has not been called
102
+ */
103
+ static get registeredPassages() {
104
+ return passagesRegistry.values();
105
+ }
106
+ /**
107
+ * Retrieves the current passage from the passage registry based on the current passage ID in the game state.
108
+ * If the current passage ID is null or the passage cannot be found, returns null.
109
+ *
110
+ * @return {Passage | null} The current passage object or null if not available.
111
+ * @throws Error if Game.init() has not been called
112
+ */
113
+ static get currentPassage() {
114
+ Game.ensureInitialized();
115
+ if (Game.state.currentPassageId === null) {
116
+ return null;
117
+ }
118
+ return passagesRegistry.get(Game.state.currentPassageId) || null;
119
+ }
120
+ /**
121
+ * Retrieves a passage by its unique identifier.
122
+ *
123
+ * @param {string} passageId - The unique ID of the passage to retrieve.
124
+ * @return {Passage|null} The passage object if found, or null if no passage exists with the given ID.
125
+ * @throws Error if Game.init() has not been called
126
+ */
127
+ static getPassageById(passageId) {
128
+ Game.ensureInitialized();
129
+ return passagesRegistry.get(passageId) || null;
130
+ }
131
+ /**
132
+ * Retrieves all the passages from the passages registry.
133
+ *
134
+ * @return {Array<Passage>} An array containing all the Passage objects.
135
+ * @throws Error if Game.init() has not been called
136
+ */
137
+ static getAllPassages() {
138
+ Game.ensureInitialized();
139
+ return Array.from(passagesRegistry.values());
140
+ }
141
+ /**
142
+ * Navigates the game to a specified passage.
143
+ *
144
+ * @param {Passage|string} passage - The passage object or identifier of the passage to jump to.
145
+ * @return {void} Does not return any value.
146
+ * @throws {Error} Throws an error if the specified passage is not found or if Game.init() has not been called
147
+ */
148
+ static jumpTo(passage) {
149
+ Game.ensureInitialized();
150
+ const passageId = typeof passage === "string" ? passage : passage.id;
151
+ const retrievedPassage = passagesRegistry.get(passageId) || null;
152
+ if (!retrievedPassage) {
153
+ throw new Error(`Passage "${passageId}" not found.`);
154
+ }
155
+ Game.state.currentPassageId = retrievedPassage
156
+ ? retrievedPassage.id
157
+ : null;
158
+ logger.log(`Jumped to passage: ${passageId}`);
159
+ }
160
+ /**
161
+ * Sets the current passage in the game state.
162
+ *
163
+ * @param {Passage|string} passage - The passage to be set as current. Can be either a Passage object or a string representing the passage ID.
164
+ * @return {void} This method does not return a value.
165
+ * @throws Error if Game.init() has not been called
166
+ */
167
+ static setCurrent(passage) {
168
+ Game.ensureInitialized();
169
+ Game.state.currentPassageId =
170
+ typeof passage === "string" ? passage : passage.id;
171
+ logger.log(`Set current passage: ${Game.state.currentPassageId}`);
172
+ }
173
+ /**
174
+ * Retrieves the proxied object from the object registry based on its ID.
175
+ * If the object is not found in the registry, the original object is returned.
176
+ *
177
+ * @internal - Used by hooks for reactive state management
178
+ * @param object - The original object to find in the registry
179
+ * @returns The proxied object from the registry if present, otherwise the original object
180
+ */
181
+ static _getProxiedObject(object) {
182
+ return objectRegistry.get(object.id) || object;
183
+ }
184
+ /**
185
+ * Retrieves all proxied objects from the object registry.
186
+ *
187
+ * @internal - Used for batch operations during save/load
188
+ * @returns An array of BaseGameObject instances stored in the object registry
189
+ */
190
+ static _getAllProxiedObjects() {
191
+ return Array.from(objectRegistry.values());
192
+ }
193
+ /**
194
+ * Provides access to the internal game state for reactive hooks.
195
+ *
196
+ * @returns The game's internal reactive state
197
+ * @throws Error if Game.init() has not been called
198
+ */
199
+ static get selfState() {
200
+ Game.ensureInitialized();
201
+ return Game.state;
202
+ }
203
+ /**
204
+ * Saves the current game state, including critical passage information, into storage.
205
+ *
206
+ * This method saves the Game's internal state (current passage) to the Storage system.
207
+ * It does NOT save entity states - use entity.save() or Game.getState() for that.
208
+ *
209
+ * @private - Called internally by Game.getState()
210
+ */
211
+ static save() {
212
+ const internalState = {
213
+ currentPassageId: Game.state.currentPassageId,
214
+ };
215
+ Storage.setValue(jsonPath, internalState, true);
216
+ logger.log(`Game state saved: ${JSON.stringify(internalState)}`);
217
+ }
218
+ /**
219
+ * Loads the saved game state from storage and sets the current passage ID in the game state.
220
+ *
221
+ * @private - Called internally by Game.setState()
222
+ * @throws Error if no saved state is found
223
+ */
224
+ static load() {
225
+ const savedState = Storage.getValue(jsonPath);
226
+ if (!savedState.length) {
227
+ throw new Error("No saved state found.");
228
+ }
229
+ const { currentPassageId } = savedState[0];
230
+ Game.state.currentPassageId = currentPassageId || null;
231
+ logger.log(`Game state loaded: ${JSON.stringify(savedState[0])}`);
232
+ }
233
+ /**
234
+ * Captures the complete game state including all entities and passages.
235
+ *
236
+ * This method:
237
+ * 1. Saves the Game's internal state (current passage)
238
+ * 2. Saves all registered entity states
239
+ * 3. Returns the complete state object
240
+ *
241
+ * @returns The complete serializable game state
242
+ * @throws Error if Game.init() has not been called
243
+ *
244
+ * @example
245
+ * ```typescript
246
+ * const savedState = Game.getState();
247
+ * localStorage.setItem('save1', JSON.stringify(savedState));
248
+ * ```
249
+ */
250
+ static getState(_fromI = false) {
251
+ if (!_fromI) {
252
+ Game.ensureInitialized();
253
+ }
254
+ Game.save();
255
+ for (const [, object] of objectRegistry) {
256
+ object.save();
257
+ }
258
+ return Storage.getState();
259
+ }
260
+ /**
261
+ * Restores the complete game state including all entities and passages.
262
+ *
263
+ * This method:
264
+ * 1. Sets the Storage state
265
+ * 2. Loads the Game's internal state (current passage)
266
+ * 3. Loads all registered entity states
267
+ *
268
+ * @param state - The game state to restore
269
+ * @throws Error if Game.init() has not been called
270
+ *
271
+ * @example
272
+ * ```typescript
273
+ * const savedState = JSON.parse(localStorage.getItem('save1'));
274
+ * Game.setState(savedState);
275
+ * ```
276
+ */
277
+ static setState(state) {
278
+ Game.ensureInitialized();
279
+ Storage.setState(state);
280
+ Game.load();
281
+ for (const [, object] of objectRegistry) {
282
+ object.load();
283
+ }
284
+ }
285
+ /**
286
+ * Saves the current game state to session storage with debouncing.
287
+ *
288
+ * Uses a 500ms debounce to prevent excessive writes during rapid state changes.
289
+ *
290
+ * @private - Called automatically when auto-save is enabled
291
+ */
292
+ static saveToSessionStorage() {
293
+ if (Game.saveTimer) {
294
+ clearTimeout(Game.saveTimer);
295
+ }
296
+ Game.saveTimer = setTimeout(() => {
297
+ const state = Game.getState();
298
+ sessionStorage.setItem(Game.AUTO_SAVE_KEY, JSON.stringify(state));
299
+ }, Game.SAVE_DEBOUNCE_MS);
300
+ }
301
+ /**
302
+ * Enables auto-save functionality.
303
+ *
304
+ * Subscribes to all game state changes (Game state and all entity states)
305
+ * and automatically saves to session storage with 500ms debouncing.
306
+ *
307
+ * @throws Error if Game.init() has not been called
308
+ *
309
+ * @example
310
+ * ```typescript
311
+ * Game.enableAutoSave();
312
+ * // Now any state change will auto-save after 500ms
313
+ * player.health = 50; // Will trigger auto-save
314
+ * ```
315
+ */
316
+ static enableAutoSave() {
317
+ Game.ensureInitialized();
318
+ if (Game.autoSaveEnabled) {
319
+ logger.warn("Auto-save is already enabled");
320
+ return;
321
+ }
322
+ Game.autoSaveEnabled = true;
323
+ // Subscribe to Game state changes
324
+ const unsubGame = subscribe(Game.state, () => {
325
+ Game.saveToSessionStorage();
326
+ });
327
+ Game.unsubscribeFunctions.push(unsubGame);
328
+ // Subscribe to all registered entities
329
+ for (const [, object] of objectRegistry) {
330
+ const unsubEntity = subscribe(object, () => {
331
+ Game.saveToSessionStorage();
332
+ });
333
+ Game.unsubscribeFunctions.push(unsubEntity);
334
+ }
335
+ logger.log("Auto-save enabled");
336
+ }
337
+ /**
338
+ * Disables auto-save functionality and clears all subscriptions.
339
+ *
340
+ * Cleans up all Valtio subscriptions and cancels any pending debounced saves.
341
+ *
342
+ * @throws Error if Game.init() has not been called
343
+ */
344
+ static disableAutoSave() {
345
+ Game.ensureInitialized();
346
+ if (!Game.autoSaveEnabled) {
347
+ logger.warn("Auto-save is already disabled");
348
+ return;
349
+ }
350
+ // Clear debounce timer
351
+ if (Game.saveTimer) {
352
+ clearTimeout(Game.saveTimer);
353
+ Game.saveTimer = null;
354
+ }
355
+ // Unsubscribe all listeners
356
+ Game.unsubscribeFunctions.forEach((unsubscribe) => unsubscribe());
357
+ Game.unsubscribeFunctions = [];
358
+ Game.autoSaveEnabled = false;
359
+ logger.log("Auto-save disabled");
360
+ }
361
+ /**
362
+ * Loads game state from session storage if available.
363
+ *
364
+ * @returns True if state was loaded successfully, false otherwise
365
+ * @throws Error if Game.init() has not been called
366
+ *
367
+ * @example
368
+ * ```typescript
369
+ * if (Game.loadFromSessionStorage()) {
370
+ * console.log('Game loaded from auto-save');
371
+ * } else {
372
+ * Game.jumpTo('start');
373
+ * }
374
+ * ```
375
+ */
376
+ static loadFromSessionStorage() {
377
+ Game.ensureInitialized();
378
+ const savedState = sessionStorage.getItem(Game.AUTO_SAVE_KEY);
379
+ if (!savedState) {
380
+ return false;
381
+ }
382
+ try {
383
+ const state = JSON.parse(savedState);
384
+ Game.setState(state);
385
+ logger.log("Game state loaded from session storage");
386
+ return true;
387
+ }
388
+ catch (error) {
389
+ logger.error("Failed to load state from session storage:", error);
390
+ return false;
391
+ }
392
+ }
393
+ /**
394
+ * Clears the auto-saved state from session storage.
395
+ *
396
+ * @throws Error if Game.init() has not been called
397
+ *
398
+ * @example
399
+ * ```typescript
400
+ * Game.clearAutoSave(); // Remove auto-save data
401
+ * ```
402
+ */
403
+ static clearAutoSave() {
404
+ Game.ensureInitialized();
405
+ sessionStorage.removeItem(Game.AUTO_SAVE_KEY);
406
+ logger.log("Auto-save data cleared from session storage");
407
+ }
408
+ /**
409
+ * Initializes the game engine with the provided options.
410
+ *
411
+ * This method MUST be called before any other Game methods can be used.
412
+ * Calling this method marks the Game as initialized and allows access to all other functionality.
413
+ *
414
+ * Optionally integrates with `@react-text-game/saves` package if installed.
415
+ *
416
+ * @param opts - Configuration options for the game
417
+ * @returns Promise that resolves when initialization is complete
418
+ *
419
+ * @example
420
+ * ```typescript
421
+ * await Game.init({
422
+ * // your options here
423
+ * });
424
+ *
425
+ * // Now you can use other Game methods
426
+ * Game.jumpTo('start');
427
+ * ```
428
+ */
429
+ static async init(opts) {
430
+ newOptions(opts);
431
+ Game.initialized = true;
432
+ if (Game.options.isDevMode) {
433
+ logger.warn("Game is running in dev mode, do not use in production!");
434
+ }
435
+ Game.setCurrent(SYSTEM_PASSAGE_NAMES.START_MENU);
436
+ const initialState = Game.getState(true);
437
+ await createOrUpdateSystemSave(initialState);
438
+ if (!Game.options.isDevMode) {
439
+ Game.loadFromSessionStorage();
440
+ Game.enableAutoSave();
441
+ }
442
+ else {
443
+ logger.warn("Save to session storage is turned off due to dev mode");
444
+ }
445
+ logger.log(`Game initialized with options: ${JSON.stringify(opts)}`);
446
+ }
447
+ /**
448
+ * Gets the game options.
449
+ *
450
+ * @returns The current game options
451
+ * @throws Error if Game.init() has not been called
452
+ */
453
+ static get options() {
454
+ Game.ensureInitialized();
455
+ return _getOptions();
456
+ }
457
+ /**
458
+ * Updates the game options with the provided settings.
459
+ *
460
+ * @param {NewOptions} options - The new options to update the game configuration.
461
+ * @return {void} No return value.
462
+ */
463
+ static updateOptions(options) {
464
+ Game.ensureInitialized();
465
+ newOptions(options);
466
+ }
467
+ /**
468
+ * Resets the game state for testing purposes.
469
+ *
470
+ * Clears all entity and passage registries, disables auto-save, and resets initialization state.
471
+ * This method is intended for use in test environments only.
472
+ *
473
+ * @internal
474
+ */
475
+ static _resetForTesting() {
476
+ // Disable auto-save if enabled
477
+ if (Game.autoSaveEnabled) {
478
+ Game.disableAutoSave();
479
+ }
480
+ // Clear all registries
481
+ objectRegistry.clear();
482
+ passagesRegistry.clear();
483
+ // Reset initialization state
484
+ Game.initialized = false;
485
+ // Reset state
486
+ Game.state.currentPassageId = null;
487
+ }
488
+ }
489
+ //# sourceMappingURL=game.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"game.js","sourceRoot":"","sources":["../src/game.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const callIfFunction: <T, Props>(value: T | ((props: Props | undefined) => T), props?: Props | undefined) => T;
2
+ //# sourceMappingURL=helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc,GAAI,CAAC,EAAE,KAAK,EACnC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,GAAG,SAAS,KAAK,CAAC,CAAC,EAC5C,QAAQ,KAAK,GAAG,SAAS,KAC1B,CAIF,CAAC"}
@@ -0,0 +1,6 @@
1
+ export const callIfFunction = (value, props) => {
2
+ return typeof value === "function"
3
+ ? value(props)
4
+ : value;
5
+ };
6
+ //# sourceMappingURL=helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,cAAc,GAAG,CAC1B,KAA4C,EAC5C,KAAyB,EACxB,EAAE;IACH,OAAO,OAAO,KAAK,KAAK,UAAU;QAC9B,CAAC,CAAE,KAAyC,CAAC,KAAK,CAAC;QACnD,CAAC,CAAC,KAAK,CAAC;AAChB,CAAC,CAAC"}
@@ -0,0 +1,4 @@
1
+ export * from './useCurrentPassage';
2
+ export * from './useGameEntity';
3
+ export * from './useGameIsStarted';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC"}
@@ -0,0 +1,4 @@
1
+ export * from './useCurrentPassage';
2
+ export * from './useGameEntity';
3
+ export * from './useGameIsStarted';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { Passage } from "../passages/passage";
2
+ /**
3
+ * Retrieves the current passage in the game based on the reactive game state.
4
+ * If there is no current passage ID, the function returns null.
5
+ *
6
+ * @function
7
+ * @returns {Passage | null} The current passage object, or null if no passage is active.
8
+ */
9
+ export declare const useCurrentPassage: () => Passage | null;
10
+ //# sourceMappingURL=useCurrentPassage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCurrentPassage.d.ts","sourceRoot":"","sources":["../../src/hooks/useCurrentPassage.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAE5C;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,QAAO,OAAO,GAAG,IAQ9C,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { useProxy } from "valtio/utils";
2
+ import { Game } from "../game";
3
+ /**
4
+ * Retrieves the current passage in the game based on the reactive game state.
5
+ * If there is no current passage ID, the function returns null.
6
+ *
7
+ * @function
8
+ * @returns {Passage | null} The current passage object, or null if no passage is active.
9
+ */
10
+ export const useCurrentPassage = () => {
11
+ const reactiveGameState = useProxy(Game.selfState);
12
+ if (reactiveGameState.currentPassageId === null) {
13
+ return null;
14
+ }
15
+ return Game.getPassageById(reactiveGameState.currentPassageId);
16
+ };
17
+ //# sourceMappingURL=useCurrentPassage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCurrentPassage.js","sourceRoot":"","sources":["../../src/hooks/useCurrentPassage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExC,OAAO,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC;AAG7B;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAmB,EAAE;IAClD,MAAM,iBAAiB,GAAG,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAEnD,IAAI,iBAAiB,CAAC,gBAAgB,KAAK,IAAI,EAAE,CAAC;QAC9C,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,OAAO,IAAI,CAAC,cAAc,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,CAAC;AACnE,CAAC,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { BaseGameObject } from "../baseGameObject";
2
+ /**
3
+ * Monitors changes to a given game entity by wrapping it in a Valtio proxy.
4
+ * This hook enables React components to automatically re-render when the entity's state changes.
5
+ *
6
+ * @param gameObject - The game entity to observe. Must extend BaseGameObject and be registered.
7
+ * @return The proxied game entity that triggers re-renders on state changes.
8
+ *
9
+ * @example
10
+ * ```tsx
11
+ * import { useGameEntity } from "@app/hooks";
12
+ * import { environment } from "@game/entities/environment";
13
+ *
14
+ * function TemperatureDisplay() {
15
+ * const env = useGameEntity(environment);
16
+ * return <div>Temperature: {env.variables.temperature}°C</div>;
17
+ * }
18
+ * ```
19
+ */
20
+ export declare function useGameEntity<T extends BaseGameObject>(gameObject: T): T;
21
+ //# sourceMappingURL=useGameEntity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useGameEntity.d.ts","sourceRoot":"","sources":["../../src/hooks/useGameEntity.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAqCjD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,cAAc,EAAE,UAAU,EAAE,CAAC,GAAG,CAAC,CAexE"}
@@ -0,0 +1,70 @@
1
+ import { useProxy } from "valtio/utils";
2
+ import { Game } from "../game";
3
+ const getErrorMessage = (id) => [
4
+ "",
5
+ "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━",
6
+ "⚠️ Entity Registration Error",
7
+ "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━",
8
+ "",
9
+ `Entity "${id}" is not registered with the game engine.`,
10
+ "",
11
+ "Why this happened:",
12
+ " React components need entities to be registered as Valtio proxies",
13
+ " to detect state changes and trigger re-renders automatically.",
14
+ "",
15
+ "How to fix:",
16
+ " Entities should auto-register in their constructor via:",
17
+ " Game.registerEntity(this)",
18
+ "",
19
+ ` If "${id}" is a custom entity, ensure its constructor`,
20
+ " calls the parent BaseGameObject constructor which handles registration:",
21
+ "",
22
+ " Example:",
23
+ " constructor(props) {",
24
+ " super(props); // This registers the entity",
25
+ " }",
26
+ "",
27
+ "Troubleshooting:",
28
+ ` 1. Check if "${id}" extends BaseGameObject`,
29
+ " 2. Verify the constructor calls super() with an id",
30
+ " 3. Make sure the entity is imported before using useGameEntity",
31
+ "",
32
+ "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━",
33
+ "",
34
+ ].join("\n");
35
+ /**
36
+ * Monitors changes to a given game entity by wrapping it in a Valtio proxy.
37
+ * This hook enables React components to automatically re-render when the entity's state changes.
38
+ *
39
+ * @param gameObject - The game entity to observe. Must extend BaseGameObject and be registered.
40
+ * @return The proxied game entity that triggers re-renders on state changes.
41
+ *
42
+ * @example
43
+ * ```tsx
44
+ * import { useGameEntity } from "@app/hooks";
45
+ * import { environment } from "@game/entities/environment";
46
+ *
47
+ * function TemperatureDisplay() {
48
+ * const env = useGameEntity(environment);
49
+ * return <div>Temperature: {env.variables.temperature}°C</div>;
50
+ * }
51
+ * ```
52
+ */
53
+ export function useGameEntity(gameObject) {
54
+ const proxiedObject = Game._getProxiedObject(gameObject);
55
+ try {
56
+ return useProxy(proxiedObject);
57
+ }
58
+ catch (error) {
59
+ // if error is a TypeError, it means the object is not registered
60
+ if (error instanceof TypeError) {
61
+ const errorMessage = getErrorMessage(gameObject.id);
62
+ console.error(errorMessage);
63
+ throw new Error(errorMessage);
64
+ }
65
+ else {
66
+ throw error; // rethrow other types of errors
67
+ }
68
+ }
69
+ }
70
+ //# sourceMappingURL=useGameEntity.js.map