Add JSON-RPC interface and refactor for MCP support
All checks were successful
Smoke tests / Build and smoke test (push) Successful in 1h0m43s

This commit is contained in:
AI Agent
2026-03-16 19:19:21 -06:00
parent 4e41038555
commit dd517d8851
10 changed files with 380 additions and 116 deletions

View File

@@ -89,19 +89,21 @@ async fn admin_promote(target: &str, state: &SharedState) -> CommandResult {
)
.as_bytes(),
);
return CommandResult {
output: format!(
"{}\r\n",
ansi::system_msg(&format!("{target} has been promoted to admin."))
),
broadcasts: vec![BroadcastMsg {
channel: conn.channel,
handle: conn.handle.clone(),
data: msg,
}],
kick_targets: Vec::new(),
quit: false,
};
if let (Some(ch), Some(h)) = (conn.channel, &conn.handle) {
return CommandResult {
output: format!(
"{}\r\n",
ansi::system_msg(&format!("{target} has been promoted to admin."))
),
broadcasts: vec![BroadcastMsg {
channel: ch,
handle: h.clone(),
data: msg,
}],
kick_targets: Vec::new(),
quit: false,
};
}
}
}
simple(&format!(
@@ -188,18 +190,31 @@ async fn admin_kick(target: &str, player_id: usize, state: &SharedState) -> Comm
let mut bcast: Vec<BroadcastMsg> = st
.players_in_room(&room_id, player_id)
.iter()
.map(|p| BroadcastMsg {
channel: p.channel,
handle: p.handle.clone(),
data: departure.clone(),
.filter_map(|p| {
if let (Some(ch), Some(h)) = (p.channel, &p.handle) {
Some(BroadcastMsg {
channel: ch,
handle: h.clone(),
data: departure.clone(),
})
} else {
None
}
})
.collect();
// Send kick message to the target before closing
bcast.push(BroadcastMsg {
channel: c.channel,
handle: c.handle.clone(),
data: kick_msg,
});
let mut kick_targets = Vec::new();
if let (Some(ch), Some(h)) = (c.channel, &c.handle) {
bcast.push(BroadcastMsg {
channel: ch,
handle: h.clone(),
data: kick_msg,
});
kick_targets.push(KickTarget {
channel: ch,
handle: h.clone(),
});
}
CommandResult {
output: format!(
@@ -207,10 +222,7 @@ async fn admin_kick(target: &str, player_id: usize, state: &SharedState) -> Comm
ansi::system_msg(&format!("Kicked {name} from the server."))
),
broadcasts: bcast,
kick_targets: vec![KickTarget {
channel: c.channel,
handle: c.handle.clone(),
}],
kick_targets,
quit: false,
}
}
@@ -265,10 +277,16 @@ async fn admin_teleport(room_id: &str, player_id: usize, state: &SharedState) ->
let mut bcast: Vec<BroadcastMsg> = st
.players_in_room(&old_rid, player_id)
.iter()
.map(|c| BroadcastMsg {
channel: c.channel,
handle: c.handle.clone(),
data: leave.clone(),
.filter_map(|c| {
if let (Some(ch), Some(h)) = (c.channel, &c.handle) {
Some(BroadcastMsg {
channel: ch,
handle: h.clone(),
data: leave.clone(),
})
} else {
None
}
})
.collect();
@@ -286,11 +304,13 @@ async fn admin_teleport(room_id: &str, player_id: usize, state: &SharedState) ->
.as_bytes(),
);
for c in st.players_in_room(room_id, player_id) {
bcast.push(BroadcastMsg {
channel: c.channel,
handle: c.handle.clone(),
data: arrive.clone(),
});
if let (Some(ch), Some(h)) = (c.channel, &c.handle) {
bcast.push(BroadcastMsg {
channel: ch,
handle: h.clone(),
data: arrive.clone(),
});
}
}
st.save_player_to_db(player_id);
@@ -360,10 +380,16 @@ async fn admin_announce(msg: &str, player_id: usize, state: &SharedState) -> Com
.players
.iter()
.filter(|(&id, _)| id != player_id)
.map(|(_, c)| BroadcastMsg {
channel: c.channel,
handle: c.handle.clone(),
data: announcement.clone(),
.filter_map(|(_, c)| {
if let (Some(ch), Some(h)) = (c.channel, &c.handle) {
Some(BroadcastMsg {
channel: ch,
handle: h.clone(),
data: announcement.clone(),
})
} else {
None
}
})
.collect();
@@ -408,19 +434,22 @@ async fn admin_heal(args: &str, player_id: usize, state: &SharedState) -> Comman
c.player.stats.hp = c.player.stats.max_hp;
let name = c.player.name.clone();
let hp = c.player.stats.max_hp;
let notify = CryptoVec::from(
format!(
"\r\n{}\r\n{}",
ansi::system_msg(&format!("An admin has fully healed you. HP: {hp}/{hp}")),
ansi::prompt()
)
.as_bytes(),
);
let bcast = vec![BroadcastMsg {
channel: c.channel,
handle: c.handle.clone(),
data: notify,
}];
let mut bcast = Vec::new();
if let (Some(ch), Some(h)) = (c.channel, &c.handle) {
let notify = CryptoVec::from(
format!(
"\r\n{}\r\n{}",
ansi::system_msg(&format!("An admin has fully healed you. HP: {hp}/{hp}")),
ansi::prompt()
)
.as_bytes(),
);
bcast.push(BroadcastMsg {
channel: ch,
handle: h.clone(),
data: notify,
});
}
let _ = c;
st.save_player_to_db(tid);
return CommandResult {