Add build_area_list command

* Reworks CanBuild to use HashSet
* Removes player argument from build permission, use sudo instead
This commit is contained in:
Louis Pearson 2021-03-26 23:53:33 -06:00
parent 21f794f84c
commit 165065725e
5 changed files with 139 additions and 144 deletions

View File

@ -41,6 +41,7 @@ pub enum ChatCommand {
Ban, Ban,
Build, Build,
BuildAreaAdd, BuildAreaAdd,
BuildAreaList,
BuildAreaRemove, BuildAreaRemove,
Campfire, Campfire,
Debug, Debug,
@ -100,6 +101,7 @@ pub static CHAT_COMMANDS: &[ChatCommand] = &[
ChatCommand::Ban, ChatCommand::Ban,
ChatCommand::Build, ChatCommand::Build,
ChatCommand::BuildAreaAdd, ChatCommand::BuildAreaAdd,
ChatCommand::BuildAreaList,
ChatCommand::BuildAreaRemove, ChatCommand::BuildAreaRemove,
ChatCommand::Campfire, ChatCommand::Campfire,
ChatCommand::Debug, ChatCommand::Debug,
@ -259,6 +261,7 @@ impl ChatCommand {
"Adds a new build area", "Adds a new build area",
Admin, Admin,
), ),
ChatCommand::BuildAreaList => cmd(vec![], "List all build areas", Admin),
ChatCommand::BuildAreaRemove => cmd( ChatCommand::BuildAreaRemove => cmd(
vec![Any("name", Required)], vec![Any("name", Required)],
"Removes specified build area", "Removes specified build area",
@ -397,7 +400,7 @@ impl ChatCommand {
Admin, Admin,
), ),
ChatCommand::PermitBuild => cmd( ChatCommand::PermitBuild => cmd(
vec![PlayerName(Required), Any("area_name", Required)], vec![Any("area_name", Required)],
"Grants player a bounded box they can build in", "Grants player a bounded box they can build in",
Admin, Admin,
), ),
@ -408,13 +411,13 @@ impl ChatCommand {
Admin, Admin,
), ),
ChatCommand::RevokeBuild => cmd( ChatCommand::RevokeBuild => cmd(
vec![PlayerName(Required), Any("area_name", Required)], vec![Any("area_name", Required)],
"Revokes build area permission for given player", "Revokes build area permission for player",
Admin, Admin,
), ),
ChatCommand::RevokeBuildAll => cmd( ChatCommand::RevokeBuildAll => cmd(
vec![PlayerName(Required)], vec![],
"Revokes all build area permissions for given player", "Revokes all build area permissions for player",
Admin, Admin,
), ),
ChatCommand::Region => cmd( ChatCommand::Region => cmd(
@ -504,6 +507,7 @@ impl ChatCommand {
ChatCommand::Ban => "ban", ChatCommand::Ban => "ban",
ChatCommand::Build => "build", ChatCommand::Build => "build",
ChatCommand::BuildAreaAdd => "build_area_add", ChatCommand::BuildAreaAdd => "build_area_add",
ChatCommand::BuildAreaList => "build_area_list",
ChatCommand::BuildAreaRemove => "build_area_remove", ChatCommand::BuildAreaRemove => "build_area_remove",
ChatCommand::Campfire => "campfire", ChatCommand::Campfire => "campfire",
ChatCommand::Debug => "debug", ChatCommand::Debug => "debug",

View File

@ -2,12 +2,13 @@ use crate::depot::Id;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use specs::{Component, DerefFlaggedStorage}; use specs::{Component, DerefFlaggedStorage};
use specs_idvs::IdvStorage; use specs_idvs::IdvStorage;
use std::collections::HashSet;
use vek::geom::Aabb; use vek::geom::Aabb;
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] #[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct CanBuild { pub struct CanBuild {
pub building_is_on: bool, pub enabled: bool,
pub build_areas: Vec<Id<Aabb<i32>>>, pub build_areas: HashSet<Id<Aabb<i32>>>,
} }
impl Component for CanBuild { impl Component for CanBuild {
type Storage = DerefFlaggedStorage<Self, IdvStorage<Self>>; type Storage = DerefFlaggedStorage<Self, IdvStorage<Self>>;

View File

@ -34,6 +34,7 @@ use common_sys::state::BuildAreas;
use rand::Rng; use rand::Rng;
use specs::{Builder, Entity as EcsEntity, Join, WorldExt}; use specs::{Builder, Entity as EcsEntity, Join, WorldExt};
use std::{ use std::{
collections::HashSet,
convert::TryFrom, convert::TryFrom,
ops::{Deref, DerefMut}, ops::{Deref, DerefMut},
time::Duration, time::Duration,
@ -87,6 +88,7 @@ fn get_handler(cmd: &ChatCommand) -> CommandHandler {
ChatCommand::Ban => handle_ban, ChatCommand::Ban => handle_ban,
ChatCommand::Build => handle_build, ChatCommand::Build => handle_build,
ChatCommand::BuildAreaAdd => handle_build_area_add, ChatCommand::BuildAreaAdd => handle_build_area_add,
ChatCommand::BuildAreaList => handle_build_area_list,
ChatCommand::BuildAreaRemove => handle_build_area_remove, ChatCommand::BuildAreaRemove => handle_build_area_remove,
ChatCommand::Campfire => handle_spawn_campfire, ChatCommand::Campfire => handle_spawn_campfire,
ChatCommand::Debug => handle_debug, ChatCommand::Debug => handle_debug,
@ -1129,31 +1131,23 @@ fn handle_safezone(
fn handle_permit_build( fn handle_permit_build(
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(target_alias), Some(area_name)) = if let Some(area_name) = scan_fmt_some!(&args, &action.arg_fmt(), String) {
scan_fmt_some!(&args, &action.arg_fmt(), String, String)
{
let ecs = server.state.ecs(); let ecs = server.state.ecs();
let target_player_opt = (&ecs.entities(), &ecs.read_storage::<comp::Player>())
.join()
.find(|(_, player)| player.alias == target_alias)
.map(|(entity, _)| entity);
if let Some(target_player) = target_player_opt {
if server if server
.state .state
.read_storage::<comp::CanBuild>() .read_storage::<comp::CanBuild>()
.get(target_player) .get(target)
.is_none() .is_none()
{ {
let _ = let _ = ecs
ecs.write_storage::<comp::CanBuild>() .write_storage::<comp::CanBuild>()
.insert(target_player, comp::CanBuild { .insert(target, comp::CanBuild {
building_is_on: false, enabled: false,
build_areas: Vec::new(), build_areas: HashSet::new(),
}); });
} }
if let Some(bb_id) = ecs if let Some(bb_id) = ecs
@ -1162,28 +1156,18 @@ fn handle_permit_build(
.area_names .area_names
.get(&area_name) .get(&area_name)
{ {
if let Some(mut comp_can_build) = if let Some(mut comp_can_build) = ecs.write_storage::<comp::CanBuild>().get_mut(target)
ecs.write_storage::<comp::CanBuild>().get_mut(target_player)
{ {
comp_can_build.build_areas.push(*bb_id); comp_can_build.build_areas.insert(*bb_id);
server.notify_client( server.notify_client(
client, client,
ServerGeneral::server_msg( ServerGeneral::server_msg(
ChatType::CommandInfo, ChatType::CommandInfo,
format!("Gave {} permission to build in {}", target_alias, area_name), format!("Permission to build in {} granted", area_name),
), ),
); );
} }
} }
} else {
server.notify_client(
client,
ServerGeneral::server_msg(
ChatType::CommandError,
format!("Player '{}' not found!", target_alias),
),
);
}
} else { } else {
server.notify_client( server.notify_client(
client, client,
@ -1195,51 +1179,30 @@ fn handle_permit_build(
fn handle_revoke_build( fn handle_revoke_build(
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(target_alias), Some(area_name)) = if let Some(area_name) = scan_fmt_some!(&args, &action.arg_fmt(), String) {
scan_fmt_some!(&args, &action.arg_fmt(), String, String)
{
let ecs = server.state.ecs(); let ecs = server.state.ecs();
let target_player_opt = (&ecs.entities(), &ecs.read_storage::<comp::Player>())
.join()
.find(|(_, player)| player.alias == target_alias)
.map(|(entity, _)| entity);
if let Some(target_player) = target_player_opt {
if let Some(bb_id) = ecs if let Some(bb_id) = ecs
.read_resource::<BuildAreas>() .read_resource::<BuildAreas>()
.deref() .deref()
.area_names .area_names
.get(&area_name) .get(&area_name)
{ {
if let Some(mut comp_can_build) = if let Some(mut comp_can_build) = ecs.write_storage::<comp::CanBuild>().get_mut(target)
ecs.write_storage::<comp::CanBuild>().get_mut(target_player)
{ {
comp_can_build.build_areas.retain(|&x| x != *bb_id); comp_can_build.build_areas.retain(|&x| x != *bb_id);
server.notify_client( server.notify_client(
client, client,
ServerGeneral::server_msg( ServerGeneral::server_msg(
ChatType::CommandInfo, ChatType::CommandInfo,
format!( format!("Permission to build in {} revoked", area_name),
"Revoked {}'s permission to build in {}",
target_alias, area_name
),
), ),
); );
} }
} }
} else {
server.notify_client(
client,
ServerGeneral::server_msg(
ChatType::CommandError,
format!("Player '{}' not found!", target_alias),
),
);
}
} else { } else {
server.notify_client( server.notify_client(
client, client,
@ -1251,41 +1214,17 @@ fn handle_revoke_build(
fn handle_revoke_build_all( fn handle_revoke_build_all(
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(target_alias) = scan_fmt_some!(&args, &action.arg_fmt(), String) {
let ecs = server.state.ecs(); let ecs = server.state.ecs();
let target_player_opt = (&ecs.entities(), &ecs.read_storage::<comp::Player>())
.join()
.find(|(_, player)| player.alias == target_alias)
.map(|(entity, _)| entity);
if let Some(target_player) = target_player_opt { ecs.write_storage::<comp::CanBuild>().remove(target);
ecs.write_storage::<comp::CanBuild>().remove(target_player);
server.notify_client( server.notify_client(
client, client,
ServerGeneral::server_msg( ServerGeneral::server_msg(ChatType::CommandInfo, "All build permissions revoked"),
ChatType::CommandInfo,
format!("Revoked {}'s permission to build everywhere", target_alias),
),
); );
} else {
server.notify_client(
client,
ServerGeneral::server_msg(
ChatType::CommandError,
format!("Player '{}' not found!", target_alias),
),
);
}
} else {
server.notify_client(
client,
ServerGeneral::server_msg(ChatType::CommandError, action.help_string()),
);
}
} }
fn handle_players( fn handle_players(
@ -1328,14 +1267,14 @@ fn handle_build(
.write_storage::<comp::CanBuild>() .write_storage::<comp::CanBuild>()
.get_mut(target) .get_mut(target)
{ {
if can_build.building_is_on { if can_build.enabled {
can_build.building_is_on = false; can_build.enabled = false;
server.notify_client( server.notify_client(
client, client,
ServerGeneral::server_msg(ChatType::CommandInfo, "Toggled off build mode!"), ServerGeneral::server_msg(ChatType::CommandInfo, "Toggled off build mode!"),
); );
} else { } else {
can_build.building_is_on = true; can_build.enabled = true;
server.notify_client( server.notify_client(
client, client,
ServerGeneral::server_msg(ChatType::CommandInfo, "Toggled on build mode!"), ServerGeneral::server_msg(ChatType::CommandInfo, "Toggled on build mode!"),
@ -1371,13 +1310,28 @@ fn handle_build_area_add(
i32 i32
) { ) {
let ecs = server.state.ecs(); let ecs = server.state.ecs();
if ecs
.read_resource::<BuildAreas>()
.deref()
.area_names
.contains_key(&area_name)
{
server.notify_client(
client,
ServerGeneral::server_msg(
ChatType::CommandError,
format!("Build zone {} already exists!", area_name),
),
);
return;
}
let bb_id = ecs let bb_id = ecs
.write_resource::<BuildAreas>() .write_resource::<BuildAreas>()
.deref_mut() .deref_mut()
.areas .areas
.insert(Aabb { .insert(Aabb {
min: Vec3::new(xlo, ylo, zlo), min: Vec3::new(xlo.min(xhi), ylo.min(yhi), zlo.min(zhi)),
max: Vec3::new(xhi, yhi, zhi), max: Vec3::new(xhi.max(xlo), yhi.max(ylo), zhi.max(zlo)),
}); });
ecs.write_resource::<BuildAreas>() ecs.write_resource::<BuildAreas>()
.deref_mut() .deref_mut()
@ -1393,6 +1347,34 @@ fn handle_build_area_add(
} }
} }
fn handle_build_area_list(
server: &mut Server,
client: EcsEntity,
_target: EcsEntity,
_args: String,
_action: &ChatCommand,
) {
let ecs = server.state.ecs();
let build_areas = ecs.read_resource::<BuildAreas>();
server.notify_client(
client,
ServerGeneral::server_msg(
ChatType::CommandInfo,
build_areas.area_names.iter().fold(
"Build Areas:".to_string(),
|acc, (area_name, bb_id)| {
if let Some(aabb) = build_areas.areas.get(*bb_id) {
format!("{}\n{}: {} to {}", acc, area_name, aabb.min, aabb.max)
} else {
acc
}
},
),
),
);
}
fn handle_build_area_remove( fn handle_build_area_remove(
server: &mut Server, server: &mut Server,
client: EcsEntity, client: EcsEntity,

View File

@ -104,31 +104,39 @@ impl Sys {
}, },
ClientGeneral::BreakBlock(pos) => { ClientGeneral::BreakBlock(pos) => {
if let Some(comp_can_build) = can_build.get(entity) { if let Some(comp_can_build) = can_build.get(entity) {
if comp_can_build.building_is_on { if comp_can_build.enabled {
for area in comp_can_build.build_areas.iter() { for area in comp_can_build.build_areas.iter() {
if let Some(aabb) = build_areas.areas.get(*area) { if let Some(block) = build_areas
if aabb.contains_point(pos) { .areas
if let Ok(block) = terrain.get(pos) { .get(*area)
// TODO: Make this an exclusive check on the upper bound of the AABB
// Vek defaults to inclusive which is not optimal
.filter(|aabb| aabb.contains_point(pos))
.and_then(|_| terrain.get(pos).ok())
{
block_changes.set(pos, block.into_vacant()); block_changes.set(pos, block.into_vacant());
} }
} }
} }
} }
}
}
}, },
ClientGeneral::PlaceBlock(pos, block) => { ClientGeneral::PlaceBlock(pos, block) => {
if let Some(comp_can_build) = can_build.get(entity) { if let Some(comp_can_build) = can_build.get(entity) {
if comp_can_build.building_is_on { if comp_can_build.enabled {
for area in comp_can_build.build_areas.iter() { for area in comp_can_build.build_areas.iter() {
if let Some(aabb) = build_areas.areas.get(*area) { if build_areas
if aabb.contains_point(pos) { .areas
.get(*area)
// TODO: Make this an exclusive check on the upper bound of the AABB
// Vek defaults to inclusive which is not optimal
.filter(|aabb| aabb.contains_point(pos))
.is_some()
{
block_changes.try_set(pos, block); block_changes.try_set(pos, block);
} }
} }
} }
} }
}
}, },
ClientGeneral::UnlockSkill(skill) => { ClientGeneral::UnlockSkill(skill) => {
stats stats

View File

@ -317,7 +317,7 @@ impl PlayState for SessionState {
.state() .state()
.read_storage::<comp::CanBuild>() .read_storage::<comp::CanBuild>()
.get(player_entity) .get(player_entity)
.map_or_else(|| false, |cb| cb.building_is_on); .map_or_else(|| false, |cb| cb.enabled);
let is_mining = self let is_mining = self
.client .client