Merge branch 'zesterer/release-map' into 'master'

Added location system, switched to release map

See merge request veloren/veloren!3213
This commit is contained in:
Marcel 2022-02-17 16:31:01 +00:00
commit d463b67ef4
5 changed files with 195 additions and 6 deletions

BIN
assets/world/map/veloren_0_9_0_0.bin (Stored with Git LFS)

Binary file not shown.

View File

@ -108,6 +108,9 @@ pub enum ChatCommand {
Wiring,
World,
MakeVolume,
Location,
CreateLocation,
DeleteLocation,
}
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
@ -320,7 +323,7 @@ impl ChatCommand {
),
ChatCommand::Ban => cmd(
vec![
Any("username", Required),
PlayerName(Required),
Boolean("overwrite", "true".to_string(), Optional),
Any("ban duration", Optional),
Message(Optional),
@ -458,7 +461,7 @@ impl ChatCommand {
Some(Admin),
),
ChatCommand::Kick => cmd(
vec![Any("username", Required), Message(Optional)],
vec![PlayerName(Required), Message(Optional)],
"Kick a player with a given username",
Some(Moderator),
),
@ -559,7 +562,7 @@ impl ChatCommand {
),
ChatCommand::ServerPhysics => cmd(
vec![
Any("username", Required),
PlayerName(Required),
Boolean("enabled", "true".to_string(), Optional),
],
"Set/unset server-authoritative physics for an account",
@ -621,7 +624,7 @@ impl ChatCommand {
Some(Moderator),
),
ChatCommand::Unban => cmd(
vec![Any("username", Required)],
vec![PlayerName(Required)],
"Remove the ban for the given username",
Some(Moderator),
),
@ -633,7 +636,7 @@ impl ChatCommand {
),
ChatCommand::Wiring => cmd(vec![], "Create wiring element", Some(Admin)),
ChatCommand::Whitelist => cmd(
vec![Any("add/remove", Required), Any("username", Required)],
vec![Any("add/remove", Required), PlayerName(Required)],
"Adds/removes username to whitelist",
Some(Moderator),
),
@ -643,6 +646,19 @@ impl ChatCommand {
None,
),
ChatCommand::MakeVolume => cmd(vec![], "Create a volume (experimental)", Some(Admin)),
ChatCommand::Location => {
cmd(vec![Any("name", Required)], "Teleport to a location", None)
},
ChatCommand::CreateLocation => cmd(
vec![Any("name", Required)],
"Create a location at the current position",
Some(Moderator),
),
ChatCommand::DeleteLocation => cmd(
vec![Any("name", Required)],
"Delete a location",
Some(Moderator),
),
}
}
@ -715,6 +731,9 @@ impl ChatCommand {
ChatCommand::Whitelist => "whitelist",
ChatCommand::World => "world",
ChatCommand::MakeVolume => "make_volume",
ChatCommand::Location => "location",
ChatCommand::CreateLocation => "create_location",
ChatCommand::DeleteLocation => "delete_location",
}
}

View File

@ -4,6 +4,7 @@
use crate::{
client::Client,
location::Locations,
login_provider::LoginProvider,
settings::{
Ban, BanAction, BanInfo, EditableSetting, SettingError, WhitelistInfo, WhitelistRecord,
@ -182,6 +183,9 @@ fn do_command(
ChatCommand::Whitelist => handle_whitelist,
ChatCommand::World => handle_world,
ChatCommand::MakeVolume => handle_make_volume,
ChatCommand::Location => handle_location,
ChatCommand::CreateLocation => handle_create_location,
ChatCommand::DeleteLocation => handle_delete_location,
};
handler(server, client, target, args, cmd)
@ -3516,3 +3520,101 @@ fn set_skills(skill_set: &mut comp::SkillSet, preset: &str) -> CmdResult<()> {
Err("Such preset doesn't exist".to_owned())
}
}
fn handle_location(
server: &mut Server,
client: EcsEntity,
target: EcsEntity,
args: Vec<String>,
_action: &ChatCommand,
) -> CmdResult<()> {
if let Some(name) = parse_args!(args, String) {
let loc = server.state.ecs().read_resource::<Locations>().get(&name);
match loc {
Ok(loc) => position_mut(server, target, "target", |target_pos| {
target_pos.0 = loc;
}),
Err(e) => Err(e.to_string()),
}
} else {
let locations = server.state.ecs().read_resource::<Locations>();
let mut locations = locations.iter().map(|s| s.as_str()).collect::<Vec<_>>();
locations.sort_unstable();
server.notify_client(
client,
ServerGeneral::server_msg(
ChatType::CommandInfo,
if locations.is_empty() {
"No locations currently exist".to_owned()
} else {
format!("Available locations:\n{}", locations.join(", "))
},
),
);
Ok(())
}
}
fn handle_create_location(
server: &mut Server,
client: EcsEntity,
target: EcsEntity,
args: Vec<String>,
action: &ChatCommand,
) -> CmdResult<()> {
if let Some(name) = parse_args!(args, String) {
let target_pos = position(server, target, "target")?;
let res = server
.state
.ecs_mut()
.write_resource::<Locations>()
.insert(name.clone(), target_pos.0);
match res {
Ok(()) => {
server.notify_client(
client,
ServerGeneral::server_msg(
ChatType::CommandInfo,
format!("Created location '{}'", name),
),
);
Ok(())
},
Err(e) => Err(e.to_string()),
}
} else {
Err(action.help_string())
}
}
fn handle_delete_location(
server: &mut Server,
client: EcsEntity,
_target: EcsEntity,
args: Vec<String>,
action: &ChatCommand,
) -> CmdResult<()> {
if let Some(name) = parse_args!(args, String) {
let res = server
.state
.ecs_mut()
.write_resource::<Locations>()
.remove(&name);
match res {
Ok(()) => {
server.notify_client(
client,
ServerGeneral::server_msg(
ChatType::CommandInfo,
format!("Deleted location '{}'", name),
),
);
Ok(())
},
Err(e) => Err(e.to_string()),
}
} else {
Err(action.help_string())
}
}

View File

@ -23,6 +23,7 @@ mod data_dir;
pub mod error;
pub mod events;
pub mod input;
pub mod location;
pub mod login_provider;
pub mod metrics;
pub mod persistence;
@ -55,6 +56,7 @@ use crate::{
cmd::ChatCommandExt,
connection_handler::ConnectionHandler,
data_dir::DataDir,
location::Locations,
login_provider::LoginProvider,
persistence::PersistedComponents,
presence::{Presence, RegionSubscription, RepositionOnChunkLoad},
@ -243,6 +245,7 @@ impl Server {
});
state.ecs_mut().insert(EventBus::<ServerEvent>::default());
state.ecs_mut().insert(Vec::<ChunkRequest>::new());
state.ecs_mut().insert(Locations::default());
state.ecs_mut().insert(LoginProvider::new(
settings.auth_server_address.clone(),
Arc::clone(&runtime),

65
server/src/location.rs Normal file
View File

@ -0,0 +1,65 @@
use hashbrown::HashMap;
use std::fmt;
use vek::*;
#[derive(Debug)]
pub enum LocationError<'a> {
InvalidName(String),
DuplicateName(String),
DoesNotExist(&'a str),
}
impl<'a> fmt::Display for LocationError<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::InvalidName(name) => write!(
f,
"Location name '{}' is invalid. Names may only contain lowercase ASCII and \
underscores",
name
),
Self::DuplicateName(name) => write!(
f,
"Location '{}' already exists, consider deleting it first",
name
),
Self::DoesNotExist(name) => write!(f, "Location '{}' does not exist", name),
}
}
}
/// Locations are moderator-defined positions that can be teleported between by
/// players. They currently do not persist between server sessions.
#[derive(Default)]
pub struct Locations {
locations: HashMap<String, Vec3<f32>>,
}
impl Locations {
pub fn insert(&mut self, name: String, pos: Vec3<f32>) -> Result<(), LocationError<'static>> {
if name.chars().all(|c| c.is_ascii_lowercase() || c == '_') {
self.locations
.try_insert(name, pos)
.map(|_| ())
.map_err(|o| LocationError::DuplicateName(o.entry.key().clone()))
} else {
Err(LocationError::InvalidName(name))
}
}
pub fn get<'a>(&self, name: &'a str) -> Result<Vec3<f32>, LocationError<'a>> {
self.locations
.get(name)
.copied()
.ok_or(LocationError::DoesNotExist(name))
}
pub fn iter(&self) -> impl Iterator<Item = &String> { self.locations.keys() }
pub fn remove<'a>(&mut self, name: &'a str) -> Result<(), LocationError<'a>> {
self.locations
.remove(name)
.map(|_| ())
.ok_or(LocationError::DoesNotExist(name))
}
}