Try to solve Pumpkin's locking problem

This commit is contained in:
Snowiiii 2024-09-09 21:12:49 +02:00
parent d797518cd7
commit c8fee9b23c
17 changed files with 508 additions and 497 deletions

View File

@ -1,3 +1,5 @@
use std::sync::atomic::AtomicU32;
use crate::container_click::MouseClick; use crate::container_click::MouseClick;
use crate::{handle_item_change, Container, InventoryError, WindowType}; use crate::{handle_item_change, Container, InventoryError, WindowType};
use pumpkin_world::item::ItemStack; use pumpkin_world::item::ItemStack;
@ -11,7 +13,7 @@ pub struct PlayerInventory {
offhand: Option<ItemStack>, offhand: Option<ItemStack>,
// current selected slot in hotbar // current selected slot in hotbar
selected: usize, selected: usize,
pub state_id: u32, pub state_id: AtomicU32,
// Notchian server wraps this value at 100, we can just keep it as a u8 that automatically wraps // Notchian server wraps this value at 100, we can just keep it as a u8 that automatically wraps
pub total_opened_containers: u8, pub total_opened_containers: u8,
} }
@ -32,7 +34,7 @@ impl PlayerInventory {
offhand: None, offhand: None,
// TODO: What when player spawns in with an different index ? // TODO: What when player spawns in with an different index ?
selected: 0, selected: 0,
state_id: 0, state_id: AtomicU32::new(0),
total_opened_containers: 2, total_opened_containers: 2,
} }
} }

View File

@ -85,7 +85,6 @@ impl PacketEncoder {
let mut front = &mut self.buf[start_len..]; let mut front = &mut self.buf[start_len..];
#[allow(clippy::needless_borrows_for_generic_args)]
VarInt(packet_len as i32) VarInt(packet_len as i32)
.encode(&mut front) .encode(&mut front)
.map_err(|_| PacketError::EncodeLength)?; .map_err(|_| PacketError::EncodeLength)?;

View File

@ -37,12 +37,16 @@ use super::{
/// NEVER TRUST THE CLIENT. HANDLE EVERY ERROR, UNWRAP/EXPECT /// NEVER TRUST THE CLIENT. HANDLE EVERY ERROR, UNWRAP/EXPECT
/// TODO: REMOVE ALL UNWRAPS /// TODO: REMOVE ALL UNWRAPS
impl Client { impl Client {
pub fn handle_handshake(&mut self, _server: &Arc<Server>, handshake: SHandShake) { pub fn handle_handshake(&self, _server: &Arc<Server>, handshake: SHandShake) {
dbg!("handshake"); dbg!("handshake");
self.protocol_version = handshake.protocol_version.0; let version = handshake.protocol_version.0;
self.connection_state = handshake.next_state; self.protocol_version
if self.connection_state != ConnectionState::Status { .store(version, std::sync::atomic::Ordering::Relaxed);
let protocol = self.protocol_version; let mut connection_state = self.connection_state.lock().unwrap();
*connection_state = handshake.next_state;
if *connection_state != ConnectionState::Status {
let protocol = version;
match protocol.cmp(&(CURRENT_MC_PROTOCOL as i32)) { match protocol.cmp(&(CURRENT_MC_PROTOCOL as i32)) {
std::cmp::Ordering::Less => { std::cmp::Ordering::Less => {
self.kick(&format!("Client outdated ({protocol}), Server uses Minecraft {CURRENT_MC_VERSION}, Protocol {CURRENT_MC_PROTOCOL}")); self.kick(&format!("Client outdated ({protocol}), Server uses Minecraft {CURRENT_MC_VERSION}, Protocol {CURRENT_MC_PROTOCOL}"));
@ -55,11 +59,11 @@ impl Client {
} }
} }
pub fn handle_status_request(&mut self, server: &Arc<Server>, _status_request: SStatusRequest) { pub fn handle_status_request(&self, server: &Arc<Server>, _status_request: SStatusRequest) {
self.send_packet(&CStatusResponse::new(&server.status_response_json)); self.send_packet(&CStatusResponse::new(&server.status_response_json));
} }
pub fn handle_ping_request(&mut self, _server: &Arc<Server>, ping_request: SStatusPingRequest) { pub fn handle_ping_request(&self, _server: &Arc<Server>, ping_request: SStatusPingRequest) {
dbg!("ping"); dbg!("ping");
self.send_packet(&CPingResponse::new(ping_request.payload)); self.send_packet(&CPingResponse::new(ping_request.payload));
self.close(); self.close();
@ -72,7 +76,7 @@ impl Client {
.all(|c| c > 32_u8 as char && c < 127_u8 as char) .all(|c| c > 32_u8 as char && c < 127_u8 as char)
} }
pub fn handle_login_start(&mut self, server: &Arc<Server>, login_start: SLoginStart) { pub fn handle_login_start(&self, server: &Arc<Server>, login_start: SLoginStart) {
log::debug!("login start, State {:?}", self.connection_state); log::debug!("login start, State {:?}", self.connection_state);
if !Self::is_valid_player_name(&login_start.name) { if !Self::is_valid_player_name(&login_start.name) {
@ -81,7 +85,8 @@ impl Client {
} }
// default game profile, when no online mode // default game profile, when no online mode
// TODO: make offline uuid // TODO: make offline uuid
self.gameprofile = Some(GameProfile { let mut gameprofile = self.gameprofile.lock().unwrap();
*gameprofile = Some(GameProfile {
id: login_start.uuid, id: login_start.uuid,
name: login_start.name, name: login_start.name,
properties: vec![], properties: vec![],
@ -108,7 +113,7 @@ impl Client {
} }
pub async fn handle_encryption_response( pub async fn handle_encryption_response(
&mut self, &self,
server: &Arc<Server>, server: &Arc<Server>,
encryption_response: SEncryptionResponse, encryption_response: SEncryptionResponse,
) { ) {
@ -120,15 +125,17 @@ impl Client {
self.enable_encryption(&shared_secret) self.enable_encryption(&shared_secret)
.unwrap_or_else(|e| self.kick(&e.to_string())); .unwrap_or_else(|e| self.kick(&e.to_string()));
let mut gameprofile = self.gameprofile.lock().unwrap();
if BASIC_CONFIG.online_mode { if BASIC_CONFIG.online_mode {
let hash = Sha1::new() let hash = Sha1::new()
.chain_update(&shared_secret) .chain_update(&shared_secret)
.chain_update(&server.public_key_der) .chain_update(&server.public_key_der)
.finalize(); .finalize();
let hash = auth_digest(&hash); let hash = auth_digest(&hash);
let ip = self.address.ip(); let ip = self.address.lock().unwrap().ip();
match authentication::authenticate( match authentication::authenticate(
&self.gameprofile.as_ref().unwrap().name, &gameprofile.as_ref().unwrap().name,
&hash, &hash,
&ip, &ip,
server, server,
@ -159,12 +166,12 @@ impl Client {
} }
} }
} }
self.gameprofile = Some(p); *gameprofile = Some(p);
} }
Err(e) => self.kick(&e.to_string()), Err(e) => self.kick(&e.to_string()),
} }
} }
for ele in self.gameprofile.as_ref().unwrap().properties.clone() { for ele in gameprofile.as_ref().unwrap().properties.clone() {
// todo, use this // todo, use this
unpack_textures(ele, &ADVANCED_CONFIG.authentication.textures); unpack_textures(ele, &ADVANCED_CONFIG.authentication.textures);
} }
@ -177,7 +184,7 @@ impl Client {
self.set_compression(Some((threshold, level))); self.set_compression(Some((threshold, level)));
} }
if let Some(profile) = self.gameprofile.as_ref().cloned() { if let Some(profile) = gameprofile.as_ref().cloned() {
let packet = CLoginSuccess::new(&profile.id, &profile.name, &profile.properties, false); let packet = CLoginSuccess::new(&profile.id, &profile.name, &profile.properties, false);
self.send_packet(&packet); self.send_packet(&packet);
} else { } else {
@ -186,18 +193,18 @@ impl Client {
} }
pub fn handle_plugin_response( pub fn handle_plugin_response(
&mut self, &self,
_server: &Arc<Server>, _server: &Arc<Server>,
_plugin_response: SLoginPluginResponse, _plugin_response: SLoginPluginResponse,
) { ) {
} }
pub fn handle_login_acknowledged( pub fn handle_login_acknowledged(
&mut self, &self,
server: &Arc<Server>, server: &Arc<Server>,
_login_acknowledged: SLoginAcknowledged, _login_acknowledged: SLoginAcknowledged,
) { ) {
self.connection_state = ConnectionState::Config; *self.connection_state.lock().unwrap() = ConnectionState::Config;
server.send_brand(self); server.send_brand(self);
let resource_config = &ADVANCED_CONFIG.resource_pack; let resource_config = &ADVANCED_CONFIG.resource_pack;
@ -228,12 +235,12 @@ impl Client {
dbg!("login achnowlaged"); dbg!("login achnowlaged");
} }
pub fn handle_client_information_config( pub fn handle_client_information_config(
&mut self, &self,
_server: &Arc<Server>, _server: &Arc<Server>,
client_information: SClientInformationConfig, client_information: SClientInformationConfig,
) { ) {
dbg!("got client settings"); dbg!("got client settings");
self.config = Some(PlayerConfig { *self.config.lock().unwrap() = Some(PlayerConfig {
locale: client_information.locale, locale: client_information.locale,
view_distance: client_information.view_distance, view_distance: client_information.view_distance,
chat_mode: ChatMode::from_i32(client_information.chat_mode.into()).unwrap(), chat_mode: ChatMode::from_i32(client_information.chat_mode.into()).unwrap(),
@ -245,19 +252,19 @@ impl Client {
}); });
} }
pub fn handle_plugin_message(&mut self, _server: &Arc<Server>, plugin_message: SPluginMessage) { pub fn handle_plugin_message(&self, _server: &Arc<Server>, plugin_message: SPluginMessage) {
if plugin_message.channel.starts_with("minecraft:brand") if plugin_message.channel.starts_with("minecraft:brand")
|| plugin_message.channel.starts_with("MC|Brand") || plugin_message.channel.starts_with("MC|Brand")
{ {
dbg!("got a client brand"); dbg!("got a client brand");
match String::from_utf8(plugin_message.data) { match String::from_utf8(plugin_message.data) {
Ok(brand) => self.brand = Some(brand), Ok(brand) => *self.brand.lock().unwrap() = Some(brand),
Err(e) => self.kick(&e.to_string()), Err(e) => self.kick(&e.to_string()),
} }
} }
} }
pub fn handle_known_packs(&mut self, server: &Arc<Server>, _config_acknowledged: SKnownPacks) { pub fn handle_known_packs(&self, server: &Arc<Server>, _config_acknowledged: SKnownPacks) {
for registry in &server.cached_registry { for registry in &server.cached_registry {
self.send_packet(&CRegistryData::new( self.send_packet(&CRegistryData::new(
&registry.registry_id, &registry.registry_id,
@ -271,12 +278,13 @@ impl Client {
} }
pub async fn handle_config_acknowledged( pub async fn handle_config_acknowledged(
&mut self, &self,
_server: &Arc<Server>, _server: &Arc<Server>,
_config_acknowledged: SAcknowledgeFinishConfig, _config_acknowledged: SAcknowledgeFinishConfig,
) { ) {
dbg!("config acknowledged"); dbg!("config acknowledged");
self.connection_state = ConnectionState::Play; *self.connection_state.lock().unwrap() = ConnectionState::Play;
self.make_player = true; self.make_player
.store(true, std::sync::atomic::Ordering::Relaxed);
} }
} }

View File

@ -19,7 +19,7 @@ use pumpkin_world::item::ItemStack;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
impl Player { impl Player {
pub fn open_container(&mut self, server: &Arc<Server>, minecraft_menu_id: &str) { pub fn open_container(&self, server: &Arc<Server>, minecraft_menu_id: &str) {
self.inventory.state_id = 0; self.inventory.state_id = 0;
let total_opened_containers = self.inventory.total_opened_containers; let total_opened_containers = self.inventory.total_opened_containers;
let container = self.get_open_container(server); let container = self.get_open_container(server);
@ -49,9 +49,9 @@ impl Player {
self.set_container_content(container.as_deref_mut()); self.set_container_content(container.as_deref_mut());
} }
pub fn set_container_content(&mut self, container: Option<&mut Box<dyn Container>>) { pub fn set_container_content(&self, container: Option<&mut Box<dyn Container>>) {
let total_opened_containers = self.inventory.total_opened_containers; let total_opened_containers = self.inventory.total_opened_containers;
let container = OptionallyCombinedContainer::new(&mut self.inventory, container); let container = OptionallyCombinedContainer::new(&mut self.inventory.lock().unwrap(), container);
let slots = container let slots = container
.all_slots_ref() .all_slots_ref()
@ -77,7 +77,7 @@ impl Player {
} }
/// The official Minecraft client is weird, and will always just close *any* window that is opened when this gets sent /// The official Minecraft client is weird, and will always just close *any* window that is opened when this gets sent
pub fn close_container(&mut self) { pub fn close_container(&self) {
self.inventory.total_opened_containers += 1; self.inventory.total_opened_containers += 1;
self.client.send_packet(&CCloseContainer::new( self.client.send_packet(&CCloseContainer::new(
self.inventory.total_opened_containers, self.inventory.total_opened_containers,
@ -97,7 +97,7 @@ impl Player {
} }
pub async fn handle_click_container( pub async fn handle_click_container(
&mut self, &self,
server: &Arc<Server>, server: &Arc<Server>,
packet: SClickContainer, packet: SClickContainer,
) -> Result<(), InventoryError> { ) -> Result<(), InventoryError> {
@ -178,7 +178,7 @@ impl Player {
self.send_whole_container_change(server).await?; self.send_whole_container_change(server).await?;
} else if let container_click::Slot::Normal(slot_index) = click.slot { } else if let container_click::Slot::Normal(slot_index) = click.slot {
let combined_container = OptionallyCombinedContainer::new( let combined_container = OptionallyCombinedContainer::new(
&mut self.inventory, &mut self.inventory.lock().unwrap().lock().unwrap().lock().unwrap(),
Some(&mut opened_container), Some(&mut opened_container),
); );
if let Some(slot) = combined_container.get_slot_excluding_inventory(slot_index) { if let Some(slot) = combined_container.get_slot_excluding_inventory(slot_index) {
@ -193,27 +193,30 @@ impl Player {
} }
fn mouse_click( fn mouse_click(
&mut self, &self,
opened_container: Option<&mut Box<dyn Container>>, opened_container: Option<&mut Box<dyn Container>>,
mouse_click: MouseClick, mouse_click: MouseClick,
slot: container_click::Slot, slot: container_click::Slot,
) -> Result<(), InventoryError> { ) -> Result<(), InventoryError> {
let mut container = OptionallyCombinedContainer::new(&mut self.inventory, opened_container); let mut inventory = self.inventory.lock().unwrap();
let mut container =
OptionallyCombinedContainer::new(&mut inventory, opened_container);
match slot { match slot {
container_click::Slot::Normal(slot) => { container_click::Slot::Normal(slot) => {
container.handle_item_change(&mut self.carried_item, slot, mouse_click) container.handle_item_change(&mut self.carried_item.lock().unwrap(), slot, mouse_click)
} }
container_click::Slot::OutsideInventory => Ok(()), container_click::Slot::OutsideInventory => Ok(()),
} }
} }
fn shift_mouse_click( fn shift_mouse_click(
&mut self, &self,
opened_container: Option<&mut Box<dyn Container>>, opened_container: Option<&mut Box<dyn Container>>,
slot: container_click::Slot, slot: container_click::Slot,
) -> Result<(), InventoryError> { ) -> Result<(), InventoryError> {
let mut container = OptionallyCombinedContainer::new(&mut self.inventory, opened_container); let mut inventory = self.inventory.lock().unwrap();
let mut container = OptionallyCombinedContainer::new(&mut inventory, opened_container);
match slot { match slot {
container_click::Slot::Normal(slot) => { container_click::Slot::Normal(slot) => {
@ -265,7 +268,7 @@ impl Player {
KeyClick::Offhand => 45, KeyClick::Offhand => 45,
}; };
let mut changing_item_slot = self.inventory.get_slot(changing_slot as usize)?.to_owned(); let mut changing_item_slot = self.inventory.get_slot(changing_slot as usize)?.to_owned();
let mut container = OptionallyCombinedContainer::new(&mut self.inventory, opened_container); let mut container = OptionallyCombinedContainer::new(&mut self.inventory.lock().unwrap(), opened_container);
container.handle_item_change(&mut changing_item_slot, slot, MouseClick::Left)?; container.handle_item_change(&mut changing_item_slot, slot, MouseClick::Left)?;
*self.inventory.get_slot(changing_slot as usize)? = changing_item_slot; *self.inventory.get_slot(changing_slot as usize)? = changing_item_slot;
@ -280,7 +283,7 @@ impl Player {
if self.gamemode != GameMode::Creative { if self.gamemode != GameMode::Creative {
return Err(InventoryError::PermissionError); return Err(InventoryError::PermissionError);
} }
let mut container = OptionallyCombinedContainer::new(&mut self.inventory, opened_container); let mut container = OptionallyCombinedContainer::new(&mut self.inventory.lock().unwrap(), opened_container);
if let Some(Some(item)) = container.all_slots().get_mut(slot) { if let Some(Some(item)) = container.all_slots().get_mut(slot) {
self.carried_item = Some(item.to_owned()) self.carried_item = Some(item.to_owned())
} }
@ -292,7 +295,7 @@ impl Player {
opened_container: Option<&mut Box<dyn Container>>, opened_container: Option<&mut Box<dyn Container>>,
slot: usize, slot: usize,
) -> Result<(), InventoryError> { ) -> Result<(), InventoryError> {
let mut container = OptionallyCombinedContainer::new(&mut self.inventory, opened_container); let mut container = OptionallyCombinedContainer::new(&mut self.inventory.lock().unwrap(), opened_container);
let mut slots = container.all_slots(); let mut slots = container.all_slots();
let Some(item) = slots.get_mut(slot) else { let Some(item) = slots.get_mut(slot) else {
@ -345,7 +348,7 @@ impl Player {
MouseDragState::AddSlot(slot) => drag_handler.add_slot(container_id, player_id, slot), MouseDragState::AddSlot(slot) => drag_handler.add_slot(container_id, player_id, slot),
MouseDragState::End => { MouseDragState::End => {
let mut container = let mut container =
OptionallyCombinedContainer::new(&mut self.inventory, opened_container); OptionallyCombinedContainer::new(&mut self.inventory.lock().unwrap(), opened_container);
drag_handler.apply_drag( drag_handler.apply_drag(
&mut self.carried_item, &mut self.carried_item,
&mut container, &mut container,
@ -356,10 +359,7 @@ impl Player {
} }
} }
async fn get_current_players_in_container( async fn get_current_players_in_container(&self, server: &Server) -> Vec<Arc<Player>> {
&mut self,
server: &Server,
) -> Vec<Arc<Mutex<Player>>> {
let player_ids = { let player_ids = {
let open_containers = server let open_containers = server
.open_containers .open_containers
@ -378,13 +378,18 @@ impl Player {
// TODO: Figure out better way to get only the players from player_ids // TODO: Figure out better way to get only the players from player_ids
// Also refactor out a better method to get individual advanced state ids // Also refactor out a better method to get individual advanced state ids
let world = self.entity.world.lock().await; let players = self
let players = world .entity
.lock()
.unwrap()
.world
.current_players .current_players
.lock()
.unwrap()
.iter() .iter()
.filter_map(|(token, player)| { .filter_map(|(token, player)| {
if *token != player_token { if *token != player_token {
let entity_id = player.lock().unwrap().entity_id(); let entity_id = player.entity_id();
if player_ids.contains(&entity_id) { if player_ids.contains(&entity_id) {
Some(player.clone()) Some(player.clone())
} else { } else {
@ -405,13 +410,16 @@ impl Player {
slot: Slot, slot: Slot,
) -> Result<(), InventoryError> { ) -> Result<(), InventoryError> {
for player in self.get_current_players_in_container(server).await { for player in self.get_current_players_in_container(server).await {
let mut player = player.lock().unwrap();
let total_opened_containers = player.inventory.total_opened_containers; let total_opened_containers = player.inventory.total_opened_containers;
player.inventory.state_id += 1; // Returns previous value
let i = player
.inventory
.state_id
.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
let packet = CSetContainerSlot::new( let packet = CSetContainerSlot::new(
total_opened_containers as i8, total_opened_containers as i8,
player.inventory.state_id as i32, (i + 1) as i32,
slot_index, slot_index,
&slot, &slot,
); );
@ -420,11 +428,10 @@ impl Player {
Ok(()) Ok(())
} }
async fn send_whole_container_change(&mut self, server: &Server) -> Result<(), InventoryError> { async fn send_whole_container_change(&self, server: &Server) -> Result<(), InventoryError> {
let players = self.get_current_players_in_container(server).await; let players = self.get_current_players_in_container(server).await;
for player in players { for player in players {
let mut player = player.lock().unwrap();
let container = player.get_open_container(server); let container = player.get_open_container(server);
let mut container = container.as_ref().map(|v| v.lock().unwrap()); let mut container = container.as_ref().map(|v| v.lock().unwrap());
player.set_container_content(container.as_deref_mut()); player.set_container_content(container.as_deref_mut());

View File

@ -1,7 +1,10 @@
use std::{ use std::{
io::{self, Write}, io::{self, Write},
net::SocketAddr, net::SocketAddr,
sync::Arc, sync::{
atomic::{AtomicBool, AtomicI32},
Arc, Mutex,
},
}; };
use crate::{ use crate::{
@ -31,7 +34,7 @@ use thiserror::Error;
pub mod authentication; pub mod authentication;
mod client_packet; mod client_packet;
mod container; // mod container;
pub mod player_packet; pub mod player_packet;
#[derive(Clone)] #[derive(Clone)]
@ -62,95 +65,104 @@ impl Default for PlayerConfig {
} }
pub struct Client { pub struct Client {
pub gameprofile: Option<GameProfile>, pub gameprofile: Mutex<Option<GameProfile>>,
pub config: Option<PlayerConfig>, pub config: Mutex<Option<PlayerConfig>>,
pub brand: Option<String>, pub brand: Mutex<Option<String>>,
pub protocol_version: i32, pub protocol_version: AtomicI32,
pub connection_state: ConnectionState, pub connection_state: Mutex<ConnectionState>,
pub encryption: bool, pub encryption: AtomicBool,
pub closed: bool, pub closed: AtomicBool,
pub token: Token, pub token: Token,
pub connection: TcpStream, pub connection: Arc<Mutex<TcpStream>>,
pub address: SocketAddr, pub address: Mutex<SocketAddr>,
enc: PacketEncoder, enc: Arc<Mutex<PacketEncoder>>,
dec: PacketDecoder, dec: Arc<Mutex<PacketDecoder>>,
pub client_packets_queue: Vec<RawPacket>, pub client_packets_queue: Arc<Mutex<Vec<RawPacket>>>,
pub make_player: bool, pub make_player: AtomicBool,
} }
impl Client { impl Client {
pub fn new(token: Token, connection: TcpStream, address: SocketAddr) -> Self { pub fn new(token: Token, connection: TcpStream, address: SocketAddr) -> Self {
Self { Self {
protocol_version: 0, protocol_version: AtomicI32::new(0),
gameprofile: None, gameprofile: Mutex::new(None),
config: None, config: Mutex::new(None),
brand: None, brand: Mutex::new(None),
token, token,
address, address: Mutex::new(address),
connection_state: ConnectionState::HandShake, connection_state: Mutex::new(ConnectionState::HandShake),
connection, connection: Arc::new(Mutex::new(connection)),
enc: PacketEncoder::default(), enc: Arc::new(Mutex::new(PacketEncoder::default())),
dec: PacketDecoder::default(), dec: Arc::new(Mutex::new(PacketDecoder::default())),
encryption: true, encryption: AtomicBool::new(false),
closed: false, closed: AtomicBool::new(false),
client_packets_queue: Vec::new(), client_packets_queue: Arc::new(Mutex::new(Vec::new())),
make_player: false, make_player: AtomicBool::new(false),
} }
} }
/// adds a Incoming packet to the queue /// adds a Incoming packet to the queue
pub fn add_packet(&mut self, packet: RawPacket) { pub fn add_packet(&self, packet: RawPacket) {
self.client_packets_queue.push(packet); let mut client_packets_queue = self.client_packets_queue.lock().unwrap();
client_packets_queue.push(packet);
} }
/// enables encryption /// enables encryption
pub fn enable_encryption( pub fn enable_encryption(
&mut self, &self,
shared_secret: &[u8], // decrypted shared_secret: &[u8], // decrypted
) -> Result<(), EncryptionError> { ) -> Result<(), EncryptionError> {
self.encryption = true; self.encryption
.store(true, std::sync::atomic::Ordering::Relaxed);
let crypt_key: [u8; 16] = shared_secret let crypt_key: [u8; 16] = shared_secret
.try_into() .try_into()
.map_err(|_| EncryptionError::SharedWrongLength)?; .map_err(|_| EncryptionError::SharedWrongLength)?;
self.dec.enable_encryption(&crypt_key); self.dec.lock().unwrap().enable_encryption(&crypt_key);
self.enc.enable_encryption(&crypt_key); self.enc.lock().unwrap().enable_encryption(&crypt_key);
Ok(()) Ok(())
} }
// Compression threshold, Compression level // Compression threshold, Compression level
pub fn set_compression(&mut self, compression: Option<(u32, u32)>) { pub fn set_compression(&self, compression: Option<(u32, u32)>) {
self.dec.set_compression(compression.map(|v| v.0)); self.dec
self.enc.set_compression(compression); .lock()
.unwrap()
.set_compression(compression.map(|v| v.0));
self.enc.lock().unwrap().set_compression(compression);
} }
/// Send a Clientbound Packet to the Client /// Send a Clientbound Packet to the Client
pub fn send_packet<P: ClientPacket>(&mut self, packet: &P) { pub fn send_packet<P: ClientPacket>(&self, packet: &P) {
// assert!(!self.closed); // assert!(!self.closed);
let mut enc = self.enc.lock().unwrap();
self.enc enc.append_packet(packet)
.append_packet(packet)
.unwrap_or_else(|e| self.kick(&e.to_string())); .unwrap_or_else(|e| self.kick(&e.to_string()));
self.connection self.connection
.write_all(&self.enc.take()) .lock()
.unwrap()
.write_all(&enc.take())
.map_err(|_| PacketError::ConnectionWrite) .map_err(|_| PacketError::ConnectionWrite)
.unwrap_or_else(|e| self.kick(&e.to_string())); .unwrap_or_else(|e| self.kick(&e.to_string()));
} }
pub fn try_send_packet<P: ClientPacket>(&mut self, packet: &P) -> Result<(), PacketError> { pub fn try_send_packet<P: ClientPacket>(&self, packet: &P) -> Result<(), PacketError> {
// assert!(!self.closed); // assert!(!self.closed);
self.enc.append_packet(packet)?; let mut enc = self.enc.lock().unwrap();
enc.append_packet(packet)?;
self.connection self.connection
.write_all(&self.enc.take()) .lock()
.unwrap()
.write_all(&enc.take())
.map_err(|_| PacketError::ConnectionWrite)?; .map_err(|_| PacketError::ConnectionWrite)?;
Ok(()) Ok(())
} }
pub async fn process_packets(&mut self, server: &Arc<Server>) { pub async fn process_packets(&self, server: &Arc<Server>) {
while let Some(mut packet) = self.client_packets_queue.pop() { while let Some(mut packet) = self.client_packets_queue.lock().unwrap().pop() {
match self.handle_packet(server, &mut packet).await { match self.handle_packet(server, &mut packet).await {
Ok(_) => {} Ok(_) => {}
Err(e) => { Err(e) => {
@ -164,13 +176,13 @@ impl Client {
/// Handles an incoming decoded not Play state Packet /// Handles an incoming decoded not Play state Packet
pub async fn handle_packet( pub async fn handle_packet(
&mut self, &self,
server: &Arc<Server>, server: &Arc<Server>,
packet: &mut RawPacket, packet: &mut RawPacket,
) -> Result<(), DeserializerError> { ) -> Result<(), DeserializerError> {
// TODO: handle each packet's Error instead of calling .unwrap() // TODO: handle each packet's Error instead of calling .unwrap()
let bytebuf = &mut packet.bytebuf; let bytebuf = &mut packet.bytebuf;
match self.connection_state { match *self.connection_state.lock().unwrap() {
pumpkin_protocol::ConnectionState::HandShake => match packet.id.0 { pumpkin_protocol::ConnectionState::HandShake => match packet.id.0 {
SHandShake::PACKET_ID => { SHandShake::PACKET_ID => {
self.handle_handshake(server, SHandShake::read(bytebuf)?); self.handle_handshake(server, SHandShake::read(bytebuf)?);
@ -268,15 +280,16 @@ impl Client {
} }
} }
// Reads the connection until our buffer of len 4096 is full, then decode /// Reads the connection until our buffer of len 4096 is full, then decode
/// Close connection when an error occurs /// Close connection when an error occurs or when the Client closed the connection
pub async fn poll(&mut self, event: &Event) { pub async fn poll(&self, event: &Event) {
if event.is_readable() { if event.is_readable() {
let mut received_data = vec![0; 4096]; let mut received_data = vec![0; 4096];
let mut bytes_read = 0; let mut bytes_read = 0;
// We can (maybe) read from the connection.
loop { loop {
match self.connection.read(&mut received_data[bytes_read..]) { let connection = self.connection.clone();
let mut connection = connection.lock().unwrap();
match connection.read(&mut received_data[bytes_read..]) {
Ok(0) => { Ok(0) => {
// Reading 0 bytes means the other side has closed the // Reading 0 bytes means the other side has closed the
// connection or is done writing, then so are we. // connection or is done writing, then so are we.
@ -297,9 +310,9 @@ impl Client {
} }
if bytes_read != 0 { if bytes_read != 0 {
self.dec.reserve(4096); let mut dec = self.dec.lock().unwrap();
self.dec.queue_slice(&received_data[..bytes_read]); dec.queue_slice(&received_data[..bytes_read]);
match self.dec.decode() { match dec.decode() {
Ok(packet) => { Ok(packet) => {
if let Some(packet) = packet { if let Some(packet) = packet {
self.add_packet(packet); self.add_packet(packet);
@ -307,15 +320,15 @@ impl Client {
} }
Err(err) => self.kick(&err.to_string()), Err(err) => self.kick(&err.to_string()),
} }
self.dec.clear(); dec.clear();
} }
} }
} }
/// Kicks the Client with a reason depending on the connection state /// Kicks the Client with a reason depending on the connection state
pub fn kick(&mut self, reason: &str) { pub fn kick(&self, reason: &str) {
dbg!(reason); dbg!(reason);
match self.connection_state { match *self.connection_state.lock().unwrap() {
ConnectionState::Login => { ConnectionState::Login => {
self.try_send_packet(&CLoginDisconnect::new( self.try_send_packet(&CLoginDisconnect::new(
&serde_json::to_string_pretty(&reason).unwrap_or("".into()), &serde_json::to_string_pretty(&reason).unwrap_or("".into()),
@ -339,8 +352,9 @@ impl Client {
} }
/// You should prefer to use `kick` when you can /// You should prefer to use `kick` when you can
pub fn close(&mut self) { pub fn close(&self) {
self.closed = true; self.closed
.store(true, std::sync::atomic::Ordering::Relaxed);
} }
} }

View File

@ -42,16 +42,20 @@ fn modulus(a: f32, b: f32) -> f32 {
/// NEVER TRUST THE CLIENT. HANDLE EVERY ERROR, UNWRAP/EXPECT ARE FORBIDDEN /// NEVER TRUST THE CLIENT. HANDLE EVERY ERROR, UNWRAP/EXPECT ARE FORBIDDEN
impl Player { impl Player {
pub fn handle_confirm_teleport( pub fn handle_confirm_teleport(
&mut self, &self,
_server: &Arc<Server>, _server: &Arc<Server>,
confirm_teleport: SConfirmTeleport, confirm_teleport: SConfirmTeleport,
) { ) {
if let Some((id, position)) = self.awaiting_teleport.as_ref() { let mut awaiting_teleport = self.awaiting_teleport.lock().unwrap();
if let Some((id, position)) = awaiting_teleport.as_ref() {
if id == &confirm_teleport.teleport_id { if id == &confirm_teleport.teleport_id {
// we should set the pos now to that we requested in the teleport packet, Is may fixed issues when the client sended position packets while being teleported // we should set the pos now to that we requested in the teleport packet, Is may fixed issues when the client sended position packets while being teleported
self.entity.set_pos(position.x, position.y, position.z); self.entity
.lock()
.unwrap()
.set_pos(position.x, position.y, position.z);
self.awaiting_teleport = None; *awaiting_teleport = None;
} else { } else {
self.kick(TextComponent::text("Wrong teleport id")) self.kick(TextComponent::text("Wrong teleport id"))
} }
@ -70,13 +74,14 @@ impl Player {
pos.clamp(-2.0E7, 2.0E7) pos.clamp(-2.0E7, 2.0E7)
} }
pub async fn handle_position(&mut self, _server: &Arc<Server>, position: SPlayerPosition) { pub async fn handle_position(&self, _server: &Arc<Server>, position: SPlayerPosition) {
if position.x.is_nan() || position.feet_y.is_nan() || position.z.is_nan() { if position.x.is_nan() || position.feet_y.is_nan() || position.z.is_nan() {
self.kick(TextComponent::text("Invalid movement")); self.kick(TextComponent::text("Invalid movement"));
return; return;
} }
let entity = &mut self.entity; let mut entity = self.entity.lock().unwrap();
self.last_position = entity.pos; let mut last_position = self.last_position.lock().unwrap();
*last_position = entity.pos;
entity.set_pos( entity.set_pos(
Self::clamp_horizontal(position.x), Self::clamp_horizontal(position.x),
Self::clamp_vertical(position.feet_y), Self::clamp_vertical(position.feet_y),
@ -86,9 +91,8 @@ impl Player {
let on_ground = entity.on_ground; let on_ground = entity.on_ground;
let entity_id = entity.entity_id; let entity_id = entity.entity_id;
let (x, y, z) = entity.pos.into(); let (x, y, z) = entity.pos.into();
let (lastx, lasty, lastz) = self.last_position.into(); let (lastx, lasty, lastz) = (last_position.x, last_position.y, last_position.z);
let world = self.entity.world.clone(); let world = entity.world.clone();
let world = world.lock().await;
// let delta = Vector3::new(x - lastx, y - lasty, z - lastz); // let delta = Vector3::new(x - lastx, y - lasty, z - lastz);
// let velocity = self.velocity; // let velocity = self.velocity;
@ -103,7 +107,7 @@ impl Player {
// return; // return;
// } // }
// send new position to all other players // send new position to all other players
world.broadcast_packet( world.broadcast_packet_expect(
&[self.client.token], &[self.client.token],
&CUpdateEntityPos::new( &CUpdateEntityPos::new(
entity_id.into(), entity_id.into(),
@ -117,7 +121,7 @@ impl Player {
} }
pub async fn handle_position_rotation( pub async fn handle_position_rotation(
&mut self, &self,
_server: &Arc<Server>, _server: &Arc<Server>,
position_rotation: SPlayerPositionRotation, position_rotation: SPlayerPositionRotation,
) { ) {
@ -132,9 +136,10 @@ impl Player {
self.kick(TextComponent::text("Invalid rotation")); self.kick(TextComponent::text("Invalid rotation"));
return; return;
} }
let entity = &mut self.entity; let mut entity = self.entity.lock().unwrap();
self.last_position = entity.pos; let mut last_position = self.last_position.lock().unwrap();
*last_position = entity.pos;
entity.set_pos( entity.set_pos(
Self::clamp_horizontal(position_rotation.x), Self::clamp_horizontal(position_rotation.x),
Self::clamp_vertical(position_rotation.feet_y), Self::clamp_vertical(position_rotation.feet_y),
@ -147,12 +152,12 @@ impl Player {
let on_ground = entity.on_ground; let on_ground = entity.on_ground;
let entity_id = entity.entity_id; let entity_id = entity.entity_id;
let (x, y, z) = entity.pos.into(); let (x, y, z) = entity.pos.into();
let (lastx, lasty, lastz) = self.last_position.into(); let (lastx, lasty, lastz) = (last_position.x, last_position.y, last_position.z);
let yaw = modulus(entity.yaw * 256.0 / 360.0, 256.0); let yaw = modulus(entity.yaw * 256.0 / 360.0, 256.0);
let pitch = modulus(entity.pitch * 256.0 / 360.0, 256.0); let pitch = modulus(entity.pitch * 256.0 / 360.0, 256.0);
// let head_yaw = (entity.head_yaw * 256.0 / 360.0).floor(); // let head_yaw = (entity.head_yaw * 256.0 / 360.0).floor();
let world = self.entity.world.clone(); let entity = self.entity.lock().unwrap();
let world = world.lock().await; let world = &entity.world;
// let delta = Vector3::new(x - lastx, y - lasty, z - lastz); // let delta = Vector3::new(x - lastx, y - lasty, z - lastz);
// let velocity = self.velocity; // let velocity = self.velocity;
@ -168,7 +173,7 @@ impl Player {
// } // }
// send new position to all other players // send new position to all other players
world.broadcast_packet( world.broadcast_packet_expect(
&[self.client.token], &[self.client.token],
&CUpdateEntityPosRot::new( &CUpdateEntityPosRot::new(
entity_id.into(), entity_id.into(),
@ -180,20 +185,20 @@ impl Player {
on_ground, on_ground,
), ),
); );
world.broadcast_packet( world.broadcast_packet_expect(
&[self.client.token], &[self.client.token],
&CHeadRot::new(entity_id.into(), yaw as u8), &CHeadRot::new(entity_id.into(), yaw as u8),
); );
player_chunker::update_position(&world, self).await; player_chunker::update_position(world, self).await;
} }
pub async fn handle_rotation(&mut self, _server: &Arc<Server>, rotation: SPlayerRotation) { pub async fn handle_rotation(&self, _server: &Arc<Server>, rotation: SPlayerRotation) {
if !rotation.yaw.is_finite() || !rotation.pitch.is_finite() { if !rotation.yaw.is_finite() || !rotation.pitch.is_finite() {
self.kick(TextComponent::text("Invalid rotation")); self.kick(TextComponent::text("Invalid rotation"));
return; return;
} }
let entity = &mut self.entity; let mut entity = self.entity.lock().unwrap();
entity.on_ground = rotation.ground; entity.on_ground = rotation.ground;
entity.yaw = wrap_degrees(rotation.yaw) % 360.0; entity.yaw = wrap_degrees(rotation.yaw) % 360.0;
entity.pitch = wrap_degrees(rotation.pitch).clamp(-90.0, 90.0) % 360.0; entity.pitch = wrap_degrees(rotation.pitch).clamp(-90.0, 90.0) % 360.0;
@ -204,61 +209,58 @@ impl Player {
let pitch = modulus(entity.pitch * 256.0 / 360.0, 256.0); let pitch = modulus(entity.pitch * 256.0 / 360.0, 256.0);
// let head_yaw = modulus(entity.head_yaw * 256.0 / 360.0, 256.0); // let head_yaw = modulus(entity.head_yaw * 256.0 / 360.0, 256.0);
let world = self.entity.world.lock().await; let world = &entity.world;
let packet = CUpdateEntityRot::new(entity_id.into(), yaw as u8, pitch as u8, on_ground); let packet = CUpdateEntityRot::new(entity_id.into(), yaw as u8, pitch as u8, on_ground);
// self.client.send_packet(&packet); world.broadcast_packet_expect(&[self.client.token], &packet);
world.broadcast_packet(&[self.client.token], &packet);
let packet = CHeadRot::new(entity_id.into(), yaw as u8); let packet = CHeadRot::new(entity_id.into(), yaw as u8);
// self.client.send_packet(&packet); world.broadcast_packet_expect(&[self.client.token], &packet);
world.broadcast_packet(&[self.client.token], &packet);
} }
pub fn handle_chat_command(&mut self, server: &Arc<Server>, command: SChatCommand) { pub fn handle_chat_command(&self, server: &Arc<Server>, command: SChatCommand) {
let dispatcher = server.command_dispatcher.clone(); let dispatcher = server.command_dispatcher.clone();
dispatcher.handle_command(&mut CommandSender::Player(self), server, &command.command); dispatcher.handle_command(&mut CommandSender::Player(self), server, &command.command);
} }
pub fn handle_player_ground(&mut self, _server: &Arc<Server>, ground: SSetPlayerGround) { pub fn handle_player_ground(&self, _server: &Arc<Server>, ground: SSetPlayerGround) {
self.entity.on_ground = ground.on_ground; self.entity.lock().unwrap().on_ground = ground.on_ground;
} }
pub async fn handle_player_command(&mut self, _server: &Arc<Server>, command: SPlayerCommand) { pub async fn handle_player_command(&self, _server: &Arc<Server>, command: SPlayerCommand) {
if command.entity_id != self.entity.entity_id.into() { if command.entity_id != self.entity_id().into() {
return; return;
} }
if let Some(action) = Action::from_i32(command.action.0) { if let Some(action) = Action::from_i32(command.action.0) {
let mut entity = self.entity.lock().unwrap();
match action { match action {
pumpkin_protocol::server::play::Action::StartSneaking => { pumpkin_protocol::server::play::Action::StartSneaking => {
if !self.entity.sneaking { if !entity.sneaking {
self.entity.set_sneaking(&mut self.client, true).await entity.set_sneaking(true).await
} }
} }
pumpkin_protocol::server::play::Action::StopSneaking => { pumpkin_protocol::server::play::Action::StopSneaking => {
if self.entity.sneaking { if entity.sneaking {
self.entity.set_sneaking(&mut self.client, false).await entity.set_sneaking(false).await
} }
} }
pumpkin_protocol::server::play::Action::LeaveBed => todo!(), pumpkin_protocol::server::play::Action::LeaveBed => todo!(),
pumpkin_protocol::server::play::Action::StartSprinting => { pumpkin_protocol::server::play::Action::StartSprinting => {
if !self.entity.sprinting { if !entity.sprinting {
self.entity.set_sprinting(&mut self.client, true).await entity.set_sprinting(true).await
} }
} }
pumpkin_protocol::server::play::Action::StopSprinting => { pumpkin_protocol::server::play::Action::StopSprinting => {
if self.entity.sprinting { if entity.sprinting {
self.entity.set_sprinting(&mut self.client, false).await entity.set_sprinting(false).await
} }
} }
pumpkin_protocol::server::play::Action::StartHorseJump => todo!(), pumpkin_protocol::server::play::Action::StartHorseJump => todo!(),
pumpkin_protocol::server::play::Action::StopHorseJump => todo!(), pumpkin_protocol::server::play::Action::StopHorseJump => todo!(),
pumpkin_protocol::server::play::Action::OpenVehicleInventory => todo!(), pumpkin_protocol::server::play::Action::OpenVehicleInventory => todo!(),
pumpkin_protocol::server::play::Action::StartFlyingElytra => { pumpkin_protocol::server::play::Action::StartFlyingElytra => {
let fall_flying = self.entity.check_fall_flying(); let fall_flying = entity.check_fall_flying();
if self.entity.fall_flying != fall_flying { if entity.fall_flying != fall_flying {
self.entity entity.set_fall_flying(fall_flying).await;
.set_fall_flying(&mut self.client, fall_flying)
.await;
} }
} // TODO } // TODO
} }
@ -267,7 +269,7 @@ impl Player {
} }
} }
pub async fn handle_swing_arm(&mut self, _server: &Arc<Server>, swing_arm: SSwingArm) { pub async fn handle_swing_arm(&self, _server: &Arc<Server>, swing_arm: SSwingArm) {
match Hand::from_i32(swing_arm.hand.0) { match Hand::from_i32(swing_arm.hand.0) {
Some(hand) => { Some(hand) => {
let animation = match hand { let animation = match hand {
@ -275,8 +277,9 @@ impl Player {
Hand::Off => Animation::SwingOffhand, Hand::Off => Animation::SwingOffhand,
}; };
let id = self.entity_id(); let id = self.entity_id();
let world = self.entity.world.lock().await; let entity = self.entity.lock().unwrap();
world.broadcast_packet( let world = &entity.world;
world.broadcast_packet_expect(
&[self.client.token], &[self.client.token],
&CEntityAnimation::new(id.into(), animation as u8), &CEntityAnimation::new(id.into(), animation as u8),
) )
@ -287,7 +290,7 @@ impl Player {
}; };
} }
pub async fn handle_chat_message(&mut self, _server: &Arc<Server>, chat_message: SChatMessage) { pub async fn handle_chat_message(&self, _server: &Arc<Server>, chat_message: SChatMessage) {
dbg!("got message"); dbg!("got message");
let message = chat_message.message; let message = chat_message.message;
@ -299,24 +302,22 @@ impl Player {
// TODO: filter message & validation // TODO: filter message & validation
let gameprofile = &self.gameprofile; let gameprofile = &self.gameprofile;
let world = self.entity.world.lock().await; let entity = self.entity.lock().unwrap();
world.broadcast_packet( let world = &entity.world;
&[self.client.token], world.broadcast_packet_all(&CPlayerChatMessage::new(
&CPlayerChatMessage::new( pumpkin_protocol::uuid::UUID(gameprofile.id),
pumpkin_protocol::uuid::UUID(gameprofile.id), 1.into(),
1.into(), chat_message.signature.as_deref(),
chat_message.signature.as_deref(), &message,
&message, chat_message.timestamp,
chat_message.timestamp, chat_message.salt,
chat_message.salt, &[],
&[], Some(TextComponent::text(&message)),
Some(TextComponent::text(&message)), FilterType::PassThrough,
FilterType::PassThrough, 1.into(),
1.into(), TextComponent::text(&gameprofile.name.clone()),
TextComponent::text(&gameprofile.name.clone()), None,
None, ))
),
)
/* server.broadcast_packet( /* server.broadcast_packet(
self, self,
@ -330,7 +331,7 @@ impl Player {
} }
pub fn handle_client_information_play( pub fn handle_client_information_play(
&mut self, &self,
_server: &Arc<Server>, _server: &Arc<Server>,
client_information: SClientInformationPlay, client_information: SClientInformationPlay,
) { ) {
@ -338,7 +339,7 @@ impl Player {
Hand::from_i32(client_information.main_hand.into()), Hand::from_i32(client_information.main_hand.into()),
ChatMode::from_i32(client_information.chat_mode.into()), ChatMode::from_i32(client_information.chat_mode.into()),
) { ) {
self.config = PlayerConfig { *self.config.lock().unwrap() = PlayerConfig {
locale: client_information.locale, locale: client_information.locale,
view_distance: client_information.view_distance, view_distance: client_information.view_distance,
chat_mode, chat_mode,
@ -353,10 +354,11 @@ impl Player {
} }
} }
pub async fn handle_interact(&mut self, _: &Arc<Server>, interact: SInteract) { pub async fn handle_interact(&self, _: &Arc<Server>, interact: SInteract) {
let sneaking = interact.sneaking; let sneaking = interact.sneaking;
if self.entity.sneaking != sneaking { let mut entity = self.entity.lock().unwrap();
self.entity.set_sneaking(&mut self.client, sneaking).await; if entity.sneaking != sneaking {
entity.set_sneaking(sneaking).await;
} }
match ActionType::from_i32(interact.typ.0) { match ActionType::from_i32(interact.typ.0) {
Some(action) => match action { Some(action) => match action {
@ -365,19 +367,20 @@ impl Player {
// TODO: do validation and stuff // TODO: do validation and stuff
let config = &ADVANCED_CONFIG.pvp; let config = &ADVANCED_CONFIG.pvp;
if config.enabled { if config.enabled {
let world = self.entity.world.clone(); let world = entity.world.clone();
let world = world.lock().await;
let attacked_player = world.get_by_entityid(self, entity_id.0 as EntityId); let attacked_player = world.get_by_entityid(self, entity_id.0 as EntityId);
if let Some(mut player) = attacked_player { if let Some(player) = attacked_player {
let token = player.client.token; let mut victem_entity = player.entity.lock().unwrap();
let velo = player.entity.velocity; let velo = victem_entity.velocity;
if config.protect_creative && player.gamemode == GameMode::Creative { if config.protect_creative
&& *player.gamemode.lock().unwrap() == GameMode::Creative
{
return; return;
} }
if config.knockback { if config.knockback {
let yaw = self.entity.yaw; let yaw = entity.yaw;
let strength = 1.0; let strength = 1.0;
player.entity.knockback( victem_entity.knockback(
strength * 0.5, strength * 0.5,
(yaw * (PI / 180.0)).sin() as f64, (yaw * (PI / 180.0)).sin() as f64,
-(yaw * (PI / 180.0)).cos() as f64, -(yaw * (PI / 180.0)).cos() as f64,
@ -388,21 +391,15 @@ impl Player {
velo.y as f32, velo.y as f32,
velo.z as f32, velo.z as f32,
); );
self.entity.velocity = self.entity.velocity.multiply(0.6, 1.0, 0.6); entity.velocity = entity.velocity.multiply(0.6, 1.0, 0.6);
player.entity.velocity = velo; victem_entity.velocity = velo;
player.client.send_packet(packet); player.client.send_packet(packet);
} }
if config.hurt_animation { if config.hurt_animation {
// TODO world.broadcast_packet_all(&CHurtAnimation::new(
// thats how we prevent borrow errors :c &entity_id, entity.yaw,
let packet = &CHurtAnimation::new(&entity_id, self.entity.yaw); ))
self.client.send_packet(packet);
player.client.send_packet(packet);
world.broadcast_packet(
&[self.client.token, token],
&CHurtAnimation::new(&entity_id, 10.0),
)
} }
if config.swing {} if config.swing {}
} else { } else {
@ -420,11 +417,7 @@ impl Player {
None => self.kick(TextComponent::text("Invalid action type")), None => self.kick(TextComponent::text("Invalid action type")),
} }
} }
pub async fn handle_player_action( pub async fn handle_player_action(&self, _server: &Arc<Server>, player_action: SPlayerAction) {
&mut self,
_server: &Arc<Server>,
player_action: SPlayerAction,
) {
match Status::from_i32(player_action.status.0) { match Status::from_i32(player_action.status.0) {
Some(status) => match status { Some(status) => match status {
Status::StartedDigging => { Status::StartedDigging => {
@ -434,20 +427,15 @@ impl Player {
} }
// TODO: do validation // TODO: do validation
// TODO: Config // TODO: Config
if self.gamemode == GameMode::Creative { if *self.gamemode.lock().unwrap() == GameMode::Creative {
let location = player_action.location; let location = player_action.location;
// Block break & block break sound // Block break & block break sound
// TODO: currently this is always dirt replace it // TODO: currently this is always dirt replace it
let world = self.entity.world.lock().await; let entity = self.entity.lock().unwrap();
world.broadcast_packet( let world = &entity.world;
&[self.client.token], world.broadcast_packet_all(&CWorldEvent::new(2001, &location, 11, false));
&CWorldEvent::new(2001, &location, 11, false),
);
// AIR // AIR
world.broadcast_packet( world.broadcast_packet_all(&CBlockUpdate::new(&location, 0.into()));
&[self.client.token],
&CBlockUpdate::new(&location, 0.into()),
);
} }
} }
Status::CancelledDigging => { Status::CancelledDigging => {
@ -455,7 +443,8 @@ impl Player {
// TODO: maybe log? // TODO: maybe log?
return; return;
} }
self.current_block_destroy_stage = 0; self.current_block_destroy_stage
.store(0, std::sync::atomic::Ordering::Relaxed);
} }
Status::FinishedDigging => { Status::FinishedDigging => {
// TODO: do validation // TODO: do validation
@ -466,16 +455,11 @@ impl Player {
} }
// Block break & block break sound // Block break & block break sound
// TODO: currently this is always dirt replace it // TODO: currently this is always dirt replace it
let world = self.entity.world.lock().await; let entity = self.entity.lock().unwrap();
world.broadcast_packet( let world = &entity.world;
&[self.client.token], world.broadcast_packet_all(&CWorldEvent::new(2001, &location, 11, false));
&CWorldEvent::new(2001, &location, 11, false),
);
// AIR // AIR
world.broadcast_packet( world.broadcast_packet_all(&CBlockUpdate::new(&location, 0.into()));
&[self.client.token],
&CBlockUpdate::new(&location, 0.into()),
);
// TODO: Send this every tick // TODO: Send this every tick
self.client self.client
.send_packet(&CAcknowledgeBlockChange::new(player_action.sequence)); .send_packet(&CAcknowledgeBlockChange::new(player_action.sequence));
@ -497,12 +481,12 @@ impl Player {
} }
} }
pub fn handle_play_ping_request(&mut self, _server: &Arc<Server>, request: SPlayPingRequest) { pub fn handle_play_ping_request(&self, _server: &Arc<Server>, request: SPlayPingRequest) {
self.client self.client
.send_packet(&CPingResponse::new(request.payload)); .send_packet(&CPingResponse::new(request.payload));
} }
pub async fn handle_use_item_on(&mut self, _server: &Arc<Server>, use_item_on: SUseItemOn) { pub async fn handle_use_item_on(&self, _server: &Arc<Server>, use_item_on: SUseItemOn) {
let location = use_item_on.location; let location = use_item_on.location;
if !self.can_interact_with_block_at(&location, 1.0) { if !self.can_interact_with_block_at(&location, 1.0) {
@ -511,25 +495,23 @@ impl Player {
} }
if let Some(face) = BlockFace::from_i32(use_item_on.face.0) { if let Some(face) = BlockFace::from_i32(use_item_on.face.0) {
if let Some(item) = self.inventory.held_item() { if let Some(item) = self.inventory.lock().unwrap().held_item() {
let minecraft_id = global_registry::find_minecraft_id( let minecraft_id = global_registry::find_minecraft_id(
global_registry::ITEM_REGISTRY, global_registry::ITEM_REGISTRY,
item.item_id, item.item_id,
) )
.expect("All item ids are in the global registry"); .expect("All item ids are in the global registry");
if let Ok(block_state_id) = BlockId::new(minecraft_id, None) { if let Ok(block_state_id) = BlockId::new(minecraft_id, None) {
let world = self.entity.world.lock().await; let entity = self.entity.lock().unwrap();
world.broadcast_packet( let world = &entity.world;
&[self.client.token], world.broadcast_packet_all(&CBlockUpdate::new(
&CBlockUpdate::new(&location, block_state_id.get_id_mojang_repr().into()), &location,
); block_state_id.get_id_mojang_repr().into(),
world.broadcast_packet( ));
&[self.client.token], world.broadcast_packet_all(&CBlockUpdate::new(
&CBlockUpdate::new( &WorldPosition(location.0 + face.to_offset()),
&WorldPosition(location.0 + face.to_offset()), block_state_id.get_id_mojang_repr().into(),
block_state_id.get_id_mojang_repr().into(), ));
),
);
} }
} }
self.client self.client
@ -539,38 +521,46 @@ impl Player {
} }
} }
pub fn handle_use_item(&mut self, _server: &Arc<Server>, _use_item: SUseItem) { pub fn handle_use_item(&self, _server: &Arc<Server>, _use_item: SUseItem) {
// TODO: handle packet correctly // TODO: handle packet correctly
log::error!("An item was used(SUseItem), but the packet is not implemented yet"); log::error!("An item was used(SUseItem), but the packet is not implemented yet");
} }
pub fn handle_set_held_item(&mut self, _server: &Arc<Server>, held: SSetHeldItem) { pub fn handle_set_held_item(&self, _server: &Arc<Server>, held: SSetHeldItem) {
let slot = held.slot; let slot = held.slot;
if !(0..=8).contains(&slot) { if !(0..=8).contains(&slot) {
self.kick(TextComponent::text("Invalid held slot")) self.kick(TextComponent::text("Invalid held slot"))
} }
self.inventory.set_selected(slot as usize); self.inventory.lock().unwrap().set_selected(slot as usize);
} }
pub fn handle_set_creative_slot( pub fn handle_set_creative_slot(
&mut self, &self,
_server: &Arc<Server>, _server: &Arc<Server>,
packet: SSetCreativeSlot, packet: SSetCreativeSlot,
) -> Result<(), InventoryError> { ) -> Result<(), InventoryError> {
if self.gamemode != GameMode::Creative { if *self.gamemode.lock().unwrap() != GameMode::Creative {
return Err(InventoryError::PermissionError); return Err(InventoryError::PermissionError);
} }
self.inventory self.inventory.lock().unwrap().set_slot(
.set_slot(packet.slot as usize, packet.clicked_item.to_item(), false) packet.slot as usize,
packet.clicked_item.to_item(),
false,
)
} }
// TODO: // TODO:
// This function will in the future be used to keep track of if the client is in a valid state. // This function will in the future be used to keep track of if the client is in a valid state.
// But this is not possible yet // But this is not possible yet
pub fn handle_close_container(&mut self, server: &Arc<Server>, packet: SCloseContainer) { pub fn handle_close_container(&self, server: &Arc<Server>, packet: SCloseContainer) {
// window_id 0 represents both 9x1 Generic AND inventory here // window_id 0 represents both 9x1 Generic AND inventory here
self.inventory.state_id = 0; self.inventory
if let Some(id) = self.open_container { .lock()
.unwrap()
.state_id
.store(0, std::sync::atomic::Ordering::Relaxed);
let mut open_container = self.open_container.lock().unwrap();
if let Some(id) = *open_container {
let mut open_containers = server let mut open_containers = server
.open_containers .open_containers
.write() .write()
@ -578,7 +568,7 @@ impl Player {
if let Some(container) = open_containers.get_mut(&id) { if let Some(container) = open_containers.get_mut(&id) {
container.remove_player(self.entity_id()) container.remove_player(self.entity_id())
} }
self.open_container = None; *open_container = None;
} }
let Some(_window_type) = WindowType::from_u8(packet.window_id) else { let Some(_window_type) = WindowType::from_u8(packet.window_id) else {
self.kick(TextComponent::text("Invalid window ID")); self.kick(TextComponent::text("Invalid window ID"));

View File

@ -31,7 +31,7 @@ pub fn parse_arg_player<'a>(
src: &'a mut CommandSender, src: &'a mut CommandSender,
arg_name: &str, arg_name: &str,
consumed_args: &ConsumedArgs, consumed_args: &ConsumedArgs,
) -> Result<&'a mut crate::entity::player::Player, InvalidTreeError> { ) -> Result<&'a crate::entity::player::Player, InvalidTreeError> {
let s = consumed_args let s = consumed_args
.get(arg_name) .get(arg_name)
.ok_or(InvalidConsumptionError(None))? .ok_or(InvalidConsumptionError(None))?

View File

@ -11,7 +11,7 @@ pub(crate) fn init_command_tree<'a>() -> CommandTree<'a> {
CommandTree::new(NAMES, DESCRIPTION).execute(&|sender, server, _| { CommandTree::new(NAMES, DESCRIPTION).execute(&|sender, server, _| {
if let Some(player) = sender.as_mut_player() { if let Some(player) = sender.as_mut_player() {
let entity_id = player.entity_id(); let entity_id = player.entity_id();
player.open_container = Some(0); *player.open_container.lock().unwrap() = Some(0);
{ {
let mut open_containers = server let mut open_containers = server
.open_containers .open_containers
@ -27,7 +27,8 @@ pub(crate) fn init_command_tree<'a>() -> CommandTree<'a> {
} }
} }
} }
player.open_container(server, "minecraft:generic_9x3"); // TODO
// player.open_container(server, "minecraft:generic_9x3");
} }
Ok(()) Ok(())

View File

@ -65,15 +65,14 @@ pub(crate) fn init_command_tree<'a>() -> CommandTree<'a> {
let gamemode = parse_arg_gamemode(args)?; let gamemode = parse_arg_gamemode(args)?;
return if let Player(target) = sender { return if let Player(target) = sender {
if target.gamemode == gamemode { if *target.gamemode.lock().unwrap() == gamemode {
target.send_system_message(TextComponent::text(&format!( target.send_system_message(TextComponent::text(&format!(
"You already in {:?} gamemode", "You already in {:?} gamemode",
gamemode gamemode
))); )));
} else { } else {
// TODO // TODO
#[expect(clippy::let_underscore_future)] target.set_gamemode(gamemode);
let _ = target.set_gamemode(gamemode);
target.send_system_message(TextComponent::text(&format!( target.send_system_message(TextComponent::text(&format!(
"Game mode was set to {:?}", "Game mode was set to {:?}",
gamemode gamemode
@ -90,15 +89,14 @@ pub(crate) fn init_command_tree<'a>() -> CommandTree<'a> {
let gamemode = parse_arg_gamemode(args)?; let gamemode = parse_arg_gamemode(args)?;
let target = parse_arg_player(sender, ARG_TARGET, args)?; let target = parse_arg_player(sender, ARG_TARGET, args)?;
if target.gamemode == gamemode { if *target.gamemode.lock().unwrap() == gamemode {
target.send_system_message(TextComponent::text(&format!( target.send_system_message(TextComponent::text(&format!(
"You already in {:?} gamemode", "You already in {:?} gamemode",
gamemode gamemode
))); )));
} else { } else {
// TODO // TODO
#[expect(clippy::let_underscore_future)] target.set_gamemode(gamemode);
let _ = target.set_gamemode(gamemode);
target.send_system_message(TextComponent::text(&format!( target.send_system_message(TextComponent::text(&format!(
"Game mode was set to {:?}", "Game mode was set to {:?}",
gamemode gamemode

View File

@ -21,7 +21,7 @@ mod tree_format;
pub enum CommandSender<'a> { pub enum CommandSender<'a> {
Rcon(&'a mut Vec<String>), Rcon(&'a mut Vec<String>),
Console, Console,
Player(&'a mut Player), Player(&'a Player),
} }
impl<'a> CommandSender<'a> { impl<'a> CommandSender<'a> {
@ -49,7 +49,7 @@ impl<'a> CommandSender<'a> {
CommandSender::Rcon(_) => true, CommandSender::Rcon(_) => true,
} }
} }
pub fn as_mut_player(&mut self) -> Option<&mut Player> { pub fn as_mut_player(&mut self) -> Option<&Player> {
match self { match self {
CommandSender::Player(player) => Some(player), CommandSender::Player(player) => Some(player),
CommandSender::Console => None, CommandSender::Console => None,

View File

@ -9,14 +9,14 @@ use pumpkin_protocol::{
VarInt, VarInt,
}; };
use crate::{client::Client, world::World}; use crate::world::World;
pub mod player; pub mod player;
pub struct Entity { pub struct Entity {
pub entity_id: EntityId, pub entity_id: EntityId,
pub entity_type: EntityType, pub entity_type: EntityType,
pub world: Arc<tokio::sync::Mutex<World>>, pub world: Arc<World>,
pub pos: Vector3<f64>, pub pos: Vector3<f64>,
pub block_pos: WorldPosition, pub block_pos: WorldPosition,
@ -38,11 +38,10 @@ pub struct Entity {
pub pose: EntityPose, pub pose: EntityPose,
} }
// TODO: Remove client: &mut Client, world: Arc<tokio::sync::Mutex<World>> bs
impl Entity { impl Entity {
pub fn new( pub fn new(
entity_id: EntityId, entity_id: EntityId,
world: Arc<tokio::sync::Mutex<World>>, world: Arc<World>,
entity_type: EntityType, entity_type: EntityType,
standing_eye_height: f32, standing_eye_height: f32,
) -> Self { ) -> Self {
@ -87,6 +86,10 @@ impl Entity {
} }
} }
pub async fn remove(&mut self) {
self.world.remove_entity(self);
}
pub fn knockback(&mut self, strength: f64, x: f64, z: f64) { pub fn knockback(&mut self, strength: f64, x: f64, z: f64) {
// This has some vanilla magic // This has some vanilla magic
let mut x = x; let mut x = x;
@ -109,11 +112,10 @@ impl Entity {
); );
} }
pub async fn set_sneaking(&mut self, client: &mut Client, sneaking: bool) { pub async fn set_sneaking(&mut self, sneaking: bool) {
assert!(self.sneaking != sneaking); assert!(self.sneaking != sneaking);
self.sneaking = sneaking; self.sneaking = sneaking;
self.set_flag(client, Self::SNEAKING_FLAG_INDEX, sneaking) self.set_flag(Self::SNEAKING_FLAG_INDEX, sneaking).await;
.await;
// if sneaking { // if sneaking {
// self.set_pose(EntityPose::Crouching).await; // self.set_pose(EntityPose::Crouching).await;
// } else { // } else {
@ -121,21 +123,20 @@ impl Entity {
// } // }
} }
pub async fn set_sprinting(&mut self, client: &mut Client, sprinting: bool) { pub async fn set_sprinting(&mut self, sprinting: bool) {
assert!(self.sprinting != sprinting); assert!(self.sprinting != sprinting);
self.sprinting = sprinting; self.sprinting = sprinting;
self.set_flag(client, Self::SPRINTING_FLAG_INDEX, sprinting) self.set_flag(Self::SPRINTING_FLAG_INDEX, sprinting).await;
.await;
} }
pub fn check_fall_flying(&self) -> bool { pub fn check_fall_flying(&self) -> bool {
!self.on_ground !self.on_ground
} }
pub async fn set_fall_flying(&mut self, client: &mut Client, fall_flying: bool) { pub async fn set_fall_flying(&mut self, fall_flying: bool) {
assert!(self.fall_flying != fall_flying); assert!(self.fall_flying != fall_flying);
self.fall_flying = fall_flying; self.fall_flying = fall_flying;
self.set_flag(client, Self::FALL_FLYING_FLAG_INDEX, fall_flying) self.set_flag(Self::FALL_FLYING_FLAG_INDEX, fall_flying)
.await; .await;
} }
@ -146,7 +147,7 @@ impl Entity {
pub const INVISIBLE_FLAG_INDEX: u32 = 5; pub const INVISIBLE_FLAG_INDEX: u32 = 5;
pub const GLOWING_FLAG_INDEX: u32 = 6; pub const GLOWING_FLAG_INDEX: u32 = 6;
pub const FALL_FLYING_FLAG_INDEX: u32 = 7; pub const FALL_FLYING_FLAG_INDEX: u32 = 7;
async fn set_flag(&mut self, client: &mut Client, index: u32, value: bool) { async fn set_flag(&mut self, index: u32, value: bool) {
let mut b = 0i8; let mut b = 0i8;
if value { if value {
b |= 1 << index; b |= 1 << index;
@ -154,24 +155,16 @@ impl Entity {
b &= !(1 << index); b &= !(1 << index);
} }
let packet = CSetEntityMetadata::new(self.entity_id.into(), Metadata::new(0, 0.into(), b)); let packet = CSetEntityMetadata::new(self.entity_id.into(), Metadata::new(0, 0.into(), b));
client.send_packet(&packet); self.world.broadcast_packet_all(&packet);
self.world
.lock()
.await
.broadcast_packet(&[client.token], &packet);
} }
pub async fn set_pose(&mut self, client: &mut Client, pose: EntityPose) { pub async fn set_pose(&mut self, pose: EntityPose) {
self.pose = pose; self.pose = pose;
let pose = self.pose as i32; let pose = self.pose as i32;
let packet = CSetEntityMetadata::<VarInt>::new( let packet = CSetEntityMetadata::<VarInt>::new(
self.entity_id.into(), self.entity_id.into(),
Metadata::new(6, 20.into(), (pose).into()), Metadata::new(6, 20.into(), (pose).into()),
); );
client.send_packet(&packet); self.world.broadcast_packet_all(&packet)
self.world
.lock()
.await
.broadcast_packet(&[client.token], &packet)
} }
} }

View File

@ -1,4 +1,7 @@
use std::sync::Arc; use std::sync::{
atomic::{AtomicI32, AtomicU8},
Arc, Mutex,
};
use num_derive::FromPrimitive; use num_derive::FromPrimitive;
use num_traits::ToPrimitive; use num_traits::ToPrimitive;
@ -58,43 +61,38 @@ impl Default for PlayerAbilities {
} }
pub struct Player { pub struct Player {
pub entity: Entity, pub entity: Mutex<Entity>,
pub gameprofile: GameProfile, pub gameprofile: GameProfile,
pub client: Client, pub client: Client,
pub config: PlayerConfig, pub config: Mutex<PlayerConfig>,
/// Current gamemode /// Current gamemode
pub gamemode: GameMode, pub gamemode: Mutex<GameMode>,
// TODO: prbly should put this into an Living Entitiy or something // TODO: prbly should put this into an Living Entitiy or something
pub health: f32, pub health: Mutex<f32>,
pub food: i32, pub food: AtomicI32,
pub food_saturation: f32, pub food_saturation: Mutex<f32>,
pub inventory: PlayerInventory, pub inventory: Mutex<PlayerInventory>,
pub open_container: Option<u64>, pub open_container: Mutex<Option<u64>>,
pub carried_item: Option<ItemStack>, pub carried_item: Mutex<Option<ItemStack>>,
/// send `send_abilties_update` when changed /// send `send_abilties_update` when changed
pub abilities: PlayerAbilities, pub abilities: PlayerAbilities,
pub last_position: Vector3<f64>, pub last_position: Mutex<Vector3<f64>>,
// TODO: This is currently unused, We have to calculate the block breaking speed our own and then break the block our own if its done // TODO: This is currently unused, We have to calculate the block breaking speed our own and then break the block our own if its done
pub current_block_destroy_stage: u8, pub current_block_destroy_stage: AtomicU8,
pub teleport_id_count: i32, pub teleport_id_count: AtomicI32,
// Current awaiting teleport id and location, None if did not teleport // Current awaiting teleport id and location, None if did not teleport
pub awaiting_teleport: Option<(VarInt, Vector3<f64>)>, pub awaiting_teleport: Mutex<Option<(VarInt, Vector3<f64>)>>,
pub watched_section: Vector3<i32>, pub watched_section: Mutex<Vector3<i32>>,
} }
impl Player { impl Player {
pub fn new( pub fn new(client: Client, world: Arc<World>, entity_id: EntityId, gamemode: GameMode) -> Self {
client: Client, let gameprofile = match client.gameprofile.lock().unwrap().clone() {
world: Arc<tokio::sync::Mutex<World>>,
entity_id: EntityId,
gamemode: GameMode,
) -> Self {
let gameprofile = match client.gameprofile.clone() {
Some(profile) => profile, Some(profile) => profile,
None => { None => {
log::error!("No gameprofile?. Impossible"); log::error!("No gameprofile?. Impossible");
@ -106,37 +104,36 @@ impl Player {
} }
} }
}; };
let config = client.config.clone().unwrap_or_default(); let config = client.config.lock().unwrap().clone().unwrap_or_default();
Self { Self {
entity: Entity::new(entity_id, world, EntityType::Player, 1.62), entity: Mutex::new(Entity::new(entity_id, world, EntityType::Player, 1.62)),
config, config: Mutex::new(config),
gameprofile, gameprofile,
client, client,
awaiting_teleport: None, awaiting_teleport: Mutex::new(None),
// TODO: Load this from previous instance // TODO: Load this from previous instance
health: 20.0, health: Mutex::new(20.0),
food: 20, food: AtomicI32::new(20),
food_saturation: 20.0, food_saturation: Mutex::new(20.0),
current_block_destroy_stage: 0, current_block_destroy_stage: AtomicU8::new(0),
inventory: PlayerInventory::new(), inventory: Mutex::new(PlayerInventory::new()),
open_container: None, open_container: Mutex::new(None),
carried_item: None, carried_item: Mutex::new(None),
teleport_id_count: 0, teleport_id_count: AtomicI32::new(0),
abilities: PlayerAbilities::default(), abilities: PlayerAbilities::default(),
gamemode, gamemode: Mutex::new(gamemode),
watched_section: Vector3::new(0, 0, 0), watched_section: Mutex::new(Vector3::new(0, 0, 0)),
last_position: Vector3::new(0.0, 0.0, 0.0), last_position: Mutex::new(Vector3::new(0.0, 0.0, 0.0)),
} }
} }
// TODO: Put this into entity
/// Removes the Player out of the current World /// Removes the Player out of the current World
pub async fn remove(&mut self) { pub async fn remove(&self) {
self.entity.world.lock().await.remove_player(self); self.entity.lock().unwrap().world.remove_player(self);
} }
pub fn entity_id(&self) -> EntityId { pub fn entity_id(&self) -> EntityId {
self.entity.entity_id self.entity.lock().unwrap().entity_id
} }
pub fn send_abilties_update(&mut self) { pub fn send_abilties_update(&mut self) {
@ -162,17 +159,22 @@ impl Player {
)); ));
} }
pub fn teleport(&mut self, x: f64, y: f64, z: f64, yaw: f32, pitch: f32) { pub fn teleport(&self, x: f64, y: f64, z: f64, yaw: f32, pitch: f32) {
// this is the ultra special magic code used to create the teleport id // this is the ultra special magic code used to create the teleport id
self.teleport_id_count += 1; // This returns the old value
if self.teleport_id_count == i32::MAX { let i = self
self.teleport_id_count = 0; .teleport_id_count
.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
if i + 2 == i32::MAX {
self.teleport_id_count
.store(0, std::sync::atomic::Ordering::Relaxed);
} }
let entity = &mut self.entity; let teleport_id = i + 1;
let mut entity = self.entity.lock().unwrap();
entity.set_pos(x, y, z); entity.set_pos(x, y, z);
entity.yaw = yaw; entity.yaw = yaw;
entity.pitch = pitch; entity.pitch = pitch;
self.awaiting_teleport = Some((self.teleport_id_count.into(), Vector3::new(x, y, z))); *self.awaiting_teleport.lock().unwrap() = Some((teleport_id.into(), Vector3::new(x, y, z)));
self.client.send_packet(&CSyncPlayerPosition::new( self.client.send_packet(&CSyncPlayerPosition::new(
x, x,
y, y,
@ -180,12 +182,12 @@ impl Player {
yaw, yaw,
pitch, pitch,
0, 0,
self.teleport_id_count.into(), teleport_id.into(),
)); ));
} }
pub fn block_interaction_range(&self) -> f64 { pub fn block_interaction_range(&self) -> f64 {
if self.gamemode == GameMode::Creative { if *self.gamemode.lock().unwrap() == GameMode::Creative {
5.0 5.0
} else { } else {
4.5 4.5
@ -195,17 +197,21 @@ impl Player {
pub fn can_interact_with_block_at(&self, pos: &WorldPosition, additional_range: f64) -> bool { pub fn can_interact_with_block_at(&self, pos: &WorldPosition, additional_range: f64) -> bool {
let d = self.block_interaction_range() + additional_range; let d = self.block_interaction_range() + additional_range;
let box_pos = BoundingBox::from_block(pos); let box_pos = BoundingBox::from_block(pos);
let entity = self.entity.lock().unwrap();
box_pos.squared_magnitude(Vector3 { box_pos.squared_magnitude(Vector3 {
x: self.entity.pos.x, x: entity.pos.x,
y: self.entity.pos.y + self.entity.standing_eye_height as f64, y: entity.pos.y + entity.standing_eye_height as f64,
z: self.entity.pos.z, z: entity.pos.z,
}) < d * d }) < d * d
} }
/// Kicks the Client with a reason depending on the connection state /// Kicks the Client with a reason depending on the connection state
pub fn kick(&mut self, reason: TextComponent) { pub fn kick(&self, reason: TextComponent) {
assert!(self.client.connection_state == ConnectionState::Play); assert!(*self.client.connection_state.lock().unwrap() == ConnectionState::Play);
assert!(!self.client.closed); assert!(!self
.client
.closed
.load(std::sync::atomic::Ordering::Relaxed));
self.client self.client
.try_send_packet(&CPlayDisconnect::new(&reason)) .try_send_packet(&CPlayDisconnect::new(&reason))
@ -218,53 +224,47 @@ impl Player {
self.client.close() self.client.close()
} }
pub fn update_health(&mut self, health: f32, food: i32, food_saturation: f32) { pub fn update_health(&self, health: f32, food: i32, food_saturation: f32) {
self.health = health; *self.health.lock().unwrap() = health;
self.food = food; self.food.store(food, std::sync::atomic::Ordering::Relaxed);
self.food_saturation = food_saturation; *self.food_saturation.lock().unwrap() = food_saturation;
} }
pub async fn set_gamemode(&mut self, gamemode: GameMode) { pub fn set_gamemode(&self, gamemode: GameMode) {
// We could send the same gamemode without problems. But why waste bandwidth ? // We could send the same gamemode without problems. But why waste bandwidth ?
let mut current_gamemode = self.gamemode.lock().unwrap();
assert!( assert!(
self.gamemode != gamemode, *current_gamemode != gamemode,
"Setting the same gamemode as already is" "Setting the same gamemode as already is"
); );
self.gamemode = gamemode; *current_gamemode = gamemode;
// So a little story time. I actually made an abitlties_from_gamemode function. I looked at vanilla and they always send the abilties from the gamemode. But the funny thing actually is. That the client // So a little story time. I actually made an abitlties_from_gamemode function. I looked at vanilla and they always send the abilties from the gamemode. But the funny thing actually is. That the client
// does actually use the same method and set the abilties when receiving the CGameEvent gamemode packet. Just Mojang nonsense // does actually use the same method and set the abilties when receiving the CGameEvent gamemode packet. Just Mojang nonsense
self.entity
// TODO: fix this ugly mess :c, It gives me a liftime error when saving packet as a var .lock()
self.client.send_packet(&CPlayerInfoUpdate::new( .unwrap()
0x04, .world
&[pumpkin_protocol::client::play::Player { .broadcast_packet_all(&CPlayerInfoUpdate::new(
uuid: self.gameprofile.id,
actions: vec![PlayerAction::UpdateGameMode((self.gamemode as i32).into())],
}],
));
self.entity.world.lock().await.broadcast_packet(
&[self.client.token],
&CPlayerInfoUpdate::new(
0x04, 0x04,
&[pumpkin_protocol::client::play::Player { &[pumpkin_protocol::client::play::Player {
uuid: self.gameprofile.id, uuid: self.gameprofile.id,
actions: vec![PlayerAction::UpdateGameMode((self.gamemode as i32).into())], actions: vec![PlayerAction::UpdateGameMode((gamemode as i32).into())],
}], }],
), ));
);
self.client self.client
.send_packet(&CGameEvent::new(3, gamemode.to_f32().unwrap())); .send_packet(&CGameEvent::new(3, gamemode.to_f32().unwrap()));
} }
pub fn send_system_message(&mut self, text: TextComponent) { pub fn send_system_message(&self, text: TextComponent) {
self.client self.client
.send_packet(&CSystemChatMessage::new(text, false)); .send_packet(&CSystemChatMessage::new(text, false));
} }
} }
impl Player { impl Player {
pub async fn process_packets(&mut self, server: &Arc<Server>) { pub async fn process_packets(&self, server: &Arc<Server>) {
while let Some(mut packet) = self.client.client_packets_queue.pop() { let mut packets = self.client.client_packets_queue.lock().unwrap();
while let Some(mut packet) = packets.pop() {
match self.handle_play_packet(server, &mut packet).await { match self.handle_play_packet(server, &mut packet).await {
Ok(_) => {} Ok(_) => {}
Err(e) => { Err(e) => {
@ -277,7 +277,7 @@ impl Player {
} }
pub async fn handle_play_packet( pub async fn handle_play_packet(
&mut self, &self,
server: &Arc<Server>, server: &Arc<Server>,
packet: &mut RawPacket, packet: &mut RawPacket,
) -> Result<(), DeserializerError> { ) -> Result<(), DeserializerError> {
@ -362,9 +362,10 @@ impl Player {
Ok(()) Ok(())
} }
SClickContainer::PACKET_ID => { SClickContainer::PACKET_ID => {
self.handle_click_container(server, SClickContainer::read(bytebuf)?) // TODO
.await // self.handle_click_container(server, SClickContainer::read(bytebuf)?)
.unwrap(); // .await
// .unwrap();
Ok(()) Ok(())
} }
SCloseContainer::PACKET_ID => { SCloseContainer::PACKET_ID => {

View File

@ -7,7 +7,7 @@ use mio::net::TcpListener;
use mio::{Events, Interest, Poll, Token}; use mio::{Events, Interest, Poll, Token};
use std::collections::HashMap; use std::collections::HashMap;
use std::io::{self}; use std::io::{self, Read};
use client::{interrupted, Client}; use client::{interrupted, Client};
use server::Server; use server::Server;
@ -24,7 +24,7 @@ pub mod util;
pub mod world; pub mod world;
fn main() -> io::Result<()> { fn main() -> io::Result<()> {
use std::sync::{Arc, Mutex}; use std::sync::Arc;
use entity::player::Player; use entity::player::Player;
use pumpkin_config::{ADVANCED_CONFIG, BASIC_CONFIG}; use pumpkin_config::{ADVANCED_CONFIG, BASIC_CONFIG};
@ -79,7 +79,7 @@ fn main() -> io::Result<()> {
let rcon = ADVANCED_CONFIG.rcon.clone(); let rcon = ADVANCED_CONFIG.rcon.clone();
let mut clients: HashMap<Token, Client> = HashMap::new(); let mut clients: HashMap<Token, Client> = HashMap::new();
let mut players: HashMap<Token, Arc<Mutex<Player>>> = HashMap::new(); let mut players: HashMap<Token, Arc<Player>> = HashMap::new();
let server = Arc::new(Server::new()); let server = Arc::new(Server::new());
log::info!("Started Server took {}ms", time.elapsed().as_millis()); log::info!("Started Server took {}ms", time.elapsed().as_millis());
@ -159,17 +159,19 @@ fn main() -> io::Result<()> {
token => { token => {
// Poll Players // Poll Players
if let Some(player) = players.get_mut(&token) { if let Some(player) = players.get_mut(&token) {
let mut player = player.lock().unwrap();
player.client.poll(event).await; player.client.poll(event).await;
if !player.client.closed { let closed = player
.client
.closed
.load(std::sync::atomic::Ordering::Relaxed);
if !closed {
player.process_packets(&server).await; player.process_packets(&server).await;
} }
if player.client.closed { if closed {
drop(player);
if let Some(player) = players.remove(&token) { if let Some(player) = players.remove(&token) {
let mut player = player.lock().unwrap();
player.remove().await; player.remove().await;
poll.registry().deregister(&mut player.client.connection)?; let connection = &mut player.client.connection.lock().unwrap();
poll.registry().deregister(connection.by_ref())?;
} }
} }
}; };
@ -178,23 +180,29 @@ fn main() -> io::Result<()> {
// Maybe received an event for a TCP connection. // Maybe received an event for a TCP connection.
let (done, make_player) = if let Some(client) = clients.get_mut(&token) { let (done, make_player) = if let Some(client) = clients.get_mut(&token) {
client.poll(event).await; client.poll(event).await;
if !client.closed { let closed = client.closed.load(std::sync::atomic::Ordering::Relaxed);
if !closed {
client.process_packets(&server).await; client.process_packets(&server).await;
} }
(client.closed, client.make_player) (
closed,
client
.make_player
.load(std::sync::atomic::Ordering::Relaxed),
)
} else { } else {
// Sporadic events happen, we can safely ignore them. // Sporadic events happen, we can safely ignore them.
(false, false) (false, false)
}; };
if done || make_player { if done || make_player {
if let Some(mut client) = clients.remove(&token) { if let Some(client) = clients.remove(&token) {
if done { if done {
poll.registry().deregister(&mut client.connection)?; let connection = &mut client.connection.lock().unwrap();
poll.registry().deregister(connection.by_ref())?;
} else if make_player { } else if make_player {
let token = client.token; let token = client.token;
let (player, world) = server.add_player(token, client).await; let (player, world) = server.add_player(token, client).await;
players.insert(token, player.clone()); players.insert(token, player.clone());
let mut world = world.lock().await;
world.spawn_player(&BASIC_CONFIG, player).await; world.spawn_player(&BASIC_CONFIG, player).await;
} }
} }

View File

@ -15,7 +15,7 @@ type HmacSha256 = Hmac<Sha256>;
const MAX_SUPPORTED_FORWARDING_VERSION: i32 = 4; const MAX_SUPPORTED_FORWARDING_VERSION: i32 = 4;
const PLAYER_INFO_CHANNEL: &str = "velocity:player_info"; const PLAYER_INFO_CHANNEL: &str = "velocity:player_info";
pub fn velocity_login(client: &mut Client) { pub fn velocity_login(client: &Client) {
let velocity_message_id: i32 = 0; let velocity_message_id: i32 = 0;
let mut buf = BytesMut::new(); let mut buf = BytesMut::new();
@ -36,7 +36,7 @@ pub fn check_integrity(data: (&[u8], &[u8]), secret: String) -> bool {
} }
pub fn receive_plugin_response( pub fn receive_plugin_response(
client: &mut Client, client: &Client,
config: VelocityConfig, config: VelocityConfig,
response: SLoginPluginResponse, response: SLoginPluginResponse,
) { ) {
@ -62,7 +62,7 @@ pub fn receive_plugin_response(
} }
// TODO: no unwrap // TODO: no unwrap
let addr: SocketAddr = buf.get_string().unwrap().parse().unwrap(); let addr: SocketAddr = buf.get_string().unwrap().parse().unwrap();
client.address = addr; *client.address.lock().unwrap() = addr;
todo!() todo!()
} else { } else {
client.kick("This server requires you to connect with Velocity.") client.kick("This server requires you to connect with Velocity.")

View File

@ -45,7 +45,7 @@ pub struct Server {
pub command_dispatcher: Arc<CommandDispatcher<'static>>, pub command_dispatcher: Arc<CommandDispatcher<'static>>,
pub worlds: Vec<Arc<tokio::sync::Mutex<World>>>, pub worlds: Vec<Arc<World>>,
pub status_response: StatusResponse, pub status_response: StatusResponse,
// We cache the json response here so we don't parse it every time someone makes a Status request. // We cache the json response here so we don't parse it every time someone makes a Status request.
// Keep in mind that we must parse this again, when the StatusResponse changes which usally happen when a player joins or leaves // Keep in mind that we must parse this again, when the StatusResponse changes which usally happen when a player joins or leaves
@ -109,7 +109,7 @@ impl Server {
drag_handler: DragHandler::new(), drag_handler: DragHandler::new(),
// 0 is invalid // 0 is invalid
entity_id: 2.into(), entity_id: 2.into(),
worlds: vec![Arc::new(tokio::sync::Mutex::new(world))], worlds: vec![Arc::new(world)],
public_key, public_key,
cached_server_brand, cached_server_brand,
private_key, private_key,
@ -121,11 +121,7 @@ impl Server {
} }
} }
pub async fn add_player( pub async fn add_player(&self, token: Token, client: Client) -> (Arc<Player>, Arc<World>) {
&self,
token: Token,
client: Client,
) -> (Arc<Mutex<Player>>, Arc<tokio::sync::Mutex<World>>) {
let entity_id = self.new_entity_id(); let entity_id = self.new_entity_id();
let gamemode = match BASIC_CONFIG.default_gamemode { let gamemode = match BASIC_CONFIG.default_gamemode {
GameMode::Undefined => GameMode::Survival, GameMode::Undefined => GameMode::Survival,
@ -135,13 +131,8 @@ impl Server {
// TODO: select default from config // TODO: select default from config
let world = self.worlds[0].clone(); let world = self.worlds[0].clone();
let player = Arc::new(Mutex::new(Player::new( let player = Arc::new(Player::new(client, world.clone(), entity_id, gamemode));
client, world.add_player(token, player.clone());
world.clone(),
entity_id,
gamemode,
)));
world.lock().await.add_player(token, player.clone());
(player, world) (player, world)
} }
@ -161,12 +152,12 @@ impl Server {
} }
/// Sends a Packet to all Players in all worlds /// Sends a Packet to all Players in all worlds
pub fn broadcast_packet_all<P>(&self, except: &[Token], packet: &P) pub fn broadcast_packet_all<P>(&self, packet: &P)
where where
P: ClientPacket, P: ClientPacket,
{ {
for world in &self.worlds { for world in &self.worlds {
world.blocking_lock().broadcast_packet(except, packet) world.broadcast_packet_all(packet)
} }
} }
@ -183,7 +174,7 @@ impl Server {
buf buf
} }
pub fn send_brand(&self, client: &mut Client) { pub fn send_brand(&self, client: &Client) {
// send server brand // send server brand
client.send_packet(&CPluginMessage::new( client.send_packet(&CPluginMessage::new(
"minecraft:brand", "minecraft:brand",

View File

@ -1,7 +1,6 @@
use std::{ use std::{
collections::HashMap, collections::HashMap,
ops::DerefMut, sync::{Arc, Mutex},
sync::{Arc, Mutex, MutexGuard},
}; };
pub mod player_chunker; pub mod player_chunker;
@ -22,11 +21,14 @@ use pumpkin_protocol::{
use pumpkin_world::level::Level; use pumpkin_world::level::Level;
use tokio::sync::mpsc; use tokio::sync::mpsc;
use crate::{client::Client, entity::player::Player}; use crate::{
client::Client,
entity::{player::Player, Entity},
};
pub struct World { pub struct World {
pub level: Arc<Mutex<Level>>, pub level: Arc<Mutex<Level>>,
pub current_players: HashMap<Token, Arc<Mutex<Player>>>, pub current_players: Arc<Mutex<HashMap<Token, Arc<Player>>>>,
// entities, players... // entities, players...
} }
@ -34,35 +36,36 @@ impl World {
pub fn load(level: Level) -> Self { pub fn load(level: Level) -> Self {
Self { Self {
level: Arc::new(Mutex::new(level)), level: Arc::new(Mutex::new(level)),
current_players: HashMap::new(), current_players: Arc::new(Mutex::new(HashMap::new())),
} }
} }
/// Sends a Packet to all Players, Expect some players. Because we can't lock them twice /// Sends a Packet to all Players in the World
pub fn broadcast_packet<P>(&self, except: &[Token], packet: &P) pub fn broadcast_packet_all<P>(&self, packet: &P)
where where
P: ClientPacket, P: ClientPacket,
{ {
for (_, player) in self let current_players = self.current_players.lock().unwrap();
.current_players for (_, player) in current_players.iter() {
.iter()
.filter(|c| !except.contains(c.0))
{
let mut player = player.lock().unwrap();
player.client.send_packet(packet); player.client.send_packet(packet);
} }
} }
pub async fn spawn_player( /// Sends a Packet to all Players in the World, Expect the Players given the the expect parameter
&mut self, pub fn broadcast_packet_expect<P>(&self, except: &[Token], packet: &P)
base_config: &BasicConfiguration, where
player: Arc<Mutex<Player>>, P: ClientPacket,
) { {
let mut player = player.lock().unwrap(); let current_players = self.current_players.lock().unwrap();
let player = player.deref_mut(); for (_, player) in current_players.iter().filter(|c| !except.contains(c.0)) {
player.client.send_packet(packet);
}
}
pub async fn spawn_player(&self, base_config: &BasicConfiguration, player: Arc<Player>) {
// This code follows the vanilla packet order // This code follows the vanilla packet order
let entity_id = player.entity_id(); let entity_id = player.entity_id();
let gamemode = player.gamemode; let gamemode = player.gamemode.lock().unwrap();
log::debug!("spawning player, entity id {}", entity_id); log::debug!("spawning player, entity id {}", entity_id);
// login packet for our new player // login packet for our new player
@ -104,7 +107,7 @@ impl World {
let gameprofile = &player.gameprofile; let gameprofile = &player.gameprofile;
// first send info update to our new player, So he can see his Skin // first send info update to our new player, So he can see his Skin
// also send his info to everyone else // also send his info to everyone else
player.client.send_packet(&CPlayerInfoUpdate::new( self.broadcast_packet_all(&CPlayerInfoUpdate::new(
0x01 | 0x08, 0x01 | 0x08,
&[pumpkin_protocol::client::play::Player { &[pumpkin_protocol::client::play::Player {
uuid: gameprofile.id, uuid: gameprofile.id,
@ -117,31 +120,16 @@ impl World {
], ],
}], }],
)); ));
self.broadcast_packet(
&[player.client.token],
&CPlayerInfoUpdate::new(
0x01 | 0x08,
&[pumpkin_protocol::client::play::Player {
uuid: gameprofile.id,
actions: vec![
PlayerAction::AddPlayer {
name: gameprofile.name.clone(),
properties: gameprofile.properties.clone(),
},
PlayerAction::UpdateListed(true),
],
}],
),
);
// here we send all the infos of already joined players // here we send all the infos of already joined players
let mut entries = Vec::new(); let mut entries = Vec::new();
for (_, playerr) in self for (_, playerr) in self
.current_players .current_players
.lock()
.unwrap()
.iter() .iter()
.filter(|(c, _)| **c != player.client.token) .filter(|(c, _)| **c != player.client.token)
{ {
let playerr = playerr.as_ref().lock().unwrap();
let gameprofile = &playerr.gameprofile; let gameprofile = &playerr.gameprofile;
entries.push(pumpkin_protocol::client::play::Player { entries.push(pumpkin_protocol::client::play::Player {
uuid: gameprofile.id, uuid: gameprofile.id,
@ -161,7 +149,7 @@ impl World {
let gameprofile = &player.gameprofile; let gameprofile = &player.gameprofile;
// spawn player for every client // spawn player for every client
self.broadcast_packet( self.broadcast_packet_expect(
&[player.client.token], &[player.client.token],
// TODO: add velo // TODO: add velo
&CSpawnEntity::new( &CSpawnEntity::new(
@ -182,9 +170,14 @@ impl World {
); );
// spawn players for our client // spawn players for our client
let token = player.client.token; let token = player.client.token;
for (_, existing_player) in self.current_players.iter().filter(|c| c.0 != &token) { for (_, existing_player) in self
let existing_player = existing_player.as_ref().lock().unwrap(); .current_players
let entity = &existing_player.entity; .lock()
.unwrap()
.iter()
.filter(|c| c.0 != &token)
{
let entity = existing_player.entity.lock().unwrap();
let gameprofile = &existing_player.gameprofile; let gameprofile = &existing_player.gameprofile;
player.client.send_packet(&CSpawnEntity::new( player.client.send_packet(&CSpawnEntity::new(
existing_player.entity_id().into(), existing_player.entity_id().into(),
@ -204,33 +197,27 @@ impl World {
} }
// entity meta data // entity meta data
// set skin parts // set skin parts
if let Some(config) = player.client.config.as_ref() { if let Some(config) = player.client.config.lock().unwrap().as_ref() {
let packet = CSetEntityMetadata::new( let packet = CSetEntityMetadata::new(
entity_id.into(), entity_id.into(),
Metadata::new(17, VarInt(0), config.skin_parts), Metadata::new(17, VarInt(0), config.skin_parts),
); );
player.client.send_packet(&packet); self.broadcast_packet_all(&packet)
self.broadcast_packet(&[player.client.token], &packet)
} }
// Start waiting for level chunks // Start waiting for level chunks
player.client.send_packet(&CGameEvent::new(13, 0.0)); player.client.send_packet(&CGameEvent::new(13, 0.0));
// Spawn in inital chunks // Spawn in inital chunks
player_chunker::player_join(self, player).await; player_chunker::player_join(self, player.clone()).await;
} }
async fn spawn_world_chunks( async fn spawn_world_chunks(&self, client: &Client, chunks: Vec<Vector2<i32>>, distance: i32) {
&self,
client: &mut Client,
chunks: Vec<Vector2<i32>>,
distance: i32,
) {
let inst = std::time::Instant::now(); let inst = std::time::Instant::now();
let (sender, mut chunk_receiver) = mpsc::channel(distance as usize); let (sender, mut chunk_receiver) = mpsc::channel(distance as usize);
let level = self.level.clone(); let level = self.level.clone();
let closed = client.closed; let closed = client.closed.load(std::sync::atomic::Ordering::Relaxed);
let chunks = Arc::new(chunks); let chunks = Arc::new(chunks);
tokio::task::spawn_blocking(move || { tokio::task::spawn_blocking(move || {
level.lock().unwrap().fetch_chunks(&chunks, sender, closed) level.lock().unwrap().fetch_chunks(&chunks, sender, closed)
@ -255,42 +242,47 @@ impl World {
len / (1024 * 1024) len / (1024 * 1024)
); );
} }
if !client.closed { if !client.closed.load(std::sync::atomic::Ordering::Relaxed) {
client.send_packet(&CChunkData(&chunk_data)); client.send_packet(&CChunkData(&chunk_data));
} }
} }
dbg!("DONE CHUNKS", inst.elapsed()); dbg!("DONE CHUNKS", inst.elapsed());
} }
/// TODO: This definitly should be in world pub fn get_by_entityid(&self, from: &Player, id: EntityId) -> Option<Arc<Player>> {
pub fn get_by_entityid(&self, from: &Player, id: EntityId) -> Option<MutexGuard<Player>> {
for (_, player) in self for (_, player) in self
.current_players .current_players
.lock()
.unwrap()
.iter() .iter()
.filter(|c| c.0 != &from.client.token) .filter(|c| c.0 != &from.client.token)
{ {
let player = player.lock().unwrap();
if player.entity_id() == id { if player.entity_id() == id {
return Some(player); return Some(player.clone());
} }
} }
None None
} }
pub fn add_player(&mut self, token: Token, player: Arc<Mutex<Player>>) { pub fn add_player(&self, token: Token, player: Arc<Player>) {
self.current_players.insert(token, player); self.current_players.lock().unwrap().insert(token, player);
} }
pub fn remove_player(&mut self, player: &Player) { pub fn remove_player(&self, player: &Player) {
self.current_players.remove(&player.client.token).unwrap(); self.current_players
// despawn the player .lock()
// todo: put this into the entitiy struct .unwrap()
let id = player.entity_id(); .remove(&player.client.token)
.unwrap();
let uuid = player.gameprofile.id; let uuid = player.gameprofile.id;
self.broadcast_packet( self.broadcast_packet_expect(
&[player.client.token], &[player.client.token],
&CRemovePlayerInfo::new(1.into(), &[UUID(uuid)]), &CRemovePlayerInfo::new(1.into(), &[UUID(uuid)]),
); );
self.broadcast_packet(&[player.client.token], &CRemoveEntities::new(&[id.into()])) self.remove_entity(&player.entity.lock().unwrap());
}
pub fn remove_entity(&self, entity: &Entity) {
self.broadcast_packet_all(&CRemoveEntities::new(&[entity.entity_id.into()]))
} }
} }

View File

@ -1,3 +1,5 @@
use std::sync::Arc;
use pumpkin_config::BASIC_CONFIG; use pumpkin_config::BASIC_CONFIG;
use pumpkin_core::math::{ use pumpkin_core::math::{
get_section_cord, position::WorldPosition, vector2::Vector2, vector3::Vector3, get_section_cord, position::WorldPosition, vector2::Vector2, vector3::Vector3,
@ -12,22 +14,26 @@ use super::World;
fn get_view_distance(player: &Player) -> i8 { fn get_view_distance(player: &Player) -> i8 {
player player
.config .config
.lock()
.unwrap()
.view_distance .view_distance
.clamp(2, BASIC_CONFIG.view_distance as i8) .clamp(2, BASIC_CONFIG.view_distance as i8)
} }
pub async fn player_join(world: &World, player: &mut Player) { pub async fn player_join(world: &World, player: Arc<Player>) {
let new_watched = chunk_section_from_pos(&player.entity.block_pos); let entity = player.entity.lock().unwrap();
player.watched_section = new_watched; let new_watched = chunk_section_from_pos(&entity.block_pos);
let chunk_pos = player.entity.chunk_pos; let mut watched_section = player.watched_section.lock().unwrap();
*watched_section = new_watched;
let chunk_pos = entity.chunk_pos;
player.client.send_packet(&CCenterChunk { player.client.send_packet(&CCenterChunk {
chunk_x: chunk_pos.x.into(), chunk_x: chunk_pos.x.into(),
chunk_z: chunk_pos.z.into(), chunk_z: chunk_pos.z.into(),
}); });
let view_distance = get_view_distance(player) as i32; let view_distance = get_view_distance(&player) as i32;
dbg!(view_distance); dbg!(view_distance);
let old_cylindrical = Cylindrical::new( let old_cylindrical = Cylindrical::new(
Vector2::new(player.watched_section.x, player.watched_section.z), Vector2::new(watched_section.x, watched_section.z),
view_distance, view_distance,
); );
let new_cylindrical = Cylindrical::new(Vector2::new(chunk_pos.x, chunk_pos.z), view_distance); let new_cylindrical = Cylindrical::new(Vector2::new(chunk_pos.x, chunk_pos.z), view_distance);
@ -47,16 +53,17 @@ pub async fn player_join(world: &World, player: &mut Player) {
); );
if !loading_chunks.is_empty() { if !loading_chunks.is_empty() {
world world
.spawn_world_chunks(&mut player.client, loading_chunks, view_distance) .spawn_world_chunks(&player.client, loading_chunks, view_distance)
.await; .await;
} }
} }
pub async fn update_position(world: &World, player: &mut Player) { pub async fn update_position(world: &World, player: &Player) {
let current_watched = player.watched_section; let mut current_watched = player.watched_section.lock().unwrap();
let new_watched = chunk_section_from_pos(&player.entity.block_pos); let entity = player.entity.lock().unwrap();
if current_watched != new_watched { let new_watched = chunk_section_from_pos(&entity.block_pos);
let chunk_pos = player.entity.chunk_pos; if *current_watched != new_watched {
let chunk_pos = entity.chunk_pos;
player.client.send_packet(&CCenterChunk { player.client.send_packet(&CCenterChunk {
chunk_x: chunk_pos.x.into(), chunk_x: chunk_pos.x.into(),
chunk_z: chunk_pos.z.into(), chunk_z: chunk_pos.z.into(),
@ -64,12 +71,12 @@ pub async fn update_position(world: &World, player: &mut Player) {
let view_distance = get_view_distance(player) as i32; let view_distance = get_view_distance(player) as i32;
let old_cylindrical = Cylindrical::new( let old_cylindrical = Cylindrical::new(
Vector2::new(player.watched_section.x, player.watched_section.z), Vector2::new(current_watched.x, current_watched.z),
view_distance, view_distance,
); );
let new_cylindrical = let new_cylindrical =
Cylindrical::new(Vector2::new(chunk_pos.x, chunk_pos.z), view_distance); Cylindrical::new(Vector2::new(chunk_pos.x, chunk_pos.z), view_distance);
player.watched_section = new_watched; *current_watched = new_watched;
let mut loading_chunks = Vec::new(); let mut loading_chunks = Vec::new();
Cylindrical::for_each_changed_chunk( Cylindrical::for_each_changed_chunk(
old_cylindrical, old_cylindrical,
@ -86,7 +93,7 @@ pub async fn update_position(world: &World, player: &mut Player) {
); );
if !loading_chunks.is_empty() { if !loading_chunks.is_empty() {
world world
.spawn_world_chunks(&mut player.client, loading_chunks, view_distance) .spawn_world_chunks(&player.client, loading_chunks, view_distance)
.await; .await;
} }
} }