Skip to content

Commit

Permalink
Merge pull request #7 from Jupeyy/pr_whisper
Browse files Browse the repository at this point in the history
Add whisper functionalty (client side), some server fixes
  • Loading branch information
Jupeyy authored Jan 3, 2025
2 parents bc3b49b + 7fbd9a0 commit ee7e250
Show file tree
Hide file tree
Showing 9 changed files with 514 additions and 142 deletions.
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

0 comments on commit ee7e250

Please sign in to comment.