M crates/client/Cargo.toml => crates/client/Cargo.toml +2 -0
@@ 24,6 24,7 @@ nalgebra = "0.33"
starkingdoms-common = { version = "0.1", path = "../common" }
serde = "1"
serde_json = "1"
+crossbeam = "0.8.4"
# WASM dependencies
[target.'cfg(target_arch = "wasm32")'.dependencies]
@@ 37,3 38,4 @@ reqwest = "0.11"
# Native dependencies
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
pollster = "0.4"
+tungstenite = "0.26.1"
M crates/client/src/lib.rs => crates/client/src/lib.rs +1 -2
@@ 3,7 3,6 @@ use crate::input::MouseWheelEvent;
use crate::rendering::ui::UiRenderable;
use crate::rendering::App;
use bevy_ecs::event::{EventReader, Events};
-use bevy_ecs::observer::Trigger;
use bevy_ecs::schedule::Schedule;
use bevy_ecs::system::ResMut;
use bevy_ecs::world::World;
@@ 50,7 49,7 @@ pub fn start() {
zoom: 1.0,
});
world.insert_resource(Assets::new());
- world.insert_resource(Ws::new().expect("Couldn't connect to server"));
+ world.insert_resource(Ws::new());
let send_packet_events = Events::<SendPacket>::default();
let recv_packet_events = Events::<RecvPacket>::default();
M crates/client/src/networking/ws_native.rs => crates/client/src/networking/ws_native.rs +61 -0
@@ 0,0 1,61 @@
+use std::{net::TcpStream, sync::{Arc, Mutex}};
+
+use bevy_ecs::system::Resource;
+use crossbeam::channel::{unbounded, Receiver, Sender};
+use starkingdoms_common::packet::{MsgFromError, Packet};
+use tungstenite::{connect, stream::MaybeTlsStream, Message, WebSocket};
+
+pub trait PacketMessageConvert {
+ fn from_message(value: &Message) -> Result<Packet, MsgFromError>;
+ fn into_message(&self) -> Message;
+}
+
+impl PacketMessageConvert for Packet {
+ fn from_message(value: &Message) -> Result<Packet, MsgFromError> {
+ match value {
+ Message::Text(s) => serde_json::from_str(s).map_err(MsgFromError::JSONError),
+ Message::Binary(b) => serde_json::from_slice(b).map_err(MsgFromError::JSONError),
+ Message::Close(_) => Ok(Packet::_SpecialDisconnect {}),
+ Message::Frame(_) | Message::Pong(_) | Message::Ping(_) => {
+ Err(MsgFromError::InvalidMessageType)
+ }
+ }
+ }
+ fn into_message(&self) -> Message {
+ Message::Text(serde_json::to_string(self).expect("failed to serialize packet to json").into())
+ }
+}
+
+#[derive(Resource, Debug)]
+pub struct Ws {
+ socket: Arc<Mutex<WebSocket<MaybeTlsStream<TcpStream>>>>,
+ pub sender: Sender<Packet>,
+ pub receiver: Receiver<Packet>,
+ packet_receiver: Receiver<Packet>,
+}
+impl Ws {
+ pub fn new() -> Self {
+ let (socket, _) = connect("ws://localhost:3000").expect("Failed to connect to server");
+ let socket = Arc::new(Mutex::new(socket));
+ let (packet_sender, receiver) = unbounded();
+ let (sender, packet_receiver) = unbounded();
+ let socket_clone = socket.clone();
+ std::thread::spawn(move || {
+ let socket = socket_clone;
+ loop {
+ let message = socket.lock().unwrap().read().expect("Failed to reading message");
+ let packet = Packet::from_message(&message).expect("Server sent invalid packet");
+ packet_sender.send(packet).expect("Couldn't send packet to server");
+ }
+ });
+ Ws {
+ socket,
+ sender,
+ receiver,
+ packet_receiver,
+ }
+ }
+ pub fn send_packet(&mut self, packet: &Packet) {
+ self.socket.lock().unwrap().send(packet.into_message()).expect("Couldn't send packet to server");
+ }
+}
M crates/client/src/networking/ws_wasm.rs => crates/client/src/networking/ws_wasm.rs +10 -8
@@ 1,6 1,7 @@
use std::{any::Any, cell::{OnceCell, RefCell}, rc::Rc, sync::{Arc, Mutex, RwLock}};
-use bevy_ecs::{system::Resource, world::World};
+use bevy_ecs::system::Resource;
+//use crossbeam::channel::{unbounded, Receiver, Sender};
use futures::{channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender}, SinkExt};
use wasm_bindgen::{prelude::Closure, JsCast, JsValue};
use wasm_bindgen_futures::spawn_local;
@@ 25,12 26,12 @@ pub struct Ws {
}
impl Ws {
- pub fn new() -> Result<Self, JsValue> {
+ pub fn new() -> Self {
let window = web_sys::window().unwrap();
let ws = WebSocket::new(&format!("ws://{}:{}",
- window.location().hostname().unwrap(), PORT))?;
+ window.location().hostname().unwrap(), PORT)).expect("Couldn't connect to server");
let (packet_sender, receiver) = unbounded();
- let packet_sender = Rc::new(RwLock::new(packet_sender));
+ //let packet_sender = Rc::new(RwLock::new(packet_sender));
let (sender, packet_receiver) = unbounded();
/*let onopen_callback = Closure::<dyn FnMut()>::new(move || {
@@ 42,21 43,22 @@ impl Ws {
//tracing::error!("{}", ws.ready_state());
let data = e.data().as_string().expect("Expected string, found some other type");
let data: Packet = serde_json::from_str(&data).expect("Received invalid json from server");
- let sender_clone = packet_sender.clone();
+ let mut sender_clone = packet_sender.clone();
spawn_local(async move {
- sender_clone.write().unwrap().send(data).await.expect("Couldn't transmit packet to client");
+ sender_clone.send(data).await.expect("Couldn't transmit packet to client");
});
});
ws.set_onmessage(Some(onmessage_callback.as_ref().unchecked_ref()));
onmessage_callback.forget();
- Ok(Ws {
+ Ws {
socket: Socket(ws),
sender,
receiver,
packet_receiver,
- })
+ }
}
pub fn send_all_packets_from_channel(&mut self) {
+ //for packet in self.packet_receiver.iter() {
while let Ok(Some(packet)) = self.packet_receiver.try_next() {
self.socket.0.send_with_str(&serde_json::to_string(&packet).expect("Couldn't convert packet to json")).expect("Couldn't send packet to server");
}
M crates/client/src/rendering/mod.rs => crates/client/src/rendering/mod.rs +4 -2
@@ 213,10 213,12 @@ impl<T: UiRenderable + 'static> ApplicationHandler for App<T> {
let world = self.world.take().unwrap();
let update_schedule = self.update_schedule.take().unwrap();
let ui_renderable = self.ui_renderable.take().unwrap();
+ let send_packet_events = self.send_packet_events.take().unwrap();
+ let recv_packet_events = self.recv_packet_events.take().unwrap();
let renderer = pollster::block_on(async move {
- Renderer::try_init(window.clone(), world, update_schedule, ui_renderable)
- .await
+ Renderer::try_init(window.clone(), world, update_schedule,
+ ui_renderable, send_packet_events, recv_packet_events).await
});
match renderer {
M crates/client/src/rendering/renderer.rs => crates/client/src/rendering/renderer.rs +5 -1
@@ 9,7 9,6 @@ use bevy_ecs::event::Events;
use bevy_ecs::schedule::Schedule;
use bevy_ecs::world::World;
use egui::ViewportId;
-use futures::SinkExt;
use std::collections::HashMap;
use std::fmt::{Debug, Formatter};
use std::sync::Arc;
@@ 216,9 215,14 @@ impl<T: UiRenderable> Renderer<T> {
pub fn render(&mut self) {
let mut ws = self.world.get_resource_mut::<Ws>().expect("Failed to get Ws resource");
+ #[cfg(target_arch = "wasm32")]
while let Ok(Some(packet)) = ws.receiver.try_next() {
self.recv_packet_events.send(RecvPacket(packet));
}
+ #[cfg(not(target_arch = "wasm32"))]
+ for packet in ws.receiver.iter() {
+ self.recv_packet_events.send(RecvPacket(packet));
+ }
// update the world
self.update_schedule.run(&mut self.world);
self.send_packet_events.update();