Implement MR!1043 changes suggested by Imbris

This commit is contained in:
CapsizeGlimmer 2020-06-11 01:16:42 -04:00 committed by Forest Anderson
parent 34acc4ddf3
commit b7d7696d89
11 changed files with 59 additions and 103 deletions

View File

@ -1034,7 +1034,7 @@ impl Client {
}; };
let message_format = |uid, message, group| { let message_format = |uid, message, group| {
if let Some(group) = group { if let Some(group) = group {
format!("{{{}}} [{}]: {}", group, alias_of_uid(uid), message) format!("({}) [{}]: {}", group, alias_of_uid(uid), message)
} else { } else {
format!("[{}]: {}", alias_of_uid(uid), message) format!("[{}]: {}", alias_of_uid(uid), message)
} }

View File

@ -96,10 +96,10 @@ impl ChatMsg {
pub fn to_bubble(&self) -> Option<(SpeechBubble, Uid)> { pub fn to_bubble(&self) -> Option<(SpeechBubble, Uid)> {
let icon = self.icon(); let icon = self.icon();
if let ChatType::Npc(from, r) = self.chat_type { if let ChatType::Npc(from, r) = self.chat_type {
Some((SpeechBubble::npc_new(self.message.clone(), r, icon), from)) Some((SpeechBubble::npc_new(&self.message, r, icon), from))
} else { } else {
self.uid() self.uid()
.map(|from| (SpeechBubble::player_new(self.message.clone(), icon), from)) .map(|from| (SpeechBubble::player_new(&self.message, icon), from))
} }
} }
@ -194,8 +194,8 @@ impl SpeechBubble {
/// Default duration in seconds of speech bubbles /// Default duration in seconds of speech bubbles
pub const DEFAULT_DURATION: f64 = 5.0; pub const DEFAULT_DURATION: f64 = 5.0;
pub fn npc_new(i18n_key: String, r: u16, icon: SpeechBubbleIcon) -> Self { pub fn npc_new(i18n_key: &str, r: u16, icon: SpeechBubbleIcon) -> Self {
let message = SpeechBubbleMessage::Localized(i18n_key, r); let message = SpeechBubbleMessage::Localized(i18n_key.to_string(), r);
let timeout = Instant::now() + Duration::from_secs_f64(SpeechBubble::DEFAULT_DURATION); let timeout = Instant::now() + Duration::from_secs_f64(SpeechBubble::DEFAULT_DURATION);
Self { Self {
message, message,
@ -204,8 +204,8 @@ impl SpeechBubble {
} }
} }
pub fn player_new(message: String, icon: SpeechBubbleIcon) -> Self { pub fn player_new(message: &str, icon: SpeechBubbleIcon) -> Self {
let message = SpeechBubbleMessage::Plain(message); let message = SpeechBubbleMessage::Plain(message.to_string());
let timeout = Instant::now() + Duration::from_secs_f64(SpeechBubble::DEFAULT_DURATION); let timeout = Instant::now() + Duration::from_secs_f64(SpeechBubble::DEFAULT_DURATION);
Self { Self {
message, message,
@ -216,11 +216,11 @@ impl SpeechBubble {
pub fn message<F>(&self, i18n_variation: F) -> String pub fn message<F>(&self, i18n_variation: F) -> String
where where
F: Fn(String, u16) -> String, F: Fn(&str, u16) -> String,
{ {
match &self.message { match &self.message {
SpeechBubbleMessage::Plain(m) => m.to_string(), SpeechBubbleMessage::Plain(m) => m.to_string(),
SpeechBubbleMessage::Localized(k, i) => i18n_variation(k.to_string(), *i).to_string(), SpeechBubbleMessage::Localized(k, i) => i18n_variation(&k, *i).to_string(),
} }
} }
} }

View File

@ -119,7 +119,7 @@ pub enum ServerEvent {
ClientDisconnect(EcsEntity), ClientDisconnect(EcsEntity),
ChunkRequest(EcsEntity, Vec2<i32>), ChunkRequest(EcsEntity, Vec2<i32>),
ChatCmd(EcsEntity, String), ChatCmd(EcsEntity, String),
/// Send a chat message from an npc to the player /// Send a chat message to the player from an npc or other player
Chat(comp::ChatMsg), Chat(comp::ChatMsg),
} }

View File

@ -392,12 +392,11 @@ fn handle_alias(
action: &ChatCommand, action: &ChatCommand,
) { ) {
if client != target { if client != target {
// Prevent people abusing /sudo // Notify target that an admin changed the alias due to /sudo
server.notify_client( server.notify_client(
client, target,
ServerMsg::private(String::from("Don't call people names. It's mean.")), ServerMsg::private(String::from("An admin changed your alias.")),
); );
return;
} }
if let Ok(alias) = scan_fmt!(&args, &action.arg_fmt(), String) { if let Ok(alias) = scan_fmt!(&args, &action.arg_fmt(), String) {
if !comp::Player::alias_is_valid(&alias) { if !comp::Player::alias_is_valid(&alias) {
@ -1284,7 +1283,7 @@ fn handle_join_group(
// TODO notify group // TODO notify group
server.notify_client( server.notify_client(
client, client,
ServerMsg::private(format!("Joined group {{{}}}", group)), ServerMsg::private(format!("Joined group ({})", group)),
); );
} else { } else {
let mode = comp::ChatMode::default(); let mode = comp::ChatMode::default();
@ -1293,7 +1292,7 @@ fn handle_join_group(
// TODO notify group // TODO notify group
server.notify_client( server.notify_client(
client, client,
ServerMsg::private(format!("Left group {{{}}}", group)), ServerMsg::private(format!("Left group ({})", group)),
); );
} }
} }

View File

@ -115,7 +115,6 @@ impl Server {
state.ecs_mut().insert(sys::TerrainTimer::default()); state.ecs_mut().insert(sys::TerrainTimer::default());
state.ecs_mut().insert(sys::WaypointTimer::default()); state.ecs_mut().insert(sys::WaypointTimer::default());
state.ecs_mut().insert(sys::PersistenceTimer::default()); state.ecs_mut().insert(sys::PersistenceTimer::default());
//state.ecs_mut().insert(sys::StatsPersistenceTimer::default());
// System schedulers to control execution of systems // System schedulers to control execution of systems
state state

View File

@ -244,13 +244,8 @@ impl StateExt for State {
/// by location. Faction and group are limited by component. /// by location. Faction and group are limited by component.
fn send_chat(&self, msg: comp::ChatMsg) { fn send_chat(&self, msg: comp::ChatMsg) {
let ecs = self.ecs(); let ecs = self.ecs();
let is_within = |target, a: &comp::Pos, b_opt: Option<&comp::Pos>| { let is_within =
if let Some(b) = b_opt { |target, a: &comp::Pos, b: &comp::Pos| a.0.distance_squared(b.0) < target * target;
a.0.distance(b.0) < target
} else {
false
}
};
match &msg.chat_type { match &msg.chat_type {
comp::ChatType::Broadcast comp::ChatType::Broadcast
| comp::ChatType::Kill | comp::ChatType::Kill
@ -271,56 +266,41 @@ impl StateExt for State {
} }
}, },
comp::ChatType::Say(_u) => { comp::ChatType::Say(uid) => {
for (client, pos) in ( let entity_opt =
&mut ecs.write_storage::<Client>(), (*ecs.read_resource::<UidAllocator>()).retrieve_entity_internal(uid.0);
&ecs.read_storage::<comp::Pos>(),
)
.join()
{
let entity_opt = msg.uid().and_then(|uid| {
(*ecs.read_resource::<UidAllocator>()).retrieve_entity_internal(uid.0)
});
let positions = ecs.read_storage::<comp::Pos>(); let positions = ecs.read_storage::<comp::Pos>();
let pos_opt = entity_opt.and_then(|e| positions.get(e)); if let Some(speaker_pos) = entity_opt.and_then(|e| positions.get(e)) {
if is_within(comp::ChatMsg::SAY_DISTANCE, pos, pos_opt) { for (client, pos) in (&mut ecs.write_storage::<Client>(), &positions).join() {
if is_within(comp::ChatMsg::SAY_DISTANCE, pos, speaker_pos) {
client.notify(ServerMsg::ChatMsg(msg.clone())); client.notify(ServerMsg::ChatMsg(msg.clone()));
} }
} }
}
}, },
comp::ChatType::Region(_u) => { comp::ChatType::Region(uid) => {
for (client, pos) in ( let entity_opt =
&mut ecs.write_storage::<Client>(), (*ecs.read_resource::<UidAllocator>()).retrieve_entity_internal(uid.0);
&ecs.read_storage::<comp::Pos>(),
)
.join()
{
let entity_opt = msg.uid().and_then(|uid| {
(*ecs.read_resource::<UidAllocator>()).retrieve_entity_internal(uid.0)
});
let positions = ecs.read_storage::<comp::Pos>(); let positions = ecs.read_storage::<comp::Pos>();
let pos_opt = entity_opt.and_then(|e| positions.get(e)); if let Some(speaker_pos) = entity_opt.and_then(|e| positions.get(e)) {
if is_within(comp::ChatMsg::REGION_DISTANCE, pos, pos_opt) { for (client, pos) in (&mut ecs.write_storage::<Client>(), &positions).join() {
if is_within(comp::ChatMsg::REGION_DISTANCE, pos, speaker_pos) {
client.notify(ServerMsg::ChatMsg(msg.clone())); client.notify(ServerMsg::ChatMsg(msg.clone()));
} }
} }
}
}, },
comp::ChatType::Npc(_u, _r) => { comp::ChatType::Npc(uid, _r) => {
for (client, pos) in ( let entity_opt =
&mut ecs.write_storage::<Client>(), (*ecs.read_resource::<UidAllocator>()).retrieve_entity_internal(uid.0);
&ecs.read_storage::<comp::Pos>(),
)
.join()
{
let entity_opt = msg.uid().and_then(|uid| {
(*ecs.read_resource::<UidAllocator>()).retrieve_entity_internal(uid.0)
});
let positions = ecs.read_storage::<comp::Pos>(); let positions = ecs.read_storage::<comp::Pos>();
let pos_opt = entity_opt.and_then(|e| positions.get(e)); if let Some(speaker_pos) = entity_opt.and_then(|e| positions.get(e)) {
if is_within(comp::ChatMsg::NPC_DISTANCE, pos, pos_opt) { for (client, pos) in (&mut ecs.write_storage::<Client>(), &positions).join() {
if is_within(comp::ChatMsg::NPC_DISTANCE, pos, speaker_pos) {
client.notify(ServerMsg::ChatMsg(msg.clone())); client.notify(ServerMsg::ChatMsg(msg.clone()));
} }
} }
}
}, },
comp::ChatType::Faction(_u, s) => { comp::ChatType::Faction(_u, s) => {

View File

@ -337,10 +337,7 @@ impl<'a> System<'a> for Sys {
| ClientState::Character => match validate_chat_msg(&message) { | ClientState::Character => match validate_chat_msg(&message) {
Ok(()) => { Ok(()) => {
if let Some(from) = uids.get(entity) { if let Some(from) = uids.get(entity) {
let mode = chat_modes let mode = chat_modes.get(entity).cloned().unwrap_or_default();
.get(entity)
.map(Clone::clone)
.unwrap_or(ChatMode::default());
let msg = mode.new_message(*from, message); let msg = mode.new_message(*from, message);
new_chat_msgs.push((Some(entity), msg)); new_chat_msgs.push((Some(entity), msg));
} else { } else {

View File

@ -22,8 +22,6 @@ pub type TerrainSyncTimer = SysTimer<terrain_sync::Sys>;
pub type WaypointTimer = SysTimer<waypoint::Sys>; pub type WaypointTimer = SysTimer<waypoint::Sys>;
pub type PersistenceTimer = SysTimer<persistence::Sys>; pub type PersistenceTimer = SysTimer<persistence::Sys>;
pub type PersistenceScheduler = SysScheduler<persistence::Sys>; pub type PersistenceScheduler = SysScheduler<persistence::Sys>;
//pub type StatsPersistenceTimer = SysTimer<persistence::stats::Sys>;
//pub type StatsPersistenceScheduler = SysScheduler<persistence::stats::Sys>;
// System names // System names
// Note: commented names may be useful in the future // Note: commented names may be useful in the future
@ -34,14 +32,11 @@ pub type PersistenceScheduler = SysScheduler<persistence::Sys>;
const TERRAIN_SYS: &str = "server_terrain_sys"; const TERRAIN_SYS: &str = "server_terrain_sys";
const WAYPOINT_SYS: &str = "waypoint_sys"; const WAYPOINT_SYS: &str = "waypoint_sys";
const PERSISTENCE_SYS: &str = "persistence_sys"; const PERSISTENCE_SYS: &str = "persistence_sys";
//const STATS_PERSISTENCE_SYS: &str = "stats_persistence_sys";
pub fn add_server_systems(dispatch_builder: &mut DispatcherBuilder) { pub fn add_server_systems(dispatch_builder: &mut DispatcherBuilder) {
dispatch_builder.add(terrain::Sys, TERRAIN_SYS, &[]); dispatch_builder.add(terrain::Sys, TERRAIN_SYS, &[]);
dispatch_builder.add(waypoint::Sys, WAYPOINT_SYS, &[]); dispatch_builder.add(waypoint::Sys, WAYPOINT_SYS, &[]);
dispatch_builder.add(persistence::Sys, PERSISTENCE_SYS, &[]); dispatch_builder.add(persistence::Sys, PERSISTENCE_SYS, &[]);
//dispatch_builder.add(persistence::stats::Sys, STATS_PERSISTENCE_SYS,
// &[]);
} }
pub fn run_sync_systems(ecs: &mut specs::World) { pub fn run_sync_systems(ecs: &mut specs::World) {

View File

@ -163,17 +163,7 @@ impl<'a> Widget for Chat<'a> {
let transp = self.global_state.settings.gameplay.chat_transp; let transp = self.global_state.settings.gameplay.chat_transp;
// Maintain scrolling. // Maintain scrolling.
if !self.new_messages.is_empty() { if !self.new_messages.is_empty() {
state.update(|s| { state.update(|s| s.messages.extend(self.new_messages.drain(..)));
s.messages.extend(
self.new_messages
.drain(..)
.map(|msg| {
// TODO format!([{}] {}, name, msg)
msg
})
.collect::<Vec<_>>(),
)
});
ui.scroll_widget(state.ids.message_box, [0.0, std::f64::MAX]); ui.scroll_widget(state.ids.message_box, [0.0, std::f64::MAX]);
} }
@ -354,8 +344,7 @@ impl<'a> Widget for Chat<'a> {
Dimension::Absolute(y) => y + 2.0, Dimension::Absolute(y) => y + 2.0,
_ => 0.0, _ => 0.0,
}; };
let widget = text.h(y); item.set(text.h(y), ui);
item.set(widget, ui);
let icon_id = state.ids.chat_icons[item.i]; let icon_id = state.ids.chat_icons[item.i];
Image::new(icon) Image::new(icon)
.w_h(16.0, 16.0) .w_h(16.0, 16.0)
@ -365,11 +354,13 @@ impl<'a> Widget for Chat<'a> {
} 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.
let widget = Text::new("") item.set(
Text::new("")
.font_size(self.fonts.opensans.scale(6)) .font_size(self.fonts.opensans.scale(6))
.font_id(self.fonts.opensans.conrod_id) .font_id(self.fonts.opensans.conrod_id)
.w(CHAT_BOX_WIDTH); .w(CHAT_BOX_WIDTH),
item.set(widget, ui); ui,
);
}; };
} }
@ -432,7 +423,6 @@ fn do_tab_completion(cursor: usize, input: &str, word: &str) -> (String, usize)
if char_i < cursor { if char_i < cursor {
pre_ws = Some(byte_i); pre_ws = Some(byte_i);
} else { } else {
assert_eq!(post_ws, None); // TODO debug
post_ws = Some(byte_i); post_ws = Some(byte_i);
break; break;
} }

View File

@ -940,8 +940,9 @@ impl Hud {
} }
// Pop speech bubbles // Pop speech bubbles
let now = Instant::now();
self.speech_bubbles self.speech_bubbles
.retain(|_uid, bubble| bubble.timeout > Instant::now()); .retain(|_uid, bubble| bubble.timeout > now);
// Push speech bubbles // Push speech bubbles
for msg in self.new_messages.iter() { for msg in self.new_messages.iter() {
@ -1570,13 +1571,8 @@ impl Hud {
} }
// Don't put NPC messages in chat box. // Don't put NPC messages in chat box.
self.new_messages.retain(|m| { self.new_messages
if let comp::ChatType::Npc(_, _) = m.chat_type { .retain(|m| !matches!(m.chat_type, comp::ChatType::Npc(_, _)));
false
} else {
true
}
});
// Chat box // Chat box
match Chat::new( match Chat::new(

View File

@ -148,7 +148,7 @@ impl<'a> Widget for Overhead<'a> {
if let Some(bubble) = self.bubble { if let Some(bubble) = self.bubble {
let dark_mode = self.settings.speech_bubble_dark_mode; let dark_mode = self.settings.speech_bubble_dark_mode;
let localizer = let localizer =
|s: String, i| -> String { self.voxygen_i18n.get_variation(&s, i).to_string() }; |s: &str, i| -> String { self.voxygen_i18n.get_variation(&s, i).to_string() };
let bubble_contents: String = bubble.message(localizer); let bubble_contents: String = bubble.message(localizer);
let mut text = Text::new(&bubble_contents) let mut text = Text::new(&bubble_contents)