mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Overhauled chat message representation to allow for more exhaustive localisation
This commit is contained in:
parent
bc4d1a71f6
commit
edcc2f1870
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -7173,6 +7173,7 @@ dependencies = [
|
||||
name = "veloren-voxygen-i18n-helpers"
|
||||
version = "0.10.0"
|
||||
dependencies = [
|
||||
"hashbrown 0.12.3",
|
||||
"tracing",
|
||||
"veloren-client-i18n",
|
||||
"veloren-common",
|
||||
|
@ -2280,13 +2280,15 @@ impl Client {
|
||||
.any(|r| !matches!(r, group::Role::Pet))
|
||||
{
|
||||
frontend_events
|
||||
.push(Event::Chat(comp::ChatType::Meta.chat_msg(
|
||||
// TODO: localise
|
||||
.push(Event::Chat(comp::ChatType::Meta.into_plain_msg(
|
||||
"Type /g or /group to chat with your group members",
|
||||
)));
|
||||
}
|
||||
if let Some(player_info) = self.player_list.get(&uid) {
|
||||
frontend_events.push(Event::Chat(
|
||||
comp::ChatType::GroupMeta("Group".into()).chat_msg(format!(
|
||||
// TODO: localise
|
||||
comp::ChatType::GroupMeta("Group".into()).into_plain_msg(format!(
|
||||
"[{}] joined group",
|
||||
self.personalize_alias(uid, player_info.player_alias.clone())
|
||||
)),
|
||||
@ -2303,7 +2305,8 @@ impl Client {
|
||||
Removed(uid) => {
|
||||
if let Some(player_info) = self.player_list.get(&uid) {
|
||||
frontend_events.push(Event::Chat(
|
||||
comp::ChatType::GroupMeta("Group".into()).chat_msg(format!(
|
||||
// TODO: localise
|
||||
comp::ChatType::GroupMeta("Group".into()).into_plain_msg(format!(
|
||||
"[{}] left group",
|
||||
self.personalize_alias(uid, player_info.player_alias.clone())
|
||||
)),
|
||||
@ -2790,20 +2793,20 @@ impl Client {
|
||||
KillSource::Other => (),
|
||||
};
|
||||
},
|
||||
comp::ChatType::Tell(from, to) | comp::ChatType::NpcTell(from, to, _) => {
|
||||
comp::ChatType::Tell(from, to) | comp::ChatType::NpcTell(from, to) => {
|
||||
alias_of_uid(from);
|
||||
alias_of_uid(to);
|
||||
},
|
||||
comp::ChatType::Say(uid)
|
||||
| comp::ChatType::Region(uid)
|
||||
| comp::ChatType::World(uid)
|
||||
| comp::ChatType::NpcSay(uid, _) => {
|
||||
| comp::ChatType::NpcSay(uid) => {
|
||||
alias_of_uid(uid);
|
||||
},
|
||||
comp::ChatType::Group(uid, _) | comp::ChatType::Faction(uid, _) => {
|
||||
alias_of_uid(uid);
|
||||
},
|
||||
comp::ChatType::Npc(uid, _) => alias_of_uid(uid),
|
||||
comp::ChatType::Npc(uid) => alias_of_uid(uid),
|
||||
comp::ChatType::Meta => (),
|
||||
};
|
||||
result
|
||||
|
@ -6,7 +6,7 @@ use crate::sync;
|
||||
use common::{
|
||||
calendar::Calendar,
|
||||
character::{self, CharacterItem},
|
||||
comp::{self, invite::InviteKind, item::MaterialStatManifest},
|
||||
comp::{self, invite::InviteKind, item::MaterialStatManifest, Content},
|
||||
event::UpdateCharacterMetadata,
|
||||
lod,
|
||||
outcome::Outcome,
|
||||
@ -215,11 +215,10 @@ pub enum ServerGeneral {
|
||||
}
|
||||
|
||||
impl ServerGeneral {
|
||||
pub fn server_msg<S>(chat_type: comp::ChatType<String>, msg: S) -> Self
|
||||
where
|
||||
S: Into<String>,
|
||||
{
|
||||
ServerGeneral::ChatMsg(chat_type.chat_msg(msg))
|
||||
// TODO: Don't use `Into<Content>` since this treats all strings as plaintext,
|
||||
// properly localise server messages
|
||||
pub fn server_msg(chat_type: comp::ChatType<String>, content: impl Into<Content>) -> Self {
|
||||
ServerGeneral::ChatMsg(chat_type.into_msg(content.into()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ use crate::{
|
||||
comp::{group::Group, BuffKind},
|
||||
uid::Uid,
|
||||
};
|
||||
use hashbrown::HashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use specs::{Component, DenseVecStorage};
|
||||
use std::time::{Duration, Instant};
|
||||
@ -29,8 +30,8 @@ impl Component for ChatMode {
|
||||
}
|
||||
|
||||
impl ChatMode {
|
||||
/// Create a message from your current chat mode and uuid.
|
||||
pub fn new_message(&self, from: Uid, message: String) -> UnresolvedChatMsg {
|
||||
/// Create a plain message from your current chat mode and uuid.
|
||||
pub fn to_plain_msg(&self, from: Uid, text: impl ToString) -> UnresolvedChatMsg {
|
||||
let chat_type = match self {
|
||||
ChatMode::Tell(to) => ChatType::Tell(from, *to),
|
||||
ChatMode::Say => ChatType::Say(from),
|
||||
@ -39,7 +40,10 @@ impl ChatMode {
|
||||
ChatMode::Faction(faction) => ChatType::Faction(from, faction.clone()),
|
||||
ChatMode::World => ChatType::World(from),
|
||||
};
|
||||
UnresolvedChatMsg { chat_type, message }
|
||||
UnresolvedChatMsg {
|
||||
chat_type,
|
||||
content: Content::Plain(text.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,26 +106,28 @@ pub enum ChatType<G> {
|
||||
/// World chat
|
||||
World(Uid),
|
||||
/// Messages sent from NPCs (Not shown in chat but as speech bubbles)
|
||||
///
|
||||
/// The u16 field is a random number for selecting localization variants.
|
||||
Npc(Uid, u16),
|
||||
Npc(Uid),
|
||||
/// From NPCs but in the chat for clients in the near vicinity
|
||||
NpcSay(Uid, u16),
|
||||
NpcSay(Uid),
|
||||
/// From NPCs but in the chat for a specific client. Shows a chat bubble.
|
||||
/// (from, to, localization variant)
|
||||
NpcTell(Uid, Uid, u16),
|
||||
NpcTell(Uid, Uid),
|
||||
/// Anything else
|
||||
Meta,
|
||||
}
|
||||
|
||||
impl<G> ChatType<G> {
|
||||
pub fn chat_msg<S>(self, msg: S) -> GenericChatMsg<G>
|
||||
where
|
||||
S: Into<String>,
|
||||
{
|
||||
pub fn into_plain_msg(self, text: impl ToString) -> GenericChatMsg<G> {
|
||||
GenericChatMsg {
|
||||
chat_type: self,
|
||||
message: msg.into(),
|
||||
content: Content::Plain(text.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_msg(self, content: Content) -> GenericChatMsg<G> {
|
||||
GenericChatMsg {
|
||||
chat_type: self,
|
||||
content,
|
||||
}
|
||||
}
|
||||
|
||||
@ -140,9 +146,9 @@ impl<G> ChatType<G> {
|
||||
ChatType::Faction(u, _s) => Some(*u),
|
||||
ChatType::Region(u) => Some(*u),
|
||||
ChatType::World(u) => Some(*u),
|
||||
ChatType::Npc(u, _r) => Some(*u),
|
||||
ChatType::NpcSay(u, _r) => Some(*u),
|
||||
ChatType::NpcTell(u, _t, _r) => Some(*u),
|
||||
ChatType::Npc(u) => Some(*u),
|
||||
ChatType::NpcSay(u) => Some(*u),
|
||||
ChatType::NpcTell(u, _t) => Some(*u),
|
||||
ChatType::Meta => None,
|
||||
}
|
||||
}
|
||||
@ -156,9 +162,9 @@ impl<G> ChatType<G> {
|
||||
| ChatType::CommandError
|
||||
| ChatType::FactionMeta(_)
|
||||
| ChatType::GroupMeta(_)
|
||||
| ChatType::Npc(_, _)
|
||||
| ChatType::NpcSay(_, _)
|
||||
| ChatType::NpcTell(_, _, _)
|
||||
| ChatType::Npc(_)
|
||||
| ChatType::NpcSay(_)
|
||||
| ChatType::NpcTell(_, _)
|
||||
| ChatType::Meta
|
||||
| ChatType::Kill(_, _) => None,
|
||||
ChatType::Tell(_, _) | ChatType::Group(_, _) | ChatType::Faction(_, _) => Some(true),
|
||||
@ -167,11 +173,87 @@ impl<G> ChatType<G> {
|
||||
}
|
||||
}
|
||||
|
||||
/// The content of a chat message.
|
||||
// TODO: This could be generalised to *any* in-game text, not just chat messages (hence it not being
|
||||
// called `ChatContent`). A few examples:
|
||||
//
|
||||
// - Signposts, both those appearing as overhead messages and those displayed 'in-world' on a shop
|
||||
// sign
|
||||
// - UI elements
|
||||
// - In-game notes/books (we could add a variant that allows structuring complex, novel textual
|
||||
// information as a syntax tree or some other intermediate format that can be localised by the
|
||||
// client)
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum Content {
|
||||
/// The content is a plaintext string that should be shown to the user
|
||||
/// verbatim.
|
||||
Plain(String),
|
||||
/// The content is a localizable message with the given arguments.
|
||||
Localized {
|
||||
/// i18n key
|
||||
key: String,
|
||||
/// Pseudorandom seed value that allows frontends to select a
|
||||
/// deterministic (but pseudorandom) localised output
|
||||
seed: u16,
|
||||
/// i18n arguments
|
||||
args: HashMap<String, String>,
|
||||
},
|
||||
}
|
||||
|
||||
impl From<String> for Content {
|
||||
fn from(text: String) -> Self { Self::Plain(text) }
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for Content {
|
||||
fn from(text: &'a str) -> Self { Self::Plain(text.to_string()) }
|
||||
}
|
||||
|
||||
impl Content {
|
||||
pub fn localized(key: impl ToString) -> Self {
|
||||
Self::Localized {
|
||||
key: key.to_string(),
|
||||
r: rand::random(),
|
||||
args: HashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn localized_with_args<'a, S: ToString>(
|
||||
key: impl ToString,
|
||||
args: impl IntoIterator<Item = (&'a str, S)>,
|
||||
) -> Self {
|
||||
Self::Localized {
|
||||
key: key.to_string(),
|
||||
r: rand::random(),
|
||||
args: args
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k.to_string(), v.to_string()))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_plain(&self) -> Option<&str> {
|
||||
match self {
|
||||
Self::Plain(text) => Some(text.as_str()),
|
||||
Self::Localized { .. } => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn localize<F>(&self, i18n_variation: F) -> String
|
||||
where
|
||||
F: Fn(&str, u16, &HashMap<String, String>) -> String,
|
||||
{
|
||||
match self {
|
||||
Content::Plain(text) => text.to_string(),
|
||||
Content::Localized { key, seed, args } => i18n_variation(key, *seed, args),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Stores chat text, type
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct GenericChatMsg<G> {
|
||||
pub chat_type: ChatType<G>,
|
||||
pub message: String,
|
||||
content: Content,
|
||||
}
|
||||
|
||||
pub type ChatMsg = GenericChatMsg<String>;
|
||||
@ -183,19 +265,19 @@ impl<G> GenericChatMsg<G> {
|
||||
pub const REGION_DISTANCE: f32 = 1000.0;
|
||||
pub const SAY_DISTANCE: f32 = 100.0;
|
||||
|
||||
pub fn npc(uid: Uid, message: String) -> Self {
|
||||
let chat_type = ChatType::Npc(uid, rand::random());
|
||||
Self { chat_type, message }
|
||||
pub fn npc(uid: Uid, content: Content) -> Self {
|
||||
let chat_type = ChatType::Npc(uid);
|
||||
Self { chat_type, content }
|
||||
}
|
||||
|
||||
pub fn npc_say(uid: Uid, message: String) -> Self {
|
||||
let chat_type = ChatType::NpcSay(uid, rand::random());
|
||||
Self { chat_type, message }
|
||||
pub fn npc_say(uid: Uid, content: Content) -> Self {
|
||||
let chat_type = ChatType::NpcSay(uid);
|
||||
Self { chat_type, content }
|
||||
}
|
||||
|
||||
pub fn npc_tell(from: Uid, to: Uid, message: String) -> Self {
|
||||
let chat_type = ChatType::NpcTell(from, to, rand::random());
|
||||
Self { chat_type, message }
|
||||
pub fn npc_tell(from: Uid, to: Uid, content: Content) -> Self {
|
||||
let chat_type = ChatType::NpcTell(from, to);
|
||||
Self { chat_type, content }
|
||||
}
|
||||
|
||||
pub fn map_group<T>(self, mut f: impl FnMut(G) -> T) -> GenericChatMsg<T> {
|
||||
@ -213,15 +295,15 @@ impl<G> GenericChatMsg<G> {
|
||||
ChatType::Faction(a, b) => ChatType::Faction(a, b),
|
||||
ChatType::Region(a) => ChatType::Region(a),
|
||||
ChatType::World(a) => ChatType::World(a),
|
||||
ChatType::Npc(a, b) => ChatType::Npc(a, b),
|
||||
ChatType::NpcSay(a, b) => ChatType::NpcSay(a, b),
|
||||
ChatType::NpcTell(a, b, c) => ChatType::NpcTell(a, b, c),
|
||||
ChatType::Npc(a) => ChatType::Npc(a),
|
||||
ChatType::NpcSay(a) => ChatType::NpcSay(a),
|
||||
ChatType::NpcTell(a, b) => ChatType::NpcTell(a, b),
|
||||
ChatType::Meta => ChatType::Meta,
|
||||
};
|
||||
|
||||
GenericChatMsg {
|
||||
chat_type,
|
||||
message: self.message,
|
||||
content: self.content,
|
||||
}
|
||||
}
|
||||
|
||||
@ -234,15 +316,8 @@ impl<G> GenericChatMsg<G> {
|
||||
}
|
||||
|
||||
pub fn to_bubble(&self) -> Option<(SpeechBubble, Uid)> {
|
||||
let icon = self.icon();
|
||||
if let ChatType::Npc(from, r) | ChatType::NpcSay(from, r) | ChatType::NpcTell(from, _, r) =
|
||||
self.chat_type
|
||||
{
|
||||
Some((SpeechBubble::npc_new(&self.message, r, icon), from))
|
||||
} else {
|
||||
self.uid()
|
||||
.map(|from| (SpeechBubble::player_new(&self.message, icon), from))
|
||||
}
|
||||
self.uid()
|
||||
.map(|from| (SpeechBubble::new(self.content.clone(), self.icon()), from))
|
||||
}
|
||||
|
||||
pub fn icon(&self) -> SpeechBubbleType {
|
||||
@ -260,14 +335,18 @@ impl<G> GenericChatMsg<G> {
|
||||
ChatType::Faction(_u, _s) => SpeechBubbleType::Faction,
|
||||
ChatType::Region(_u) => SpeechBubbleType::Region,
|
||||
ChatType::World(_u) => SpeechBubbleType::World,
|
||||
ChatType::Npc(_u, _r) => SpeechBubbleType::None,
|
||||
ChatType::NpcSay(_u, _r) => SpeechBubbleType::Say,
|
||||
ChatType::NpcTell(_f, _t, _) => SpeechBubbleType::Say,
|
||||
ChatType::Npc(_u) => SpeechBubbleType::None,
|
||||
ChatType::NpcSay(_u) => SpeechBubbleType::Say,
|
||||
ChatType::NpcTell(_f, _t) => SpeechBubbleType::Say,
|
||||
ChatType::Meta => SpeechBubbleType::None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn uid(&self) -> Option<Uid> { self.chat_type.uid() }
|
||||
|
||||
pub fn content(&self) -> &Content { &self.content }
|
||||
|
||||
pub fn set_content(&mut self, content: Content) { self.content = content; }
|
||||
}
|
||||
|
||||
/// Player factions are used to coordinate pvp vs hostile factions or segment
|
||||
@ -283,15 +362,6 @@ impl From<String> for Faction {
|
||||
fn from(s: String) -> Self { Faction(s) }
|
||||
}
|
||||
|
||||
/// The contents of a speech bubble
|
||||
pub enum SpeechBubbleMessage {
|
||||
/// This message was said by a player and needs no translation
|
||||
Plain(String),
|
||||
/// This message was said by an NPC. The fields are a i18n key and a random
|
||||
/// u16 index
|
||||
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`
|
||||
@ -311,7 +381,7 @@ pub enum SpeechBubbleType {
|
||||
|
||||
/// Adds a speech bubble above the character
|
||||
pub struct SpeechBubble {
|
||||
pub message: SpeechBubbleMessage,
|
||||
pub content: Content,
|
||||
pub icon: SpeechBubbleType,
|
||||
pub timeout: Instant,
|
||||
}
|
||||
@ -320,33 +390,14 @@ impl SpeechBubble {
|
||||
/// Default duration in seconds of speech bubbles
|
||||
pub const DEFAULT_DURATION: f64 = 5.0;
|
||||
|
||||
pub fn npc_new(i18n_key: &str, r: u16, icon: SpeechBubbleType) -> Self {
|
||||
let message = SpeechBubbleMessage::Localized(i18n_key.to_string(), r);
|
||||
pub fn new(content: Content, icon: SpeechBubbleType) -> Self {
|
||||
let timeout = Instant::now() + Duration::from_secs_f64(SpeechBubble::DEFAULT_DURATION);
|
||||
Self {
|
||||
message,
|
||||
content,
|
||||
icon,
|
||||
timeout,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn player_new(message: &str, icon: SpeechBubbleType) -> Self {
|
||||
let message = SpeechBubbleMessage::Plain(message.to_string());
|
||||
let timeout = Instant::now() + Duration::from_secs_f64(SpeechBubble::DEFAULT_DURATION);
|
||||
Self {
|
||||
message,
|
||||
icon,
|
||||
timeout,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn message<F>(&self, i18n_variation: F) -> String
|
||||
where
|
||||
F: Fn(&str, u16) -> String,
|
||||
{
|
||||
match &self.message {
|
||||
SpeechBubbleMessage::Plain(m) => m.to_string(),
|
||||
SpeechBubbleMessage::Localized(k, i) => i18n_variation(k, *i),
|
||||
}
|
||||
}
|
||||
pub fn content(&self) -> &Content { &self.content }
|
||||
}
|
||||
|
@ -75,7 +75,8 @@ pub use self::{
|
||||
},
|
||||
character_state::{CharacterActivity, CharacterState, StateUpdate},
|
||||
chat::{
|
||||
ChatMode, ChatMsg, ChatType, Faction, SpeechBubble, SpeechBubbleType, UnresolvedChatMsg,
|
||||
ChatMode, ChatMsg, ChatType, Content, Faction, SpeechBubble, SpeechBubbleType,
|
||||
UnresolvedChatMsg,
|
||||
},
|
||||
combo::Combo,
|
||||
controller::{
|
||||
|
@ -88,7 +88,7 @@ fn on_death(ctx: EventCtx<SimulateNpcs, OnDeath>) {
|
||||
);
|
||||
Some((npc_id, site_id))
|
||||
} else {
|
||||
warn!("No site found for respawning humaniod");
|
||||
warn!("No site found for respawning humanoid");
|
||||
None
|
||||
}
|
||||
},
|
||||
|
@ -22,7 +22,7 @@ use common::{
|
||||
},
|
||||
item_drop,
|
||||
projectile::ProjectileConstructor,
|
||||
Agent, Alignment, Body, CharacterState, ControlAction, ControlEvent, Controller,
|
||||
Agent, Alignment, Body, CharacterState, Content, ControlAction, ControlEvent, Controller,
|
||||
HealthChange, InputKind, InventoryAction, Pos, Scale, UnresolvedChatMsg, UtteranceKind,
|
||||
},
|
||||
effect::{BuffEffect, Effect},
|
||||
@ -1529,10 +1529,10 @@ impl<'a> AgentData<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn chat_npc(&self, msg: impl ToString, event_emitter: &mut Emitter<'_, ServerEvent>) {
|
||||
pub fn chat_npc(&self, key: impl ToString, event_emitter: &mut Emitter<'_, ServerEvent>) {
|
||||
event_emitter.emit(ServerEvent::Chat(UnresolvedChatMsg::npc(
|
||||
*self.uid,
|
||||
msg.to_string(),
|
||||
Content::localized(key),
|
||||
)));
|
||||
}
|
||||
|
||||
|
@ -2745,7 +2745,7 @@ fn handle_tell(
|
||||
} else {
|
||||
message_opt.join(" ")
|
||||
};
|
||||
server.state.send_chat(mode.new_message(target_uid, msg));
|
||||
server.state.send_chat(mode.to_plain_msg(target_uid, msg));
|
||||
server.notify_client(target, ServerGeneral::ChatMode(mode));
|
||||
Ok(())
|
||||
} else {
|
||||
@ -2770,7 +2770,7 @@ fn handle_faction(
|
||||
let msg = args.join(" ");
|
||||
if !msg.is_empty() {
|
||||
if let Some(uid) = server.state.ecs().read_storage().get(target) {
|
||||
server.state.send_chat(mode.new_message(*uid, msg));
|
||||
server.state.send_chat(mode.to_plain_msg(*uid, msg));
|
||||
}
|
||||
}
|
||||
server.notify_client(target, ServerGeneral::ChatMode(mode));
|
||||
@ -2797,7 +2797,7 @@ fn handle_group(
|
||||
let msg = args.join(" ");
|
||||
if !msg.is_empty() {
|
||||
if let Some(uid) = server.state.ecs().read_storage().get(target) {
|
||||
server.state.send_chat(mode.new_message(*uid, msg));
|
||||
server.state.send_chat(mode.to_plain_msg(*uid, msg));
|
||||
}
|
||||
}
|
||||
server.notify_client(target, ServerGeneral::ChatMode(mode));
|
||||
@ -2921,7 +2921,7 @@ fn handle_region(
|
||||
let msg = args.join(" ");
|
||||
if !msg.is_empty() {
|
||||
if let Some(uid) = server.state.ecs().read_storage().get(target) {
|
||||
server.state.send_chat(mode.new_message(*uid, msg));
|
||||
server.state.send_chat(mode.to_plain_msg(*uid, msg));
|
||||
}
|
||||
}
|
||||
server.notify_client(target, ServerGeneral::ChatMode(mode));
|
||||
@ -2942,7 +2942,7 @@ fn handle_say(
|
||||
let msg = args.join(" ");
|
||||
if !msg.is_empty() {
|
||||
if let Some(uid) = server.state.ecs().read_storage().get(target) {
|
||||
server.state.send_chat(mode.new_message(*uid, msg));
|
||||
server.state.send_chat(mode.to_plain_msg(*uid, msg));
|
||||
}
|
||||
}
|
||||
server.notify_client(target, ServerGeneral::ChatMode(mode));
|
||||
@ -2963,7 +2963,7 @@ fn handle_world(
|
||||
let msg = args.join(" ");
|
||||
if !msg.is_empty() {
|
||||
if let Some(uid) = server.state.ecs().read_storage().get(target) {
|
||||
server.state.send_chat(mode.new_message(*uid, msg));
|
||||
server.state.send_chat(mode.to_plain_msg(*uid, msg));
|
||||
}
|
||||
}
|
||||
server.notify_client(target, ServerGeneral::ChatMode(mode));
|
||||
@ -2992,8 +2992,9 @@ fn handle_join_faction(
|
||||
.flatten()
|
||||
.map(|f| f.0);
|
||||
server.state.send_chat(
|
||||
// TODO: Localise
|
||||
ChatType::FactionMeta(faction.clone())
|
||||
.chat_msg(format!("[{}] joined faction ({})", alias, faction)),
|
||||
.into_plain_msg(format!("[{}] joined faction ({})", alias, faction)),
|
||||
);
|
||||
(faction_join, mode)
|
||||
} else {
|
||||
@ -3009,8 +3010,9 @@ fn handle_join_faction(
|
||||
};
|
||||
if let Some(faction) = faction_leave {
|
||||
server.state.send_chat(
|
||||
// TODO: Localise
|
||||
ChatType::FactionMeta(faction.clone())
|
||||
.chat_msg(format!("[{}] left faction ({})", alias, faction)),
|
||||
.into_plain_msg(format!("[{}] left faction ({})", alias, faction)),
|
||||
);
|
||||
}
|
||||
server.notify_client(target, ServerGeneral::ChatMode(mode));
|
||||
|
@ -35,7 +35,6 @@ use common::{
|
||||
};
|
||||
use common_net::{msg::ServerGeneral, sync::WorldSyncExt};
|
||||
use common_state::BlockChange;
|
||||
use comp::chat::GenericChatMsg;
|
||||
use hashbrown::HashSet;
|
||||
use rand::{distributions::WeightedIndex, Rng};
|
||||
use rand_distr::Distribution;
|
||||
@ -198,10 +197,7 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, last_change: Healt
|
||||
_ => KillSource::Other,
|
||||
};
|
||||
|
||||
state.send_chat(GenericChatMsg {
|
||||
chat_type: comp::ChatType::Kill(kill_source, *uid),
|
||||
message: "".to_string(),
|
||||
});
|
||||
state.send_chat(comp::ChatType::Kill(kill_source, *uid).into_plain_msg(""));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -797,7 +797,11 @@ impl StateExt for State {
|
||||
(*ecs.read_resource::<UidAllocator>())
|
||||
.retrieve_entity_internal(sender.0)
|
||||
.map_or(false, |e| {
|
||||
self.validate_chat_msg(e, &msg.chat_type, &msg.message)
|
||||
self.validate_chat_msg(
|
||||
e,
|
||||
&msg.chat_type,
|
||||
msg.content().as_plain().unwrap_or_default(),
|
||||
)
|
||||
})
|
||||
}) {
|
||||
match &msg.chat_type {
|
||||
@ -827,7 +831,6 @@ impl StateExt for State {
|
||||
}
|
||||
},
|
||||
comp::ChatType::Kill(kill_source, uid) => {
|
||||
let comp::chat::GenericChatMsg { message, .. } = msg;
|
||||
let clients = ecs.read_storage::<Client>();
|
||||
let clients_count = clients.count();
|
||||
// Avoid chat spam, send kill message only to group or nearby players if a
|
||||
@ -870,7 +873,7 @@ impl StateExt for State {
|
||||
} else {
|
||||
self.notify_players(ServerGeneral::server_msg(
|
||||
comp::ChatType::Kill(kill_source.clone(), *uid),
|
||||
message,
|
||||
msg.content().clone(),
|
||||
))
|
||||
}
|
||||
},
|
||||
@ -900,7 +903,7 @@ impl StateExt for State {
|
||||
}
|
||||
}
|
||||
},
|
||||
comp::ChatType::Npc(uid, _r) => {
|
||||
comp::ChatType::Npc(uid) => {
|
||||
let entity_opt =
|
||||
(*ecs.read_resource::<UidAllocator>()).retrieve_entity_internal(uid.0);
|
||||
|
||||
@ -913,7 +916,7 @@ impl StateExt for State {
|
||||
}
|
||||
}
|
||||
},
|
||||
comp::ChatType::NpcSay(uid, _r) => {
|
||||
comp::ChatType::NpcSay(uid) => {
|
||||
let entity_opt =
|
||||
(*ecs.read_resource::<UidAllocator>()).retrieve_entity_internal(uid.0);
|
||||
|
||||
@ -926,7 +929,7 @@ impl StateExt for State {
|
||||
}
|
||||
}
|
||||
},
|
||||
comp::ChatType::NpcTell(from, to, _r) => {
|
||||
comp::ChatType::NpcTell(from, to) => {
|
||||
for (client, uid) in
|
||||
(&ecs.read_storage::<Client>(), &ecs.read_storage::<Uid>()).join()
|
||||
{
|
||||
@ -950,12 +953,10 @@ impl StateExt for State {
|
||||
comp::ChatType::Group(from, g) => {
|
||||
if group_info.is_none() {
|
||||
// group not found, reply with command error
|
||||
let reply = comp::ChatMsg {
|
||||
chat_type: comp::ChatType::CommandError,
|
||||
message: "You are using group chat but do not belong to a group. Use \
|
||||
/world or /region to change chat."
|
||||
.into(),
|
||||
};
|
||||
let reply = comp::ChatType::CommandError.into_plain_msg(
|
||||
"You are using group chat but do not belong to a group. Use /world or \
|
||||
/region to change chat.",
|
||||
);
|
||||
|
||||
if let Some((client, _)) =
|
||||
(&ecs.read_storage::<Client>(), &ecs.read_storage::<Uid>())
|
||||
|
@ -6,7 +6,8 @@ use common::{
|
||||
inventory::item::{ItemTag, MaterialStatManifest},
|
||||
invite::{InviteKind, InviteResponse},
|
||||
tool::AbilityMap,
|
||||
BehaviorState, ControlAction, Item, TradingBehavior, UnresolvedChatMsg, UtteranceKind,
|
||||
BehaviorState, Content, ControlAction, Item, TradingBehavior, UnresolvedChatMsg,
|
||||
UtteranceKind,
|
||||
},
|
||||
event::ServerEvent,
|
||||
rtsim::PersonalityTrait,
|
||||
@ -434,7 +435,7 @@ pub fn handle_inbox_update_pending_trade(bdata: &mut BehaviorData) -> bool {
|
||||
let (tradeid, pending, prices, inventories) = *boxval;
|
||||
if agent.behavior.is(BehaviorState::TRADING) {
|
||||
let who = usize::from(!agent.behavior.is(BehaviorState::TRADING_ISSUER));
|
||||
let mut message = |msg| {
|
||||
let mut message = |text| {
|
||||
if let Some(with) = agent
|
||||
.target
|
||||
.as_ref()
|
||||
@ -443,12 +444,14 @@ pub fn handle_inbox_update_pending_trade(bdata: &mut BehaviorData) -> bool {
|
||||
event_emitter.emit(ServerEvent::Chat(UnresolvedChatMsg::npc_tell(
|
||||
*agent_data.uid,
|
||||
*with,
|
||||
msg,
|
||||
// TODO: localise this
|
||||
Content::Plain(text),
|
||||
)));
|
||||
} else {
|
||||
event_emitter.emit(ServerEvent::Chat(UnresolvedChatMsg::npc_say(
|
||||
*agent_data.uid,
|
||||
msg,
|
||||
// TODO: localise this
|
||||
Content::Plain(text),
|
||||
)));
|
||||
}
|
||||
};
|
||||
|
@ -11,7 +11,7 @@ use crate::{
|
||||
EditableSettings,
|
||||
};
|
||||
use common::{
|
||||
comp::{Admin, AdminRole, ChatType, Player, Presence, UnresolvedChatMsg, Waypoint},
|
||||
comp::{Admin, AdminRole, ChatType, Player, Presence, Waypoint},
|
||||
event::{EventBus, ServerEvent},
|
||||
resources::Time,
|
||||
terrain::TerrainChunkSize,
|
||||
@ -48,7 +48,7 @@ impl Sys {
|
||||
if !editable_settings.server_description.is_empty() {
|
||||
client.send(ServerGeneral::server_msg(
|
||||
ChatType::CommandInfo,
|
||||
&*editable_settings.server_description,
|
||||
editable_settings.server_description.as_str(),
|
||||
))?;
|
||||
}
|
||||
|
||||
@ -62,10 +62,9 @@ impl Sys {
|
||||
|
||||
if !client.login_msg_sent.load(Ordering::Relaxed) {
|
||||
if let Some(player_uid) = uids.get(entity) {
|
||||
server_emitter.emit(ServerEvent::Chat(UnresolvedChatMsg {
|
||||
chat_type: ChatType::Online(*player_uid),
|
||||
message: "".to_string(),
|
||||
}));
|
||||
server_emitter.emit(ServerEvent::Chat(
|
||||
ChatType::Online(*player_uid).into_plain_msg(""),
|
||||
));
|
||||
|
||||
client.login_msg_sent.store(true, Ordering::Relaxed);
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ impl Sys {
|
||||
const CHAT_MODE_DEFAULT: &ChatMode = &ChatMode::default();
|
||||
let mode = chat_modes.get(entity).unwrap_or(CHAT_MODE_DEFAULT);
|
||||
// Send chat message
|
||||
server_emitter.emit(ServerEvent::Chat(mode.new_message(*from, message)));
|
||||
server_emitter.emit(ServerEvent::Chat(mode.to_plain_msg(*from, message)));
|
||||
} else {
|
||||
error!("Could not send message. Missing player uid");
|
||||
}
|
||||
|
@ -11,3 +11,4 @@ common = {package = "veloren-common", path = "../../common"}
|
||||
i18n = {package = "veloren-client-i18n", path = "../../client/i18n"}
|
||||
# Utility
|
||||
tracing = "0.1"
|
||||
hashbrown = { version = "0.12" }
|
||||
|
@ -1,19 +1,32 @@
|
||||
#![feature(let_chains)]
|
||||
use common::comp::{
|
||||
chat::{KillSource, KillType},
|
||||
BuffKind, ChatMsg, ChatType,
|
||||
BuffKind, ChatMsg, ChatType, Content,
|
||||
};
|
||||
use common_net::msg::{ChatTypeContext, PlayerInfo};
|
||||
use hashbrown::HashMap;
|
||||
use i18n::Localization;
|
||||
|
||||
pub fn make_localizer(
|
||||
localisation: &Localization,
|
||||
) -> impl Fn(&str, u16, &HashMap<String, String>) -> String + Copy + '_ {
|
||||
move |key: &str, seed: u16, args: &HashMap<String, String>| {
|
||||
localisation
|
||||
.get_variation_ctx(key, seed, &args.iter().collect())
|
||||
.into_owned()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn localize_chat_message(
|
||||
mut msg: ChatMsg,
|
||||
msg: ChatMsg,
|
||||
lookup_fn: impl Fn(&ChatMsg) -> ChatTypeContext,
|
||||
localisation: &Localization,
|
||||
show_char_name: bool,
|
||||
) -> ChatMsg {
|
||||
) -> (ChatType<String>, String) {
|
||||
let info = lookup_fn(&msg);
|
||||
|
||||
let localizer = make_localizer(localisation);
|
||||
|
||||
let name_format = |uid: &common::uid::Uid| match info.player_alias.get(uid).cloned() {
|
||||
Some(pi) => insert_alias(info.you == *uid, pi, localisation),
|
||||
None => info
|
||||
@ -23,13 +36,14 @@ pub fn localize_chat_message(
|
||||
.expect("client didn't proved enough info"),
|
||||
};
|
||||
|
||||
let message_format = |from: &common::uid::Uid, message: &str, group: Option<&String>| {
|
||||
let message_format = |from: &common::uid::Uid, content: &Content, group: Option<&String>| {
|
||||
let alias = name_format(from);
|
||||
let name = if let Some(pi) = info.player_alias.get(from).cloned() && show_char_name {
|
||||
pi.character.map(|c| c.name)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let message = content.localize(localizer);
|
||||
match (group, name) {
|
||||
(Some(group), None) => format!("({group}) [{alias}]: {message}"),
|
||||
(None, None) => format!("[{alias}]: {message}"),
|
||||
@ -50,40 +64,40 @@ pub fn localize_chat_message(
|
||||
),
|
||||
})
|
||||
.into_owned(),
|
||||
ChatType::CommandError => msg.message.to_string(),
|
||||
ChatType::CommandInfo => msg.message.to_string(),
|
||||
ChatType::FactionMeta(_) => msg.message.to_string(),
|
||||
ChatType::GroupMeta(_) => msg.message.to_string(),
|
||||
ChatType::CommandError => msg.content().localize(localizer),
|
||||
ChatType::CommandInfo => msg.content().localize(localizer),
|
||||
ChatType::FactionMeta(_) => msg.content().localize(localizer),
|
||||
ChatType::GroupMeta(_) => msg.content().localize(localizer),
|
||||
ChatType::Tell(from, to) => {
|
||||
let from_alias = name_format(from);
|
||||
let to_alias = name_format(to);
|
||||
// TODO: internationalise
|
||||
if *from == info.you {
|
||||
format!("To [{to_alias}]: {}", msg.message)
|
||||
format!("To [{to_alias}]: {}", msg.content().localize(localizer))
|
||||
} else {
|
||||
format!("From [{from_alias}]: {}", msg.message)
|
||||
format!("From [{from_alias}]: {}", msg.content().localize(localizer))
|
||||
}
|
||||
},
|
||||
ChatType::Say(uid) => message_format(uid, &msg.message, None),
|
||||
ChatType::Group(uid, s) => message_format(uid, &msg.message, Some(s)),
|
||||
ChatType::Faction(uid, s) => message_format(uid, &msg.message, Some(s)),
|
||||
ChatType::Region(uid) => message_format(uid, &msg.message, None),
|
||||
ChatType::World(uid) => message_format(uid, &msg.message, None),
|
||||
ChatType::Say(uid) => message_format(uid, msg.content(), None),
|
||||
ChatType::Group(uid, s) => message_format(uid, msg.content(), Some(s)),
|
||||
ChatType::Faction(uid, s) => message_format(uid, msg.content(), Some(s)),
|
||||
ChatType::Region(uid) => message_format(uid, msg.content(), None),
|
||||
ChatType::World(uid) => message_format(uid, msg.content(), None),
|
||||
// NPCs can't talk. Should be filtered by hud/mod.rs for voxygen and
|
||||
// should be filtered by server (due to not having a Pos) for chat-cli
|
||||
ChatType::Npc(uid, _r) => message_format(uid, &msg.message, None),
|
||||
ChatType::NpcSay(uid, _r) => message_format(uid, &msg.message, None),
|
||||
ChatType::NpcTell(from, to, _r) => {
|
||||
ChatType::Npc(uid) => message_format(uid, msg.content(), None),
|
||||
ChatType::NpcSay(uid) => message_format(uid, msg.content(), None),
|
||||
ChatType::NpcTell(from, to) => {
|
||||
let from_alias = name_format(from);
|
||||
let to_alias = name_format(to);
|
||||
// TODO: internationalise
|
||||
if *from == info.you {
|
||||
format!("To [{to_alias}]: {}", msg.message)
|
||||
format!("To [{to_alias}]: {}", msg.content().localize(localizer))
|
||||
} else {
|
||||
format!("From [{from_alias}]: {}", msg.message)
|
||||
format!("From [{from_alias}]: {}", msg.content().localize(localizer))
|
||||
}
|
||||
},
|
||||
ChatType::Meta => msg.message.to_string(),
|
||||
ChatType::Meta => msg.content().localize(localizer),
|
||||
ChatType::Kill(kill_source, victim) => {
|
||||
let i18n_buff = |buff| match buff {
|
||||
BuffKind::Burning => "hud-outcome-burning",
|
||||
@ -209,8 +223,7 @@ pub fn localize_chat_message(
|
||||
},
|
||||
};
|
||||
|
||||
msg.message = new_msg;
|
||||
msg
|
||||
(msg.chat_type, new_msg)
|
||||
}
|
||||
|
||||
fn insert_alias(you: bool, info: PlayerInfo, localisation: &Localization) -> String {
|
||||
|
@ -226,8 +226,8 @@ impl<'a> Widget for Chat<'a> {
|
||||
for message in self.new_messages.iter() {
|
||||
// Log the output of commands since the ingame terminal doesn't support copying
|
||||
// the output to the clipboard
|
||||
if let ChatType::CommandInfo = message.chat_type {
|
||||
tracing::info!("Chat command info: {}", message.message);
|
||||
if let ChatType::CommandInfo = &message.chat_type {
|
||||
tracing::info!("Chat command info: {:?}", message.content());
|
||||
}
|
||||
}
|
||||
//new messages - update chat w/ them & scroll down if at bottom of chat
|
||||
@ -426,14 +426,6 @@ impl<'a> Widget for Chat<'a> {
|
||||
let messages = &state
|
||||
.messages
|
||||
.iter()
|
||||
.map(|m| {
|
||||
localize_chat_message(
|
||||
m.clone(),
|
||||
|msg| self.client.lookup_msg_context(msg),
|
||||
self.localized_strings,
|
||||
show_char_name,
|
||||
)
|
||||
})
|
||||
.filter(|m| {
|
||||
if let Some(chat_tab) = current_chat_tab {
|
||||
chat_tab.filter.satisfies(m, &group_members)
|
||||
@ -447,13 +439,19 @@ impl<'a> Widget for Chat<'a> {
|
||||
.uid()
|
||||
.and_then(|uid| {
|
||||
self.client
|
||||
.lookup_msg_context(&m)
|
||||
.lookup_msg_context(m)
|
||||
.player_alias
|
||||
.get(&uid)
|
||||
.map(|i| i.is_moderator)
|
||||
})
|
||||
.unwrap_or(false);
|
||||
(is_moderator, m)
|
||||
let (chat_type, text) = localize_chat_message(
|
||||
m.clone(),
|
||||
|msg| self.client.lookup_msg_context(msg),
|
||||
self.localized_strings,
|
||||
show_char_name,
|
||||
);
|
||||
(is_moderator, chat_type, text)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let n_badges = messages.iter().filter(|t| t.0).count();
|
||||
@ -478,14 +476,14 @@ impl<'a> Widget for Chat<'a> {
|
||||
while let Some(item) = items.next(ui) {
|
||||
// This would be easier if conrod used the v-metrics from rusttype.
|
||||
if item.i < messages.len() {
|
||||
let (is_moderator, message) = &messages[item.i];
|
||||
let (color, icon) = render_chat_line(&message.chat_type, self.imgs);
|
||||
let (is_moderator, chat_type, text) = &messages[item.i];
|
||||
let (color, icon) = render_chat_line(chat_type, self.imgs);
|
||||
// For each ChatType needing localization get/set matching pre-formatted
|
||||
// localized string. This string will be formatted with the data
|
||||
// provided in ChatType in the client/src/mod.rs
|
||||
// fn format_message called below
|
||||
|
||||
let text = Text::new(&message.message)
|
||||
let text = Text::new(text)
|
||||
.font_size(self.fonts.opensans.scale(15))
|
||||
.font_id(self.fonts.opensans.conrod_id)
|
||||
.w(CHAT_BOX_WIDTH - 17.0)
|
||||
@ -688,10 +686,10 @@ impl<'a> Widget for Chat<'a> {
|
||||
if let Some(msg) = msg.strip_prefix(chat_settings.chat_cmd_prefix) {
|
||||
match parse_cmd(msg) {
|
||||
Ok((name, args)) => events.push(Event::SendCommand(name, args)),
|
||||
Err(err) => self.new_messages.push_back(ChatMsg {
|
||||
chat_type: ChatType::CommandError,
|
||||
message: err,
|
||||
}),
|
||||
// TODO: Localise
|
||||
Err(err) => self
|
||||
.new_messages
|
||||
.push_back(ChatType::CommandError.into_plain_msg(err)),
|
||||
}
|
||||
} else {
|
||||
events.push(Event::SendMessage(msg));
|
||||
@ -783,9 +781,9 @@ fn render_chat_line(chat_type: &ChatType<String>, imgs: &Imgs) -> (Color, conrod
|
||||
ChatType::Faction(_uid, _s) => (FACTION_COLOR, imgs.chat_faction_small),
|
||||
ChatType::Region(_uid) => (REGION_COLOR, imgs.chat_region_small),
|
||||
ChatType::World(_uid) => (WORLD_COLOR, imgs.chat_world_small),
|
||||
ChatType::Npc(_uid, _r) => panic!("NPCs can't talk!"), // Should be filtered by hud/mod.rs
|
||||
ChatType::NpcSay(_uid, _r) => (SAY_COLOR, imgs.chat_say_small),
|
||||
ChatType::NpcTell(_from, _to, _r) => (TELL_COLOR, imgs.chat_tell_small),
|
||||
ChatType::Npc(_uid) => panic!("NPCs can't talk!"), // Should be filtered by hud/mod.rs
|
||||
ChatType::NpcSay(_uid) => (SAY_COLOR, imgs.chat_say_small),
|
||||
ChatType::NpcTell(_from, _to) => (TELL_COLOR, imgs.chat_tell_small),
|
||||
ChatType::Meta => (INFO_COLOR, imgs.chat_command_info_small),
|
||||
}
|
||||
}
|
||||
|
@ -3278,7 +3278,7 @@ impl Hud {
|
||||
|
||||
// Don't put NPC messages in chat box.
|
||||
self.new_messages
|
||||
.retain(|m| !matches!(m.chat_type, comp::ChatType::Npc(_, _)));
|
||||
.retain(|m| !matches!(m.chat_type, comp::ChatType::Npc(_)));
|
||||
|
||||
// Chat box
|
||||
if global_state.settings.interface.toggle_chat {
|
||||
|
@ -20,6 +20,7 @@ use conrod_core::{
|
||||
widget_ids, Color, Colorable, Positionable, Sizeable, Widget, WidgetCommon,
|
||||
};
|
||||
use i18n::Localization;
|
||||
use i18n_helpers::make_localizer;
|
||||
use keyboard_keynames::key_layout::KeyLayout;
|
||||
|
||||
const MAX_BUBBLE_WIDTH: f64 = 250.0;
|
||||
@ -534,8 +535,7 @@ impl<'a> Widget for Overhead<'a> {
|
||||
// Speech bubble
|
||||
if let Some(bubble) = self.bubble {
|
||||
let dark_mode = self.settings.speech_bubble_dark_mode;
|
||||
let localizer = |s: &str, i| -> String { self.i18n.get_variation(s, i).to_string() };
|
||||
let bubble_contents: String = bubble.message(localizer);
|
||||
let bubble_contents: String = bubble.content().localize(make_localizer(self.i18n));
|
||||
let (text_color, shadow_color) = bubble_color(bubble, dark_mode);
|
||||
let mut text = Text::new(&bubble_contents)
|
||||
.color(text_color)
|
||||
|
@ -18,7 +18,7 @@ use common::{
|
||||
inventory::slot::{EquipSlot, Slot},
|
||||
invite::InviteKind,
|
||||
item::{tool::ToolKind, ItemDesc},
|
||||
ChatMsg, ChatType, InputKind, InventoryUpdateEvent, Pos, PresenceKind, Stats,
|
||||
ChatType, Content, InputKind, InventoryUpdateEvent, Pos, PresenceKind, Stats,
|
||||
UtteranceKind, Vel,
|
||||
},
|
||||
consts::MAX_MOUNT_RANGE,
|
||||
@ -309,17 +309,17 @@ impl SessionState {
|
||||
InviteAnswer::TimedOut => "timed out",
|
||||
};
|
||||
let msg = format!("{} invite to {} {}", kind_str, target_name, answer_str);
|
||||
self.hud.new_message(ChatType::Meta.chat_msg(msg));
|
||||
// TODO: Localise
|
||||
self.hud.new_message(ChatType::Meta.into_plain_msg(msg));
|
||||
},
|
||||
client::Event::TradeComplete { result, trade: _ } => {
|
||||
self.hud.clear_cursor();
|
||||
let i18n = global_state.i18n.read();
|
||||
let msg = match result {
|
||||
TradeResult::Completed => i18n.get_msg("hud-trade-result-completed"),
|
||||
TradeResult::Declined => i18n.get_msg("hud-trade-result-declined"),
|
||||
TradeResult::NotEnoughSpace => i18n.get_msg("hud-trade-result-nospace"),
|
||||
};
|
||||
self.hud.new_message(ChatType::Meta.chat_msg(msg));
|
||||
self.hud
|
||||
.new_message(ChatType::Meta.into_msg(Content::localized(match result {
|
||||
TradeResult::Completed => "hud-trade-result-completed",
|
||||
TradeResult::Declined => "hud-trade-result-declined",
|
||||
TradeResult::NotEnoughSpace => "hud-trade-result-nospace",
|
||||
})));
|
||||
},
|
||||
client::Event::InventoryUpdated(inv_event) => {
|
||||
let sfx_triggers = self.scene.sfx_mgr.triggers.read();
|
||||
@ -380,21 +380,13 @@ impl SessionState {
|
||||
},
|
||||
client::Event::Disconnect => return Ok(TickAction::Disconnect),
|
||||
client::Event::DisconnectionNotification(time) => {
|
||||
let i18n = global_state.i18n.read();
|
||||
|
||||
let message = match time {
|
||||
0 => String::from(i18n.get_msg("hud-chat-goodbye")),
|
||||
_ => i18n
|
||||
.get_msg_ctx("hud-chat-connection_lost", &i18n::fluent_args! {
|
||||
"time" => time
|
||||
})
|
||||
.into_owned(),
|
||||
};
|
||||
|
||||
self.hud.new_message(ChatMsg {
|
||||
chat_type: ChatType::CommandError,
|
||||
message,
|
||||
});
|
||||
self.hud
|
||||
.new_message(ChatType::CommandError.into_msg(match time {
|
||||
0 => Content::localized("hud-chat-goodbye"),
|
||||
_ => Content::localized_with_args("hud-chat-connection_lost", [(
|
||||
"time", time,
|
||||
)]),
|
||||
}));
|
||||
},
|
||||
client::Event::Kicked(reason) => {
|
||||
global_state.info_message = Some(format!(
|
||||
@ -992,18 +984,12 @@ impl PlayState for SessionState {
|
||||
|e| e.name.to_owned(),
|
||||
)
|
||||
});
|
||||
let msg = global_state
|
||||
.i18n
|
||||
.read()
|
||||
.get_msg_ctx(
|
||||
self.hud.new_message(ChatType::Meta.into_msg(
|
||||
Content::localized_with_args(
|
||||
"hud-trade-invite_sent",
|
||||
&i18n::fluent_args! {
|
||||
"playername" => &name
|
||||
},
|
||||
)
|
||||
.into_owned();
|
||||
self.hud
|
||||
.new_message(ChatType::Meta.chat_msg(msg));
|
||||
[("playername", &name)],
|
||||
),
|
||||
));
|
||||
client.send_invite(uid, InviteKind::Trade)
|
||||
};
|
||||
},
|
||||
@ -1115,10 +1101,11 @@ impl PlayState for SessionState {
|
||||
);
|
||||
},
|
||||
},
|
||||
Event::ScreenshotMessage(screenshot_message) => self.hud.new_message(ChatMsg {
|
||||
chat_type: ChatType::CommandInfo,
|
||||
message: screenshot_message,
|
||||
}),
|
||||
|
||||
// TODO: Localise
|
||||
Event::ScreenshotMessage(screenshot_msg) => self
|
||||
.hud
|
||||
.new_message(ChatType::CommandInfo.into_plain_msg(screenshot_msg)),
|
||||
|
||||
Event::Zoom(delta) if self.zoom_lock => {
|
||||
// only fire this Hud event when player has "intent" to zoom
|
||||
@ -1414,11 +1401,15 @@ impl PlayState for SessionState {
|
||||
match run_command(&mut self.client.borrow_mut(), global_state, &name, args)
|
||||
{
|
||||
Ok(Some(info)) => {
|
||||
self.hud.new_message(ChatType::CommandInfo.chat_msg(&info))
|
||||
// TODO: Localise
|
||||
self.hud
|
||||
.new_message(ChatType::CommandInfo.into_plain_msg(&info))
|
||||
},
|
||||
Ok(None) => {}, // Server will provide an info message
|
||||
Err(error) => {
|
||||
self.hud.new_message(ChatType::CommandError.chat_msg(error))
|
||||
// TODO: Localise
|
||||
self.hud
|
||||
.new_message(ChatType::CommandError.into_plain_msg(error))
|
||||
},
|
||||
};
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user