mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Move message processing and chat bubbles to the client
This commit is contained in:

committed by
Forest Anderson
parent
0b2a3ebe8b
commit
289ef5d6b2
@ -802,7 +802,11 @@ impl Client {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ServerMsg::PlayerListUpdate(PlayerListUpdate::Remove(uid)) => {
|
ServerMsg::PlayerListUpdate(PlayerListUpdate::Remove(_uid)) => {
|
||||||
|
// Don't remove players because we need to remember the
|
||||||
|
// names of disconnected players in chat.
|
||||||
|
|
||||||
|
/*
|
||||||
if self.player_list.remove(&uid).is_none() {
|
if self.player_list.remove(&uid).is_none() {
|
||||||
warn!(
|
warn!(
|
||||||
"Received msg to remove uid {} from the player list by they \
|
"Received msg to remove uid {} from the player list by they \
|
||||||
@ -810,6 +814,7 @@ impl Client {
|
|||||||
uid
|
uid
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
},
|
},
|
||||||
ServerMsg::PlayerListUpdate(PlayerListUpdate::Alias(uid, new_name)) => {
|
ServerMsg::PlayerListUpdate(PlayerListUpdate::Alias(uid, new_name)) => {
|
||||||
if let Some(player_info) = self.player_list.get_mut(&uid) {
|
if let Some(player_info) = self.player_list.get_mut(&uid) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::{path::Chaser, state::Time};
|
use crate::path::Chaser;
|
||||||
use specs::{Component, Entity as EcsEntity, FlaggedStorage, HashMapStorage};
|
use specs::{Component, Entity as EcsEntity};
|
||||||
use specs_idvs::IDVStorage;
|
use specs_idvs::IDVStorage;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use crate::sync::Uid;
|
use crate::sync::Uid;
|
||||||
use specs::Component;
|
use specs::Component;
|
||||||
use specs_idvs::IDVStorage;
|
use specs_idvs::IDVStorage;
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
/// A player's current chat mode.
|
/// A player's current chat mode.
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
@ -18,10 +19,26 @@ pub enum ChatMode {
|
|||||||
/// Talk to every player on the server
|
/// Talk to every player on the server
|
||||||
World,
|
World,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for ChatMode {
|
impl Component for ChatMode {
|
||||||
type Storage = IDVStorage<Self>;
|
type Storage = IDVStorage<Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ChatMode {
|
||||||
|
/// Create a message from your current chat mode and uuid.
|
||||||
|
pub fn msg_from(&self, from: Uid, message: String) -> ChatMsg {
|
||||||
|
let chat_type = match self {
|
||||||
|
ChatMode::Tell(to) => ChatType::Tell(from, *to),
|
||||||
|
ChatMode::Say => ChatType::Say(from),
|
||||||
|
ChatMode::Region => ChatType::Region(from),
|
||||||
|
ChatMode::Group => ChatType::Group(from),
|
||||||
|
ChatMode::Faction => ChatType::Faction(from),
|
||||||
|
ChatMode::World => ChatType::World(from),
|
||||||
|
};
|
||||||
|
ChatMsg { chat_type, message }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// List of chat types. Note that this is a superset of `ChatMode`; this is
|
/// List of chat types. Note that this is a superset of `ChatMode`; this is
|
||||||
/// because `ChatType::Kill`, `ChatType::Broadcast`, and `ChatType::Private`
|
/// because `ChatType::Kill`, `ChatType::Broadcast`, and `ChatType::Private`
|
||||||
/// cannot be sent by players.
|
/// cannot be sent by players.
|
||||||
@ -45,6 +62,10 @@ pub enum ChatType {
|
|||||||
Region(Uid),
|
Region(Uid),
|
||||||
/// World chat
|
/// World chat
|
||||||
World(Uid),
|
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),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
@ -53,18 +74,32 @@ pub struct ChatMsg {
|
|||||||
pub message: String,
|
pub message: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChatMode {
|
impl ChatMsg {
|
||||||
/// Create a message from your current chat mode and uuid.
|
pub fn npc(uid: Uid, message: String) -> Self {
|
||||||
pub fn msg_from(&self, from: Uid, message: String) -> ChatMsg {
|
let chat_type = ChatType::Npc(uid, rand::random());
|
||||||
let chat_type = match self {
|
Self { chat_type, message }
|
||||||
ChatMode::Tell(to) => ChatType::Tell(from, *to),
|
}
|
||||||
ChatMode::Say => ChatType::Say(from),
|
|
||||||
ChatMode::Region => ChatType::Region(from),
|
pub fn to_bubble(&self) -> Option<(SpeechBubble, Uid)> {
|
||||||
ChatMode::Group => ChatType::Group(from),
|
let tuple = match self.chat_type {
|
||||||
ChatMode::Faction => ChatType::Faction(from),
|
ChatType::Broadcast => None,
|
||||||
ChatMode::World => ChatType::World(from),
|
ChatType::Private => None,
|
||||||
|
ChatType::Kill => None,
|
||||||
|
ChatType::Tell(u, _) => Some((SpeechBubbleIcon::Tell, u, None)),
|
||||||
|
ChatType::Say(u) => Some((SpeechBubbleIcon::Say, u, None)),
|
||||||
|
ChatType::Group(u) => Some((SpeechBubbleIcon::Group, u, None)),
|
||||||
|
ChatType::Faction(u) => Some((SpeechBubbleIcon::Faction, u, None)),
|
||||||
|
ChatType::Region(u) => Some((SpeechBubbleIcon::Region, u, None)),
|
||||||
|
ChatType::World(u) => Some((SpeechBubbleIcon::World, u, None)),
|
||||||
|
ChatType::Npc(u, r) => Some((SpeechBubbleIcon::None, u, Some(r))),
|
||||||
};
|
};
|
||||||
ChatMsg { chat_type, message }
|
tuple.map(|(icon, from, npc_rand)| {
|
||||||
|
if let Some(r) = npc_rand {
|
||||||
|
(SpeechBubble::npc_new(self.message.clone(), r, icon), from)
|
||||||
|
} else {
|
||||||
|
(SpeechBubble::player_new(self.message.clone(), icon), from)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,3 +120,68 @@ pub struct Faction(String);
|
|||||||
impl Component for Faction {
|
impl Component for Faction {
|
||||||
type Storage = IDVStorage<Self>;
|
type Storage = IDVStorage<Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum SpeechBubbleIcon {
|
||||||
|
// One for each chat mode
|
||||||
|
Tell,
|
||||||
|
Say,
|
||||||
|
Region,
|
||||||
|
Group,
|
||||||
|
Faction,
|
||||||
|
World,
|
||||||
|
// For NPCs
|
||||||
|
Quest, // TODO not implemented
|
||||||
|
Trade, // TODO not implemented
|
||||||
|
None, // No icon (default for npcs)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds a speech bubble above the character
|
||||||
|
pub struct SpeechBubble {
|
||||||
|
pub message: SpeechBubbleMessage,
|
||||||
|
pub icon: SpeechBubbleIcon,
|
||||||
|
pub timeout: Instant,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SpeechBubble {
|
||||||
|
/// Default duration in seconds of speech bubbles
|
||||||
|
pub const DEFAULT_DURATION: f64 = 5.0;
|
||||||
|
|
||||||
|
pub fn npc_new(i18n_key: String, r: u16, icon: SpeechBubbleIcon) -> Self {
|
||||||
|
let message = SpeechBubbleMessage::Localized(i18n_key, r);
|
||||||
|
let timeout = Instant::now() + Duration::from_secs_f64(SpeechBubble::DEFAULT_DURATION);
|
||||||
|
Self {
|
||||||
|
message,
|
||||||
|
timeout,
|
||||||
|
icon,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn player_new(message: String, icon: SpeechBubbleIcon) -> Self {
|
||||||
|
let message = SpeechBubbleMessage::Plain(message);
|
||||||
|
let timeout = Instant::now() + Duration::from_secs_f64(SpeechBubble::DEFAULT_DURATION);
|
||||||
|
Self {
|
||||||
|
message,
|
||||||
|
timeout,
|
||||||
|
icon,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn message<F>(&self, i18n_variation: F) -> String
|
||||||
|
where
|
||||||
|
F: Fn(String, u16) -> String,
|
||||||
|
{
|
||||||
|
match &self.message {
|
||||||
|
SpeechBubbleMessage::Plain(m) => m.to_string(),
|
||||||
|
SpeechBubbleMessage::Localized(k, i) => i18n_variation(k.to_string(), *i).to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -19,13 +19,13 @@ mod visual;
|
|||||||
// Reexports
|
// Reexports
|
||||||
pub use ability::{CharacterAbility, CharacterAbilityType, ItemConfig, Loadout};
|
pub use ability::{CharacterAbility, CharacterAbilityType, ItemConfig, Loadout};
|
||||||
pub use admin::Admin;
|
pub use admin::Admin;
|
||||||
pub use agent::{Agent, Alignment, SpeechBubble, SPEECH_BUBBLE_DURATION};
|
pub use agent::{Agent, Alignment};
|
||||||
pub use body::{
|
pub use body::{
|
||||||
biped_large, bird_medium, bird_small, critter, dragon, fish_medium, fish_small, golem,
|
biped_large, bird_medium, bird_small, critter, dragon, fish_medium, fish_small, golem,
|
||||||
humanoid, object, quadruped_medium, quadruped_small, AllBodies, Body, BodyData,
|
humanoid, object, quadruped_medium, quadruped_small, AllBodies, Body, BodyData,
|
||||||
};
|
};
|
||||||
pub use character_state::{Attacking, CharacterState, StateUpdate};
|
pub use character_state::{Attacking, CharacterState, StateUpdate};
|
||||||
pub use chat::{ChatMode, ChatMsg, ChatType, Faction, Group};
|
pub use chat::{ChatMode, ChatMsg, ChatType, Faction, Group, SpeechBubble};
|
||||||
pub use controller::{
|
pub use controller::{
|
||||||
Climb, ControlAction, ControlEvent, Controller, ControllerInputs, Input, InventoryManip,
|
Climb, ControlAction, ControlEvent, Controller, ControllerInputs, Input, InventoryManip,
|
||||||
MountState, Mounting,
|
MountState, Mounting,
|
||||||
|
@ -119,6 +119,8 @@ 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
|
||||||
|
Chat(comp::ChatMsg),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EventBus<E> {
|
pub struct EventBus<E> {
|
||||||
|
@ -25,7 +25,6 @@ sum_type! {
|
|||||||
Sticky(comp::Sticky),
|
Sticky(comp::Sticky),
|
||||||
Loadout(comp::Loadout),
|
Loadout(comp::Loadout),
|
||||||
CharacterState(comp::CharacterState),
|
CharacterState(comp::CharacterState),
|
||||||
SpeechBubble(comp::SpeechBubble),
|
|
||||||
Pos(comp::Pos),
|
Pos(comp::Pos),
|
||||||
Vel(comp::Vel),
|
Vel(comp::Vel),
|
||||||
Ori(comp::Ori),
|
Ori(comp::Ori),
|
||||||
@ -52,7 +51,6 @@ sum_type! {
|
|||||||
Sticky(PhantomData<comp::Sticky>),
|
Sticky(PhantomData<comp::Sticky>),
|
||||||
Loadout(PhantomData<comp::Loadout>),
|
Loadout(PhantomData<comp::Loadout>),
|
||||||
CharacterState(PhantomData<comp::CharacterState>),
|
CharacterState(PhantomData<comp::CharacterState>),
|
||||||
SpeechBubble(PhantomData<comp::SpeechBubble>),
|
|
||||||
Pos(PhantomData<comp::Pos>),
|
Pos(PhantomData<comp::Pos>),
|
||||||
Vel(PhantomData<comp::Vel>),
|
Vel(PhantomData<comp::Vel>),
|
||||||
Ori(PhantomData<comp::Ori>),
|
Ori(PhantomData<comp::Ori>),
|
||||||
@ -79,7 +77,6 @@ impl sync::CompPacket for EcsCompPacket {
|
|||||||
EcsCompPacket::Sticky(comp) => sync::handle_insert(comp, entity, world),
|
EcsCompPacket::Sticky(comp) => sync::handle_insert(comp, entity, world),
|
||||||
EcsCompPacket::Loadout(comp) => sync::handle_insert(comp, entity, world),
|
EcsCompPacket::Loadout(comp) => sync::handle_insert(comp, entity, world),
|
||||||
EcsCompPacket::CharacterState(comp) => sync::handle_insert(comp, entity, world),
|
EcsCompPacket::CharacterState(comp) => sync::handle_insert(comp, entity, world),
|
||||||
EcsCompPacket::SpeechBubble(comp) => sync::handle_insert(comp, entity, world),
|
|
||||||
EcsCompPacket::Pos(comp) => sync::handle_insert(comp, entity, world),
|
EcsCompPacket::Pos(comp) => sync::handle_insert(comp, entity, world),
|
||||||
EcsCompPacket::Vel(comp) => sync::handle_insert(comp, entity, world),
|
EcsCompPacket::Vel(comp) => sync::handle_insert(comp, entity, world),
|
||||||
EcsCompPacket::Ori(comp) => sync::handle_insert(comp, entity, world),
|
EcsCompPacket::Ori(comp) => sync::handle_insert(comp, entity, world),
|
||||||
@ -104,7 +101,6 @@ impl sync::CompPacket for EcsCompPacket {
|
|||||||
EcsCompPacket::Sticky(comp) => sync::handle_modify(comp, entity, world),
|
EcsCompPacket::Sticky(comp) => sync::handle_modify(comp, entity, world),
|
||||||
EcsCompPacket::Loadout(comp) => sync::handle_modify(comp, entity, world),
|
EcsCompPacket::Loadout(comp) => sync::handle_modify(comp, entity, world),
|
||||||
EcsCompPacket::CharacterState(comp) => sync::handle_modify(comp, entity, world),
|
EcsCompPacket::CharacterState(comp) => sync::handle_modify(comp, entity, world),
|
||||||
EcsCompPacket::SpeechBubble(comp) => sync::handle_modify(comp, entity, world),
|
|
||||||
EcsCompPacket::Pos(comp) => sync::handle_modify(comp, entity, world),
|
EcsCompPacket::Pos(comp) => sync::handle_modify(comp, entity, world),
|
||||||
EcsCompPacket::Vel(comp) => sync::handle_modify(comp, entity, world),
|
EcsCompPacket::Vel(comp) => sync::handle_modify(comp, entity, world),
|
||||||
EcsCompPacket::Ori(comp) => sync::handle_modify(comp, entity, world),
|
EcsCompPacket::Ori(comp) => sync::handle_modify(comp, entity, world),
|
||||||
@ -133,9 +129,6 @@ impl sync::CompPacket for EcsCompPacket {
|
|||||||
EcsCompPhantom::CharacterState(_) => {
|
EcsCompPhantom::CharacterState(_) => {
|
||||||
sync::handle_remove::<comp::CharacterState>(entity, world)
|
sync::handle_remove::<comp::CharacterState>(entity, world)
|
||||||
},
|
},
|
||||||
EcsCompPhantom::SpeechBubble(_) => {
|
|
||||||
sync::handle_remove::<comp::SpeechBubble>(entity, world)
|
|
||||||
},
|
|
||||||
EcsCompPhantom::Pos(_) => sync::handle_remove::<comp::Pos>(entity, world),
|
EcsCompPhantom::Pos(_) => sync::handle_remove::<comp::Pos>(entity, world),
|
||||||
EcsCompPhantom::Vel(_) => sync::handle_remove::<comp::Vel>(entity, world),
|
EcsCompPhantom::Vel(_) => sync::handle_remove::<comp::Vel>(entity, world),
|
||||||
EcsCompPhantom::Ori(_) => sync::handle_remove::<comp::Ori>(entity, world),
|
EcsCompPhantom::Ori(_) => sync::handle_remove::<comp::Ori>(entity, world),
|
||||||
|
@ -71,7 +71,7 @@ pub enum ServerMsg {
|
|||||||
Ping,
|
Ping,
|
||||||
Pong,
|
Pong,
|
||||||
/// A message to go into the client chat box. The client is responsible for
|
/// A message to go into the client chat box. The client is responsible for
|
||||||
/// formatting the message.
|
/// formatting the message and turning it into a speech bubble.
|
||||||
ChatMsg(comp::ChatMsg),
|
ChatMsg(comp::ChatMsg),
|
||||||
SetPlayerEntity(Uid),
|
SetPlayerEntity(Uid),
|
||||||
TimeOfDay(state::TimeOfDay),
|
TimeOfDay(state::TimeOfDay),
|
||||||
|
@ -122,7 +122,6 @@ impl State {
|
|||||||
ecs.register::<comp::Sticky>();
|
ecs.register::<comp::Sticky>();
|
||||||
ecs.register::<comp::Gravity>();
|
ecs.register::<comp::Gravity>();
|
||||||
ecs.register::<comp::CharacterState>();
|
ecs.register::<comp::CharacterState>();
|
||||||
ecs.register::<comp::SpeechBubble>();
|
|
||||||
|
|
||||||
// Register components send from clients -> server
|
// Register components send from clients -> server
|
||||||
ecs.register::<comp::Controller>();
|
ecs.register::<comp::Controller>();
|
||||||
|
@ -3,12 +3,13 @@ use crate::{
|
|||||||
self,
|
self,
|
||||||
agent::Activity,
|
agent::Activity,
|
||||||
item::{tool::ToolKind, ItemKind},
|
item::{tool::ToolKind, ItemKind},
|
||||||
Agent, Alignment, CharacterState, ControlAction, Controller, Loadout, MountState, Ori, Pos,
|
Agent, Alignment, CharacterState, ChatMsg, ControlAction, Controller, Loadout, MountState,
|
||||||
Scale, SpeechBubble, Stats,
|
Ori, Pos, Scale, Stats,
|
||||||
},
|
},
|
||||||
|
event::{EventBus, ServerEvent},
|
||||||
path::Chaser,
|
path::Chaser,
|
||||||
state::{DeltaTime, Time},
|
state::{DeltaTime, Time},
|
||||||
sync::UidAllocator,
|
sync::{Uid, UidAllocator},
|
||||||
terrain::TerrainGrid,
|
terrain::TerrainGrid,
|
||||||
util::Dir,
|
util::Dir,
|
||||||
vol::ReadVol,
|
vol::ReadVol,
|
||||||
@ -16,7 +17,7 @@ use crate::{
|
|||||||
use rand::{thread_rng, Rng};
|
use rand::{thread_rng, Rng};
|
||||||
use specs::{
|
use specs::{
|
||||||
saveload::{Marker, MarkerAllocator},
|
saveload::{Marker, MarkerAllocator},
|
||||||
Entities, Join, Read, ReadExpect, ReadStorage, System, WriteStorage,
|
Entities, Join, Read, ReadExpect, ReadStorage, System, Write, WriteStorage,
|
||||||
};
|
};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
@ -28,6 +29,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
Read<'a, UidAllocator>,
|
Read<'a, UidAllocator>,
|
||||||
Read<'a, Time>,
|
Read<'a, Time>,
|
||||||
Read<'a, DeltaTime>,
|
Read<'a, DeltaTime>,
|
||||||
|
Write<'a, EventBus<ServerEvent>>,
|
||||||
Entities<'a>,
|
Entities<'a>,
|
||||||
ReadStorage<'a, Pos>,
|
ReadStorage<'a, Pos>,
|
||||||
ReadStorage<'a, Ori>,
|
ReadStorage<'a, Ori>,
|
||||||
@ -35,11 +37,11 @@ impl<'a> System<'a> for Sys {
|
|||||||
ReadStorage<'a, Stats>,
|
ReadStorage<'a, Stats>,
|
||||||
ReadStorage<'a, Loadout>,
|
ReadStorage<'a, Loadout>,
|
||||||
ReadStorage<'a, CharacterState>,
|
ReadStorage<'a, CharacterState>,
|
||||||
|
ReadStorage<'a, Uid>,
|
||||||
ReadExpect<'a, TerrainGrid>,
|
ReadExpect<'a, TerrainGrid>,
|
||||||
ReadStorage<'a, Alignment>,
|
ReadStorage<'a, Alignment>,
|
||||||
WriteStorage<'a, Agent>,
|
WriteStorage<'a, Agent>,
|
||||||
WriteStorage<'a, Controller>,
|
WriteStorage<'a, Controller>,
|
||||||
WriteStorage<'a, SpeechBubble>,
|
|
||||||
ReadStorage<'a, MountState>,
|
ReadStorage<'a, MountState>,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -50,6 +52,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
uid_allocator,
|
uid_allocator,
|
||||||
time,
|
time,
|
||||||
dt,
|
dt,
|
||||||
|
event_bus,
|
||||||
entities,
|
entities,
|
||||||
positions,
|
positions,
|
||||||
orientations,
|
orientations,
|
||||||
@ -57,11 +60,11 @@ impl<'a> System<'a> for Sys {
|
|||||||
stats,
|
stats,
|
||||||
loadouts,
|
loadouts,
|
||||||
character_states,
|
character_states,
|
||||||
|
uids,
|
||||||
terrain,
|
terrain,
|
||||||
alignments,
|
alignments,
|
||||||
mut agents,
|
mut agents,
|
||||||
mut controllers,
|
mut controllers,
|
||||||
mut speech_bubbles,
|
|
||||||
mount_states,
|
mount_states,
|
||||||
): Self::SystemData,
|
): Self::SystemData,
|
||||||
) {
|
) {
|
||||||
@ -72,6 +75,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
alignment,
|
alignment,
|
||||||
loadout,
|
loadout,
|
||||||
character_state,
|
character_state,
|
||||||
|
uid,
|
||||||
agent,
|
agent,
|
||||||
controller,
|
controller,
|
||||||
mount_state,
|
mount_state,
|
||||||
@ -82,6 +86,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
alignments.maybe(),
|
alignments.maybe(),
|
||||||
&loadouts,
|
&loadouts,
|
||||||
&character_states,
|
&character_states,
|
||||||
|
&uids,
|
||||||
&mut agents,
|
&mut agents,
|
||||||
&mut controllers,
|
&mut controllers,
|
||||||
mount_states.maybe(),
|
mount_states.maybe(),
|
||||||
@ -386,10 +391,9 @@ impl<'a> System<'a> for Sys {
|
|||||||
{
|
{
|
||||||
if stats.get(attacker).map_or(false, |a| !a.is_dead) {
|
if stats.get(attacker).map_or(false, |a| !a.is_dead) {
|
||||||
if agent.can_speak {
|
if agent.can_speak {
|
||||||
let message =
|
let msg = "npc.speech.villager_under_attack".to_string();
|
||||||
"npc.speech.villager_under_attack".to_string();
|
event_bus
|
||||||
let bubble = SpeechBubble::npc_new(message, *time);
|
.emit_now(ServerEvent::Chat(ChatMsg::npc(*uid, msg)));
|
||||||
let _ = speech_bubbles.insert(entity, bubble);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
agent.activity = Activity::Attack {
|
agent.activity = Activity::Attack {
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
use crate::Server;
|
use crate::{state_ext::StateExt, Server};
|
||||||
use common::event::{EventBus, ServerEvent};
|
use common::{
|
||||||
|
event::{EventBus, ServerEvent},
|
||||||
|
msg::ServerMsg,
|
||||||
|
};
|
||||||
use entity_creation::{
|
use entity_creation::{
|
||||||
handle_create_npc, handle_create_waypoint, handle_initialize_character,
|
handle_create_npc, handle_create_waypoint, handle_initialize_character,
|
||||||
handle_loaded_character_data, handle_shoot,
|
handle_loaded_character_data, handle_shoot,
|
||||||
@ -103,6 +106,10 @@ impl Server {
|
|||||||
ServerEvent::ChatCmd(entity, cmd) => {
|
ServerEvent::ChatCmd(entity, cmd) => {
|
||||||
chat_commands.push((entity, cmd));
|
chat_commands.push((entity, cmd));
|
||||||
},
|
},
|
||||||
|
ServerEvent::Chat(msg) => {
|
||||||
|
self.state
|
||||||
|
.notify_registered_clients(ServerMsg::ChatMsg(msg));
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,8 +114,8 @@ impl Server {
|
|||||||
state.ecs_mut().insert(sys::TerrainSyncTimer::default());
|
state.ecs_mut().insert(sys::TerrainSyncTimer::default());
|
||||||
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::SpeechBubbleTimer::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
|
||||||
|
@ -464,7 +464,8 @@ impl<'a> System<'a> for Sys {
|
|||||||
server_emitter.emit(ServerEvent::ChatCmd(entity, argv));
|
server_emitter.emit(ServerEvent::ChatCmd(entity, argv));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// TODO FIXME speech bubbles and prefixes are handled by the client now
|
// Send speech bubble and chat message
|
||||||
|
// TODO filter group, faction, say, and bubble distance.
|
||||||
for client in (&mut clients).join().filter(|c| c.is_registered()) {
|
for client in (&mut clients).join().filter(|c| c.is_registered()) {
|
||||||
client.notify(ServerMsg::ChatMsg(msg.clone()));
|
client.notify(ServerMsg::ChatMsg(msg.clone()));
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ pub mod entity_sync;
|
|||||||
pub mod message;
|
pub mod message;
|
||||||
pub mod persistence;
|
pub mod persistence;
|
||||||
pub mod sentinel;
|
pub mod sentinel;
|
||||||
pub mod speech_bubble;
|
|
||||||
pub mod subscription;
|
pub mod subscription;
|
||||||
pub mod terrain;
|
pub mod terrain;
|
||||||
pub mod terrain_sync;
|
pub mod terrain_sync;
|
||||||
@ -21,9 +20,10 @@ pub type SubscriptionTimer = SysTimer<subscription::Sys>;
|
|||||||
pub type TerrainTimer = SysTimer<terrain::Sys>;
|
pub type TerrainTimer = SysTimer<terrain::Sys>;
|
||||||
pub type TerrainSyncTimer = SysTimer<terrain_sync::Sys>;
|
pub type TerrainSyncTimer = SysTimer<terrain_sync::Sys>;
|
||||||
pub type WaypointTimer = SysTimer<waypoint::Sys>;
|
pub type WaypointTimer = SysTimer<waypoint::Sys>;
|
||||||
pub type SpeechBubbleTimer = SysTimer<speech_bubble::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
|
||||||
@ -33,14 +33,14 @@ pub type PersistenceScheduler = SysScheduler<persistence::Sys>;
|
|||||||
//const TERRAIN_SYNC_SYS: &str = "server_terrain_sync_sys";
|
//const TERRAIN_SYNC_SYS: &str = "server_terrain_sync_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 SPEECH_BUBBLE_SYS: &str = "speech_bubble_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(speech_bubble::Sys, SPEECH_BUBBLE_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) {
|
||||||
|
@ -2,7 +2,7 @@ use super::SysTimer;
|
|||||||
use common::{
|
use common::{
|
||||||
comp::{
|
comp::{
|
||||||
Body, CanBuild, CharacterState, Collider, Energy, Gravity, Item, LightEmitter, Loadout,
|
Body, CanBuild, CharacterState, Collider, Energy, Gravity, Item, LightEmitter, Loadout,
|
||||||
Mass, MountState, Mounting, Ori, Player, Pos, Scale, SpeechBubble, Stats, Sticky, Vel,
|
Mass, MountState, Mounting, Ori, Player, Pos, Scale, Stats, Sticky, Vel,
|
||||||
},
|
},
|
||||||
msg::EcsCompPacket,
|
msg::EcsCompPacket,
|
||||||
sync::{CompSyncPackage, EntityPackage, EntitySyncPackage, Uid, UpdateTracker, WorldSyncExt},
|
sync::{CompSyncPackage, EntityPackage, EntitySyncPackage, Uid, UpdateTracker, WorldSyncExt},
|
||||||
@ -54,7 +54,6 @@ pub struct TrackedComps<'a> {
|
|||||||
pub gravity: ReadStorage<'a, Gravity>,
|
pub gravity: ReadStorage<'a, Gravity>,
|
||||||
pub loadout: ReadStorage<'a, Loadout>,
|
pub loadout: ReadStorage<'a, Loadout>,
|
||||||
pub character_state: ReadStorage<'a, CharacterState>,
|
pub character_state: ReadStorage<'a, CharacterState>,
|
||||||
pub speech_bubble: ReadStorage<'a, SpeechBubble>,
|
|
||||||
}
|
}
|
||||||
impl<'a> TrackedComps<'a> {
|
impl<'a> TrackedComps<'a> {
|
||||||
pub fn create_entity_package(
|
pub fn create_entity_package(
|
||||||
@ -126,10 +125,6 @@ impl<'a> TrackedComps<'a> {
|
|||||||
.get(entity)
|
.get(entity)
|
||||||
.cloned()
|
.cloned()
|
||||||
.map(|c| comps.push(c.into()));
|
.map(|c| comps.push(c.into()));
|
||||||
self.speech_bubble
|
|
||||||
.get(entity)
|
|
||||||
.cloned()
|
|
||||||
.map(|c| comps.push(c.into()));
|
|
||||||
// Add untracked comps
|
// Add untracked comps
|
||||||
pos.map(|c| comps.push(c.into()));
|
pos.map(|c| comps.push(c.into()));
|
||||||
vel.map(|c| comps.push(c.into()));
|
vel.map(|c| comps.push(c.into()));
|
||||||
@ -157,7 +152,6 @@ pub struct ReadTrackers<'a> {
|
|||||||
pub gravity: ReadExpect<'a, UpdateTracker<Gravity>>,
|
pub gravity: ReadExpect<'a, UpdateTracker<Gravity>>,
|
||||||
pub loadout: ReadExpect<'a, UpdateTracker<Loadout>>,
|
pub loadout: ReadExpect<'a, UpdateTracker<Loadout>>,
|
||||||
pub character_state: ReadExpect<'a, UpdateTracker<CharacterState>>,
|
pub character_state: ReadExpect<'a, UpdateTracker<CharacterState>>,
|
||||||
pub speech_bubble: ReadExpect<'a, UpdateTracker<SpeechBubble>>,
|
|
||||||
}
|
}
|
||||||
impl<'a> ReadTrackers<'a> {
|
impl<'a> ReadTrackers<'a> {
|
||||||
pub fn create_sync_packages(
|
pub fn create_sync_packages(
|
||||||
@ -194,12 +188,6 @@ impl<'a> ReadTrackers<'a> {
|
|||||||
&*self.character_state,
|
&*self.character_state,
|
||||||
&comps.character_state,
|
&comps.character_state,
|
||||||
filter,
|
filter,
|
||||||
)
|
|
||||||
.with_component(
|
|
||||||
&comps.uid,
|
|
||||||
&*self.speech_bubble,
|
|
||||||
&comps.speech_bubble,
|
|
||||||
filter,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
(entity_sync_package, comp_sync_package)
|
(entity_sync_package, comp_sync_package)
|
||||||
@ -225,7 +213,6 @@ pub struct WriteTrackers<'a> {
|
|||||||
gravity: WriteExpect<'a, UpdateTracker<Gravity>>,
|
gravity: WriteExpect<'a, UpdateTracker<Gravity>>,
|
||||||
loadout: WriteExpect<'a, UpdateTracker<Loadout>>,
|
loadout: WriteExpect<'a, UpdateTracker<Loadout>>,
|
||||||
character_state: WriteExpect<'a, UpdateTracker<CharacterState>>,
|
character_state: WriteExpect<'a, UpdateTracker<CharacterState>>,
|
||||||
speech_bubble: WriteExpect<'a, UpdateTracker<SpeechBubble>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn record_changes(comps: &TrackedComps, trackers: &mut WriteTrackers) {
|
fn record_changes(comps: &TrackedComps, trackers: &mut WriteTrackers) {
|
||||||
@ -249,7 +236,6 @@ fn record_changes(comps: &TrackedComps, trackers: &mut WriteTrackers) {
|
|||||||
trackers
|
trackers
|
||||||
.character_state
|
.character_state
|
||||||
.record_changes(&comps.character_state);
|
.record_changes(&comps.character_state);
|
||||||
trackers.speech_bubble.record_changes(&comps.speech_bubble);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register_trackers(world: &mut World) {
|
pub fn register_trackers(world: &mut World) {
|
||||||
@ -270,7 +256,6 @@ pub fn register_trackers(world: &mut World) {
|
|||||||
world.register_tracker::<Gravity>();
|
world.register_tracker::<Gravity>();
|
||||||
world.register_tracker::<Loadout>();
|
world.register_tracker::<Loadout>();
|
||||||
world.register_tracker::<CharacterState>();
|
world.register_tracker::<CharacterState>();
|
||||||
world.register_tracker::<SpeechBubble>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deleted entities grouped by region
|
/// Deleted entities grouped by region
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
use super::SysTimer;
|
|
||||||
use common::{comp::SpeechBubble, state::Time};
|
|
||||||
use specs::{Entities, Join, Read, System, Write, WriteStorage};
|
|
||||||
|
|
||||||
/// This system removes timed-out speech bubbles
|
|
||||||
pub struct Sys;
|
|
||||||
impl<'a> System<'a> for Sys {
|
|
||||||
type SystemData = (
|
|
||||||
Entities<'a>,
|
|
||||||
Read<'a, Time>,
|
|
||||||
WriteStorage<'a, SpeechBubble>,
|
|
||||||
Write<'a, SysTimer<Self>>,
|
|
||||||
);
|
|
||||||
|
|
||||||
fn run(&mut self, (entities, time, mut speech_bubbles, mut timer): Self::SystemData) {
|
|
||||||
timer.start();
|
|
||||||
|
|
||||||
let expired_ents: Vec<_> = (&entities, &mut speech_bubbles)
|
|
||||||
.join()
|
|
||||||
.filter(|(_, speech_bubble)| speech_bubble.timeout.map_or(true, |t| t.0 < time.0))
|
|
||||||
.map(|(ent, _)| ent)
|
|
||||||
.collect();
|
|
||||||
for ent in expired_ents {
|
|
||||||
speech_bubbles.remove(ent);
|
|
||||||
}
|
|
||||||
|
|
||||||
timer.end();
|
|
||||||
}
|
|
||||||
}
|
|
@ -367,6 +367,7 @@ impl<'a> Widget for Chat<'a> {
|
|||||||
ChatType::Faction(uid) => (FACTION_COLOR, message_format(uid, message)),
|
ChatType::Faction(uid) => (FACTION_COLOR, message_format(uid, message)),
|
||||||
ChatType::Region(uid) => (REGION_COLOR, message_format(uid, message)),
|
ChatType::Region(uid) => (REGION_COLOR, message_format(uid, message)),
|
||||||
ChatType::World(uid) => (WORLD_COLOR, message_format(uid, message)),
|
ChatType::World(uid) => (WORLD_COLOR, message_format(uid, message)),
|
||||||
|
ChatType::Npc(_uid, _r) => continue, // Should be filtered by hud/mod.rs
|
||||||
};
|
};
|
||||||
let text = Text::new(&msg)
|
let text = Text::new(&msg)
|
||||||
.font_size(self.fonts.opensans.scale(15))
|
.font_size(self.fonts.opensans.scale(15))
|
||||||
|
@ -47,14 +47,17 @@ use crate::{
|
|||||||
GlobalState,
|
GlobalState,
|
||||||
};
|
};
|
||||||
use client::Client;
|
use client::Client;
|
||||||
use common::{assets::load_expect, comp, terrain::TerrainChunk, vol::RectRasterableVol};
|
use common::{assets::load_expect, comp, sync::Uid, terrain::TerrainChunk, vol::RectRasterableVol};
|
||||||
use conrod_core::{
|
use conrod_core::{
|
||||||
text::cursor::Index,
|
text::cursor::Index,
|
||||||
widget::{self, Button, Image, Text},
|
widget::{self, Button, Image, Text},
|
||||||
widget_ids, Color, Colorable, Labelable, Positionable, Sizeable, Widget,
|
widget_ids, Color, Colorable, Labelable, Positionable, Sizeable, Widget,
|
||||||
};
|
};
|
||||||
use specs::{Join, WorldExt};
|
use specs::{Join, WorldExt};
|
||||||
use std::collections::VecDeque;
|
use std::{
|
||||||
|
collections::{HashMap, VecDeque},
|
||||||
|
time::Instant,
|
||||||
|
};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
const XP_COLOR: Color = Color::Rgba(0.59, 0.41, 0.67, 1.0);
|
const XP_COLOR: Color = Color::Rgba(0.59, 0.41, 0.67, 1.0);
|
||||||
@ -465,6 +468,7 @@ pub struct Hud {
|
|||||||
rot_imgs: ImgsRot,
|
rot_imgs: ImgsRot,
|
||||||
new_messages: VecDeque<comp::ChatMsg>,
|
new_messages: VecDeque<comp::ChatMsg>,
|
||||||
new_notifications: VecDeque<common::msg::Notification>,
|
new_notifications: VecDeque<common::msg::Notification>,
|
||||||
|
speech_bubbles: HashMap<Uid, comp::SpeechBubble>,
|
||||||
show: Show,
|
show: Show,
|
||||||
//never_show: bool,
|
//never_show: bool,
|
||||||
//intro: bool,
|
//intro: bool,
|
||||||
@ -530,9 +534,10 @@ impl Hud {
|
|||||||
fonts,
|
fonts,
|
||||||
ids,
|
ids,
|
||||||
new_messages: VecDeque::new(),
|
new_messages: VecDeque::new(),
|
||||||
|
new_notifications: VecDeque::new(),
|
||||||
|
speech_bubbles: HashMap::new(),
|
||||||
//intro: false,
|
//intro: false,
|
||||||
//intro_2: false,
|
//intro_2: false,
|
||||||
new_notifications: VecDeque::new(),
|
|
||||||
show: Show {
|
show: Show {
|
||||||
help: false,
|
help: false,
|
||||||
intro: true,
|
intro: true,
|
||||||
@ -606,7 +611,7 @@ impl Hud {
|
|||||||
let stats = ecs.read_storage::<comp::Stats>();
|
let stats = ecs.read_storage::<comp::Stats>();
|
||||||
let energy = ecs.read_storage::<comp::Energy>();
|
let energy = ecs.read_storage::<comp::Energy>();
|
||||||
let hp_floater_lists = ecs.read_storage::<vcomp::HpFloaterList>();
|
let hp_floater_lists = ecs.read_storage::<vcomp::HpFloaterList>();
|
||||||
let speech_bubbles = ecs.read_storage::<comp::SpeechBubble>();
|
let uids = ecs.read_storage::<common::sync::Uid>();
|
||||||
let interpolated = ecs.read_storage::<vcomp::Interpolated>();
|
let interpolated = ecs.read_storage::<vcomp::Interpolated>();
|
||||||
let players = ecs.read_storage::<comp::Player>();
|
let players = ecs.read_storage::<comp::Player>();
|
||||||
let scales = ecs.read_storage::<comp::Scale>();
|
let scales = ecs.read_storage::<comp::Scale>();
|
||||||
@ -934,12 +939,23 @@ impl Hud {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pop speech bubbles
|
||||||
|
self.speech_bubbles
|
||||||
|
.retain(|_uid, bubble| bubble.timeout > Instant::now());
|
||||||
|
|
||||||
|
// Push speech bubbles
|
||||||
|
for msg in self.new_messages.iter() {
|
||||||
|
if let Some((bubble, uid)) = msg.to_bubble() {
|
||||||
|
self.speech_bubbles.insert(uid, bubble);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut overhead_walker = self.ids.overheads.walk();
|
let mut overhead_walker = self.ids.overheads.walk();
|
||||||
let mut sct_walker = self.ids.scts.walk();
|
let mut sct_walker = self.ids.scts.walk();
|
||||||
let mut sct_bg_walker = self.ids.sct_bgs.walk();
|
let mut sct_bg_walker = self.ids.sct_bgs.walk();
|
||||||
|
|
||||||
// Render overhead name tags and health bars
|
// Render overhead name tags and health bars
|
||||||
for (pos, name, stats, energy, height_offset, hpfl, bubble) in (
|
for (pos, name, stats, energy, height_offset, hpfl, uid) in (
|
||||||
&entities,
|
&entities,
|
||||||
&pos,
|
&pos,
|
||||||
interpolated.maybe(),
|
interpolated.maybe(),
|
||||||
@ -949,7 +965,7 @@ impl Hud {
|
|||||||
scales.maybe(),
|
scales.maybe(),
|
||||||
&bodies,
|
&bodies,
|
||||||
&hp_floater_lists,
|
&hp_floater_lists,
|
||||||
speech_bubbles.maybe(),
|
&uids,
|
||||||
)
|
)
|
||||||
.join()
|
.join()
|
||||||
.filter(|(entity, _, _, stats, _, _, _, _, _, _)| *entity != me && !stats.is_dead)
|
.filter(|(entity, _, _, stats, _, _, _, _, _, _)| *entity != me && !stats.is_dead)
|
||||||
@ -966,7 +982,7 @@ impl Hud {
|
|||||||
})
|
})
|
||||||
.powi(2)
|
.powi(2)
|
||||||
})
|
})
|
||||||
.map(|(_, pos, interpolated, stats, energy, player, scale, body, hpfl, bubble)| {
|
.map(|(_, pos, interpolated, stats, energy, player, scale, body, hpfl, uid)| {
|
||||||
// TODO: This is temporary
|
// TODO: This is temporary
|
||||||
// If the player used the default character name display their name instead
|
// If the player used the default character name display their name instead
|
||||||
let name = if stats.name == "Character Name" {
|
let name = if stats.name == "Character Name" {
|
||||||
@ -982,10 +998,12 @@ impl Hud {
|
|||||||
// TODO: when body.height() is more accurate remove the 2.0
|
// TODO: when body.height() is more accurate remove the 2.0
|
||||||
body.height() * 2.0 * scale.map_or(1.0, |s| s.0),
|
body.height() * 2.0 * scale.map_or(1.0, |s| s.0),
|
||||||
hpfl,
|
hpfl,
|
||||||
bubble,
|
uid,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
|
let bubble = self.speech_bubbles.get(uid);
|
||||||
|
|
||||||
let overhead_id = overhead_walker.next(
|
let overhead_id = overhead_walker.next(
|
||||||
&mut self.ids.overheads,
|
&mut self.ids.overheads,
|
||||||
&mut ui_widgets.widget_id_generator(),
|
&mut ui_widgets.widget_id_generator(),
|
||||||
@ -1551,6 +1569,15 @@ impl Hud {
|
|||||||
.set(self.ids.skillbar, ui_widgets);
|
.set(self.ids.skillbar, ui_widgets);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Don't put NPC messages in chat box.
|
||||||
|
self.new_messages.retain(|m| {
|
||||||
|
if let comp::ChatType::Npc(_, _) = m.chat_type {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Chat box
|
// Chat box
|
||||||
match Chat::new(
|
match Chat::new(
|
||||||
&mut self.new_messages,
|
&mut self.new_messages,
|
||||||
|
@ -77,11 +77,8 @@ impl SessionState {
|
|||||||
fn tick(&mut self, dt: Duration, global_state: &mut GlobalState) -> Result<TickAction, Error> {
|
fn tick(&mut self, dt: Duration, global_state: &mut GlobalState) -> Result<TickAction, Error> {
|
||||||
self.inputs.tick(dt);
|
self.inputs.tick(dt);
|
||||||
|
|
||||||
for event in self.client.borrow_mut().tick(
|
let mut client = self.client.borrow_mut();
|
||||||
self.inputs.clone(),
|
for event in client.tick(self.inputs.clone(), dt, crate::ecs::sys::add_local_systems)? {
|
||||||
dt,
|
|
||||||
crate::ecs::sys::add_local_systems,
|
|
||||||
)? {
|
|
||||||
match event {
|
match event {
|
||||||
client::Event::Chat(m) => {
|
client::Event::Chat(m) => {
|
||||||
self.hud.new_message(m);
|
self.hud.new_message(m);
|
||||||
|
Reference in New Issue
Block a user