mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Re-implement names in chat. It is done client-side now and /alias changes are retroactive.
This commit is contained in:
parent
b08d717eac
commit
0b2a3ebe8b
@ -66,7 +66,7 @@ pub struct Client {
|
||||
thread_pool: ThreadPool,
|
||||
pub server_info: ServerInfo,
|
||||
pub world_map: (Arc<DynamicImage>, Vec2<u32>),
|
||||
pub player_list: HashMap<u64, PlayerInfo>,
|
||||
pub player_list: HashMap<Uid, PlayerInfo>,
|
||||
pub character_list: CharacterList,
|
||||
pub active_character_id: Option<i32>,
|
||||
|
||||
@ -759,6 +759,16 @@ impl Client {
|
||||
);
|
||||
}
|
||||
},
|
||||
ServerMsg::PlayerListUpdate(PlayerListUpdate::Admin(uid, admin)) => {
|
||||
if let Some(player_info) = self.player_list.get_mut(&uid) {
|
||||
player_info.is_admin = admin;
|
||||
} else {
|
||||
warn!(
|
||||
"Received msg to update admin status of uid {}, but they were not in the list.",
|
||||
uid
|
||||
);
|
||||
}
|
||||
},
|
||||
ServerMsg::PlayerListUpdate(PlayerListUpdate::SelectedCharacter(
|
||||
uid,
|
||||
char_info,
|
||||
@ -822,7 +832,7 @@ impl Client {
|
||||
},
|
||||
ServerMsg::ChatMsg(m) => frontend_events.push(Event::Chat(m)),
|
||||
ServerMsg::SetPlayerEntity(uid) => {
|
||||
if let Some(entity) = self.state.ecs().entity_from_uid(uid) {
|
||||
if let Some(entity) = self.state.ecs().entity_from_uid(uid.0) {
|
||||
self.entity = entity;
|
||||
} else {
|
||||
return Err(Error::Other("Failed to find entity from uid.".to_owned()));
|
||||
@ -853,7 +863,7 @@ impl Client {
|
||||
{
|
||||
self.state
|
||||
.ecs_mut()
|
||||
.delete_entity_and_clear_from_uid_allocator(entity);
|
||||
.delete_entity_and_clear_from_uid_allocator(entity.0);
|
||||
}
|
||||
},
|
||||
// Cleanup for when the client goes back to the `Registered` state
|
||||
|
@ -2,6 +2,7 @@ use super::{ClientState, EcsCompPacket};
|
||||
use crate::{
|
||||
character::CharacterItem,
|
||||
comp, state, sync,
|
||||
sync::Uid,
|
||||
terrain::{Block, TerrainChunk},
|
||||
};
|
||||
use authc::AuthClientError;
|
||||
@ -17,18 +18,21 @@ pub struct ServerInfo {
|
||||
pub auth_provider: Option<String>,
|
||||
}
|
||||
|
||||
/// Inform the client of updates to the player list.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum PlayerListUpdate {
|
||||
Init(HashMap<u64, PlayerInfo>),
|
||||
Add(u64, PlayerInfo),
|
||||
SelectedCharacter(u64, CharacterInfo),
|
||||
LevelChange(u64, u32),
|
||||
Remove(u64),
|
||||
Alias(u64, String),
|
||||
Init(HashMap<Uid, PlayerInfo>),
|
||||
Add(Uid, PlayerInfo),
|
||||
SelectedCharacter(Uid, CharacterInfo),
|
||||
LevelChange(Uid, u32),
|
||||
Admin(Uid, bool),
|
||||
Remove(Uid),
|
||||
Alias(Uid, String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct PlayerInfo {
|
||||
pub is_admin: bool,
|
||||
pub player_alias: String,
|
||||
pub character: Option<CharacterInfo>,
|
||||
}
|
||||
@ -69,12 +73,12 @@ pub enum ServerMsg {
|
||||
/// A message to go into the client chat box. The client is responsible for
|
||||
/// formatting the message.
|
||||
ChatMsg(comp::ChatMsg),
|
||||
SetPlayerEntity(u64),
|
||||
SetPlayerEntity(Uid),
|
||||
TimeOfDay(state::TimeOfDay),
|
||||
EntitySync(sync::EntitySyncPackage),
|
||||
CompSync(sync::CompSyncPackage<EcsCompPacket>),
|
||||
CreateEntity(sync::EntityPackage<EcsCompPacket>),
|
||||
DeleteEntity(u64),
|
||||
DeleteEntity(Uid),
|
||||
InventoryUpdate(comp::Inventory, comp::InventoryUpdateEvent),
|
||||
TerrainChunkUpdate {
|
||||
key: Vec2<i32>,
|
||||
@ -112,7 +116,8 @@ impl From<AuthClientError> for RegisterError {
|
||||
}
|
||||
|
||||
impl ServerMsg {
|
||||
/// Sends either say, world, group, etc. based on the player's current chat mode.
|
||||
/// Sends either say, world, group, etc. based on the player's current chat
|
||||
/// mode.
|
||||
pub fn chat(mode: comp::ChatMode, uid: sync::Uid, message: String) -> ServerMsg {
|
||||
ServerMsg::ChatMsg(mode.msg_from(uid, message))
|
||||
}
|
||||
|
@ -388,7 +388,20 @@ fn handle_alias(
|
||||
args: String,
|
||||
action: &ChatCommand,
|
||||
) {
|
||||
if client != target {
|
||||
// Prevent people abusing /sudo
|
||||
server.notify_client(
|
||||
client,
|
||||
ServerMsg::private(String::from("Don't call people names. It's mean.")),
|
||||
);
|
||||
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.")));
|
||||
return;
|
||||
}
|
||||
let old_alias_optional = server
|
||||
.state
|
||||
.ecs_mut()
|
||||
@ -932,26 +945,30 @@ fn handle_adminify(
|
||||
let ecs = server.state.ecs();
|
||||
let opt_player = (&ecs.entities(), &ecs.read_storage::<comp::Player>())
|
||||
.join()
|
||||
.find(|(_, player)| player.alias == alias)
|
||||
.find(|(_, player)| alias == player.alias)
|
||||
.map(|(entity, _)| entity);
|
||||
match opt_player {
|
||||
Some(player) => match server.state.read_component_cloned::<comp::Admin>(player) {
|
||||
Some(_admin) => {
|
||||
Some(player) => {
|
||||
let is_admin = if server.state.read_component_cloned::<comp::Admin>(player).is_some() {
|
||||
ecs.write_storage::<comp::Admin>().remove(player);
|
||||
},
|
||||
None => {
|
||||
server.state.write_component(player, comp::Admin);
|
||||
},
|
||||
false
|
||||
} else {
|
||||
ecs.write_storage().insert(player, comp::Admin).is_ok()
|
||||
};
|
||||
// Update player list so the player shows up as admin in client chat.
|
||||
let msg = ServerMsg::PlayerListUpdate(PlayerListUpdate::Admin(
|
||||
*ecs.read_storage::<Uid>()
|
||||
.get(player)
|
||||
.expect("Player should have uid"),
|
||||
is_admin,
|
||||
));
|
||||
server.state.notify_registered_clients(msg);
|
||||
},
|
||||
None => {
|
||||
server.notify_client(
|
||||
client,
|
||||
ServerMsg::private(format!("Player '{}' not found!", alias)),
|
||||
);
|
||||
server.notify_client(
|
||||
client,
|
||||
ServerMsg::private(String::from(action.help_string())),
|
||||
);
|
||||
},
|
||||
}
|
||||
} else {
|
||||
@ -1319,13 +1336,12 @@ fn handle_set_level(
|
||||
|
||||
match target {
|
||||
Ok(player) => {
|
||||
let uid = server
|
||||
let uid = *server
|
||||
.state
|
||||
.ecs()
|
||||
.read_storage::<Uid>()
|
||||
.get(player)
|
||||
.expect("Failed to get uid for player")
|
||||
.0;
|
||||
.expect("Failed to get uid for player");
|
||||
server
|
||||
.state
|
||||
.notify_registered_clients(ServerMsg::PlayerListUpdate(
|
||||
|
@ -471,12 +471,11 @@ pub fn handle_level_up(server: &mut Server, entity: EcsEntity, new_level: u32) {
|
||||
let uids = server.state.ecs().read_storage::<Uid>();
|
||||
let uid = uids
|
||||
.get(entity)
|
||||
.expect("Failed to fetch uid component for entity.")
|
||||
.0;
|
||||
.expect("Failed to fetch uid component for entity.");
|
||||
|
||||
server
|
||||
.state
|
||||
.notify_registered_clients(ServerMsg::PlayerListUpdate(PlayerListUpdate::LevelChange(
|
||||
uid, new_level,
|
||||
*uid, new_level,
|
||||
)));
|
||||
}
|
||||
|
@ -301,7 +301,7 @@ impl<'a> System<'a> for Sys {
|
||||
})
|
||||
{
|
||||
for uid in &deleted {
|
||||
client.notify(ServerMsg::DeleteEntity(*uid));
|
||||
client.notify(ServerMsg::DeleteEntity(Uid(*uid)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,8 @@ use crate::{
|
||||
};
|
||||
use common::{
|
||||
comp::{
|
||||
CanBuild, ChatMode, ControlEvent, Controller, ForceUpdate, Ori, Player, Pos, Stats, Vel,
|
||||
Admin, CanBuild, ChatMode, ControlEvent, Controller, ForceUpdate, Ori, Player, Pos, Stats,
|
||||
Vel,
|
||||
},
|
||||
event::{EventBus, ServerEvent},
|
||||
msg::{
|
||||
@ -33,6 +34,7 @@ impl<'a> System<'a> for Sys {
|
||||
ReadExpect<'a, CharacterLoader>,
|
||||
ReadExpect<'a, TerrainGrid>,
|
||||
Write<'a, SysTimer<Self>>,
|
||||
ReadStorage<'a, Admin>,
|
||||
ReadStorage<'a, Uid>,
|
||||
ReadStorage<'a, CanBuild>,
|
||||
ReadStorage<'a, ForceUpdate>,
|
||||
@ -62,6 +64,7 @@ impl<'a> System<'a> for Sys {
|
||||
character_loader,
|
||||
terrain,
|
||||
mut timer,
|
||||
admins,
|
||||
uids,
|
||||
can_build,
|
||||
force_updates,
|
||||
@ -86,13 +89,13 @@ impl<'a> System<'a> for Sys {
|
||||
let mut new_chat_msgs = Vec::new();
|
||||
|
||||
// Player list to send new players.
|
||||
let player_list = (&uids, &players, &stats)
|
||||
let player_list = (&uids, &players, stats.maybe(), admins.maybe())
|
||||
.join()
|
||||
.map(|(uid, player, stats)| {
|
||||
.map(|(uid, player, stats, admin)| {
|
||||
((*uid).into(), PlayerInfo {
|
||||
is_admin: admin.is_some(),
|
||||
player_alias: player.alias.clone(),
|
||||
// TODO: player might not have a character selected
|
||||
character: Some(CharacterInfo {
|
||||
character: stats.map(|stats| CharacterInfo {
|
||||
name: stats.name.clone(),
|
||||
level: stats.level.level(),
|
||||
}),
|
||||
@ -441,6 +444,7 @@ impl<'a> System<'a> for Sys {
|
||||
let msg =
|
||||
ServerMsg::PlayerListUpdate(PlayerListUpdate::Add((*uid).into(), PlayerInfo {
|
||||
player_alias: player.alias.clone(),
|
||||
is_admin: admins.get(entity).is_some(),
|
||||
character: None, // new players will be on character select.
|
||||
}));
|
||||
for client in (&mut clients).join().filter(|c| c.is_registered()) {
|
||||
|
@ -169,7 +169,7 @@ impl<'a> System<'a> for Sys {
|
||||
.iter()
|
||||
.flat_map(|v| v.iter())
|
||||
{
|
||||
client.notify(ServerMsg::DeleteEntity(*uid));
|
||||
client.notify(ServerMsg::DeleteEntity(Uid(*uid)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@ use conrod_core::{
|
||||
widget::{self, Button, Id, List, Rectangle, Text, TextEdit},
|
||||
widget_ids, Colorable, Positionable, Sizeable, Ui, UiCell, Widget, WidgetCommon,
|
||||
};
|
||||
use specs::world::WorldExt;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
widget_ids! {
|
||||
@ -36,6 +37,7 @@ const MAX_MESSAGES: usize = 100;
|
||||
#[derive(WidgetCommon)]
|
||||
pub struct Chat<'a> {
|
||||
new_messages: &'a mut VecDeque<ChatMsg>,
|
||||
client: &'a Client,
|
||||
force_input: Option<String>,
|
||||
force_cursor: Option<Index>,
|
||||
force_completions: Option<Vec<String>>,
|
||||
@ -54,12 +56,14 @@ pub struct Chat<'a> {
|
||||
impl<'a> Chat<'a> {
|
||||
pub fn new(
|
||||
new_messages: &'a mut VecDeque<ChatMsg>,
|
||||
client: &'a Client,
|
||||
global_state: &'a GlobalState,
|
||||
imgs: &'a Imgs,
|
||||
fonts: &'a ConrodVoxygenFonts,
|
||||
) -> Self {
|
||||
Self {
|
||||
new_messages,
|
||||
client,
|
||||
force_input: None,
|
||||
force_cursor: None,
|
||||
force_completions: None,
|
||||
@ -71,9 +75,9 @@ impl<'a> Chat<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prepare_tab_completion(mut self, input: String, client: &Client) -> Self {
|
||||
pub fn prepare_tab_completion(mut self, input: String) -> Self {
|
||||
if let Some(index) = input.find('\t') {
|
||||
self.force_completions = Some(cmd::complete(&input[..index], &client));
|
||||
self.force_completions = Some(cmd::complete(&input[..index], &self.client));
|
||||
} else {
|
||||
self.force_completions = None;
|
||||
}
|
||||
@ -305,6 +309,19 @@ impl<'a> Widget for Chat<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
let alias_of_uid = |uid| {
|
||||
self.client
|
||||
.player_list
|
||||
.get(uid)
|
||||
.map_or("<?>".to_string(), |player_info| {
|
||||
if player_info.is_admin {
|
||||
format!("ADMIN - {}", player_info.player_alias)
|
||||
} else {
|
||||
player_info.player_alias.to_string()
|
||||
}
|
||||
})
|
||||
};
|
||||
let message_format = |uid, message| format!("[{}]: {}", alias_of_uid(uid), message);
|
||||
// Message box
|
||||
Rectangle::fill([470.0, 174.0])
|
||||
.rgba(0.0, 0.0, 0.0, transp)
|
||||
@ -323,20 +340,35 @@ impl<'a> Widget for Chat<'a> {
|
||||
.set(state.ids.message_box, ui);
|
||||
while let Some(item) = items.next(ui) {
|
||||
// This would be easier if conrod used the v-metrics from rusttype.
|
||||
let widget = if item.i < state.messages.len() {
|
||||
let msg = &state.messages[item.i];
|
||||
let color = match msg.chat_type {
|
||||
ChatType::Tell(_, _) => TELL_COLOR,
|
||||
ChatType::Private => PRIVATE_COLOR,
|
||||
ChatType::Broadcast => BROADCAST_COLOR,
|
||||
ChatType::Say(_) => SAY_COLOR,
|
||||
ChatType::Group(_) => GROUP_COLOR,
|
||||
ChatType::Faction(_) => FACTION_COLOR,
|
||||
ChatType::Region(_) => REGION_COLOR,
|
||||
ChatType::Kill => KILL_COLOR,
|
||||
ChatType::World(_) => WORLD_COLOR,
|
||||
if item.i < state.messages.len() {
|
||||
let ChatMsg { chat_type, message } = &state.messages[item.i];
|
||||
let (color, msg) = match chat_type {
|
||||
ChatType::Private => (PRIVATE_COLOR, message.to_string()),
|
||||
ChatType::Broadcast => (BROADCAST_COLOR, message.to_string()),
|
||||
ChatType::Kill => (KILL_COLOR, message.to_string()),
|
||||
ChatType::Tell(from, to) => {
|
||||
let from_alias = alias_of_uid(&from);
|
||||
let to_alias = alias_of_uid(&to);
|
||||
if Some(from)
|
||||
== self
|
||||
.client
|
||||
.state()
|
||||
.ecs()
|
||||
.read_storage()
|
||||
.get(self.client.entity())
|
||||
{
|
||||
(TELL_COLOR, format!("To [{}]: {}", to_alias, message))
|
||||
} else {
|
||||
(TELL_COLOR, format!("From [{}]: {}", from_alias, message))
|
||||
}
|
||||
},
|
||||
ChatType::Say(uid) => (SAY_COLOR, message_format(uid, message)),
|
||||
ChatType::Group(uid) => (GROUP_COLOR, message_format(uid, message)),
|
||||
ChatType::Faction(uid) => (FACTION_COLOR, message_format(uid, message)),
|
||||
ChatType::Region(uid) => (REGION_COLOR, message_format(uid, message)),
|
||||
ChatType::World(uid) => (WORLD_COLOR, message_format(uid, message)),
|
||||
};
|
||||
let text = Text::new(&msg.message)
|
||||
let text = Text::new(&msg)
|
||||
.font_size(self.fonts.opensans.scale(15))
|
||||
.font_id(self.fonts.opensans.conrod_id)
|
||||
.w(470.0)
|
||||
@ -347,23 +379,17 @@ impl<'a> Widget for Chat<'a> {
|
||||
Dimension::Absolute(y) => y + 2.0,
|
||||
_ => 0.0,
|
||||
};
|
||||
Some(text.h(y))
|
||||
let widget = text.h(y);
|
||||
item.set(widget, ui);
|
||||
} else {
|
||||
// Spacer at bottom of the last message so that it is not cut off.
|
||||
// Needs to be larger than the space above.
|
||||
Some(
|
||||
Text::new("")
|
||||
.font_size(self.fonts.opensans.scale(6))
|
||||
.font_id(self.fonts.opensans.conrod_id)
|
||||
.w(470.0),
|
||||
)
|
||||
let widget = Text::new("")
|
||||
.font_size(self.fonts.opensans.scale(6))
|
||||
.font_id(self.fonts.opensans.conrod_id)
|
||||
.w(470.0);
|
||||
item.set(widget, ui);
|
||||
};
|
||||
match widget {
|
||||
Some(widget) => {
|
||||
item.set(widget, ui);
|
||||
},
|
||||
None => {},
|
||||
}
|
||||
}
|
||||
|
||||
// Chat Arrow
|
||||
|
@ -81,7 +81,7 @@ 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(0.9, 0.2, 0.2, 1.0);
|
||||
const SAY_COLOR: Color = Color::Rgba(1.0, 0.8, 0.8, 1.0);
|
||||
/// Color for group chat
|
||||
const GROUP_COLOR: Color = Color::Rgba(0.47, 0.84, 1.0, 1.0);
|
||||
/// Color for factional chat
|
||||
@ -1554,13 +1554,14 @@ impl Hud {
|
||||
// Chat box
|
||||
match Chat::new(
|
||||
&mut self.new_messages,
|
||||
&client,
|
||||
global_state,
|
||||
&self.imgs,
|
||||
&self.fonts,
|
||||
)
|
||||
.and_then(self.force_chat_input.take(), |c, input| c.input(input))
|
||||
.and_then(self.tab_complete.take(), |c, input| {
|
||||
c.prepare_tab_completion(input, &client)
|
||||
c.prepare_tab_completion(input)
|
||||
})
|
||||
.and_then(self.force_chat_cursor.take(), |c, pos| c.cursor_pos(pos))
|
||||
.set(self.ids.chat, ui_widgets)
|
||||
|
Loading…
Reference in New Issue
Block a user