|
|
|
@ -1,10 +1,24 @@
|
|
|
|
|
use std::{collections::HashMap, sync::Mutex};
|
|
|
|
|
use std::{
|
|
|
|
|
collections::HashMap,
|
|
|
|
|
sync::{atomic::Ordering, Mutex},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
use once_cell::sync::Lazy;
|
|
|
|
|
use valence::{
|
|
|
|
|
entity::{living::Health, EntityId},
|
|
|
|
|
entity::{living::Health, player::PlayerEntityBundle, EntityId},
|
|
|
|
|
packet::WritePacket,
|
|
|
|
|
prelude::{event::PlayerMove, *},
|
|
|
|
|
};
|
|
|
|
|
use valence_protocol::{
|
|
|
|
|
packet::s2c::play::{
|
|
|
|
|
synchronize_tags::{Tag, TagGroup},
|
|
|
|
|
ChunkRenderDistanceCenterS2c, SynchronizeTagsS2c,
|
|
|
|
|
},
|
|
|
|
|
var_int::VarInt,
|
|
|
|
|
Encode,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
use crate::PLAYER_COUNT;
|
|
|
|
|
|
|
|
|
|
static PLAYER_HEIGHT_HISTORY: Lazy<Mutex<HashMap<i32, f64>>> =
|
|
|
|
|
Lazy::new(|| Mutex::new(HashMap::new()));
|
|
|
|
@ -63,3 +77,90 @@ pub fn death(mut healths: Query<(&mut Client, &Health, &Username), Changed<Healt
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn init_clients(
|
|
|
|
|
mut new_clients: Query<
|
|
|
|
|
(
|
|
|
|
|
&mut Position,
|
|
|
|
|
Entity,
|
|
|
|
|
&UniqueId,
|
|
|
|
|
&mut Client,
|
|
|
|
|
&mut GameMode,
|
|
|
|
|
&Username,
|
|
|
|
|
&mut HasRespawnScreen,
|
|
|
|
|
),
|
|
|
|
|
Added<Client>,
|
|
|
|
|
>,
|
|
|
|
|
instances: Query<Entity, With<Instance>>,
|
|
|
|
|
mut commands: Commands,
|
|
|
|
|
) {
|
|
|
|
|
for (_pos, entity, uuid, mut client, mut game_mode, username, mut has_respawn_screen) in
|
|
|
|
|
&mut new_clients
|
|
|
|
|
{
|
|
|
|
|
// initialize client
|
|
|
|
|
has_respawn_screen.0 = true;
|
|
|
|
|
*game_mode = GameMode::Creative;
|
|
|
|
|
commands.entity(entity).insert(PlayerEntityBundle {
|
|
|
|
|
location: Location(instances.single()),
|
|
|
|
|
position: Position(DVec3 {
|
|
|
|
|
x: -214.0,
|
|
|
|
|
y: 83.0,
|
|
|
|
|
z: 276.0,
|
|
|
|
|
}),
|
|
|
|
|
uuid: *uuid,
|
|
|
|
|
..Default::default()
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// send packet that magically fixes chunks
|
|
|
|
|
// TODO: make this configurable as different maps will have different chunks we need to force load
|
|
|
|
|
client.write_packet(&ChunkRenderDistanceCenterS2c {
|
|
|
|
|
chunk_x: VarInt(-14),
|
|
|
|
|
chunk_z: VarInt(17),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// send block tags packet
|
|
|
|
|
client.write_packet(&SynchronizeTagsS2c {
|
|
|
|
|
tags: vec![
|
|
|
|
|
TagGroup {
|
|
|
|
|
kind: ident!("block").into(),
|
|
|
|
|
tags: vec![Tag {
|
|
|
|
|
name: ident!("climbable").into(),
|
|
|
|
|
entries: vec![
|
|
|
|
|
VarInt(BlockKind::Vine.to_raw().into()),
|
|
|
|
|
VarInt(BlockKind::Ladder.to_raw().into()),
|
|
|
|
|
],
|
|
|
|
|
}],
|
|
|
|
|
},
|
|
|
|
|
TagGroup {
|
|
|
|
|
kind: ident!("fluid").into(),
|
|
|
|
|
tags: vec![Tag {
|
|
|
|
|
name: ident!("water").into(),
|
|
|
|
|
entries: vec![VarInt(1), VarInt(2)],
|
|
|
|
|
}],
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// send server brand
|
|
|
|
|
let mut buf = Vec::new();
|
|
|
|
|
"Valence".encode(&mut buf).unwrap();
|
|
|
|
|
client.send_custom_payload(ident!("brand"), &buf);
|
|
|
|
|
|
|
|
|
|
// add player to count
|
|
|
|
|
PLAYER_COUNT.fetch_add(1, Ordering::SeqCst);
|
|
|
|
|
|
|
|
|
|
tracing::info!("{username} joined the game");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn despawn_disconnected_clients(
|
|
|
|
|
mut commands: Commands,
|
|
|
|
|
mut disconnected_clients: RemovedComponents<Client>,
|
|
|
|
|
) {
|
|
|
|
|
for entity in disconnected_clients.iter() {
|
|
|
|
|
if let Some(mut entity) = commands.get_entity(entity) {
|
|
|
|
|
entity.insert(Despawned);
|
|
|
|
|
PLAYER_COUNT.fetch_sub(1, Ordering::SeqCst);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|