From 99116190d972965f1ccca93bce32bf8d35343e51 Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Wed, 21 Aug 2024 13:00:49 +0200 Subject: [PATCH 01/38] first steps towards making containers openable --- pumpkin-inventory/src/lib.rs | 10 +++- pumpkin-inventory/src/player.rs | 9 ++++ .../client/play/c_set_container_content.rs | 27 +++++++++++ pumpkin-protocol/src/client/play/mod.rs | 2 + pumpkin-protocol/src/slot.rs | 32 ++++++++++--- pumpkin/src/client/mod.rs | 48 ++++++++++++++++++- 6 files changed, 118 insertions(+), 10 deletions(-) create mode 100644 pumpkin-protocol/src/client/play/c_set_container_content.rs diff --git a/pumpkin-inventory/src/lib.rs b/pumpkin-inventory/src/lib.rs index 1ab7cba1c..2b5730afb 100644 --- a/pumpkin-inventory/src/lib.rs +++ b/pumpkin-inventory/src/lib.rs @@ -3,7 +3,7 @@ use num_derive::ToPrimitive; pub mod player; /// https://wiki.vg/Inventory -#[derive(Debug, ToPrimitive)] +#[derive(Debug, ToPrimitive, Clone)] pub enum WindowType { // not used Generic9x1, @@ -41,3 +41,11 @@ pub enum WindowType { CartographyTable, Stonecutter, } + +impl WindowType { + pub const fn default_title(&self) -> &'static str { + match self { + _ => "WINDOW TITLE" + } + } +} \ No newline at end of file diff --git a/pumpkin-inventory/src/player.rs b/pumpkin-inventory/src/player.rs index f7147f181..fe01acc98 100644 --- a/pumpkin-inventory/src/player.rs +++ b/pumpkin-inventory/src/player.rs @@ -95,4 +95,13 @@ impl PlayerInventory { debug_assert!((0..9).contains(&self.selected)); self.items[self.selected + 36 - 9].as_ref() } + + pub fn slots(&self) -> Vec> { + let mut slots = vec![self.crafting_output.as_ref()]; + slots.extend(self.crafting.iter().map(|c|c.as_ref())); + slots.extend(self.armor.iter().map(|c|c.as_ref())); + slots.extend(self.items.iter().map(|c|c.as_ref())); + slots.push(self.offhand.as_ref()); + slots + } } diff --git a/pumpkin-protocol/src/client/play/c_set_container_content.rs b/pumpkin-protocol/src/client/play/c_set_container_content.rs new file mode 100644 index 000000000..39a298d47 --- /dev/null +++ b/pumpkin-protocol/src/client/play/c_set_container_content.rs @@ -0,0 +1,27 @@ +use pumpkin_macros::packet; +use serde::Serialize; +use crate::slot::Slot; +use crate::VarInt; + +#[derive(Serialize)] +#[packet(0x13)] +pub struct CSetContainerContent<'a> { + window_id: u8, + state_id: VarInt, + count: VarInt, + slot_data: &'a [Slot], + carried_item: Slot +} + + +impl<'a> CSetContainerContent<'a> { + pub fn new(window_id: u8,state_id: VarInt, slots: &'a [Slot], carried_item: Slot) -> Self { + Self { + window_id, + state_id, + count: slots.len().try_into().unwrap(), + slot_data: slots, + carried_item + } + } +} diff --git a/pumpkin-protocol/src/client/play/mod.rs b/pumpkin-protocol/src/client/play/mod.rs index 2ff20e4c0..6437e23a5 100644 --- a/pumpkin-protocol/src/client/play/mod.rs +++ b/pumpkin-protocol/src/client/play/mod.rs @@ -33,6 +33,7 @@ mod c_update_entity_pos; mod c_update_entity_rot; mod c_worldevent; mod player_action; +mod c_set_container_content; pub use c_acknowledge_block::*; pub use c_actionbar::*; @@ -69,3 +70,4 @@ pub use c_update_entity_pos::*; pub use c_update_entity_rot::*; pub use c_worldevent::*; pub use player_action::*; +pub use c_set_container_content::*; \ No newline at end of file diff --git a/pumpkin-protocol/src/slot.rs b/pumpkin-protocol/src/slot.rs index 22223f3b4..84ffd662d 100644 --- a/pumpkin-protocol/src/slot.rs +++ b/pumpkin-protocol/src/slot.rs @@ -3,9 +3,10 @@ use pumpkin_world::item::Item; use serde::{ de::{self, SeqAccess, Visitor}, Deserialize, + Serialize }; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize)] #[allow(dead_code)] pub struct Slot { item_count: VarInt, @@ -83,12 +84,29 @@ impl Slot { item_count: self.item_count.0.try_into().unwrap(), }) } -} -impl From for Item { - fn from(slot: Slot) -> Self { - Item { - item_count: slot.item_count.0.try_into().unwrap(), - item_id: slot.item_id.unwrap().0.try_into().unwrap(), + + pub const fn empty() -> Self { + Slot { + item_count: VarInt(0), + item_id: None, + num_components_to_add: None, + num_components_to_remove: None, + components_to_add: None, + components_to_remove: None, } } } + +impl From<&Item> for Slot { + fn from(item: &Item) -> Self { + Slot { + item_count: item.item_count.into(), + item_id: Some(item.item_id.into()), + // TODO: add these + num_components_to_add: None, + num_components_to_remove: None, + components_to_add: None, + components_to_remove: None, + } + } +} \ No newline at end of file diff --git a/pumpkin/src/client/mod.rs b/pumpkin/src/client/mod.rs index 837976873..59e38e0f0 100644 --- a/pumpkin/src/client/mod.rs +++ b/pumpkin/src/client/mod.rs @@ -18,7 +18,7 @@ use pumpkin_protocol::{ client::{ config::CConfigDisconnect, login::CLoginDisconnect, - play::{CGameEvent, CPlayDisconnect, CSyncPlayerPostion, CSystemChatMessge}, + play::{CGameEvent, CPlayDisconnect, CSyncPlayerPostion, CSystemChatMessge, CSetContainerContent}, }, packet_decoder::PacketDecoder, packet_encoder::PacketEncoder, @@ -40,6 +40,10 @@ use pumpkin_text::TextComponent; use std::io::Read; use thiserror::Error; +use pumpkin_inventory::WindowType; +use pumpkin_protocol::client::play::COpenScreen; +use pumpkin_protocol::slot::Slot; +use pumpkin_world::item::Item; pub mod authentication; mod client_packet; @@ -174,6 +178,46 @@ impl Client { player.gamemode = gamemode; self.send_packet(&CGameEvent::new(3, gamemode.to_f32().unwrap())); } + + pub fn open_container(&mut self, window_type: WindowType, minecraft_menu_id: &str,window_title: Option<&str>) { + let menu_protocol_id = (*pumpkin_world::global_registry::REGISTRY.get("minecraft:menu").unwrap().entries.get(minecraft_menu_id).expect("Should be a valid menu id").get("protocol_id").unwrap()).into(); + let title = TextComponent::text(window_title.unwrap_or(window_type.default_title())); + self.send_packet(&COpenScreen::new((window_type.clone() as u8 +1).into(),menu_protocol_id, title)); + let temp_item = Item { + item_id: 91, // Diamond block + item_count: 64 + }; + self.set_container_content(window_type, Some([Some(&temp_item);27].to_vec()), None); + } + + pub fn set_container_content<'a>(&mut self, window_type: WindowType, items: Option>>, carried_item: Option<&'a Item>) { + let player = self.player.as_ref().unwrap(); + + let slots: Vec = {if let Some(mut items) = items { + items.extend(player.inventory.slots() + ); + items + } else { + player.inventory.slots() + }.into_iter() + .map(|item|{ + if let Some(item) = item { + Slot::from(item) + } else { + Slot::empty() + } + }).collect()}; + + let carried_item = { + if let Some(item) = carried_item { + item.into() + } else { + Slot::empty() + } + }; + + self.send_packet(&CSetContainerContent::new(window_type as u8, 10.into(), &slots, carried_item)) + } pub async fn process_packets(&mut self, server: &mut Server) { let mut i = 0; @@ -359,7 +403,7 @@ impl Client { } } } - + pub fn send_system_message(&mut self, text: TextComponent) { self.send_packet(&CSystemChatMessge::new(text, false)); } From 53f7b3b573da0f7f53017b6e4bcde08883a7952c Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Wed, 21 Aug 2024 13:00:54 +0200 Subject: [PATCH 02/38] testing command --- pumpkin/src/commands/cmd_chest.rs | 14 ++++++++++++++ pumpkin/src/commands/mod.rs | 3 ++- 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 pumpkin/src/commands/cmd_chest.rs diff --git a/pumpkin/src/commands/cmd_chest.rs b/pumpkin/src/commands/cmd_chest.rs new file mode 100644 index 000000000..0e7957932 --- /dev/null +++ b/pumpkin/src/commands/cmd_chest.rs @@ -0,0 +1,14 @@ +use pumpkin_inventory::WindowType; + +use crate::commands::tree::CommandTree; + +pub(crate) const NAME: &str = "chest"; + +const DESCRIPTION: &str = "Open a chest containing lots of diamond blocks"; + +pub(crate) fn init_command_tree<'a>() -> CommandTree<'a> { + CommandTree::new(DESCRIPTION).execute(&|sender, _| { + sender.as_mut_player().unwrap().open_container(WindowType::Generic3x3,"minecraft:generic_9x3",None); + Ok(()) + }) +} diff --git a/pumpkin/src/commands/mod.rs b/pumpkin/src/commands/mod.rs index c622691d6..c1b2d9f6c 100644 --- a/pumpkin/src/commands/mod.rs +++ b/pumpkin/src/commands/mod.rs @@ -12,6 +12,7 @@ mod cmd_stop; mod dispatcher; mod tree; mod tree_builder; +mod cmd_chest; pub enum CommandSender<'a> { Rcon(&'a mut Vec), @@ -77,7 +78,7 @@ fn dispatcher_init<'a>() -> CommandDispatcher<'a> { map.insert(cmd_stop::NAME, cmd_stop::init_command_tree()); map.insert(cmd_help::NAME, cmd_help::init_command_tree()); map.insert(cmd_help::ALIAS, cmd_help::init_command_tree()); - + map.insert(cmd_chest::NAME,cmd_chest::init_command_tree()); CommandDispatcher { commands: map } } From 5041b441eb511fc488c4ea6c96f299adda14c78b Mon Sep 17 00:00:00 2001 From: user622628252416 Date: Wed, 21 Aug 2024 17:59:54 +0200 Subject: [PATCH 03/38] add prettier CommandTree formatting for help command and usage hint --- pumpkin/src/commands/cmd_gamemode.rs | 4 +- pumpkin/src/commands/cmd_help.rs | 24 ++--- pumpkin/src/commands/cmd_pumpkin.rs | 4 +- pumpkin/src/commands/cmd_stop.rs | 4 +- pumpkin/src/commands/dispatcher.rs | 18 +++- pumpkin/src/commands/mod.rs | 16 ++-- pumpkin/src/commands/tree.rs | 56 ++---------- pumpkin/src/commands/tree_builder.rs | 15 +++- pumpkin/src/commands/tree_format.rs | 125 +++++++++++++++++++++++++++ 9 files changed, 185 insertions(+), 81 deletions(-) create mode 100644 pumpkin/src/commands/tree_format.rs diff --git a/pumpkin/src/commands/cmd_gamemode.rs b/pumpkin/src/commands/cmd_gamemode.rs index b054fdc24..88c7ae39f 100644 --- a/pumpkin/src/commands/cmd_gamemode.rs +++ b/pumpkin/src/commands/cmd_gamemode.rs @@ -15,7 +15,7 @@ use crate::commands::CommandSender; use crate::commands::CommandSender::Player; use crate::entity::player::GameMode; -pub(crate) const NAME: &str = "gamemode"; +const NAMES: [&str; 1] = ["gamemode"]; const DESCRIPTION: &str = "Change a player's gamemode."; @@ -57,7 +57,7 @@ pub fn parse_arg_gamemode(consumed_args: &ConsumedArgs) -> Result() -> CommandTree<'a> { - CommandTree::new(DESCRIPTION).with_child( + CommandTree::new(NAMES, DESCRIPTION).with_child( require(&|sender| sender.permission_lvl() >= 2).with_child( argument(ARG_GAMEMODE, consume_arg_gamemode) .with_child( diff --git a/pumpkin/src/commands/cmd_help.rs b/pumpkin/src/commands/cmd_help.rs index 7ffa733c1..1e1b0e5b7 100644 --- a/pumpkin/src/commands/cmd_help.rs +++ b/pumpkin/src/commands/cmd_help.rs @@ -5,8 +5,7 @@ use crate::commands::tree_builder::argument; use crate::commands::{dispatcher_init, CommandSender, DISPATCHER}; use pumpkin_text::TextComponent; -pub(crate) const NAME: &str = "help"; -pub(crate) const ALIAS: &str = "?"; +const NAMES: [&str; 3] = ["help", "h", "?"]; const DESCRIPTION: &str = "Print a help message."; @@ -40,7 +39,7 @@ fn parse_arg_command<'a>( } pub(crate) fn init_command_tree<'a>() -> CommandTree<'a> { - CommandTree::new(DESCRIPTION) + CommandTree::new(NAMES, DESCRIPTION) .with_child( argument(ARG_COMMAND, consume_arg_command).execute(&|sender, args| { let dispatcher = DISPATCHER.get_or_init(dispatcher_init); @@ -48,10 +47,8 @@ pub(crate) fn init_command_tree<'a>() -> CommandTree<'a> { let (name, tree) = parse_arg_command(args, dispatcher)?; sender.send_message(TextComponent::text(&format!( - "{} - {} Usage:{}", - name, - tree.description, - tree.paths_formatted(name) + "{} - {} Usage: {}", + name, tree.description, tree ))); Ok(()) @@ -60,12 +57,15 @@ pub(crate) fn init_command_tree<'a>() -> CommandTree<'a> { .execute(&|sender, _args| { let dispatcher = DISPATCHER.get_or_init(dispatcher_init); - for (name, tree) in &dispatcher.commands { + let mut names: Vec<&str> = dispatcher.commands.keys().copied().collect(); + names.sort(); + + for name in names { + let tree = &dispatcher.commands[name]; + sender.send_message(TextComponent::text(&format!( - "{} - {} Usage:{}", - name, - tree.description, - tree.paths_formatted(name) + "{} - {} Usage: {}", + name, tree.description, tree ))); } diff --git a/pumpkin/src/commands/cmd_pumpkin.rs b/pumpkin/src/commands/cmd_pumpkin.rs index cbbac0680..b4cfb1847 100644 --- a/pumpkin/src/commands/cmd_pumpkin.rs +++ b/pumpkin/src/commands/cmd_pumpkin.rs @@ -4,12 +4,12 @@ use pumpkin_text::{color::NamedColor, TextComponent}; use crate::commands::tree::CommandTree; -pub(crate) const NAME: &str = "pumpkin"; +const NAMES: [&str; 1] = ["pumpkin"]; const DESCRIPTION: &str = "Display information about Pumpkin."; pub(crate) fn init_command_tree<'a>() -> CommandTree<'a> { - CommandTree::new(DESCRIPTION).execute(&|sender, _| { + CommandTree::new(NAMES, DESCRIPTION).execute(&|sender, _| { let version = env!("CARGO_PKG_VERSION"); let description = env!("CARGO_PKG_DESCRIPTION"); diff --git a/pumpkin/src/commands/cmd_stop.rs b/pumpkin/src/commands/cmd_stop.rs index b576c299d..60f425b76 100644 --- a/pumpkin/src/commands/cmd_stop.rs +++ b/pumpkin/src/commands/cmd_stop.rs @@ -1,12 +1,12 @@ use crate::commands::tree::CommandTree; use crate::commands::tree_builder::require; -pub(crate) const NAME: &str = "stop"; +const NAMES: [&str; 1] = ["stop"]; const DESCRIPTION: &str = "Stop the server."; pub(crate) fn init_command_tree<'a>() -> CommandTree<'a> { - CommandTree::new(DESCRIPTION).with_child( + CommandTree::new(NAMES, DESCRIPTION).with_child( require(&|sender| sender.permission_lvl() >= 4) .execute(&|_sender, _args| std::process::exit(0)), ) diff --git a/pumpkin/src/commands/dispatcher.rs b/pumpkin/src/commands/dispatcher.rs index a01e20b81..d4a829818 100644 --- a/pumpkin/src/commands/dispatcher.rs +++ b/pumpkin/src/commands/dispatcher.rs @@ -49,10 +49,7 @@ impl<'a> CommandDispatcher<'a> { } } - Err(format!( - "Invalid Syntax. Usage:{}", - tree.paths_formatted(key) - )) + Err(format!("Invalid Syntax. Usage: {}", tree)) } fn try_is_fitting_path( @@ -99,4 +96,17 @@ impl<'a> CommandDispatcher<'a> { Ok(false) } + + /// Register a command with the dispatcher. + pub(crate) fn register(&mut self, tree: CommandTree<'a>) { + let mut names = tree.names.iter(); + + let primary_name = names.next().expect("at least one name must be provided"); + + for &name in names { + self.commands.insert(name, tree.clone()); + } + + self.commands.insert(primary_name, tree); + } } diff --git a/pumpkin/src/commands/mod.rs b/pumpkin/src/commands/mod.rs index c622691d6..9f49033ba 100644 --- a/pumpkin/src/commands/mod.rs +++ b/pumpkin/src/commands/mod.rs @@ -12,6 +12,7 @@ mod cmd_stop; mod dispatcher; mod tree; mod tree_builder; +mod tree_format; pub enum CommandSender<'a> { Rcon(&'a mut Vec), @@ -70,15 +71,16 @@ static DISPATCHER: OnceLock = OnceLock::new(); /// create [CommandDispatcher] instance for [DISPATCHER] fn dispatcher_init<'a>() -> CommandDispatcher<'a> { - let mut map = HashMap::new(); + let mut dispatcher = CommandDispatcher { + commands: HashMap::new(), + }; - map.insert(cmd_pumpkin::NAME, cmd_pumpkin::init_command_tree()); - map.insert(cmd_gamemode::NAME, cmd_gamemode::init_command_tree()); - map.insert(cmd_stop::NAME, cmd_stop::init_command_tree()); - map.insert(cmd_help::NAME, cmd_help::init_command_tree()); - map.insert(cmd_help::ALIAS, cmd_help::init_command_tree()); + dispatcher.register(cmd_pumpkin::init_command_tree()); + dispatcher.register(cmd_gamemode::init_command_tree()); + dispatcher.register(cmd_stop::init_command_tree()); + dispatcher.register(cmd_help::init_command_tree()); - CommandDispatcher { commands: map } + dispatcher } pub fn handle_command(sender: &mut CommandSender, cmd: &str) { diff --git a/pumpkin/src/commands/tree.rs b/pumpkin/src/commands/tree.rs index b4132b18e..2e2741f38 100644 --- a/pumpkin/src/commands/tree.rs +++ b/pumpkin/src/commands/tree.rs @@ -2,6 +2,7 @@ use std::collections::{HashMap, VecDeque}; use crate::commands::dispatcher::InvalidTreeError; use crate::commands::CommandSender; + /// see [crate::commands::tree_builder::argument] pub(crate) type RawArgs<'a> = Vec<&'a str>; @@ -11,11 +12,13 @@ pub(crate) type ConsumedArgs<'a> = HashMap<&'a str, String>; /// see [crate::commands::tree_builder::argument] pub(crate) type ArgumentConsumer<'a> = fn(&CommandSender, &mut RawArgs) -> Option; +#[derive(Clone)] pub(crate) struct Node<'a> { pub(crate) children: Vec, pub(crate) node_type: NodeType<'a>, } +#[derive(Clone)] pub(crate) enum NodeType<'a> { ExecuteLeaf { run: &'a (dyn Fn(&mut CommandSender, &ConsumedArgs) -> Result<(), InvalidTreeError> + Sync), @@ -31,9 +34,11 @@ pub(crate) enum NodeType<'a> { }, } +#[derive(Clone)] pub(crate) struct CommandTree<'a> { pub(crate) nodes: Vec>, pub(crate) children: Vec, + pub(crate) names: Vec<&'a str>, pub(crate) description: &'a str, } @@ -51,57 +56,6 @@ impl<'a> CommandTree<'a> { todo, } } - - /// format possible paths as [String], using ```name``` as the command name - /// - /// todo: merge into single line - pub(crate) fn paths_formatted(&'a self, name: &str) -> String { - let paths: Vec> = self - .iter_paths() - .map(|path| path.iter().map(|&i| &self.nodes[i].node_type).collect()) - .collect(); - - let len = paths - .iter() - .map(|path| { - path.iter() - .map(|node| match node { - NodeType::ExecuteLeaf { .. } => 0, - NodeType::Literal { string } => string.len() + 1, - NodeType::Argument { name, .. } => name.len() + 3, - NodeType::Require { .. } => 0, - }) - .sum::() - + name.len() - + 2 - }) - .sum::(); - - let mut s = String::with_capacity(len); - - for path in paths.iter() { - s.push(if paths.len() > 1 { '\n' } else { ' ' }); - s.push('/'); - s.push_str(name); - for node in path { - match node { - NodeType::Literal { string } => { - s.push(' '); - s.push_str(string); - } - NodeType::Argument { name, .. } => { - s.push(' '); - s.push('<'); - s.push_str(name); - s.push('>'); - } - _ => {} - } - } - } - - s - } } struct TraverseAllPathsIter<'a> { diff --git a/pumpkin/src/commands/tree_builder.rs b/pumpkin/src/commands/tree_builder.rs index 63531909b..d34ee3a6a 100644 --- a/pumpkin/src/commands/tree_builder.rs +++ b/pumpkin/src/commands/tree_builder.rs @@ -11,10 +11,23 @@ impl<'a> CommandTree<'a> { self } - pub fn new(description: &'a str) -> Self { + /// provide at least one name + pub fn new( + names: [&'a str; NAME_COUNT], + description: &'a str, + ) -> Self { + assert!(NAME_COUNT > 0); + + let mut names_vec = Vec::with_capacity(NAME_COUNT); + + for name in names { + names_vec.push(name); + } + Self { nodes: Vec::new(), children: Vec::new(), + names: names_vec, description, } } diff --git a/pumpkin/src/commands/tree_format.rs b/pumpkin/src/commands/tree_format.rs new file mode 100644 index 000000000..b13b0e1fe --- /dev/null +++ b/pumpkin/src/commands/tree_format.rs @@ -0,0 +1,125 @@ +use crate::commands::tree::{CommandTree, Node, NodeType}; +use std::collections::VecDeque; +use std::fmt::{Display, Formatter, Write}; + +trait IsVisible { + /// whether node should be printed in help command/usage hint + fn is_visible(&self) -> bool; +} + +impl<'a> IsVisible for Node<'a> { + fn is_visible(&self) -> bool { + match self.node_type { + NodeType::ExecuteLeaf { .. } => false, + NodeType::Literal { .. } => true, + NodeType::Argument { .. } => true, + NodeType::Require { .. } => false, + } + } +} + +impl<'a> Display for Node<'a> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self.node_type { + NodeType::Literal { string } => { + f.write_str(string)?; + } + NodeType::Argument { name, .. } => { + f.write_char('<')?; + f.write_str(name)?; + f.write_char('>')?; + } + _ => {} + }; + + Ok(()) + } +} + +fn flatten_require_nodes(nodes: &[Node], children: &[usize]) -> Vec { + let mut new_children = Vec::with_capacity(children.len()); + + for &i in children { + let node = &nodes[i]; + match &node.node_type { + NodeType::Require { .. } => { + new_children.extend(flatten_require_nodes(nodes, node.children.as_slice())) + } + _ => new_children.push(i), + } + } + + new_children +} + +impl<'a> Display for CommandTree<'a> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.write_char('/')?; + f.write_str(self.names[0])?; + + let mut todo = VecDeque::<&[usize]>::with_capacity(self.children.len()); + todo.push_back(&self.children); + + loop { + let Some(children) = todo.pop_front() else { + break; + }; + + let flattened_children = flatten_require_nodes(&self.nodes, children); + let visible_children = flattened_children + .iter() + .copied() + .filter(|&i| self.nodes[i].is_visible()) + .collect::>(); + + if visible_children.is_empty() { + break; + }; + + f.write_char(' ')?; + + let is_optional = flattened_children + .iter() + .map(|&i| &self.nodes[i].node_type) + .any(|node| matches!(node, NodeType::ExecuteLeaf { .. })); + + if is_optional { + f.write_char('[')?; + } + + match visible_children.as_slice() { + [] => unreachable!(), + [i] => { + let node = &self.nodes[*i]; + + node.fmt(f)?; + + todo.push_back(&node.children); + } + _ => { + // todo: handle cases where one of these nodes has visible children + f.write_char('(')?; + + let mut iter = visible_children.iter().map(|&i| &self.nodes[i]); + + if let Some(node) = iter.next() { + node.fmt(f)?; + } + + for node in iter { + f.write_char('|')?; + node.fmt(f)?; + } + + f.write_char(')')?; + } + } + + if is_optional { + f.write_char(']')?; + } + } + + Ok(()) + } +} From 8bc55e8dda82cf30b42e9d674999d168762d26f6 Mon Sep 17 00:00:00 2001 From: kralverde Date: Wed, 21 Aug 2024 12:34:25 -0400 Subject: [PATCH 04/38] parse fixed bitset from player chat --- pumpkin-protocol/src/bytebuf/mod.rs | 10 ++++++++-- pumpkin-protocol/src/lib.rs | 1 + pumpkin-protocol/src/server/play/s_chat_message.rs | 6 +++--- pumpkin/src/client/player_packet.rs | 6 ++++++ 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/pumpkin-protocol/src/bytebuf/mod.rs b/pumpkin-protocol/src/bytebuf/mod.rs index fa275bb15..250d4fa1f 100644 --- a/pumpkin-protocol/src/bytebuf/mod.rs +++ b/pumpkin-protocol/src/bytebuf/mod.rs @@ -1,4 +1,4 @@ -use crate::{BitSet, VarInt, VarLongType}; +use crate::{BitSet, FixedBitSet, VarInt, VarLongType}; use bytes::{Buf, BufMut, BytesMut}; use core::str; use std::io::{self, Error, ErrorKind}; @@ -107,6 +107,10 @@ impl ByteBuffer { uuid::Uuid::from_slice(&bytes).expect("Failed to parse UUID") } + pub fn get_fixed_bitset(&mut self, bits: usize) -> FixedBitSet { + self.copy_to_bytes(bits.div_ceil(8)) + } + pub fn put_bool(&mut self, v: bool) { if v { self.buffer.put_u8(1); @@ -168,7 +172,9 @@ impl ByteBuffer { /// some, then it also calls the `write` closure. pub fn put_option(&mut self, val: &Option, write: impl FnOnce(&mut Self, &T)) { self.put_bool(val.is_some()); - if let Some(v) = val { write(self, v) } + if let Some(v) = val { + write(self, v) + } } pub fn get_list(&mut self, val: impl Fn(&mut Self) -> T) -> Vec { diff --git a/pumpkin-protocol/src/lib.rs b/pumpkin-protocol/src/lib.rs index 3f7a4b607..f44a0a811 100644 --- a/pumpkin-protocol/src/lib.rs +++ b/pumpkin-protocol/src/lib.rs @@ -21,6 +21,7 @@ pub const MAX_PACKET_SIZE: i32 = 2097152; pub type Identifier = String; pub type VarIntType = i32; pub type VarLongType = i64; +pub type FixedBitSet = bytes::Bytes; pub struct BitSet<'a>(pub VarInt, pub &'a [i64]); diff --git a/pumpkin-protocol/src/server/play/s_chat_message.rs b/pumpkin-protocol/src/server/play/s_chat_message.rs index fc153094a..e644a5bc3 100644 --- a/pumpkin-protocol/src/server/play/s_chat_message.rs +++ b/pumpkin-protocol/src/server/play/s_chat_message.rs @@ -3,7 +3,7 @@ use pumpkin_macros::packet; use crate::{ bytebuf::{ByteBuffer, DeserializerError}, - ServerPacket, VarInt, + FixedBitSet, ServerPacket, VarInt, }; // derive(Deserialize)] @@ -14,8 +14,7 @@ pub struct SChatMessage { pub salt: i64, pub signature: Option, pub messagee_count: VarInt, - // TODO: Properly implement BitSet decoding - // acknowledged: BitSet, + pub acknowledged: FixedBitSet, } // TODO @@ -27,6 +26,7 @@ impl ServerPacket for SChatMessage { salt: bytebuf.get_i64(), signature: bytebuf.get_option(|v| v.copy_to_bytes(256)), messagee_count: bytebuf.get_var_int(), + acknowledged: bytebuf.get_fixed_bitset(20), }) } } diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index b8a7853d7..6f7a4d9e5 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -212,7 +212,13 @@ impl Client { pub fn handle_chat_message(&mut self, server: &mut Server, chat_message: SChatMessage) { dbg!("got message"); + let message = chat_message.message; + if message.len() > 256 { + self.kick("Oversized message"); + return; + } + // TODO: filter message & validation let gameprofile = self.gameprofile.as_ref().unwrap(); From ab8956a7b5d7b5b4e8fc9f3cc33a2d90cade5451 Mon Sep 17 00:00:00 2001 From: user622628252416 Date: Wed, 21 Aug 2024 19:27:20 +0200 Subject: [PATCH 05/38] remove repeating command aliases in /help --- pumpkin/src/commands/cmd_help.rs | 38 +++++++++++++++--------------- pumpkin/src/commands/dispatcher.rs | 25 ++++++++++++++++---- pumpkin/src/commands/tree.rs | 8 ++++--- 3 files changed, 44 insertions(+), 27 deletions(-) diff --git a/pumpkin/src/commands/cmd_help.rs b/pumpkin/src/commands/cmd_help.rs index 1e1b0e5b7..71bce754b 100644 --- a/pumpkin/src/commands/cmd_help.rs +++ b/pumpkin/src/commands/cmd_help.rs @@ -1,6 +1,6 @@ use crate::commands::dispatcher::InvalidTreeError::InvalidConsumptionError; use crate::commands::dispatcher::{CommandDispatcher, InvalidTreeError}; -use crate::commands::tree::{CommandTree, ConsumedArgs, RawArgs}; +use crate::commands::tree::{Command, CommandTree, ConsumedArgs, RawArgs}; use crate::commands::tree_builder::argument; use crate::commands::{dispatcher_init, CommandSender, DISPATCHER}; use pumpkin_text::TextComponent; @@ -16,26 +16,20 @@ fn consume_arg_command(_src: &CommandSender, args: &mut RawArgs) -> Option( consumed_args: &'a ConsumedArgs, dispatcher: &'a CommandDispatcher, -) -> Result<(&'a str, &'a CommandTree<'a>), InvalidTreeError> { +) -> Result<&'a CommandTree<'a>, InvalidTreeError> { let command_name = consumed_args .get(ARG_COMMAND) .ok_or(InvalidConsumptionError(None))?; - if let Some(tree) = dispatcher.commands.get::<&str>(&command_name.as_str()) { - Ok((command_name, tree)) - } else { - Err(InvalidConsumptionError(Some(command_name.into()))) - } + dispatcher + .get_tree(command_name) + .map_err(|_| InvalidConsumptionError(Some(command_name.into()))) } pub(crate) fn init_command_tree<'a>() -> CommandTree<'a> { @@ -44,11 +38,13 @@ pub(crate) fn init_command_tree<'a>() -> CommandTree<'a> { argument(ARG_COMMAND, consume_arg_command).execute(&|sender, args| { let dispatcher = DISPATCHER.get_or_init(dispatcher_init); - let (name, tree) = parse_arg_command(args, dispatcher)?; + let tree = parse_arg_command(args, dispatcher)?; sender.send_message(TextComponent::text(&format!( "{} - {} Usage: {}", - name, tree.description, tree + tree.names.join("/"), + tree.description, + tree ))); Ok(()) @@ -57,15 +53,19 @@ pub(crate) fn init_command_tree<'a>() -> CommandTree<'a> { .execute(&|sender, _args| { let dispatcher = DISPATCHER.get_or_init(dispatcher_init); - let mut names: Vec<&str> = dispatcher.commands.keys().copied().collect(); - names.sort(); + let mut keys: Vec<&str> = dispatcher.commands.keys().copied().collect(); + keys.sort(); - for name in names { - let tree = &dispatcher.commands[name]; + for key in keys { + let Command::Tree(tree) = &dispatcher.commands[key] else { + continue; + }; sender.send_message(TextComponent::text(&format!( "{} - {} Usage: {}", - name, tree.description, tree + tree.names.join("/"), + tree.description, + tree ))); } diff --git a/pumpkin/src/commands/dispatcher.rs b/pumpkin/src/commands/dispatcher.rs index d4a829818..dac9c8894 100644 --- a/pumpkin/src/commands/dispatcher.rs +++ b/pumpkin/src/commands/dispatcher.rs @@ -1,7 +1,7 @@ use crate::commands::dispatcher::InvalidTreeError::{ InvalidConsumptionError, InvalidRequirementError, }; -use crate::commands::tree::{CommandTree, ConsumedArgs, NodeType, RawArgs}; +use crate::commands::tree::{Command, CommandTree, ConsumedArgs, NodeType, RawArgs}; use crate::commands::CommandSender; use std::collections::HashMap; @@ -17,7 +17,7 @@ pub(crate) enum InvalidTreeError { } pub(crate) struct CommandDispatcher<'a> { - pub(crate) commands: HashMap<&'a str, CommandTree<'a>>, + pub(crate) commands: HashMap<&'a str, Command<'a>>, } /// Stores registered [CommandTree]s and dispatches commands to them. @@ -28,7 +28,7 @@ impl<'a> CommandDispatcher<'a> { let key = parts.next().ok_or("Empty Command")?; let raw_args: Vec<&str> = parts.rev().collect(); - let tree = self.commands.get(key).ok_or("Command not found")?; + let tree = self.get_tree(key)?; // try paths until fitting path is found for path in tree.iter_paths() { @@ -52,6 +52,21 @@ impl<'a> CommandDispatcher<'a> { Err(format!("Invalid Syntax. Usage: {}", tree)) } + pub(crate) fn get_tree(&'a self, key: &str) -> Result<&'a CommandTree<'a>, String> { + let command = self.commands.get(key).ok_or("Command not found")?; + + match command { + Command::Tree(tree) => Ok(tree), + Command::Alias(target) => { + let Some(Command::Tree(tree)) = &self.commands.get(target) else { + println!("Error while parsing command alias \"{key}\": pointing to \"{target}\" which is not a valid tree"); + return Err("Internal Error (See logs for details)".into()); + }; + Ok(tree) + } + } + } + fn try_is_fitting_path( src: &mut CommandSender, path: Vec, @@ -104,9 +119,9 @@ impl<'a> CommandDispatcher<'a> { let primary_name = names.next().expect("at least one name must be provided"); for &name in names { - self.commands.insert(name, tree.clone()); + self.commands.insert(name, Command::Alias(primary_name)); } - self.commands.insert(primary_name, tree); + self.commands.insert(primary_name, Command::Tree(tree)); } } diff --git a/pumpkin/src/commands/tree.rs b/pumpkin/src/commands/tree.rs index 2e2741f38..59d2473c8 100644 --- a/pumpkin/src/commands/tree.rs +++ b/pumpkin/src/commands/tree.rs @@ -12,13 +12,11 @@ pub(crate) type ConsumedArgs<'a> = HashMap<&'a str, String>; /// see [crate::commands::tree_builder::argument] pub(crate) type ArgumentConsumer<'a> = fn(&CommandSender, &mut RawArgs) -> Option; -#[derive(Clone)] pub(crate) struct Node<'a> { pub(crate) children: Vec, pub(crate) node_type: NodeType<'a>, } -#[derive(Clone)] pub(crate) enum NodeType<'a> { ExecuteLeaf { run: &'a (dyn Fn(&mut CommandSender, &ConsumedArgs) -> Result<(), InvalidTreeError> + Sync), @@ -34,7 +32,11 @@ pub(crate) enum NodeType<'a> { }, } -#[derive(Clone)] +pub(crate) enum Command<'a> { + Tree(CommandTree<'a>), + Alias(&'a str), +} + pub(crate) struct CommandTree<'a> { pub(crate) nodes: Vec>, pub(crate) children: Vec, From 9003ee3dcc4518135bb9f7712d36423475475102 Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Wed, 21 Aug 2024 19:27:58 +0200 Subject: [PATCH 06/38] add CSetContainerContent --- .../client/play/c_set_container_content.rs | 4 +- pumpkin-protocol/src/slot.rs | 65 +++++++++++++++++-- pumpkin/src/client/mod.rs | 15 ++--- 3 files changed, 65 insertions(+), 19 deletions(-) diff --git a/pumpkin-protocol/src/client/play/c_set_container_content.rs b/pumpkin-protocol/src/client/play/c_set_container_content.rs index 39a298d47..666039a7f 100644 --- a/pumpkin-protocol/src/client/play/c_set_container_content.rs +++ b/pumpkin-protocol/src/client/play/c_set_container_content.rs @@ -10,12 +10,12 @@ pub struct CSetContainerContent<'a> { state_id: VarInt, count: VarInt, slot_data: &'a [Slot], - carried_item: Slot + carried_item: &'a Slot } impl<'a> CSetContainerContent<'a> { - pub fn new(window_id: u8,state_id: VarInt, slots: &'a [Slot], carried_item: Slot) -> Self { + pub fn new(window_id: u8,state_id: VarInt, slots: &'a [Slot], carried_item: &'a Slot) -> Self { Self { window_id, state_id, diff --git a/pumpkin-protocol/src/slot.rs b/pumpkin-protocol/src/slot.rs index 84ffd662d..51521a960 100644 --- a/pumpkin-protocol/src/slot.rs +++ b/pumpkin-protocol/src/slot.rs @@ -1,12 +1,9 @@ use crate::VarInt; use pumpkin_world::item::Item; -use serde::{ - de::{self, SeqAccess, Visitor}, - Deserialize, - Serialize -}; +use serde::{de::{self, SeqAccess, Visitor}, Deserialize, Serialize, Serializer}; +use serde::ser::SerializeSeq; -#[derive(Debug, Clone, Serialize)] +#[derive(Debug, Clone)] #[allow(dead_code)] pub struct Slot { item_count: VarInt, @@ -76,6 +73,60 @@ impl<'de> Deserialize<'de> for Slot { deserializer.deserialize_seq(VarIntVisitor) } } + +impl Serialize for Slot { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + if self.item_count == 0.into() { + let mut s = serializer.serialize_seq(Some(1))?; + s.serialize_element(&self.item_count)?; + s.end() + } else { + match (&self.num_components_to_add,&self.num_components_to_remove) { + (Some(to_add),Some(to_remove)) => { + let mut s = serializer.serialize_seq(Some(6))?; + s.serialize_element(&self.item_count)?; + s.serialize_element(self.item_id.as_ref().unwrap())?; + s.serialize_element(to_add)?; + s.serialize_element(to_remove)?; + s.serialize_element(self.components_to_add.as_ref().unwrap())?; + s.serialize_element(self.components_to_remove.as_ref().unwrap())?; + s.end() + } + (None, Some(to_remove)) => { + let mut s = serializer.serialize_seq(Some(5))?; + s.serialize_element(&self.item_count)?; + s.serialize_element(self.item_id.as_ref().unwrap())?; + s.serialize_element(&VarInt(0))?; + s.serialize_element(to_remove)?; + s.serialize_element(self.components_to_remove.as_ref().unwrap())?; + s.end() + } + (Some(to_add),None) => { + let mut s = serializer.serialize_seq(Some(5))?; + s.serialize_element(&self.item_count)?; + s.serialize_element(self.item_id.as_ref().unwrap())?; + s.serialize_element(to_add)?; + s.serialize_element(&VarInt(0))?; + s.serialize_element(self.components_to_add.as_ref().unwrap())?; + s.end() + } + (None,None) => { + let mut s = serializer.serialize_seq(Some(4))?; + s.serialize_element(&self.item_count)?; + s.serialize_element(&self.item_id.as_ref().unwrap())?; + s.serialize_element(&VarInt(0))?; + s.serialize_element(&VarInt(0))?; + s.end() + } + } + + } + } +} + impl Slot { pub fn to_item(self) -> Option { let item_id = self.item_id?.0.try_into().unwrap(); @@ -103,7 +154,7 @@ impl From<&Item> for Slot { item_count: item.item_count.into(), item_id: Some(item.item_id.into()), // TODO: add these - num_components_to_add: None, + num_components_to_add:None, num_components_to_remove: None, components_to_add: None, components_to_remove: None, diff --git a/pumpkin/src/client/mod.rs b/pumpkin/src/client/mod.rs index 59e38e0f0..bc7d598ff 100644 --- a/pumpkin/src/client/mod.rs +++ b/pumpkin/src/client/mod.rs @@ -41,6 +41,7 @@ use pumpkin_text::TextComponent; use std::io::Read; use thiserror::Error; use pumpkin_inventory::WindowType; +use pumpkin_protocol::bytebuf::ByteBuffer; use pumpkin_protocol::client::play::COpenScreen; use pumpkin_protocol::slot::Slot; use pumpkin_world::item::Item; @@ -179,23 +180,18 @@ impl Client { self.send_packet(&CGameEvent::new(3, gamemode.to_f32().unwrap())); } - pub fn open_container(&mut self, window_type: WindowType, minecraft_menu_id: &str,window_title: Option<&str>) { + pub fn open_container(&mut self, window_type: WindowType, minecraft_menu_id: &str,window_title: Option<&str>, items: Option>>, carried_item: Option<&Item>) { let menu_protocol_id = (*pumpkin_world::global_registry::REGISTRY.get("minecraft:menu").unwrap().entries.get(minecraft_menu_id).expect("Should be a valid menu id").get("protocol_id").unwrap()).into(); let title = TextComponent::text(window_title.unwrap_or(window_type.default_title())); self.send_packet(&COpenScreen::new((window_type.clone() as u8 +1).into(),menu_protocol_id, title)); - let temp_item = Item { - item_id: 91, // Diamond block - item_count: 64 - }; - self.set_container_content(window_type, Some([Some(&temp_item);27].to_vec()), None); + self.set_container_content(window_type, items, carried_item); } pub fn set_container_content<'a>(&mut self, window_type: WindowType, items: Option>>, carried_item: Option<&'a Item>) { let player = self.player.as_ref().unwrap(); let slots: Vec = {if let Some(mut items) = items { - items.extend(player.inventory.slots() - ); + items.extend(player.inventory.slots()); items } else { player.inventory.slots() @@ -215,8 +211,7 @@ impl Client { Slot::empty() } }; - - self.send_packet(&CSetContainerContent::new(window_type as u8, 10.into(), &slots, carried_item)) + self.send_packet(&CSetContainerContent::new(window_type as u8+1, 0.into(), &slots, &carried_item)); } pub async fn process_packets(&mut self, server: &mut Server) { From 2e00110d5dd02644a0436ce987c3afbfafdeacaf Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Wed, 21 Aug 2024 19:28:27 +0200 Subject: [PATCH 07/38] remove debug thing --- pumpkin/src/commands/cmd_chest.rs | 14 -------------- pumpkin/src/commands/mod.rs | 2 -- 2 files changed, 16 deletions(-) delete mode 100644 pumpkin/src/commands/cmd_chest.rs diff --git a/pumpkin/src/commands/cmd_chest.rs b/pumpkin/src/commands/cmd_chest.rs deleted file mode 100644 index 0e7957932..000000000 --- a/pumpkin/src/commands/cmd_chest.rs +++ /dev/null @@ -1,14 +0,0 @@ -use pumpkin_inventory::WindowType; - -use crate::commands::tree::CommandTree; - -pub(crate) const NAME: &str = "chest"; - -const DESCRIPTION: &str = "Open a chest containing lots of diamond blocks"; - -pub(crate) fn init_command_tree<'a>() -> CommandTree<'a> { - CommandTree::new(DESCRIPTION).execute(&|sender, _| { - sender.as_mut_player().unwrap().open_container(WindowType::Generic3x3,"minecraft:generic_9x3",None); - Ok(()) - }) -} diff --git a/pumpkin/src/commands/mod.rs b/pumpkin/src/commands/mod.rs index c1b2d9f6c..c977bb0f9 100644 --- a/pumpkin/src/commands/mod.rs +++ b/pumpkin/src/commands/mod.rs @@ -12,7 +12,6 @@ mod cmd_stop; mod dispatcher; mod tree; mod tree_builder; -mod cmd_chest; pub enum CommandSender<'a> { Rcon(&'a mut Vec), @@ -78,7 +77,6 @@ fn dispatcher_init<'a>() -> CommandDispatcher<'a> { map.insert(cmd_stop::NAME, cmd_stop::init_command_tree()); map.insert(cmd_help::NAME, cmd_help::init_command_tree()); map.insert(cmd_help::ALIAS, cmd_help::init_command_tree()); - map.insert(cmd_chest::NAME,cmd_chest::init_command_tree()); CommandDispatcher { commands: map } } From 816215c698b060903bb0a3d2158e697f69716ebe Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Wed, 21 Aug 2024 19:28:48 +0200 Subject: [PATCH 08/38] format --- pumpkin-inventory/src/lib.rs | 4 +- pumpkin-inventory/src/player.rs | 6 +- .../client/play/c_set_container_content.rs | 11 ++- pumpkin-protocol/src/client/play/mod.rs | 4 +- pumpkin-protocol/src/slot.rs | 18 +++-- pumpkin/src/client/mod.rs | 76 ++++++++++++++----- 6 files changed, 78 insertions(+), 41 deletions(-) diff --git a/pumpkin-inventory/src/lib.rs b/pumpkin-inventory/src/lib.rs index 2b5730afb..691c69370 100644 --- a/pumpkin-inventory/src/lib.rs +++ b/pumpkin-inventory/src/lib.rs @@ -45,7 +45,7 @@ pub enum WindowType { impl WindowType { pub const fn default_title(&self) -> &'static str { match self { - _ => "WINDOW TITLE" + _ => "WINDOW TITLE", } } -} \ No newline at end of file +} diff --git a/pumpkin-inventory/src/player.rs b/pumpkin-inventory/src/player.rs index fe01acc98..b67af9c6b 100644 --- a/pumpkin-inventory/src/player.rs +++ b/pumpkin-inventory/src/player.rs @@ -98,9 +98,9 @@ impl PlayerInventory { pub fn slots(&self) -> Vec> { let mut slots = vec![self.crafting_output.as_ref()]; - slots.extend(self.crafting.iter().map(|c|c.as_ref())); - slots.extend(self.armor.iter().map(|c|c.as_ref())); - slots.extend(self.items.iter().map(|c|c.as_ref())); + slots.extend(self.crafting.iter().map(|c| c.as_ref())); + slots.extend(self.armor.iter().map(|c| c.as_ref())); + slots.extend(self.items.iter().map(|c| c.as_ref())); slots.push(self.offhand.as_ref()); slots } diff --git a/pumpkin-protocol/src/client/play/c_set_container_content.rs b/pumpkin-protocol/src/client/play/c_set_container_content.rs index 666039a7f..919bc44d3 100644 --- a/pumpkin-protocol/src/client/play/c_set_container_content.rs +++ b/pumpkin-protocol/src/client/play/c_set_container_content.rs @@ -1,7 +1,7 @@ -use pumpkin_macros::packet; -use serde::Serialize; use crate::slot::Slot; use crate::VarInt; +use pumpkin_macros::packet; +use serde::Serialize; #[derive(Serialize)] #[packet(0x13)] @@ -10,18 +10,17 @@ pub struct CSetContainerContent<'a> { state_id: VarInt, count: VarInt, slot_data: &'a [Slot], - carried_item: &'a Slot + carried_item: &'a Slot, } - impl<'a> CSetContainerContent<'a> { - pub fn new(window_id: u8,state_id: VarInt, slots: &'a [Slot], carried_item: &'a Slot) -> Self { + pub fn new(window_id: u8, state_id: VarInt, slots: &'a [Slot], carried_item: &'a Slot) -> Self { Self { window_id, state_id, count: slots.len().try_into().unwrap(), slot_data: slots, - carried_item + carried_item, } } } diff --git a/pumpkin-protocol/src/client/play/mod.rs b/pumpkin-protocol/src/client/play/mod.rs index 6437e23a5..df63734c9 100644 --- a/pumpkin-protocol/src/client/play/mod.rs +++ b/pumpkin-protocol/src/client/play/mod.rs @@ -22,6 +22,7 @@ mod c_player_chat_message; mod c_player_info_update; mod c_player_remove; mod c_remove_entities; +mod c_set_container_content; mod c_set_held_item; mod c_set_title; mod c_spawn_player; @@ -33,7 +34,6 @@ mod c_update_entity_pos; mod c_update_entity_rot; mod c_worldevent; mod player_action; -mod c_set_container_content; pub use c_acknowledge_block::*; pub use c_actionbar::*; @@ -59,6 +59,7 @@ pub use c_player_chat_message::*; pub use c_player_info_update::*; pub use c_player_remove::*; pub use c_remove_entities::*; +pub use c_set_container_content::*; pub use c_set_held_item::*; pub use c_set_title::*; pub use c_spawn_player::*; @@ -70,4 +71,3 @@ pub use c_update_entity_pos::*; pub use c_update_entity_rot::*; pub use c_worldevent::*; pub use player_action::*; -pub use c_set_container_content::*; \ No newline at end of file diff --git a/pumpkin-protocol/src/slot.rs b/pumpkin-protocol/src/slot.rs index 51521a960..4f18a23da 100644 --- a/pumpkin-protocol/src/slot.rs +++ b/pumpkin-protocol/src/slot.rs @@ -1,7 +1,10 @@ use crate::VarInt; use pumpkin_world::item::Item; -use serde::{de::{self, SeqAccess, Visitor}, Deserialize, Serialize, Serializer}; use serde::ser::SerializeSeq; +use serde::{ + de::{self, SeqAccess, Visitor}, + Deserialize, Serialize, Serializer, +}; #[derive(Debug, Clone)] #[allow(dead_code)] @@ -84,8 +87,8 @@ impl Serialize for Slot { s.serialize_element(&self.item_count)?; s.end() } else { - match (&self.num_components_to_add,&self.num_components_to_remove) { - (Some(to_add),Some(to_remove)) => { + match (&self.num_components_to_add, &self.num_components_to_remove) { + (Some(to_add), Some(to_remove)) => { let mut s = serializer.serialize_seq(Some(6))?; s.serialize_element(&self.item_count)?; s.serialize_element(self.item_id.as_ref().unwrap())?; @@ -104,7 +107,7 @@ impl Serialize for Slot { s.serialize_element(self.components_to_remove.as_ref().unwrap())?; s.end() } - (Some(to_add),None) => { + (Some(to_add), None) => { let mut s = serializer.serialize_seq(Some(5))?; s.serialize_element(&self.item_count)?; s.serialize_element(self.item_id.as_ref().unwrap())?; @@ -113,7 +116,7 @@ impl Serialize for Slot { s.serialize_element(self.components_to_add.as_ref().unwrap())?; s.end() } - (None,None) => { + (None, None) => { let mut s = serializer.serialize_seq(Some(4))?; s.serialize_element(&self.item_count)?; s.serialize_element(&self.item_id.as_ref().unwrap())?; @@ -122,7 +125,6 @@ impl Serialize for Slot { s.end() } } - } } } @@ -154,10 +156,10 @@ impl From<&Item> for Slot { item_count: item.item_count.into(), item_id: Some(item.item_id.into()), // TODO: add these - num_components_to_add:None, + num_components_to_add: None, num_components_to_remove: None, components_to_add: None, components_to_remove: None, } } -} \ No newline at end of file +} diff --git a/pumpkin/src/client/mod.rs b/pumpkin/src/client/mod.rs index bc7d598ff..4497f1128 100644 --- a/pumpkin/src/client/mod.rs +++ b/pumpkin/src/client/mod.rs @@ -18,7 +18,10 @@ use pumpkin_protocol::{ client::{ config::CConfigDisconnect, login::CLoginDisconnect, - play::{CGameEvent, CPlayDisconnect, CSyncPlayerPostion, CSystemChatMessge, CSetContainerContent}, + play::{ + CGameEvent, CPlayDisconnect, CSetContainerContent, CSyncPlayerPostion, + CSystemChatMessge, + }, }, packet_decoder::PacketDecoder, packet_encoder::PacketEncoder, @@ -38,13 +41,13 @@ use pumpkin_protocol::{ }; use pumpkin_text::TextComponent; -use std::io::Read; -use thiserror::Error; use pumpkin_inventory::WindowType; use pumpkin_protocol::bytebuf::ByteBuffer; use pumpkin_protocol::client::play::COpenScreen; use pumpkin_protocol::slot::Slot; use pumpkin_world::item::Item; +use std::io::Read; +use thiserror::Error; pub mod authentication; mod client_packet; @@ -179,30 +182,58 @@ impl Client { player.gamemode = gamemode; self.send_packet(&CGameEvent::new(3, gamemode.to_f32().unwrap())); } - - pub fn open_container(&mut self, window_type: WindowType, minecraft_menu_id: &str,window_title: Option<&str>, items: Option>>, carried_item: Option<&Item>) { - let menu_protocol_id = (*pumpkin_world::global_registry::REGISTRY.get("minecraft:menu").unwrap().entries.get(minecraft_menu_id).expect("Should be a valid menu id").get("protocol_id").unwrap()).into(); + + pub fn open_container( + &mut self, + window_type: WindowType, + minecraft_menu_id: &str, + window_title: Option<&str>, + items: Option>>, + carried_item: Option<&Item>, + ) { + let menu_protocol_id = (*pumpkin_world::global_registry::REGISTRY + .get("minecraft:menu") + .unwrap() + .entries + .get(minecraft_menu_id) + .expect("Should be a valid menu id") + .get("protocol_id") + .unwrap()) + .into(); let title = TextComponent::text(window_title.unwrap_or(window_type.default_title())); - self.send_packet(&COpenScreen::new((window_type.clone() as u8 +1).into(),menu_protocol_id, title)); + self.send_packet(&COpenScreen::new( + (window_type.clone() as u8 + 1).into(), + menu_protocol_id, + title, + )); self.set_container_content(window_type, items, carried_item); } - - pub fn set_container_content<'a>(&mut self, window_type: WindowType, items: Option>>, carried_item: Option<&'a Item>) { + + pub fn set_container_content<'a>( + &mut self, + window_type: WindowType, + items: Option>>, + carried_item: Option<&'a Item>, + ) { let player = self.player.as_ref().unwrap(); - - let slots: Vec = {if let Some(mut items) = items { - items.extend(player.inventory.slots()); - items - } else { - player.inventory.slots() - }.into_iter() - .map(|item|{ + + let slots: Vec = { + if let Some(mut items) = items { + items.extend(player.inventory.slots()); + items + } else { + player.inventory.slots() + } + .into_iter() + .map(|item| { if let Some(item) = item { Slot::from(item) } else { Slot::empty() } - }).collect()}; + }) + .collect() + }; let carried_item = { if let Some(item) = carried_item { @@ -211,7 +242,12 @@ impl Client { Slot::empty() } }; - self.send_packet(&CSetContainerContent::new(window_type as u8+1, 0.into(), &slots, &carried_item)); + self.send_packet(&CSetContainerContent::new( + window_type as u8 + 1, + 0.into(), + &slots, + &carried_item, + )); } pub async fn process_packets(&mut self, server: &mut Server) { @@ -398,7 +434,7 @@ impl Client { } } } - + pub fn send_system_message(&mut self, text: TextComponent) { self.send_packet(&CSystemChatMessge::new(text, false)); } From 7818f83ea2af73b0aeef52e45f4acd26b5a9032c Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Wed, 21 Aug 2024 19:38:19 +0200 Subject: [PATCH 09/38] fix lints --- pumpkin-inventory/src/lib.rs | 6 ++++-- pumpkin-protocol/src/client/play/c_set_container_content.rs | 2 +- pumpkin-protocol/src/slot.rs | 3 +-- pumpkin/src/client/mod.rs | 1 - 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pumpkin-inventory/src/lib.rs b/pumpkin-inventory/src/lib.rs index 691c69370..044980cc4 100644 --- a/pumpkin-inventory/src/lib.rs +++ b/pumpkin-inventory/src/lib.rs @@ -44,8 +44,10 @@ pub enum WindowType { impl WindowType { pub const fn default_title(&self) -> &'static str { - match self { + // TODO: Add titles here: + /*match self { _ => "WINDOW TITLE", - } + }*/ + "WINDOW TITLE" } } diff --git a/pumpkin-protocol/src/client/play/c_set_container_content.rs b/pumpkin-protocol/src/client/play/c_set_container_content.rs index 919bc44d3..791ee1db5 100644 --- a/pumpkin-protocol/src/client/play/c_set_container_content.rs +++ b/pumpkin-protocol/src/client/play/c_set_container_content.rs @@ -18,7 +18,7 @@ impl<'a> CSetContainerContent<'a> { Self { window_id, state_id, - count: slots.len().try_into().unwrap(), + count: slots.len().into(), slot_data: slots, carried_item, } diff --git a/pumpkin-protocol/src/slot.rs b/pumpkin-protocol/src/slot.rs index 114e1e77a..053813fc7 100644 --- a/pumpkin-protocol/src/slot.rs +++ b/pumpkin-protocol/src/slot.rs @@ -2,7 +2,7 @@ use crate::VarInt; use pumpkin_world::item::Item; use serde::ser::SerializeSeq; use serde::{ - de::{self, SeqAccess, Visitor}, + de::{self, SeqAccess}, Deserialize, Serialize, Serializer, }; @@ -129,7 +129,6 @@ impl Serialize for Slot { } } - impl Slot { pub fn to_item(self) -> Option { let item_id = self.item_id?.0.try_into().unwrap(); diff --git a/pumpkin/src/client/mod.rs b/pumpkin/src/client/mod.rs index a8b9ade7c..0e1083a3e 100644 --- a/pumpkin/src/client/mod.rs +++ b/pumpkin/src/client/mod.rs @@ -42,7 +42,6 @@ use pumpkin_protocol::{ }; use pumpkin_inventory::WindowType; -use pumpkin_protocol::bytebuf::ByteBuffer; use pumpkin_protocol::client::play::COpenScreen; use pumpkin_protocol::slot::Slot; use pumpkin_world::item::Item; From 1fd3595ecce654a9d2b13c2c95081cc6d19d8ce9 Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Wed, 21 Aug 2024 19:41:33 +0200 Subject: [PATCH 10/38] whoops --- pumpkin/src/commands/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pumpkin/src/commands/mod.rs b/pumpkin/src/commands/mod.rs index 6e34b4eb0..d784122c1 100644 --- a/pumpkin/src/commands/mod.rs +++ b/pumpkin/src/commands/mod.rs @@ -79,6 +79,8 @@ fn dispatcher_init<'a>() -> CommandDispatcher<'a> { dispatcher.register(cmd_gamemode::init_command_tree()); dispatcher.register(cmd_stop::init_command_tree()); dispatcher.register(cmd_help::init_command_tree()); + + dispatcher } pub fn handle_command(sender: &mut CommandSender, cmd: &str) { From d80bbb725665b681ddaca749fa936a48514adb9c Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Wed, 21 Aug 2024 19:41:48 +0200 Subject: [PATCH 11/38] fmt --- pumpkin/src/commands/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pumpkin/src/commands/mod.rs b/pumpkin/src/commands/mod.rs index d784122c1..d6b2f4bde 100644 --- a/pumpkin/src/commands/mod.rs +++ b/pumpkin/src/commands/mod.rs @@ -79,7 +79,7 @@ fn dispatcher_init<'a>() -> CommandDispatcher<'a> { dispatcher.register(cmd_gamemode::init_command_tree()); dispatcher.register(cmd_stop::init_command_tree()); dispatcher.register(cmd_help::init_command_tree()); - + dispatcher } From 3bbe19f4d4392b60d1c8910609191c1088a1b07a Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Wed, 21 Aug 2024 20:05:50 +0200 Subject: [PATCH 12/38] make sure the players gamemode is creative when client sends SSetCreativeSlot --- pumpkin/src/client/player_packet.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index b8a7853d7..097e22f9c 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -400,6 +400,10 @@ impl Client { } pub fn handle_set_creative_slot(&mut self, _server: &mut Server, packet: SSetCreativeSlot) { + let gamemode = self.player.as_ref().unwrap().gamemode; + if gamemode != GameMode::Creative { + self.kick("CHEATER") + } let inventory = &mut self.player.as_mut().unwrap().inventory; inventory.set_slot(packet.slot as usize, packet.clicked_item.to_item(), false); From dda2958e2af15911d49bc77aff047a0e6b0f555a Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Wed, 21 Aug 2024 20:19:18 +0200 Subject: [PATCH 13/38] fix kick message --- pumpkin/src/client/player_packet.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index 097e22f9c..d2f855b0c 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -402,7 +402,7 @@ impl Client { pub fn handle_set_creative_slot(&mut self, _server: &mut Server, packet: SSetCreativeSlot) { let gamemode = self.player.as_ref().unwrap().gamemode; if gamemode != GameMode::Creative { - self.kick("CHEATER") + self.kick("Invalid action, you can only do that if you are in creative") } let inventory = &mut self.player.as_mut().unwrap().inventory; From e34fc4733208e80dae0b3f6bd38d9a95350444fb Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Wed, 21 Aug 2024 20:43:09 +0200 Subject: [PATCH 14/38] refactor out double call to self.player --- pumpkin/src/client/player_packet.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index d2f855b0c..2457f1a62 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -400,11 +400,12 @@ impl Client { } pub fn handle_set_creative_slot(&mut self, _server: &mut Server, packet: SSetCreativeSlot) { - let gamemode = self.player.as_ref().unwrap().gamemode; - if gamemode != GameMode::Creative { - self.kick("Invalid action, you can only do that if you are in creative") + let player = self.player.as_mut().unwrap(); + if player.gamemode != GameMode::Creative { + self.kick("Invalid action, you can only do that if you are in creative"); + return; } - let inventory = &mut self.player.as_mut().unwrap().inventory; + let inventory = &mut player.inventory; inventory.set_slot(packet.slot as usize, packet.clicked_item.to_item(), false); } From 13206d58d9816a6a43b8936256e33b2cc45acccc Mon Sep 17 00:00:00 2001 From: Alexander Medvedev <71594357+Snowiiii@users.noreply.github.com> Date: Wed, 21 Aug 2024 20:08:14 +0100 Subject: [PATCH 15/38] Add Console Colors & Styles --- Cargo.lock | 1 + pumpkin-core/Cargo.toml | 1 + .../src/text/{_README.md => README.md} | 0 pumpkin-core/src/text/color.rs | 27 ++++++++++++++++ pumpkin-core/src/text/mod.rs | 31 +++++++++++++++++++ pumpkin/src/commands/mod.rs | 2 +- pumpkin/src/main.rs | 4 ++- 7 files changed, 64 insertions(+), 2 deletions(-) rename pumpkin-core/src/text/{_README.md => README.md} (100%) diff --git a/Cargo.lock b/Cargo.lock index 28e90afa5..1bb3825f5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1229,6 +1229,7 @@ dependencies = [ name = "pumpkin-core" version = "0.1.0" dependencies = [ + "colored", "fastnbt", "serde", "uuid", diff --git a/pumpkin-core/Cargo.toml b/pumpkin-core/Cargo.toml index 34ad5239d..a77ec0311 100644 --- a/pumpkin-core/Cargo.toml +++ b/pumpkin-core/Cargo.toml @@ -7,3 +7,4 @@ edition.workspace = true serde = { version = "1.0", features = ["derive"] } fastnbt = { git = "https://github.com/owengage/fastnbt.git" } uuid.workspace = true +colored = "2" \ No newline at end of file diff --git a/pumpkin-core/src/text/_README.md b/pumpkin-core/src/text/README.md similarity index 100% rename from pumpkin-core/src/text/_README.md rename to pumpkin-core/src/text/README.md diff --git a/pumpkin-core/src/text/color.rs b/pumpkin-core/src/text/color.rs index 6fa25219b..94d83f5bf 100644 --- a/pumpkin-core/src/text/color.rs +++ b/pumpkin-core/src/text/color.rs @@ -1,3 +1,4 @@ +use colored::{ColoredString, Colorize}; use serde::{Deserialize, Serialize}; /// Text color @@ -13,6 +14,32 @@ pub enum Color { Named(NamedColor), } +impl Color { + pub fn console_color(&self, text: &str) -> ColoredString { + match self { + Color::Reset => text.clear(), + Color::Named(color) => match color { + NamedColor::Black => text.black(), + NamedColor::DarkBlue => text.blue(), + NamedColor::DarkGreen => text.green(), + NamedColor::DarkAqua => text.cyan(), + NamedColor::DarkRed => text.red(), + NamedColor::DarkPurple => text.purple(), + NamedColor::Gold => text.yellow(), + NamedColor::Gray => text.bright_black(), + NamedColor::DarkGray => text.bright_black(), // ? + NamedColor::Blue => text.bright_blue(), + NamedColor::Green => text.bright_green(), + NamedColor::Aqua => text.cyan(), + NamedColor::Red => text.red(), + NamedColor::LightPurple => text.bright_purple(), + NamedColor::Yellow => text.bright_yellow(), + NamedColor::White => text.white(), + }, + } + } +} + /// Named Minecraft color #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] diff --git a/pumpkin-core/src/text/mod.rs b/pumpkin-core/src/text/mod.rs index 9bd4499d2..706c034ea 100644 --- a/pumpkin-core/src/text/mod.rs +++ b/pumpkin-core/src/text/mod.rs @@ -3,6 +3,7 @@ use std::borrow::Cow; use click::ClickEvent; use color::Color; +use colored::Colorize; use fastnbt::SerOpts; use hover::HoverEvent; use serde::{Deserialize, Serialize}; @@ -38,6 +39,36 @@ impl<'a> TextComponent<'a> { style: Style::default(), } } + + pub fn to_pretty_console(self) -> String { + let style = self.style; + let color = style.color; + let mut text = match self.content { + TextContent::Text { text } => text.into_owned(), + TextContent::Translate { translate, with: _ } => translate.into_owned(), + TextContent::EntityNames { + selector, + separator: _, + } => selector.into_owned(), + TextContent::Keybind { keybind } => keybind.into_owned(), + }; + if let Some(color) = color { + text = color.console_color(&text).to_string(); + } + if style.bold.is_some() { + text = text.bold().to_string(); + } + if style.italic.is_some() { + text = text.italic().to_string(); + } + if style.underlined.is_some() { + text = text.underline().to_string(); + } + if style.strikethrough.is_some() { + text = text.strikethrough().to_string(); + } + text + } } impl<'a> serde::Serialize for TextComponent<'a> { diff --git a/pumpkin/src/commands/mod.rs b/pumpkin/src/commands/mod.rs index d6b2f4bde..8eea87a11 100644 --- a/pumpkin/src/commands/mod.rs +++ b/pumpkin/src/commands/mod.rs @@ -24,7 +24,7 @@ impl<'a> CommandSender<'a> { pub fn send_message(&mut self, text: TextComponent) { match self { // TODO: add color and stuff to console - CommandSender::Console => log::info!("{:?}", text.content), + CommandSender::Console => log::info!("{}", text.to_pretty_console()), CommandSender::Player(c) => c.send_system_message(text), CommandSender::Rcon(s) => s.push(format!("{:?}", text.content)), } diff --git a/pumpkin/src/main.rs b/pumpkin/src/main.rs index e4db13870..69f839c91 100644 --- a/pumpkin/src/main.rs +++ b/pumpkin/src/main.rs @@ -94,7 +94,9 @@ fn main() -> io::Result<()> { stdin .read_line(&mut out) .expect("Failed to read console line"); - handle_command(&mut commands::CommandSender::Console, &out); + if !out.is_empty() { + handle_command(&mut commands::CommandSender::Console, &out); + } } }); } From caa6a7088b0fa17dbb2525b7574989d203f6f72b Mon Sep 17 00:00:00 2001 From: Alexander Medvedev <71594357+Snowiiii@users.noreply.github.com> Date: Wed, 21 Aug 2024 20:12:14 +0100 Subject: [PATCH 16/38] Also pretty commands for RCON --- pumpkin/src/commands/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pumpkin/src/commands/mod.rs b/pumpkin/src/commands/mod.rs index 8eea87a11..3a06cfdab 100644 --- a/pumpkin/src/commands/mod.rs +++ b/pumpkin/src/commands/mod.rs @@ -26,7 +26,7 @@ impl<'a> CommandSender<'a> { // TODO: add color and stuff to console CommandSender::Console => log::info!("{}", text.to_pretty_console()), CommandSender::Player(c) => c.send_system_message(text), - CommandSender::Rcon(s) => s.push(format!("{:?}", text.content)), + CommandSender::Rcon(s) => s.push(format!("{}", text.to_pretty_console())), } } From f920f31a81826fd6cf5b00cb93d30fa866194bda Mon Sep 17 00:00:00 2001 From: Alexander Medvedev <71594357+Snowiiii@users.noreply.github.com> Date: Wed, 21 Aug 2024 20:16:42 +0100 Subject: [PATCH 17/38] Fix: Clippy warn upsi --- pumpkin/src/commands/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pumpkin/src/commands/mod.rs b/pumpkin/src/commands/mod.rs index 3a06cfdab..7ca503fd5 100644 --- a/pumpkin/src/commands/mod.rs +++ b/pumpkin/src/commands/mod.rs @@ -26,7 +26,7 @@ impl<'a> CommandSender<'a> { // TODO: add color and stuff to console CommandSender::Console => log::info!("{}", text.to_pretty_console()), CommandSender::Player(c) => c.send_system_message(text), - CommandSender::Rcon(s) => s.push(format!("{}", text.to_pretty_console())), + CommandSender::Rcon(s) => s.push(text.to_pretty_console()), } } From cd6defe9a257e9ba4fd1bd03aa683d962c176538 Mon Sep 17 00:00:00 2001 From: kralverde Date: Wed, 21 Aug 2024 17:17:33 -0400 Subject: [PATCH 18/38] implement filtering and serialization changes --- pumpkin-protocol/src/bytebuf/serializer.rs | 25 +++++-- .../src/client/play/c_player_chat_message.rs | 74 +++---------------- pumpkin/src/client/player_packet.rs | 3 +- 3 files changed, 30 insertions(+), 72 deletions(-) diff --git a/pumpkin-protocol/src/bytebuf/serializer.rs b/pumpkin-protocol/src/bytebuf/serializer.rs index 446c87650..791002c2c 100644 --- a/pumpkin-protocol/src/bytebuf/serializer.rs +++ b/pumpkin-protocol/src/bytebuf/serializer.rs @@ -48,6 +48,14 @@ impl ser::Error for SerializerError { } } +// General notes on the serializer: +// +// Primitives are written as-is +// Strings automatically pre-pend a varint +// Enums are written as a varint of the index +// Structs are ignored +// Iterables' values are written in order, but NO information (e.g. size) about the +// iterable itself is written (list sizes should be a seperate field) impl<'a> ser::Serializer for &'a mut Serializer { type Ok = (); type Error = SerializerError; @@ -121,7 +129,8 @@ impl<'a> ser::Serializer for &'a mut Serializer { where T: ?Sized + Serialize, { - unimplemented!() + self.output.put_var_int(&_variant_index.into()); + _value.serialize(self) } fn serialize_none(self) -> Result { self.output.put_bool(false); @@ -160,7 +169,7 @@ impl<'a> ser::Serializer for &'a mut Serializer { unimplemented!() } fn serialize_tuple(self, _len: usize) -> Result { - unimplemented!() + Ok(self) } fn serialize_tuple_struct( self, @@ -176,7 +185,9 @@ impl<'a> ser::Serializer for &'a mut Serializer { _variant: &'static str, _len: usize, ) -> Result { - unimplemented!() + // Serialize ENUM index as varint + self.output.put_var_int(&_variant_index.into()); + Ok(self) } fn serialize_u128(self, _v: u128) -> Result { unimplemented!() @@ -209,7 +220,9 @@ impl<'a> ser::Serializer for &'a mut Serializer { _variant_index: u32, _variant: &'static str, ) -> Result { - todo!() + // For ENUMs, only write enum index as varint + self.output.put_var_int(&_variant_index.into()); + Ok(()) } } @@ -241,11 +254,11 @@ impl<'a> ser::SerializeTuple for &'a mut Serializer { where T: ?Sized + Serialize, { - todo!() + _value.serialize(&mut **self) } fn end(self) -> Result<(), Self::Error> { - todo!() + Ok(()) } } diff --git a/pumpkin-protocol/src/client/play/c_player_chat_message.rs b/pumpkin-protocol/src/client/play/c_player_chat_message.rs index e47e9d225..a79d0516c 100644 --- a/pumpkin-protocol/src/client/play/c_player_chat_message.rs +++ b/pumpkin-protocol/src/client/play/c_player_chat_message.rs @@ -1,11 +1,9 @@ -use num_derive::{FromPrimitive, ToPrimitive}; -use num_traits::FromPrimitive; use pumpkin_core::text::TextComponent; use pumpkin_macros::packet; use serde::Serialize; -use crate::{bytebuf::ByteBuffer, uuid::UUID, BitSet, ClientPacket, VarInt}; - +use crate::{uuid::UUID, BitSet, VarInt}; +#[derive(Serialize)] #[packet(0x39)] pub struct CPlayerChatMessage<'a> { sender: UUID, @@ -17,12 +15,7 @@ pub struct CPlayerChatMessage<'a> { previous_messages_count: VarInt, previous_messages: &'a [PreviousMessage<'a>], // max 20 unsigned_content: Option>, - /// See `FilterType` - filter_type: VarInt, - - // TODO: Implement - #[allow(dead_code)] - filter_type_bits: Option>, + filter_type: FilterType<'a>, chat_type: VarInt, sender_name: TextComponent<'a>, target_name: Option>, @@ -39,8 +32,7 @@ impl<'a> CPlayerChatMessage<'a> { salt: i64, previous_messages: &'a [PreviousMessage<'a>], unsigned_content: Option>, - filter_type: VarInt, - filter_type_bits: Option>, + filter_type: FilterType<'a>, chat_type: VarInt, sender_name: TextComponent<'a>, target_name: Option>, @@ -56,7 +48,6 @@ impl<'a> CPlayerChatMessage<'a> { previous_messages, unsigned_content, filter_type, - filter_type_bits, chat_type, sender_name, target_name, @@ -64,64 +55,19 @@ impl<'a> CPlayerChatMessage<'a> { } } -impl<'a> ClientPacket for CPlayerChatMessage<'a> { - fn write(&self, bytebuf: &mut ByteBuffer) { - bytebuf.put_uuid(self.sender.0); - bytebuf.put_var_int(&self.index); - bytebuf.put_option(&self.message_signature, |p, v| p.put_slice(v)); - bytebuf.put_string(self.message); - bytebuf.put_i64(self.timestamp); - bytebuf.put_i64(self.salt); - - if self.previous_messages_count.0 > 20 { - // TODO: Assert this is <=20 - } - - bytebuf.put_var_int(&self.previous_messages_count); - for previous_message in self.previous_messages { - bytebuf.put_var_int(&previous_message.message_id); - if let Some(prev_sig) = previous_message.signature { - // TODO: validate whether this should be None or not - bytebuf.put_slice(prev_sig); - } - } - - bytebuf.put_option(&self.unsigned_content, |p, v| { - p.put_slice(v.encode().as_slice()) - }); - - bytebuf.put_var_int(&self.filter_type); - match FilterType::from_i32(self.filter_type.0) { - Some(FilterType::PassThrough) => (), - Some(FilterType::FullyFiltered) => { - // TODO: Implement - } - Some(FilterType::PartiallyFiltered) => { - // TODO: Implement - } - None => { - // TODO: Implement - } - } - - bytebuf.put_var_int(&self.chat_type); - bytebuf.put_slice(self.sender_name.encode().as_slice()); - bytebuf.put_option(&self.target_name, |p, v| p.put_slice(v.encode().as_slice())); - } -} - #[derive(Serialize)] pub struct PreviousMessage<'a> { message_id: VarInt, signature: Option<&'a [u8]>, } -#[derive(FromPrimitive, ToPrimitive)] -pub enum FilterType { +#[derive(Serialize)] +#[repr(i32)] +pub enum FilterType<'a> { /// Message is not filtered at all - PassThrough, + PassThrough = 0, /// Message is fully filtered - FullyFiltered, + FullyFiltered = 1, /// Only some characters in the message are filtered - PartiallyFiltered, + PartiallyFiltered(BitSet<'a>) = 2, } diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index 6f7a4d9e5..34806b91c 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -233,8 +233,7 @@ impl Client { chat_message.salt, &[], Some(TextComponent::text(&message)), - pumpkin_protocol::VarInt(FilterType::PassThrough as i32), - None, + FilterType::PassThrough, 1.into(), TextComponent::text(&gameprofile.name.clone()), None, From b8d350f32d42f8702ae75bd31c5d576247fb94c5 Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Thu, 22 Aug 2024 13:20:01 +0200 Subject: [PATCH 19/38] move container logic into its own file --- pumpkin/src/client/container.rs | 71 +++++++++++++++++++++++++++++++++ pumpkin/src/client/mod.rs | 68 +------------------------------ 2 files changed, 72 insertions(+), 67 deletions(-) create mode 100644 pumpkin/src/client/container.rs diff --git a/pumpkin/src/client/container.rs b/pumpkin/src/client/container.rs new file mode 100644 index 000000000..64a371491 --- /dev/null +++ b/pumpkin/src/client/container.rs @@ -0,0 +1,71 @@ +use pumpkin_core::text::TextComponent; +use pumpkin_inventory::WindowType; +use pumpkin_protocol::client::play::{COpenScreen, CSetContainerContent}; +use pumpkin_protocol::slot::Slot; +use pumpkin_world::item::Item; + +impl super::Client { + pub fn open_container( + &mut self, + window_type: WindowType, + minecraft_menu_id: &str, + window_title: Option<&str>, + items: Option>>, + carried_item: Option<&Item>, + ) { + let menu_protocol_id = (*pumpkin_world::global_registry::REGISTRY + .get("minecraft:menu") + .unwrap() + .entries + .get(minecraft_menu_id) + .expect("Should be a valid menu id") + .get("protocol_id") + .unwrap()) + .into(); + let title = TextComponent::text(window_title.unwrap_or(window_type.default_title())); + self.send_packet(&COpenScreen::new( + (window_type.clone() as u8 + 1).into(), + menu_protocol_id, + title, + )); + self.set_container_content(window_type, items, carried_item); + } + + pub fn set_container_content<'a>( + &mut self, + window_type: WindowType, + items: Option>>, + carried_item: Option<&'a Item>, + ) { + let player = self.player.as_ref().unwrap(); + + let slots: Vec = { + if let Some(mut items) = items { + items.extend(player.inventory.slots()); + items + } else { + player.inventory.slots() + } + .into_iter() + .map(|item| { + if let Some(item) = item { + Slot::from(item) + } else { + Slot::empty() + } + }) + .collect() + }; + + let carried_item = { + if let Some(item) = carried_item { + item.into() + } else { + Slot::empty() + } + }; + let packet = + CSetContainerContent::new(window_type as u8 + 1, 0.into(), &slots, &carried_item); + self.send_packet(&packet); + } +} diff --git a/pumpkin/src/client/mod.rs b/pumpkin/src/client/mod.rs index 0e1083a3e..7c3781483 100644 --- a/pumpkin/src/client/mod.rs +++ b/pumpkin/src/client/mod.rs @@ -50,6 +50,7 @@ use thiserror::Error; pub mod authentication; mod client_packet; +mod container; pub mod player_packet; pub struct PlayerConfig { @@ -182,73 +183,6 @@ impl Client { self.send_packet(&CGameEvent::new(3, gamemode.to_f32().unwrap())); } - pub fn open_container( - &mut self, - window_type: WindowType, - minecraft_menu_id: &str, - window_title: Option<&str>, - items: Option>>, - carried_item: Option<&Item>, - ) { - let menu_protocol_id = (*pumpkin_world::global_registry::REGISTRY - .get("minecraft:menu") - .unwrap() - .entries - .get(minecraft_menu_id) - .expect("Should be a valid menu id") - .get("protocol_id") - .unwrap()) - .into(); - let title = TextComponent::text(window_title.unwrap_or(window_type.default_title())); - self.send_packet(&COpenScreen::new( - (window_type.clone() as u8 + 1).into(), - menu_protocol_id, - title, - )); - self.set_container_content(window_type, items, carried_item); - } - - pub fn set_container_content<'a>( - &mut self, - window_type: WindowType, - items: Option>>, - carried_item: Option<&'a Item>, - ) { - let player = self.player.as_ref().unwrap(); - - let slots: Vec = { - if let Some(mut items) = items { - items.extend(player.inventory.slots()); - items - } else { - player.inventory.slots() - } - .into_iter() - .map(|item| { - if let Some(item) = item { - Slot::from(item) - } else { - Slot::empty() - } - }) - .collect() - }; - - let carried_item = { - if let Some(item) = carried_item { - item.into() - } else { - Slot::empty() - } - }; - self.send_packet(&CSetContainerContent::new( - window_type as u8 + 1, - 0.into(), - &slots, - &carried_item, - )); - } - pub async fn process_packets(&mut self, server: &mut Server) { let mut i = 0; while i < self.client_packets_queue.len() { From 4c572eca2d387bbca470ccce5f5357c1a4d34725 Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Thu, 22 Aug 2024 13:24:12 +0200 Subject: [PATCH 20/38] add CSetContainerSlot packet --- .../src/client/play/c_set_container_slot.rs | 23 +++++++++++++++++++ pumpkin-protocol/src/client/play/mod.rs | 2 ++ pumpkin-protocol/src/slot.rs | 6 +++++ pumpkin/src/client/container.rs | 16 ++++++++++++- pumpkin/src/client/mod.rs | 6 +---- 5 files changed, 47 insertions(+), 6 deletions(-) create mode 100644 pumpkin-protocol/src/client/play/c_set_container_slot.rs diff --git a/pumpkin-protocol/src/client/play/c_set_container_slot.rs b/pumpkin-protocol/src/client/play/c_set_container_slot.rs new file mode 100644 index 000000000..e07d07d82 --- /dev/null +++ b/pumpkin-protocol/src/client/play/c_set_container_slot.rs @@ -0,0 +1,23 @@ +use crate::slot::Slot; +use crate::VarInt; +use pumpkin_macros::packet; +use serde::Serialize; +#[derive(Serialize)] +#[packet(0x15)] +pub struct CSetContainerSlot<'a> { + window_id: i8, + state_id: VarInt, + slot: i16, + slot_data: &'a Slot, +} + +impl<'a> CSetContainerSlot<'a> { + pub fn new(window_id: i8, state_id: i32, slot: usize, slot_data: &'a Slot) -> Self { + Self { + window_id, + state_id: state_id.into(), + slot: slot.try_into().unwrap(), + slot_data, + } + } +} diff --git a/pumpkin-protocol/src/client/play/mod.rs b/pumpkin-protocol/src/client/play/mod.rs index df63734c9..a732f2ccb 100644 --- a/pumpkin-protocol/src/client/play/mod.rs +++ b/pumpkin-protocol/src/client/play/mod.rs @@ -23,6 +23,7 @@ mod c_player_info_update; mod c_player_remove; mod c_remove_entities; mod c_set_container_content; +mod c_set_container_slot; mod c_set_held_item; mod c_set_title; mod c_spawn_player; @@ -60,6 +61,7 @@ pub use c_player_info_update::*; pub use c_player_remove::*; pub use c_remove_entities::*; pub use c_set_container_content::*; +pub use c_set_container_slot::*; pub use c_set_held_item::*; pub use c_set_title::*; pub use c_spawn_player::*; diff --git a/pumpkin-protocol/src/slot.rs b/pumpkin-protocol/src/slot.rs index 053813fc7..2ccab79b9 100644 --- a/pumpkin-protocol/src/slot.rs +++ b/pumpkin-protocol/src/slot.rs @@ -163,3 +163,9 @@ impl From<&Item> for Slot { } } } + +impl From> for Slot { + fn from(item: Option<&Item>) -> Self { + item.map(Slot::from).unwrap_or(Slot::empty()) + } +} diff --git a/pumpkin/src/client/container.rs b/pumpkin/src/client/container.rs index 64a371491..b8a242dbd 100644 --- a/pumpkin/src/client/container.rs +++ b/pumpkin/src/client/container.rs @@ -1,6 +1,6 @@ use pumpkin_core::text::TextComponent; use pumpkin_inventory::WindowType; -use pumpkin_protocol::client::play::{COpenScreen, CSetContainerContent}; +use pumpkin_protocol::client::play::{COpenScreen, CSetContainerContent, CSetContainerSlot}; use pumpkin_protocol::slot::Slot; use pumpkin_world::item::Item; @@ -68,4 +68,18 @@ impl super::Client { CSetContainerContent::new(window_type as u8 + 1, 0.into(), &slots, &carried_item); self.send_packet(&packet); } + + pub fn set_container_slot( + &mut self, + window_type: WindowType, + slot: usize, + item: Option<&Item>, + ) { + self.send_packet(&CSetContainerSlot::new( + window_type as i8, + 0, + slot, + &item.into(), + )) + } } diff --git a/pumpkin/src/client/mod.rs b/pumpkin/src/client/mod.rs index 7c3781483..c0880ef70 100644 --- a/pumpkin/src/client/mod.rs +++ b/pumpkin/src/client/mod.rs @@ -20,7 +20,7 @@ use pumpkin_protocol::{ config::CConfigDisconnect, login::CLoginDisconnect, play::{ - CGameEvent, CPlayDisconnect, CSetContainerContent, CSyncPlayerPostion, + CGameEvent, CPlayDisconnect, CSyncPlayerPostion, CSystemChatMessge, }, }, @@ -41,10 +41,6 @@ use pumpkin_protocol::{ ClientPacket, ConnectionState, PacketError, RawPacket, ServerPacket, }; -use pumpkin_inventory::WindowType; -use pumpkin_protocol::client::play::COpenScreen; -use pumpkin_protocol::slot::Slot; -use pumpkin_world::item::Item; use std::io::Read; use thiserror::Error; From 10bf3098b3c747c1584a548a82dfcc7114072642 Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Thu, 22 Aug 2024 13:29:31 +0200 Subject: [PATCH 21/38] fix formatting --- pumpkin/src/client/mod.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pumpkin/src/client/mod.rs b/pumpkin/src/client/mod.rs index c0880ef70..282f4381a 100644 --- a/pumpkin/src/client/mod.rs +++ b/pumpkin/src/client/mod.rs @@ -19,10 +19,7 @@ use pumpkin_protocol::{ client::{ config::CConfigDisconnect, login::CLoginDisconnect, - play::{ - CGameEvent, CPlayDisconnect, CSyncPlayerPostion, - CSystemChatMessge, - }, + play::{CGameEvent, CPlayDisconnect, CSyncPlayerPostion, CSystemChatMessge}, }, packet_decoder::PacketDecoder, packet_encoder::PacketEncoder, From afa68f381ce61a9cf967a4b063c252af7096dcd4 Mon Sep 17 00:00:00 2001 From: Luk-ESC Date: Wed, 21 Aug 2024 22:38:28 +0200 Subject: [PATCH 22/38] fix typo in method name --- pumpkin/src/client/player_packet.rs | 4 ++-- pumpkin/src/server.rs | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index 2457f1a62..26cc866a3 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -204,7 +204,7 @@ impl Client { }; let player = self.player.as_mut().unwrap(); let id = player.entity_id(); - server.broadcast_packet_expect( + server.broadcast_packet_except( &[&self.token], &CEntityAnimation::new(id.into(), animation as u8), ) @@ -305,7 +305,7 @@ impl Client { let packet = &CHurtAnimation::new(&entity_id, attacker_player.entity.yaw); self.send_packet(packet); client.send_packet(packet); - server.broadcast_packet_expect( + server.broadcast_packet_except( &[self.token.as_ref(), token.as_ref()], &CHurtAnimation::new(&entity_id, 10.0), ) diff --git a/pumpkin/src/server.rs b/pumpkin/src/server.rs index 38133844b..f45c525fc 100644 --- a/pumpkin/src/server.rs +++ b/pumpkin/src/server.rs @@ -141,11 +141,11 @@ impl Server { if client.is_player() { let id = client.player.as_ref().unwrap().entity_id(); let uuid = client.gameprofile.as_ref().unwrap().id; - self.broadcast_packet_expect( + self.broadcast_packet_except( &[&client.token], &CRemovePlayerInfo::new(1.into(), &[UUID(uuid)]), ); - self.broadcast_packet_expect(&[&client.token], &CRemoveEntities::new(&[id.into()])) + self.broadcast_packet_except(&[&client.token], &CRemoveEntities::new(&[id.into()])) } } @@ -241,7 +241,7 @@ impl Server { let gameprofile = client.gameprofile.as_ref().unwrap(); // spawn player for every client - self.broadcast_packet_expect( + self.broadcast_packet_except( &[&client.token], // TODO: add velo &CSpawnEntity::new( @@ -327,7 +327,8 @@ impl Server { } } - pub fn broadcast_packet_expect

(&self, from: &[&Token], packet: &P) + /// Sends a packet to all players except those specified in `from` + pub fn broadcast_packet_except

(&self, from: &[&Token], packet: &P) where P: ClientPacket, { From 6f9ce489cade5141cdc443e46df44768f7a51e64 Mon Sep 17 00:00:00 2001 From: lukas0008 Date: Thu, 22 Aug 2024 13:52:00 +0200 Subject: [PATCH 23/38] Split ci into multiple jobs --- .github/workflows/rust.yml | 56 +++++++++++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 7 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 57acdd34d..83e159714 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -8,19 +8,61 @@ env: CARGO_TERM_COLOR: always jobs: + format: + name: Rust project - latest + runs-on: ubuntu-latest + strategy: + matrix: + toolchain: + - stable + + steps: + - uses: actions/checkout@v4 + + - run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }} + + - run: cargo fmt --check + clippy: + name: Rust project - latest + runs-on: ubuntu-latest + strategy: + matrix: + toolchain: + - stable + + steps: + - uses: actions/checkout@v4 + + - run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }} + + - run: cargo clippy --all-targets --all-features --no-default-features -- -D warnings build_and_test: name: Rust project - latest runs-on: ubuntu-latest strategy: matrix: toolchain: - - stable + - stable steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v4 - - run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }} - - run: cargo build --verbose - - run: cargo test --verbose - - run: cargo clippy --all-targets --all-features --no-default-features -- -D warnings - - run: cargo fmt --check \ No newline at end of file + - run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }} + + - run: cargo build --verbose + - run: cargo test --verbose + build_release: + name: Rust project - latest + runs-on: ubuntu-latest + strategy: + matrix: + toolchain: + - stable + + steps: + - uses: actions/checkout@v4 + + - run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }} + + - run: cargo build --verbose --release + - run: cargo clippy --release --all-targets --all-features --no-default-features -- -D warnings From b27f6c245bc7025120a3df0a9976a13dde0697bc Mon Sep 17 00:00:00 2001 From: lukas0008 Date: Thu, 22 Aug 2024 13:53:36 +0200 Subject: [PATCH 24/38] Update names of jobs --- .github/workflows/rust.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 83e159714..a4d27a193 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -9,7 +9,7 @@ env: jobs: format: - name: Rust project - latest + name: Check formatting runs-on: ubuntu-latest strategy: matrix: @@ -23,7 +23,7 @@ jobs: - run: cargo fmt --check clippy: - name: Rust project - latest + name: Run lints runs-on: ubuntu-latest strategy: matrix: @@ -37,7 +37,7 @@ jobs: - run: cargo clippy --all-targets --all-features --no-default-features -- -D warnings build_and_test: - name: Rust project - latest + name: Build project and test runs-on: ubuntu-latest strategy: matrix: @@ -52,7 +52,7 @@ jobs: - run: cargo build --verbose - run: cargo test --verbose build_release: - name: Rust project - latest + name: Build project in release runs-on: ubuntu-latest strategy: matrix: From 10ed8c0472af2e20afb30de922630bdd024c55f6 Mon Sep 17 00:00:00 2001 From: lukas0008 Date: Thu, 22 Aug 2024 13:58:03 +0200 Subject: [PATCH 25/38] ci: Separate clippy and build for build release job --- .github/workflows/rust.yml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index a4d27a193..af6568d7b 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -65,4 +65,17 @@ jobs: - run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }} - run: cargo build --verbose --release - - run: cargo clippy --release --all-targets --all-features --no-default-features -- -D warnings + clippy_release: + name: Run lints in release mode + runs-on: ubuntu-latest + strategy: + matrix: + toolchain: + - stable + + steps: + - uses: actions/checkout@v4 + + - run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }} + + - run: cargo clippy --release --all-targets --all-features --no-default-features -- -D warnings \ No newline at end of file From e1a1a22047977abe9cd2640909bc41e3eadcfbfb Mon Sep 17 00:00:00 2001 From: lukas0008 Date: Thu, 22 Aug 2024 14:02:12 +0200 Subject: [PATCH 26/38] Fix clippy warnings --- pumpkin/src/server.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pumpkin/src/server.rs b/pumpkin/src/server.rs index f45c525fc..0316a34b8 100644 --- a/pumpkin/src/server.rs +++ b/pumpkin/src/server.rs @@ -17,7 +17,6 @@ use mio::{event::Event, Poll, Token}; use num_traits::ToPrimitive; use pumpkin_entity::{entity_type::EntityType, EntityId}; use pumpkin_protocol::{ - bytebuf::ByteBuffer, client::{ config::CPluginMessage, play::{ @@ -364,14 +363,15 @@ impl Server { chunk_z: 0.into(), }); - while let Some((chunk_pos, chunk_data)) = chunk_receiver.recv().await { + while let Some((_chunk_pos, chunk_data)) = chunk_receiver.recv().await { // dbg!(chunk_pos); let chunk_data = match chunk_data { Ok(d) => d, Err(_) => continue, }; #[cfg(debug_assertions)] - if chunk_pos == (0, 0) { + if _chunk_pos == (0, 0) { + use pumpkin_protocol::bytebuf::ByteBuffer; let mut test = ByteBuffer::empty(); CChunkData(&chunk_data).write(&mut test); let len = test.buf().len(); From d85e9bcbad1cb3bcb8e98008dbaaaf5084fc1875 Mon Sep 17 00:00:00 2001 From: Luk-ESC Date: Thu, 22 Aug 2024 18:40:43 +0200 Subject: [PATCH 27/38] fix set_slot armor indexing --- pumpkin-inventory/src/player.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pumpkin-inventory/src/player.rs b/pumpkin-inventory/src/player.rs index b67af9c6b..fd92220a9 100644 --- a/pumpkin-inventory/src/player.rs +++ b/pumpkin-inventory/src/player.rs @@ -51,7 +51,7 @@ impl PlayerInventory { 1..=4 => self.crafting[slot - 1] = item, 5..=8 => { match item { - None => self.armor[slot - 4] = None, + None => self.armor[slot - 5] = None, Some(item) => { // TODO: Replace asserts with error handling match slot - 5 { From 60bb30a8834bad7110f7db80d3a12850765b19b9 Mon Sep 17 00:00:00 2001 From: DaniD3v Date: Tue, 20 Aug 2024 23:04:42 +0200 Subject: [PATCH 28/38] use rustls instead of system openssl to make compilation easier --- Cargo.lock | 286 +++++++++++---------------------------------- pumpkin/Cargo.toml | 2 +- 2 files changed, 71 insertions(+), 217 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1bb3825f5..d01e7e507 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -192,9 +192,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" @@ -297,7 +297,7 @@ dependencies = [ "lazy_static", "mintex", "parking_lot", - "rustc-hash", + "rustc-hash 1.1.0", "serde", "serde_json", "thousands", @@ -331,31 +331,12 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" -[[package]] -name = "encoding_rs" -version = "0.8.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" -dependencies = [ - "cfg-if", -] - [[package]] name = "equivalent" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" -[[package]] -name = "errno" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - [[package]] name = "fastnbt" version = "2.5.0" @@ -367,12 +348,6 @@ dependencies = [ "serde_bytes", ] -[[package]] -name = "fastrand" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" - [[package]] name = "fastsnbt" version = "0.2.0" @@ -411,21 +386,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - [[package]] name = "form_urlencoded" version = "1.2.1" @@ -675,22 +635,7 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", -] - -[[package]] -name = "hyper-tls" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" -dependencies = [ - "bytes", - "http-body-util", - "hyper", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", + "webpki-roots", ] [[package]] @@ -805,12 +750,6 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" -[[package]] -name = "linux-raw-sys" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" - [[package]] name = "lock_api" version = "0.4.12" @@ -884,23 +823,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "native-tls" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - [[package]] name = "nom" version = "7.1.3" @@ -1009,50 +931,6 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" -[[package]] -name = "openssl" -version = "0.10.66" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" -dependencies = [ - "bitflags 2.6.0", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.103" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "parking_lot" version = "0.12.3" @@ -1144,12 +1022,6 @@ dependencies = [ "spki", ] -[[package]] -name = "pkg-config" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" - [[package]] name = "png" version = "0.17.13" @@ -1314,6 +1186,54 @@ dependencies = [ "tokio", ] +[[package]] +name = "quinn" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b22d8e7369034b9a7132bc2008cac12f2013c8132b45e0554e6e20e2617f2156" +dependencies = [ + "bytes", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash 2.0.0", + "rustls", + "socket2", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "quinn-proto" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba92fb39ec7ad06ca2582c0ca834dfeadcaf06ddfc8e635c80aa7e1c05315fdd" +dependencies = [ + "bytes", + "rand", + "ring", + "rustc-hash 2.0.0", + "rustls", + "slab", + "thiserror", + "tinyvec", + "tracing", +] + +[[package]] +name = "quinn-udp" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bffec3605b73c6f1754535084a85229fa8a30f86014e6c81aeec4abb68b0285" +dependencies = [ + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.52.0", +] + [[package]] name = "quote" version = "1.0.36" @@ -1390,7 +1310,6 @@ checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" dependencies = [ "base64", "bytes", - "encoding_rs", "futures-core", "futures-util", "h2", @@ -1399,29 +1318,31 @@ dependencies = [ "http-body-util", "hyper", "hyper-rustls", - "hyper-tls", "hyper-util", "ipnet", "js-sys", "log", "mime", - "native-tls", "once_cell", "percent-encoding", "pin-project-lite", + "quinn", + "rustls", "rustls-pemfile", + "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper", "system-configuration", "tokio", - "tokio-native-tls", + "tokio-rustls", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", + "webpki-roots", "winreg", ] @@ -1482,17 +1403,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] -name = "rustix" -version = "0.38.34" +name = "rustc-hash" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" -dependencies = [ - "bitflags 2.6.0", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.52.0", -] +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" [[package]] name = "rustls" @@ -1501,6 +1415,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" dependencies = [ "once_cell", + "ring", "rustls-pki-types", "rustls-webpki", "subtle", @@ -1540,44 +1455,12 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" -[[package]] -name = "schannel" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" -dependencies = [ - "windows-sys 0.52.0", -] - [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "security-framework" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" -dependencies = [ - "bitflags 2.6.0", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "serde" version = "1.0.205" @@ -1793,19 +1676,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" -[[package]] -name = "tempfile" -version = "3.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" -dependencies = [ - "cfg-if", - "fastrand", - "once_cell", - "rustix", - "windows-sys 0.59.0", -] - [[package]] name = "thiserror" version = "1.0.63" @@ -1907,16 +1777,6 @@ dependencies = [ "syn", ] -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - [[package]] name = "tokio-rustls" version = "0.26.0" @@ -2081,12 +1941,6 @@ dependencies = [ "serde", ] -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - [[package]] name = "version_check" version = "0.9.5" @@ -2184,6 +2038,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-roots" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -2202,15 +2065,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-targets" version = "0.48.5" diff --git a/pumpkin/Cargo.toml b/pumpkin/Cargo.toml index c6d12a44c..97b0b3a4a 100644 --- a/pumpkin/Cargo.toml +++ b/pumpkin/Cargo.toml @@ -38,7 +38,7 @@ rsa = "0.9.6" rsa-der = "0.3.0" # authentication -reqwest = { version = "0.12.5", features = ["json"]} +reqwest = { version = "0.12.5", default-features=false, features = ["json", "rustls-tls", "http2", "macos-system-configuration"]} sha1 = "0.10.6" digest = "=0.11.0-pre.9" From c07ea947fc6c8bbe4897874cbe488c77c524db51 Mon Sep 17 00:00:00 2001 From: kralverde Date: Thu, 22 Aug 2024 15:24:58 -0400 Subject: [PATCH 29/38] remove _ from used values --- pumpkin-protocol/src/bytebuf/serializer.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pumpkin-protocol/src/bytebuf/serializer.rs b/pumpkin-protocol/src/bytebuf/serializer.rs index 791002c2c..825288c2a 100644 --- a/pumpkin-protocol/src/bytebuf/serializer.rs +++ b/pumpkin-protocol/src/bytebuf/serializer.rs @@ -122,15 +122,15 @@ impl<'a> ser::Serializer for &'a mut Serializer { fn serialize_newtype_variant( self, _name: &'static str, - _variant_index: u32, + variant_index: u32, _variant: &'static str, - _value: &T, + value: &T, ) -> Result where T: ?Sized + Serialize, { - self.output.put_var_int(&_variant_index.into()); - _value.serialize(self) + self.output.put_var_int(&variant_index.into()); + value.serialize(self) } fn serialize_none(self) -> Result { self.output.put_bool(false); @@ -181,12 +181,12 @@ impl<'a> ser::Serializer for &'a mut Serializer { fn serialize_tuple_variant( self, _name: &'static str, - _variant_index: u32, + variant_index: u32, _variant: &'static str, _len: usize, ) -> Result { // Serialize ENUM index as varint - self.output.put_var_int(&_variant_index.into()); + self.output.put_var_int(&variant_index.into()); Ok(self) } fn serialize_u128(self, _v: u128) -> Result { @@ -217,11 +217,11 @@ impl<'a> ser::Serializer for &'a mut Serializer { fn serialize_unit_variant( self, _name: &'static str, - _variant_index: u32, + variant_index: u32, _variant: &'static str, ) -> Result { // For ENUMs, only write enum index as varint - self.output.put_var_int(&_variant_index.into()); + self.output.put_var_int(&variant_index.into()); Ok(()) } } @@ -250,11 +250,11 @@ impl<'a> ser::SerializeTuple for &'a mut Serializer { type Ok = (); type Error = SerializerError; - fn serialize_element(&mut self, _value: &T) -> Result<(), Self::Error> + fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> where T: ?Sized + Serialize, { - _value.serialize(&mut **self) + value.serialize(&mut **self) } fn end(self) -> Result<(), Self::Error> { From 88ebd25e9b143a5863bba947e018f6448d20eb21 Mon Sep 17 00:00:00 2001 From: kralverde Date: Thu, 22 Aug 2024 18:21:52 -0400 Subject: [PATCH 30/38] implement the unload chunk packet --- .../src/client/play/c_unload_chunk.rs | 15 +++++++++++++++ pumpkin-protocol/src/client/play/mod.rs | 2 ++ 2 files changed, 17 insertions(+) create mode 100644 pumpkin-protocol/src/client/play/c_unload_chunk.rs diff --git a/pumpkin-protocol/src/client/play/c_unload_chunk.rs b/pumpkin-protocol/src/client/play/c_unload_chunk.rs new file mode 100644 index 000000000..09294b9b0 --- /dev/null +++ b/pumpkin-protocol/src/client/play/c_unload_chunk.rs @@ -0,0 +1,15 @@ +use pumpkin_macros::packet; +use serde::Serialize; + +#[derive(Serialize)] +#[packet(0x21)] +pub struct CUnloadChunk { + z: i32, + x: i32, +} + +impl CUnloadChunk { + pub fn new(x: i32, z: i32) -> Self { + Self { z, x } + } +} diff --git a/pumpkin-protocol/src/client/play/mod.rs b/pumpkin-protocol/src/client/play/mod.rs index a732f2ccb..2e15aa978 100644 --- a/pumpkin-protocol/src/client/play/mod.rs +++ b/pumpkin-protocol/src/client/play/mod.rs @@ -30,6 +30,7 @@ mod c_spawn_player; mod c_subtitle; mod c_sync_player_position; mod c_system_chat_message; +mod c_unload_chunk; mod c_update_entitiy_pos_rot; mod c_update_entity_pos; mod c_update_entity_rot; @@ -68,6 +69,7 @@ pub use c_spawn_player::*; pub use c_subtitle::*; pub use c_sync_player_position::*; pub use c_system_chat_message::*; +pub use c_unload_chunk::*; pub use c_update_entitiy_pos_rot::*; pub use c_update_entity_pos::*; pub use c_update_entity_rot::*; From ebb5727bbd493141f68047f467147ca1601dd0ff Mon Sep 17 00:00:00 2001 From: we sell insurance Date: Thu, 22 Aug 2024 19:39:36 -0500 Subject: [PATCH 31/38] Change to print hex packet id instead of decimal for umimplemented packets --- pumpkin/src/client/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pumpkin/src/client/mod.rs b/pumpkin/src/client/mod.rs index 837976873..ec824cf39 100644 --- a/pumpkin/src/client/mod.rs +++ b/pumpkin/src/client/mod.rs @@ -311,7 +311,7 @@ impl Client { SPlayPingRequest::PACKET_ID => { self.handle_play_ping_request(server, SPlayPingRequest::read(bytebuf).unwrap()) } - _ => log::error!("Failed to handle player packet id {}", packet.id.0), + _ => log::error!("Failed to handle player packet id {:#04x}", packet.id.0), } } From 51da48d937a7b63a98748bb58fd533e350259c87 Mon Sep 17 00:00:00 2001 From: StripedMonkey Date: Tue, 20 Aug 2024 19:52:04 -0400 Subject: [PATCH 32/38] hourse -> Horse --- pumpkin-protocol/src/server/play/s_player_command.rs | 4 ++-- pumpkin/src/client/player_packet.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pumpkin-protocol/src/server/play/s_player_command.rs b/pumpkin-protocol/src/server/play/s_player_command.rs index 235baa6d5..9399e25ce 100644 --- a/pumpkin-protocol/src/server/play/s_player_command.rs +++ b/pumpkin-protocol/src/server/play/s_player_command.rs @@ -16,8 +16,8 @@ pub enum Action { LeaveBed, StartSprinting, StopSprinting, - StartHourseJump, - StopHourseJump, + StartHorseJump, + StopHorseJump, OpenVehicleInventory, StartFlyingElytra, } diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index 52d1defad..8e82c8935 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -187,8 +187,8 @@ impl Client { pumpkin_protocol::server::play::Action::LeaveBed => todo!(), pumpkin_protocol::server::play::Action::StartSprinting => player.sprinting = true, pumpkin_protocol::server::play::Action::StopSprinting => player.sprinting = false, - pumpkin_protocol::server::play::Action::StartHourseJump => todo!(), - pumpkin_protocol::server::play::Action::StopHourseJump => todo!(), + pumpkin_protocol::server::play::Action::StartHorseJump => todo!(), + pumpkin_protocol::server::play::Action::StopHorseJump => todo!(), pumpkin_protocol::server::play::Action::OpenVehicleInventory => todo!(), pumpkin_protocol::server::play::Action::StartFlyingElytra => {} // TODO } From 849438832477db2254d88bf5f9e6561d98e7e378 Mon Sep 17 00:00:00 2001 From: StripedMonkey Date: Tue, 20 Aug 2024 19:56:17 -0400 Subject: [PATCH 33/38] entitiy -> entity --- pumpkin-protocol/src/client/play/c_entity_velocity.rs | 6 +++--- pumpkin-protocol/src/client/play/c_hurt_animation.rs | 6 +++--- pumpkin-protocol/src/client/play/c_remove_entities.rs | 8 ++++---- ...date_entitiy_pos_rot.rs => c_update_entity_pos_rot.rs} | 0 pumpkin-protocol/src/client/play/mod.rs | 3 +-- pumpkin-protocol/src/server/play/s_player_command.rs | 4 ++-- pumpkin/src/client/player_packet.rs | 4 ++-- 7 files changed, 15 insertions(+), 16 deletions(-) rename pumpkin-protocol/src/client/play/{c_update_entitiy_pos_rot.rs => c_update_entity_pos_rot.rs} (100%) diff --git a/pumpkin-protocol/src/client/play/c_entity_velocity.rs b/pumpkin-protocol/src/client/play/c_entity_velocity.rs index 842fc1cda..fcfdccd59 100644 --- a/pumpkin-protocol/src/client/play/c_entity_velocity.rs +++ b/pumpkin-protocol/src/client/play/c_entity_velocity.rs @@ -6,16 +6,16 @@ use crate::VarInt; #[derive(Serialize)] #[packet(0x5A)] pub struct CEntityVelocity<'a> { - entitiy_id: &'a VarInt, + entity_id: &'a VarInt, velocity_x: i16, velocity_y: i16, velocity_z: i16, } impl<'a> CEntityVelocity<'a> { - pub fn new(entitiy_id: &'a VarInt, velocity_x: f32, velocity_y: f32, velocity_z: f32) -> Self { + pub fn new(entity_id: &'a VarInt, velocity_x: f32, velocity_y: f32, velocity_z: f32) -> Self { Self { - entitiy_id, + entity_id, velocity_x: (velocity_x.clamp(-3.9, 3.9) * 8000.0) as i16, velocity_y: (velocity_y.clamp(-3.9, 3.9) * 8000.0) as i16, velocity_z: (velocity_z.clamp(-3.9, 3.9) * 8000.0) as i16, diff --git a/pumpkin-protocol/src/client/play/c_hurt_animation.rs b/pumpkin-protocol/src/client/play/c_hurt_animation.rs index 6166acbd3..2b1b04d8f 100644 --- a/pumpkin-protocol/src/client/play/c_hurt_animation.rs +++ b/pumpkin-protocol/src/client/play/c_hurt_animation.rs @@ -6,12 +6,12 @@ use crate::VarInt; #[derive(Serialize)] #[packet(0x24)] pub struct CHurtAnimation<'a> { - entitiy_id: &'a VarInt, + entity_id: &'a VarInt, yaw: f32, } impl<'a> CHurtAnimation<'a> { - pub fn new(entitiy_id: &'a VarInt, yaw: f32) -> Self { - Self { entitiy_id, yaw } + pub fn new(entity_id: &'a VarInt, yaw: f32) -> Self { + Self { entity_id, yaw } } } diff --git a/pumpkin-protocol/src/client/play/c_remove_entities.rs b/pumpkin-protocol/src/client/play/c_remove_entities.rs index 9e89ec260..1b16ad92e 100644 --- a/pumpkin-protocol/src/client/play/c_remove_entities.rs +++ b/pumpkin-protocol/src/client/play/c_remove_entities.rs @@ -7,14 +7,14 @@ use crate::VarInt; #[packet(0x42)] pub struct CRemoveEntities<'a> { count: VarInt, - entitiy_ids: &'a [VarInt], + entity_ids: &'a [VarInt], } impl<'a> CRemoveEntities<'a> { - pub fn new(entitiy_ids: &'a [VarInt]) -> Self { + pub fn new(entity_ids: &'a [VarInt]) -> Self { Self { - count: VarInt(entitiy_ids.len() as i32), - entitiy_ids, + count: VarInt(entity_ids.len() as i32), + entity_ids, } } } diff --git a/pumpkin-protocol/src/client/play/c_update_entitiy_pos_rot.rs b/pumpkin-protocol/src/client/play/c_update_entity_pos_rot.rs similarity index 100% rename from pumpkin-protocol/src/client/play/c_update_entitiy_pos_rot.rs rename to pumpkin-protocol/src/client/play/c_update_entity_pos_rot.rs diff --git a/pumpkin-protocol/src/client/play/mod.rs b/pumpkin-protocol/src/client/play/mod.rs index 2e15aa978..a5a2a097b 100644 --- a/pumpkin-protocol/src/client/play/mod.rs +++ b/pumpkin-protocol/src/client/play/mod.rs @@ -31,7 +31,6 @@ mod c_subtitle; mod c_sync_player_position; mod c_system_chat_message; mod c_unload_chunk; -mod c_update_entitiy_pos_rot; mod c_update_entity_pos; mod c_update_entity_rot; mod c_worldevent; @@ -70,8 +69,8 @@ pub use c_subtitle::*; pub use c_sync_player_position::*; pub use c_system_chat_message::*; pub use c_unload_chunk::*; -pub use c_update_entitiy_pos_rot::*; pub use c_update_entity_pos::*; +pub use c_update_entity_pos_rot::*; pub use c_update_entity_rot::*; pub use c_worldevent::*; pub use player_action::*; diff --git a/pumpkin-protocol/src/server/play/s_player_command.rs b/pumpkin-protocol/src/server/play/s_player_command.rs index 9399e25ce..f6365cc02 100644 --- a/pumpkin-protocol/src/server/play/s_player_command.rs +++ b/pumpkin-protocol/src/server/play/s_player_command.rs @@ -5,7 +5,7 @@ use crate::{bytebuf::DeserializerError, ServerPacket, VarInt}; #[packet(0x25)] pub struct SPlayerCommand { - pub entitiy_id: VarInt, + pub entity_id: VarInt, pub action: VarInt, pub jump_boost: VarInt, } @@ -25,7 +25,7 @@ pub enum Action { impl ServerPacket for SPlayerCommand { fn read(bytebuf: &mut crate::bytebuf::ByteBuffer) -> Result { Ok(Self { - entitiy_id: bytebuf.get_var_int(), + entity_id: bytebuf.get_var_int(), action: bytebuf.get_var_int(), jump_boost: bytebuf.get_var_int(), }) diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index 8e82c8935..a1b4273ec 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -176,7 +176,7 @@ impl Client { pub fn handle_player_command(&mut self, _server: &mut Server, command: SPlayerCommand) { let player = self.player.as_mut().unwrap(); - if command.entitiy_id != player.entity.entity_id.into() { + if command.entity_id != player.entity.entity_id.into() { return; } @@ -317,7 +317,7 @@ impl Client { } if config.swing {} } else { - self.kick("Interacted with invalid entitiy id") + self.kick("Interacted with invalid entity id") } } } From 7c30391e2c040c623e5909044e8c110288ff5ed5 Mon Sep 17 00:00:00 2001 From: StripedMonkey Date: Tue, 20 Aug 2024 20:01:28 -0400 Subject: [PATCH 34/38] messge,messagee -> message --- pumpkin-protocol/src/client/play/c_system_chat_message.rs | 4 ++-- pumpkin-protocol/src/server/play/s_chat_message.rs | 4 ++-- pumpkin/src/client/mod.rs | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pumpkin-protocol/src/client/play/c_system_chat_message.rs b/pumpkin-protocol/src/client/play/c_system_chat_message.rs index a0f2342d1..2751b40c7 100644 --- a/pumpkin-protocol/src/client/play/c_system_chat_message.rs +++ b/pumpkin-protocol/src/client/play/c_system_chat_message.rs @@ -4,12 +4,12 @@ use serde::Serialize; #[derive(Serialize)] #[packet(0x6C)] -pub struct CSystemChatMessge<'a> { +pub struct CSystemChatMessage<'a> { content: TextComponent<'a>, overlay: bool, } -impl<'a> CSystemChatMessge<'a> { +impl<'a> CSystemChatMessage<'a> { pub fn new(content: TextComponent<'a>, overlay: bool) -> Self { Self { content, overlay } } diff --git a/pumpkin-protocol/src/server/play/s_chat_message.rs b/pumpkin-protocol/src/server/play/s_chat_message.rs index e644a5bc3..9332a28f2 100644 --- a/pumpkin-protocol/src/server/play/s_chat_message.rs +++ b/pumpkin-protocol/src/server/play/s_chat_message.rs @@ -13,7 +13,7 @@ pub struct SChatMessage { pub timestamp: i64, pub salt: i64, pub signature: Option, - pub messagee_count: VarInt, + pub message_count: VarInt, pub acknowledged: FixedBitSet, } @@ -25,7 +25,7 @@ impl ServerPacket for SChatMessage { timestamp: bytebuf.get_i64(), salt: bytebuf.get_i64(), signature: bytebuf.get_option(|v| v.copy_to_bytes(256)), - messagee_count: bytebuf.get_var_int(), + message_count: bytebuf.get_var_int(), acknowledged: bytebuf.get_fixed_bitset(20), }) } diff --git a/pumpkin/src/client/mod.rs b/pumpkin/src/client/mod.rs index 8edca66c7..cd8d39177 100644 --- a/pumpkin/src/client/mod.rs +++ b/pumpkin/src/client/mod.rs @@ -19,7 +19,7 @@ use pumpkin_protocol::{ client::{ config::CConfigDisconnect, login::CLoginDisconnect, - play::{CGameEvent, CPlayDisconnect, CSyncPlayerPostion, CSystemChatMessge}, + play::{CGameEvent, CPlayDisconnect, CSetContainerContent, CSyncPlayerPosition, CSystemChatMessage}, }, packet_decoder::PacketDecoder, packet_encoder::PacketEncoder, @@ -160,7 +160,7 @@ impl Client { entity.yaw = yaw; entity.pitch = pitch; player.awaiting_teleport = Some(id.into()); - self.send_packet(&CSyncPlayerPostion::new(x, y, z, yaw, pitch, 0, id.into())); + self.send_packet(&CSyncPlayerPosition::new(x, y, z, yaw, pitch, 0, id.into())); } pub fn update_health(&mut self, health: f32, food: i32, food_saturation: f32) { @@ -362,7 +362,7 @@ impl Client { } pub fn send_system_message(&mut self, text: TextComponent) { - self.send_packet(&CSystemChatMessge::new(text, false)); + self.send_packet(&CSystemChatMessage::new(text, false)); } /// Kicks the Client with a reason depending on the connection state From f56b566afb1bdc1e829487aa3359ddb279e4a3e9 Mon Sep 17 00:00:00 2001 From: StripedMonkey Date: Tue, 20 Aug 2024 20:02:09 -0400 Subject: [PATCH 35/38] mailformed -> malformed --- pumpkin-protocol/src/lib.rs | 2 +- pumpkin-protocol/src/packet_decoder.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pumpkin-protocol/src/lib.rs b/pumpkin-protocol/src/lib.rs index f44a0a811..e79388163 100644 --- a/pumpkin-protocol/src/lib.rs +++ b/pumpkin-protocol/src/lib.rs @@ -143,7 +143,7 @@ pub enum PacketError { #[error("packet length is out of bounds")] OutOfBounds, #[error("malformed packet length VarInt")] - MailformedLength, + MalformedLength, } #[derive(Debug, PartialEq)] diff --git a/pumpkin-protocol/src/packet_decoder.rs b/pumpkin-protocol/src/packet_decoder.rs index 3d3e3449a..308716ccb 100644 --- a/pumpkin-protocol/src/packet_decoder.rs +++ b/pumpkin-protocol/src/packet_decoder.rs @@ -28,7 +28,7 @@ impl PacketDecoder { let packet_len = match VarInt::decode_partial(&mut r) { Ok(len) => len, Err(VarIntDecodeError::Incomplete) => return Ok(None), - Err(VarIntDecodeError::TooLarge) => Err(PacketError::MailformedLength)?, + Err(VarIntDecodeError::TooLarge) => Err(PacketError::MalformedLength)?, }; if !(0..=MAX_PACKET_SIZE).contains(&packet_len) { From dbe3964e4150cecc3a9431a231fd9b374f62658b Mon Sep 17 00:00:00 2001 From: StripedMonkey Date: Tue, 20 Aug 2024 20:04:33 -0400 Subject: [PATCH 36/38] postion -> position --- pumpkin-protocol/src/client/play/c_sync_player_position.rs | 4 ++-- pumpkin/src/client/mod.rs | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/pumpkin-protocol/src/client/play/c_sync_player_position.rs b/pumpkin-protocol/src/client/play/c_sync_player_position.rs index 056214281..422160ad2 100644 --- a/pumpkin-protocol/src/client/play/c_sync_player_position.rs +++ b/pumpkin-protocol/src/client/play/c_sync_player_position.rs @@ -5,7 +5,7 @@ use crate::VarInt; #[derive(Serialize)] #[packet(0x40)] -pub struct CSyncPlayerPostion { +pub struct CSyncPlayerPosition { x: f64, y: f64, z: f64, @@ -15,7 +15,7 @@ pub struct CSyncPlayerPostion { teleport_id: VarInt, } -impl CSyncPlayerPostion { +impl CSyncPlayerPosition { pub fn new( x: f64, y: f64, diff --git a/pumpkin/src/client/mod.rs b/pumpkin/src/client/mod.rs index cd8d39177..9cdccef3d 100644 --- a/pumpkin/src/client/mod.rs +++ b/pumpkin/src/client/mod.rs @@ -19,7 +19,10 @@ use pumpkin_protocol::{ client::{ config::CConfigDisconnect, login::CLoginDisconnect, - play::{CGameEvent, CPlayDisconnect, CSetContainerContent, CSyncPlayerPosition, CSystemChatMessage}, + play::{ + CGameEvent, CPlayDisconnect, CSetContainerContent, CSyncPlayerPosition, + CSystemChatMessage, + }, }, packet_decoder::PacketDecoder, packet_encoder::PacketEncoder, From 4240df86b761404e238cd5d7e54855ee609a698a Mon Sep 17 00:00:00 2001 From: StripedMonkey Date: Wed, 21 Aug 2024 18:18:43 -0400 Subject: [PATCH 37/38] cargo fmt --- pumpkin-protocol/src/client/play/mod.rs | 1 + pumpkin/src/client/mod.rs | 5 +---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/pumpkin-protocol/src/client/play/mod.rs b/pumpkin-protocol/src/client/play/mod.rs index a5a2a097b..d5064aae4 100644 --- a/pumpkin-protocol/src/client/play/mod.rs +++ b/pumpkin-protocol/src/client/play/mod.rs @@ -32,6 +32,7 @@ mod c_sync_player_position; mod c_system_chat_message; mod c_unload_chunk; mod c_update_entity_pos; +mod c_update_entity_pos_rot; mod c_update_entity_rot; mod c_worldevent; mod player_action; diff --git a/pumpkin/src/client/mod.rs b/pumpkin/src/client/mod.rs index 9cdccef3d..7793ec46d 100644 --- a/pumpkin/src/client/mod.rs +++ b/pumpkin/src/client/mod.rs @@ -19,10 +19,7 @@ use pumpkin_protocol::{ client::{ config::CConfigDisconnect, login::CLoginDisconnect, - play::{ - CGameEvent, CPlayDisconnect, CSetContainerContent, CSyncPlayerPosition, - CSystemChatMessage, - }, + play::{CGameEvent, CPlayDisconnect, CSyncPlayerPosition, CSystemChatMessage}, }, packet_decoder::PacketDecoder, packet_encoder::PacketEncoder, From fa1ca0782e3f6418706e66ca3137da4b5f90a0f9 Mon Sep 17 00:00:00 2001 From: Snowiiii Date: Sat, 24 Aug 2024 11:17:36 +0200 Subject: [PATCH 38/38] Handle CTRL-C shutdown --- Cargo.lock | 38 ++++++++++++++++++++++++++++++++ pumpkin/Cargo.toml | 2 ++ pumpkin/src/commands/cmd_stop.rs | 10 +++++++-- pumpkin/src/main.rs | 13 +++++++++++ 4 files changed, 61 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d01e7e507..6e165f7d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -154,6 +154,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "cipher" version = "0.4.4" @@ -267,6 +273,16 @@ dependencies = [ "hybrid-array", ] +[[package]] +name = "ctrlc" +version = "3.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3" +dependencies = [ + "nix", + "windows-sys 0.59.0", +] + [[package]] name = "der" version = "0.7.9" @@ -823,6 +839,18 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "cfg_aliases", + "libc", +] + [[package]] name = "nom" version = "7.1.3" @@ -1066,6 +1094,7 @@ dependencies = [ "base64", "bytes", "crossbeam-channel", + "ctrlc", "dhat", "digest 0.11.0-pre.9", "hmac", @@ -2065,6 +2094,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-targets" version = "0.48.5" diff --git a/pumpkin/Cargo.toml b/pumpkin/Cargo.toml index 97b0b3a4a..1bd1fe81c 100644 --- a/pumpkin/Cargo.toml +++ b/pumpkin/Cargo.toml @@ -33,6 +33,8 @@ num-traits = "0.2" num-derive = "0.4" num-bigint = "0.4.6" +ctrlc = "3.4" + # encryption rsa = "0.9.6" rsa-der = "0.3.0" diff --git a/pumpkin/src/commands/cmd_stop.rs b/pumpkin/src/commands/cmd_stop.rs index 60f425b76..81bd07ea9 100644 --- a/pumpkin/src/commands/cmd_stop.rs +++ b/pumpkin/src/commands/cmd_stop.rs @@ -1,3 +1,6 @@ +use pumpkin_core::text::color::NamedColor; +use pumpkin_core::text::TextComponent; + use crate::commands::tree::CommandTree; use crate::commands::tree_builder::require; @@ -7,7 +10,10 @@ const DESCRIPTION: &str = "Stop the server."; pub(crate) fn init_command_tree<'a>() -> CommandTree<'a> { CommandTree::new(NAMES, DESCRIPTION).with_child( - require(&|sender| sender.permission_lvl() >= 4) - .execute(&|_sender, _args| std::process::exit(0)), + require(&|sender| sender.permission_lvl() >= 4).execute(&|sender, _args| { + sender + .send_message(TextComponent::text("Stopping Server").color_named(NamedColor::Red)); + std::process::exit(0) + }), ) } diff --git a/pumpkin/src/main.rs b/pumpkin/src/main.rs index 69f839c91..42ecb4423 100644 --- a/pumpkin/src/main.rs +++ b/pumpkin/src/main.rs @@ -31,6 +31,8 @@ static ALLOC: dhat::Alloc = dhat::Alloc; #[cfg(not(target_os = "wasi"))] fn main() -> io::Result<()> { + use pumpkin_core::text::{color::NamedColor, TextComponent}; + #[cfg(feature = "dhat-heap")] let _profiler = dhat::Profiler::new_heap(); #[cfg(feature = "dhat-heap")] @@ -39,6 +41,17 @@ fn main() -> io::Result<()> { .enable_all() .build() .unwrap(); + + ctrlc::set_handler(|| { + log::warn!( + "{}", + TextComponent::text("Stopping Server") + .color_named(NamedColor::Red) + .to_pretty_console() + ); + std::process::exit(0); + }) + .unwrap(); // ensure rayon is built outside of tokio scope rayon::ThreadPoolBuilder::new().build_global().unwrap(); rt.block_on(async {