mirror of
https://github.com/griffi-gh/kubi.git
synced 2024-11-21 14:28:43 -06:00
wip
This commit is contained in:
parent
03fbb774b5
commit
4bf2b350c6
|
@ -33,6 +33,7 @@ pub fn authenticate_players(
|
|||
let config = storages.borrow::<UniqueView<ConfigTable>>().unwrap();
|
||||
|
||||
for event in &events.0 {
|
||||
// NOT using `check_message_auth` here because the user is not authed yet!
|
||||
let ServerEvent::Receive(client_addr, data) = event else{
|
||||
continue
|
||||
};
|
||||
|
|
|
@ -1,12 +1,18 @@
|
|||
use shipyard::{Component, EntityId, Unique, AllStoragesView, UniqueView, NonSendSync, View, Get};
|
||||
use glam::Mat4;
|
||||
use shipyard::{Component, EntityId, Unique, AllStoragesView, UniqueView, NonSendSync, View, ViewMut, Get};
|
||||
use hashbrown::HashMap;
|
||||
use std::net::SocketAddr;
|
||||
use uflow::server::Event as ServerEvent;
|
||||
use kubi_shared::networking::{
|
||||
client::{ClientIdMap, Client},
|
||||
messages::{ClientToServerMessage, C_POSITION_CHANGED}
|
||||
use kubi_shared::{
|
||||
networking::{
|
||||
client::{ClientIdMap, Client},
|
||||
messages::{ClientToServerMessage, C_POSITION_CHANGED}
|
||||
},
|
||||
transform::Transform
|
||||
};
|
||||
use crate::{
|
||||
server::{ServerEvents, UdpServer},
|
||||
util::check_message_auth
|
||||
};
|
||||
use crate::server::{ServerEvents, IsMessageOfType, UdpServer};
|
||||
|
||||
#[derive(Component, Clone, Copy)]
|
||||
pub struct ClientAddress(pub SocketAddr);
|
||||
|
@ -29,34 +35,18 @@ pub fn sync_client_positions(
|
|||
events: UniqueView<ServerEvents>,
|
||||
addr_map: UniqueView<ClientAddressMap>,
|
||||
clients: View<Client>,
|
||||
mut transforms: ViewMut<Transform>
|
||||
) {
|
||||
for event in &events.0 {
|
||||
let ServerEvent::Receive(client_addr, data) = event else{
|
||||
continue
|
||||
let Some(message) = check_message_auth::<C_POSITION_CHANGED>(&server, event, &clients, &addr_map) 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 {
|
||||
let ClientToServerMessage::PositionChanged { position, velocity: _, direction } = message.message else {
|
||||
unreachable!()
|
||||
};
|
||||
//Apply position to client
|
||||
let mut trans = (&mut transforms).get(message.entity_id).unwrap();
|
||||
trans.0 = Mat4::from_rotation_translation(direction, position);
|
||||
|
||||
//TODO: sync positions on server
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use shipyard::{World, Workload, IntoWorkload};
|
||||
use std::{thread, time::Duration};
|
||||
|
||||
mod util;
|
||||
mod config;
|
||||
mod server;
|
||||
mod client;
|
||||
|
|
72
kubi-server/src/util.rs
Normal file
72
kubi-server/src/util.rs
Normal file
|
@ -0,0 +1,72 @@
|
|||
use std::{net::SocketAddr, rc::Rc, cell::RefCell};
|
||||
use shipyard::{View, Get, EntityId};
|
||||
use uflow::server::{Event as ServerEvent, RemoteClient};
|
||||
use kubi_shared::networking::{
|
||||
messages::ClientToServerMessage,
|
||||
client::{Client, ClientId}
|
||||
};
|
||||
use crate::{
|
||||
server::{IsMessageOfType, UdpServer},
|
||||
client::ClientAddressMap
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CtsMessageMetadata<'a> {
|
||||
pub message: ClientToServerMessage,
|
||||
pub client_id: ClientId,
|
||||
pub entity_id: EntityId,
|
||||
pub client_addr: SocketAddr,
|
||||
pub client: &'a Rc<RefCell<RemoteClient>>,
|
||||
}
|
||||
impl From<CtsMessageMetadata<'_>> for ClientToServerMessage {
|
||||
fn from(value: CtsMessageMetadata) -> Self { value.message }
|
||||
}
|
||||
impl From<CtsMessageMetadata<'_>> for ClientId {
|
||||
fn from(value: CtsMessageMetadata) -> Self { value.client_id }
|
||||
}
|
||||
impl From<CtsMessageMetadata<'_>> for EntityId {
|
||||
fn from(value: CtsMessageMetadata) -> Self { value.entity_id }
|
||||
}
|
||||
impl From<CtsMessageMetadata<'_>> for SocketAddr {
|
||||
fn from(value: CtsMessageMetadata) -> Self { value.client_addr }
|
||||
}
|
||||
impl<'a> From<CtsMessageMetadata<'a>> for &'a Rc<RefCell<RemoteClient>> {
|
||||
fn from(value: CtsMessageMetadata<'a>) -> Self { value.client }
|
||||
}
|
||||
|
||||
pub fn check_message_auth<'a, const C_MSG: u8>(
|
||||
server: &'a UdpServer,
|
||||
event: &ServerEvent,
|
||||
clients: &View<Client>,
|
||||
addr_map: &ClientAddressMap
|
||||
) -> Option<CtsMessageMetadata<'a>> {
|
||||
let ServerEvent::Receive(client_addr, data) = event else{
|
||||
return None
|
||||
};
|
||||
if !event.is_message_of_type::<C_MSG>() {
|
||||
return None
|
||||
}
|
||||
let Some(client) = server.0.client(client_addr) else {
|
||||
log::error!("Client doesn't exist");
|
||||
return None
|
||||
};
|
||||
let Some(&entity_id) = addr_map.0.get(client_addr) else {
|
||||
log::error!("Client not authenticated");
|
||||
return None
|
||||
};
|
||||
let Ok(&Client(client_id)) = (&clients).get(entity_id) else {
|
||||
log::error!("Entity ID is invalid");
|
||||
return None
|
||||
};
|
||||
let Ok(message) = postcard::from_bytes(data) else {
|
||||
log::error!("Malformed message");
|
||||
return None
|
||||
};
|
||||
Some(CtsMessageMetadata {
|
||||
message,
|
||||
client_id,
|
||||
entity_id,
|
||||
client_addr: *client_addr,
|
||||
client
|
||||
})
|
||||
}
|
|
@ -18,6 +18,7 @@ use crate::{
|
|||
server::{UdpServer, ServerEvents, IsMessageOfType},
|
||||
config::ConfigTable,
|
||||
client::{ClientAddress, ClientAddressMap},
|
||||
util::check_message_auth,
|
||||
};
|
||||
|
||||
pub mod chunk;
|
||||
|
@ -61,38 +62,19 @@ fn process_chunk_requests(
|
|||
clients: View<Client>
|
||||
) {
|
||||
for event in &events.0 {
|
||||
let ServerEvent::Receive(client_addr, data) = event else{
|
||||
continue
|
||||
let Some(message) = check_message_auth::<C_CHUNK_SUB_REQUEST>(&server, event, &clients, &addr_map) else {
|
||||
continue;
|
||||
};
|
||||
if !event.is_message_of_type::<C_CHUNK_SUB_REQUEST>() {
|
||||
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::ChunkSubRequest { chunk: chunk_position } = parsed_message else {
|
||||
let ClientToServerMessage::ChunkSubRequest { chunk: chunk_position } = message.message else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
if let Some(chunk) = chunk_manager.chunks.get_mut(&chunk_position) {
|
||||
chunk.subscriptions.insert(client_id);
|
||||
chunk.subscriptions.insert(message.client_id);
|
||||
//TODO Start task here if status is "Nothing"
|
||||
if let Some(blocks) = &chunk.blocks {
|
||||
send_chunk_compressed(
|
||||
&client,
|
||||
&message.client,
|
||||
&ServerToClientMessage::ChunkResponse {
|
||||
chunk: chunk_position,
|
||||
data: blocks.clone(),
|
||||
|
@ -103,7 +85,7 @@ fn process_chunk_requests(
|
|||
} else {
|
||||
let mut chunk = Chunk::new(chunk_position);
|
||||
chunk.state = ChunkState::Loading;
|
||||
chunk.subscriptions.insert(client_id);
|
||||
chunk.subscriptions.insert(message.client_id);
|
||||
chunk_manager.chunks.insert(chunk_position, chunk);
|
||||
task_manager.spawn_task(ChunkTask::LoadChunk {
|
||||
position: chunk_position,
|
||||
|
@ -172,32 +154,15 @@ fn process_block_queue_messages(
|
|||
addrs: View<ClientAddress>,
|
||||
) {
|
||||
for event in &events.0 {
|
||||
let ServerEvent::Receive(client_addr, data) = event else{
|
||||
continue
|
||||
};
|
||||
if !event.is_message_of_type::<C_QUEUE_BLOCK>() {
|
||||
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::QueueBlock { item } = parsed_message else {
|
||||
unreachable!()
|
||||
let Some(message) = check_message_auth::<C_QUEUE_BLOCK>(&server, event, &clients, &addr_map) else {
|
||||
continue;
|
||||
};
|
||||
let ClientToServerMessage::QueueBlock { item } = message.message else { unreachable!() };
|
||||
//TODO place in our own queue, for now just send to other clients
|
||||
log::info!("Placed block {:?} at {}", item.block_type, item.position);
|
||||
for (other_client, other_client_address) in (&clients, &addrs).iter() {
|
||||
//No need to send the event back
|
||||
if client_id == other_client.0 {
|
||||
if message.client_id == other_client.0 {
|
||||
continue
|
||||
}
|
||||
//Get client
|
||||
|
|
|
@ -9,9 +9,26 @@ flat in uint v_tex_index;
|
|||
out vec4 color;
|
||||
uniform sampler2DArray tex;
|
||||
|
||||
vec4 alpha_drop(vec4 b, vec4 a) {
|
||||
if ((a.w < 1.) || (b.w < 1.)) {
|
||||
return vec4(b.xyz, 0.);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
void main() {
|
||||
// base color from texture
|
||||
color = texture(tex, vec3(v_uv, v_tex_index));
|
||||
// HACKY texture "antialiasing"
|
||||
color += (
|
||||
alpha_drop(color, texture(tex, vec3(v_uv + vec2(.000, .001), v_tex_index))) +
|
||||
alpha_drop(color, texture(tex, vec3(v_uv + vec2(.001, .000), v_tex_index))) +
|
||||
alpha_drop(color, texture(tex, vec3(v_uv + vec2(.001, .001), v_tex_index))) +
|
||||
alpha_drop(color, texture(tex, vec3(v_uv - vec2(.000, .001), v_tex_index))) +
|
||||
alpha_drop(color, texture(tex, vec3(v_uv - vec2(.001, .000), v_tex_index))) +
|
||||
alpha_drop(color, texture(tex, vec3(v_uv - vec2(.001, .001), v_tex_index)))
|
||||
) / 6.;
|
||||
color /= 2.;
|
||||
// discard fully transparent pixels
|
||||
if (color.w <= 0.0) {
|
||||
discard;
|
||||
|
|
|
@ -78,7 +78,7 @@ use delta_time::{DeltaTime, init_delta_time};
|
|||
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 state::{is_ingame, is_ingame_or_loading, is_loading, init_state, update_state, is_connecting};
|
||||
use networking::{update_networking, update_networking_late, is_multiplayer, disconnect_on_exit};
|
||||
use networking::{update_networking, update_networking_late, is_multiplayer, disconnect_on_exit, is_singleplayer};
|
||||
use init::initialize_from_args;
|
||||
use gui::{render_gui, init_gui, update_gui};
|
||||
use loading_screen::update_loading_screen;
|
||||
|
@ -114,7 +114,9 @@ fn update() -> Workload {
|
|||
process_inputs,
|
||||
(
|
||||
init_game_world.run_if_missing_unique::<ChunkTaskManager>(),
|
||||
spawn_player.run_if_storage_empty::<MainPlayer>(),
|
||||
(
|
||||
spawn_player.run_if_storage_empty::<MainPlayer>(),
|
||||
).into_sequential_workload().run_if(is_singleplayer),
|
||||
).into_sequential_workload().run_if(is_ingame_or_loading),
|
||||
update_networking.run_if(is_multiplayer),
|
||||
(
|
||||
|
|
|
@ -4,7 +4,8 @@ use std::net::SocketAddr;
|
|||
use uflow::{client::{Client, Config as ClientConfig, Event as ClientEvent}, EndpointConfig};
|
||||
use kubi_shared::networking::{
|
||||
messages::ServerToClientMessage,
|
||||
state::ClientJoinState,
|
||||
state::ClientJoinState,
|
||||
client::ClientIdMap,
|
||||
};
|
||||
use crate::{
|
||||
events::EventComponent,
|
||||
|
@ -27,7 +28,10 @@ use world::{
|
|||
send_block_place_events,
|
||||
recv_block_place_events,
|
||||
};
|
||||
use player::send_player_movement_events;
|
||||
use player::{
|
||||
init_client_map,
|
||||
send_player_movement_events,
|
||||
};
|
||||
|
||||
use self::player::{receive_player_movement_events, receive_player_connect_events};
|
||||
|
||||
|
@ -111,6 +115,7 @@ fn handle_disconnect(
|
|||
|
||||
pub fn update_networking() -> Workload {
|
||||
(
|
||||
init_client_map.run_if_missing_unique::<ClientIdMap>(),
|
||||
connect_client.run_if_missing_unique::<UdpClient>(),
|
||||
poll_client,
|
||||
(
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
use glam::Mat4;
|
||||
use shipyard::{UniqueViewMut, View, IntoIter, AllStoragesViewMut, ViewMut, IntoWithId};
|
||||
use shipyard::{UniqueViewMut, View, IntoIter, AllStoragesViewMut};
|
||||
use uflow::{client::Event as ClientEvent, SendMode};
|
||||
use kubi_shared::{
|
||||
networking::{
|
||||
messages::{ClientToServerMessage, ServerToClientMessage, S_SERVER_HELLO},
|
||||
state::ClientJoinState,
|
||||
channels::CHANNEL_AUTH,
|
||||
client::{Username, Client},
|
||||
client::Username,
|
||||
},
|
||||
transform::Transform, entity::Health
|
||||
};
|
||||
use crate::player::MainPlayer;
|
||||
use super::{UdpClient, NetworkEvent, player::add_net_player};
|
||||
use crate::player::{MainPlayer, spawn_local_player_multiplayer, spawn_remote_player_multiplayer};
|
||||
use super::{UdpClient, NetworkEvent};
|
||||
|
||||
pub fn set_client_join_state_to_connected(
|
||||
mut join_state: UniqueViewMut<ClientJoinState>
|
||||
|
@ -25,7 +23,7 @@ pub fn say_hello(
|
|||
main_player: View<MainPlayer>,
|
||||
username: View<Username>
|
||||
) {
|
||||
let username = (&main_player, &username).iter().next().unwrap().1.0.clone();
|
||||
let username = "XxX-FishFucker-69420-XxX".into(); //(&main_player, &username).iter().next().unwrap().1.0.clone();
|
||||
let password = None;
|
||||
log::info!("Authenticating");
|
||||
client.0.send(
|
||||
|
@ -68,28 +66,11 @@ pub fn check_server_hello_response(
|
|||
// }
|
||||
|
||||
//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;
|
||||
}
|
||||
}
|
||||
spawn_local_player_multiplayer(&mut storages, init.user);
|
||||
|
||||
//Init players
|
||||
for init_data in init.users {
|
||||
add_net_player(&mut storages, init_data);
|
||||
spawn_remote_player_multiplayer(&mut storages, init_data);
|
||||
}
|
||||
|
||||
// Set state to connected
|
||||
|
|
|
@ -2,16 +2,17 @@ use glam::{Vec3, Mat4};
|
|||
use shipyard::{UniqueViewMut, View, IntoIter, AllStoragesView, AllStoragesViewMut, UniqueView, ViewMut, Get};
|
||||
use uflow::{SendMode, client::Event as ClientEvent};
|
||||
use kubi_shared::{
|
||||
player::{Player, PlayerHolding},
|
||||
entity::Entity,
|
||||
transform::Transform,
|
||||
networking::{
|
||||
messages::{ClientToServerMessage, ServerToClientMessage, S_PLAYER_POSITION_CHANGED, ClientInitData},
|
||||
messages::{ClientToServerMessage, ServerToClientMessage, S_PLAYER_POSITION_CHANGED},
|
||||
channels::CHANNEL_MOVE,
|
||||
client::{ClientIdMap, Username, Client},
|
||||
client::ClientIdMap,
|
||||
},
|
||||
};
|
||||
use crate::events::player_actions::PlayerActionEvent;
|
||||
use crate::{
|
||||
events::player_actions::PlayerActionEvent,
|
||||
player::spawn_remote_player_multiplayer,
|
||||
};
|
||||
use super::{UdpClient, NetworkEvent};
|
||||
|
||||
pub fn init_client_map(
|
||||
|
@ -20,35 +21,6 @@ pub fn init_client_map(
|
|||
storages.add_unique(ClientIdMap::new());
|
||||
}
|
||||
|
||||
pub fn add_net_player(
|
||||
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(
|
||||
actions: View<PlayerActionEvent>,
|
||||
mut client: UniqueViewMut<UdpClient>,
|
||||
|
@ -124,6 +96,6 @@ pub fn receive_player_connect_events(
|
|||
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);
|
||||
spawn_remote_player_multiplayer(&mut storages, init);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
use shipyard::{Component, AllStoragesViewMut};
|
||||
use glam::Mat4;
|
||||
use shipyard::{Component, AllStoragesViewMut, UniqueViewMut};
|
||||
use kubi_shared::{
|
||||
entity::{Entity, Health},
|
||||
player::{PLAYER_HEALTH, PlayerHolding},
|
||||
networking::client::Username
|
||||
networking::{
|
||||
client::{Username, Client, ClientIdMap},
|
||||
messages::ClientInitData
|
||||
}
|
||||
};
|
||||
use crate::{
|
||||
transform::Transform,
|
||||
|
@ -16,7 +20,7 @@ pub use kubi_shared::player::Player;
|
|||
pub struct MainPlayer;
|
||||
|
||||
pub fn spawn_player (
|
||||
mut storages: AllStoragesViewMut
|
||||
mut storages: AllStoragesViewMut,
|
||||
) {
|
||||
log::info!("spawning player");
|
||||
storages.add_entity((
|
||||
|
@ -29,6 +33,55 @@ pub fn spawn_player (
|
|||
FlyController,
|
||||
LookingAtBlock::default(),
|
||||
PlayerHolding::default(),
|
||||
Username("Sbeve".into())
|
||||
Username("LocalPlayer".into())
|
||||
));
|
||||
}
|
||||
|
||||
pub fn spawn_local_player_multiplayer (
|
||||
storages: &mut AllStoragesViewMut,
|
||||
init: ClientInitData
|
||||
) {
|
||||
log::info!("spawning local multiplayer player");
|
||||
let entity_id = storages.add_entity((
|
||||
(
|
||||
Player,
|
||||
Client(init.client_id),
|
||||
MainPlayer,
|
||||
Entity,
|
||||
init.health,
|
||||
Transform(Mat4::from_rotation_translation(init.direction, init.position)),
|
||||
Camera::default(),
|
||||
FlyController,
|
||||
LookingAtBlock::default(),
|
||||
PlayerHolding::default(),
|
||||
),(
|
||||
Username(init.username)
|
||||
)
|
||||
));
|
||||
|
||||
//Add ourself 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 spawn_remote_player_multiplayer(
|
||||
storages: &mut AllStoragesViewMut,
|
||||
init: ClientInitData
|
||||
) {
|
||||
log::info!("spawning remote multiplayer player");
|
||||
|
||||
//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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue