@rpgjs/map-builder 0.0.0-stage → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +19 -0
- package/README.md +341 -2
- package/dist/authority/authority.d.ts +118 -0
- package/dist/authority/authority.d.ts.map +1 -0
- package/dist/authority/authority.js +289 -0
- package/dist/authority/authority.js.map +1 -0
- package/dist/authority/index.d.ts +3 -0
- package/dist/authority/index.d.ts.map +1 -0
- package/dist/authority/index.js +3 -0
- package/dist/authority/store.d.ts +36 -0
- package/dist/authority/store.d.ts.map +1 -0
- package/dist/authority/store.js +35 -0
- package/dist/authority/store.js.map +1 -0
- package/dist/client/index.d.ts +72 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +200 -0
- package/dist/client/index.js.map +1 -0
- package/dist/embed/client.d.ts +85 -0
- package/dist/embed/client.d.ts.map +1 -0
- package/dist/embed/client.js +255 -0
- package/dist/embed/client.js.map +1 -0
- package/dist/embed/host.d.ts +112 -0
- package/dist/embed/host.d.ts.map +1 -0
- package/dist/embed/host.js +278 -0
- package/dist/embed/host.js.map +1 -0
- package/dist/embed/index.d.ts +4 -0
- package/dist/embed/index.d.ts.map +1 -0
- package/dist/embed/index.js +4 -0
- package/dist/embed/protocol.d.ts +137 -0
- package/dist/embed/protocol.d.ts.map +1 -0
- package/dist/embed/protocol.js +161 -0
- package/dist/embed/protocol.js.map +1 -0
- package/dist/features/index.d.ts +66 -0
- package/dist/features/index.d.ts.map +1 -0
- package/dist/features/index.js +157 -0
- package/dist/features/index.js.map +1 -0
- package/dist/features/skin.d.ts +9 -0
- package/dist/features/skin.d.ts.map +1 -0
- package/dist/features/skin.js +43 -0
- package/dist/features/skin.js.map +1 -0
- package/dist/features/terrain.d.ts +66 -0
- package/dist/features/terrain.d.ts.map +1 -0
- package/dist/features/terrain.js +291 -0
- package/dist/features/terrain.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +51 -0
- package/dist/interaction/builtin-intents.d.ts +9 -0
- package/dist/interaction/builtin-intents.d.ts.map +1 -0
- package/dist/interaction/builtin-intents.js +61 -0
- package/dist/interaction/builtin-intents.js.map +1 -0
- package/dist/interaction/catalog.d.ts +24 -0
- package/dist/interaction/catalog.d.ts.map +1 -0
- package/dist/interaction/catalog.js +20 -0
- package/dist/interaction/catalog.js.map +1 -0
- package/dist/interaction/controller.d.ts +137 -0
- package/dist/interaction/controller.d.ts.map +1 -0
- package/dist/interaction/controller.js +215 -0
- package/dist/interaction/controller.js.map +1 -0
- package/dist/interaction/index.d.ts +14 -0
- package/dist/interaction/index.d.ts.map +1 -0
- package/dist/interaction/index.js +13 -0
- package/dist/interaction/input.d.ts +26 -0
- package/dist/interaction/input.d.ts.map +1 -0
- package/dist/interaction/input.js +33 -0
- package/dist/interaction/input.js.map +1 -0
- package/dist/interaction/intents.d.ts +80 -0
- package/dist/interaction/intents.d.ts.map +1 -0
- package/dist/interaction/keyboard.d.ts +26 -0
- package/dist/interaction/keyboard.d.ts.map +1 -0
- package/dist/interaction/keyboard.js +32 -0
- package/dist/interaction/keyboard.js.map +1 -0
- package/dist/interaction/picking.d.ts +33 -0
- package/dist/interaction/picking.d.ts.map +1 -0
- package/dist/interaction/picking.js +35 -0
- package/dist/interaction/picking.js.map +1 -0
- package/dist/interaction/pipeline.d.ts +45 -0
- package/dist/interaction/pipeline.d.ts.map +1 -0
- package/dist/interaction/pipeline.js +26 -0
- package/dist/interaction/pipeline.js.map +1 -0
- package/dist/interaction/placement.d.ts +76 -0
- package/dist/interaction/placement.d.ts.map +1 -0
- package/dist/interaction/placement.js +238 -0
- package/dist/interaction/placement.js.map +1 -0
- package/dist/interaction/selection-tool.d.ts +29 -0
- package/dist/interaction/selection-tool.d.ts.map +1 -0
- package/dist/interaction/selection-tool.js +190 -0
- package/dist/interaction/selection-tool.js.map +1 -0
- package/dist/interaction/steps.d.ts +62 -0
- package/dist/interaction/steps.d.ts.map +1 -0
- package/dist/interaction/steps.js +126 -0
- package/dist/interaction/steps.js.map +1 -0
- package/dist/interaction/store.d.ts +10 -0
- package/dist/interaction/store.d.ts.map +1 -0
- package/dist/interaction/store.js +28 -0
- package/dist/interaction/store.js.map +1 -0
- package/dist/interaction/tools.d.ts +26 -0
- package/dist/interaction/tools.d.ts.map +1 -0
- package/dist/interaction/tools.js +41 -0
- package/dist/interaction/tools.js.map +1 -0
- package/dist/model/assets.d.ts +36 -0
- package/dist/model/assets.d.ts.map +1 -0
- package/dist/model/assets.js +18 -0
- package/dist/model/assets.js.map +1 -0
- package/dist/model/committer.d.ts +66 -0
- package/dist/model/committer.d.ts.map +1 -0
- package/dist/model/committer.js +38 -0
- package/dist/model/committer.js.map +1 -0
- package/dist/model/core-patches.d.ts +2 -0
- package/dist/model/core-patches.d.ts.map +1 -0
- package/dist/model/core-patches.js +193 -0
- package/dist/model/core-patches.js.map +1 -0
- package/dist/model/define-map.d.ts +52 -0
- package/dist/model/define-map.d.ts.map +1 -0
- package/dist/model/define-map.js +66 -0
- package/dist/model/define-map.js.map +1 -0
- package/dist/model/definition.d.ts +57 -0
- package/dist/model/definition.d.ts.map +1 -0
- package/dist/model/definition.js +6 -0
- package/dist/model/definition.js.map +1 -0
- package/dist/model/errors.d.ts +21 -0
- package/dist/model/errors.d.ts.map +1 -0
- package/dist/model/errors.js +14 -0
- package/dist/model/errors.js.map +1 -0
- package/dist/model/history.d.ts +43 -0
- package/dist/model/history.d.ts.map +1 -0
- package/dist/model/history.js +141 -0
- package/dist/model/history.js.map +1 -0
- package/dist/model/index.d.ts +14 -0
- package/dist/model/index.d.ts.map +1 -0
- package/dist/model/index.js +14 -0
- package/dist/model/json.d.ts +15 -0
- package/dist/model/json.d.ts.map +1 -0
- package/dist/model/json.js +35 -0
- package/dist/model/json.js.map +1 -0
- package/dist/model/model.d.ts +68 -0
- package/dist/model/model.d.ts.map +1 -0
- package/dist/model/model.js +170 -0
- package/dist/model/model.js.map +1 -0
- package/dist/model/parse.d.ts +24 -0
- package/dist/model/parse.d.ts.map +1 -0
- package/dist/model/parse.js +165 -0
- package/dist/model/parse.js.map +1 -0
- package/dist/model/patches.d.ts +100 -0
- package/dist/model/patches.d.ts.map +1 -0
- package/dist/model/patches.js +21 -0
- package/dist/model/patches.js.map +1 -0
- package/dist/model/result.d.ts +22 -0
- package/dist/model/result.d.ts.map +1 -0
- package/dist/model/result.js +10 -0
- package/dist/model/result.js.map +1 -0
- package/dist/model/source.d.ts +52 -0
- package/dist/model/source.d.ts.map +1 -0
- package/dist/model/source.js +75 -0
- package/dist/model/source.js.map +1 -0
- package/dist/protocol/index.d.ts +92 -0
- package/dist/protocol/index.d.ts.map +1 -0
- package/dist/protocol/index.js +106 -0
- package/dist/protocol/index.js.map +1 -0
- package/dist/remote/committer.d.ts +43 -0
- package/dist/remote/committer.d.ts.map +1 -0
- package/dist/remote/committer.js +206 -0
- package/dist/remote/committer.js.map +1 -0
- package/dist/remote/index.d.ts +4 -0
- package/dist/remote/index.d.ts.map +1 -0
- package/dist/remote/index.js +4 -0
- package/dist/remote/join.d.ts +30 -0
- package/dist/remote/join.d.ts.map +1 -0
- package/dist/remote/join.js +36 -0
- package/dist/remote/join.js.map +1 -0
- package/dist/remote/memory-transport.d.ts +20 -0
- package/dist/remote/memory-transport.d.ts.map +1 -0
- package/dist/remote/memory-transport.js +48 -0
- package/dist/remote/memory-transport.js.map +1 -0
- package/dist/renderer/effects.d.ts +52 -0
- package/dist/renderer/effects.d.ts.map +1 -0
- package/dist/renderer/effects.js +111 -0
- package/dist/renderer/effects.js.map +1 -0
- package/dist/renderer/feature.d.ts +79 -0
- package/dist/renderer/feature.d.ts.map +1 -0
- package/dist/renderer/feature.js +50 -0
- package/dist/renderer/feature.js.map +1 -0
- package/dist/renderer/geometry.d.ts +59 -0
- package/dist/renderer/geometry.d.ts.map +1 -0
- package/dist/renderer/geometry.js +114 -0
- package/dist/renderer/geometry.js.map +1 -0
- package/dist/renderer/index.d.ts +7 -0
- package/dist/renderer/index.d.ts.map +1 -0
- package/dist/renderer/index.js +7 -0
- package/dist/renderer/scene.d.ts +77 -0
- package/dist/renderer/scene.d.ts.map +1 -0
- package/dist/renderer/scene.js +125 -0
- package/dist/renderer/scene.js.map +1 -0
- package/dist/renderer/textures.d.ts +20 -0
- package/dist/renderer/textures.d.ts.map +1 -0
- package/dist/renderer/textures.js +61 -0
- package/dist/renderer/textures.js.map +1 -0
- package/dist/renderer/view.d.ts +139 -0
- package/dist/renderer/view.d.ts.map +1 -0
- package/dist/renderer/view.js +349 -0
- package/dist/renderer/view.js.map +1 -0
- package/dist/rpgjs/shared.d.ts +41 -0
- package/dist/rpgjs/shared.d.ts.map +1 -0
- package/dist/rpgjs/shared.js +77 -0
- package/dist/rpgjs/shared.js.map +1 -0
- package/dist/server/index.d.ts +64 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +205 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/storage.d.ts +16 -0
- package/dist/server/storage.d.ts.map +1 -0
- package/dist/server/storage.js +52 -0
- package/dist/server/storage.js.map +1 -0
- package/dist/skins/default.d.ts +27 -0
- package/dist/skins/default.d.ts.map +1 -0
- package/dist/skins/default.js +144 -0
- package/dist/skins/default.js.map +1 -0
- package/dist/skins/frames.d.ts +19 -0
- package/dist/skins/frames.d.ts.map +1 -0
- package/dist/skins/frames.js +49 -0
- package/dist/skins/frames.js.map +1 -0
- package/dist/skins/game.d.ts +21 -0
- package/dist/skins/game.d.ts.map +1 -0
- package/dist/skins/game.js +21 -0
- package/dist/skins/game.js.map +1 -0
- package/dist/skins/index.d.ts +5 -0
- package/dist/skins/index.d.ts.map +1 -0
- package/dist/skins/index.js +5 -0
- package/dist/skins/types.d.ts +46 -0
- package/dist/skins/types.d.ts.map +1 -0
- package/dist/skins/types.js +12 -0
- package/dist/skins/types.js.map +1 -0
- package/dist/terrain/data.d.ts +10 -0
- package/dist/terrain/data.d.ts.map +1 -0
- package/dist/terrain/data.js +83 -0
- package/dist/terrain/data.js.map +1 -0
- package/dist/terrain/define.d.ts +72 -0
- package/dist/terrain/define.d.ts.map +1 -0
- package/dist/terrain/define.js +91 -0
- package/dist/terrain/define.js.map +1 -0
- package/dist/terrain/editing.d.ts +54 -0
- package/dist/terrain/editing.d.ts.map +1 -0
- package/dist/terrain/editing.js +169 -0
- package/dist/terrain/editing.js.map +1 -0
- package/dist/terrain/index.d.ts +10 -0
- package/dist/terrain/index.d.ts.map +1 -0
- package/dist/terrain/index.js +10 -0
- package/dist/terrain/kernel.d.ts +57 -0
- package/dist/terrain/kernel.d.ts.map +1 -0
- package/dist/terrain/kernel.js +198 -0
- package/dist/terrain/kernel.js.map +1 -0
- package/dist/terrain/mask.d.ts +37 -0
- package/dist/terrain/mask.d.ts.map +1 -0
- package/dist/terrain/mask.js +244 -0
- package/dist/terrain/mask.js.map +1 -0
- package/dist/terrain/patches.d.ts +32 -0
- package/dist/terrain/patches.d.ts.map +1 -0
- package/dist/terrain/patches.js +135 -0
- package/dist/terrain/patches.js.map +1 -0
- package/dist/terrain/rle.d.ts +4 -0
- package/dist/terrain/rle.d.ts.map +1 -0
- package/dist/terrain/rle.js +68 -0
- package/dist/terrain/rle.js.map +1 -0
- package/dist/terrain/scheduler.d.ts +46 -0
- package/dist/terrain/scheduler.d.ts.map +1 -0
- package/dist/terrain/scheduler.js +148 -0
- package/dist/terrain/scheduler.js.map +1 -0
- package/dist/terrain/types.d.ts +110 -0
- package/dist/terrain/types.d.ts.map +1 -0
- package/dist/terrain/types.js +11 -0
- package/dist/terrain/types.js.map +1 -0
- package/dist/terrain-render/backend.d.ts +66 -0
- package/dist/terrain-render/backend.d.ts.map +1 -0
- package/dist/terrain-render/backend.js +96 -0
- package/dist/terrain-render/backend.js.map +1 -0
- package/dist/terrain-render/host.d.ts +21 -0
- package/dist/terrain-render/host.d.ts.map +1 -0
- package/dist/terrain-render/host.js +62 -0
- package/dist/terrain-render/host.js.map +1 -0
- package/dist/terrain-render/index.d.ts +3 -0
- package/dist/terrain-render/index.d.ts.map +1 -0
- package/dist/terrain-render/index.js +3 -0
- package/dist/terrain-render/worker.d.ts +2 -0
- package/dist/terrain-render/worker.d.ts.map +1 -0
- package/dist/terrain-render/worker.js +34 -0
- package/dist/terrain-render/worker.js.map +1 -0
- package/package.json +124 -3
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import { createMapModel } from "../model/model.js";
|
|
2
|
+
import { describeElement, describeEvent } from "../renderer/scene.js";
|
|
3
|
+
import { createInteraction } from "../interaction/controller.js";
|
|
4
|
+
import { registerElementIntents } from "../interaction/builtin-intents.js";
|
|
5
|
+
import { registerPlacementIntent } from "../interaction/placement.js";
|
|
6
|
+
import { parseClientMessage } from "../protocol/index.js";
|
|
7
|
+
import { MapStoreCorruptError } from "./store.js";
|
|
8
|
+
//#region src/authority/authority.ts
|
|
9
|
+
var DEFAULT_LOG = 512;
|
|
10
|
+
var DEFAULT_SNAPSHOT_EVERY = 50;
|
|
11
|
+
var DEFAULT_SAVE_DELAY = 1e3;
|
|
12
|
+
var sceneOf = (state, context) => [...state.elements.flatMap((element) => describeElement(element, context) ?? []), ...state.events.flatMap((event) => describeEvent(event, context) ?? [])];
|
|
13
|
+
/**
|
|
14
|
+
* The authority over one map: it holds the truth, decides what clients may do, tells
|
|
15
|
+
* everybody what became true, catches late clients up and keeps the map between
|
|
16
|
+
* restarts. It knows nothing of any framework: connect it to whatever carries messages.
|
|
17
|
+
*/
|
|
18
|
+
function createMapAuthority(options) {
|
|
19
|
+
const reportError = options.onError ?? ((error) => console.error(error));
|
|
20
|
+
const model = createMapModel(options.definition, {
|
|
21
|
+
...options.revision !== void 0 ? { revision: options.revision } : {},
|
|
22
|
+
...options.patchHandlers ? { patchHandlers: options.patchHandlers } : {},
|
|
23
|
+
history: false,
|
|
24
|
+
onListenerError: reportError
|
|
25
|
+
});
|
|
26
|
+
const describeContext = {
|
|
27
|
+
assets: options.assets,
|
|
28
|
+
...options.hooks ? { hooks: options.hooks } : {}
|
|
29
|
+
};
|
|
30
|
+
const sessions = /* @__PURE__ */ new Set();
|
|
31
|
+
let acting;
|
|
32
|
+
let destroyed = false;
|
|
33
|
+
const controller = createInteraction({
|
|
34
|
+
model,
|
|
35
|
+
assets: options.assets,
|
|
36
|
+
describe: describeContext,
|
|
37
|
+
nodes: () => sceneOf(model.state, describeContext),
|
|
38
|
+
actor: () => acting?.session.actor,
|
|
39
|
+
onError: reportError
|
|
40
|
+
});
|
|
41
|
+
registerElementIntents(controller);
|
|
42
|
+
if (options.pipeline?.move) controller.usePipeline("element.move", options.pipeline.move);
|
|
43
|
+
if (options.pipeline?.remove) controller.usePipeline("element.remove", options.pipeline.remove);
|
|
44
|
+
if (options.placement) registerPlacementIntent(controller, options.placement);
|
|
45
|
+
options.setup?.(controller);
|
|
46
|
+
for (const entry of options.replay ?? []) {
|
|
47
|
+
if (entry.revision !== model.revision + 1) throw new MapStoreCorruptError(`Expected revision ${model.revision + 1}, found ${entry.revision} while restoring the map`);
|
|
48
|
+
const result = model.apply(entry.patches);
|
|
49
|
+
if (!result.ok) throw new MapStoreCorruptError(`Revision ${entry.revision} cannot be replayed: ${result.rejection.message}`);
|
|
50
|
+
}
|
|
51
|
+
const logLimit = Math.max(0, options.log ?? DEFAULT_LOG);
|
|
52
|
+
const patchLog = [];
|
|
53
|
+
const send = (session, message) => {
|
|
54
|
+
try {
|
|
55
|
+
session.send(message);
|
|
56
|
+
} catch (error) {
|
|
57
|
+
reportError(error);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
const broadcast = (message) => {
|
|
61
|
+
for (const session of [...sessions]) send(session, message);
|
|
62
|
+
};
|
|
63
|
+
const persist = options.persist;
|
|
64
|
+
const snapshotEvery = Math.max(1, persist?.snapshotEvery ?? DEFAULT_SNAPSHOT_EVERY);
|
|
65
|
+
const saveDelay = persist?.saveDelayMs ?? DEFAULT_SAVE_DELAY;
|
|
66
|
+
const schedule = persist?.schedule ?? ((run, delayMs) => {
|
|
67
|
+
const handle = setTimeout(run, delayMs);
|
|
68
|
+
return () => clearTimeout(handle);
|
|
69
|
+
});
|
|
70
|
+
let lastSnapshotRevision = model.revision - (options.replay?.length ?? 0);
|
|
71
|
+
let cancelScheduled;
|
|
72
|
+
let queue = Promise.resolve();
|
|
73
|
+
const enqueue = (work) => {
|
|
74
|
+
queue = queue.then(work).catch(reportError);
|
|
75
|
+
};
|
|
76
|
+
if (persist && !persist.baseSaved) {
|
|
77
|
+
const base = {
|
|
78
|
+
definition: model.getDefinition(),
|
|
79
|
+
revision: model.revision
|
|
80
|
+
};
|
|
81
|
+
enqueue(() => persist.store.save(persist.id, base));
|
|
82
|
+
}
|
|
83
|
+
const saveSnapshot = () => {
|
|
84
|
+
if (!persist) return;
|
|
85
|
+
cancelScheduled?.();
|
|
86
|
+
cancelScheduled = void 0;
|
|
87
|
+
const snapshot = {
|
|
88
|
+
definition: model.getDefinition(),
|
|
89
|
+
revision: model.revision
|
|
90
|
+
};
|
|
91
|
+
lastSnapshotRevision = snapshot.revision;
|
|
92
|
+
enqueue(() => persist.store.save(persist.id, snapshot));
|
|
93
|
+
};
|
|
94
|
+
const unsubscribe = model.subscribe((change) => {
|
|
95
|
+
if (change.reset) return;
|
|
96
|
+
const entry = {
|
|
97
|
+
revision: change.revision,
|
|
98
|
+
patches: change.patches
|
|
99
|
+
};
|
|
100
|
+
if (logLimit > 0) {
|
|
101
|
+
patchLog.push(entry);
|
|
102
|
+
if (patchLog.length > logLimit) patchLog.splice(0, patchLog.length - logLimit);
|
|
103
|
+
}
|
|
104
|
+
const author = acting ? options.author?.(acting.session.actor) : void 0;
|
|
105
|
+
const base = {
|
|
106
|
+
type: "patches",
|
|
107
|
+
revision: change.revision,
|
|
108
|
+
patches: change.patches,
|
|
109
|
+
...author !== void 0 ? { author } : {}
|
|
110
|
+
};
|
|
111
|
+
for (const session of [...sessions]) send(session, acting && acting.requestId !== void 0 && acting.session === session ? {
|
|
112
|
+
...base,
|
|
113
|
+
requestId: acting.requestId
|
|
114
|
+
} : base);
|
|
115
|
+
if (persist) {
|
|
116
|
+
if (persist.store.append) enqueue(() => persist.store.append(persist.id, entry));
|
|
117
|
+
if (change.revision - lastSnapshotRevision >= snapshotEvery) saveSnapshot();
|
|
118
|
+
else {
|
|
119
|
+
cancelScheduled?.();
|
|
120
|
+
cancelScheduled = schedule(saveSnapshot, saveDelay);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
try {
|
|
124
|
+
options.onChange?.(change);
|
|
125
|
+
} catch (error) {
|
|
126
|
+
reportError(error);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
const snapshotMessage = () => ({
|
|
130
|
+
type: "snapshot",
|
|
131
|
+
revision: model.revision,
|
|
132
|
+
definition: model.getDefinition()
|
|
133
|
+
});
|
|
134
|
+
const catchUp = (session, since) => {
|
|
135
|
+
if (since === model.revision) return send(session, {
|
|
136
|
+
type: "synced",
|
|
137
|
+
revision: model.revision
|
|
138
|
+
});
|
|
139
|
+
const oldest = patchLog[0]?.revision;
|
|
140
|
+
if (!(since !== void 0 && since < model.revision && oldest !== void 0 && since + 1 >= oldest)) return send(session, snapshotMessage());
|
|
141
|
+
for (const entry of patchLog) if (entry.revision > since) send(session, {
|
|
142
|
+
type: "patches",
|
|
143
|
+
revision: entry.revision,
|
|
144
|
+
patches: entry.patches
|
|
145
|
+
});
|
|
146
|
+
send(session, {
|
|
147
|
+
type: "synced",
|
|
148
|
+
revision: model.revision
|
|
149
|
+
});
|
|
150
|
+
};
|
|
151
|
+
const reject = (session, id, failure) => send(session, {
|
|
152
|
+
type: "rejected",
|
|
153
|
+
id,
|
|
154
|
+
reason: failure.rejection.code,
|
|
155
|
+
message: failure.rejection.message,
|
|
156
|
+
...failure.rejection.patchIndex !== void 0 ? { patchIndex: failure.rejection.patchIndex } : {}
|
|
157
|
+
});
|
|
158
|
+
const handle = (session, raw) => {
|
|
159
|
+
if (destroyed || !sessions.has(session)) return;
|
|
160
|
+
const message = parseClientMessage(raw);
|
|
161
|
+
if (!message) return;
|
|
162
|
+
switch (message.type) {
|
|
163
|
+
case "sync": return catchUp(session, message.since);
|
|
164
|
+
case "intent":
|
|
165
|
+
acting = {
|
|
166
|
+
session,
|
|
167
|
+
requestId: message.id
|
|
168
|
+
};
|
|
169
|
+
try {
|
|
170
|
+
const result = controller.submit(message.intents);
|
|
171
|
+
if (!result.ok) reject(session, message.id, result);
|
|
172
|
+
} finally {
|
|
173
|
+
acting = void 0;
|
|
174
|
+
}
|
|
175
|
+
return;
|
|
176
|
+
case "patches":
|
|
177
|
+
if (!options.trustPatches?.(session.actor)) return reject(session, message.id, {
|
|
178
|
+
ok: false,
|
|
179
|
+
rejection: {
|
|
180
|
+
code: "patches-not-allowed",
|
|
181
|
+
message: "Only intents are accepted from this client"
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
acting = {
|
|
185
|
+
session,
|
|
186
|
+
requestId: message.id
|
|
187
|
+
};
|
|
188
|
+
try {
|
|
189
|
+
const result = model.apply(message.patches);
|
|
190
|
+
if (!result.ok) reject(session, message.id, result);
|
|
191
|
+
} finally {
|
|
192
|
+
acting = void 0;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
return {
|
|
197
|
+
model,
|
|
198
|
+
get revision() {
|
|
199
|
+
return model.revision;
|
|
200
|
+
},
|
|
201
|
+
interaction: controller,
|
|
202
|
+
get connections() {
|
|
203
|
+
return sessions.size;
|
|
204
|
+
},
|
|
205
|
+
connect(session) {
|
|
206
|
+
sessions.add(session);
|
|
207
|
+
send(session, snapshotMessage());
|
|
208
|
+
return {
|
|
209
|
+
session,
|
|
210
|
+
receive: (raw) => handle(session, raw),
|
|
211
|
+
disconnect: () => void sessions.delete(session)
|
|
212
|
+
};
|
|
213
|
+
},
|
|
214
|
+
apply: (patches) => model.apply(patches),
|
|
215
|
+
submit(intents, actor) {
|
|
216
|
+
const before = acting;
|
|
217
|
+
acting = {
|
|
218
|
+
session: {
|
|
219
|
+
id: "server",
|
|
220
|
+
actor,
|
|
221
|
+
send: () => void 0
|
|
222
|
+
},
|
|
223
|
+
requestId: void 0
|
|
224
|
+
};
|
|
225
|
+
try {
|
|
226
|
+
return controller.submit(intents);
|
|
227
|
+
} finally {
|
|
228
|
+
acting = before;
|
|
229
|
+
}
|
|
230
|
+
},
|
|
231
|
+
effect(target, name, params) {
|
|
232
|
+
broadcast({
|
|
233
|
+
type: "effect",
|
|
234
|
+
target,
|
|
235
|
+
name,
|
|
236
|
+
...params ? { params } : {}
|
|
237
|
+
});
|
|
238
|
+
},
|
|
239
|
+
snapshot: snapshotMessage,
|
|
240
|
+
async flush() {
|
|
241
|
+
if (persist && model.revision > lastSnapshotRevision) saveSnapshot();
|
|
242
|
+
await queue;
|
|
243
|
+
},
|
|
244
|
+
async destroy() {
|
|
245
|
+
if (destroyed) return;
|
|
246
|
+
await this.flush();
|
|
247
|
+
destroyed = true;
|
|
248
|
+
unsubscribe();
|
|
249
|
+
cancelScheduled?.();
|
|
250
|
+
controller.destroy();
|
|
251
|
+
sessions.clear();
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Brings a map back from a store, or starts it from `definition` when the store has
|
|
257
|
+
* nothing yet. Changes written after the last snapshot are replayed.
|
|
258
|
+
*/
|
|
259
|
+
async function restoreMapAuthority(options) {
|
|
260
|
+
const { store, id } = options.persist;
|
|
261
|
+
const stored = await store.load(id);
|
|
262
|
+
if (!stored) {
|
|
263
|
+
await store.save(id, {
|
|
264
|
+
definition: options.definition,
|
|
265
|
+
revision: options.revision ?? 0
|
|
266
|
+
});
|
|
267
|
+
return createMapAuthority({
|
|
268
|
+
...options,
|
|
269
|
+
persist: {
|
|
270
|
+
...options.persist,
|
|
271
|
+
baseSaved: true
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
return createMapAuthority({
|
|
276
|
+
...options,
|
|
277
|
+
persist: {
|
|
278
|
+
...options.persist,
|
|
279
|
+
baseSaved: true
|
|
280
|
+
},
|
|
281
|
+
definition: stored.snapshot.definition,
|
|
282
|
+
revision: stored.snapshot.revision,
|
|
283
|
+
replay: stored.patches
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
//#endregion
|
|
287
|
+
export { createMapAuthority, restoreMapAuthority };
|
|
288
|
+
|
|
289
|
+
//# sourceMappingURL=authority.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authority.js","names":[],"sources":["../../src/authority/authority.ts"],"sourcesContent":["import type { AssetResolver } from \"../model/assets\";\nimport type { MapDefinition } from \"../model/definition\";\nimport { createMapModel, type MapChange, type MapModel } from \"../model/model\";\nimport type { PatchHandlers } from \"../model/patches\";\nimport type { MapPatch } from \"../model/patches\";\nimport type { ApplyFailure, ApplyResult } from \"../model/result\";\nimport type { Catalog } from \"../interaction/catalog\";\nimport { registerElementIntents } from \"../interaction/builtin-intents\";\nimport { createInteraction, type InteractionController } from \"../interaction/controller\";\nimport type { MapIntent } from \"../interaction/intents\";\nimport type { PipelineStep } from \"../interaction/pipeline\";\nimport { registerPlacementIntent, type PlacementIntentOptions } from \"../interaction/placement\";\nimport {\n parseClientMessage,\n type EffectTargetMessage,\n type ServerMessage,\n} from \"../protocol\";\nimport { describeElement, describeEvent, type DescribeContext, type MapViewHooks, type SceneNode } from \"../renderer/scene\";\nimport { MapStoreCorruptError, type MapStore, type PatchEntry } from \"./store\";\n\n/** A client connected to the authority. The authority does not care how: `send` is all it needs. */\nexport interface AuthoritySession {\n readonly id: string;\n /** Who is acting: whatever the game decides, handed to the steps of the pipelines. */\n readonly actor: unknown;\n send(message: ServerMessage): void;\n}\n\nexport interface AuthorityConnection {\n readonly session: AuthoritySession;\n /** Gives the authority what the client sent. Anything that is not a valid message is ignored. */\n receive(raw: unknown): void;\n disconnect(): void;\n}\n\nexport interface PersistOptions {\n readonly store: MapStore;\n /** Key of the map in the store. */\n readonly id: string;\n /** Write a snapshot every this many revisions. Defaults to 50. */\n readonly snapshotEvery?: number;\n /** Write a snapshot this long after the last change. Defaults to 1000. */\n readonly saveDelayMs?: number;\n /** Replaces `setTimeout`, so tests control time. Returns the function that cancels it. */\n readonly schedule?: (run: () => void, delayMs: number) => () => void;\n /**\n * The store already holds a snapshot of the state the authority starts from, so it does\n * not write one first. `restoreMapAuthority` sets it. Otherwise the authority writes the\n * starting snapshot itself, so that the changes it appends have something to follow.\n */\n readonly baseSaved?: boolean;\n}\n\nexport interface MapAuthorityOptions<C extends Catalog<string> = Catalog<string>> {\n readonly definition: MapDefinition;\n /** Revision the map starts at. Defaults to 0. */\n readonly revision?: number;\n /**\n * What the map is made of. Sizes and hitboxes come from here, so assets must declare\n * a `size` or a `frame`: a server has no image to measure.\n */\n readonly assets: AssetResolver;\n readonly hooks?: MapViewHooks;\n /** Rules for every move and removal, whoever asks. The same steps the clients use to preview. */\n readonly pipeline?: {\n readonly move?: readonly PipelineStep<\"element.move\">[];\n readonly remove?: readonly PipelineStep<\"element.remove\">[];\n };\n /** What can be placed, and the rules for it. */\n readonly placement?: PlacementIntentOptions<C>;\n /** Handlers of the patch types features add (`terrainPatchHandlers`): the authority must know them to apply them. */\n readonly patchHandlers?: readonly PatchHandlers[];\n /** Registers more intents and pipelines, e.g. those of a custom feature. */\n readonly setup?: (controller: InteractionController) => void;\n /**\n * Whether this actor may send patches as they are (an editor, an undo). Never by default:\n * a client asks with intents, and the authority decides.\n */\n readonly trustPatches?: (actor: unknown) => boolean;\n /** Who made a change, in the words other players see. */\n readonly author?: (actor: unknown) => string | undefined;\n /** Changes kept to catch late clients up without sending the whole map. Defaults to 512. */\n readonly log?: number;\n readonly persist?: PersistOptions;\n /** Called after every change, whoever made it: the place to keep a physics world in step. */\n readonly onChange?: (change: MapChange) => void;\n readonly onError?: (error: unknown) => void;\n /** Changes to replay on top of `definition`, in order: what a store gives back after a restart. */\n readonly replay?: readonly PatchEntry[];\n}\n\nexport interface MapAuthority {\n /** The truth. Never change it directly: use `apply`, so everybody hears about it. */\n readonly model: MapModel<ApplyResult>;\n readonly revision: number;\n readonly interaction: InteractionController;\n /** How many clients are connected. */\n readonly connections: number;\n connect(session: AuthoritySession): AuthorityConnection;\n /**\n * A change the game itself makes (a lever, a quest). It is trusted: no pipeline. Everybody\n * connected hears about it.\n */\n apply(patches: MapPatch | readonly MapPatch[]): ApplyResult;\n /** Runs intents through the pipelines on behalf of an actor, e.g. a non-player character. */\n submit(intents: MapIntent | readonly MapIntent[], actor?: unknown): ApplyResult | ApplyFailure;\n /** Shows a short effect to everybody connected. It is not kept. */\n effect(target: EffectTargetMessage, name: string, params?: Readonly<Record<string, unknown>>): void;\n /** The map as it is now, as a message. */\n snapshot(): ServerMessage;\n /** Writes what is pending to the store. */\n flush(): Promise<void>;\n /** Flushes, then stops. */\n destroy(): Promise<void>;\n}\n\nconst DEFAULT_LOG = 512;\nconst DEFAULT_SNAPSHOT_EVERY = 50;\nconst DEFAULT_SAVE_DELAY = 1000;\n\nconst sceneOf = (state: MapDefinition, context: DescribeContext): SceneNode[] => [\n ...state.elements.flatMap((element) => describeElement(element, context) ?? []),\n ...state.events.flatMap((event) => describeEvent(event, context) ?? []),\n];\n\n/**\n * The authority over one map: it holds the truth, decides what clients may do, tells\n * everybody what became true, catches late clients up and keeps the map between\n * restarts. It knows nothing of any framework: connect it to whatever carries messages.\n */\nexport function createMapAuthority<C extends Catalog<string> = Catalog<string>>(options: MapAuthorityOptions<C>): MapAuthority {\n const reportError = options.onError ?? ((error: unknown) => console.error(error));\n const model = createMapModel(options.definition, {\n ...(options.revision !== undefined ? { revision: options.revision } : {}),\n ...(options.patchHandlers ? { patchHandlers: options.patchHandlers } : {}),\n // The authority has nothing to undo: clients keep their own history.\n history: false,\n onListenerError: reportError,\n });\n\n const describeContext: DescribeContext = { assets: options.assets, ...(options.hooks ? { hooks: options.hooks } : {}) };\n const sessions = new Set<AuthoritySession>();\n let acting: { session: AuthoritySession; requestId: string | undefined } | undefined;\n let destroyed = false;\n\n const controller = createInteraction({\n model,\n assets: options.assets,\n describe: describeContext,\n nodes: () => sceneOf(model.state, describeContext),\n actor: () => acting?.session.actor,\n onError: reportError,\n });\n registerElementIntents(controller);\n if (options.pipeline?.move) controller.usePipeline(\"element.move\", options.pipeline.move);\n if (options.pipeline?.remove) controller.usePipeline(\"element.remove\", options.pipeline.remove);\n if (options.placement) registerPlacementIntent(controller, options.placement);\n options.setup?.(controller);\n\n // Changes made before anybody listens: what a restart replays.\n for (const entry of options.replay ?? []) {\n if (entry.revision !== model.revision + 1) {\n throw new MapStoreCorruptError(`Expected revision ${model.revision + 1}, found ${entry.revision} while restoring the map`);\n }\n const result = model.apply(entry.patches);\n if (!result.ok) throw new MapStoreCorruptError(`Revision ${entry.revision} cannot be replayed: ${result.rejection.message}`);\n }\n\n const logLimit = Math.max(0, options.log ?? DEFAULT_LOG);\n const patchLog: PatchEntry[] = [];\n\n const send = (session: AuthoritySession, message: ServerMessage): void => {\n try {\n session.send(message);\n } catch (error) {\n reportError(error);\n }\n };\n const broadcast = (message: ServerMessage): void => {\n for (const session of [...sessions]) send(session, message);\n };\n\n // --- persistence\n const persist = options.persist;\n const snapshotEvery = Math.max(1, persist?.snapshotEvery ?? DEFAULT_SNAPSHOT_EVERY);\n const saveDelay = persist?.saveDelayMs ?? DEFAULT_SAVE_DELAY;\n const schedule =\n persist?.schedule ??\n ((run: () => void, delayMs: number) => {\n const handle = setTimeout(run, delayMs);\n return () => clearTimeout(handle);\n });\n let lastSnapshotRevision = model.revision - (options.replay?.length ?? 0);\n let cancelScheduled: (() => void) | undefined;\n let queue: Promise<void> = Promise.resolve();\n\n const enqueue = (work: () => Promise<void>): void => {\n queue = queue.then(work).catch(reportError);\n };\n if (persist && !persist.baseSaved) {\n const base = { definition: model.getDefinition(), revision: model.revision };\n enqueue(() => persist.store.save(persist.id, base));\n }\n const saveSnapshot = (): void => {\n if (!persist) return;\n cancelScheduled?.();\n cancelScheduled = undefined;\n const snapshot = { definition: model.getDefinition(), revision: model.revision };\n lastSnapshotRevision = snapshot.revision;\n enqueue(() => persist.store.save(persist.id, snapshot));\n };\n\n // --- what everybody must hear about\n const unsubscribe = model.subscribe((change) => {\n if (change.reset) return;\n const entry: PatchEntry = { revision: change.revision, patches: change.patches };\n if (logLimit > 0) {\n patchLog.push(entry);\n if (patchLog.length > logLimit) patchLog.splice(0, patchLog.length - logLimit);\n }\n\n const author = acting ? options.author?.(acting.session.actor) : undefined;\n const base = {\n type: \"patches\" as const,\n revision: change.revision,\n patches: change.patches,\n ...(author !== undefined ? { author } : {}),\n };\n // The request id goes only to whoever asked: it is how they recognise their own change.\n for (const session of [...sessions]) {\n send(session, acting && acting.requestId !== undefined && acting.session === session ? { ...base, requestId: acting.requestId } : base);\n }\n\n if (persist) {\n if (persist.store.append) enqueue(() => persist.store.append!(persist.id, entry));\n if (change.revision - lastSnapshotRevision >= snapshotEvery) saveSnapshot();\n else {\n cancelScheduled?.();\n cancelScheduled = schedule(saveSnapshot, saveDelay);\n }\n }\n try {\n options.onChange?.(change);\n } catch (error) {\n reportError(error);\n }\n });\n\n const snapshotMessage = (): ServerMessage => ({ type: \"snapshot\", revision: model.revision, definition: model.getDefinition() });\n\n const catchUp = (session: AuthoritySession, since: number | undefined): void => {\n if (since === model.revision) return send(session, { type: \"synced\", revision: model.revision });\n const oldest = patchLog[0]?.revision;\n const canReplay = since !== undefined && since < model.revision && oldest !== undefined && since + 1 >= oldest;\n if (!canReplay) return send(session, snapshotMessage());\n for (const entry of patchLog) {\n if (entry.revision > since) send(session, { type: \"patches\", revision: entry.revision, patches: entry.patches });\n }\n send(session, { type: \"synced\", revision: model.revision });\n };\n\n const reject = (session: AuthoritySession, id: string, failure: ApplyFailure): void =>\n send(session, {\n type: \"rejected\",\n id,\n reason: failure.rejection.code,\n message: failure.rejection.message,\n ...(failure.rejection.patchIndex !== undefined ? { patchIndex: failure.rejection.patchIndex } : {}),\n });\n\n const handle = (session: AuthoritySession, raw: unknown): void => {\n if (destroyed || !sessions.has(session)) return;\n const message = parseClientMessage(raw);\n if (!message) return;\n\n switch (message.type) {\n case \"sync\":\n return catchUp(session, message.since);\n case \"intent\": {\n acting = { session, requestId: message.id };\n try {\n const result = controller.submit(message.intents);\n if (!result.ok) reject(session, message.id, result);\n } finally {\n acting = undefined;\n }\n return;\n }\n case \"patches\": {\n if (!options.trustPatches?.(session.actor)) {\n return reject(session, message.id, {\n ok: false,\n rejection: { code: \"patches-not-allowed\", message: \"Only intents are accepted from this client\" },\n });\n }\n acting = { session, requestId: message.id };\n try {\n const result = model.apply(message.patches);\n if (!result.ok) reject(session, message.id, result);\n } finally {\n acting = undefined;\n }\n }\n }\n };\n\n return {\n model,\n get revision() {\n return model.revision;\n },\n interaction: controller,\n get connections() {\n return sessions.size;\n },\n connect(session) {\n sessions.add(session);\n // The client gets the map at once, without having to ask.\n send(session, snapshotMessage());\n return {\n session,\n receive: (raw) => handle(session, raw),\n disconnect: () => void sessions.delete(session),\n };\n },\n apply: (patches) => model.apply(patches),\n submit(intents, actor) {\n const before = acting;\n acting = { session: { id: \"server\", actor, send: () => undefined }, requestId: undefined };\n try {\n return controller.submit(intents);\n } finally {\n acting = before;\n }\n },\n effect(target, name, params) {\n broadcast({ type: \"effect\", target, name, ...(params ? { params } : {}) });\n },\n snapshot: snapshotMessage,\n async flush() {\n if (persist && model.revision > lastSnapshotRevision) saveSnapshot();\n await queue;\n },\n async destroy() {\n if (destroyed) return;\n await this.flush();\n destroyed = true;\n unsubscribe();\n cancelScheduled?.();\n controller.destroy();\n sessions.clear();\n },\n };\n}\n\n/**\n * Brings a map back from a store, or starts it from `definition` when the store has\n * nothing yet. Changes written after the last snapshot are replayed.\n */\nexport async function restoreMapAuthority<C extends Catalog<string> = Catalog<string>>(\n options: MapAuthorityOptions<C> & { readonly persist: PersistOptions },\n): Promise<MapAuthority> {\n const { store, id } = options.persist;\n const stored = await store.load(id);\n if (!stored) {\n // A snapshot first, so that changes appended later have something to follow.\n await store.save(id, { definition: options.definition, revision: options.revision ?? 0 });\n return createMapAuthority({ ...options, persist: { ...options.persist, baseSaved: true } });\n }\n return createMapAuthority({\n ...options,\n persist: { ...options.persist, baseSaved: true },\n definition: stored.snapshot.definition,\n revision: stored.snapshot.revision,\n replay: stored.patches,\n });\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/authority/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { MapDefinition } from '../model/definition';
|
|
2
|
+
import { MapPatch } from '../model/patches';
|
|
3
|
+
/** The whole map at a revision. */
|
|
4
|
+
export interface MapStoreSnapshot {
|
|
5
|
+
readonly definition: MapDefinition;
|
|
6
|
+
readonly revision: number;
|
|
7
|
+
}
|
|
8
|
+
/** One change, as it was applied. */
|
|
9
|
+
export interface PatchEntry {
|
|
10
|
+
readonly revision: number;
|
|
11
|
+
readonly patches: readonly MapPatch[];
|
|
12
|
+
}
|
|
13
|
+
export interface StoredMap {
|
|
14
|
+
readonly snapshot: MapStoreSnapshot;
|
|
15
|
+
/** Changes made after the snapshot, in order. */
|
|
16
|
+
readonly patches: readonly PatchEntry[];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Where an authority keeps a map between restarts. A snapshot is written from time to
|
|
20
|
+
* time; `append`, when the store offers it, records each change in between, so a restart
|
|
21
|
+
* loses nothing even if the last snapshot is old.
|
|
22
|
+
*/
|
|
23
|
+
export interface MapStore {
|
|
24
|
+
load(id: string): Promise<StoredMap | undefined>;
|
|
25
|
+
/** Replaces the snapshot. Changes up to its revision are no longer needed. */
|
|
26
|
+
save(id: string, snapshot: MapStoreSnapshot): Promise<void>;
|
|
27
|
+
append?(id: string, entry: PatchEntry): Promise<void>;
|
|
28
|
+
}
|
|
29
|
+
export declare class MapStoreCorruptError extends Error {
|
|
30
|
+
constructor(message: string);
|
|
31
|
+
}
|
|
32
|
+
/** Keeps maps in memory. For tests, and for games that do not need to survive a restart. */
|
|
33
|
+
export declare function memoryMapStore(): MapStore & {
|
|
34
|
+
readonly maps: ReadonlyMap<string, StoredMap>;
|
|
35
|
+
};
|
|
36
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/authority/store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEjD,mCAAmC;AACnC,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC;IACnC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,qCAAqC;AACrC,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,SAAS,QAAQ,EAAE,CAAC;CACvC;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IACpC,iDAAiD;IACjD,QAAQ,CAAC,OAAO,EAAE,SAAS,UAAU,EAAE,CAAC;CACzC;AAED;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACvB,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAAC;IACjD,8EAA8E;IAC9E,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D,MAAM,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvD;AAED,qBAAa,oBAAqB,SAAQ,KAAK;gBACjC,OAAO,EAAE,MAAM;CAI5B;AAED,4FAA4F;AAC5F,wBAAgB,cAAc,IAAI,QAAQ,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;CAAE,CAsB7F"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
//#region src/authority/store.ts
|
|
2
|
+
var MapStoreCorruptError = class extends Error {
|
|
3
|
+
constructor(message) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.name = "MapStoreCorruptError";
|
|
6
|
+
}
|
|
7
|
+
};
|
|
8
|
+
/** Keeps maps in memory. For tests, and for games that do not need to survive a restart. */
|
|
9
|
+
function memoryMapStore() {
|
|
10
|
+
const maps = /* @__PURE__ */ new Map();
|
|
11
|
+
const copy = (value) => JSON.parse(JSON.stringify(value));
|
|
12
|
+
return {
|
|
13
|
+
maps,
|
|
14
|
+
async load(id) {
|
|
15
|
+
const stored = maps.get(id);
|
|
16
|
+
return stored ? copy(stored) : void 0;
|
|
17
|
+
},
|
|
18
|
+
async save(id, snapshot) {
|
|
19
|
+
const previous = maps.get(id);
|
|
20
|
+
maps.set(id, {
|
|
21
|
+
snapshot: copy(snapshot),
|
|
22
|
+
patches: (previous?.patches ?? []).filter((entry) => entry.revision > snapshot.revision)
|
|
23
|
+
});
|
|
24
|
+
},
|
|
25
|
+
async append(id, entry) {
|
|
26
|
+
const stored = maps.get(id);
|
|
27
|
+
if (!stored) throw new Error(`Cannot append to "${id}": it has no snapshot yet`);
|
|
28
|
+
stored.patches.push(copy(entry));
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
//#endregion
|
|
33
|
+
export { MapStoreCorruptError, memoryMapStore };
|
|
34
|
+
|
|
35
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","names":[],"sources":["../../src/authority/store.ts"],"sourcesContent":["import type { MapDefinition } from \"../model/definition\";\nimport type { MapPatch } from \"../model/patches\";\n\n/** The whole map at a revision. */\nexport interface MapStoreSnapshot {\n readonly definition: MapDefinition;\n readonly revision: number;\n}\n\n/** One change, as it was applied. */\nexport interface PatchEntry {\n readonly revision: number;\n readonly patches: readonly MapPatch[];\n}\n\nexport interface StoredMap {\n readonly snapshot: MapStoreSnapshot;\n /** Changes made after the snapshot, in order. */\n readonly patches: readonly PatchEntry[];\n}\n\n/**\n * Where an authority keeps a map between restarts. A snapshot is written from time to\n * time; `append`, when the store offers it, records each change in between, so a restart\n * loses nothing even if the last snapshot is old.\n */\nexport interface MapStore {\n load(id: string): Promise<StoredMap | undefined>;\n /** Replaces the snapshot. Changes up to its revision are no longer needed. */\n save(id: string, snapshot: MapStoreSnapshot): Promise<void>;\n append?(id: string, entry: PatchEntry): Promise<void>;\n}\n\nexport class MapStoreCorruptError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"MapStoreCorruptError\";\n }\n}\n\n/** Keeps maps in memory. For tests, and for games that do not need to survive a restart. */\nexport function memoryMapStore(): MapStore & { readonly maps: ReadonlyMap<string, StoredMap> } {\n const maps = new Map<string, { snapshot: MapStoreSnapshot; patches: PatchEntry[] }>();\n const copy = <T>(value: T): T => JSON.parse(JSON.stringify(value)) as T;\n return {\n maps,\n async load(id) {\n const stored = maps.get(id);\n return stored ? copy(stored) : undefined;\n },\n async save(id, snapshot) {\n const previous = maps.get(id);\n maps.set(id, {\n snapshot: copy(snapshot),\n patches: (previous?.patches ?? []).filter((entry) => entry.revision > snapshot.revision),\n });\n },\n async append(id, entry) {\n const stored = maps.get(id);\n if (!stored) throw new Error(`Cannot append to \"${id}\": it has no snapshot yet`);\n stored.patches.push(copy(entry));\n },\n };\n}\n"],"mappings":";AAiCA,IAAa,uBAAb,cAA0C,MAAM;CAC9C,YAAY,SAAiB;EAC3B,MAAM,OAAO;EACb,KAAK,OAAO;CACd;AACF;;AAGA,SAAgB,iBAA+E;CAC7F,MAAM,uBAAO,IAAI,IAAmE;CACpF,MAAM,QAAW,UAAgB,KAAK,MAAM,KAAK,UAAU,KAAK,CAAC;CACjE,OAAO;EACL;EACA,MAAM,KAAK,IAAI;GACb,MAAM,SAAS,KAAK,IAAI,EAAE;GAC1B,OAAO,SAAS,KAAK,MAAM,IAAI,KAAA;EACjC;EACA,MAAM,KAAK,IAAI,UAAU;GACvB,MAAM,WAAW,KAAK,IAAI,EAAE;GAC5B,KAAK,IAAI,IAAI;IACX,UAAU,KAAK,QAAQ;IACvB,UAAU,UAAU,WAAW,CAAC,EAAA,CAAG,QAAQ,UAAU,MAAM,WAAW,SAAS,QAAQ;GACzF,CAAC;EACH;EACA,MAAM,OAAO,IAAI,OAAO;GACtB,MAAM,SAAS,KAAK,IAAI,EAAE;GAC1B,IAAI,CAAC,QAAQ,MAAM,IAAI,MAAM,qBAAqB,GAAG,0BAA0B;GAC/E,OAAO,QAAQ,KAAK,KAAK,KAAK,CAAC;EACjC;CACF;AACF"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { RpgProvider } from '@rpgjs/common';
|
|
2
|
+
import { RpgClient } from '@rpgjs/client';
|
|
3
|
+
import { Container } from 'pixi.js';
|
|
4
|
+
import { AssetResolver } from '../model/assets';
|
|
5
|
+
import { PatchHandlers } from '../model/patches';
|
|
6
|
+
import { ApplyResult, Unsubscribe } from '../model/result';
|
|
7
|
+
import { RemoteMap } from '../remote';
|
|
8
|
+
import { FeatureApis, MapFeature } from '../renderer/feature';
|
|
9
|
+
import { MapView, MapViewOptions } from '../renderer/view';
|
|
10
|
+
import { elements } from '../features';
|
|
11
|
+
export { MAP_BUILDER_CHANNEL } from '../rpgjs/shared';
|
|
12
|
+
type Features = readonly MapFeature<string, object>[];
|
|
13
|
+
export interface MapBuilderClientOptions<F extends Features = Features> {
|
|
14
|
+
/** What the maps are made of: the same assets the server has. */
|
|
15
|
+
readonly assets: AssetResolver;
|
|
16
|
+
/**
|
|
17
|
+
* What the view draws and lets the player do. Defaults to `[elements()]`: events are RPGJS
|
|
18
|
+
* events, drawn by RPGJS, so `events()` would draw them twice.
|
|
19
|
+
*/
|
|
20
|
+
readonly features?: F;
|
|
21
|
+
/** Options of the view: textures, hooks, modes, actor, culling… */
|
|
22
|
+
readonly view?: Omit<MapViewOptions<F, Promise<ApplyResult>>, "model" | "assets" | "features">;
|
|
23
|
+
/** Keep the static colliders of the client's physics in step, so the player does not walk through what was built. Defaults to true. */
|
|
24
|
+
readonly physics?: boolean;
|
|
25
|
+
/** Handlers of the patch types the features add (`terrainPatchHandlers`): the model must know them to apply what the server tells. */
|
|
26
|
+
readonly patchHandlers?: readonly PatchHandlers[];
|
|
27
|
+
/** How long to wait for the server before giving up. Defaults to 10000. */
|
|
28
|
+
readonly timeoutMs?: number;
|
|
29
|
+
/** The player is on a modifiable map: the place to wire controls (`handle.view.placement.start("oak")`). */
|
|
30
|
+
readonly onJoin?: (handle: MapBuilderHandle<F>) => void;
|
|
31
|
+
readonly onLeave?: (handle: MapBuilderHandle<F>) => void;
|
|
32
|
+
readonly onError?: (error: unknown) => void;
|
|
33
|
+
}
|
|
34
|
+
export interface MapBuilderHandle<F extends Features = Features> {
|
|
35
|
+
readonly mapId: string;
|
|
36
|
+
readonly remote: RemoteMap;
|
|
37
|
+
readonly view: MapView<Promise<ApplyResult>> & FeatureApis<F>;
|
|
38
|
+
/** Adds the view to a PixiJS container, e.g. the `componentInstance` of a CanvasEngine component. */
|
|
39
|
+
attachTo(container: Container): () => void;
|
|
40
|
+
/** Leaves the map: stops listening, removes the colliders, destroys the view. */
|
|
41
|
+
dispose(): void;
|
|
42
|
+
}
|
|
43
|
+
export interface MapBuilderClient<F extends Features = Features> {
|
|
44
|
+
/** The map the player is on, once joined. */
|
|
45
|
+
current(): MapBuilderHandle<F> | undefined;
|
|
46
|
+
/** Resolves once the player has joined a modifiable map. */
|
|
47
|
+
whenReady(): Promise<MapBuilderHandle<F>>;
|
|
48
|
+
/**
|
|
49
|
+
* The view as PixiJS children, for the `pixiChildren` prop of RPGJS's `EventLayerComponent`: that
|
|
50
|
+
* puts the elements in the same layer as the characters, so they are sorted in depth together.
|
|
51
|
+
* Empty when the player is not on a modifiable map.
|
|
52
|
+
*/
|
|
53
|
+
readonly pixiChildren: {
|
|
54
|
+
(): Container[];
|
|
55
|
+
set(value: Container[]): void;
|
|
56
|
+
};
|
|
57
|
+
/** Called when the player joins or leaves a modifiable map. */
|
|
58
|
+
onChange(listener: (handle: MapBuilderHandle<F> | undefined) => void): Unsubscribe;
|
|
59
|
+
}
|
|
60
|
+
/** What the map builder gives a game on the client. Pass the type of your features to get `view.placement` and the like typed. */
|
|
61
|
+
export declare function getMapBuilder<F extends Features = Features>(engine?: object): MapBuilderClient<F>;
|
|
62
|
+
/** The module of the map builder for an RPGJS client. Install it with `provideMapBuilder`, or `provideClientModules`. */
|
|
63
|
+
export declare function createMapBuilderClient<const F extends Features = readonly [ReturnType<typeof elements>]>(options: MapBuilderClientOptions<F>): RpgClient;
|
|
64
|
+
/**
|
|
65
|
+
* Installs the map builder on an RPGJS client:
|
|
66
|
+
*
|
|
67
|
+
* ```ts
|
|
68
|
+
* startGame({ providers: [provideMapBuilder({ assets, features: [elements(), selection(), placement({ catalog })] })] })
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export declare function provideMapBuilder<const F extends Features = readonly [ReturnType<typeof elements>]>(options: MapBuilderClientOptions<F>): RpgProvider[];
|
|
72
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"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"}
|