Add JSON-RPC interface and refactor for MCP support
All checks were successful
Smoke tests / Build and smoke test (push) Successful in 1h0m43s
All checks were successful
Smoke tests / Build and smoke test (push) Successful in 1h0m43s
This commit is contained in:
115
src/commands.rs
115
src/commands.rs
@@ -42,17 +42,42 @@ fn resolve_dir(input: &str) -> &str {
|
||||
input
|
||||
}
|
||||
|
||||
pub async fn execute(
|
||||
pub async fn execute_for_ssh(
|
||||
input: &str,
|
||||
player_id: usize,
|
||||
state: &SharedState,
|
||||
session: &mut Session,
|
||||
channel: ChannelId,
|
||||
) -> Result<bool, russh::Error> {
|
||||
let result = execute(input, player_id, state).await;
|
||||
|
||||
send(session, channel, &result.output)?;
|
||||
for msg in result.broadcasts {
|
||||
let _ = msg.handle.data(msg.channel, msg.data).await;
|
||||
}
|
||||
for kick in result.kick_targets {
|
||||
let _ = kick.handle.close(kick.channel).await;
|
||||
}
|
||||
if result.quit {
|
||||
return Ok(false);
|
||||
}
|
||||
send(session, channel, &ansi::prompt())?;
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
pub async fn execute(
|
||||
input: &str,
|
||||
player_id: usize,
|
||||
state: &SharedState,
|
||||
) -> CommandResult {
|
||||
let input = input.trim();
|
||||
if input.is_empty() {
|
||||
send(session, channel, &ansi::prompt())?;
|
||||
return Ok(true);
|
||||
return CommandResult {
|
||||
output: ansi::prompt(),
|
||||
broadcasts: Vec::new(),
|
||||
kick_targets: Vec::new(),
|
||||
quit: false,
|
||||
};
|
||||
}
|
||||
|
||||
let (cmd, args) = match input.split_once(' ') {
|
||||
@@ -72,24 +97,23 @@ pub async fn execute(
|
||||
| "spells" | "skills" | "quit" | "exit"
|
||||
)
|
||||
{
|
||||
drop(st);
|
||||
send(
|
||||
session,
|
||||
channel,
|
||||
&format!(
|
||||
return CommandResult {
|
||||
output: format!(
|
||||
"{}\r\n{}",
|
||||
ansi::error_msg(
|
||||
"You're in combat! Use 'attack', 'defend', 'flee', 'cast', 'use', 'look', 'stats', or 'inventory'."
|
||||
),
|
||||
ansi::prompt()
|
||||
),
|
||||
)?;
|
||||
return Ok(true);
|
||||
broadcasts: Vec::new(),
|
||||
kick_targets: Vec::new(),
|
||||
quit: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let result = match cmd.as_str() {
|
||||
match cmd.as_str() {
|
||||
"look" | "l" => cmd_look(player_id, &args, state).await,
|
||||
"go" => cmd_go(player_id, &args, state).await,
|
||||
"north" | "south" | "east" | "west" | "up" | "down" | "n" | "s" | "e" | "w" | "u"
|
||||
@@ -118,28 +142,21 @@ pub async fn execute(
|
||||
kick_targets: Vec::new(),
|
||||
quit: true,
|
||||
},
|
||||
_ => simple(&format!(
|
||||
"{}\r\n",
|
||||
ansi::error_msg(&format!(
|
||||
"Unknown command: '{cmd}'. Type 'help' for commands."
|
||||
))
|
||||
)),
|
||||
};
|
||||
|
||||
send(session, channel, &result.output)?;
|
||||
for msg in result.broadcasts {
|
||||
let _ = msg.handle.data(msg.channel, msg.data).await;
|
||||
_ => CommandResult {
|
||||
output: format!(
|
||||
"{}\r\n",
|
||||
ansi::error_msg(&format!(
|
||||
"Unknown command: '{cmd}'. Type 'help' for commands."
|
||||
))
|
||||
),
|
||||
broadcasts: Vec::new(),
|
||||
kick_targets: Vec::new(),
|
||||
quit: false,
|
||||
},
|
||||
}
|
||||
for kick in result.kick_targets {
|
||||
let _ = kick.handle.close(kick.channel).await;
|
||||
}
|
||||
if result.quit {
|
||||
return Ok(false);
|
||||
}
|
||||
send(session, channel, &ansi::prompt())?;
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
|
||||
fn send(session: &mut Session, channel: ChannelId, text: &str) -> Result<(), russh::Error> {
|
||||
session.data(channel, CryptoVec::from(text.as_bytes()))?;
|
||||
Ok(())
|
||||
@@ -457,11 +474,13 @@ async fn cmd_go(pid: usize, direction: &str, state: &SharedState) -> CommandResu
|
||||
);
|
||||
let mut bcast = Vec::new();
|
||||
for c in st.players_in_room(&old_rid, pid) {
|
||||
bcast.push(BroadcastMsg {
|
||||
channel: c.channel,
|
||||
handle: c.handle.clone(),
|
||||
data: leave.clone(),
|
||||
});
|
||||
if let (Some(ch), Some(h)) = (c.channel, &c.handle) {
|
||||
bcast.push(BroadcastMsg {
|
||||
channel: ch,
|
||||
handle: h.clone(),
|
||||
data: leave.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(c) = st.players.get_mut(&pid) {
|
||||
@@ -477,11 +496,13 @@ async fn cmd_go(pid: usize, direction: &str, state: &SharedState) -> CommandResu
|
||||
.as_bytes(),
|
||||
);
|
||||
for c in st.players_in_room(&new_rid, pid) {
|
||||
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(pid);
|
||||
@@ -524,10 +545,16 @@ async fn cmd_say(pid: usize, msg: &str, state: &SharedState) -> CommandResult {
|
||||
let bcast: Vec<_> = st
|
||||
.players_in_room(&rid, pid)
|
||||
.iter()
|
||||
.map(|c| BroadcastMsg {
|
||||
channel: c.channel,
|
||||
handle: c.handle.clone(),
|
||||
data: other.clone(),
|
||||
.filter_map(|c| {
|
||||
if let (Some(ch), Some(h)) = (c.channel, &c.handle) {
|
||||
Some(BroadcastMsg {
|
||||
channel: ch,
|
||||
handle: h.clone(),
|
||||
data: other.clone(),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
CommandResult {
|
||||
|
||||
Reference in New Issue
Block a user