@crowdedkingdoms/crowdyjs 18.10.0 → 18.11.0-dev.1
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 +43 -0
- package/README.md +79 -30
- package/dist/crowdy-client.d.ts +11 -3
- package/dist/crowdy-client.d.ts.map +1 -1
- package/dist/crowdy-client.js +25 -4
- package/dist/default-origin.d.ts +6 -6
- package/dist/default-origin.d.ts.map +1 -1
- package/dist/default-origin.js +6 -6
- package/dist/domains/exec.d.ts +6 -0
- package/dist/domains/exec.d.ts.map +1 -1
- package/dist/domains/exec.js +28 -2
- package/dist/generated/graphql-schema.d.ts +1 -1
- package/dist/generated/graphql-schema.d.ts.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -3
- package/dist/kit/index.d.ts +13 -2
- package/dist/kit/index.d.ts.map +1 -1
- package/dist/kit/index.js +13 -2
- package/dist/kit/kit.d.ts +83 -7
- package/dist/kit/kit.d.ts.map +1 -1
- package/dist/kit/kit.js +82 -4
- package/dist/kit/mirror.d.ts +111 -0
- package/dist/kit/mirror.d.ts.map +1 -0
- package/dist/kit/mirror.js +295 -0
- package/dist/kit/modules/matchmaking.d.ts +107 -0
- package/dist/kit/modules/matchmaking.d.ts.map +1 -0
- package/dist/kit/modules/matchmaking.js +109 -0
- package/dist/kit/modules/npcs.d.ts +80 -0
- package/dist/kit/modules/npcs.d.ts.map +1 -0
- package/dist/kit/modules/npcs.js +102 -0
- package/dist/kit/modules/presence.d.ts +81 -0
- package/dist/kit/modules/presence.d.ts.map +1 -0
- package/dist/kit/modules/presence.js +99 -0
- package/dist/kit/modules/sessions.d.ts +91 -0
- package/dist/kit/modules/sessions.d.ts.map +1 -0
- package/dist/kit/modules/sessions.js +84 -0
- package/dist/kit/modules/world.d.ts +69 -0
- package/dist/kit/modules/world.d.ts.map +1 -0
- package/dist/kit/modules/world.js +35 -0
- package/dist/kit/protocol.d.ts +128 -0
- package/dist/kit/protocol.d.ts.map +1 -0
- package/dist/kit/protocol.js +171 -0
- package/dist/kit/realtime.d.ts +72 -0
- package/dist/kit/realtime.d.ts.map +1 -0
- package/dist/kit/realtime.js +108 -0
- package/dist/kit/runtime.d.ts +90 -0
- package/dist/kit/runtime.d.ts.map +1 -0
- package/dist/kit/runtime.js +194 -0
- package/dist/kit/store.d.ts +20 -0
- package/dist/kit/store.d.ts.map +1 -0
- package/dist/kit/store.js +25 -0
- package/dist/kit/topology.d.ts +69 -0
- package/dist/kit/topology.d.ts.map +1 -0
- package/dist/kit/topology.js +156 -0
- package/dist/kit/wire.d.ts +45 -5
- package/dist/kit/wire.d.ts.map +1 -1
- package/dist/kit/wire.js +51 -5
- package/dist/live-coding/assets/browser-authoring-index.json +1 -1
- package/dist/live-coding/assets/manifest.json +1 -1
- package/dist/live-coding/browser-authoring-index.generated.d.ts.map +1 -1
- package/dist/live-coding/browser-authoring-index.generated.js +1935 -45
- package/package.json +1 -1
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { CollectionMirror } from '../mirror.js';
|
|
2
|
+
import { shardKey } from '../protocol.js';
|
|
3
|
+
/**
|
|
4
|
+
* The world's areas of mobs, NPCs and pets (the `npc-mobs` starter): one hub per area,
|
|
5
|
+
* keyed by its centre chunk, so a client finds the hub for where it stands
|
|
6
|
+
* ({@link areaAt}) without asking.
|
|
7
|
+
*/
|
|
8
|
+
export class NpcsKit {
|
|
9
|
+
constructor(runtime, options = {}) {
|
|
10
|
+
this.runtime = runtime;
|
|
11
|
+
this.areas = new Map();
|
|
12
|
+
this.nodeType = options.nodeType ?? 'npcs';
|
|
13
|
+
this.size = Math.max(1, options.areaSize ?? 8);
|
|
14
|
+
}
|
|
15
|
+
/** The key of the area holding chunk `(chunkX, chunkZ)`. */
|
|
16
|
+
keyAt(chunkX, chunkZ) {
|
|
17
|
+
return shardKey(chunkX, chunkZ, this.size);
|
|
18
|
+
}
|
|
19
|
+
/** The area holding chunk `(chunkX, chunkZ)`. */
|
|
20
|
+
areaAt(chunkX, chunkZ) {
|
|
21
|
+
return this.area(this.keyAt(chunkX, chunkZ));
|
|
22
|
+
}
|
|
23
|
+
/** The area with key `key` (`"<x>,<z>"`, its centre chunk). */
|
|
24
|
+
area(key) {
|
|
25
|
+
let a = this.areas.get(key);
|
|
26
|
+
if (!a) {
|
|
27
|
+
a = new NpcArea(this.runtime, this.nodeType, key);
|
|
28
|
+
this.areas.set(key, a);
|
|
29
|
+
}
|
|
30
|
+
return a;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* One area: its mobs, NPCs and pets mirrored from the `area` topic ({@link members}), hits
|
|
35
|
+
* on mobs (the hub decides reach, cooldown and damage), NPC talk, and the player's pets.
|
|
36
|
+
* The hub also shows its actors through the realtime tier (`kitActorCodec`).
|
|
37
|
+
*/
|
|
38
|
+
export class NpcArea {
|
|
39
|
+
constructor(runtime, nodeType, key) {
|
|
40
|
+
this.runtime = runtime;
|
|
41
|
+
this.nodeType = nodeType;
|
|
42
|
+
this.key = key;
|
|
43
|
+
this.members = new CollectionMirror(runtime, nodeType, key, 'area');
|
|
44
|
+
}
|
|
45
|
+
/** Mirrors the area. */
|
|
46
|
+
async watch() {
|
|
47
|
+
await this.members.start();
|
|
48
|
+
}
|
|
49
|
+
unwatch() {
|
|
50
|
+
return this.members.stop();
|
|
51
|
+
}
|
|
52
|
+
mobs() {
|
|
53
|
+
return this.members.list('Mob');
|
|
54
|
+
}
|
|
55
|
+
npcs() {
|
|
56
|
+
return this.members.list('Npc');
|
|
57
|
+
}
|
|
58
|
+
pets() {
|
|
59
|
+
return this.members.list('Pet');
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Hits mob `mob`; resolves with its hp after the hit.
|
|
63
|
+
* @throws {KitError} `not_in_area`, `out_of_reach`, `cooldown`, `down`, `not_found`.
|
|
64
|
+
*/
|
|
65
|
+
attack(mob) {
|
|
66
|
+
return this.runtime.call(this.nodeType, this.key, 'attack', { mob }, { action: true });
|
|
67
|
+
}
|
|
68
|
+
/** What NPC `npc` says, with its public properties. */
|
|
69
|
+
talk(npc) {
|
|
70
|
+
return this.runtime.call(this.nodeType, this.key, 'talk', { npc });
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Adopts a pet where the player stands; resolves with its id.
|
|
74
|
+
* @throws {KitError} `not_in_area`, `limit` (pets a player), `full`, `bad_request`.
|
|
75
|
+
*/
|
|
76
|
+
adopt(species, name) {
|
|
77
|
+
return this.runtime.call(this.nodeType, this.key, 'adopt', { species, name }, { action: true });
|
|
78
|
+
}
|
|
79
|
+
rename(pet, name) {
|
|
80
|
+
return this.pet('rename', pet, name);
|
|
81
|
+
}
|
|
82
|
+
/** The pet follows its owner (and its bond grows). */
|
|
83
|
+
summon(pet) {
|
|
84
|
+
return this.pet('summon', pet);
|
|
85
|
+
}
|
|
86
|
+
/** The pet stays where it is. */
|
|
87
|
+
dismiss(pet) {
|
|
88
|
+
return this.pet('dismiss', pet);
|
|
89
|
+
}
|
|
90
|
+
/** The pet is gone. */
|
|
91
|
+
release(pet) {
|
|
92
|
+
return this.pet('release', pet);
|
|
93
|
+
}
|
|
94
|
+
/** The player's pets in this area, with their bond. */
|
|
95
|
+
myPets() {
|
|
96
|
+
return this.runtime.call(this.nodeType, this.key, 'pets');
|
|
97
|
+
}
|
|
98
|
+
pet(method, pet, name) {
|
|
99
|
+
const args = name === undefined ? { pet } : { pet, name };
|
|
100
|
+
return this.runtime.call(this.nodeType, this.key, method, args, { action: true });
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { UdpAPI } from '../../domains/udp.js';
|
|
2
|
+
import { type EmoteEvent } from '../wire.js';
|
|
3
|
+
/** A chunk, in chunk coordinates. */
|
|
4
|
+
export interface KitChunk {
|
|
5
|
+
x: number;
|
|
6
|
+
y: number;
|
|
7
|
+
z: number;
|
|
8
|
+
}
|
|
9
|
+
/** How a spectator stays where the world's messages reach them. */
|
|
10
|
+
export interface SpectateOptions {
|
|
11
|
+
/** The spectator's actor uuid (32 characters), as with `udp.sendActorUpdate`. */
|
|
12
|
+
uuid: string;
|
|
13
|
+
/** Where to watch from: a chunk inside the app's world grid. */
|
|
14
|
+
chunk: KitChunk;
|
|
15
|
+
/** How often to say so, in milliseconds. Default 2 000. */
|
|
16
|
+
intervalMs?: number;
|
|
17
|
+
/** The actor state to send (base64); empty by default, which registers without a body. */
|
|
18
|
+
state?: string;
|
|
19
|
+
/** Replication distance, 0-8. Default 8. */
|
|
20
|
+
distance?: number;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Spectating: the realtime tier delivers what happens near an actor only while that actor is
|
|
24
|
+
* live, so a viewer with no avatar of its own (a spectator, a kill-cam, a second screen) sends
|
|
25
|
+
* a small actor update every couple of seconds from a chunk inside the app's world grid.
|
|
26
|
+
* Outside the grid the update is refused and delivery stops.
|
|
27
|
+
*/
|
|
28
|
+
export declare class SpectateKit {
|
|
29
|
+
private readonly appId;
|
|
30
|
+
private readonly udp;
|
|
31
|
+
constructor(appId: string, udp: UdpAPI | undefined);
|
|
32
|
+
/** Starts the heartbeat; returns the handle that moves or stops it. */
|
|
33
|
+
observe(options: SpectateOptions): SpectatorHeartbeat;
|
|
34
|
+
}
|
|
35
|
+
/** A running spectator heartbeat. */
|
|
36
|
+
export declare class SpectatorHeartbeat {
|
|
37
|
+
private readonly appId;
|
|
38
|
+
private readonly udp;
|
|
39
|
+
private readonly options;
|
|
40
|
+
private chunk;
|
|
41
|
+
private timer;
|
|
42
|
+
private lastError;
|
|
43
|
+
constructor(appId: string, udp: UdpAPI, options: SpectateOptions);
|
|
44
|
+
private beat;
|
|
45
|
+
/** Watches from another chunk from the next beat on (sent at once). */
|
|
46
|
+
moveTo(chunk: KitChunk): void;
|
|
47
|
+
/** The last send's error, or null when it went out. */
|
|
48
|
+
get error(): unknown;
|
|
49
|
+
stop(): void;
|
|
50
|
+
}
|
|
51
|
+
/** One emote to send. */
|
|
52
|
+
export interface EmoteSend {
|
|
53
|
+
/** The sending actor's uuid (32 characters). */
|
|
54
|
+
uuid: string;
|
|
55
|
+
/** The chunk the sender stands in. */
|
|
56
|
+
chunk: KitChunk;
|
|
57
|
+
/** The emote's name, as the game knows it: `wave`, `cheer`, ... */
|
|
58
|
+
emote: string;
|
|
59
|
+
/** The actor it is aimed at, if any. */
|
|
60
|
+
targetUuid?: string;
|
|
61
|
+
/** Replication distance, 0-8. Default 2. */
|
|
62
|
+
distance?: number;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Emotes: a client event (type {@link EVENT_EMOTE}) with a JSON body `{ emote, targetUuid }`,
|
|
66
|
+
* replicated to the players near the sender. A kit convention, so players on CrowdyJS,
|
|
67
|
+
* CrowdyCPP and CrowdyPy see each other's; no hub is involved.
|
|
68
|
+
*/
|
|
69
|
+
export declare class EmotesKit {
|
|
70
|
+
private readonly appId;
|
|
71
|
+
private readonly udp;
|
|
72
|
+
constructor(appId: string, udp: UdpAPI | undefined);
|
|
73
|
+
/** Sends an emote; `true` when it was accepted for sending. */
|
|
74
|
+
send(emote: EmoteSend): Promise<boolean>;
|
|
75
|
+
/** An emote from a `clientEvent` notification, or null when it is another event. */
|
|
76
|
+
parse(notification: {
|
|
77
|
+
eventType: number;
|
|
78
|
+
state: string;
|
|
79
|
+
}): EmoteEvent | null;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=presence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presence.d.ts","sourceRoot":"","sources":["../../../src/kit/modules/presence.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,EAAgC,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAE3E,qCAAqC;AACrC,MAAM,WAAW,QAAQ;IACvB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAID,mEAAmE;AACnE,MAAM,WAAW,eAAe;IAC9B,iFAAiF;IACjF,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,KAAK,EAAE,QAAQ,CAAC;IAChB,2DAA2D;IAC3D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0FAA0F;IAC1F,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;GAKG;AACH,qBAAa,WAAW;IAEpB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,GAAG;gBADH,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,GAAG,SAAS;IAG1C,uEAAuE;IACvE,OAAO,CAAC,OAAO,EAAE,eAAe,GAAG,kBAAkB;CAItD;AAED,qCAAqC;AACrC,qBAAa,kBAAkB;IAM3B,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAP1B,OAAO,CAAC,KAAK,CAAW;IACxB,OAAO,CAAC,KAAK,CAAwC;IACrD,OAAO,CAAC,SAAS,CAAiB;gBAGf,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,eAAe;IAO3C,OAAO,CAAC,IAAI;IAiBZ,uEAAuE;IACvE,MAAM,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI;IAK7B,uDAAuD;IACvD,IAAI,KAAK,IAAI,OAAO,CAEnB;IAED,IAAI,IAAI,IAAI;CAIb;AAED,yBAAyB;AACzB,MAAM,WAAW,SAAS;IACxB,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,sCAAsC;IACtC,KAAK,EAAE,QAAQ,CAAC;IAChB,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,qBAAa,SAAS;IAElB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,GAAG;gBADH,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,GAAG,SAAS;IAG1C,+DAA+D;IAC/D,IAAI,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC;IAaxC,oFAAoF;IACpF,KAAK,CAAC,YAAY,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,UAAU,GAAG,IAAI;CAS7E"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { decodeBase64, encodeBase64 } from '../../utils.js';
|
|
2
|
+
import { EVENT_EMOTE, parseEmoteEvent } from '../wire.js';
|
|
3
|
+
const chunkInput = (c) => ({ x: String(Math.trunc(c.x)), y: String(Math.trunc(c.y)), z: String(Math.trunc(c.z)) });
|
|
4
|
+
/**
|
|
5
|
+
* Spectating: the realtime tier delivers what happens near an actor only while that actor is
|
|
6
|
+
* live, so a viewer with no avatar of its own (a spectator, a kill-cam, a second screen) sends
|
|
7
|
+
* a small actor update every couple of seconds from a chunk inside the app's world grid.
|
|
8
|
+
* Outside the grid the update is refused and delivery stops.
|
|
9
|
+
*/
|
|
10
|
+
export class SpectateKit {
|
|
11
|
+
constructor(appId, udp) {
|
|
12
|
+
this.appId = appId;
|
|
13
|
+
this.udp = udp;
|
|
14
|
+
}
|
|
15
|
+
/** Starts the heartbeat; returns the handle that moves or stops it. */
|
|
16
|
+
observe(options) {
|
|
17
|
+
if (!this.udp)
|
|
18
|
+
throw new Error('the kit has no udp client to spectate with');
|
|
19
|
+
return new SpectatorHeartbeat(this.appId, this.udp, options);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/** A running spectator heartbeat. */
|
|
23
|
+
export class SpectatorHeartbeat {
|
|
24
|
+
constructor(appId, udp, options) {
|
|
25
|
+
this.appId = appId;
|
|
26
|
+
this.udp = udp;
|
|
27
|
+
this.options = options;
|
|
28
|
+
this.lastError = null;
|
|
29
|
+
this.chunk = options.chunk;
|
|
30
|
+
this.beat();
|
|
31
|
+
this.timer = setInterval(() => this.beat(), Math.max(250, options.intervalMs ?? 2000));
|
|
32
|
+
}
|
|
33
|
+
beat() {
|
|
34
|
+
this.udp
|
|
35
|
+
.sendActorUpdate({
|
|
36
|
+
appId: this.appId,
|
|
37
|
+
uuid: this.options.uuid,
|
|
38
|
+
chunk: chunkInput(this.chunk),
|
|
39
|
+
state: this.options.state ?? '',
|
|
40
|
+
distance: this.options.distance ?? 8,
|
|
41
|
+
})
|
|
42
|
+
.then(() => {
|
|
43
|
+
this.lastError = null;
|
|
44
|
+
})
|
|
45
|
+
.catch((e) => {
|
|
46
|
+
this.lastError = e;
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
/** Watches from another chunk from the next beat on (sent at once). */
|
|
50
|
+
moveTo(chunk) {
|
|
51
|
+
this.chunk = chunk;
|
|
52
|
+
this.beat();
|
|
53
|
+
}
|
|
54
|
+
/** The last send's error, or null when it went out. */
|
|
55
|
+
get error() {
|
|
56
|
+
return this.lastError;
|
|
57
|
+
}
|
|
58
|
+
stop() {
|
|
59
|
+
if (this.timer)
|
|
60
|
+
clearInterval(this.timer);
|
|
61
|
+
this.timer = null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Emotes: a client event (type {@link EVENT_EMOTE}) with a JSON body `{ emote, targetUuid }`,
|
|
66
|
+
* replicated to the players near the sender. A kit convention, so players on CrowdyJS,
|
|
67
|
+
* CrowdyCPP and CrowdyPy see each other's; no hub is involved.
|
|
68
|
+
*/
|
|
69
|
+
export class EmotesKit {
|
|
70
|
+
constructor(appId, udp) {
|
|
71
|
+
this.appId = appId;
|
|
72
|
+
this.udp = udp;
|
|
73
|
+
}
|
|
74
|
+
/** Sends an emote; `true` when it was accepted for sending. */
|
|
75
|
+
send(emote) {
|
|
76
|
+
if (!this.udp)
|
|
77
|
+
return Promise.reject(new Error('the kit has no udp client to send emotes with'));
|
|
78
|
+
const body = JSON.stringify({ emote: emote.emote, targetUuid: emote.targetUuid ?? null });
|
|
79
|
+
return this.udp.sendClientEvent({
|
|
80
|
+
appId: this.appId,
|
|
81
|
+
uuid: emote.uuid,
|
|
82
|
+
chunk: chunkInput(emote.chunk),
|
|
83
|
+
eventType: EVENT_EMOTE,
|
|
84
|
+
state: encodeBase64(new TextEncoder().encode(body)),
|
|
85
|
+
distance: emote.distance ?? 2,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
/** An emote from a `clientEvent` notification, or null when it is another event. */
|
|
89
|
+
parse(notification) {
|
|
90
|
+
if (notification.eventType !== EVENT_EMOTE)
|
|
91
|
+
return null;
|
|
92
|
+
const state = decodeBase64(notification.state);
|
|
93
|
+
const bytes = new Uint8Array(2 + state.length);
|
|
94
|
+
bytes[0] = EVENT_EMOTE & 0xff;
|
|
95
|
+
bytes[1] = EVENT_EMOTE >> 8;
|
|
96
|
+
bytes.set(state, 2);
|
|
97
|
+
return parseEmoteEvent(bytes);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { HubState } from '../mirror.js';
|
|
2
|
+
import type { KitRuntime } from '../runtime.js';
|
|
3
|
+
export type SessionPhase = 'lobby' | 'playing' | 'finished';
|
|
4
|
+
export interface SessionConfig {
|
|
5
|
+
min_players: number;
|
|
6
|
+
max_players: number;
|
|
7
|
+
turn_ms: number;
|
|
8
|
+
target_score: number;
|
|
9
|
+
max_rounds: number;
|
|
10
|
+
/** A lobby nobody joins closes after this long. */
|
|
11
|
+
lobby_idle_ms: number;
|
|
12
|
+
}
|
|
13
|
+
export interface SessionMove {
|
|
14
|
+
player: number;
|
|
15
|
+
round: number;
|
|
16
|
+
/** null when the player ran out of time. */
|
|
17
|
+
points: number | null;
|
|
18
|
+
}
|
|
19
|
+
/** A session as everyone sees it: what `state` answers and the `session` topic carries. */
|
|
20
|
+
export interface SessionState {
|
|
21
|
+
config: SessionConfig;
|
|
22
|
+
phase: SessionPhase;
|
|
23
|
+
/** Only these players may join, when set (a matchmaker's reservation). */
|
|
24
|
+
reserved: number[];
|
|
25
|
+
players: number[];
|
|
26
|
+
ready: number[];
|
|
27
|
+
connected: number[];
|
|
28
|
+
host: number | null;
|
|
29
|
+
turn: number;
|
|
30
|
+
round: number;
|
|
31
|
+
/** Scores by player id (the keys are the ids as text). */
|
|
32
|
+
scores: Record<string, number>;
|
|
33
|
+
winner: number | null;
|
|
34
|
+
moves: SessionMove[];
|
|
35
|
+
}
|
|
36
|
+
/** Where the session hubs are: type `session`, one per session key, in the starter pack. */
|
|
37
|
+
export interface SessionsKitOptions {
|
|
38
|
+
nodeType?: string;
|
|
39
|
+
}
|
|
40
|
+
/** Game sessions (the `session` starter): {@link open} one by its key. */
|
|
41
|
+
export declare class SessionsKit {
|
|
42
|
+
private readonly runtime;
|
|
43
|
+
private readonly sessions;
|
|
44
|
+
private readonly nodeType;
|
|
45
|
+
constructor(runtime: KitRuntime, options?: SessionsKitOptions);
|
|
46
|
+
/** The session with key `key` (a matchmaker's `matched.session`, or one a game names). */
|
|
47
|
+
open(key: string): GameSessionHandle;
|
|
48
|
+
}
|
|
49
|
+
/** Whose turn it is in `state`, while it plays. */
|
|
50
|
+
export declare function sessionTurn(state: SessionState | undefined): number | null;
|
|
51
|
+
/**
|
|
52
|
+
* One session from lobby to result: join, ready up, the host starts, players act in turn
|
|
53
|
+
* under a time limit, and the hub keeps the score and names the winner. {@link state} mirrors
|
|
54
|
+
* the `session` topic; every change is a snapshot on it.
|
|
55
|
+
*/
|
|
56
|
+
export declare class GameSessionHandle {
|
|
57
|
+
private readonly runtime;
|
|
58
|
+
readonly nodeType: string;
|
|
59
|
+
readonly key: string;
|
|
60
|
+
/** The `session` topic: the whole session. {@link watch} starts it. */
|
|
61
|
+
readonly state: HubState<SessionState>;
|
|
62
|
+
constructor(runtime: KitRuntime, nodeType: string, key: string);
|
|
63
|
+
/** Mirrors the session; resolves with it. */
|
|
64
|
+
watch(): Promise<SessionState>;
|
|
65
|
+
unwatch(): Promise<void>;
|
|
66
|
+
/** Whose turn it is, as the mirror last saw it. */
|
|
67
|
+
currentTurn(): number | null;
|
|
68
|
+
/** Whether it is the player's turn, as the mirror last saw it. */
|
|
69
|
+
isMyTurn(): Promise<boolean>;
|
|
70
|
+
/** @throws {KitError} `started`, `reserved`, `full`. */
|
|
71
|
+
join(): Promise<boolean>;
|
|
72
|
+
leave(): Promise<boolean>;
|
|
73
|
+
/** @throws {KitError} `not_member` (join the lobby first). */
|
|
74
|
+
ready(ready?: boolean): Promise<boolean>;
|
|
75
|
+
/**
|
|
76
|
+
* Starts the session (the host, once everyone is ready).
|
|
77
|
+
* @throws {KitError} `forbidden` (not the host), `not_ready`, `too_few_players`, `started`.
|
|
78
|
+
*/
|
|
79
|
+
startGame(): Promise<boolean>;
|
|
80
|
+
/**
|
|
81
|
+
* Plays the player's move (the starter's is `{ points }`, 0 to 3); resolves with whether play
|
|
82
|
+
* goes on. Sent with an action id: a move resent after a lost reply is played once.
|
|
83
|
+
* @throws {KitError} `not_your_turn`, `invalid_move` (the game's rule).
|
|
84
|
+
*/
|
|
85
|
+
act<A extends object = {
|
|
86
|
+
points: number;
|
|
87
|
+
}>(action: A): Promise<boolean>;
|
|
88
|
+
/** Changes the config: the host in the lobby, or a developer. */
|
|
89
|
+
configure(config: Partial<SessionConfig>): Promise<boolean>;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=sessions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../../../src/kit/modules/sessions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { HubState } from '../mirror.js';
|
|
2
|
+
/** Game sessions (the `session` starter): {@link open} one by its key. */
|
|
3
|
+
export class SessionsKit {
|
|
4
|
+
constructor(runtime, options = {}) {
|
|
5
|
+
this.runtime = runtime;
|
|
6
|
+
this.sessions = new Map();
|
|
7
|
+
this.nodeType = options.nodeType ?? 'session';
|
|
8
|
+
}
|
|
9
|
+
/** The session with key `key` (a matchmaker's `matched.session`, or one a game names). */
|
|
10
|
+
open(key) {
|
|
11
|
+
let s = this.sessions.get(key);
|
|
12
|
+
if (!s) {
|
|
13
|
+
s = new GameSessionHandle(this.runtime, this.nodeType, key);
|
|
14
|
+
this.sessions.set(key, s);
|
|
15
|
+
}
|
|
16
|
+
return s;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/** Whose turn it is in `state`, while it plays. */
|
|
20
|
+
export function sessionTurn(state) {
|
|
21
|
+
if (!state || state.phase !== 'playing')
|
|
22
|
+
return null;
|
|
23
|
+
return state.players[state.turn] ?? null;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* One session from lobby to result: join, ready up, the host starts, players act in turn
|
|
27
|
+
* under a time limit, and the hub keeps the score and names the winner. {@link state} mirrors
|
|
28
|
+
* the `session` topic; every change is a snapshot on it.
|
|
29
|
+
*/
|
|
30
|
+
export class GameSessionHandle {
|
|
31
|
+
constructor(runtime, nodeType, key) {
|
|
32
|
+
this.runtime = runtime;
|
|
33
|
+
this.nodeType = nodeType;
|
|
34
|
+
this.key = key;
|
|
35
|
+
this.state = new HubState(runtime, nodeType, key, 'session');
|
|
36
|
+
}
|
|
37
|
+
/** Mirrors the session; resolves with it. */
|
|
38
|
+
watch() {
|
|
39
|
+
return this.state.start();
|
|
40
|
+
}
|
|
41
|
+
unwatch() {
|
|
42
|
+
return this.state.stop();
|
|
43
|
+
}
|
|
44
|
+
/** Whose turn it is, as the mirror last saw it. */
|
|
45
|
+
currentTurn() {
|
|
46
|
+
return sessionTurn(this.state.get());
|
|
47
|
+
}
|
|
48
|
+
/** Whether it is the player's turn, as the mirror last saw it. */
|
|
49
|
+
async isMyTurn() {
|
|
50
|
+
const me = await this.runtime.playerId();
|
|
51
|
+
const turn = this.currentTurn();
|
|
52
|
+
return me !== null && turn !== null && String(turn) === me;
|
|
53
|
+
}
|
|
54
|
+
/** @throws {KitError} `started`, `reserved`, `full`. */
|
|
55
|
+
join() {
|
|
56
|
+
return this.runtime.call(this.nodeType, this.key, 'join', null, { action: true });
|
|
57
|
+
}
|
|
58
|
+
leave() {
|
|
59
|
+
return this.runtime.call(this.nodeType, this.key, 'leave', null, { action: true });
|
|
60
|
+
}
|
|
61
|
+
/** @throws {KitError} `not_member` (join the lobby first). */
|
|
62
|
+
ready(ready = true) {
|
|
63
|
+
return this.runtime.call(this.nodeType, this.key, 'ready', { ready }, { action: true });
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Starts the session (the host, once everyone is ready).
|
|
67
|
+
* @throws {KitError} `forbidden` (not the host), `not_ready`, `too_few_players`, `started`.
|
|
68
|
+
*/
|
|
69
|
+
startGame() {
|
|
70
|
+
return this.runtime.call(this.nodeType, this.key, 'start', null, { action: true });
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Plays the player's move (the starter's is `{ points }`, 0 to 3); resolves with whether play
|
|
74
|
+
* goes on. Sent with an action id: a move resent after a lost reply is played once.
|
|
75
|
+
* @throws {KitError} `not_your_turn`, `invalid_move` (the game's rule).
|
|
76
|
+
*/
|
|
77
|
+
act(action) {
|
|
78
|
+
return this.runtime.call(this.nodeType, this.key, 'act', action, { action: true });
|
|
79
|
+
}
|
|
80
|
+
/** Changes the config: the host in the lobby, or a developer. */
|
|
81
|
+
configure(config) {
|
|
82
|
+
return this.runtime.call(this.nodeType, this.key, 'configure', config, { action: true });
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { CollectionMirror, HubState } from '../mirror.js';
|
|
2
|
+
import type { KitRuntime } from '../runtime.js';
|
|
3
|
+
/** What the `world` topic carries: the world's conditions now. */
|
|
4
|
+
export interface WorldConditions {
|
|
5
|
+
/** 0 at midnight, 0.5 at noon. */
|
|
6
|
+
time_of_day: number;
|
|
7
|
+
night: boolean;
|
|
8
|
+
/** `clear`, `rain`, `storm` or `fog` in the starter. */
|
|
9
|
+
weather: string;
|
|
10
|
+
/** The active liveops events' modifiers; where events overlap they multiply. */
|
|
11
|
+
modifiers: Record<string, number>;
|
|
12
|
+
}
|
|
13
|
+
/** A resource node, as `state` lists it. */
|
|
14
|
+
export interface WorldResourceNode {
|
|
15
|
+
id: number;
|
|
16
|
+
amount: number;
|
|
17
|
+
/** When it grows back (Unix ms), while it is empty. */
|
|
18
|
+
regrow_at: number | null;
|
|
19
|
+
}
|
|
20
|
+
/** A liveops event: between `start_ms` and `end_ms` its modifiers apply. */
|
|
21
|
+
export interface WorldLiveopsEvent {
|
|
22
|
+
name: string;
|
|
23
|
+
start_ms: number;
|
|
24
|
+
end_ms: number;
|
|
25
|
+
modifiers?: Record<string, number>;
|
|
26
|
+
}
|
|
27
|
+
/** What the world hub's `state` answers. */
|
|
28
|
+
export interface WorldView {
|
|
29
|
+
conditions: WorldConditions;
|
|
30
|
+
/** Game time since the world began, advanced only while it runs. */
|
|
31
|
+
clock_ms: number;
|
|
32
|
+
nodes: WorldResourceNode[];
|
|
33
|
+
events: WorldLiveopsEvent[];
|
|
34
|
+
/** Players in the app. */
|
|
35
|
+
online: number;
|
|
36
|
+
}
|
|
37
|
+
/** Where the world hub is: the root hub, `world` with an empty key, in the starter pack. */
|
|
38
|
+
export interface WorldKitOptions {
|
|
39
|
+
nodeType?: string;
|
|
40
|
+
key?: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The root world hub (the `world-tick` starter): its clock, weather and liveops modifiers as a
|
|
44
|
+
* mirrored {@link conditions} topic, its resource nodes as a mirrored {@link nodes} collection,
|
|
45
|
+
* harvesting, and for developers the liveops schedule. The root hub takes 50 calls a second for
|
|
46
|
+
* the whole app, so read it from the mirrors (`conditions.start()`), not by polling `state`.
|
|
47
|
+
*/
|
|
48
|
+
export declare class WorldKit {
|
|
49
|
+
private readonly runtime;
|
|
50
|
+
/** The `world` topic: conditions now. `start()` it to keep it current. */
|
|
51
|
+
readonly conditions: HubState<WorldConditions>;
|
|
52
|
+
/** The `nodes` topic: each resource node's `amount` and `regrow_at`, by node id. */
|
|
53
|
+
readonly nodes: CollectionMirror;
|
|
54
|
+
private readonly nodeType;
|
|
55
|
+
private readonly key;
|
|
56
|
+
constructor(runtime: KitRuntime, options?: WorldKitOptions);
|
|
57
|
+
/** Everything the world shows: conditions, clock, nodes, events, players online. */
|
|
58
|
+
state(): Promise<WorldView>;
|
|
59
|
+
/**
|
|
60
|
+
* Takes one from resource node `node`; resolves with what it holds now.
|
|
61
|
+
* @throws {KitError} `cooldown`, `empty` (it grows back), `not_found`.
|
|
62
|
+
*/
|
|
63
|
+
harvest(node: number): Promise<number>;
|
|
64
|
+
/** Schedules (or replaces) a liveops event. Developers only (a developer kit). */
|
|
65
|
+
schedule(event: WorldLiveopsEvent): Promise<boolean>;
|
|
66
|
+
/** Cancels a liveops event; resolves with whether there was one. Developers only. */
|
|
67
|
+
cancel(name: string): Promise<boolean>;
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=world.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"world.d.ts","sourceRoot":"","sources":["../../../src/kit/modules/world.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,kEAAkE;AAClE,MAAM,WAAW,eAAe;IAC9B,kCAAkC;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;IACf,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB,gFAAgF;IAChF,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AAED,4CAA4C;AAC5C,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,uDAAuD;IACvD,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,4EAA4E;AAC5E,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC;AAED,4CAA4C;AAC5C,MAAM,WAAW,SAAS;IACxB,UAAU,EAAE,eAAe,CAAC;IAC5B,oEAAoE;IACpE,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,iBAAiB,EAAE,CAAC;IAC3B,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAC5B,0BAA0B;IAC1B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,4FAA4F;AAC5F,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;;;GAKG;AACH,qBAAa,QAAQ;IASjB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAR1B,0EAA0E;IAC1E,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,eAAe,CAAC,CAAC;IAC/C,oFAAoF;IACpF,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAC;IACjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;gBAGV,OAAO,EAAE,UAAU,EACpC,OAAO,GAAE,eAAoB;IAQ/B,oFAAoF;IACpF,KAAK,IAAI,OAAO,CAAC,SAAS,CAAC;IAI3B;;;OAGG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAItC,kFAAkF;IAClF,QAAQ,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IAIpD,qFAAqF;IACrF,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAGvC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { CollectionMirror, HubState } from '../mirror.js';
|
|
2
|
+
/**
|
|
3
|
+
* The root world hub (the `world-tick` starter): its clock, weather and liveops modifiers as a
|
|
4
|
+
* mirrored {@link conditions} topic, its resource nodes as a mirrored {@link nodes} collection,
|
|
5
|
+
* harvesting, and for developers the liveops schedule. The root hub takes 50 calls a second for
|
|
6
|
+
* the whole app, so read it from the mirrors (`conditions.start()`), not by polling `state`.
|
|
7
|
+
*/
|
|
8
|
+
export class WorldKit {
|
|
9
|
+
constructor(runtime, options = {}) {
|
|
10
|
+
this.runtime = runtime;
|
|
11
|
+
this.nodeType = options.nodeType ?? 'world';
|
|
12
|
+
this.key = options.key ?? '';
|
|
13
|
+
this.conditions = new HubState(runtime, this.nodeType, this.key, 'world');
|
|
14
|
+
this.nodes = new CollectionMirror(runtime, this.nodeType, this.key, 'nodes');
|
|
15
|
+
}
|
|
16
|
+
/** Everything the world shows: conditions, clock, nodes, events, players online. */
|
|
17
|
+
state() {
|
|
18
|
+
return this.runtime.call(this.nodeType, this.key, 'state');
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Takes one from resource node `node`; resolves with what it holds now.
|
|
22
|
+
* @throws {KitError} `cooldown`, `empty` (it grows back), `not_found`.
|
|
23
|
+
*/
|
|
24
|
+
harvest(node) {
|
|
25
|
+
return this.runtime.call(this.nodeType, this.key, 'harvest', { node }, { action: true });
|
|
26
|
+
}
|
|
27
|
+
/** Schedules (or replaces) a liveops event. Developers only (a developer kit). */
|
|
28
|
+
schedule(event) {
|
|
29
|
+
return this.runtime.call(this.nodeType, this.key, 'schedule', event, { action: true });
|
|
30
|
+
}
|
|
31
|
+
/** Cancels a liveops event; resolves with whether there was one. Developers only. */
|
|
32
|
+
cancel(name) {
|
|
33
|
+
return this.runtime.call(this.nodeType, this.key, 'cancel', { name }, { action: true });
|
|
34
|
+
}
|
|
35
|
+
}
|