mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Server server::cmd depends on common::cmd
This commit is contained in:
parent
307e478671
commit
7ecea34f85
@ -1,14 +1,10 @@
|
|||||||
use crate::{assets, comp::Player, state::State};
|
use crate::{assets, comp::Player, state::State};
|
||||||
use lazy_static::lazy_static;
|
|
||||||
use specs::prelude::{Join, WorldExt};
|
use specs::prelude::{Join, WorldExt};
|
||||||
|
|
||||||
|
|
||||||
/// Struct representing a command that a user can run from server chat.
|
/// Struct representing a command that a user can run from server chat.
|
||||||
pub struct ChatCommand {
|
pub struct ChatCommandData {
|
||||||
/// The keyword used to invoke the command, omitting the leading '/'.
|
|
||||||
pub keyword: &'static str,
|
|
||||||
/// A format string for parsing arguments.
|
/// A format string for parsing arguments.
|
||||||
pub args: Vec<ArgumentSyntax>,
|
pub args: Vec<ArgumentSpec>,
|
||||||
/// A one-line message that explains what the command does
|
/// A one-line message that explains what the command does
|
||||||
pub description: &'static str,
|
pub description: &'static str,
|
||||||
/// A boolean that is used to check whether the command requires
|
/// A boolean that is used to check whether the command requires
|
||||||
@ -16,15 +12,9 @@ pub struct ChatCommand {
|
|||||||
pub needs_admin: bool,
|
pub needs_admin: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChatCommand {
|
impl ChatCommandData {
|
||||||
pub fn new(
|
pub fn new(args: Vec<ArgumentSpec>, description: &'static str, needs_admin: bool) -> Self {
|
||||||
keyword: &'static str,
|
|
||||||
args: Vec<ArgumentSyntax>,
|
|
||||||
description: &'static str,
|
|
||||||
needs_admin: bool,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
keyword,
|
|
||||||
args,
|
args,
|
||||||
description,
|
description,
|
||||||
needs_admin,
|
needs_admin,
|
||||||
@ -32,17 +22,267 @@ impl ChatCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
// Please keep this sorted alphabetically :-)
|
||||||
static ref CHAT_COMMANDS: Vec<ChatCommand> = {
|
#[derive(Copy, Clone)]
|
||||||
use ArgumentSyntax::*;
|
pub enum ChatCommand {
|
||||||
vec![
|
Adminify,
|
||||||
ChatCommand::new("help", vec![Command(true)], "Display information about commands", false),
|
Alias,
|
||||||
]
|
Build,
|
||||||
};
|
Debug,
|
||||||
|
DebugColumn,
|
||||||
|
Explosion,
|
||||||
|
GiveExp,
|
||||||
|
GiveItem,
|
||||||
|
Goto,
|
||||||
|
Health,
|
||||||
|
Help,
|
||||||
|
Jump,
|
||||||
|
Kill,
|
||||||
|
KillNpcs,
|
||||||
|
Lantern,
|
||||||
|
Light,
|
||||||
|
Object,
|
||||||
|
Players,
|
||||||
|
RemoveLights,
|
||||||
|
SetLevel,
|
||||||
|
Spawn,
|
||||||
|
Sudo,
|
||||||
|
Tell,
|
||||||
|
Time,
|
||||||
|
Tp,
|
||||||
|
Version,
|
||||||
|
Waypoint,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Thank you for keeping this sorted alphabetically :-)
|
||||||
|
pub static CHAT_COMMANDS: &'static [ChatCommand] = &[
|
||||||
|
ChatCommand::Adminify,
|
||||||
|
ChatCommand::Alias,
|
||||||
|
ChatCommand::Build,
|
||||||
|
ChatCommand::Debug,
|
||||||
|
ChatCommand::DebugColumn,
|
||||||
|
ChatCommand::Explosion,
|
||||||
|
ChatCommand::GiveExp,
|
||||||
|
ChatCommand::GiveItem,
|
||||||
|
ChatCommand::Goto,
|
||||||
|
ChatCommand::Health,
|
||||||
|
ChatCommand::Help,
|
||||||
|
ChatCommand::Jump,
|
||||||
|
ChatCommand::Kill,
|
||||||
|
ChatCommand::KillNpcs,
|
||||||
|
ChatCommand::Lantern,
|
||||||
|
ChatCommand::Light,
|
||||||
|
ChatCommand::Object,
|
||||||
|
ChatCommand::Players,
|
||||||
|
ChatCommand::RemoveLights,
|
||||||
|
ChatCommand::SetLevel,
|
||||||
|
ChatCommand::Spawn,
|
||||||
|
ChatCommand::Sudo,
|
||||||
|
ChatCommand::Tell,
|
||||||
|
ChatCommand::Time,
|
||||||
|
ChatCommand::Tp,
|
||||||
|
ChatCommand::Version,
|
||||||
|
ChatCommand::Waypoint,
|
||||||
|
];
|
||||||
|
|
||||||
|
impl ChatCommand {
|
||||||
|
pub fn data(&self) -> ChatCommandData {
|
||||||
|
use ArgumentSpec::*;
|
||||||
|
let cmd = ChatCommandData::new;
|
||||||
|
match self {
|
||||||
|
ChatCommand::Adminify => cmd(
|
||||||
|
vec![PlayerName(false)],
|
||||||
|
"Temporarily gives a player admin permissions or removes them",
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
ChatCommand::Alias => cmd(vec![Any("name", false)], "Change your alias", false),
|
||||||
|
ChatCommand::Build => cmd(vec![], "Toggles build mode on and off", true),
|
||||||
|
ChatCommand::Debug => cmd(vec![], "Place all debug items into your pack.", true),
|
||||||
|
ChatCommand::DebugColumn => cmd(
|
||||||
|
vec![Float("x", f32::NAN, false), Float("y", f32::NAN, false)],
|
||||||
|
"Prints some debug information about a column",
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
ChatCommand::Explosion => cmd(
|
||||||
|
vec![Float("radius", 5.0, false)],
|
||||||
|
"Explodes the ground around you",
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
ChatCommand::GiveExp => cmd(
|
||||||
|
vec![Integer("amount", 50, false)],
|
||||||
|
"Give experience to yourself",
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
ChatCommand::GiveItem => cmd(
|
||||||
|
vec![ItemSpec(false), Integer("num", 1, true)],
|
||||||
|
"Give yourself some items",
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
ChatCommand::Goto => cmd(
|
||||||
|
vec![
|
||||||
|
Float("x", 0.0, false),
|
||||||
|
Float("y", 0.0, false),
|
||||||
|
Float("z", 0.0, false),
|
||||||
|
],
|
||||||
|
"Teleport to a position",
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
ChatCommand::Health => cmd(
|
||||||
|
vec![Integer("hp", 100, false)],
|
||||||
|
"Set your current health",
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
ChatCommand::Help => ChatCommandData::new(
|
||||||
|
vec![Command(true)],
|
||||||
|
"Display information about commands",
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
ChatCommand::Jump => cmd(
|
||||||
|
vec![
|
||||||
|
Float("x", 0.0, false),
|
||||||
|
Float("y", 0.0, false),
|
||||||
|
Float("z", 0.0, false),
|
||||||
|
],
|
||||||
|
"Offset your current position",
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
ChatCommand::Kill => cmd(vec![], "Kill yourself", false),
|
||||||
|
ChatCommand::KillNpcs => cmd(vec![], "Kill the NPCs", true),
|
||||||
|
ChatCommand::Lantern => cmd(
|
||||||
|
vec![
|
||||||
|
Float("strength", 5.0, false),
|
||||||
|
Float("r", 1.0, true),
|
||||||
|
Float("g", 1.0, true),
|
||||||
|
Float("b", 1.0, true),
|
||||||
|
],
|
||||||
|
"Change your lantern's strength and color",
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
ChatCommand::Light => cmd(
|
||||||
|
vec![
|
||||||
|
Float("r", 1.0, true),
|
||||||
|
Float("g", 1.0, true),
|
||||||
|
Float("b", 1.0, true),
|
||||||
|
Float("x", 0.0, true),
|
||||||
|
Float("y", 0.0, true),
|
||||||
|
Float("z", 0.0, true),
|
||||||
|
Float("strength", 5.0, true),
|
||||||
|
],
|
||||||
|
"Spawn entity with light",
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
ChatCommand::Object => cmd(vec![/*TODO*/], "Spawn an object", true),
|
||||||
|
ChatCommand::Players => cmd(vec![], "Lists players currently online", false),
|
||||||
|
ChatCommand::RemoveLights => cmd(
|
||||||
|
vec![Float("radius", 20.0, true)],
|
||||||
|
"Removes all lights spawned by players",
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
ChatCommand::SetLevel => {
|
||||||
|
cmd(vec![Integer("level", 10, false)], "Set player Level", true)
|
||||||
|
},
|
||||||
|
ChatCommand::Spawn => cmd(vec![/*TODO*/], "Spawn a test entity", true),
|
||||||
|
ChatCommand::Sudo => cmd(
|
||||||
|
vec![PlayerName(false), Command(false), Message /* TODO */],
|
||||||
|
"Run command as if you were another player",
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
ChatCommand::Tell => cmd(
|
||||||
|
vec![PlayerName(false), Message],
|
||||||
|
"Send a message to another player",
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
ChatCommand::Time => cmd(vec![/*TODO*/], "Set the time of day", true),
|
||||||
|
ChatCommand::Tp => cmd(vec![PlayerName(true)], "Teleport to another player", true),
|
||||||
|
ChatCommand::Version => cmd(vec![], "Prints server version", false),
|
||||||
|
ChatCommand::Waypoint => {
|
||||||
|
cmd(vec![], "Set your waypoint to your current position", true)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn keyword(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
ChatCommand::Adminify => "adminify",
|
||||||
|
ChatCommand::Alias => "alias",
|
||||||
|
ChatCommand::Build => "build",
|
||||||
|
ChatCommand::Debug => "debug",
|
||||||
|
ChatCommand::DebugColumn => "debug_column",
|
||||||
|
ChatCommand::Explosion => "explosion",
|
||||||
|
ChatCommand::GiveExp => "give_exp",
|
||||||
|
ChatCommand::GiveItem => "give_item",
|
||||||
|
ChatCommand::Goto => "goto",
|
||||||
|
ChatCommand::Health => "health",
|
||||||
|
ChatCommand::Help => "help",
|
||||||
|
ChatCommand::Jump => "jump",
|
||||||
|
ChatCommand::Kill => "kill",
|
||||||
|
ChatCommand::KillNpcs => "kill_npcs",
|
||||||
|
ChatCommand::Lantern => "lantern",
|
||||||
|
ChatCommand::Light => "light",
|
||||||
|
ChatCommand::Object => "object",
|
||||||
|
ChatCommand::Players => "players",
|
||||||
|
ChatCommand::RemoveLights => "remove_lights",
|
||||||
|
ChatCommand::SetLevel => "set_level",
|
||||||
|
ChatCommand::Spawn => "spawn",
|
||||||
|
ChatCommand::Sudo => "sudo",
|
||||||
|
ChatCommand::Tell => "tell",
|
||||||
|
ChatCommand::Time => "time",
|
||||||
|
ChatCommand::Tp => "tp",
|
||||||
|
ChatCommand::Version => "version",
|
||||||
|
ChatCommand::Waypoint => "waypoint",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn help_string(&self) -> String {
|
||||||
|
let data = self.data();
|
||||||
|
let usage = std::iter::once(format!("/{}", self.keyword()))
|
||||||
|
.chain(data.args.iter().map(|arg| arg.usage_string()))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(" ");
|
||||||
|
format!("{}: {}", usage, data.description)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn needs_admin(&self) -> bool { self.data().needs_admin }
|
||||||
|
|
||||||
|
pub fn arg_fmt(&self) -> String {
|
||||||
|
self.data()
|
||||||
|
.args
|
||||||
|
.iter()
|
||||||
|
.map(|arg| match arg {
|
||||||
|
ArgumentSpec::PlayerName(_) => "{}",
|
||||||
|
ArgumentSpec::ItemSpec(_) => "{}",
|
||||||
|
ArgumentSpec::Float(_, _, _) => "{f}",
|
||||||
|
ArgumentSpec::Integer(_, _, _) => "{d}",
|
||||||
|
ArgumentSpec::Any(_, _) => "{}",
|
||||||
|
ArgumentSpec::Command(_) => "{}",
|
||||||
|
ArgumentSpec::Message => "{/.*/}",
|
||||||
|
ArgumentSpec::OneOf(_, _, _, _) => "{}", // TODO
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(" ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::str::FromStr for ChatCommand {
|
||||||
|
type Err = ();
|
||||||
|
|
||||||
|
fn from_str(keyword: &str) -> Result<ChatCommand, ()> {
|
||||||
|
let kwd = if keyword.chars().next() == Some('/') {
|
||||||
|
&keyword[1..]
|
||||||
|
} else {
|
||||||
|
&keyword[..]
|
||||||
|
};
|
||||||
|
for c in CHAT_COMMANDS {
|
||||||
|
if kwd == c.keyword() {
|
||||||
|
return Ok(*c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Representation for chat command arguments
|
/// Representation for chat command arguments
|
||||||
pub enum ArgumentSyntax {
|
pub enum ArgumentSpec {
|
||||||
/// The argument refers to a player by alias
|
/// The argument refers to a player by alias
|
||||||
PlayerName(bool),
|
PlayerName(bool),
|
||||||
/// The argument refers to an item asset by path
|
/// The argument refers to an item asset by path
|
||||||
@ -56,61 +296,74 @@ pub enum ArgumentSyntax {
|
|||||||
/// * label
|
/// * label
|
||||||
/// * default tab-completion
|
/// * default tab-completion
|
||||||
/// * whether it's optional
|
/// * whether it's optional
|
||||||
Integer(&'static str, f32, bool),
|
Integer(&'static str, i32, bool),
|
||||||
|
/// The argument is any string that doesn't contain spaces
|
||||||
|
Any(&'static str, bool),
|
||||||
/// The argument is a command name
|
/// The argument is a command name
|
||||||
Command(bool),
|
Command(bool),
|
||||||
/// This is the final argument, consuming all characters until the end of input.
|
/// This is the final argument, consuming all characters until the end of
|
||||||
|
/// input.
|
||||||
Message,
|
Message,
|
||||||
/// The argument is likely an enum. The associated values are
|
/// The argument is likely an enum. The associated values are
|
||||||
/// * label
|
/// * label
|
||||||
/// * Predefined string completions
|
/// * Predefined string completions
|
||||||
/// * Other completion types
|
/// * Other completion types
|
||||||
/// * whether it's optional
|
/// * whether it's optional
|
||||||
OneOf(&'static str, &'static [&'static str], Vec<Box<ArgumentSyntax>>, bool),
|
OneOf(
|
||||||
|
&'static str,
|
||||||
|
&'static [&'static str],
|
||||||
|
Vec<Box<ArgumentSpec>>,
|
||||||
|
bool,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ArgumentSyntax {
|
impl ArgumentSpec {
|
||||||
pub fn help_string(arg: &ArgumentSyntax) -> String {
|
pub fn usage_string(&self) -> String {
|
||||||
match arg {
|
match self {
|
||||||
ArgumentSyntax::PlayerName(optional) => {
|
ArgumentSpec::PlayerName(optional) => {
|
||||||
if *optional {
|
if *optional {
|
||||||
"[player]".to_string()
|
"[player]".to_string()
|
||||||
} else {
|
} else {
|
||||||
"<player>".to_string()
|
"<player>".to_string()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ArgumentSyntax::ItemSpec(optional) => {
|
ArgumentSpec::ItemSpec(optional) => {
|
||||||
if *optional {
|
if *optional {
|
||||||
"[item]".to_string()
|
"[item]".to_string()
|
||||||
} else {
|
} else {
|
||||||
"<item>".to_string()
|
"<item>".to_string()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ArgumentSyntax::Float(label, _, optional) => {
|
ArgumentSpec::Float(label, _, optional) => {
|
||||||
if *optional {
|
if *optional {
|
||||||
format!("[{}]", label)
|
format!("[{}]", label)
|
||||||
} else {
|
} else {
|
||||||
format!("<{}>", label)
|
format!("<{}>", label)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ArgumentSyntax::Integer(label, _, optional) => {
|
ArgumentSpec::Integer(label, _, optional) => {
|
||||||
if *optional {
|
if *optional {
|
||||||
format!("[{}]", label)
|
format!("[{}]", label)
|
||||||
} else {
|
} else {
|
||||||
format!("<{}>", label)
|
format!("<{}>", label)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ArgumentSyntax::Command(optional) => {
|
ArgumentSpec::Any(label, optional) => {
|
||||||
|
if *optional {
|
||||||
|
format!("[{}]", label)
|
||||||
|
} else {
|
||||||
|
format!("<{}>", label)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ArgumentSpec::Command(optional) => {
|
||||||
if *optional {
|
if *optional {
|
||||||
"[[/]command]".to_string()
|
"[[/]command]".to_string()
|
||||||
} else {
|
} else {
|
||||||
"<[/]command>".to_string()
|
"<[/]command>".to_string()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ArgumentSyntax::Message => {
|
ArgumentSpec::Message => "<message>".to_string(),
|
||||||
"<message>".to_string()
|
ArgumentSpec::OneOf(label, _, _, optional) => {
|
||||||
},
|
|
||||||
ArgumentSyntax::OneOf(label, _, _, optional) => {
|
|
||||||
if *optional {
|
if *optional {
|
||||||
format! {"[{}]", label}
|
format! {"[{}]", label}
|
||||||
} else {
|
} else {
|
||||||
@ -122,25 +375,26 @@ impl ArgumentSyntax {
|
|||||||
|
|
||||||
pub fn complete(&self, state: &State, part: &String) -> Vec<String> {
|
pub fn complete(&self, state: &State, part: &String) -> Vec<String> {
|
||||||
match self {
|
match self {
|
||||||
ArgumentSyntax::PlayerName(_) => (&state.ecs().read_storage::<Player>())
|
ArgumentSpec::PlayerName(_) => (&state.ecs().read_storage::<Player>())
|
||||||
.join()
|
.join()
|
||||||
.filter(|player| player.alias.starts_with(part))
|
.filter(|player| player.alias.starts_with(part))
|
||||||
.map(|player| player.alias.clone())
|
.map(|player| player.alias.clone())
|
||||||
.collect(),
|
.collect(),
|
||||||
ArgumentSyntax::ItemSpec(_) => assets::iterate()
|
ArgumentSpec::ItemSpec(_) => assets::iterate()
|
||||||
.filter(|asset| asset.starts_with(part))
|
.filter(|asset| asset.starts_with(part))
|
||||||
.map(|c| c.to_string())
|
.map(|c| c.to_string())
|
||||||
.collect(),
|
.collect(),
|
||||||
ArgumentSyntax::Float(_, x, _) => vec![format!("{}", x)],
|
ArgumentSpec::Float(_, x, _) => vec![format!("{}", x)],
|
||||||
ArgumentSyntax::Integer(_, x, _) => vec![format!("{}", x)],
|
ArgumentSpec::Integer(_, x, _) => vec![format!("{}", x)],
|
||||||
ArgumentSyntax::Command(_) => CHAT_COMMANDS
|
ArgumentSpec::Any(_, _) => vec![],
|
||||||
|
ArgumentSpec::Command(_) => CHAT_COMMANDS
|
||||||
.iter()
|
.iter()
|
||||||
.map(|com| com.keyword.clone())
|
.map(|com| com.keyword())
|
||||||
.filter(|kwd| kwd.starts_with(part) || format!("/{}", kwd).starts_with(part))
|
.filter(|kwd| kwd.starts_with(part) || format!("/{}", kwd).starts_with(part))
|
||||||
.map(|c| c.to_string())
|
.map(|c| c.to_string())
|
||||||
.collect(),
|
.collect(),
|
||||||
ArgumentSyntax::Message => vec![],
|
ArgumentSpec::Message => vec![],
|
||||||
ArgumentSyntax::OneOf(_, strings, alts, _) => {
|
ArgumentSpec::OneOf(_, strings, alts, _) => {
|
||||||
let string_completions = strings
|
let string_completions = strings
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|string| string.starts_with(part))
|
.filter(|string| string.starts_with(part))
|
||||||
@ -150,7 +404,7 @@ impl ArgumentSyntax {
|
|||||||
.flat_map(|b| (*b).complete(&state, part))
|
.flat_map(|b| (*b).complete(&state, part))
|
||||||
.map(|c| c.to_string());
|
.map(|c| c.to_string());
|
||||||
string_completions.chain(alt_completions).collect()
|
string_completions.chain(alt_completions).collect()
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,9 @@
|
|||||||
use crate::{Server, StateExt};
|
use crate::{Server, StateExt};
|
||||||
use chrono::{NaiveTime, Timelike};
|
use chrono::{NaiveTime, Timelike};
|
||||||
use common::{
|
use common::{
|
||||||
assets, comp,
|
assets,
|
||||||
|
cmd::{ChatCommand, CHAT_COMMANDS},
|
||||||
|
comp,
|
||||||
event::{EventBus, ServerEvent},
|
event::{EventBus, ServerEvent},
|
||||||
msg::{PlayerListUpdate, ServerMsg},
|
msg::{PlayerListUpdate, ServerMsg},
|
||||||
npc::{self, get_npc_name},
|
npc::{self, get_npc_name},
|
||||||
@ -20,274 +22,70 @@ use specs::{Builder, Entity as EcsEntity, Join, WorldExt};
|
|||||||
use vek::*;
|
use vek::*;
|
||||||
use world::util::Sampler;
|
use world::util::Sampler;
|
||||||
|
|
||||||
use lazy_static::lazy_static;
|
|
||||||
use log::error;
|
use log::error;
|
||||||
use scan_fmt::{scan_fmt, scan_fmt_some};
|
use scan_fmt::{scan_fmt, scan_fmt_some};
|
||||||
|
|
||||||
/// Struct representing a command that a user can run from server chat.
|
pub trait ChatCommandExt {
|
||||||
pub struct ChatCommand {
|
fn execute(&self, server: &mut Server, entity: EcsEntity, args: String);
|
||||||
/// The keyword used to invoke the command, omitting the leading '/'.
|
|
||||||
pub keyword: &'static str,
|
|
||||||
/// A format string for parsing arguments.
|
|
||||||
arg_fmt: &'static str,
|
|
||||||
/// A message that explains how the command is used.
|
|
||||||
help_string: &'static str,
|
|
||||||
/// A boolean that is used to check whether the command requires
|
|
||||||
/// administrator permissions or not.
|
|
||||||
needs_admin: bool,
|
|
||||||
/// Handler function called when the command is executed.
|
|
||||||
/// # Arguments
|
|
||||||
/// * `&mut Server` - the `Server` instance executing the command.
|
|
||||||
/// * `EcsEntity` - an `Entity` corresponding to the player that invoked the
|
|
||||||
/// command.
|
|
||||||
/// * `EcsEntity` - an `Entity` for the player on whom the command is
|
|
||||||
/// invoked. This differs from the previous argument when using /sudo
|
|
||||||
/// * `String` - a `String` containing the part of the command after the
|
|
||||||
/// keyword.
|
|
||||||
/// * `&ChatCommand` - the command to execute with the above arguments.
|
|
||||||
/// Handler functions must parse arguments from the the given `String`
|
|
||||||
/// (`scan_fmt!` is included for this purpose).
|
|
||||||
handler: fn(&mut Server, EcsEntity, EcsEntity, String, &ChatCommand),
|
|
||||||
}
|
}
|
||||||
|
impl ChatCommandExt for ChatCommand {
|
||||||
impl ChatCommand {
|
fn execute(&self, server: &mut Server, entity: EcsEntity, args: String) {
|
||||||
/// Creates a new chat command.
|
let cmd_data = self.data();
|
||||||
pub fn new(
|
if cmd_data.needs_admin && !server.entity_is_admin(entity) {
|
||||||
keyword: &'static str,
|
server.notify_client(
|
||||||
arg_fmt: &'static str,
|
entity,
|
||||||
help_string: &'static str,
|
ServerMsg::private(format!(
|
||||||
needs_admin: bool,
|
"You don't have permission to use '/{}'.",
|
||||||
handler: fn(&mut Server, EcsEntity, EcsEntity, String, &ChatCommand),
|
self.keyword()
|
||||||
) -> Self {
|
)),
|
||||||
Self {
|
);
|
||||||
keyword,
|
return;
|
||||||
arg_fmt,
|
|
||||||
help_string,
|
|
||||||
needs_admin,
|
|
||||||
handler,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calls the contained handler function, passing `&self` as the last
|
|
||||||
/// argument.
|
|
||||||
pub fn execute(&self, server: &mut Server, entity: EcsEntity, args: String) {
|
|
||||||
if self.needs_admin {
|
|
||||||
if !server.entity_is_admin(entity) {
|
|
||||||
server.notify_client(
|
|
||||||
entity,
|
|
||||||
ServerMsg::private(format!(
|
|
||||||
"You don't have permission to use '/{}'.",
|
|
||||||
self.keyword
|
|
||||||
)),
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
(self.handler)(server, entity, entity, args, self);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
(self.handler)(server, entity, entity, args, self);
|
get_handler(self)(server, entity, entity, args, &self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
type CommandHandler = fn(&mut Server, EcsEntity, EcsEntity, String, &ChatCommand);
|
||||||
/// Static list of chat commands available to the server.
|
fn get_handler(cmd: &ChatCommand) -> CommandHandler {
|
||||||
pub static ref CHAT_COMMANDS: Vec<ChatCommand> = vec![
|
match cmd {
|
||||||
ChatCommand::new(
|
ChatCommand::Adminify => handle_adminify,
|
||||||
"give_item",
|
ChatCommand::Alias => handle_alias,
|
||||||
"{} {d}",
|
ChatCommand::Build => handle_build,
|
||||||
"/give_item <path to item> [num]\n\
|
ChatCommand::Debug => handle_debug,
|
||||||
Example items: common/items/apple, common/items/debug/boost",
|
ChatCommand::DebugColumn => handle_debug_column,
|
||||||
true,
|
ChatCommand::Explosion => handle_explosion,
|
||||||
handle_give,),
|
ChatCommand::GiveExp => handle_give_exp,
|
||||||
ChatCommand::new(
|
ChatCommand::GiveItem => handle_give_item,
|
||||||
"jump",
|
ChatCommand::Goto => handle_goto,
|
||||||
"{d} {d} {d}",
|
ChatCommand::Health => handle_health,
|
||||||
"/jump <dx> <dy> <dz> : Offset your current position",
|
ChatCommand::Help => handle_help,
|
||||||
true,
|
ChatCommand::Jump => handle_jump,
|
||||||
handle_jump,
|
ChatCommand::Kill => handle_kill,
|
||||||
),
|
ChatCommand::KillNpcs => handle_kill_npcs,
|
||||||
ChatCommand::new(
|
ChatCommand::Lantern => handle_lantern,
|
||||||
"goto",
|
ChatCommand::Light => handle_light,
|
||||||
"{d} {d} {d}",
|
ChatCommand::Object => handle_object,
|
||||||
"/goto <x> <y> <z> : Teleport to a position",
|
ChatCommand::Players => handle_players,
|
||||||
true,
|
ChatCommand::RemoveLights => handle_remove_lights,
|
||||||
handle_goto,
|
ChatCommand::SetLevel => handle_set_level,
|
||||||
),
|
ChatCommand::Spawn => handle_spawn,
|
||||||
ChatCommand::new(
|
ChatCommand::Sudo => handle_sudo,
|
||||||
"alias",
|
ChatCommand::Tell => handle_tell,
|
||||||
"{}",
|
ChatCommand::Time => handle_time,
|
||||||
"/alias <name> : Change your alias",
|
ChatCommand::Tp => handle_tp,
|
||||||
false,
|
ChatCommand::Version => handle_version,
|
||||||
handle_alias,
|
ChatCommand::Waypoint => handle_waypoint,
|
||||||
),
|
}
|
||||||
ChatCommand::new(
|
|
||||||
"tp",
|
|
||||||
"{}",
|
|
||||||
"/tp <alias> : Teleport to another player",
|
|
||||||
true,
|
|
||||||
handle_tp,
|
|
||||||
),
|
|
||||||
ChatCommand::new(
|
|
||||||
"kill",
|
|
||||||
"{}",
|
|
||||||
"/kill : Kill yourself",
|
|
||||||
false,
|
|
||||||
handle_kill,
|
|
||||||
),
|
|
||||||
ChatCommand::new(
|
|
||||||
"time",
|
|
||||||
"{} {s}",
|
|
||||||
"/time <XY:XY> or [Time of day] : Set the time of day",
|
|
||||||
true,
|
|
||||||
handle_time,
|
|
||||||
),
|
|
||||||
ChatCommand::new(
|
|
||||||
"spawn",
|
|
||||||
"{} {} {d}",
|
|
||||||
"/spawn <alignment> <entity> [amount] : Spawn a test entity",
|
|
||||||
true,
|
|
||||||
handle_spawn,
|
|
||||||
),
|
|
||||||
ChatCommand::new(
|
|
||||||
"players",
|
|
||||||
"{}",
|
|
||||||
"/players : Lists players currently online",
|
|
||||||
false,
|
|
||||||
handle_players,
|
|
||||||
),
|
|
||||||
ChatCommand::new(
|
|
||||||
"help", "", "/help: Display this message", false, handle_help),
|
|
||||||
ChatCommand::new(
|
|
||||||
"health",
|
|
||||||
"{}",
|
|
||||||
"/health : Set your current health",
|
|
||||||
true,
|
|
||||||
handle_health,
|
|
||||||
),
|
|
||||||
ChatCommand::new(
|
|
||||||
"build",
|
|
||||||
"",
|
|
||||||
"/build : Toggles build mode on and off",
|
|
||||||
true,
|
|
||||||
handle_build,
|
|
||||||
),
|
|
||||||
ChatCommand::new(
|
|
||||||
"tell",
|
|
||||||
"{}",
|
|
||||||
"/tell <alias> <message>: Send a message to another player",
|
|
||||||
false,
|
|
||||||
handle_tell,
|
|
||||||
),
|
|
||||||
ChatCommand::new(
|
|
||||||
"killnpcs",
|
|
||||||
"{}",
|
|
||||||
"/killnpcs : Kill the NPCs",
|
|
||||||
true,
|
|
||||||
handle_killnpcs,
|
|
||||||
),
|
|
||||||
ChatCommand::new(
|
|
||||||
"object",
|
|
||||||
"{}",
|
|
||||||
"/object [Name]: Spawn an object",
|
|
||||||
true,
|
|
||||||
handle_object,
|
|
||||||
),
|
|
||||||
ChatCommand::new(
|
|
||||||
"light",
|
|
||||||
"{} {} {} {} {} {} {}",
|
|
||||||
"/light <opt: <<cr> <cg> <cb>> <<ox> <oy> <oz>> <<strength>>>: Spawn entity with light",
|
|
||||||
true,
|
|
||||||
handle_light,
|
|
||||||
),
|
|
||||||
ChatCommand::new(
|
|
||||||
"lantern",
|
|
||||||
"{} {} {} {}",
|
|
||||||
"/lantern <strength> [<r> <g> <b>]: Change your lantern's strength and color",
|
|
||||||
true,
|
|
||||||
handle_lantern,
|
|
||||||
),
|
|
||||||
ChatCommand::new(
|
|
||||||
"explosion",
|
|
||||||
"{}",
|
|
||||||
"/explosion <radius> : Explodes the ground around you",
|
|
||||||
true,
|
|
||||||
handle_explosion,
|
|
||||||
),
|
|
||||||
ChatCommand::new(
|
|
||||||
"waypoint",
|
|
||||||
"{}",
|
|
||||||
"/waypoint : Set your waypoint to your current position",
|
|
||||||
true,
|
|
||||||
handle_waypoint,
|
|
||||||
),
|
|
||||||
ChatCommand::new(
|
|
||||||
"adminify",
|
|
||||||
"{}",
|
|
||||||
"/adminify <playername> : Temporarily gives a player admin permissions or removes them",
|
|
||||||
true,
|
|
||||||
handle_adminify,
|
|
||||||
),
|
|
||||||
ChatCommand::new(
|
|
||||||
"debug_column",
|
|
||||||
"{} {}",
|
|
||||||
"/debug_column <x> <y> : Prints some debug information about a column",
|
|
||||||
false,
|
|
||||||
handle_debug_column,
|
|
||||||
),
|
|
||||||
ChatCommand::new(
|
|
||||||
"give_exp",
|
|
||||||
"{d} {}",
|
|
||||||
"/give_exp <amount> <playername?> : Give experience to yourself or specify a target player",
|
|
||||||
true,
|
|
||||||
handle_exp,
|
|
||||||
),
|
|
||||||
ChatCommand::new(
|
|
||||||
"set_level",
|
|
||||||
"{d} {}",
|
|
||||||
"/set_level <level> <playername?> : Set own Level or specify a target player",
|
|
||||||
true,
|
|
||||||
handle_level
|
|
||||||
),
|
|
||||||
ChatCommand::new(
|
|
||||||
"removelights",
|
|
||||||
"{}",
|
|
||||||
"/removelights [radius] : Removes all lights spawned by players",
|
|
||||||
true,
|
|
||||||
handle_remove_lights,
|
|
||||||
),
|
|
||||||
ChatCommand::new(
|
|
||||||
"debug",
|
|
||||||
"",
|
|
||||||
"/debug : Place all debug items into your pack.",
|
|
||||||
true,
|
|
||||||
handle_debug,
|
|
||||||
),
|
|
||||||
ChatCommand::new(
|
|
||||||
"sudo",
|
|
||||||
"{} {} {/.*/}",
|
|
||||||
"/sudo <player> /<command> [args...] : Run command as if you were another player",
|
|
||||||
true,
|
|
||||||
handle_sudo,
|
|
||||||
),
|
|
||||||
ChatCommand::new(
|
|
||||||
"version",
|
|
||||||
"",
|
|
||||||
"/version : Prints server version",
|
|
||||||
false,
|
|
||||||
handle_version,
|
|
||||||
),
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
fn handle_give_item(
|
||||||
fn handle_give(
|
|
||||||
server: &mut Server,
|
server: &mut Server,
|
||||||
client: EcsEntity,
|
client: EcsEntity,
|
||||||
target: EcsEntity,
|
target: EcsEntity,
|
||||||
args: String,
|
args: String,
|
||||||
action: &ChatCommand,
|
action: &ChatCommand,
|
||||||
) {
|
) {
|
||||||
if let (Some(item_name), give_amount_opt) = scan_fmt_some!(&args, action.arg_fmt, String, u32) {
|
if let (Some(item_name), give_amount_opt) = scan_fmt_some!(&args, &action.arg_fmt(), String, u32) {
|
||||||
let give_amount = give_amount_opt.unwrap_or(1);
|
let give_amount = give_amount_opt.unwrap_or(1);
|
||||||
if let Ok(item) = assets::load_cloned(&item_name) {
|
if let Ok(item) = assets::load_cloned(&item_name) {
|
||||||
let mut item: Item = item;
|
let mut item: Item = item;
|
||||||
@ -346,7 +144,7 @@ fn handle_give(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
server.notify_client(client, ServerMsg::private(String::from(action.help_string)));
|
server.notify_client(client, ServerMsg::private(String::from(action.help_string())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,7 +155,7 @@ fn handle_jump(
|
|||||||
args: String,
|
args: String,
|
||||||
action: &ChatCommand,
|
action: &ChatCommand,
|
||||||
) {
|
) {
|
||||||
if let Ok((x, y, z)) = scan_fmt!(&args, action.arg_fmt, f32, f32, f32) {
|
if let Ok((x, y, z)) = scan_fmt!(&args, &action.arg_fmt(), f32, f32, f32) {
|
||||||
match server.state.read_component_cloned::<comp::Pos>(target) {
|
match server.state.read_component_cloned::<comp::Pos>(target) {
|
||||||
Some(current_pos) => {
|
Some(current_pos) => {
|
||||||
server
|
server
|
||||||
@ -380,7 +178,7 @@ fn handle_goto(
|
|||||||
args: String,
|
args: String,
|
||||||
action: &ChatCommand,
|
action: &ChatCommand,
|
||||||
) {
|
) {
|
||||||
if let Ok((x, y, z)) = scan_fmt!(&args, action.arg_fmt, f32, f32, f32) {
|
if let Ok((x, y, z)) = scan_fmt!(&args, &action.arg_fmt(), f32, f32, f32) {
|
||||||
if server
|
if server
|
||||||
.state
|
.state
|
||||||
.read_component_cloned::<comp::Pos>(target)
|
.read_component_cloned::<comp::Pos>(target)
|
||||||
@ -397,7 +195,10 @@ fn handle_goto(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
server.notify_client(client, ServerMsg::private(String::from(action.help_string)));
|
server.notify_client(
|
||||||
|
client,
|
||||||
|
ServerMsg::private(String::from(action.help_string())),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -432,7 +233,7 @@ fn handle_time(
|
|||||||
args: String,
|
args: String,
|
||||||
action: &ChatCommand,
|
action: &ChatCommand,
|
||||||
) {
|
) {
|
||||||
let time = scan_fmt_some!(&args, action.arg_fmt, String);
|
let time = scan_fmt_some!(&args, &action.arg_fmt(), String);
|
||||||
let new_time = match time.as_ref().map(|s| s.as_str()) {
|
let new_time = match time.as_ref().map(|s| s.as_str()) {
|
||||||
Some("midnight") => NaiveTime::from_hms(0, 0, 0),
|
Some("midnight") => NaiveTime::from_hms(0, 0, 0),
|
||||||
Some("night") => NaiveTime::from_hms(20, 0, 0),
|
Some("night") => NaiveTime::from_hms(20, 0, 0),
|
||||||
@ -490,7 +291,7 @@ fn handle_health(
|
|||||||
args: String,
|
args: String,
|
||||||
action: &ChatCommand,
|
action: &ChatCommand,
|
||||||
) {
|
) {
|
||||||
if let Ok(hp) = scan_fmt!(&args, action.arg_fmt, u32) {
|
if let Ok(hp) = scan_fmt!(&args, &action.arg_fmt(), u32) {
|
||||||
if let Some(stats) = server
|
if let Some(stats) = server
|
||||||
.state
|
.state
|
||||||
.ecs()
|
.ecs()
|
||||||
@ -519,7 +320,7 @@ fn handle_alias(
|
|||||||
args: String,
|
args: String,
|
||||||
action: &ChatCommand,
|
action: &ChatCommand,
|
||||||
) {
|
) {
|
||||||
if let Ok(alias) = scan_fmt!(&args, action.arg_fmt, String) {
|
if let Ok(alias) = scan_fmt!(&args, &action.arg_fmt(), String) {
|
||||||
server
|
server
|
||||||
.state
|
.state
|
||||||
.ecs_mut()
|
.ecs_mut()
|
||||||
@ -540,7 +341,10 @@ fn handle_alias(
|
|||||||
server.state.notify_registered_clients(msg);
|
server.state.notify_registered_clients(msg);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
server.notify_client(client, ServerMsg::private(String::from(action.help_string)));
|
server.notify_client(
|
||||||
|
client,
|
||||||
|
ServerMsg::private(String::from(action.help_string())),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -551,7 +355,7 @@ fn handle_tp(
|
|||||||
args: String,
|
args: String,
|
||||||
action: &ChatCommand,
|
action: &ChatCommand,
|
||||||
) {
|
) {
|
||||||
if let Ok(alias) = scan_fmt!(&args, action.arg_fmt, String) {
|
if let Ok(alias) = scan_fmt!(&args, &action.arg_fmt(), String) {
|
||||||
let ecs = server.state.ecs();
|
let ecs = server.state.ecs();
|
||||||
let opt_player = (&ecs.entities(), &ecs.read_storage::<comp::Player>())
|
let opt_player = (&ecs.entities(), &ecs.read_storage::<comp::Player>())
|
||||||
.join()
|
.join()
|
||||||
@ -576,7 +380,7 @@ fn handle_tp(
|
|||||||
);
|
);
|
||||||
server.notify_client(
|
server.notify_client(
|
||||||
client,
|
client,
|
||||||
ServerMsg::private(String::from(action.help_string)),
|
ServerMsg::private(String::from(action.help_string())),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -585,7 +389,10 @@ fn handle_tp(
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
server.notify_client(client, ServerMsg::private(String::from(action.help_string)));
|
server.notify_client(
|
||||||
|
client,
|
||||||
|
ServerMsg::private(String::from(action.help_string())),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -596,7 +403,7 @@ fn handle_spawn(
|
|||||||
args: String,
|
args: String,
|
||||||
action: &ChatCommand,
|
action: &ChatCommand,
|
||||||
) {
|
) {
|
||||||
match scan_fmt_some!(&args, action.arg_fmt, String, npc::NpcBody, String) {
|
match scan_fmt_some!(&args, &action.arg_fmt(), String, npc::NpcBody, String) {
|
||||||
(Some(opt_align), Some(npc::NpcBody(id, mut body)), opt_amount) => {
|
(Some(opt_align), Some(npc::NpcBody(id, mut body)), opt_amount) => {
|
||||||
if let Some(alignment) = parse_alignment(target, &opt_align) {
|
if let Some(alignment) = parse_alignment(target, &opt_align) {
|
||||||
let amount = opt_amount
|
let amount = opt_amount
|
||||||
@ -659,7 +466,10 @@ fn handle_spawn(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
server.notify_client(client, ServerMsg::private(String::from(action.help_string)));
|
server.notify_client(
|
||||||
|
client,
|
||||||
|
ServerMsg::private(String::from(action.help_string())),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -733,12 +543,16 @@ fn handle_help(
|
|||||||
server: &mut Server,
|
server: &mut Server,
|
||||||
client: EcsEntity,
|
client: EcsEntity,
|
||||||
_target: EcsEntity,
|
_target: EcsEntity,
|
||||||
_args: String,
|
args: String,
|
||||||
_action: &ChatCommand,
|
action: &ChatCommand,
|
||||||
) {
|
) {
|
||||||
for cmd in CHAT_COMMANDS.iter() {
|
if let Some(cmd) = scan_fmt_some!(&args, &action.arg_fmt(), ChatCommand) {
|
||||||
if !cmd.needs_admin || server.entity_is_admin(client) {
|
server.notify_client(client, ServerMsg::private(String::from(cmd.help_string())));
|
||||||
server.notify_client(client, ServerMsg::private(String::from(cmd.help_string)));
|
} else {
|
||||||
|
for cmd in CHAT_COMMANDS.iter() {
|
||||||
|
if !cmd.needs_admin() || server.entity_is_admin(client) {
|
||||||
|
server.notify_client(client, ServerMsg::private(String::from(cmd.help_string())));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -753,7 +567,7 @@ fn parse_alignment(owner: EcsEntity, alignment: &str) -> Option<comp::Alignment>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_killnpcs(
|
fn handle_kill_npcs(
|
||||||
server: &mut Server,
|
server: &mut Server,
|
||||||
client: EcsEntity,
|
client: EcsEntity,
|
||||||
_target: EcsEntity,
|
_target: EcsEntity,
|
||||||
@ -781,9 +595,9 @@ fn handle_object(
|
|||||||
client: EcsEntity,
|
client: EcsEntity,
|
||||||
target: EcsEntity,
|
target: EcsEntity,
|
||||||
args: String,
|
args: String,
|
||||||
_action: &ChatCommand,
|
action: &ChatCommand,
|
||||||
) {
|
) {
|
||||||
let obj_type = scan_fmt!(&args, _action.arg_fmt, String);
|
let obj_type = scan_fmt!(&args, &action.arg_fmt(), String);
|
||||||
|
|
||||||
let pos = server
|
let pos = server
|
||||||
.state
|
.state
|
||||||
@ -894,7 +708,7 @@ fn handle_light(
|
|||||||
action: &ChatCommand,
|
action: &ChatCommand,
|
||||||
) {
|
) {
|
||||||
let (opt_r, opt_g, opt_b, opt_x, opt_y, opt_z, opt_s) =
|
let (opt_r, opt_g, opt_b, opt_x, opt_y, opt_z, opt_s) =
|
||||||
scan_fmt_some!(&args, action.arg_fmt, f32, f32, f32, f32, f32, f32, f32);
|
scan_fmt_some!(&args, &action.arg_fmt(), f32, f32, f32, f32, f32, f32, f32);
|
||||||
|
|
||||||
let mut light_emitter = comp::LightEmitter::default();
|
let mut light_emitter = comp::LightEmitter::default();
|
||||||
let mut light_offset_opt = None;
|
let mut light_offset_opt = None;
|
||||||
@ -955,7 +769,8 @@ fn handle_lantern(
|
|||||||
args: String,
|
args: String,
|
||||||
action: &ChatCommand,
|
action: &ChatCommand,
|
||||||
) {
|
) {
|
||||||
if let (Some(s), r, g, b) = scan_fmt_some!(&args, action.arg_fmt, f32, f32, f32, f32) {
|
println!("args: '{}', fmt: '{}'", &args, &action.arg_fmt());
|
||||||
|
if let (Some(s), r, g, b) = scan_fmt_some!(&args, &action.arg_fmt(), f32, f32, f32, f32) {
|
||||||
if let Some(light) = server
|
if let Some(light) = server
|
||||||
.state
|
.state
|
||||||
.ecs()
|
.ecs()
|
||||||
@ -987,7 +802,10 @@ fn handle_lantern(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
server.notify_client(client, ServerMsg::private(String::from(action.help_string)));
|
server.notify_client(
|
||||||
|
client,
|
||||||
|
ServerMsg::private(String::from(action.help_string())),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -998,7 +816,7 @@ fn handle_explosion(
|
|||||||
args: String,
|
args: String,
|
||||||
action: &ChatCommand,
|
action: &ChatCommand,
|
||||||
) {
|
) {
|
||||||
let power = scan_fmt!(&args, action.arg_fmt, f32).unwrap_or(8.0);
|
let power = scan_fmt!(&args, &action.arg_fmt(), f32).unwrap_or(8.0);
|
||||||
|
|
||||||
if power > 512.0 {
|
if power > 512.0 {
|
||||||
server.notify_client(
|
server.notify_client(
|
||||||
@ -1062,7 +880,7 @@ fn handle_adminify(
|
|||||||
args: String,
|
args: String,
|
||||||
action: &ChatCommand,
|
action: &ChatCommand,
|
||||||
) {
|
) {
|
||||||
if let Ok(alias) = scan_fmt!(&args, action.arg_fmt, String) {
|
if let Ok(alias) = scan_fmt!(&args, &action.arg_fmt(), String) {
|
||||||
let ecs = server.state.ecs();
|
let ecs = server.state.ecs();
|
||||||
let opt_player = (&ecs.entities(), &ecs.read_storage::<comp::Player>())
|
let opt_player = (&ecs.entities(), &ecs.read_storage::<comp::Player>())
|
||||||
.join()
|
.join()
|
||||||
@ -1082,11 +900,17 @@ fn handle_adminify(
|
|||||||
client,
|
client,
|
||||||
ServerMsg::private(format!("Player '{}' not found!", alias)),
|
ServerMsg::private(format!("Player '{}' not found!", alias)),
|
||||||
);
|
);
|
||||||
server.notify_client(client, ServerMsg::private(String::from(action.help_string)));
|
server.notify_client(
|
||||||
|
client,
|
||||||
|
ServerMsg::private(String::from(action.help_string())),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
server.notify_client(client, ServerMsg::private(String::from(action.help_string)));
|
server.notify_client(
|
||||||
|
client,
|
||||||
|
ServerMsg::private(String::from(action.help_string())),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1104,7 +928,7 @@ fn handle_tell(
|
|||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if let Ok(alias) = scan_fmt!(&args, action.arg_fmt, String) {
|
if let Ok(alias) = scan_fmt!(&args, &action.arg_fmt(), String) {
|
||||||
let ecs = server.state.ecs();
|
let ecs = server.state.ecs();
|
||||||
let msg = &args[alias.len()..args.len()];
|
let msg = &args[alias.len()..args.len()];
|
||||||
if let Some(player) = (&ecs.entities(), &ecs.read_storage::<comp::Player>())
|
if let Some(player) = (&ecs.entities(), &ecs.read_storage::<comp::Player>())
|
||||||
@ -1152,7 +976,10 @@ fn handle_tell(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
server.notify_client(client, ServerMsg::private(String::from(action.help_string)));
|
server.notify_client(
|
||||||
|
client,
|
||||||
|
ServerMsg::private(String::from(action.help_string())),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1180,7 +1007,7 @@ fn handle_debug_column(
|
|||||||
) {
|
) {
|
||||||
let sim = server.world.sim();
|
let sim = server.world.sim();
|
||||||
let sampler = server.world.sample_columns();
|
let sampler = server.world.sample_columns();
|
||||||
if let Ok((x, y)) = scan_fmt!(&args, action.arg_fmt, i32, i32) {
|
if let Ok((x, y)) = scan_fmt!(&args, &action.arg_fmt(), i32, i32) {
|
||||||
let wpos = Vec2::new(x, y);
|
let wpos = Vec2::new(x, y);
|
||||||
/* let chunk_pos = wpos.map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| {
|
/* let chunk_pos = wpos.map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| {
|
||||||
e / sz as i32
|
e / sz as i32
|
||||||
@ -1244,7 +1071,10 @@ spawn_rate {:?} "#,
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
server.notify_client(client, ServerMsg::private(String::from(action.help_string)));
|
server.notify_client(
|
||||||
|
client,
|
||||||
|
ServerMsg::private(String::from(action.help_string())),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1264,14 +1094,14 @@ fn find_target(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_exp(
|
fn handle_give_exp(
|
||||||
server: &mut Server,
|
server: &mut Server,
|
||||||
client: EcsEntity,
|
client: EcsEntity,
|
||||||
target: EcsEntity,
|
target: EcsEntity,
|
||||||
args: String,
|
args: String,
|
||||||
action: &ChatCommand,
|
action: &ChatCommand,
|
||||||
) {
|
) {
|
||||||
let (a_exp, a_alias) = scan_fmt_some!(&args, action.arg_fmt, i64, String);
|
let (a_exp, a_alias) = scan_fmt_some!(&args, &action.arg_fmt(), i64, String);
|
||||||
|
|
||||||
if let Some(exp) = a_exp {
|
if let Some(exp) = a_exp {
|
||||||
let ecs = server.state.ecs_mut();
|
let ecs = server.state.ecs_mut();
|
||||||
@ -1298,14 +1128,14 @@ fn handle_exp(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_level(
|
fn handle_set_level(
|
||||||
server: &mut Server,
|
server: &mut Server,
|
||||||
client: EcsEntity,
|
client: EcsEntity,
|
||||||
target: EcsEntity,
|
target: EcsEntity,
|
||||||
args: String,
|
args: String,
|
||||||
action: &ChatCommand,
|
action: &ChatCommand,
|
||||||
) {
|
) {
|
||||||
let (a_lvl, a_alias) = scan_fmt_some!(&args, action.arg_fmt, u32, String);
|
let (a_lvl, a_alias) = scan_fmt_some!(&args, &action.arg_fmt(), u32, String);
|
||||||
|
|
||||||
if let Some(lvl) = a_lvl {
|
if let Some(lvl) = a_lvl {
|
||||||
let ecs = server.state.ecs_mut();
|
let ecs = server.state.ecs_mut();
|
||||||
@ -1378,7 +1208,7 @@ fn handle_remove_lights(
|
|||||||
args: String,
|
args: String,
|
||||||
action: &ChatCommand,
|
action: &ChatCommand,
|
||||||
) {
|
) {
|
||||||
let opt_radius = scan_fmt_some!(&args, action.arg_fmt, f32);
|
let opt_radius = scan_fmt_some!(&args, &action.arg_fmt(), f32);
|
||||||
let opt_player_pos = server.state.read_component_cloned::<comp::Pos>(target);
|
let opt_player_pos = server.state.read_component_cloned::<comp::Pos>(target);
|
||||||
let mut to_delete = vec![];
|
let mut to_delete = vec![];
|
||||||
|
|
||||||
@ -1430,7 +1260,7 @@ fn handle_sudo(
|
|||||||
action: &ChatCommand,
|
action: &ChatCommand,
|
||||||
) {
|
) {
|
||||||
if let (Some(player_alias), Some(cmd), cmd_args) =
|
if let (Some(player_alias), Some(cmd), cmd_args) =
|
||||||
scan_fmt_some!(&args, action.arg_fmt, String, String, String)
|
scan_fmt_some!(&args, &action.arg_fmt(), String, String, String)
|
||||||
{
|
{
|
||||||
let cmd_args = cmd_args.unwrap_or(String::from(""));
|
let cmd_args = cmd_args.unwrap_or(String::from(""));
|
||||||
let cmd = if cmd.chars().next() == Some('/') {
|
let cmd = if cmd.chars().next() == Some('/') {
|
||||||
@ -1438,14 +1268,14 @@ fn handle_sudo(
|
|||||||
} else {
|
} else {
|
||||||
cmd
|
cmd
|
||||||
};
|
};
|
||||||
if let Some(action) = CHAT_COMMANDS.iter().find(|c| c.keyword == cmd) {
|
if let Some(action) = CHAT_COMMANDS.iter().find(|c| c.keyword() == cmd) {
|
||||||
let ecs = server.state.ecs();
|
let ecs = server.state.ecs();
|
||||||
let entity_opt = (&ecs.entities(), &ecs.read_storage::<comp::Player>())
|
let entity_opt = (&ecs.entities(), &ecs.read_storage::<comp::Player>())
|
||||||
.join()
|
.join()
|
||||||
.find(|(_, player)| player.alias == player_alias)
|
.find(|(_, player)| player.alias == player_alias)
|
||||||
.map(|(entity, _)| entity);
|
.map(|(entity, _)| entity);
|
||||||
if let Some(entity) = entity_opt {
|
if let Some(entity) = entity_opt {
|
||||||
(action.handler)(server, client, entity, cmd_args, action);
|
get_handler(action)(server, client, entity, cmd_args, action);
|
||||||
} else {
|
} else {
|
||||||
server.notify_client(
|
server.notify_client(
|
||||||
client,
|
client,
|
||||||
@ -1459,7 +1289,10 @@ fn handle_sudo(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
server.notify_client(client, ServerMsg::private(String::from(action.help_string)));
|
server.notify_client(
|
||||||
|
client,
|
||||||
|
ServerMsg::private(String::from(action.help_string())),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1479,3 +1312,4 @@ fn handle_version(
|
|||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,11 +22,12 @@ use crate::{
|
|||||||
auth_provider::AuthProvider,
|
auth_provider::AuthProvider,
|
||||||
chunk_generator::ChunkGenerator,
|
chunk_generator::ChunkGenerator,
|
||||||
client::{Client, RegionSubscription},
|
client::{Client, RegionSubscription},
|
||||||
cmd::CHAT_COMMANDS,
|
cmd::ChatCommandExt,
|
||||||
state_ext::StateExt,
|
state_ext::StateExt,
|
||||||
sys::sentinel::{DeletedEntities, TrackedComps},
|
sys::sentinel::{DeletedEntities, TrackedComps},
|
||||||
};
|
};
|
||||||
use common::{
|
use common::{
|
||||||
|
cmd::ChatCommand,
|
||||||
comp,
|
comp,
|
||||||
event::{EventBus, ServerEvent},
|
event::{EventBus, ServerEvent},
|
||||||
msg::{ClientMsg, ClientState, ServerInfo, ServerMsg},
|
msg::{ClientMsg, ClientState, ServerInfo, ServerMsg},
|
||||||
@ -534,18 +535,16 @@ impl Server {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Find the command object and run its handler.
|
// Find the command object and run its handler.
|
||||||
let action_opt = CHAT_COMMANDS.iter().find(|x| x.keyword == kwd);
|
if let Ok(command) = kwd.parse::<ChatCommand>() {
|
||||||
match action_opt {
|
command.execute(self, entity, args);
|
||||||
Some(action) => action.execute(self, entity, args),
|
} else {
|
||||||
// Unknown command
|
self.notify_client(
|
||||||
None => {
|
entity,
|
||||||
if let Some(client) = self.state.ecs().write_storage::<Client>().get_mut(entity) {
|
ServerMsg::private(format!(
|
||||||
client.notify(ServerMsg::private(format!(
|
"Unknown command '/{}'.\nType '/help' for available commands",
|
||||||
"Unknown command '/{}'.\nType '/help' for available commands",
|
kwd
|
||||||
kwd
|
)),
|
||||||
)));
|
);
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user