@crowdedkingdoms/crowdyjs 17.13.0-dev.1 → 18.0.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 +163 -1
- package/README.md +142 -146
- package/dist/crowdy-client.d.ts +12 -31
- package/dist/crowdy-client.d.ts.map +1 -1
- package/dist/crowdy-client.js +15 -37
- package/dist/crowdy-dsh/bridge.d.ts.map +1 -1
- package/dist/crowdy-dsh/bridge.js +3 -6
- package/dist/crowdy-studio/controller.d.ts +59 -57
- package/dist/crowdy-studio/controller.d.ts.map +1 -1
- package/dist/crowdy-studio/controller.js +268 -206
- package/dist/crowdy-studio/diagnostics.d.ts +3 -12
- package/dist/crowdy-studio/diagnostics.d.ts.map +1 -1
- package/dist/crowdy-studio/dom-shell.d.ts +2 -4
- package/dist/crowdy-studio/dom-shell.d.ts.map +1 -1
- package/dist/crowdy-studio/dom-shell.js +16 -47
- package/dist/crowdy-studio/embed/hud-layer.d.ts +1 -1
- package/dist/crowdy-studio/embed/panel.d.ts +3 -12
- package/dist/crowdy-studio/embed/panel.d.ts.map +1 -1
- package/dist/crowdy-studio/embed/panel.js +3 -6
- package/dist/crowdy-studio/index.d.ts +1 -3
- package/dist/crowdy-studio/index.d.ts.map +1 -1
- package/dist/crowdy-studio/index.js +0 -2
- package/dist/crowdy-studio/models.d.ts +3 -4
- package/dist/crowdy-studio/models.d.ts.map +1 -1
- package/dist/crowdy-studio/starter-projects.d.ts +8 -4
- package/dist/crowdy-studio/starter-projects.d.ts.map +1 -1
- package/dist/crowdy-studio/starter-projects.js +83 -100
- package/dist/domains/appAccess.d.ts +14 -1
- package/dist/domains/appAccess.d.ts.map +1 -1
- package/dist/domains/appAccess.js +37 -1
- package/dist/domains/exec.d.ts +162 -15
- package/dist/domains/exec.d.ts.map +1 -1
- package/dist/domains/exec.js +180 -18
- package/dist/domains/host.d.ts +3 -3
- package/dist/domains/host.js +3 -3
- package/dist/domains/marketplace.d.ts +9 -58
- package/dist/domains/marketplace.d.ts.map +1 -1
- package/dist/domains/marketplace.js +9 -106
- package/dist/domains/playerWallet.d.ts +6 -12
- package/dist/domains/playerWallet.d.ts.map +1 -1
- package/dist/domains/playerWallet.js +6 -21
- package/dist/errors.d.ts +7 -13
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +6 -10
- package/dist/generated/graphql.d.ts +1384 -7977
- package/dist/generated/graphql.d.ts.map +1 -1
- package/dist/generated/graphql.js +22 -321
- package/dist/grid-mods/exec-client-halves.d.ts +156 -0
- package/dist/grid-mods/exec-client-halves.d.ts.map +1 -0
- package/dist/grid-mods/exec-client-halves.js +356 -0
- package/dist/grid-mods/grid-host-calls.d.ts +29 -15
- package/dist/grid-mods/grid-host-calls.d.ts.map +1 -1
- package/dist/grid-mods/grid-host-calls.js +40 -44
- package/dist/grid-mods/index.d.ts +1 -0
- package/dist/grid-mods/index.d.ts.map +1 -1
- package/dist/grid-mods/index.js +1 -0
- package/dist/grid-mods/mod-runtime.d.ts +21 -6
- package/dist/grid-mods/mod-runtime.d.ts.map +1 -1
- package/dist/grid-mods/mod-runtime.js +6 -2
- package/dist/grid-scope.d.ts +0 -188
- package/dist/grid-scope.d.ts.map +1 -1
- package/dist/grid-scope.js +0 -69
- package/dist/index.d.ts +12 -18
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -16
- package/dist/kit/actions.d.ts +5 -9
- package/dist/kit/actions.d.ts.map +1 -1
- package/dist/kit/actions.js +5 -9
- package/dist/kit/index.d.ts +2 -33
- package/dist/kit/index.d.ts.map +1 -1
- package/dist/kit/index.js +1 -32
- package/dist/kit/kit.d.ts +8 -208
- package/dist/kit/kit.d.ts.map +1 -1
- package/dist/kit/kit.js +5 -163
- package/dist/kit/social.d.ts +1 -3
- package/dist/kit/social.d.ts.map +1 -1
- package/dist/kit/social.js +1 -3
- package/dist/kit/wire.d.ts +16 -5
- package/dist/kit/wire.d.ts.map +1 -1
- package/dist/kit/wire.js +19 -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 +1496 -4386
- package/dist/live-coding/rust-analysis.d.ts.map +1 -1
- package/dist/live-coding/rust-analysis.js +31 -23
- package/dist/player-runtime/client-host-calls.d.ts +8 -0
- package/dist/player-runtime/client-host-calls.d.ts.map +1 -0
- package/dist/player-runtime/client-host-calls.js +28 -0
- package/dist/player-runtime/glue-runtime.d.ts +27 -10
- package/dist/player-runtime/glue-runtime.d.ts.map +1 -1
- package/dist/player-runtime/glue-runtime.js +40 -45
- package/dist/player-runtime/glue-sab.d.ts +2 -2
- package/dist/player-runtime/glue-sab.js +2 -2
- package/dist/player-runtime/player-code-broker.d.ts +80 -24
- package/dist/player-runtime/player-code-broker.d.ts.map +1 -1
- package/dist/player-runtime/player-code-broker.js +169 -41
- package/dist/player-runtime/player-glue-worker.d.ts +8 -8
- package/dist/player-runtime/player-glue-worker.d.ts.map +1 -1
- package/dist/player-runtime/player-glue-worker.js +26 -9
- package/dist/stores/actors.d.ts +12 -2
- package/dist/stores/actors.d.ts.map +1 -1
- package/dist/stores/actors.js +43 -18
- package/dist/stores/chunks.d.ts +12 -0
- package/dist/stores/chunks.d.ts.map +1 -1
- package/dist/stores/chunks.js +112 -39
- package/dist/stores/durable.d.ts.map +1 -1
- package/dist/stores/durable.js +2 -1
- package/dist/stores/inbox.d.ts +1 -1
- package/dist/stores/inbox.d.ts.map +1 -1
- package/dist/stores/index.d.ts +0 -11
- package/dist/stores/index.d.ts.map +1 -1
- package/dist/stores/index.js +0 -4
- package/dist/stores/session.d.ts +0 -2
- package/dist/stores/session.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/crowdy-studio/model-lint-log.d.ts +0 -76
- package/dist/crowdy-studio/model-lint-log.d.ts.map +0 -1
- package/dist/crowdy-studio/model-lint-log.js +0 -93
- package/dist/crowdy-studio/model-lint.d.ts +0 -61
- package/dist/crowdy-studio/model-lint.d.ts.map +0 -1
- package/dist/crowdy-studio/model-lint.js +0 -45
- package/dist/domains/compute.d.ts +0 -208
- package/dist/domains/compute.d.ts.map +0 -1
- package/dist/domains/compute.js +0 -274
- package/dist/domains/controlPlane.d.ts +0 -38
- package/dist/domains/controlPlane.d.ts.map +0 -1
- package/dist/domains/controlPlane.js +0 -43
- package/dist/domains/gameModel.d.ts +0 -1174
- package/dist/domains/gameModel.d.ts.map +0 -1
- package/dist/domains/gameModel.js +0 -1333
- package/dist/domains/playerCompute.d.ts +0 -91
- package/dist/domains/playerCompute.d.ts.map +0 -1
- package/dist/domains/playerCompute.js +0 -136
- package/dist/domains/playerModel.d.ts +0 -20
- package/dist/domains/playerModel.d.ts.map +0 -1
- package/dist/domains/playerModel.js +0 -54
- package/dist/kit/abilities.d.ts +0 -66
- package/dist/kit/abilities.d.ts.map +0 -1
- package/dist/kit/abilities.js +0 -71
- package/dist/kit/blueprints/combat.d.ts +0 -81
- package/dist/kit/blueprints/combat.d.ts.map +0 -1
- package/dist/kit/blueprints/combat.js +0 -357
- package/dist/kit/blueprints/core.d.ts +0 -222
- package/dist/kit/blueprints/core.d.ts.map +0 -1
- package/dist/kit/blueprints/core.js +0 -185
- package/dist/kit/blueprints/decks.d.ts +0 -50
- package/dist/kit/blueprints/decks.d.ts.map +0 -1
- package/dist/kit/blueprints/decks.js +0 -163
- package/dist/kit/blueprints/economy.d.ts +0 -88
- package/dist/kit/blueprints/economy.d.ts.map +0 -1
- package/dist/kit/blueprints/economy.js +0 -533
- package/dist/kit/blueprints/guild.d.ts +0 -51
- package/dist/kit/blueprints/guild.d.ts.map +0 -1
- package/dist/kit/blueprints/guild.js +0 -50
- package/dist/kit/blueprints/index.d.ts +0 -23
- package/dist/kit/blueprints/index.d.ts.map +0 -1
- package/dist/kit/blueprints/index.js +0 -22
- package/dist/kit/blueprints/inventory.d.ts +0 -84
- package/dist/kit/blueprints/inventory.d.ts.map +0 -1
- package/dist/kit/blueprints/inventory.js +0 -257
- package/dist/kit/blueprints/leaderboards.d.ts +0 -49
- package/dist/kit/blueprints/leaderboards.d.ts.map +0 -1
- package/dist/kit/blueprints/leaderboards.js +0 -126
- package/dist/kit/blueprints/liveops.d.ts +0 -42
- package/dist/kit/blueprints/liveops.d.ts.map +0 -1
- package/dist/kit/blueprints/liveops.js +0 -170
- package/dist/kit/blueprints/locks.d.ts +0 -82
- package/dist/kit/blueprints/locks.d.ts.map +0 -1
- package/dist/kit/blueprints/locks.js +0 -155
- package/dist/kit/blueprints/loot.d.ts +0 -90
- package/dist/kit/blueprints/loot.d.ts.map +0 -1
- package/dist/kit/blueprints/loot.js +0 -229
- package/dist/kit/blueprints/matches.d.ts +0 -84
- package/dist/kit/blueprints/matches.d.ts.map +0 -1
- package/dist/kit/blueprints/matches.js +0 -349
- package/dist/kit/blueprints/moderation.d.ts +0 -32
- package/dist/kit/blueprints/moderation.d.ts.map +0 -1
- package/dist/kit/blueprints/moderation.js +0 -140
- package/dist/kit/blueprints/npcs.d.ts +0 -78
- package/dist/kit/blueprints/npcs.d.ts.map +0 -1
- package/dist/kit/blueprints/npcs.js +0 -125
- package/dist/kit/blueprints/plots.d.ts +0 -63
- package/dist/kit/blueprints/plots.d.ts.map +0 -1
- package/dist/kit/blueprints/plots.js +0 -151
- package/dist/kit/blueprints/progression.d.ts +0 -68
- package/dist/kit/blueprints/progression.d.ts.map +0 -1
- package/dist/kit/blueprints/progression.js +0 -324
- package/dist/kit/blueprints/quests.d.ts +0 -72
- package/dist/kit/blueprints/quests.d.ts.map +0 -1
- package/dist/kit/blueprints/quests.js +0 -285
- package/dist/kit/blueprints/worldsim.d.ts +0 -91
- package/dist/kit/blueprints/worldsim.d.ts.map +0 -1
- package/dist/kit/blueprints/worldsim.js +0 -468
- package/dist/kit/combat.d.ts +0 -141
- package/dist/kit/combat.d.ts.map +0 -1
- package/dist/kit/combat.js +0 -196
- package/dist/kit/decks.d.ts +0 -157
- package/dist/kit/decks.d.ts.map +0 -1
- package/dist/kit/decks.js +0 -186
- package/dist/kit/director.d.ts +0 -88
- package/dist/kit/director.d.ts.map +0 -1
- package/dist/kit/director.js +0 -86
- package/dist/kit/economy.d.ts +0 -289
- package/dist/kit/economy.d.ts.map +0 -1
- package/dist/kit/economy.js +0 -427
- package/dist/kit/engine.d.ts +0 -48
- package/dist/kit/engine.d.ts.map +0 -1
- package/dist/kit/engine.js +0 -113
- package/dist/kit/features.d.ts +0 -60
- package/dist/kit/features.d.ts.map +0 -1
- package/dist/kit/features.js +0 -65
- package/dist/kit/instances.d.ts +0 -52
- package/dist/kit/instances.d.ts.map +0 -1
- package/dist/kit/instances.js +0 -60
- package/dist/kit/inventory.d.ts +0 -129
- package/dist/kit/inventory.d.ts.map +0 -1
- package/dist/kit/inventory.js +0 -200
- package/dist/kit/leaderboards.d.ts +0 -86
- package/dist/kit/leaderboards.d.ts.map +0 -1
- package/dist/kit/leaderboards.js +0 -133
- package/dist/kit/liveops.d.ts +0 -112
- package/dist/kit/liveops.d.ts.map +0 -1
- package/dist/kit/liveops.js +0 -183
- package/dist/kit/loot.d.ts +0 -128
- package/dist/kit/loot.d.ts.map +0 -1
- package/dist/kit/loot.js +0 -160
- package/dist/kit/matches.d.ts +0 -301
- package/dist/kit/matches.d.ts.map +0 -1
- package/dist/kit/matches.js +0 -458
- package/dist/kit/matchmaking.d.ts +0 -57
- package/dist/kit/matchmaking.d.ts.map +0 -1
- package/dist/kit/matchmaking.js +0 -59
- package/dist/kit/minigames.d.ts +0 -30
- package/dist/kit/minigames.d.ts.map +0 -1
- package/dist/kit/minigames.js +0 -38
- package/dist/kit/mobs.d.ts +0 -90
- package/dist/kit/mobs.d.ts.map +0 -1
- package/dist/kit/mobs.js +0 -98
- package/dist/kit/moderation.d.ts +0 -73
- package/dist/kit/moderation.d.ts.map +0 -1
- package/dist/kit/moderation.js +0 -103
- package/dist/kit/movement.d.ts +0 -78
- package/dist/kit/movement.d.ts.map +0 -1
- package/dist/kit/movement.js +0 -103
- package/dist/kit/notifications.d.ts +0 -45
- package/dist/kit/notifications.d.ts.map +0 -1
- package/dist/kit/notifications.js +0 -67
- package/dist/kit/npcs.d.ts +0 -226
- package/dist/kit/npcs.d.ts.map +0 -1
- package/dist/kit/npcs.js +0 -141
- package/dist/kit/objects.d.ts +0 -116
- package/dist/kit/objects.d.ts.map +0 -1
- package/dist/kit/objects.js +0 -119
- package/dist/kit/pets.d.ts +0 -85
- package/dist/kit/pets.d.ts.map +0 -1
- package/dist/kit/pets.js +0 -96
- package/dist/kit/plots.d.ts +0 -85
- package/dist/kit/plots.d.ts.map +0 -1
- package/dist/kit/plots.js +0 -113
- package/dist/kit/progression.d.ts +0 -181
- package/dist/kit/progression.d.ts.map +0 -1
- package/dist/kit/progression.js +0 -265
- package/dist/kit/quests.d.ts +0 -171
- package/dist/kit/quests.d.ts.map +0 -1
- package/dist/kit/quests.js +0 -237
- package/dist/kit/racing.d.ts +0 -85
- package/dist/kit/racing.d.ts.map +0 -1
- package/dist/kit/racing.js +0 -99
- package/dist/kit/shared.d.ts +0 -73
- package/dist/kit/shared.d.ts.map +0 -1
- package/dist/kit/shared.js +0 -101
- package/dist/kit/telemetry.d.ts +0 -66
- package/dist/kit/telemetry.d.ts.map +0 -1
- package/dist/kit/telemetry.js +0 -133
- package/dist/kit/territory.d.ts +0 -97
- package/dist/kit/territory.d.ts.map +0 -1
- package/dist/kit/territory.js +0 -114
- package/dist/kit/worldsim.d.ts +0 -263
- package/dist/kit/worldsim.d.ts.map +0 -1
- package/dist/kit/worldsim.js +0 -268
- package/dist/stores/model.d.ts +0 -81
- package/dist/stores/model.d.ts.map +0 -1
- package/dist/stores/model.js +0 -163
package/MIGRATION.md
CHANGED
|
@@ -1,3 +1,164 @@
|
|
|
1
|
+
# CrowdyJS v18 — the legacy engines are gone
|
|
2
|
+
|
|
3
|
+
**Breaking.** The game API deleted its legacy developer-code engines on dev (cks-game-api #417,
|
|
4
|
+
ck-api `v2.27.0`): Studio compute, the game model and its automations, player compute (its
|
|
5
|
+
browser CLIENT modules too) and the player model. `18.0.0` removes their SDK surface. Their
|
|
6
|
+
code moves to ck-exec (`client.exec`): an app's server code as hubs and spokes, a player's grid
|
|
7
|
+
code as mods, and a mod's browser code as its CLIENT half. Nothing is migrated for you; port the
|
|
8
|
+
code, then upgrade.
|
|
9
|
+
|
|
10
|
+
**What it needs.** 18.0.0 calls nothing the legacy engines served, so it runs against any API
|
|
11
|
+
with ck-exec CLIENT halves (ck-api `v2.24.0`, as 17.14.0 did). **Crowdy Studio's CLIENT
|
|
12
|
+
projects need ck-api `v2.25.1` or later:** `v2.24.0` and `v2.25.0` refuse to save a
|
|
13
|
+
`crowdy-client-sdk` crate in a Studio project (`CROWDY_STUDIO_MANIFEST_INVALID`, cks-game-api
|
|
14
|
+
#425). The other way round, a 17.x SDK against `v2.27.0` fails every call into a deleted field
|
|
15
|
+
as a GraphQL validation error.
|
|
16
|
+
|
|
17
|
+
| 17.x | 18.0 |
|
|
18
|
+
| --- | --- |
|
|
19
|
+
| `client.gameModel` (containers, properties, functions, `invoke`, sessions, events, timers, automations, `seed`, lint, the player-count feed) | A hub's own state and endpoints: `client.exec.connect(appId, { nodeType, key })`, then `call` / `subscribe`; timers are `ctx.timer_after` / `ctx.timer_every` in the hub; sessions are a keyed hub (the `session` starter) |
|
|
20
|
+
| `gameModel.defineFeature`, `grantTierFeature`, `revokeTierFeature`, `features`, `tierFeatures` | `client.appAccess.defineFeature`, `grantTierFeature`, `revokeTierFeature`, `features(appId)`, `tierFeatures(appId, tierId?)` (same fields; a hub reads them with `players.features`) |
|
|
21
|
+
| `client.compute` (modules, `invoke`, templates, runs, logs) | `client.exec.starters` / `build` / `waitForBuild` / `deploy`, `logs`, `instances`, `versions`, `activateVersion`, `setEnabled`; manual calls through `connectAsDeveloper` |
|
|
22
|
+
| `client.playerModel` (containers, automations) | A mod's own state and timers |
|
|
23
|
+
| `client.playerCompute` SERVER side (`deploy` with `target: SERVER`, `setEnabled`, `setRequires`, `invoke`, `runs`, `logs`) | Mods: `client.exec.modBuild` / `waitForModBuild` / `modDeploy` / `modSetEnabled`, calls through `connect(appId, { nodeType: execModType(name), key: gridId })`, `modLogs` |
|
|
24
|
+
| `client.playerCompute` CLIENT modules (`deploy`, `versions`, `artifact`, `artifactBytes`, `usage`, `myModules`, `delete`, `setSwitch`, `switches`) | A mod's CLIENT half: `client.exec.modClientBuild` (polled with `modBuildStatus` / `waitForModBuild`), `modClientDeploy` / `modClientDelete`, `modClientArtifactBytes`; its kill ladder is the mod's, `modSetSwitch` |
|
|
25
|
+
| `marketplace.gridClientMods`, `consentGridClientMod`, `trustGridAuthor`, `clientArtifact`, `clientArtifactBytes`, and `client.grid(...).compute.clientMods` | `client.exec.gridClientMods`, `consentClientMod`, `trustAuthor`, `modClientArtifactBytes` (which checks the bytes against their digest); `ExecClientHalves` runs a grid's CLIENT halves |
|
|
26
|
+
| `marketplace.listings` / `versions` / `publishListing` / `publishVersion` / `acquire` / `install` / `uninstall` / `myAcquisitions` / `myInstalls` | `client.exec.modPublish` / `modListings` / `modInstall` / `modUnpublish`; a listing carries its mod's CLIENT half |
|
|
27
|
+
| `playerWallet.policies` / `setPolicy` / `deletePolicy` (`playerWasmPolicies`) | Mods run under the platform's mod limits; the kill ladder is `client.exec.modSetSwitch` |
|
|
28
|
+
| `client.operator` (`computePlatformCeilings`, `setComputePlatformCeilings`) | ck-exec code is bounded by its manifest limits within the platform's; there is nothing to call |
|
|
29
|
+
| `client.kit(appId)` blueprints, `kit.deploy`, engines, `kit.inventory` … `kit.minigames`, `kit.features` | Hubs; the starters for NPCs and mobs, sessions and matchmaking. `kit.social` stays; `kit/wire.ts` codecs and `runOptimisticAction` stay |
|
|
30
|
+
| `createWorldSession({ model })` (`ContainerMirror`) | Subscribe to the hub's topic |
|
|
31
|
+
| `client.grid(...).sessions`, `.model`, `.compute` | A mod on the grid (`client.exec.mod*`) |
|
|
32
|
+
| `PlayerCodeBroker` / `startGridMod` without `engine` (a legacy CLIENT module: unmetered, with the whole client catalog), `ALLOWED_HOST_CALLS` | A CLIENT half, the only kind of player module: `artifactHash`, `fuelPerDispatch` and `consentedHostCalls` are required, the allowlist is `EXEC_CLIENT_HOST_CALLS`, and the module must carry the `ck_fuel` meter |
|
|
33
|
+
| `MODEL_LINT_QUERY`, `modelLintDiagnostics`, `CrowdyModelLintLog`, the `'model-lint'` diagnostic source | The Rust compiler's diagnostics from the build |
|
|
34
|
+
|
|
35
|
+
- **The player runtime runs CLIENT halves only.** `PlayerCodeBroker`'s `artifactHash` (the
|
|
36
|
+
served `digest`), `fuelPerDispatch` and `consentedHostCalls` are required, and `engine` is
|
|
37
|
+
`'ck-exec'` or absent; a broker without them, or asked for another engine, does not start.
|
|
38
|
+
The glue offers exactly `EXEC_CLIENT_ABI_IMPORTS` and refuses a module without the `ck_fuel`
|
|
39
|
+
meter; its inert wasi stubs and the `wasi_unstable` alias are gone. `ALLOWED_HOST_CALLS` is
|
|
40
|
+
gone, and `GLUE_HOST_FUNCTIONS` names the CLIENT allowlist. `startGridMod`'s wasm spec needs
|
|
41
|
+
the same three values.
|
|
42
|
+
- **CLIENT host calls the legacy engines answered are refused** by the broker as not allowed:
|
|
43
|
+
the Game Model group (`container_*`, `containers_list`, `property_set`, `edge_*`,
|
|
44
|
+
`model_invoke`), `sessions_list`, and `grid_state_get` / `grid_state_set`. A mod's server
|
|
45
|
+
half, a hub keyed by the grid, holds grid state now. `createGridHostCalls` / `startGridMod`
|
|
46
|
+
lost `allowModelInvoke` and the client's `gameModel`.
|
|
47
|
+
- **What a CLIENT half says and answers, on the page** (new):
|
|
48
|
+
- `onLog`: its `crowdy::log` lines (crowdy-client-sdk levels 0 debug, 1 info, 2 warn,
|
|
49
|
+
3 error), at most `PLAYER_CODE_LOG_LINES_PER_SECOND` (20) a second and
|
|
50
|
+
`PLAYER_CODE_LOG_MAX_CHARS` (1,000) characters each, then a `warn` counting what was
|
|
51
|
+
dropped. On `PlayerCodeBroker`, `ExecClientHalves` (with the mod) and `startGridMod`. The
|
|
52
|
+
text is the mod author's: render it as text. Crowdy Studio shows its preview's lines in
|
|
53
|
+
Logs.
|
|
54
|
+
- `invoke(payload)`: the module's `handle_invoke` export, called by the page:
|
|
55
|
+
`PlayerCodeBroker.invoke`, `ExecClientHalves.invoke(modId, payload)` and
|
|
56
|
+
`RunningGridMod.invoke`, up to `PLAYER_CODE_INVOKE_MAX_BYTES` (256 KiB) each way. The reply
|
|
57
|
+
is the module's: treat it as untrusted input.
|
|
58
|
+
- `createGridHostCalls` answers `avatar_state_get` and `grid_permission_check` as the host
|
|
59
|
+
catalog scopes them: an avatar whose live actor the game places inside the grid
|
|
60
|
+
(`local.avatarChunk`, then the public `avatarAppState`), and the visiting player
|
|
61
|
+
(`userId`) on this grid, from the permission keys the game knows
|
|
62
|
+
(`local.gridPermissionKeys`). Without those they are refused as not offered, as
|
|
63
|
+
`actors_list` is without `local.actorsInChunk`.
|
|
64
|
+
- **Crowdy Studio runs on ck-exec only.** Drop `serverEngine` from the embed, the controller
|
|
65
|
+
and `mountCrowdyStudio`, and `playerCompute` from the embed's services and the controller's
|
|
66
|
+
and `mountCrowdyStudio`'s options (`CrowdyStudioPlayerCompute` is gone); they require
|
|
67
|
+
`mods: client.exec`, and the embed requires `client.exec`. `CrowdyStudioState` loses
|
|
68
|
+
`serverEngine`, `runs` (the Runs panel went) and `usage` (`CrowdyStudioUsageSnapshot`:
|
|
69
|
+
nothing on ck-exec spends player compute quota, and the `'usage'` surface reads the
|
|
70
|
+
wallet); `logs` are `CrowdyStudioLogLine`s (`id`, `source` `'mod' | 'preview'`,
|
|
71
|
+
`moduleName`, `level`, `at`, `text`); `CrowdyStudioInvokeResult` is
|
|
72
|
+
`{ resultJson, durationUs }`. `createCrowdyStudioStarterProject` needs `modStarter` for a
|
|
73
|
+
kind with a SERVER target and has no `engine`: a CLIENT target is a `crowdy-client-sdk`
|
|
74
|
+
CLIENT half. The pairing control went: a mod has no pairing.
|
|
75
|
+
- A CLIENT crate still on `crowdy-compute-sdk` is refused before any build, with what to
|
|
76
|
+
change: `crowdy-client-sdk = "0.1.0"` in `Cargo.toml` and `crowdy_client_sdk` in place of
|
|
77
|
+
`crowdy_compute_sdk` in `src/`. Its host calls are the same less the Game Model, sessions and
|
|
78
|
+
grid state (`grid_state_get` / `grid_state_set`).
|
|
79
|
+
- `ENGINE_SWITCHED_OFF` left `CrowdyFaultCode`: nothing raises it now.
|
|
80
|
+
- The kit's type-98 parser is `parseZoneChangeEvent` beside the other wire parsers.
|
|
81
|
+
|
|
82
|
+
`schema.gql` and the generated types follow the game API: the release carries cks-game-api
|
|
83
|
+
`dev`'s SDL after #417 merged (`npm run schema:sync:paths -- --schema <that schema.gql>`, then
|
|
84
|
+
`npm run codegen`).
|
|
85
|
+
|
|
86
|
+
# 17.14.0 ck-exec CLIENT halves
|
|
87
|
+
|
|
88
|
+
Dev-tier preview (cks-game-api #422, P3 W1). **The release needs a game API that has #422:**
|
|
89
|
+
the build and listing documents now select `ExecBuild.kind`, the artifacts' capability fields
|
|
90
|
+
and the listings' `client*` fields, which an older API refuses as a validation error. Deploy
|
|
91
|
+
the API first.
|
|
92
|
+
|
|
93
|
+
A mod can carry a **CLIENT half**: browser WASM from one `crowdy-client-sdk` crate, built on
|
|
94
|
+
the platform, attached to the mod and served by its grid to visitors who consent to it or
|
|
95
|
+
trust its author. It replaces the legacy grid-attached client mods, which keep working until
|
|
96
|
+
18.0.
|
|
97
|
+
|
|
98
|
+
- **`client.exec`**: `modClientBuild(appId, crate)` (a build of `kind` `client`; poll it with
|
|
99
|
+
`modBuildStatus` / `waitForModBuild`), `modClientDeploy(appId, gridId, name, buildId)` →
|
|
100
|
+
`ExecModClient`, `modClientDelete(appId, gridId, name)`, `gridClientMods(appId, gridId)` →
|
|
101
|
+
`ExecGridClientMod[]` (with `capabilitySummary` and `authorCapabilitySummary` parsed beside
|
|
102
|
+
the JSON), `consentClientMod(appId, modId, capabilityHash)`, `trustAuthor(appId, gridId,
|
|
103
|
+
authorId, capabilityHash)`, `modClientArtifact(appId, modId)` and
|
|
104
|
+
`modClientArtifactBytes(appId, modId)`, which decodes the module, recomputes its SHA-256 and
|
|
105
|
+
refuses bytes that differ from `digest` (or a CLIENT ABI other than
|
|
106
|
+
`EXEC_CLIENT_ABI_VERSION`, 0, or a capability summary that does not parse) with a
|
|
107
|
+
`CrowdyProtocolError`. Errors are the API's: a stale
|
|
108
|
+
hash is `CONFLICT`, every artifact refusal `NOT_FOUND`, more than 12 fetches a minute per
|
|
109
|
+
player and mod `RATE_LIMITED`.
|
|
110
|
+
- **Types**: `ExecBuild.kind`; `ExecBuildArtifact` (`capabilitySummaryJson`,
|
|
111
|
+
`capabilitySummary`, `capabilityHash`, `tickIntervalMs`, null for a ck-exec module);
|
|
112
|
+
`ExecModListing.clientDigest`, `clientCapabilitySummaryJson`, `clientCapabilitySummary`,
|
|
113
|
+
`clientCapabilityHash`, `clientTickIntervalMs`; `ExecClientCapabilitySummary`,
|
|
114
|
+
`ExecModClient`, `ExecGridClientMod`, `ExecModClientArtifact`, `ExecModClientArtifactBytes`.
|
|
115
|
+
- **`ExecClientHalves`**, the exec twin of the-construct's `runConsentedGridMod` and
|
|
116
|
+
`ClientModLifecycle`: tell it the grid (`enterGrid`) and `refresh()` on a cadence. It lists
|
|
117
|
+
the grid's CLIENT halves, stops the ones removed or changed (keyed by `modId`, `digest`,
|
|
118
|
+
`capabilityHash` and tick interval), asks the player once per author (`trustAuthor`) or per
|
|
119
|
+
CLIENT half (`ask: 'mod'`, `consentClientMod`) through your `confirm`, fetches and caches by
|
|
120
|
+
digest, and runs each in a `PlayerCodeBroker` with its fuel budget and tick interval.
|
|
121
|
+
`NOT_FOUND` holds a CLIENT half back 15 s, `RATE_LIMITED` 60 s, refused bytes and a tripped
|
|
122
|
+
circuit 60 s.
|
|
123
|
+
- **`PlayerCodeBroker({ engine: 'ck-exec' })`**: the allowlist is `EXEC_CLIENT_HOST_CALLS`,
|
|
124
|
+
exactly what crowdy-client-sdk calls (the client catalog less the Game Model group,
|
|
125
|
+
`sessions_list` and `grid_state_*`); the glue offers exactly `EXEC_CLIENT_ABI_IMPORTS`
|
|
126
|
+
(`ck::{log,now_ms,state_get,state_set,host_call}`, `wasi_snapshot_preview1::random_get`),
|
|
127
|
+
refuses a module without the `ck_fuel` meter, and the broker will not start without
|
|
128
|
+
`artifactHash`, `fuelPerDispatch` and `consentedHostCalls` (the served capability summary's
|
|
129
|
+
`hostFunctions`). A call outside that summary is refused too: the build derives the summary by
|
|
130
|
+
scanning the module for host-call names, so a name assembled at run time would otherwise reach
|
|
131
|
+
calls the player never consented to. The default, `'player-compute'`, is unchanged for legacy
|
|
132
|
+
CLIENT modules. `startGridMod`'s wasm spec takes `engine` and `consentedHostCalls` too.
|
|
133
|
+
- **Crowdy Studio's CLIENT target runs on ck-exec** with `serverEngine: 'ck-exec'` (the
|
|
134
|
+
default when `exec` is present). A new CLIENT target starts from a `crowdy-client-sdk` crate
|
|
135
|
+
(`createCrowdyStudioStarterProject({ engine: 'ck-exec' })`); Test draft and Deploy live
|
|
136
|
+
build it with `modClientBuild`, attach it to the project's mod with `modClientDeploy`,
|
|
137
|
+
consent to it as its author and preview the served module with `engine: 'ck-exec'`. A
|
|
138
|
+
CLIENT-only project's CLIENT half rides the mod named for its CLIENT module (which must be a
|
|
139
|
+
mod name now): with no such mod of the player's on the grid, Studio deploys the mod starter's
|
|
140
|
+
server half under it first and says so in the build log, switches it on, and Stop switches
|
|
141
|
+
it off. The preview loads only for a player with `run_client_code` standing in the grid. On
|
|
142
|
+
ck-exec no target reads player compute usage, and the pairing select is disabled.
|
|
143
|
+
- **`CrowdyStudioMods` gained `myMods`, `modClientBuild`, `modClientDeploy`,
|
|
144
|
+
`consentClientMod` and `modClientArtifactBytes`.** Pass `client.exec`; a hand-written
|
|
145
|
+
stand-in needs those too.
|
|
146
|
+
- **Superseded** (`@deprecated`, removed in 18.0): `marketplace.gridClientMods`,
|
|
147
|
+
`consentGridClientMod`, `trustGridAuthor`, `clientArtifact`, `clientArtifactBytes`, and
|
|
148
|
+
`GridScope.compute.clientMods`.
|
|
149
|
+
|
|
150
|
+
Existing CLIENT projects keep their files: a CLIENT crate on `crowdy-compute-sdk` is refused on
|
|
151
|
+
ck-exec before any build, with what to change (the SDK line becomes
|
|
152
|
+
`crowdy-client-sdk = "0.1.0"`, `crowdy_compute_sdk` becomes `crowdy_client_sdk`; the host
|
|
153
|
+
calls are the same less the Game Model, sessions and grid state, `grid_state_get` /
|
|
154
|
+
`grid_state_set`, which a mod's server half holds now). `serverEngine: 'player-compute'` keeps
|
|
155
|
+
both targets on legacy player compute until 18.0.
|
|
156
|
+
|
|
157
|
+
**Studio's CLIENT target on ck-exec needs ck-api `v2.25.1` or later.** `v2.24.0` and
|
|
158
|
+
`v2.25.0` refuse to save a `crowdy-client-sdk` crate in a Studio project
|
|
159
|
+
(`CROWDY_STUDIO_MANIFEST_INVALID`, cks-game-api #425), so a CLIENT project cannot start there;
|
|
160
|
+
the SDK calls themselves need only `v2.24.0`.
|
|
161
|
+
|
|
1
162
|
# 17.13.0 ck-exec observability
|
|
2
163
|
|
|
3
164
|
Additive (dev-tier preview; ck-api `v2.22.0`).
|
|
@@ -37,7 +198,8 @@ Crowdy Studio's SERVER target moves to ck-exec mods, which 17.12.0 offered behin
|
|
|
37
198
|
package named for the project, instead of the legacy `crowdy-compute-sdk` crate; the
|
|
38
199
|
server module name fits a mod's (48 characters, starting with a letter) and a full-stack
|
|
39
200
|
project records pairing `NONE`, since a mod has no client pairing. The CLIENT crate is
|
|
40
|
-
unchanged. `createCrowdyStudioStarterProject` takes the
|
|
201
|
+
unchanged (17.14.0 moved it to ck-exec). `createCrowdyStudioStarterProject` takes the
|
|
202
|
+
starter as `modStarter`.
|
|
41
203
|
- **Invoke, Logs, Runs and the budget line follow the engine.** On ck-exec, Invoke calls the
|
|
42
204
|
mod's endpoint (default `state`, JSON arguments sent as MessagePack) over one exec
|
|
43
205
|
connection, and the result is the decoded reply as JSON; Logs are the mod's `ctx.log`
|
package/README.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
The official browser-first TypeScript SDK for **Crowded Kingdoms**. CrowdyJS
|
|
4
4
|
gives you typed clients for the whole platform: identity and
|
|
5
|
-
studio administration (the Management surface), world data
|
|
6
|
-
|
|
7
|
-
one unified GraphQL API.
|
|
5
|
+
studio administration (the Management surface), world data (the Game surface),
|
|
6
|
+
the UDP proxy realtime stream, and ck-exec, where an app's server code runs —
|
|
7
|
+
all behind one unified GraphQL API.
|
|
8
8
|
|
|
9
9
|
Authentication follows a two-token model: an identity **session token** for
|
|
10
10
|
account and admin operations, and short-lived **app-scoped tokens** for
|
|
@@ -225,23 +225,19 @@ never told about, so a native refresh without it is a re-placement.
|
|
|
225
225
|
| `client.platform` | Public platform configuration (`config()`). |
|
|
226
226
|
| `client.serverStatus` | `gameClientBootstrap(appId)` — per-app version info, UDP status, spatial limits. |
|
|
227
227
|
| `client.chunks`, `client.voxels`, `client.actors`, `client.avatars`, `client.state` | World data reads + writes: terrain/LODs, voxel edit + history/rollback, durable actors, avatars, per-user app state blobs. |
|
|
228
|
-
| `client.host` | Game-host election (`get`, `amIHost`) + actor liveness `heartbeat`. `amIHost` is UI convenience only —
|
|
228
|
+
| `client.host` | Game-host election (`get`, `amIHost`) + actor liveness `heartbeat`. `amIHost` is UI convenience only — a hub decides host-only actions from its caller. |
|
|
229
229
|
| `client.teleport` | Teleport requests. |
|
|
230
230
|
| `client.channels`, `client.teams` | Messaging channels and app-scoped player teams (membership + roles). |
|
|
231
|
-
| `client.
|
|
232
|
-
| `client.
|
|
233
|
-
| `client.
|
|
234
|
-
| `client.playerCompute` | Player-authored SERVER/CLIENT Rust/WASM bound to player-owned grids: deploy source, activate/deactivate, list modules/versions, delete self-authored modules. |
|
|
235
|
-
| `client.playerModel` | Player-owned flexible model containers and grid-confined automations (`containers`, `createContainer`, `setProperty`, `automations`, `createAutomation`, …). |
|
|
236
|
-
| `client.playerWallet` | Player spend: balance, spend caps, card setup, policy, charges. |
|
|
237
|
-
| `client.marketplace` | Player-code store/install/consent flows plus player-authorized grid claims (`claimGridOwnership`, `claimGridChunk`, `releaseClaimedGrid`) and client-mod artifact fetches. |
|
|
231
|
+
| `client.exec` | **ck-exec (dev-tier preview):** an app's server code as hubs and spokes. `connect(appId, { nodeType, key })` opens a player's connection to an execution host; the `ExecConnection` it returns has `call`, `callRaw`, `subscribe`, `ping`, `onReconnect` and `close`, with MessagePack payloads, and it reconnects and renews subscriptions by itself. `starters` / `build` / `deploy` build and deploy an app (`manage_compute`); `logs`, `instances`, `versions`, `activateVersion` and `setEnabled` operate it; `mod*` are players' mods on grids they own, and `modClient*`, `gridClientMods`, `consentClientMod` and `trustAuthor` their CLIENT halves. See [ck-exec](#ck-exec-dev-tier-preview). |
|
|
232
|
+
| `client.playerWallet` | Player spend: balance, ledger, hourly charges, spend caps, card setup, auto-recharge. A ck-exec mod's compute is billed here, to its owner. |
|
|
233
|
+
| `client.marketplace` | Player-authorized grid claims (`claimGridOwnership`, `claimGridChunk`, `releaseClaimedGrid`, requests and invites) and studio moderation of player code (admission queue, listing administration, claim policy). Mods publish and install through `client.exec`. |
|
|
238
234
|
| `client.crowdyStudio` | Cloud project, personal-library, and common-file APIs for Crowdy Studio: target-scoped files, metadata/module names, optimistic revisions, copy-by-value imports, atomic saves. |
|
|
239
235
|
| `client.crowdyStudioGitHub` | Optional GitHub repository for a Crowdy Studio project: status, `bind` (push the project in, or take the repository), `unbind`, `refresh`, `layout`, `tree`, `getFile`, commit-guarded `putFile` / `deleteFile`. While bound the repository is the working tree and every Studio save commits; the project's `files` are the server's mirror at `github.sha`. Never required. |
|
|
240
236
|
| `client.udp` | UDP proxy subscriptions + spatial mutations (`sendActorUpdate`, `sendVoxelUpdate`, `sendAudioPacket`, `sendVideoPacket` / `sendVideoFrame`, `sendTextPacket`, `sendClientEvent`, `sendSingleActorMessage`, `sendChannelMessage`). |
|
|
241
237
|
| `client.realtime` | Connection status, manual `connect()` / `disconnect()`, `onStatus()` listener. |
|
|
242
238
|
| `client.refreshGameplayToken()` | Safely rotates an active game client's app token (see [Token refresh](#token-refresh-during-gameplay)). |
|
|
243
239
|
| `client.world(appId)` | Higher-level helpers for browser games (`actor.join`, `actor.sendState`, `actor.sendText`, `actor.sendToActor`). |
|
|
244
|
-
| `client.kit(appId)` | Game Kit:
|
|
240
|
+
| `client.kit(appId)` | Game Kit: parties, guilds and chat over teams and channels (`kit.social`) — see [Game Kit](#game-kit). |
|
|
245
241
|
| `createWorldSession(client, appId, config)` | World Stores: opt-in, SDK-managed game state from the `@crowdedkingdoms/crowdyjs/stores` subpath — see [World Stores](#world-stores). |
|
|
246
242
|
|
|
247
243
|
**Studio-admin surface** (privileged; drive with a server-side / studio token,
|
|
@@ -251,7 +247,7 @@ grouped under `client.admin` and mirrored at the top level):
|
|
|
251
247
|
|---|---|
|
|
252
248
|
| `client.organizations` | Orgs, members, RBAC roles, org API tokens. |
|
|
253
249
|
| `client.apps` | App registry, discovery + routing (`create`, `routeFor`, `marketplace`), visibility, and player-code admission mode / allow-list administration. |
|
|
254
|
-
| `client.appAccess` | Access tiers + per-user grants. |
|
|
250
|
+
| `client.appAccess` | Access tiers + per-user grants, and the feature keys a tier grants (`defineFeature`, `grantTierFeature`, `tierFeatures`, …), which a hub checks with the node API's `players.features`. |
|
|
255
251
|
| `client.billing` | Org wallet + per-app spend budgets. |
|
|
256
252
|
| `client.payments` | Payment checkouts (wallet top-ups, plan purchases). |
|
|
257
253
|
| `client.quotas` | Usage quotas at the org/app scope. |
|
|
@@ -259,15 +255,13 @@ grouped under `client.admin` and mirrored at the top level):
|
|
|
259
255
|
| `client.sharedEnvironment` | Publish to shared, runtime gating, spend caps, auto-billing. |
|
|
260
256
|
| `client.gameApps` | App grids (`createGrid` / `deleteGrid`), first-class grid ownership (`ownership` / `assignOwnership` / `transferOwnership`), and grid runtime-permission administration. |
|
|
261
257
|
|
|
262
|
-
|
|
258
|
+
There is no operator surface: `client.operator` held only the legacy compute ceilings and
|
|
259
|
+
went with them in 18.0.0 (ck-exec code is bounded by its manifest limits within the
|
|
260
|
+
platform's), and infrastructure operations live in the separate infra-control-plane service.
|
|
263
261
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
Auth, user reads and the studio-admin / operator surfaces use the **identity
|
|
269
|
-
session token**; the world/UDP surfaces require an **app-scoped token** for that
|
|
270
|
-
app. Both go to the same endpoint.
|
|
262
|
+
Auth, user reads and the studio-admin surface use the **identity session token**; the
|
|
263
|
+
world/UDP surfaces require an **app-scoped token** for that app. Both go to the same
|
|
264
|
+
endpoint.
|
|
271
265
|
|
|
272
266
|
CrowdyJS wraps the full public API surface — every
|
|
273
267
|
non-deprecated public root field has a typed method, with Relay `*Connection`
|
|
@@ -485,16 +479,14 @@ pre-bound — convenient for browser games. Advanced callers can always use
|
|
|
485
479
|
|
|
486
480
|
## Grids: player code inside one grid
|
|
487
481
|
|
|
488
|
-
A grid is a box of chunks a player can own.
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
bus, sessions hosted in it, and the player-tier Game Model.
|
|
482
|
+
A grid is a box of chunks a player can own. Code running in a grid is confined
|
|
483
|
+
to it: spatial messages that originate in it, the grid's own channels, and a
|
|
484
|
+
grid event bus. Its server side is a ck-exec mod (`client.exec.mod*`).
|
|
492
485
|
|
|
493
486
|
```ts
|
|
494
487
|
const plot = client.grid(appId, gridId);
|
|
495
488
|
await plot.mintToken(); // learns the box; a grid-scoped token
|
|
496
489
|
await plot.channels.create('plot-chat'); // a grid channel (owner only)
|
|
497
|
-
await plot.sessions.create({ name: 'race' }); // a game within the game
|
|
498
490
|
await plot.send.text({ chunk: { x: 4, y: 0, z: 0 }, uuid, text: 'hi', distance: 2 });
|
|
499
491
|
plot.send.text({ chunk: { x: 9, y: 0, z: 0 }, uuid, text: 'x' }); // throws GridScopeError
|
|
500
492
|
```
|
|
@@ -512,9 +504,17 @@ import { hostGridProgram } from '@crowdedkingdoms/crowdyjs/grid-program';
|
|
|
512
504
|
await hostGridProgram({ port, scope: client.grid(appId, gridId), graphqlUrl, graphqlWsUrl });
|
|
513
505
|
```
|
|
514
506
|
|
|
515
|
-
`startGridMod` runs either a
|
|
516
|
-
behind one interface
|
|
517
|
-
|
|
507
|
+
`startGridMod` runs either a mod's CLIENT half (WASM) or a JS grid program
|
|
508
|
+
behind one interface, and `ExecClientHalves` runs a whole grid's CLIENT halves
|
|
509
|
+
(see [A mod's CLIENT half](#a-mods-client-half)). `createGridHostCalls` answers
|
|
510
|
+
a CLIENT half's host calls through CrowdyJS confined to the grid. The ones only
|
|
511
|
+
the game can answer need its knowledge: `local.actorsInChunk` for
|
|
512
|
+
`actors_list*`, `local.avatarChunk` (where an avatar's live actor is) for
|
|
513
|
+
`avatar_state_get`, `local.gridPermissionKeys` with the visiting player's
|
|
514
|
+
`userId` for `grid_permission_check`, and `local.drainPointerClicks` for
|
|
515
|
+
`pointer_clicks`; without its hook such a call is refused as not offered. The
|
|
516
|
+
Game Model, sessions and grid state calls went with the legacy engines in
|
|
517
|
+
18.0.0: the broker refuses them.
|
|
518
518
|
|
|
519
519
|
## World Stores
|
|
520
520
|
|
|
@@ -571,8 +571,8 @@ The available stores are `self` (your actor + send loop), `actors` (remote
|
|
|
571
571
|
actor registry with lanes/history/staleness), `errors` (attributed send
|
|
572
572
|
errors), `chunks` (chunk/voxel cache with realtime merge + worldgen
|
|
573
573
|
write-back), `channelInbox` / `actorInbox` (message inboxes), `events` (typed
|
|
574
|
-
event router), `host` (host tracking), `save` / `avatar` (typed durable
|
|
575
|
-
state)
|
|
574
|
+
event router), `host` (host tracking), and `save` / `avatar` (typed durable
|
|
575
|
+
state).
|
|
576
576
|
|
|
577
577
|
Every store is **opt-in twice over**: only configured stores are constructed
|
|
578
578
|
(and only they exist on the session's TYPE — `session.host` without
|
|
@@ -586,101 +586,25 @@ keep timer-driven sends at full rate while hidden. See the
|
|
|
586
586
|
|
|
587
587
|
## Game Kit
|
|
588
588
|
|
|
589
|
-
`client.kit(appId)`
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
runtime helpers. Everything composes `client.gameModel` — no new server
|
|
593
|
-
surface.
|
|
589
|
+
`client.kit(appId).social` gives parties, guilds and chat rooms in familiar
|
|
590
|
+
words over teams (membership and roles) and channels (messaging), with
|
|
591
|
+
realtime delivery on the UDP notification subscription:
|
|
594
592
|
|
|
595
593
|
```ts
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
inventoryBlueprint(),
|
|
601
|
-
lockBlueprint({ objectTypeName: 'Door', authority: { kind: 'key' } }),
|
|
602
|
-
npcBlueprint({
|
|
603
|
-
behaviors: [{
|
|
604
|
-
name: 'npc-wander',
|
|
605
|
-
role: 'wanderer',
|
|
606
|
-
trigger: { intervalMs: 60000 },
|
|
607
|
-
mutations: [
|
|
608
|
-
{ target: 'self', property: 'x', expression: 'self.x + rand_int(-2, 2)' },
|
|
609
|
-
{ target: 'self', property: 'z', expression: 'self.z + rand_int(-2, 2)' },
|
|
610
|
-
],
|
|
611
|
-
}],
|
|
612
|
-
}),
|
|
613
|
-
]);
|
|
614
|
-
|
|
615
|
-
// Game client (player token):
|
|
616
|
-
const kit = game.kit(appId);
|
|
617
|
-
const bag = await kit.inventory.ensure(me.userId);
|
|
618
|
-
const result = await kit.objects.open(doorId, { keyId });
|
|
619
|
-
if (!result.success) console.warn('locked:', result.errorMessage);
|
|
594
|
+
const kit = game.kit(appId, { social: { actorUuid: me.uuid } });
|
|
595
|
+
const party = await kit.social.party.create('raid'); // team + paired channel
|
|
596
|
+
const room = await kit.social.chat.room('lobby');
|
|
597
|
+
kit.social.chat.onMessage(room.groupId, (m) => log(m.senderUuid, m.text));
|
|
620
598
|
```
|
|
621
599
|
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
]);
|
|
631
|
-
|
|
632
|
-
// Game client: buying spends gold AND grants enforced grid access atomically.
|
|
633
|
-
const buy = await kit.plots.buy(plotId, walletId);
|
|
634
|
-
if (buy.success) await kit.objects.open(doorId); // has_chunk_permission passes now
|
|
635
|
-
```
|
|
636
|
-
|
|
637
|
-
NPC blueprints can target by permissions too — e.g. a guard automation whose
|
|
638
|
-
selector has `candidatePermissionWhere: [{ userFrom: { property: 'owner_user_id' },
|
|
639
|
-
op: 'lacks', key: 'access', grid: { property: 'grid_id' } }]` reacts only to
|
|
640
|
-
intruders.
|
|
641
|
-
|
|
642
|
-
The kit covers the common genre staples end to end — each layer is a blueprint
|
|
643
|
-
builder plus a typed runtime helper:
|
|
644
|
-
|
|
645
|
-
| Layer | Builder → helper | Highlights |
|
|
646
|
-
| --- | --- | --- |
|
|
647
|
-
| Inventory | `inventoryBlueprint` → `kit.inventory` | bags/stacks, grant/consume/transfer, craft, barter |
|
|
648
|
-
| Objects | `lockBlueprint` → `kit.objects` | lockable doors/chests with key or permission authority |
|
|
649
|
-
| NPCs | `npcBlueprint` → `kit.npcs` | automation-driven NPC instances (spawn, runNow, enable) |
|
|
650
|
-
| Plots | `plotBlueprint` → `kit.plots` | buy/rent land with transactional, replication-enforced grid grants |
|
|
651
|
-
| Economy | `economyBlueprint` → `kit.economy` | multi-currency wallets, atomic shop buys, escrow trades, player market, escrowed order book (`kit.economy.orderBook`) |
|
|
652
|
-
| Progression | `progressionBlueprint` → `kit.progression` | xp/levels via the `fn:` curve helper, skill prerequisite chains, achievements, host-gated rating |
|
|
653
|
-
| Loot | `lootBlueprint` → `kit.loot` | weighted tables unrolled into seed-driven expressions, atomic single-claim, event-triggered drops |
|
|
654
|
-
| Quests | `questsBlueprint` → `kit.quests` | event-automation progress, atomic claim into stack+wallet, cron daily resets, tutorial sequencing |
|
|
655
|
-
| Combat | `combatBlueprint` → `kit.combat` | server-side damage/death, status-effect tick automation, `turnBased`/`hostSynced`, routed attacks |
|
|
656
|
-
| Matches | `matchesBlueprint` → `kit.matches` | session lobbies/rounds/turns/scores, per-match channel + `onMatchChanged` (notify-to-pull) |
|
|
657
|
-
| Decks | `decksBlueprint` → `kit.decks` | hidden hands via owner-visibility `card_id`, shuffle-by-position automation |
|
|
658
|
-
| World sim | `worldsimBlueprint` → `kit.worldsim` | day/night clock with spatial notify, node regen + atomic gather, crops, wave counters, forecasts |
|
|
659
|
-
| Social | `guildBlueprint` → `kit.social` | parties/guilds/chat over teams+channels, grid territory grants, guild hall + bank composite |
|
|
660
|
-
| Leaderboards | `leaderboardsBlueprint` → `kit.leaderboards` | trusted keep-best submits, client-side ranking, cron seasons |
|
|
661
|
-
| Live ops | `liveopsBlueprint` → `kit.liveops` | timed event windows and seasons |
|
|
662
|
-
| Moderation | `moderationBlueprint` → `kit.moderation` | reports, queues, mutes |
|
|
663
|
-
| Telemetry | `telemetryBlueprint` → `kit.telemetry` | counters and lightweight event tracking |
|
|
664
|
-
| Monetization | `featureGate` → `kit.features` | feature keys, tier grants, `*policyExtra` gating on builders |
|
|
665
|
-
| Abilities | — → `kit.abilities` | ability definitions, casts, loadouts |
|
|
666
|
-
| Movement | — → `kit.movement` | movement warden configs + violation parsing |
|
|
667
|
-
| Territory | — → `kit.territory` | control points, factions, enrollment |
|
|
668
|
-
| Racing | — → `kit.racing` | courses, entries, possession (claim/pass/shoot) |
|
|
669
|
-
|
|
670
|
-
Engine-aware layers talk to compute-module game engines when they are
|
|
671
|
-
deployed, and degrade gracefully on model-only apps via capability detection
|
|
672
|
-
(`kit.engines`): `kit.mobs` (refereed attacks, defs/slots, contact-damage
|
|
673
|
-
parsing), `kit.pets` (adopt/summon/dismiss/rename), `kit.instances` (private
|
|
674
|
-
world slices, seeded runs), `kit.director` (encounter runs),
|
|
675
|
-
`kit.matchmaking` (queues/proposals/rating), `kit.minigames` (invoke-loop
|
|
676
|
-
wrapper), plus engine paths on `kit.matches` / `kit.decks` /
|
|
677
|
-
`kit.leaderboards` and the `kit/wire` pose codec + event parsers. Deploy
|
|
678
|
-
engines alongside blueprints with `kit.deploy(blueprints, { engines })`.
|
|
679
|
-
|
|
680
|
-
See the docs guides [Modeling game concepts](https://docs.crowdedkingdoms.com/game-api/modeling-game-concepts)
|
|
681
|
-
(the underlying model + genre map) and [Game Kit](https://docs.crowdedkingdoms.com/crowdyjs/game-kit)
|
|
682
|
-
(the SDK surface + the simulation-tier / notify-to-pull / timer / hidden-info
|
|
683
|
-
/ anti-cheat patterns).
|
|
600
|
+
Game rules and state are ck-exec hubs (`client.exec`, below). Two kit pieces
|
|
601
|
+
stand alone: the wire codecs (`encodeEnginePose` / `decodeEnginePose`, the
|
|
602
|
+
48-byte engine pose, `engineLanes`, and `parseEngineEvent` with the typed
|
|
603
|
+
parsers for server events 77 and 90-98) for games whose hubs keep that wire,
|
|
604
|
+
and `runOptimisticAction`, which applies an action locally, asks a referee
|
|
605
|
+
(a hub endpoint, say) and rolls back on a denial. The blueprints,
|
|
606
|
+
`kit.deploy`, the engines and the model-backed helpers went with the game
|
|
607
|
+
model in 18.0.0; see [MIGRATION.md](MIGRATION.md).
|
|
684
608
|
|
|
685
609
|
## ck-exec (dev-tier preview)
|
|
686
610
|
|
|
@@ -735,6 +659,65 @@ Integers above 2^53 decode as `number` and lose precision unless you pass
|
|
|
735
659
|
`{ decode: { useBigInt64: true } }`. The wire format is in the
|
|
736
660
|
[ck-exec docs](https://docs.dev.crowdedkingdoms.com/exec/intro).
|
|
737
661
|
|
|
662
|
+
### A mod's CLIENT half
|
|
663
|
+
|
|
664
|
+
A mod (a player's code on a grid they own: `modBuild`, `modDeploy`) can carry a **CLIENT
|
|
665
|
+
half** (17.14.0): browser WASM from one `crowdy-client-sdk` crate, which the mod's grid serves
|
|
666
|
+
to visitors who consent to it or trust its author. It runs in the visitor's
|
|
667
|
+
`PlayerCodeBroker`, in a worker with no DOM, token or network, and it is the only kind of
|
|
668
|
+
player module the broker runs since 18.0.0.
|
|
669
|
+
|
|
670
|
+
```ts
|
|
671
|
+
// The mod's owner builds one crowdy-client-sdk crate and attaches it to the mod.
|
|
672
|
+
const queued = await client.exec.modClientBuild(appId, { name: 'hud', files }); // kind 'client'
|
|
673
|
+
const built = await client.exec.waitForModBuild(appId, queued.buildId);
|
|
674
|
+
const half = await client.exec.modClientDeploy(appId, gridId, 'shop', built.buildId);
|
|
675
|
+
```
|
|
676
|
+
|
|
677
|
+
A visitor's page lists what the grid serves (`gridClientMods`: each CLIENT half's capability
|
|
678
|
+
summary and hash, its author's union and hash, and whether the player consented or trusts the
|
|
679
|
+
author), asks the player, consents (`consentClientMod(appId, modId, capabilityHash)`, or
|
|
680
|
+
`trustAuthor(appId, gridId, authorId, authorCapabilityHash)` once per author) and fetches the
|
|
681
|
+
module (`modClientArtifactBytes(appId, modId)`: its bytes checked against `digest`, its fuel
|
|
682
|
+
budget and tick interval). A stale hash is `CONFLICT`. The module is served only to a player
|
|
683
|
+
holding `run_client_code` who stands in the grid now, every refusal is `NOT_FOUND`, and a
|
|
684
|
+
player may fetch a mod's 12 times a minute, so cache it by `digest`. `ExecClientHalves` does
|
|
685
|
+
all of that:
|
|
686
|
+
|
|
687
|
+
```ts
|
|
688
|
+
import { ExecClientHalves } from '@crowdedkingdoms/crowdyjs';
|
|
689
|
+
|
|
690
|
+
const halves = new ExecClientHalves({
|
|
691
|
+
exec: client.exec,
|
|
692
|
+
appId,
|
|
693
|
+
workerUrl, // the platform glue worker, same origin
|
|
694
|
+
onHostCall: (call) => hostCalls(call), // e.g. createGridHostCalls({ scope, client })
|
|
695
|
+
onPresentation: (p, mod) => hud.set({ source: mod.modId, label: mod.name, payload: p.payload }),
|
|
696
|
+
onLog: (line, mod) => devConsole.append(mod.name, line.level, line.message), // text, never HTML
|
|
697
|
+
confirm: (prompt) => window.confirm(describe(prompt)), // once per author; ask: 'mod' for each
|
|
698
|
+
onStopped: (mod) => hud.remove(mod.modId),
|
|
699
|
+
});
|
|
700
|
+
halves.enterGrid({ gridId, low, high }); // the grid the player stands in; null to leave
|
|
701
|
+
setInterval(() => void halves.refresh().catch(console.warn), 10_000);
|
|
702
|
+
|
|
703
|
+
// The page calls a running CLIENT half's handle_invoke; the reply is the module's bytes.
|
|
704
|
+
const reply = await halves.invoke(modId, new TextEncoder().encode('{"ask":"score"}'));
|
|
705
|
+
```
|
|
706
|
+
|
|
707
|
+
Each refresh stops the CLIENT halves whose mod is gone or whose digest, capability hash or
|
|
708
|
+
tick interval changed, asks about the rest, and starts the consented ones in a broker. The
|
|
709
|
+
broker allows at most the host calls crowdy-client-sdk makes (`EXEC_CLIENT_HOST_CALLS`: no Game
|
|
710
|
+
Model, sessions or `grid_state_*`), offers exactly the CLIENT ABI imports
|
|
711
|
+
(`EXEC_CLIENT_ABI_IMPORTS`) and runs a module only with its digest, its fuel budget and
|
|
712
|
+
`consentedHostCalls`, the host calls of the summary the player consented to: a call outside them
|
|
713
|
+
is refused, even one whose name the module assembled at run time. A CLIENT half's
|
|
714
|
+
`crowdy::log` lines reach `onLog` at most 20 a second and 1,000 characters each (then a `warn`
|
|
715
|
+
counts what was dropped); `invoke` sends at most 256 KiB each way and is refused while the
|
|
716
|
+
module is not running. `NOT_FOUND` holds a CLIENT half back 15 s and `RATE_LIMITED` 60 s. The
|
|
717
|
+
grid's owner is asked about their own CLIENT halves like anyone; answer yes in `confirm` when
|
|
718
|
+
`prompt.authorId` is the player. See
|
|
719
|
+
[CLIENT halves](https://docs.dev.crowdedkingdoms.com/exec/client-halves).
|
|
720
|
+
|
|
738
721
|
## Hosting a game on Crowdy Games
|
|
739
722
|
|
|
740
723
|
Since 17.2.0 (ck-api v2.1) a developer can publish a built static bundle to the
|
|
@@ -773,28 +756,32 @@ Crowdy Studio is the in-game SERVER/CLIENT Rust authoring surface for player
|
|
|
773
756
|
code: cloud projects with target-scoped files, optimistic-concurrency
|
|
774
757
|
autosave, draft/live/stop orchestration, and a Monaco editor backed by a local
|
|
775
758
|
Rust language worker. The worker receives source files and the embedded
|
|
776
|
-
platform index
|
|
777
|
-
|
|
778
|
-
on the page, allow-lists host calls
|
|
779
|
-
to the
|
|
780
|
-
|
|
781
|
-
|
|
759
|
+
platform index (the `ckx-sdk` and `crowdy-client-sdk` symbols) only — never a
|
|
760
|
+
credential and never a server connection. A CLIENT half runs through
|
|
761
|
+
`PlayerCodeBroker`, which keeps tokens on the page, allow-lists host calls
|
|
762
|
+
(narrowed to what the player consented to), and locally clamps chunk-targeted
|
|
763
|
+
effects to the owned grid before the normal SDK path reaches server
|
|
764
|
+
authorization. It takes what the platform served with the module, and ticks it
|
|
765
|
+
only when `tickIntervalMs` is set (omit or `0` is invoke-only):
|
|
782
766
|
|
|
783
767
|
```ts
|
|
784
768
|
import { PlayerCodeBroker } from '@crowdedkingdoms/crowdyjs';
|
|
785
769
|
|
|
770
|
+
const half = await client.exec.modClientArtifactBytes(appId, modId);
|
|
786
771
|
const broker = new PlayerCodeBroker({
|
|
787
772
|
workerUrl,
|
|
788
773
|
grid,
|
|
789
774
|
onHostCall,
|
|
790
|
-
|
|
775
|
+
moduleName: half.name,
|
|
776
|
+
artifactHash: half.digest,
|
|
777
|
+
fuelPerDispatch: half.fuelPerDispatch,
|
|
778
|
+
consentedHostCalls: half.capabilitySummary.hostFunctions,
|
|
779
|
+
tickIntervalMs: half.tickIntervalMs, // omit for invoke-only
|
|
780
|
+
onLog: (line) => console.log(`[${line.moduleName}] ${line.level}: ${line.message}`),
|
|
791
781
|
});
|
|
792
|
-
await broker.start(
|
|
782
|
+
await broker.start(half.bytes);
|
|
793
783
|
```
|
|
794
784
|
|
|
795
|
-
The Studio embed defaults `clientTickIntervalMs` to `1000` when you do not
|
|
796
|
-
pass one; a raw `PlayerCodeBroker` does not.
|
|
797
|
-
|
|
798
785
|
Most games embed the ready-made shell rather than hand-rolling window chrome
|
|
799
786
|
around `mountCrowdyStudio`:
|
|
800
787
|
|
|
@@ -805,7 +792,7 @@ import { createCrowdyStudioEmbed } from '@crowdedkingdoms/crowdyjs/crowdy-studio
|
|
|
805
792
|
import workerUrl from '@crowdedkingdoms/crowdyjs/player-glue-worker?worker&url';
|
|
806
793
|
|
|
807
794
|
const studio = createCrowdyStudioEmbed({
|
|
808
|
-
client: game, // CrowdyClient: crowdyStudio, exec,
|
|
795
|
+
client: game, // CrowdyClient: crowdyStudio, exec, playerWallet, crowdyStudioGitHub
|
|
809
796
|
appId,
|
|
810
797
|
gameName: 'My Game',
|
|
811
798
|
suppressGameplayInput: () => pauseInput(),
|
|
@@ -828,18 +815,27 @@ fullscreen modal on narrow screens. For custom chrome, call
|
|
|
828
815
|
`new CrowdyStudioController(options)`. New games should start SERVER-only.
|
|
829
816
|
Untrusted HUD payloads always render as text, never HTML.
|
|
830
817
|
|
|
831
|
-
**The SERVER target runs as a ck-exec mod.**
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
`
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
`
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
818
|
+
**The SERVER target runs as a ck-exec mod.** A new project's SERVER target starts from
|
|
819
|
+
the platform's mod starter (`client.exec.modStarter(appId)`, a `ckx-sdk` crate), Test draft
|
|
820
|
+
and Deploy live build it with `modBuild` and deploy it to the grid as the mod
|
|
821
|
+
`mod:<server module name>`, Invoke calls one of its endpoints (`state` by default) over an
|
|
822
|
+
exec connection, and Logs shows its `ctx.log` lines.
|
|
823
|
+
|
|
824
|
+
**The CLIENT target is that mod's CLIENT half** (17.14.0). A new CLIENT target starts from a
|
|
825
|
+
`crowdy-client-sdk` crate; Test draft and Deploy live build it with `modClientBuild`, attach
|
|
826
|
+
it to the project's mod with `modClientDeploy`, consent to it as its author (the API serves a
|
|
827
|
+
CLIENT half only to players who consented, its author too) and preview the served module in
|
|
828
|
+
the HUD layer; the preview's `crowdy::log` lines show in Logs beside the mod's own. A
|
|
829
|
+
CLIENT-only project's CLIENT half rides the mod named for its CLIENT module:
|
|
830
|
+
when the player has no mod of that name on the grid, Studio deploys the mod starter's server
|
|
831
|
+
half under it first and says so in the build log, and Stop switches that mod off. The
|
|
832
|
+
preview loads only while the player stands in the grid with `run_client_code`, and saving a
|
|
833
|
+
CLIENT project needs ck-api `v2.25.1` or later. A CLIENT crate still on the legacy
|
|
834
|
+
`crowdy-compute-sdk` is refused with what to change. The embed takes `exec` from the client;
|
|
835
|
+
`mountCrowdyStudio` and the controller take `mods: client.exec`. Crowdy Studio runs nothing
|
|
836
|
+
on legacy player compute since 18.0.0.
|
|
837
|
+
|
|
838
|
+
See [CLIENT halves](https://docs.dev.crowdedkingdoms.com/exec/client-halves), [mods](https://docs.dev.crowdedkingdoms.com/exec/mods)
|
|
843
839
|
and [Embed Crowdy Studio in your game](https://docs.crowdedkingdoms.com/crowdyjs/crowdy-studio-embed).
|
|
844
840
|
|
|
845
841
|
### The Studio agent (DeepSeek Harness in the browser)
|