Base implementation of /group /faction /say /region

This commit is contained in:
CapsizeGlimmer 2020-06-01 00:33:39 -04:00 committed by Forest Anderson
parent 8e67782a49
commit 702a21302c
10 changed files with 378 additions and 75 deletions

View File

@ -25,7 +25,7 @@ impl TabComplete for ArgumentSpec {
}, },
ArgumentSpec::Any(_, _) => vec![], ArgumentSpec::Any(_, _) => vec![],
ArgumentSpec::Command(_) => complete_command(part), ArgumentSpec::Command(_) => complete_command(part),
ArgumentSpec::Message => complete_player(part, &client), ArgumentSpec::Message(_) => complete_player(part, &client),
ArgumentSpec::SubCommand => complete_command(part), ArgumentSpec::SubCommand => complete_command(part),
ArgumentSpec::Enum(_, strings, _) => strings ArgumentSpec::Enum(_, strings, _) => strings
.iter() .iter()
@ -92,10 +92,25 @@ pub fn complete(line: &str, client: &Client) -> Vec<String> {
if i == 0 { if i == 0 {
// Completing chat command name // Completing chat command name
complete_command(word) complete_command(word)
} else if let Ok(cmd) = cmd.parse::<ChatCommand>() { } else {
if let Some(arg) = cmd.data().args.get(i - 1) { if let Ok(cmd) = cmd.parse::<ChatCommand>() {
// Complete ith argument if let Some(arg) = cmd.data().args.get(i - 1) {
arg.complete(word, &client) // Complete ith argument
arg.complete(word, &client)
} else {
// Complete past the last argument
match cmd.data().args.last() {
Some(ArgumentSpec::SubCommand) => {
if let Some(index) = nth_word(line, cmd.data().args.len()) {
complete(&line[index..], &client)
} else {
vec![]
}
},
Some(ArgumentSpec::Message(_)) => complete_player(word, &client),
_ => vec![], // End of command. Nothing to complete
}
}
} else { } else {
// Complete past the last argument // Complete past the last argument
match cmd.data().args.last() { match cmd.data().args.last() {

View File

@ -9,13 +9,16 @@ pub struct ChatCommandData {
pub args: Vec<ArgumentSpec>, 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 /// Whether the command requires administrator permissions.
/// administrator permissions or not. pub needs_admin: IsAdminOnly,
pub needs_admin: bool,
} }
impl ChatCommandData { impl ChatCommandData {
pub fn new(args: Vec<ArgumentSpec>, description: &'static str, needs_admin: bool) -> Self { pub fn new(
args: Vec<ArgumentSpec>,
description: &'static str,
needs_admin: IsAdminOnly,
) -> Self {
Self { Self {
args, args,
description, description,
@ -33,9 +36,11 @@ pub enum ChatCommand {
Debug, Debug,
DebugColumn, DebugColumn,
Explosion, Explosion,
Faction,
GiveExp, GiveExp,
GiveItem, GiveItem,
Goto, Goto,
Group,
Health, Health,
Help, Help,
Jump, Jump,
@ -46,7 +51,9 @@ pub enum ChatCommand {
Motd, Motd,
Object, Object,
Players, Players,
Region,
RemoveLights, RemoveLights,
Say,
SetLevel, SetLevel,
SetMotd, SetMotd,
Spawn, Spawn,
@ -56,6 +63,7 @@ pub enum ChatCommand {
Tp, Tp,
Version, Version,
Waypoint, Waypoint,
World,
} }
// Thank you for keeping this sorted alphabetically :-) // Thank you for keeping this sorted alphabetically :-)
@ -66,9 +74,11 @@ pub static CHAT_COMMANDS: &[ChatCommand] = &[
ChatCommand::Debug, ChatCommand::Debug,
ChatCommand::DebugColumn, ChatCommand::DebugColumn,
ChatCommand::Explosion, ChatCommand::Explosion,
ChatCommand::Faction,
ChatCommand::GiveExp, ChatCommand::GiveExp,
ChatCommand::GiveItem, ChatCommand::GiveItem,
ChatCommand::Goto, ChatCommand::Goto,
ChatCommand::Group,
ChatCommand::Health, ChatCommand::Health,
ChatCommand::Help, ChatCommand::Help,
ChatCommand::Jump, ChatCommand::Jump,
@ -79,7 +89,9 @@ pub static CHAT_COMMANDS: &[ChatCommand] = &[
ChatCommand::Motd, ChatCommand::Motd,
ChatCommand::Object, ChatCommand::Object,
ChatCommand::Players, ChatCommand::Players,
ChatCommand::Region,
ChatCommand::RemoveLights, ChatCommand::RemoveLights,
ChatCommand::Say,
ChatCommand::SetLevel, ChatCommand::SetLevel,
ChatCommand::SetMotd, ChatCommand::SetMotd,
ChatCommand::Spawn, ChatCommand::Spawn,
@ -89,6 +101,7 @@ pub static CHAT_COMMANDS: &[ChatCommand] = &[
ChatCommand::Tp, ChatCommand::Tp,
ChatCommand::Version, ChatCommand::Version,
ChatCommand::Waypoint, ChatCommand::Waypoint,
ChatCommand::World,
]; ];
lazy_static! { lazy_static! {
@ -141,31 +154,37 @@ lazy_static! {
impl ChatCommand { impl ChatCommand {
pub fn data(&self) -> ChatCommandData { pub fn data(&self) -> ChatCommandData {
use ArgumentSpec::*; use ArgumentSpec::*;
use IsAdminOnly::*;
use Requirement::*; use Requirement::*;
let cmd = ChatCommandData::new; let cmd = ChatCommandData::new;
match self { match self {
ChatCommand::Adminify => cmd( ChatCommand::Adminify => cmd(
vec![PlayerName(Required)], vec![PlayerName(Required)],
"Temporarily gives a player admin permissions or removes them", "Temporarily gives a player admin permissions or removes them",
true, Admin,
), ),
ChatCommand::Alias => cmd(vec![Any("name", Required)], "Change your alias", false), ChatCommand::Alias => cmd(vec![Any("name", Required)], "Change your alias", NoAdmin),
ChatCommand::Build => cmd(vec![], "Toggles build mode on and off", true), ChatCommand::Build => cmd(vec![], "Toggles build mode on and off", Admin),
ChatCommand::Debug => cmd(vec![], "Place all debug items into your pack.", true), ChatCommand::Debug => cmd(vec![], "Place all debug items into your pack.", Admin),
ChatCommand::DebugColumn => cmd( ChatCommand::DebugColumn => cmd(
vec![Integer("x", 15000, Required), Integer("y", 15000, Required)], vec![Integer("x", 15000, Required), Integer("y", 15000, Required)],
"Prints some debug information about a column", "Prints some debug information about a column",
false, NoAdmin,
), ),
ChatCommand::Explosion => cmd( ChatCommand::Explosion => cmd(
vec![Float("radius", 5.0, Required)], vec![Float("radius", 5.0, Required)],
"Explodes the ground around you", "Explodes the ground around you",
true, Admin,
),
ChatCommand::Faction => cmd(
vec![Message(Optional)],
"Send messages to your faction",
NoAdmin,
), ),
ChatCommand::GiveExp => cmd( ChatCommand::GiveExp => cmd(
vec![Integer("amount", 50, Required)], vec![Integer("amount", 50, Required)],
"Give experience to yourself", "Give experience to yourself",
true, Admin,
), ),
ChatCommand::GiveItem => cmd( ChatCommand::GiveItem => cmd(
vec![ vec![
@ -173,7 +192,7 @@ impl ChatCommand {
Integer("num", 1, Optional), Integer("num", 1, Optional),
], ],
"Give yourself some items", "Give yourself some items",
true, Admin,
), ),
ChatCommand::Goto => cmd( ChatCommand::Goto => cmd(
vec![ vec![
@ -182,17 +201,22 @@ impl ChatCommand {
Float("z", 0.0, Required), Float("z", 0.0, Required),
], ],
"Teleport to a position", "Teleport to a position",
true, Admin,
),
ChatCommand::Group => cmd(
vec![Message(Optional)],
"Send messages to your group",
NoAdmin,
), ),
ChatCommand::Health => cmd( ChatCommand::Health => cmd(
vec![Integer("hp", 100, Required)], vec![Integer("hp", 100, Required)],
"Set your current health", "Set your current health",
true, Admin,
), ),
ChatCommand::Help => ChatCommandData::new( ChatCommand::Help => ChatCommandData::new(
vec![Command(Optional)], vec![Command(Optional)],
"Display information about commands", "Display information about commands",
false, NoAdmin,
), ),
ChatCommand::Jump => cmd( ChatCommand::Jump => cmd(
vec![ vec![
@ -201,10 +225,10 @@ impl ChatCommand {
Float("z", 0.0, Required), Float("z", 0.0, Required),
], ],
"Offset your current position", "Offset your current position",
true, Admin,
), ),
ChatCommand::Kill => cmd(vec![], "Kill yourself", false), ChatCommand::Kill => cmd(vec![], "Kill yourself", NoAdmin),
ChatCommand::KillNpcs => cmd(vec![], "Kill the NPCs", true), ChatCommand::KillNpcs => cmd(vec![], "Kill the NPCs", Admin),
ChatCommand::Lantern => cmd( ChatCommand::Lantern => cmd(
vec![ vec![
Float("strength", 5.0, Required), Float("strength", 5.0, Required),
@ -213,7 +237,7 @@ impl ChatCommand {
Float("b", 1.0, Optional), Float("b", 1.0, Optional),
], ],
"Change your lantern's strength and color", "Change your lantern's strength and color",
true, Admin,
), ),
ChatCommand::Light => cmd( ChatCommand::Light => cmd(
vec![ vec![
@ -226,24 +250,34 @@ impl ChatCommand {
Float("strength", 5.0, Optional), Float("strength", 5.0, Optional),
], ],
"Spawn entity with light", "Spawn entity with light",
true, Admin,
), ),
ChatCommand::Motd => cmd(vec![Message], "View the server description", false), ChatCommand::Motd => cmd(vec![Message], "View the server description", false),
ChatCommand::Object => cmd( ChatCommand::Object => cmd(
vec![Enum("object", OBJECTS.clone(), Required)], vec![Enum("object", OBJECTS.clone(), Required)],
"Spawn an object", "Spawn an object",
true, Admin,
), ),
ChatCommand::Players => cmd(vec![], "Lists players currently online", false), ChatCommand::Players => cmd(vec![], "Lists players currently online", NoAdmin),
ChatCommand::RemoveLights => cmd( ChatCommand::RemoveLights => cmd(
vec![Float("radius", 20.0, Optional)], vec![Float("radius", 20.0, Optional)],
"Removes all lights spawned by players", "Removes all lights spawned by players",
true, Admin,
),
ChatCommand::Region => cmd(
vec![Message(Optional)],
"Send messages to everyone in your region of the world",
NoAdmin,
),
ChatCommand::Say => cmd(
vec![Message(Optional)],
"Send messages to everyone within shouting distance",
NoAdmin,
), ),
ChatCommand::SetLevel => cmd( ChatCommand::SetLevel => cmd(
vec![Integer("level", 10, Required)], vec![Integer("level", 10, Required)],
"Set player Level", "Set player Level",
true, Admin,
), ),
ChatCommand::SetMotd => cmd(vec![Message], "Set the server description", true), ChatCommand::SetMotd => cmd(vec![Message], "Set the server description", true),
ChatCommand::Spawn => cmd( ChatCommand::Spawn => cmd(
@ -253,32 +287,37 @@ impl ChatCommand {
Integer("amount", 1, Optional), Integer("amount", 1, Optional),
], ],
"Spawn a test entity", "Spawn a test entity",
true, Admin,
), ),
ChatCommand::Sudo => cmd( ChatCommand::Sudo => cmd(
vec![PlayerName(Required), SubCommand], vec![PlayerName(Required), SubCommand],
"Run command as if you were another player", "Run command as if you were another player",
true, Admin,
), ),
ChatCommand::Tell => cmd( ChatCommand::Tell => cmd(
vec![PlayerName(Required), Message], vec![PlayerName(Required), Message(Optional)],
"Send a message to another player", "Send a message to another player",
false, NoAdmin,
), ),
ChatCommand::Time => cmd( ChatCommand::Time => cmd(
vec![Enum("time", TIMES.clone(), Optional)], vec![Enum("time", TIMES.clone(), Optional)],
"Set the time of day", "Set the time of day",
true, Admin,
), ),
ChatCommand::Tp => cmd( ChatCommand::Tp => cmd(
vec![PlayerName(Optional)], vec![PlayerName(Optional)],
"Teleport to another player", "Teleport to another player",
true, Admin,
), ),
ChatCommand::Version => cmd(vec![], "Prints server version", false), ChatCommand::Version => cmd(vec![], "Prints server version", NoAdmin),
ChatCommand::Waypoint => { ChatCommand::Waypoint => {
cmd(vec![], "Set your waypoint to your current position", true) cmd(vec![], "Set your waypoint to your current position", Admin)
}, },
ChatCommand::World => cmd(
vec![Message(Optional)],
"Send messages to everyone on the server",
NoAdmin,
),
} }
} }
@ -291,9 +330,11 @@ impl ChatCommand {
ChatCommand::Debug => "debug", ChatCommand::Debug => "debug",
ChatCommand::DebugColumn => "debug_column", ChatCommand::DebugColumn => "debug_column",
ChatCommand::Explosion => "explosion", ChatCommand::Explosion => "explosion",
ChatCommand::Faction => "faction",
ChatCommand::GiveExp => "give_exp", ChatCommand::GiveExp => "give_exp",
ChatCommand::GiveItem => "give_item", ChatCommand::GiveItem => "give_item",
ChatCommand::Goto => "goto", ChatCommand::Goto => "goto",
ChatCommand::Group => "group",
ChatCommand::Health => "health", ChatCommand::Health => "health",
ChatCommand::Help => "help", ChatCommand::Help => "help",
ChatCommand::Jump => "jump", ChatCommand::Jump => "jump",
@ -304,7 +345,9 @@ impl ChatCommand {
ChatCommand::Motd => "motd", ChatCommand::Motd => "motd",
ChatCommand::Object => "object", ChatCommand::Object => "object",
ChatCommand::Players => "players", ChatCommand::Players => "players",
ChatCommand::Region => "region",
ChatCommand::RemoveLights => "remove_lights", ChatCommand::RemoveLights => "remove_lights",
ChatCommand::Say => "say",
ChatCommand::SetLevel => "set_level", ChatCommand::SetLevel => "set_level",
ChatCommand::SetMotd => "set_motd", ChatCommand::SetMotd => "set_motd",
ChatCommand::Spawn => "spawn", ChatCommand::Spawn => "spawn",
@ -314,6 +357,7 @@ impl ChatCommand {
ChatCommand::Tp => "tp", ChatCommand::Tp => "tp",
ChatCommand::Version => "version", ChatCommand::Version => "version",
ChatCommand::Waypoint => "waypoint", ChatCommand::Waypoint => "waypoint",
ChatCommand::World => "world",
} }
} }
@ -329,7 +373,7 @@ impl ChatCommand {
/// A boolean that is used to check whether the command requires /// A boolean that is used to check whether the command requires
/// administrator permissions or not. /// administrator permissions or not.
pub fn needs_admin(&self) -> bool { self.data().needs_admin } pub fn needs_admin(&self) -> bool { *self.data().needs_admin }
/// Returns a format string for parsing arguments with scan_fmt /// Returns a format string for parsing arguments with scan_fmt
pub fn arg_fmt(&self) -> String { pub fn arg_fmt(&self) -> String {
@ -342,7 +386,7 @@ impl ChatCommand {
ArgumentSpec::Integer(_, _, _) => "{d}", ArgumentSpec::Integer(_, _, _) => "{d}",
ArgumentSpec::Any(_, _) => "{}", ArgumentSpec::Any(_, _) => "{}",
ArgumentSpec::Command(_) => "{}", ArgumentSpec::Command(_) => "{}",
ArgumentSpec::Message => "{/.*/}", ArgumentSpec::Message(_) => "{/.*/}",
ArgumentSpec::SubCommand => "{} {/.*/}", ArgumentSpec::SubCommand => "{} {/.*/}",
ArgumentSpec::Enum(_, _, _) => "{}", // TODO ArgumentSpec::Enum(_, _, _) => "{}", // TODO
}) })
@ -369,6 +413,20 @@ impl FromStr for ChatCommand {
} }
} }
pub enum IsAdminOnly {
Admin,
NoAdmin,
}
impl Deref for IsAdminOnly {
type Target = bool;
fn deref(&self) -> &bool {
match self {
IsAdminOnly::Admin => &true,
IsAdminOnly::NoAdmin => &false,
}
}
}
pub enum Requirement { pub enum Requirement {
Required, Required,
Optional, Optional,
@ -404,7 +462,7 @@ pub enum ArgumentSpec {
Command(Requirement), Command(Requirement),
/// This is the final argument, consuming all characters until the end of /// This is the final argument, consuming all characters until the end of
/// input. /// input.
Message, Message(Requirement),
/// This command is followed by another command (such as in /sudo) /// This command is followed by another command (such as in /sudo)
SubCommand, SubCommand,
/// The argument is likely an enum. The associated values are /// The argument is likely an enum. The associated values are
@ -452,7 +510,13 @@ impl ArgumentSpec {
"[[/]command]".to_string() "[[/]command]".to_string()
} }
}, },
ArgumentSpec::Message => "<message>".to_string(), ArgumentSpec::Message(req) => {
if **req {
"<message>".to_string()
} else {
"<message>".to_string()
}
},
ArgumentSpec::SubCommand => "<[/]command> [args...]".to_string(), ArgumentSpec::SubCommand => "<[/]command> [args...]".to_string(),
ArgumentSpec::Enum(label, _, req) => { ArgumentSpec::Enum(label, _, req) => {
if **req { if **req {

39
common/src/comp/chat.rs Normal file
View File

@ -0,0 +1,39 @@
use specs::{Component, Entity};
use specs_idvs::IDVStorage;
/// Limit chat to a subset of players
pub enum ChatMode {
/// Private message to another player (by entity)
Tell(Entity),
/// Talk to players within shouting distance
Say,
/// Talk to players in your region of the world
Region,
/// Talk to your current group of players
Group,
/// Talk to your faction
Faction,
/// Talk to every player on the server
World,
}
impl Component for ChatMode {
type Storage = IDVStorage<Self>;
}
/// Player groups are useful when forming raiding parties and coordinating
/// gameplay.
///
/// Groups are currently just an associated String (the group's name)
pub struct Group(String);
impl Component for Group {
type Storage = IDVStorage<Self>;
}
/// Player factions are used to coordinate pvp vs hostile factions or segment
/// chat from the world
///
/// Factions are currently just an associated String (the faction's name)
pub struct Faction(String);
impl Component for Faction {
type Storage = IDVStorage<Self>;
}

View File

@ -3,6 +3,7 @@ mod admin;
pub mod agent; pub mod agent;
mod body; mod body;
mod character_state; mod character_state;
mod chat;
mod controller; mod controller;
mod energy; mod energy;
mod inputs; mod inputs;
@ -24,6 +25,7 @@ pub use body::{
humanoid, object, quadruped_medium, quadruped_small, AllBodies, Body, BodyData, humanoid, object, quadruped_medium, quadruped_small, AllBodies, Body, BodyData,
}; };
pub use character_state::{Attacking, CharacterState, StateUpdate}; pub use character_state::{Attacking, CharacterState, StateUpdate};
pub use chat::{ChatMode, Faction, Group};
pub use controller::{ pub use controller::{
Climb, ControlAction, ControlEvent, Controller, ControllerInputs, Input, InventoryManip, Climb, ControlAction, ControlEvent, Controller, ControllerInputs, Input, InventoryManip,
MountState, Mounting, MountState, Mounting,

View File

@ -69,14 +69,22 @@ pub mod net;
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ChatType { pub enum ChatType {
/// Tell all players something (such as players connecting or alias changes)
Broadcast, Broadcast,
Chat, Chat, // TODO Is this still needed?
GameUpdate, GameUpdate, // TODO What is this?
Private, Private, // TODO What is this?
/// One-on-one chat
Tell, Tell,
/// Chat with nearby players
Say, Say,
/// Group chat
Group, Group,
/// Factional chat
Faction, Faction,
Meta, Meta, // TODO What is this?
/// Inform players that someone died
Kill, Kill,
/// Regional chat
Region,
} }

View File

@ -113,6 +113,7 @@ impl From<AuthClientError> for RegisterError {
} }
impl ServerMsg { impl ServerMsg {
// TODO is this needed?
pub fn chat(message: String) -> ServerMsg { pub fn chat(message: String) -> ServerMsg {
ServerMsg::ChatMsg { ServerMsg::ChatMsg {
chat_type: ChatType::Chat, chat_type: ChatType::Chat,
@ -141,6 +142,7 @@ impl ServerMsg {
} }
} }
// TODO is this needed?
pub fn private(message: String) -> ServerMsg { pub fn private(message: String) -> ServerMsg {
ServerMsg::ChatMsg { ServerMsg::ChatMsg {
chat_type: ChatType::Private, chat_type: ChatType::Private,
@ -148,6 +150,41 @@ impl ServerMsg {
} }
} }
pub fn group(message: String) -> ServerMsg {
ServerMsg::ChatMsg {
chat_type: ChatType::Group,
message,
}
}
pub fn region(message: String) -> ServerMsg {
ServerMsg::ChatMsg {
chat_type: ChatType::Region,
message,
}
}
pub fn say(message: String) -> ServerMsg {
ServerMsg::ChatMsg {
chat_type: ChatType::Say,
message,
}
}
pub fn faction(message: String) -> ServerMsg {
ServerMsg::ChatMsg {
chat_type: ChatType::Faction,
message,
}
}
pub fn world(message: String) -> ServerMsg {
ServerMsg::ChatMsg {
chat_type: ChatType::Chat,
message,
}
}
pub fn kill(message: String) -> ServerMsg { pub fn kill(message: String) -> ServerMsg {
ServerMsg::ChatMsg { ServerMsg::ChatMsg {
chat_type: ChatType::Kill, chat_type: ChatType::Kill,

View File

@ -155,6 +155,7 @@ impl State {
ecs.register::<comp::Projectile>(); ecs.register::<comp::Projectile>();
ecs.register::<comp::Attacking>(); ecs.register::<comp::Attacking>();
ecs.register::<comp::ItemDrop>(); ecs.register::<comp::ItemDrop>();
ecs.register::<comp::ChatMode>();
// Register synced resources used by the ECS. // Register synced resources used by the ECS.
ecs.insert(TimeOfDay(0.0)); ecs.insert(TimeOfDay(0.0));

View File

@ -32,7 +32,7 @@ impl ChatCommandExt for ChatCommand {
#[allow(clippy::needless_return)] // TODO: Pending review in #587 #[allow(clippy::needless_return)] // TODO: Pending review in #587
fn execute(&self, server: &mut Server, entity: EcsEntity, args: String) { fn execute(&self, server: &mut Server, entity: EcsEntity, args: String) {
let cmd_data = self.data(); let cmd_data = self.data();
if cmd_data.needs_admin && !server.entity_is_admin(entity) { if *cmd_data.needs_admin && !server.entity_is_admin(entity) {
server.notify_client( server.notify_client(
entity, entity,
ServerMsg::private(format!( ServerMsg::private(format!(
@ -68,9 +68,11 @@ fn get_handler(cmd: &ChatCommand) -> CommandHandler {
ChatCommand::Debug => handle_debug, ChatCommand::Debug => handle_debug,
ChatCommand::DebugColumn => handle_debug_column, ChatCommand::DebugColumn => handle_debug_column,
ChatCommand::Explosion => handle_explosion, ChatCommand::Explosion => handle_explosion,
ChatCommand::Faction => handle_faction,
ChatCommand::GiveExp => handle_give_exp, ChatCommand::GiveExp => handle_give_exp,
ChatCommand::GiveItem => handle_give_item, ChatCommand::GiveItem => handle_give_item,
ChatCommand::Goto => handle_goto, ChatCommand::Goto => handle_goto,
ChatCommand::Group => handle_group,
ChatCommand::Health => handle_health, ChatCommand::Health => handle_health,
ChatCommand::Help => handle_help, ChatCommand::Help => handle_help,
ChatCommand::Jump => handle_jump, ChatCommand::Jump => handle_jump,
@ -81,7 +83,9 @@ fn get_handler(cmd: &ChatCommand) -> CommandHandler {
ChatCommand::Motd => handle_motd, ChatCommand::Motd => handle_motd,
ChatCommand::Object => handle_object, ChatCommand::Object => handle_object,
ChatCommand::Players => handle_players, ChatCommand::Players => handle_players,
ChatCommand::Region => handle_region,
ChatCommand::RemoveLights => handle_remove_lights, ChatCommand::RemoveLights => handle_remove_lights,
ChatCommand::Say => handle_say,
ChatCommand::SetLevel => handle_set_level, ChatCommand::SetLevel => handle_set_level,
ChatCommand::SetMotd => handle_set_motd, ChatCommand::SetMotd => handle_set_motd,
ChatCommand::Spawn => handle_spawn, ChatCommand::Spawn => handle_spawn,
@ -91,6 +95,7 @@ fn get_handler(cmd: &ChatCommand) -> CommandHandler {
ChatCommand::Tp => handle_tp, ChatCommand::Tp => handle_tp,
ChatCommand::Version => handle_version, ChatCommand::Version => handle_version,
ChatCommand::Waypoint => handle_waypoint, ChatCommand::Waypoint => handle_waypoint,
ChatCommand::World => handle_world,
} }
} }
@ -967,6 +972,7 @@ fn handle_tell(
action: &ChatCommand, action: &ChatCommand,
) { ) {
if client != target { if client != target {
// This happens when [ab]using /sudo
server.notify_client( server.notify_client(
client, client,
ServerMsg::tell(String::from("It's rude to impersonate people")), ServerMsg::tell(String::from("It's rude to impersonate people")),
@ -981,38 +987,32 @@ fn handle_tell(
.find(|(_, player)| player.alias == alias) .find(|(_, player)| player.alias == alias)
.map(|(entity, _)| entity) .map(|(entity, _)| entity)
{ {
if player != target { if player == client {
if msg.len() > 1 {
if let Some(name) = ecs
.read_storage::<comp::Player>()
.get(target)
.map(|s| s.alias.clone())
{
server.notify_client(
player,
ServerMsg::tell(format!("[{}] tells:{}", name, msg)),
);
server.notify_client(
client,
ServerMsg::tell(format!("To [{}]:{}", alias, msg)),
);
} else {
server.notify_client(
client,
ServerMsg::private(String::from("Failed to send message.")),
);
}
} else {
server.notify_client(
client,
ServerMsg::private(format!("[{}] wants to talk to you.", alias)),
);
}
} else {
server.notify_client( server.notify_client(
client, client,
ServerMsg::private(format!("You can't /tell yourself.")), ServerMsg::private(format!("You can't /tell yourself.")),
); );
return;
}
if msg.is_empty() {
server.notify_client(
client,
ServerMsg::private(format!("[{}] wants to talk to you.", alias)),
);
return;
}
if let Some(name) = ecs
.read_storage::<comp::Player>()
.get(client)
.map(|s| s.alias.clone())
{
server.notify_client(player, ServerMsg::tell(format!("[{}] tells:{}", name, msg)));
server.notify_client(client, ServerMsg::tell(format!("To [{}]:{}", alias, msg)));
} else {
server.notify_client(
client,
ServerMsg::private(String::from("Failed to send message.")),
);
} }
} else { } else {
server.notify_client( server.notify_client(
@ -1028,6 +1028,141 @@ fn handle_tell(
} }
} }
fn handle_faction(
server: &mut Server,
client: EcsEntity,
target: EcsEntity,
msg: String,
_action: &ChatCommand,
) {
if client != target {
// This happens when [ab]using /sudo
server.notify_client(
client,
ServerMsg::tell(String::from("It's rude to impersonate people")),
);
return;
}
let _ = server
.state
.ecs()
.write_storage()
.insert(client, comp::ChatMode::Faction);
if !msg.is_empty() {
server
.state
.notify_registered_clients(ServerMsg::faction(msg.to_string()));
}
}
fn handle_group(
server: &mut Server,
client: EcsEntity,
target: EcsEntity,
msg: String,
_action: &ChatCommand,
) {
if client != target {
// This happens when [ab]using /sudo
server.notify_client(
client,
ServerMsg::tell(String::from("It's rude to impersonate people")),
);
return;
}
let _ = server
.state
.ecs()
.write_storage()
.insert(client, comp::ChatMode::Group);
if !msg.is_empty() {
server
.state
.notify_registered_clients(ServerMsg::group(msg.to_string()));
}
}
fn handle_region(
server: &mut Server,
client: EcsEntity,
target: EcsEntity,
msg: String,
_action: &ChatCommand,
) {
if client != target {
// This happens when [ab]using /sudo
server.notify_client(
client,
ServerMsg::tell(String::from("It's rude to impersonate people")),
);
return;
}
let _ = server
.state
.ecs()
.write_storage()
.insert(client, comp::ChatMode::Region);
if !msg.is_empty() {
server
.state
.notify_registered_clients(ServerMsg::region(msg.to_string()));
}
}
fn handle_say(
server: &mut Server,
client: EcsEntity,
target: EcsEntity,
msg: String,
_action: &ChatCommand,
) {
if client != target {
// This happens when [ab]using /sudo
server.notify_client(
client,
ServerMsg::tell(String::from("It's rude to impersonate people")),
);
return;
}
let _ = server
.state
.ecs()
.write_storage()
.insert(client, comp::ChatMode::Say);
if !msg.is_empty() {
server
.state
.notify_registered_clients(ServerMsg::say(msg.to_string()));
}
}
fn handle_world(
server: &mut Server,
client: EcsEntity,
target: EcsEntity,
msg: String,
_action: &ChatCommand,
) {
if client != target {
// This happens when [ab]using /sudo
server.notify_client(
client,
ServerMsg::tell(String::from("It's rude to impersonate people")),
);
return;
}
let _ = server
.state
.ecs()
.write_storage()
.insert(client, comp::ChatMode::World);
if !msg.is_empty() {
server
.state
.notify_registered_clients(ServerMsg::world(msg.to_string()));
}
}
#[cfg(not(feature = "worldgen"))] #[cfg(not(feature = "worldgen"))]
fn handle_debug_column( fn handle_debug_column(
server: &mut Server, server: &mut Server,

View File

@ -1,6 +1,6 @@
use super::{ use super::{
img_ids::Imgs, BROADCAST_COLOR, FACTION_COLOR, GAME_UPDATE_COLOR, GROUP_COLOR, KILL_COLOR, img_ids::Imgs, BROADCAST_COLOR, FACTION_COLOR, GAME_UPDATE_COLOR, GROUP_COLOR, KILL_COLOR,
META_COLOR, PRIVATE_COLOR, SAY_COLOR, TELL_COLOR, TEXT_COLOR, META_COLOR, PRIVATE_COLOR, REGION_COLOR, SAY_COLOR, TELL_COLOR, TEXT_COLOR,
}; };
use crate::{ui::fonts::ConrodVoxygenFonts, GlobalState}; use crate::{ui::fonts::ConrodVoxygenFonts, GlobalState};
use client::{cmd, Client, Event as ClientEvent}; use client::{cmd, Client, Event as ClientEvent};
@ -324,6 +324,7 @@ impl<'a> Widget for Chat<'a> {
ChatType::Say => SAY_COLOR, ChatType::Say => SAY_COLOR,
ChatType::Group => GROUP_COLOR, ChatType::Group => GROUP_COLOR,
ChatType::Faction => FACTION_COLOR, ChatType::Faction => FACTION_COLOR,
ChatType::Region => REGION_COLOR,
ChatType::Kill => KILL_COLOR, ChatType::Kill => KILL_COLOR,
}; };
let text = Text::new(&message) let text = Text::new(&message)

View File

@ -82,6 +82,7 @@ const GAME_UPDATE_COLOR: Color = Color::Rgba(1.0, 1.0, 0.0, 1.0);
const SAY_COLOR: Color = Color::Rgba(1.0, 1.0, 1.0, 1.0); const SAY_COLOR: Color = Color::Rgba(1.0, 1.0, 1.0, 1.0);
const GROUP_COLOR: Color = Color::Rgba(0.47, 0.84, 1.0, 1.0); const GROUP_COLOR: Color = Color::Rgba(0.47, 0.84, 1.0, 1.0);
const FACTION_COLOR: Color = Color::Rgba(0.24, 1.0, 0.48, 1.0); const FACTION_COLOR: Color = Color::Rgba(0.24, 1.0, 0.48, 1.0);
const REGION_COLOR: Color = Color::Rgba(1.0, 1.0, 0.0, 1.0);
const KILL_COLOR: Color = Color::Rgba(1.0, 0.17, 0.17, 1.0); const KILL_COLOR: Color = Color::Rgba(1.0, 0.17, 0.17, 1.0);
// UI Color-Theme // UI Color-Theme