mirror of
https://github.com/griffi-gh/kubi.git
synced 2024-12-26 21:58:20 -06:00
Big refactor + Early wip position sync /connect events in multiplayer
This commit is contained in:
parent
c0ce1c71d9
commit
163298fe38
|
@ -1,4 +1,5 @@
|
||||||
use shipyard::{UniqueView, NonSendSync, EntitiesViewMut, ViewMut, UniqueViewMut, AllStoragesView};
|
use glam::{Vec3, Mat4, vec3};
|
||||||
|
use shipyard::{UniqueView, NonSendSync, EntitiesViewMut, ViewMut, UniqueViewMut, AllStoragesView, IntoIter};
|
||||||
use uflow::{server::Event as ServerEvent, SendMode};
|
use uflow::{server::Event as ServerEvent, SendMode};
|
||||||
use kubi_shared::{
|
use kubi_shared::{
|
||||||
networking::{
|
networking::{
|
||||||
|
@ -6,9 +7,11 @@ use kubi_shared::{
|
||||||
ClientToServerMessage,
|
ClientToServerMessage,
|
||||||
ServerToClientMessage,
|
ServerToClientMessage,
|
||||||
InitData,
|
InitData,
|
||||||
C_CLIENT_HELLO
|
ClientInitData,
|
||||||
|
C_CLIENT_HELLO,
|
||||||
},
|
},
|
||||||
client::{Client, ClientId}, channels::CHANNEL_AUTH
|
client::{Client, ClientId, Username},
|
||||||
|
channels::{CHANNEL_AUTH, CHANNEL_SYS_EVT},
|
||||||
},
|
},
|
||||||
player::{Player, PLAYER_HEALTH},
|
player::{Player, PLAYER_HEALTH},
|
||||||
transform::Transform, entity::{Entity, Health}
|
transform::Transform, entity::{Entity, Health}
|
||||||
|
@ -99,13 +102,15 @@ pub fn authenticate_players(
|
||||||
&mut storages.borrow::<ViewMut<Client>>().unwrap(),
|
&mut storages.borrow::<ViewMut<Client>>().unwrap(),
|
||||||
&mut storages.borrow::<ViewMut<ClientAddress>>().unwrap(),
|
&mut storages.borrow::<ViewMut<ClientAddress>>().unwrap(),
|
||||||
&mut storages.borrow::<ViewMut<Transform>>().unwrap(),
|
&mut storages.borrow::<ViewMut<Transform>>().unwrap(),
|
||||||
|
&mut storages.borrow::<ViewMut<Username>>().unwrap(),
|
||||||
), (
|
), (
|
||||||
Entity,
|
Entity,
|
||||||
Player,
|
Player,
|
||||||
Health::new(PLAYER_HEALTH),
|
Health::new(PLAYER_HEALTH),
|
||||||
Client(client_id),
|
Client(client_id),
|
||||||
ClientAddress(*client_addr),
|
ClientAddress(*client_addr),
|
||||||
Transform::default(),
|
Transform(Mat4::from_translation(vec3(0., 60., 0.))),
|
||||||
|
Username(username.clone()),
|
||||||
))
|
))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -113,12 +118,60 @@ pub fn authenticate_players(
|
||||||
client_entity_map.0.insert(client_id, entity_id);
|
client_entity_map.0.insert(client_id, entity_id);
|
||||||
client_addr_map.0.insert(*client_addr, entity_id);
|
client_addr_map.0.insert(*client_addr, entity_id);
|
||||||
|
|
||||||
//Approve the user
|
//Create init data
|
||||||
|
let init_data = {
|
||||||
|
let mut user = None;
|
||||||
|
let mut users = Vec::with_capacity(client_entity_map.0.len() - 1);
|
||||||
|
for (client, username, transform, &health) in (
|
||||||
|
&storages.borrow::<ViewMut<Client>>().unwrap(),
|
||||||
|
&storages.borrow::<ViewMut<Username>>().unwrap(),
|
||||||
|
&storages.borrow::<ViewMut<Transform>>().unwrap(),
|
||||||
|
&storages.borrow::<ViewMut<Health>>().unwrap(),
|
||||||
|
).iter() {
|
||||||
|
let (_, direction, position) = transform.0.to_scale_rotation_translation();
|
||||||
|
let idata = ClientInitData {
|
||||||
|
client_id: client.0,
|
||||||
|
username: username.0.clone(),
|
||||||
|
position,
|
||||||
|
velocity: Vec3::ZERO,
|
||||||
|
direction,
|
||||||
|
health,
|
||||||
|
};
|
||||||
|
if client_id == client.0 {
|
||||||
|
user = Some(idata);
|
||||||
|
} else {
|
||||||
|
users.push(idata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
InitData {
|
||||||
|
user: user.unwrap(),
|
||||||
|
users
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//Announce new player to other clients
|
||||||
|
{
|
||||||
|
let message = &ServerToClientMessage::PlayerConnected {
|
||||||
|
init: init_data.user.clone()
|
||||||
|
};
|
||||||
|
for (other_client_addr, _) in client_addr_map.0.iter() {
|
||||||
|
//TODO: ONLY JOINED CLIENTS HERE!
|
||||||
|
let Some(other_client) = server.0.client(other_client_addr) else {
|
||||||
|
log::error!("Other client doesn't exist");
|
||||||
|
continue
|
||||||
|
};
|
||||||
|
other_client.borrow_mut().send(
|
||||||
|
postcard::to_allocvec(&message).unwrap().into_boxed_slice(),
|
||||||
|
CHANNEL_SYS_EVT,
|
||||||
|
SendMode::Reliable
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Approve the user and send init data
|
||||||
client.borrow_mut().send(
|
client.borrow_mut().send(
|
||||||
postcard::to_allocvec(&ServerToClientMessage::ServerHello {
|
postcard::to_allocvec(&ServerToClientMessage::ServerHello {
|
||||||
init: InitData {
|
init: init_data
|
||||||
users: vec![] //TODO create init data
|
|
||||||
}
|
|
||||||
}).unwrap().into_boxed_slice(),
|
}).unwrap().into_boxed_slice(),
|
||||||
CHANNEL_AUTH,
|
CHANNEL_AUTH,
|
||||||
SendMode::Reliable
|
SendMode::Reliable
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
use shipyard::{Component, EntityId, Unique, AllStoragesView};
|
use shipyard::{Component, EntityId, Unique, AllStoragesView, UniqueView, NonSendSync, View, Get};
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
pub use kubi_shared::networking::client::ClientIdMap;
|
use uflow::server::Event as ServerEvent;
|
||||||
|
use kubi_shared::networking::{
|
||||||
|
client::{ClientIdMap, Client},
|
||||||
|
messages::{ClientToServerMessage, C_POSITION_CHANGED}
|
||||||
|
};
|
||||||
|
use crate::server::{ServerEvents, IsMessageOfType, UdpServer};
|
||||||
|
|
||||||
#[derive(Component, Clone, Copy)]
|
#[derive(Component, Clone, Copy)]
|
||||||
pub struct ClientAddress(pub SocketAddr);
|
pub struct ClientAddress(pub SocketAddr);
|
||||||
|
@ -18,3 +23,40 @@ pub fn init_client_maps(
|
||||||
storages.add_unique(ClientIdMap::new());
|
storages.add_unique(ClientIdMap::new());
|
||||||
storages.add_unique(ClientAddressMap::new());
|
storages.add_unique(ClientAddressMap::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sync_client_positions(
|
||||||
|
server: NonSendSync<UniqueView<UdpServer>>,
|
||||||
|
events: UniqueView<ServerEvents>,
|
||||||
|
addr_map: UniqueView<ClientAddressMap>,
|
||||||
|
clients: View<Client>,
|
||||||
|
) {
|
||||||
|
for event in &events.0 {
|
||||||
|
let ServerEvent::Receive(client_addr, data) = event else{
|
||||||
|
continue
|
||||||
|
};
|
||||||
|
if !event.is_message_of_type::<C_POSITION_CHANGED>() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
let Some(client) = server.0.client(client_addr) else {
|
||||||
|
log::error!("Client doesn't exist");
|
||||||
|
continue
|
||||||
|
};
|
||||||
|
let Some(&entity_id) = addr_map.0.get(client_addr) else {
|
||||||
|
log::error!("Client not authenticated");
|
||||||
|
continue
|
||||||
|
};
|
||||||
|
let Ok(&Client(client_id)) = (&clients).get(entity_id) else {
|
||||||
|
log::error!("Entity ID is invalid");
|
||||||
|
continue
|
||||||
|
};
|
||||||
|
let Ok(parsed_message) = postcard::from_bytes(data) else {
|
||||||
|
log::error!("Malformed message");
|
||||||
|
continue
|
||||||
|
};
|
||||||
|
let ClientToServerMessage::PositionChanged { position, velocity, direction } = parsed_message else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -13,10 +13,11 @@ use uflow::{
|
||||||
use lz4_flex::compress_prepend_size as lz4_compress;
|
use lz4_flex::compress_prepend_size as lz4_compress;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use std::{rc::Rc, cell::RefCell};
|
use std::{rc::Rc, cell::RefCell};
|
||||||
|
use kubi_shared::networking::client::ClientIdMap;
|
||||||
use crate::{
|
use crate::{
|
||||||
server::{UdpServer, ServerEvents, IsMessageOfType},
|
server::{UdpServer, ServerEvents, IsMessageOfType},
|
||||||
config::ConfigTable,
|
config::ConfigTable,
|
||||||
client::{ClientAddress, ClientIdMap, ClientAddressMap},
|
client::{ClientAddress, ClientAddressMap},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod chunk;
|
pub mod chunk;
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
use shipyard::Component;
|
use shipyard::Component;
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct Entity;
|
pub struct Entity;
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component, Serialize, Deserialize, Clone, Copy, Debug)]
|
||||||
pub struct Health {
|
pub struct Health {
|
||||||
pub current: u8,
|
pub current: u8,
|
||||||
pub max: u8,
|
pub max: u8,
|
||||||
|
@ -16,3 +17,19 @@ impl Health {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl PartialEq for Health {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.current == other.current
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Eq for Health {}
|
||||||
|
impl PartialOrd for Health {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
|
self.current.partial_cmp(&other.current)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Ord for Health {
|
||||||
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||||
|
self.current.cmp(&other.current)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -3,3 +3,4 @@ pub const CHANNEL_AUTH: usize = 1;
|
||||||
pub const CHANNEL_WORLD: usize = 2;
|
pub const CHANNEL_WORLD: usize = 2;
|
||||||
pub const CHANNEL_BLOCK: usize = 3;
|
pub const CHANNEL_BLOCK: usize = 3;
|
||||||
pub const CHANNEL_MOVE: usize = 4;
|
pub const CHANNEL_MOVE: usize = 4;
|
||||||
|
pub const CHANNEL_SYS_EVT: usize = 5;
|
||||||
|
|
|
@ -4,16 +4,24 @@ use nohash_hasher::BuildNoHashHasher;
|
||||||
|
|
||||||
pub type ClientId = u16;
|
pub type ClientId = u16;
|
||||||
|
|
||||||
|
#[derive(Component, Clone, Debug)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct Username(pub String);
|
||||||
|
|
||||||
#[derive(Component, Clone, Copy, Debug)]
|
#[derive(Component, Clone, Copy, Debug)]
|
||||||
|
#[repr(transparent)]
|
||||||
pub struct Client(pub ClientId);
|
pub struct Client(pub ClientId);
|
||||||
|
|
||||||
#[derive(Unique)]
|
#[derive(Unique)]
|
||||||
|
#[repr(transparent)]
|
||||||
pub struct ClientIdMap(pub HashMap<ClientId, EntityId, BuildNoHashHasher<ClientId>>);
|
pub struct ClientIdMap(pub HashMap<ClientId, EntityId, BuildNoHashHasher<ClientId>>);
|
||||||
|
|
||||||
impl ClientIdMap {
|
impl ClientIdMap {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self(HashMap::with_capacity_and_hasher(16, BuildNoHashHasher::default()))
|
Self(HashMap::with_capacity_and_hasher(16, BuildNoHashHasher::default()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ClientIdMap {
|
impl Default for ClientIdMap {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new()
|
Self::new()
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use glam::{Vec3, IVec3, Quat};
|
use glam::{Vec3, IVec3, Quat};
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use crate::{chunk::BlockData, queue::QueuedBlock};
|
use crate::{chunk::BlockData, queue::QueuedBlock, entity::Health};
|
||||||
use super::client::ClientId;
|
use super::client::ClientId;
|
||||||
|
|
||||||
//protocol id not used yet
|
//protocol id not used yet
|
||||||
|
@ -41,6 +41,7 @@ pub const S_PLAYER_POSITION_CHANGED: u8 = 2;
|
||||||
pub const S_CHUNK_RESPONSE: u8 = 3;
|
pub const S_CHUNK_RESPONSE: u8 = 3;
|
||||||
pub const S_QUEUE_BLOCK: u8 = 4;
|
pub const S_QUEUE_BLOCK: u8 = 4;
|
||||||
pub const S_PLAYER_CONNECTED: u8 = 5;
|
pub const S_PLAYER_CONNECTED: u8 = 5;
|
||||||
|
pub const S_PLAYER_DISCONNECTED: u8 = 6;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone)]
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
|
@ -52,7 +53,7 @@ pub enum ServerToClientMessage {
|
||||||
reason: String,
|
reason: String,
|
||||||
} = S_SERVER_FUCK_OFF,
|
} = S_SERVER_FUCK_OFF,
|
||||||
PlayerPositionChanged {
|
PlayerPositionChanged {
|
||||||
client_id: u8,
|
client_id: ClientId,
|
||||||
position: Vec3,
|
position: Vec3,
|
||||||
direction: Quat,
|
direction: Quat,
|
||||||
} = S_PLAYER_POSITION_CHANGED,
|
} = S_PLAYER_POSITION_CHANGED,
|
||||||
|
@ -69,22 +70,27 @@ pub enum ServerToClientMessage {
|
||||||
item: QueuedBlock
|
item: QueuedBlock
|
||||||
} = S_QUEUE_BLOCK,
|
} = S_QUEUE_BLOCK,
|
||||||
PlayerConnected {
|
PlayerConnected {
|
||||||
init: UserInitData
|
init: ClientInitData
|
||||||
} = S_PLAYER_CONNECTED,
|
} = S_PLAYER_CONNECTED,
|
||||||
|
PlayerDisconnected {
|
||||||
|
id: ClientId
|
||||||
|
} = S_PLAYER_DISCONNECTED,
|
||||||
}
|
}
|
||||||
|
|
||||||
//---
|
//---
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone)]
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
pub struct UserInitData {
|
pub struct ClientInitData {
|
||||||
pub client_id: ClientId,
|
pub client_id: ClientId,
|
||||||
pub username: String,
|
pub username: String,
|
||||||
pub position: Vec3,
|
pub position: Vec3,
|
||||||
pub velocity: Vec3,
|
pub velocity: Vec3,
|
||||||
pub direction: Quat,
|
pub direction: Quat,
|
||||||
|
pub health: Health,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone)]
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
pub struct InitData {
|
pub struct InitData {
|
||||||
pub users: Vec<UserInitData>
|
pub user: ClientInitData,
|
||||||
|
pub users: Vec<ClientInitData>
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
use shipyard::Component;
|
use shipyard::Component;
|
||||||
|
use crate::block::Block;
|
||||||
|
|
||||||
pub const PLAYER_HEALTH: u8 = 20;
|
pub const PLAYER_HEALTH: u8 = 20;
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct Player;
|
pub struct Player;
|
||||||
|
|
||||||
|
#[derive(Component, Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct PlayerHolding(pub Option<Block>);
|
||||||
|
|
|
@ -2,7 +2,9 @@ use shipyard::Component;
|
||||||
use glam::{Mat4, Mat3};
|
use glam::{Mat4, Mat3};
|
||||||
|
|
||||||
#[derive(Component, Clone, Copy, Debug, Default)]
|
#[derive(Component, Clone, Copy, Debug, Default)]
|
||||||
|
#[repr(transparent)]
|
||||||
pub struct Transform(pub Mat4);
|
pub struct Transform(pub Mat4);
|
||||||
|
|
||||||
#[derive(Component, Clone, Copy, Debug, Default)]
|
#[derive(Component, Clone, Copy, Debug, Default)]
|
||||||
|
#[repr(transparent)]
|
||||||
pub struct Transform2d(pub Mat3);
|
pub struct Transform2d(pub Mat3);
|
||||||
|
|
|
@ -3,6 +3,7 @@ use glium::glutin::event::VirtualKeyCode;
|
||||||
use kubi_shared::{
|
use kubi_shared::{
|
||||||
block::Block,
|
block::Block,
|
||||||
queue::QueuedBlock,
|
queue::QueuedBlock,
|
||||||
|
player::PlayerHolding,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
player::MainPlayer,
|
player::MainPlayer,
|
||||||
|
@ -11,14 +12,6 @@ use crate::{
|
||||||
events::{EventComponent, player_actions::PlayerActionEvent},
|
events::{EventComponent, player_actions::PlayerActionEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Component)]
|
|
||||||
pub struct PlayerHolding(pub Block);
|
|
||||||
impl Default for PlayerHolding {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self(Block::Cobblestone)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const BLOCK_KEY_MAP: &[(VirtualKeyCode, Block)] = &[
|
const BLOCK_KEY_MAP: &[(VirtualKeyCode, Block)] = &[
|
||||||
(VirtualKeyCode::Key1, Block::Cobblestone),
|
(VirtualKeyCode::Key1, Block::Cobblestone),
|
||||||
(VirtualKeyCode::Key2, Block::Planks),
|
(VirtualKeyCode::Key2, Block::Planks),
|
||||||
|
@ -38,7 +31,7 @@ fn pick_block_with_number_keys(
|
||||||
let Some((_, mut holding)) = (&main_player, &mut holding).iter().next() else { return };
|
let Some((_, mut holding)) = (&main_player, &mut holding).iter().next() else { return };
|
||||||
for &(key, block) in BLOCK_KEY_MAP {
|
for &(key, block) in BLOCK_KEY_MAP {
|
||||||
if input.keyboard_state.contains(&key) {
|
if input.keyboard_state.contains(&key) {
|
||||||
holding.0 = block;
|
holding.0 = Some(block);
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,9 +56,9 @@ fn block_placement_system(
|
||||||
let Some(ray) = ray.0 else { return };
|
let Some(ray) = ray.0 else { return };
|
||||||
//get coord and block type
|
//get coord and block type
|
||||||
let (place_position, place_block) = if action_place {
|
let (place_position, place_block) = if action_place {
|
||||||
if block.0 == Block::Air { return }
|
if block.0.is_none() { return }
|
||||||
let position = (ray.position - ray.direction * (RAYCAST_STEP + 0.001)).floor().as_ivec3();
|
let position = (ray.position - ray.direction * (RAYCAST_STEP + 0.001)).floor().as_ivec3();
|
||||||
(position, block.0)
|
(position, block.0.unwrap())
|
||||||
} else {
|
} else {
|
||||||
(ray.block_position, Block::Air)
|
(ray.block_position, Block::Air)
|
||||||
};
|
};
|
||||||
|
|
|
@ -29,6 +29,8 @@ use world::{
|
||||||
};
|
};
|
||||||
use player::send_player_movement_events;
|
use player::send_player_movement_events;
|
||||||
|
|
||||||
|
use self::player::{receive_player_movement_events, receive_player_connect_events};
|
||||||
|
|
||||||
#[derive(Unique, Clone, Copy, PartialEq, Eq)]
|
#[derive(Unique, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum GameType {
|
pub enum GameType {
|
||||||
Singleplayer,
|
Singleplayer,
|
||||||
|
@ -120,8 +122,14 @@ pub fn update_networking() -> Workload {
|
||||||
handle_disconnect,
|
handle_disconnect,
|
||||||
).into_sequential_workload().run_if(is_join_state::<{ClientJoinState::Connected as u8}>),
|
).into_sequential_workload().run_if(is_join_state::<{ClientJoinState::Connected as u8}>),
|
||||||
(
|
(
|
||||||
recv_block_place_events
|
(
|
||||||
).run_if(is_join_state::<{ClientJoinState::Joined as u8}>).run_if(is_ingame_or_loading),
|
receive_player_connect_events
|
||||||
|
),
|
||||||
|
(
|
||||||
|
recv_block_place_events,
|
||||||
|
receive_player_movement_events,
|
||||||
|
).into_workload()
|
||||||
|
).into_sequential_workload().run_if(is_join_state::<{ClientJoinState::Joined as u8}>).run_if(is_ingame_or_loading),
|
||||||
inject_network_responses_into_manager_queue.run_if(is_ingame_or_loading).skip_if_missing_unique::<ChunkTaskManager>(),
|
inject_network_responses_into_manager_queue.run_if(is_ingame_or_loading).skip_if_missing_unique::<ChunkTaskManager>(),
|
||||||
).into_sequential_workload()
|
).into_sequential_workload()
|
||||||
}
|
}
|
||||||
|
@ -131,7 +139,7 @@ pub fn update_networking_late() -> Workload {
|
||||||
(
|
(
|
||||||
send_block_place_events,
|
send_block_place_events,
|
||||||
send_player_movement_events,
|
send_player_movement_events,
|
||||||
).into_sequential_workload().run_if(is_join_state::<{ClientJoinState::Joined as u8}>),
|
).into_workload().run_if(is_join_state::<{ClientJoinState::Joined as u8}>),
|
||||||
flush_client,
|
flush_client,
|
||||||
).into_sequential_workload()
|
).into_sequential_workload()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,17 @@
|
||||||
use shipyard::{UniqueViewMut, View, IntoIter};
|
use glam::Mat4;
|
||||||
|
use shipyard::{UniqueViewMut, View, IntoIter, AllStoragesViewMut, ViewMut, IntoWithId};
|
||||||
use uflow::{client::Event as ClientEvent, SendMode};
|
use uflow::{client::Event as ClientEvent, SendMode};
|
||||||
use kubi_shared::networking::{
|
use kubi_shared::{
|
||||||
|
networking::{
|
||||||
messages::{ClientToServerMessage, ServerToClientMessage, S_SERVER_HELLO},
|
messages::{ClientToServerMessage, ServerToClientMessage, S_SERVER_HELLO},
|
||||||
state::ClientJoinState,
|
state::ClientJoinState,
|
||||||
channels::CHANNEL_AUTH,
|
channels::CHANNEL_AUTH,
|
||||||
|
client::{Username, Client},
|
||||||
|
},
|
||||||
|
transform::Transform, entity::Health
|
||||||
};
|
};
|
||||||
use super::{UdpClient, NetworkEvent};
|
use crate::player::MainPlayer;
|
||||||
|
use super::{UdpClient, NetworkEvent, player::add_net_player};
|
||||||
|
|
||||||
pub fn set_client_join_state_to_connected(
|
pub fn set_client_join_state_to_connected(
|
||||||
mut join_state: UniqueViewMut<ClientJoinState>
|
mut join_state: UniqueViewMut<ClientJoinState>
|
||||||
|
@ -16,14 +22,15 @@ pub fn set_client_join_state_to_connected(
|
||||||
|
|
||||||
pub fn say_hello(
|
pub fn say_hello(
|
||||||
mut client: UniqueViewMut<UdpClient>,
|
mut client: UniqueViewMut<UdpClient>,
|
||||||
|
main_player: View<MainPlayer>,
|
||||||
|
username: View<Username>
|
||||||
) {
|
) {
|
||||||
|
let username = (&main_player, &username).iter().next().unwrap().1.0.clone();
|
||||||
|
let password = None;
|
||||||
log::info!("Authenticating");
|
log::info!("Authenticating");
|
||||||
client.0.send(
|
client.0.send(
|
||||||
postcard::to_allocvec(
|
postcard::to_allocvec(
|
||||||
&ClientToServerMessage::ClientHello {
|
&ClientToServerMessage::ClientHello { username, password }
|
||||||
username: "Sbeve".into(),
|
|
||||||
password: None
|
|
||||||
}
|
|
||||||
).unwrap().into_boxed_slice(),
|
).unwrap().into_boxed_slice(),
|
||||||
CHANNEL_AUTH,
|
CHANNEL_AUTH,
|
||||||
SendMode::Reliable
|
SendMode::Reliable
|
||||||
|
@ -31,26 +38,63 @@ pub fn say_hello(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_server_hello_response(
|
pub fn check_server_hello_response(
|
||||||
network_events: View<NetworkEvent>,
|
mut storages: AllStoragesViewMut,
|
||||||
mut join_state: UniqueViewMut<ClientJoinState>
|
|
||||||
) {
|
) {
|
||||||
for event in network_events.iter() {
|
//Check if we got the message and extract the init data from it
|
||||||
|
let Some(init) = storages.borrow::<View<NetworkEvent>>().unwrap().iter().find_map(|event| {
|
||||||
let ClientEvent::Receive(data) = &event.0 else {
|
let ClientEvent::Receive(data) = &event.0 else {
|
||||||
continue
|
return None
|
||||||
};
|
};
|
||||||
if !event.is_message_of_type::<S_SERVER_HELLO>() {
|
if !event.is_message_of_type::<S_SERVER_HELLO>() {
|
||||||
continue
|
return None
|
||||||
}
|
}
|
||||||
let Ok(parsed_message) = postcard::from_bytes(data) else {
|
let Ok(parsed_message) = postcard::from_bytes(data) else {
|
||||||
log::error!("Malformed message");
|
log::error!("Malformed message");
|
||||||
continue
|
return None
|
||||||
};
|
};
|
||||||
let ServerToClientMessage::ServerHello { init: _ } = parsed_message else {
|
let ServerToClientMessage::ServerHello { init } = parsed_message else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
//TODO handle init data
|
Some(init)
|
||||||
*join_state = ClientJoinState::Joined;
|
}) else { return };
|
||||||
log::info!("Joined the server!");
|
|
||||||
return;
|
// struct ClientInitData {
|
||||||
|
// client_id: ClientId,
|
||||||
|
// username: String,
|
||||||
|
// position: Vec3,
|
||||||
|
// velocity: Vec3,
|
||||||
|
// direction: Quat,
|
||||||
|
// health: Health,
|
||||||
|
// }
|
||||||
|
|
||||||
|
//Add components to main player
|
||||||
|
{
|
||||||
|
let entity = (&storages.borrow::<View<MainPlayer>>().unwrap()).iter().with_id().next().unwrap().0;
|
||||||
|
storages.add_component(entity, Client(init.user.client_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Modify main player
|
||||||
|
{
|
||||||
|
for (entity, (_, mut username, mut transform, mut health)) in (
|
||||||
|
&storages.borrow::<View<MainPlayer>>().unwrap(),
|
||||||
|
&mut storages.borrow::<ViewMut<Username>>().unwrap(),
|
||||||
|
&mut storages.borrow::<ViewMut<Transform>>().unwrap(),
|
||||||
|
&mut storages.borrow::<ViewMut<Health>>().unwrap(),
|
||||||
|
).iter().with_id() {
|
||||||
|
username.0 = init.user.username.clone();
|
||||||
|
transform.0 = Mat4::from_rotation_translation(init.user.direction, init.user.position);
|
||||||
|
*health = init.user.health;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Init players
|
||||||
|
for init_data in init.users {
|
||||||
|
add_net_player(&mut storages, init_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set state to connected
|
||||||
|
let mut join_state = storages.borrow::<UniqueViewMut<ClientJoinState>>().unwrap();
|
||||||
|
*join_state = ClientJoinState::Joined;
|
||||||
|
|
||||||
|
log::info!("Joined the server!");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
use glam::Vec3;
|
use glam::{Vec3, Mat4};
|
||||||
use hashbrown::HashMap;
|
use shipyard::{UniqueViewMut, View, IntoIter, AllStoragesView, AllStoragesViewMut, UniqueView, ViewMut, Get};
|
||||||
use nohash_hasher::BuildNoHashHasher;
|
|
||||||
use shipyard::{UniqueViewMut, View, IntoIter, Unique, EntityId, AllStoragesView};
|
|
||||||
use uflow::{SendMode, client::Event as ClientEvent};
|
use uflow::{SendMode, client::Event as ClientEvent};
|
||||||
use kubi_shared::networking::{
|
use kubi_shared::{
|
||||||
messages::{ClientToServerMessage, ServerToClientMessage, S_PLAYER_POSITION_CHANGED},
|
player::{Player, PlayerHolding},
|
||||||
|
entity::Entity,
|
||||||
|
transform::Transform,
|
||||||
|
networking::{
|
||||||
|
messages::{ClientToServerMessage, ServerToClientMessage, S_PLAYER_POSITION_CHANGED, ClientInitData},
|
||||||
channels::CHANNEL_MOVE,
|
channels::CHANNEL_MOVE,
|
||||||
client::{ClientId, ClientIdMap},
|
client::{ClientIdMap, Username, Client},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use crate::events::player_actions::PlayerActionEvent;
|
use crate::events::player_actions::PlayerActionEvent;
|
||||||
use super::{UdpClient, NetworkEvent};
|
use super::{UdpClient, NetworkEvent};
|
||||||
|
@ -17,8 +20,33 @@ pub fn init_client_map(
|
||||||
storages.add_unique(ClientIdMap::new());
|
storages.add_unique(ClientIdMap::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_net_player() {
|
pub fn add_net_player(
|
||||||
//TODO
|
storages: &mut AllStoragesViewMut,
|
||||||
|
init: ClientInitData
|
||||||
|
) {
|
||||||
|
// struct ClientInitData {
|
||||||
|
// client_id: ClientId,
|
||||||
|
// username: String,
|
||||||
|
// position: Vec3,
|
||||||
|
// velocity: Vec3,
|
||||||
|
// direction: Quat,
|
||||||
|
// health: Health,
|
||||||
|
// }
|
||||||
|
|
||||||
|
//Spawn player locally
|
||||||
|
let entity_id = storages.add_entity((
|
||||||
|
Username(init.username),
|
||||||
|
Client(init.client_id),
|
||||||
|
Player,
|
||||||
|
Entity,
|
||||||
|
init.health,
|
||||||
|
Transform(Mat4::from_rotation_translation(init.direction, init.position)),
|
||||||
|
PlayerHolding::default(),
|
||||||
|
));
|
||||||
|
|
||||||
|
//Add it to the client id map
|
||||||
|
let mut client_id_map = storages.borrow::<UniqueViewMut<ClientIdMap>>().unwrap();
|
||||||
|
client_id_map.0.insert(init.client_id, entity_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_player_movement_events(
|
pub fn send_player_movement_events(
|
||||||
|
@ -42,29 +70,60 @@ pub fn send_player_movement_events(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn receive_player_movement_events(
|
pub fn receive_player_movement_events(
|
||||||
|
mut transforms: ViewMut<Transform>,
|
||||||
network_events: View<NetworkEvent>,
|
network_events: View<NetworkEvent>,
|
||||||
|
id_map: UniqueView<ClientIdMap>
|
||||||
) {
|
) {
|
||||||
for event in network_events.iter() {
|
for event in network_events.iter() {
|
||||||
let ClientEvent::Receive(data) = &event.0 else {
|
let ClientEvent::Receive(data) = &event.0 else {
|
||||||
continue
|
continue
|
||||||
};
|
};
|
||||||
|
|
||||||
if !event.is_message_of_type::<S_PLAYER_POSITION_CHANGED>() {
|
if !event.is_message_of_type::<S_PLAYER_POSITION_CHANGED>() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
let Ok(parsed_message) = postcard::from_bytes(data) else {
|
let Ok(parsed_message) = postcard::from_bytes(data) else {
|
||||||
log::error!("Malformed message");
|
log::error!("Malformed message");
|
||||||
continue
|
continue
|
||||||
};
|
};
|
||||||
|
|
||||||
let ServerToClientMessage::PlayerPositionChanged {
|
let ServerToClientMessage::PlayerPositionChanged {
|
||||||
client_id, position, direction
|
client_id, position, direction
|
||||||
} = parsed_message else { unreachable!() };
|
} = parsed_message else { unreachable!() };
|
||||||
//TODO apply position to local player
|
|
||||||
|
let Some(&ent_id) = id_map.0.get(&client_id) else {
|
||||||
|
log::error!("Not in client-id map");
|
||||||
|
continue
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut transform = (&mut transforms).get(ent_id)
|
||||||
|
.expect("invalid player entity id");
|
||||||
|
|
||||||
|
transform.0 = Mat4::from_rotation_translation(direction, position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn receive_player_connect_events(
|
||||||
pub fn receive_connected_players(
|
mut storages: AllStoragesViewMut,
|
||||||
network_events: View<NetworkEvent>,
|
|
||||||
) {
|
) {
|
||||||
|
let messages: Vec<ServerToClientMessage> = storages.borrow::<View<NetworkEvent>>().unwrap().iter().filter_map(|event| {
|
||||||
|
let ClientEvent::Receive(data) = &event.0 else {
|
||||||
|
return None
|
||||||
|
};
|
||||||
|
if !event.is_message_of_type::<S_PLAYER_POSITION_CHANGED>() {
|
||||||
|
return None
|
||||||
|
};
|
||||||
|
let Ok(parsed_message) = postcard::from_bytes(data) else {
|
||||||
|
log::error!("Malformed message");
|
||||||
|
return None
|
||||||
|
};
|
||||||
|
Some(parsed_message)
|
||||||
|
}).collect();
|
||||||
|
|
||||||
|
for message in messages {
|
||||||
|
let ServerToClientMessage::PlayerConnected { init } = message else { unreachable!() };
|
||||||
|
log::info!("player connected: {} (id {})", init.username, init.client_id);
|
||||||
|
add_net_player(&mut storages, init);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
use shipyard::{Component, AllStoragesViewMut};
|
use shipyard::{Component, AllStoragesViewMut};
|
||||||
use kubi_shared::{
|
use kubi_shared::{
|
||||||
entity::{Entity, Health},
|
entity::{Entity, Health},
|
||||||
player::PLAYER_HEALTH
|
player::{PLAYER_HEALTH, PlayerHolding},
|
||||||
|
networking::client::Username
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
transform::Transform,
|
transform::Transform,
|
||||||
camera::Camera,
|
camera::Camera,
|
||||||
fly_controller::FlyController,
|
fly_controller::FlyController,
|
||||||
world::raycast::LookingAtBlock,
|
world::raycast::LookingAtBlock,
|
||||||
block_placement::PlayerHolding,
|
|
||||||
};
|
};
|
||||||
pub use kubi_shared::player::Player;
|
pub use kubi_shared::player::Player;
|
||||||
|
|
||||||
|
@ -29,5 +29,6 @@ pub fn spawn_player (
|
||||||
FlyController,
|
FlyController,
|
||||||
LookingAtBlock::default(),
|
LookingAtBlock::default(),
|
||||||
PlayerHolding::default(),
|
PlayerHolding::default(),
|
||||||
|
Username("Sbeve".into())
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue