mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'scott-c/improve-chat-aliases' into 'master'
fix #562 Confusing chat alias Closes #562 See merge request veloren/veloren!1006
This commit is contained in:
commit
43dc2322bf
@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Speech bubbles appear when nearby players talk
|
||||
- NPCs call for help when attacked
|
||||
- Eyebrows and shapes can now be selected
|
||||
- Character name and level information to chat, social tab and `/players` command.
|
||||
|
||||
### Changed
|
||||
|
||||
|
@ -40,6 +40,7 @@ fn complete_player(part: &str, client: &Client) -> Vec<String> {
|
||||
client
|
||||
.player_list
|
||||
.values()
|
||||
.map(|player_info| &player_info.player_alias)
|
||||
.filter(|alias| alias.starts_with(part))
|
||||
.cloned()
|
||||
.collect()
|
||||
|
@ -23,7 +23,7 @@ use common::{
|
||||
event::{EventBus, SfxEvent, SfxEventItem},
|
||||
msg::{
|
||||
validate_chat_msg, ChatMsgValidationError, ClientMsg, ClientState, Notification,
|
||||
PlayerListUpdate, RegisterError, RequestStateError, ServerInfo, ServerMsg,
|
||||
PlayerInfo, PlayerListUpdate, RegisterError, RequestStateError, ServerInfo, ServerMsg,
|
||||
MAX_BYTES_CHAT_MSG,
|
||||
},
|
||||
net::PostBox,
|
||||
@ -68,7 +68,7 @@ pub struct Client {
|
||||
thread_pool: ThreadPool,
|
||||
pub server_info: ServerInfo,
|
||||
pub world_map: (Arc<DynamicImage>, Vec2<u32>),
|
||||
pub player_list: HashMap<u64, String>,
|
||||
pub player_list: HashMap<u64, PlayerInfo>,
|
||||
pub character_list: CharacterList,
|
||||
|
||||
postbox: PostBox<ClientMsg, ServerMsg>,
|
||||
@ -734,16 +734,51 @@ impl Client {
|
||||
ServerMsg::PlayerListUpdate(PlayerListUpdate::Init(list)) => {
|
||||
self.player_list = list
|
||||
},
|
||||
ServerMsg::PlayerListUpdate(PlayerListUpdate::Add(uid, name)) => {
|
||||
if let Some(old_name) = self.player_list.insert(uid, name.clone()) {
|
||||
ServerMsg::PlayerListUpdate(PlayerListUpdate::Add(uid, player_info)) => {
|
||||
if let Some(old_player_info) =
|
||||
self.player_list.insert(uid, player_info.clone())
|
||||
{
|
||||
warn!(
|
||||
"Received msg to insert {} with uid {} into the player list but \
|
||||
there was already an entry for {} with the same uid that was \
|
||||
overwritten!",
|
||||
name, uid, old_name
|
||||
player_info.player_alias, uid, old_player_info.player_alias
|
||||
);
|
||||
}
|
||||
},
|
||||
ServerMsg::PlayerListUpdate(PlayerListUpdate::SelectedCharacter(
|
||||
uid,
|
||||
char_info,
|
||||
)) => {
|
||||
if let Some(player_info) = self.player_list.get_mut(&uid) {
|
||||
player_info.character = Some(char_info);
|
||||
} else {
|
||||
warn!(
|
||||
"Received msg to update character info for uid {}, but they were \
|
||||
not in the list.",
|
||||
uid
|
||||
);
|
||||
}
|
||||
},
|
||||
ServerMsg::PlayerListUpdate(PlayerListUpdate::LevelChange(uid, next_level)) => {
|
||||
if let Some(player_info) = self.player_list.get_mut(&uid) {
|
||||
player_info.character = match &player_info.character {
|
||||
Some(character) => Some(common::msg::CharacterInfo {
|
||||
name: character.name.to_string(),
|
||||
level: next_level,
|
||||
}),
|
||||
None => {
|
||||
warn!(
|
||||
"Received msg to update character level info to {} for \
|
||||
uid {}, but this player's character is None.",
|
||||
next_level, uid
|
||||
);
|
||||
|
||||
None
|
||||
},
|
||||
};
|
||||
}
|
||||
},
|
||||
ServerMsg::PlayerListUpdate(PlayerListUpdate::Remove(uid)) => {
|
||||
if self.player_list.remove(&uid).is_none() {
|
||||
warn!(
|
||||
@ -754,8 +789,8 @@ impl Client {
|
||||
}
|
||||
},
|
||||
ServerMsg::PlayerListUpdate(PlayerListUpdate::Alias(uid, new_name)) => {
|
||||
if let Some(name) = self.player_list.get_mut(&uid) {
|
||||
*name = new_name;
|
||||
if let Some(player_info) = self.player_list.get_mut(&uid) {
|
||||
player_info.player_alias = new_name;
|
||||
} else {
|
||||
warn!(
|
||||
"Received msg to alias player with uid {} to {} but this uid is \
|
||||
|
@ -90,6 +90,7 @@ pub enum ServerEvent {
|
||||
Mount(EcsEntity, EcsEntity),
|
||||
Unmount(EcsEntity),
|
||||
Possess(Uid, Uid),
|
||||
LevelUp(EcsEntity, u32),
|
||||
SelectCharacter {
|
||||
entity: EcsEntity,
|
||||
character_id: i32,
|
||||
|
@ -7,7 +7,8 @@ pub use self::{
|
||||
client::ClientMsg,
|
||||
ecs_packet::EcsCompPacket,
|
||||
server::{
|
||||
Notification, PlayerListUpdate, RegisterError, RequestStateError, ServerInfo, ServerMsg,
|
||||
CharacterInfo, Notification, PlayerInfo, PlayerListUpdate, RegisterError,
|
||||
RequestStateError, ServerInfo, ServerMsg,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -20,12 +20,26 @@ pub struct ServerInfo {
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum PlayerListUpdate {
|
||||
Init(HashMap<u64, String>),
|
||||
Add(u64, String),
|
||||
Init(HashMap<u64, PlayerInfo>),
|
||||
Add(u64, PlayerInfo),
|
||||
SelectedCharacter(u64, CharacterInfo),
|
||||
LevelChange(u64, u32),
|
||||
Remove(u64),
|
||||
Alias(u64, String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct PlayerInfo {
|
||||
pub player_alias: String,
|
||||
pub character: Option<CharacterInfo>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct CharacterInfo {
|
||||
pub name: String,
|
||||
pub level: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum Notification {
|
||||
WaypointSaved,
|
||||
|
@ -66,6 +66,7 @@ impl<'a> System<'a> for Sys {
|
||||
stat.exp.change_by(-(stat.exp.maximum() as i64));
|
||||
stat.level.change_by(1);
|
||||
stat.exp.update_maximum(stat.level.level());
|
||||
server_event_emitter.emit(ServerEvent::LevelUp(entity, stat.level.level()));
|
||||
}
|
||||
|
||||
stat.update_max_hp();
|
||||
|
@ -514,26 +514,28 @@ fn handle_players(
|
||||
_action: &ChatCommand,
|
||||
) {
|
||||
let ecs = server.state.ecs();
|
||||
let players = ecs.read_storage::<comp::Player>();
|
||||
let count = players.join().count();
|
||||
let header_message: String = format!("{} online players: \n", count);
|
||||
if count > 0 {
|
||||
let mut player_iter = players.join();
|
||||
let first = player_iter
|
||||
.next()
|
||||
.expect("Player iterator returned none.")
|
||||
.alias
|
||||
.to_owned();
|
||||
let player_list = player_iter.fold(first, |mut s, p| {
|
||||
s += ",\n";
|
||||
s += &p.alias;
|
||||
s
|
||||
});
|
||||
|
||||
server.notify_client(client, ServerMsg::private(header_message + &player_list));
|
||||
} else {
|
||||
server.notify_client(client, ServerMsg::private(header_message));
|
||||
}
|
||||
let entity_tuples = (
|
||||
&ecs.entities(),
|
||||
&ecs.read_storage::<comp::Player>(),
|
||||
&ecs.read_storage::<comp::Stats>(),
|
||||
);
|
||||
|
||||
server.notify_client(
|
||||
client,
|
||||
ServerMsg::private(entity_tuples.join().fold(
|
||||
format!("{} online players:", entity_tuples.join().count()),
|
||||
|s, (_, player, stat)| {
|
||||
format!(
|
||||
"{}\n[{}]{} Lvl {}",
|
||||
s,
|
||||
player.alias,
|
||||
stat.name,
|
||||
stat.level.level()
|
||||
)
|
||||
},
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
||||
fn handle_build(
|
||||
@ -1125,14 +1127,31 @@ fn handle_set_level(
|
||||
let (a_lvl, a_alias) = scan_fmt_some!(&args, &action.arg_fmt(), u32, String);
|
||||
|
||||
if let Some(lvl) = a_lvl {
|
||||
let ecs = server.state.ecs_mut();
|
||||
let target = find_target(&ecs, a_alias, target);
|
||||
let target = find_target(&server.state.ecs(), a_alias, target);
|
||||
|
||||
let mut error_msg = None;
|
||||
|
||||
match target {
|
||||
Ok(player) => {
|
||||
if let Some(stats) = ecs.write_storage::<comp::Stats>().get_mut(player) {
|
||||
let uid = server
|
||||
.state
|
||||
.ecs()
|
||||
.read_storage::<Uid>()
|
||||
.get(player)
|
||||
.expect("Failed to get uid for player")
|
||||
.0;
|
||||
server
|
||||
.state
|
||||
.notify_registered_clients(ServerMsg::PlayerListUpdate(
|
||||
PlayerListUpdate::LevelChange(uid, lvl),
|
||||
));
|
||||
|
||||
if let Some(stats) = server
|
||||
.state
|
||||
.ecs_mut()
|
||||
.write_storage::<comp::Stats>()
|
||||
.get_mut(player)
|
||||
{
|
||||
stats.level.set_level(lvl);
|
||||
|
||||
stats.update_max_hp();
|
||||
|
@ -2,7 +2,7 @@ use crate::{client::Client, Server, SpawnPoint, StateExt};
|
||||
use common::{
|
||||
assets,
|
||||
comp::{self, object, Body, HealthChange, HealthSource, Item, Player, Stats},
|
||||
msg::ServerMsg,
|
||||
msg::{PlayerListUpdate, ServerMsg},
|
||||
state::BlockChange,
|
||||
sync::{Uid, WorldSyncExt},
|
||||
sys::combat::{BLOCK_ANGLE, BLOCK_EFFICIENCY},
|
||||
@ -295,3 +295,17 @@ pub fn handle_explosion(server: &Server, pos: Vec3<f32>, power: f32, owner: Opti
|
||||
.cast();
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
server
|
||||
.state
|
||||
.notify_registered_clients(ServerMsg::PlayerListUpdate(PlayerListUpdate::LevelChange(
|
||||
uid, new_level,
|
||||
)));
|
||||
}
|
||||
|
@ -4,7 +4,8 @@ use entity_creation::{
|
||||
handle_create_character, handle_create_npc, handle_create_waypoint, handle_shoot,
|
||||
};
|
||||
use entity_manipulation::{
|
||||
handle_damage, handle_destroy, handle_explosion, handle_land_on_ground, handle_respawn,
|
||||
handle_damage, handle_destroy, handle_explosion, handle_land_on_ground, handle_level_up,
|
||||
handle_respawn,
|
||||
};
|
||||
use interaction::{handle_lantern, handle_mount, handle_possess, handle_unmount};
|
||||
use inventory_manip::handle_inventory;
|
||||
@ -75,6 +76,7 @@ impl Server {
|
||||
body,
|
||||
main,
|
||||
} => handle_create_character(self, entity, character_id, body, main),
|
||||
ServerEvent::LevelUp(entity, new_level) => handle_level_up(self, entity, new_level),
|
||||
ServerEvent::ExitIngame { entity } => handle_exit_ingame(self, entity),
|
||||
ServerEvent::CreateNpc {
|
||||
pos,
|
||||
|
@ -6,7 +6,9 @@ use common::{
|
||||
assets,
|
||||
comp::{self, item},
|
||||
effect::Effect,
|
||||
msg::{ClientState, RegisterError, RequestStateError, ServerMsg},
|
||||
msg::{
|
||||
CharacterInfo, ClientState, PlayerListUpdate, RegisterError, RequestStateError, ServerMsg,
|
||||
},
|
||||
state::State,
|
||||
sync::{Uid, WorldSyncExt},
|
||||
util::Dir,
|
||||
@ -279,6 +281,24 @@ impl StateExt for State {
|
||||
self.write_component(entity, comp::Admin);
|
||||
}
|
||||
|
||||
let uids = &self.ecs().read_storage::<Uid>();
|
||||
let uid = uids
|
||||
.get(entity)
|
||||
.expect("Failed to fetch uid component for entity.")
|
||||
.0;
|
||||
|
||||
let stats = &self.ecs().read_storage::<comp::Stats>();
|
||||
let stat = stats
|
||||
.get(entity)
|
||||
.expect("Failed to fetch stats component for entity.");
|
||||
|
||||
self.notify_registered_clients(ServerMsg::PlayerListUpdate(
|
||||
PlayerListUpdate::SelectedCharacter(uid, CharacterInfo {
|
||||
name: stat.name.to_string(),
|
||||
level: stat.level.level(),
|
||||
}),
|
||||
));
|
||||
|
||||
// Tell the client its request was successful.
|
||||
if let Some(client) = self.ecs().write_storage::<Client>().get_mut(entity) {
|
||||
client.allow_state(ClientState::Character);
|
||||
|
@ -10,8 +10,8 @@ use common::{
|
||||
},
|
||||
event::{EventBus, ServerEvent},
|
||||
msg::{
|
||||
validate_chat_msg, ChatMsgValidationError, ClientMsg, ClientState, PlayerListUpdate,
|
||||
RequestStateError, ServerMsg, MAX_BYTES_CHAT_MSG,
|
||||
validate_chat_msg, CharacterInfo, ChatMsgValidationError, ClientMsg, ClientState,
|
||||
PlayerInfo, PlayerListUpdate, RequestStateError, ServerMsg, MAX_BYTES_CHAT_MSG,
|
||||
},
|
||||
state::{BlockChange, Time},
|
||||
sync::Uid,
|
||||
@ -83,9 +83,18 @@ impl<'a> System<'a> for Sys {
|
||||
let mut new_chat_msgs = Vec::new();
|
||||
|
||||
// Player list to send new players.
|
||||
let player_list = (&uids, &players)
|
||||
let player_list = (&uids, &players, &stats)
|
||||
.join()
|
||||
.map(|(uid, player)| ((*uid).into(), player.alias.clone()))
|
||||
.map(|(uid, player, stats)| {
|
||||
((*uid).into(), PlayerInfo {
|
||||
player_alias: player.alias.clone(),
|
||||
// TODO: player might not have a character selected
|
||||
character: Some(CharacterInfo {
|
||||
name: stats.name.clone(),
|
||||
level: stats.level.level(),
|
||||
}),
|
||||
})
|
||||
})
|
||||
.collect::<HashMap<_, _>>();
|
||||
// List of new players to update player lists of all clients.
|
||||
let mut new_players = Vec::new();
|
||||
@ -383,10 +392,11 @@ impl<'a> System<'a> for Sys {
|
||||
// Tell all clients to add them to the player list.
|
||||
for entity in new_players {
|
||||
if let (Some(uid), Some(player)) = (uids.get(entity), players.get(entity)) {
|
||||
let msg = ServerMsg::PlayerListUpdate(PlayerListUpdate::Add(
|
||||
(*uid).into(),
|
||||
player.alias.clone(),
|
||||
));
|
||||
let msg =
|
||||
ServerMsg::PlayerListUpdate(PlayerListUpdate::Add((*uid).into(), PlayerInfo {
|
||||
player_alias: player.alias.clone(),
|
||||
character: None, // new players will be on character select.
|
||||
}));
|
||||
for client in (&mut clients).join().filter(|c| c.is_registered()) {
|
||||
client.notify(msg.clone())
|
||||
}
|
||||
@ -406,16 +416,22 @@ impl<'a> System<'a> for Sys {
|
||||
} else {
|
||||
let bubble = SpeechBubble::player_new(message.clone(), *time);
|
||||
let _ = speech_bubbles.insert(entity, bubble);
|
||||
match players.get(entity) {
|
||||
Some(player) => {
|
||||
if admins.get(entity).is_some() {
|
||||
format!("[ADMIN][{}] {}", &player.alias, message)
|
||||
} else {
|
||||
format!("[{}] {}", &player.alias, message)
|
||||
}
|
||||
format!(
|
||||
"{}[{}] {}: {}",
|
||||
match admins.get(entity) {
|
||||
Some(_) => "[ADMIN]",
|
||||
None => "",
|
||||
},
|
||||
None => format!("[<Unknown>] {}", message),
|
||||
}
|
||||
match players.get(entity) {
|
||||
Some(player) => &player.alias,
|
||||
None => "<Unknown>",
|
||||
},
|
||||
match stats.get(entity) {
|
||||
Some(stat) => &stat.name,
|
||||
None => "<Unknown>",
|
||||
},
|
||||
message
|
||||
)
|
||||
}
|
||||
} else {
|
||||
message
|
||||
|
@ -192,13 +192,20 @@ impl<'a> Widget for Social<'a> {
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.color(TEXT_COLOR)
|
||||
.set(ids.online_title, ui);
|
||||
for (i, (_, player_alias)) in self.client.player_list.iter().enumerate() {
|
||||
Text::new(player_alias)
|
||||
.down(3.0)
|
||||
.font_size(self.fonts.cyri.scale(15))
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.color(TEXT_COLOR)
|
||||
.set(ids.player_names[i], ui);
|
||||
for (i, (_, player_info)) in self.client.player_list.iter().enumerate() {
|
||||
Text::new(&format!(
|
||||
"[{}] {}",
|
||||
player_info.player_alias,
|
||||
match &player_info.character {
|
||||
Some(character) => format!("{} Lvl {}", &character.name, &character.level),
|
||||
None => "<None>".to_string(), // character select or spectating
|
||||
}
|
||||
))
|
||||
.down(3.0)
|
||||
.font_size(self.fonts.cyri.scale(15))
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.color(TEXT_COLOR)
|
||||
.set(ids.player_names[i], ui);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user