Files
guardian/crates/guardian_core/src/dcs/text.rs
2023-12-23 08:53:46 +01:00

136 lines
3.4 KiB
Rust

use std::{
borrow::Cow,
hash::{Hash, Hasher},
};
use bevy::{
app::{Plugin, PostUpdate},
ecs::{
component::Component,
entity::Entity,
query::Added,
reflect::ReflectComponent,
system::{Commands, Query, Res},
},
reflect::{std_traits::ReflectDefault, Reflect},
utils::AHasher,
};
use dcs_grpc::dcs::{
common::v0::Coalition,
net::v0::{net_service_client::NetServiceClient, SendChatRequest},
};
use crate::{components::GrpcBaseUrl, TokioResource};
pub struct TextPlugin;
impl Plugin for TextPlugin {
fn build(&self, app: &mut bevy::prelude::App) {
app.add_systems(PostUpdate, send_text_message);
}
}
fn send_text_message(
mut commands: Commands,
query: Query<(Entity, &TextMessage), Added<TextMessage>>,
url: Res<GrpcBaseUrl>,
tokio: Res<TokioResource>,
) {
let url = url.to_string();
for (ent, msg) in query.iter() {
if msg.as_str().is_empty() {
commands.entity(ent).remove::<TextMessage>().despawn();
continue;
}
let message = msg.clone();
let url = url.clone();
tokio.0.spawn(async move {
let Ok(mut client) = NetServiceClient::connect(url.to_string()).await else {
return;
};
let request = SendChatRequest {
message: message.to_string(),
coalition: Coalition::All as i32,
// target_player_id: player_id,
};
println!("> {}", message);
client.send_chat(request).await.ok();
});
commands.entity(ent).remove::<TextMessage>().despawn();
}
}
#[derive(Reflect, Component, Clone)]
#[reflect(Component, Default, Debug)]
pub struct TextMessage {
hash: u64,
message: Cow<'static, str>,
}
impl Default for TextMessage {
fn default() -> Self {
TextMessage::new("")
}
}
impl TextMessage {
/// Creates a new [`TextMessage`] from any string-like type.
///
/// The internal hash will be computed immediately.
pub fn new(message: impl Into<Cow<'static, str>>) -> Self {
let message = message.into();
let mut message = TextMessage { message, hash: 0 };
message.update_hash();
message
}
/// Sets the entity's message.
///
/// The internal hash will be re-computed.
#[inline(always)]
pub fn set(&mut self, message: impl Into<Cow<'static, str>>) {
*self = TextMessage::new(message);
}
/// Updates the message of the entity in place.
///
/// This will allocate a new string if the message was previously
/// created from a borrow.
#[inline(always)]
pub fn mutate<F: FnOnce(&mut String)>(&mut self, f: F) {
f(self.message.to_mut());
self.update_hash();
}
/// Gets the message of the entity as a `&str`.
#[inline(always)]
pub fn as_str(&self) -> &str {
&self.message
}
fn update_hash(&mut self) {
let mut hasher = AHasher::default();
self.message.hash(&mut hasher);
self.hash = hasher.finish();
}
}
impl std::fmt::Display for TextMessage {
#[inline(always)]
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
std::fmt::Display::fmt(&self.message, f)
}
}
impl std::fmt::Debug for TextMessage {
#[inline(always)]
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
std::fmt::Debug::fmt(&self.message, f)
}
}