136 lines
3.4 KiB
Rust
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)
|
|
}
|
|
}
|