adding feature requested in issue #153 - displaying your alias in game as 'you'

This commit is contained in:
TheThirdSpartan 2020-09-06 19:42:32 +00:00 committed by Imbris
parent b87bbaff0b
commit 6dbd1bc132
10 changed files with 184 additions and 63 deletions

View File

@ -159,7 +159,7 @@ https://account.veloren.net."#,
"hud.press_key_to_toggle_debug_info_fmt": "Press {key} to toggle debug info",
// Chat outputs
"hud.chat.online_msg": "[{name}] is now online.",
"hud.chat.online_msg": "[{name}] joined.",
"hud.chat.offline_msg": "{name} went offline.",
"hud.chat.loot_msg": "You picked up [{item}]",
"hud.chat.loot_fail": "Your Inventory is full!",

View File

@ -17,7 +17,9 @@ use byteorder::{ByteOrder, LittleEndian};
use common::{
character::CharacterItem,
comp::{
self, group, ControlAction, ControlEvent, Controller, ControllerInputs, GroupManip,
self,
chat::{KillSource, KillType},
group, ControlAction, ControlEvent, Controller, ControllerInputs, GroupManip,
InventoryManip, InventoryUpdateEvent,
},
msg::{
@ -1226,7 +1228,10 @@ impl Client {
frontend_events.push(Event::Chat(
comp::ChatType::GroupMeta("Group".into()).chat_msg(format!(
"[{}] joined group",
player_info.player_alias
self.personalize_alias(
uid,
player_info.player_alias.clone()
)
)),
));
}
@ -1243,7 +1248,10 @@ impl Client {
frontend_events.push(Event::Chat(
comp::ChatType::GroupMeta("Group".into()).chat_msg(format!(
"[{}] left group",
player_info.player_alias
self.personalize_alias(
uid,
player_info.player_alias.clone()
)
)),
));
}
@ -1539,17 +1547,32 @@ impl Client {
self.entity = entity_builder.with(uid).build();
}
/// Change player alias to "You" if client belongs to matching player
fn personalize_alias(&self, uid: Uid, alias: String) -> String {
let client_uid = self.uid().expect("Client doesn't have a Uid!!!");
if client_uid == uid {
"You".to_string() // TODO: Localize
} else {
alias
}
}
/// Format a message for the client (voxygen chat box or chat-cli)
pub fn format_message(&self, msg: &comp::ChatMsg, character_name: bool) -> String {
let comp::ChatMsg { chat_type, message } = &msg;
let comp::ChatMsg {
chat_type, message, ..
} = &msg;
let alias_of_uid = |uid| {
self.player_list
.get(uid)
.map_or("<?>".to_string(), |player_info| {
if player_info.is_admin {
format!("ADMIN - {}", player_info.player_alias)
format!(
"ADMIN - {}",
self.personalize_alias(*uid, player_info.player_alias.clone())
)
} else {
player_info.player_alias.to_string()
self.personalize_alias(*uid, player_info.player_alias.clone())
}
})
};
@ -1580,14 +1603,44 @@ impl Client {
}
};
match chat_type {
comp::ChatType::Online => message.to_string(),
comp::ChatType::Offline => message.to_string(),
comp::ChatType::Online(uid) => format!("{} joined", alias_of_uid(uid)),
comp::ChatType::Offline(uid) => format!("{} left", alias_of_uid(uid)),
comp::ChatType::CommandError => message.to_string(),
comp::ChatType::CommandInfo => message.to_string(),
comp::ChatType::Loot => message.to_string(),
comp::ChatType::FactionMeta(_) => message.to_string(),
comp::ChatType::GroupMeta(_) => message.to_string(),
comp::ChatType::Kill => message.to_string(),
comp::ChatType::Kill(kill_source, victim) => {
// TODO: Localize
match kill_source {
KillSource::Player(attacker_uid, KillType::Melee) => format!(
"{} killed {}",
alias_of_uid(attacker_uid),
alias_of_uid(victim)
),
KillSource::Player(attacker_uid, KillType::Projectile) => format!(
"{} shot {}",
alias_of_uid(attacker_uid),
alias_of_uid(victim)
),
KillSource::NonPlayer(attacker_name, KillType::Melee) => {
format!("[{}] killed {}", attacker_name, alias_of_uid(victim))
},
KillSource::NonPlayer(attacker_name, KillType::Projectile) => {
format!("[{}] shot {}", attacker_name, alias_of_uid(victim))
},
KillSource::Environment(environment) => {
format!("{} died in [{}]", alias_of_uid(victim), environment)
},
KillSource::FallDamage => {
format!("{} died from fall damage", alias_of_uid(victim))
},
KillSource::Suicide => {
format!("{} died from self-inflicted wounds", alias_of_uid(victim))
},
KillSource::Other => format!("{} died", alias_of_uid(victim)),
}
},
comp::ChatType::Tell(from, to) => {
let from_alias = alias_of_uid(from);
let to_alias = alias_of_uid(to);

View File

@ -45,21 +45,39 @@ impl Default for ChatMode {
fn default() -> Self { Self::World }
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum KillType {
Melee,
Projectile,
// Projectile(String), TODO: add projectile name when available
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum KillSource {
Player(Uid, KillType),
NonPlayer(String, KillType),
Environment(String),
FallDamage,
Suicide,
Other,
}
/// 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<G> {
/// A player came online
Online,
Online(Uid),
/// A player went offline
Offline,
Offline(Uid),
/// The result of chat commands
CommandInfo,
/// A chat command failed
CommandError,
/// Inform players that someone died
Kill,
/// Inform players that someone died (Source, Victim) Source may be None
/// (ex: fall damage)
Kill(KillSource, Uid),
/// Server notifications to a group, such as player join/leave
GroupMeta(G),
/// Server notifications to a faction, such as player join/leave
@ -105,7 +123,7 @@ impl ChatType<String> {
ServerMsg::ChatMsg(self.chat_msg(msg))
}
}
// Stores chat text, type
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GenericChatMsg<G> {
pub chat_type: ChatType<G>,
@ -127,14 +145,14 @@ impl<G> GenericChatMsg<G> {
pub fn map_group<T>(self, mut f: impl FnMut(G) -> T) -> GenericChatMsg<T> {
let chat_type = match self.chat_type {
ChatType::Online => ChatType::Online,
ChatType::Offline => ChatType::Offline,
ChatType::Online(a) => ChatType::Online(a),
ChatType::Offline(a) => ChatType::Offline(a),
ChatType::CommandInfo => ChatType::CommandInfo,
ChatType::CommandError => ChatType::CommandError,
ChatType::Loot => ChatType::Loot,
ChatType::FactionMeta(a) => ChatType::FactionMeta(a),
ChatType::GroupMeta(g) => ChatType::GroupMeta(f(g)),
ChatType::Kill => ChatType::Kill,
ChatType::Kill(a, b) => ChatType::Kill(a, b),
ChatType::Tell(a, b) => ChatType::Tell(a, b),
ChatType::Say(a) => ChatType::Say(a),
ChatType::Group(a, g) => ChatType::Group(a, f(g)),
@ -163,14 +181,14 @@ impl<G> GenericChatMsg<G> {
pub fn icon(&self) -> SpeechBubbleType {
match &self.chat_type {
ChatType::Online => SpeechBubbleType::None,
ChatType::Offline => SpeechBubbleType::None,
ChatType::Online(_) => SpeechBubbleType::None,
ChatType::Offline(_) => SpeechBubbleType::None,
ChatType::CommandInfo => SpeechBubbleType::None,
ChatType::CommandError => SpeechBubbleType::None,
ChatType::Loot => SpeechBubbleType::None,
ChatType::FactionMeta(_) => SpeechBubbleType::None,
ChatType::GroupMeta(_) => SpeechBubbleType::None,
ChatType::Kill => SpeechBubbleType::None,
ChatType::Kill(_, _) => SpeechBubbleType::None,
ChatType::Tell(_u, _) => SpeechBubbleType::Tell,
ChatType::Say(_u) => SpeechBubbleType::Say,
ChatType::Group(_u, _s) => SpeechBubbleType::Group,
@ -184,14 +202,14 @@ impl<G> GenericChatMsg<G> {
pub fn uid(&self) -> Option<Uid> {
match &self.chat_type {
ChatType::Online => None,
ChatType::Offline => None,
ChatType::Online(_) => None,
ChatType::Offline(_) => None,
ChatType::CommandInfo => None,
ChatType::CommandError => None,
ChatType::Loot => None,
ChatType::FactionMeta(_) => None,
ChatType::GroupMeta(_) => None,
ChatType::Kill => None,
ChatType::Kill(_, _) => None,
ChatType::Tell(u, _t) => Some(*u),
ChatType::Say(u) => Some(*u),
ChatType::Group(u, _s) => Some(*u),

View File

@ -3,7 +3,7 @@ mod admin;
pub mod agent;
mod body;
mod character_state;
mod chat;
pub mod chat;
mod controller;
mod damage;
mod energy;

View File

@ -86,7 +86,9 @@ impl<'a> System<'a> for Sys {
uid: other,
change: HealthChange {
amount: damage.healthchange as i32,
cause: HealthSource::Attack { by: owner_uid },
cause: HealthSource::Projectile {
owner: Some(owner_uid),
},
},
});
}

View File

@ -2,8 +2,11 @@ use crate::{client::Client, comp::quadruped_small, Server, SpawnPoint, StateExt}
use common::{
assets::Asset,
comp::{
self, item::ItemAsset, object, Alignment, Body, Damage, DamageSource, Group, HealthChange,
HealthSource, Player, Pos, Stats,
self,
chat::{KillSource, KillType},
item::ItemAsset,
object, Alignment, Body, Damage, DamageSource, Group, HealthChange, HealthSource, Player,
Pos, Stats,
},
lottery::Lottery,
msg::{PlayerListUpdate, ServerMsg},
@ -53,25 +56,68 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, cause: HealthSourc
}
// Chat message
if let Some(player) = state.ecs().read_storage::<Player>().get(entity) {
let msg = if let HealthSource::Attack { by }
| HealthSource::Projectile { owner: Some(by) } = cause
{
state.ecs().entity_from_uid(by.into()).and_then(|attacker| {
state
.ecs()
.read_storage::<Player>()
.get(attacker)
.map(|attacker_alias| {
format!("{} was killed by {}", &player.alias, &attacker_alias.alias)
})
})
} else {
None
// If it was a player that died
if let Some(_player) = state.ecs().read_storage::<Player>().get(entity) {
if let Some(uid) = state.ecs().read_storage::<Uid>().get(entity) {
let kill_source = match cause {
HealthSource::Attack { by } => {
// Get attacker entity
if let Some(char_entity) = state.ecs().entity_from_uid(by.into()) {
// Check if attacker is another player or entity with stats (npc)
if state
.ecs()
.read_storage::<Player>()
.get(char_entity)
.is_some()
{
KillSource::Player(by, KillType::Melee)
} else if let Some(stats) =
state.ecs().read_storage::<Stats>().get(char_entity)
{
KillSource::NonPlayer(stats.name.clone(), KillType::Melee)
} else {
KillSource::NonPlayer("Unknown".to_string(), KillType::Melee)
}
} else {
KillSource::NonPlayer("Unknown".to_string(), KillType::Melee)
}
},
HealthSource::Projectile { owner: Some(by) } => {
// Get projectile owner entity TODO: add names to projectiles and send in
// message
if let Some(char_entity) = state.ecs().entity_from_uid(by.into()) {
// Check if attacker is another player or entity with stats (npc)
if state
.ecs()
.read_storage::<Player>()
.get(char_entity)
.is_some()
{
KillSource::Player(by, KillType::Projectile)
} else if let Some(stats) =
state.ecs().read_storage::<Stats>().get(char_entity)
{
KillSource::NonPlayer(stats.name.clone(), KillType::Projectile)
} else {
KillSource::NonPlayer("Unknown".to_string(), KillType::Projectile)
}
} else {
KillSource::NonPlayer("Unknown".to_string(), KillType::Projectile)
}
},
HealthSource::World => KillSource::FallDamage,
HealthSource::Suicide => KillSource::Suicide,
HealthSource::Projectile { owner: None }
| HealthSource::Revive
| HealthSource::Command
| HealthSource::LevelUp
| HealthSource::Item
| HealthSource::Unknown => KillSource::Other,
};
state.notify_registered_clients(
comp::ChatType::Kill(kill_source, *uid).server_msg("".to_string()),
);
}
.unwrap_or(format!("{} died", &player.alias));
state.notify_registered_clients(comp::ChatType::Kill.server_msg(msg));
}
// Give EXP to the killer if entity had stats

View File

@ -112,21 +112,21 @@ pub fn handle_client_disconnect(server: &mut Server, entity: EcsEntity) -> Event
let state = server.state_mut();
// Tell other clients to remove from player list
// And send a disconnected message
if let (Some(uid), Some(_)) = (
state.read_storage::<Uid>().get(entity),
state.read_storage::<comp::Player>().get(entity),
) {
state.notify_registered_clients(ServerMsg::PlayerListUpdate(PlayerListUpdate::Remove(*uid)))
state.notify_registered_clients(comp::ChatType::Offline(*uid).server_msg(""));
state
.notify_registered_clients(ServerMsg::PlayerListUpdate(PlayerListUpdate::Remove(*uid)));
}
// Make sure to remove the player from the logged in list. (See LoginProvider)
// And send a disconnected message
if let Some(player) = state.ecs().read_storage::<Player>().get(entity) {
let mut login_provider = state.ecs().write_resource::<LoginProvider>();
login_provider.logout(player.uuid());
let msg = comp::ChatType::Offline.server_msg(format!("[{}] went offline.", &player.alias));
state.notify_registered_clients(msg);
}
// Sync the player's character data to the database

View File

@ -230,12 +230,12 @@ impl StateExt for State {
});
match &msg.chat_type {
comp::ChatType::Online
| comp::ChatType::Offline
comp::ChatType::Online(_)
| comp::ChatType::Offline(_)
| comp::ChatType::CommandInfo
| comp::ChatType::CommandError
| comp::ChatType::Loot
| comp::ChatType::Kill
| comp::ChatType::Kill(_, _)
| comp::ChatType::Meta
| comp::ChatType::World(_) => {
self.notify_registered_clients(ServerMsg::ChatMsg(resolved_msg))
@ -323,7 +323,7 @@ impl StateExt for State {
.join()
.filter(|c| c.is_registered())
{
client.notify(msg.clone())
client.notify(msg.clone());
}
}

View File

@ -203,12 +203,14 @@ impl Sys {
// Only send login message if it wasn't already
// sent previously
if !client.login_msg_sent {
new_chat_msgs.push((None, UnresolvedChatMsg {
chat_type: ChatType::Online,
message: format!("[{}] is now online.", &player.alias), // TODO: Localize this
}));
if let Some(player_uid) = uids.get(entity) {
new_chat_msgs.push((None, UnresolvedChatMsg {
chat_type: ChatType::Online(*player_uid),
message: "".to_string(),
}));
client.login_msg_sent = true;
client.login_msg_sent = true;
}
}
} else {
client.notify(ServerMsg::CharacterDataLoadError(String::from(

View File

@ -474,14 +474,14 @@ 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<String>, imgs: &Imgs) -> (Color, conrod_core::image::Id) {
match chat_type {
ChatType::Online => (ONLINE_COLOR, imgs.chat_online_small),
ChatType::Offline => (OFFLINE_COLOR, imgs.chat_offline_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::Loot => (LOOT_COLOR, imgs.chat_loot_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::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),
ChatType::Group(_uid, _s) => (GROUP_COLOR, imgs.chat_group_small),