use std::i32; use godot::{ classes::{ Engine, IVBoxContainer, InputEvent, LineEdit, RichTextLabel, ScrollContainer, VBoxContainer, }, global::HorizontalAlignment, prelude::*, }; use crate::{ chat::Chat, game_manager::Game, net::network_manager::{NetworkManager, Package, PeerKind}, }; #[derive(GodotClass)] #[class(base=VBoxContainer, tool)] pub struct ChatBox { #[export] scroll: Option>, #[export] messages: Option>, #[export] line_edit: Option>, #[export] pub in_game: bool, #[export] text_alignment: HorizontalAlignment, scroll_on_next_update: bool, base: Base, } #[godot_api] impl IVBoxContainer for ChatBox { fn init(base: Base) -> ChatBox { ChatBox { scroll: None, messages: None, line_edit: None, in_game: false, text_alignment: HorizontalAlignment::LEFT, scroll_on_next_update: false, base, } } fn ready(&mut self) { if !Engine::singleton().is_editor_hint() { self.run_deferred(|s| { if let Some(chat) = Chat::singleton() { for message in chat.bind().get_messages() { s.on_new_message(message); } chat.signals() .on_new_message() .connect_other(s, |s, m| s.run_deferred(|s| s.on_new_message(m))); } }); if let Some(line_edit) = self.line_edit.clone() { line_edit .signals() .text_submitted() .connect_other(self, Self::on_submit); } } if self.in_game && let Some(line_edit) = &mut self.line_edit { line_edit.set_visible(false); } } fn process(&mut self, _: f64) { if self.scroll_on_next_update && let Some(scroll) = &mut self.scroll { scroll.set_v_scroll(i32::MAX); self.scroll_on_next_update = false; } } fn input(&mut self, event: Gd) { if self.in_game && event.is_action_pressed("open_chat") { if let Some(line_edit) = &mut self.line_edit { let is_visible = line_edit.is_visible(); if !is_visible { line_edit.set_visible(true); let mut line_edit = line_edit.clone(); self.run_deferred(move |_| { if line_edit.is_visible() { line_edit.grab_focus(); } }); self.signals().on_opened().emit(); } } } } } #[godot_api] impl ChatBox { #[signal] pub fn on_opened(); #[signal] pub fn on_closed(); fn on_new_message(&mut self, mut message: Gd) { message.set_horizontal_alignment(self.text_alignment); if let Some(messages) = &mut self.messages { messages.add_child(&message); } self.scroll_on_next_update = true; } pub fn on_submit(&mut self, message: GString) { let message = message.to_string().trim().to_owned(); if let Some(line_edit) = &mut self.line_edit { line_edit.clear(); if self.in_game { line_edit.set_visible(false); } } self.signals().on_closed().emit(); if message.is_empty() { return; } if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer { match peer { PeerKind::Client(peer, socket_addr) => { peer.send_reliable(socket_addr, Package::ChatMessage(0, message.to_string())); } PeerKind::Server(..) => { self.run_deferred(move |_| { if let Some(game) = &mut Game::singleton() { let self_id = game.bind().self_id; game.bind_mut() .on_chat_message(self_id.unwrap_or(0), message.to_string()); } }); } } } } pub fn is_editing(&self) -> bool { if let Some(line_edit) = &self.line_edit { line_edit.is_visible() } else { false } } }