@crowdedkingdoms/crowdyjs 8.6.0 → 8.7.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/dist/kit/kit.js CHANGED
@@ -2,12 +2,15 @@ import { mergeBlueprints } from './blueprints/index.js';
2
2
  import { CombatKit } from './combat.js';
3
3
  import { DecksKit } from './decks.js';
4
4
  import { EconomyKit } from './economy.js';
5
+ import { EngineDetector } from './engine.js';
5
6
  import { FeaturesKit } from './features.js';
6
7
  import { InventoryKit } from './inventory.js';
7
8
  import { LeaderboardsKit } from './leaderboards.js';
8
9
  import { LootKit } from './loot.js';
10
+ import { MobsKit } from './mobs.js';
9
11
  import { NpcsKit } from './npcs.js';
10
12
  import { ObjectsKit } from './objects.js';
13
+ import { PetsKit } from './pets.js';
11
14
  import { PlotsKit } from './plots.js';
12
15
  import { MatchesKit } from './matches.js';
13
16
  import { ProgressionKit } from './progression.js';
@@ -56,18 +59,21 @@ export class GameKitClient {
56
59
  constructor(appId, gameModel, gameApps, options = {}, domains = {}) {
57
60
  this.appId = appId;
58
61
  this.gameModel = gameModel;
62
+ this.engines = new EngineDetector(String(appId), domains.compute);
59
63
  this.inventory = new InventoryKit(appId, gameModel, options.inventory);
60
64
  this.objects = new ObjectsKit(appId, gameModel, options.objects);
61
- this.npcs = new NpcsKit(appId, gameModel, options.npcs);
65
+ this.npcs = new NpcsKit(appId, gameModel, options.npcs, this.engines);
62
66
  this.plots = new PlotsKit(appId, gameModel, gameApps, options.plots);
63
67
  this.economy = new EconomyKit(appId, gameModel, options.economy);
64
68
  this.progression = new ProgressionKit(appId, gameModel, options.progression);
65
69
  this.loot = new LootKit(appId, gameModel, options.loot);
66
70
  this.quests = new QuestsKit(appId, gameModel, options.quests);
67
- this.combat = new CombatKit(appId, gameModel, options.combat);
71
+ this.combat = new CombatKit(appId, gameModel, options.combat, this.engines);
68
72
  this.matches = new MatchesKit(appId, gameModel, domains.channels, domains.udp, options.matches);
69
73
  this.decks = new DecksKit(appId, gameModel, options.decks);
70
- this.worldsim = new WorldsimKit(appId, gameModel, options.worldsim);
74
+ this.worldsim = new WorldsimKit(appId, gameModel, options.worldsim, this.engines);
75
+ this.mobs = new MobsKit(appId, gameModel, this.engines, options.mobs);
76
+ this.pets = new PetsKit(appId, gameModel, this.engines, options.pets);
71
77
  this.social = new SocialKit(appId, domains.teams, domains.channels, domains.udp, gameApps, options.social);
72
78
  this.leaderboards = new LeaderboardsKit(appId, gameModel, options.leaderboards);
73
79
  this.features = new FeaturesKit(appId, gameModel);
@@ -0,0 +1,90 @@
1
+ import type { GameModelAPI } from '../domains/gameModel.js';
2
+ import type { Scalars } from '../generated/graphql.js';
3
+ import type { EngineDetector, EngineInvokeResult } from './engine.js';
4
+ import { type ContactDamageEvent } from './wire.js';
5
+ /** Options for {@link MobsKit}. Must match the deployed mob engine. */
6
+ export interface MobsKitOptions {
7
+ /** The compute module serving `attack_mob`/`status`. Defaults to `'mob-engine'`. */
8
+ moduleName?: string;
9
+ /** The mob-definition container type. Defaults to `'MobDef'`. */
10
+ defTypeName?: string;
11
+ /** The mob slot container type. Defaults to `'Mob'`. */
12
+ slotTypeName?: string;
13
+ }
14
+ /** A parsed mob definition container. */
15
+ export interface KitMobDef {
16
+ containerId: string;
17
+ displayName: string;
18
+ mobId: string;
19
+ maxHealth: number;
20
+ damage: number;
21
+ speed: number;
22
+ hostile: boolean;
23
+ spawnTime: string;
24
+ properties: Record<string, unknown>;
25
+ }
26
+ /** A parsed mob slot container (durable state; live poses ride the mob lane). */
27
+ export interface KitMobSlot {
28
+ containerId: string;
29
+ displayName: string;
30
+ mobId: string;
31
+ actorUuid: string;
32
+ health: number;
33
+ x: number;
34
+ y: number;
35
+ z: number;
36
+ /** health > 0 — the slot is live and being simulated. */
37
+ alive: boolean;
38
+ properties: Record<string, unknown>;
39
+ }
40
+ /** The referee's verdict for an accepted/denied attack. */
41
+ export interface KitAttackResult {
42
+ success: boolean;
43
+ /** Remaining health after an accepted hit. */
44
+ health?: number;
45
+ killed?: boolean;
46
+ /** The referee's denial reason ("out of range", "mob not live", ...). */
47
+ reason?: string;
48
+ }
49
+ /**
50
+ * Runtime helpers for compute-module mob engines (the Wave 1 `mob-engine`
51
+ * template / BWF's `bwf-mobs`): definition + slot reads off the model, the
52
+ * refereed `attack_mob` invoke, and the type-77 contact-damage event parser.
53
+ *
54
+ * Live mob poses arrive on the actor stream (FLAG_MOB, container-id
55
+ * suffix) — decode them with `kit/wire`'s {@link engineLanes} +
56
+ * `enginePoseCodec` in your world session; this kit reads the durable side.
57
+ *
58
+ * Obtained via `client.kit(appId).mobs`.
59
+ */
60
+ export declare class MobsKit {
61
+ private readonly appId;
62
+ private readonly gameModel;
63
+ private readonly engines;
64
+ private readonly moduleName;
65
+ private readonly defTypeName;
66
+ private readonly slotTypeName;
67
+ constructor(appId: Scalars['BigInt']['input'], gameModel: GameModelAPI, engines: EngineDetector, options?: MobsKitOptions);
68
+ /** Is the mob engine deployed + enabled (cached per session)? */
69
+ engineAvailable(): Promise<boolean>;
70
+ /**
71
+ * Attack a live mob slot through the server referee: presence, range and
72
+ * damage clamps are validated engine-side before health moves. Denials
73
+ * resolve with `success: false` and the referee's `reason`.
74
+ */
75
+ attack(containerId: string, amount?: number): Promise<KitAttackResult>;
76
+ /** The engine's `status` snapshot (mob/def counts, tick counter). */
77
+ status(): Promise<EngineInvokeResult>;
78
+ /** List mob definitions with parsed stats. */
79
+ defs(): Promise<KitMobDef[]>;
80
+ /** List mob slots (durable positions/health; `alive` = health > 0). */
81
+ slots(): Promise<KitMobSlot[]>;
82
+ /**
83
+ * Parse a server-event payload as engine contact damage (type 77), or
84
+ * null when it is another event type. Feed it your world session's
85
+ * server-event stream and apply the damage to your own player when
86
+ * `targetUuid` matches your actor uuid.
87
+ */
88
+ parseContactDamage(payload: Uint8Array): ContactDamageEvent | null;
89
+ }
90
+ //# sourceMappingURL=mobs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mobs.d.ts","sourceRoot":"","sources":["../../src/kit/mobs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEtE,OAAO,EAAsB,KAAK,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAExE,uEAAuE;AACvE,MAAM,WAAW,cAAc;IAC7B,oFAAoF;IACpF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iEAAiE;IACjE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wDAAwD;IACxD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,yCAAyC;AACzC,MAAM,WAAW,SAAS;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAED,iFAAiF;AACjF,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,yDAAyD;IACzD,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAED,2DAA2D;AAC3D,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,8CAA8C;IAC9C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,yEAAyE;IACzE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;GAUG;AACH,qBAAa,OAAO;IAMhB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAP1B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;gBAGnB,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EACjC,SAAS,EAAE,YAAY,EACvB,OAAO,EAAE,cAAc,EACxC,OAAO,GAAE,cAAmB;IAO9B,iEAAiE;IACjE,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC;IAInC;;;;OAIG;IACG,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,SAAI,GAAG,OAAO,CAAC,eAAe,CAAC;IAcvE,qEAAqE;IAC/D,MAAM,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAI3C,8CAA8C;IACxC,IAAI,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;IA2BlC,uEAAuE;IACjE,KAAK,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;IA6BpC;;;;;OAKG;IACH,kBAAkB,CAAC,OAAO,EAAE,UAAU,GAAG,kBAAkB,GAAG,IAAI;CAGnE"}
@@ -0,0 +1,98 @@
1
+ import { kitContainerProperties } from './shared.js';
2
+ import { parseContactDamage } from './wire.js';
3
+ /**
4
+ * Runtime helpers for compute-module mob engines (the Wave 1 `mob-engine`
5
+ * template / BWF's `bwf-mobs`): definition + slot reads off the model, the
6
+ * refereed `attack_mob` invoke, and the type-77 contact-damage event parser.
7
+ *
8
+ * Live mob poses arrive on the actor stream (FLAG_MOB, container-id
9
+ * suffix) — decode them with `kit/wire`'s {@link engineLanes} +
10
+ * `enginePoseCodec` in your world session; this kit reads the durable side.
11
+ *
12
+ * Obtained via `client.kit(appId).mobs`.
13
+ */
14
+ export class MobsKit {
15
+ constructor(appId, gameModel, engines, options = {}) {
16
+ this.appId = appId;
17
+ this.gameModel = gameModel;
18
+ this.engines = engines;
19
+ this.moduleName = options.moduleName ?? 'mob-engine';
20
+ this.defTypeName = options.defTypeName ?? 'MobDef';
21
+ this.slotTypeName = options.slotTypeName ?? 'Mob';
22
+ }
23
+ /** Is the mob engine deployed + enabled (cached per session)? */
24
+ engineAvailable() {
25
+ return this.engines.has(this.moduleName);
26
+ }
27
+ /**
28
+ * Attack a live mob slot through the server referee: presence, range and
29
+ * damage clamps are validated engine-side before health moves. Denials
30
+ * resolve with `success: false` and the referee's `reason`.
31
+ */
32
+ async attack(containerId, amount = 1) {
33
+ const result = await this.engines.invoke(this.moduleName, 'attack_mob', { containerId, amount });
34
+ return {
35
+ success: result.success,
36
+ health: typeof result.body.health === 'number' ? result.body.health : undefined,
37
+ killed: typeof result.body.killed === 'boolean' ? result.body.killed : undefined,
38
+ reason: result.reason,
39
+ };
40
+ }
41
+ /** The engine's `status` snapshot (mob/def counts, tick counter). */
42
+ async status() {
43
+ return this.engines.invoke(this.moduleName, 'status');
44
+ }
45
+ /** List mob definitions with parsed stats. */
46
+ async defs() {
47
+ const containers = await this.gameModel.containers({
48
+ appId: this.appId,
49
+ typeName: this.defTypeName,
50
+ });
51
+ return Promise.all(containers.map(async (c) => {
52
+ const props = await kitContainerProperties(this.gameModel, String(this.appId), c.containerId);
53
+ return {
54
+ containerId: c.containerId,
55
+ displayName: c.displayName,
56
+ mobId: String(props.mob_id ?? ''),
57
+ maxHealth: Number(props.max_health ?? 0),
58
+ damage: Number(props.damage ?? 0),
59
+ speed: Number(props.speed ?? 0),
60
+ hostile: props.hostile === true || props.hostile === 'true',
61
+ spawnTime: String(props.spawn_time ?? 'any'),
62
+ properties: props,
63
+ };
64
+ }));
65
+ }
66
+ /** List mob slots (durable positions/health; `alive` = health > 0). */
67
+ async slots() {
68
+ const containers = await this.gameModel.containers({
69
+ appId: this.appId,
70
+ typeName: this.slotTypeName,
71
+ });
72
+ return Promise.all(containers.map(async (c) => {
73
+ const props = await kitContainerProperties(this.gameModel, String(this.appId), c.containerId);
74
+ const health = Number(props.health ?? 0);
75
+ return {
76
+ containerId: c.containerId,
77
+ displayName: c.displayName,
78
+ mobId: String(props.mob_id ?? ''),
79
+ actorUuid: String(props.actor_uuid ?? ''),
80
+ health,
81
+ x: Number(props.x ?? 0),
82
+ y: Number(props.y ?? 0),
83
+ z: Number(props.z ?? 0),
84
+ alive: health > 0,
85
+ properties: props,
86
+ };
87
+ }));
88
+ }
89
+ /**
90
+ * Parse a server-event payload as engine contact damage (type 77), or
91
+ * null when it is another event type. Feed it your world session's
92
+ * server-event stream and apply the damage to your own player when
93
+ * `targetUuid` matches your actor uuid.
94
+ */
95
+ parseContactDamage(payload) {
96
+ return parseContactDamage(payload);
97
+ }
98
+ }
@@ -1,9 +1,26 @@
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';
4
+ import type { EnginePose } from './wire.js';
3
5
  /** Options for {@link NpcsKit}. Must match the deployed NPC blueprint. */
4
6
  export interface NpcsKitOptions {
5
7
  /** The `typeName` the NPC blueprint was deployed with. Defaults to `'Npc'`. */
6
8
  typeName?: string;
9
+ /**
10
+ * The compute module driving NPC movement when the app runs an engine
11
+ * (smooth FLAG_NPC actor emits instead of property nudges). Defaults to
12
+ * `'npc-engine'`.
13
+ */
14
+ moduleName?: string;
15
+ }
16
+ /**
17
+ * The minimal shape of a live actor entry {@link overlayLivePoses} reads —
18
+ * matches the world-session `RemoteActor<EnginePose>` without importing it.
19
+ */
20
+ export interface LiveNpcPose {
21
+ uuid: string;
22
+ state: Pick<EnginePose, 'x' | 'y' | 'z'>;
23
+ receivedAt: number;
7
24
  }
8
25
  /** A parsed view of one live NPC. */
9
26
  export interface KitNpc {
@@ -32,8 +49,28 @@ export interface KitNpc {
32
49
  export declare class NpcsKit {
33
50
  private readonly appId;
34
51
  private readonly gameModel;
52
+ private readonly engines?;
35
53
  private readonly typeName;
36
- constructor(appId: Scalars['BigInt']['input'], gameModel: GameModelAPI, options?: NpcsKitOptions);
54
+ private readonly moduleName;
55
+ constructor(appId: Scalars['BigInt']['input'], gameModel: GameModelAPI, options?: NpcsKitOptions, engines?: EngineDetector | undefined);
56
+ /**
57
+ * Is an NPC compute engine deployed + enabled (cached per session)? When
58
+ * true, NPCs stream smooth FLAG_NPC actor poses — overlay them with
59
+ * {@link overlayLivePoses}. When false (model-only deployment), the polled
60
+ * container positions are all there is, exactly as before.
61
+ */
62
+ engineAvailable(): Promise<boolean>;
63
+ /**
64
+ * Overlay live engine-driven poses onto a polled NPC snapshot (the
65
+ * generalized BWF `NpcService.withLivePoses` pattern): each NPC whose
66
+ * `actor_uuid` has a fresh pose in the npcs actor lane gets its position
67
+ * replaced; the rest keep their durable container position, so NPCs stand
68
+ * at their last synced spot instead of disappearing.
69
+ *
70
+ * @param npcs - The polled snapshot (from {@link list}).
71
+ * @param lane - The live actors, e.g. `session.actors.lane('npcs').list()`.
72
+ */
73
+ overlayLivePoses(npcs: KitNpc[], lane: LiveNpcPose[]): KitNpc[];
37
74
  /** Spawn a live NPC instance (admin — the type is admin-instantiable). */
38
75
  spawn(input: {
39
76
  displayName: string;
@@ -1 +1 @@
1
- {"version":3,"file":"npcs.d.ts","sourceRoot":"","sources":["../../src/kit/npcs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAG1E,0EAA0E;AAC1E,MAAM,WAAW,cAAc;IAC7B,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,qCAAqC;AACrC,MAAM,WAAW,MAAM;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAED;;;;;;;;;;GAUG;AACH,qBAAa,OAAO;IAIhB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAJ5B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAGf,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EACjC,SAAS,EAAE,YAAY,EACxC,OAAO,GAAE,cAAmB;IAK9B,0EAA0E;IACpE,KAAK,CAAC,KAAK,EAAE;QACjB,WAAW,EAAE,MAAM,CAAC;QACpB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,QAAQ,CAAC,EAAE;YAAE,CAAC,EAAE,MAAM,CAAC;YAAC,CAAC,EAAE,MAAM,CAAC;YAAC,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QAC/C,UAAU,CAAC,EAAE,iBAAiB,EAAE,CAAC;QACjC,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB;;;;;;;;;;;IAuBD;;;;OAIG;IACG,IAAI,CAAC,OAAO,GAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAclF,gDAAgD;IAC1C,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAQ3C,8EAA8E;IACxE,MAAM,CAAC,cAAc,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;IAInC;;;OAGG;IACG,UAAU,CAAC,cAAc,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAQzD,6EAA6E;IACvE,KAAK,CAAC,aAAa,CAAC,EAAE,MAAM;;;;;;;;;;;;sBA+Bm8ke,CAAC;;;;;;;;;;IAxBt+ke,2DAA2D;IACrD,IAAI,CAAC,OAAO,GAAE;QAAE,cAAc,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAO;;;;;;;;;;;;;;;;;;;;;;YAIzE,KAAK;CAkBpB"}
1
+ {"version":3,"file":"npcs.d.ts","sourceRoot":"","sources":["../../src/kit/npcs.ts"],"names":[],"mappings":"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"}
package/dist/kit/npcs.js CHANGED
@@ -11,10 +11,45 @@ import { kitContainerProperties } from './shared.js';
11
11
  * Obtained via `client.kit(appId).npcs`.
12
12
  */
13
13
  export class NpcsKit {
14
- constructor(appId, gameModel, options = {}) {
14
+ constructor(appId, gameModel, options = {}, engines) {
15
15
  this.appId = appId;
16
16
  this.gameModel = gameModel;
17
+ this.engines = engines;
17
18
  this.typeName = options.typeName ?? 'Npc';
19
+ this.moduleName = options.moduleName ?? 'npc-engine';
20
+ }
21
+ /**
22
+ * Is an NPC compute engine deployed + enabled (cached per session)? When
23
+ * true, NPCs stream smooth FLAG_NPC actor poses — overlay them with
24
+ * {@link overlayLivePoses}. When false (model-only deployment), the polled
25
+ * container positions are all there is, exactly as before.
26
+ */
27
+ engineAvailable() {
28
+ if (!this.engines)
29
+ return Promise.resolve(false);
30
+ return this.engines.has(this.moduleName);
31
+ }
32
+ /**
33
+ * Overlay live engine-driven poses onto a polled NPC snapshot (the
34
+ * generalized BWF `NpcService.withLivePoses` pattern): each NPC whose
35
+ * `actor_uuid` has a fresh pose in the npcs actor lane gets its position
36
+ * replaced; the rest keep their durable container position, so NPCs stand
37
+ * at their last synced spot instead of disappearing.
38
+ *
39
+ * @param npcs - The polled snapshot (from {@link list}).
40
+ * @param lane - The live actors, e.g. `session.actors.lane('npcs').list()`.
41
+ */
42
+ overlayLivePoses(npcs, lane) {
43
+ if (lane.length === 0)
44
+ return npcs;
45
+ const poses = new Map(lane.map((actor) => [actor.uuid, actor]));
46
+ return npcs.map((npc) => {
47
+ const uuid = String(npc.properties.actor_uuid ?? '');
48
+ const live = uuid ? poses.get(uuid) : undefined;
49
+ if (!live)
50
+ return npc;
51
+ return { ...npc, x: live.state.x, y: live.state.y, z: live.state.z };
52
+ });
18
53
  }
19
54
  /** Spawn a live NPC instance (admin — the type is admin-instantiable). */
20
55
  async spawn(input) {
@@ -0,0 +1,85 @@
1
+ import type { GameModelAPI } from '../domains/gameModel.js';
2
+ import type { Scalars, SeedPropertyInput } from '../generated/graphql.js';
3
+ import type { EngineDetector } from './engine.js';
4
+ /** Options for {@link PetsKit}. Must match the deployed npc engine. */
5
+ export interface PetsKitOptions {
6
+ /** The compute module serving summon/dismiss/rename. Defaults to `'npc-engine'`. */
7
+ moduleName?: string;
8
+ /** The pet container type. Defaults to `'Pet'`. */
9
+ typeName?: string;
10
+ }
11
+ /** A parsed pet container. */
12
+ export interface KitPet {
13
+ containerId: string;
14
+ displayName: string;
15
+ species: string;
16
+ name: string;
17
+ ownerUserId: string | null;
18
+ bond: number;
19
+ active: boolean;
20
+ actorUuid: string;
21
+ x: number;
22
+ y: number;
23
+ z: number;
24
+ properties: Record<string, unknown>;
25
+ }
26
+ /** An engine verdict for a pet invoke. */
27
+ export interface KitPetResult {
28
+ success: boolean;
29
+ reason?: string;
30
+ }
31
+ /**
32
+ * Runtime helpers for engine-driven pets (the Wave 1 npc-engine template):
33
+ * `Pet` containers hold species/name/owner/bond; the engine walks active
34
+ * pets after their owner (kit-ai `follow_owner`) and streams FLAG_NPC actor
35
+ * poses with the pet's container id as the payload suffix — decode the lane
36
+ * with `kit/wire` and match `pose.suffix` to the container id.
37
+ *
38
+ * Obtained via `client.kit(appId).pets`.
39
+ */
40
+ export declare class PetsKit {
41
+ private readonly appId;
42
+ private readonly gameModel;
43
+ private readonly engines;
44
+ private readonly moduleName;
45
+ private readonly typeName;
46
+ constructor(appId: Scalars['BigInt']['input'], gameModel: GameModelAPI, engines: EngineDetector, options?: PetsKitOptions);
47
+ /** Is the pet-driving npc engine deployed + enabled (cached per session)? */
48
+ engineAvailable(): Promise<boolean>;
49
+ /**
50
+ * Adopt a pet: creates the caller-owned Pet container (active). Member
51
+ * instantiation defaults the owner to the caller; admin tokens must pass
52
+ * `ownerUserId` explicitly (the engine validates ownership on every
53
+ * summon/dismiss/rename).
54
+ */
55
+ adopt(input: {
56
+ species: string;
57
+ name: string;
58
+ ownerUserId?: Scalars['BigInt']['input'];
59
+ position?: {
60
+ x: number;
61
+ y: number;
62
+ z: number;
63
+ };
64
+ properties?: SeedPropertyInput[];
65
+ }): Promise<{
66
+ __typename?: "GmContainer";
67
+ containerId: string;
68
+ appId: string;
69
+ sessionId: string | null;
70
+ typeName: string;
71
+ displayName: string;
72
+ description: string | null;
73
+ ownerUserId: string | null;
74
+ metadataJson: string;
75
+ }>;
76
+ /** List pets (all, or one owner's with `ownerUserId`). */
77
+ list(ownerUserId?: Scalars['BigInt']['input']): Promise<KitPet[]>;
78
+ /** Summon your pet: it starts following you (owner-validated engine-side). */
79
+ summon(containerId: string): Promise<KitPetResult>;
80
+ /** Dismiss your pet: it stops simulating until summoned again. */
81
+ dismiss(containerId: string): Promise<KitPetResult>;
82
+ /** Rename your pet (1-32 chars; owner-validated engine-side). */
83
+ rename(containerId: string, name: string): Promise<KitPetResult>;
84
+ }
85
+ //# sourceMappingURL=pets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pets.d.ts","sourceRoot":"","sources":["../../src/kit/pets.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC1E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAGlD,uEAAuE;AACvE,MAAM,WAAW,cAAc;IAC7B,oFAAoF;IACpF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mDAAmD;IACnD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,8BAA8B;AAC9B,MAAM,WAAW,MAAM;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAED,0CAA0C;AAC1C,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;GAQG;AACH,qBAAa,OAAO;IAKhB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAN1B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAGf,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,EACjC,SAAS,EAAE,YAAY,EACvB,OAAO,EAAE,cAAc,EACxC,OAAO,GAAE,cAAmB;IAM9B,6EAA6E;IAC7E,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC;IAInC;;;;;OAKG;IACG,KAAK,CAAC,KAAK,EAAE;QACjB,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC;QACzC,QAAQ,CAAC,EAAE;YAAE,CAAC,EAAE,MAAM,CAAC;YAAC,CAAC,EAAE,MAAM,CAAC;YAAC,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QAC/C,UAAU,CAAC,EAAE,iBAAiB,EAAE,CAAC;KAClC;;;;;;;;;;;IAuBD,0DAA0D;IACpD,IAAI,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAoCvE,8EAA8E;IACxE,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAKxD,kEAAkE;IAC5D,OAAO,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAKzD,iEAAiE;IAC3D,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;CAOvE"}
@@ -0,0 +1,96 @@
1
+ import { kitContainerProperties } from './shared.js';
2
+ /**
3
+ * Runtime helpers for engine-driven pets (the Wave 1 npc-engine template):
4
+ * `Pet` containers hold species/name/owner/bond; the engine walks active
5
+ * pets after their owner (kit-ai `follow_owner`) and streams FLAG_NPC actor
6
+ * poses with the pet's container id as the payload suffix — decode the lane
7
+ * with `kit/wire` and match `pose.suffix` to the container id.
8
+ *
9
+ * Obtained via `client.kit(appId).pets`.
10
+ */
11
+ export class PetsKit {
12
+ constructor(appId, gameModel, engines, options = {}) {
13
+ this.appId = appId;
14
+ this.gameModel = gameModel;
15
+ this.engines = engines;
16
+ this.moduleName = options.moduleName ?? 'npc-engine';
17
+ this.typeName = options.typeName ?? 'Pet';
18
+ }
19
+ /** Is the pet-driving npc engine deployed + enabled (cached per session)? */
20
+ engineAvailable() {
21
+ return this.engines.has(this.moduleName);
22
+ }
23
+ /**
24
+ * Adopt a pet: creates the caller-owned Pet container (active). Member
25
+ * instantiation defaults the owner to the caller; admin tokens must pass
26
+ * `ownerUserId` explicitly (the engine validates ownership on every
27
+ * summon/dismiss/rename).
28
+ */
29
+ async adopt(input) {
30
+ return this.gameModel.createContainer({
31
+ appId: this.appId,
32
+ typeName: this.typeName,
33
+ displayName: input.name,
34
+ ...(input.ownerUserId !== undefined ? { ownerUserId: input.ownerUserId } : {}),
35
+ properties: [
36
+ { key: 'species', valueType: 'string', valueJson: JSON.stringify(input.species) },
37
+ { key: 'name', valueType: 'string', valueJson: JSON.stringify(input.name) },
38
+ { key: 'bond', valueType: 'int', valueJson: '0' },
39
+ { key: 'active', valueType: 'string', valueJson: '"true"' },
40
+ ...(input.position
41
+ ? [
42
+ { key: 'x', valueType: 'int', valueJson: String(Math.round(input.position.x)) },
43
+ { key: 'y', valueType: 'int', valueJson: String(Math.round(input.position.y)) },
44
+ { key: 'z', valueType: 'int', valueJson: String(Math.round(input.position.z)) },
45
+ ]
46
+ : []),
47
+ ...(input.properties ?? []),
48
+ ],
49
+ });
50
+ }
51
+ /** List pets (all, or one owner's with `ownerUserId`). */
52
+ async list(ownerUserId) {
53
+ const containers = await this.gameModel.containers({
54
+ appId: this.appId,
55
+ typeName: this.typeName,
56
+ });
57
+ const filtered = ownerUserId === undefined
58
+ ? containers
59
+ : containers.filter((c) => c.ownerUserId != null && String(c.ownerUserId) === String(ownerUserId));
60
+ return Promise.all(filtered.map(async (c) => {
61
+ const props = await kitContainerProperties(this.gameModel, String(this.appId), c.containerId);
62
+ return {
63
+ containerId: c.containerId,
64
+ displayName: c.displayName,
65
+ species: String(props.species ?? ''),
66
+ name: String(props.name ?? c.displayName),
67
+ ownerUserId: c.ownerUserId != null ? String(c.ownerUserId) : null,
68
+ bond: Number(props.bond ?? 0),
69
+ active: props.active !== 'false' && props.active !== false,
70
+ actorUuid: String(props.actor_uuid ?? ''),
71
+ x: Number(props.x ?? 0),
72
+ y: Number(props.y ?? 0),
73
+ z: Number(props.z ?? 0),
74
+ properties: props,
75
+ };
76
+ }));
77
+ }
78
+ /** Summon your pet: it starts following you (owner-validated engine-side). */
79
+ async summon(containerId) {
80
+ const result = await this.engines.invoke(this.moduleName, 'summon', { containerId });
81
+ return { success: result.success, reason: result.reason };
82
+ }
83
+ /** Dismiss your pet: it stops simulating until summoned again. */
84
+ async dismiss(containerId) {
85
+ const result = await this.engines.invoke(this.moduleName, 'dismiss', { containerId });
86
+ return { success: result.success, reason: result.reason };
87
+ }
88
+ /** Rename your pet (1-32 chars; owner-validated engine-side). */
89
+ async rename(containerId, name) {
90
+ const result = await this.engines.invoke(this.moduleName, 'rename_pet', {
91
+ containerId,
92
+ name,
93
+ });
94
+ return { success: result.success, reason: result.reason };
95
+ }
96
+ }
@@ -0,0 +1,87 @@
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
+ /** Split an engine server-event payload into its type + JSON body. */
64
+ export declare function parseEngineEvent(bytes: Uint8Array): {
65
+ eventType: number;
66
+ body: Record<string, unknown>;
67
+ } | null;
68
+ /** A parsed type-77 contact-damage event. */
69
+ export interface ContactDamageEvent {
70
+ targetUuid: string;
71
+ damage: number;
72
+ mobId: string;
73
+ mobName: string;
74
+ }
75
+ /** Parse a contact-damage event; null when the payload is another type. */
76
+ export declare function parseContactDamage(bytes: Uint8Array): ContactDamageEvent | null;
77
+ /** A parsed type-90 weather transition event. */
78
+ export interface WeatherEvent {
79
+ weather: string;
80
+ sinceMs: number;
81
+ untilMs: number;
82
+ /** Extra fields engines add (dayPhase, isNight, remainingMs, ...). */
83
+ body: Record<string, unknown>;
84
+ }
85
+ /** Parse a weather event; null when the payload is another type. */
86
+ export declare function parseWeatherEvent(bytes: Uint8Array): WeatherEvent | null;
87
+ //# sourceMappingURL=wire.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wire.d.ts","sourceRoot":"","sources":["../../src/kit/wire.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,eAAO,MAAM,UAAU,KAAK,CAAC;AAE7B,4EAA4E;AAC5E,eAAO,MAAM,aAAa,IAAS,CAAC;AACpC,eAAO,MAAM,QAAQ,IAAS,CAAC;AAC/B,eAAO,MAAM,QAAQ,IAAS,CAAC;AAC/B,eAAO,MAAM,cAAc,IAAS,CAAC;AAErC,uEAAuE;AACvE,MAAM,WAAW,UAAU;IACzB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,0EAA0E;IAC1E,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,gDAAgD;AAChD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,UAAU,CAiBtE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,GAAG,IAAI,CAqBrE;AAED,sEAAsE;AACtE,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,CAI3D;AAED;;;;;GAKG;AACH,eAAO,MAAM,eAAe,EAAE,UAAU,CAAC,UAAU,CAiBlD,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,OAAO,CAAC,CAM5E;AAMD,wEAAwE;AACxE,eAAO,MAAM,oBAAoB,KAAK,CAAC;AACvC,uEAAuE;AACvE,eAAO,MAAM,aAAa,KAAK,CAAC;AAEhC,sEAAsE;AACtE,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,UAAU,GAChB;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAAG,IAAI,CAY7D;AAED,6CAA6C;AAC7C,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,2EAA2E;AAC3E,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,GAAG,kBAAkB,GAAG,IAAI,CAS/E;AAED,iDAAiD;AACjD,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,sEAAsE;IACtE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED,oEAAoE;AACpE,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,UAAU,GAAG,YAAY,GAAG,IAAI,CASxE"}