mirror of
https://github.com/griffi-gh/kubi.git
synced 2024-11-22 06:48:43 -06:00
client networking calls
This commit is contained in:
parent
bcd3066c95
commit
8758938e7e
|
@ -51,7 +51,7 @@ pub enum ClientEvent<T> where T: Encode + Decode {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Client<S, R> where S: Encode + Decode, R: Encode + Decode {
|
pub struct Client<S, R> where S: Encode + Decode, R: Encode + Decode {
|
||||||
pub config: ClientConfig,
|
config: ClientConfig,
|
||||||
addr: SocketAddr,
|
addr: SocketAddr,
|
||||||
socket: UdpSocket,
|
socket: UdpSocket,
|
||||||
status: ClientStatus,
|
status: ClientStatus,
|
||||||
|
@ -125,6 +125,28 @@ impl<S, R> Client<S, R> where S: Encode + Decode, R: Encode + Decode {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_status(&self) -> ClientStatus {
|
||||||
|
self.status
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_connected(&self) -> bool {
|
||||||
|
self.status == ClientStatus::Connected
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_connecting(&self) -> bool {
|
||||||
|
self.status == ClientStatus::Connecting
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_disconnected(&self) -> bool {
|
||||||
|
self.status == ClientStatus::Disconnected
|
||||||
|
}
|
||||||
|
|
||||||
|
//Return true if the client has not made any connection attempts yet
|
||||||
|
pub fn has_not_made_connection_attempts(&self) -> bool {
|
||||||
|
matches!(self.status, ClientStatus::Disconnected) &&
|
||||||
|
matches!(self.disconnect_reason, DisconnectReason::NotConnected)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn send_message(&self, message: S) -> Result<()> {
|
pub fn send_message(&self, message: S) -> Result<()> {
|
||||||
if self.status != ClientStatus::Connected {
|
if self.status != ClientStatus::Connected {
|
||||||
bail!("Not Connected");
|
bail!("Not Connected");
|
||||||
|
@ -152,6 +174,7 @@ impl<S, R> Client<S, R> where S: Encode + Decode, R: Encode + Decode {
|
||||||
}
|
}
|
||||||
//receive
|
//receive
|
||||||
let mut buf = [0; u16::MAX as usize];
|
let mut buf = [0; u16::MAX as usize];
|
||||||
|
loop {
|
||||||
match self.socket.recv(&mut buf) {
|
match self.socket.recv(&mut buf) {
|
||||||
Ok(length) => {
|
Ok(length) => {
|
||||||
//TODO check the first byte of the raw data instead of decoding?
|
//TODO check the first byte of the raw data instead of decoding?
|
||||||
|
@ -183,12 +206,13 @@ impl<S, R> Client<S, R> where S: Encode + Decode, R: Encode + Decode {
|
||||||
Err(error) if error.kind() != ErrorKind::WouldBlock => {
|
Err(error) if error.kind() != ErrorKind::WouldBlock => {
|
||||||
return Err(error.into());
|
return Err(error.into());
|
||||||
},
|
},
|
||||||
_ => (),
|
_ => break,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_event(&mut self) -> Option<ClientEvent<R>> {
|
pub fn pop_event(&mut self) -> Option<ClientEvent<R>> {
|
||||||
self.event_queue.pop_front()
|
self.event_queue.pop_front()
|
||||||
}
|
}
|
||||||
pub fn process_events(&mut self) -> DrainDeque<ClientEvent<R>> {
|
pub fn process_events(&mut self) -> DrainDeque<ClientEvent<R>> {
|
||||||
|
|
|
@ -52,11 +52,25 @@ pub struct Server<S, R> where S: Encode + Decode, R: Encode + Decode {
|
||||||
_s: PhantomData<S>,
|
_s: PhantomData<S>,
|
||||||
}
|
}
|
||||||
impl<S, R> Server<S, R> where S: Encode + Decode, R: Encode + Decode {
|
impl<S, R> Server<S, R> where S: Encode + Decode, R: Encode + Decode {
|
||||||
|
pub fn bind(addr: SocketAddr, config: ServerConfig) -> anyhow::Result<Self> {
|
||||||
|
assert!(config.max_clients <= MAX_CLIENTS);
|
||||||
|
let socket = UdpSocket::bind(addr)?;
|
||||||
|
socket.set_nonblocking(true)?;
|
||||||
|
Ok(Self {
|
||||||
|
config,
|
||||||
|
socket,
|
||||||
|
clients: HashMap::with_capacity_and_hasher(MAX_CLIENTS, BuildNoHashHasher::default()),
|
||||||
|
event_queue: VecDeque::new(),
|
||||||
|
_s: PhantomData,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn send_to_addr(&self, addr: SocketAddr, packet: IdServerPacket<S>) -> Result<()> {
|
fn send_to_addr(&self, addr: SocketAddr, packet: IdServerPacket<S>) -> Result<()> {
|
||||||
let bytes = bincode::encode_to_vec(packet, BINCODE_CONFIG)?;
|
let bytes = bincode::encode_to_vec(packet, BINCODE_CONFIG)?;
|
||||||
self.socket.send_to(&bytes, addr)?;
|
self.socket.send_to(&bytes, addr)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_packet(&self, packet: IdServerPacket<S>) -> Result<()> {
|
fn send_packet(&self, packet: IdServerPacket<S>) -> Result<()> {
|
||||||
let Some(id) = packet.0 else {
|
let Some(id) = packet.0 else {
|
||||||
bail!("send_to_client call without id")
|
bail!("send_to_client call without id")
|
||||||
|
@ -67,6 +81,7 @@ impl<S, R> Server<S, R> where S: Encode + Decode, R: Encode + Decode {
|
||||||
self.send_to_addr(client.addr, packet)?;
|
self.send_to_addr(client.addr, packet)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_client(&mut self, addr: SocketAddr) -> Result<ClientId> {
|
fn add_client(&mut self, addr: SocketAddr) -> Result<ClientId> {
|
||||||
let Some(id) = (1..=self.config.max_clients)
|
let Some(id) = (1..=self.config.max_clients)
|
||||||
.map(|x| ClientId::new(x as _).unwrap())
|
.map(|x| ClientId::new(x as _).unwrap())
|
||||||
|
@ -83,6 +98,7 @@ impl<S, R> Server<S, R> where S: Encode + Decode, R: Encode + Decode {
|
||||||
});
|
});
|
||||||
Ok(id)
|
Ok(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn disconnect_client_inner(&mut self, id: ClientId, reason: String) -> Result<()> {
|
fn disconnect_client_inner(&mut self, id: ClientId, reason: String) -> Result<()> {
|
||||||
let result = self.send_packet(IdServerPacket(
|
let result = self.send_packet(IdServerPacket(
|
||||||
Some(id), ServerPacket::Disconnected(reason)
|
Some(id), ServerPacket::Disconnected(reason)
|
||||||
|
@ -98,6 +114,7 @@ impl<S, R> Server<S, R> where S: Encode + Decode, R: Encode + Decode {
|
||||||
self.disconnect_client_inner(id, reason)?;
|
self.disconnect_client_inner(id, reason)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn shutdown(mut self) -> Result<()> {
|
pub fn shutdown(mut self) -> Result<()> {
|
||||||
let clients = self.clients.keys().copied().collect::<Vec<ClientId>>();
|
let clients = self.clients.keys().copied().collect::<Vec<ClientId>>();
|
||||||
for id in clients {
|
for id in clients {
|
||||||
|
@ -105,25 +122,16 @@ impl<S, R> Server<S, R> where S: Encode + Decode, R: Encode + Decode {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_message(&mut self, id: ClientId, message: S) -> anyhow::Result<()> {
|
pub fn send_message(&mut self, id: ClientId, message: S) -> anyhow::Result<()> {
|
||||||
self.send_packet(IdServerPacket(Some(id), ServerPacket::Data(message)))?;
|
self.send_packet(IdServerPacket(Some(id), ServerPacket::Data(message)))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
pub fn bind(addr: SocketAddr, config: ServerConfig) -> anyhow::Result<Self> {
|
|
||||||
assert!(config.max_clients <= MAX_CLIENTS);
|
|
||||||
let socket = UdpSocket::bind(addr)?;
|
|
||||||
socket.set_nonblocking(true)?;
|
|
||||||
Ok(Self {
|
|
||||||
config,
|
|
||||||
socket,
|
|
||||||
clients: HashMap::with_capacity_and_hasher(MAX_CLIENTS, BuildNoHashHasher::default()),
|
|
||||||
event_queue: VecDeque::new(),
|
|
||||||
_s: PhantomData,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
pub fn update(&mut self) -> Result<()> {
|
pub fn update(&mut self) -> Result<()> {
|
||||||
//TODO client timeout
|
//TODO client timeout
|
||||||
let mut buf = [0; u16::MAX as usize];
|
let mut buf = [0; u16::MAX as usize];
|
||||||
|
loop {
|
||||||
match self.socket.recv_from(&mut buf) {
|
match self.socket.recv_from(&mut buf) {
|
||||||
Ok((len, addr)) => {
|
Ok((len, addr)) => {
|
||||||
if let Ok(packet) = bincode::decode_from_slice(&buf[..len], BINCODE_CONFIG) {
|
if let Ok(packet) = bincode::decode_from_slice(&buf[..len], BINCODE_CONFIG) {
|
||||||
|
@ -183,12 +191,13 @@ impl<S, R> Server<S, R> where S: Encode + Decode, R: Encode + Decode {
|
||||||
Err(error) if error.kind() != ErrorKind::WouldBlock => {
|
Err(error) if error.kind() != ErrorKind::WouldBlock => {
|
||||||
return Err(error.into());
|
return Err(error.into());
|
||||||
},
|
},
|
||||||
_ => (),
|
_ => break,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_event(&mut self) -> Option<ServerEvent<R>> {
|
pub fn pop_event(&mut self) -> Option<ServerEvent<R>> {
|
||||||
self.event_queue.pop_front()
|
self.event_queue.pop_front()
|
||||||
}
|
}
|
||||||
pub fn process_events(&mut self) -> DrainDeque<ServerEvent<R>> {
|
pub fn process_events(&mut self) -> DrainDeque<ServerEvent<R>> {
|
||||||
|
|
|
@ -63,16 +63,19 @@ use rendering::{
|
||||||
RenderTarget,
|
RenderTarget,
|
||||||
BackgroundColor,
|
BackgroundColor,
|
||||||
clear_background,
|
clear_background,
|
||||||
|
init_window_size,
|
||||||
|
update_window_size,
|
||||||
primitives::init_primitives,
|
primitives::init_primitives,
|
||||||
selection_box::render_selection_box,
|
selection_box::render_selection_box,
|
||||||
world::draw_world,
|
world::draw_world,
|
||||||
world::draw_current_chunk_border, init_window_size, update_window_size,
|
world::draw_current_chunk_border,
|
||||||
};
|
};
|
||||||
use block_placement::block_placement_system;
|
use block_placement::block_placement_system;
|
||||||
use delta_time::{DeltaTime, init_delta_time};
|
use delta_time::{DeltaTime, init_delta_time};
|
||||||
use cursor_lock::{insert_lock_state, update_cursor_lock_state, lock_cursor_now};
|
use cursor_lock::{insert_lock_state, update_cursor_lock_state, lock_cursor_now};
|
||||||
use control_flow::{exit_on_esc, insert_control_flow_unique, SetControlFlow};
|
use control_flow::{exit_on_esc, insert_control_flow_unique, SetControlFlow};
|
||||||
use state::{is_ingame, is_ingame_or_loading, is_loading, init_state, update_state};
|
use state::{is_ingame, is_ingame_or_loading, is_loading, init_state, update_state};
|
||||||
|
use networking::{update_networking, is_multiplayer};
|
||||||
use init::initialize_from_args;
|
use init::initialize_from_args;
|
||||||
use gui::{render_gui, init_gui, update_gui};
|
use gui::{render_gui, init_gui, update_gui};
|
||||||
use loading_screen::update_loading_screen;
|
use loading_screen::update_loading_screen;
|
||||||
|
@ -102,6 +105,9 @@ fn update() -> Workload {
|
||||||
update_cursor_lock_state,
|
update_cursor_lock_state,
|
||||||
process_inputs,
|
process_inputs,
|
||||||
exit_on_esc,
|
exit_on_esc,
|
||||||
|
(
|
||||||
|
update_networking
|
||||||
|
).into_workload().run_if(is_multiplayer),
|
||||||
(
|
(
|
||||||
update_loading_screen,
|
update_loading_screen,
|
||||||
).into_workload().run_if(is_loading),
|
).into_workload().run_if(is_loading),
|
||||||
|
@ -114,8 +120,8 @@ fn update() -> Workload {
|
||||||
update_raycasts,
|
update_raycasts,
|
||||||
block_placement_system,
|
block_placement_system,
|
||||||
apply_queued_blocks,
|
apply_queued_blocks,
|
||||||
).into_workload().run_if(is_ingame),
|
|
||||||
compute_cameras,
|
compute_cameras,
|
||||||
|
).into_workload().run_if(is_ingame),
|
||||||
update_gui,
|
update_gui,
|
||||||
update_state,
|
update_state,
|
||||||
).into_workload()
|
).into_workload()
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
use shipyard::{Unique, AllStoragesView, UniqueView, UniqueViewMut, Workload, IntoWorkload, WorkloadModificator};
|
use shipyard::{Unique, AllStoragesView, UniqueView, UniqueViewMut, Workload, IntoWorkload, WorkloadModificator, EntitiesView, EntitiesViewMut, Component, ViewMut, SystemModificator};
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use kubi_udp::client::{Client, ClientConfig};
|
use kubi_udp::client::{Client, ClientConfig, ClientEvent};
|
||||||
use kubi_shared::networking::{
|
use kubi_shared::networking::{
|
||||||
messages::{ClientToServerMessage, ServerToClientMessage},
|
messages::{ClientToServerMessage, ServerToClientMessage},
|
||||||
state::ClientJoinState
|
state::ClientJoinState
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::events::EventComponent;
|
||||||
|
|
||||||
#[derive(Unique, Clone, Copy, PartialEq, Eq)]
|
#[derive(Unique, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum GameType {
|
pub enum GameType {
|
||||||
Singleplayer,
|
Singleplayer,
|
||||||
|
@ -18,6 +20,9 @@ pub struct ServerAddress(pub SocketAddr);
|
||||||
#[derive(Unique)]
|
#[derive(Unique)]
|
||||||
pub struct UdpClient(pub Client<ClientToServerMessage, ServerToClientMessage>);
|
pub struct UdpClient(pub Client<ClientToServerMessage, ServerToClientMessage>);
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct NetworkEvent(pub ClientEvent<ServerToClientMessage>);
|
||||||
|
|
||||||
pub fn create_client(
|
pub fn create_client(
|
||||||
storages: AllStoragesView
|
storages: AllStoragesView
|
||||||
) {
|
) {
|
||||||
|
@ -29,34 +34,47 @@ pub fn create_client(
|
||||||
storages.add_unique(ClientJoinState::Disconnected);
|
storages.add_unique(ClientJoinState::Disconnected);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn client_connect(
|
pub fn connect_client(
|
||||||
mut client: UniqueViewMut<UdpClient>
|
mut client: UniqueViewMut<UdpClient>
|
||||||
) {
|
) {
|
||||||
client.0.connect().unwrap();
|
client.0.connect().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_client_and_get_events(
|
pub fn update_client(
|
||||||
mut client: UniqueViewMut<UdpClient>,
|
mut client: UniqueViewMut<UdpClient>,
|
||||||
) {
|
) {
|
||||||
client.0.update().unwrap();
|
client.0.update().unwrap();
|
||||||
for event in client.0.process_events() {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init_networking() -> Workload {
|
pub fn insert_client_events(
|
||||||
(
|
mut client: UniqueViewMut<UdpClient>,
|
||||||
create_client,
|
mut entities: EntitiesViewMut,
|
||||||
client_connect,
|
mut events: ViewMut<EventComponent>,
|
||||||
).into_workload().run_if(is_multiplayer)
|
mut network_events: ViewMut<NetworkEvent>,
|
||||||
|
) {
|
||||||
|
entities.bulk_add_entity((
|
||||||
|
&mut events,
|
||||||
|
&mut network_events,
|
||||||
|
), client.0.process_events().map(|event| {
|
||||||
|
(EventComponent, NetworkEvent(event))
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_networking() -> Workload {
|
pub fn update_networking() -> Workload {
|
||||||
(
|
(
|
||||||
update_client_and_get_events,
|
create_client.run_if_missing_unique::<UdpClient>(),
|
||||||
|
connect_client.run_if(client_needs_connect_call),
|
||||||
|
update_client,
|
||||||
|
insert_client_events,
|
||||||
).into_workload().run_if(is_multiplayer)
|
).into_workload().run_if(is_multiplayer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn client_needs_connect_call(
|
||||||
|
client: UniqueView<UdpClient>,
|
||||||
|
) -> bool {
|
||||||
|
client.0.has_not_made_connection_attempts()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_multiplayer(
|
pub fn is_multiplayer(
|
||||||
game_type: UniqueView<GameType>
|
game_type: UniqueView<GameType>
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
|
Loading…
Reference in a new issue