Adds colour to tells in chat box #194

This commit is contained in:
tommy 2019-07-17 18:10:42 -04:00
parent b9a5ee0981
commit cc6aa6f33d
10 changed files with 174 additions and 95 deletions

View File

@ -68,7 +68,7 @@ fn main() {
for event in events { for event in events {
match event { match event {
Event::Chat(msg) => println!("{}", msg), Event::ChatMsg(msg) => println!("{}", msg),
Event::Disconnect => {} // TODO Event::Disconnect => {} // TODO
} }
} }

View File

@ -14,6 +14,7 @@ use common::{
state::State, state::State,
terrain::{block::Block, chonk::ChonkMetrics, TerrainChunk, TerrainChunkSize}, terrain::{block::Block, chonk::ChonkMetrics, TerrainChunk, TerrainChunkSize},
vol::VolSize, vol::VolSize,
ChatType,
}; };
use log::{info, log_enabled, warn}; use log::{info, log_enabled, warn};
use std::{ use std::{
@ -28,7 +29,10 @@ use vek::*;
const SERVER_TIMEOUT: Duration = Duration::from_secs(20); const SERVER_TIMEOUT: Duration = Duration::from_secs(20);
pub enum Event { pub enum Event {
Chat(String), Chat {
chat_type: ChatType,
message: String,
},
Disconnect, Disconnect,
} }
@ -187,7 +191,7 @@ impl Client {
/// Send a chat message to the server. /// Send a chat message to the server.
#[allow(dead_code)] #[allow(dead_code)]
pub fn send_chat(&mut self, msg: String) { pub fn send_chat(&mut self, msg: String) {
self.postbox.send_message(ClientMsg::Chat(msg)) self.postbox.send_message(ClientMsg::chat(msg))
} }
/// Remove all cached terrain /// Remove all cached terrain
@ -385,7 +389,16 @@ impl Client {
.duration_since(self.last_server_ping) .duration_since(self.last_server_ping)
.as_secs_f64() .as_secs_f64()
} }
ServerMsg::Chat(msg) => frontend_events.push(Event::Chat(msg)), ServerMsg::ChatMsg { chat_type, msg } => match chat_type {
ChatType::Chat => frontend_events.push(Event::Chat {
chat_type: ChatType::Chat,
message: msg,
}),
ChatType::Tell => frontend_events.push(Event::Chat {
chat_type: ChatType::Tell,
message: msg,
}),
},
ServerMsg::SetPlayerEntity(uid) => { ServerMsg::SetPlayerEntity(uid) => {
self.entity = self.state.ecs().entity_from_uid(uid).unwrap() self.entity = self.state.ecs().entity_from_uid(uid).unwrap()
} // TODO: Don't unwrap here! } // TODO: Don't unwrap here!

View File

@ -50,3 +50,9 @@ pub mod volumes;
/// assert_eq!("bar", scon.next_message().unwrap()); /// assert_eq!("bar", scon.next_message().unwrap());
/// ``` /// ```
pub mod net; pub mod net;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ChatType {
Chat,
Tell,
}

View File

@ -1,6 +1,6 @@
use super::ClientState; use super::ClientState;
use crate::comp;
use crate::terrain::block::Block; use crate::terrain::block::Block;
use crate::{comp, ChatType};
use vek::*; use vek::*;
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
@ -19,7 +19,10 @@ pub enum ClientMsg {
PlaceBlock(Vec3<i32>, Block), PlaceBlock(Vec3<i32>, Block),
Ping, Ping,
Pong, Pong,
Chat(String), ChatMsg {
chat_type: ChatType,
msg: String,
},
PlayerPhysics { PlayerPhysics {
pos: comp::Pos, pos: comp::Pos,
vel: comp::Vel, vel: comp::Vel,
@ -30,3 +33,18 @@ pub enum ClientMsg {
}, },
Disconnect, Disconnect,
} }
impl ClientMsg {
pub fn chat(message: String) -> crate::msg::client::ClientMsg {
crate::msg::client::ClientMsg::ChatMsg {
chat_type: ChatType::Chat,
msg: message,
}
}
pub fn tell(message: String) -> crate::msg::client::ClientMsg {
crate::msg::client::ClientMsg::ChatMsg {
chat_type: ChatType::Tell,
msg: message,
}
}
}

View File

@ -1,9 +1,5 @@
use super::{ClientState, EcsCompPacket, EcsResPacket}; use super::{ClientState, EcsCompPacket, EcsResPacket};
use crate::{ use crate::{comp, terrain::TerrainChunk, ChatType};
comp,
terrain::{Block, TerrainChunk},
};
use fxhash::FxHashMap;
use vek::*; use vek::*;
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
@ -32,7 +28,10 @@ pub enum ServerMsg {
ForceState(ClientState), ForceState(ClientState),
Ping, Ping,
Pong, Pong,
Chat(String), ChatMsg {
chat_type: ChatType,
msg: String,
},
SetPlayerEntity(u64), SetPlayerEntity(u64),
EcsSync(sphynx::SyncPackage<EcsCompPacket, EcsResPacket>), EcsSync(sphynx::SyncPackage<EcsCompPacket, EcsResPacket>),
EntityPhysics { EntityPhysics {
@ -57,3 +56,18 @@ pub enum ServerError {
TooManyPlayers, TooManyPlayers,
//TODO: InvalidAlias, //TODO: InvalidAlias,
} }
impl ServerMsg {
pub fn chat(message: String) -> crate::msg::server::ServerMsg {
crate::msg::server::ServerMsg::ChatMsg {
chat_type: ChatType::Chat,
msg: message,
}
}
pub fn tell(message: String) -> crate::msg::server::ServerMsg {
crate::msg::server::ServerMsg::ChatMsg {
chat_type: ChatType::Tell,
msg: message,
}
}
}

View File

@ -166,13 +166,13 @@ fn handle_jump(server: &mut Server, entity: EcsEntity, args: String, action: &Ch
} }
None => server.clients.notify( None => server.clients.notify(
entity, entity,
ServerMsg::Chat(String::from("You have no position!")), ServerMsg::chat(String::from("You have no position!")),
), ),
} }
} }
_ => server _ => server
.clients .clients
.notify(entity, ServerMsg::Chat(String::from(action.help_string))), .notify(entity, ServerMsg::chat(String::from(action.help_string))),
} }
} }
@ -188,12 +188,12 @@ fn handle_goto(server: &mut Server, entity: EcsEntity, args: String, action: &Ch
} }
_ => server _ => server
.clients .clients
.notify(entity, ServerMsg::Chat(String::from(action.help_string))), .notify(entity, ServerMsg::chat(String::from(action.help_string))),
}, },
None => { None => {
server.clients.notify( server.clients.notify(
entity, entity,
ServerMsg::Chat(String::from("You don't have any position!")), ServerMsg::chat(String::from("You don't have any position!")),
); );
} }
} }
@ -221,14 +221,14 @@ fn handle_time(server: &mut Server, entity: EcsEntity, args: String, action: &Ch
Err(_) => { Err(_) => {
server server
.clients .clients
.notify(entity, ServerMsg::Chat(format!("'{}' is not a time!", n))); .notify(entity, ServerMsg::chat(format!("'{}' is not a time!", n)));
return; return;
} }
}, },
None => { None => {
server.clients.notify( server.clients.notify(
entity, entity,
ServerMsg::Chat("You must specify a time!".to_string()), ServerMsg::chat("You must specify a time!".to_string()),
); );
return; return;
} }
@ -249,13 +249,13 @@ fn handle_health(server: &mut Server, entity: EcsEntity, args: String, action: &
None => { None => {
server.clients.notify( server.clients.notify(
entity, entity,
ServerMsg::Chat(String::from("You must specify health amount!")), ServerMsg::chat(String::from("You must specify health amount!")),
); );
} }
}, },
None => server.clients.notify( None => server.clients.notify(
entity, entity,
ServerMsg::Chat(String::from("You have no position.")), ServerMsg::chat(String::from("You have no position.")),
), ),
} }
} }
@ -273,7 +273,7 @@ fn handle_alias(server: &mut Server, entity: EcsEntity, args: String, action: &C
} }
None => server None => server
.clients .clients
.notify(entity, ServerMsg::Chat(String::from(action.help_string))), .notify(entity, ServerMsg::chat(String::from(action.help_string))),
} }
} }
@ -295,29 +295,29 @@ fn handle_tp(server: &mut Server, entity: EcsEntity, args: String, action: &Chat
} }
None => server.clients.notify( None => server.clients.notify(
entity, entity,
ServerMsg::Chat(format!("Unable to teleport to player '{}'!", alias)), ServerMsg::chat(format!("Unable to teleport to player '{}'!", alias)),
), ),
}, },
None => { None => {
server.clients.notify( server.clients.notify(
entity, entity,
ServerMsg::Chat(format!("Player '{}' not found!", alias)), ServerMsg::chat(format!("Player '{}' not found!", alias)),
); );
server server
.clients .clients
.notify(entity, ServerMsg::Chat(String::from(action.help_string))); .notify(entity, ServerMsg::chat(String::from(action.help_string)));
} }
}, },
None => { None => {
server server
.clients .clients
.notify(entity, ServerMsg::Chat(format!("You have no position!"))); .notify(entity, ServerMsg::chat(format!("You have no position!")));
} }
} }
} }
None => server None => server
.clients .clients
.notify(entity, ServerMsg::Chat(String::from(action.help_string))), .notify(entity, ServerMsg::chat(String::from(action.help_string))),
} }
} }
@ -351,17 +351,17 @@ fn handle_spawn(server: &mut Server, entity: EcsEntity, args: String, action: &C
} }
server.clients.notify( server.clients.notify(
entity, entity,
ServerMsg::Chat(format!("Spawned {} entities", amount).to_owned()), ServerMsg::chat(format!("Spawned {} entities", amount).to_owned()),
); );
} }
None => server None => server
.clients .clients
.notify(entity, ServerMsg::Chat("You have no position!".to_owned())), .notify(entity, ServerMsg::chat("You have no position!".to_owned())),
} }
} }
_ => server _ => server
.clients .clients
.notify(entity, ServerMsg::Chat(String::from(action.help_string))), .notify(entity, ServerMsg::chat(String::from(action.help_string))),
} }
} }
@ -381,11 +381,11 @@ fn handle_players(server: &mut Server, entity: EcsEntity, _args: String, _action
server server
.clients .clients
.notify(entity, ServerMsg::Chat(header_message + &player_list)); .notify(entity, ServerMsg::chat(header_message + &player_list));
} else { } else {
server server
.clients .clients
.notify(entity, ServerMsg::Chat(header_message)); .notify(entity, ServerMsg::chat(header_message));
} }
} }
@ -403,7 +403,7 @@ fn handle_build(server: &mut Server, entity: EcsEntity, _args: String, _action:
.remove(entity); .remove(entity);
server.clients.notify( server.clients.notify(
entity, entity,
ServerMsg::Chat(String::from("Toggled off build mode!")), ServerMsg::chat(String::from("Toggled off build mode!")),
); );
} else { } else {
let _ = server let _ = server
@ -413,7 +413,7 @@ fn handle_build(server: &mut Server, entity: EcsEntity, _args: String, _action:
.insert(entity, comp::CanBuild); .insert(entity, comp::CanBuild);
server.clients.notify( server.clients.notify(
entity, entity,
ServerMsg::Chat(String::from("Toggled on build mode!")), ServerMsg::chat(String::from("Toggled on build mode!")),
); );
} }
} }
@ -422,7 +422,7 @@ fn handle_help(server: &mut Server, entity: EcsEntity, _args: String, _action: &
for cmd in CHAT_COMMANDS.iter() { for cmd in CHAT_COMMANDS.iter() {
server server
.clients .clients
.notify(entity, ServerMsg::Chat(String::from(cmd.help_string))); .notify(entity, ServerMsg::chat(String::from(cmd.help_string)));
} }
} }
@ -460,7 +460,7 @@ fn handle_killnpcs(server: &mut Server, entity: EcsEntity, _args: String, _actio
} else { } else {
"No NPCs on server.".to_string() "No NPCs on server.".to_string()
}; };
server.clients.notify(entity, ServerMsg::Chat(text)); server.clients.notify(entity, ServerMsg::chat(text));
} }
fn handle_object(server: &mut Server, entity: EcsEntity, args: String, _action: &ChatCommand) { fn handle_object(server: &mut Server, entity: EcsEntity, args: String, _action: &ChatCommand) {
@ -613,29 +613,23 @@ fn handle_tell(server: &mut Server, entity: EcsEntity, args: String, action: &Ch
let msg = &args[alias.len()..args.len()]; let msg = &args[alias.len()..args.len()];
match opt_player { match opt_player {
Some(player) => { Some(player) => {
if player != entity { if msg.len() > 1 {
if msg.len() > 1 { let opt_name = ecs
let opt_name = ecs .read_storage::<comp::Player>()
.read_storage::<comp::Player>() .get(entity)
.get(entity) .map(|s| s.alias.clone());
.map(|s| s.alias.clone()); match opt_name {
match opt_name { Some(name) => {
Some(name) => { server.clients.notify(
server.clients.notify( player,
player, ServerMsg::tell(format!("{} tells you:{}", name, msg)),
ServerMsg::Chat(format!("{} tells you:{}", name, msg)), );
); }
server.clients.notify( None => {
entity, server.clients.notify(
ServerMsg::Chat(format!("You tell {}:{}", alias, msg)), entity,
); ServerMsg::chat(String::from("You do not exist!")),
} );
None => {
server.clients.notify(
entity,
ServerMsg::Chat(String::from("You do not exist!")),
);
}
} }
} else { } else {
server.clients.notify( server.clients.notify(
@ -647,21 +641,25 @@ fn handle_tell(server: &mut Server, entity: EcsEntity, args: String, action: &Ch
); );
} }
} else { } else {
server server.clients.notify(
.clients entity,
.notify(entity, ServerMsg::Chat(format!("Don't be crazy!"))); ServerMsg::chat(format!(
"You really should say something to {}!",
alias
)),
);
} }
} }
None => { None => {
server.clients.notify( server.clients.notify(
entity, entity,
ServerMsg::Chat(format!("Player '{}' not found!", alias)), ServerMsg::chat(format!("Player '{}' not found!", alias)),
); );
} }
} }
} }
None => server None => server
.clients .clients
.notify(entity, ServerMsg::Chat(String::from(action.help_string))), .notify(entity, ServerMsg::chat(String::from(action.help_string))),
} }
} }

View File

@ -526,14 +526,17 @@ impl Server {
} }
ClientState::Pending => {} ClientState::Pending => {}
}, },
ClientMsg::Chat(msg) => match client.client_state { ClientMsg::ChatMsg {
chat_type: _,
msg: message,
} => match client.client_state {
ClientState::Connected => { ClientState::Connected => {
client.error_state(RequestStateError::Impossible) client.error_state(RequestStateError::Impossible)
} }
ClientState::Registered ClientState::Registered
| ClientState::Spectator | ClientState::Spectator
| ClientState::Dead | ClientState::Dead
| ClientState::Character => new_chat_msgs.push((Some(entity), msg)), | ClientState::Character => new_chat_msgs.push((Some(entity), message)),
ClientState::Pending => {} ClientState::Pending => {}
}, },
ClientMsg::PlayerPhysics { pos, vel, ori } => match client.client_state { ClientMsg::PlayerPhysics { pos, vel, ori } => match client.client_state {
@ -622,7 +625,7 @@ impl Server {
let argv = String::from(&msg[1..]); let argv = String::from(&msg[1..]);
self.process_chat_cmd(entity, argv); self.process_chat_cmd(entity, argv);
} else { } else {
self.clients.notify_registered(ServerMsg::Chat( self.clients.notify_registered(ServerMsg::chat(
match self.state.ecs().read_storage::<comp::Player>().get(entity) { match self.state.ecs().read_storage::<comp::Player>().get(entity) {
Some(player) => format!("[{}] {}", &player.alias, msg), Some(player) => format!("[{}] {}", &player.alias, msg),
None => format!("[<anon>] {}", msg), None => format!("[<anon>] {}", msg),
@ -630,7 +633,7 @@ impl Server {
)); ));
} }
} else { } else {
self.clients.notify_registered(ServerMsg::Chat(msg.clone())); self.clients.notify_registered(ServerMsg::chat(msg.clone()));
} }
frontend_events.push(Event::Chat { entity, msg }); frontend_events.push(Event::Chat { entity, msg });
} }
@ -719,7 +722,7 @@ impl Server {
} }
.unwrap_or(format!("{} died", &player.alias)); .unwrap_or(format!("{} died", &player.alias));
clients.notify_registered(ServerMsg::Chat(msg)); clients.notify_registered(ServerMsg::chat(msg));
} }
entity entity
@ -849,7 +852,7 @@ impl Server {
None => { None => {
self.clients.notify( self.clients.notify(
entity, entity,
ServerMsg::Chat(format!( ServerMsg::chat(format!(
"Unrecognised command: '/{}'\ntype '/help' for a list of available commands", "Unrecognised command: '/{}'\ntype '/help' for a list of available commands",
kwd kwd
)), )),

View File

@ -1,4 +1,6 @@
use super::{img_ids::Imgs, Fonts, TEXT_COLOR}; use super::{img_ids::Imgs, Fonts, TELL_COLOR, TEXT_COLOR};
use client::Event as ClientEvent;
use common::ChatType;
use conrod_core::{ use conrod_core::{
input::Key, input::Key,
position::Dimension, position::Dimension,
@ -22,7 +24,7 @@ const MAX_MESSAGES: usize = 100;
#[derive(WidgetCommon)] #[derive(WidgetCommon)]
pub struct Chat<'a> { pub struct Chat<'a> {
new_messages: &'a mut VecDeque<String>, new_messages: &'a mut VecDeque<ClientEvent>,
force_input: Option<String>, force_input: Option<String>,
force_cursor: Option<Index>, force_cursor: Option<Index>,
@ -34,7 +36,11 @@ pub struct Chat<'a> {
} }
impl<'a> Chat<'a> { impl<'a> Chat<'a> {
pub fn new(new_messages: &'a mut VecDeque<String>, imgs: &'a Imgs, fonts: &'a Fonts) -> Self { pub fn new(
new_messages: &'a mut VecDeque<ClientEvent>,
imgs: &'a Imgs,
fonts: &'a Fonts,
) -> Self {
Self { Self {
new_messages, new_messages,
force_input: None, force_input: None,
@ -71,7 +77,7 @@ impl<'a> Chat<'a> {
} }
pub struct State { pub struct State {
messages: VecDeque<String>, messages: VecDeque<ClientEvent>,
input: String, input: String,
ids: Ids, ids: Ids,
@ -179,27 +185,44 @@ impl<'a> Widget for Chat<'a> {
while let Some(item) = items.next(ui) { while let Some(item) = items.next(ui) {
// This would be easier if conrod used the v-metrics from rusttype. // This would be easier if conrod used the v-metrics from rusttype.
let widget = if item.i < state.messages.len() { let widget = if item.i < state.messages.len() {
let text = Text::new(&state.messages[item.i]) let msg = &state.messages[item.i];
.font_size(15) match msg {
.font_id(self.fonts.opensans) ClientEvent::Chat { chat_type, message } => {
.w(470.0) let color = match chat_type {
.color(TEXT_COLOR) ChatType::Tell => TELL_COLOR,
.line_spacing(2.0); _ => TEXT_COLOR,
// Add space between messages. };
let y = match text.get_y_dimension(ui) { let text = Text::new(&message)
Dimension::Absolute(y) => y + 2.0, .font_size(15)
_ => 0.0, .font_id(self.fonts.opensans)
}; .w(470.0)
text.h(y) .color(color)
.line_spacing(2.0);
// Add space between messages.
let y = match text.get_y_dimension(ui) {
Dimension::Absolute(y) => y + 2.0,
_ => 0.0,
};
Some(text.h(y))
}
_ => None,
}
} else { } else {
// Spacer at bottom of the last message so that it is not cut off. // Spacer at bottom of the last message so that it is not cut off.
// Needs to be larger than the space above. // Needs to be larger than the space above.
Text::new("") Some(
.font_size(6) Text::new("")
.font_id(self.fonts.opensans) .font_size(6)
.w(470.0) .font_id(self.fonts.opensans)
.w(470.0),
)
}; };
item.set(widget, ui); match widget {
Some(widget) => {
item.set(widget, ui);
}
None => {}
}
} }
// Chat Arrow // Chat Arrow

View File

@ -31,7 +31,7 @@ use crate::{
window::{Event as WinEvent, GameInput, Window}, window::{Event as WinEvent, GameInput, Window},
GlobalState, GlobalState,
}; };
use client::Client; use client::{Client, Event as ClientEvent};
use common::{comp, terrain::TerrainChunkSize, vol::VolSize}; use common::{comp, terrain::TerrainChunkSize, vol::VolSize};
use conrod_core::{ use conrod_core::{
text::cursor::Index, text::cursor::Index,
@ -50,6 +50,7 @@ const TEXT_COLOR: Color = Color::Rgba(1.0, 1.0, 1.0, 1.0);
const TEXT_COLOR_2: Color = Color::Rgba(0.0, 0.0, 0.0, 1.0); const TEXT_COLOR_2: Color = Color::Rgba(0.0, 0.0, 0.0, 1.0);
const HP_COLOR: Color = Color::Rgba(0.33, 0.63, 0.0, 1.0); const HP_COLOR: Color = Color::Rgba(0.33, 0.63, 0.0, 1.0);
const MANA_COLOR: Color = Color::Rgba(0.42, 0.41, 0.66, 1.0); const MANA_COLOR: Color = Color::Rgba(0.42, 0.41, 0.66, 1.0);
const TELL_COLOR: Color = Color::Rgba(1.0, 1.0, 0.0, 1.0);
widget_ids! { widget_ids! {
struct Ids { struct Ids {
@ -269,7 +270,7 @@ pub struct Hud {
ids: Ids, ids: Ids,
imgs: Imgs, imgs: Imgs,
fonts: Fonts, fonts: Fonts,
new_messages: VecDeque<String>, new_messages: VecDeque<ClientEvent>,
inventory_space: usize, inventory_space: usize,
show: Show, show: Show,
to_focus: Option<Option<widget::Id>>, to_focus: Option<Option<widget::Id>>,
@ -743,7 +744,7 @@ impl Hud {
events events
} }
pub fn new_message(&mut self, msg: String) { pub fn new_message(&mut self, msg: ClientEvent) {
self.new_messages.push_back(msg); self.new_messages.push_back(msg);
} }

View File

@ -44,8 +44,11 @@ impl SessionState {
fn tick(&mut self, dt: Duration) -> Result<(), Error> { fn tick(&mut self, dt: Duration) -> Result<(), Error> {
for event in self.client.borrow_mut().tick(self.controller.clone(), dt)? { for event in self.client.borrow_mut().tick(self.controller.clone(), dt)? {
match event { match event {
client::Event::Chat(msg) => { client::Event::Chat {
self.hud.new_message(msg); chat_type: _,
message: _,
} => {
self.hud.new_message(event);
} }
client::Event::Disconnect => {} // TODO client::Event::Disconnect => {} // TODO
} }