@crowdedkingdoms/ckx-kit 0.2.0-test.1 → 0.3.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/README.md +9 -0
- package/crates/ckx-sdk/Cargo.toml +1 -1
- package/crates/ckx-sdk/src/kit/mod.rs +494 -0
- package/crates/ckx-sdk/src/kit/rng.rs +127 -0
- package/crates/ckx-sdk/src/kit/shard.rs +65 -0
- package/crates/ckx-sdk/src/kit/wire.rs +266 -0
- package/crates/ckx-sdk/src/lib.rs +13 -0
- package/crates/ckx-sdk/src/model.rs +5 -0
- package/crates/crowdy-client-sdk/Cargo.toml +1 -1
- package/kit.pin +4 -4
- package/package.json +1 -1
- package/starters/grid-mod/Cargo.toml +1 -1
- package/starters/matchmaker/Cargo.toml +1 -1
- package/starters/matchmaker/src/lib.rs +334 -74
- package/starters/npc-mobs/Cargo.toml +1 -1
- package/starters/npc-mobs/src/lib.rs +277 -67
- package/starters/session/Cargo.toml +1 -1
- package/starters/session/src/lib.rs +191 -86
- package/starters/world-tick/Cargo.toml +1 -1
- package/starters/world-tick/src/lib.rs +151 -38
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
//! Shard keys: one keyed hub per square of the world, so no one hub holds everyone.
|
|
2
|
+
//!
|
|
3
|
+
//! A shard is `size` by `size` chunks on the x and z axes, and its key is its centre chunk,
|
|
4
|
+
//! `"<x>,<z>"`. Players' clients compute the same keys (the kit clients carry this function),
|
|
5
|
+
//! so a client finds the hub for where it stands without asking anyone. A hub that sees its
|
|
6
|
+
//! neighbours' edges subscribes to [`around`]'s keys.
|
|
7
|
+
|
|
8
|
+
/// The shard's centre chunk for chunk `(x, z)`. `size` is at least 1.
|
|
9
|
+
pub fn centre(x: i64, z: i64, size: i64) -> (i64, i64) {
|
|
10
|
+
let size = size.max(1);
|
|
11
|
+
(x.div_euclid(size) * size + size / 2, z.div_euclid(size) * size + size / 2)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/// The key of the shard that holds chunk `(x, z)`.
|
|
15
|
+
pub fn key(x: i64, z: i64, size: i64) -> String {
|
|
16
|
+
let (cx, cz) = centre(x, z, size);
|
|
17
|
+
format!("{cx},{cz}")
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/// The centre chunk a key names, or `None` when it is not `"<x>,<z>"`.
|
|
21
|
+
pub fn parse(key: &str) -> Option<(i64, i64)> {
|
|
22
|
+
let (x, z) = key.split_once(',')?;
|
|
23
|
+
Some((x.trim().parse().ok()?, z.trim().parse().ok()?))
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/// The keys of the shards within `radius` shards of the one holding `(x, z)`, its own first,
|
|
27
|
+
/// then row by row.
|
|
28
|
+
pub fn around(x: i64, z: i64, size: i64, radius: i64) -> Vec<String> {
|
|
29
|
+
let size = size.max(1);
|
|
30
|
+
let (cx, cz) = centre(x, z, size);
|
|
31
|
+
let mut keys = vec![format!("{cx},{cz}")];
|
|
32
|
+
for dz in -radius..=radius {
|
|
33
|
+
for dx in -radius..=radius {
|
|
34
|
+
if (dx, dz) != (0, 0) {
|
|
35
|
+
keys.push(format!("{},{}", cx + dx * size, cz + dz * size));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
keys
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
#[cfg(test)]
|
|
43
|
+
mod tests {
|
|
44
|
+
use super::*;
|
|
45
|
+
|
|
46
|
+
#[test]
|
|
47
|
+
fn a_chunk_falls_in_one_shard_named_by_its_centre() {
|
|
48
|
+
assert_eq!(key(10, -4, 8), "12,-4");
|
|
49
|
+
assert_eq!(key(8, -8, 8), "12,-4");
|
|
50
|
+
assert_eq!(key(7, -9, 8), "4,-12");
|
|
51
|
+
assert_eq!(key(-1, 0, 16), "-8,8");
|
|
52
|
+
assert_eq!(key(3, 5, 1), "3,5", "size 1 is the chunk itself");
|
|
53
|
+
assert_eq!(parse("12,-4"), Some((12, -4)));
|
|
54
|
+
assert_eq!(parse("x"), None);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
#[test]
|
|
58
|
+
fn around_starts_with_its_own_shard() {
|
|
59
|
+
let keys = around(0, 0, 8, 1);
|
|
60
|
+
assert_eq!(keys.len(), 9);
|
|
61
|
+
assert_eq!(keys[0], "4,4");
|
|
62
|
+
assert!(keys.contains(&"-4,-4".to_string()) && keys.contains(&"12,12".to_string()));
|
|
63
|
+
assert_eq!(around(0, 0, 8, 0), vec!["4,4".to_string()]);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
//! What kit hubs show players near them through the realtime tier ([`crate::emit`]): server
|
|
2
|
+
//! events, numbered by the registry below, and the state of server-driven actors.
|
|
3
|
+
//!
|
|
4
|
+
//! A server event's payload is `[event type, u16 little endian][JSON]`. The bodies here use
|
|
5
|
+
//! camelCase keys, the shape the kit clients' event parsers read. An app's own events take
|
|
6
|
+
//! numbers from [`APP_EVENTS`] up.
|
|
7
|
+
//!
|
|
8
|
+
//! A server-driven actor's state is [`ActorState`] as MessagePack: the kit clients decode it
|
|
9
|
+
//! into their actor stores like a player's.
|
|
10
|
+
|
|
11
|
+
use serde::{Deserialize, Serialize};
|
|
12
|
+
|
|
13
|
+
use crate::emit::{MAX_DISTANCE, MAX_PAYLOAD, Spatial};
|
|
14
|
+
use crate::node::ChunkPos;
|
|
15
|
+
use crate::{Ctx, Error, Result, encode};
|
|
16
|
+
|
|
17
|
+
/// A mob or a trap hit a player.
|
|
18
|
+
pub const CONTACT_DAMAGE: u16 = 77;
|
|
19
|
+
/// The weather or the time of day turned.
|
|
20
|
+
pub const WEATHER: u16 = 90;
|
|
21
|
+
/// A turn passed to the next player.
|
|
22
|
+
pub const TURN: u16 = 91;
|
|
23
|
+
/// Scores or a result.
|
|
24
|
+
pub const SCORE: u16 = 92;
|
|
25
|
+
/// A match was proposed to the players in it.
|
|
26
|
+
pub const PROPOSAL: u16 = 93;
|
|
27
|
+
/// An ability was cast, or landed.
|
|
28
|
+
pub const ABILITY: u16 = 94;
|
|
29
|
+
/// A movement the warden flagged.
|
|
30
|
+
pub const MOVEMENT_VIOLATION: u16 = 95;
|
|
31
|
+
/// A control point changed hands, or its capture moved.
|
|
32
|
+
pub const CONTROL_POINT: u16 = 96;
|
|
33
|
+
/// A racer started, passed a checkpoint, finished a lap or the race.
|
|
34
|
+
pub const RACE_TIMING: u16 = 97;
|
|
35
|
+
/// A play zone moved or shrank.
|
|
36
|
+
pub const ZONE_CHANGE: u16 = 98;
|
|
37
|
+
/// A wave began or ended, or a boss changed phase.
|
|
38
|
+
pub const ENCOUNTER: u16 = 99;
|
|
39
|
+
/// The contested object (a ball) changed hands, or a goal was scored.
|
|
40
|
+
pub const POSSESSION: u16 = 100;
|
|
41
|
+
/// An emote: a client event players send each other (the kit clients' convention); a hub may
|
|
42
|
+
/// send one too, for a server-driven actor.
|
|
43
|
+
pub const EMOTE: u16 = 101;
|
|
44
|
+
/// The first number an app's own events may use.
|
|
45
|
+
pub const APP_EVENTS: u16 = 1000;
|
|
46
|
+
|
|
47
|
+
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
|
48
|
+
#[serde(rename_all = "camelCase")]
|
|
49
|
+
pub struct ContactDamage {
|
|
50
|
+
pub target_uuid: String,
|
|
51
|
+
pub damage: i64,
|
|
52
|
+
pub mob_id: String,
|
|
53
|
+
pub mob_name: String,
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
|
57
|
+
#[serde(rename_all = "camelCase")]
|
|
58
|
+
pub struct WeatherChange {
|
|
59
|
+
pub weather: String,
|
|
60
|
+
pub since_ms: u64,
|
|
61
|
+
pub until_ms: u64,
|
|
62
|
+
pub night: bool,
|
|
63
|
+
pub time_of_day: f64,
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
|
67
|
+
#[serde(rename_all = "camelCase")]
|
|
68
|
+
pub struct TurnChange {
|
|
69
|
+
/// Whose turn it is now: a player id, or a unit's id.
|
|
70
|
+
pub actor_id: String,
|
|
71
|
+
pub round: u32,
|
|
72
|
+
pub turn_in_round: u32,
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
|
76
|
+
#[serde(rename_all = "camelCase")]
|
|
77
|
+
pub struct Standing {
|
|
78
|
+
pub actor_id: String,
|
|
79
|
+
pub score: i64,
|
|
80
|
+
pub rank: u32,
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
|
84
|
+
#[serde(rename_all = "camelCase")]
|
|
85
|
+
pub struct ScoreUpdate {
|
|
86
|
+
pub standings: Vec<Standing>,
|
|
87
|
+
pub winner_id: Option<String>,
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
|
91
|
+
#[serde(rename_all = "camelCase")]
|
|
92
|
+
pub struct ProposalMade {
|
|
93
|
+
pub proposal_id: String,
|
|
94
|
+
pub mode: String,
|
|
95
|
+
pub players: Vec<String>,
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
|
99
|
+
#[serde(rename_all = "camelCase")]
|
|
100
|
+
pub struct AbilityUse {
|
|
101
|
+
/// `cast` or `impact`.
|
|
102
|
+
pub kind: String,
|
|
103
|
+
pub ability_id: String,
|
|
104
|
+
pub caster_id: String,
|
|
105
|
+
pub victim_id: Option<String>,
|
|
106
|
+
pub damage: i64,
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
|
110
|
+
#[serde(rename_all = "camelCase")]
|
|
111
|
+
pub struct MovementViolation {
|
|
112
|
+
/// `speed`, `teleport` or `bounds`.
|
|
113
|
+
pub kind: String,
|
|
114
|
+
pub user_id: String,
|
|
115
|
+
pub detail: String,
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
|
119
|
+
#[serde(rename_all = "camelCase")]
|
|
120
|
+
pub struct ControlPointChange {
|
|
121
|
+
pub point_id: String,
|
|
122
|
+
pub owner: String,
|
|
123
|
+
pub previous_owner: String,
|
|
124
|
+
/// Capture progress toward the attacker, 0 to 1.
|
|
125
|
+
pub progress: f64,
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
|
129
|
+
#[serde(rename_all = "camelCase")]
|
|
130
|
+
pub struct RaceTiming {
|
|
131
|
+
/// `started`, `checkpoint`, `lap` or `finished`.
|
|
132
|
+
pub kind: String,
|
|
133
|
+
pub course_id: String,
|
|
134
|
+
pub user_id: String,
|
|
135
|
+
pub checkpoint: u32,
|
|
136
|
+
pub lap: u32,
|
|
137
|
+
pub elapsed_ms: u64,
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
|
141
|
+
#[serde(rename_all = "camelCase")]
|
|
142
|
+
pub struct ZoneChange {
|
|
143
|
+
/// `hold`, `shrink` or `closed`.
|
|
144
|
+
pub kind: String,
|
|
145
|
+
pub phase: Option<u32>,
|
|
146
|
+
pub radius_now: f64,
|
|
147
|
+
pub center_x: f64,
|
|
148
|
+
pub center_z: f64,
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
|
152
|
+
#[serde(rename_all = "camelCase")]
|
|
153
|
+
pub struct EncounterChange {
|
|
154
|
+
/// `wave_started`, `wave_cleared`, `boss_phase` or `finished`.
|
|
155
|
+
pub kind: String,
|
|
156
|
+
pub encounter_id: String,
|
|
157
|
+
pub wave: u32,
|
|
158
|
+
pub phase: u32,
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
|
162
|
+
#[serde(rename_all = "camelCase")]
|
|
163
|
+
pub struct PossessionChange {
|
|
164
|
+
/// `claimed`, `passed`, `loose` or `goal`.
|
|
165
|
+
pub kind: String,
|
|
166
|
+
pub holder_id: Option<String>,
|
|
167
|
+
pub team: Option<String>,
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
|
171
|
+
#[serde(rename_all = "camelCase")]
|
|
172
|
+
pub struct Emote {
|
|
173
|
+
/// The emote's name, as the game knows it: `wave`, `cheer`, ...
|
|
174
|
+
pub emote: String,
|
|
175
|
+
/// The actor it is aimed at, if any.
|
|
176
|
+
pub target_uuid: Option<String>,
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/// A server event's payload: its type, then its body as JSON.
|
|
180
|
+
pub fn event_bytes<T: Serialize + ?Sized>(event_type: u16, body: &T) -> Result<Vec<u8>> {
|
|
181
|
+
let json = serde_json::to_vec(body).map_err(|e| Error::new(format!("an event body encodes as JSON: {e}")))?;
|
|
182
|
+
let mut out = Vec::with_capacity(2 + json.len());
|
|
183
|
+
out.extend_from_slice(&event_type.to_le_bytes());
|
|
184
|
+
out.extend_from_slice(&json);
|
|
185
|
+
if out.len() > MAX_PAYLOAD {
|
|
186
|
+
return Err(Error::new(format!("a realtime payload is at most {MAX_PAYLOAD} bytes")));
|
|
187
|
+
}
|
|
188
|
+
Ok(out)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/// Sends a server event to the players within `distance` chunks of `at` (at most
|
|
192
|
+
/// [`MAX_DISTANCE`]). `actor` is the event's actor: the one it is about, or the hub's own.
|
|
193
|
+
pub fn emit_event<T: Serialize + ?Sized>(ctx: &Ctx, at: ChunkPos, distance: u8, actor: &[u8; 32], event_type: u16, body: &T) -> Result<()> {
|
|
194
|
+
let bytes = event_bytes(event_type, body)?;
|
|
195
|
+
ctx.emit_spatial(at, distance.min(MAX_DISTANCE), actor, Spatial::Event { event_type, state: &bytes[2..] })?;
|
|
196
|
+
Ok(())
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/// A server-driven actor as players near it see it.
|
|
200
|
+
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
|
201
|
+
pub struct ActorState {
|
|
202
|
+
/// What it is: `mob`, `npc`, `pet`, `ball`, `ghost`, a game's own word.
|
|
203
|
+
pub kind: String,
|
|
204
|
+
/// Its id within the hub that shows it.
|
|
205
|
+
pub id: u64,
|
|
206
|
+
/// Where it is, in chunks.
|
|
207
|
+
pub x: f64,
|
|
208
|
+
#[serde(default)]
|
|
209
|
+
pub y: f64,
|
|
210
|
+
pub z: f64,
|
|
211
|
+
/// Its health, when it has any.
|
|
212
|
+
pub hp: Option<i64>,
|
|
213
|
+
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
214
|
+
pub max_hp: Option<i64>,
|
|
215
|
+
/// What it is doing: `idle`, `chase`, `follow`, ...
|
|
216
|
+
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
217
|
+
pub mode: Option<String>,
|
|
218
|
+
/// The player it belongs to (a pet, a summon).
|
|
219
|
+
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
220
|
+
pub owner: Option<u64>,
|
|
221
|
+
/// Facing, in radians.
|
|
222
|
+
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
223
|
+
pub yaw: Option<f64>,
|
|
224
|
+
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
225
|
+
pub name: Option<String>,
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
impl ActorState {
|
|
229
|
+
pub fn new(kind: &str, id: u64, x: f64, z: f64) -> Self {
|
|
230
|
+
Self { kind: kind.to_owned(), id, x, y: 0.0, z, hp: None, max_hp: None, mode: None, owner: None, yaw: None, name: None }
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/// The chunk it stands in.
|
|
234
|
+
pub fn chunk(&self) -> ChunkPos {
|
|
235
|
+
ChunkPos::new(self.x.floor() as i64, self.y.floor() as i64, self.z.floor() as i64)
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/// Shows a server-driven actor to the players within `distance` chunks of where it stands.
|
|
240
|
+
pub fn emit_actor_state(ctx: &Ctx, actor: &[u8; 32], distance: u8, state: &ActorState) -> Result<()> {
|
|
241
|
+
ctx.emit_actor(actor, state.chunk(), distance.min(MAX_DISTANCE), &encode(state)?)?;
|
|
242
|
+
Ok(())
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
#[cfg(test)]
|
|
246
|
+
mod tests {
|
|
247
|
+
use super::*;
|
|
248
|
+
|
|
249
|
+
#[test]
|
|
250
|
+
fn an_event_is_its_type_then_json() {
|
|
251
|
+
let bytes = event_bytes(TURN, &TurnChange { actor_id: "7".into(), round: 2, turn_in_round: 1 }).unwrap();
|
|
252
|
+
assert_eq!(&bytes[..2], &[91, 0]);
|
|
253
|
+
let body: serde_json::Value = serde_json::from_slice(&bytes[2..]).unwrap();
|
|
254
|
+
assert_eq!(body, serde_json::json!({ "actorId": "7", "round": 2, "turnInRound": 1 }));
|
|
255
|
+
assert!(event_bytes(APP_EVENTS, &"x".repeat(MAX_PAYLOAD)).is_err());
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
#[test]
|
|
259
|
+
fn an_actor_state_leaves_out_what_it_does_not_have() {
|
|
260
|
+
let mut s = ActorState::new("mob", 3, 1.5, -2.25);
|
|
261
|
+
s.hp = Some(40);
|
|
262
|
+
let back: serde_json::Value = crate::decode(&encode(&s).unwrap()).unwrap();
|
|
263
|
+
assert_eq!(back, serde_json::json!({ "kind": "mob", "id": 3, "x": 1.5, "y": 0.0, "z": -2.25, "hp": 40 }));
|
|
264
|
+
assert_eq!(s.chunk(), ChunkPos::new(1, 0, -3));
|
|
265
|
+
}
|
|
266
|
+
}
|
|
@@ -44,10 +44,15 @@
|
|
|
44
44
|
//! Nodes are unit tested natively with `cargo test`: `testing` runs one against a fake of the
|
|
45
45
|
//! platform (calls, timers, events, snapshots, the node API, a mod's grid). [`limits`] has the
|
|
46
46
|
//! platform's bounds.
|
|
47
|
+
//!
|
|
48
|
+
//! [`kit`] is the game kit's half here: the protocol kit hubs speak to the kit clients
|
|
49
|
+
//! (snapshots and deltas with sequence numbers, retry-safe actions, refusal codes), shard keys,
|
|
50
|
+
//! a seeded random generator, and the realtime event registry.
|
|
47
51
|
|
|
48
52
|
mod abi;
|
|
49
53
|
pub mod cron;
|
|
50
54
|
pub mod emit;
|
|
55
|
+
pub mod kit;
|
|
51
56
|
pub mod limits;
|
|
52
57
|
pub mod model;
|
|
53
58
|
pub mod node;
|
|
@@ -546,20 +551,25 @@ macro_rules! export_spoke {
|
|
|
546
551
|
};
|
|
547
552
|
}
|
|
548
553
|
|
|
554
|
+
// Only the module the sandbox loads needs the exports: a native build (a unit test, a crate
|
|
555
|
+
// that includes several nodes' sources) defines none, so nodes link side by side.
|
|
549
556
|
#[doc(hidden)]
|
|
550
557
|
#[macro_export]
|
|
551
558
|
macro_rules! __export_node {
|
|
552
559
|
($node:ty) => {
|
|
560
|
+
#[cfg(target_arch = "wasm32")]
|
|
553
561
|
#[unsafe(no_mangle)]
|
|
554
562
|
pub extern "C" fn ckx_abi() -> u32 {
|
|
555
563
|
$crate::rt::ABI_VERSION
|
|
556
564
|
}
|
|
557
565
|
|
|
566
|
+
#[cfg(target_arch = "wasm32")]
|
|
558
567
|
#[unsafe(no_mangle)]
|
|
559
568
|
pub extern "C" fn ckx_alloc(len: u32) -> u32 {
|
|
560
569
|
$crate::rt::alloc(len)
|
|
561
570
|
}
|
|
562
571
|
|
|
572
|
+
#[cfg(target_arch = "wasm32")]
|
|
563
573
|
#[unsafe(no_mangle)]
|
|
564
574
|
pub extern "C" fn ckx_init(
|
|
565
575
|
ctx_ptr: u32,
|
|
@@ -574,16 +584,19 @@ macro_rules! __export_node {
|
|
|
574
584
|
$crate::rt::init::<$node>(ctx_ptr, ctx_len, seed_ptr, seed_len, snap_ptr, snap_len, snap_version, has_snap)
|
|
575
585
|
}
|
|
576
586
|
|
|
587
|
+
#[cfg(target_arch = "wasm32")]
|
|
577
588
|
#[unsafe(no_mangle)]
|
|
578
589
|
pub extern "C" fn ckx_handle(caller_kind: u32, caller_id: u64, buf_ptr: u32, method_len: u32, payload_len: u32) -> u64 {
|
|
579
590
|
$crate::rt::handle(caller_kind, caller_id, buf_ptr, method_len, payload_len)
|
|
580
591
|
}
|
|
581
592
|
|
|
593
|
+
#[cfg(target_arch = "wasm32")]
|
|
582
594
|
#[unsafe(no_mangle)]
|
|
583
595
|
pub extern "C" fn ckx_persist() -> u64 {
|
|
584
596
|
$crate::rt::persist()
|
|
585
597
|
}
|
|
586
598
|
|
|
599
|
+
#[cfg(target_arch = "wasm32")]
|
|
587
600
|
#[unsafe(no_mangle)]
|
|
588
601
|
pub extern "C" fn ckx_evict() {
|
|
589
602
|
$crate::rt::evict()
|
|
@@ -209,6 +209,11 @@ impl Model {
|
|
|
209
209
|
self.containers.get(&id)
|
|
210
210
|
}
|
|
211
211
|
|
|
212
|
+
/// Every container's id, oldest first.
|
|
213
|
+
pub fn ids(&self) -> impl Iterator<Item = u64> + '_ {
|
|
214
|
+
self.containers.keys().copied()
|
|
215
|
+
}
|
|
216
|
+
|
|
212
217
|
/// Every container of `type_name`, oldest first.
|
|
213
218
|
pub fn of_type<'a>(&'a self, type_name: &'a str) -> impl Iterator<Item = u64> + 'a {
|
|
214
219
|
self.containers.iter().filter(move |(_, c)| c.type_name == type_name).map(|(id, _)| *id)
|
package/kit.pin
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# The platform toolchain release this kit was copied from (sync-kit.sh in the platform's
|
|
2
2
|
# repository). The paths in `copied` are byte-identical to it: change them there, never here.
|
|
3
|
-
toolchain_version=v1.
|
|
4
|
-
toolchain_commit=
|
|
5
|
-
sdk_commit=
|
|
6
|
-
ckx_sdk_version=0.
|
|
3
|
+
toolchain_version=v1.12.0
|
|
4
|
+
toolchain_commit=41921e53e1bbd4901fb8c4946e4277aa1e93bfec
|
|
5
|
+
sdk_commit=60e91d4892727b847531e657cc9c4ba1edd2e2c1
|
|
6
|
+
ckx_sdk_version=0.10.0
|
|
7
7
|
crowdy_client_sdk_version=0.1.0
|
|
8
8
|
rust_version=1.97.1
|
|
9
9
|
copied=crates/ckx-sdk/src crates/crowdy-client-sdk/src tools/instrument/Cargo.toml tools/instrument/Cargo.lock tools/instrument/src checks/src/build/exec-source.ts checks/src/build/exec-source.spec.ts checks/src/build/rust-source-guard.ts checks/src/build/rust-source-guard.spec.ts checks/src/build/wasm-inspect.ts checks/src/build/wasm-inspect.spec.ts checks/src/build/client-capabilities.ts checks/src/build/client-capabilities.spec.ts checks/src/test-support/wasm-module.ts checks/compute-toolchain/host-catalog.json starters rust-toolchain.toml vendor.lock
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crowdedkingdoms/ckx-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0-dev.1",
|
|
4
4
|
"description": "Build, check and test Crowded Kingdoms ck-exec mods, hubs and spokes on your machine, as the platform builds them",
|
|
5
5
|
"license": "MIT OR Apache-2.0",
|
|
6
6
|
"homepage": "https://docs.crowdedkingdoms.com/exec/intro",
|