Implement /sudo command

This commit is contained in:
CapsizeGlimmer 2020-04-23 22:36:19 -04:00
parent 1831c0e20c
commit bbbe03a033
2 changed files with 329 additions and 124 deletions

View File

@ -61,6 +61,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added waypoints next to dungeons
- Made players spawn in towns
- Added non-uniform block heights
- Added `/sudo` command
### Changed

View File

@ -40,12 +40,14 @@ pub struct ChatCommand {
/// * `&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, String, &ChatCommand),
handler: fn(&mut Server, EcsEntity, EcsEntity, String, &ChatCommand),
}
impl ChatCommand {
@ -55,7 +57,7 @@ impl ChatCommand {
arg_fmt: &'static str,
help_string: &'static str,
needs_admin: bool,
handler: fn(&mut Server, EcsEntity, String, &ChatCommand),
handler: fn(&mut Server, EcsEntity, EcsEntity, String, &ChatCommand),
) -> Self {
Self {
keyword,
@ -80,10 +82,10 @@ impl ChatCommand {
);
return;
} else {
(self.handler)(server, entity, args, self);
(self.handler)(server, entity, entity, args, self);
}
} else {
(self.handler)(server, entity, args, self);
(self.handler)(server, entity, entity, args, self);
}
}
}
@ -261,79 +263,116 @@ lazy_static! {
true,
handle_debug,
),
ChatCommand::new(
"sudo",
"{} {} {/.*/}",
"/sudo <player> /<command> [args...] : Run command as if you were another player",
true,
handle_sudo,
),
];
}
fn handle_give(server: &mut Server, entity: EcsEntity, args: String, _action: &ChatCommand) {
fn handle_give(
server: &mut Server,
client: EcsEntity,
target: EcsEntity,
args: String,
_action: &ChatCommand,
) {
if let Ok(item) = assets::load_cloned(&args) {
server
.state
.ecs()
.write_storage::<comp::Inventory>()
.get_mut(entity)
.get_mut(target)
.map(|inv| inv.push(item));
let _ = server
.state
.ecs()
.write_storage::<comp::InventoryUpdate>()
.insert(
entity,
target,
comp::InventoryUpdate::new(comp::InventoryUpdateEvent::Given),
);
} else {
server.notify_client(entity, ServerMsg::private(String::from("Invalid item!")));
server.notify_client(client, ServerMsg::private(String::from("Invalid item!")));
}
}
fn handle_jump(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) {
fn handle_jump(
server: &mut Server,
client: EcsEntity,
target: EcsEntity,
args: String,
action: &ChatCommand,
) {
if let Ok((x, y, z)) = scan_fmt!(&args, action.arg_fmt, f32, f32, f32) {
match server.state.read_component_cloned::<comp::Pos>(entity) {
match server.state.read_component_cloned::<comp::Pos>(target) {
Some(current_pos) => {
server
.state
.write_component(entity, comp::Pos(current_pos.0 + Vec3::new(x, y, z)));
server.state.write_component(entity, comp::ForceUpdate);
.write_component(target, comp::Pos(current_pos.0 + Vec3::new(x, y, z)));
server.state.write_component(target, comp::ForceUpdate);
},
None => server.notify_client(
entity,
client,
ServerMsg::private(String::from("You have no position.")),
),
}
}
}
fn handle_goto(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) {
fn handle_goto(
server: &mut Server,
client: EcsEntity,
target: EcsEntity,
args: String,
action: &ChatCommand,
) {
if let Ok((x, y, z)) = scan_fmt!(&args, action.arg_fmt, f32, f32, f32) {
if server
.state
.read_component_cloned::<comp::Pos>(entity)
.read_component_cloned::<comp::Pos>(target)
.is_some()
{
server
.state
.write_component(entity, comp::Pos(Vec3::new(x, y, z)));
server.state.write_component(entity, comp::ForceUpdate);
.write_component(target, comp::Pos(Vec3::new(x, y, z)));
server.state.write_component(target, comp::ForceUpdate);
} else {
server.notify_client(
entity,
client,
ServerMsg::private(String::from("You have no position.")),
);
}
} else {
server.notify_client(entity, ServerMsg::private(String::from(action.help_string)));
server.notify_client(client, ServerMsg::private(String::from(action.help_string)));
}
}
fn handle_kill(server: &mut Server, entity: EcsEntity, _args: String, _action: &ChatCommand) {
fn handle_kill(
server: &mut Server,
_client: EcsEntity,
target: EcsEntity,
_args: String,
_action: &ChatCommand,
) {
server
.state
.ecs_mut()
.write_storage::<comp::Stats>()
.get_mut(entity)
.get_mut(target)
.map(|s| s.health.set_to(0, comp::HealthSource::Suicide));
}
fn handle_time(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) {
fn handle_time(
server: &mut Server,
client: EcsEntity,
_target: EcsEntity,
args: String,
action: &ChatCommand,
) {
let time = scan_fmt_some!(&args, action.arg_fmt, String);
let new_time = match time.as_ref().map(|s| s.as_str()) {
Some("midnight") => NaiveTime::from_hms(0, 0, 0),
@ -349,7 +388,7 @@ fn handle_time(server: &mut Server, entity: EcsEntity, args: String, action: &Ch
Ok(time) => time,
Err(_) => {
server.notify_client(
entity,
client,
ServerMsg::private(format!("'{}' is not a valid time.", n)),
);
return;
@ -368,7 +407,7 @@ fn handle_time(server: &mut Server, entity: EcsEntity, args: String, action: &Ch
Some(time) => format!("It is {}", time.format("%H:%M").to_string()),
None => String::from("Unknown Time"),
};
server.notify_client(entity, ServerMsg::private(msg));
server.notify_client(client, ServerMsg::private(msg));
return;
},
};
@ -377,7 +416,7 @@ fn handle_time(server: &mut Server, entity: EcsEntity, args: String, action: &Ch
new_time.num_seconds_from_midnight() as f64;
server.notify_client(
entity,
client,
ServerMsg::private(format!(
"Time changed to: {}",
new_time.format("%H:%M").to_string()
@ -385,43 +424,55 @@ fn handle_time(server: &mut Server, entity: EcsEntity, args: String, action: &Ch
);
}
fn handle_health(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) {
fn handle_health(
server: &mut Server,
client: EcsEntity,
target: EcsEntity,
args: String,
action: &ChatCommand,
) {
if let Ok(hp) = scan_fmt!(&args, action.arg_fmt, u32) {
if let Some(stats) = server
.state
.ecs()
.write_storage::<comp::Stats>()
.get_mut(entity)
.get_mut(target)
{
stats.health.set_to(hp, comp::HealthSource::Command);
} else {
server.notify_client(
entity,
client,
ServerMsg::private(String::from("You have no health.")),
);
}
} else {
server.notify_client(
entity,
client,
ServerMsg::private(String::from("You must specify health amount!")),
);
}
}
fn handle_alias(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) {
fn handle_alias(
server: &mut Server,
client: EcsEntity,
target: EcsEntity,
args: String,
action: &ChatCommand,
) {
if let Ok(alias) = scan_fmt!(&args, action.arg_fmt, String) {
server
.state
.ecs_mut()
.write_storage::<comp::Player>()
.get_mut(entity)
.get_mut(target)
.map(|player| player.alias = alias);
// Update name on client player lists
let ecs = server.state.ecs();
if let (Some(uid), Some(player)) = (
ecs.read_storage::<Uid>().get(entity),
ecs.read_storage::<comp::Player>().get(entity),
ecs.read_storage::<Uid>().get(target),
ecs.read_storage::<comp::Player>().get(target),
) {
let msg = ServerMsg::PlayerListUpdate(PlayerListUpdate::Alias(
(*uid).into(),
@ -430,60 +481,72 @@ fn handle_alias(server: &mut Server, entity: EcsEntity, args: String, action: &C
server.state.notify_registered_clients(msg);
}
} else {
server.notify_client(entity, ServerMsg::private(String::from(action.help_string)));
server.notify_client(client, ServerMsg::private(String::from(action.help_string)));
}
}
fn handle_tp(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) {
fn handle_tp(
server: &mut Server,
client: EcsEntity,
target: EcsEntity,
args: String,
action: &ChatCommand,
) {
if let Ok(alias) = scan_fmt!(&args, action.arg_fmt, String) {
let ecs = server.state.ecs();
let opt_player = (&ecs.entities(), &ecs.read_storage::<comp::Player>())
.join()
.find(|(_, player)| player.alias == alias)
.map(|(entity, _)| entity);
match server.state.read_component_cloned::<comp::Pos>(entity) {
match server.state.read_component_cloned::<comp::Pos>(target) {
Some(_pos) => match opt_player {
Some(player) => match server.state.read_component_cloned::<comp::Pos>(player) {
Some(pos) => {
server.state.write_component(entity, pos);
server.state.write_component(entity, comp::ForceUpdate);
server.state.write_component(target, pos);
server.state.write_component(target, comp::ForceUpdate);
},
None => server.notify_client(
entity,
client,
ServerMsg::private(format!("Unable to teleport to player '{}'!", alias)),
),
},
None => {
server.notify_client(
entity,
client,
ServerMsg::private(format!("Player '{}' not found!", alias)),
);
server.notify_client(
entity,
client,
ServerMsg::private(String::from(action.help_string)),
);
},
},
None => {
server.notify_client(entity, ServerMsg::private(format!("You have no position!")));
server.notify_client(client, ServerMsg::private(format!("You have no position!")));
},
}
} else {
server.notify_client(entity, ServerMsg::private(String::from(action.help_string)));
server.notify_client(client, ServerMsg::private(String::from(action.help_string)));
}
}
fn handle_spawn(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) {
fn handle_spawn(
server: &mut Server,
client: EcsEntity,
target: EcsEntity,
args: String,
action: &ChatCommand,
) {
match scan_fmt_some!(&args, action.arg_fmt, String, npc::NpcBody, String) {
(Some(opt_align), Some(npc::NpcBody(id, mut body)), opt_amount) => {
if let Some(alignment) = parse_alignment(entity, &opt_align) {
if let Some(alignment) = parse_alignment(target, &opt_align) {
let amount = opt_amount
.and_then(|a| a.parse().ok())
.filter(|x| *x > 0)
.unwrap_or(1)
.min(10);
match server.state.read_component_cloned::<comp::Pos>(entity) {
match server.state.read_component_cloned::<comp::Pos>(target) {
Some(pos) => {
let agent =
if let comp::Alignment::Owned(_) | comp::Alignment::Npc = alignment {
@ -517,7 +580,7 @@ fn handle_spawn(server: &mut Server, entity: EcsEntity, args: String, action: &C
if let Some(uid) = server.state.ecs().uid_from_entity(new_entity) {
server.notify_client(
entity,
client,
ServerMsg::private(
format!("Spawned entity with ID: {}", uid).to_owned(),
),
@ -525,24 +588,30 @@ fn handle_spawn(server: &mut Server, entity: EcsEntity, args: String, action: &C
}
}
server.notify_client(
entity,
client,
ServerMsg::private(format!("Spawned {} entities", amount).to_owned()),
);
},
None => server.notify_client(
entity,
client,
ServerMsg::private("You have no position!".to_owned()),
),
}
}
},
_ => {
server.notify_client(entity, ServerMsg::private(String::from(action.help_string)));
server.notify_client(client, ServerMsg::private(String::from(action.help_string)));
},
}
}
fn handle_players(server: &mut Server, entity: EcsEntity, _args: String, _action: &ChatCommand) {
fn handle_players(
server: &mut Server,
client: EcsEntity,
_target: EcsEntity,
_args: String,
_action: &ChatCommand,
) {
let ecs = server.state.ecs();
let players = ecs.read_storage::<comp::Player>();
let count = players.join().count();
@ -560,26 +629,32 @@ fn handle_players(server: &mut Server, entity: EcsEntity, _args: String, _action
s
});
server.notify_client(entity, ServerMsg::private(header_message + &player_list));
server.notify_client(client, ServerMsg::private(header_message + &player_list));
} else {
server.notify_client(entity, ServerMsg::private(header_message));
server.notify_client(client, ServerMsg::private(header_message));
}
}
fn handle_build(server: &mut Server, entity: EcsEntity, _args: String, _action: &ChatCommand) {
fn handle_build(
server: &mut Server,
client: EcsEntity,
target: EcsEntity,
_args: String,
_action: &ChatCommand,
) {
if server
.state
.read_storage::<comp::CanBuild>()
.get(entity)
.get(target)
.is_some()
{
server
.state
.ecs()
.write_storage::<comp::CanBuild>()
.remove(entity);
.remove(target);
server.notify_client(
entity,
client,
ServerMsg::private(String::from("Toggled off build mode!")),
);
} else {
@ -587,18 +662,24 @@ fn handle_build(server: &mut Server, entity: EcsEntity, _args: String, _action:
.state
.ecs()
.write_storage::<comp::CanBuild>()
.insert(entity, comp::CanBuild);
.insert(target, comp::CanBuild);
server.notify_client(
entity,
client,
ServerMsg::private(String::from("Toggled on build mode!")),
);
}
}
fn handle_help(server: &mut Server, entity: EcsEntity, _args: String, _action: &ChatCommand) {
fn handle_help(
server: &mut Server,
client: EcsEntity,
_target: EcsEntity,
_args: String,
_action: &ChatCommand,
) {
for cmd in CHAT_COMMANDS.iter() {
if !cmd.needs_admin || server.entity_is_admin(entity) {
server.notify_client(entity, ServerMsg::private(String::from(cmd.help_string)));
if !cmd.needs_admin || server.entity_is_admin(client) {
server.notify_client(client, ServerMsg::private(String::from(cmd.help_string)));
}
}
}
@ -613,7 +694,13 @@ fn parse_alignment(owner: EcsEntity, alignment: &str) -> Option<comp::Alignment>
}
}
fn handle_killnpcs(server: &mut Server, entity: EcsEntity, _args: String, _action: &ChatCommand) {
fn handle_killnpcs(
server: &mut Server,
client: EcsEntity,
_target: EcsEntity,
_args: String,
_action: &ChatCommand,
) {
let ecs = server.state.ecs();
let mut stats = ecs.write_storage::<comp::Stats>();
let players = ecs.read_storage::<comp::Player>();
@ -627,23 +714,29 @@ fn handle_killnpcs(server: &mut Server, entity: EcsEntity, _args: String, _actio
} else {
"No NPCs on server.".to_string()
};
server.notify_client(entity, ServerMsg::private(text));
server.notify_client(client, ServerMsg::private(text));
}
fn handle_object(server: &mut Server, entity: EcsEntity, args: String, _action: &ChatCommand) {
fn handle_object(
server: &mut Server,
client: EcsEntity,
target: EcsEntity,
args: String,
_action: &ChatCommand,
) {
let obj_type = scan_fmt!(&args, _action.arg_fmt, String);
let pos = server
.state
.ecs()
.read_storage::<comp::Pos>()
.get(entity)
.get(target)
.copied();
let ori = server
.state
.ecs()
.read_storage::<comp::Ori>()
.get(entity)
.get(target)
.copied();
/*let builder = server.state
.create_object(pos, ori, obj_type)
@ -701,7 +794,7 @@ fn handle_object(server: &mut Server, entity: EcsEntity, args: String, _action:
Ok("crafting_bench") => comp::object::Body::CraftingBench,
_ => {
return server.notify_client(
entity,
client,
ServerMsg::private(String::from("Object not found!")),
);
},
@ -723,18 +816,24 @@ fn handle_object(server: &mut Server, entity: EcsEntity, args: String, _action:
))
.build();
server.notify_client(
entity,
client,
ServerMsg::private(format!(
"Spawned: {}",
obj_str_res.unwrap_or("<Unknown object>")
)),
);
} else {
server.notify_client(entity, ServerMsg::private(format!("You have no position!")));
server.notify_client(client, ServerMsg::private(format!("You have no position!")));
}
}
fn handle_light(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) {
fn handle_light(
server: &mut Server,
client: EcsEntity,
target: EcsEntity,
args: String,
action: &ChatCommand,
) {
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);
@ -756,7 +855,7 @@ fn handle_light(server: &mut Server, entity: EcsEntity, args: String, action: &C
.state
.ecs()
.read_storage::<comp::Pos>()
.get(entity)
.get(target)
.copied();
if let Some(pos) = pos {
server
@ -767,19 +866,25 @@ fn handle_light(server: &mut Server, entity: EcsEntity, args: String, action: &C
.with(comp::ForceUpdate)
.with(light_emitter)
.build();
server.notify_client(entity, ServerMsg::private(format!("Spawned object.")));
server.notify_client(client, ServerMsg::private(format!("Spawned object.")));
} else {
server.notify_client(entity, ServerMsg::private(format!("You have no position!")));
server.notify_client(client, ServerMsg::private(format!("You have no position!")));
}
}
fn handle_lantern(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) {
fn handle_lantern(
server: &mut Server,
client: EcsEntity,
target: EcsEntity,
args: String,
action: &ChatCommand,
) {
let opt_s = scan_fmt_some!(&args, action.arg_fmt, f32);
if server
.state
.read_storage::<comp::LightEmitter>()
.get(entity)
.get(target)
.is_some()
{
if let Some(s) = opt_s {
@ -787,11 +892,11 @@ fn handle_lantern(server: &mut Server, entity: EcsEntity, args: String, action:
.state
.ecs()
.write_storage::<comp::LightEmitter>()
.get_mut(entity)
.get_mut(target)
{
light.strength = s.max(0.1).min(10.0);
server.notify_client(
entity,
client,
ServerMsg::private(String::from("You adjusted flame strength.")),
);
}
@ -800,9 +905,9 @@ fn handle_lantern(server: &mut Server, entity: EcsEntity, args: String, action:
.state
.ecs()
.write_storage::<comp::LightEmitter>()
.remove(entity);
.remove(target);
server.notify_client(
entity,
client,
ServerMsg::private(String::from("You put out the lantern.")),
);
}
@ -811,7 +916,7 @@ fn handle_lantern(server: &mut Server, entity: EcsEntity, args: String, action:
.state
.ecs()
.write_storage::<comp::LightEmitter>()
.insert(entity, comp::LightEmitter {
.insert(target, comp::LightEmitter {
offset: Vec3::new(0.5, 0.2, 0.8),
col: Rgb::new(1.0, 0.75, 0.3),
strength: if let Some(s) = opt_s {
@ -822,50 +927,68 @@ fn handle_lantern(server: &mut Server, entity: EcsEntity, args: String, action:
});
server.notify_client(
entity,
client,
ServerMsg::private(String::from("You lit your lantern.")),
);
}
}
fn handle_explosion(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) {
fn handle_explosion(
server: &mut Server,
client: EcsEntity,
target: EcsEntity,
args: String,
action: &ChatCommand,
) {
let power = scan_fmt!(&args, action.arg_fmt, f32).unwrap_or(8.0);
let ecs = server.state.ecs();
match server.state.read_component_cloned::<comp::Pos>(entity) {
match server.state.read_component_cloned::<comp::Pos>(target) {
Some(pos) => {
ecs.read_resource::<EventBus<ServerEvent>>()
.emit_now(ServerEvent::Explosion {
pos: pos.0,
power,
owner: ecs.read_storage::<Uid>().get(entity).copied(),
owner: ecs.read_storage::<Uid>().get(target).copied(),
})
},
None => server.notify_client(
entity,
client,
ServerMsg::private(String::from("You have no position!")),
),
}
}
fn handle_waypoint(server: &mut Server, entity: EcsEntity, _args: String, _action: &ChatCommand) {
match server.state.read_component_cloned::<comp::Pos>(entity) {
fn handle_waypoint(
server: &mut Server,
client: EcsEntity,
target: EcsEntity,
_args: String,
_action: &ChatCommand,
) {
match server.state.read_component_cloned::<comp::Pos>(target) {
Some(pos) => {
let _ = server
.state
.ecs()
.write_storage::<comp::Waypoint>()
.insert(entity, comp::Waypoint::new(pos.0));
server.notify_client(entity, ServerMsg::private(String::from("Waypoint set!")));
.insert(target, comp::Waypoint::new(pos.0));
server.notify_client(client, ServerMsg::private(String::from("Waypoint set!")));
},
None => server.notify_client(
entity,
client,
ServerMsg::private(String::from("You have no position!")),
),
}
}
fn handle_adminify(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) {
fn handle_adminify(
server: &mut Server,
client: EcsEntity,
_target: EcsEntity,
args: String,
action: &ChatCommand,
) {
if let Ok(alias) = scan_fmt!(&args, action.arg_fmt, String) {
let ecs = server.state.ecs();
let opt_player = (&ecs.entities(), &ecs.read_storage::<comp::Player>())
@ -883,18 +1006,31 @@ fn handle_adminify(server: &mut Server, entity: EcsEntity, args: String, action:
},
None => {
server.notify_client(
entity,
client,
ServerMsg::private(format!("Player '{}' not found!", alias)),
);
server.notify_client(entity, ServerMsg::private(String::from(action.help_string)));
server.notify_client(client, ServerMsg::private(String::from(action.help_string)));
},
}
} else {
server.notify_client(entity, ServerMsg::private(String::from(action.help_string)));
server.notify_client(client, ServerMsg::private(String::from(action.help_string)));
}
}
fn handle_tell(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) {
fn handle_tell(
server: &mut Server,
client: EcsEntity,
target: EcsEntity,
args: String,
action: &ChatCommand,
) {
if client != target {
server.notify_client(
client,
ServerMsg::tell(String::from("It's rude to impersonate people")),
);
return;
}
if let Ok(alias) = scan_fmt!(&args, action.arg_fmt, String) {
let ecs = server.state.ecs();
let msg = &args[alias.len()..args.len()];
@ -903,11 +1039,11 @@ fn handle_tell(server: &mut Server, entity: EcsEntity, args: String, action: &Ch
.find(|(_, player)| player.alias == alias)
.map(|(entity, _)| entity)
{
if player != entity {
if player != target {
if msg.len() > 1 {
if let Some(name) = ecs
.read_storage::<comp::Player>()
.get(entity)
.get(target)
.map(|s| s.alias.clone())
{
server.notify_client(
@ -915,53 +1051,60 @@ fn handle_tell(server: &mut Server, entity: EcsEntity, args: String, action: &Ch
ServerMsg::tell(format!("[{}] tells:{}", name, msg)),
);
server.notify_client(
entity,
client,
ServerMsg::tell(format!("To [{}]:{}", alias, msg)),
);
} else {
server.notify_client(
entity,
client,
ServerMsg::private(String::from("Failed to send message.")),
);
}
} else {
server.notify_client(
entity,
client,
ServerMsg::private(format!("[{}] wants to talk to you.", alias)),
);
}
} else {
server.notify_client(
entity,
client,
ServerMsg::private(format!("You can't /tell yourself.")),
);
}
} else {
server.notify_client(
entity,
client,
ServerMsg::private(format!("Player '{}' not found!", alias)),
);
}
} else {
server.notify_client(entity, ServerMsg::private(String::from(action.help_string)));
server.notify_client(client, ServerMsg::private(String::from(action.help_string)));
}
}
#[cfg(not(feature = "worldgen"))]
fn handle_debug_column(
server: &mut Server,
entity: EcsEntity,
client: EcsEntity,
target: EcsEntity,
_args: String,
_action: &ChatCommand,
) {
server.notify_client(
entity,
client,
ServerMsg::private(String::from("Unsupported without worldgen enabled")),
);
}
#[cfg(feature = "worldgen")]
fn handle_debug_column(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) {
fn handle_debug_column(
server: &mut Server,
client: EcsEntity,
_target: EcsEntity,
args: String,
action: &ChatCommand,
) {
let sim = server.world.sim();
let sampler = server.world.sample_columns();
if let Ok((x, y)) = scan_fmt!(&args, action.arg_fmt, i32, i32) {
@ -1020,15 +1163,15 @@ spawn_rate {:?} "#,
))
};
if let Some(s) = foo() {
server.notify_client(entity, ServerMsg::private(s));
server.notify_client(client, ServerMsg::private(s));
} else {
server.notify_client(
entity,
client,
ServerMsg::private(String::from("Not a pregenerated chunk.")),
);
}
} else {
server.notify_client(entity, ServerMsg::private(String::from(action.help_string)));
server.notify_client(client, ServerMsg::private(String::from(action.help_string)));
}
}
@ -1048,12 +1191,18 @@ fn find_target(
}
}
fn handle_exp(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) {
fn handle_exp(
server: &mut Server,
client: EcsEntity,
target: EcsEntity,
args: String,
action: &ChatCommand,
) {
let (a_exp, a_alias) = scan_fmt_some!(&args, action.arg_fmt, i64, String);
if let Some(exp) = a_exp {
let ecs = server.state.ecs_mut();
let target = find_target(&ecs, a_alias, entity);
let target = find_target(&ecs, a_alias, target);
let mut error_msg = None;
@ -1071,17 +1220,23 @@ fn handle_exp(server: &mut Server, entity: EcsEntity, args: String, action: &Cha
}
if let Some(msg) = error_msg {
server.notify_client(entity, msg);
server.notify_client(client, msg);
}
}
}
fn handle_level(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) {
fn handle_level(
server: &mut Server,
client: EcsEntity,
target: EcsEntity,
args: String,
action: &ChatCommand,
) {
let (a_lvl, a_alias) = scan_fmt_some!(&args, action.arg_fmt, u32, String);
if let Some(lvl) = a_lvl {
let ecs = server.state.ecs_mut();
let target = find_target(&ecs, a_alias, entity);
let target = find_target(&ecs, a_alias, target);
let mut error_msg = None;
@ -1104,19 +1259,25 @@ fn handle_level(server: &mut Server, entity: EcsEntity, args: String, action: &C
}
if let Some(msg) = error_msg {
server.notify_client(entity, msg);
server.notify_client(client, msg);
}
}
}
use common::comp::Item;
fn handle_debug(server: &mut Server, entity: EcsEntity, _args: String, _action: &ChatCommand) {
fn handle_debug(
server: &mut Server,
client: EcsEntity,
target: EcsEntity,
_args: String,
_action: &ChatCommand,
) {
if let Ok(items) = assets::load_glob::<Item>("common.items.debug.*") {
server
.state()
.ecs()
.write_storage::<comp::Inventory>()
.get_mut(entity)
.get_mut(target)
// TODO: Consider writing a `load_glob_cloned` in `assets` and using that here
.map(|inv| inv.push_all_unique(items.iter().map(|item| item.as_ref().clone())));
let _ = server
@ -1124,12 +1285,12 @@ fn handle_debug(server: &mut Server, entity: EcsEntity, _args: String, _action:
.ecs()
.write_storage::<comp::InventoryUpdate>()
.insert(
entity,
target,
comp::InventoryUpdate::new(comp::InventoryUpdateEvent::Debug),
);
} else {
server.notify_client(
entity,
client,
ServerMsg::private(String::from(
"Debug items not found? Something is very broken.",
)),
@ -1139,12 +1300,13 @@ fn handle_debug(server: &mut Server, entity: EcsEntity, _args: String, _action:
fn handle_remove_lights(
server: &mut Server,
entity: EcsEntity,
client: EcsEntity,
target: EcsEntity,
args: String,
action: &ChatCommand,
) {
let opt_radius = scan_fmt_some!(&args, action.arg_fmt, f32);
let opt_player_pos = server.state.read_component_cloned::<comp::Pos>(entity);
let opt_player_pos = server.state.read_component_cloned::<comp::Pos>(target);
let mut to_delete = vec![];
match opt_player_pos {
@ -1168,7 +1330,7 @@ fn handle_remove_lights(
}
},
None => server.notify_client(
entity,
client,
ServerMsg::private(String::from("You have no position.")),
),
}
@ -1182,7 +1344,49 @@ fn handle_remove_lights(
}
server.notify_client(
entity,
client,
ServerMsg::private(String::from(format!("Removed {} lights!", size))),
);
}
fn handle_sudo(
server: &mut Server,
client: EcsEntity,
_target: EcsEntity,
args: String,
action: &ChatCommand,
) {
if let (Some(player_alias), Some(mut cmd), cmd_args) =
scan_fmt_some!(&args, action.arg_fmt, String, String, String)
{
let cmd_args = cmd_args.unwrap_or(String::from(""));
if cmd.chars().next() == Some('/') {
cmd.remove(0);
}
if let Some(action) = CHAT_COMMANDS.iter().find(|c| c.keyword == cmd) {
let mut entity_opt = None;
let ecs = server.state.ecs();
for (ent, player) in (&ecs.entities(), &ecs.read_storage::<comp::Player>()).join() {
if player.alias == player_alias {
entity_opt = Some(ent);
break;
}
}
if let Some(entity) = entity_opt {
(action.handler)(server, client, entity, cmd_args, action);
} else {
server.notify_client(
client,
ServerMsg::private(format!("Could not find that player")),
);
}
} else {
server.notify_client(
client,
ServerMsg::private(format!("Unknown command: /{}", cmd)),
);
}
} else {
server.notify_client(client, ServerMsg::private(String::from(action.help_string)));
}
}