@crowdedkingdoms/crowdyjs 8.6.0 → 8.8.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/MIGRATION.md +81 -0
- package/README.md +2 -2
- package/dist/crowdy-client.d.ts.map +1 -1
- package/dist/crowdy-client.js +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/kit/combat.d.ts +38 -1
- package/dist/kit/combat.d.ts.map +1 -1
- package/dist/kit/combat.js +45 -1
- package/dist/kit/decks.d.ts +33 -1
- package/dist/kit/decks.d.ts.map +1 -1
- package/dist/kit/decks.js +49 -1
- package/dist/kit/director.d.ts +88 -0
- package/dist/kit/director.d.ts.map +1 -0
- package/dist/kit/director.js +86 -0
- package/dist/kit/economy.d.ts +46 -1
- package/dist/kit/economy.d.ts.map +1 -1
- package/dist/kit/economy.js +63 -1
- package/dist/kit/engine.d.ts +43 -0
- package/dist/kit/engine.d.ts.map +1 -0
- package/dist/kit/engine.js +108 -0
- package/dist/kit/index.d.ts +12 -4
- package/dist/kit/index.d.ts.map +1 -1
- package/dist/kit/index.js +10 -2
- package/dist/kit/instances.d.ts +52 -0
- package/dist/kit/instances.d.ts.map +1 -0
- package/dist/kit/instances.js +60 -0
- package/dist/kit/kit.d.ts +31 -1
- package/dist/kit/kit.d.ts.map +1 -1
- package/dist/kit/kit.js +21 -7
- package/dist/kit/leaderboards.d.ts +21 -1
- package/dist/kit/leaderboards.d.ts.map +1 -1
- package/dist/kit/leaderboards.js +40 -1
- package/dist/kit/matches.d.ts +33 -1
- package/dist/kit/matches.d.ts.map +1 -1
- package/dist/kit/matches.js +56 -1
- package/dist/kit/matchmaking.d.ts +57 -0
- package/dist/kit/matchmaking.d.ts.map +1 -0
- package/dist/kit/matchmaking.js +59 -0
- package/dist/kit/minigames.d.ts +30 -0
- package/dist/kit/minigames.d.ts.map +1 -0
- package/dist/kit/minigames.js +38 -0
- package/dist/kit/mobs.d.ts +90 -0
- package/dist/kit/mobs.d.ts.map +1 -0
- package/dist/kit/mobs.js +98 -0
- package/dist/kit/npcs.d.ts +38 -1
- package/dist/kit/npcs.d.ts.map +1 -1
- package/dist/kit/npcs.js +36 -1
- package/dist/kit/pets.d.ts +85 -0
- package/dist/kit/pets.d.ts.map +1 -0
- package/dist/kit/pets.js +96 -0
- package/dist/kit/quests.d.ts +57 -0
- package/dist/kit/quests.d.ts.map +1 -1
- package/dist/kit/quests.js +72 -0
- package/dist/kit/wire.d.ts +124 -0
- package/dist/kit/wire.d.ts.map +1 -0
- package/dist/kit/wire.js +206 -0
- package/dist/kit/worldsim.d.ts +34 -1
- package/dist/kit/worldsim.d.ts.map +1 -1
- package/dist/kit/worldsim.js +38 -1
- package/package.json +1 -1
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Engine wire registry — the client mirror of the server's
|
|
3
|
+
* `crowdy-game-kit-core::wire` (the single source of truth for the actor
|
|
4
|
+
* pose layout and flag-bit registry used by compute-module game engines).
|
|
5
|
+
* Parity with the Rust crate is checked by the kit unit suite: any change
|
|
6
|
+
* here must land in kit-core first.
|
|
7
|
+
*
|
|
8
|
+
* 48-byte little-endian pose: pos f32 x3 (0..11), yaw/pitch f32 (12..19),
|
|
9
|
+
* velocity f32 x3 (20..31), flags u8 (32), held u8 (33), 34-35 reserved,
|
|
10
|
+
* updated_at f64 ms (36..43), 44-47 reserved. Payloads may append opaque
|
|
11
|
+
* UTF-8 suffix bytes (engines put the entity's container id there).
|
|
12
|
+
*/
|
|
13
|
+
import type { StateCodec } from '../stores/codec.js';
|
|
14
|
+
export declare const POSE_BYTES = 48;
|
|
15
|
+
/** Flag-bit registry. Bits 0-3 are platform-reserved; games may use 4-7. */
|
|
16
|
+
export declare const FLAG_GROUNDED = 1;
|
|
17
|
+
export declare const FLAG_MOB = 2;
|
|
18
|
+
export declare const FLAG_NPC = 4;
|
|
19
|
+
export declare const FLAG_RESERVED3 = 8;
|
|
20
|
+
/** The decoded engine pose (plus the payload suffix, when present). */
|
|
21
|
+
export interface EnginePose {
|
|
22
|
+
x: number;
|
|
23
|
+
y: number;
|
|
24
|
+
z: number;
|
|
25
|
+
yaw: number;
|
|
26
|
+
pitch: number;
|
|
27
|
+
velX: number;
|
|
28
|
+
velY: number;
|
|
29
|
+
velZ: number;
|
|
30
|
+
flags: number;
|
|
31
|
+
held: number;
|
|
32
|
+
updatedAtMs: number;
|
|
33
|
+
/** UTF-8 payload suffix after the 48-byte pose (container id), if any. */
|
|
34
|
+
suffix: string | null;
|
|
35
|
+
}
|
|
36
|
+
/** Encode a pose (suffix appended when set). */
|
|
37
|
+
export declare function encodeEnginePose(pose: Partial<EnginePose>): Uint8Array;
|
|
38
|
+
/**
|
|
39
|
+
* Decode the leading 48 bytes (tolerates longer payloads — the suffix is
|
|
40
|
+
* extracted). Returns null for short or non-finite payloads.
|
|
41
|
+
*/
|
|
42
|
+
export declare function decodeEnginePose(bytes: Uint8Array): EnginePose | null;
|
|
43
|
+
/** The UTF-8 suffix after the pose (engine container ids), if any. */
|
|
44
|
+
export declare function poseSuffix(bytes: Uint8Array): string | null;
|
|
45
|
+
/**
|
|
46
|
+
* A {@link StateCodec} for engine poses over the base64 wire form — plug it
|
|
47
|
+
* into `attachRemoteActors` / `createWorldSession` actor config. Undecodable
|
|
48
|
+
* payloads yield a zeroed pose with `flags: 0` (they land in the players
|
|
49
|
+
* lane predicate's care, same as unknown custom states).
|
|
50
|
+
*/
|
|
51
|
+
export declare const enginePoseCodec: StateCodec<EnginePose>;
|
|
52
|
+
/**
|
|
53
|
+
* Ready-made lane predicates for `createWorldSession` when the world runs
|
|
54
|
+
* compute-module engines: `players` (no engine flag), `mobs` (FLAG_MOB) and
|
|
55
|
+
* `npcs` (FLAG_NPC) — what Blocks with Friends hand-wired in its Phase 9
|
|
56
|
+
* adoption. Spread extra lanes on top as needed.
|
|
57
|
+
*/
|
|
58
|
+
export declare function engineLanes(): Record<string, (state: EnginePose) => boolean>;
|
|
59
|
+
/** Contact damage decided by a mob/combat engine (kit-play referee). */
|
|
60
|
+
export declare const EVENT_CONTACT_DAMAGE = 77;
|
|
61
|
+
/** Weather/season transition from a world engine (kit-sim weather). */
|
|
62
|
+
export declare const EVENT_WEATHER = 90;
|
|
63
|
+
/** Turn changed (kit-play turns; match engines). */
|
|
64
|
+
export declare const EVENT_TURN = 91;
|
|
65
|
+
/** Score / match summary (kit-play score). */
|
|
66
|
+
export declare const EVENT_SCORE = 92;
|
|
67
|
+
/** Match proposal (matchmaking → matches handoff). */
|
|
68
|
+
export declare const EVENT_PROPOSAL = 93;
|
|
69
|
+
/** Split an engine server-event payload into its type + JSON body. */
|
|
70
|
+
export declare function parseEngineEvent(bytes: Uint8Array): {
|
|
71
|
+
eventType: number;
|
|
72
|
+
body: Record<string, unknown>;
|
|
73
|
+
} | null;
|
|
74
|
+
/** A parsed type-77 contact-damage event. */
|
|
75
|
+
export interface ContactDamageEvent {
|
|
76
|
+
targetUuid: string;
|
|
77
|
+
damage: number;
|
|
78
|
+
mobId: string;
|
|
79
|
+
mobName: string;
|
|
80
|
+
}
|
|
81
|
+
/** Parse a contact-damage event; null when the payload is another type. */
|
|
82
|
+
export declare function parseContactDamage(bytes: Uint8Array): ContactDamageEvent | null;
|
|
83
|
+
/** A parsed type-90 weather transition event. */
|
|
84
|
+
export interface WeatherEvent {
|
|
85
|
+
weather: string;
|
|
86
|
+
sinceMs: number;
|
|
87
|
+
untilMs: number;
|
|
88
|
+
/** Extra fields engines add (dayPhase, isNight, remainingMs, ...). */
|
|
89
|
+
body: Record<string, unknown>;
|
|
90
|
+
}
|
|
91
|
+
/** Parse a weather event; null when the payload is another type. */
|
|
92
|
+
export declare function parseWeatherEvent(bytes: Uint8Array): WeatherEvent | null;
|
|
93
|
+
/** A parsed type-91 turn-changed event (match engines). */
|
|
94
|
+
export interface TurnEvent {
|
|
95
|
+
actorId: string;
|
|
96
|
+
round: number;
|
|
97
|
+
turnInRound: number;
|
|
98
|
+
body: Record<string, unknown>;
|
|
99
|
+
}
|
|
100
|
+
/** Parse a turn event; null when the payload is another type. */
|
|
101
|
+
export declare function parseTurnEvent(bytes: Uint8Array): TurnEvent | null;
|
|
102
|
+
/** A parsed type-92 score/summary event (match engines). */
|
|
103
|
+
export interface ScoreEvent {
|
|
104
|
+
/** Per-actor standings when present. */
|
|
105
|
+
standings: Array<{
|
|
106
|
+
actorId: string;
|
|
107
|
+
score: number;
|
|
108
|
+
rank: number;
|
|
109
|
+
}>;
|
|
110
|
+
winnerId: string | null;
|
|
111
|
+
body: Record<string, unknown>;
|
|
112
|
+
}
|
|
113
|
+
/** Parse a score event; null when the payload is another type. */
|
|
114
|
+
export declare function parseScoreEvent(bytes: Uint8Array): ScoreEvent | null;
|
|
115
|
+
/** A parsed type-93 match-proposal event (matchmaking handoff). */
|
|
116
|
+
export interface ProposalEvent {
|
|
117
|
+
proposalId: string;
|
|
118
|
+
mode: string;
|
|
119
|
+
players: string[];
|
|
120
|
+
body: Record<string, unknown>;
|
|
121
|
+
}
|
|
122
|
+
/** Parse a proposal event; null when the payload is another type. */
|
|
123
|
+
export declare function parseProposalEvent(bytes: Uint8Array): ProposalEvent | null;
|
|
124
|
+
//# sourceMappingURL=wire.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wire.d.ts","sourceRoot":"","sources":["../../src/kit/wire.ts"],"names":[],"mappings":"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"}
|
package/dist/kit/wire.js
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Engine wire registry — the client mirror of the server's
|
|
3
|
+
* `crowdy-game-kit-core::wire` (the single source of truth for the actor
|
|
4
|
+
* pose layout and flag-bit registry used by compute-module game engines).
|
|
5
|
+
* Parity with the Rust crate is checked by the kit unit suite: any change
|
|
6
|
+
* here must land in kit-core first.
|
|
7
|
+
*
|
|
8
|
+
* 48-byte little-endian pose: pos f32 x3 (0..11), yaw/pitch f32 (12..19),
|
|
9
|
+
* velocity f32 x3 (20..31), flags u8 (32), held u8 (33), 34-35 reserved,
|
|
10
|
+
* updated_at f64 ms (36..43), 44-47 reserved. Payloads may append opaque
|
|
11
|
+
* UTF-8 suffix bytes (engines put the entity's container id there).
|
|
12
|
+
*/
|
|
13
|
+
import { decodeBase64, encodeBase64 } from '../utils.js';
|
|
14
|
+
export const POSE_BYTES = 48;
|
|
15
|
+
/** Flag-bit registry. Bits 0-3 are platform-reserved; games may use 4-7. */
|
|
16
|
+
export const FLAG_GROUNDED = 0b0001;
|
|
17
|
+
export const FLAG_MOB = 0b0010;
|
|
18
|
+
export const FLAG_NPC = 0b0100;
|
|
19
|
+
export const FLAG_RESERVED3 = 0b1000;
|
|
20
|
+
/** Encode a pose (suffix appended when set). */
|
|
21
|
+
export function encodeEnginePose(pose) {
|
|
22
|
+
const suffix = pose.suffix != null ? new TextEncoder().encode(pose.suffix) : null;
|
|
23
|
+
const bytes = new Uint8Array(POSE_BYTES + (suffix?.length ?? 0));
|
|
24
|
+
const view = new DataView(bytes.buffer);
|
|
25
|
+
view.setFloat32(0, pose.x ?? 0, true);
|
|
26
|
+
view.setFloat32(4, pose.y ?? 0, true);
|
|
27
|
+
view.setFloat32(8, pose.z ?? 0, true);
|
|
28
|
+
view.setFloat32(12, pose.yaw ?? 0, true);
|
|
29
|
+
view.setFloat32(16, pose.pitch ?? 0, true);
|
|
30
|
+
view.setFloat32(20, pose.velX ?? 0, true);
|
|
31
|
+
view.setFloat32(24, pose.velY ?? 0, true);
|
|
32
|
+
view.setFloat32(28, pose.velZ ?? 0, true);
|
|
33
|
+
view.setUint8(32, pose.flags ?? 0);
|
|
34
|
+
view.setUint8(33, pose.held ?? 0);
|
|
35
|
+
view.setFloat64(36, pose.updatedAtMs ?? 0, true);
|
|
36
|
+
if (suffix)
|
|
37
|
+
bytes.set(suffix, POSE_BYTES);
|
|
38
|
+
return bytes;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Decode the leading 48 bytes (tolerates longer payloads — the suffix is
|
|
42
|
+
* extracted). Returns null for short or non-finite payloads.
|
|
43
|
+
*/
|
|
44
|
+
export function decodeEnginePose(bytes) {
|
|
45
|
+
if (bytes.length < POSE_BYTES)
|
|
46
|
+
return null;
|
|
47
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
48
|
+
const pose = {
|
|
49
|
+
x: view.getFloat32(0, true),
|
|
50
|
+
y: view.getFloat32(4, true),
|
|
51
|
+
z: view.getFloat32(8, true),
|
|
52
|
+
yaw: view.getFloat32(12, true),
|
|
53
|
+
pitch: view.getFloat32(16, true),
|
|
54
|
+
velX: view.getFloat32(20, true),
|
|
55
|
+
velY: view.getFloat32(24, true),
|
|
56
|
+
velZ: view.getFloat32(28, true),
|
|
57
|
+
flags: view.getUint8(32),
|
|
58
|
+
held: view.getUint8(33),
|
|
59
|
+
updatedAtMs: view.getFloat64(36, true),
|
|
60
|
+
suffix: poseSuffix(bytes),
|
|
61
|
+
};
|
|
62
|
+
if (!Number.isFinite(pose.x) || !Number.isFinite(pose.y) || !Number.isFinite(pose.z)) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
return pose;
|
|
66
|
+
}
|
|
67
|
+
/** The UTF-8 suffix after the pose (engine container ids), if any. */
|
|
68
|
+
export function poseSuffix(bytes) {
|
|
69
|
+
if (bytes.length <= POSE_BYTES)
|
|
70
|
+
return null;
|
|
71
|
+
const text = new TextDecoder().decode(bytes.subarray(POSE_BYTES)).trim();
|
|
72
|
+
return text.length > 0 ? text : null;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* A {@link StateCodec} for engine poses over the base64 wire form — plug it
|
|
76
|
+
* into `attachRemoteActors` / `createWorldSession` actor config. Undecodable
|
|
77
|
+
* payloads yield a zeroed pose with `flags: 0` (they land in the players
|
|
78
|
+
* lane predicate's care, same as unknown custom states).
|
|
79
|
+
*/
|
|
80
|
+
export const enginePoseCodec = {
|
|
81
|
+
encode: (pose) => encodeBase64(encodeEnginePose(pose)),
|
|
82
|
+
decode: (data) => decodeEnginePose(decodeBase64(data)) ?? {
|
|
83
|
+
x: 0,
|
|
84
|
+
y: 0,
|
|
85
|
+
z: 0,
|
|
86
|
+
yaw: 0,
|
|
87
|
+
pitch: 0,
|
|
88
|
+
velX: 0,
|
|
89
|
+
velY: 0,
|
|
90
|
+
velZ: 0,
|
|
91
|
+
flags: 0,
|
|
92
|
+
held: 0,
|
|
93
|
+
updatedAtMs: 0,
|
|
94
|
+
suffix: null,
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* Ready-made lane predicates for `createWorldSession` when the world runs
|
|
99
|
+
* compute-module engines: `players` (no engine flag), `mobs` (FLAG_MOB) and
|
|
100
|
+
* `npcs` (FLAG_NPC) — what Blocks with Friends hand-wired in its Phase 9
|
|
101
|
+
* adoption. Spread extra lanes on top as needed.
|
|
102
|
+
*/
|
|
103
|
+
export function engineLanes() {
|
|
104
|
+
return {
|
|
105
|
+
mobs: (state) => (state.flags & FLAG_MOB) !== 0,
|
|
106
|
+
npcs: (state) => (state.flags & FLAG_NPC) !== 0,
|
|
107
|
+
players: (state) => (state.flags & (FLAG_MOB | FLAG_NPC)) === 0,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
// ---------------------------------------------------------------------------
|
|
111
|
+
// Server-event payloads ([u16 LE event type][state bytes], state = JSON)
|
|
112
|
+
// ---------------------------------------------------------------------------
|
|
113
|
+
/** Contact damage decided by a mob/combat engine (kit-play referee). */
|
|
114
|
+
export const EVENT_CONTACT_DAMAGE = 77;
|
|
115
|
+
/** Weather/season transition from a world engine (kit-sim weather). */
|
|
116
|
+
export const EVENT_WEATHER = 90;
|
|
117
|
+
/** Turn changed (kit-play turns; match engines). */
|
|
118
|
+
export const EVENT_TURN = 91;
|
|
119
|
+
/** Score / match summary (kit-play score). */
|
|
120
|
+
export const EVENT_SCORE = 92;
|
|
121
|
+
/** Match proposal (matchmaking → matches handoff). */
|
|
122
|
+
export const EVENT_PROPOSAL = 93;
|
|
123
|
+
/** Split an engine server-event payload into its type + JSON body. */
|
|
124
|
+
export function parseEngineEvent(bytes) {
|
|
125
|
+
if (bytes.length < 2)
|
|
126
|
+
return null;
|
|
127
|
+
const eventType = bytes[0] | (bytes[1] << 8);
|
|
128
|
+
let body = {};
|
|
129
|
+
if (bytes.length > 2) {
|
|
130
|
+
try {
|
|
131
|
+
body = JSON.parse(new TextDecoder().decode(bytes.subarray(2)));
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return { eventType, body };
|
|
138
|
+
}
|
|
139
|
+
/** Parse a contact-damage event; null when the payload is another type. */
|
|
140
|
+
export function parseContactDamage(bytes) {
|
|
141
|
+
const parsed = parseEngineEvent(bytes);
|
|
142
|
+
if (!parsed || parsed.eventType !== EVENT_CONTACT_DAMAGE)
|
|
143
|
+
return null;
|
|
144
|
+
return {
|
|
145
|
+
targetUuid: String(parsed.body.targetUuid ?? ''),
|
|
146
|
+
damage: Number(parsed.body.damage ?? 0),
|
|
147
|
+
mobId: String(parsed.body.mobId ?? ''),
|
|
148
|
+
mobName: String(parsed.body.mobName ?? ''),
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
/** Parse a weather event; null when the payload is another type. */
|
|
152
|
+
export function parseWeatherEvent(bytes) {
|
|
153
|
+
const parsed = parseEngineEvent(bytes);
|
|
154
|
+
if (!parsed || parsed.eventType !== EVENT_WEATHER)
|
|
155
|
+
return null;
|
|
156
|
+
return {
|
|
157
|
+
weather: String(parsed.body.weather ?? ''),
|
|
158
|
+
sinceMs: Number(parsed.body.sinceMs ?? 0),
|
|
159
|
+
untilMs: Number(parsed.body.untilMs ?? 0),
|
|
160
|
+
body: parsed.body,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
/** Parse a turn event; null when the payload is another type. */
|
|
164
|
+
export function parseTurnEvent(bytes) {
|
|
165
|
+
const parsed = parseEngineEvent(bytes);
|
|
166
|
+
if (!parsed || parsed.eventType !== EVENT_TURN)
|
|
167
|
+
return null;
|
|
168
|
+
return {
|
|
169
|
+
actorId: String(parsed.body.actorId ?? ''),
|
|
170
|
+
round: Number(parsed.body.round ?? 0),
|
|
171
|
+
turnInRound: Number(parsed.body.turnInRound ?? 0),
|
|
172
|
+
body: parsed.body,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
/** Parse a score event; null when the payload is another type. */
|
|
176
|
+
export function parseScoreEvent(bytes) {
|
|
177
|
+
const parsed = parseEngineEvent(bytes);
|
|
178
|
+
if (!parsed || parsed.eventType !== EVENT_SCORE)
|
|
179
|
+
return null;
|
|
180
|
+
const standings = Array.isArray(parsed.body.standings)
|
|
181
|
+
? parsed.body.standings.map((s) => ({
|
|
182
|
+
actorId: String(s.actorId ?? ''),
|
|
183
|
+
score: Number(s.score ?? 0),
|
|
184
|
+
rank: Number(s.rank ?? 0),
|
|
185
|
+
}))
|
|
186
|
+
: [];
|
|
187
|
+
return {
|
|
188
|
+
standings,
|
|
189
|
+
winnerId: parsed.body.winnerId != null ? String(parsed.body.winnerId) : null,
|
|
190
|
+
body: parsed.body,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
/** Parse a proposal event; null when the payload is another type. */
|
|
194
|
+
export function parseProposalEvent(bytes) {
|
|
195
|
+
const parsed = parseEngineEvent(bytes);
|
|
196
|
+
if (!parsed || parsed.eventType !== EVENT_PROPOSAL)
|
|
197
|
+
return null;
|
|
198
|
+
return {
|
|
199
|
+
proposalId: String(parsed.body.proposalId ?? ''),
|
|
200
|
+
mode: String(parsed.body.mode ?? ''),
|
|
201
|
+
players: Array.isArray(parsed.body.players)
|
|
202
|
+
? parsed.body.players.map(String)
|
|
203
|
+
: [],
|
|
204
|
+
body: parsed.body,
|
|
205
|
+
};
|
|
206
|
+
}
|
package/dist/kit/worldsim.d.ts
CHANGED
|
@@ -1,10 +1,27 @@
|
|
|
1
1
|
import type { GameModelAPI } from '../domains/gameModel.js';
|
|
2
2
|
import type { Scalars, SeedPropertyInput } from '../generated/graphql.js';
|
|
3
|
+
import type { EngineDetector } from './engine.js';
|
|
3
4
|
import { type KitInvokeResult } from './shared.js';
|
|
5
|
+
import { type WeatherEvent } from './wire.js';
|
|
4
6
|
/** Options for {@link WorldsimKit}. Must match the deployed worldsim blueprint. */
|
|
5
7
|
export interface WorldsimKitOptions {
|
|
6
8
|
/** The `typePrefix` the worldsim blueprint was deployed with. */
|
|
7
9
|
typePrefix?: string;
|
|
10
|
+
/**
|
|
11
|
+
* The compute module serving `forecast` when the app runs a world engine.
|
|
12
|
+
* Defaults to `'world-engine'`.
|
|
13
|
+
*/
|
|
14
|
+
moduleName?: string;
|
|
15
|
+
}
|
|
16
|
+
/** A world engine's forecast (current front + day phase). */
|
|
17
|
+
export interface KitForecast {
|
|
18
|
+
weather: string;
|
|
19
|
+
/** Day phase in [0, 1) when the engine reports it. */
|
|
20
|
+
dayPhase?: number;
|
|
21
|
+
isNight?: boolean;
|
|
22
|
+
/** Milliseconds until the current front rolls. */
|
|
23
|
+
remainingMs?: number;
|
|
24
|
+
body: Record<string, unknown>;
|
|
8
25
|
}
|
|
9
26
|
/** A parsed view of the world clock/weather state. */
|
|
10
27
|
export interface KitWorldState {
|
|
@@ -56,8 +73,24 @@ export interface KitWaveSpawner {
|
|
|
56
73
|
export declare class WorldsimKit {
|
|
57
74
|
private readonly appId;
|
|
58
75
|
private readonly gameModel;
|
|
76
|
+
private readonly engines?;
|
|
59
77
|
private readonly names;
|
|
60
|
-
|
|
78
|
+
private readonly moduleName;
|
|
79
|
+
constructor(appId: Scalars['BigInt']['input'], gameModel: GameModelAPI, options?: WorldsimKitOptions, engines?: EngineDetector | undefined);
|
|
80
|
+
/** Is a world compute engine deployed + enabled (cached per session)? */
|
|
81
|
+
engineAvailable(): Promise<boolean>;
|
|
82
|
+
/**
|
|
83
|
+
* The world engine's `forecast` invoke: the current weather front plus
|
|
84
|
+
* day-phase fields. Late joiners call this once, then track transitions
|
|
85
|
+
* from the type-90 event stream ({@link parseWeather}).
|
|
86
|
+
*/
|
|
87
|
+
forecast(): Promise<KitForecast>;
|
|
88
|
+
/**
|
|
89
|
+
* Parse a server-event payload as a world-engine weather transition
|
|
90
|
+
* (type 90), or null when it is another event type. Feed it your world
|
|
91
|
+
* session's server-event stream.
|
|
92
|
+
*/
|
|
93
|
+
parseWeather(payload: Uint8Array): WeatherEvent | null;
|
|
61
94
|
/**
|
|
62
95
|
* Find-or-create the WorldState singleton (admin). `anchorChunk` is where
|
|
63
96
|
* the clock's spatial time-changed ping is emitted.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worldsim.d.ts","sourceRoot":"","sources":["../../src/kit/worldsim.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAE1E,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"worldsim.d.ts","sourceRoot":"","sources":["../../src/kit/worldsim.ts"],"names":[],"mappings":"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"}
|
package/dist/kit/worldsim.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { worldsimNames } from './blueprints/index.js';
|
|
2
2
|
import { kitContainerProperties, kitInvoke, } from './shared.js';
|
|
3
|
+
import { parseWeatherEvent } from './wire.js';
|
|
3
4
|
/**
|
|
4
5
|
* Runtime helpers for the {@link worldsimBlueprint} conventions: the world
|
|
5
6
|
* clock/weather singleton, regenerating resource nodes players gather from,
|
|
@@ -10,10 +11,46 @@ import { kitContainerProperties, kitInvoke, } from './shared.js';
|
|
|
10
11
|
* Obtained via `client.kit(appId).worldsim`.
|
|
11
12
|
*/
|
|
12
13
|
export class WorldsimKit {
|
|
13
|
-
constructor(appId, gameModel, options = {}) {
|
|
14
|
+
constructor(appId, gameModel, options = {}, engines) {
|
|
14
15
|
this.appId = appId;
|
|
15
16
|
this.gameModel = gameModel;
|
|
17
|
+
this.engines = engines;
|
|
16
18
|
this.names = worldsimNames(options.typePrefix ?? '');
|
|
19
|
+
this.moduleName = options.moduleName ?? 'world-engine';
|
|
20
|
+
}
|
|
21
|
+
/** Is a world compute engine deployed + enabled (cached per session)? */
|
|
22
|
+
engineAvailable() {
|
|
23
|
+
if (!this.engines)
|
|
24
|
+
return Promise.resolve(false);
|
|
25
|
+
return this.engines.has(this.moduleName);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The world engine's `forecast` invoke: the current weather front plus
|
|
29
|
+
* day-phase fields. Late joiners call this once, then track transitions
|
|
30
|
+
* from the type-90 event stream ({@link parseWeather}).
|
|
31
|
+
*/
|
|
32
|
+
async forecast() {
|
|
33
|
+
const result = this.engines
|
|
34
|
+
? await this.engines.invoke(this.moduleName, 'forecast')
|
|
35
|
+
: { success: false, reason: 'compute domain unavailable', body: {} };
|
|
36
|
+
if (!result.success) {
|
|
37
|
+
throw new Error(`forecast unavailable: ${result.reason ?? 'engine missing'}`);
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
weather: String(result.body.weather ?? ''),
|
|
41
|
+
dayPhase: typeof result.body.dayPhase === 'number' ? result.body.dayPhase : undefined,
|
|
42
|
+
isNight: typeof result.body.isNight === 'boolean' ? result.body.isNight : undefined,
|
|
43
|
+
remainingMs: typeof result.body.remainingMs === 'number' ? result.body.remainingMs : undefined,
|
|
44
|
+
body: result.body,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Parse a server-event payload as a world-engine weather transition
|
|
49
|
+
* (type 90), or null when it is another event type. Feed it your world
|
|
50
|
+
* session's server-event stream.
|
|
51
|
+
*/
|
|
52
|
+
parseWeather(payload) {
|
|
53
|
+
return parseWeatherEvent(payload);
|
|
17
54
|
}
|
|
18
55
|
/**
|
|
19
56
|
* Find-or-create the WorldState singleton (admin). `anchorChunk` is where
|