Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add whisper functionalty (client side), some server fixes #7

Merged
merged 1 commit into from
Jan 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 19 additions & 4 deletions examples/wasm-modules/chat/src/chat/page.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use client_containers::skins::SkinContainer;
use client_render_base::render::tee::RenderTee;
use client_types::chat::{ChatMsg, MsgSystem, ServerMsg, SystemMsgPlayerSkin};
use client_ui::chat::user_data::{ChatMode, MsgInChat};
use game_base::network::types::chat::NetChatMsgPlayerChannel;
use game_interface::types::character_info::NetworkSkinInfo;
use game_base::network::types::chat::{ChatPlayerInfo, NetChatMsgPlayerChannel};
use game_interface::types::{character_info::NetworkSkinInfo, id_gen::IdGenerator};
use graphics::{
graphics::graphics::Graphics,
handles::{canvas::canvas::GraphicsCanvasHandle, stream::stream::GraphicsStreamHandle},
Expand Down Expand Up @@ -38,6 +38,7 @@ impl ChatPage {
pipe: &mut UiRenderPipe<()>,
ui_state: &mut UiState,
) {
let id_gen = IdGenerator::default();
let mut entries: VecDeque<MsgInChat> = vec![
MsgInChat {
msg: ServerMsg::Chat(ChatMsg {
Expand All @@ -49,7 +50,7 @@ impl ChatPage {
feet_color: ubvec4::new(255, 255, 255, 255),
},
msg: "test".into(),
channel: NetChatMsgPlayerChannel::Global,
channel: NetChatMsgPlayerChannel::GameTeam,
}),
add_time: Duration::MAX,
},
Expand All @@ -66,7 +67,15 @@ impl ChatPage {
smth like that bla bla bla bla bla bla bla bla bla bla \
bla bla bla bla bla bla"
.into(),
channel: NetChatMsgPlayerChannel::Global,
channel: NetChatMsgPlayerChannel::Whisper(ChatPlayerInfo {
id: id_gen.next_id(),
name: "other".try_into().unwrap(),
skin: "skin".try_into().unwrap(),
skin_info: NetworkSkinInfo::Custom {
body_color: ubvec4::new(0, 255, 255, 255),
feet_color: ubvec4::new(255, 255, 255, 255),
},
}),
}),
add_time: Duration::MAX,
},
Expand Down Expand Up @@ -150,7 +159,13 @@ impl ChatPage {
skin_container: &mut self.skin_container,
render_tee: &self.render_tee,
mode: ChatMode::Global,

character_infos: &Default::default(),
local_character_ids: &Default::default(),

find_player_prompt: &mut Default::default(),
find_player_id: &mut Default::default(),
cur_whisper_player_id: &mut Default::default(),
},
),
ui_state,
Expand Down
28 changes: 26 additions & 2 deletions game/client-render-game/src/render_game.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
use std::{borrow::Borrow, collections::HashMap, num::NonZeroU32, sync::Arc, time::Duration};
use std::{
borrow::Borrow,
collections::{HashMap, HashSet},
num::NonZeroU32,
sync::Arc,
time::Duration,
};

use crate::components::{
cursor::{RenderCursor, RenderCursorPipe},
Expand Down Expand Up @@ -781,6 +787,7 @@ impl RenderGame {

render_info: &RenderGameInput,
mut player_info: Option<(&PlayerId, &mut RenderGameForPlayer)>,
local_player_ids: &Option<HashSet<PlayerId>>,
player_vote_rect: &mut Option<Rect>,
expects_player_vote_miniscreen: bool,
) -> Vec<PlayerFeedbackEvent> {
Expand All @@ -806,6 +813,9 @@ impl RenderGame {
false
};

let dummy_local_player_ids = HashSet::default();
let local_player_ids = local_player_ids.as_ref().unwrap_or(&dummy_local_player_ids);

res.extend(
self.chat
.render(&mut ChatRenderPipe {
Expand All @@ -820,6 +830,7 @@ impl RenderGame {
skin_container: &mut self.containers.skin_container,
tee_render: &mut self.players.tee_renderer,
character_infos: &render_info.character_infos,
local_character_ids: local_player_ids,
})
.into_iter()
.map(PlayerFeedbackEvent::Chat),
Expand Down Expand Up @@ -2526,6 +2537,7 @@ impl RenderGameInterface for RenderGame {
self.handle_events(cur_time, &mut input);

let mut has_scoreboard = false;
let mut has_chat_input = false;

let mut next_sound_listeners = self.world_sound_listeners_pool.new();
std::mem::swap(&mut *next_sound_listeners, &mut self.world_sound_listeners);
Expand Down Expand Up @@ -2576,6 +2588,7 @@ impl RenderGameInterface for RenderGame {
}

has_scoreboard |= player.render_for_player.scoreboard_active;
has_chat_input |= player.render_for_player.chat_info.is_some();
}

// always clear motd if scoreboard is open
Expand All @@ -2584,11 +2597,21 @@ impl RenderGameInterface for RenderGame {
self.motd.started_at = None;
}

// only call this when chat input is active, since it will allocate memory on heap
let local_player_ids = has_chat_input.then(|| {
input
.players
.keys()
.copied()
.chain(input.dummies.iter().copied())
.collect()
});

let player_count = input.players.len();
if player_count == 0 {
self.render_ingame(config_map, cur_time, &input, None);
self.backend_handle.consumble_multi_samples();
let _ = self.render_uis(cur_time, &input, None, &mut None, false);
let _ = self.render_uis(cur_time, &input, None, &local_player_ids, &mut None, false);
} else {
let players_per_row = Self::calc_players_per_row(player_count);
let window_props = self.canvas_handle.window_props();
Expand Down Expand Up @@ -2660,6 +2683,7 @@ impl RenderGameInterface for RenderGame {
cur_time,
&input,
Some((player_id, render_for_player_game)),
&local_player_ids,
&mut player_vote_rect,
expected_vote_miniscreen,
);
Expand Down
23 changes: 21 additions & 2 deletions game/client-render/src/chat/render.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use std::{collections::VecDeque, time::Duration};
use std::{
collections::{HashSet, VecDeque},
time::Duration,
};

use base::linked_hash_map_view::FxLinkedHashMap;
use client_containers::skins::SkinContainer;
Expand All @@ -8,7 +11,10 @@ use client_ui::chat::{
user_data::{ChatEvent, ChatMode, MsgInChat, UserData},
};
use egui::Color32;
use game_interface::types::{id_types::CharacterId, render::character::CharacterInfo};
use game_interface::types::{
id_types::{CharacterId, PlayerId},
render::character::CharacterInfo,
};
use graphics::{
graphics::graphics::Graphics,
handles::{
Expand Down Expand Up @@ -40,6 +46,7 @@ pub struct ChatRenderPipe<'a> {
pub skin_container: &'a mut SkinContainer,
pub tee_render: &'a RenderTee,
pub character_infos: &'a FxLinkedHashMap<CharacterId, CharacterInfo>,
pub local_character_ids: &'a HashSet<CharacterId>,
}

pub struct ChatRender {
Expand All @@ -49,6 +56,10 @@ pub struct ChatRender {
pub msgs: RememberMut<VecDeque<MsgInChat>>,
pub last_render_options: Option<ChatRenderOptions>,

find_player_prompt: String,
find_player_id: Option<PlayerId>,
cur_whisper_player_id: Option<PlayerId>,

backend_handle: GraphicsBackendHandle,
canvas_handle: GraphicsCanvasHandle,
stream_handle: GraphicsStreamHandle,
Expand All @@ -66,6 +77,10 @@ impl ChatRender {
msgs: Default::default(),
last_render_options: None,

find_player_prompt: Default::default(),
find_player_id: Default::default(),
cur_whisper_player_id: Default::default(),

backend_handle: graphics.backend_handle.clone(),
canvas_handle: graphics.canvas_handle.clone(),
stream_handle: graphics.stream_handle.clone(),
Expand Down Expand Up @@ -103,6 +118,10 @@ impl ChatRender {
render_tee: pipe.tee_render,
mode: pipe.mode,
character_infos: pipe.character_infos,
local_character_ids: pipe.local_character_ids,
find_player_prompt: &mut self.find_player_prompt,
find_player_id: &mut self.find_player_id,
cur_whisper_player_id: &mut self.cur_whisper_player_id,
};
let mut dummy_pipe = UiRenderPipe::new(*pipe.cur_time, &mut user_data);
let (screen_rect, full_output, zoom_level) = self.ui.render_cached(
Expand Down
163 changes: 93 additions & 70 deletions game/client-ui/src/chat/chat_entry.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use std::borrow::Borrow;

use client_types::chat::ChatMsg;
use egui::{text::LayoutJob, Align, Color32, FontId, Layout, Stroke, Vec2};
use game_base::network::types::chat::NetChatMsgPlayerChannel;
use game_interface::types::render::character::TeeEye;
use math::math::vector::vec2;
use game_base::network::types::chat::NetChatMsgPlayerChannel;
use ui_base::types::{UiRenderPipe, UiState};

use crate::utils::render_tee_for_ui;
Expand All @@ -19,78 +21,99 @@ pub fn render(
ui_state: &mut UiState,
msg: &ChatMsg,
) {
entry_frame(
ui,
match &msg.channel {
NetChatMsgPlayerChannel::Global => Stroke::NONE,
NetChatMsgPlayerChannel::GameTeam => Stroke::new(2.0, Color32::LIGHT_GREEN),
NetChatMsgPlayerChannel::Whisper(_) => Stroke::new(2.0, Color32::RED),
},
|ui| {
let (stroke, to) = match &msg.channel {
NetChatMsgPlayerChannel::Global => (Stroke::NONE, None),
NetChatMsgPlayerChannel::GameTeam => (Stroke::new(2.0, Color32::LIGHT_GREEN), None),
NetChatMsgPlayerChannel::Whisper(to) => (Stroke::new(2.0, Color32::RED), Some(to)),
};
entry_frame(ui, stroke, |ui| {
ui.add_space(MARGIN);
let response = ui.horizontal(|ui| {
ui.add_space(MARGIN);
let response = ui.horizontal(|ui| {
ui.add_space(MARGIN);
ui.add_space(TEE_SIZE + MARGIN_FROM_TEE);
ui.style_mut().spacing.item_spacing.x = 4.0;
ui.style_mut().spacing.item_spacing.y = 0.0;
ui.with_layout(Layout::bottom_up(egui::Align::Min), |ui| {
ui.add_space(2.0);
let text_format = egui::TextFormat {
color: Color32::WHITE,
..Default::default()
};
let job = LayoutJob::single_section(msg.msg.clone(), text_format);
ui.label(job);
ui.allocate_ui_with_layout(
Vec2::new(ui.available_width(), 14.0),
Layout::left_to_right(Align::Max),
|ui| {
let text_format = egui::TextFormat {
line_height: Some(14.0),
font_id: FontId::proportional(12.0),
valign: Align::BOTTOM,
color: Color32::WHITE,
..Default::default()
};
let mut job =
LayoutJob::single_section(msg.player.clone(), text_format);
let text_format_clan = egui::TextFormat {
line_height: Some(12.0),
font_id: FontId::proportional(10.0),
valign: Align::BOTTOM,
color: Color32::LIGHT_GRAY,
..Default::default()
};
job.append(&msg.clan, 4.0, text_format_clan);
ui.label(job);
},
);
ui.add_space(2.0);
});
ui.add_space(ui.available_width().min(4.0));
ui.add_space(MARGIN);
ui.add_space(TEE_SIZE + MARGIN_FROM_TEE);
ui.style_mut().spacing.item_spacing.x = 4.0;
ui.style_mut().spacing.item_spacing.y = 0.0;
ui.with_layout(Layout::bottom_up(egui::Align::Min), |ui| {
ui.add_space(2.0);
let text_format = egui::TextFormat {
color: Color32::WHITE,
..Default::default()
};
let job = LayoutJob::single_section(msg.msg.clone(), text_format);
ui.label(job);
ui.allocate_ui_with_layout(
Vec2::new(ui.available_width(), 14.0),
Layout::left_to_right(Align::Max),
|ui| {
let text_format = egui::TextFormat {
line_height: Some(14.0),
font_id: FontId::proportional(12.0),
valign: Align::BOTTOM,
color: Color32::WHITE,
..Default::default()
};
let mut job = LayoutJob::single_section(msg.player.clone(), text_format);
let text_format_clan = egui::TextFormat {
line_height: Some(12.0),
font_id: FontId::proportional(10.0),
valign: Align::BOTTOM,
color: Color32::LIGHT_GRAY,
..Default::default()
};
job.append(&msg.clan, 4.0, text_format_clan);
ui.label(job);

if let Some(to) = to {
ui.colored_label(Color32::WHITE, "to");
ui.colored_label(Color32::WHITE, to.name.as_str());

let rect = ui.available_rect_before_wrap();

const TEE_SIZE_MINI: f32 = 12.0;
ui.add_space(TEE_SIZE_MINI);

render_tee_for_ui(
pipe.user_data.canvas_handle,
pipe.user_data.skin_container,
pipe.user_data.render_tee,
ui,
ui_state,
ui.ctx().screen_rect(),
Some(ui.clip_rect()),
to.skin.borrow(),
Some(&to.skin_info),
vec2::new(rect.min.x + TEE_SIZE_MINI / 2.0, rect.left_center().y),
TEE_SIZE_MINI,
TeeEye::Normal,
);
}
},
);
ui.add_space(2.0);
});
ui.add_space(ui.available_width().min(4.0));
ui.add_space(MARGIN);
});
ui.add_space(MARGIN);

let rect = response.response.rect;
let rect = response.response.rect;

render_tee_for_ui(
pipe.user_data.canvas_handle,
pipe.user_data.skin_container,
pipe.user_data.render_tee,
ui,
ui_state,
ui.ctx().screen_rect(),
Some(ui.clip_rect()),
&msg.skin_name,
Some(&msg.skin_info),
vec2::new(
rect.min.x + MARGIN + TEE_SIZE / 2.0,
rect.min.y + TEE_SIZE / 2.0 + 5.0,
),
TEE_SIZE,
TeeEye::Normal,
);
},
);
render_tee_for_ui(
pipe.user_data.canvas_handle,
pipe.user_data.skin_container,
pipe.user_data.render_tee,
ui,
ui_state,
ui.ctx().screen_rect(),
Some(ui.clip_rect()),
&msg.skin_name,
Some(&msg.skin_info),
vec2::new(
rect.min.x + MARGIN + TEE_SIZE / 2.0,
rect.min.y + TEE_SIZE / 2.0 + 5.0,
),
TEE_SIZE,
TeeEye::Normal,
);
});
}
2 changes: 1 addition & 1 deletion game/client-ui/src/chat/chat_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use super::user_data::UserData;
pub fn render(ui: &mut egui::Ui, pipe: &mut UiRenderPipe<UserData>, ui_state: &mut UiState) {
ui.with_layout(Layout::bottom_up(egui::Align::Min), |ui| {
// active input comes first (most bottom)
super::input::render(ui, pipe);
super::input::render(ui, ui_state, pipe);

for msg in pipe.user_data.entries.iter() {
let time_diff = if pipe.user_data.show_chat_history {
Expand Down
Loading
Loading