Add chat types for offline, online. Implement Pfau's fixes

This commit is contained in:
CapsizeGlimmer 2020-06-12 03:43:20 -04:00 committed by Forest Anderson
parent a497fb92d3
commit 5ad212b7ed
24 changed files with 335 additions and 275 deletions

BIN
assets/voxygen/element/icons/chat/command_error_small.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
assets/voxygen/element/icons/chat/command_info_small.png (Stored with Git LFS) Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
assets/voxygen/element/icons/chat/tell.png (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

View File

@ -895,7 +895,7 @@ impl Client {
message: String::from(
"Failed to collect item. Your inventory may be full!",
),
chat_type: comp::ChatType::Private,
chat_type: comp::ChatType::CommandError,
}))
},
_ => {
@ -1040,8 +1040,12 @@ impl Client {
}
};
match chat_type {
comp::ChatType::Private => message.to_string(),
comp::ChatType::Broadcast => message.to_string(),
comp::ChatType::Online => message.to_string(),
comp::ChatType::Offline => message.to_string(),
comp::ChatType::CommandError => message.to_string(),
comp::ChatType::CommandInfo => message.to_string(),
comp::ChatType::FactionMeta => message.to_string(),
comp::ChatType::GroupMeta => message.to_string(),
comp::ChatType::Kill => message.to_string(),
comp::ChatType::Tell(from, to) => {
let from_alias = alias_of_uid(from);
@ -1058,7 +1062,7 @@ impl Client {
comp::ChatType::Region(uid) => message_format(uid, message, None),
comp::ChatType::World(uid) => message_format(uid, message, None),
// NPCs can't talk. Should be filtered by hud/mod.rs for voxygen and should be filtered
// by server for chat-cli
// by server (due to not having a Pos) for chat-cli
comp::ChatType::Npc(_uid, _r) => "".to_string(),
}
}

View File

@ -1,9 +1,10 @@
use crate::sync::Uid;
use crate::{msg::ServerMsg, sync::Uid};
use specs::Component;
use specs_idvs::IDVStorage;
use std::time::{Duration, Instant};
/// A player's current chat mode.
/// A player's current chat mode. These are chat types that can only be sent by
/// the player.
#[derive(Clone, Debug)]
pub enum ChatMode {
/// Private message to another player (by uuid)
@ -43,17 +44,25 @@ impl Default for ChatMode {
fn default() -> Self { Self::World }
}
/// List of chat types. Note that this is a superset of `ChatMode`; this is
/// because `ChatType::Kill`, `ChatType::Broadcast`, and `ChatType::Private`
/// cannot be sent by players.
/// List of chat types. Each one is colored differently and has its own icon.
///
/// This is a superset of `SpeechBubbleType`, which is a superset of `ChatMode`
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ChatType {
/// Tell all players something (such as players connecting or alias changes)
Broadcast,
/// Private messages from the server (such as results of chat commands)
Private,
/// A player came online
Online,
/// A player went offline
Offline,
/// The result of chat commands
CommandInfo,
/// A chat command failed
CommandError,
/// Inform players that someone died
Kill,
/// Server notifications to a group, such as player join/leave
GroupMeta,
/// Server notifications to a faction, such as player join/leave
FactionMeta,
/// One-on-one chat (from, to)
Tell(Uid, Uid),
/// Chat with nearby players
@ -72,6 +81,19 @@ pub enum ChatType {
Npc(Uid, u16),
}
impl ChatType {
pub fn message<S>(self, msg: S) -> ServerMsg
where
S: Into<String>,
{
let msg = ChatMsg {
chat_type: self,
message: msg.into(),
};
ServerMsg::ChatMsg(msg)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChatMsg {
pub chat_type: ChatType,
@ -83,11 +105,6 @@ impl ChatMsg {
pub const REGION_DISTANCE: f32 = 1000.0;
pub const SAY_DISTANCE: f32 = 100.0;
pub fn broadcast(message: String) -> Self {
let chat_type = ChatType::Broadcast;
Self { chat_type, message }
}
pub fn npc(uid: Uid, message: String) -> Self {
let chat_type = ChatType::Npc(uid, rand::random());
Self { chat_type, message }
@ -105,8 +122,12 @@ impl ChatMsg {
pub fn icon(&self) -> SpeechBubbleType {
match &self.chat_type {
ChatType::Broadcast => SpeechBubbleType::None,
ChatType::Private => SpeechBubbleType::None,
ChatType::Online => SpeechBubbleType::None,
ChatType::Offline => SpeechBubbleType::None,
ChatType::CommandInfo => SpeechBubbleType::None,
ChatType::CommandError => SpeechBubbleType::None,
ChatType::FactionMeta => SpeechBubbleType::None,
ChatType::GroupMeta => SpeechBubbleType::None,
ChatType::Kill => SpeechBubbleType::None,
ChatType::Tell(_u, _) => SpeechBubbleType::Tell,
ChatType::Say(_u) => SpeechBubbleType::Say,
@ -120,8 +141,12 @@ impl ChatMsg {
pub fn uid(&self) -> Option<Uid> {
match &self.chat_type {
ChatType::Broadcast => None,
ChatType::Private => None,
ChatType::Online => None,
ChatType::Offline => None,
ChatType::CommandInfo => None,
ChatType::CommandError => None,
ChatType::FactionMeta => None,
ChatType::GroupMeta => None,
ChatType::Kill => None,
ChatType::Tell(u, _t) => Some(*u),
ChatType::Say(u) => Some(*u),
@ -169,6 +194,9 @@ pub enum SpeechBubbleMessage {
Localized(String, u16),
}
/// List of chat types for players and NPCs. Each one has its own icon.
///
/// This is a subset of `ChatType`, and a superset of `ChatMode`
pub enum SpeechBubbleType {
// One for each chat mode
Tell,

View File

@ -116,25 +116,30 @@ impl From<AuthClientError> for RegisterError {
fn from(err: AuthClientError) -> Self { Self::AuthError(err.to_string()) }
}
impl ServerMsg {
pub fn broadcast(message: String) -> ServerMsg {
ServerMsg::ChatMsg(comp::ChatMsg {
chat_type: comp::ChatType::Broadcast,
message,
})
}
pub fn private(message: String) -> ServerMsg {
ServerMsg::ChatMsg(comp::ChatMsg {
chat_type: comp::ChatType::Private,
message,
})
}
pub fn kill(message: String) -> ServerMsg {
ServerMsg::ChatMsg(comp::ChatMsg {
chat_type: comp::ChatType::Kill,
message,
})
}
impl From<comp::ChatMsg> for ServerMsg {
fn from(v: comp::ChatMsg) -> Self { ServerMsg::ChatMsg(v) }
}
impl ServerMsg {
// TODO remove unneeded
// pub fn broadcast(message: String) -> ServerMsg {
// ServerMsg::ChatMsg(comp::ChatMsg {
// chat_type: comp::ChatType::Broadcast,
// message,
// })
// }
// pub fn private(message: String) -> ServerMsg {
// ServerMsg::ChatMsg(comp::ChatMsg {
// chat_type: comp::ChatType::Private,
// message,
// })
// }
// pub fn kill(message: String) -> ServerMsg {
// ServerMsg::ChatMsg(comp::ChatMsg {
// chat_type: comp::ChatType::Kill,
// message,
// })
// }
}

View File

@ -7,8 +7,7 @@ use chrono::{NaiveTime, Timelike};
use common::{
assets,
cmd::{ChatCommand, CHAT_COMMANDS, CHAT_SHORTCUTS},
comp,
comp::Item,
comp::{self, ChatType, Item},
event::{EventBus, ServerEvent},
msg::{Notification, PlayerListUpdate, ServerMsg},
npc::{self, get_npc_name},
@ -36,7 +35,7 @@ impl ChatCommandExt for ChatCommand {
if *cmd_data.needs_admin && !server.entity_is_admin(entity) {
server.notify_client(
entity,
ServerMsg::private(format!(
ChatType::CommandError.message(format!(
"You don't have permission to use '/{}'.",
self.keyword()
)),
@ -126,7 +125,7 @@ fn handle_give_item(
if inv.push(item).is_some() {
server.notify_client(
client,
ServerMsg::private(format!(
ChatType::CommandError.message(format!(
"Player inventory full. Gave 0 of {} items.",
give_amount
)),
@ -145,7 +144,7 @@ fn handle_give_item(
if inv.push(item.clone()).is_some() {
server.notify_client(
client,
ServerMsg::private(format!(
ChatType::CommandError.message(format!(
"Player inventory full. Gave {} of {} items.",
i, give_amount
)),
@ -167,14 +166,11 @@ fn handle_give_item(
} else {
server.notify_client(
client,
ServerMsg::private(format!("Invalid item: {}", item_name)),
ChatType::CommandError.message(format!("Invalid item: {}", item_name)),
);
}
} else {
server.notify_client(
client,
ServerMsg::private(String::from(action.help_string())),
);
server.notify_client(client, ChatType::CommandError.message(action.help_string()));
}
}
@ -235,7 +231,7 @@ fn handle_jump(
},
None => server.notify_client(
client,
ServerMsg::private(String::from("You have no position.")),
ChatType::CommandError.message("You have no position."),
),
}
}
@ -262,14 +258,11 @@ fn handle_goto(
} else {
server.notify_client(
client,
ServerMsg::private(String::from("You have no position.")),
ChatType::CommandError.message("You have no position."),
);
}
} else {
server.notify_client(
client,
ServerMsg::private(String::from(action.help_string())),
);
server.notify_client(client, ChatType::CommandError.message(action.help_string()));
}
}
@ -319,7 +312,7 @@ fn handle_time(
Err(_) => {
server.notify_client(
client,
ServerMsg::private(format!("'{}' is not a valid time.", n)),
ChatType::CommandError.message(format!("'{}' is not a valid time.", n)),
);
return;
},
@ -337,7 +330,7 @@ fn handle_time(
Some(time) => format!("It is {}", time.format("%H:%M").to_string()),
None => String::from("Unknown Time"),
};
server.notify_client(client, ServerMsg::private(msg));
server.notify_client(client, ChatType::CommandInfo.message(msg));
return;
},
};
@ -347,7 +340,7 @@ fn handle_time(
server.notify_client(
client,
ServerMsg::private(format!(
ChatType::CommandInfo.message(format!(
"Time changed to: {}",
new_time.format("%H:%M").to_string()
)),
@ -372,13 +365,13 @@ fn handle_health(
} else {
server.notify_client(
client,
ServerMsg::private(String::from("You have no health.")),
ChatType::CommandError.message("You have no health."),
);
}
} else {
server.notify_client(
client,
ServerMsg::private(String::from("You must specify health amount!")),
ChatType::CommandError.message("You must specify health amount!"),
);
}
}
@ -395,13 +388,14 @@ fn handle_alias(
// Notify target that an admin changed the alias due to /sudo
server.notify_client(
target,
ServerMsg::private(String::from("An admin changed your alias.")),
ChatType::CommandInfo.message("An admin changed your alias."),
);
return;
}
if let Ok(alias) = scan_fmt!(&args, &action.arg_fmt(), String) {
if !comp::Player::alias_is_valid(&alias) {
// Prevent silly aliases
server.notify_client(client, ServerMsg::private(String::from("Invalid alias.")));
server.notify_client(client, ChatType::CommandError.message("Invalid alias."));
return;
}
let old_alias_optional = server
@ -426,19 +420,14 @@ fn handle_alias(
// Announce alias change if target has a Body.
if ecs.read_storage::<comp::Body>().get(target).is_some() {
server
.state
.notify_registered_clients(ServerMsg::broadcast(format!(
"{} is now known as {}.",
old_alias, player.alias
)));
server.state.notify_registered_clients(
ChatType::CommandInfo
.message(format!("{} is now known as {}.", old_alias, player.alias)),
);
}
}
} else {
server.notify_client(
client,
ServerMsg::private(String::from(action.help_string())),
);
server.notify_client(client, ChatType::CommandError.message(action.help_string()));
}
}
@ -460,15 +449,16 @@ fn handle_tp(
} else if client != target {
Some(client)
} else {
server.notify_client(
client,
ServerMsg::private("You must specify a player name".to_string()),
);
server.notify_client(
client,
ServerMsg::private(String::from(action.help_string())),
);
return;
if client != target {
Some(client)
} else {
server.notify_client(
client,
ChatType::CommandError.message("You must specify a player name".to_string()),
);
server.notify_client(client, ChatType::CommandError.message(action.help_string()));
return;
}
};
if let Some(_pos) = server.state.read_component_cloned::<comp::Pos>(target) {
if let Some(player) = opt_player {
@ -478,18 +468,21 @@ fn handle_tp(
} else {
server.notify_client(
client,
ServerMsg::private(format!("Unable to teleport to player!")),
ChatType::CommandError.message(format!("Unable to teleport to player!")),
);
}
} else {
server.notify_client(client, ServerMsg::private(format!("Player not found!")));
server.notify_client(
client,
ServerMsg::private(String::from(action.help_string())),
ChatType::CommandError.message(format!("Player not found!")),
);
server.notify_client(client, ChatType::CommandError.message(action.help_string()));
}
} else {
server.notify_client(client, ServerMsg::private(format!("You have no position!")));
server.notify_client(
client,
ChatType::CommandError.message(format!("You have no position!")),
);
}
}
@ -546,7 +539,7 @@ fn handle_spawn(
if let Some(uid) = server.state.ecs().uid_from_entity(new_entity) {
server.notify_client(
client,
ServerMsg::private(
ChatType::CommandInfo.message(
format!("Spawned entity with ID: {}", uid).to_owned(),
),
);
@ -554,21 +547,19 @@ fn handle_spawn(
}
server.notify_client(
client,
ServerMsg::private(format!("Spawned {} entities", amount).to_owned()),
ChatType::CommandInfo
.message(format!("Spawned {} entities", amount).to_owned()),
);
},
None => server.notify_client(
client,
ServerMsg::private("You have no position!".to_owned()),
ChatType::CommandError.message("You have no position!".to_owned()),
),
}
}
},
_ => {
server.notify_client(
client,
ServerMsg::private(String::from(action.help_string())),
);
server.notify_client(client, ChatType::CommandError.message(action.help_string()));
},
}
}
@ -590,7 +581,7 @@ fn handle_players(
server.notify_client(
client,
ServerMsg::private(entity_tuples.join().fold(
ChatType::CommandInfo.message(entity_tuples.join().fold(
format!("{} online players:", entity_tuples.join().count()),
|s, (_, player, stat)| {
format!(
@ -625,7 +616,7 @@ fn handle_build(
.remove(target);
server.notify_client(
client,
ServerMsg::private(String::from("Toggled off build mode!")),
ChatType::CommandInfo.message("Toggled off build mode!"),
);
} else {
let _ = server
@ -635,7 +626,7 @@ fn handle_build(
.insert(target, comp::CanBuild);
server.notify_client(
client,
ServerMsg::private(String::from("Toggled on build mode!")),
ChatType::CommandInfo.message("Toggled on build mode!"),
);
}
}
@ -649,7 +640,7 @@ fn handle_help(
action: &ChatCommand,
) {
if let Some(cmd) = scan_fmt_some!(&args, &action.arg_fmt(), ChatCommand) {
server.notify_client(client, ServerMsg::private(String::from(cmd.help_string())));
server.notify_client(client, ChatType::CommandInfo.message(cmd.help_string()));
} else {
let mut message = String::new();
for cmd in CHAT_COMMANDS.iter() {
@ -662,7 +653,7 @@ fn handle_help(
for (k, v) in CHAT_SHORTCUTS.iter() {
message += &format!(" /{} => /{}", k, v.keyword());
}
server.notify_client(client, ServerMsg::private(message));
server.notify_client(client, ChatType::CommandInfo.message(message));
}
}
@ -696,7 +687,7 @@ fn handle_kill_npcs(
} else {
"No NPCs on server.".to_string()
};
server.notify_client(client, ServerMsg::private(text));
server.notify_client(client, ChatType::CommandInfo.message(text));
}
#[allow(clippy::float_cmp)] // TODO: Pending review in #587
@ -750,19 +741,20 @@ fn handle_object(
.build();
server.notify_client(
client,
ServerMsg::private(format!(
ChatType::CommandInfo.message(format!(
"Spawned: {}",
obj_str_res.unwrap_or("<Unknown object>")
)),
);
} else {
return server.notify_client(
client,
ServerMsg::private(String::from("Object not found!")),
);
return server
.notify_client(client, ChatType::CommandError.message("Object not found!"));
}
} else {
server.notify_client(client, ServerMsg::private(format!("You have no position!")));
server.notify_client(
client,
ChatType::CommandError.message(format!("You have no position!")),
);
}
}
@ -784,7 +776,7 @@ fn handle_light(
if r < 0.0 || g < 0.0 || b < 0.0 {
server.notify_client(
client,
ServerMsg::private(String::from("cr, cg and cb values mustn't be negative.")),
ChatType::CommandError.message("cr, cg and cb values mustn't be negative."),
);
return;
}
@ -823,9 +815,15 @@ fn handle_light(
} else {
builder.build();
}
server.notify_client(client, ServerMsg::private(format!("Spawned object.")));
server.notify_client(
client,
ChatType::CommandInfo.message(format!("Spawned object.")),
);
} else {
server.notify_client(client, ServerMsg::private(format!("You have no position!")));
server.notify_client(
client,
ChatType::CommandError.message(format!("You have no position!")),
);
}
}
@ -854,25 +852,22 @@ fn handle_lantern(
.into();
server.notify_client(
client,
ServerMsg::private(String::from("You adjusted flame strength and color.")),
ChatType::CommandInfo.message("You adjusted flame strength and color."),
);
} else {
server.notify_client(
client,
ServerMsg::private(String::from("You adjusted flame strength.")),
ChatType::CommandInfo.message("You adjusted flame strength."),
);
}
} else {
server.notify_client(
client,
ServerMsg::private(String::from("Please equip a lantern first")),
ChatType::CommandError.message("Please equip a lantern first"),
);
}
} else {
server.notify_client(
client,
ServerMsg::private(String::from(action.help_string())),
);
server.notify_client(client, ChatType::CommandError.message(action.help_string()));
}
}
@ -888,13 +883,13 @@ fn handle_explosion(
if power > 512.0 {
server.notify_client(
client,
ServerMsg::private(String::from("Explosion power mustn't be more than 512.")),
ChatType::CommandError.message("Explosion power mustn't be more than 512."),
);
return;
} else if power <= 0.0 {
server.notify_client(
client,
ServerMsg::private(String::from("Explosion power must be more than 0.")),
ChatType::CommandError.message("Explosion power must be more than 0."),
);
return;
}
@ -912,7 +907,7 @@ fn handle_explosion(
},
None => server.notify_client(
client,
ServerMsg::private(String::from("You have no position!")),
ChatType::CommandError.message("You have no position!"),
),
}
}
@ -932,12 +927,12 @@ fn handle_waypoint(
.ecs()
.write_storage::<comp::Waypoint>()
.insert(target, comp::Waypoint::new(pos.0, *time));
server.notify_client(client, ServerMsg::private(String::from("Waypoint saved!")));
server.notify_client(client, ChatType::CommandInfo.message("Waypoint saved!"));
server.notify_client(client, ServerMsg::Notification(Notification::WaypointSaved));
},
None => server.notify_client(
client,
ServerMsg::private(String::from("You have no position!")),
ChatType::CommandError.message("You have no position!"),
),
}
}
@ -980,15 +975,12 @@ fn handle_adminify(
None => {
server.notify_client(
client,
ServerMsg::private(format!("Player '{}' not found!", alias)),
ChatType::CommandError.message(format!("Player '{}' not found!", alias)),
);
},
}
} else {
server.notify_client(
client,
ServerMsg::private(String::from(action.help_string())),
);
server.notify_client(client, ChatType::CommandError.message(action.help_string()));
}
}
@ -1005,13 +997,12 @@ fn handle_tell(
// This happens when [ab]using /sudo
server.notify_client(
client,
ServerMsg::private(String::from("It's rude to impersonate people")),
ChatType::CommandError.message("It's rude to impersonate people"),
);
return;
}
if let Ok(alias) = scan_fmt!(&args, &action.arg_fmt(), String) {
if let (Some(alias), message_opt) = scan_fmt_some!(&args, &action.arg_fmt(), String, String) {
let ecs = server.state.ecs();
let msg = &args[alias.len()..args.len()];
if let Some(player) = (&ecs.entities(), &ecs.read_storage::<comp::Player>())
.join()
.find(|(_, player)| player.alias == alias)
@ -1020,7 +1011,7 @@ fn handle_tell(
if player == client {
server.notify_client(
client,
ServerMsg::private(format!("You can't /tell yourself.")),
ChatType::CommandError.message(format!("You can't /tell yourself.")),
);
return;
}
@ -1038,23 +1029,16 @@ fn handle_tell(
.ecs()
.write_storage()
.insert(client, mode.clone());
let msg = if msg.is_empty() {
format!("{} wants to talk to you.", alias)
} else {
msg.to_string()
};
let msg = message_opt.unwrap_or_else(|| format!("{} wants to talk to you.", alias));
server.state.send_chat(mode.new_message(client_uid, msg));
} else {
server.notify_client(
client,
ServerMsg::private(format!("Player '{}' not found!", alias)),
ChatType::CommandError.message(format!("Player '{}' not found!", alias)),
);
}
} else {
server.notify_client(
client,
ServerMsg::private(String::from(action.help_string())),
);
server.notify_client(client, ChatType::CommandError.message(action.help_string()));
}
}
@ -1069,7 +1053,7 @@ fn handle_faction(
// This happens when [ab]using /sudo
server.notify_client(
client,
ServerMsg::private(String::from("It's rude to impersonate people")),
ChatType::CommandError.message("It's rude to impersonate people"),
);
return;
}
@ -1087,7 +1071,7 @@ fn handle_faction(
} else {
server.notify_client(
client,
ServerMsg::private(String::from("Please join a faction with /join_faction")),
ChatType::CommandError.message("Please join a faction with /join_faction"),
);
}
}
@ -1103,7 +1087,7 @@ fn handle_group(
// This happens when [ab]using /sudo
server.notify_client(
client,
ServerMsg::private(String::from("It's rude to impersonate people")),
ChatType::CommandError.message("It's rude to impersonate people"),
);
return;
}
@ -1121,7 +1105,7 @@ fn handle_group(
} else {
server.notify_client(
client,
ServerMsg::private(String::from("Please join a group with /join_group")),
ChatType::CommandError.message("Please join a group with /join_group"),
);
}
}
@ -1137,7 +1121,7 @@ fn handle_region(
// This happens when [ab]using /sudo
server.notify_client(
client,
ServerMsg::private(String::from("It's rude to impersonate people")),
ChatType::CommandError.message("It's rude to impersonate people"),
);
return;
}
@ -1167,7 +1151,7 @@ fn handle_say(
// This happens when [ab]using /sudo
server.notify_client(
client,
ServerMsg::private(String::from("It's rude to impersonate people")),
ChatType::CommandError.message("It's rude to impersonate people"),
);
return;
}
@ -1197,7 +1181,7 @@ fn handle_world(
// This happens when [ab]using /sudo
server.notify_client(
client,
ServerMsg::private(String::from("It's rude to impersonate people")),
ChatType::CommandError.message("It's rude to impersonate people"),
);
return;
}
@ -1227,33 +1211,46 @@ fn handle_join_faction(
// This happens when [ab]using /sudo
server.notify_client(
client,
ServerMsg::private(String::from("It's rude to impersonate people")),
ChatType::CommandError.message("It's rude to impersonate people"),
);
return;
}
if let Ok(faction) = scan_fmt!(&args, &action.arg_fmt(), String) {
let mode = comp::ChatMode::Faction(faction.clone());
let _ = server.state.ecs().write_storage().insert(client, mode);
let _ = server
.state
.ecs()
.write_storage()
.insert(client, comp::Faction(faction.clone()));
// TODO notify faction
server.notify_client(
client,
ServerMsg::private(format!("Joined faction {{{}}}", faction)),
);
} else {
let mode = comp::ChatMode::default();
let _ = server.state.ecs().write_storage().insert(client, mode);
if let Some(comp::Faction(faction)) = server.state.ecs().write_storage().remove(client) {
// TODO notify faction
if let Some(alias) = server
.state
.ecs()
.read_storage::<comp::Player>()
.get(target)
.map(|player| player.alias.clone())
{
if let Ok(faction) = scan_fmt!(&args, &action.arg_fmt(), String) {
let mode = comp::ChatMode::Faction(faction.clone());
let _ = server.state.ecs().write_storage().insert(client, mode);
let _ = server
.state
.ecs()
.write_storage()
.insert(client, comp::Faction(faction.clone()));
server.notify_client(
client,
ServerMsg::private(format!("Left faction {{{}}}", faction)),
ChatType::FactionMeta.message(format!("[{}] joined faction ({})", alias, faction)),
);
} else {
let mode = comp::ChatMode::default();
let _ = server.state.ecs().write_storage().insert(client, mode);
if let Some(comp::Faction(faction)) = server.state.ecs().write_storage().remove(client)
{
server.notify_client(
client,
ChatType::FactionMeta
.message(format!("[{}] left faction ({})", alias, faction)),
);
}
}
} else {
server.notify_client(
client,
ChatType::CommandError.message("Could not find your player alias"),
);
}
}
@ -1268,33 +1265,44 @@ fn handle_join_group(
// This happens when [ab]using /sudo
server.notify_client(
client,
ServerMsg::private(String::from("It's rude to impersonate people")),
ChatType::CommandError.message("It's rude to impersonate people"),
);
return;
}
if let Ok(group) = scan_fmt!(&args, &action.arg_fmt(), String) {
let mode = comp::ChatMode::Group(group.clone());
let _ = server.state.ecs().write_storage().insert(client, mode);
let _ = server
.state
.ecs()
.write_storage()
.insert(client, comp::Group(group.clone()));
// TODO notify group
server.notify_client(
client,
ServerMsg::private(format!("Joined group ({})", group)),
);
} else {
let mode = comp::ChatMode::default();
let _ = server.state.ecs().write_storage().insert(client, mode);
if let Some(comp::Group(group)) = server.state.ecs().write_storage().remove(client) {
// TODO notify group
if let Some(alias) = server
.state
.ecs()
.read_storage::<comp::Player>()
.get(target)
.map(|player| player.alias.clone())
{
if let Ok(group) = scan_fmt!(&args, &action.arg_fmt(), String) {
let mode = comp::ChatMode::Group(group.clone());
let _ = server.state.ecs().write_storage().insert(client, mode);
let _ = server
.state
.ecs()
.write_storage()
.insert(client, comp::Group(group.clone()));
server.notify_client(
client,
ServerMsg::private(format!("Left group ({})", group)),
ChatType::GroupMeta.message(format!("[{}] joined group ({})", alias, group)),
);
} else {
let mode = comp::ChatMode::default();
let _ = server.state.ecs().write_storage().insert(client, mode);
if let Some(comp::Group(group)) = server.state.ecs().write_storage().remove(client) {
server.notify_client(
client,
ChatType::GroupMeta.message(format!("[{}] left group ({})", alias, group)),
);
}
}
} else {
server.notify_client(
client,
ChatType::CommandError.message("Could not find your player alias"),
);
}
}
@ -1308,7 +1316,7 @@ fn handle_debug_column(
) {
server.notify_client(
client,
ServerMsg::private(String::from("Unsupported without worldgen enabled")),
ChatType::CommandError.message("Unsupported without worldgen enabled"),
);
}
@ -1380,18 +1388,15 @@ spawn_rate {:?} "#,
))
};
if let Some(s) = foo() {
server.notify_client(client, ServerMsg::private(s));
server.notify_client(client, ChatType::CommandInfo.message(s));
} else {
server.notify_client(
client,
ServerMsg::private(String::from("Not a pregenerated chunk.")),
ChatType::CommandError.message("Not a pregenerated chunk."),
);
}
} else {
server.notify_client(
client,
ServerMsg::private(String::from(action.help_string())),
);
server.notify_client(client, ChatType::CommandError.message(action.help_string()));
}
}
@ -1406,7 +1411,7 @@ fn find_target(
.join()
.find(|(_, player)| player.alias == alias)
.map(|(entity, _)| entity)
.ok_or(ServerMsg::private(format!("Player '{}' not found!", alias)))
.ok_or(ChatType::CommandError.message(format!("Player '{}' not found!", alias)))
} else {
Ok(fallback)
}
@ -1432,7 +1437,7 @@ fn handle_give_exp(
if let Some(stats) = ecs.write_storage::<comp::Stats>().get_mut(player) {
stats.exp.change_by(exp);
} else {
error_msg = Some(ServerMsg::private(String::from("Player has no stats!")));
error_msg = Some(ChatType::CommandError.message("Player has no stats!"));
}
},
Err(e) => {
@ -1487,7 +1492,7 @@ fn handle_set_level(
.health
.set_to(stats.health.maximum(), comp::HealthSource::LevelUp);
} else {
error_msg = Some(ServerMsg::private(String::from("Player has no stats!")));
error_msg = Some(ChatType::CommandError.message("Player has no stats!"));
}
},
Err(e) => {
@ -1527,9 +1532,7 @@ fn handle_debug(
} else {
server.notify_client(
client,
ServerMsg::private(String::from(
"Debug items not found? Something is very broken.",
)),
ChatType::CommandError.message("Debug items not found? Something is very broken."),
);
}
}
@ -1568,7 +1571,7 @@ fn handle_remove_lights(
},
None => server.notify_client(
client,
ServerMsg::private(String::from("You have no position.")),
ChatType::CommandError.message("You have no position."),
),
}
@ -1582,7 +1585,7 @@ fn handle_remove_lights(
server.notify_client(
client,
ServerMsg::private(String::from(format!("Removed {} lights!", size))),
ChatType::CommandError.message(format!("Removed {} lights!", size)),
);
}
@ -1612,20 +1615,17 @@ fn handle_sudo(
} else {
server.notify_client(
client,
ServerMsg::private(format!("Could not find that player")),
ChatType::CommandError.message(format!("Could not find that player")),
);
}
} else {
server.notify_client(
client,
ServerMsg::private(format!("Unknown command: /{}", cmd)),
ChatType::CommandError.message(format!("Unknown command: /{}", cmd)),
);
}
} else {
server.notify_client(
client,
ServerMsg::private(String::from(action.help_string())),
);
server.notify_client(client, ChatType::CommandError.message(action.help_string()));
}
}
@ -1638,7 +1638,7 @@ fn handle_version(
) {
server.notify_client(
client,
ServerMsg::private(format!(
ChatType::CommandInfo.message(format!(
"Server is running {}[{}]",
common::util::GIT_HASH.to_string(),
common::util::GIT_DATE.to_string(),

View File

@ -46,7 +46,7 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, cause: HealthSourc
}
.unwrap_or(format!("{} died", &player.alias));
state.notify_registered_clients(ServerMsg::kill(msg));
state.notify_registered_clients(comp::ChatType::Kill.message(msg));
}
{

View File

@ -64,7 +64,7 @@ pub fn handle_client_disconnect(server: &mut Server, entity: EcsEntity) -> Event
let mut accounts = state.ecs().write_resource::<AuthProvider>();
accounts.logout(player.uuid());
let msg = ServerMsg::broadcast(format!("{} went offline.", &player.alias));
let msg = comp::ChatType::Online.message(format!("{} went offline.", &player.alias));
state.notify_registered_clients(msg);
}

View File

@ -29,7 +29,7 @@ use crate::{
};
use common::{
cmd::ChatCommand,
comp,
comp::{self, ChatType},
event::{EventBus, ServerEvent},
msg::{ClientMsg, ClientState, ServerInfo, ServerMsg},
net::PostOffice,
@ -622,9 +622,12 @@ impl Server {
Ok(frontend_events)
}
pub fn notify_client(&self, entity: EcsEntity, msg: ServerMsg) {
pub fn notify_client<S>(&self, entity: EcsEntity, msg: S)
where
S: Into<ServerMsg>,
{
if let Some(client) = self.state.ecs().write_storage::<Client>().get_mut(entity) {
client.notify(msg)
client.notify(msg.into())
}
}
@ -649,7 +652,7 @@ impl Server {
} else {
self.notify_client(
entity,
ServerMsg::private(format!(
ChatType::CommandError.message(format!(
"Unknown command '/{}'.\nType '/help' for available commands",
kwd
)),

View File

@ -247,9 +247,13 @@ impl StateExt for State {
let is_within =
|target, a: &comp::Pos, b: &comp::Pos| a.0.distance_squared(b.0) < target * target;
match &msg.chat_type {
comp::ChatType::Broadcast
comp::ChatType::Online
| comp::ChatType::Offline
| comp::ChatType::CommandInfo
| comp::ChatType::CommandError
| comp::ChatType::Kill
| comp::ChatType::Private
| comp::ChatType::GroupMeta
| comp::ChatType::FactionMeta
| comp::ChatType::World(_) => {
self.notify_registered_clients(ServerMsg::ChatMsg(msg.clone()))
},

View File

@ -5,8 +5,8 @@ use crate::{
};
use common::{
comp::{
Admin, CanBuild, ChatMode, ChatMsg, ControlEvent, Controller, ForceUpdate, Ori, Player,
Pos, Stats, Vel,
Admin, CanBuild, ChatMode, ChatMsg, ChatType, ControlEvent, Controller, ForceUpdate, Ori,
Player, Pos, Stats, Vel,
},
event::{EventBus, ServerEvent},
msg::{
@ -245,9 +245,10 @@ impl<'a> System<'a> for Sys {
character_id,
);
server_emitter.emit(ServerEvent::Chat(ChatMsg::broadcast(
format!("[{}] is now online.", &player.alias),
)));
server_emitter.emit(ServerEvent::Chat(ChatMsg {
chat_type: ChatType::Online,
message: format!("[{}] is now online.", &player.alias),
}));
// Start inserting non-persisted/default components for the entity
// while we load the DB data

View File

@ -1,6 +1,6 @@
use super::{
img_ids::Imgs, BROADCAST_COLOR, FACTION_COLOR, GROUP_COLOR, KILL_COLOR, PRIVATE_COLOR,
REGION_COLOR, SAY_COLOR, TELL_COLOR, TEXT_COLOR, WORLD_COLOR,
img_ids::Imgs, ERROR_COLOR, FACTION_COLOR, GROUP_COLOR, INFO_COLOR, KILL_COLOR, OFFLINE_COLOR,
ONLINE_COLOR, REGION_COLOR, SAY_COLOR, TELL_COLOR, TEXT_COLOR, WORLD_COLOR,
};
use crate::{ui::fonts::ConrodVoxygenFonts, GlobalState};
use client::{cmd, Client};
@ -474,8 +474,12 @@ fn cursor_offset_to_index(
/// Get the color and icon for the current line in the chat box
fn render_chat_line(chat_type: &ChatType, imgs: &Imgs) -> (Color, conrod_core::image::Id) {
match chat_type {
ChatType::Private => (PRIVATE_COLOR, imgs.chat_private_small),
ChatType::Broadcast => (BROADCAST_COLOR, imgs.chat_broadcast_small),
ChatType::Online => (ONLINE_COLOR, imgs.chat_online_small),
ChatType::Offline => (OFFLINE_COLOR, imgs.chat_offline_small),
ChatType::CommandError => (ERROR_COLOR, imgs.chat_command_error_small),
ChatType::CommandInfo => (INFO_COLOR, imgs.chat_command_info_small),
ChatType::GroupMeta => (GROUP_COLOR, imgs.chat_group_small),
ChatType::FactionMeta => (FACTION_COLOR, imgs.chat_faction_small),
ChatType::Kill => (KILL_COLOR, imgs.chat_kill_small),
ChatType::Tell(_from, _to) => (TELL_COLOR, imgs.chat_tell_small),
ChatType::Say(_uid) => (SAY_COLOR, imgs.chat_say_small),

View File

@ -298,15 +298,17 @@ image_ids! {
dark_bubble_tail: "voxygen.element.frames.bubble_dark.tail",
// Chat icons
chat_broadcast_small: "voxygen.element.icons.chat.broadcast_small",
chat_faction_small: "voxygen.element.icons.chat.faction_small",
chat_group_small: "voxygen.element.icons.chat.group_small",
chat_kill_small: "voxygen.element.icons.chat.kill_small",
chat_private_small: "voxygen.element.icons.chat.private_small",
chat_region_small: "voxygen.element.icons.chat.region_small",
chat_say_small: "voxygen.element.icons.chat.say_small",
chat_tell_small: "voxygen.element.icons.chat.tell_small",
chat_world_small: "voxygen.element.icons.chat.world_small",
chat_command_error_small: "voxygen.element.icons.chat.command_error_small",
chat_command_info_small: "voxygen.element.icons.chat.command_info_small",
chat_online_small: "voxygen.element.icons.chat.online_small",
chat_offline_small: "voxygen.element.icons.chat.offline_small",
chat_faction: "voxygen.element.icons.chat.faction",
chat_group: "voxygen.element.icons.chat.group",

View File

@ -47,10 +47,7 @@ use crate::{
GlobalState,
};
use client::Client;
use common::{
assets::load_expect, comp, comp::SpeechBubbleType, sync::Uid, terrain::TerrainChunk,
vol::RectRasterableVol,
};
use common::{assets::load_expect, comp, sync::Uid, terrain::TerrainChunk, vol::RectRasterableVol};
use conrod_core::{
text::cursor::Index,
widget::{self, Button, Image, Text},
@ -80,12 +77,16 @@ const MANA_COLOR: Color = Color::Rgba(0.29, 0.62, 0.75, 0.9);
//const RAGE_COLOR: Color = Color::Rgba(0.5, 0.04, 0.13, 1.0);
// Chat Colors
/// Color for chat command errors (yellow !)
const ERROR_COLOR: Color = Color::Rgba(1.0, 1.0, 0.0, 1.0);
/// Color for chat command info (blue i)
const INFO_COLOR: Color = Color::Rgba(0.28, 0.83, 0.71, 1.0);
/// Online color
const ONLINE_COLOR: Color = Color::Rgba(0.3, 1.0, 0.3, 1.0);
/// Offline color
const OFFLINE_COLOR: Color = Color::Rgba(1.0, 0.3, 0.3, 1.0);
/// Color for a private message from another player
const TELL_COLOR: Color = Color::Rgba(0.98, 0.71, 1.0, 1.0);
/// Color for private messages from the server (such as /cmd)
const PRIVATE_COLOR: Color = Color::Rgba(1.0, 1.0, 0.0, 1.0);
/// Color for public messages from the server
const BROADCAST_COLOR: Color = Color::Rgba(0.28, 0.83, 0.71, 1.0);
/// Color for local chat
const SAY_COLOR: Color = Color::Rgba(1.0, 0.8, 0.8, 1.0);
/// Color for group chat
@ -93,11 +94,11 @@ const GROUP_COLOR: Color = Color::Rgba(0.47, 0.84, 1.0, 1.0);
/// Color for factional chat
const FACTION_COLOR: Color = Color::Rgba(0.24, 1.0, 0.48, 1.0);
/// Color for regional chat
const REGION_COLOR: Color = Color::Rgba(0.2, 0.2, 1.0, 1.0);
const REGION_COLOR: Color = Color::Rgba(0.8, 1.0, 0.8, 1.0);
/// Color for death messages
const KILL_COLOR: Color = Color::Rgba(1.0, 0.17, 0.17, 1.0);
/// Color for global messages
const WORLD_COLOR: Color = Color::Rgba(0.9, 1.0, 0.9, 1.0);
const WORLD_COLOR: Color = Color::Rgba(0.95, 1.0, 0.95, 1.0);
// UI Color-Theme
const UI_MAIN: Color = Color::Rgba(0.61, 0.70, 0.70, 1.0); // Greenish Blue
@ -472,7 +473,6 @@ pub struct Hud {
new_messages: VecDeque<comp::ChatMsg>,
new_notifications: VecDeque<common::msg::Notification>,
speech_bubbles: HashMap<Uid, comp::SpeechBubble>,
bubble_type: SpeechBubbleType,
show: Show,
//never_show: bool,
//intro: bool,
@ -540,7 +540,6 @@ impl Hud {
new_messages: VecDeque::new(),
new_notifications: VecDeque::new(),
speech_bubbles: HashMap::new(),
bubble_type: SpeechBubbleType::None,
//intro: false,
//intro_2: false,
show: Show {
@ -1020,7 +1019,6 @@ impl Hud {
overhead::Overhead::new(
&name,
bubble,
&self.bubble_type,
stats,
energy,
own_level,

View File

@ -1,6 +1,6 @@
use super::{
img_ids::Imgs, FACTION_COLOR, GROUP_COLOR, HP_COLOR, LOW_HP_COLOR, MANA_COLOR, SAY_COLOR,
TELL_COLOR, TEXT_BG, TEXT_COLOR,
img_ids::Imgs, FACTION_COLOR, GROUP_COLOR, HP_COLOR, LOW_HP_COLOR, MANA_COLOR, REGION_COLOR,
SAY_COLOR, TELL_COLOR, TEXT_BG, TEXT_COLOR,
};
use crate::{
i18n::VoxygenLocalization,
@ -59,7 +59,6 @@ pub struct Overhead<'a> {
voxygen_i18n: &'a std::sync::Arc<VoxygenLocalization>,
imgs: &'a Imgs,
fonts: &'a ConrodVoxygenFonts,
bubble_type: &'a SpeechBubbleType,
#[conrod(common_builder)]
common: widget::CommonBuilder,
}
@ -69,7 +68,6 @@ impl<'a> Overhead<'a> {
pub fn new(
name: &'a str,
bubble: Option<&'a SpeechBubble>,
bubble_type: &'a SpeechBubbleType,
stats: &'a Stats,
energy: &'a Energy,
own_level: u32,
@ -82,7 +80,6 @@ impl<'a> Overhead<'a> {
Self {
name,
bubble,
bubble_type,
stats,
energy,
own_level,
@ -157,25 +154,13 @@ impl<'a> Widget for Overhead<'a> {
|s: &str, i| -> String { self.voxygen_i18n.get_variation(&s, i).to_string() };
let bubble_contents: String = bubble.message(localizer);
let mut text = Text::new(&bubble_contents)
.color(bubble_color(&bubble, dark_mode))
.font_id(self.fonts.cyri.conrod_id)
.font_size(18)
.up_from(state.ids.name, 20.0)
.x_align_to(state.ids.name, Align::Middle)
.parent(id);
text = match self.bubble_type {
SpeechBubbleType::Tell => text.color(TELL_COLOR),
SpeechBubbleType::Say => text.color(SAY_COLOR),
SpeechBubbleType::Group => text.color(GROUP_COLOR),
SpeechBubbleType::Faction => text.color(FACTION_COLOR),
_ => {
if dark_mode {
text.color(TEXT_COLOR)
} else {
text.color(TEXT_BG)
}
},
};
if let Some(w) = text.get_w(ui) {
if w > 250.0 {
text = text.w(250.0);
@ -382,6 +367,26 @@ impl<'a> Widget for Overhead<'a> {
}
}
fn bubble_color(bubble: &SpeechBubble, dark_mode: bool) -> Color {
match bubble.icon {
SpeechBubbleType::Tell => TELL_COLOR,
SpeechBubbleType::Say => SAY_COLOR,
SpeechBubbleType::Region => REGION_COLOR,
SpeechBubbleType::Group => GROUP_COLOR,
SpeechBubbleType::Faction => FACTION_COLOR,
SpeechBubbleType::World
| SpeechBubbleType::Quest
| SpeechBubbleType::Trade
| SpeechBubbleType::None => {
if dark_mode {
TEXT_COLOR
} else {
TEXT_BG
}
},
}
}
fn bubble_icon(sb: &SpeechBubble, imgs: &Imgs) -> conrod_core::image::Id {
match sb.icon {
// One for each chat mode

View File

@ -91,7 +91,7 @@ impl SessionState {
};
self.hud.new_message(comp::ChatMsg {
chat_type: comp::ChatType::Private,
chat_type: comp::ChatType::CommandError,
message,
});
},
@ -500,7 +500,7 @@ impl PlayState for SessionState {
},
Event::ScreenshotMessage(screenshot_message) => {
self.hud.new_message(comp::ChatMsg {
chat_type: comp::ChatType::Private,
chat_type: comp::ChatType::CommandInfo,
message: screenshot_message,
})
},