Merge pull request 'feat(sidecar): protocol 14 — POST /kits/uses (PLAN_REDESIGNS §2.6)' (#24) from feat/protocol-14-step-editor into edge
Reviewed-on: #24
This commit is contained in:
@@ -175,11 +175,19 @@ use tracing_subscriber::EnvFilter;
|
||||
/// `POST /permissions/inventory`: the plugin's whole store, in pages it sizes to the game link's
|
||||
/// line cap. Forwarded like every other object; the pages are never kept here.
|
||||
///
|
||||
/// # Protocol 14 — the step editor (opened 2026-10-12)
|
||||
///
|
||||
/// Opened by the module's PLAN_REDESIGNS.md §2 (D332), after protocol 13 shipped with RunicNPC.
|
||||
/// One route, `POST /kits/uses`: how many of a list of players have used a kit up, or are waiting
|
||||
/// out its cooldown — counts, never a list. And `perm.sync` gains `notices`, the one-time "you
|
||||
/// earned a kit" messages (D333), with `noticesTold` in its report; both pass through untouched
|
||||
/// like the rest of that body. The first-class optional plugins (§11) join this protocol too.
|
||||
///
|
||||
/// `docs/rust-link/PROTOCOL.md` is the specification — §8 the read path, §9 identity, §10 the
|
||||
/// mirror, §11 configuration, §12 clans, §13 the raid frame, §14 the leases, §15 the world verbs,
|
||||
/// §16 the rewards, §17 the map, §18 the optional mods, §19 the walk's fixes; this constant is one
|
||||
/// of its four declaration sites.
|
||||
pub const PROTOCOL_VERSION: u32 = 13;
|
||||
/// §16 the rewards, §17 the map, §18 the optional mods, §19 the walk's fixes, §20 the step editor;
|
||||
/// this constant is one of its four declaration sites.
|
||||
pub const PROTOCOL_VERSION: u32 = 14;
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
let args = match cli::parse(std::env::args().skip(1)) {
|
||||
|
||||
@@ -130,6 +130,10 @@ pub async fn serve(addr: &str, state: AppState) -> anyhow::Result<()> {
|
||||
.route("/tally/snapshot", get(tally_snapshot))
|
||||
.route("/tally/close", post(tally_close))
|
||||
.route("/kits", get(kits))
|
||||
// Protocol 14 (the module's PLAN_REDESIGNS.md §2.6): how many of the given players have
|
||||
// used a kit up or are on its cooldown, for the warning beside a kit weekend. The plugin
|
||||
// reads Kits and answers counts; the list of players is the website's and is not kept.
|
||||
.route("/kits/uses", post(kits_uses))
|
||||
.route("/chat", post(chat))
|
||||
// Protocol 11 (§30): the map. The picture passes through in slices and is never kept
|
||||
// here, and positions are asked for while somebody is looking and never filed (D111). The
|
||||
@@ -579,6 +583,13 @@ async fn kits(State(st): State<AppState>) -> Response {
|
||||
respond(st.rpc.call(&st.game, command, &req_id).await)
|
||||
}
|
||||
|
||||
/// How many of a list of players have used one kit up, and how many are on its cooldown (protocol
|
||||
/// 14). The body is `{kit, steamIds}` and is forwarded as it is; the answer is counts. A POST
|
||||
/// because the list rides in the body — it can be as long as a server's linked players.
|
||||
async fn kits_uses(State(st): State<AppState>, Json(body): Json<Value>) -> Response {
|
||||
forward_object(&st, body, "kits.uses", "a kit-use question").await
|
||||
}
|
||||
|
||||
/// Say one line in the server's chat. A repeated key is answered `ok` by the plugin and not said
|
||||
/// again, so a retried step never repeats itself.
|
||||
async fn chat(State(st): State<AppState>, Json(body): Json<Value>) -> Response {
|
||||
@@ -1158,6 +1169,32 @@ mod tests {
|
||||
assert!(stamp(json!([0]), "perm.inventory", "r-8").is_none());
|
||||
}
|
||||
|
||||
/// Protocol 14: a kit-use question keeps its list and cannot become another command, and a
|
||||
/// sync's `notices` pass through it untouched like every other part of the body.
|
||||
#[test]
|
||||
fn a_protocol_14_kit_use_question_and_notices_pass_through() {
|
||||
let body = json!({ "cmd": "perm.sync", "kit": "vip", "steamIds": ["76561190000000001", "76561190000000002"] });
|
||||
let stamped = stamp(body, "kits.uses", "r-12").expect("an object is stamped");
|
||||
|
||||
assert_eq!(stamped["cmd"], "kits.uses");
|
||||
assert_eq!(stamped["reqId"], "r-12");
|
||||
assert_eq!(stamped["kit"], "vip");
|
||||
assert_eq!(stamped["steamIds"][1], "76561190000000002");
|
||||
assert!(stamp(json!(["vip"]), "kits.uses", "r-13").is_none());
|
||||
|
||||
let body = json!({
|
||||
"setId": "s-2",
|
||||
"notices": [{ "key": "run:4:step:9", "steamId": "76561190000000001", "message": "You earned kit vip — type /kit vip", "delivery": "popup" }],
|
||||
});
|
||||
let stamped = stamp(body, "perm.sync", "r-14").expect("an object is stamped");
|
||||
|
||||
assert_eq!(
|
||||
stamped["notices"][0]["message"],
|
||||
"You earned kit vip — type /kit vip"
|
||||
);
|
||||
assert_eq!(stamped["notices"][0]["delivery"], "popup");
|
||||
}
|
||||
|
||||
/// Protocol 12: a title set is forwarded whole. The markup inside each `text` is the module's
|
||||
/// and the plugin's business, so it must arrive byte for byte as the website composed it.
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user