@crowdedkingdoms/crowdyjs 8.2.0 → 8.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/README.md +81 -3
  2. package/dist/crowdy-client.d.ts.map +1 -1
  3. package/dist/crowdy-client.js +5 -1
  4. package/dist/index.d.ts +3 -2
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +2 -2
  7. package/dist/kit/blueprints/combat.d.ts +75 -0
  8. package/dist/kit/blueprints/combat.d.ts.map +1 -0
  9. package/dist/kit/blueprints/combat.js +351 -0
  10. package/dist/kit/blueprints/core.d.ts +222 -0
  11. package/dist/kit/blueprints/core.d.ts.map +1 -0
  12. package/dist/kit/blueprints/core.js +185 -0
  13. package/dist/kit/blueprints/decks.d.ts +50 -0
  14. package/dist/kit/blueprints/decks.d.ts.map +1 -0
  15. package/dist/kit/blueprints/decks.js +163 -0
  16. package/dist/kit/blueprints/economy.d.ts +88 -0
  17. package/dist/kit/blueprints/economy.d.ts.map +1 -0
  18. package/dist/kit/blueprints/economy.js +533 -0
  19. package/dist/kit/blueprints/guild.d.ts +51 -0
  20. package/dist/kit/blueprints/guild.d.ts.map +1 -0
  21. package/dist/kit/blueprints/guild.js +50 -0
  22. package/dist/kit/blueprints/index.d.ts +21 -0
  23. package/dist/kit/blueprints/index.d.ts.map +1 -0
  24. package/dist/kit/blueprints/index.js +20 -0
  25. package/dist/kit/blueprints/inventory.d.ts +38 -0
  26. package/dist/kit/blueprints/inventory.d.ts.map +1 -0
  27. package/dist/kit/blueprints/inventory.js +157 -0
  28. package/dist/kit/blueprints/leaderboards.d.ts +49 -0
  29. package/dist/kit/blueprints/leaderboards.d.ts.map +1 -0
  30. package/dist/kit/blueprints/leaderboards.js +126 -0
  31. package/dist/kit/blueprints/locks.d.ts +82 -0
  32. package/dist/kit/blueprints/locks.d.ts.map +1 -0
  33. package/dist/kit/blueprints/locks.js +155 -0
  34. package/dist/kit/blueprints/loot.d.ts +84 -0
  35. package/dist/kit/blueprints/loot.d.ts.map +1 -0
  36. package/dist/kit/blueprints/loot.js +228 -0
  37. package/dist/kit/blueprints/matches.d.ts +59 -0
  38. package/dist/kit/blueprints/matches.d.ts.map +1 -0
  39. package/dist/kit/blueprints/matches.js +246 -0
  40. package/dist/kit/blueprints/npcs.d.ts +71 -0
  41. package/dist/kit/blueprints/npcs.d.ts.map +1 -0
  42. package/dist/kit/blueprints/npcs.js +122 -0
  43. package/dist/kit/blueprints/plots.d.ts +54 -0
  44. package/dist/kit/blueprints/plots.d.ts.map +1 -0
  45. package/dist/kit/blueprints/plots.js +146 -0
  46. package/dist/kit/blueprints/progression.d.ts +68 -0
  47. package/dist/kit/blueprints/progression.d.ts.map +1 -0
  48. package/dist/kit/blueprints/progression.js +324 -0
  49. package/dist/kit/blueprints/quests.d.ts +65 -0
  50. package/dist/kit/blueprints/quests.d.ts.map +1 -0
  51. package/dist/kit/blueprints/quests.js +284 -0
  52. package/dist/kit/blueprints/worldsim.d.ts +84 -0
  53. package/dist/kit/blueprints/worldsim.d.ts.map +1 -0
  54. package/dist/kit/blueprints/worldsim.js +461 -0
  55. package/dist/kit/combat.d.ts +103 -0
  56. package/dist/kit/combat.d.ts.map +1 -0
  57. package/dist/kit/combat.js +151 -0
  58. package/dist/kit/decks.d.ts +123 -0
  59. package/dist/kit/decks.d.ts.map +1 -0
  60. package/dist/kit/decks.js +138 -0
  61. package/dist/kit/economy.d.ts +244 -0
  62. package/dist/kit/economy.d.ts.map +1 -0
  63. package/dist/kit/economy.js +365 -0
  64. package/dist/kit/features.d.ts +60 -0
  65. package/dist/kit/features.d.ts.map +1 -0
  66. package/dist/kit/features.js +65 -0
  67. package/dist/kit/index.d.ts +13 -2
  68. package/dist/kit/index.d.ts.map +1 -1
  69. package/dist/kit/index.js +12 -1
  70. package/dist/kit/inventory.d.ts +5 -0
  71. package/dist/kit/inventory.d.ts.map +1 -1
  72. package/dist/kit/inventory.js +14 -1
  73. package/dist/kit/kit.d.ts +58 -2
  74. package/dist/kit/kit.d.ts.map +1 -1
  75. package/dist/kit/kit.js +24 -2
  76. package/dist/kit/leaderboards.d.ts +66 -0
  77. package/dist/kit/leaderboards.d.ts.map +1 -0
  78. package/dist/kit/leaderboards.js +94 -0
  79. package/dist/kit/loot.d.ts +106 -0
  80. package/dist/kit/loot.d.ts.map +1 -0
  81. package/dist/kit/loot.js +120 -0
  82. package/dist/kit/matches.d.ts +140 -0
  83. package/dist/kit/matches.d.ts.map +1 -0
  84. package/dist/kit/matches.js +253 -0
  85. package/dist/kit/objects.js +1 -1
  86. package/dist/kit/plots.js +1 -1
  87. package/dist/kit/progression.d.ts +181 -0
  88. package/dist/kit/progression.d.ts.map +1 -0
  89. package/dist/kit/progression.js +265 -0
  90. package/dist/kit/quests.d.ts +110 -0
  91. package/dist/kit/quests.d.ts.map +1 -0
  92. package/dist/kit/quests.js +158 -0
  93. package/dist/kit/social.d.ts +267 -0
  94. package/dist/kit/social.d.ts.map +1 -0
  95. package/dist/kit/social.js +230 -0
  96. package/dist/kit/worldsim.d.ts +225 -0
  97. package/dist/kit/worldsim.d.ts.map +1 -0
  98. package/dist/kit/worldsim.js +231 -0
  99. package/dist/stores/actors.d.ts +316 -0
  100. package/dist/stores/actors.d.ts.map +1 -0
  101. package/dist/stores/actors.js +506 -0
  102. package/dist/stores/chunks.d.ts +180 -0
  103. package/dist/stores/chunks.d.ts.map +1 -0
  104. package/dist/stores/chunks.js +378 -0
  105. package/dist/stores/codec.d.ts +109 -0
  106. package/dist/stores/codec.d.ts.map +1 -0
  107. package/dist/stores/codec.js +186 -0
  108. package/dist/stores/durable.d.ts +144 -0
  109. package/dist/stores/durable.d.ts.map +1 -0
  110. package/dist/stores/durable.js +246 -0
  111. package/dist/stores/errors.d.ts +69 -0
  112. package/dist/stores/errors.d.ts.map +1 -0
  113. package/dist/stores/errors.js +87 -0
  114. package/dist/stores/inbox.d.ts +184 -0
  115. package/dist/stores/inbox.d.ts.map +1 -0
  116. package/dist/stores/inbox.js +326 -0
  117. package/dist/stores/index.d.ts +186 -0
  118. package/dist/stores/index.d.ts.map +1 -0
  119. package/dist/stores/index.js +109 -0
  120. package/dist/stores/keys.d.ts +52 -0
  121. package/dist/stores/keys.d.ts.map +1 -0
  122. package/dist/stores/keys.js +76 -0
  123. package/dist/stores/model.d.ts +81 -0
  124. package/dist/stores/model.d.ts.map +1 -0
  125. package/dist/stores/model.js +163 -0
  126. package/dist/stores/session.d.ts +119 -0
  127. package/dist/stores/session.d.ts.map +1 -0
  128. package/dist/stores/session.js +116 -0
  129. package/dist/stores/ticker.d.ts +44 -0
  130. package/dist/stores/ticker.d.ts.map +1 -0
  131. package/dist/stores/ticker.js +127 -0
  132. package/package.json +6 -1
  133. package/dist/kit/blueprints.d.ts +0 -370
  134. package/dist/kit/blueprints.d.ts.map +0 -1
  135. package/dist/kit/blueprints.js +0 -643
@@ -0,0 +1,186 @@
1
+ /**
2
+ * World Stores — opt-in, SDK-managed game state for CrowdyJS
3
+ * (`@crowdedkingdoms/crowdyjs/stores`).
4
+ *
5
+ * The core client is a thin transport; this layer adds the source-of-truth
6
+ * data structures every game otherwise hand-writes: typed codecs, actor
7
+ * registries, chunk/voxel caches, error attribution, message inboxes, host
8
+ * tracking, and durable-state wrappers. Import only what you use — the core
9
+ * bundle never includes this module, and unused stores tree-shake away
10
+ * (`"sideEffects": false`).
11
+ *
12
+ * Entry point: {@link createWorldSession}.
13
+ */
14
+ export { bool8, bytes, f32, f64, i8, i16, i32, jsonCodec, rawCodec, reserved, structCodec, textCodec, u8, u16, u32, type StateCodec, type StructCodec, type StructField, type StructSpec, type StructValue, } from './codec.js';
15
+ export { CHUNK_SIZE, CHUNK_VOLUME, chunkDistance, chunkKey, chunksAround, fromChunkInput, parseChunkKey, toChunkInput, voxelCoordFromIndex, voxelIndex, worldToChunk, worldToLocalVoxel, type ChunkCoord, } from './keys.js';
16
+ export { intervalTicker, manualTicker, workerTicker, type ManualTicker, type Ticker, } from './ticker.js';
17
+ export { WorldSessionCore, type BusKey, type SentPacketKind, type SentPacketRecord, type WorldSessionBaseConfig, type WorldSessionContext, type WorldStoresClient, } from './session.js';
18
+ export { LocalActorStore, RemoteActorLane, RemoteActorStore, attachLocalActor, attachRemoteActors, localStorageUuidStore, memoryUuidStore, type AckedActorUpdate, type ActorSendError, type ActorUpdateEcho, type GenericErrorEcho, type LocalActorConfig, type LocalActorStatus, type RemoteActor, type RemoteActorSample, type RemoteActorsConfig, type SendReason, type SentActorUpdate, type UuidStore, } from './actors.js';
19
+ export { ErrorStore, attachErrorStore, type AttributedError, type ErrorStoreConfig, } from './errors.js';
20
+ export { ChunkStore, attachChunkStore, type CachedChunk, type ChunkLoadState, type ChunkStoreConfig, type SetVoxelInput, } from './chunks.js';
21
+ export { ActorInbox, ChannelInbox, EventRouter, attachActorInbox, attachChannelInbox, attachEventRouter, type ActorInboxConfig, type ChannelInboxConfig, type EventRouterConfig, type InboxMessage, type TypedEvent, } from './inbox.js';
22
+ export { ContainerMirror, attachContainerMirror, type ContainerMirrorConfig, type MirroredContainer, } from './model.js';
23
+ export { AvatarStateStore, HostTracker, SaveStateStore, attachAvatarState, attachHostTracker, attachSaveState, type AvatarStateConfig, type HostTrackerConfig, type SaveStateConfig, } from './durable.js';
24
+ import { LocalActorStore, RemoteActorStore, type LocalActorConfig, type RemoteActorsConfig } from './actors.js';
25
+ import type { StateCodec } from './codec.js';
26
+ import { ChunkStore, type ChunkStoreConfig } from './chunks.js';
27
+ import { AvatarStateStore, HostTracker, SaveStateStore, type AvatarStateConfig, type HostTrackerConfig, type SaveStateConfig } from './durable.js';
28
+ import { ContainerMirror, type ContainerMirrorConfig } from './model.js';
29
+ import { ErrorStore, type ErrorStoreConfig } from './errors.js';
30
+ import { ActorInbox, ChannelInbox, EventRouter, type ActorInboxConfig, type ChannelInboxConfig, type EventRouterConfig } from './inbox.js';
31
+ import { WorldSessionCore, type WorldSessionBaseConfig, type WorldStoresClient } from './session.js';
32
+ /**
33
+ * Configuration for {@link createWorldSession}: one optional key per store.
34
+ * Only configured stores are constructed — and, via {@link WorldSession}'s
35
+ * conditional typing, only configured stores exist on the returned session's
36
+ * TYPE, so touching an unconfigured store is a compile error, not a runtime
37
+ * surprise. Keys documented on each store's config type; `true` selects a
38
+ * store's defaults.
39
+ */
40
+ export interface WorldSessionConfig extends WorldSessionBaseConfig {
41
+ /** Your own actor: identity, typed state, 5 Hz send loop ({@link LocalActorStore}). */
42
+ self?: LocalActorConfig<any>;
43
+ /**
44
+ * Remote actors: typed registry with lanes, history, staleness
45
+ * ({@link RemoteActorStore}). The self-echo filter is wired from `self`
46
+ * automatically; set `selfUuid` yourself otherwise.
47
+ */
48
+ actors?: RemoteActorsConfig<any>;
49
+ /**
50
+ * Send-error log: attributes `GenericErrorResponse`s to the sends that
51
+ * caused them ({@link ErrorStore}).
52
+ */
53
+ errors?: ErrorStoreConfig | true;
54
+ /**
55
+ * Chunk/voxel cache: bulk loading, typed states, realtime merge,
56
+ * optimistic edits, worldgen write-back ({@link ChunkStore}). The outbound
57
+ * sender uuid is wired from `self` automatically.
58
+ */
59
+ chunks?: ChunkStoreConfig<any, any> | true;
60
+ /** Channel message inbox: per-channel typed history + send ({@link ChannelInbox}). */
61
+ channelInbox?: ChannelInboxConfig<any> | true;
62
+ /** Direct actor-to-actor message inbox ({@link ActorInbox}). */
63
+ actorInbox?: ActorInboxConfig<any> | true;
64
+ /**
65
+ * App-defined event router: per-eventType codecs + handlers, lastEvent
66
+ * cache ({@link EventRouter}).
67
+ */
68
+ events?: EventRouterConfig | true;
69
+ /** Host election tracking: heartbeat loop + isHost ({@link HostTracker}). */
70
+ host?: HostTrackerConfig | true;
71
+ /** Typed per-user app save blob with debounced autosave ({@link SaveStateStore}). */
72
+ save?: SaveStateConfig<any> | true;
73
+ /** Typed avatar public/private/app state ({@link AvatarStateStore}). */
74
+ avatar?: AvatarStateConfig<any, any, any> | true;
75
+ /**
76
+ * Game-model mirror: typed cached container snapshots with coalesced
77
+ * refresh + notify-to-pull channel binding ({@link ContainerMirror}).
78
+ */
79
+ model?: ContainerMirrorConfig | true;
80
+ }
81
+ /** Infer the payload type of a `codec` config field (else the default `D`). */
82
+ type CodecType<CC, D> = CC extends {
83
+ codec: StateCodec<infer T>;
84
+ } ? T : D;
85
+ type VoxelStateType<CC> = CC extends {
86
+ voxelStateCodec: StateCodec<infer T>;
87
+ } ? T : string;
88
+ type ChunkStateType<CC> = CC extends {
89
+ chunkStateCodec: StateCodec<infer T>;
90
+ } ? T : string;
91
+ type AvatarPublicType<CC> = CC extends {
92
+ publicCodec: StateCodec<infer T>;
93
+ } ? T : unknown;
94
+ type AvatarPrivateType<CC> = CC extends {
95
+ privateCodec: StateCodec<infer T>;
96
+ } ? T : unknown;
97
+ type AvatarAppType<CC> = CC extends {
98
+ appCodec: StateCodec<infer T>;
99
+ } ? T : unknown;
100
+ /** The parts of a {@link WorldSession} that exist regardless of config. */
101
+ export interface WorldSessionBase {
102
+ /** The app this session is scoped to. */
103
+ readonly appId: string;
104
+ /** Close the shared subscription, cancel timers, and release the stores. */
105
+ dispose(): void;
106
+ /** The wiring context (for custom store implementations). */
107
+ readonly context: WorldSessionCore;
108
+ }
109
+ /**
110
+ * The session returned by {@link createWorldSession}: the base surface plus
111
+ * exactly the stores your config declared, with every store's value types
112
+ * inferred from the codecs you passed. Annotate variables as
113
+ * `WorldSession<typeof config>` when you need a name for it.
114
+ */
115
+ export type WorldSession<C extends WorldSessionConfig = WorldSessionConfig> = WorldSessionBase & (C extends {
116
+ self: LocalActorConfig<infer T>;
117
+ } ? {
118
+ readonly self: LocalActorStore<T>;
119
+ } : unknown) & (C extends {
120
+ actors: RemoteActorsConfig<infer T>;
121
+ } ? {
122
+ readonly actors: RemoteActorStore<T>;
123
+ } : unknown) & (C extends {
124
+ errors: ErrorStoreConfig | true;
125
+ } ? {
126
+ readonly errors: ErrorStore;
127
+ } : unknown) & (C extends {
128
+ chunks: infer CC;
129
+ } ? {
130
+ readonly chunks: ChunkStore<VoxelStateType<CC>, ChunkStateType<CC>>;
131
+ } : unknown) & (C extends {
132
+ channelInbox: infer CC;
133
+ } ? {
134
+ readonly channelInbox: ChannelInbox<CodecType<CC, string>>;
135
+ } : unknown) & (C extends {
136
+ actorInbox: infer CC;
137
+ } ? {
138
+ readonly actorInbox: ActorInbox<CodecType<CC, string>>;
139
+ } : unknown) & (C extends {
140
+ events: EventRouterConfig | true;
141
+ } ? {
142
+ readonly events: EventRouter;
143
+ } : unknown) & (C extends {
144
+ host: HostTrackerConfig | true;
145
+ } ? {
146
+ readonly host: HostTracker;
147
+ } : unknown) & (C extends {
148
+ save: infer CC;
149
+ } ? {
150
+ readonly save: SaveStateStore<CodecType<CC, unknown>>;
151
+ } : unknown) & (C extends {
152
+ avatar: infer CC;
153
+ } ? {
154
+ readonly avatar: AvatarStateStore<AvatarPublicType<CC>, AvatarPrivateType<CC>, AvatarAppType<CC>>;
155
+ } : unknown) & (C extends {
156
+ model: ContainerMirrorConfig | true;
157
+ } ? {
158
+ readonly model: ContainerMirror;
159
+ } : unknown);
160
+ /**
161
+ * Create a **world session**: one shared `udpNotifications` subscription
162
+ * fanned out to the stores you configure, one shared {@link Ticker}, and a
163
+ * single `dispose()`. Pass your `CrowdyClient` (it satisfies
164
+ * {@link WorldStoresClient} structurally) and the app id.
165
+ *
166
+ * ```ts
167
+ * import { createWorldSession, structCodec, f32, u8, jsonCodec, workerTicker } from '@crowdedkingdoms/crowdyjs/stores';
168
+ *
169
+ * const poseCodec = structCodec({ x: f32(), y: f32(), z: f32(), flags: u8() });
170
+ * const session = createWorldSession(client, appId, {
171
+ * ticker: workerTicker(), // hold 5 Hz in backgrounded tabs
172
+ * self: { codec: poseCodec, initialState: { x: 0, y: 0, z: 0, flags: 0 } },
173
+ * actors: { codec: poseCodec },
174
+ * errors: true,
175
+ * save: { codec: jsonCodec<{ level: number }>(), autosaveMs: 5000 },
176
+ * });
177
+ * await session.self.join({ x: '0', y: '0', z: '0' });
178
+ * session.self.patchState({ x: 12.5 }); // next tick replicates it
179
+ * for (const other of session.actors.list()) {} // typed poses, self filtered
180
+ * session.save.set({ level: 2 }); // autosaves, typed
181
+ * // session.chunks — compile error: not configured.
182
+ * session.dispose();
183
+ * ```
184
+ */
185
+ export declare function createWorldSession<const C extends WorldSessionConfig = Record<never, never>>(client: WorldStoresClient, appId: string, config?: C): WorldSession<C>;
186
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/stores/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * World Stores — opt-in, SDK-managed game state for CrowdyJS
3
+ * (`@crowdedkingdoms/crowdyjs/stores`).
4
+ *
5
+ * The core client is a thin transport; this layer adds the source-of-truth
6
+ * data structures every game otherwise hand-writes: typed codecs, actor
7
+ * registries, chunk/voxel caches, error attribution, message inboxes, host
8
+ * tracking, and durable-state wrappers. Import only what you use — the core
9
+ * bundle never includes this module, and unused stores tree-shake away
10
+ * (`"sideEffects": false`).
11
+ *
12
+ * Entry point: {@link createWorldSession}.
13
+ */
14
+ export { bool8, bytes, f32, f64, i8, i16, i32, jsonCodec, rawCodec, reserved, structCodec, textCodec, u8, u16, u32, } from './codec.js';
15
+ export { CHUNK_SIZE, CHUNK_VOLUME, chunkDistance, chunkKey, chunksAround, fromChunkInput, parseChunkKey, toChunkInput, voxelCoordFromIndex, voxelIndex, worldToChunk, worldToLocalVoxel, } from './keys.js';
16
+ export { intervalTicker, manualTicker, workerTicker, } from './ticker.js';
17
+ export { WorldSessionCore, } from './session.js';
18
+ export { LocalActorStore, RemoteActorLane, RemoteActorStore, attachLocalActor, attachRemoteActors, localStorageUuidStore, memoryUuidStore, } from './actors.js';
19
+ export { ErrorStore, attachErrorStore, } from './errors.js';
20
+ export { ChunkStore, attachChunkStore, } from './chunks.js';
21
+ export { ActorInbox, ChannelInbox, EventRouter, attachActorInbox, attachChannelInbox, attachEventRouter, } from './inbox.js';
22
+ export { ContainerMirror, attachContainerMirror, } from './model.js';
23
+ export { AvatarStateStore, HostTracker, SaveStateStore, attachAvatarState, attachHostTracker, attachSaveState, } from './durable.js';
24
+ import { LocalActorStore, RemoteActorStore, } from './actors.js';
25
+ import { ChunkStore } from './chunks.js';
26
+ import { AvatarStateStore, HostTracker, SaveStateStore, } from './durable.js';
27
+ import { ContainerMirror } from './model.js';
28
+ import { ErrorStore } from './errors.js';
29
+ import { ActorInbox, ChannelInbox, EventRouter, } from './inbox.js';
30
+ import { WorldSessionCore, } from './session.js';
31
+ /**
32
+ * Create a **world session**: one shared `udpNotifications` subscription
33
+ * fanned out to the stores you configure, one shared {@link Ticker}, and a
34
+ * single `dispose()`. Pass your `CrowdyClient` (it satisfies
35
+ * {@link WorldStoresClient} structurally) and the app id.
36
+ *
37
+ * ```ts
38
+ * import { createWorldSession, structCodec, f32, u8, jsonCodec, workerTicker } from '@crowdedkingdoms/crowdyjs/stores';
39
+ *
40
+ * const poseCodec = structCodec({ x: f32(), y: f32(), z: f32(), flags: u8() });
41
+ * const session = createWorldSession(client, appId, {
42
+ * ticker: workerTicker(), // hold 5 Hz in backgrounded tabs
43
+ * self: { codec: poseCodec, initialState: { x: 0, y: 0, z: 0, flags: 0 } },
44
+ * actors: { codec: poseCodec },
45
+ * errors: true,
46
+ * save: { codec: jsonCodec<{ level: number }>(), autosaveMs: 5000 },
47
+ * });
48
+ * await session.self.join({ x: '0', y: '0', z: '0' });
49
+ * session.self.patchState({ x: 12.5 }); // next tick replicates it
50
+ * for (const other of session.actors.list()) {} // typed poses, self filtered
51
+ * session.save.set({ level: 2 }); // autosaves, typed
52
+ * // session.chunks — compile error: not configured.
53
+ * session.dispose();
54
+ * ```
55
+ */
56
+ export function createWorldSession(client, appId, config) {
57
+ const cfg = config ?? {};
58
+ const opt = (value) => value === true ? {} : value;
59
+ const core = new WorldSessionCore(client, appId, cfg.ticker);
60
+ // The error store registers the send-tracking sink — construct it first so
61
+ // the very first actor/chunk sends are already attributable.
62
+ const errors = cfg.errors ? new ErrorStore(core, opt(cfg.errors)) : undefined;
63
+ const self = cfg.self ? new LocalActorStore(core, cfg.self) : undefined;
64
+ const selfUuid = self ? () => self.uuid : undefined;
65
+ const actors = cfg.actors
66
+ ? new RemoteActorStore(core, {
67
+ // Filter the local echo automatically when a self store exists.
68
+ selfUuid,
69
+ ...cfg.actors,
70
+ })
71
+ : undefined;
72
+ const chunks = cfg.chunks
73
+ ? new ChunkStore(core, {
74
+ // Stamp outbound voxel edits with the local actor's uuid.
75
+ actorUuid: selfUuid,
76
+ ...opt(cfg.chunks),
77
+ })
78
+ : undefined;
79
+ const channelInbox = cfg.channelInbox
80
+ ? new ChannelInbox(core, { senderUuid: selfUuid, ...opt(cfg.channelInbox) })
81
+ : undefined;
82
+ const actorInbox = cfg.actorInbox
83
+ ? new ActorInbox(core, opt(cfg.actorInbox))
84
+ : undefined;
85
+ const events = cfg.events
86
+ ? new EventRouter(core, { senderUuid: selfUuid, ...opt(cfg.events) })
87
+ : undefined;
88
+ const host = cfg.host ? new HostTracker(core, opt(cfg.host)) : undefined;
89
+ const save = cfg.save ? new SaveStateStore(core, opt(cfg.save)) : undefined;
90
+ const avatar = cfg.avatar ? new AvatarStateStore(core, opt(cfg.avatar)) : undefined;
91
+ const model = cfg.model ? new ContainerMirror(core, opt(cfg.model)) : undefined;
92
+ const session = {
93
+ appId,
94
+ context: core,
95
+ ...(self ? { self } : {}),
96
+ ...(actors ? { actors } : {}),
97
+ ...(errors ? { errors } : {}),
98
+ ...(chunks ? { chunks } : {}),
99
+ ...(channelInbox ? { channelInbox } : {}),
100
+ ...(actorInbox ? { actorInbox } : {}),
101
+ ...(events ? { events } : {}),
102
+ ...(host ? { host } : {}),
103
+ ...(save ? { save } : {}),
104
+ ...(avatar ? { avatar } : {}),
105
+ ...(model ? { model } : {}),
106
+ dispose: () => core.dispose(),
107
+ };
108
+ return session;
109
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Chunk/voxel coordinate math shared by the World Stores — the helpers every
3
+ * voxel game re-derives (chunk keys, world→chunk mapping, the 4096-slot voxel
4
+ * index). A chunk is a 16×16×16 voxel cube addressed by signed-int64 chunk
5
+ * coordinates (decimal strings on the wire).
6
+ */
7
+ import type { ChunkCoordinatesInput } from '../generated/graphql.js';
8
+ /** Voxels per chunk axis. */
9
+ export declare const CHUNK_SIZE = 16;
10
+ /** Voxels per chunk (16³) — the length of a dense voxel array. */
11
+ export declare const CHUNK_VOLUME: number;
12
+ /** A chunk coordinate with numeric axes (convenient client-side form). */
13
+ export interface ChunkCoord {
14
+ x: number;
15
+ y: number;
16
+ z: number;
17
+ }
18
+ /** The stable string key a chunk is cached under: `"x:y:z"`. */
19
+ export declare function chunkKey(coord: ChunkCoord | ChunkCoordinatesInput): string;
20
+ /** Parse a {@link chunkKey} back into numeric coordinates. */
21
+ export declare function parseChunkKey(key: string): ChunkCoord;
22
+ /** Convert a numeric chunk coordinate to the wire form (decimal strings). */
23
+ export declare function toChunkInput(coord: ChunkCoord): ChunkCoordinatesInput;
24
+ /** Convert a wire chunk coordinate (decimal strings) to numeric form. */
25
+ export declare function fromChunkInput(coord: ChunkCoordinatesInput): ChunkCoord;
26
+ /** The chunk containing a world-space position. */
27
+ export declare function worldToChunk(x: number, y: number, z: number): ChunkCoord;
28
+ /** The within-chunk voxel coordinate (0-15 per axis) of a world position. */
29
+ export declare function worldToLocalVoxel(x: number, y: number, z: number): {
30
+ x: number;
31
+ y: number;
32
+ z: number;
33
+ };
34
+ /**
35
+ * The dense-array index of a within-chunk voxel coordinate:
36
+ * `x + y*16 + z*256` (the platform's chunk `voxels` layout).
37
+ */
38
+ export declare function voxelIndex(x: number, y: number, z: number): number;
39
+ /** Invert {@link voxelIndex} back to within-chunk coordinates. */
40
+ export declare function voxelCoordFromIndex(index: number): {
41
+ x: number;
42
+ y: number;
43
+ z: number;
44
+ };
45
+ /**
46
+ * Every chunk coordinate within a Chebyshev radius of `center` (the cube
47
+ * `(2r+1)³`, matching `chunks.byDistance` semantics), center first.
48
+ */
49
+ export declare function chunksAround(center: ChunkCoord, radius: number): ChunkCoord[];
50
+ /** Chebyshev (chunk-grid) distance between two chunk coordinates. */
51
+ export declare function chunkDistance(a: ChunkCoord, b: ChunkCoord): number;
52
+ //# sourceMappingURL=keys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../../src/stores/keys.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAErE,6BAA6B;AAC7B,eAAO,MAAM,UAAU,KAAK,CAAC;AAC7B,kEAAkE;AAClE,eAAO,MAAM,YAAY,QAAuC,CAAC;AAEjE,0EAA0E;AAC1E,MAAM,WAAW,UAAU;IACzB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,gEAAgE;AAChE,wBAAgB,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,qBAAqB,GAAG,MAAM,CAE1E;AAED,8DAA8D;AAC9D,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAGrD;AAED,6EAA6E;AAC7E,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,qBAAqB,CAErE;AAED,yEAAyE;AACzE,wBAAgB,cAAc,CAAC,KAAK,EAAE,qBAAqB,GAAG,UAAU,CAEvE;AAED,mDAAmD;AACnD,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,UAAU,CAMxE;AAED,6EAA6E;AAC7E,wBAAgB,iBAAiB,CAC/B,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,GACR;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAGrC;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAElE;AAED,kEAAkE;AAClE,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAMtF;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,EAAE,CAW7E;AAED,qEAAqE;AACrE,wBAAgB,aAAa,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,GAAG,MAAM,CAElE"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Chunk/voxel coordinate math shared by the World Stores — the helpers every
3
+ * voxel game re-derives (chunk keys, world→chunk mapping, the 4096-slot voxel
4
+ * index). A chunk is a 16×16×16 voxel cube addressed by signed-int64 chunk
5
+ * coordinates (decimal strings on the wire).
6
+ */
7
+ /** Voxels per chunk axis. */
8
+ export const CHUNK_SIZE = 16;
9
+ /** Voxels per chunk (16³) — the length of a dense voxel array. */
10
+ export const CHUNK_VOLUME = CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE;
11
+ /** The stable string key a chunk is cached under: `"x:y:z"`. */
12
+ export function chunkKey(coord) {
13
+ return `${coord.x}:${coord.y}:${coord.z}`;
14
+ }
15
+ /** Parse a {@link chunkKey} back into numeric coordinates. */
16
+ export function parseChunkKey(key) {
17
+ const [x, y, z] = key.split(':').map(Number);
18
+ return { x, y, z };
19
+ }
20
+ /** Convert a numeric chunk coordinate to the wire form (decimal strings). */
21
+ export function toChunkInput(coord) {
22
+ return { x: String(coord.x), y: String(coord.y), z: String(coord.z) };
23
+ }
24
+ /** Convert a wire chunk coordinate (decimal strings) to numeric form. */
25
+ export function fromChunkInput(coord) {
26
+ return { x: Number(coord.x), y: Number(coord.y), z: Number(coord.z) };
27
+ }
28
+ /** The chunk containing a world-space position. */
29
+ export function worldToChunk(x, y, z) {
30
+ return {
31
+ x: Math.floor(x / CHUNK_SIZE),
32
+ y: Math.floor(y / CHUNK_SIZE),
33
+ z: Math.floor(z / CHUNK_SIZE),
34
+ };
35
+ }
36
+ /** The within-chunk voxel coordinate (0-15 per axis) of a world position. */
37
+ export function worldToLocalVoxel(x, y, z) {
38
+ const mod = (n) => ((Math.floor(n) % CHUNK_SIZE) + CHUNK_SIZE) % CHUNK_SIZE;
39
+ return { x: mod(x), y: mod(y), z: mod(z) };
40
+ }
41
+ /**
42
+ * The dense-array index of a within-chunk voxel coordinate:
43
+ * `x + y*16 + z*256` (the platform's chunk `voxels` layout).
44
+ */
45
+ export function voxelIndex(x, y, z) {
46
+ return x + y * CHUNK_SIZE + z * CHUNK_SIZE * CHUNK_SIZE;
47
+ }
48
+ /** Invert {@link voxelIndex} back to within-chunk coordinates. */
49
+ export function voxelCoordFromIndex(index) {
50
+ return {
51
+ x: index % CHUNK_SIZE,
52
+ y: Math.floor(index / CHUNK_SIZE) % CHUNK_SIZE,
53
+ z: Math.floor(index / (CHUNK_SIZE * CHUNK_SIZE)),
54
+ };
55
+ }
56
+ /**
57
+ * Every chunk coordinate within a Chebyshev radius of `center` (the cube
58
+ * `(2r+1)³`, matching `chunks.byDistance` semantics), center first.
59
+ */
60
+ export function chunksAround(center, radius) {
61
+ const out = [center];
62
+ for (let dx = -radius; dx <= radius; dx++) {
63
+ for (let dy = -radius; dy <= radius; dy++) {
64
+ for (let dz = -radius; dz <= radius; dz++) {
65
+ if (dx === 0 && dy === 0 && dz === 0)
66
+ continue;
67
+ out.push({ x: center.x + dx, y: center.y + dy, z: center.z + dz });
68
+ }
69
+ }
70
+ }
71
+ return out;
72
+ }
73
+ /** Chebyshev (chunk-grid) distance between two chunk coordinates. */
74
+ export function chunkDistance(a, b) {
75
+ return Math.max(Math.abs(a.x - b.x), Math.abs(a.y - b.y), Math.abs(a.z - b.z));
76
+ }
@@ -0,0 +1,81 @@
1
+ /**
2
+ * ContainerMirror — the client half of the platform's **notify-to-pull**
3
+ * pattern for game-model state: keep typed snapshots of the containers you
4
+ * care about, re-pull them on demand or whenever a bound channel pings
5
+ * ("state changed"), and render straight from the cache.
6
+ *
7
+ * Model changes are pull-based on this platform (there is no model
8
+ * subscription); functions declare channel/spatial notifications and clients
9
+ * re-read. The Game Kit's match layer pings a per-match channel — bind the
10
+ * mirror to that channel and every watched container refreshes itself.
11
+ */
12
+ import type { WorldSessionContext } from './session.js';
13
+ /** A typed snapshot of one watched container. */
14
+ export interface MirroredContainer<T = Record<string, unknown>> {
15
+ readonly containerId: string;
16
+ typeName: string;
17
+ displayName: string;
18
+ ownerUserId: string | null;
19
+ /** The parsed, caller-visible properties. */
20
+ value: T;
21
+ /** Bumped on every refresh that changed the snapshot. */
22
+ revision: number;
23
+ /** Local time of the last refresh. */
24
+ refreshedAt: number;
25
+ }
26
+ /** Options for {@link attachContainerMirror}. */
27
+ export interface ContainerMirrorConfig {
28
+ /** Clock override for tests. Defaults to `Date.now`. */
29
+ now?: () => number;
30
+ }
31
+ /**
32
+ * The SDK-managed **model mirror**: typed, cached snapshots of watched
33
+ * game-model containers with coalesced refresh and channel-ping binding.
34
+ * Reads are synchronous ({@link get}); {@link onChange} fires only when a
35
+ * refresh actually changed the visible state.
36
+ */
37
+ export declare class ContainerMirror {
38
+ private readonly ctx;
39
+ private readonly watches;
40
+ private readonly listeners;
41
+ private readonly boundChannels;
42
+ private readonly now;
43
+ private refreshing;
44
+ private refreshQueued;
45
+ constructor(ctx: WorldSessionContext, config?: ContainerMirrorConfig);
46
+ /**
47
+ * Watch a container: fetches the initial snapshot and keeps it refreshable.
48
+ * `parse` maps the visible properties object to your type (defaults to the
49
+ * raw object).
50
+ */
51
+ watch<T = Record<string, unknown>>(containerId: string, parse?: (properties: Record<string, unknown>) => T): Promise<MirroredContainer<T>>;
52
+ /** Stop watching a container (its snapshot is dropped). */
53
+ unwatch(containerId: string): void;
54
+ /** The current snapshot of a watched container (undefined before watch resolves). */
55
+ get<T = Record<string, unknown>>(containerId: string): MirroredContainer<T> | undefined;
56
+ /** Every watched snapshot. */
57
+ list(): Array<MirroredContainer<unknown>>;
58
+ /**
59
+ * Subscribe to snapshot changes — every watched container, or one
60
+ * `containerId`. Fires only when a refresh changed the visible state.
61
+ * @returns off.
62
+ */
63
+ onChange(handler: (container: MirroredContainer<unknown>) => void, containerId?: string): () => void;
64
+ /**
65
+ * Bind a channel: any message on it triggers a coalesced {@link refreshAll}
66
+ * — pair with model functions that declare channel notifications (e.g. the
67
+ * Game Kit's `match_changed` pings).
68
+ */
69
+ bindToChannel(channelId: string): () => void;
70
+ /** Re-pull one watched container now. */
71
+ refresh(containerId: string): Promise<void>;
72
+ /**
73
+ * Re-pull every watched container. Concurrent calls coalesce: a refresh
74
+ * requested while one is running queues exactly one follow-up pass (pings
75
+ * can burst; state converges without stampeding the API).
76
+ */
77
+ refreshAll(): Promise<void>;
78
+ }
79
+ /** Attach a {@link ContainerMirror}. Prefer the `model` config key. */
80
+ export declare function attachContainerMirror(ctx: WorldSessionContext, config?: ContainerMirrorConfig): ContainerMirror;
81
+ //# sourceMappingURL=model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../src/stores/model.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAExD,iDAAiD;AACjD,MAAM,WAAW,iBAAiB,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC5D,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,6CAA6C;IAC7C,KAAK,EAAE,CAAC,CAAC;IACT,yDAAyD;IACzD,QAAQ,EAAE,MAAM,CAAC;IACjB,sCAAsC;IACtC,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,iDAAiD;AACjD,MAAM,WAAW,qBAAqB;IACpC,wDAAwD;IACxD,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AASD;;;;;GAKG;AACH,qBAAa,eAAe;IAYxB,OAAO,CAAC,QAAQ,CAAC,GAAG;IAXtB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiC;IACzD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAGrB;IACL,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAqB;IACnD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,aAAa,CAAS;gBAGX,GAAG,EAAE,mBAAmB,EACzC,MAAM,GAAE,qBAA0B;IAcpC;;;;OAIG;IACG,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrC,WAAW,EAAE,MAAM,EACnB,KAAK,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,GACjD,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;IAWhC,2DAA2D;IAC3D,OAAO,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAIlC,qFAAqF;IACrF,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,EAAE,MAAM,GAAG,iBAAiB,CAAC,CAAC,CAAC,GAAG,SAAS;IAMvF,8BAA8B;IAC9B,IAAI,IAAI,KAAK,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAQzC;;;;OAIG;IACH,QAAQ,CACN,OAAO,EAAE,CAAC,SAAS,EAAE,iBAAiB,CAAC,OAAO,CAAC,KAAK,IAAI,EACxD,WAAW,CAAC,EAAE,MAAM,GACnB,MAAM,IAAI;IAMb;;;;OAIG;IACH,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,IAAI;IAK5C,yCAAyC;IACnC,OAAO,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiDjD;;;;OAIG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;CAqBlC;AAED,uEAAuE;AACvE,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,mBAAmB,EACxB,MAAM,GAAE,qBAA0B,GACjC,eAAe,CAEjB"}