No more panics :)
This commit is contained in:
parent
dad37262a5
commit
e81b6fa1fa
1 changed files with 77 additions and 45 deletions
122
src/net.rs
122
src/net.rs
|
@ -1,18 +1,67 @@
|
||||||
use std::{
|
use std::{
|
||||||
net::{Ipv6Addr, SocketAddr, UdpSocket},
|
net::{Ipv6Addr, SocketAddr, UdpSocket},
|
||||||
thread,
|
thread::{JoinHandle, spawn},
|
||||||
};
|
};
|
||||||
|
|
||||||
use bevy::prelude::*;
|
use bevy::{prelude::*, tasks::futures_lite::io};
|
||||||
use crossbeam_channel::{Receiver, Sender, unbounded};
|
use crossbeam_channel::{Receiver, Sender, unbounded};
|
||||||
|
|
||||||
use crate::game::seed::Seed;
|
use crate::game::seed::Seed;
|
||||||
|
|
||||||
#[derive(Resource)]
|
fn configure_socket(socket: &UdpSocket) -> io::Result<()> {
|
||||||
pub struct NetworkSend(Sender<(u64, SocketAddr)>);
|
socket.set_read_timeout(None)?;
|
||||||
|
socket.set_write_timeout(None)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
type NetworkMessage = (u64, SocketAddr);
|
||||||
|
|
||||||
|
fn start_network_thread<M: Send + 'static>(
|
||||||
|
network_loop: fn(M, UdpSocket) -> Result,
|
||||||
|
messages: M,
|
||||||
|
socket: UdpSocket,
|
||||||
|
) -> JoinHandle<Result> {
|
||||||
|
spawn(move || {
|
||||||
|
let result = network_loop(messages, socket);
|
||||||
|
match result {
|
||||||
|
Ok(()) => error!("Network thread: Loop returned without error?"),
|
||||||
|
Err(ref err) => error!("Network thread: {}", err),
|
||||||
|
};
|
||||||
|
result
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn network_send_loop(messages: Receiver<NetworkMessage>, socket: UdpSocket) -> Result {
|
||||||
|
loop {
|
||||||
|
let (message, address) = messages.recv()?;
|
||||||
|
socket.send_to(&message.to_le_bytes(), address)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn network_receive_loop(messages: Sender<NetworkMessage>, socket: UdpSocket) -> Result {
|
||||||
|
loop {
|
||||||
|
let mut message = [0u8; 8];
|
||||||
|
let (len, address) = socket.recv_from(&mut message)?;
|
||||||
|
info!("Network thread: Received {len} bytes");
|
||||||
|
messages.try_send((u64::from_le_bytes(message), address))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_socket(port: u16) -> Result<(Sender<NetworkMessage>, Receiver<NetworkMessage>)> {
|
||||||
|
let socket = UdpSocket::bind((Ipv6Addr::LOCALHOST, port))?;
|
||||||
|
configure_socket(&socket)?;
|
||||||
|
let (send_inbound, receive_inbound) = unbounded();
|
||||||
|
start_network_thread(network_receive_loop, send_inbound, socket.try_clone()?);
|
||||||
|
let (send_outbound, receive_outbound) = unbounded();
|
||||||
|
start_network_thread(network_send_loop, receive_outbound, socket);
|
||||||
|
Ok((send_outbound, receive_inbound))
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
pub struct NetworkReceive(Receiver<(u64, SocketAddr)>);
|
pub struct NetworkSend(Sender<NetworkMessage>);
|
||||||
|
|
||||||
|
#[derive(Resource)]
|
||||||
|
pub struct NetworkReceive(Receiver<NetworkMessage>);
|
||||||
|
|
||||||
fn handle_network_io(
|
fn handle_network_io(
|
||||||
receive: Res<NetworkReceive>,
|
receive: Res<NetworkReceive>,
|
||||||
|
@ -31,6 +80,13 @@ fn handle_network_io(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(States, Default, Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
enum NetworkState {
|
||||||
|
#[default]
|
||||||
|
SinglePlayer,
|
||||||
|
MultiPlayer,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct NetIOPlugin {
|
pub struct NetIOPlugin {
|
||||||
listen: u16,
|
listen: u16,
|
||||||
peer: Option<SocketAddr>,
|
peer: Option<SocketAddr>,
|
||||||
|
@ -44,51 +100,27 @@ impl NetIOPlugin {
|
||||||
|
|
||||||
impl Plugin for NetIOPlugin {
|
impl Plugin for NetIOPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.add_systems(FixedUpdate, handle_network_io);
|
app.init_state::<NetworkState>().add_systems(
|
||||||
|
FixedUpdate,
|
||||||
|
handle_network_io.run_if(in_state(NetworkState::MultiPlayer)),
|
||||||
|
);
|
||||||
|
|
||||||
let (send, receive) = match UdpSocket::bind((Ipv6Addr::LOCALHOST, self.listen)) {
|
match setup_socket(self.listen) {
|
||||||
Ok(socket) => {
|
Ok((send, receive)) => {
|
||||||
socket.set_read_timeout(None).unwrap();
|
if let Some(socket) = self.peer {
|
||||||
socket.set_write_timeout(None).unwrap();
|
if let Err(err) = send.try_send((0, socket)) {
|
||||||
let (send_outbound, receive_outbound) = unbounded::<(u64, SocketAddr)>();
|
warn!("Failed to send to peer: {err}");
|
||||||
let send_socket = socket.try_clone().unwrap();
|
return;
|
||||||
thread::spawn(move || {
|
|
||||||
loop {
|
|
||||||
match receive_outbound.recv() {
|
|
||||||
Ok((message, address)) => send_socket
|
|
||||||
.send_to(&message.to_le_bytes(), address)
|
|
||||||
.unwrap(),
|
|
||||||
Err(err) => {
|
|
||||||
error!("{err}");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
let (send_inbound, receive_inbound) = unbounded::<(u64, SocketAddr)>();
|
|
||||||
thread::spawn(move || {
|
app.insert_state(NetworkState::MultiPlayer)
|
||||||
loop {
|
.insert_resource(NetworkSend(send))
|
||||||
let mut message = [0u8; 8];
|
.insert_resource(NetworkReceive(receive));
|
||||||
let (len, address) = socket.recv_from(&mut message).unwrap();
|
|
||||||
info!("Received {len} bytes");
|
|
||||||
send_inbound
|
|
||||||
.try_send((u64::from_le_bytes(message), address))
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
(send_outbound, receive_inbound)
|
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!("Could not bind socket: {err}");
|
warn!("Failed to set up networking: {err}");
|
||||||
todo!("bounded(0) is apparently meaningful so find another solution")
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(socket) = self.peer {
|
|
||||||
send.try_send((0, socket)).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
app.insert_resource(NetworkSend(send));
|
|
||||||
app.insert_resource(NetworkReceive(receive));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue