mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
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:
commit
d463b67ef4
BIN
assets/world/map/veloren_0_9_0_0.bin
(Stored with Git LFS)
BIN
assets/world/map/veloren_0_9_0_0.bin
(Stored with Git LFS)
Binary file not shown.
@ -108,6 +108,9 @@ pub enum ChatCommand {
|
|||||||
Wiring,
|
Wiring,
|
||||||
World,
|
World,
|
||||||
MakeVolume,
|
MakeVolume,
|
||||||
|
Location,
|
||||||
|
CreateLocation,
|
||||||
|
DeleteLocation,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
||||||
@ -320,7 +323,7 @@ impl ChatCommand {
|
|||||||
),
|
),
|
||||||
ChatCommand::Ban => cmd(
|
ChatCommand::Ban => cmd(
|
||||||
vec![
|
vec![
|
||||||
Any("username", Required),
|
PlayerName(Required),
|
||||||
Boolean("overwrite", "true".to_string(), Optional),
|
Boolean("overwrite", "true".to_string(), Optional),
|
||||||
Any("ban duration", Optional),
|
Any("ban duration", Optional),
|
||||||
Message(Optional),
|
Message(Optional),
|
||||||
@ -458,7 +461,7 @@ impl ChatCommand {
|
|||||||
Some(Admin),
|
Some(Admin),
|
||||||
),
|
),
|
||||||
ChatCommand::Kick => cmd(
|
ChatCommand::Kick => cmd(
|
||||||
vec![Any("username", Required), Message(Optional)],
|
vec![PlayerName(Required), Message(Optional)],
|
||||||
"Kick a player with a given username",
|
"Kick a player with a given username",
|
||||||
Some(Moderator),
|
Some(Moderator),
|
||||||
),
|
),
|
||||||
@ -559,7 +562,7 @@ impl ChatCommand {
|
|||||||
),
|
),
|
||||||
ChatCommand::ServerPhysics => cmd(
|
ChatCommand::ServerPhysics => cmd(
|
||||||
vec![
|
vec![
|
||||||
Any("username", Required),
|
PlayerName(Required),
|
||||||
Boolean("enabled", "true".to_string(), Optional),
|
Boolean("enabled", "true".to_string(), Optional),
|
||||||
],
|
],
|
||||||
"Set/unset server-authoritative physics for an account",
|
"Set/unset server-authoritative physics for an account",
|
||||||
@ -621,7 +624,7 @@ impl ChatCommand {
|
|||||||
Some(Moderator),
|
Some(Moderator),
|
||||||
),
|
),
|
||||||
ChatCommand::Unban => cmd(
|
ChatCommand::Unban => cmd(
|
||||||
vec![Any("username", Required)],
|
vec![PlayerName(Required)],
|
||||||
"Remove the ban for the given username",
|
"Remove the ban for the given username",
|
||||||
Some(Moderator),
|
Some(Moderator),
|
||||||
),
|
),
|
||||||
@ -633,7 +636,7 @@ impl ChatCommand {
|
|||||||
),
|
),
|
||||||
ChatCommand::Wiring => cmd(vec![], "Create wiring element", Some(Admin)),
|
ChatCommand::Wiring => cmd(vec![], "Create wiring element", Some(Admin)),
|
||||||
ChatCommand::Whitelist => cmd(
|
ChatCommand::Whitelist => cmd(
|
||||||
vec![Any("add/remove", Required), Any("username", Required)],
|
vec![Any("add/remove", Required), PlayerName(Required)],
|
||||||
"Adds/removes username to whitelist",
|
"Adds/removes username to whitelist",
|
||||||
Some(Moderator),
|
Some(Moderator),
|
||||||
),
|
),
|
||||||
@ -643,6 +646,19 @@ impl ChatCommand {
|
|||||||
None,
|
None,
|
||||||
),
|
),
|
||||||
ChatCommand::MakeVolume => cmd(vec![], "Create a volume (experimental)", Some(Admin)),
|
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::Whitelist => "whitelist",
|
||||||
ChatCommand::World => "world",
|
ChatCommand::World => "world",
|
||||||
ChatCommand::MakeVolume => "make_volume",
|
ChatCommand::MakeVolume => "make_volume",
|
||||||
|
ChatCommand::Location => "location",
|
||||||
|
ChatCommand::CreateLocation => "create_location",
|
||||||
|
ChatCommand::DeleteLocation => "delete_location",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
client::Client,
|
client::Client,
|
||||||
|
location::Locations,
|
||||||
login_provider::LoginProvider,
|
login_provider::LoginProvider,
|
||||||
settings::{
|
settings::{
|
||||||
Ban, BanAction, BanInfo, EditableSetting, SettingError, WhitelistInfo, WhitelistRecord,
|
Ban, BanAction, BanInfo, EditableSetting, SettingError, WhitelistInfo, WhitelistRecord,
|
||||||
@ -182,6 +183,9 @@ fn do_command(
|
|||||||
ChatCommand::Whitelist => handle_whitelist,
|
ChatCommand::Whitelist => handle_whitelist,
|
||||||
ChatCommand::World => handle_world,
|
ChatCommand::World => handle_world,
|
||||||
ChatCommand::MakeVolume => handle_make_volume,
|
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)
|
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())
|
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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -23,6 +23,7 @@ mod data_dir;
|
|||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod events;
|
pub mod events;
|
||||||
pub mod input;
|
pub mod input;
|
||||||
|
pub mod location;
|
||||||
pub mod login_provider;
|
pub mod login_provider;
|
||||||
pub mod metrics;
|
pub mod metrics;
|
||||||
pub mod persistence;
|
pub mod persistence;
|
||||||
@ -55,6 +56,7 @@ use crate::{
|
|||||||
cmd::ChatCommandExt,
|
cmd::ChatCommandExt,
|
||||||
connection_handler::ConnectionHandler,
|
connection_handler::ConnectionHandler,
|
||||||
data_dir::DataDir,
|
data_dir::DataDir,
|
||||||
|
location::Locations,
|
||||||
login_provider::LoginProvider,
|
login_provider::LoginProvider,
|
||||||
persistence::PersistedComponents,
|
persistence::PersistedComponents,
|
||||||
presence::{Presence, RegionSubscription, RepositionOnChunkLoad},
|
presence::{Presence, RegionSubscription, RepositionOnChunkLoad},
|
||||||
@ -243,6 +245,7 @@ impl Server {
|
|||||||
});
|
});
|
||||||
state.ecs_mut().insert(EventBus::<ServerEvent>::default());
|
state.ecs_mut().insert(EventBus::<ServerEvent>::default());
|
||||||
state.ecs_mut().insert(Vec::<ChunkRequest>::new());
|
state.ecs_mut().insert(Vec::<ChunkRequest>::new());
|
||||||
|
state.ecs_mut().insert(Locations::default());
|
||||||
state.ecs_mut().insert(LoginProvider::new(
|
state.ecs_mut().insert(LoginProvider::new(
|
||||||
settings.auth_server_address.clone(),
|
settings.auth_server_address.clone(),
|
||||||
Arc::clone(&runtime),
|
Arc::clone(&runtime),
|
||||||
|
65
server/src/location.rs
Normal file
65
server/src/location.rs
Normal 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))
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user