diff --git a/Cargo.lock b/Cargo.lock index b9731cb09..6faa49ef5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3355,6 +3355,7 @@ dependencies = [ "num-bigint 0.5.1", "ordered-float", "postcard", + "pumpkin-auth", "pumpkin-command", "pumpkin-config", "pumpkin-data", @@ -3395,6 +3396,7 @@ dependencies = [ "wasmtime-wasi", "wasmtime-wasi-http", "webrtc", + "xxhash-rust", ] [[package]] @@ -3407,6 +3409,27 @@ dependencies = [ "syn 3.0.5", ] +[[package]] +name = "pumpkin-auth" +version = "0.1.0+26.2-26.45" +dependencies = [ + "base64 0.23.1", + "crypto-bigint 0.7.5", + "ecdsa 0.17.0", + "md5", + "p384 0.14.0", + "pumpkin-util", + "reqwest", + "rsa", + "rustls", + "serde", + "serde_json", + "sha2 0.11.0", + "thiserror 2.0.20", + "uuid", + "webpki-root-certs", +] + [[package]] name = "pumpkin-codecs" version = "0.1.0+26.2-26.45" @@ -3507,7 +3530,6 @@ dependencies = [ "pumpkin-nbt", "pumpkin-protocol", "pumpkin-util", - "pumpkin-world", "rand", "rustc-hash", "thiserror 2.0.20", @@ -3521,7 +3543,6 @@ dependencies = [ "heck", "proc-macro-error2", "proc-macro2", - "pumpkin-data", "quote", "syn 3.0.5", ] @@ -3585,6 +3606,7 @@ version = "0.1.0+26.2-26.45" dependencies = [ "aes 0.9.3", "async-compression", + "base64 0.23.1", "bitflags 2.13.1", "bytes", "cesu8", @@ -3595,7 +3617,6 @@ dependencies = [ "pumpkin-macros", "pumpkin-nbt", "pumpkin-util", - "pumpkin-world", "serde", "serde_json", "thiserror 2.0.20", @@ -3608,31 +3629,22 @@ dependencies = [ name = "pumpkin-util" version = "0.1.0+26.2-26.45" dependencies = [ - "base64 0.23.1", "bytes", "colored", "criterion", - "crypto-bigint 0.7.5", "dashmap", - "ecdsa 0.17.0", "md5", "num-derive", "num-traits", - "p384 0.14.0", "proc-macro2", "pumpkin-codecs", "pumpkin-nbt", "quote", - "reqwest", - "rsa", - "rustls", "serde", "serde_json", - "sha2 0.11.0", "syn 3.0.5", "thiserror 2.0.20", "uuid", - "webpki-root-certs", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 5cfdc8b2e..2db502445 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ resolver = "3" members = [ "crates/pumpkin", "crates/pumpkin-api-macros", + "crates/pumpkin-auth", "crates/pumpkin-codecs", "crates/pumpkin-command", "crates/pumpkin-config", @@ -176,6 +177,8 @@ num-traits = { version = "0.2", default-features = false, features = ["std"] } p384 = { version = "0.14.0", default-features = false, features = ["std", "arithmetic", "pkcs8"] } phf = { version = "0.14.0", default-features = false, features = ["std"] } proc-macro2 = { version = "1.0", default-features = false, features = ["proc-macro"] } +pumpkin-api-macros = { path = "crates/pumpkin-api-macros", default-features = false } +pumpkin-auth = { path = "crates/pumpkin-auth", default-features = false } pumpkin-codecs = { path = "crates/pumpkin-codecs", default-features = false } pumpkin-command = { path = "crates/pumpkin-command", default-features = false } pumpkin-config = { path = "crates/pumpkin-config", default-features = false } diff --git a/crates/pumpkin-auth/Cargo.toml b/crates/pumpkin-auth/Cargo.toml new file mode 100644 index 000000000..eb7c68b5d --- /dev/null +++ b/crates/pumpkin-auth/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "pumpkin-auth" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true + +[dependencies] +pumpkin-util.workspace = true + +serde.workspace = true +serde_json.workspace = true +thiserror.workspace = true +base64.workspace = true +uuid.workspace = true +md5.workspace = true + +p384 = { workspace = true, features = ["ecdsa"] } +ecdsa.workspace = true +rsa.workspace = true +sha2.workspace = true +crypto-bigint.workspace = true + +reqwest.workspace = true +rustls.workspace = true +webpki-root-certs.workspace = true + +[lints] +workspace = true diff --git a/crates/pumpkin-util/src/client.rs b/crates/pumpkin-auth/src/client.rs similarity index 100% rename from crates/pumpkin-util/src/client.rs rename to crates/pumpkin-auth/src/client.rs diff --git a/crates/pumpkin-util/src/jwt/mod.rs b/crates/pumpkin-auth/src/jwt/mod.rs similarity index 100% rename from crates/pumpkin-util/src/jwt/mod.rs rename to crates/pumpkin-auth/src/jwt/mod.rs diff --git a/crates/pumpkin-auth/src/lib.rs b/crates/pumpkin-auth/src/lib.rs new file mode 100644 index 000000000..cd2f460cd --- /dev/null +++ b/crates/pumpkin-auth/src/lib.rs @@ -0,0 +1,10 @@ +//! Authentication and HTTP client utilities for Pumpkin. + +#![deny(clippy::unwrap_used)] +#![cfg_attr(test, allow(clippy::unwrap_used, clippy::panic))] + +pub mod client; +pub mod jwt; + +pub use client::{client, client_builder}; +pub use p384; diff --git a/crates/pumpkin-config/src/networking/proxy.rs b/crates/pumpkin-config/src/networking/proxy.rs index 2c2a330b0..dc4e096a1 100644 --- a/crates/pumpkin-config/src/networking/proxy.rs +++ b/crates/pumpkin-config/src/networking/proxy.rs @@ -12,6 +12,8 @@ pub struct ProxyConfig { pub velocity: VelocityConfig, /// Configuration for `BungeeCord` proxy integration. pub bungeecord: BungeeCordConfig, + /// Configuration for Vine modern proxy integration with Ed25519 authentication. + pub vine: VineConfig, } /// Configuration for `BungeeCord` proxy integration. @@ -37,3 +39,17 @@ pub struct VelocityConfig { /// Shared secret for authenticating connections from the Velocity proxy. pub secret: String, } + +/// Configuration for Vine proxy integration with Ed25519 authentication and replay protection. +#[derive(Deserialize, Serialize, Default, Clone)] +#[serde(default)] +pub struct VineConfig { + /// Whether Vine support is enabled. + pub enabled: bool, + /// Ed25519 public key (64 hex characters) of the Vine proxy. + /// Backend only needs this public key to verify forwarded player identities. + pub public_key: String, + /// Optional shared secret string. If provided and `public_key` is empty, + /// the public key is automatically derived from this secret. + pub secret: String, +} diff --git a/crates/pumpkin-data/src/blocks.rs b/crates/pumpkin-data/src/blocks.rs index c62a0ebff..844a85734 100644 --- a/crates/pumpkin-data/src/blocks.rs +++ b/crates/pumpkin-data/src/blocks.rs @@ -361,6 +361,20 @@ impl From for u16 { } } +impl From for BlockId { + #[inline] + fn from(value: Block) -> Self { + value.id + } +} + +impl From<&Block> for BlockId { + #[inline] + fn from(value: &Block) -> Self { + value.id + } +} + impl Default for BlockId { #[inline] fn default() -> Self { diff --git a/crates/pumpkin-inventory/Cargo.toml b/crates/pumpkin-inventory/Cargo.toml index 8dda69449..f4913f0c1 100644 --- a/crates/pumpkin-inventory/Cargo.toml +++ b/crates/pumpkin-inventory/Cargo.toml @@ -19,7 +19,6 @@ pumpkin-data = { workspace = true, features = [ "statistic", ] } -pumpkin-world.workspace = true pumpkin-util.workspace = true pumpkin-nbt.workspace = true diff --git a/crates/pumpkin-inventory/src/anvil/anvil_screen_handler.rs b/crates/pumpkin-inventory/src/anvil/anvil_screen_handler.rs index 16415a5e2..6d394de62 100644 --- a/crates/pumpkin-inventory/src/anvil/anvil_screen_handler.rs +++ b/crates/pumpkin-inventory/src/anvil/anvil_screen_handler.rs @@ -3,13 +3,13 @@ use std::borrow::Cow; use std::sync::Arc; use std::sync::atomic::{AtomicBool, AtomicI32, AtomicU8, Ordering}; +use crate::inventory::Inventory; use pumpkin_data::Enchantment; use pumpkin_data::data_component::DataComponent; use pumpkin_data::data_component_impl::{EnchantmentsImpl, StoredEnchantmentsImpl}; use pumpkin_data::item::Item; use pumpkin_data::item_stack::ItemStack; use pumpkin_data::screen::WindowType; -use pumpkin_world::inventory::Inventory; use crate::{ player::player_inventory::PlayerInventory, @@ -559,11 +559,11 @@ impl ScreenHandler for AnvilScreenHandler { mod tests { use super::*; use crate::entity_equipment::EntityEquipment; + use crate::inventory::SimpleInventory; use pumpkin_protocol::java::client::play::{ CSetContainerContent, CSetContainerProperty, CSetContainerSlot, CSetCursorItem, CSetPlayerInventory, CSetSelectedSlot, }; - use pumpkin_world::inventory::SimpleInventory; use std::sync::Mutex; use std::sync::atomic::AtomicI32; diff --git a/crates/pumpkin-inventory/src/beacon_screen_handler.rs b/crates/pumpkin-inventory/src/beacon_screen_handler.rs index f8617ad94..a7e129e69 100644 --- a/crates/pumpkin-inventory/src/beacon_screen_handler.rs +++ b/crates/pumpkin-inventory/src/beacon_screen_handler.rs @@ -1,7 +1,7 @@ use std::{any::Any, sync::Arc}; +use crate::inventory::Inventory; use pumpkin_data::{item_stack::ItemStack, screen::WindowType}; -use pumpkin_world::inventory::Inventory; use crate::{ player::player_inventory::PlayerInventory, diff --git a/crates/pumpkin-inventory/src/brewing/brewing_screen_handler.rs b/crates/pumpkin-inventory/src/brewing/brewing_screen_handler.rs index f4b0dd15d..f738f659d 100644 --- a/crates/pumpkin-inventory/src/brewing/brewing_screen_handler.rs +++ b/crates/pumpkin-inventory/src/brewing/brewing_screen_handler.rs @@ -2,13 +2,13 @@ use std::any::Any; use std::sync::Arc; use std::sync::atomic::{AtomicU8, Ordering}; +use crate::inventory::Inventory; +use crate::window_property::PropertyDelegate; use pumpkin_data::item::Item; use pumpkin_data::item_stack::ItemStack; use pumpkin_data::potion_brewing::{ITEM_RECIPES, POTION_RECIPES}; use pumpkin_data::screen::WindowType; use pumpkin_data::tag::{self, Taggable}; -use pumpkin_world::block::entities::PropertyDelegate; -use pumpkin_world::inventory::Inventory; use crate::player::player_inventory::PlayerInventory; use crate::screen_handler::{ diff --git a/crates/pumpkin-inventory/src/cartography_table_screen_handler.rs b/crates/pumpkin-inventory/src/cartography_table_screen_handler.rs index af7ef441e..eb8c61e36 100644 --- a/crates/pumpkin-inventory/src/cartography_table_screen_handler.rs +++ b/crates/pumpkin-inventory/src/cartography_table_screen_handler.rs @@ -6,14 +6,14 @@ use crate::player::player_inventory::PlayerInventory; use crate::screen_handler::{InventoryPlayer, ScreenHandler, ScreenHandlerBehaviour}; use crate::slot::Slot; +use crate::inventory::Inventory; +use crate::inventory::SimpleInventory; use pumpkin_data::data_component_impl::{MapIdImpl, MapPostProcessingImpl}; use pumpkin_data::item::Item; use pumpkin_data::item_stack::ItemStack; use pumpkin_data::screen::WindowType; use pumpkin_data::statistic::StatisticCategory; use pumpkin_protocol::java::server::play::SlotActionType; -use pumpkin_world::inventory::Inventory; -use pumpkin_world::inventory::SimpleInventory; #[must_use] pub fn is_map_item(stack: &ItemStack) -> bool { diff --git a/crates/pumpkin-inventory/src/crafting/crafting_inventory.rs b/crates/pumpkin-inventory/src/crafting/crafting_inventory.rs index 8a05e142d..d0196daff 100644 --- a/crates/pumpkin-inventory/src/crafting/crafting_inventory.rs +++ b/crates/pumpkin-inventory/src/crafting/crafting_inventory.rs @@ -12,8 +12,8 @@ use std::any::Any; use std::sync::RwLock; +use crate::inventory::{Clearable, Inventory}; use pumpkin_data::item_stack::ItemStack; -use pumpkin_world::inventory::{Clearable, Inventory}; use super::recipes::RecipeInputInventory; diff --git a/crates/pumpkin-inventory/src/crafting/crafting_screen_handler.rs b/crates/pumpkin-inventory/src/crafting/crafting_screen_handler.rs index 762802899..e8a3a5587 100644 --- a/crates/pumpkin-inventory/src/crafting/crafting_screen_handler.rs +++ b/crates/pumpkin-inventory/src/crafting/crafting_screen_handler.rs @@ -27,6 +27,7 @@ use crate::screen_handler::{ }; use crate::slot::{NormalSlot, Slot}; +use crate::inventory::Inventory; use pumpkin_data::item_stack::ItemStack; use pumpkin_data::recipes::{CraftingRecipeTypes, RECIPES_CRAFTING}; use pumpkin_data::screen::WindowType; @@ -34,7 +35,6 @@ use pumpkin_data::statistic::StatisticCategory; use pumpkin_data::tag; use pumpkin_data::tag::Taggable; use pumpkin_protocol::codec::recipe::{DynamicRecipe, OwnedCraftingRecipe}; -use pumpkin_world::inventory::Inventory; /// The result slot in a crafting screen. pub struct ResultSlot { diff --git a/crates/pumpkin-inventory/src/crafting/recipes.rs b/crates/pumpkin-inventory/src/crafting/recipes.rs index 97fb62bce..6a30af4a8 100644 --- a/crates/pumpkin-inventory/src/crafting/recipes.rs +++ b/crates/pumpkin-inventory/src/crafting/recipes.rs @@ -12,7 +12,7 @@ //! - [`RecipeMatcher`] - Helper for matching items to recipes //! - [`RecipeFinder`] - Helper for finding recipes -use pumpkin_world::inventory::Inventory; +use crate::inventory::Inventory; /// Helper struct for matching recipe ingredients. // RecipeMatcher.java diff --git a/crates/pumpkin-inventory/src/double.rs b/crates/pumpkin-inventory/src/double.rs index 6ed1edef9..2b027d1c8 100644 --- a/crates/pumpkin-inventory/src/double.rs +++ b/crates/pumpkin-inventory/src/double.rs @@ -10,8 +10,8 @@ use std::{any::Any, sync::Arc}; +use crate::inventory::{Clearable, Inventory}; use pumpkin_data::item_stack::ItemStack; -use pumpkin_world::inventory::{Clearable, Inventory}; /// A composite inventory combining two inventories. /// diff --git a/crates/pumpkin-inventory/src/enchanting/enchanting_screen_handler.rs b/crates/pumpkin-inventory/src/enchanting/enchanting_screen_handler.rs index 4d19cbc9a..e8a395803 100644 --- a/crates/pumpkin-inventory/src/enchanting/enchanting_screen_handler.rs +++ b/crates/pumpkin-inventory/src/enchanting/enchanting_screen_handler.rs @@ -1,6 +1,7 @@ use std::any::Any; use std::sync::Arc; +use crate::inventory::Inventory; use pumpkin_data::Enchantment; use pumpkin_data::data_component_impl::EnchantableImpl; use pumpkin_data::item::Item; @@ -10,7 +11,6 @@ use pumpkin_data::sound::Sound; use pumpkin_data::statistic::{CustomStatistic, StatisticCategory}; use pumpkin_data::tag::{Enchantment as EnchantmentTag, Taggable}; use pumpkin_util::random::{RandomImpl, legacy_rand::LegacyRand}; -use pumpkin_world::inventory::Inventory; use crate::{ player::player_inventory::PlayerInventory, diff --git a/crates/pumpkin-inventory/src/furnace_like/furnace_like_screen_handler.rs b/crates/pumpkin-inventory/src/furnace_like/furnace_like_screen_handler.rs index cfb567277..a7b5a45a1 100644 --- a/crates/pumpkin-inventory/src/furnace_like/furnace_like_screen_handler.rs +++ b/crates/pumpkin-inventory/src/furnace_like/furnace_like_screen_handler.rs @@ -1,14 +1,14 @@ use std::any::Any; use std::sync::Arc; +use crate::{ + inventory::Inventory, + window_property::{ExperienceContainer, PropertyDelegate}, +}; use pumpkin_data::fuels::is_fuel; use pumpkin_data::item_stack::ItemStack; use pumpkin_data::recipes::{CookingRecipeKind, CookingRecipeType}; use pumpkin_data::screen::WindowType; -use pumpkin_world::{ - block::entities::{ExperienceContainer, PropertyDelegate}, - inventory::Inventory, -}; use crate::{ player::player_inventory::PlayerInventory, diff --git a/crates/pumpkin-inventory/src/furnace_like/furnace_like_slot.rs b/crates/pumpkin-inventory/src/furnace_like/furnace_like_slot.rs index 91362999d..d87c557a1 100644 --- a/crates/pumpkin-inventory/src/furnace_like/furnace_like_slot.rs +++ b/crates/pumpkin-inventory/src/furnace_like/furnace_like_slot.rs @@ -8,8 +8,8 @@ use std::sync::{Arc, atomic::AtomicU8}; +use crate::{inventory::Inventory, window_property::ExperienceContainer}; use pumpkin_data::{fuels::is_fuel, item::Item, statistic::StatisticCategory}; -use pumpkin_world::{block::entities::ExperienceContainer, inventory::Inventory}; use tracing::debug; diff --git a/crates/pumpkin-inventory/src/generic_container_screen_handler.rs b/crates/pumpkin-inventory/src/generic_container_screen_handler.rs index 448eafc22..295ddabd7 100644 --- a/crates/pumpkin-inventory/src/generic_container_screen_handler.rs +++ b/crates/pumpkin-inventory/src/generic_container_screen_handler.rs @@ -11,8 +11,8 @@ use std::{any::Any, sync::Arc}; +use crate::inventory::Inventory; use pumpkin_data::{item_stack::ItemStack, screen::WindowType}; -use pumpkin_world::inventory::Inventory; use crate::{ player::player_inventory::PlayerInventory, diff --git a/crates/pumpkin-inventory/src/grindstone_screen_handler.rs b/crates/pumpkin-inventory/src/grindstone_screen_handler.rs index fedf93627..ab05a01f6 100644 --- a/crates/pumpkin-inventory/src/grindstone_screen_handler.rs +++ b/crates/pumpkin-inventory/src/grindstone_screen_handler.rs @@ -3,6 +3,7 @@ use std::borrow::Cow; use std::sync::Arc; use std::sync::atomic::{AtomicU8, Ordering}; +use crate::inventory::Inventory; use pumpkin_data::data_component::DataComponent; use pumpkin_data::data_component_impl::{EnchantmentsImpl, MaxDamageImpl, StoredEnchantmentsImpl}; use pumpkin_data::enchantment::Enchantment; @@ -12,7 +13,6 @@ use pumpkin_data::screen::WindowType; use pumpkin_data::tag::Enchantment as EnchantmentTag; use pumpkin_data::tag::Taggable; use pumpkin_protocol::java::server::play::SlotActionType; -use pumpkin_world::inventory::Inventory; use crate::{ anvil::anvil_screen_handler::calculate_increased_repair_cost, diff --git a/crates/pumpkin-inventory/src/gui_builder.rs b/crates/pumpkin-inventory/src/gui_builder.rs index 64c76e489..a6dea4884 100644 --- a/crates/pumpkin-inventory/src/gui_builder.rs +++ b/crates/pumpkin-inventory/src/gui_builder.rs @@ -1,10 +1,10 @@ +use crate::inventory::Inventory; use crate::{ player::player_inventory::PlayerInventory, screen_handler::{InventoryPlayer, ScreenHandler, ScreenHandlerBehaviour}, slot::NormalSlot, }; use pumpkin_data::{item_stack::ItemStack, screen::WindowType}; -use pumpkin_world::inventory::Inventory; use std::{any::Any, sync::Arc}; /// Builder for custom GUIs. diff --git a/crates/pumpkin-world/src/inventory/inventory.rs b/crates/pumpkin-inventory/src/inventory/inventory.rs similarity index 100% rename from crates/pumpkin-world/src/inventory/inventory.rs rename to crates/pumpkin-inventory/src/inventory/inventory.rs diff --git a/crates/pumpkin-world/src/inventory/mod.rs b/crates/pumpkin-inventory/src/inventory/mod.rs similarity index 100% rename from crates/pumpkin-world/src/inventory/mod.rs rename to crates/pumpkin-inventory/src/inventory/mod.rs diff --git a/crates/pumpkin-world/src/inventory/simple_inventory.rs b/crates/pumpkin-inventory/src/inventory/simple_inventory.rs similarity index 100% rename from crates/pumpkin-world/src/inventory/simple_inventory.rs rename to crates/pumpkin-inventory/src/inventory/simple_inventory.rs diff --git a/crates/pumpkin-inventory/src/lectern_screen_handler.rs b/crates/pumpkin-inventory/src/lectern_screen_handler.rs index 0f595d1db..83d96cc6a 100644 --- a/crates/pumpkin-inventory/src/lectern_screen_handler.rs +++ b/crates/pumpkin-inventory/src/lectern_screen_handler.rs @@ -6,10 +6,10 @@ use crate::screen_handler::{ }; use crate::slot::NormalSlot; +use crate::inventory::Inventory; +use crate::window_property::PropertyDelegate; use pumpkin_data::item_stack::ItemStack; use pumpkin_data::screen::WindowType; -use pumpkin_world::block::entities::PropertyDelegate; -use pumpkin_world::inventory::Inventory; /// Callbacks into the lectern block so page turns and book removal can drive /// block-state changes (redstone pulse, `has_book`) that live outside this crate. diff --git a/crates/pumpkin-inventory/src/lib.rs b/crates/pumpkin-inventory/src/lib.rs index 038103d5e..a96e2392c 100644 --- a/crates/pumpkin-inventory/src/lib.rs +++ b/crates/pumpkin-inventory/src/lib.rs @@ -27,7 +27,7 @@ //! - [`sync_handler`] - Client-server inventory synchronization //! - [`window_property`] - Container UI properties (furnace progress, enchantment levels, etc.) //! -//! [`Inventory`]: pumpkin_world::inventory::Inventory +//! [`Inventory`]: inventory::Inventory //! [`ScreenHandler`]: screen_handler::ScreenHandler //! [`Slot`]: slot::Slot //! [`PlayerInventory`]: PlayerInventory @@ -48,6 +48,7 @@ pub mod furnace_like; pub mod generic_container_screen_handler; pub mod grindstone_screen_handler; pub mod gui_builder; +pub mod inventory; pub mod lectern_screen_handler; pub mod loom_screen_handler; pub mod merchant; @@ -58,12 +59,19 @@ pub mod slot; pub mod smithing_table_screen_handler; pub mod stonecutter_screen_handler; pub mod sync_handler; +pub mod viewer; pub mod window_property; use rustc_hash::FxHashMap; pub use error::InventoryError; +pub use inventory::{ + Clearable, ComparableInventory, Inventory, SimpleInventory, split_stack_slice, + sync_read_items_from_nbt, sync_write_items_to_nbt, +}; use pumpkin_data::data_component_impl::EquipmentSlot; +pub use viewer::ViewerCountTracker; +pub use window_property::{ExperienceContainer, PropertyDelegate}; use crate::player::player_inventory::PlayerInventory; diff --git a/crates/pumpkin-inventory/src/loom_screen_handler.rs b/crates/pumpkin-inventory/src/loom_screen_handler.rs index 45726cbb4..929747711 100644 --- a/crates/pumpkin-inventory/src/loom_screen_handler.rs +++ b/crates/pumpkin-inventory/src/loom_screen_handler.rs @@ -8,6 +8,9 @@ use crate::screen_handler::{ }; use crate::slot::Slot; +use crate::inventory::Inventory; +use crate::inventory::SimpleInventory; +use crate::window_property::PropertyDelegate; use pumpkin_data::data_component_impl::{BannerPatternLayer, BannerPatternsImpl}; use pumpkin_data::dye_color::DyeColor; use pumpkin_data::item::Item; @@ -16,9 +19,6 @@ use pumpkin_data::screen::WindowType; use pumpkin_data::statistic::StatisticCategory; use pumpkin_data::tag::{BannerPattern, RegistryKey, get_tag_values}; use pumpkin_protocol::java::server::play::SlotActionType; -use pumpkin_world::block::entities::PropertyDelegate; -use pumpkin_world::inventory::Inventory; -use pumpkin_world::inventory::SimpleInventory; pub const NO_ITEM_REQUIRED_PATTERNS: &[&str] = BannerPattern::MINECRAFT_NO_ITEM_REQUIRED.0; diff --git a/crates/pumpkin-inventory/src/merchant/merchant_screen_handler.rs b/crates/pumpkin-inventory/src/merchant/merchant_screen_handler.rs index afb717df9..4396ce5ff 100644 --- a/crates/pumpkin-inventory/src/merchant/merchant_screen_handler.rs +++ b/crates/pumpkin-inventory/src/merchant/merchant_screen_handler.rs @@ -6,12 +6,12 @@ use std::{ }, }; +use crate::inventory::Inventory; use pumpkin_data::{ item_stack::ItemStack, screen::WindowType, statistic::{CustomStatistic, StatisticCategory}, }; -use pumpkin_world::inventory::Inventory; use crate::{ player::player_inventory::PlayerInventory, @@ -495,6 +495,7 @@ mod tests { sync::atomic::{AtomicI32, AtomicUsize, Ordering}, }; + use crate::inventory::SimpleInventory; use pumpkin_data::{data_component_impl::EquipmentSlot, item::Item}; use pumpkin_protocol::{ codec::item_stack_seralizer::ItemStackSerializer, @@ -506,7 +507,6 @@ mod tests { server::play::SlotActionType, }, }; - use pumpkin_world::inventory::SimpleInventory; use std::sync::Mutex; use crate::{entity_equipment::EntityEquipment, screen_handler::InventoryPlayer}; diff --git a/crates/pumpkin-inventory/src/mount_screen_handler.rs b/crates/pumpkin-inventory/src/mount_screen_handler.rs index 76e86a875..18a1a9c8c 100644 --- a/crates/pumpkin-inventory/src/mount_screen_handler.rs +++ b/crates/pumpkin-inventory/src/mount_screen_handler.rs @@ -1,9 +1,9 @@ use std::any::Any; use std::sync::Arc; +use crate::inventory::Inventory; use pumpkin_data::data_component_impl::EquipmentSlot; use pumpkin_data::item_stack::ItemStack; -use pumpkin_world::inventory::Inventory; use crate::player::player_inventory::PlayerInventory; use crate::screen_handler::{InventoryPlayer, ScreenHandler, ScreenHandlerBehaviour}; diff --git a/crates/pumpkin-inventory/src/player/ender_chest_inventory.rs b/crates/pumpkin-inventory/src/player/ender_chest_inventory.rs index 6d36e7c7a..1fda4b505 100644 --- a/crates/pumpkin-inventory/src/player/ender_chest_inventory.rs +++ b/crates/pumpkin-inventory/src/player/ender_chest_inventory.rs @@ -13,11 +13,11 @@ use std::any::Any; use std::sync::{Arc, Mutex, RwLock}; -use pumpkin_data::item_stack::ItemStack; -use pumpkin_world::{ - block::viewer::ViewerCountTracker, +use crate::{ inventory::{Clearable, Inventory}, + viewer::ViewerCountTracker, }; +use pumpkin_data::item_stack::ItemStack; /// A player's ender chest inventory. /// diff --git a/crates/pumpkin-inventory/src/player/player_inventory.rs b/crates/pumpkin-inventory/src/player/player_inventory.rs index 61b96909e..81d0388e9 100644 --- a/crates/pumpkin-inventory/src/player/player_inventory.rs +++ b/crates/pumpkin-inventory/src/player/player_inventory.rs @@ -10,12 +10,12 @@ use crate::entity_equipment::EntityEquipment; use crate::screen_handler::InventoryPlayer; +use crate::inventory::{Clearable, Inventory}; use pumpkin_data::data_component_impl::EquipmentSlot; use pumpkin_data::item::Item; use pumpkin_data::item_stack::ItemStack; use pumpkin_protocol::java::client::play::CSetPlayerInventory; use pumpkin_util::Hand; -use pumpkin_world::inventory::{Clearable, Inventory}; use rustc_hash::FxHashMap; use std::any::Any; use std::sync::atomic::{AtomicU8, Ordering}; diff --git a/crates/pumpkin-inventory/src/player/player_screen_handler.rs b/crates/pumpkin-inventory/src/player/player_screen_handler.rs index 603e0f752..b13bc1362 100644 --- a/crates/pumpkin-inventory/src/player/player_screen_handler.rs +++ b/crates/pumpkin-inventory/src/player/player_screen_handler.rs @@ -22,12 +22,12 @@ use super::player_inventory::PlayerInventory; use crate::crafting::crafting_inventory::CraftingInventory; use crate::crafting::crafting_screen_handler::CraftingScreenHandler; use crate::crafting::recipes::{RecipeFinderScreenHandler, RecipeInputInventory}; +use crate::inventory::Inventory; use crate::screen_handler::{InventoryPlayer, ScreenHandler, ScreenHandlerBehaviour}; use crate::slot::{ArmorSlot, NormalSlot, Slot}; use pumpkin_data::data_component_impl::{EquipmentSlot, EquipmentType, EquippableImpl}; use pumpkin_data::item_stack::ItemStack; use pumpkin_data::screen::WindowType; -use pumpkin_world::inventory::Inventory; use std::any::Any; use std::sync::Arc; diff --git a/crates/pumpkin-inventory/src/screen_handler.rs b/crates/pumpkin-inventory/src/screen_handler.rs index 3f7de9316..77801b371 100644 --- a/crates/pumpkin-inventory/src/screen_handler.rs +++ b/crates/pumpkin-inventory/src/screen_handler.rs @@ -31,6 +31,10 @@ use crate::{ slot::{NormalSlot, Slot}, sync_handler::{SyncHandler, TrackedStack}, }; +use crate::{ + inventory::{ComparableInventory, Inventory}, + window_property::PropertyDelegate, +}; use pumpkin_data::item_stack::ItemStack; use pumpkin_data::{ Enchantment, @@ -50,10 +54,6 @@ use pumpkin_protocol::{ }, }; use pumpkin_util::text::TextComponent; -use pumpkin_world::{ - block::entities::PropertyDelegate, - inventory::{ComparableInventory, Inventory}, -}; use std::cmp::max; use std::sync::Mutex; use std::sync::atomic::{AtomicU32, Ordering}; diff --git a/crates/pumpkin-inventory/src/slot.rs b/crates/pumpkin-inventory/src/slot.rs index c158d296a..06b11da5e 100644 --- a/crates/pumpkin-inventory/src/slot.rs +++ b/crates/pumpkin-inventory/src/slot.rs @@ -25,10 +25,10 @@ use std::sync::{ use crate::screen_handler::InventoryPlayer; +use crate::inventory::Inventory; use pumpkin_data::data_component_impl::EquipmentSlot; use pumpkin_data::item::Item; use pumpkin_data::item_stack::ItemStack; -use pumpkin_world::inventory::Inventory; /// A slot in an inventory. /// diff --git a/crates/pumpkin-inventory/src/smithing_table_screen_handler.rs b/crates/pumpkin-inventory/src/smithing_table_screen_handler.rs index f1211202f..7f6be49a7 100644 --- a/crates/pumpkin-inventory/src/smithing_table_screen_handler.rs +++ b/crates/pumpkin-inventory/src/smithing_table_screen_handler.rs @@ -6,6 +6,8 @@ use crate::player::player_inventory::PlayerInventory; use crate::screen_handler::{InventoryPlayer, ScreenHandler, ScreenHandlerBehaviour}; use crate::slot::{NormalSlot, Slot}; +use crate::inventory::Inventory; +use crate::inventory::SimpleInventory; use pumpkin_data::data_component_impl::TrimImpl; use pumpkin_data::item::Item; use pumpkin_data::item_stack::ItemStack; @@ -16,8 +18,6 @@ use pumpkin_data::screen::WindowType; use pumpkin_data::statistic::StatisticCategory; use pumpkin_nbt::tag::NbtTag; use pumpkin_protocol::java::server::play::SlotActionType; -use pumpkin_world::inventory::Inventory; -use pumpkin_world::inventory::SimpleInventory; pub struct SmithingTableScreenHandler { behaviour: ScreenHandlerBehaviour, diff --git a/crates/pumpkin-inventory/src/stonecutter_screen_handler.rs b/crates/pumpkin-inventory/src/stonecutter_screen_handler.rs index c6cfe2ab8..e620179e7 100644 --- a/crates/pumpkin-inventory/src/stonecutter_screen_handler.rs +++ b/crates/pumpkin-inventory/src/stonecutter_screen_handler.rs @@ -6,14 +6,14 @@ use crate::player::player_inventory::PlayerInventory; use crate::screen_handler::{InventoryPlayer, ScreenHandler, ScreenHandlerBehaviour}; use crate::slot::{NormalSlot, Slot}; +use crate::inventory::Inventory; +use crate::inventory::SimpleInventory; use pumpkin_data::item::Item; use pumpkin_data::item_stack::ItemStack; use pumpkin_data::recipes::{RECIPES_STONECUTTING, StonecutterRecipe}; use pumpkin_data::screen::WindowType; use pumpkin_data::statistic::StatisticCategory; use pumpkin_protocol::java::server::play::SlotActionType; -use pumpkin_world::inventory::Inventory; -use pumpkin_world::inventory::SimpleInventory; pub struct StonecutterScreenHandler { behaviour: ScreenHandlerBehaviour, diff --git a/crates/pumpkin-world/src/block/viewer.rs b/crates/pumpkin-inventory/src/viewer.rs similarity index 100% rename from crates/pumpkin-world/src/block/viewer.rs rename to crates/pumpkin-inventory/src/viewer.rs diff --git a/crates/pumpkin-inventory/src/window_property.rs b/crates/pumpkin-inventory/src/window_property.rs index 48203034f..f5bdeeb11 100644 --- a/crates/pumpkin-inventory/src/window_property.rs +++ b/crates/pumpkin-inventory/src/window_property.rs @@ -141,3 +141,15 @@ pub enum Lectern { /// Current page number being viewed. PageNumber, } + +pub trait PropertyDelegate: Sync + Send { + fn get_property(&self, index: i32) -> i32; + fn set_property(&self, index: i32, value: i32); + fn get_properties_size(&self) -> i32; +} + +/// Trait for extracting smelting experience from cooking block entities. +pub trait ExperienceContainer: Send + Sync { + /// Extract and reset accumulated experience, returning the total as an integer + fn extract_experience(&self) -> i32; +} diff --git a/crates/pumpkin-macros/Cargo.toml b/crates/pumpkin-macros/Cargo.toml index 3ddaf1244..fb0157d10 100644 --- a/crates/pumpkin-macros/Cargo.toml +++ b/crates/pumpkin-macros/Cargo.toml @@ -10,7 +10,6 @@ proc-macro = true [dependencies] proc-macro-error2.workspace = true -pumpkin-data = { workspace = true, features = ["block", "tag", "translation"] } heck.workspace = true proc-macro2 = "1.0" diff --git a/crates/pumpkin-macros/src/lib.rs b/crates/pumpkin-macros/src/lib.rs index 51e8d0369..a0de779b3 100644 --- a/crates/pumpkin-macros/src/lib.rs +++ b/crates/pumpkin-macros/src/lib.rs @@ -3,11 +3,10 @@ use heck::ToShoutySnakeCase; use proc_macro::TokenStream; use proc_macro_error2::{abort, abort_call_site}; -use pumpkin_data::tag::{RegistryKey, get_tag_ids}; -use pumpkin_data::{Block, BlockId}; -use quote::{format_ident, quote}; +use quote::{format_ident, quote, quote_spanned}; +use syn::punctuated::Punctuated; use syn::spanned::Spanned; -use syn::{self, Attribute, DeriveInput, LitStr, Type, parse_quote}; +use syn::{self, Attribute, DeriveInput, Token, Type, parse_quote}; use syn::{Block as SynBlock, Expr, Field, Fields, ItemStruct, Stmt, parse_macro_input}; /// Derives the `Payload` trait for an event struct, enabling it to be used in the plugin system. @@ -314,25 +313,51 @@ pub fn java_packet(args: TokenStream, item: TokenStream) -> TokenStream { .into() } -/// Marks a struct as representing a specific block by its name. +fn block_expr_to_id(expr: &Expr) -> proc_macro2::TokenStream { + match expr { + Expr::Lit(syn::ExprLit { + lit: syn::Lit::Str(lit_str), + .. + }) => { + let val = lit_str.value(); + let name = val.strip_prefix("minecraft:").unwrap_or(&val); + let const_ident = format_ident!("{}", name.to_shouty_snake_case()); + quote_spanned! { lit_str.span() => pumpkin_data::BlockId::#const_ident } + } + Expr::Path(syn::ExprPath { path, .. }) => { + if path.segments.len() == 1 { + let ident = &path.segments[0].ident; + quote_spanned! { expr.span() => pumpkin_data::BlockId::#ident } + } else if path.segments.len() == 2 + && (path.segments[0].ident == "Block" || path.segments[0].ident == "BlockId") + { + let ident = &path.segments[1].ident; + quote_spanned! { expr.span() => pumpkin_data::BlockId::#ident } + } else { + quote_spanned! { expr.span() => pumpkin_data::BlockId::from(#expr) } + } + } + _ => { + quote_spanned! { expr.span() => pumpkin_data::BlockId::from(#expr) } + } + } +} + +/// Marks a struct as representing a specific block (or blocks) by name, expression, or constant. /// /// # Arguments -/// - `args` – The `TokenStream` representing the block name literal. +/// - `args` – One or more block names (e.g. `"stone"`, `"minecraft:stone"`), constants (e.g. `Block::STONE`, `BlockId::STONE`, `STONE`), or expressions. /// - `item` – The input `TokenStream` representing the struct to implement `BlockMetadata` for. #[proc_macro_attribute] pub fn pumpkin_block(args: TokenStream, item: TokenStream) -> TokenStream { let input_item = item.clone(); - let arg_lit = parse_macro_input!(args as LitStr); - let arg_value = arg_lit.value(); + let args = parse_macro_input!(args with Punctuated::parse_terminated); + if args.is_empty() { + abort_call_site!("expected at least one block argument"); + } - let block_name = arg_value.strip_prefix("minecraft:").unwrap_or(&arg_value); - let Some(block) = Block::from_name(block_name) else { - return syn::Error::new(arg_lit.span(), "Invalid block name") - .to_compile_error() - .into(); - }; - let const_ident = format_ident!("{}", block.name.to_shouty_snake_case()); + let id_tokens: Vec<_> = args.iter().map(block_expr_to_id).collect(); let ast = parse_macro_input!(item as DeriveInput); let name = &ast.ident; @@ -341,7 +366,7 @@ pub fn pumpkin_block(args: TokenStream, item: TokenStream) -> TokenStream { let generated = quote! { impl #impl_generics crate::block::BlockMetadata for #name #ty_generics #where_clause { fn ids() -> Box<[pumpkin_data::BlockId]> { - [pumpkin_data::BlockId::#const_ident].into() + Box::new([ #(#id_tokens),* ]) } } }; @@ -355,37 +380,27 @@ pub fn pumpkin_block(args: TokenStream, item: TokenStream) -> TokenStream { /// Marks a struct as representing a set of blocks from a given tag. /// /// # Arguments -/// - `args` – The `TokenStream` representing the block tag literal. +/// - `args` – The `TokenStream` representing the block tag literal or expression. /// - `item` – The input `TokenStream` representing the struct to implement `BlockMetadata` for. #[proc_macro_attribute] pub fn pumpkin_block_from_tag(args: TokenStream, item: TokenStream) -> TokenStream { let original_item = item.clone(); - let arg_lit = parse_macro_input!(args as LitStr); + let arg_expr = parse_macro_input!(args as Expr); let ast = parse_macro_input!(item as DeriveInput); let name = &ast.ident; let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl(); - let full_tag = arg_lit.value(); - - let Some(values) = get_tag_ids(RegistryKey::Block, &full_tag) else { - return syn::Error::new(arg_lit.span(), format!("Failed to get tag IDs: {full_tag}")) - .to_compile_error() - .into(); - }; - let const_values: Vec<_> = values - .iter() - .map(|v| { - let block = BlockId::new_or_air(*v).to_block(); - format_ident!("{}", block.name.to_shouty_snake_case()) - }) - .collect(); - let expanded = quote! { impl #impl_generics crate::block::BlockMetadata for #name #ty_generics #where_clause { fn ids() -> Box<[pumpkin_data::BlockId]> { - Box::new([ #(pumpkin_data::BlockId::#const_values),* ]) + pumpkin_data::tag::get_tag_ids(pumpkin_data::tag::RegistryKey::Block, #arg_expr) + .unwrap_or_else(|| panic!("Failed to get tag IDs for: {}", #arg_expr)) + .iter() + .copied() + .map(pumpkin_data::BlockId::new_or_air) + .collect() } } }; @@ -804,33 +819,6 @@ impl syn::parse::Parse for TranslateCrossInput { fn eval_translation_key_expr(expr: &syn::Expr) -> Option<(&'static str, proc_macro2::Span)> { match expr { - syn::Expr::Path(expr_path) => { - let segments: Vec = expr_path - .path - .segments - .iter() - .map(|s| s.ident.to_string()) - .collect(); - let seg_refs: Vec<&str> = segments.iter().map(String::as_str).collect(); - - let (is_java, const_ident) = match seg_refs.as_slice() { - ["translation", "java", ident] - | ["pumpkin_data" | "crate", "translation", "java", ident] => (true, *ident), - ["translation", "bedrock", ident] - | ["pumpkin_data" | "crate", "translation", "bedrock", ident] => (false, *ident), - _ => return None, - }; - - let key = if is_java { - pumpkin_data::translation::java::get(const_ident) - .and_then(pumpkin_data::translation::java::get_value) - } else { - pumpkin_data::translation::bedrock::get(const_ident) - .and_then(pumpkin_data::translation::bedrock::get_value) - }; - - key.map(|k| (k, expr.span())) - } syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::Str(lit_str), .. diff --git a/crates/pumpkin-protocol/Cargo.toml b/crates/pumpkin-protocol/Cargo.toml index 1f4609401..82597a42d 100644 --- a/crates/pumpkin-protocol/Cargo.toml +++ b/crates/pumpkin-protocol/Cargo.toml @@ -13,9 +13,8 @@ query = [] [dependencies] pumpkin-nbt.workspace = true -pumpkin-data = { workspace = true, features = ["packet", "item_id_remap", "entity_id_remap", "sound_id_remap", "particle_id_remap", "menu_id_remap", "recipe_serializer_id_remap", "argument_type_id_remap", "attribute_id_remap", "block_entity_type_id_remap", "custom_stat_id_remap", "data_component_type_id_remap", "enchantment_id_remap", "environment_attribute_id_remap", "painting_variant_id_remap", "slot_display_id_remap", "recipes", "bedrock_creative", "bedrock_biome"] } +pumpkin-data = { workspace = true, features = ["default", "item_id_remap", "entity_id_remap", "sound_id_remap", "particle_id_remap", "menu_id_remap", "recipe_serializer_id_remap", "argument_type_id_remap", "attribute_id_remap", "block_entity_type_id_remap", "custom_stat_id_remap", "data_component_type_id_remap", "enchantment_id_remap", "environment_attribute_id_remap", "painting_variant_id_remap", "slot_display_id_remap", "bedrock_creative", "bedrock_biome"] } pumpkin-macros.workspace = true -pumpkin-world.workspace = true pumpkin-util.workspace = true serde = { workspace = true, features = ["derive"] } serde_json.workspace = true @@ -23,7 +22,7 @@ cesu8.workspace = true uuid.workspace = true thiserror.workspace = true -tokio = { workspace = true, features = ["net"] } +tokio = { workspace = true, features = ["net", "io-util"] } bytes.workspace = true # encryption @@ -36,9 +35,11 @@ async-compression = { workspace = true, features = ["tokio", "zlib", "deflate"] flate2.workspace = true bitflags.workspace = true +base64.workspace = true xxhash-rust.workspace = true [dev-dependencies] +tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } # Validate correctness [lints] diff --git a/crates/pumpkin-protocol/src/bedrock/client/mod.rs b/crates/pumpkin-protocol/src/bedrock/client/mod.rs index ffb273299..92ba73211 100644 --- a/crates/pumpkin-protocol/src/bedrock/client/mod.rs +++ b/crates/pumpkin-protocol/src/bedrock/client/mod.rs @@ -20,7 +20,6 @@ pub mod inventory_content; pub mod inventory_slot; pub mod item_registry; pub mod item_stack_response; -pub mod level_chunk; pub mod level_event; pub mod level_sound_event; pub mod mob_effect; @@ -80,7 +79,6 @@ pub use inventory_content::*; pub use inventory_slot::*; pub use item_registry::*; pub use item_stack_response::*; -pub use level_chunk::*; pub use level_event::*; pub use level_sound_event::*; pub use mob_effect::*; diff --git a/crates/pumpkin-protocol/src/java/client/play/chunk_data.rs b/crates/pumpkin-protocol/src/java/client/play/chunk_data.rs new file mode 100644 index 000000000..3241ff08e --- /dev/null +++ b/crates/pumpkin-protocol/src/java/client/play/chunk_data.rs @@ -0,0 +1,153 @@ +use std::io::Write; + +use crate::ClientPacket; +use crate::codec::var_int::VarInt; +use crate::packet::MultiVersionJavaPacket; +use crate::ser::{NetworkWriteExt, WritingError}; +use pumpkin_data::packet::clientbound::play::LEVEL_CHUNK_WITH_LIGHT; +use pumpkin_nbt::compound::NbtCompound; +use pumpkin_nbt::tag::NbtTag; +use pumpkin_util::version::JavaMinecraftVersion; + +use super::light_update::LightData; + +/// Heightmap data accompanying a chunk packet. +#[derive(Clone, Debug, PartialEq, Eq, Default)] +pub struct ChunkHeightmaps { + pub world_surface: Option>, + pub motion_blocking: Option>, + pub motion_blocking_no_leaves: Option>, +} + +impl ChunkHeightmaps { + pub fn write_to( + &self, + mut write: impl Write, + version: &JavaMinecraftVersion, + ) -> Result<(), WritingError> { + if *version >= JavaMinecraftVersion::V_1_21_5 { + write.write_var_int(&VarInt(3))?; // Map size + + let mut write_heightmap = |index: i32, data: &[i64]| -> Result<(), WritingError> { + write.write_var_int(&VarInt(index))?; + write.write_var_int(&VarInt(data.len() as i32))?; + for val in data { + write.write_i64_be(*val)?; + } + Ok(()) + }; + + write_heightmap(1, self.world_surface.as_deref().unwrap_or(&[0; 37]))?; + write_heightmap(4, self.motion_blocking.as_deref().unwrap_or(&[0; 37]))?; + write_heightmap( + 5, + self.motion_blocking_no_leaves + .as_deref() + .unwrap_or(&[0; 37]), + )?; + } else { + let mut comp = NbtCompound::new(); + if let Some(ref ws) = self.world_surface { + comp.put("WORLD_SURFACE", NbtTag::LongArray(ws.clone())); + } + if let Some(ref mb) = self.motion_blocking { + comp.put("MOTION_BLOCKING", NbtTag::LongArray(mb.clone())); + } + if let Some(ref mbnl) = self.motion_blocking_no_leaves { + comp.put("MOTION_BLOCKING_NO_LEAVES", NbtTag::LongArray(mbnl.clone())); + } + write.write_compound_nbt_with_version(Some(&comp), version)?; + } + Ok(()) + } +} + +/// Block entity metadata serialized in chunk packets. +#[derive(Clone, Debug, PartialEq)] +pub struct ChunkBlockEntity { + pub packed_xz: u8, + pub y: i16, + pub type_id: VarInt, + pub data: NbtCompound, +} + +impl ChunkBlockEntity { + #[must_use] + pub const fn new(packed_xz: u8, y: i16, type_id: VarInt, data: NbtCompound) -> Self { + Self { + packed_xz, + y, + type_id, + data, + } + } +} + +/// The chunk data and light packet sent to clients (`LEVEL_CHUNK_WITH_LIGHT`). +/// +/// Contains chunk position, heightmaps, pre-encoded section and biome payload, +/// block entities, and lighting data. +#[derive(Clone, Debug, PartialEq)] +pub struct CChunkData<'a> { + pub chunk_x: i32, + pub chunk_z: i32, + pub heightmaps: ChunkHeightmaps, + pub data: &'a [u8], + pub block_entities: Vec, + pub light_data: LightData, +} + +impl MultiVersionJavaPacket for CChunkData<'_> { + fn to_id(version: JavaMinecraftVersion) -> i32 { + LEVEL_CHUNK_WITH_LIGHT.to_id(version) + } +} + +impl<'a> CChunkData<'a> { + #[must_use] + pub const fn new( + chunk_x: i32, + chunk_z: i32, + heightmaps: ChunkHeightmaps, + data: &'a [u8], + block_entities: Vec, + light_data: LightData, + ) -> Self { + Self { + chunk_x, + chunk_z, + heightmaps, + data, + block_entities, + light_data, + } + } +} + +impl ClientPacket for CChunkData<'_> { + fn write_packet_data( + &self, + mut write: impl Write, + version: &JavaMinecraftVersion, + ) -> Result<(), WritingError> { + write.write_i32_be(self.chunk_x)?; + write.write_i32_be(self.chunk_z)?; + + self.heightmaps.write_to(&mut write, version)?; + + write.write_var_int(&VarInt(self.data.len() as i32))?; + write.write_slice(self.data)?; + + write.write_var_int(&VarInt(self.block_entities.len() as i32))?; + for be in &self.block_entities { + write.write_u8(be.packed_xz)?; + write.write_i16_be(be.y)?; + write.write_var_int(&be.type_id)?; + write.write_compound_nbt_with_version(Some(&be.data), version)?; + } + + self.light_data.write(&mut write, version)?; + + Ok(()) + } +} diff --git a/crates/pumpkin-protocol/src/java/client/play/light_update.rs b/crates/pumpkin-protocol/src/java/client/play/light_update.rs index d5d212505..27df70a15 100644 --- a/crates/pumpkin-protocol/src/java/client/play/light_update.rs +++ b/crates/pumpkin-protocol/src/java/client/play/light_update.rs @@ -7,8 +7,6 @@ use crate::{ClientPacket, ServerPacket}; use pumpkin_data::packet::clientbound::play::LIGHT_UPDATE; use pumpkin_macros::java_packet; use pumpkin_util::version::JavaMinecraftVersion; -use pumpkin_world::chunk::ChunkData; -use pumpkin_world::chunk::format::LightContainer; /// Sent by the server to update light levels (block light and sky light) for a chunk. /// @@ -44,18 +42,6 @@ impl CLightUpdate { light_data, } } - - pub fn from_chunk( - chunk: &ChunkData, - version: JavaMinecraftVersion, - ) -> Result { - let light_data = LightData::from_chunk(chunk, version)?; - Ok(Self { - chunk_x: VarInt(chunk.x), - chunk_z: VarInt(chunk.z), - light_data, - }) - } } impl LightData { @@ -80,197 +66,6 @@ impl LightData { } } - #[expect(clippy::too_many_lines)] - pub fn from_chunk( - chunk: &ChunkData, - version: JavaMinecraftVersion, - ) -> Result { - let light_engine = chunk - .light_engine - .lock() - .map_err(|_| WritingError::Message("light_engine lock poisoned".into()))?; - - if version < JavaMinecraftVersion::V_1_18 { - let base_section = (0 - chunk.section.min_y).max(0) as usize / 16; - let mut sky_light_mask = 0u64; - let mut block_light_mask = 0u64; - let mut sky_light_empty_mask = 0u64; - let mut block_light_empty_mask = 0u64; - let mut sky_light_arrays = Vec::new(); - let mut block_light_arrays = Vec::new(); - - // Bit 0: Y = -1 (below world section 0) - if base_section > 0 && base_section - 1 < light_engine.sky_light.len() { - match &light_engine.sky_light[base_section - 1] { - LightContainer::Full(data) => { - sky_light_mask |= 1 << 0; - sky_light_arrays.push(data.to_vec()); - } - LightContainer::Empty(val) if *val > 0 => { - sky_light_mask |= 1 << 0; - sky_light_arrays.push(vec![*val << 4 | *val; 2048]); - } - LightContainer::Empty(_) => { - sky_light_empty_mask |= 1 << 0; - } - } - } else { - sky_light_empty_mask |= 1 << 0; - } - - if base_section > 0 && base_section - 1 < light_engine.block_light.len() { - match &light_engine.block_light[base_section - 1] { - LightContainer::Full(data) => { - block_light_mask |= 1 << 0; - block_light_arrays.push(data.to_vec()); - } - LightContainer::Empty(val) if *val > 0 => { - block_light_mask |= 1 << 0; - block_light_arrays.push(vec![*val << 4 | *val; 2048]); - } - LightContainer::Empty(_) => { - block_light_empty_mask |= 1 << 0; - } - } - } else { - block_light_empty_mask |= 1 << 0; - } - - // Bits 1..=16: world sections (Y = 0..15) - for i in 0..16 { - let bit_index = i + 1; - let sec_idx = base_section + i; - - if sec_idx < light_engine.sky_light.len() { - match &light_engine.sky_light[sec_idx] { - LightContainer::Full(data) => { - sky_light_mask |= 1 << bit_index; - sky_light_arrays.push(data.to_vec()); - } - LightContainer::Empty(val) if *val > 0 => { - sky_light_mask |= 1 << bit_index; - sky_light_arrays.push(vec![*val << 4 | *val; 2048]); - } - LightContainer::Empty(_) => { - sky_light_empty_mask |= 1 << bit_index; - } - } - } else { - sky_light_empty_mask |= 1 << bit_index; - } - - if sec_idx < light_engine.block_light.len() { - match &light_engine.block_light[sec_idx] { - LightContainer::Full(data) => { - block_light_mask |= 1 << bit_index; - block_light_arrays.push(data.to_vec()); - } - LightContainer::Empty(val) if *val > 0 => { - block_light_mask |= 1 << bit_index; - block_light_arrays.push(vec![*val << 4 | *val; 2048]); - } - LightContainer::Empty(_) => { - block_light_empty_mask |= 1 << bit_index; - } - } - } else { - block_light_empty_mask |= 1 << bit_index; - } - } - - // Bit 17: Y = 16 (above world section 15) - let top_sec = base_section + 16; - if top_sec < light_engine.sky_light.len() { - match &light_engine.sky_light[top_sec] { - LightContainer::Full(data) => { - sky_light_mask |= 1 << 17; - sky_light_arrays.push(data.to_vec()); - } - LightContainer::Empty(val) if *val > 0 => { - sky_light_mask |= 1 << 17; - sky_light_arrays.push(vec![*val << 4 | *val; 2048]); - } - LightContainer::Empty(_) => { - sky_light_empty_mask |= 1 << 17; - } - } - } else { - sky_light_empty_mask |= 1 << 17; - } - - if top_sec < light_engine.block_light.len() { - match &light_engine.block_light[top_sec] { - LightContainer::Full(data) => { - block_light_mask |= 1 << 17; - block_light_arrays.push(data.to_vec()); - } - LightContainer::Empty(val) if *val > 0 => { - block_light_mask |= 1 << 17; - block_light_arrays.push(vec![*val << 4 | *val; 2048]); - } - LightContainer::Empty(_) => { - block_light_empty_mask |= 1 << 17; - } - } - } else { - block_light_empty_mask |= 1 << 17; - } - - Ok(Self { - trust_edges: true, - sky_light_mask: BitSet::from_u64(sky_light_mask), - block_light_mask: BitSet::from_u64(block_light_mask), - empty_sky_light_mask: BitSet::from_u64(sky_light_empty_mask), - empty_block_light_mask: BitSet::from_u64(block_light_empty_mask), - sky_light_arrays, - block_light_arrays, - }) - } else { - let num_sections = light_engine.sky_light.len(); - let mut sky_light_empty_mask = 0u64; - let mut block_light_empty_mask = 0u64; - let mut sky_light_mask = 0u64; - let mut block_light_mask = 0u64; - - let mut sky_light_arrays = Vec::new(); - let mut block_light_arrays = Vec::new(); - - sky_light_empty_mask |= 1 << 0; - block_light_empty_mask |= 1 << 0; - - for section_index in 0..num_sections { - let bit_index = section_index + 1; - - if let LightContainer::Full(data) = &light_engine.sky_light[section_index] { - sky_light_mask |= 1 << bit_index; - sky_light_arrays.push(data.to_vec()); - } else { - sky_light_empty_mask |= 1 << bit_index; - } - - if let LightContainer::Full(data) = &light_engine.block_light[section_index] { - block_light_mask |= 1 << bit_index; - block_light_arrays.push(data.to_vec()); - } else { - block_light_empty_mask |= 1 << bit_index; - } - } - - sky_light_empty_mask |= 1 << (num_sections + 1); - block_light_empty_mask |= 1 << (num_sections + 1); - - Ok(Self { - trust_edges: true, - sky_light_mask: BitSet::from_u64(sky_light_mask), - block_light_mask: BitSet::from_u64(block_light_mask), - empty_sky_light_mask: BitSet::from_u64(sky_light_empty_mask), - empty_block_light_mask: BitSet::from_u64(block_light_empty_mask), - sky_light_arrays, - block_light_arrays, - }) - } - } - pub fn write( &self, mut write: impl Write, diff --git a/crates/pumpkin-protocol/src/java/client/play/mod.rs b/crates/pumpkin-protocol/src/java/client/play/mod.rs index 0851ba376..6e95e249c 100644 --- a/crates/pumpkin-protocol/src/java/client/play/mod.rs +++ b/crates/pumpkin-protocol/src/java/client/play/mod.rs @@ -16,7 +16,7 @@ mod center_chunk; mod change_difficulty; mod chunk_batch_end; mod chunk_batch_start; -mod chunk_data; +pub mod chunk_data; mod clear_dialog; mod clear_title; mod close_container; diff --git a/crates/pumpkin-protocol/src/java/client/play/server_data.rs b/crates/pumpkin-protocol/src/java/client/play/server_data.rs index a76400ceb..cdd5443d2 100644 --- a/crates/pumpkin-protocol/src/java/client/play/server_data.rs +++ b/crates/pumpkin-protocol/src/java/client/play/server_data.rs @@ -29,7 +29,9 @@ impl ClientPacket for CServerData<'_> { if let Some(icon) = self.icon_base64 { write.write_bool(true)?; let raw_b64 = icon.strip_prefix("data:image/png;base64,").unwrap_or(icon); - if let Ok(bytes) = pumpkin_util::jwt::decode_b64_standard(raw_b64) { + if let Ok(bytes) = + base64::Engine::decode(&base64::engine::general_purpose::STANDARD, raw_b64) + { write.write_slice(&bytes)?; } else { write.write_slice(&[])?; diff --git a/crates/pumpkin-util/Cargo.toml b/crates/pumpkin-util/Cargo.toml index f4fb121fb..29dde9657 100644 --- a/crates/pumpkin-util/Cargo.toml +++ b/crates/pumpkin-util/Cargo.toml @@ -23,16 +23,7 @@ proc-macro2 = { workspace = true, optional = true } uuid.workspace = true dashmap.workspace = true -base64.workspace = true -p384 = { workspace = true, features = ["ecdsa"] } thiserror.workspace = true -ecdsa.workspace = true -rsa.workspace = true -sha2.workspace = true -crypto-bigint.workspace = true -reqwest.workspace = true -rustls.workspace = true -webpki-root-certs.workspace = true [dev-dependencies] criterion = { workspace = true, features = ["html_reports"] } diff --git a/crates/pumpkin-util/src/lib.rs b/crates/pumpkin-util/src/lib.rs index 5119797bc..ce1646cd0 100644 --- a/crates/pumpkin-util/src/lib.rs +++ b/crates/pumpkin-util/src/lib.rs @@ -6,7 +6,6 @@ use serde::{Deserialize, Serialize}; use std::ops::{Index, IndexMut}; -pub use p384; pub use serde_json; pub use difficulty::Difficulty; @@ -32,14 +31,10 @@ pub mod version; pub mod world_seed; pub mod y_offset; -pub mod client; pub mod identifier; -pub mod jwt; pub mod resource; pub mod uuid; -pub use client::{client, client_builder}; - /// Represents the different types of height maps used for terrain generation and collision checks. #[derive(Deserialize, Clone, Copy, Debug, PartialEq, Eq)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] diff --git a/crates/pumpkin-world/src/block/entities.rs b/crates/pumpkin-world/src/block/entities.rs deleted file mode 100644 index 9e6d71fb6..000000000 --- a/crates/pumpkin-world/src/block/entities.rs +++ /dev/null @@ -1,11 +0,0 @@ -pub trait PropertyDelegate: Sync + Send { - fn get_property(&self, _index: i32) -> i32; - fn set_property(&self, _index: i32, _value: i32); - fn get_properties_size(&self) -> i32; -} - -/// Trait for extracting smelting experience from cooking block entities. -pub trait ExperienceContainer: Send + Sync { - /// Extract and reset accumulated experience, returning the total as an integer - fn extract_experience(&self) -> i32; -} diff --git a/crates/pumpkin-world/src/block/mod.rs b/crates/pumpkin-world/src/block/mod.rs index 320718cff..cc206acd3 100644 --- a/crates/pumpkin-world/src/block/mod.rs +++ b/crates/pumpkin-world/src/block/mod.rs @@ -1,6 +1,3 @@ -pub mod entities; -pub mod viewer; - use std::collections::HashMap; use pumpkin_data::{Block, BlockState, BlockStateId}; diff --git a/crates/pumpkin-world/src/lib.rs b/crates/pumpkin-world/src/lib.rs index bae5cd98a..ce50da23a 100644 --- a/crates/pumpkin-world/src/lib.rs +++ b/crates/pumpkin-world/src/lib.rs @@ -11,7 +11,6 @@ pub mod cylindrical_chunk_iterator; pub mod data; pub mod dimension; pub mod generation; -pub mod inventory; pub mod level; pub mod lighting; pub mod poi; diff --git a/crates/pumpkin/Cargo.toml b/crates/pumpkin/Cargo.toml index 8c4e3987b..e75507bb3 100644 --- a/crates/pumpkin/Cargo.toml +++ b/crates/pumpkin/Cargo.toml @@ -22,6 +22,7 @@ doctest = false arc-swap.workspace = true rayon.workspace = true pumpkin-util.workspace = true +pumpkin-auth.workspace = true pumpkin-nbt.workspace = true pumpkin-config.workspace = true pumpkin-command.workspace = true @@ -127,6 +128,8 @@ bitflags = { workspace = true } image = { version = "0.25.10", default-features = false, features = ["png"] } indexmap.workspace = true +xxhash-rust.workspace = true + [dev-dependencies] tempfile.workspace = true diff --git a/crates/pumpkin/src/block/blocks/anvil.rs b/crates/pumpkin/src/block/blocks/anvil.rs index c887d8fb3..35a6c3c76 100644 --- a/crates/pumpkin/src/block/blocks/anvil.rs +++ b/crates/pumpkin/src/block/blocks/anvil.rs @@ -8,6 +8,7 @@ use crate::block::{ use pumpkin_data::block_properties::WallTorchLikeProperties; use pumpkin_data::translation; use pumpkin_data::{Block, BlockState, BlockStateId}; +use pumpkin_inventory::SimpleInventory; use pumpkin_inventory::anvil::AnvilScreenHandler; use pumpkin_inventory::player::player_inventory::PlayerInventory; use pumpkin_inventory::screen_handler::{ @@ -15,7 +16,6 @@ use pumpkin_inventory::screen_handler::{ }; use pumpkin_macros::pumpkin_block_from_tag; use pumpkin_util::text::TextComponent; -use pumpkin_world::inventory::SimpleInventory; use std::sync::Arc; use std::sync::Mutex; diff --git a/crates/pumpkin/src/block/blocks/barrel.rs b/crates/pumpkin/src/block/blocks/barrel.rs index 9bb35a4e4..2f28ed54b 100644 --- a/crates/pumpkin/src/block/blocks/barrel.rs +++ b/crates/pumpkin/src/block/blocks/barrel.rs @@ -12,6 +12,7 @@ use crate::entity::EntityBase; use pumpkin_data::BlockStateId; use pumpkin_data::block_properties::BarrelLikeProperties; use pumpkin_data::translation; +use pumpkin_inventory::Inventory; use pumpkin_inventory::generic_container_screen_handler::create_generic_9x3; use pumpkin_inventory::player::player_inventory::PlayerInventory; use pumpkin_inventory::screen_handler::{ @@ -19,7 +20,6 @@ use pumpkin_inventory::screen_handler::{ }; use pumpkin_macros::pumpkin_block; use pumpkin_util::text::TextComponent; -use pumpkin_world::inventory::Inventory; struct BarrelScreenFactory(Arc); diff --git a/crates/pumpkin/src/block/blocks/beacon.rs b/crates/pumpkin/src/block/blocks/beacon.rs index a7484b315..a1ee4e7bf 100644 --- a/crates/pumpkin/src/block/blocks/beacon.rs +++ b/crates/pumpkin/src/block/blocks/beacon.rs @@ -2,6 +2,7 @@ use std::sync::Arc; use std::sync::Mutex; use pumpkin_data::translation; +use pumpkin_inventory::Inventory; use pumpkin_inventory::beacon_screen_handler::create_beacon_handler; use pumpkin_inventory::player::player_inventory::PlayerInventory; use pumpkin_inventory::screen_handler::{ @@ -9,7 +10,6 @@ use pumpkin_inventory::screen_handler::{ }; use pumpkin_macros::pumpkin_block; use pumpkin_util::text::TextComponent; -use pumpkin_world::inventory::Inventory; use crate::block::registry::BlockActionResult; use crate::block::{BlockBehaviour, GetScreenHandlerFactoryArgs, NormalUseArgs}; diff --git a/crates/pumpkin/src/block/blocks/blast_furnace.rs b/crates/pumpkin/src/block/blocks/blast_furnace.rs index 099415ad3..bdbc5a5cd 100644 --- a/crates/pumpkin/src/block/blocks/blast_furnace.rs +++ b/crates/pumpkin/src/block/blocks/blast_furnace.rs @@ -8,13 +8,13 @@ use crate::block::entities::{ use pumpkin_data::{ BlockStateId, block_properties::FurnaceLikeProperties, screen::WindowType, translation, }; +use pumpkin_inventory::Inventory; use pumpkin_inventory::{ furnace_like::furnace_like_screen_handler::FurnaceLikeScreenHandler, player::player_inventory::PlayerInventory, screen_handler::{InventoryPlayer, ScreenHandlerFactory, SharedScreenHandler}, }; use pumpkin_macros::pumpkin_block; -use pumpkin_world::inventory::Inventory; use crate::{ block::{ diff --git a/crates/pumpkin/src/block/blocks/brewing_stand.rs b/crates/pumpkin/src/block/blocks/brewing_stand.rs index ecfe2eca9..044f2536f 100644 --- a/crates/pumpkin/src/block/blocks/brewing_stand.rs +++ b/crates/pumpkin/src/block/blocks/brewing_stand.rs @@ -12,13 +12,13 @@ use crate::block::{ use crate::block::entities::brewing_stand::BrewingStandBlockEntity; use pumpkin_data::BlockState; use pumpkin_data::translation; +use pumpkin_inventory::Inventory; use pumpkin_inventory::player::player_inventory::PlayerInventory; use pumpkin_inventory::screen_handler::{ InventoryPlayer, ScreenHandlerFactory, SharedScreenHandler, }; use pumpkin_macros::pumpkin_block; use pumpkin_util::text::TextComponent; -use pumpkin_world::inventory::Inventory; struct BrewingScreenFactory( Arc, diff --git a/crates/pumpkin/src/block/blocks/chests.rs b/crates/pumpkin/src/block/blocks/chests.rs index c5cbbcc8b..88e356f68 100644 --- a/crates/pumpkin/src/block/blocks/chests.rs +++ b/crates/pumpkin/src/block/blocks/chests.rs @@ -7,6 +7,7 @@ use pumpkin_data::block_properties::{ChestLikeProperties, ChestType, HorizontalF use pumpkin_data::entity::EntityPose; use pumpkin_data::loot_table::get_loot_table; use pumpkin_data::{Block, BlockDirection, translation}; +use pumpkin_inventory::Inventory; use pumpkin_inventory::double::DoubleInventory; use pumpkin_inventory::generic_container_screen_handler::{create_generic_9x3, create_generic_9x6}; use pumpkin_inventory::player::player_inventory::PlayerInventory; @@ -17,7 +18,6 @@ use pumpkin_macros::{pumpkin_block, pumpkin_block_from_tag}; use pumpkin_util::GameMode; use pumpkin_util::math::position::BlockPos; use pumpkin_util::text::TextComponent; -use pumpkin_world::inventory::Inventory; use pumpkin_world::world::BlockFlags; use std::sync::Mutex; diff --git a/crates/pumpkin/src/block/blocks/cobweb.rs b/crates/pumpkin/src/block/blocks/cobweb.rs index 7a4b2881d..25e1c00bf 100644 --- a/crates/pumpkin/src/block/blocks/cobweb.rs +++ b/crates/pumpkin/src/block/blocks/cobweb.rs @@ -4,7 +4,7 @@ use pumpkin_data::effect::StatusEffect; use pumpkin_macros::pumpkin_block; use pumpkin_util::math::vector3::Vector3; -#[pumpkin_block("minecraft:cobweb")] +#[pumpkin_block(Block::COBWEB)] pub struct CobwebBlock; impl BlockBehaviour for CobwebBlock { diff --git a/crates/pumpkin/src/block/blocks/enchanting_table.rs b/crates/pumpkin/src/block/blocks/enchanting_table.rs index b541cca3c..19b98c397 100644 --- a/crates/pumpkin/src/block/blocks/enchanting_table.rs +++ b/crates/pumpkin/src/block/blocks/enchanting_table.rs @@ -12,10 +12,10 @@ use pumpkin_inventory::player::player_inventory::PlayerInventory; use pumpkin_inventory::screen_handler::{ InventoryPlayer, ScreenHandlerFactory, SharedScreenHandler, }; +use pumpkin_inventory::{Inventory, SimpleInventory}; use pumpkin_macros::pumpkin_block; use pumpkin_util::math::position::BlockPos; use pumpkin_util::text::TextComponent; -use pumpkin_world::inventory::{Inventory, SimpleInventory}; #[pumpkin_block("minecraft:enchanting_table")] pub struct EnchantingTableBlock; diff --git a/crates/pumpkin/src/block/blocks/ender_chest.rs b/crates/pumpkin/src/block/blocks/ender_chest.rs index 5b4453424..6e2f28aa2 100644 --- a/crates/pumpkin/src/block/blocks/ender_chest.rs +++ b/crates/pumpkin/src/block/blocks/ender_chest.rs @@ -9,6 +9,7 @@ use crate::block::{ use crate::world::World; use pumpkin_data::block_properties::LadderLikeProperties; use pumpkin_data::{BlockState, BlockStateId, translation}; +use pumpkin_inventory::ViewerCountTracker; use pumpkin_inventory::{ generic_container_screen_handler::create_generic_9x3, player::ender_chest_inventory::EnderChestInventory, @@ -18,7 +19,6 @@ use pumpkin_inventory::{ use pumpkin_macros::pumpkin_block; use pumpkin_util::math::position::BlockPos; use pumpkin_util::text::TextComponent; -use pumpkin_world::block::viewer::ViewerCountTracker; pub struct EnderChestScreenFactory { pub inventory: Arc, diff --git a/crates/pumpkin/src/block/blocks/furnace.rs b/crates/pumpkin/src/block/blocks/furnace.rs index 0502835ab..3259f5801 100644 --- a/crates/pumpkin/src/block/blocks/furnace.rs +++ b/crates/pumpkin/src/block/blocks/furnace.rs @@ -7,13 +7,13 @@ use crate::block::entities::{ use pumpkin_data::{ BlockStateId, block_properties::FurnaceLikeProperties, screen::WindowType, translation, }; +use pumpkin_inventory::Inventory; use pumpkin_inventory::{ furnace_like::furnace_like_screen_handler::FurnaceLikeScreenHandler, player::player_inventory::PlayerInventory, screen_handler::{InventoryPlayer, ScreenHandlerFactory, SharedScreenHandler}, }; use pumpkin_macros::pumpkin_block; -use pumpkin_world::inventory::Inventory; use crate::{ block::{ diff --git a/crates/pumpkin/src/block/blocks/grindstone.rs b/crates/pumpkin/src/block/blocks/grindstone.rs index abf940cac..7e0492bd3 100644 --- a/crates/pumpkin/src/block/blocks/grindstone.rs +++ b/crates/pumpkin/src/block/blocks/grindstone.rs @@ -6,6 +6,7 @@ use pumpkin_data::{ Block, BlockDirection, BlockStateId, HorizontalFacingExt, block_properties::{AttachFace, GrindstoneLikeProperties}, }; +use pumpkin_inventory::SimpleInventory; use pumpkin_inventory::grindstone_screen_handler::GrindstoneScreenHandler; use pumpkin_inventory::player::player_inventory::PlayerInventory; use pumpkin_inventory::screen_handler::{ @@ -14,7 +15,6 @@ use pumpkin_inventory::screen_handler::{ use pumpkin_macros::pumpkin_block; use pumpkin_util::math::position::BlockPos; use pumpkin_util::text::TextComponent; -use pumpkin_world::inventory::SimpleInventory; use pumpkin_world::world::BlockAccessor; use crate::block::registry::BlockActionResult; diff --git a/crates/pumpkin/src/block/blocks/hopper.rs b/crates/pumpkin/src/block/blocks/hopper.rs index d1ce8ccce..91b97a72b 100644 --- a/crates/pumpkin/src/block/blocks/hopper.rs +++ b/crates/pumpkin/src/block/blocks/hopper.rs @@ -15,6 +15,7 @@ use crate::world::World; use crate::block::entities::hopper::HopperBlockEntity; use pumpkin_data::block_properties::FacingHopper; use pumpkin_data::{Block, BlockDirection, BlockState, BlockStateId, translation}; +use pumpkin_inventory::Inventory; use pumpkin_inventory::generic_container_screen_handler::create_hopper; use pumpkin_inventory::player::player_inventory::PlayerInventory; use pumpkin_inventory::screen_handler::{ @@ -23,7 +24,6 @@ use pumpkin_inventory::screen_handler::{ use pumpkin_macros::pumpkin_block; use pumpkin_util::math::position::BlockPos; use pumpkin_util::text::TextComponent; -use pumpkin_world::inventory::Inventory; use pumpkin_world::world::BlockFlags; struct HopperBlockScreenFactory(Arc); diff --git a/crates/pumpkin/src/block/blocks/lectern.rs b/crates/pumpkin/src/block/blocks/lectern.rs index 72b44ac2a..d72a01e2a 100644 --- a/crates/pumpkin/src/block/blocks/lectern.rs +++ b/crates/pumpkin/src/block/blocks/lectern.rs @@ -17,6 +17,7 @@ use pumpkin_data::sound::{Sound, SoundCategory}; use pumpkin_data::tag::Taggable; use pumpkin_data::world::WorldEvent; use pumpkin_data::{Block, BlockDirection, BlockState, BlockStateId, tag, translation}; +use pumpkin_inventory::Inventory; use pumpkin_inventory::lectern_screen_handler::{LecternController, LecternScreenHandler}; use pumpkin_inventory::player::player_inventory::PlayerInventory; use pumpkin_inventory::screen_handler::{ @@ -26,7 +27,6 @@ use pumpkin_macros::pumpkin_block; use pumpkin_util::math::position::BlockPos; use pumpkin_util::math::vector3::Vector3; use pumpkin_util::text::TextComponent; -use pumpkin_world::inventory::Inventory; use pumpkin_world::tick::TickPriority; use pumpkin_world::world::BlockFlags; use std::sync::Mutex; diff --git a/crates/pumpkin/src/block/blocks/redstone/crafter.rs b/crates/pumpkin/src/block/blocks/redstone/crafter.rs index 49ecf3e86..8bf37dc92 100644 --- a/crates/pumpkin/src/block/blocks/redstone/crafter.rs +++ b/crates/pumpkin/src/block/blocks/redstone/crafter.rs @@ -21,6 +21,7 @@ use pumpkin_data::recipe_remainder::get_recipe_remainder_id; use pumpkin_data::translation; use pumpkin_data::world::WorldEvent; use pumpkin_data::{Block, BlockDirection, BlockStateId}; +use pumpkin_inventory::Inventory; use pumpkin_inventory::crafting::crafting_screen_handler::match_crafting_recipe; use pumpkin_inventory::generic_container_screen_handler::create_crafter_3x3; use pumpkin_inventory::player::player_inventory::PlayerInventory; @@ -31,7 +32,6 @@ use pumpkin_macros::pumpkin_block; use pumpkin_util::math::position::BlockPos; use pumpkin_util::math::vector3::Vector3; use pumpkin_util::text::TextComponent; -use pumpkin_world::inventory::Inventory; use pumpkin_world::tick::TickPriority; use pumpkin_world::world::BlockFlags; diff --git a/crates/pumpkin/src/block/blocks/redstone/dispenser.rs b/crates/pumpkin/src/block/blocks/redstone/dispenser.rs index b2e380e5c..11fb55762 100644 --- a/crates/pumpkin/src/block/blocks/redstone/dispenser.rs +++ b/crates/pumpkin/src/block/blocks/redstone/dispenser.rs @@ -47,6 +47,7 @@ use pumpkin_data::sound::{Sound, SoundCategory}; use pumpkin_data::translation; use pumpkin_data::world::WorldEvent; use pumpkin_data::{Block, BlockStateId, FacingExt}; +use pumpkin_inventory::Inventory; use pumpkin_inventory::generic_container_screen_handler::create_generic_3x3; use pumpkin_inventory::player::player_inventory::PlayerInventory; use pumpkin_inventory::screen_handler::{ @@ -58,7 +59,6 @@ use pumpkin_util::math::position::BlockPos; use pumpkin_util::math::vector3::Vector3; use pumpkin_util::math::wrap_degrees; use pumpkin_util::text::TextComponent; -use pumpkin_world::inventory::Inventory; use pumpkin_world::tick::TickPriority; use pumpkin_world::world::BlockFlags; diff --git a/crates/pumpkin/src/block/blocks/redstone/dropper.rs b/crates/pumpkin/src/block/blocks/redstone/dropper.rs index e08377259..b70b18229 100644 --- a/crates/pumpkin/src/block/blocks/redstone/dropper.rs +++ b/crates/pumpkin/src/block/blocks/redstone/dropper.rs @@ -18,6 +18,7 @@ use pumpkin_data::block_properties::Facing; use pumpkin_data::entity::EntityType; use pumpkin_data::world::WorldEvent; use pumpkin_data::{FacingExt, translation}; +use pumpkin_inventory::Inventory; use pumpkin_inventory::generic_container_screen_handler::create_generic_3x3; use pumpkin_inventory::player::player_inventory::PlayerInventory; use pumpkin_inventory::screen_handler::{ @@ -26,7 +27,6 @@ use pumpkin_inventory::screen_handler::{ use pumpkin_macros::pumpkin_block; use pumpkin_util::math::vector3::Vector3; use pumpkin_util::text::TextComponent; -use pumpkin_world::inventory::Inventory; use pumpkin_world::tick::TickPriority; use pumpkin_world::world::BlockFlags; diff --git a/crates/pumpkin/src/block/blocks/shelf.rs b/crates/pumpkin/src/block/blocks/shelf.rs index 4c151d4c8..827a0e516 100644 --- a/crates/pumpkin/src/block/blocks/shelf.rs +++ b/crates/pumpkin/src/block/blocks/shelf.rs @@ -1,7 +1,7 @@ use pumpkin_data::block_properties::AcaciaShelfLikeProperties; use pumpkin_data::{BlockState, BlockStateId}; +use pumpkin_inventory::Inventory; use pumpkin_macros::pumpkin_block_from_tag; -use pumpkin_world::inventory::Inventory; use crate::block::entities::shelf::ShelfBlockEntity; use crate::block::{ diff --git a/crates/pumpkin/src/block/blocks/shulker_box.rs b/crates/pumpkin/src/block/blocks/shulker_box.rs index 05733d723..6427d6282 100644 --- a/crates/pumpkin/src/block/blocks/shulker_box.rs +++ b/crates/pumpkin/src/block/blocks/shulker_box.rs @@ -13,6 +13,7 @@ use crate::block::{ use crate::block::entities::shulker_box::ShulkerBoxBlockEntity; use pumpkin_data::BlockStateId; use pumpkin_data::translation; +use pumpkin_inventory::Inventory; use pumpkin_inventory::generic_container_screen_handler::create_generic_9x3; use pumpkin_inventory::player::player_inventory::PlayerInventory; use pumpkin_inventory::screen_handler::{ @@ -20,7 +21,6 @@ use pumpkin_inventory::screen_handler::{ }; use pumpkin_macros::pumpkin_block_from_tag; use pumpkin_util::text::TextComponent; -use pumpkin_world::inventory::Inventory; struct ShulkerBoxScreenFactory(Arc); diff --git a/crates/pumpkin/src/block/blocks/smoker.rs b/crates/pumpkin/src/block/blocks/smoker.rs index e9e07eacb..322ad26cf 100644 --- a/crates/pumpkin/src/block/blocks/smoker.rs +++ b/crates/pumpkin/src/block/blocks/smoker.rs @@ -7,13 +7,13 @@ use crate::block::entities::{ use pumpkin_data::{ BlockStateId, block_properties::FurnaceLikeProperties, screen::WindowType, translation, }; +use pumpkin_inventory::Inventory; use pumpkin_inventory::{ furnace_like::furnace_like_screen_handler::FurnaceLikeScreenHandler, player::player_inventory::PlayerInventory, screen_handler::{InventoryPlayer, ScreenHandlerFactory, SharedScreenHandler}, }; use pumpkin_macros::pumpkin_block; -use pumpkin_world::inventory::Inventory; use crate::{ block::{ diff --git a/crates/pumpkin/src/block/entities/barrel.rs b/crates/pumpkin/src/block/entities/barrel.rs index b645eadb5..d88aa8e52 100644 --- a/crates/pumpkin/src/block/entities/barrel.rs +++ b/crates/pumpkin/src/block/entities/barrel.rs @@ -18,7 +18,7 @@ use std::{ use crate::block::viewer::{ViewerCountListener, ViewerCountTracker, ViewerCountTrackerExt}; use crate::world::{BlockFlags, World}; -use pumpkin_world::inventory::{Clearable, Inventory, sync_write_items_to_nbt}; +use pumpkin_inventory::{Clearable, Inventory, sync_write_items_to_nbt}; use super::BlockEntity; @@ -51,7 +51,7 @@ impl BlockEntity for BarrelBlockEntity { viewers: ViewerCountTracker::new(), }; - pumpkin_world::inventory::sync_read_items_from_nbt( + pumpkin_inventory::sync_read_items_from_nbt( nbt, barrel .items diff --git a/crates/pumpkin/src/block/entities/beacon.rs b/crates/pumpkin/src/block/entities/beacon.rs index d698365f3..6af863f79 100644 --- a/crates/pumpkin/src/block/entities/beacon.rs +++ b/crates/pumpkin/src/block/entities/beacon.rs @@ -12,7 +12,7 @@ use pumpkin_util::math::position::BlockPos; use crate::block::entities::BlockEntity; use crate::world::World; -use pumpkin_world::inventory::{Clearable, Inventory}; +use pumpkin_inventory::{Clearable, Inventory}; pub struct BeaconBlockEntity { pub position: BlockPos, diff --git a/crates/pumpkin/src/block/entities/blasting_furnace.rs b/crates/pumpkin/src/block/entities/blasting_furnace.rs index 616e80a77..3aee254eb 100644 --- a/crates/pumpkin/src/block/entities/blasting_furnace.rs +++ b/crates/pumpkin/src/block/entities/blasting_furnace.rs @@ -1,5 +1,5 @@ use pumpkin_data::item_stack::ItemStack; -use pumpkin_world::inventory::Inventory; +use pumpkin_inventory::Inventory; use std::{ array::from_fn, diff --git a/crates/pumpkin/src/block/entities/brewing_stand.rs b/crates/pumpkin/src/block/entities/brewing_stand.rs index cb4446bb1..82cba7952 100644 --- a/crates/pumpkin/src/block/entities/brewing_stand.rs +++ b/crates/pumpkin/src/block/entities/brewing_stand.rs @@ -11,10 +11,10 @@ use pumpkin_data::item_stack::ItemStack; use pumpkin_data::potion_brewing::{ITEM_RECIPES, POTION_RECIPES}; use pumpkin_data::sound::{Sound, SoundCategory}; use pumpkin_data::tag::{self, Taggable}; +use pumpkin_inventory::{Inventory, sync_read_items_from_nbt, sync_write_items_to_nbt}; use pumpkin_nbt::compound::NbtCompound; use pumpkin_util::math::position::BlockPos; use pumpkin_util::math::vector3::Vector3; -use pumpkin_world::inventory::{Inventory, sync_read_items_from_nbt, sync_write_items_to_nbt}; pub struct BrewingStandBlockEntity { pub position: BlockPos, @@ -276,7 +276,7 @@ impl BrewingStandBlockEntity { } } -impl pumpkin_world::inventory::Inventory for BrewingStandBlockEntity { +impl pumpkin_inventory::Inventory for BrewingStandBlockEntity { fn size(&self) -> usize { Self::INVENTORY_SIZE } @@ -376,7 +376,7 @@ impl pumpkin_world::inventory::Inventory for BrewingStandBlockEntity { } } -impl pumpkin_world::inventory::Clearable for BrewingStandBlockEntity { +impl pumpkin_inventory::Clearable for BrewingStandBlockEntity { fn clear(&self) { let mut items = self .items diff --git a/crates/pumpkin/src/block/entities/chest_like_block_entity.rs b/crates/pumpkin/src/block/entities/chest_like_block_entity.rs index b0d7ec2c4..7f953a5e7 100644 --- a/crates/pumpkin/src/block/entities/chest_like_block_entity.rs +++ b/crates/pumpkin/src/block/entities/chest_like_block_entity.rs @@ -40,7 +40,7 @@ macro_rules! impl_block_entity_for_chest { .unwrap_or_else(std::sync::PoisonError::into_inner) .is_some(); if !has_loot_table { - pumpkin_world::inventory::sync_read_items_from_nbt( + pumpkin_inventory::sync_read_items_from_nbt( nbt, chest .items @@ -53,7 +53,7 @@ macro_rules! impl_block_entity_for_chest { } fn write_nbt(&self, nbt: &mut pumpkin_nbt::compound::NbtCompound) { - use pumpkin_world::inventory::Inventory; + use pumpkin_inventory::Inventory; let loot_table_key = { let guard = self @@ -84,9 +84,7 @@ macro_rules! impl_block_entity_for_chest { ); } - fn get_inventory( - self: Arc, - ) -> Option> { + fn get_inventory(self: Arc) -> Option> { Some(self) } @@ -108,7 +106,7 @@ macro_rules! impl_block_entity_for_chest { .is_some(); if !has_loot_table { if let Ok(items) = self.items.try_read() { - pumpkin_world::inventory::sync_write_items_to_nbt(&*items, &mut nbt); + pumpkin_inventory::sync_write_items_to_nbt(&*items, &mut nbt); } } Some(nbt) @@ -140,7 +138,7 @@ macro_rules! impl_block_entity_for_chest { #[macro_export] macro_rules! impl_inventory_for_chest { ($struct_name:ty) => { - impl pumpkin_world::inventory::Inventory for $struct_name { + impl pumpkin_inventory::Inventory for $struct_name { fn size(&self) -> usize { Self::INVENTORY_SIZE } @@ -217,14 +215,14 @@ macro_rules! impl_inventory_for_chest { #[macro_export] macro_rules! impl_clearable_for_chest { ($struct_name:ty) => { - impl pumpkin_world::inventory::Clearable for $struct_name { + impl pumpkin_inventory::Clearable for $struct_name { fn clear(&self) { let mut items = self .items .write() .unwrap_or_else(std::sync::PoisonError::into_inner); items.fill_with(|| ItemStack::EMPTY.clone()); - <$struct_name as pumpkin_world::inventory::Inventory>::mark_dirty(self); + <$struct_name as pumpkin_inventory::Inventory>::mark_dirty(self); } } }; diff --git a/crates/pumpkin/src/block/entities/chiseled_bookshelf.rs b/crates/pumpkin/src/block/entities/chiseled_bookshelf.rs index 49c5a0586..d25914e36 100644 --- a/crates/pumpkin/src/block/entities/chiseled_bookshelf.rs +++ b/crates/pumpkin/src/block/entities/chiseled_bookshelf.rs @@ -18,7 +18,7 @@ use crate::{ block::entities::BlockEntity, world::{BlockFlags, World}, }; -use pumpkin_world::inventory::{Clearable, Inventory, sync_write_items_to_nbt}; +use pumpkin_inventory::{Clearable, Inventory, sync_write_items_to_nbt}; pub struct ChiseledBookshelfBlockEntity { pub position: BlockPos, @@ -48,7 +48,7 @@ impl BlockEntity for ChiseledBookshelfBlockEntity { last_interacted_slot: AtomicI8::new(-1), dirty: AtomicBool::new(false), }; - pumpkin_world::inventory::sync_read_items_from_nbt( + pumpkin_inventory::sync_read_items_from_nbt( nbt, bookshelf .items diff --git a/crates/pumpkin/src/block/entities/crafter.rs b/crates/pumpkin/src/block/entities/crafter.rs index a324f7df4..d9414b991 100644 --- a/crates/pumpkin/src/block/entities/crafter.rs +++ b/crates/pumpkin/src/block/entities/crafter.rs @@ -3,12 +3,10 @@ use crate::world::World; use pumpkin_data::block_properties::CrafterLikeProperties; use pumpkin_data::item_stack::ItemStack; use pumpkin_inventory::crafting::recipes::RecipeInputInventory; +use pumpkin_inventory::{Clearable, Inventory, sync_read_items_from_nbt, sync_write_items_to_nbt}; use pumpkin_nbt::compound::NbtCompound; use pumpkin_nbt::tag::NbtTag; use pumpkin_util::math::position::BlockPos; -use pumpkin_world::inventory::{ - Clearable, Inventory, sync_read_items_from_nbt, sync_write_items_to_nbt, -}; use pumpkin_world::world::BlockFlags; use std::any::Any; use std::array::from_fn; diff --git a/crates/pumpkin/src/block/entities/dispenser.rs b/crates/pumpkin/src/block/entities/dispenser.rs index cac502ce8..702b7e3f8 100644 --- a/crates/pumpkin/src/block/entities/dispenser.rs +++ b/crates/pumpkin/src/block/entities/dispenser.rs @@ -1,8 +1,8 @@ use crate::block::entities::BlockEntity; use pumpkin_data::item_stack::ItemStack; +use pumpkin_inventory::{Clearable, Inventory, sync_write_items_to_nbt}; use pumpkin_nbt::compound::NbtCompound; use pumpkin_util::math::position::BlockPos; -use pumpkin_world::inventory::{Clearable, Inventory, sync_write_items_to_nbt}; use rand::{RngExt, rng}; use std::any::Any; use std::array::from_fn; @@ -31,7 +31,7 @@ impl BlockEntity for DispenserBlockEntity { dirty: AtomicBool::new(false), }; - pumpkin_world::inventory::sync_read_items_from_nbt( + pumpkin_inventory::sync_read_items_from_nbt( nbt, dispenser .items diff --git a/crates/pumpkin/src/block/entities/dropper.rs b/crates/pumpkin/src/block/entities/dropper.rs index a445dd543..87d178445 100644 --- a/crates/pumpkin/src/block/entities/dropper.rs +++ b/crates/pumpkin/src/block/entities/dropper.rs @@ -1,8 +1,8 @@ use crate::block::entities::BlockEntity; use pumpkin_data::item_stack::ItemStack; +use pumpkin_inventory::{Clearable, Inventory, sync_write_items_to_nbt}; use pumpkin_nbt::compound::NbtCompound; use pumpkin_util::math::position::BlockPos; -use pumpkin_world::inventory::{Clearable, Inventory, sync_write_items_to_nbt}; use rand::{RngExt, rng}; use std::any::Any; use std::array::from_fn; @@ -31,7 +31,7 @@ impl BlockEntity for DropperBlockEntity { dirty: AtomicBool::new(false), }; - pumpkin_world::inventory::sync_read_items_from_nbt( + pumpkin_inventory::sync_read_items_from_nbt( nbt, dropper .items diff --git a/crates/pumpkin/src/block/entities/furnace.rs b/crates/pumpkin/src/block/entities/furnace.rs index a2105be02..81ed841b6 100644 --- a/crates/pumpkin/src/block/entities/furnace.rs +++ b/crates/pumpkin/src/block/entities/furnace.rs @@ -1,4 +1,4 @@ -use pumpkin_world::inventory::Inventory; +use pumpkin_inventory::Inventory; use std::{ array::from_fn, diff --git a/crates/pumpkin/src/block/entities/furnace_like_block_entity.rs b/crates/pumpkin/src/block/entities/furnace_like_block_entity.rs index 495bcbb93..c69e8c375 100644 --- a/crates/pumpkin/src/block/entities/furnace_like_block_entity.rs +++ b/crates/pumpkin/src/block/entities/furnace_like_block_entity.rs @@ -1,8 +1,8 @@ use pumpkin_data::{item_stack::ItemStack, recipes::CookingRecipe}; use crate::block::entities::{BlockEntity, PropertyDelegate}; -pub use pumpkin_world::block::entities::ExperienceContainer; -use pumpkin_world::inventory::{Clearable, Inventory}; +pub use pumpkin_inventory::ExperienceContainer; +use pumpkin_inventory::{Clearable, Inventory}; /// Trait for extracting smelting experience from cooking block entities. pub trait CookingBlockEntityBase: @@ -239,7 +239,7 @@ macro_rules! impl_property_delegate_for_cooking { #[macro_export] macro_rules! impl_clearable_for_cooking { ($struct_name:ty) => { - impl pumpkin_world::inventory::Clearable for $struct_name { + impl pumpkin_inventory::Clearable for $struct_name { fn clear(&self) { let mut items = self .items @@ -269,7 +269,7 @@ macro_rules! impl_experience_container_for_cooking { #[macro_export] macro_rules! impl_inventory_for_cooking { ($struct_name:ty) => { - impl pumpkin_world::inventory::Inventory for $struct_name { + impl pumpkin_inventory::Inventory for $struct_name { fn size(&self) -> usize { Self::INVENTORY_SIZE } @@ -567,7 +567,7 @@ macro_rules! impl_block_entity_for_cooking { lit_time_remaining, recipes_used: std::sync::Mutex::new(recipes_used_map), }; - pumpkin_world::inventory::sync_read_items_from_nbt(nbt, furnace.items.get_mut().unwrap_or_else(std::sync::PoisonError::into_inner)); + pumpkin_inventory::sync_read_items_from_nbt(nbt, furnace.items.get_mut().unwrap_or_else(std::sync::PoisonError::into_inner)); furnace } @@ -604,7 +604,7 @@ macro_rules! impl_block_entity_for_cooking { fn get_inventory( self: Arc, - ) -> Option> { + ) -> Option> { Some(self) } @@ -636,7 +636,7 @@ macro_rules! impl_block_entity_for_cooking { } if let Ok(guard) = self.items.try_read() { - pumpkin_world::inventory::sync_write_items_to_nbt(&*guard, &mut nbt); + pumpkin_inventory::sync_write_items_to_nbt(&*guard, &mut nbt); } Some(nbt) } diff --git a/crates/pumpkin/src/block/entities/hopper.rs b/crates/pumpkin/src/block/entities/hopper.rs index f82f9c0fb..b5e0a193f 100644 --- a/crates/pumpkin/src/block/entities/hopper.rs +++ b/crates/pumpkin/src/block/entities/hopper.rs @@ -6,11 +6,11 @@ use pumpkin_data::block_properties::{FacingHopper, HopperLikeProperties}; use pumpkin_data::item_stack::ItemStack; use pumpkin_data::tag; use pumpkin_data::tag::Taggable; +use pumpkin_inventory::{Clearable, Inventory, sync_write_items_to_nbt}; use pumpkin_nbt::compound::NbtCompound; use pumpkin_nbt::tag::NbtTag; use pumpkin_util::math::position::BlockPos; use pumpkin_util::math::vector3::Vector3; -use pumpkin_world::inventory::{Clearable, Inventory, sync_write_items_to_nbt}; use std::any::Any; use std::array::from_fn; use std::sync::Arc; @@ -61,7 +61,7 @@ impl BlockEntity for HopperBlockEntity { ticked_game_time: AtomicI64::new(0), }; - pumpkin_world::inventory::sync_read_items_from_nbt( + pumpkin_inventory::sync_read_items_from_nbt( nbt, hopper .items diff --git a/crates/pumpkin/src/block/entities/jukebox.rs b/crates/pumpkin/src/block/entities/jukebox.rs index f87b6be2d..7ae73f85a 100644 --- a/crates/pumpkin/src/block/entities/jukebox.rs +++ b/crates/pumpkin/src/block/entities/jukebox.rs @@ -9,7 +9,7 @@ use pumpkin_util::math::position::BlockPos; use crate::block::entities::BlockEntity; use crate::world::World; -use pumpkin_world::inventory::{Clearable, Inventory}; +use pumpkin_inventory::{Clearable, Inventory}; /// Matches vanilla's `JukeboxBlockEntity` pub struct JukeboxBlockEntity { diff --git a/crates/pumpkin/src/block/entities/lectern.rs b/crates/pumpkin/src/block/entities/lectern.rs index 93c5e7ed6..53637d3ad 100644 --- a/crates/pumpkin/src/block/entities/lectern.rs +++ b/crates/pumpkin/src/block/entities/lectern.rs @@ -12,7 +12,7 @@ use std::{ }; use crate::block::entities::BlockEntity; -use pumpkin_world::inventory::{Clearable, Inventory}; +use pumpkin_inventory::{Clearable, Inventory}; pub struct LecternBlockEntity { pub position: BlockPos, diff --git a/crates/pumpkin/src/block/entities/mod.rs b/crates/pumpkin/src/block/entities/mod.rs index d1c9f5a3c..3ad4bcb8b 100644 --- a/crates/pumpkin/src/block/entities/mod.rs +++ b/crates/pumpkin/src/block/entities/mod.rs @@ -6,7 +6,7 @@ use pumpkin_util::math::position::BlockPos; use crate::world::World; use pumpkin_data::BlockStateId; -use pumpkin_world::inventory::Inventory; +use pumpkin_inventory::Inventory; pub mod barrel; pub mod beacon; @@ -64,7 +64,7 @@ pub mod trial_spawner; pub mod vault; pub use furnace_like_block_entity::ExperienceContainer; -pub use pumpkin_world::block::entities::PropertyDelegate; +pub use pumpkin_inventory::PropertyDelegate; //TODO: We need a mark_dirty for chests pub trait BlockEntity: Any + Send + Sync { @@ -429,9 +429,9 @@ pub fn create_block_entity( mod test { use super::{BlockEntity, block_entity_from_nbt, furnace::FurnaceBlockEntity}; use pumpkin_data::{item::Item, item_stack::ItemStack}; + use pumpkin_inventory::Inventory; use pumpkin_nbt::compound::NbtCompound; use pumpkin_util::math::position::BlockPos; - use pumpkin_world::inventory::Inventory; use std::sync::Arc; /// A loaded block entity is serialized back into its chunk with diff --git a/crates/pumpkin/src/block/entities/shelf.rs b/crates/pumpkin/src/block/entities/shelf.rs index 31fef26cc..a12897c66 100644 --- a/crates/pumpkin/src/block/entities/shelf.rs +++ b/crates/pumpkin/src/block/entities/shelf.rs @@ -1,8 +1,8 @@ use crate::block::entities::BlockEntity; use pumpkin_data::item_stack::ItemStack; +use pumpkin_inventory::{Clearable, Inventory, sync_write_items_to_nbt}; use pumpkin_nbt::compound::NbtCompound; use pumpkin_util::math::position::BlockPos; -use pumpkin_world::inventory::{Clearable, Inventory, sync_write_items_to_nbt}; use std::any::Any; use std::array::from_fn; use std::sync::Arc; @@ -36,7 +36,7 @@ impl BlockEntity for ShelfBlockEntity { dirty: AtomicBool::new(false), }; - pumpkin_world::inventory::sync_read_items_from_nbt( + pumpkin_inventory::sync_read_items_from_nbt( nbt, shelf .items diff --git a/crates/pumpkin/src/block/entities/shulker_box.rs b/crates/pumpkin/src/block/entities/shulker_box.rs index d527c1c49..46244d076 100644 --- a/crates/pumpkin/src/block/entities/shulker_box.rs +++ b/crates/pumpkin/src/block/entities/shulker_box.rs @@ -10,7 +10,7 @@ use std::{array::from_fn, sync::Arc}; use crate::block::entities::BlockEntity; use crate::block::viewer::{ViewerCountListener, ViewerCountTracker, ViewerCountTrackerExt}; use crate::world::World; -use pumpkin_world::inventory::{Clearable, Inventory, sync_write_items_to_nbt}; +use pumpkin_inventory::{Clearable, Inventory, sync_write_items_to_nbt}; pub struct ShulkerBoxBlockEntity { pub position: BlockPos, @@ -41,7 +41,7 @@ impl BlockEntity for ShulkerBoxBlockEntity { viewers: ViewerCountTracker::new(), }; - pumpkin_world::inventory::sync_read_items_from_nbt( + pumpkin_inventory::sync_read_items_from_nbt( nbt, shulker_box .items diff --git a/crates/pumpkin/src/block/entities/smoker.rs b/crates/pumpkin/src/block/entities/smoker.rs index e17d67ebd..022fc58bc 100644 --- a/crates/pumpkin/src/block/entities/smoker.rs +++ b/crates/pumpkin/src/block/entities/smoker.rs @@ -1,5 +1,5 @@ use pumpkin_data::item_stack::ItemStack; -use pumpkin_world::inventory::Inventory; +use pumpkin_inventory::Inventory; use std::{ array::from_fn, diff --git a/crates/pumpkin/src/block/mod.rs b/crates/pumpkin/src/block/mod.rs index baf304d1e..734633fa5 100644 --- a/crates/pumpkin/src/block/mod.rs +++ b/crates/pumpkin/src/block/mod.rs @@ -548,7 +548,7 @@ impl BlockIsReplacing { } } -pub fn calculate_comparator_output(inventory: &dyn pumpkin_world::inventory::Inventory) -> u8 { +pub fn calculate_comparator_output(inventory: &dyn pumpkin_inventory::Inventory) -> u8 { let size = inventory.size(); if size == 0 { return 0; diff --git a/crates/pumpkin/src/block/viewer.rs b/crates/pumpkin/src/block/viewer.rs index d0f256f5d..bdbf6f503 100644 --- a/crates/pumpkin/src/block/viewer.rs +++ b/crates/pumpkin/src/block/viewer.rs @@ -4,7 +4,7 @@ use pumpkin_util::math::position::BlockPos; use crate::{block::entities::BlockEntity, world::World}; -pub use pumpkin_world::block::viewer::ViewerCountTracker; +pub use pumpkin_inventory::ViewerCountTracker; pub trait ViewerCountTrackerExt { fn update_viewer_count(&self, entity: &T, world: &Arc, position: &BlockPos) diff --git a/crates/pumpkin/src/command/commands/fillbiome.rs b/crates/pumpkin/src/command/commands/fillbiome.rs index c00bfa9d9..b893d7efc 100644 --- a/crates/pumpkin/src/command/commands/fillbiome.rs +++ b/crates/pumpkin/src/command/commands/fillbiome.rs @@ -7,8 +7,8 @@ use crate::command::context::command_context::CommandContext; use crate::command::errors::error_types::CommandErrorType; use crate::command::node::dispatcher::CommandDispatcher; use crate::command::node::{CommandExecutor, CommandExecutorResult}; +use crate::net::java::chunk_data::CChunkData; use pumpkin_data::translation; -use pumpkin_protocol::java::client::play::CChunkData; use pumpkin_util::PermissionLvl; use pumpkin_util::math::vector2::Vector2; use pumpkin_util::permission::{Permission, PermissionDefault, PermissionRegistry}; diff --git a/crates/pumpkin/src/command/commands/item.rs b/crates/pumpkin/src/command/commands/item.rs index e1f7c5c68..f7893bc0a 100644 --- a/crates/pumpkin/src/command/commands/item.rs +++ b/crates/pumpkin/src/command/commands/item.rs @@ -1,5 +1,6 @@ use pumpkin_data::data_component_impl::EquipmentSlot; use pumpkin_data::translation; +use pumpkin_inventory::Inventory; use pumpkin_inventory::screen_handler::InventoryPlayer; use pumpkin_protocol::codec::item_stack_seralizer::ItemStackSerializer; use pumpkin_protocol::java::client::play::CSetContainerSlot; @@ -7,7 +8,6 @@ use pumpkin_util::PermissionLvl; use pumpkin_util::permission::{Permission, PermissionDefault, PermissionRegistry}; use pumpkin_util::text::TextComponent; use pumpkin_util::text::hover::HoverEvent; -use pumpkin_world::inventory::Inventory; use crate::command::argument_builder::{ ArgumentBuilder, RequiredArgumentBuilder, argument, command, literal, diff --git a/crates/pumpkin/src/command/commands/loot.rs b/crates/pumpkin/src/command/commands/loot.rs index 637d0896d..07e6b5fa5 100644 --- a/crates/pumpkin/src/command/commands/loot.rs +++ b/crates/pumpkin/src/command/commands/loot.rs @@ -1,6 +1,7 @@ use pumpkin_data::data_component_impl::EquipmentSlot; use pumpkin_data::item_stack::ItemStack; use pumpkin_data::translation; +use pumpkin_inventory::Inventory; use pumpkin_inventory::screen_handler::InventoryPlayer; use pumpkin_protocol::codec::item_stack_seralizer::ItemStackSerializer; use pumpkin_protocol::java::client::play::CSetContainerSlot; @@ -10,7 +11,6 @@ use pumpkin_util::math::vector3::Vector3; use pumpkin_util::permission::{Permission, PermissionDefault, PermissionRegistry}; use pumpkin_util::text::TextComponent; use pumpkin_util::text::hover::HoverEvent; -use pumpkin_world::inventory::Inventory; use crate::command::argument_builder::{ ArgumentBuilder, LiteralArgumentBuilder, argument, command, literal, diff --git a/crates/pumpkin/src/command/commands/pumpkin.rs b/crates/pumpkin/src/command/commands/pumpkin.rs index 0045511a9..5eafb3471 100644 --- a/crates/pumpkin/src/command/commands/pumpkin.rs +++ b/crates/pumpkin/src/command/commands/pumpkin.rs @@ -81,7 +81,7 @@ fn fetch_all_contributors_cached() -> Vec { } async fn fetch_all_contributors() -> Vec { - let client = pumpkin_util::client_builder() + let client = pumpkin_auth::client_builder() .user_agent("Pumpkin-MC") .build() .unwrap_or_default(); @@ -196,7 +196,7 @@ fn tier_color(tier_slug: &str, tier_name: &str) -> NamedColor { async fn fetch_donators_hover() -> TextComponent { let url = "https://market.pumpkinmc.org/api/v1/rest/donators"; - let client = pumpkin_util::client_builder() + let client = pumpkin_auth::client_builder() .user_agent("Pumpkin-MC") .build() .unwrap_or_default(); diff --git a/crates/pumpkin/src/entity/passive/villager/mod.rs b/crates/pumpkin/src/entity/passive/villager/mod.rs index bf6bd17bd..16121db45 100644 --- a/crates/pumpkin/src/entity/passive/villager/mod.rs +++ b/crates/pumpkin/src/entity/passive/villager/mod.rs @@ -14,6 +14,7 @@ use pumpkin_data::item_stack::ItemStack; use pumpkin_data::potion::Effect; use pumpkin_data::tag::{Enchantment as EnchantmentTag, Taggable}; use pumpkin_data::tracked_data; +use pumpkin_inventory::SimpleInventory; use pumpkin_inventory::merchant::merchant_screen_handler::MerchantScreenHandler; use pumpkin_inventory::screen_handler::{ InventoryPlayer, ScreenHandlerFactory, SharedScreenHandler, @@ -29,7 +30,6 @@ use pumpkin_protocol::java::client::play::{CMerchantOffers, Metadata}; use pumpkin_util::math::{boundingbox::BoundingBox, position::BlockPos, vector3::Vector3}; use pumpkin_util::text::TextComponent; use pumpkin_util::version::JavaMinecraftVersion; -use pumpkin_world::inventory::SimpleInventory; use crate::entity::player::Player; use crate::entity::{ diff --git a/crates/pumpkin/src/entity/passive/wandering_trader.rs b/crates/pumpkin/src/entity/passive/wandering_trader.rs index 62b82c05d..9b3f1880a 100644 --- a/crates/pumpkin/src/entity/passive/wandering_trader.rs +++ b/crates/pumpkin/src/entity/passive/wandering_trader.rs @@ -15,6 +15,7 @@ use pumpkin_data::villager::{ TRADES_WANDERING_TRADER_BUYING, TRADES_WANDERING_TRADER_COMMON, TRADES_WANDERING_TRADER_UNCOMMON, VillagerTrade, VillagerTradeModifier, }; +use pumpkin_inventory::SimpleInventory; use pumpkin_inventory::merchant::merchant_screen_handler::MerchantScreenHandler; use pumpkin_inventory::screen_handler::{ InventoryPlayer, ScreenHandlerFactory, SharedScreenHandler, @@ -26,7 +27,6 @@ use pumpkin_protocol::java::client::play::CMerchantOffers; use pumpkin_util::math::position::BlockPos; use pumpkin_util::math::vector3::Vector3; use pumpkin_util::text::TextComponent; -use pumpkin_world::inventory::SimpleInventory; use rand::RngExt; use rand::seq::IndexedRandom; diff --git a/crates/pumpkin/src/entity/player.rs b/crates/pumpkin/src/entity/player.rs index 63a97c211..ae60a9f64 100644 --- a/crates/pumpkin/src/entity/player.rs +++ b/crates/pumpkin/src/entity/player.rs @@ -19,6 +19,7 @@ use crossbeam::atomic::AtomicCell; use crossbeam::channel::Receiver; use crossbeam::queue::SegQueue; use pumpkin_data::dimension::Dimension; +use pumpkin_inventory::Inventory; use pumpkin_inventory::merchant::merchant_screen_handler::MerchantScreenHandler; use pumpkin_inventory::player::ender_chest_inventory::EnderChestInventory; use pumpkin_protocol::RawPacket; @@ -43,7 +44,6 @@ use pumpkin_protocol::codec::item_stack_seralizer::ItemStackSerializer; use pumpkin_util::translation::Locale; use pumpkin_util::version::JavaMinecraftVersion; use pumpkin_world::chunk::ChunkData; -use pumpkin_world::inventory::Inventory; use tokio::task::JoinHandle; use tracing::{debug, warn}; use uuid::Uuid; @@ -575,13 +575,13 @@ impl Player { let bytes = if let Ok(handle) = tokio::runtime::Handle::try_current() { tokio::task::block_in_place(|| { handle.block_on(async { - let client = pumpkin_util::client(); + let client = pumpkin_auth::client(); client.get(&url).send().await.ok()?.bytes().await.ok() }) })? } else { tokio::runtime::Runtime::new().ok()?.block_on(async { - let client = pumpkin_util::client(); + let client = pumpkin_auth::client(); client.get(&url).send().await.ok()?.bytes().await.ok() })? }; diff --git a/crates/pumpkin/src/entity/vehicle/minecart.rs b/crates/pumpkin/src/entity/vehicle/minecart.rs index e4b2856c1..e5c9a339f 100644 --- a/crates/pumpkin/src/entity/vehicle/minecart.rs +++ b/crates/pumpkin/src/entity/vehicle/minecart.rs @@ -22,11 +22,11 @@ use pumpkin_data::entity::EntityType; use pumpkin_data::item::Item; use pumpkin_data::item_stack::ItemStack; use pumpkin_data::tag::{self, Taggable}; +use pumpkin_inventory::Inventory; use pumpkin_nbt::compound::NbtCompound; use pumpkin_util::GameMode; use pumpkin_util::math::position::BlockPos; use pumpkin_util::math::vector3::Vector3; -use pumpkin_world::inventory::Inventory; use crate::entity::vehicle::vehicle::VehicleEntity; use chest::ChestMinecart; diff --git a/crates/pumpkin/src/entity/vehicle/minecart/container.rs b/crates/pumpkin/src/entity/vehicle/minecart/container.rs index b7ccc1c48..5419459f0 100644 --- a/crates/pumpkin/src/entity/vehicle/minecart/container.rs +++ b/crates/pumpkin/src/entity/vehicle/minecart/container.rs @@ -9,10 +9,10 @@ use pumpkin_inventory::player::player_inventory::PlayerInventory; use pumpkin_inventory::screen_handler::{ InventoryPlayer, ScreenHandlerFactory, SharedScreenHandler, }; +use pumpkin_inventory::{Clearable, Inventory}; use pumpkin_nbt::compound::NbtCompound; use pumpkin_util::math::vector3::Vector3; use pumpkin_util::text::TextComponent; -use pumpkin_world::inventory::{Clearable, Inventory}; use crate::entity::{Entity, player::Player}; use crate::world::loot::fill_chest_inventory; @@ -273,8 +273,8 @@ mod tests { use super::MinecartInventory; use pumpkin_data::item::Item; use pumpkin_data::item_stack::ItemStack; + use pumpkin_inventory::Inventory; use pumpkin_nbt::compound::NbtCompound; - use pumpkin_world::inventory::Inventory; #[test] fn deferred_mineshaft_loot_is_preserved_until_unpacked() { diff --git a/crates/pumpkin/src/entity/vehicle/minecart/hopper.rs b/crates/pumpkin/src/entity/vehicle/minecart/hopper.rs index e63a3176f..ba5863b42 100644 --- a/crates/pumpkin/src/entity/vehicle/minecart/hopper.rs +++ b/crates/pumpkin/src/entity/vehicle/minecart/hopper.rs @@ -147,7 +147,7 @@ impl HopperMinecart { #[cfg(test)] mod tests { use super::HopperMinecart; - use pumpkin_world::inventory::Inventory; + use pumpkin_inventory::Inventory; #[test] fn hopper_minecart_inventory_has_five_slots() { diff --git a/crates/pumpkin/src/net/authentication.rs b/crates/pumpkin/src/net/authentication.rs index f344d1978..9718d0a54 100644 --- a/crates/pumpkin/src/net/authentication.rs +++ b/crates/pumpkin/src/net/authentication.rs @@ -55,7 +55,7 @@ const MOJANG_PROFILE_BY_UUID_URL: &str = "https://sessionserver.mojang.com/session/minecraft/profile/{uuid}?unsigned=false"; fn create_client(auth_config: &AuthenticationConfig) -> reqwest::Client { - pumpkin_util::client_builder() + pumpkin_auth::client_builder() .connect_timeout(std::time::Duration::from_millis( auth_config.connect_timeout as u64, )) diff --git a/crates/pumpkin-protocol/src/bedrock/client/level_chunk.rs b/crates/pumpkin/src/net/bedrock/level_chunk.rs similarity index 98% rename from crates/pumpkin-protocol/src/bedrock/client/level_chunk.rs rename to crates/pumpkin/src/net/bedrock/level_chunk.rs index a269bf298..f33e202fe 100644 --- a/crates/pumpkin-protocol/src/bedrock/client/level_chunk.rs +++ b/crates/pumpkin/src/net/bedrock/level_chunk.rs @@ -1,14 +1,13 @@ use std::io::{Error, Write}; use xxhash_rust::xxh64::xxh64; -use pumpkin_macros::packet; use pumpkin_nbt::{Nbt, compound::NbtCompound}; use pumpkin_world::chunk::{ ChunkData, palette::{BeNetworkSerialization, NetworkPalette}, }; -use crate::{ +use pumpkin_protocol::{ codec::{var_int::VarInt, var_uint::VarUInt}, serial::PacketWrite, }; @@ -38,7 +37,6 @@ fn write_block_storage( Ok(()) } -#[packet(58)] pub struct CLevelChunk<'a> { // https://mojang.github.io/bedrock-protocol-docs/html/LevelChunkPacket.html pub dimension: i32, @@ -50,6 +48,10 @@ pub struct CLevelChunk<'a> { pub block_actors: &'a [NbtCompound], } +impl pumpkin_protocol::packet::Packet for CLevelChunk<'_> { + const PACKET_ID: i32 = 58; +} + pub type ChunkBlob = (u64, Vec); pub type EncodedChunk = (Vec, Vec); @@ -202,7 +204,7 @@ mod tests { use pumpkin_world::chunk::ChunkData; use super::{CLevelChunk, VERSION}; - use crate::serial::PacketWrite; + use pumpkin_protocol::serial::PacketWrite; fn read_var_uint(data: &[u8], offset: &mut usize) -> u32 { let mut value = 0; diff --git a/crates/pumpkin/src/net/bedrock/login/login.rs b/crates/pumpkin/src/net/bedrock/login/login.rs index c6cdf7ac7..9203349e6 100644 --- a/crates/pumpkin/src/net/bedrock/login/login.rs +++ b/crates/pumpkin/src/net/bedrock/login/login.rs @@ -58,7 +58,7 @@ impl BedrockClient { } } } else { - pumpkin_util::jwt::extract_oidc_token_player_claims(&auth_payload.token)? + pumpkin_auth::jwt::extract_oidc_token_player_claims(&auth_payload.token)? }; let raw_token_str = std::str::from_utf8(&packet.raw_token).map_err(|_| { @@ -71,7 +71,7 @@ impl BedrockClient { let _header = parts.next().ok_or(AuthError::InvalidTokenFormat)?; let payload_b64 = parts.next().ok_or(AuthError::InvalidTokenFormat)?; - let payload_bytes = pumpkin_util::jwt::decode_b64_url_nopad(payload_b64) + let payload_bytes = pumpkin_auth::jwt::decode_b64_url_nopad(payload_b64) .map_err(|_| LoginError::DecodeExtraError)?; let client_data: ClientData = serde_json::from_slice(&payload_bytes)?; @@ -89,7 +89,7 @@ impl BedrockClient { profile_actions: None, }; - let login_public_key = pumpkin_util::jwt::extract_cpk_from_token(&auth_payload.token) + let login_public_key = pumpkin_auth::jwt::extract_cpk_from_token(&auth_payload.token) .map_err(LoginError::ChainValidationFailed)?; if self .nethernet_public_key() diff --git a/crates/pumpkin/src/net/bedrock/login/mod.rs b/crates/pumpkin/src/net/bedrock/login/mod.rs index b01f71b75..9eb1be228 100644 --- a/crates/pumpkin/src/net/bedrock/login/mod.rs +++ b/crates/pumpkin/src/net/bedrock/login/mod.rs @@ -5,6 +5,7 @@ use crate::{ server::Server, }; use arc_swap::ArcSwap; +use pumpkin_auth::jwt::AuthError; use pumpkin_protocol::bedrock::{ client::{ network_settings::CNetworkSettings, play_status::CPlayStatus, @@ -17,7 +18,6 @@ use pumpkin_protocol::bedrock::{ client::{resource_pack_stack::PackInstanceId, resource_packs_info::PackInfoData}, server::{login::ClientData, resource_pack_client_response::SResourcePackClientResponse}, }; -use pumpkin_util::jwt::AuthError; use pumpkin_util::version::BedrockMinecraftVersion; use pumpkin_world::{CURRENT_BEDROCK_MC_PROTOCOL, CURRENT_BEDROCK_MC_VERSION}; use serde::{Deserialize, de::Error}; @@ -65,12 +65,12 @@ async fn verify_oidc_token_path( server: &Server, token: &str, self_signed: bool, -) -> Result { +) -> Result { let token = token.to_string(); let (tx, rx) = tokio::sync::oneshot::channel(); if self_signed { rayon::spawn(move || { - let res = pumpkin_util::jwt::verify_oidc_token_self_signed(&token) + let res = pumpkin_auth::jwt::verify_oidc_token_self_signed(&token) .map_err(LoginError::ChainValidationFailed); let _ = tx.send(res); }); @@ -85,7 +85,7 @@ async fn verify_oidc_token_path( ))?; rayon::spawn(move || { - let res = pumpkin_util::jwt::verify_oidc_token(&token, &issuer, &jwks) + let res = pumpkin_auth::jwt::verify_oidc_token(&token, &issuer, &jwks) .map_err(LoginError::ChainValidationFailed); let _ = tx.send(res); }); diff --git a/crates/pumpkin/src/net/bedrock/mod.rs b/crates/pumpkin/src/net/bedrock/mod.rs index 7f6170787..1d73683fc 100644 --- a/crates/pumpkin/src/net/bedrock/mod.rs +++ b/crates/pumpkin/src/net/bedrock/mod.rs @@ -23,7 +23,6 @@ use pumpkin_protocol::{ client::{ client_cache_miss_response::{CClientCacheMissResponse, MissingBlobData}, disconnect::CDisconnect, - level_chunk::CLevelChunk, }, packet_decoder::BedrockBatchDecoder, packet_encoder::BedrockBatchEncoder, @@ -54,7 +53,9 @@ use tokio::{ use tokio_util::{sync::CancellationToken, task::TaskTracker}; +pub mod level_chunk; pub mod login; +use self::level_chunk::CLevelChunk; use self::nethernet::NetherNetSession; use crate::{ entity::player::Player, @@ -291,7 +292,7 @@ impl BedrockClient { } } - pub fn nethernet_public_key(&self) -> Option<&pumpkin_util::p384::PublicKey> { + pub fn nethernet_public_key(&self) -> Option<&pumpkin_auth::p384::PublicKey> { self.session.client_public_key() } diff --git a/crates/pumpkin/src/net/bedrock/nethernet.rs b/crates/pumpkin/src/net/bedrock/nethernet.rs index 8057b844f..d8d7c50f2 100644 --- a/crates/pumpkin/src/net/bedrock/nethernet.rs +++ b/crates/pumpkin/src/net/bedrock/nethernet.rs @@ -24,8 +24,8 @@ use axum::{ }; use base64::{Engine, engine::general_purpose}; use bytes::{BufMut, BytesMut}; -use pumpkin_util::jwt::Jwks; -use pumpkin_util::p384::{ +use pumpkin_auth::jwt::Jwks; +use pumpkin_auth::p384::{ PublicKey, ecdsa::{ Signature, SigningKey, @@ -834,12 +834,12 @@ fn verify_and_strip_identity( { return Err("invalid identity provider".to_string()); } - pumpkin_util::jwt::verify_oidc_token(token, issuer, keys) + pumpkin_auth::jwt::verify_oidc_token(token, issuer, keys) .map_err(|error| format!("invalid GameServerToken: {error}"))?; } else { validate_token_expiration(token)?; } - let public_key = pumpkin_util::jwt::extract_cpk_from_token(token) + let public_key = pumpkin_auth::jwt::extract_cpk_from_token(token) .map_err(|error| format!("invalid identity public key: {error}"))?; let fingerprints = assertion["fingerprints"] .as_str() @@ -916,7 +916,7 @@ fn verify_fingerprint_assertion( .map_err(|error| format!("invalid fingerprint signature: {error}"))?; let signature = Signature::from_slice(&signature) .map_err(|error| format!("invalid ES384 signature: {error}"))?; - let verifying_key = pumpkin_util::p384::ecdsa::VerifyingKey::from(public_key); + let verifying_key = pumpkin_auth::p384::ecdsa::VerifyingKey::from(public_key); verifying_key .verify(format!("{header}.{payload_b64}").as_bytes(), &signature) .map_err(|_| "fingerprint signature verification failed".to_string()) diff --git a/crates/pumpkin/src/net/bedrock/play/mod.rs b/crates/pumpkin/src/net/bedrock/play/mod.rs index 74209c222..f0a14db2d 100644 --- a/crates/pumpkin/src/net/bedrock/play/mod.rs +++ b/crates/pumpkin/src/net/bedrock/play/mod.rs @@ -48,7 +48,7 @@ use pumpkin_protocol::{ }; use pumpkin_util::{GameMode, Hand, math::position::BlockPos, text::TextComponent}; -use pumpkin_world::inventory::Inventory; +use pumpkin_inventory::Inventory; use pumpkin_world::world::BlockFlags; use crate::{ diff --git a/crates/pumpkin/src/net/chunk_sender.rs b/crates/pumpkin/src/net/chunk_sender.rs index efaa2a650..76e6bf01c 100644 --- a/crates/pumpkin/src/net/chunk_sender.rs +++ b/crates/pumpkin/src/net/chunk_sender.rs @@ -3,9 +3,10 @@ use rayon::prelude::*; use rustc_hash::{FxHashMap, FxHashSet}; use std::sync::{Arc, Weak}; +use crate::net::java::chunk_data::{CChunkData, ChunkLightExt}; use pumpkin_protocol::codec::var_int::VarInt; use pumpkin_protocol::java::client::play::{ - CChunkBatchEnd, CChunkBatchStart, CChunkData, CLightUpdate, CUnloadChunk, + CChunkBatchEnd, CChunkBatchStart, CLightUpdate, CUnloadChunk, }; use pumpkin_protocol::ser::NetworkWriteExt; use pumpkin_protocol::{ClientPacket, MultiVersionJavaPacket}; diff --git a/crates/pumpkin/src/net/java/chunk_data/light.rs b/crates/pumpkin/src/net/java/chunk_data/light.rs new file mode 100644 index 000000000..94e7dafa4 --- /dev/null +++ b/crates/pumpkin/src/net/java/chunk_data/light.rs @@ -0,0 +1,215 @@ +use pumpkin_protocol::codec::bit_set::BitSet; +use pumpkin_protocol::codec::var_int::VarInt; +use pumpkin_protocol::java::client::play::{CLightUpdate, LightData}; +use pumpkin_protocol::ser::WritingError; +use pumpkin_util::version::JavaMinecraftVersion; +use pumpkin_world::chunk::ChunkData; +use pumpkin_world::chunk::format::LightContainer; + +pub trait ChunkLightExt { + fn from_chunk(chunk: &ChunkData, version: JavaMinecraftVersion) -> Result + where + Self: Sized; +} + +impl ChunkLightExt for CLightUpdate { + fn from_chunk(chunk: &ChunkData, version: JavaMinecraftVersion) -> Result { + let light_data = light_data_from_chunk(chunk, version)?; + Ok(Self { + chunk_x: VarInt(chunk.x), + chunk_z: VarInt(chunk.z), + light_data, + }) + } +} + +#[expect(clippy::too_many_lines)] +pub fn light_data_from_chunk( + chunk: &ChunkData, + version: JavaMinecraftVersion, +) -> Result { + let light_engine = chunk + .light_engine + .lock() + .map_err(|_| WritingError::Message("light_engine lock poisoned".into()))?; + + if version < JavaMinecraftVersion::V_1_18 { + let base_section = (0 - chunk.section.min_y).max(0) as usize / 16; + let mut sky_light_mask = 0u64; + let mut block_light_mask = 0u64; + let mut sky_light_empty_mask = 0u64; + let mut block_light_empty_mask = 0u64; + let mut sky_light_arrays = Vec::new(); + let mut block_light_arrays = Vec::new(); + + // Bit 0: Y = -1 (below world section 0) + if base_section > 0 && base_section - 1 < light_engine.sky_light.len() { + match &light_engine.sky_light[base_section - 1] { + LightContainer::Full(data) => { + sky_light_mask |= 1 << 0; + sky_light_arrays.push(data.to_vec()); + } + LightContainer::Empty(val) if *val > 0 => { + sky_light_mask |= 1 << 0; + sky_light_arrays.push(vec![*val << 4 | *val; 2048]); + } + LightContainer::Empty(_) => { + sky_light_empty_mask |= 1 << 0; + } + } + } else { + sky_light_empty_mask |= 1 << 0; + } + + if base_section > 0 && base_section - 1 < light_engine.block_light.len() { + match &light_engine.block_light[base_section - 1] { + LightContainer::Full(data) => { + block_light_mask |= 1 << 0; + block_light_arrays.push(data.to_vec()); + } + LightContainer::Empty(val) if *val > 0 => { + block_light_mask |= 1 << 0; + block_light_arrays.push(vec![*val << 4 | *val; 2048]); + } + LightContainer::Empty(_) => { + block_light_empty_mask |= 1 << 0; + } + } + } else { + block_light_empty_mask |= 1 << 0; + } + + // Bits 1..=16: world sections (Y = 0..15) + for i in 0..16 { + let bit_index = i + 1; + let sec_idx = base_section + i; + + if sec_idx < light_engine.sky_light.len() { + match &light_engine.sky_light[sec_idx] { + LightContainer::Full(data) => { + sky_light_mask |= 1 << bit_index; + sky_light_arrays.push(data.to_vec()); + } + LightContainer::Empty(val) if *val > 0 => { + sky_light_mask |= 1 << bit_index; + sky_light_arrays.push(vec![*val << 4 | *val; 2048]); + } + LightContainer::Empty(_) => { + sky_light_empty_mask |= 1 << bit_index; + } + } + } else { + sky_light_empty_mask |= 1 << bit_index; + } + + if sec_idx < light_engine.block_light.len() { + match &light_engine.block_light[sec_idx] { + LightContainer::Full(data) => { + block_light_mask |= 1 << bit_index; + block_light_arrays.push(data.to_vec()); + } + LightContainer::Empty(val) if *val > 0 => { + block_light_mask |= 1 << bit_index; + block_light_arrays.push(vec![*val << 4 | *val; 2048]); + } + LightContainer::Empty(_) => { + block_light_empty_mask |= 1 << bit_index; + } + } + } else { + block_light_empty_mask |= 1 << bit_index; + } + } + + // Bit 17: Y = 16 (above world section 15) + let top_sec = base_section + 16; + if top_sec < light_engine.sky_light.len() { + match &light_engine.sky_light[top_sec] { + LightContainer::Full(data) => { + sky_light_mask |= 1 << 17; + sky_light_arrays.push(data.to_vec()); + } + LightContainer::Empty(val) if *val > 0 => { + sky_light_mask |= 1 << 17; + sky_light_arrays.push(vec![*val << 4 | *val; 2048]); + } + LightContainer::Empty(_) => { + sky_light_empty_mask |= 1 << 17; + } + } + } else { + sky_light_empty_mask |= 1 << 17; + } + + if top_sec < light_engine.block_light.len() { + match &light_engine.block_light[top_sec] { + LightContainer::Full(data) => { + block_light_mask |= 1 << 17; + block_light_arrays.push(data.to_vec()); + } + LightContainer::Empty(val) if *val > 0 => { + block_light_mask |= 1 << 17; + block_light_arrays.push(vec![*val << 4 | *val; 2048]); + } + LightContainer::Empty(_) => { + block_light_empty_mask |= 1 << 17; + } + } + } else { + block_light_empty_mask |= 1 << 17; + } + + Ok(LightData { + trust_edges: true, + sky_light_mask: BitSet::from_u64(sky_light_mask), + block_light_mask: BitSet::from_u64(block_light_mask), + empty_sky_light_mask: BitSet::from_u64(sky_light_empty_mask), + empty_block_light_mask: BitSet::from_u64(block_light_empty_mask), + sky_light_arrays, + block_light_arrays, + }) + } else { + let num_sections = light_engine.sky_light.len(); + let mut sky_light_empty_mask = 0u64; + let mut block_light_empty_mask = 0u64; + let mut sky_light_mask = 0u64; + let mut block_light_mask = 0u64; + + let mut sky_light_arrays = Vec::new(); + let mut block_light_arrays = Vec::new(); + + sky_light_empty_mask |= 1 << 0; + block_light_empty_mask |= 1 << 0; + + for section_index in 0..num_sections { + let bit_index = section_index + 1; + + if let LightContainer::Full(data) = &light_engine.sky_light[section_index] { + sky_light_mask |= 1 << bit_index; + sky_light_arrays.push(data.to_vec()); + } else { + sky_light_empty_mask |= 1 << bit_index; + } + + if let LightContainer::Full(data) = &light_engine.block_light[section_index] { + block_light_mask |= 1 << bit_index; + block_light_arrays.push(data.to_vec()); + } else { + block_light_empty_mask |= 1 << bit_index; + } + } + + sky_light_empty_mask |= 1 << (num_sections + 1); + block_light_empty_mask |= 1 << (num_sections + 1); + + Ok(LightData { + trust_edges: true, + sky_light_mask: BitSet::from_u64(sky_light_mask), + block_light_mask: BitSet::from_u64(block_light_mask), + empty_sky_light_mask: BitSet::from_u64(sky_light_empty_mask), + empty_block_light_mask: BitSet::from_u64(block_light_empty_mask), + sky_light_arrays, + block_light_arrays, + }) + } +} diff --git a/crates/pumpkin-protocol/src/java/client/play/chunk_data/mod.rs b/crates/pumpkin/src/net/java/chunk_data/mod.rs similarity index 96% rename from crates/pumpkin-protocol/src/java/client/play/chunk_data/mod.rs rename to crates/pumpkin/src/net/java/chunk_data/mod.rs index 58b21c679..c42baa1eb 100644 --- a/crates/pumpkin-protocol/src/java/client/play/chunk_data/mod.rs +++ b/crates/pumpkin/src/net/java/chunk_data/mod.rs @@ -1,12 +1,16 @@ +pub mod light; pub mod util; pub mod v1_18; pub mod v1_7; pub mod v1_8; pub mod v1_9; -use crate::packet::MultiVersionJavaPacket; -use crate::{ClientPacket, WritingError}; +pub use light::ChunkLightExt; + use pumpkin_data::packet::clientbound::play::LEVEL_CHUNK_WITH_LIGHT; +use pumpkin_protocol::ClientPacket; +use pumpkin_protocol::packet::MultiVersionJavaPacket; +use pumpkin_protocol::ser::WritingError; use pumpkin_util::version::JavaMinecraftVersion; use pumpkin_world::chunk::ChunkData; use std::io::Write; diff --git a/crates/pumpkin-protocol/src/java/client/play/chunk_data/util.rs b/crates/pumpkin/src/net/java/chunk_data/util.rs similarity index 97% rename from crates/pumpkin-protocol/src/java/client/play/chunk_data/util.rs rename to crates/pumpkin/src/net/java/chunk_data/util.rs index 974600674..e1d7a6a43 100644 --- a/crates/pumpkin-protocol/src/java/client/play/chunk_data/util.rs +++ b/crates/pumpkin/src/net/java/chunk_data/util.rs @@ -1,10 +1,9 @@ -use crate::WritingError; +use pumpkin_protocol::ser::NetworkWriteExt; +use pumpkin_protocol::ser::WritingError; use pumpkin_util::version::JavaMinecraftVersion; use pumpkin_world::chunk::format::LightContainer; use std::io::Write; -use crate::ser::NetworkWriteExt; - /// Writes an NBT compound tag to the writer, formatted appropriately for the target Minecraft version. pub fn write_compound_nbt( mut write: impl Write, diff --git a/crates/pumpkin-protocol/src/java/client/play/chunk_data/v1_18.rs b/crates/pumpkin/src/net/java/chunk_data/v1_18.rs similarity index 98% rename from crates/pumpkin-protocol/src/java/client/play/chunk_data/v1_18.rs rename to crates/pumpkin/src/net/java/chunk_data/v1_18.rs index 8a03bc1a5..4ce8df93d 100644 --- a/crates/pumpkin-protocol/src/java/client/play/chunk_data/v1_18.rs +++ b/crates/pumpkin/src/net/java/chunk_data/v1_18.rs @@ -1,10 +1,10 @@ use super::util::write_compound_nbt; -use crate::VarInt; -use crate::WritingError; -use crate::codec::bit_set::BitSet; -use crate::ser::NetworkWriteExt; use pumpkin_data::block_state_remap::remap_block_state_for_version; use pumpkin_data::packet::CURRENT_MC_VERSION; +use pumpkin_protocol::codec::bit_set::BitSet; +use pumpkin_protocol::codec::var_int::VarInt; +use pumpkin_protocol::ser::NetworkWriteExt; +use pumpkin_protocol::ser::WritingError; use pumpkin_util::math::position::get_local_cord; use pumpkin_util::version::JavaMinecraftVersion; use pumpkin_world::chunk::ChunkData; diff --git a/crates/pumpkin-protocol/src/java/client/play/chunk_data/v1_7.rs b/crates/pumpkin/src/net/java/chunk_data/v1_7.rs similarity index 98% rename from crates/pumpkin-protocol/src/java/client/play/chunk_data/v1_7.rs rename to crates/pumpkin/src/net/java/chunk_data/v1_7.rs index a40765b53..65babd022 100644 --- a/crates/pumpkin-protocol/src/java/client/play/chunk_data/v1_7.rs +++ b/crates/pumpkin/src/net/java/chunk_data/v1_7.rs @@ -1,7 +1,7 @@ use super::util::get_light_bytes; -use crate::WritingError; -use crate::ser::NetworkWriteExt; use pumpkin_data::block_state_remap::remap_block_state_for_version; +use pumpkin_protocol::ser::NetworkWriteExt; +use pumpkin_protocol::ser::WritingError; use pumpkin_util::version::JavaMinecraftVersion; use pumpkin_world::chunk::ChunkData; use std::io::Write; diff --git a/crates/pumpkin-protocol/src/java/client/play/chunk_data/v1_8.rs b/crates/pumpkin/src/net/java/chunk_data/v1_8.rs similarity index 95% rename from crates/pumpkin-protocol/src/java/client/play/chunk_data/v1_8.rs rename to crates/pumpkin/src/net/java/chunk_data/v1_8.rs index ff4cbc1b8..1b78ae343 100644 --- a/crates/pumpkin-protocol/src/java/client/play/chunk_data/v1_8.rs +++ b/crates/pumpkin/src/net/java/chunk_data/v1_8.rs @@ -1,8 +1,8 @@ use super::util::get_light_bytes; -use crate::VarInt; -use crate::WritingError; -use crate::ser::NetworkWriteExt; use pumpkin_data::block_state_remap::remap_block_state_for_version; +use pumpkin_protocol::codec::var_int::VarInt; +use pumpkin_protocol::ser::NetworkWriteExt; +use pumpkin_protocol::ser::WritingError; use pumpkin_util::version::JavaMinecraftVersion; use pumpkin_world::chunk::ChunkData; use std::io::Write; diff --git a/crates/pumpkin-protocol/src/java/client/play/chunk_data/v1_9.rs b/crates/pumpkin/src/net/java/chunk_data/v1_9.rs similarity index 98% rename from crates/pumpkin-protocol/src/java/client/play/chunk_data/v1_9.rs rename to crates/pumpkin/src/net/java/chunk_data/v1_9.rs index 0b7846006..a2a02f3f1 100644 --- a/crates/pumpkin-protocol/src/java/client/play/chunk_data/v1_9.rs +++ b/crates/pumpkin/src/net/java/chunk_data/v1_9.rs @@ -1,9 +1,9 @@ use super::util::{get_light_bytes, pack_legacy_data, pack_modern_data, write_compound_nbt}; -use crate::VarInt; -use crate::WritingError; -use crate::codec::bit_set::BitSet; -use crate::ser::NetworkWriteExt; use pumpkin_data::block_state_remap::remap_block_state_for_version; +use pumpkin_protocol::codec::bit_set::BitSet; +use pumpkin_protocol::codec::var_int::VarInt; +use pumpkin_protocol::ser::NetworkWriteExt; +use pumpkin_protocol::ser::WritingError; use pumpkin_util::encompassing_bits; use pumpkin_util::version::JavaMinecraftVersion; use pumpkin_world::chunk::ChunkData; diff --git a/crates/pumpkin/src/net/java/login/login_start.rs b/crates/pumpkin/src/net/java/login/login_start.rs index a500c9aa2..a2fdfc676 100644 --- a/crates/pumpkin/src/net/java/login/login_start.rs +++ b/crates/pumpkin/src/net/java/login/login_start.rs @@ -28,7 +28,18 @@ impl PendingConnection { let proxy = &server.advanced_config.networking.proxy; if proxy.enabled { - if proxy.velocity.enabled { + if proxy.vine.enabled { + if self.version.load().is_modern() { + vine::vine_login(self).await; + None + } else { + self.kick(TextComponent::text( + "Modern forwarding is not supported for client versions older than 1.13", + )) + .await; + Some(PacketHandlerResult::Stop) + } + } else if proxy.velocity.enabled { if self.version.load().is_modern() { velocity::velocity_login(self).await; None diff --git a/crates/pumpkin/src/net/java/login/mod.rs b/crates/pumpkin/src/net/java/login/mod.rs index b974b3cb9..150c76c3c 100644 --- a/crates/pumpkin/src/net/java/login/mod.rs +++ b/crates/pumpkin/src/net/java/login/mod.rs @@ -25,7 +25,7 @@ use crate::{ can_not_join, is_valid_player_name, java::pending::PendingConnection, offline_uuid, - proxy::{bungeecord, velocity}, + proxy::{bungeecord, velocity, vine}, }, server::Server, }; diff --git a/crates/pumpkin/src/net/java/login/plugin_response.rs b/crates/pumpkin/src/net/java/login/plugin_response.rs index a5e94afe5..b1b6da34b 100644 --- a/crates/pumpkin/src/net/java/login/plugin_response.rs +++ b/crates/pumpkin/src/net/java/login/plugin_response.rs @@ -8,11 +8,29 @@ impl PendingConnection { plugin_response: SLoginPluginResponse, ) -> Option { debug!("Handling plugin"); - let velocity_config = &server.advanced_config.networking.proxy.velocity; - if velocity_config.enabled { + let proxy_config = &server.advanced_config.networking.proxy; + if proxy_config.vine.enabled { + let expected_challenge = self.vine_challenge.take(); + match vine::receive_vine_plugin_response( + self.address.port(), + &proxy_config.vine, + plugin_response, + expected_challenge, + ) { + Ok((profile, new_address)) => { + self.gameprofile = Some(profile.clone()); + self.address = new_address; + self.finish_login(server, &profile).await + } + Err(error) => { + self.kick(TextComponent::text(error.to_string())).await; + Some(PacketHandlerResult::Stop) + } + } + } else if proxy_config.velocity.enabled { match velocity::receive_velocity_plugin_response( self.address.port(), - velocity_config, + &proxy_config.velocity, plugin_response, ) { Ok((profile, new_address)) => { diff --git a/crates/pumpkin/src/net/java/mod.rs b/crates/pumpkin/src/net/java/mod.rs index 3d159ef7f..0f2f339ce 100644 --- a/crates/pumpkin/src/net/java/mod.rs +++ b/crates/pumpkin/src/net/java/mod.rs @@ -1,5 +1,5 @@ use pumpkin_protocol::java::client::play::{ - CChunkBatchEnd, CChunkBatchStart, CChunkData, CLightUpdate, CPlayDisconnect, + CChunkBatchEnd, CChunkBatchStart, CLightUpdate, CPlayDisconnect, }; use pumpkin_world::level::SyncChunk; use std::net::SocketAddr; @@ -53,6 +53,7 @@ use tokio_util::sync::CancellationToken; use tokio_util::task::TaskTracker; use tracing::{debug, error, warn}; +pub mod chunk_data; pub mod config; pub mod handshake; pub mod login; @@ -61,6 +62,8 @@ pub mod play; pub mod recipe_helper; pub mod status; +pub use chunk_data::{CChunkData, ChunkLightExt}; + use arc_swap::ArcSwap; use pending::PendingConnection; diff --git a/crates/pumpkin/src/net/java/pending.rs b/crates/pumpkin/src/net/java/pending.rs index 2522573e0..b00d291cb 100644 --- a/crates/pumpkin/src/net/java/pending.rs +++ b/crates/pumpkin/src/net/java/pending.rs @@ -68,6 +68,7 @@ pub struct PendingConnection { pub brand: Option, pub packet_limiter: PacketRateLimiter, pub verify_token: Option<[u8; 4]>, + pub vine_challenge: Option<[u8; 16]>, } impl PendingConnection { @@ -93,6 +94,7 @@ impl PendingConnection { brand: None, packet_limiter, verify_token: None, + vine_challenge: None, } } diff --git a/crates/pumpkin/src/net/java/play/set_beacon.rs b/crates/pumpkin/src/net/java/play/set_beacon.rs index ed1cec793..abbbd07fc 100644 --- a/crates/pumpkin/src/net/java/play/set_beacon.rs +++ b/crates/pumpkin/src/net/java/play/set_beacon.rs @@ -1,9 +1,9 @@ #[allow(clippy::wildcard_imports)] use super::*; use crate::block::entities::beacon::BeaconBlockEntity; +use pumpkin_inventory::Inventory; use pumpkin_inventory::beacon_screen_handler::BeaconScreenHandler; use pumpkin_protocol::java::server::play::SSetBeacon; -use pumpkin_world::inventory::Inventory; impl JavaClient { pub fn handle_set_beacon(&self, player: &Arc, packet: &SSetBeacon) { diff --git a/crates/pumpkin/src/net/proxy/mod.rs b/crates/pumpkin/src/net/proxy/mod.rs index 31c8418a9..daa930c29 100644 --- a/crates/pumpkin/src/net/proxy/mod.rs +++ b/crates/pumpkin/src/net/proxy/mod.rs @@ -1,4 +1,5 @@ pub mod bungeecord; pub mod velocity; +pub mod vine; // TODO: Maybe make a trait for proxies diff --git a/crates/pumpkin/src/net/proxy/vine.rs b/crates/pumpkin/src/net/proxy/vine.rs new file mode 100644 index 000000000..2759baea9 --- /dev/null +++ b/crates/pumpkin/src/net/proxy/vine.rs @@ -0,0 +1,345 @@ +use std::io::Read; +use std::net::{IpAddr, SocketAddr}; +use std::sync::Arc; +use std::time::{SystemTime, UNIX_EPOCH}; + +use arc_swap::ArcSwap; +use bytes::{BufMut, BytesMut}; +use ed25519_dalek::{Signature, Verifier, VerifyingKey}; +use pumpkin_config::networking::proxy::VineConfig; +use pumpkin_protocol::{ + Property, java::client::login::CLoginPluginRequest, java::server::login::SLoginPluginResponse, + ser::NetworkReadExt, +}; +use sha2::{Digest, Sha256}; +use thiserror::Error; +use tracing::debug; + +use crate::net::{GameProfile, java::pending::PendingConnection}; + +pub const VINE_PLAYER_INFO_CHANNEL: &str = "vine:player_info"; +pub const VINE_FORWARDING_VERSION: i32 = 1; +pub const MAX_TIMESTAMP_DRIFT_SECS: i64 = 30; + +#[derive(Error, Debug)] +pub enum VineError { + #[error("No response data received")] + NoData, + #[error("Vine response data too short (minimum 89 bytes)")] + DataTooShort, + #[error("No public key or secret configured for Vine proxy")] + MissingKeyConfig, + #[error("Invalid Ed25519 public key")] + InvalidPublicKey, + #[error("Failed to verify Ed25519 signature")] + InvalidSignature, + #[error("Failed to read forward version")] + FailedReadForwardVersion, + #[error("Unsupported forwarding version {0}. Expected {1}")] + UnsupportedForwardVersion(i32, i32), + #[error("Vine timestamp expired or desynchronized: skew of {0}s exceeds limit of {1}s")] + TimestampExpired(i64, i64), + #[error("Vine challenge nonce mismatch")] + ChallengeMismatch, + #[error("Missing expected challenge from pending connection")] + MissingChallenge, + #[error("Failed to read address")] + FailedReadAddress, + #[error("Failed to parse address")] + FailedParseAddress, + #[error("Failed to read game profile name")] + FailedReadProfileName, + #[error("Failed to read game profile UUID")] + FailedReadProfileUUID, + #[error("Failed to read game profile properties")] + FailedReadProfileProperties, +} + +/// Initiates Vine modern forwarding handshake by sending a `CLoginPluginRequest` +/// with a unique 16-byte challenge nonce to protect against replay attacks. +pub async fn vine_login(connection: &mut PendingConnection) { + let message_id: i32 = rand::random(); + let challenge: [u8; 16] = rand::random(); + + let mut buf = BytesMut::with_capacity(17); + buf.put_u8(VINE_FORWARDING_VERSION as u8); + buf.put_slice(&challenge); + + connection.vine_challenge = Some(challenge); + + connection + .send_packet_now(&CLoginPluginRequest::new( + message_id.into(), + VINE_PLAYER_INFO_CHANNEL, + &buf, + )) + .await; +} + +/// Derives the Ed25519 verifying (public) key from configuration. +/// If `public_key` is provided in hex, parses it directly (32 bytes). +/// If `secret` is provided, computes SHA-256 to derive the 32-byte Ed25519 seed +/// and gets the corresponding public key. +pub fn get_verifying_key(config: &VineConfig) -> Result { + if !config.public_key.trim().is_empty() { + let hex_str = config.public_key.trim(); + let bytes = hex::decode(hex_str).map_err(|_| VineError::InvalidPublicKey)?; + if bytes.len() != 32 { + return Err(VineError::InvalidPublicKey); + } + let mut key_bytes = [0u8; 32]; + key_bytes.copy_from_slice(&bytes); + VerifyingKey::from_bytes(&key_bytes).map_err(|_| VineError::InvalidPublicKey) + } else if !config.secret.trim().is_empty() { + let secret = config.secret.trim(); + let seed: [u8; 32] = if secret.len() == 64 + && let Ok(decoded) = hex::decode(secret) + { + let mut s = [0u8; 32]; + s.copy_from_slice(&decoded); + s + } else { + Sha256::digest(secret.as_bytes()).into() + }; + let signing_key = ed25519_dalek::SigningKey::from_bytes(&seed); + Ok(signing_key.verifying_key()) + } else { + Err(VineError::MissingKeyConfig) + } +} + +fn read_game_profile(read: impl Read) -> Result { + let mut read = read; + let id = read + .get_uuid() + .map_err(|_| VineError::FailedReadProfileUUID)?; + + let name = read + .get_str() + .map_err(|_| VineError::FailedReadProfileName)?; + + let properties = read + .get_list(|data| { + let name = data.get_str()?; + let value = data.get_str()?; + let signature = data.get_option(NetworkReadExt::get_str)?; + + Ok(Property { + name, + value, + signature, + }) + }) + .map_err(|_| VineError::FailedReadProfileProperties)?; + + Ok(GameProfile { + id, + name: name.into_string(), + properties: ArcSwap::new(Arc::from(properties)), + profile_actions: None, + }) +} + +pub fn receive_vine_plugin_response( + port: u16, + config: &VineConfig, + response: SLoginPluginResponse, + expected_challenge: Option<[u8; 16]>, +) -> Result<(GameProfile, SocketAddr), VineError> { + debug!("Received Vine plugin response"); + let expected_challenge = expected_challenge.ok_or(VineError::MissingChallenge)?; + + if let Some(data) = response.data { + // Minimum size: 64 (Ed25519 signature) + 1 (VarInt version) + 8 (u64 timestamp) + 16 (challenge) + if data.len() < 64 + 1 + 8 + 16 { + return Err(VineError::DataTooShort); + } + + let (sig_bytes, mut payload) = data.split_at(64); + let mut sig_arr = [0u8; 64]; + sig_arr.copy_from_slice(sig_bytes); + let signature = Signature::from_bytes(&sig_arr); + + // Verify Ed25519 signature against proxy's public key + let verifying_key = get_verifying_key(config)?; + verifying_key + .verify(payload, &signature) + .map_err(|_| VineError::InvalidSignature)?; + + // 1. Version + let version = payload + .get_var_int() + .map_err(|_| VineError::FailedReadForwardVersion)?; + if version.0 != VINE_FORWARDING_VERSION { + return Err(VineError::UnsupportedForwardVersion( + version.0, + VINE_FORWARDING_VERSION, + )); + } + + // 2. Timestamp (u64 big-endian) + let mut ts_bytes = [0u8; 8]; + payload + .read_exact(&mut ts_bytes) + .map_err(|_| VineError::DataTooShort)?; + let timestamp = u64::from_be_bytes(ts_bytes); + + let now = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap_or_default() + .as_secs(); + let drift = (now as i64) - (timestamp as i64); + if drift.abs() > MAX_TIMESTAMP_DRIFT_SECS { + return Err(VineError::TimestampExpired(drift, MAX_TIMESTAMP_DRIFT_SECS)); + } + + // 3. Challenge nonce + let mut challenge = [0u8; 16]; + payload + .read_exact(&mut challenge) + .map_err(|_| VineError::DataTooShort)?; + if challenge != expected_challenge { + return Err(VineError::ChallengeMismatch); + } + + // 4. Client IP + let addr_str = payload + .get_str() + .map_err(|_| VineError::FailedReadAddress)?; + let ip: IpAddr = addr_str + .parse() + .map_err(|_| VineError::FailedParseAddress)?; + let socket_addr = SocketAddr::new(ip, port); + + // 5. GameProfile (UUID, Name, Properties) + let profile = read_game_profile(&mut payload)?; + + Ok((profile, socket_addr)) + } else { + Err(VineError::NoData) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use ed25519_dalek::Signer; + use pumpkin_protocol::codec::var_int::VarInt; + use pumpkin_protocol::ser::NetworkWriteExt; + use uuid::Uuid; + + #[test] + fn vine_key_derivation() { + let config = VineConfig { + enabled: true, + public_key: String::new(), + secret: "my-super-secret-seed".to_string(), + }; + let key = get_verifying_key(&config).unwrap(); + let pub_hex = hex::encode(key.to_bytes()); + let config_with_hex = VineConfig { + enabled: true, + public_key: pub_hex, + secret: String::new(), + }; + let key2 = get_verifying_key(&config_with_hex).unwrap(); + assert_eq!(key, key2); + } + + #[test] + fn vine_plugin_response_verification() { + let secret = "test-vine-secret"; + let seed: [u8; 32] = Sha256::digest(secret.as_bytes()).into(); + let signing_key = ed25519_dalek::SigningKey::from_bytes(&seed); + let verifying_key = signing_key.verifying_key(); + let pub_hex = hex::encode(verifying_key.to_bytes()); + + let config = VineConfig { + enabled: true, + public_key: pub_hex, + secret: String::new(), + }; + + let challenge = [42u8; 16]; + let now = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs(); + + // Build payload + let mut payload = Vec::new(); + VarInt(VINE_FORWARDING_VERSION) + .encode(&mut payload) + .unwrap(); + payload.extend_from_slice(&now.to_be_bytes()); + payload.extend_from_slice(&challenge); + payload.write_string("127.0.0.1").unwrap(); + let test_uuid = Uuid::new_v4(); + payload.extend_from_slice(test_uuid.as_bytes()); + payload.write_string("Steve").unwrap(); + VarInt(0).encode(&mut payload).unwrap(); // 0 properties + + // Sign payload + let signature = signing_key.sign(&payload); + let mut full_packet_data = Vec::new(); + full_packet_data.extend_from_slice(&signature.to_bytes()); + full_packet_data.extend_from_slice(&payload); + + let response = SLoginPluginResponse { + message_id: VarInt(1), + data: Some(full_packet_data.into_boxed_slice()), + }; + + let result = receive_vine_plugin_response(25565, &config, response, Some(challenge)); + assert!(result.is_ok()); + let (profile, addr) = result.unwrap(); + assert_eq!(profile.name, "Steve"); + assert_eq!(profile.id, test_uuid); + assert_eq!(addr.ip().to_string(), "127.0.0.1"); + } + + #[test] + fn vine_plugin_response_rejects_tampered_challenge() { + let secret = "test-vine-secret"; + let seed: [u8; 32] = Sha256::digest(secret.as_bytes()).into(); + let signing_key = ed25519_dalek::SigningKey::from_bytes(&seed); + let pub_hex = hex::encode(signing_key.verifying_key().to_bytes()); + + let config = VineConfig { + enabled: true, + public_key: pub_hex, + secret: String::new(), + }; + + let challenge = [42u8; 16]; + let wrong_challenge = [99u8; 16]; + let now = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs(); + + let mut payload = Vec::new(); + VarInt(VINE_FORWARDING_VERSION) + .encode(&mut payload) + .unwrap(); + payload.extend_from_slice(&now.to_be_bytes()); + payload.extend_from_slice(&challenge); + payload.write_string("127.0.0.1").unwrap(); + payload.extend_from_slice(Uuid::new_v4().as_bytes()); + payload.write_string("Steve").unwrap(); + VarInt(0).encode(&mut payload).unwrap(); + + let signature = signing_key.sign(&payload); + let mut full_packet_data = Vec::new(); + full_packet_data.extend_from_slice(&signature.to_bytes()); + full_packet_data.extend_from_slice(&payload); + + let response = SLoginPluginResponse { + message_id: VarInt(1), + data: Some(full_packet_data.into_boxed_slice()), + }; + + let result = receive_vine_plugin_response(25565, &config, response, Some(wrong_challenge)); + assert!(matches!(result, Err(VineError::ChallengeMismatch))); + } +} diff --git a/crates/pumpkin/src/plugin/api/gui.rs b/crates/pumpkin/src/plugin/api/gui.rs index d89d32310..4bb01edd2 100644 --- a/crates/pumpkin/src/plugin/api/gui.rs +++ b/crates/pumpkin/src/plugin/api/gui.rs @@ -5,8 +5,8 @@ use std::sync::RwLock; use pumpkin_data::{item_stack::ItemStack, screen::WindowType}; use pumpkin_inventory::screen_handler::{InventoryPlayer, ScreenHandler, ScreenHandlerBehaviour}; use pumpkin_inventory::slot::NormalSlot; +use pumpkin_inventory::{Clearable, Inventory}; use pumpkin_util::text::TextComponent; -use pumpkin_world::inventory::{Clearable, Inventory}; pub struct PluginGui { pub window_type: WindowType, diff --git a/crates/pumpkin/src/plugin/loader/wasm/wasm_host/signature.rs b/crates/pumpkin/src/plugin/loader/wasm/wasm_host/signature.rs index b0f4e08ee..7c868a397 100644 --- a/crates/pumpkin/src/plugin/loader/wasm/wasm_host/signature.rs +++ b/crates/pumpkin/src/plugin/loader/wasm/wasm_host/signature.rs @@ -185,7 +185,7 @@ pub fn fetch_market_public_key() -> Result { let body = if let Ok(handle) = tokio::runtime::Handle::try_current() { tokio::task::block_in_place(|| { handle.block_on(async { - let client = pumpkin_util::client_builder() + let client = pumpkin_auth::client_builder() .user_agent("Pumpkin-MC") .build() .map_err(|e| format!("Failed to build HTTP client: {e}"))?; @@ -204,7 +204,7 @@ pub fn fetch_market_public_key() -> Result { tokio::runtime::Runtime::new() .map_err(|e| format!("Failed to create runtime: {e}"))? .block_on(async { - let client = pumpkin_util::client_builder() + let client = pumpkin_auth::client_builder() .user_agent("Pumpkin-MC") .build() .map_err(|e| format!("Failed to build HTTP client: {e}"))?; diff --git a/crates/pumpkin/src/plugin/loader/wasm/wasm_host/state.rs b/crates/pumpkin/src/plugin/loader/wasm/wasm_host/state.rs index b06ab74df..e67553a14 100644 --- a/crates/pumpkin/src/plugin/loader/wasm/wasm_host/state.rs +++ b/crates/pumpkin/src/plugin/loader/wasm/wasm_host/state.rs @@ -144,7 +144,7 @@ pub type BlockEntityResource = WasmResource), + Generic(Arc), PlayerMain(Arc), PlayerEnderChest(Arc), } @@ -158,7 +158,7 @@ pub type MobResource = WasmResource>; #[derive(Clone)] pub struct ContainerBlockEntity { pub provider: Arc, - pub inventory: Arc, + pub inventory: Arc, } pub type ContainerBlockEntityResource = WasmResource; @@ -503,7 +503,7 @@ impl PluginHostState { pub fn add_container_block_entity( &mut self, provider: Arc, - inventory: Arc, + inventory: Arc, ) -> wasmtime::Result> { let resource = self.resource_table.push(ContainerBlockEntityResource { provider: ContainerBlockEntity { diff --git a/crates/pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1/gui.rs b/crates/pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1/gui.rs index 7c06c072a..dcb5048b9 100644 --- a/crates/pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1/gui.rs +++ b/crates/pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1/gui.rs @@ -210,13 +210,13 @@ impl gui::HostGui for PluginHostState { } async fn get_size(&mut self, res: Resource) -> wasmtime::Result { - use pumpkin_world::inventory::Inventory; + use pumpkin_inventory::Inventory; let gui = self.get_gui_res(&res)?.provider.lock().await; Ok(gui.inventory.size() as u32) } async fn clear_items(&mut self, res: Resource) -> wasmtime::Result<()> { - use pumpkin_world::inventory::Clearable; + use pumpkin_inventory::Clearable; let gui = self.get_gui_res(&res)?.provider.lock().await; gui.inventory.clear(); Ok(()) diff --git a/crates/pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1/inventory.rs b/crates/pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1/inventory.rs index cade06135..4de06ef5d 100644 --- a/crates/pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1/inventory.rs +++ b/crates/pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1/inventory.rs @@ -15,9 +15,9 @@ use crate::plugin::loader::wasm::wasm_host::{ }, }; use pumpkin_inventory::player::player_inventory::PlayerInventory; +use pumpkin_inventory::{Clearable, Inventory}; use pumpkin_protocol::codec::item_stack_seralizer::ItemStackSerializer; use pumpkin_protocol::java::client::play::CSetContainerSlot; -use pumpkin_world::inventory::{Clearable, Inventory}; const fn from_wasm_hand(hand: WitHand) -> pumpkin_util::Hand { match hand { diff --git a/crates/pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1/player.rs b/crates/pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1/player.rs index d8a485e15..0b5fc6fc3 100644 --- a/crates/pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1/player.rs +++ b/crates/pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1/player.rs @@ -1147,9 +1147,9 @@ impl pumpkin::plugin::player::Host for PluginHostState { use crate::plugin::loader::wasm::wasm_host::wit::v0_1::events::from_wasm_hand; use pumpkin_inventory::generic_container_screen_handler::GenericContainerScreenHandler; use pumpkin_inventory::player::ender_chest_inventory::EnderChestInventory; +use pumpkin_inventory::{Clearable, Inventory}; use pumpkin_protocol::codec::item_stack_seralizer::ItemStackSerializer; use pumpkin_protocol::java::client::play::CSetContainerSlot; -use pumpkin_world::inventory::{Clearable, Inventory}; use crate::plugin::loader::wasm::wasm_host::wit::v0_1::pumpkin::plugin::item_stack::ItemStack as WitHostItemStack; diff --git a/crates/pumpkin/src/server/mod.rs b/crates/pumpkin/src/server/mod.rs index 6ea63f726..66532fdb0 100644 --- a/crates/pumpkin/src/server/mod.rs +++ b/crates/pumpkin/src/server/mod.rs @@ -83,9 +83,9 @@ pub struct Server { /// Handles cryptographic keys for secure communication. key_store: OnceCell>, /// Bedrock OIDC provider keys, fetched on startup for 1.26.10+ token validation. - pub bedrock_oidc_keys: Arc>, + pub bedrock_oidc_keys: Arc>, /// Cached Bedrock server private key (process-lifetime). Generated on first Bedrock login and reused. - pub bedrock_private_key: OnceCell>, + pub bedrock_private_key: OnceCell>, /// Manages server status information. listing: std::sync::Mutex, /// Saves server branding information. @@ -369,7 +369,7 @@ impl Server { .bedrock .authentication .clone(); - let keys = match pumpkin_util::jwt::fetch_oidc_jwks( + let keys = match pumpkin_auth::jwt::fetch_oidc_jwks( auth.url.as_deref(), auth.connect_timeout, auth.read_timeout, @@ -379,7 +379,7 @@ impl Server { Ok(keys) => keys, Err(error) => { error!("Failed to fetch Bedrock OIDC keys: {error}"); - (String::new(), pumpkin_util::jwt::Jwks { keys: Vec::new() }) + (String::new(), pumpkin_auth::jwt::Jwks { keys: Vec::new() }) } }; let _ = server_clone.bedrock_oidc_keys.set(keys); diff --git a/crates/pumpkin/src/telemetry.rs b/crates/pumpkin/src/telemetry.rs index 872a9a737..d9984212b 100644 --- a/crates/pumpkin/src/telemetry.rs +++ b/crates/pumpkin/src/telemetry.rs @@ -460,7 +460,7 @@ pub fn start_telemetry_with_config(server: Arc, config: &TelemetryConfig ); let user_agent = format!("Pumpkin-Server/{}", env!("CARGO_PKG_VERSION")); - let http_client = match pumpkin_util::client_builder() + let http_client = match pumpkin_auth::client_builder() .timeout(Duration::from_secs(10)) .user_agent(&user_agent) .build() @@ -801,7 +801,7 @@ mod tests { }); let endpoint = format!("http://127.0.0.1:{port}/api/v1/rest/telemetry/heartbeat"); - let http_client = pumpkin_util::client_builder().build().unwrap(); + let http_client = pumpkin_auth::client_builder().build().unwrap(); let client = TelemetryClient::new(signing_key, http_client, endpoint); let payload = HeartbeatPayload { @@ -840,7 +840,7 @@ mod tests { .unwrap() .as_secs() .to_string(); - let response = pumpkin_util::client_builder() + let response = pumpkin_auth::client_builder() .build() .unwrap() .post(format!( diff --git a/crates/pumpkin/src/world/loot.rs b/crates/pumpkin/src/world/loot.rs index 07339b1dc..fce690f46 100644 --- a/crates/pumpkin/src/world/loot.rs +++ b/crates/pumpkin/src/world/loot.rs @@ -233,7 +233,7 @@ pub fn generate_loot_with_context( pub use generate_loot as generate_chest_loot; pub fn fill_chest_inventory( - inventory: &std::sync::Arc, + inventory: &std::sync::Arc, table: &LootTable, seed: i64, ) { diff --git a/crates/pumpkin/src/world/mod.rs b/crates/pumpkin/src/world/mod.rs index bf4c70d20..56202c475 100644 --- a/crates/pumpkin/src/world/mod.rs +++ b/crates/pumpkin/src/world/mod.rs @@ -87,6 +87,7 @@ use pumpkin_data::{ }; use pumpkin_inventory::crafting::recipe_provider::RecipeProvider; use pumpkin_inventory::screen_handler::InventoryPlayer; +use pumpkin_inventory::{Clearable, Inventory}; use pumpkin_nbt::compound::NbtCompound; use pumpkin_protocol::bedrock::client::set_actor_data::{CSetActorData, PropertySyncData}; use pumpkin_protocol::bedrock::client::start_game::{CStartGame, ServerTelemetryData}; @@ -148,12 +149,10 @@ use pumpkin_util::{ math::{get_section_cord, position::chunk_section_from_pos, vector2::Vector2}, random::{RandomImpl, get_seed, xoroshiro128::Xoroshiro}, }; -use pumpkin_world::inventory::Clearable; use pumpkin_world::world::{GetBlockError, WorldPortalExt}; use pumpkin_world::{ CURRENT_BEDROCK_MC_VERSION, biome, chunk::{io::Dirtiable, palette::bedrock_water_state}, - inventory::Inventory, }; use pumpkin_world::{chunk::ChunkData, world::BlockAccessor}; use pumpkin_world::{level::Level, tick::TickPriority};