@rpgjs/client 5.0.0-beta.24 → 5.0.0-beta.26

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 (64) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/dist/Game/Map.d.ts +1 -0
  3. package/dist/Game/Map.js +5 -0
  4. package/dist/Game/Map.js.map +1 -1
  5. package/dist/Gui/Gui.js +5 -0
  6. package/dist/Gui/Gui.js.map +1 -1
  7. package/dist/RpgClient.d.ts +2 -1
  8. package/dist/RpgClientEngine.d.ts +76 -0
  9. package/dist/RpgClientEngine.js +59 -4
  10. package/dist/RpgClientEngine.js.map +1 -1
  11. package/dist/components/gui/dialogbox/index.ce.js +23 -2
  12. package/dist/components/gui/dialogbox/index.ce.js.map +1 -1
  13. package/dist/components/gui/index.d.ts +3 -1
  14. package/dist/components/gui/index.js +2 -0
  15. package/dist/components/gui/input-field.ce.js +123 -0
  16. package/dist/components/gui/input-field.ce.js.map +1 -0
  17. package/dist/components/gui/input.ce.js +40 -0
  18. package/dist/components/gui/input.ce.js.map +1 -0
  19. package/dist/components/scenes/draw-map.ce.js +5 -2
  20. package/dist/components/scenes/draw-map.ce.js.map +1 -1
  21. package/dist/components/scenes/weather-lifecycle-compat.d.ts +0 -0
  22. package/dist/components/scenes/weather-lifecycle-compat.js +11 -0
  23. package/dist/components/scenes/weather-lifecycle-compat.js.map +1 -0
  24. package/dist/components/scenes/weather-tick-lifecycle.d.ts +17 -0
  25. package/dist/components/scenes/weather-tick-lifecycle.js +44 -0
  26. package/dist/components/scenes/weather-tick-lifecycle.js.map +1 -0
  27. package/dist/components/scenes/weather-tick-lifecycle.spec.d.ts +1 -0
  28. package/dist/i18n.d.ts +12 -0
  29. package/dist/i18n.js +12 -0
  30. package/dist/i18n.js.map +1 -1
  31. package/dist/index.d.ts +2 -0
  32. package/dist/index.js +15 -11
  33. package/dist/services/loadMap.d.ts +10 -2
  34. package/dist/services/loadMap.js +2 -1
  35. package/dist/services/loadMap.js.map +1 -1
  36. package/dist/services/mapStreaming.d.ts +85 -0
  37. package/dist/services/mapStreaming.js +210 -0
  38. package/dist/services/mapStreaming.js.map +1 -0
  39. package/dist/services/mapStreaming.spec.d.ts +1 -0
  40. package/dist/services/mmorpg.d.ts +6 -0
  41. package/dist/services/mmorpg.js +2 -2
  42. package/dist/services/mmorpg.js.map +1 -1
  43. package/package.json +4 -4
  44. package/src/Game/Map.ts +7 -0
  45. package/src/Gui/Gui.spec.ts +5 -0
  46. package/src/Gui/Gui.ts +5 -1
  47. package/src/RpgClient.ts +2 -1
  48. package/src/RpgClientEngine.ts +147 -6
  49. package/src/components/gui/dialogbox/index.ce +26 -1
  50. package/src/components/gui/index.ts +5 -1
  51. package/src/components/gui/input-field.ce +106 -0
  52. package/src/components/gui/input.ce +26 -0
  53. package/src/components/scenes/draw-map.ce +4 -1
  54. package/src/components/scenes/weather-lifecycle-compat.ts +8 -0
  55. package/src/components/scenes/weather-tick-lifecycle.spec.ts +60 -0
  56. package/src/components/scenes/weather-tick-lifecycle.ts +69 -0
  57. package/src/i18n.spec.ts +2 -1
  58. package/src/i18n.ts +12 -0
  59. package/src/index.ts +2 -0
  60. package/src/services/loadMap.ts +9 -2
  61. package/src/services/mapStreaming.spec.ts +240 -0
  62. package/src/services/mapStreaming.ts +275 -0
  63. package/src/services/mmorpg.ts +15 -2
  64. package/vite.config.ts +5 -2
@@ -1,5 +1,6 @@
1
1
  import { inject } from "../../../core/inject.js";
2
2
  import { getKeyboardControlBind } from "../../../services/actionInput.js";
3
+ import __ce_component$1 from "../input-field.ce.js";
3
4
  import { RpgClientEngine } from "../../../RpgClientEngine.js";
4
5
  import { DOMContainer, DOMElement, DOMSprite, Navigation, computed, cond, createTabindexNavigator, effect, h, loop, mount, signal, useDefineEmits, useDefineProps, useProps } from "canvasengine";
5
6
  import { delay } from "@rpgjs/common";
@@ -23,6 +24,8 @@ function component($$props) {
23
24
  const position = computed(() => dialogData().position);
24
25
  const typewriterEffect = computed(() => dialogData().typewriterEffect);
25
26
  const fullWidth = computed(() => dialogData().fullWidth || false);
27
+ const dialogInput = computed(() => dialogData().input || null);
28
+ const hasInput = computed(() => !!dialogInput());
26
29
  const resolveProp = (value) => typeof value === "function" ? value() : value;
27
30
  const normalizeOpenId = (value) => {
28
31
  const resolved = resolveProp(value);
@@ -76,7 +79,7 @@ function component($$props) {
76
79
  startTypewriter(text);
77
80
  });
78
81
  const hasChoices = computed(() => dialogChoices().length > 0);
79
- const showIndicator = computed(() => !hasChoices() && !isTyping());
82
+ const showIndicator = computed(() => !hasChoices() && !hasInput() && !isTyping());
80
83
  const nav = createTabindexNavigator(selectedItem, { count: () => dialogChoices().length }, "wrap");
81
84
  function selectChoice(index) {
82
85
  return function() {
@@ -91,6 +94,10 @@ function component($$props) {
91
94
  event?.stopPropagation?.();
92
95
  };
93
96
  const closeDialog = () => {
97
+ if (hasInput()) {
98
+ onInteraction?.("cancel");
99
+ return;
100
+ }
94
101
  _onFinish();
95
102
  };
96
103
  const closeDialogFromPointer = (event) => {
@@ -100,6 +107,12 @@ function component($$props) {
100
107
  const onSelect = (index) => {
101
108
  _onFinish(index);
102
109
  };
110
+ const submitInput = (payload) => {
111
+ onInteraction?.("submit", payload);
112
+ };
113
+ const cancelInput = () => {
114
+ onInteraction?.("cancel");
115
+ };
103
116
  const canAcceptAction = () => Date.now() - openedAt >= ACTION_OPEN_GUARD_MS;
104
117
  const controls = signal({
105
118
  up: {
@@ -142,6 +155,7 @@ function component($$props) {
142
155
  finishTyping();
143
156
  return;
144
157
  }
158
+ if (hasInput()) return;
145
159
  if (hasChoices()) return;
146
160
  _onFinish();
147
161
  }
@@ -223,7 +237,14 @@ function component($$props) {
223
237
  click: selectChoice(index)
224
238
  },
225
239
  textContent: choice.text
226
- })))))
240
+ }))))),
241
+ cond(computed(() => hasInput()), () => h(__ce_component$1, {
242
+ data: dialogInput,
243
+ layout: "dialog",
244
+ showMessage: false,
245
+ submit: submitInput,
246
+ cancel: cancelInput
247
+ }))
227
248
  ]), cond(computed(() => hasFace()), () => h(DOMElement, {
228
249
  element: "div",
229
250
  attrs: { class: "rpg-ui-dialog-face" }
@@ -1 +1 @@
1
- {"version":3,"file":"index.ce.js","names":[],"sources":["../../../../src/components/gui/dialogbox/index.ce"],"sourcesContent":["<DOMContainer width=\"100%\" height=\"100%\" controls={dialogControls}>\n <div class=\"rpg-ui-dialog-layer\" click={closeDialogFromPointer}>\n <button class=\"rpg-ui-close-button\" type=\"button\" title=\"Close\" aria-label=\"Close dialog\" click={closeDialogFromPointer}>x</button>\n <div\n class=\"rpg-ui-dialog-container\"\n data-position={dialogPosition()}\n data-full-width={isFullWidth() ? \"true\" : \"false\"}\n data-has-face={hasFace() ? \"true\" : \"false\"}\n >\n <div class=\"rpg-ui-dialog rpg-anim-fade-in\" click={stopEvent}>\n <div class=\"rpg-ui-dialog-body\">\n <div>\n @if (speakerName()) {\n <div class=\"rpg-ui-dialog-speaker\">{speakerName()}</div>\n }\n <div class=\"rpg-ui-dialog-content\">\n {displayMessage()}\n </div>\n @if (hasChoices()) {\n <Navigation tabindex={selectedItem} controls={controls}>\n <div class=\"rpg-ui-dialog-choices\">\n @for ((choice,index) of dialogChoices()) {\n <div\n class=\"rpg-ui-dialog-choice\"\n class={{active: selectedItem() === index}}\n tabindex={index}\n data-choice-index={index}\n click={selectChoice(index)}\n >{{ choice.text }}</div>\n }\n </div>\n </Navigation>\n }\n </div>\n @if (hasFace()) {\n <div class=\"rpg-ui-dialog-face\">\n <DOMSprite\n sheet={faceSheet(dialogFace())}\n width=\"100%\"\n height=\"100%\"\n objectFit=\"contain\"\n />\n </div>\n }\n </div>\n @if (showIndicator) {\n <div class=\"rpg-ui-dialog-indicator\"></div>\n }\n </div>\n </div>\n </div>\n</DOMContainer>\n \n<script>\n import { effect, signal, computed, createTabindexNavigator, mount } from \"canvasengine\";\n import { inject } from \"../../../core/inject\";\n import { RpgClientEngine } from \"../../../RpgClientEngine\";\n import { delay } from \"@rpgjs/common\";\n import { getKeyboardControlBind } from \"../../../services/actionInput\";\n\n const engine = inject(RpgClientEngine);\n const currentPlayer = engine.scene.currentPlayer\n const keyboardControls = engine.globalConfig.keyboardControls;\n\n engine.stopProcessingInput = true;\n\n const selectedItem = signal(0)\n const ACTION_OPEN_GUARD_MS = 150;\n const openedAt = Date.now();\n\n const {\n data,\n onFinish,\n onInteraction,\n guiOpenId\n } = defineProps();\n\n const dialogData = computed(() => data() || {});\n const dialogChoices = computed(() => Array.isArray(dialogData().choices) ? dialogData().choices : []);\n const message = computed(() => dialogData().message);\n const speaker = computed(() => dialogData().speaker);\n const position = computed(() => dialogData().position);\n const typewriterEffect = computed(() => dialogData().typewriterEffect);\n const fullWidth = computed(() => dialogData().fullWidth || false);\n\n const resolveProp = (value) => typeof value === \"function\" ? value() : value;\n const normalizeOpenId = (value) => {\n const resolved = resolveProp(value);\n return typeof resolved === \"string\" && resolved.length > 0 ? resolved : undefined;\n };\n\n const speakerName = computed(() => {\n const value = resolveProp(speaker());\n return value ? String(value) : \"\";\n });\n\n const dialogPosition = computed(() => resolveProp(position()) || \"bottom\");\n const isFullWidth = computed(() => resolveProp(fullWidth) !== false);\n const dialogFace = computed(() => resolveProp(dialogData().face));\n const hasFace = computed(() => {\n const value = dialogFace();\n return !!(value && value.id);\n });\n\n const displayMessage = signal(\"\");\n const fullMessage = signal(\"\");\n const isTyping = signal(false);\n let typewriterTimer = null;\n let rootElement = null;\n\n mount((element) => {\n rootElement = element;\n });\n\n const startTypewriter = (text) => {\n if (typewriterTimer) clearInterval(typewriterTimer);\n displayMessage.set(\"\");\n if (!text) return;\n let index = 0;\n isTyping.set(true);\n typewriterTimer = setInterval(() => {\n index += 1;\n displayMessage.set(text.slice(0, index));\n if (index >= text.length) {\n clearInterval(typewriterTimer);\n typewriterTimer = null;\n isTyping.set(false);\n }\n }, 20);\n };\n\n const finishTyping = () => {\n if (typewriterTimer) clearInterval(typewriterTimer);\n typewriterTimer = null;\n displayMessage.set(fullMessage());\n isTyping.set(false);\n };\n\n effect(() => {\n const text = resolveProp(message()) || \"\";\n fullMessage.set(text);\n const useTypewriter = resolveProp(typewriterEffect()) !== false;\n if (!useTypewriter) {\n finishTyping();\n return;\n }\n startTypewriter(text);\n });\n\n\n const hasChoices = computed(() => dialogChoices().length > 0);\n const showIndicator = computed(() => !hasChoices() && !isTyping());\n const nav = createTabindexNavigator(selectedItem, { count: () => dialogChoices().length }, 'wrap');\n\n function selectChoice(index) {\n return function() {\n selectedItem.set(index);\n onSelect(index);\n }\n }\n\n function _onFinish(value) {\n if (onFinish) onFinish(value, normalizeOpenId(guiOpenId));\n }\n\n const stopEvent = (event) => {\n event?.stopPropagation?.();\n };\n\n const closeDialog = () => {\n _onFinish();\n };\n\n const closeDialogFromPointer = (event) => {\n stopEvent(event);\n closeDialog();\n };\n\n const onSelect = (index) => {\n _onFinish(index);\n };\n\n const canAcceptAction = () => Date.now() - openedAt >= ACTION_OPEN_GUARD_MS;\n\n const controls = signal({\n up: {\n repeat: true,\n bind: keyboardControls.up,\n throttle: 150,\n keyDown() {\n if (!hasChoices()) return;\n nav.next(-1);\n }\n },\n down: {\n repeat: true,\n bind: keyboardControls.down,\n throttle: 150,\n keyDown() {\n if (!hasChoices()) return;\n nav.next(1);\n }\n },\n action: {\n bind: getKeyboardControlBind(keyboardControls.action),\n keyDown() {\n if (!canAcceptAction()) {\n return;\n }\n if (isTyping()) {\n finishTyping();\n return;\n }\n if (!hasChoices()) return;\n onSelect(selectedItem());\n }\n },\n gamepad: {\n enabled: true\n }\n });\n \n const dialogControls = signal({\n action: {\n bind: getKeyboardControlBind(keyboardControls.action),\n keyDown() {\n if (!canAcceptAction()) {\n return;\n }\n if (isTyping()) {\n finishTyping();\n return;\n }\n if (hasChoices()) return;\n _onFinish();\n }\n },\n })\n\n const faceSheet = (faceValue) => {\n if (!faceValue || !faceValue.id) {\n return undefined;\n }\n return {\n definition: engine.getSpriteSheet(faceValue.id),\n playing: faceValue.expression || \"default\",\n };\n }\n\n mount((element) => {\n return () => {\n // Wait destroy is finished before start processing input\n delay(() => {\n engine.stopProcessingInput = false;\n })\n }\n })\n</script>\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.ce.js","names":[],"sources":["../../../../src/components/gui/dialogbox/index.ce"],"sourcesContent":["<DOMContainer width=\"100%\" height=\"100%\" controls={dialogControls}>\n <div class=\"rpg-ui-dialog-layer\" click={closeDialogFromPointer}>\n <button class=\"rpg-ui-close-button\" type=\"button\" title=\"Close\" aria-label=\"Close dialog\" click={closeDialogFromPointer}>x</button>\n <div\n class=\"rpg-ui-dialog-container\"\n data-position={dialogPosition()}\n data-full-width={isFullWidth() ? \"true\" : \"false\"}\n data-has-face={hasFace() ? \"true\" : \"false\"}\n >\n <div class=\"rpg-ui-dialog rpg-anim-fade-in\" click={stopEvent}>\n <div class=\"rpg-ui-dialog-body\">\n <div>\n @if (speakerName()) {\n <div class=\"rpg-ui-dialog-speaker\">{speakerName()}</div>\n }\n <div class=\"rpg-ui-dialog-content\">\n {displayMessage()}\n </div>\n @if (hasChoices()) {\n <Navigation tabindex={selectedItem} controls={controls}>\n <div class=\"rpg-ui-dialog-choices\">\n @for ((choice,index) of dialogChoices()) {\n <div\n class=\"rpg-ui-dialog-choice\"\n class={{active: selectedItem() === index}}\n tabindex={index}\n data-choice-index={index}\n click={selectChoice(index)}\n >{{ choice.text }}</div>\n }\n </div>\n </Navigation>\n }\n @if (hasInput()) {\n <InputField\n data={dialogInput}\n layout=\"dialog\"\n showMessage={false}\n submit={submitInput}\n cancel={cancelInput}\n />\n }\n </div>\n @if (hasFace()) {\n <div class=\"rpg-ui-dialog-face\">\n <DOMSprite\n sheet={faceSheet(dialogFace())}\n width=\"100%\"\n height=\"100%\"\n objectFit=\"contain\"\n />\n </div>\n }\n </div>\n @if (showIndicator) {\n <div class=\"rpg-ui-dialog-indicator\"></div>\n }\n </div>\n </div>\n </div>\n</DOMContainer>\n \n<script>\n import { effect, signal, computed, createTabindexNavigator, mount } from \"canvasengine\";\n import { inject } from \"../../../core/inject\";\n import { RpgClientEngine } from \"../../../RpgClientEngine\";\n import { delay } from \"@rpgjs/common\";\n import { getKeyboardControlBind } from \"../../../services/actionInput\";\n import InputField from \"../input-field.ce\";\n\n const engine = inject(RpgClientEngine);\n const currentPlayer = engine.scene.currentPlayer\n const keyboardControls = engine.globalConfig.keyboardControls;\n\n engine.stopProcessingInput = true;\n\n const selectedItem = signal(0)\n const ACTION_OPEN_GUARD_MS = 150;\n const openedAt = Date.now();\n\n const {\n data,\n onFinish,\n onInteraction,\n guiOpenId\n } = defineProps();\n\n const dialogData = computed(() => data() || {});\n const dialogChoices = computed(() => Array.isArray(dialogData().choices) ? dialogData().choices : []);\n const message = computed(() => dialogData().message);\n const speaker = computed(() => dialogData().speaker);\n const position = computed(() => dialogData().position);\n const typewriterEffect = computed(() => dialogData().typewriterEffect);\n const fullWidth = computed(() => dialogData().fullWidth || false);\n const dialogInput = computed(() => dialogData().input || null);\n const hasInput = computed(() => !!dialogInput());\n\n const resolveProp = (value) => typeof value === \"function\" ? value() : value;\n const normalizeOpenId = (value) => {\n const resolved = resolveProp(value);\n return typeof resolved === \"string\" && resolved.length > 0 ? resolved : undefined;\n };\n\n const speakerName = computed(() => {\n const value = resolveProp(speaker());\n return value ? String(value) : \"\";\n });\n\n const dialogPosition = computed(() => resolveProp(position()) || \"bottom\");\n const isFullWidth = computed(() => resolveProp(fullWidth) !== false);\n const dialogFace = computed(() => resolveProp(dialogData().face));\n const hasFace = computed(() => {\n const value = dialogFace();\n return !!(value && value.id);\n });\n\n const displayMessage = signal(\"\");\n const fullMessage = signal(\"\");\n const isTyping = signal(false);\n let typewriterTimer = null;\n let rootElement = null;\n\n mount((element) => {\n rootElement = element;\n });\n\n const startTypewriter = (text) => {\n if (typewriterTimer) clearInterval(typewriterTimer);\n displayMessage.set(\"\");\n if (!text) return;\n let index = 0;\n isTyping.set(true);\n typewriterTimer = setInterval(() => {\n index += 1;\n displayMessage.set(text.slice(0, index));\n if (index >= text.length) {\n clearInterval(typewriterTimer);\n typewriterTimer = null;\n isTyping.set(false);\n }\n }, 20);\n };\n\n const finishTyping = () => {\n if (typewriterTimer) clearInterval(typewriterTimer);\n typewriterTimer = null;\n displayMessage.set(fullMessage());\n isTyping.set(false);\n };\n\n effect(() => {\n const text = resolveProp(message()) || \"\";\n fullMessage.set(text);\n const useTypewriter = resolveProp(typewriterEffect()) !== false;\n if (!useTypewriter) {\n finishTyping();\n return;\n }\n startTypewriter(text);\n });\n\n\n const hasChoices = computed(() => dialogChoices().length > 0);\n const showIndicator = computed(() => !hasChoices() && !hasInput() && !isTyping());\n const nav = createTabindexNavigator(selectedItem, { count: () => dialogChoices().length }, 'wrap');\n\n function selectChoice(index) {\n return function() {\n selectedItem.set(index);\n onSelect(index);\n }\n }\n\n function _onFinish(value) {\n if (onFinish) onFinish(value, normalizeOpenId(guiOpenId));\n }\n\n const stopEvent = (event) => {\n event?.stopPropagation?.();\n };\n\n const closeDialog = () => {\n if (hasInput()) {\n onInteraction?.(\"cancel\");\n return;\n }\n _onFinish();\n };\n\n const closeDialogFromPointer = (event) => {\n stopEvent(event);\n closeDialog();\n };\n\n const onSelect = (index) => {\n _onFinish(index);\n };\n\n const submitInput = (payload) => {\n onInteraction?.(\"submit\", payload);\n };\n\n const cancelInput = () => {\n onInteraction?.(\"cancel\");\n };\n\n const canAcceptAction = () => Date.now() - openedAt >= ACTION_OPEN_GUARD_MS;\n\n const controls = signal({\n up: {\n repeat: true,\n bind: keyboardControls.up,\n throttle: 150,\n keyDown() {\n if (!hasChoices()) return;\n nav.next(-1);\n }\n },\n down: {\n repeat: true,\n bind: keyboardControls.down,\n throttle: 150,\n keyDown() {\n if (!hasChoices()) return;\n nav.next(1);\n }\n },\n action: {\n bind: getKeyboardControlBind(keyboardControls.action),\n keyDown() {\n if (!canAcceptAction()) {\n return;\n }\n if (isTyping()) {\n finishTyping();\n return;\n }\n if (!hasChoices()) return;\n onSelect(selectedItem());\n }\n },\n gamepad: {\n enabled: true\n }\n });\n \n const dialogControls = signal({\n action: {\n bind: getKeyboardControlBind(keyboardControls.action),\n keyDown() {\n if (!canAcceptAction()) {\n return;\n }\n if (isTyping()) {\n finishTyping();\n return;\n }\n if (hasInput()) return;\n if (hasChoices()) return;\n _onFinish();\n }\n },\n })\n\n const faceSheet = (faceValue) => {\n if (!faceValue || !faceValue.id) {\n return undefined;\n }\n return {\n definition: engine.getSpriteSheet(faceValue.id),\n playing: faceValue.expression || \"default\",\n };\n }\n\n mount((element) => {\n return () => {\n // Wait destroy is finished before start processing input\n delay(() => {\n engine.stopProcessingInput = false;\n })\n }\n })\n</script>\n"],"mappings":"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"}
@@ -12,4 +12,6 @@ import { default as ExitMenuComponent } from './menu/exit-menu.ce';
12
12
  import { default as NotificationComponent } from './notification/notification.ce';
13
13
  import { default as TitleScreenComponent } from './title-screen.ce';
14
14
  import { default as GameoverComponent } from './gameover.ce';
15
- export { DialogboxComponent, BoxComponent, ShopComponent, HudComponent, SaveLoadComponent, MainMenuComponent, ItemsMenuComponent, SkillsMenuComponent, EquipMenuComponent, OptionsMenuComponent, ExitMenuComponent, NotificationComponent, TitleScreenComponent, GameoverComponent };
15
+ import { default as InputComponent } from './input.ce';
16
+ import { default as InputFieldComponent } from './input-field.ce';
17
+ export { DialogboxComponent, BoxComponent, ShopComponent, HudComponent, SaveLoadComponent, MainMenuComponent, ItemsMenuComponent, SkillsMenuComponent, EquipMenuComponent, OptionsMenuComponent, ExitMenuComponent, NotificationComponent, TitleScreenComponent, GameoverComponent, InputComponent, InputFieldComponent };
@@ -1,3 +1,4 @@
1
+ import "./input-field.ce.js";
1
2
  import "./dialogbox/index.ce.js";
2
3
  import "./box.ce.js";
3
4
  import "./shop/shop.ce.js";
@@ -12,3 +13,4 @@ import "./menu/main-menu.ce.js";
12
13
  import "./notification/notification.ce.js";
13
14
  import "./title-screen.ce.js";
14
15
  import "./gameover.ce.js";
16
+ import "./input.ce.js";
@@ -0,0 +1,123 @@
1
+ import { inject } from "../../core/inject.js";
2
+ import { RpgClientEngine } from "../../RpgClientEngine.js";
3
+ import { DOMElement, computed, cond, effect, h, signal, useDefineEmits, useDefineProps, useProps } from "canvasengine";
4
+ //#region src/components/gui/input-field.ce
5
+ function component($$props) {
6
+ useProps($$props);
7
+ const defineProps = useDefineProps($$props);
8
+ const defineEmits = useDefineEmits($$props);
9
+ const { t } = inject(RpgClientEngine).i18n();
10
+ const { data, layout, showMessage } = defineProps({
11
+ layout: "standalone",
12
+ showMessage: true
13
+ });
14
+ const { submit, cancel } = defineEmits();
15
+ const formData = computed(() => data() || {});
16
+ const value = signal(String(formData().defaultValue ?? ""));
17
+ const fieldId = computed(() => `rpg-input-value-${layout()}`);
18
+ const errorText = computed(() => formData().errorKey ? t(formData().errorKey, formData().errorParams || {}) : "");
19
+ const showCancelButton = computed(() => formData().cancelButton !== false);
20
+ let focused = false;
21
+ function submitForm(event, collectedData) {
22
+ const submittedValue = collectedData && Object.prototype.hasOwnProperty.call(collectedData, "value") ? collectedData.value : event?.currentTarget?.elements?.value?.value ?? value();
23
+ value.set(String(submittedValue ?? ""));
24
+ submit({ value: submittedValue ?? "" });
25
+ }
26
+ function cancelForm() {
27
+ cancel();
28
+ }
29
+ function handleKeydown(event) {
30
+ if (event?.key !== "Escape") return;
31
+ event.preventDefault?.();
32
+ event.stopPropagation?.();
33
+ cancelForm();
34
+ }
35
+ effect(() => {
36
+ if (focused) return;
37
+ focused = true;
38
+ setTimeout(() => {
39
+ document.getElementById(fieldId())?.focus?.();
40
+ });
41
+ });
42
+ return h(DOMElement, {
43
+ element: "form",
44
+ attrs: {
45
+ class: "rpg-ui-input-form",
46
+ "data-layout": computed(() => layout()),
47
+ submit: submitForm,
48
+ keydown: handleKeydown
49
+ }
50
+ }, [
51
+ cond(computed(() => showMessage()), () => h(DOMElement, {
52
+ element: "label",
53
+ attrs: {
54
+ class: "rpg-ui-input-message",
55
+ for: computed(() => fieldId())
56
+ },
57
+ textContent: computed(() => formData().message)
58
+ })),
59
+ cond(computed(() => formData().control === "textarea"), () => h(DOMElement, {
60
+ element: "textarea",
61
+ attrs: {
62
+ id: computed(() => fieldId()),
63
+ class: "rpg-ui-input rpg-ui-input-dialog-field",
64
+ name: "value",
65
+ value,
66
+ placeholder: computed(() => formData().placeholder || ""),
67
+ rows: computed(() => formData().rows || 4),
68
+ minlength: computed(() => formData().minLength),
69
+ maxlength: computed(() => formData().maxLength),
70
+ "aria-required": computed(() => formData().required ? "true" : "false")
71
+ }
72
+ }), () => h(DOMElement, {
73
+ element: "input",
74
+ attrs: {
75
+ id: computed(() => fieldId()),
76
+ class: "rpg-ui-input rpg-ui-input-dialog-field",
77
+ name: "value",
78
+ type: computed(() => formData().type || "text"),
79
+ value,
80
+ placeholder: computed(() => formData().placeholder || ""),
81
+ min: computed(() => formData().min),
82
+ max: computed(() => formData().max),
83
+ step: computed(() => formData().step),
84
+ minlength: computed(() => formData().minLength),
85
+ maxlength: computed(() => formData().maxLength),
86
+ "aria-required": computed(() => formData().required ? "true" : "false")
87
+ }
88
+ })),
89
+ cond(computed(() => errorText()), () => h(DOMElement, {
90
+ element: "div",
91
+ attrs: {
92
+ class: "rpg-ui-input-error",
93
+ role: "alert"
94
+ },
95
+ textContent: computed(() => errorText())
96
+ })),
97
+ h(DOMElement, {
98
+ element: "div",
99
+ attrs: { class: "rpg-ui-input-actions" }
100
+ }, [cond(computed(() => showCancelButton()), () => h(DOMElement, {
101
+ element: "button",
102
+ attrs: {
103
+ class: "rpg-ui-btn rpg-ui-input-button rpg-ui-input-button-cancel",
104
+ type: "button",
105
+ click: cancelForm
106
+ },
107
+ textContent: computed(() => formData().cancelText || t("rpg.input.cancel"))
108
+ })), h(DOMElement, {
109
+ element: "button",
110
+ attrs: {
111
+ class: "rpg-ui-btn rpg-ui-input-button rpg-ui-input-button-confirm",
112
+ "data-variant": "primary",
113
+ type: "submit"
114
+ },
115
+ textContent: computed(() => formData().confirmText || t("rpg.input.confirm"))
116
+ })])
117
+ ]);
118
+ }
119
+ var __ce_component = component;
120
+ //#endregion
121
+ export { __ce_component as default };
122
+
123
+ //# sourceMappingURL=input-field.ce.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-field.ce.js","names":[],"sources":["../../../src/components/gui/input-field.ce"],"sourcesContent":["<form\n class=\"rpg-ui-input-form\"\n data-layout={layout()}\n submit={submitForm}\n keydown={handleKeydown}\n>\n @if (showMessage()) {\n <label class=\"rpg-ui-input-message\" for={fieldId()}>{formData().message}</label>\n }\n @if (formData().control === \"textarea\") {\n <textarea\n id={fieldId()}\n class=\"rpg-ui-input rpg-ui-input-dialog-field\"\n name=\"value\"\n value={value}\n placeholder={formData().placeholder || \"\"}\n rows={formData().rows || 4}\n minlength={formData().minLength}\n maxlength={formData().maxLength}\n aria-required={formData().required ? \"true\" : \"false\"}\n ></textarea>\n }\n @else {\n <input\n id={fieldId()}\n class=\"rpg-ui-input rpg-ui-input-dialog-field\"\n name=\"value\"\n type={formData().type || \"text\"}\n value={value}\n placeholder={formData().placeholder || \"\"}\n min={formData().min}\n max={formData().max}\n step={formData().step}\n minlength={formData().minLength}\n maxlength={formData().maxLength}\n aria-required={formData().required ? \"true\" : \"false\"}\n />\n }\n @if (errorText()) {\n <div class=\"rpg-ui-input-error\" role=\"alert\">{errorText()}</div>\n }\n <div class=\"rpg-ui-input-actions\">\n @if (showCancelButton()) {\n <button class=\"rpg-ui-btn rpg-ui-input-button rpg-ui-input-button-cancel\" type=\"button\" click={cancelForm}>\n {formData().cancelText || t(\"rpg.input.cancel\")}\n </button>\n }\n <button\n class=\"rpg-ui-btn rpg-ui-input-button rpg-ui-input-button-confirm\"\n data-variant=\"primary\"\n type=\"submit\"\n >\n {formData().confirmText || t(\"rpg.input.confirm\")}\n </button>\n </div>\n</form>\n\n<script>\n import { computed, effect, signal } from \"canvasengine\";\n import { inject } from \"../../core/inject\";\n import { RpgClientEngine } from \"../../RpgClientEngine\";\n\n const engine = inject(RpgClientEngine);\n const { t } = engine.i18n();\n const { data, layout, showMessage } = defineProps({\n layout: \"standalone\",\n showMessage: true,\n });\n const { submit, cancel } = defineEmits();\n const formData = computed(() => data() || {});\n const value = signal(String(formData().defaultValue ?? \"\"));\n const fieldId = computed(() => `rpg-input-value-${layout()}`);\n const errorText = computed(() => formData().errorKey\n ? t(formData().errorKey, formData().errorParams || {})\n : \"\"\n );\n const showCancelButton = computed(() => formData().cancelButton !== false);\n let focused = false;\n\n function submitForm(event, collectedData) {\n const submittedValue = collectedData && Object.prototype.hasOwnProperty.call(collectedData, \"value\")\n ? collectedData.value\n : event?.currentTarget?.elements?.value?.value ?? value();\n value.set(String(submittedValue ?? \"\"));\n submit({ value: submittedValue ?? \"\" });\n }\n\n function cancelForm() {\n cancel();\n }\n\n function handleKeydown(event) {\n if (event?.key !== \"Escape\") return;\n event.preventDefault?.();\n event.stopPropagation?.();\n cancelForm();\n }\n\n effect(() => {\n if (focused) return;\n focused = true;\n setTimeout(() => {\n document.getElementById(fieldId())?.focus?.();\n });\n });\n</script>\n"],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ import __ce_component$1 from "./input-field.ce.js";
2
+ import { DOMContainer, DOMElement, computed, cond, h, useDefineEmits, useDefineProps, useProps } from "canvasengine";
3
+ //#region src/components/gui/input.ce
4
+ function component($$props) {
5
+ useProps($$props);
6
+ const defineProps = useDefineProps($$props);
7
+ useDefineEmits($$props);
8
+ const { data, onInteraction } = defineProps();
9
+ const title = computed(() => data().title || "");
10
+ function submit(payload) {
11
+ onInteraction?.("submit", payload);
12
+ }
13
+ function cancel() {
14
+ onInteraction?.("cancel");
15
+ }
16
+ return h(DOMContainer, {
17
+ width: "100%",
18
+ height: "100%"
19
+ }, h(DOMElement, {
20
+ element: "div",
21
+ attrs: { class: "rpg-ui-input-layer" }
22
+ }, h(DOMElement, {
23
+ element: "div",
24
+ attrs: { class: "rpg-ui-input-dialog rpg-ui-window rpg-anim-fade-in" }
25
+ }, [cond(computed(() => title()), () => h(DOMElement, {
26
+ element: "div",
27
+ attrs: { class: "rpg-ui-window-title" },
28
+ textContent: computed(() => title())
29
+ })), h(__ce_component$1, {
30
+ data,
31
+ layout: "standalone",
32
+ submit,
33
+ cancel
34
+ })])));
35
+ }
36
+ var __ce_component = component;
37
+ //#endregion
38
+ export { __ce_component as default };
39
+
40
+ //# sourceMappingURL=input.ce.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input.ce.js","names":[],"sources":["../../../src/components/gui/input.ce"],"sourcesContent":["<DOMContainer width=\"100%\" height=\"100%\">\n <div class=\"rpg-ui-input-layer\">\n <div class=\"rpg-ui-input-dialog rpg-ui-window rpg-anim-fade-in\">\n @if (title()) {\n <div class=\"rpg-ui-window-title\">{title()}</div>\n }\n <InputField data={data} layout=\"standalone\" submit={submit} cancel={cancel} />\n </div>\n </div>\n</DOMContainer>\n\n<script>\n import { computed } from \"canvasengine\";\n import InputField from \"./input-field.ce\";\n\n const { data, onInteraction } = defineProps();\n const title = computed(() => data().title || \"\");\n\n function submit(payload) {\n onInteraction?.(\"submit\", payload);\n }\n\n function cancel() {\n onInteraction?.(\"cancel\");\n }\n</script>\n"],"mappings":";;;AAQI,SAAG,UAAA,SAAA;CACO,SAAA,OAAA;;CAEP,eAAA,OAAA;CACC,MAAG,EAAA,MAAW,kBAAkB,YAAC;CACzC,MAAE,QAAO,eAAmB,KAAM,EAAA,SAAS,EAAA;;EAEzC,gBAAc,UAAc,OAAI;CAClC;;EAEE,gBAAgB,QAAS;CAC3B;QACE,EAAA,cAAA;EAAA,OAAA;EAAA,QAAA;CAAA,GAAA,EAAA,YAAA;EAAA,SAAA;EAAA,OAAA,EAAA,OAAA,qBAAA;CAAA,GAAA,EAAA,YAAA;EAAA,SAAA;EAAA,OAAA,EAAA,OAAA,qDAAA;CAAA,GAAA,CAAA,KAAA,eAAA,MAAA,CAAA,SAAA,EAAA,YAAA;EAAA,SAAA;EAAA,OAAA,EAAA,OAAA,sBAAA;EAAA,aAAA,eAAA,MAAA,CAAA;CAAA,CAAA,CAAA,GAAA,EAAA,kBAAA;EAAA;EAAA,QAAA;EAAA;EAAA;CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAEA;AAEA,IAAA,iBAAA"}
@@ -1,4 +1,5 @@
1
1
  import { inject } from "../../core/inject.js";
2
+ import "./weather-lifecycle-compat.js";
2
3
  import { RpgClientEngine } from "../../RpgClientEngine.js";
3
4
  import { Container, computed, cond, h, loop, useDefineEmits, useDefineProps, useProps } from "canvasengine";
4
5
  import { Weather } from "@canvasengine/presets";
@@ -12,6 +13,8 @@ function component($$props) {
12
13
  const componentAnimations = engine.componentAnimations;
13
14
  const projectiles = engine.projectiles.current;
14
15
  const map = engine.sceneMap?.data;
16
+ const emptySceneData = { params: {} };
17
+ const emptySceneParams = {};
15
18
  const sceneComponent = computed(() => map()?.component);
16
19
  const weather = engine.sceneMap.weather;
17
20
  const backgroundMusic = computed(() => {
@@ -73,8 +76,8 @@ function component($$props) {
73
76
  cond(computed(() => backgroundMusic()), () => h(Container, { sound: computed(() => backgroundMusic()) })),
74
77
  cond(computed(() => backgroundAmbientSound()), () => h(Container, { sound: computed(() => backgroundAmbientSound()) })),
75
78
  h(Container, null, cond(computed(() => map() && sceneComponent()), () => h(sceneComponent(), {
76
- data: computed(() => map().data),
77
- params: computed(() => map().params)
79
+ data: computed(() => map()?.data ?? emptySceneData),
80
+ params: computed(() => map()?.params ?? emptySceneParams)
78
81
  }))),
79
82
  loop(children, (child) => h(child)),
80
83
  loop(componentAnimations, (componentAnimation) => h(Container, null, loop(componentAnimation.current, (animation) => h(componentAnimation.component, animation)))),
@@ -1 +1 @@
1
- {"version":3,"file":"draw-map.ce.js","names":[],"sources":["../../../src/components/scenes/draw-map.ce"],"sourcesContent":["<Container shake={shakeConfig} freeze={engine.gamePause}>\n @if (backgroundMusic()) {\n <Container sound={backgroundMusic()} />\n }\n\n @if (backgroundAmbientSound()) {\n <Container sound={backgroundAmbientSound()} />\n }\n\n <Container>\n @if (map() && sceneComponent()) {\n <sceneComponent() data={map().data} params={map().params} />\n }\n </Container>\n\n @for (child of children) {\n <child />\n }\n\n @for (componentAnimation of componentAnimations) {\n <Container>\n @for (animation of componentAnimation.current) {\n <componentAnimation.component ...animation />\n }\n </Container>\n }\n\n <Container sortableChildren={true}>\n @for (projectile of projectiles() ; track projectile.props.id) {\n <projectile.component ...projectile.props />\n }\n </Container>\n\n @if (weatherProps()) {\n <Weather ...weatherProps() />\n }\n</Container>\n\n<script>\n import { computed, effect } from 'canvasengine'\n import { inject } from \"../../core/inject\";\n import { RpgClientEngine } from \"../../RpgClientEngine\";\n import { Weather } from '@canvasengine/presets'\n\n const { children } = defineProps()\n const engine = inject(RpgClientEngine);\n const componentAnimations = engine.componentAnimations\n const projectiles = engine.projectiles.current\n const map = engine.sceneMap?.data\n const sceneComponent = computed(() => map()?.component)\n const weather = engine.sceneMap.weather\n const backgroundMusic = computed(() => {\n const src = map()?.params?.backgroundMusic\n return src ? { src, autoplay: true, loop: true } : undefined\n })\n const backgroundAmbientSound = computed(() => {\n const src = map()?.params?.backgroundAmbientSound\n return src ? { src, autoplay: true, loop: true } : undefined\n })\n\n const shakeConfig = {\n trigger: engine.mapShakeTrigger,\n intensity: 10,\n duration: 500,\n frequency: 10,\n direction: 'both'\n }\n\n const weatherProps = computed(() => {\n const state = weather?.()\n if (!state) {\n return null\n }\n const validEffects = ['rain', 'snow', 'fog', 'cloud']\n if (!validEffects.includes(state.effect)) {\n return null\n }\n const params = state.params ?? {}\n return {\n effect: state.effect,\n speed: params.speed,\n windDirection: params.windDirection,\n windStrength: params.windStrength,\n density: params.density,\n maxDrops: params.maxDrops,\n height: params.height,\n scale: params.scale,\n sunIntensity: params.sunIntensity,\n sunAngle: params.sunAngle,\n raySpread: params.raySpread,\n rayTwinkle: params.rayTwinkle,\n rayTwinkleSpeed: params.rayTwinkleSpeed,\n zIndex: params.zIndex ?? 1000,\n alpha: params.alpha,\n blendMode: params.blendMode,\n }\n })\n</script>\n"],"mappings":";;;;;AASG,SAAS,UAAA,SAAA;CACM,SAAc,OAAI;CAC7B,MAAA,cAAqB,eAAc,OAAQ;CAC9C,eAAA,OAAA;CACA,MAAS,EAAA,aAAA,YAAA;;CAEb,MAAM,sBAAqB,OAAA;CAC3B,MAAK,cAAO,OAAA,YAAA;CACZ,MAAE,MAAA,OAAA,UAAA;;CAEF,MAAM,UAAE,OAAA,SAAsB;CAC9B,MAAK,kBAAS,eAAA;EACV,MAAM,MAAE,IAAA,GAAU,QAAG;EACrB,OAAK,MAAA;GAAA;GAAA,UAAmB;GAAY,MAAC;EAAU,IAAC,KAAA;CACpD,CAAC;CACD,MAAM,yBAAS,eAAA;EACb,MAAA,MAAA,IAAA,GAAA,QAAA;;;;;;CAEF,CAAC;CACD,MAAK,cAAe;EAChB,SAAG,OAAW;EACd,WAAA;EACA,UAAS;;EAEV,WAAI;CACP;CACA,MAAE,eAAA,eAAA;EACA,MAAA,QAAS,UAAA;cAEJ,OAAA;EAGH,IAAA,CAAA;GADsB;GAAQ;GAAK;GAAO;EACjC,EAAA,SAAkB,MAAM,MAAM,GACvC,OAAS;EAET,MAAM,SAAE,MAAa,UAAA,CAAW;EAChC,OAAM;GACN,QAAM,MAAA;GACN,OAAM,OAAY;GAClB,eAAmB,OAAA;GACnB,cAAM,OAAiB;GACvB,SAAa,OAAG;GAChB,UAAM,OAAe;GACnB,QAAU,OAAO;GACjB,OAAO,OAAQ;GAChB,cAAA,OAAA;GACD,UAAM,OAAA;GACJ,WAAY,OAAO;GACnB,YAAc,OAAM;GACrB,iBAAA,OAAA;;GAED,OAAM,OAAY;GAChB,WAAS,OAAO;EAClB;CACJ,CAAC;CAEK,OADa,EAAA,WAAA;EAAA,OAAA;EAAA,QAAA,OAAA;CAAA,GAAA;EAAA,KAAA,eAAA,gBAAA,CAAA,SAAA,EAAA,WAAA,EAAA,OAAA,eAAA,gBAAA,CAAA,EAAA,CAAA,CAAA;EAAA,KAAA,eAAA,uBAAA,CAAA,SAAA,EAAA,WAAA,EAAA,OAAA,eAAA,uBAAA,CAAA,EAAA,CAAA,CAAA;EAAA,EAAA,WAAA,MAAA,KAAA,eAAA,IAAA,KAAA,eAAA,CAAA,SAAA,EAAA,eAAA,GAAA;GAAA,MAAA,eAAA,IAAA,EAAA,IAAA;GAAA,QAAA,eAAA,IAAA,EAAA,MAAA;EAAA,CAAA,CAAA,CAAA;EAAA,KAAA,WAAA,UAAA,EAAA,KAAA,CAAA;EAAA,KAAA,sBAAA,uBAAA,EAAA,WAAA,MAAA,KAAA,mBAAA,UAAA,cAAA,EAAA,mBAAA,WAAA,SAAA,CAAA,CAAA,CAAA;EAAA,EAAA,WAAA,EAAA,kBAAA,KAAA,GAAA,KAAA,eAAA,YAAA,CAAA,IAAA,eAAA,EAAA,WAAA,WAAA,WAAA,KAAA,GAAA,EAAA,QAAA,eAAA,WAAA,MAAA,GAAA,CAAA,CAAA;EAAA,KAAA,eAAA,aAAA,CAAA,SAAA,EAAA,SAAA,aAAA,CAAA,CAAA;CAAA,CACD;AACd;AAEA,IAAM,iBAAe"}
1
+ {"version":3,"file":"draw-map.ce.js","names":[],"sources":["../../../src/components/scenes/draw-map.ce"],"sourcesContent":["<Container shake={shakeConfig} freeze={engine.gamePause}>\n @if (backgroundMusic()) {\n <Container sound={backgroundMusic()} />\n }\n\n @if (backgroundAmbientSound()) {\n <Container sound={backgroundAmbientSound()} />\n }\n\n <Container>\n @if (map() && sceneComponent()) {\n <sceneComponent() data={map()?.data ?? emptySceneData} params={map()?.params ?? emptySceneParams} />\n }\n </Container>\n\n @for (child of children) {\n <child />\n }\n\n @for (componentAnimation of componentAnimations) {\n <Container>\n @for (animation of componentAnimation.current) {\n <componentAnimation.component ...animation />\n }\n </Container>\n }\n\n <Container sortableChildren={true}>\n @for (projectile of projectiles() ; track projectile.props.id) {\n <projectile.component ...projectile.props />\n }\n </Container>\n\n @if (weatherProps()) {\n <Weather ...weatherProps() />\n }\n</Container>\n\n<script>\n import { computed, effect } from 'canvasengine'\n import './weather-lifecycle-compat'\n import { inject } from \"../../core/inject\";\n import { RpgClientEngine } from \"../../RpgClientEngine\";\n import { Weather } from '@canvasengine/presets'\n\n const { children } = defineProps()\n const engine = inject(RpgClientEngine);\n const componentAnimations = engine.componentAnimations\n const projectiles = engine.projectiles.current\n const map = engine.sceneMap?.data\n const emptySceneData = { params: {} }\n const emptySceneParams = {}\n const sceneComponent = computed(() => map()?.component)\n const weather = engine.sceneMap.weather\n const backgroundMusic = computed(() => {\n const src = map()?.params?.backgroundMusic\n return src ? { src, autoplay: true, loop: true } : undefined\n })\n const backgroundAmbientSound = computed(() => {\n const src = map()?.params?.backgroundAmbientSound\n return src ? { src, autoplay: true, loop: true } : undefined\n })\n\n const shakeConfig = {\n trigger: engine.mapShakeTrigger,\n intensity: 10,\n duration: 500,\n frequency: 10,\n direction: 'both'\n }\n\n const weatherProps = computed(() => {\n const state = weather?.()\n if (!state) {\n return null\n }\n const validEffects = ['rain', 'snow', 'fog', 'cloud']\n if (!validEffects.includes(state.effect)) {\n return null\n }\n const params = state.params ?? {}\n return {\n effect: state.effect,\n speed: params.speed,\n windDirection: params.windDirection,\n windStrength: params.windStrength,\n density: params.density,\n maxDrops: params.maxDrops,\n height: params.height,\n scale: params.scale,\n sunIntensity: params.sunIntensity,\n sunAngle: params.sunAngle,\n raySpread: params.raySpread,\n rayTwinkle: params.rayTwinkle,\n rayTwinkleSpeed: params.rayTwinkleSpeed,\n zIndex: params.zIndex ?? 1000,\n alpha: params.alpha,\n blendMode: params.blendMode,\n }\n })\n</script>\n"],"mappings":";;;;;;AAUK,SAAU,UAAG,SAAgB;CACX,SAAO,OAAO;CACjC,MAAA,cAAA,eAAA,OAAA;CACS,eAAA,OAAA;;CAEb,MAAM,SAAQ,OAAG,eAAU;CAC3B,MAAK,sBAAO,OAAA;CACZ,MAAE,cAAA,OAAA,YAAA;;CAEF,MAAM,iBAAE,EAAA,QAAsB,CAAA,EAAA;CAC9B,MAAK,mBAAS,CAAA;CACd,MAAM,iBAAgB,eAAG,IAAA,GAAmB,SAAS;CACrD,MAAM,UAAG,OAAA,SAAmB;CAC5B,MAAM,kBAAA,eAAA;EACF,MAAE,MAAS,IAAA,GAAA,QAAA;EACb,OAAA,MAAA;GAAA;GAAA,UAAA;GAAA,MAAA;EAAA,IAAA,KAAA;;CAEF,MAAG,yBAA4B,eAAK;EAChC,MAAM,MAAA,IAAU,GAAG,QAAC;EACpB,OAAG,MAAU;GAAC;GAAA,UAAa;GAAA,MAAW;EAAO,IAAA,KAAA;CACjD,CAAC;CACD,MAAI,cAAS;;EAEV,WAAI;EACH,UAAU;EACZ,WAAA;EACA,WAAS;;CAEX,MAAC,eAAM,eAAA;EACH,MAAM,QAAG,UAAU;EACnB,IAAA,CAAA,OACA,OAAS;;GAEU;GAAO;GAAY;GAAC;4BAEvC,OAAQ;EAER,MAAM,SAAA,MAAA,UAAsB,CAAA;EAC5B,OAAM;GACN,QAAY,MAAM;GAClB,OAAM,OAAA;GACN,eAAM,OAAoB;GAC1B,cAAM,OAAiB;GACvB,SAAa,OAAG;GAChB,UAAM,OAAe;GACnB,QAAU,OAAO;GACjB,OAAO,OAAQ;GAChB,cAAA,OAAA;GACD,UAAM,OAAA;GACJ,WAAY,OAAO;GACnB,YAAc,OAAM;GACrB,iBAAA,OAAA;;GAED,OAAM,OAAY;GAChB,WAAS,OAAO;EAClB;CACJ,CAAC;CAEK,OADa,EAAA,WAAA;EAAA,OAAA;EAAA,QAAA,OAAA;CAAA,GAAA;EAAA,KAAA,eAAA,gBAAA,CAAA,SAAA,EAAA,WAAA,EAAA,OAAA,eAAA,gBAAA,CAAA,EAAA,CAAA,CAAA;EAAA,KAAA,eAAA,uBAAA,CAAA,SAAA,EAAA,WAAA,EAAA,OAAA,eAAA,uBAAA,CAAA,EAAA,CAAA,CAAA;EAAA,EAAA,WAAA,MAAA,KAAA,eAAA,IAAA,KAAA,eAAA,CAAA,SAAA,EAAA,eAAA,GAAA;GAAA,MAAA,eAAA,IAAA,GAAA,QAAA,cAAA;GAAA,QAAA,eAAA,IAAA,GAAA,UAAA,gBAAA;EAAA,CAAA,CAAA,CAAA;EAAA,KAAA,WAAA,UAAA,EAAA,KAAA,CAAA;EAAA,KAAA,sBAAA,uBAAA,EAAA,WAAA,MAAA,KAAA,mBAAA,UAAA,cAAA,EAAA,mBAAA,WAAA,SAAA,CAAA,CAAA,CAAA;EAAA,EAAA,WAAA,EAAA,kBAAA,KAAA,GAAA,KAAA,eAAA,YAAA,CAAA,IAAA,eAAA,EAAA,WAAA,WAAA,WAAA,KAAA,GAAA,EAAA,QAAA,eAAA,WAAA,MAAA,GAAA,CAAA,CAAA;EAAA,KAAA,eAAA,aAAA,CAAA,SAAA,EAAA,SAAA,aAAA,CAAA,CAAA;CAAA,CACD;AACd;AAEA,IAAM,iBAAe"}
@@ -0,0 +1,11 @@
1
+ import { patchWeatherTickLifecycle } from "./weather-tick-lifecycle.js";
2
+ import { createComponent } from "canvasengine";
3
+ import "@canvasengine/presets";
4
+ //#region src/components/scenes/weather-lifecycle-compat.ts
5
+ for (const tag of ["RainTextureLayer", "RainImpactLayer"]) {
6
+ const probe = createComponent(tag);
7
+ patchWeatherTickLifecycle(Object.getPrototypeOf(probe.componentInstance));
8
+ }
9
+ //#endregion
10
+
11
+ //# sourceMappingURL=weather-lifecycle-compat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"weather-lifecycle-compat.js","names":[],"sources":["../../../src/components/scenes/weather-lifecycle-compat.ts"],"sourcesContent":["import \"@canvasengine/presets\";\nimport { createComponent } from \"canvasengine\";\nimport { patchWeatherTickLifecycle } from \"./weather-tick-lifecycle\";\n\nfor (const tag of [\"RainTextureLayer\", \"RainImpactLayer\"]) {\n const probe = createComponent(tag);\n patchWeatherTickLifecycle(Object.getPrototypeOf(probe.componentInstance));\n}\n"],"mappings":";;;;AAIA,KAAK,MAAM,OAAO,CAAC,oBAAoB,iBAAiB,GAAG;CACzD,MAAM,QAAQ,gBAAgB,GAAG;CACjC,0BAA0B,OAAO,eAAe,MAAM,iBAAiB,CAAC;AAC1E"}
@@ -0,0 +1,17 @@
1
+ declare const PATCHED: unique symbol;
2
+ type TickSubscriptionPrototype = {
3
+ [PATCHED]?: boolean;
4
+ onMount?: (...args: any[]) => unknown;
5
+ onDestroy?: (...args: any[]) => unknown;
6
+ };
7
+ /**
8
+ * CanvasEngine presets 2.0.0 can finish mounting a rain layer after that layer
9
+ * has already been destroyed. The late mount then leaves a tick subscription
10
+ * operating on a destroyed Pixi object. It can also overwrite an existing
11
+ * subscription when mounts overlap.
12
+ *
13
+ * Keep this compatibility patch local to the affected preset prototypes. It
14
+ * can be removed once the preset owns the same lifecycle guarantees.
15
+ */
16
+ export declare function patchWeatherTickLifecycle(prototype: TickSubscriptionPrototype): void;
17
+ export {};
@@ -0,0 +1,44 @@
1
+ //#region src/components/scenes/weather-tick-lifecycle.ts
2
+ var PATCHED = Symbol.for("@rpgjs/client/weather-tick-lifecycle-patched");
3
+ var DISPOSED = Symbol("weather-tick-lifecycle-disposed");
4
+ var MOUNT_QUEUE = Symbol("weather-tick-lifecycle-mount-queue");
5
+ function stopTickSubscription(instance) {
6
+ instance.tickSubscription?.unsubscribe?.();
7
+ instance.tickSubscription = void 0;
8
+ }
9
+ /**
10
+ * CanvasEngine presets 2.0.0 can finish mounting a rain layer after that layer
11
+ * has already been destroyed. The late mount then leaves a tick subscription
12
+ * operating on a destroyed Pixi object. It can also overwrite an existing
13
+ * subscription when mounts overlap.
14
+ *
15
+ * Keep this compatibility patch local to the affected preset prototypes. It
16
+ * can be removed once the preset owns the same lifecycle guarantees.
17
+ */
18
+ function patchWeatherTickLifecycle(prototype) {
19
+ if (!prototype || prototype[PATCHED]) return;
20
+ const originalOnMount = prototype.onMount;
21
+ const originalOnDestroy = prototype.onDestroy;
22
+ if (!originalOnMount || !originalOnDestroy) return;
23
+ Object.defineProperty(prototype, PATCHED, { value: true });
24
+ prototype.onMount = function(...args) {
25
+ const mount = async () => {
26
+ if (this[DISPOSED] || this.destroyed) return;
27
+ stopTickSubscription(this);
28
+ await originalOnMount.apply(this, args);
29
+ if (this[DISPOSED] || this.destroyed) stopTickSubscription(this);
30
+ };
31
+ const pendingMount = (this[MOUNT_QUEUE] ?? Promise.resolve()).catch(() => void 0).then(mount);
32
+ this[MOUNT_QUEUE] = pendingMount;
33
+ return pendingMount;
34
+ };
35
+ prototype.onDestroy = function(...args) {
36
+ this[DISPOSED] = true;
37
+ stopTickSubscription(this);
38
+ return originalOnDestroy.apply(this, args);
39
+ };
40
+ }
41
+ //#endregion
42
+ export { patchWeatherTickLifecycle };
43
+
44
+ //# sourceMappingURL=weather-tick-lifecycle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"weather-tick-lifecycle.js","names":[],"sources":["../../../src/components/scenes/weather-tick-lifecycle.ts"],"sourcesContent":["const PATCHED = Symbol.for(\"@rpgjs/client/weather-tick-lifecycle-patched\");\nconst DISPOSED = Symbol(\"weather-tick-lifecycle-disposed\");\nconst MOUNT_QUEUE = Symbol(\"weather-tick-lifecycle-mount-queue\");\n\ntype TickSubscription = {\n unsubscribe?: () => void;\n};\n\ntype TickSubscriptionInstance = {\n destroyed?: boolean;\n tickSubscription?: TickSubscription;\n [DISPOSED]?: boolean;\n [MOUNT_QUEUE]?: Promise<void>;\n};\n\ntype TickSubscriptionPrototype = {\n [PATCHED]?: boolean;\n onMount?: (...args: any[]) => unknown;\n onDestroy?: (...args: any[]) => unknown;\n};\n\nfunction stopTickSubscription(instance: TickSubscriptionInstance) {\n instance.tickSubscription?.unsubscribe?.();\n instance.tickSubscription = undefined;\n}\n\n/**\n * CanvasEngine presets 2.0.0 can finish mounting a rain layer after that layer\n * has already been destroyed. The late mount then leaves a tick subscription\n * operating on a destroyed Pixi object. It can also overwrite an existing\n * subscription when mounts overlap.\n *\n * Keep this compatibility patch local to the affected preset prototypes. It\n * can be removed once the preset owns the same lifecycle guarantees.\n */\nexport function patchWeatherTickLifecycle(prototype: TickSubscriptionPrototype) {\n if (!prototype || prototype[PATCHED]) return;\n\n const originalOnMount = prototype.onMount;\n const originalOnDestroy = prototype.onDestroy;\n if (!originalOnMount || !originalOnDestroy) return;\n\n Object.defineProperty(prototype, PATCHED, { value: true });\n\n prototype.onMount = function (this: TickSubscriptionInstance, ...args: any[]) {\n const mount = async () => {\n if (this[DISPOSED] || this.destroyed) return;\n\n stopTickSubscription(this);\n await originalOnMount.apply(this, args);\n\n if (this[DISPOSED] || this.destroyed) {\n stopTickSubscription(this);\n }\n };\n\n const pendingMount = (this[MOUNT_QUEUE] ?? Promise.resolve())\n .catch(() => undefined)\n .then(mount);\n this[MOUNT_QUEUE] = pendingMount;\n return pendingMount;\n };\n\n prototype.onDestroy = function (this: TickSubscriptionInstance, ...args: any[]) {\n this[DISPOSED] = true;\n stopTickSubscription(this);\n return originalOnDestroy.apply(this, args);\n };\n}\n"],"mappings":";AAAA,IAAM,UAAU,OAAO,IAAI,8CAA8C;AACzE,IAAM,WAAW,OAAO,iCAAiC;AACzD,IAAM,cAAc,OAAO,oCAAoC;AAmB/D,SAAS,qBAAqB,UAAoC;CAChE,SAAS,kBAAkB,cAAc;CACzC,SAAS,mBAAmB,KAAA;AAC9B;;;;;;;;;;AAWA,SAAgB,0BAA0B,WAAsC;CAC9E,IAAI,CAAC,aAAa,UAAU,UAAU;CAEtC,MAAM,kBAAkB,UAAU;CAClC,MAAM,oBAAoB,UAAU;CACpC,IAAI,CAAC,mBAAmB,CAAC,mBAAmB;CAE5C,OAAO,eAAe,WAAW,SAAS,EAAE,OAAO,KAAK,CAAC;CAEzD,UAAU,UAAU,SAA0C,GAAG,MAAa;EAC5E,MAAM,QAAQ,YAAY;GACxB,IAAI,KAAK,aAAa,KAAK,WAAW;GAEtC,qBAAqB,IAAI;GACzB,MAAM,gBAAgB,MAAM,MAAM,IAAI;GAEtC,IAAI,KAAK,aAAa,KAAK,WACzB,qBAAqB,IAAI;EAE7B;EAEA,MAAM,gBAAgB,KAAK,gBAAgB,QAAQ,QAAQ,GACxD,YAAY,KAAA,CAAS,EACrB,KAAK,KAAK;EACb,KAAK,eAAe;EACpB,OAAO;CACT;CAEA,UAAU,YAAY,SAA0C,GAAG,MAAa;EAC9E,KAAK,YAAY;EACjB,qBAAqB,IAAI;EACzB,OAAO,kBAAkB,MAAM,MAAM,IAAI;CAC3C;AACF"}
package/dist/i18n.d.ts CHANGED
@@ -39,6 +39,18 @@ export declare const RpgClientBuiltinI18n: {
39
39
  "rpg.gameover.title": string;
40
40
  "rpg.gameover.title-screen": string;
41
41
  "rpg.gameover.load-game": string;
42
+ "rpg.input.confirm": string;
43
+ "rpg.input.cancel": string;
44
+ "rpg.input.error.invalid": string;
45
+ "rpg.input.error.required": string;
46
+ "rpg.input.error.number": string;
47
+ "rpg.input.error.min": string;
48
+ "rpg.input.error.max": string;
49
+ "rpg.input.error.step": string;
50
+ "rpg.input.error.min-length": string;
51
+ "rpg.input.error.max-length": string;
52
+ "rpg.input.error.email": string;
53
+ "rpg.transition.loading": string;
42
54
  "rpg.shop.default-message": string;
43
55
  "rpg.shop.choose-action": string;
44
56
  "rpg.shop.buy": string;
package/dist/i18n.js CHANGED
@@ -39,6 +39,18 @@ var RpgClientBuiltinI18n = { en: {
39
39
  "rpg.gameover.title": "Game Over",
40
40
  "rpg.gameover.title-screen": "Title Screen",
41
41
  "rpg.gameover.load-game": "Load Game",
42
+ "rpg.input.confirm": "Confirm",
43
+ "rpg.input.cancel": "Cancel",
44
+ "rpg.input.error.invalid": "Invalid value.",
45
+ "rpg.input.error.required": "A value is required.",
46
+ "rpg.input.error.number": "Enter a valid number.",
47
+ "rpg.input.error.min": "The value must be at least {min}.",
48
+ "rpg.input.error.max": "The value must be at most {max}.",
49
+ "rpg.input.error.step": "The value must use increments of {step}.",
50
+ "rpg.input.error.min-length": "Enter at least {minLength} characters.",
51
+ "rpg.input.error.max-length": "Enter no more than {maxLength} characters.",
52
+ "rpg.input.error.email": "Enter a valid email address.",
53
+ "rpg.transition.loading": "Loading area…",
42
54
  "rpg.shop.default-message": "Welcome to my shop!",
43
55
  "rpg.shop.choose-action": "Choose an action",
44
56
  "rpg.shop.buy": "Buy",
package/dist/i18n.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"i18n.js","names":[],"sources":["../src/i18n.ts"],"sourcesContent":["import { createI18nProvider, type I18nConfig } from \"@rpgjs/common\";\n\nexport const RpgClientBuiltinI18n = {\n en: {\n \"rpg.menu.title\": \"Menu\",\n \"rpg.menu.status\": \"Status\",\n \"rpg.menu.level\": \"Level\",\n \"rpg.menu.gold\": \"Gold\",\n \"rpg.menu.parameters\": \"Parameters\",\n \"rpg.menu.items\": \"Items\",\n \"rpg.menu.skills\": \"Skills\",\n \"rpg.menu.equip\": \"Equip\",\n \"rpg.menu.options\": \"Options\",\n \"rpg.menu.save\": \"Save\",\n \"rpg.menu.exit\": \"Exit\",\n \"rpg.menu.weapons\": \"Weapons\",\n \"rpg.menu.armor\": \"Armor\",\n \"rpg.menu.use\": \"Use\",\n \"rpg.menu.cancel\": \"Cancel\",\n \"rpg.menu.unequip\": \"Unequip\",\n \"rpg.menu.remove-equipment\": \"Remove the current equipment\",\n \"rpg.menu.empty\": \"Empty\",\n \"rpg.menu.leave-game\": \"Leave the game?\",\n \"rpg.menu.exit-help\": \"Press Action to confirm or Escape to go back.\",\n \"rpg.menu.options-help\": \"Configure your preferences here.\",\n \"rpg.save.title\": \"Save Game\",\n \"rpg.save.subtitle\": \"Choose a slot to overwrite or create.\",\n \"rpg.load.title\": \"Load Game\",\n \"rpg.load.subtitle\": \"Select a slot to load your progress.\",\n \"rpg.save.auto\": \"Auto Save\",\n \"rpg.save.slot\": \"Slot {index}\",\n \"rpg.save.empty-slot\": \"Empty Slot\",\n \"rpg.save.level\": \"Level\",\n \"rpg.save.exp\": \"Exp\",\n \"rpg.save.map\": \"Map\",\n \"rpg.save.date\": \"Date\",\n \"rpg.title.default\": \"RPG\",\n \"rpg.title.start\": \"Start\",\n \"rpg.title.load\": \"Load\",\n \"rpg.gameover.title\": \"Game Over\",\n \"rpg.gameover.title-screen\": \"Title Screen\",\n \"rpg.gameover.load-game\": \"Load Game\",\n \"rpg.shop.default-message\": \"Welcome to my shop!\",\n \"rpg.shop.choose-action\": \"Choose an action\",\n \"rpg.shop.buy\": \"Buy\",\n \"rpg.shop.sell\": \"Sell\",\n \"rpg.shop.back\": \"Back\",\n \"rpg.shop.equipped\": \"Equipped\",\n \"rpg.shop.already-equipped\": \"Already equipped\",\n \"rpg.shop.qty\": \"Qty\",\n \"rpg.shop.available\": \"Available\",\n \"rpg.shop.quantity\": \"Quantity\",\n \"rpg.shop.total\": \"Total\",\n },\n};\n\nexport function provideI18n(config: I18nConfig = {}) {\n return createI18nProvider(config);\n}\n"],"mappings":";;AAEA,IAAa,uBAAuB,EAClC,IAAI;CACF,kBAAkB;CAClB,mBAAmB;CACnB,kBAAkB;CAClB,iBAAiB;CACjB,uBAAuB;CACvB,kBAAkB;CAClB,mBAAmB;CACnB,kBAAkB;CAClB,oBAAoB;CACpB,iBAAiB;CACjB,iBAAiB;CACjB,oBAAoB;CACpB,kBAAkB;CAClB,gBAAgB;CAChB,mBAAmB;CACnB,oBAAoB;CACpB,6BAA6B;CAC7B,kBAAkB;CAClB,uBAAuB;CACvB,sBAAsB;CACtB,yBAAyB;CACzB,kBAAkB;CAClB,qBAAqB;CACrB,kBAAkB;CAClB,qBAAqB;CACrB,iBAAiB;CACjB,iBAAiB;CACjB,uBAAuB;CACvB,kBAAkB;CAClB,gBAAgB;CAChB,gBAAgB;CAChB,iBAAiB;CACjB,qBAAqB;CACrB,mBAAmB;CACnB,kBAAkB;CAClB,sBAAsB;CACtB,6BAA6B;CAC7B,0BAA0B;CAC1B,4BAA4B;CAC5B,0BAA0B;CAC1B,gBAAgB;CAChB,iBAAiB;CACjB,iBAAiB;CACjB,qBAAqB;CACrB,6BAA6B;CAC7B,gBAAgB;CAChB,sBAAsB;CACtB,qBAAqB;CACrB,kBAAkB;AACpB,EACF;AAEA,SAAgB,YAAY,SAAqB,CAAC,GAAG;CACnD,OAAO,mBAAmB,MAAM;AAClC"}
1
+ {"version":3,"file":"i18n.js","names":[],"sources":["../src/i18n.ts"],"sourcesContent":["import { createI18nProvider, type I18nConfig } from \"@rpgjs/common\";\n\nexport const RpgClientBuiltinI18n = {\n en: {\n \"rpg.menu.title\": \"Menu\",\n \"rpg.menu.status\": \"Status\",\n \"rpg.menu.level\": \"Level\",\n \"rpg.menu.gold\": \"Gold\",\n \"rpg.menu.parameters\": \"Parameters\",\n \"rpg.menu.items\": \"Items\",\n \"rpg.menu.skills\": \"Skills\",\n \"rpg.menu.equip\": \"Equip\",\n \"rpg.menu.options\": \"Options\",\n \"rpg.menu.save\": \"Save\",\n \"rpg.menu.exit\": \"Exit\",\n \"rpg.menu.weapons\": \"Weapons\",\n \"rpg.menu.armor\": \"Armor\",\n \"rpg.menu.use\": \"Use\",\n \"rpg.menu.cancel\": \"Cancel\",\n \"rpg.menu.unequip\": \"Unequip\",\n \"rpg.menu.remove-equipment\": \"Remove the current equipment\",\n \"rpg.menu.empty\": \"Empty\",\n \"rpg.menu.leave-game\": \"Leave the game?\",\n \"rpg.menu.exit-help\": \"Press Action to confirm or Escape to go back.\",\n \"rpg.menu.options-help\": \"Configure your preferences here.\",\n \"rpg.save.title\": \"Save Game\",\n \"rpg.save.subtitle\": \"Choose a slot to overwrite or create.\",\n \"rpg.load.title\": \"Load Game\",\n \"rpg.load.subtitle\": \"Select a slot to load your progress.\",\n \"rpg.save.auto\": \"Auto Save\",\n \"rpg.save.slot\": \"Slot {index}\",\n \"rpg.save.empty-slot\": \"Empty Slot\",\n \"rpg.save.level\": \"Level\",\n \"rpg.save.exp\": \"Exp\",\n \"rpg.save.map\": \"Map\",\n \"rpg.save.date\": \"Date\",\n \"rpg.title.default\": \"RPG\",\n \"rpg.title.start\": \"Start\",\n \"rpg.title.load\": \"Load\",\n \"rpg.gameover.title\": \"Game Over\",\n \"rpg.gameover.title-screen\": \"Title Screen\",\n \"rpg.gameover.load-game\": \"Load Game\",\n \"rpg.input.confirm\": \"Confirm\",\n \"rpg.input.cancel\": \"Cancel\",\n \"rpg.input.error.invalid\": \"Invalid value.\",\n \"rpg.input.error.required\": \"A value is required.\",\n \"rpg.input.error.number\": \"Enter a valid number.\",\n \"rpg.input.error.min\": \"The value must be at least {min}.\",\n \"rpg.input.error.max\": \"The value must be at most {max}.\",\n \"rpg.input.error.step\": \"The value must use increments of {step}.\",\n \"rpg.input.error.min-length\": \"Enter at least {minLength} characters.\",\n \"rpg.input.error.max-length\": \"Enter no more than {maxLength} characters.\",\n \"rpg.input.error.email\": \"Enter a valid email address.\",\n \"rpg.transition.loading\": \"Loading area…\",\n \"rpg.shop.default-message\": \"Welcome to my shop!\",\n \"rpg.shop.choose-action\": \"Choose an action\",\n \"rpg.shop.buy\": \"Buy\",\n \"rpg.shop.sell\": \"Sell\",\n \"rpg.shop.back\": \"Back\",\n \"rpg.shop.equipped\": \"Equipped\",\n \"rpg.shop.already-equipped\": \"Already equipped\",\n \"rpg.shop.qty\": \"Qty\",\n \"rpg.shop.available\": \"Available\",\n \"rpg.shop.quantity\": \"Quantity\",\n \"rpg.shop.total\": \"Total\",\n },\n};\n\nexport function provideI18n(config: I18nConfig = {}) {\n return createI18nProvider(config);\n}\n"],"mappings":";;AAEA,IAAa,uBAAuB,EAClC,IAAI;CACF,kBAAkB;CAClB,mBAAmB;CACnB,kBAAkB;CAClB,iBAAiB;CACjB,uBAAuB;CACvB,kBAAkB;CAClB,mBAAmB;CACnB,kBAAkB;CAClB,oBAAoB;CACpB,iBAAiB;CACjB,iBAAiB;CACjB,oBAAoB;CACpB,kBAAkB;CAClB,gBAAgB;CAChB,mBAAmB;CACnB,oBAAoB;CACpB,6BAA6B;CAC7B,kBAAkB;CAClB,uBAAuB;CACvB,sBAAsB;CACtB,yBAAyB;CACzB,kBAAkB;CAClB,qBAAqB;CACrB,kBAAkB;CAClB,qBAAqB;CACrB,iBAAiB;CACjB,iBAAiB;CACjB,uBAAuB;CACvB,kBAAkB;CAClB,gBAAgB;CAChB,gBAAgB;CAChB,iBAAiB;CACjB,qBAAqB;CACrB,mBAAmB;CACnB,kBAAkB;CAClB,sBAAsB;CACtB,6BAA6B;CAC7B,0BAA0B;CAC1B,qBAAqB;CACrB,oBAAoB;CACpB,2BAA2B;CAC3B,4BAA4B;CAC5B,0BAA0B;CAC1B,uBAAuB;CACvB,uBAAuB;CACvB,wBAAwB;CACxB,8BAA8B;CAC9B,8BAA8B;CAC9B,yBAAyB;CACzB,0BAA0B;CAC1B,4BAA4B;CAC5B,0BAA0B;CAC1B,gBAAgB;CAChB,iBAAiB;CACjB,iBAAiB;CACjB,qBAAqB;CACrB,6BAA6B;CAC7B,gBAAgB;CAChB,sBAAsB;CACtB,qBAAqB;CACrB,kBAAkB;AACpB,EACF;AAEA,SAAgB,YAAY,SAAqB,CAAC,GAAG;CACnD,OAAO,mBAAmB,MAAM;AAClC"}
package/dist/index.d.ts CHANGED
@@ -7,6 +7,7 @@ export * from './core/setup';
7
7
  export * from './core/inject';
8
8
  export * from './services/loadMap';
9
9
  export * from './services/actionInput';
10
+ export * from './services/mapStreaming';
10
11
  export * from './services/pointerContext';
11
12
  export * from './services/interactions';
12
13
  export * from './module';
@@ -24,6 +25,7 @@ export * from './utils/getEntityProp';
24
25
  export { Context } from '@signe/di';
25
26
  export { KeyboardControls, Input } from 'canvasengine';
26
27
  export { Control } from './services/keyboardControls';
28
+ export { defineModule } from '@rpgjs/common';
27
29
  export { RpgClientObject } from './Game/Object';
28
30
  export { RpgClientPlayer } from './Game/Player';
29
31
  export { RpgClientEvent } from './Game/Event';