diff --git a/Cargo.lock b/Cargo.lock index 966efd56b..fd53bd141 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1901,6 +1901,7 @@ dependencies = [ "digest 0.11.0-pre.9", "hmac", "image", + "itertools 0.13.0", "log", "mio", "num-bigint", @@ -2806,9 +2807,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.39.2" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "bytes", diff --git a/pumpkin-inventory/src/container_click.rs b/pumpkin-inventory/src/container_click.rs index c84315195..14a26c905 100644 --- a/pumpkin-inventory/src/container_click.rs +++ b/pumpkin-inventory/src/container_click.rs @@ -1,4 +1,3 @@ -use crate::WindowType; use pumpkin_world::item::ItemStack; pub struct ClickMode { @@ -8,8 +7,6 @@ pub struct ClickMode { pub struct Click { pub mode: ClickMode, - pub state_id: u32, - pub window_type: WindowType, pub changed_items: Vec, pub carried_item: Option, } @@ -25,7 +22,7 @@ impl ClickMode { click_type: ClickType::CreativePickItem, slot: Slot::Normal(slot.try_into().unwrap()), }, - 4 => Self::new_drop_item(button, slot), + 4 => Self::new_drop_item(button), 5 => Self::new_drag_item(button, slot), 6 => Self { click_type: ClickType::DoubleClick, @@ -78,7 +75,7 @@ impl ClickMode { } } - fn new_drop_item(button: i8, slot: i16) -> Self { + fn new_drop_item(button: i8) -> Self { let drop_type = match button { 0 => DropType::SingleItem, 1 => DropType::FullStack, @@ -87,7 +84,7 @@ impl ClickMode { }; Self { click_type: ClickType::DropType(drop_type), - slot: Slot::Normal(slot.try_into().unwrap()), + slot: Slot::OutsideInventory, } } @@ -108,7 +105,6 @@ impl ClickMode { MouseDragState::End, Slot::OutsideInventory, ), - 4 => ( MouseDragType::Right, MouseDragState::Start, diff --git a/pumpkin-inventory/src/lib.rs b/pumpkin-inventory/src/lib.rs index 144893f7b..654d2352e 100644 --- a/pumpkin-inventory/src/lib.rs +++ b/pumpkin-inventory/src/lib.rs @@ -76,7 +76,28 @@ pub trait Container: Sync + Send { fn all_slots_ref(&self) -> Vec>; - fn state_id(&mut self) -> i32; + fn all_combinable_slots(&self) -> Vec> { + self.all_slots_ref() + } + + fn all_combinable_slots_mut(&mut self) -> Vec<&mut Option> { + self.all_slots() + } + + fn advance_state_id(&mut self) -> i32; + + fn reset_state_id(&mut self); + fn state_id(&self) -> i32; + + fn print_all_contents(&self) { + self.all_slots_ref() + .into_iter() + .enumerate() + .filter_map(|(slot, item)| item.map(|item| (slot, item))) + .for_each(|(slot, item)| { + dbg!(slot, item); + }); + } } pub fn handle_item_take( @@ -106,12 +127,6 @@ pub fn handle_item_change( current_slot: &mut Option, mouse_click: MouseClick, ) { - if let Some(carried) = carried_slot.as_ref() { - dbg!(carried); - } - if let Some(current) = current_slot.as_ref() { - dbg!(current); - } match (current_slot.as_mut(), carried_slot.as_mut()) { // Swap or combine current and carried (Some(current), Some(carried)) => { @@ -170,25 +185,23 @@ pub fn combine_stacks( } } -pub struct OptionallyCombinedContainer<'a> { +pub struct OptionallyCombinedContainer<'a, 'b> { container: Option<&'a mut Box>, - inventory: &'a mut PlayerInventory, - state_id: i32, + inventory: &'b mut PlayerInventory, } -impl<'a> OptionallyCombinedContainer<'a> { +impl<'a, 'b> OptionallyCombinedContainer<'a, 'b> { pub fn new( - player_inventory: &'a mut PlayerInventory, + player_inventory: &'b mut PlayerInventory, container: Option<&'a mut Box>, ) -> Self { Self { inventory: player_inventory, container, - state_id: 0, } } } -impl<'a> Container for OptionallyCombinedContainer<'a> { +impl<'a> Container for OptionallyCombinedContainer<'a, 'a> { fn window_type(&self) -> &'static WindowType { if let Some(container) = &self.container { container.window_type() @@ -198,27 +211,38 @@ impl<'a> Container for OptionallyCombinedContainer<'a> { } fn all_slots(&mut self) -> Vec<&mut Option> { - let mut slots = if let Some(container) = &mut self.container { - container.all_slots() - } else { - vec![] + let slots = match &mut self.container { + Some(container) => { + let mut slots = container.all_slots(); + slots.extend(self.inventory.all_combinable_slots_mut()); + slots + } + None => self.inventory.all_slots(), }; - slots.extend(self.inventory.all_slots()); + dbg!(slots.len()); slots } fn all_slots_ref(&self) -> Vec> { - let mut slots = if let Some(container) = &self.container { - container.all_slots_ref() - } else { - vec![] - }; - slots.extend(self.inventory.all_slots_ref()); - slots + match &self.container { + Some(container) => { + let mut slots = container.all_slots_ref(); + slots.extend(self.inventory.all_combinable_slots()); + slots + } + None => self.inventory.all_slots_ref(), + } } - fn state_id(&mut self) -> i32 { - self.state_id += 1; - self.state_id - 1 + fn advance_state_id(&mut self) -> i32 { + self.inventory.advance_state_id() + } + + fn reset_state_id(&mut self) { + self.inventory.reset_state_id() + } + + fn state_id(&self) -> i32 { + self.inventory.state_id() } } diff --git a/pumpkin-inventory/src/open_container.rs b/pumpkin-inventory/src/open_container.rs index f5a361b2b..601262384 100644 --- a/pumpkin-inventory/src/open_container.rs +++ b/pumpkin-inventory/src/open_container.rs @@ -10,6 +10,7 @@ pub struct OpenContainer { impl OpenContainer { pub fn try_open(&self, player_id: i32) -> Option>> { if !self.players.contains(&player_id) { + dbg!("couldn't open container"); return None; } let container = self.container.lock().unwrap(); @@ -31,6 +32,18 @@ impl OpenContainer { } } + pub fn remove_player(&mut self, player_id: i32) { + if let Some(index) = self.players.iter().enumerate().find_map(|(index, id)| { + if *id == player_id { + Some(index) + } else { + None + } + }) { + self.players.remove(index); + } + } + pub fn empty(player_id: i32) -> Self { Self { players: vec![player_id], @@ -58,6 +71,7 @@ impl Container for Chest { } fn all_slots(&mut self) -> Vec<&mut Option> { + dbg!(self.slots.iter().len()); self.slots.iter_mut().collect() } @@ -65,8 +79,16 @@ impl Container for Chest { self.slots.iter().map(|slot| slot.as_ref()).collect() } - fn state_id(&mut self) -> i32 { + fn advance_state_id(&mut self) -> i32 { self.state_id += 1; self.state_id - 1 } + + fn reset_state_id(&mut self) { + self.state_id = 0; + } + + fn state_id(&self) -> i32 { + self.state_id + } } diff --git a/pumpkin-inventory/src/player.rs b/pumpkin-inventory/src/player.rs index b84a4acc7..355fea173 100644 --- a/pumpkin-inventory/src/player.rs +++ b/pumpkin-inventory/src/player.rs @@ -14,6 +14,7 @@ pub struct PlayerInventory { // current selected slot in hotbar selected: usize, state_id: i32, + pub total_opened_containers: u8, } impl Default for PlayerInventory { @@ -33,6 +34,7 @@ impl PlayerInventory { // TODO: What when player spawns in with an different index ? selected: 0, state_id: 0, + total_opened_containers: 2, } } @@ -155,8 +157,23 @@ impl Container for PlayerInventory { self.slots() } - fn state_id(&mut self) -> i32 { + fn all_combinable_slots(&self) -> Vec> { + self.items.iter().map(|item| item.as_ref()).collect() + } + + fn all_combinable_slots_mut(&mut self) -> Vec<&mut Option> { + self.items.iter_mut().collect() + } + + fn advance_state_id(&mut self) -> i32 { self.state_id += 1; - self.state_id - 1 + self.state_id + } + + fn reset_state_id(&mut self) { + self.state_id = 0; + } + fn state_id(&self) -> i32 { + self.state_id } } diff --git a/pumpkin/Cargo.toml b/pumpkin/Cargo.toml index 3cdd834e3..bd0264416 100644 --- a/pumpkin/Cargo.toml +++ b/pumpkin/Cargo.toml @@ -64,3 +64,4 @@ crossbeam-channel = "0.5.13" uuid.workspace = true tokio.workspace = true rayon.workspace = true +itertools = "0.13.0" diff --git a/pumpkin/src/client/container.rs b/pumpkin/src/client/container.rs index 46320a61f..dee0ae9ca 100644 --- a/pumpkin/src/client/container.rs +++ b/pumpkin/src/client/container.rs @@ -1,8 +1,8 @@ -use num_traits::FromPrimitive; +use itertools::Itertools; use pumpkin_core::text::TextComponent; use pumpkin_inventory::container_click::{KeyClick, MouseClick}; use pumpkin_inventory::window_property::{WindowProperty, WindowPropertyTrait}; -use pumpkin_inventory::{container_click, handle_item_change, OptionallyCombinedContainer}; +use pumpkin_inventory::{container_click, OptionallyCombinedContainer}; use pumpkin_inventory::{Container, WindowType}; use pumpkin_protocol::client::play::{ CCloseContainer, COpenScreen, CSetContainerContent, CSetContainerProperty, CSetContainerSlot, @@ -10,6 +10,7 @@ use pumpkin_protocol::client::play::{ use pumpkin_protocol::server::play::SClickContainer; use pumpkin_protocol::slot::Slot; use pumpkin_world::item::ItemStack; +use std::sync::MutexGuard; use crate::entity::player::Player; use crate::server::Server; @@ -17,12 +18,12 @@ use crate::server::Server; impl Player { pub fn open_container( &mut self, - container: &Box, + server: &mut Server, minecraft_menu_id: &str, window_title: Option<&str>, - carried_item: Option<&ItemStack>, - state_id: i32, ) { + let mut container = self.get_open_container(server); + let container = container.as_deref_mut(); let menu_protocol_id = (*pumpkin_world::global_registry::REGISTRY .get("minecraft:menu") .unwrap() @@ -32,56 +33,48 @@ impl Player { .get("protocol_id") .unwrap()) .into(); - let window_type = container.window_type(); + let window_type = match &container { + Some(container) => container.window_type(), + None => &WindowType::Generic9x1, + } + .to_owned(); let title = TextComponent::text(window_title.unwrap_or(window_type.default_title())); + + self.inventory.reset_state_id(); + self.client.send_packet(&COpenScreen::new( - (*window_type as u8 + 1).into(), + self.inventory.total_opened_containers.into(), menu_protocol_id, title, )); - - self.set_container_content(Some(container), carried_item, state_id); + self.set_container_content(container); } - pub fn set_container_content<'a>( - &mut self, - container: Option<&Box>, - carried_item: Option<&'a ItemStack>, - state_id: i32, - ) { - let slots: Vec = { - let items = container.map(|container| container.all_slots_ref()); - if let Some(mut items) = items { - items.extend(self.inventory.all_slots_ref()); - items - } else { - self.inventory.all_slots_ref() - } + pub fn set_container_content(&mut self, container: Option<&mut Box>) { + let total_opened_containers = self.inventory.total_opened_containers; + let container = OptionallyCombinedContainer::new(&mut self.inventory, container); + + let slots = container + .all_slots_ref() .into_iter() - .map(|item| { - if let Some(item) = item { - Slot::from(item) - } else { - Slot::empty() - } - }) - .collect() - }; + .map(Slot::from) + .collect_vec(); let carried_item = { - if let Some(item) = carried_item { + if let Some(item) = self.carried_item.as_ref() { item.into() } else { Slot::empty() } }; - let window_type = match container { - Some(container) => *container.window_type() as u8, - None => 0, - }; - - let packet = CSetContainerContent::new(window_type, state_id.into(), &slots, &carried_item); + let packet = CSetContainerContent::new( + total_opened_containers, + self.inventory.state_id().into(), + &slots, + &carried_item, + ); + self.inventory.advance_state_id(); self.client.send_packet(&packet); } @@ -101,32 +94,54 @@ impl Player { } /// 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, window_type: WindowType) { - self.client - .send_packet(&CCloseContainer::new(window_type as u8)) + pub fn close_container(&mut self) { + self.inventory.total_opened_containers += 1; + self.client.send_packet(&CCloseContainer::new( + self.inventory.total_opened_containers, + )) } pub fn set_container_property( &mut self, - window_type: WindowType, window_property: WindowProperty, ) { let (id, value) = window_property.into_tuple(); - self.client - .send_packet(&CSetContainerProperty::new(window_type as u8, id, value)); + self.client.send_packet(&CSetContainerProperty::new( + self.inventory.total_opened_containers, + id, + value, + )); } pub fn handle_click_container(&mut self, server: &mut Server, packet: SClickContainer) { use container_click::*; - let mut opened_container = if let Some(id) = self.open_container { - server.try_get_container(self.entity_id(), id) - } else { - None - }; + let mut opened_container = self.get_open_container(server); let opened_container = opened_container.as_deref_mut(); + let current_state_id = if let Some(container) = opened_container.as_ref() { + container.state_id() + } else { + self.inventory.state_id() + }; + if current_state_id != packet.state_id.0 { + dbg!(current_state_id, packet.state_id.0); + //self.set_container_content(opened_container.as_deref_mut()); + //return; + } + + if opened_container.is_some() { + if packet.window_id != self.inventory.total_opened_containers { + dbg!( + self.inventory.total_opened_containers, + opened_container.unwrap().window_type() + ); + return; + } + } else if packet.window_id != 0 { + dbg!("weird"); + return; + } let click = Click { - state_id: packet.state_id.0.try_into().unwrap(), changed_items: packet .array_of_changed_slots .into_iter() @@ -139,12 +154,6 @@ impl Player { } }) .collect::>(), - window_type: WindowType::from_u8(if packet.window_id == 0 { - 0 - } else { - packet.window_id - 1 - }) - .unwrap(), carried_item: packet.carried_item.to_item(), mode: ClickMode::new( packet @@ -157,18 +166,13 @@ impl Player { ), }; match click.mode.click_type { - ClickType::MouseClick(mouse_click) => self.mouse_click( - opened_container, - mouse_click, - click.window_type, - click.mode.slot, - ), - ClickType::ShiftClick => { - self.shift_mouse_click(opened_container, click.window_type, click.mode.slot) + ClickType::MouseClick(mouse_click) => { + self.mouse_click(opened_container, mouse_click, click.mode.slot) } + ClickType::ShiftClick => self.shift_mouse_click(opened_container, click.mode.slot), ClickType::KeyClick(key_click) => match click.mode.slot { container_click::Slot::Normal(slot) => { - self.number_button_pressed(opened_container, click.window_type, key_click, slot) + self.number_button_pressed(opened_container, key_click, slot) } container_click::Slot::OutsideInventory => { unimplemented!("This is not a valid state") @@ -189,20 +193,16 @@ impl Player { drag_type: _, } => (), ClickType::DropType(_drop_type) => (), - } + }; } fn mouse_click( &mut self, opened_container: Option<&mut Box>, mouse_click: MouseClick, - window_type: WindowType, slot: container_click::Slot, ) { let mut container = OptionallyCombinedContainer::new(&mut self.inventory, opened_container); - if container.window_type() != &window_type { - return; - } match slot { container_click::Slot::Normal(slot) => { @@ -215,41 +215,42 @@ impl Player { fn shift_mouse_click( &mut self, opened_container: Option<&mut Box>, - window_type: WindowType, slot: container_click::Slot, ) { - let container = OptionallyCombinedContainer::new(&mut self.inventory, opened_container); - if container.window_type() != &window_type { - return; - } + let mut container = OptionallyCombinedContainer::new(&mut self.inventory, opened_container); match slot { container_click::Slot::Normal(slot) => { - if let Some(item_in_pressed_slot) = self.inventory.slots()[slot] { - let slots = self.inventory.slots().into_iter().enumerate(); + let all_slots = container.all_slots(); + if let Some(item_in_pressed_slot) = all_slots[slot].to_owned() { + let slots = all_slots.into_iter().enumerate(); // Hotbar - let find_condition = |(_, slot): &(usize, Option<&ItemStack>)| { - slot.is_none_or(|item| item.item_id == item_in_pressed_slot.item_id) + let find_condition = |(slot_number, slot): (usize, &mut Option)| { + // TODO: Check for max item count here + match slot { + Some(item) => { + if item.item_id == item_in_pressed_slot.item_id + && item.item_count != 64 + { + Some(slot_number) + } else { + None + } + } + None => Some(slot_number), + } }; let slots = if slot > 35 { - slots - .skip(9) - .find(find_condition) - .map(|(slot_num, _)| slot_num) + slots.skip(9).find_map(find_condition) } else { - slots - .skip(36) - .rev() - .find(find_condition) - .map(|(slot_num, _)| slot_num) + slots.skip(36).rev().find_map(find_condition) }; if let Some(slot) = slots { - let mut item_slot = self.inventory.slots()[slot].map(|i| i.to_owned()); + let mut item_slot = container.all_slots()[slot].map(|i| i.to_owned()); - self.inventory - .handle_item_change(&mut item_slot, slot, MouseClick::Left); - *self.inventory.slots_mut()[slot] = item_slot; + container.handle_item_change(&mut item_slot, slot, MouseClick::Left); + *container.all_slots()[slot] = item_slot; } } } @@ -260,7 +261,6 @@ impl Player { fn number_button_pressed( &mut self, opened_container: Option<&mut Box>, - window_type: WindowType, key_click: KeyClick, slot: usize, ) { @@ -270,15 +270,9 @@ impl Player { }; 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); - if container.window_type() != &window_type { - return; - } - let item_slot = &mut container.all_slots()[slot]; - if item_slot.is_some() { - handle_item_change(&mut changing_item_slot, item_slot, MouseClick::Left); - *self.inventory.get_slot(changing_slot as usize) = changing_item_slot - } + container.handle_item_change(&mut changing_item_slot, slot, MouseClick::Left); + *self.inventory.get_slot(changing_slot as usize) = changing_item_slot } fn creative_pick_item( @@ -293,4 +287,15 @@ impl Player { } fn double_click(&mut self, _slot: usize) {} + + pub fn get_open_container<'a>( + &self, + server: &'a Server, + ) -> Option>> { + if let Some(id) = self.open_container { + server.try_get_container(self.entity_id(), id) + } else { + None + } + } } diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index 45fb667a5..76df0811d 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -537,8 +537,14 @@ impl Player { // TODO: // 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 - pub fn handle_close_container(&mut self, _server: &mut Server, packet: SCloseContainer) { + pub fn handle_close_container(&mut self, server: &mut Server, packet: SCloseContainer) { // window_id 0 represents both 9x1 Generic AND inventory here + if let Some(id) = self.open_container { + if let Some(container) = server.open_containers.get_mut(&id) { + container.remove_player(self.entity_id()) + } + self.open_container = None; + } let Some(_window_type) = WindowType::from_u8(packet.window_id) else { self.kick(TextComponent::text("Invalid window ID")); return; diff --git a/pumpkin/src/commands/cmd_echest.rs b/pumpkin/src/commands/cmd_echest.rs index 8a06233f0..594015cb6 100644 --- a/pumpkin/src/commands/cmd_echest.rs +++ b/pumpkin/src/commands/cmd_echest.rs @@ -10,34 +10,18 @@ const DESCRIPTION: &str = pub(crate) fn init_command_tree<'a>() -> CommandTree<'a> { CommandTree::new(NAMES, DESCRIPTION).execute(&|sender, server, _| { if let Some(player) = sender.as_mut_player() { - let entity_id = player.entity_id().clone(); + let entity_id = player.entity_id(); player.open_container = Some(0); - let mut container = match server.open_containers.get_mut(&0) { + match server.open_containers.get_mut(&0) { Some(ender_chest) => { - if ender_chest.try_open(entity_id).is_none() { - ender_chest.add_player(entity_id); - } - ender_chest.try_open(entity_id).unwrap() + ender_chest.add_player(entity_id); } None => { let open_container = OpenContainer::empty(entity_id); server.open_containers.insert(0, open_container); - server - .open_containers - .get_mut(&0) - .unwrap() - .try_open(entity_id) - .unwrap() } - }; - let state_id = container.state_id(); - player.open_container( - &container, - "minecraft:generic_9x3", - Some("Ender Chest"), - None, - state_id, - ); + } + player.open_container(server, "minecraft:generic_9x3", Some("Ender Chest")); } Ok(()) diff --git a/pumpkin/src/entity/player.rs b/pumpkin/src/entity/player.rs index dec87a738..d2e1afe4d 100644 --- a/pumpkin/src/entity/player.rs +++ b/pumpkin/src/entity/player.rs @@ -1,8 +1,6 @@ use std::sync::Arc; - -use crate::{client::Client, server::Server}; -use num_derive::{FromPrimitive, ToPrimitive}; +use num_derive::FromPrimitive; use num_traits::ToPrimitive; use pumpkin_core::{ math::{boundingbox::BoundingBox, position::WorldPosition, vector3::Vector3}, @@ -26,16 +24,13 @@ use pumpkin_protocol::{ ConnectionState, RawPacket, ServerPacket, VarInt, }; +use pumpkin_protocol::server::play::SCloseContainer; use pumpkin_world::item::ItemStack; -use pumpkin_world::vector3::Vector3; -use serde::{Deserialize, Serialize}; - use crate::{ client::{authentication::GameProfile, Client, PlayerConfig}, server::Server, world::World, - util::boundingbox::BoundingBox }; pub struct PlayerAbilities { @@ -460,6 +455,10 @@ impl Player { self.handle_click_container(server, SClickContainer::read(bytebuf)?); Ok(()) } + SCloseContainer::PACKET_ID => { + self.handle_close_container(server, SCloseContainer::read(bytebuf)?); + Ok(()) + } _ => { log::error!("Failed to handle player packet id {:#04x}", packet.id.0); Ok(()) diff --git a/pumpkin/src/server.rs b/pumpkin/src/server.rs index 155acf4de..f83f3f421 100644 --- a/pumpkin/src/server.rs +++ b/pumpkin/src/server.rs @@ -1,13 +1,3 @@ -use std::{ - io::Cursor, - path::Path, - sync::{ - atomic::{AtomicI32, Ordering}, - Arc, Mutex, - }, - time::Duration, -}; - use base64::{engine::general_purpose, Engine}; use image::GenericImageView; use mio::Token; @@ -20,19 +10,21 @@ use pumpkin_protocol::{ CURRENT_MC_PROTOCOL, }; use pumpkin_world::dimension::Dimension; - -use crate::{ - client::Client, - config::{AdvancedConfiguration, BasicConfiguration}, - entity::player::{GameMode, Player}, - world::World, +use std::collections::HashMap; +use std::{ + io::Cursor, + path::Path, + sync::{ + atomic::{AtomicI32, Ordering}, + Arc, Mutex, MutexGuard, + }, + time::Duration, }; + +use crate::{client::Client, entity::player::Player, world::World}; use pumpkin_inventory::{Container, OpenContainer}; use pumpkin_registry::Registry; use rsa::{traits::PublicKeyParts, RsaPrivateKey, RsaPublicKey}; -use serde::{Deserialize, Serialize}; -use tokio::sync::mpsc; - pub const CURRENT_MC_VERSION: &str = "1.21.1"; @@ -55,7 +47,6 @@ pub struct Server { /// Cache the registry so we don't have to parse it every time a player joins pub cached_registry: Vec, - pub current_players: HashMap, Arc>>, pub open_containers: HashMap, entity_id: AtomicI32, @@ -102,6 +93,7 @@ impl Server { Self { plugin_loader, cached_registry: Registry::get_static(), + open_containers: HashMap::new(), // 0 is invalid entity_id: 2.into(), worlds: vec![Arc::new(tokio::sync::Mutex::new(world))], @@ -111,8 +103,6 @@ impl Server { status_response, status_response_json, public_key_der, - open_containers: HashMap::new(), - base_config: config.0, auth_client, } } @@ -134,188 +124,20 @@ impl Server { client, world.clone(), entity_id, - self.base_config.hardcore, - &["minecraft:overworld"], - self.base_config.max_players.into(), - self.base_config.view_distance.into(), // TODO: view distance - self.base_config.simulation_distance.into(), // TODO: sim view dinstance - false, - false, - false, - 0.into(), - "minecraft:overworld", - 0, // seed - gamemode.to_u8().unwrap(), - self.base_config.default_gamemode.to_i8().unwrap(), - false, - false, - None, - 0.into(), - false, - )); - dbg!("sending abilities"); - // player abilities - player - .client - .send_packet(&CPlayerAbilities::new(0x02, 0.1, 0.1)); - - // teleport - let x = 10.0; - let y = 120.0; - let z = 10.0; - let yaw = 10.0; - let pitch = 10.0; - player.teleport(x, y, z, 10.0, 10.0); - let gameprofile = &player.gameprofile; - // first send info update to our new player, So he can see his Skin - // also send his info to everyone else - self.broadcast_packet( - player, - &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 - let mut entries = Vec::new(); - for (_, playerr) in self - .current_players - .iter() - .filter(|c| c.0 != &player.client.token) - { - let playerr = playerr.as_ref().lock().unwrap(); - let gameprofile = &playerr.gameprofile; - entries.push(pumpkin_protocol::client::play::Player { - uuid: gameprofile.id, - actions: vec![ - PlayerAction::AddPlayer { - name: gameprofile.name.clone(), - properties: gameprofile.properties.clone(), - }, - PlayerAction::UpdateListed(true), - ], - }) - } - player - .client - .send_packet(&CPlayerInfoUpdate::new(0x01 | 0x08, &entries)); - - // Start waiting for level chunks - player.client.send_packet(&CGameEvent::new(13, 0.0)); - - let gameprofile = &player.gameprofile; - - // spawn player for every client - self.broadcast_packet_except( - &[&player.client.token], - // TODO: add velo - &CSpawnEntity::new( - entity_id.into(), - UUID(gameprofile.id), - (EntityType::Player as i32).into(), - x, - y, - z, - pitch, - yaw, - yaw, - 0.into(), - 0.0, - 0.0, - 0.0, - ), - ); - // spawn players for our client - let token = player.client.token.clone(); - for (_, existing_player) in self.current_players.iter().filter(|c| c.0 != &token) { - let existing_player = existing_player.as_ref().lock().unwrap(); - let entity = &existing_player.entity; - let gameprofile = &existing_player.gameprofile; - player.client.send_packet(&CSpawnEntity::new( - existing_player.entity_id().into(), - UUID(gameprofile.id), - EntityType::Player.to_i32().unwrap().into(), - entity.x, - entity.y, - entity.z, - entity.yaw, - entity.pitch, - entity.pitch, - 0.into(), - 0.0, - 0.0, - 0.0, - )) - } - // entity meta data - if let Some(config) = player.client.config.as_ref() { - self.broadcast_packet( - player, - &CSetEntityMetadata::new( - entity_id.into(), - Metadata::new(17, VarInt(0), config.skin_parts), - ), - ) - } - - self.spawn_test_chunk(player, self.base_config.view_distance as u32) - .await; - } - - /// TODO: This definitly should be in world - pub fn get_by_entityid(&self, from: &Player, id: EntityId) -> Option> { - for (_, player) in self - .current_players - .iter() - .filter(|c| c.0 != &from.client.token) - { - let player = player.lock().unwrap(); - if player.entity_id() == id { - return Some(player); - } - } - None + gamemode, + ))); + world.lock().await.add_player(token, player.clone()); + (player, world) } pub fn try_get_container( &self, player_id: EntityId, container_id: u64, - ) -> Option>> { + ) -> Option>> { self.open_containers.get(&container_id)?.try_open(player_id) } - /// Sends a Packet to all Players - pub fn broadcast_packet

(&self, from: &mut Player, packet: &P) - where - P: ClientPacket, - { - // we can't borrow twice at same time - from.client.send_packet(packet); - for (_, player) in self - .current_players - .iter() - .filter(|c| c.0 != &from.client.token) - { - let mut player = player.lock().unwrap(); - player.client.send_packet(packet); - } - gamemode, - ))); - world.lock().await.add_player(token, player.clone()); - (player, world) - } - /// Sends a Packet to all Players in all worlds pub fn broadcast_packet_all

(&self, expect: &[&Arc], packet: &P) where