diff --git a/Cargo.lock b/Cargo.lock index 6ab2f4512..9b5e417e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -227,9 +227,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d809780667f4410e7c41b07f52439b94d2bdf8528eeedc287fa38d3b7f95d82" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] name = "bitflags" @@ -951,9 +951,9 @@ checksum = "f449e6c6c08c865631d4890cfacf252b3d396c9bcc83adb6623cdb02a8336c41" [[package]] name = "flate2" -version = "1.1.5" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" +checksum = "b375d6465b98090a5f25b1c7703f3859783755aa9a80433b36e0379a3ec2f369" dependencies = [ "crc32fast", "miniz_oxide", @@ -1082,9 +1082,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", "libc", @@ -2059,9 +2059,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.14.1" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7231bd9b3d3d33c86b58adbac74b5ec0ad9f496b19d22801d773636feaa95f3d" +checksum = "d2ea70524a2f82d518bce41317d0fae74151505651af45faf1ffbd6fd33f0568" dependencies = [ "bytes", "prost-derive", @@ -2069,9 +2069,9 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.14.1" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9120690fafc389a67ba3803df527d0ec9cbbc9cc45e4cc20b332996dfb672425" +checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b" dependencies = [ "anyhow", "itertools 0.14.0", @@ -2082,9 +2082,9 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.14.1" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9b4db3d6da204ed77bb26ba83b6122a73aeb2e87e25fbf7ad2e84c4ccbf8f72" +checksum = "8991c4cbdb8bc5b11f0b074ffe286c30e523de90fee5ba8132f1399f23cb3dd7" dependencies = [ "prost", ] @@ -2336,7 +2336,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", ] [[package]] @@ -2421,7 +2421,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.16", + "getrandom 0.2.17", "libc", "untrusted", "windows-sys 0.52.0", @@ -3763,6 +3763,6 @@ dependencies = [ [[package]] name = "zmij" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fc5a66a20078bf1251bde995aa2fdcc4b800c70b5d92dd2c62abc5c60f679f8" +checksum = "ac93432f5b761b22864c774aac244fa5c0fd877678a4c37ebf6cf42208f9c9ec" diff --git a/Cargo.toml b/Cargo.toml index 010758ac8..748bb905b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,7 +65,7 @@ dashmap = "6.1" ecdsa = "0.16.9" enum_dispatch = "0.3.13" env_logger = "0.11.8" -flate2 = "1.1.5" +flate2 = "1.1.8" heck = "0.5" hmac = "=0.13.0-rc.3" indexmap = "2.13" diff --git a/assets/meta_data_type.json b/assets/meta_data_type.json new file mode 100644 index 000000000..edf220988 --- /dev/null +++ b/assets/meta_data_type.json @@ -0,0 +1,41 @@ +{ + "byte": 0, + "integer": 1, + "long": 2, + "float": 3, + "string": 4, + "text_component": 5, + "optional_text_component": 6, + "item_stack": 7, + "block_state": 14, + "optional_block_state": 15, + "boolean": 8, + "particle": 16, + "particle_list": 17, + "rotation": 9, + "block_pos": 10, + "optional_block_pos": 11, + "facing": 12, + "lazy_entity_reference": 13, + "optional_global_pos": 29, + "villager_data": 18, + "optional_int": 19, + "entity_pose": 20, + "cat_variant": 21, + "chicken_variant": 27, + "cow_variant": 22, + "wolf_variant": 23, + "wolf_sound_variant": 24, + "frog_variant": 25, + "pig_variant": 26, + "zombie_nautilus_variant": 28, + "painting_variant": 30, + "armadillo_state": 32, + "sniffer_state": 31, + "oxidation_level": 34, + "copper_golem_state": 33, + "vector_3f": 35, + "quaternion_f": 36, + "profile": 37, + "arm": 38 +} \ No newline at end of file diff --git a/assets/tracked_data.json b/assets/tracked_data.json new file mode 100644 index 000000000..1a4d2947b --- /dev/null +++ b/assets/tracked_data.json @@ -0,0 +1,178 @@ +{ + "LEFT_PADDLE_MOVING": 11, + "RIGHT_PADDLE_MOVING": 12, + "BUBBLE_WOBBLE_TICKS": 13, + "DAMAGE_WOBBLE_TICKS": 8, + "DAMAGE_WOBBLE_SIDE": 9, + "DAMAGE_WOBBLE_STRENGTH": 10, + "FLAGS": 0, + "AIR": 1, + "CUSTOM_NAME": 2, + "NAME_VISIBLE": 3, + "SILENT": 4, + "NO_GRAVITY": 5, + "POSE": 6, + "FROZEN_TICKS": 7, + "DANCING": 19, + "CAN_DUPLICATE": 17, + "MOB_FLAGS": 15, + "LIVING_FLAGS": 8, + "HEALTH": 9, + "POTION_SWIRLS": 10, + "POTION_SWIRLS_AMBIENT": 11, + "STUCK_ARROW_COUNT": 12, + "STINGER_COUNT": 13, + "SLEEPING_POSITION": 14, + "RADIUS": 8, + "WAITING": 9, + "PARTICLE": 10, + "STATE": 17, + "CHILD": 16, + "ARMOR_STAND_FLAGS": 15, + "TRACKER_HEAD_ROTATION": 16, + "TRACKER_BODY_ROTATION": 17, + "TRACKER_LEFT_ARM_ROTATION": 18, + "TRACKER_RIGHT_ARM_ROTATION": 19, + "TRACKER_LEFT_LEG_ROTATION": 20, + "TRACKER_RIGHT_LEG_ROTATION": 21, + "COLOR": 18, + "PROJECTILE_FLAGS": 8, + "PIERCE_LEVEL": 9, + "IN_GROUND": 10, + "VARIANT": 20, + "PLAYING_DEAD": 18, + "FROM_BUCKET": 16, + "BAT_FLAGS": 16, + "BEE_FLAGS": 17, + "ANGER_END_TIME": 21, + "BLAZE_FLAGS": 16, + "BLOCK_STATE": 9, + "START_INTERPOLATION": 8, + "INTERPOLATION_DURATION": 9, + "TELEPORT_DURATION": 10, + "TRANSLATION": 11, + "SCALE": 12, + "LEFT_ROTATION": 13, + "RIGHT_ROTATION": 14, + "BILLBOARD": 15, + "BRIGHTNESS": 16, + "VIEW_RANGE": 17, + "SHADOW_RADIUS": 18, + "SHADOW_STRENGTH": 19, + "WIDTH": 20, + "HEIGHT": 21, + "GLOW_COLOR_OVERRIDE": 22, + "SHEARED": 16, + "DASHING": 19, + "LAST_POSE_TICK": 19, + "HORSE_FLAGS": 17, + "CAT_VARIANT": 19, + "IN_SLEEPING_POSE": 20, + "HEAD_DOWN": 21, + "COLLAR_COLOR": 20, + "TAMEABLE_FLAGS": 17, + "OWNER_UUID": 18, + "SPIDER_FLAGS": 16, + "CUSTOM_BLOCK_STATE": 11, + "BLOCK_OFFSET": 12, + "OXIDATION_LEVEL": 16, + "COPPER_GOLEM_STATE": 17, + "COMMAND": 13, + "LAST_OUTPUT": 14, + "UNROOTED": 16, + "ACTIVE": 17, + "CRUMBLING": 18, + "HOME_POS": 19, + "FUSE_SPEED": 16, + "CHARGED": 8, + "IGNITED": 18, + "HAS_FISH": 17, + "MOISTNESS": 18, + "CHEST": 18, + "BABY": 16, + "ZOMBIE_TYPE": 17, + "CONVERTING_IN_WATER": 18, + "ITEM": 8, + "SPIKES_RETRACTED": 16, + "BEAM_TARGET_ID": 17, + "CARRIED_BLOCK": 16, + "ANGRY": 17, + "PROVOKED": 18, + "PHASE_TYPE": 16, + "BEAM_TARGET": 8, + "SHOW_BOTTOM": 9, + "SPELL": 17, + "CELEBRATING": 16, + "VALUE": 8, + "BLOCK_POS": 8, + "SHOOTER_ENTITY_ID": 9, + "SHOT_AT_ANGLE": 10, + "FOX_FLAGS": 18, + "OWNER": 19, + "OTHER_TRUSTED": 20, + "TARGET": 18, + "LIT": 13, + "SHOOTING": 16, + "HAS_ROPES": 17, + "STAYING_STILL": 18, + "ITEM_STACK": 9, + "ROTATION": 10, + "FACING": 8, + "DARK_TICKS_REMAINING": 17, + "SCREAMING": 17, + "LEFT_HORN": 18, + "RIGHT_HORN": 19, + "RESPONSE": 10, + "IRON_GOLEM_FLAGS": 16, + "STACK": 8, + "ITEM_DISPLAY": 24, + "STRENGTH": 19, + "SLIME_SIZE": 16, + "PROFILE": 17, + "IMMOVABLE": 18, + "DESCRIPTION": 19, + "MAIN_ARM_ID": 15, + "PLAYER_MODE_CUSTOMIZATION_ID": 16, + "TRUSTING": 17, + "ASK_FOR_BAMBOO_TICKS": 17, + "SNEEZE_PROGRESS": 18, + "EATING_TICKS": 19, + "MAIN_GENE": 20, + "HIDDEN_GENE": 21, + "PANDA_FLAGS": 22, + "SIZE": 16, + "BOOST_TIME": 17, + "CHARGING": 17, + "IMMUNE_TO_ZOMBIFICATION": 16, + "WARNING": 17, + "PUFF_STATE": 17, + "ATTACHED_FACE": 16, + "PEEK_AMOUNT": 17, + "CONVERTING": 19, + "FINISH_DIG_TIME": 18, + "SNOW_GOLEM_FLAGS": 16, + "COLD": 18, + "TEXT": 23, + "LINE_WIDTH": 24, + "BACKGROUND": 25, + "TEXT_OPACITY": 26, + "TEXT_DISPLAY_FLAGS": 27, + "FUSE": 8, + "LOYALTY": 11, + "ENCHANTED": 12, + "HAS_EGG": 17, + "DIGGING_SAND": 18, + "VEX_FLAGS": 16, + "VILLAGER_DATA": 20, + "HEAD_ROLLING_TIME_LEFT": 17, + "ANGER": 16, + "DRINKING": 17, + "TRACKED_ENTITY_ID_1": 16, + "TRACKED_ENTITY_ID_2": 17, + "TRACKED_ENTITY_ID_3": 18, + "INVUL_TIMER": 19, + "BEGGING": 19, + "SOUND_VARIANT": 23, + "HOOK_ENTITY_ID": 8, + "CAUGHT_FISH": 9 +} \ No newline at end of file diff --git a/pumpkin-data/build/build.rs b/pumpkin-data/build/build.rs index 04e2cc65f..0f0922294 100644 --- a/pumpkin-data/build/build.rs +++ b/pumpkin-data/build/build.rs @@ -30,6 +30,7 @@ mod game_rules; mod item; pub mod loot; mod message_type; +mod meta_data_type; mod noise_parameter; mod noise_router; mod packet; @@ -44,6 +45,7 @@ mod sound; mod sound_category; mod spawn_egg; mod tag; +mod tracked_data; mod world_event; pub const OUT_DIR: &str = "src/generated"; @@ -60,6 +62,8 @@ pub fn main() { (screen::build, "screen.rs"), (particle::build, "particle.rs"), (sound::build, "sound.rs"), + (meta_data_type::build, "meta_data_type.rs"), + (tracked_data::build, "tracked_data.rs"), (chunk_status::build, "chunk_status.rs"), (game_event::build, "game_event.rs"), (game_rules::build, "game_rules.rs"), diff --git a/pumpkin-data/build/meta_data_type.rs b/pumpkin-data/build/meta_data_type.rs new file mode 100644 index 000000000..be64a0c79 --- /dev/null +++ b/pumpkin-data/build/meta_data_type.rs @@ -0,0 +1,54 @@ +use std::{collections::HashMap, fs}; + +use heck::ToPascalCase; +use proc_macro2::TokenStream; +use quote::{format_ident, quote}; + +pub(crate) fn build() -> TokenStream { + println!("cargo:rerun-if-changed=../assets/meta_data_type.json"); + + let handlers_map: HashMap = + serde_json::from_str(&fs::read_to_string("../assets/meta_data_type.json").unwrap()) + .expect("Failed to parse meta_data_type.json"); + + let mut handlers: Vec<(&String, &i32)> = handlers_map.iter().collect(); + handlers.sort_by_key(|&(_, id)| id); + + let variants = handlers.iter().map(|(name, _)| { + let ident = format_ident!("{}", name.to_pascal_case()); + quote! { #ident } + }); + + let from_id = handlers.iter().map(|(name, id)| { + let ident = format_ident!("{}", name.to_pascal_case()); + quote! { #id => Some(Self::#ident), } + }); + + let to_id = handlers.iter().map(|(name, id)| { + let ident = format_ident!("{}", name.to_pascal_case()); + quote! { Self::#ident => #id, } + }); + + quote! { + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] + #[repr(i32)] + pub enum MetaDataType { + #(#variants),* + } + + impl MetaDataType { + pub fn from_id(id: i32) -> Option { + match id { + #(#from_id)* + _ => None, + } + } + + pub const fn id(&self) -> i32 { + match self { + #(#to_id)* + } + } + } + } +} diff --git a/pumpkin-data/build/tracked_data.rs b/pumpkin-data/build/tracked_data.rs new file mode 100644 index 000000000..462a59608 --- /dev/null +++ b/pumpkin-data/build/tracked_data.rs @@ -0,0 +1,33 @@ +use std::fs; + +use proc_macro2::TokenStream; +use quote::{format_ident, quote}; + +pub(crate) fn build() -> TokenStream { + println!("cargo:rerun-if-changed=../assets/tracked_data.json"); + + let mut handlers: Vec<(String, u8)> = + serde_json::from_str::>( + &fs::read_to_string("../assets/tracked_data.json").unwrap(), + ) + .expect("Failed to parse tracked_data.json") + .into_iter() + .collect(); + + handlers.sort_by_key(|&(_, id)| id); + + let constants = handlers.iter().map(|(name, id)| { + let ident = format_ident!("DATA_{}", name.to_uppercase()); + quote! { + pub const #ident: u8 = #id; + } + }); + + quote! { + pub struct TrackedData; + + impl TrackedData { + #(#constants)* + } + } +} diff --git a/pumpkin-data/src/block_state.rs b/pumpkin-data/src/block_state.rs index e0a35a03a..47f089030 100644 --- a/pumpkin-data/src/block_state.rs +++ b/pumpkin-data/src/block_state.rs @@ -35,7 +35,6 @@ pub enum PistonBehavior { PushOnly, } -// Add your methods here impl BlockState { pub const fn is_air(&self) -> bool { self.state_flags & IS_AIR != 0 diff --git a/pumpkin-data/src/lib.rs b/pumpkin-data/src/lib.rs index 033957df2..c1b49957c 100644 --- a/pumpkin-data/src/lib.rs +++ b/pumpkin-data/src/lib.rs @@ -42,6 +42,14 @@ pub mod sound { pub use crate::sound_enum::*; } +#[rustfmt::skip] +#[path = "generated/tracked_data.rs"] +pub mod tracked_data; + +#[rustfmt::skip] +#[path = "generated/meta_data_type.rs"] +pub mod meta_data_type; + #[rustfmt::skip] #[path = "generated/noise_parameter.rs"] pub mod noise_parameter; diff --git a/pumpkin-protocol/src/bedrock/client/network_chunk_publisher_update.rs b/pumpkin-protocol/src/bedrock/client/network_chunk_publisher_update.rs index dffd4ccf6..36a0ac11b 100644 --- a/pumpkin-protocol/src/bedrock/client/network_chunk_publisher_update.rs +++ b/pumpkin-protocol/src/bedrock/client/network_chunk_publisher_update.rs @@ -4,14 +4,14 @@ use pumpkin_macros::packet; use pumpkin_util::math::{position::BlockPos, vector2::Vector2}; use crate::{ - codec::{var_int::VarInt, var_uint::VarUInt}, + codec::{bedrock_block_pos::NetworkPos, var_int::VarInt, var_uint::VarUInt}, serial::PacketWrite, }; #[packet(121)] pub struct CNetworkChunkPublisherUpdate { // https://mojang.github.io/bedrock-protocol-docs/html/NetworkChunkPublisherUpdatePacket.html - pub pos_for_view: BlockPos, + pub pos_for_view: NetworkPos, // Is in blocks, not chunks! pub new_radius: VarUInt, // TODO @@ -21,8 +21,8 @@ pub struct CNetworkChunkPublisherUpdate { impl CNetworkChunkPublisherUpdate { pub fn new(pos_for_view: BlockPos, new_radius: u32) -> Self { Self { - pos_for_view, - new_radius: VarUInt(new_radius << 4), + pos_for_view: NetworkPos(pos_for_view), + new_radius: VarUInt(new_radius), server_build_chunk_list: Vec::new(), } } @@ -30,7 +30,7 @@ impl CNetworkChunkPublisherUpdate { impl PacketWrite for CNetworkChunkPublisherUpdate { fn write(&self, writer: &mut W) -> Result<(), Error> { - self.pos_for_view.write(writer)?; + self.pos_for_view.write_signed(writer)?; self.new_radius.write(writer)?; (self.server_build_chunk_list.len() as u32).write(writer)?; diff --git a/pumpkin-protocol/src/bedrock/client/resource_pack_stack.rs b/pumpkin-protocol/src/bedrock/client/resource_pack_stack.rs index 1490dd6ec..f90265774 100644 --- a/pumpkin-protocol/src/bedrock/client/resource_pack_stack.rs +++ b/pumpkin-protocol/src/bedrock/client/resource_pack_stack.rs @@ -6,11 +6,10 @@ use crate::{ #[derive(PacketWrite)] #[packet(7)] +/// https://mojang.github.io/bedrock-protocol-docs/html/ResourcePackStackPacket.html pub struct CResourcePackStackPacket { - // https://mojang.github.io/bedrock-protocol-docs/html/ResourcePackStackPacket.html resource_pack_required: bool, addons_list_size: VarUInt, - texture_pack_list_size: VarUInt, game_version: String, experiments: Experiments, /// When connecting to an Editor world, include the vanilla editor packs in the stack @@ -21,7 +20,6 @@ impl CResourcePackStackPacket { pub fn new( resource_pack_required: bool, addons_list_size: VarUInt, - texture_pack_list_size: VarUInt, game_version: String, experiments: Experiments, include_editor_packs: bool, @@ -29,7 +27,6 @@ impl CResourcePackStackPacket { Self { resource_pack_required, addons_list_size, - texture_pack_list_size, game_version, experiments, include_editor_packs, diff --git a/pumpkin-protocol/src/bedrock/client/resource_packs_info.rs b/pumpkin-protocol/src/bedrock/client/resource_packs_info.rs index 3dacfcbbc..d4c40a61e 100644 --- a/pumpkin-protocol/src/bedrock/client/resource_packs_info.rs +++ b/pumpkin-protocol/src/bedrock/client/resource_packs_info.rs @@ -1,8 +1,10 @@ +use std::io::{Error, Write}; + use crate::serial::PacketWrite; use pumpkin_macros::packet; -#[derive(PacketWrite)] #[packet(6)] +/// https://mojang.github.io/bedrock-protocol-docs/html/ResourcePacksInfoPacket.html pub struct CResourcePacksInfo { resource_pack_required: bool, has_addon_packs: bool, @@ -14,6 +16,20 @@ pub struct CResourcePacksInfo { resource_packs: Vec, } +impl PacketWrite for CResourcePacksInfo { + fn write(&self, writer: &mut W) -> Result<(), Error> { + self.resource_pack_required.write(writer)?; + self.has_addon_packs.write(writer)?; + self.has_scripts.write(writer)?; + self.is_vibrant_visuals_force_disabled.write(writer)?; + self.world_template_id.write(writer)?; + self.world_template_version.write(writer)?; + self.resource_packs_size.write(writer)?; + self.resource_packs.write(writer)?; + Ok(()) + } +} + #[derive(PacketWrite)] pub struct ResourcePack { pack_id: uuid::Uuid, diff --git a/pumpkin-protocol/src/bedrock/client/start_game.rs b/pumpkin-protocol/src/bedrock/client/start_game.rs index 5b81d208a..f61fd62e7 100644 --- a/pumpkin-protocol/src/bedrock/client/start_game.rs +++ b/pumpkin-protocol/src/bedrock/client/start_game.rs @@ -34,6 +34,7 @@ pub struct CStartGame { pub current_level_time: u64, pub enchantment_seed: VarInt, + pub block_properties_size: VarUInt, //pub block_properties: [GG; 2], pub multiplayer_correlation_id: String, @@ -50,8 +51,8 @@ pub struct CStartGame { pub enable_clientside_generation: bool, pub blocknetwork_ids_are_hashed: bool, - pub tick_death_system_enabled: bool, - pub server_auth_sounds: bool, + // NetworkPermissions + pub disable_client_sounds: bool, } #[derive(PacketWrite)] @@ -114,6 +115,7 @@ pub struct LevelSettings { pub new_nether: bool, pub edu_shared_uri_button_name: String, pub edu_shared_uri_link_uri: String, + pub override_force_experimental_gameplay_has_value: bool, pub chat_restriction_level: i8, pub disable_player_interactions: bool, diff --git a/pumpkin-protocol/src/bedrock/server/interaction.rs b/pumpkin-protocol/src/bedrock/server/interaction.rs index 062d4815e..0ec3907c6 100644 --- a/pumpkin-protocol/src/bedrock/server/interaction.rs +++ b/pumpkin-protocol/src/bedrock/server/interaction.rs @@ -5,30 +5,13 @@ use pumpkin_util::math::vector3::Vector3; use crate::{codec::var_ulong::VarULong, serial::PacketRead}; -#[derive(Debug)] +#[derive(Debug, PacketRead)] #[packet(33)] pub struct SInteraction { // https://mojang.github.io/bedrock-protocol-docs/html/InteractPacket.html pub action: Action, pub target_runtime_id: VarULong, - pub position: Vector3, -} - -impl PacketRead for SInteraction { - fn read(reader: &mut R) -> Result { - let action = Action::read(reader)?; - let target_runtime_id = VarULong::read(reader)?; - let mut position = Vector3::default(); - - if matches!(action, Action::InteractUpdate | Action::StopRiding) { - position = Vector3::read(reader)?; - } - Ok(Self { - action, - target_runtime_id, - position, - }) - } + pub position: Option>, } #[derive(Debug)] diff --git a/pumpkin-protocol/src/bedrock/server/resource_pack_response.rs b/pumpkin-protocol/src/bedrock/server/resource_pack_response.rs index 3bb457e63..a85524536 100644 --- a/pumpkin-protocol/src/bedrock/server/resource_pack_response.rs +++ b/pumpkin-protocol/src/bedrock/server/resource_pack_response.rs @@ -7,3 +7,10 @@ pub struct SResourcePackResponse { pub response: u8, pub download_size: u16, } + +impl SResourcePackResponse { + pub const STATUS_REFUSED: u8 = 1; + pub const STATUS_SEND_PACKS: u8 = 2; + pub const STATUS_HAVE_ALL_PACKS: u8 = 3; + pub const STATUS_COMPLETED: u8 = 4; +} diff --git a/pumpkin-protocol/src/codec/bedrock_block_pos.rs b/pumpkin-protocol/src/codec/bedrock_block_pos.rs index baf2429cc..dbee597bd 100644 --- a/pumpkin-protocol/src/codec/bedrock_block_pos.rs +++ b/pumpkin-protocol/src/codec/bedrock_block_pos.rs @@ -10,6 +10,14 @@ use crate::{ /// Bedrocks Writes and Reads BlockPos types in Packets differently pub struct NetworkPos(pub BlockPos); +impl NetworkPos { + pub fn write_signed(&self, writer: &mut W) -> Result<(), Error> { + VarInt(self.0.0.x).write(writer)?; + VarInt(self.0.0.y).write(writer)?; + VarInt(self.0.0.z).write(writer) + } +} + impl PacketWrite for NetworkPos { fn write(&self, writer: &mut W) -> Result<(), Error> { VarInt(self.0.0.x).write(writer)?; diff --git a/pumpkin-protocol/src/codec/mod.rs b/pumpkin-protocol/src/codec/mod.rs index 04cee81d5..b59836df1 100644 --- a/pumpkin-protocol/src/codec/mod.rs +++ b/pumpkin-protocol/src/codec/mod.rs @@ -4,6 +4,7 @@ pub mod bitset; pub mod data_component; pub mod item_stack_seralizer; pub mod little_endian; +pub mod optional_int; mod u24_type; pub mod uuid; pub mod var_int; diff --git a/pumpkin-protocol/src/codec/optional_int.rs b/pumpkin-protocol/src/codec/optional_int.rs new file mode 100644 index 000000000..5a599594d --- /dev/null +++ b/pumpkin-protocol/src/codec/optional_int.rs @@ -0,0 +1,17 @@ +use serde::{Serialize, Serializer}; + +use crate::codec::var_int::VarInt; + +#[derive(Debug, Clone, Copy)] +pub struct OptionalInt(pub Option); + +impl Serialize for OptionalInt { + fn serialize(&self, serializer: S) -> Result { + // Vanilla logic: empty is 0, otherwise value + 1 + let val = match self.0 { + None => 0, + Some(id) => id + 1, + }; + VarInt(val).serialize(serializer) + } +} diff --git a/pumpkin-protocol/src/java/client/play/entity_metadata.rs b/pumpkin-protocol/src/java/client/play/entity_metadata.rs index 929607e1c..24bbbc3df 100644 --- a/pumpkin-protocol/src/java/client/play/entity_metadata.rs +++ b/pumpkin-protocol/src/java/client/play/entity_metadata.rs @@ -1,4 +1,4 @@ -use pumpkin_data::packet::clientbound::PLAY_SET_ENTITY_DATA; +use pumpkin_data::{meta_data_type::MetaDataType, packet::clientbound::PLAY_SET_ENTITY_DATA}; use pumpkin_macros::packet; use serde::Serialize; @@ -38,43 +38,3 @@ impl Metadata { } } } - -pub enum MetaDataType { - Byte = 0, - Integer = 1, - Long = 2, - Float = 3, - String = 4, - TextComponent = 5, - OptionalTextComponent = 6, - ItemStack = 7, - Boolean = 8, - Rotation = 9, - BlockPos = 10, - OptionalBlockPos = 11, - Facing = 12, - LazyEntityReference = 13, - BlockState = 14, - OptionalBlockState = 15, - Particle = 16, - ParticleList = 17, - VillagerData = 18, - OptionalInt = 19, - EntityPose = 20, - CatVariant = 21, - ChickenVariant = 22, - CowVariant = 23, - WolfVariant = 24, - WolfSoundVariant = 25, - FrogVariant = 26, - PigVariant = 27, - OptionalGlobalPos = 28, - PaintingVariant = 29, - SnifferState = 30, - ArmadilloState = 31, - CopperGolemState = 32, - OxidationLevel = 33, - Vector3f = 34, - QuaternionF = 35, - Profile = 36, -} diff --git a/pumpkin-util/src/math/mod.rs b/pumpkin-util/src/math/mod.rs index 483ab664a..8709e0335 100644 --- a/pumpkin-util/src/math/mod.rs +++ b/pumpkin-util/src/math/mod.rs @@ -77,7 +77,9 @@ pub const fn smallest_encompassing_power_of_two(value: u32) -> u32 { #[inline] pub fn floor_div(x: T, y: T) -> T { let div = x / y; - if (x ^ y) < T::zero() && div * y != x { + let rem = x % y; + + if (x ^ y) < T::zero() && rem != T::zero() { div - T::one() } else { div diff --git a/pumpkin-util/src/math/vector3.rs b/pumpkin-util/src/math/vector3.rs index e40f1ae32..58eb60bdc 100644 --- a/pumpkin-util/src/math/vector3.rs +++ b/pumpkin-util/src/math/vector3.rs @@ -233,6 +233,17 @@ impl Add for Vector3 { } } +impl Sub for Vector3 { + type Output = Vector3; + fn sub(self, rhs: Self) -> Self::Output { + Self { + x: self.x - rhs.x, + y: self.y - rhs.y, + z: self.z - rhs.z, + } + } +} + impl AddAssign for Vector3 { fn add_assign(&mut self, other: Self) { self.x += other.x; @@ -279,6 +290,16 @@ impl> Vector3 { } } +impl> Vector3 { + pub fn to_f32(&self) -> Vector3 { + Vector3 { + x: self.x.into(), + y: self.y.into(), + z: self.z.into(), + } + } +} + impl> Vector3 { pub fn to_i32(&self) -> Vector3 { let x: f64 = self.x.into(); diff --git a/pumpkin-world/src/chunk_system.rs b/pumpkin-world/src/chunk_system.rs index 739648c76..25f2749b3 100644 --- a/pumpkin-world/src/chunk_system.rs +++ b/pumpkin-world/src/chunk_system.rs @@ -1028,7 +1028,7 @@ impl GenerationCache for Cache { ); } Chunk::Proto(data) => { - data.set_block_state(pos, block_state); + data.set_block_state(pos.x, pos.y, pos.z, block_state); } } } @@ -1745,7 +1745,7 @@ impl GenerationSchedule { send: crossfire::MTx<(ChunkPos, RecvChunk)>, level: Arc, ) { - log::info!( + log::debug!( "generation thread start id: {:?} name: {}", thread::current().id(), thread::current().name().unwrap_or("unknown") @@ -1767,7 +1767,7 @@ impl GenerationSchedule { break; } } - log::info!( + log::debug!( "generation thread stop id: {:?} name: {}", thread::current().id(), thread::current().name().unwrap_or("unknown") diff --git a/pumpkin-world/src/entity/entity_data_flags.rs b/pumpkin-world/src/entity/entity_data_flags.rs deleted file mode 100644 index 258e315e5..000000000 --- a/pumpkin-world/src/entity/entity_data_flags.rs +++ /dev/null @@ -1,382 +0,0 @@ -// Entity -pub const DATA_SHARED_FLAGS_ID: u8 = 0; -pub const DATA_AIR_SUPPLY_ID: u8 = 1; -pub const DATA_CUSTOM_NAME: u8 = 2; -pub const DATA_CUSTOM_NAME_VISIBLE: u8 = 3; -pub const DATA_SILENT: u8 = 4; -pub const DATA_NO_GRAVITY: u8 = 5; -pub const DATA_POSE: u8 = 6; -pub const DATA_TICKS_FROZEN: u8 = 7; -// OminousItemSpawner -// DATA_ITEM -pub const DATA_ITEM_OMINOUS_ITEM_SPAWNER: u8 = 8; -// LivingEntity -pub const DATA_LIVING_ENTITY_FLAGS: u8 = 8; -pub const DATA_HEALTH_ID: u8 = 9; -pub const DATA_EFFECT_PARTICLES: u8 = 10; -pub const DATA_EFFECT_AMBIENCE_ID: u8 = 11; -pub const DATA_ARROW_COUNT_ID: u8 = 12; -pub const DATA_STINGER_COUNT_ID: u8 = 13; -pub const SLEEPING_POS_ID: u8 = 14; -// Mob -pub const DATA_MOB_FLAGS_ID: u8 = 15; -// PathfinderMob -// AgeableMob -// DATA_BABY_ID -pub const DATA_BABY_ID_AGEABLE_MOB: u8 = 16; -// Interaction -// DATA_WIDTH_ID -pub const DATA_WIDTH_ID_INTERACTION: u8 = 8; -// DATA_HEIGHT_ID -pub const DATA_HEIGHT_ID_INTERACTION: u8 = 9; -pub const DATA_RESPONSE_ID: u8 = 10; -// Animal -// TamableAnimal -// DATA_FLAGS_ID -pub const DATA_FLAGS_ID_TAMABLE_ANIMAL: u8 = 17; -pub const DATA_OWNERUUID_ID: u8 = 18; -// Display -pub const DATA_TRANSFORMATION_INTERPOLATION_START_DELTA_TICKS_ID: u8 = 8; -pub const DATA_TRANSFORMATION_INTERPOLATION_DURATION_ID: u8 = 9; -pub const DATA_POS_ROT_INTERPOLATION_DURATION_ID: u8 = 10; -pub const DATA_TRANSLATION_ID: u8 = 11; -pub const DATA_SCALE_ID: u8 = 12; -pub const DATA_LEFT_ROTATION_ID: u8 = 13; -pub const DATA_RIGHT_ROTATION_ID: u8 = 14; -pub const DATA_BILLBOARD_RENDER_CONSTRAINTS_ID: u8 = 15; -pub const DATA_BRIGHTNESS_OVERRIDE_ID: u8 = 16; -pub const DATA_VIEW_RANGE_ID: u8 = 17; -pub const DATA_SHADOW_RADIUS_ID: u8 = 18; -pub const DATA_SHADOW_STRENGTH_ID: u8 = 19; -// DATA_WIDTH_ID -pub const DATA_WIDTH_ID_DISPLAY: u8 = 20; -// DATA_HEIGHT_ID -pub const DATA_HEIGHT_ID_DISPLAY: u8 = 21; -pub const DATA_GLOW_COLOR_OVERRIDE_ID: u8 = 22; -// Display.BlockDisplay -// DATA_BLOCK_STATE_ID -pub const DATA_BLOCK_STATE_ID_DISPLAY_BLOCK_DISPLAY: u8 = 0; -// Display.ItemDisplay -pub const DATA_ITEM_STACK_ID: u8 = 0; -pub const DATA_ITEM_DISPLAY_ID: u8 = 1; -// Display.TextDisplay -pub const DATA_TEXT_ID: u8 = 0; -pub const DATA_LINE_WIDTH_ID: u8 = 1; -pub const DATA_BACKGROUND_COLOR_ID: u8 = 2; -pub const DATA_TEXT_OPACITY_ID: u8 = 3; -pub const DATA_STYLE_FLAGS_ID: u8 = 4; -// AgeableWaterCreature -// Squid -// GlowSquid -pub const DATA_DARK_TICKS_REMAINING: u8 = 17; -// ExperienceOrb -pub const DATA_VALUE: u8 = 8; -// AreaEffectCloud -pub const DATA_RADIUS: u8 = 8; -pub const DATA_WAITING: u8 = 9; -pub const DATA_PARTICLE: u8 = 10; -// ArmorStand -pub const DATA_CLIENT_FLAGS: u8 = 15; -pub const DATA_HEAD_POSE: u8 = 16; -pub const DATA_BODY_POSE: u8 = 17; -pub const DATA_LEFT_ARM_POSE: u8 = 18; -pub const DATA_RIGHT_ARM_POSE: u8 = 19; -pub const DATA_LEFT_LEG_POSE: u8 = 20; -pub const DATA_RIGHT_LEG_POSE: u8 = 21; -// BlockAttachedEntity -// HangingEntity -// ItemFrame -// DATA_ITEM -pub const DATA_ITEM_ITEM_FRAME: u8 = 8; -pub const DATA_ROTATION: u8 = 9; -// Painting -pub const DATA_PAINTING_VARIANT_ID: u8 = 8; -// VehicleEntity -pub const DATA_ID_HURT: u8 = 8; -pub const DATA_ID_HURTDIR: u8 = 9; -pub const DATA_ID_DAMAGE: u8 = 10; -// AbstractBoat -pub const DATA_ID_PADDLE_LEFT: u8 = 11; -pub const DATA_ID_PADDLE_RIGHT: u8 = 12; -pub const DATA_ID_BUBBLE_TIME: u8 = 13; -// AbstractMinecart -pub const DATA_ID_CUSTOM_DISPLAY_BLOCK: u8 = 11; -pub const DATA_ID_DISPLAY_OFFSET: u8 = 12; -// MinecartFurnace -pub const DATA_ID_FUEL: u8 = 13; -// MinecartCommandBlock -pub const DATA_ID_COMMAND_NAME: u8 = 13; -pub const DATA_ID_LAST_OUTPUT: u8 = 14; -// AmbientCreature -// Bat -// DATA_ID_FLAGS -pub const DATA_ID_FLAGS_BAT: u8 = 16; -// EndCrystal -pub const DATA_BEAM_TARGET: u8 = 8; -pub const DATA_SHOW_BOTTOM: u8 = 9; -// EnderDragon -pub const DATA_PHASE: u8 = 16; -// Monster -// WitherBoss -pub const DATA_TARGET_A: u8 = 16; -pub const DATA_TARGET_B: u8 = 17; -pub const DATA_TARGET_C: u8 = 18; -pub const DATA_ID_INV: u8 = 19; -// Projectile -// FishingHook -pub const DATA_HOOKED_ENTITY: u8 = 8; -pub const DATA_BITING: u8 = 9; -// EyeOfEnder -// DATA_ITEM_STACK -pub const DATA_ITEM_STACK_EYE_OF_ENDER: u8 = 8; -// AbstractArrow -pub const ID_FLAGS: u8 = 8; -pub const PIERCE_LEVEL: u8 = 9; -pub const IN_GROUND: u8 = 10; -// ThrownTrident -pub const ID_LOYALTY: u8 = 11; -pub const ID_FOIL: u8 = 12; -// Arrow -pub const ID_EFFECT_COLOR: u8 = 11; -// AbstractHurtingProjectile -// WitherSkull -pub const DATA_DANGEROUS: u8 = 8; -// Fireball -// DATA_ITEM_STACK -pub const DATA_ITEM_STACK_FIREBALL: u8 = 8; -// FireworkRocketEntity -pub const DATA_ID_FIREWORKS_ITEM: u8 = 8; -pub const DATA_ATTACHED_TO_TARGET: u8 = 9; -pub const DATA_SHOT_AT_ANGLE: u8 = 10; -// ThrowableProjectile -// ThrowableItemProjectile -// DATA_ITEM_STACK -pub const DATA_ITEM_STACK_THROWABLE_ITEM_PROJECTILE: u8 = 8; -// FallingBlockEntity -pub const DATA_START_POS: u8 = 8; -// PrimedTnt -pub const DATA_FUSE_ID: u8 = 8; -// DATA_BLOCK_STATE_ID -pub const DATA_BLOCK_STATE_ID_PRIMED_TNT: u8 = 9; -// ItemEntity -// DATA_ITEM -pub const DATA_ITEM_ITEM_ENTITY: u8 = 8; -// PatrollingMonster -// Raider -pub const IS_CELEBRATING: u8 = 16; -// Rabbit -// DATA_TYPE_ID -pub const DATA_TYPE_ID_RABBIT: u8 = 17; -// ShoulderRidingEntity -// Parrot -// DATA_VARIANT_ID -pub const DATA_VARIANT_ID_PARROT: u8 = 19; -// Turtle -pub const HAS_EGG: u8 = 17; -pub const LAYING_EGG: u8 = 18; -// WaterAnimal -// AbstractFish -// FROM_BUCKET -pub const FROM_BUCKET_ABSTRACT_FISH: u8 = 16; -// Pufferfish -pub const PUFF_STATE: u8 = 17; -// AbstractGolem -// IronGolem -// DATA_FLAGS_ID -pub const DATA_FLAGS_ID_IRON_GOLEM: u8 = 16; -// Bee -// DATA_FLAGS_ID -pub const DATA_FLAGS_ID_BEE: u8 = 17; -// DATA_REMAINING_ANGER_TIME -pub const DATA_REMAINING_ANGER_TIME_BEE: u8 = 18; -// SnowGolem -pub const DATA_PUMPKIN_ID: u8 = 16; -// AbstractCow -// Cow -// DATA_VARIANT_ID -pub const DATA_VARIANT_ID_COW: u8 = 17; -// AbstractSchoolingFish -// Salmon -// DATA_TYPE -pub const DATA_TYPE_SALMON: u8 = 17; -// Cat -// DATA_VARIANT_ID -pub const DATA_VARIANT_ID_CAT: u8 = 19; -pub const IS_LYING: u8 = 20; -pub const RELAX_STATE_ONE: u8 = 21; -// DATA_COLLAR_COLOR -pub const DATA_COLLAR_COLOR_CAT: u8 = 22; -// PolarBear -pub const DATA_STANDING_ID: u8 = 17; -// TropicalFish -// DATA_ID_TYPE_VARIANT -pub const DATA_ID_TYPE_VARIANT_TROPICAL_FISH: u8 = 17; -// Fox -// DATA_TYPE_ID -pub const DATA_TYPE_ID_FOX: u8 = 17; -// DATA_FLAGS_ID -pub const DATA_FLAGS_ID_FOX: u8 = 18; -pub const DATA_TRUSTED_ID_0: u8 = 19; -pub const DATA_TRUSTED_ID_1: u8 = 20; -// Ocelot -pub const DATA_TRUSTING: u8 = 17; -// Chicken -// DATA_VARIANT_ID -pub const DATA_VARIANT_ID_CHICKEN: u8 = 17; -// Panda -pub const UNHAPPY_COUNTER: u8 = 17; -pub const SNEEZE_COUNTER: u8 = 18; -pub const EAT_COUNTER: u8 = 19; -pub const MAIN_GENE_ID: u8 = 20; -pub const HIDDEN_GENE_ID: u8 = 21; -// DATA_ID_FLAGS -pub const DATA_ID_FLAGS_PANDA: u8 = 22; -// MushroomCow -// DATA_TYPE -pub const DATA_TYPE_MUSHROOM_COW: u8 = 17; -// Pig -// DATA_BOOST_TIME -pub const DATA_BOOST_TIME_PIG: u8 = 17; -// DATA_VARIANT_ID -pub const DATA_VARIANT_ID_PIG: u8 = 18; -// Dolphin -pub const GOT_FISH: u8 = 17; -pub const MOISTNESS_LEVEL: u8 = 18; -// Sniffer -pub const DATA_STATE: u8 = 17; -pub const DATA_DROP_SEED_AT_TICK: u8 = 18; -// Allay -pub const DATA_DANCING: u8 = 16; -pub const DATA_CAN_DUPLICATE: u8 = 17; -// Sheep -pub const DATA_WOOL_ID: u8 = 17; -// AbstractHorse -// DATA_ID_FLAGS -pub const DATA_ID_FLAGS_ABSTRACT_HORSE: u8 = 17; -// Camel -pub const DASH: u8 = 18; -pub const LAST_POSE_CHANGE_TICK: u8 = 19; -// Goat -pub const DATA_IS_SCREAMING_GOAT: u8 = 17; -pub const DATA_HAS_LEFT_HORN: u8 = 18; -pub const DATA_HAS_RIGHT_HORN: u8 = 19; -// Wolf -pub const DATA_INTERESTED_ID: u8 = 19; -// DATA_COLLAR_COLOR -pub const DATA_COLLAR_COLOR_WOLF: u8 = 20; -// DATA_REMAINING_ANGER_TIME -pub const DATA_REMAINING_ANGER_TIME_WOLF: u8 = 21; -// DATA_VARIANT_ID -pub const DATA_VARIANT_ID_WOLF: u8 = 22; -pub const DATA_SOUND_VARIANT_ID: u8 = 23; -// Frog -// DATA_VARIANT_ID -pub const DATA_VARIANT_ID_FROG: u8 = 17; -pub const DATA_TONGUE_TARGET_ID: u8 = 18; -// Horse -// DATA_ID_TYPE_VARIANT -pub const DATA_ID_TYPE_VARIANT_HORSE: u8 = 18; -// AbstractChestedHorse -pub const DATA_ID_CHEST: u8 = 18; -// Llama -pub const DATA_STRENGTH_ID: u8 = 19; -// DATA_VARIANT_ID -pub const DATA_VARIANT_ID_LLAMA: u8 = 20; -// Axolotl -pub const DATA_VARIANT: u8 = 17; -pub const DATA_PLAYING_DEAD: u8 = 18; -// FROM_BUCKET -pub const FROM_BUCKET_AXOLOTL: u8 = 19; -// Armadillo -pub const ARMADILLO_STATE: u8 = 17; -// AbstractVillager -pub const DATA_UNHAPPY_COUNTER: u8 = 17; -// Villager -// DATA_VILLAGER_DATA -pub const DATA_VILLAGER_DATA_VILLAGER: u8 = 18; -// Vex -// DATA_FLAGS_ID -pub const DATA_FLAGS_ID_VEX: u8 = 16; -// FlyingMob -// Ghast -pub const DATA_IS_CHARGING: u8 = 16; -// Zoglin -// DATA_BABY_ID -pub const DATA_BABY_ID_ZOGLIN: u8 = 16; -// Zombie -// DATA_BABY_ID -pub const DATA_BABY_ID_ZOMBIE: u8 = 16; -pub const DATA_SPECIAL_TYPE_ID: u8 = 17; -pub const DATA_DROWNED_CONVERSION_ID: u8 = 18; -// Blaze -// DATA_FLAGS_ID -pub const DATA_FLAGS_ID_BLAZE: u8 = 16; -// Guardian -pub const DATA_ID_MOVING: u8 = 16; -pub const DATA_ID_ATTACK_TARGET: u8 = 17; -// Strider -// DATA_BOOST_TIME -pub const DATA_BOOST_TIME_STRIDER: u8 = 17; -pub const DATA_SUFFOCATING: u8 = 18; -// Spider -// DATA_FLAGS_ID -pub const DATA_FLAGS_ID_SPIDER: u8 = 16; -// Phantom -// ID_SIZE -pub const ID_SIZE_PHANTOM: u8 = 16; -// AbstractSkeleton -// Skeleton -pub const DATA_STRAY_CONVERSION_ID: u8 = 16; -// AbstractIllager -// SpellcasterIllager -pub const DATA_SPELL_CASTING_ID: u8 = 17; -// Witch -pub const DATA_USING_ITEM: u8 = 17; -// Bogged -pub const DATA_SHEARED: u8 = 16; -// Slime -// ID_SIZE -pub const ID_SIZE_SLIME: u8 = 16; -// Creeper -pub const DATA_SWELL_DIR: u8 = 16; -pub const DATA_IS_POWERED: u8 = 17; -pub const DATA_IS_IGNITED: u8 = 18; -// EnderMan -pub const DATA_CARRY_STATE: u8 = 16; -pub const DATA_CREEPY: u8 = 17; -pub const DATA_STARED_AT: u8 = 18; -// Pillager -pub const IS_CHARGING_CROSSBOW: u8 = 17; -// ZombieVillager -pub const DATA_CONVERTING_ID: u8 = 19; -// DATA_VILLAGER_DATA -pub const DATA_VILLAGER_DATA_ZOMBIE_VILLAGER: u8 = 20; -// Shulker -pub const DATA_ATTACH_FACE_ID: u8 = 16; -pub const DATA_PEEK_ID: u8 = 17; -pub const DATA_COLOR_ID: u8 = 18; -// Creaking -pub const CAN_MOVE: u8 = 16; -pub const IS_ACTIVE: u8 = 17; -pub const IS_TEARING_DOWN: u8 = 18; -pub const HOME_POS: u8 = 19; -// AbstractPiglin -// DATA_IMMUNE_TO_ZOMBIFICATION -pub const DATA_IMMUNE_TO_ZOMBIFICATION_ABSTRACT_PIGLIN: u8 = 16; -// Piglin -// DATA_BABY_ID -pub const DATA_BABY_ID_PIGLIN: u8 = 17; -pub const DATA_IS_CHARGING_CROSSBOW: u8 = 18; -pub const DATA_IS_DANCING: u8 = 19; -// Hoglin -// DATA_IMMUNE_TO_ZOMBIFICATION -pub const DATA_IMMUNE_TO_ZOMBIFICATION_HOGLIN: u8 = 17; -// Warden -pub const CLIENT_ANGER_LEVEL: u8 = 16; -// Player -pub const DATA_PLAYER_ABSORPTION_ID: u8 = 15; -pub const DATA_SCORE_ID: u8 = 16; -pub const DATA_PLAYER_MODE_CUSTOMISATION: u8 = 17; -pub const DATA_PLAYER_MAIN_HAND: u8 = 18; -pub const DATA_SHOULDER_LEFT: u8 = 19; -pub const DATA_SHOULDER_RIGHT: u8 = 20; diff --git a/pumpkin-world/src/entity/mod.rs b/pumpkin-world/src/entity/mod.rs deleted file mode 100644 index 70acab9c0..000000000 --- a/pumpkin-world/src/entity/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod entity_data_flags; diff --git a/pumpkin-world/src/generation/aquifer_sampler.rs b/pumpkin-world/src/generation/aquifer_sampler.rs index 827725a63..c9c211126 100644 --- a/pumpkin-world/src/generation/aquifer_sampler.rs +++ b/pumpkin-world/src/generation/aquifer_sampler.rs @@ -1,7 +1,7 @@ use enum_dispatch::enum_dispatch; use pumpkin_data::{Block, BlockState}; use pumpkin_util::{ - math::{clamped_map, floor_div, vector3::Vector3}, + math::{clamped_map, floor_div}, random::{RandomDeriver, RandomDeriverImpl, RandomImpl}, }; @@ -170,7 +170,7 @@ impl WorldAquiferSampler { let index = packed_position_index!(offset_x, offset_y, offset_z, size_y, size_z); packed_positions[index as usize] = - block_pos::packed(&Vector3::new(rand_x, rand_y, rand_z)); + block_pos::packed(rand_x as i64, rand_y as i64, rand_z as i64); } } } @@ -196,30 +196,31 @@ impl WorldAquiferSampler { } fn random_positions_for_pos(&self, x: i32, y: i32, z: i32) -> [i64; 12] { - // (x, y - 1, z) to (x + 1, y + 1, z + 1) - // y values are contiguous in packed array: - // ($local_x * $dim_z + $local_z) * $dim_y + $local_y + let sy = self.size_y; + let syz = self.size_y * self.size_z; - let x0z0_index = self.packed_position_index(x, y - 1, z); - let x0z1_index = x0z0_index + self.size_y; - let x1z0_index = x0z0_index + self.size_y * self.size_z; - let x1z1_index = x1z0_index + self.size_y; - // Remove bounds checks on subsequent indexes - assert!(x1z1_index + 2 < self.packed_positions.len()); + let i00 = self.packed_position_index(x, y - 1, z); + let i01 = i00 + sy; + let i10 = i00 + syz; + let i11 = i10 + sy; + + assert!(i11 + 2 < self.packed_positions.len(), "Index out of bounds"); + + let p = &self.packed_positions; [ - self.packed_positions[x1z1_index + 2], - self.packed_positions[x1z0_index + 2], - self.packed_positions[x0z1_index + 2], - self.packed_positions[x0z0_index + 2], - self.packed_positions[x1z1_index + 1], - self.packed_positions[x1z0_index + 1], - self.packed_positions[x0z1_index + 1], - self.packed_positions[x0z0_index + 1], - self.packed_positions[x1z1_index], - self.packed_positions[x1z0_index], - self.packed_positions[x0z1_index], - self.packed_positions[x0z0_index], + p[i11 + 2], + p[i10 + 2], + p[i01 + 2], + p[i00 + 2], + p[i11 + 1], + p[i10 + 1], + p[i01 + 1], + p[i00 + 1], + p[i11], + p[i10], + p[i01], + p[i00], ] } @@ -288,20 +289,22 @@ impl WorldAquiferSampler { let local_z = local_xz!(z); let index = self.packed_position_index(local_x, local_y, local_z); - let entry = &mut self.levels[index]; + if let Some(ref level) = self.levels[index] { + return level; + } - let fluid_level = &self.fluid_level_sampler; - entry.get_or_insert_with(|| { - Self::get_fluid_level( - fluid_level, - x, - y, - z, - router, - height_estimator, - sample_options, - ) - }) + let sampled = Self::get_fluid_level( + &self.fluid_level_sampler, + x, + y, + z, + router, + height_estimator, + sample_options, + ); + + self.levels[index] = Some(sampled); + self.levels[index].as_ref().unwrap() } fn get_fluid_level( @@ -685,7 +688,7 @@ pub trait AquiferSamplerImpl { #[cfg(test)] mod random_positions_and_hypot { - use std::{mem, sync::LazyLock}; + use std::sync::LazyLock; use pumpkin_data::noise_router::OVERWORLD_BASE_NOISE_ROUTER; @@ -693,10 +696,7 @@ mod random_positions_and_hypot { block::RawBlockState, generation::{ GlobalRandomConfig, biome_coords, - chunk_noise::{ - BlockStateSampler, ChainedBlockStateSampler, ChunkNoiseGenerator, LAVA_BLOCK, - WATER_BLOCK, - }, + chunk_noise::{BlockStateSampler, ChunkNoiseGenerator, LAVA_BLOCK, WATER_BLOCK}, noise::router::{ chunk_density_function::{ChunkNoiseFunctionSampleOptions, SampleAction}, chunk_noise_router::ChunkNoiseRouter, @@ -755,20 +755,14 @@ mod random_positions_and_hypot { ); let options = ChunkNoiseFunctionSampleOptions::new(false, SampleAction::SkipCellCaches, 0, 0, 0); - let sampler = match noise.state_sampler { - BlockStateSampler::Chained(chained) => chained, - _ => unreachable!(), - }; - let mut samplers = sampler.samplers; + let mut samplers_vec = noise.state_sampler.samplers.into_vec(); + let first_sampler = samplers_vec.remove(0); - let mut dummy_sampler = - BlockStateSampler::Chained(ChainedBlockStateSampler::new(Box::new([]))); - mem::swap(&mut dummy_sampler, &mut samplers[0]); - - let sampler = match dummy_sampler { - BlockStateSampler::Aquifer(aquifer) => aquifer, - _ => unreachable!(), + let sampler = match first_sampler { + BlockStateSampler::Aquifer(a) => a, + _ => panic!("Expected Aquifer"), }; + let aquifer = match sampler { AquiferSampler::Aquifer(aquifer) => aquifer, _ => unreachable!(), diff --git a/pumpkin-world/src/generation/chunk_noise.rs b/pumpkin-world/src/generation/chunk_noise.rs index 9daf2a1d0..7ba027544 100644 --- a/pumpkin-world/src/generation/chunk_noise.rs +++ b/pumpkin-world/src/generation/chunk_noise.rs @@ -1,5 +1,5 @@ use pumpkin_data::{Block, BlockState}; -use pumpkin_util::math::{floor_div, floor_mod, vector2::Vector2}; +use pumpkin_util::math::{floor_div, floor_mod}; use crate::generation::section_coords; @@ -32,7 +32,6 @@ pub const CHUNK_DIM: u8 = 16; pub enum BlockStateSampler { Aquifer(AquiferSampler), Ore(OreVeinSampler), - Chained(ChainedBlockStateSampler), } impl BlockStateSampler { @@ -46,7 +45,6 @@ impl BlockStateSampler { match self { Self::Aquifer(aquifer) => aquifer.apply(router, pos, sample_options, height_estimator), Self::Ore(ore) => ore.sample(router, pos, sample_options), - Self::Chained(chained) => chained.sample(router, pos, sample_options, height_estimator), } } } @@ -67,11 +65,12 @@ impl ChainedBlockStateSampler { sample_options: &ChunkNoiseFunctionSampleOptions, height_estimator: &mut SurfaceHeightEstimateSampler, ) -> Option<&'static BlockState> { - self.samplers - .iter_mut() - .map(|sampler| sampler.sample(router, pos, sample_options, height_estimator)) - .find(|state| state.is_some()) - .unwrap_or(None) + for sampler in self.samplers.iter_mut() { + if let Some(state) = sampler.sample(router, pos, sample_options, height_estimator) { + return Some(state); + } + } + None } } @@ -140,7 +139,7 @@ impl IndexToNoisePos for ChunkIndexMapper { } pub struct ChunkNoiseGenerator<'a> { - pub state_sampler: BlockStateSampler, + pub state_sampler: ChainedBlockStateSampler, generation_shape: &'a GenerationShapeConfig, start_cell_pos_x: i32, start_cell_pos_z: i32, @@ -176,10 +175,6 @@ impl<'a> ChunkNoiseGenerator<'a> { generation_shape.horizontal_cell_block_count() as i32, ); - let biome_pos = Vector2::new( - biome_coords::from_block(start_block_x), - biome_coords::from_block(start_block_z), - ); let horizontal_biome_end = biome_coords::from_block( horizontal_cell_count * generation_shape.horizontal_cell_block_count() as usize, ); @@ -199,8 +194,8 @@ impl<'a> ChunkNoiseGenerator<'a> { vertical_cell_block_count as usize, vertical_cell_count, horizontal_cell_count, - biome_pos.x, - biome_pos.y, + biome_coords::from_block(start_block_x), + biome_coords::from_block(start_block_z), horizontal_biome_end, ); @@ -219,20 +214,16 @@ impl<'a> ChunkNoiseGenerator<'a> { AquiferSampler::SeaLevel(SeaLevelAquiferSampler::new(level_sampler)) }; - let state_sampler = if ore_veins { + let samplers: Box<[BlockStateSampler]> = if ore_veins { let ore_sampler = OreVeinSampler::new(random_config.ore_random_deriver.clone()); - let samplers: Box<[BlockStateSampler]> = Box::new([ + Box::new([ BlockStateSampler::Aquifer(aquifer_sampler), BlockStateSampler::Ore(ore_sampler), - ]); - - BlockStateSampler::Chained(ChainedBlockStateSampler::new(samplers)) + ]) } else { - let samplers: Box<[BlockStateSampler]> = - Box::new([BlockStateSampler::Aquifer(aquifer_sampler)]); - - BlockStateSampler::Chained(ChainedBlockStateSampler::new(samplers)) + Box::new([BlockStateSampler::Aquifer(aquifer_sampler)]) }; + let state_sampler = ChainedBlockStateSampler::new(samplers); let router = ChunkNoiseRouter::generate(noise_router_base, &builder_options); @@ -258,8 +249,8 @@ impl<'a> ChunkNoiseGenerator<'a> { } #[inline] - pub fn sample_end_density(&mut self, cell_x: u8) { - self.sample_density(false, self.start_cell_pos_x + cell_x as i32 + 1); + pub fn sample_end_density(&mut self, cell_x: i32) { + self.sample_density(false, self.start_cell_pos_x + cell_x + 1); } fn sample_density(&mut self, start: bool, current_x: i32) { @@ -330,17 +321,14 @@ impl<'a> ChunkNoiseGenerator<'a> { self.router.swap_buffers(); } - pub fn on_sampled_cell_corners(&mut self, cell_x: u8, cell_y: u16, cell_z: u8) { + pub fn on_sampled_cell_corners(&mut self, cell_x: i32, cell_y: i32, cell_z: i32) { self.router .on_sampled_cell_corners(cell_y as usize, cell_z as usize); self.cache_fill_unique_id += 1; - let start_x = - (self.start_cell_pos_x + cell_x as i32) * self.horizontal_cell_block_count() as i32; - let start_y = - (cell_y as i32 + self.minimum_cell_y) * self.vertical_cell_block_count() as i32; - let start_z = - (self.start_cell_pos_z + cell_z as i32) * self.horizontal_cell_block_count() as i32; + let start_x = (self.start_cell_pos_x + cell_x) * self.horizontal_cell_block_count() as i32; + let start_y = (cell_y + self.minimum_cell_y) * self.vertical_cell_block_count() as i32; + let start_z = (self.start_cell_pos_z + cell_z) * self.horizontal_cell_block_count() as i32; let mapper = ChunkIndexMapper { start_x, diff --git a/pumpkin-world/src/generation/feature/features/fallen_tree.rs b/pumpkin-world/src/generation/feature/features/fallen_tree.rs index 5520cd313..696c86b6f 100644 --- a/pumpkin-world/src/generation/feature/features/fallen_tree.rs +++ b/pumpkin-world/src/generation/feature/features/fallen_tree.rs @@ -22,6 +22,11 @@ impl FallenTreeFeature { } fn gen_stump(&self, chunk: &mut ProtoChunk, random: &mut RandomGenerator, pos: BlockPos) { - chunk.set_block_state(&pos.0, self.trunk_provider.get(random, pos)); + chunk.set_block_state( + pos.0.x, + pos.0.y, + pos.0.z, + self.trunk_provider.get(random, pos), + ); } } diff --git a/pumpkin-world/src/generation/height_provider.rs b/pumpkin-world/src/generation/height_provider.rs index 720a75895..2fb0c53c0 100644 --- a/pumpkin-world/src/generation/height_provider.rs +++ b/pumpkin-world/src/generation/height_provider.rs @@ -1,3 +1,5 @@ +use std::num::NonZeroU32; + use pumpkin_util::random::{RandomGenerator, RandomImpl}; use serde::Deserialize; @@ -28,14 +30,14 @@ impl HeightProvider { pub struct VeryBiasedToBottomHeightProvider { min_inclusive: YOffset, max_inclusive: YOffset, - inner: Option, + inner: Option, } impl VeryBiasedToBottomHeightProvider { pub fn get(&self, random: &mut RandomGenerator, min_y: i8, height: u16) -> i32 { let min = self.min_inclusive.get_y(min_y as i16, height); let max = self.max_inclusive.get_y(min_y as i16, height); - let inner = self.inner.unwrap_or(1) as i32; + let inner = self.inner.map(|i| i.get()).unwrap_or(1) as i32; let min_rnd = random.next_inbetween_i32(min + inner, max); let max_rnd = random.next_inbetween_i32(min, min_rnd - 1); diff --git a/pumpkin-world/src/generation/noise/router/surface_height_sampler.rs b/pumpkin-world/src/generation/noise/router/surface_height_sampler.rs index 30f8a6b5a..284a53543 100644 --- a/pumpkin-world/src/generation/noise/router/surface_height_sampler.rs +++ b/pumpkin-world/src/generation/noise/router/surface_height_sampler.rs @@ -68,33 +68,43 @@ impl<'a> SurfaceHeightEstimateSampler<'a> { let biome_aligned_z = biome_coords::to_block(biome_coords::from_block(block_z)); let packed_column = chunk_pos::packed(biome_aligned_x as u64, biome_aligned_z as u64); - if let Some(estimate) = self.cache.get(&packed_column) { - *estimate - } else { - let estimate = self.calculate_height_estimate(biome_aligned_x, biome_aligned_z); - self.cache.insert(packed_column, estimate); - estimate + if let Some(&estimate) = self.cache.get(&packed_column) { + return estimate; } + + let estimate = self.calculate_height_estimate(biome_aligned_x, biome_aligned_z); + self.cache.insert(packed_column, estimate); + estimate } fn calculate_height_estimate(&mut self, aligned_x: i32, aligned_z: i32) -> i32 { - for y in (self.minimum_y..=self.maximum_y) - .rev() - .step_by(self.y_level_step_count) - { - let pos = UnblendedNoisePos::new(aligned_x, y, aligned_z); - let density_sample = ChunkNoiseFunctionComponent::sample_from_stack( + let mut low = self.minimum_y; + let mut high = self.maximum_y; + let mut result = i32::MAX; + + let sample_options = + ChunkNoiseFunctionSampleOptions::new(false, SampleAction::SkipCellCaches, 0, 0, 0); + + while low <= high { + let mid = low + ((high - low) / 2); + let stepped_mid = mid - (mid % self.y_level_step_count as i32); + + let pos = UnblendedNoisePos::new(aligned_x, stepped_mid, aligned_z); + let density = ChunkNoiseFunctionComponent::sample_from_stack( &mut self.component_stack, &pos, - &ChunkNoiseFunctionSampleOptions::new(false, SampleAction::SkipCellCaches, 0, 0, 0), + &sample_options, ); - if density_sample > Self::NOTCHIAN_SAMPLE_CUTOFF { - return y; + if density > Self::NOTCHIAN_SAMPLE_CUTOFF { + result = stepped_mid; + low = stepped_mid + self.y_level_step_count as i32; + } else { + high = stepped_mid - self.y_level_step_count as i32; } } - i32::MAX + result } pub fn generate( diff --git a/pumpkin-world/src/generation/positions.rs b/pumpkin-world/src/generation/positions.rs index 2a29f927e..97cd356e3 100644 --- a/pumpkin-world/src/generation/positions.rs +++ b/pumpkin-world/src/generation/positions.rs @@ -1,8 +1,6 @@ use pumpkin_util::math::{floor_log2, smallest_encompassing_power_of_two}; pub mod block_pos { - use pumpkin_util::math::vector3::Vector3; - use super::{ BIT_SHIFT_X, BIT_SHIFT_Z, BITS_X, BITS_Y, BITS_Z, SIZE_BITS_X, SIZE_BITS_Y, SIZE_BITS_Z, }; @@ -23,12 +21,12 @@ pub mod block_pos { } #[inline] - pub const fn packed(vec: &Vector3) -> i64 { + pub const fn packed(x: i64, y: i64, z: i64) -> i64 { let mut result = 0i64; // Need to go to i64 first to conserve sign - result |= (vec.x as i64 & BITS_X as i64) << BIT_SHIFT_X; - result |= (vec.z as i64 & BITS_Z as i64) << BIT_SHIFT_Z; - result |= vec.y as i64 & BITS_Y as i64; + result |= (x & BITS_X as i64) << BIT_SHIFT_X; + result |= (z & BITS_Z as i64) << BIT_SHIFT_Z; + result |= y & BITS_Y as i64; result } } @@ -107,8 +105,6 @@ pub const MIN_HEIGHT_CELL: i32 = MIN_HEIGHT << 4; #[cfg(test)] mod test { - use pumpkin_util::math::vector3::Vector3; - use super::{block_pos, chunk_pos}; #[test] @@ -123,21 +119,19 @@ mod test { #[test] fn test_block_packing() { - let pos = Vector3::new(-30000000, 120, 30000000); - let packed = block_pos::packed(&pos); + let packed = block_pos::packed(-30000000, 120, 30000000); assert_eq!(packed, -8246337085439999880i64); - assert_eq!(pos.x, block_pos::unpack_x(packed)); - assert_eq!(pos.y, block_pos::unpack_y(packed)); - assert_eq!(pos.z, block_pos::unpack_z(packed)); + assert_eq!(-30000000, block_pos::unpack_x(packed)); + assert_eq!(120, block_pos::unpack_y(packed)); + assert_eq!(30000000, block_pos::unpack_z(packed)); for x in -10..=10 { for y in -10..=10 { for z in -10..=10 { - let pos = Vector3::new(x * 1000000, y * 10, z * 1000000); - let packed = block_pos::packed(&pos); - assert_eq!(pos.x, block_pos::unpack_x(packed)); - assert_eq!(pos.y, block_pos::unpack_y(packed)); - assert_eq!(pos.z, block_pos::unpack_z(packed)); + let packed = block_pos::packed(x * 1000000, y * 10, z * 1000000); + assert_eq!(x * 1000000, block_pos::unpack_x(packed) as i64); + assert_eq!(y * 10, block_pos::unpack_y(packed) as i64); + assert_eq!(z * 1000000, block_pos::unpack_z(packed) as i64); } } } diff --git a/pumpkin-world/src/generation/proto_chunk.rs b/pumpkin-world/src/generation/proto_chunk.rs index e68bf9a0f..68c1b688e 100644 --- a/pumpkin-world/src/generation/proto_chunk.rs +++ b/pumpkin-world/src/generation/proto_chunk.rs @@ -233,10 +233,7 @@ impl ProtoChunk { let absolute_y = section_base_y + y as i32 + chunk_data.section.min_y; - proto_chunk.set_block_state( - &Vector3::new(x as i32, absolute_y, z as i32), - block_state, - ); + proto_chunk.set_block_state(x as i32, absolute_y, z as i32, block_state); } } } @@ -452,29 +449,27 @@ impl ProtoChunk { RawBlockState(self.get_block_state_raw(local_pos.x & 15, local_y, local_pos.z & 15)) } - pub fn set_block_state(&mut self, pos: &Vector3, block_state: &BlockState) { - let local_x = pos.x & 15; - let local_y = pos.y - self.bottom_y() as i32; - let local_z = pos.z & 15; + pub fn set_block_state(&mut self, x: i32, y: i32, z: i32, block_state: &BlockState) { + let local_x = x & 15; + let local_y = y - self.bottom_y() as i32; + let local_z = z & 15; if local_y < 0 || local_y >= self.height() as i32 { return; } if !block_state.is_air() { - self.maybe_update_surface_height_map(local_x, pos.y, local_z); + self.maybe_update_surface_height_map(local_x, y, local_z); let block = Block::from_state_id(block_state.id); let blocks_movement = blocks_movement(block_state, block); if blocks_movement { - self.maybe_update_ocean_floor_height_map(local_x, pos.y, local_z); + self.maybe_update_ocean_floor_height_map(local_x, y, local_z); } if blocks_movement || block_state.is_liquid() { - self.maybe_update_motion_blocking_height_map(local_x, pos.y, local_z); + self.maybe_update_motion_blocking_height_map(local_x, y, local_z); if !block.has_tag(&tag::Block::MINECRAFT_LEAVES) { { - self.maybe_update_motion_blocking_no_leaves_height_map( - local_x, pos.y, local_z, - ); + self.maybe_update_motion_blocking_no_leaves_height_map(local_x, y, local_z); } } } @@ -657,69 +652,52 @@ impl ProtoChunk { noise_sampler: &mut ChunkNoiseGenerator, surface_height_estimate_sampler: &mut SurfaceHeightEstimateSampler, ) { - let horizontal_cell_block_count = noise_sampler.horizontal_cell_block_count(); - let vertical_cell_block_count = noise_sampler.vertical_cell_block_count(); - let horizontal_cells = CHUNK_DIM / horizontal_cell_block_count; + let h_count = noise_sampler.horizontal_cell_block_count() as i32; + let v_count = noise_sampler.vertical_cell_block_count() as i32; + let horizontal_cells = CHUNK_DIM as i32 / h_count; let min_y = self.bottom_y(); - let minimum_cell_y = min_y / vertical_cell_block_count as i8; - let cell_height = self.height() / vertical_cell_block_count as u16; + let minimum_cell_y = min_y / v_count as i8; + let cell_height = self.height() / v_count as u16; - let start_block_x = self.start_block_x(); - let start_block_z = self.start_block_z(); - let start_cell_x = self.start_cell_x(horizontal_cell_block_count); - let start_cell_z = self.start_cell_z(horizontal_cell_block_count); + let delta_y_step = 1.0 / v_count as f64; + let delta_x_z_step = 1.0 / h_count as f64; // TODO: Block state updates when we implement those noise_sampler.sample_start_density(); for cell_x in 0..horizontal_cells { noise_sampler.sample_end_density(cell_x); - let sample_start_x = - (start_cell_x + cell_x as i32) * horizontal_cell_block_count as i32; + let sample_start_x = (self.start_cell_x(h_count) + cell_x) * h_count; + let block_x_base = self.start_block_x() + cell_x * h_count; for cell_z in 0..horizontal_cells { - let sample_start_z = - (start_cell_z + cell_z as i32) * horizontal_cell_block_count as i32; + let sample_start_z = (self.start_cell_z(h_count) + cell_z) * h_count; + let block_z_base = self.start_block_z() + cell_z * h_count; for cell_y in (0..cell_height).rev() { - noise_sampler.on_sampled_cell_corners(cell_x, cell_y, cell_z); - let sample_start_y = - (minimum_cell_y as i32 + cell_y as i32) * vertical_cell_block_count as i32; + noise_sampler.on_sampled_cell_corners(cell_x, cell_y as i32, cell_z); + let sample_start_y = (minimum_cell_y as i32 + cell_y as i32) * v_count; - let block_y_base = sample_start_y; - let delta_y_step = 1.0 / vertical_cell_block_count as f64; + for local_y in (0..v_count).rev() { + let block_y = sample_start_y + local_y; + noise_sampler.interpolate_y(local_y as f64 * delta_y_step); - for local_y in (0..vertical_cell_block_count).rev() { - let block_y = block_y_base + local_y as i32; - let delta_y = local_y as f64 * delta_y_step; - noise_sampler.interpolate_y(delta_y); + for local_x in 0..h_count { + noise_sampler.interpolate_x(local_x as f64 * delta_x_z_step); + let block_x = block_x_base + local_x; - let block_x_base = - start_block_x + cell_x as i32 * horizontal_cell_block_count as i32; - let delta_x_step = 1.0 / horizontal_cell_block_count as f64; - - for local_x in 0..horizontal_cell_block_count { - let block_x = block_x_base + local_x as i32; - let delta_x = local_x as f64 * delta_x_step; - noise_sampler.interpolate_x(delta_x); - - let block_z_base = - start_block_z + cell_z as i32 * horizontal_cell_block_count as i32; - let delta_z_step = 1.0 / horizontal_cell_block_count as f64; - - for local_z in 0..horizontal_cell_block_count { - let block_z = block_z_base + local_z as i32; - let delta_z = local_z as f64 * delta_z_step; - noise_sampler.interpolate_z(delta_z); + for local_z in 0..h_count { + noise_sampler.interpolate_z(local_z as f64 * delta_x_z_step); + let block_z = block_z_base + local_z; // The `cell_offset` calculations are still a good idea for clarity and correctness // but let's confirm the values. // block_x = start_block_x + cell_x*H + local_x // sample_start_x = start_cell_x*H + cell_x*H = (start_cell_x+cell_x)*H // These can be simplified. - let cell_offset_x = local_x as i32; + let cell_offset_x = local_x; let cell_offset_y = block_y - sample_start_y; - let cell_offset_z = local_z as i32; + let cell_offset_z = local_z; let block_state = noise_sampler .sample_block_state( @@ -732,10 +710,7 @@ impl ProtoChunk { surface_height_estimate_sampler, ) .unwrap_or(self.default_block); - self.set_block_state( - &Vector3::new(block_x, block_y, block_z), - block_state, - ); + self.set_block_state(block_x, block_y, block_z, block_state); } } } @@ -872,7 +847,7 @@ impl ProtoChunk { ); if let Some(state) = new_state { - self.set_block_state(&pos, state); + self.set_block_state(x, y, z, state); } } } @@ -1126,12 +1101,12 @@ impl ProtoChunk { center_chunk.stage = StagedChunkEnum::StructureReferences; } - fn start_cell_x(&self, horizontal_cell_block_count: u8) -> i32 { - self.start_block_x() / horizontal_cell_block_count as i32 + fn start_cell_x(&self, horizontal_cell_block_count: i32) -> i32 { + self.start_block_x() / horizontal_cell_block_count } - fn start_cell_z(&self, horizontal_cell_block_count: u8) -> i32 { - self.start_block_z() / horizontal_cell_block_count as i32 + fn start_cell_z(&self, horizontal_cell_block_count: i32) -> i32 { + self.start_block_z() / horizontal_cell_block_count } fn start_block_x(&self) -> i32 { diff --git a/pumpkin-world/src/generation/structure/structures/buried_treasure.rs b/pumpkin-world/src/generation/structure/structures/buried_treasure.rs index 75fc7b34e..63d1f9d6c 100644 --- a/pumpkin-world/src/generation/structure/structures/buried_treasure.rs +++ b/pumpkin-world/src/generation/structure/structures/buried_treasure.rs @@ -96,7 +96,12 @@ impl StructurePieceBase for BuriedTreasurePiece { || Self::is_liquid(down_offset_state.to_block())) && dir != BlockDirection::Up { - chunk.set_block_state(&offset_pos.0, down_raw_state.to_state()); + chunk.set_block_state( + offset_pos.0.x, + offset_pos.0.y, + offset_pos.0.z, + down_raw_state.to_state(), + ); continue; } @@ -105,12 +110,12 @@ impl StructurePieceBase for BuriedTreasurePiece { } else { state.to_state() }; - chunk.set_block_state(&offset_pos.0, state1); + chunk.set_block_state(offset_pos.0.x, offset_pos.0.y, offset_pos.0.z, state1); } // Place the Chest // TODO: Add loot table logic here (requires seed) - chunk.set_block_state(&pos.0, Block::CHEST.default_state); + chunk.set_block_state(pos.0.x, pos.0.y, pos.0.z, Block::CHEST.default_state); return; } pos = pos.down(); diff --git a/pumpkin-world/src/generation/structure/structures/mod.rs b/pumpkin-world/src/generation/structure/structures/mod.rs index f3daf8c5e..78b895b65 100644 --- a/pumpkin-world/src/generation/structure/structures/mod.rs +++ b/pumpkin-world/src/generation/structure/structures/mod.rs @@ -274,10 +274,8 @@ impl StructurePiece { for current_y in (end_y..=start_y).rev() { // We bypass add_block here because add_block transforms X/Z again. // We use the already-transformed world X/Z but iterate Y manually. - let current_pos = Vector3::new(world_pos.x, current_y, world_pos.z); - - if box_limit.contains_pos(¤t_pos) { - chunk.set_block_state(¤t_pos, state); + if box_limit.contains(world_pos.x, current_y, world_pos.z) { + chunk.set_block_state(world_pos.x, current_y, world_pos.z, state); } } } @@ -344,7 +342,7 @@ impl StructurePiece { // } // World interaction - world.set_block_state(&block_pos, block); + world.set_block_state(block_pos.x, block_pos.y, block_pos.z, block); // let fluid_state = world.get_fluid_state(&block_pos); // if !fluid_state.is_empty() { diff --git a/pumpkin-world/src/generation/surface/terrain.rs b/pumpkin-world/src/generation/surface/terrain.rs index 51e2aec0e..bf6bd5d5e 100644 --- a/pumpkin-world/src/generation/surface/terrain.rs +++ b/pumpkin-world/src/generation/surface/terrain.rs @@ -170,7 +170,7 @@ impl SurfaceTerrainBuilder { } let default_block = &chunk.default_block; - chunk.set_block_state(&pos, default_block); + chunk.set_block_state(global_x, y, global_z, default_block); } } } @@ -246,10 +246,10 @@ impl SurfaceTerrainBuilder { && rand.next_f64() > 0.15) { if snow_blocks <= snow_block_count && y > snow_bottom { - chunk.set_block_state(&pos, Self::SNOW_BLOCK.default_state); + chunk.set_block_state(x, y, z, Self::SNOW_BLOCK.default_state); snow_blocks += 1; } else { - chunk.set_block_state(&pos, Self::PACKED_ICE.default_state); + chunk.set_block_state(x, y, z, Self::PACKED_ICE.default_state); } } } diff --git a/pumpkin-world/src/lib.rs b/pumpkin-world/src/lib.rs index a55be2566..b5715d2fd 100644 --- a/pumpkin-world/src/lib.rs +++ b/pumpkin-world/src/lib.rs @@ -9,7 +9,6 @@ pub mod chunk_system; pub mod cylindrical_chunk_iterator; pub mod data; pub mod dimension; -pub mod entity; pub mod generation; pub mod inventory; pub mod item; @@ -23,7 +22,8 @@ pub type BlockId = u16; pub type BlockStateId = u16; pub const CURRENT_MC_VERSION: &str = "1.21.11"; -pub const CURRENT_BEDROCK_MC_VERSION: &str = "1.21.111"; +pub const CURRENT_BEDROCK_MC_VERSION: &str = "1.21.32"; +pub const CURRENT_BEDROCK_MC_PROTOCOL: u32 = 898; #[macro_export] macro_rules! global_path { diff --git a/pumpkin/src/command/tree/builder.rs b/pumpkin/src/command/tree/builder.rs index 1f6375943..94c1712dd 100644 --- a/pumpkin/src/command/tree/builder.rs +++ b/pumpkin/src/command/tree/builder.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::sync::Arc; use super::CommandExecutor; @@ -19,7 +20,7 @@ impl CommandTree { #[must_use] pub fn new( names: impl IntoIterator>, - description: impl Into, + description: impl Into>, ) -> Self { let names_vec = names.into_iter().map(Into::into).collect(); diff --git a/pumpkin/src/command/tree/mod.rs b/pumpkin/src/command/tree/mod.rs index 24007bc84..9bc17587e 100644 --- a/pumpkin/src/command/tree/mod.rs +++ b/pumpkin/src/command/tree/mod.rs @@ -1,6 +1,6 @@ use super::{CommandExecutor, args::ArgumentConsumer}; use crate::command::CommandSender; -use std::{collections::VecDeque, fmt::Debug, sync::Arc}; +use std::{borrow::Cow, collections::VecDeque, fmt::Debug, sync::Arc}; pub mod builder; pub mod format; @@ -59,7 +59,7 @@ pub struct CommandTree { pub nodes: Vec, pub children: Vec, pub names: Vec, - pub description: String, + pub description: Cow<'static, str>, } impl CommandTree { diff --git a/pumpkin/src/entity/decoration/end_crystal.rs b/pumpkin/src/entity/decoration/end_crystal.rs index 046a57571..66670df8c 100644 --- a/pumpkin/src/entity/decoration/end_crystal.rs +++ b/pumpkin/src/entity/decoration/end_crystal.rs @@ -1,8 +1,8 @@ use core::f32; use crate::entity::{Entity, EntityBase, EntityBaseFuture, NBTStorage, living::LivingEntity}; -use pumpkin_data::damage::DamageType; -use pumpkin_protocol::java::client::play::{MetaDataType, Metadata}; +use pumpkin_data::{damage::DamageType, meta_data_type::MetaDataType, tracked_data::TrackedData}; +use pumpkin_protocol::java::client::play::Metadata; use pumpkin_util::math::vector3::Vector3; pub struct EndCrystalEntity { @@ -18,7 +18,11 @@ impl EndCrystalEntity { impl EndCrystalEntity { pub async fn set_show_bottom(&self, show_bottom: bool) { self.entity - .send_meta_data(&[Metadata::new(9, MetaDataType::Boolean, show_bottom)]) + .send_meta_data(&[Metadata::new( + TrackedData::DATA_SHOW_BOTTOM, + MetaDataType::Boolean, + show_bottom, + )]) .await; } } diff --git a/pumpkin/src/entity/falling.rs b/pumpkin/src/entity/falling.rs index 05650765a..284b9a8a0 100644 --- a/pumpkin/src/entity/falling.rs +++ b/pumpkin/src/entity/falling.rs @@ -1,6 +1,7 @@ -use pumpkin_data::Block; use pumpkin_data::entity::EntityType; -use pumpkin_protocol::java::client::play::{MetaDataType, Metadata}; +use pumpkin_data::meta_data_type::MetaDataType; +use pumpkin_data::{Block, tracked_data::TrackedData}; +use pumpkin_protocol::java::client::play::Metadata; use pumpkin_util::math::position::BlockPos; use pumpkin_world::{BlockStateId, world::BlockFlags}; use std::sync::{Arc, atomic::Ordering}; @@ -95,7 +96,7 @@ impl EntityBase for FallingEntity { Box::pin(async move { self.entity .send_meta_data(&[Metadata::new( - 8, + TrackedData::DATA_BLOCK_POS, MetaDataType::BlockPos, self.entity.block_pos.load(), )]) diff --git a/pumpkin/src/entity/item.rs b/pumpkin/src/entity/item.rs index 78ea9bc35..74a035945 100644 --- a/pumpkin/src/entity/item.rs +++ b/pumpkin/src/entity/item.rs @@ -8,10 +8,10 @@ use std::sync::{ }; use crossbeam::atomic::AtomicCell; -use pumpkin_data::damage::DamageType; +use pumpkin_data::{damage::DamageType, meta_data_type::MetaDataType, tracked_data::TrackedData}; use pumpkin_protocol::{ codec::item_stack_seralizer::ItemStackSerializer, - java::client::play::{CTakeItemEntity, MetaDataType, Metadata}, + java::client::play::{CTakeItemEntity, Metadata}, }; use pumpkin_util::math::vector3::Vector3; use pumpkin_world::item::ItemStack; @@ -349,7 +349,7 @@ impl EntityBase for ItemEntity { Box::pin(async { self.entity .send_meta_data(&[Metadata::new( - 8, + TrackedData::DATA_STACK, MetaDataType::ItemStack, &ItemStackSerializer::from(self.item_stack.lock().await.clone()), )]) diff --git a/pumpkin/src/entity/living.rs b/pumpkin/src/entity/living.rs index e5896e099..c8d2c679f 100644 --- a/pumpkin/src/entity/living.rs +++ b/pumpkin/src/entity/living.rs @@ -1,4 +1,6 @@ +use pumpkin_data::meta_data_type::MetaDataType; use pumpkin_data::potion::Effect; +use pumpkin_data::tracked_data::TrackedData; use pumpkin_inventory::build_equipment_slots; use pumpkin_inventory::player::player_inventory::PlayerInventory; use pumpkin_util::Hand; @@ -31,7 +33,7 @@ use pumpkin_protocol::codec::var_int::VarInt; use pumpkin_protocol::java::client::play::{CHurtAnimation, CTakeItemEntity}; use pumpkin_protocol::{ codec::item_stack_seralizer::ItemStackSerializer, - java::client::play::{CDamageEvent, CSetEquipment, MetaDataType, Metadata}, + java::client::play::{CDamageEvent, CSetEquipment, Metadata}, }; use pumpkin_util::math::vector3::Vector3; use pumpkin_util::text::TextComponent; @@ -78,10 +80,10 @@ pub struct LivingEntity { } impl LivingEntity { - const USING_ITEM_FLAG: i32 = 1; - const OFF_HAND_ACTIVE_FLAG: i32 = 2; + const USING_ITEM_FLAG: u8 = 1; + const OFF_HAND_ACTIVE_FLAG: u8 = 2; #[expect(dead_code)] - const USING_RIPTIDE_FLAG: i32 = 4; + const USING_RIPTIDE_FLAG: u8 = 4; pub fn new(entity: Entity) -> Self { let water_movement_speed_multiplier = if entity.entity_type == &EntityType::POLAR_BEAR { @@ -160,8 +162,8 @@ impl LivingEntity { .await; } - async fn set_living_flag(&self, flag: i32, value: bool) { - let index = flag as u8; + async fn set_living_flag(&self, flag: u8, value: bool) { + let index = flag; let mut b = self.livings_flags.load(Ordering::Relaxed); if value { b |= index; @@ -170,7 +172,11 @@ impl LivingEntity { } self.livings_flags.store(b, Ordering::Relaxed); self.entity - .send_meta_data(&[Metadata::new(8, MetaDataType::Byte, b)]) + .send_meta_data(&[Metadata::new( + TrackedData::DATA_LIVING_FLAGS, + MetaDataType::Byte, + b, + )]) .await; } @@ -191,7 +197,11 @@ impl LivingEntity { self.health.store(health.max(0.0)); // tell everyone entities health changed self.entity - .send_meta_data(&[Metadata::new(9, MetaDataType::Float, health)]) + .send_meta_data(&[Metadata::new( + TrackedData::DATA_HEALTH, + MetaDataType::Float, + health, + )]) .await; } diff --git a/pumpkin/src/entity/mod.rs b/pumpkin/src/entity/mod.rs index a0155ef5b..382648eac 100644 --- a/pumpkin/src/entity/mod.rs +++ b/pumpkin/src/entity/mod.rs @@ -9,6 +9,8 @@ use pumpkin_data::BlockState; use pumpkin_data::block_properties::{EnumVariants, Integer0To15}; use pumpkin_data::dimension::Dimension; use pumpkin_data::fluid::Fluid; +use pumpkin_data::meta_data_type::MetaDataType; +use pumpkin_data::tracked_data::TrackedData; use pumpkin_data::{Block, BlockDirection}; use pumpkin_data::{ block_properties::{Facing, HorizontalFacing}, @@ -22,7 +24,7 @@ use pumpkin_protocol::{ codec::var_int::VarInt, java::client::play::{ CEntityPositionSync, CEntityVelocity, CHeadRot, CSetEntityMetadata, CSpawnEntity, - CUpdateEntityRot, MetaDataType, Metadata, + CUpdateEntityRot, Metadata, }, ser::serializer::Serializer, }; @@ -37,7 +39,6 @@ use pumpkin_util::math::{ }; use pumpkin_util::text::TextComponent; use pumpkin_util::text::hover::HoverEvent; -use pumpkin_world::entity::entity_data_flags::DATA_POSE; use serde::Serialize; use std::collections::BTreeMap; use std::f32::consts::PI; @@ -443,7 +444,7 @@ impl Entity { /// Sets a custom name for the entity, typically used with nametags pub async fn set_custom_name(&self, name: TextComponent) { self.send_meta_data(&[Metadata::new( - 2, + TrackedData::DATA_CUSTOM_NAME, MetaDataType::OptionalTextComponent, Some(name), )]) @@ -499,16 +500,15 @@ impl Entity { /// Returns entity rotation as vector pub fn rotation(&self) -> Vector3 { - // Convert degrees to radians if necessary - let yaw_rad = self.yaw.load().to_radians(); let pitch_rad = self.pitch.load().to_radians(); + let yaw_rad = -self.yaw.load().to_radians(); - Vector3::new( - yaw_rad.cos() * pitch_rad.cos(), - pitch_rad.sin(), - yaw_rad.sin() * pitch_rad.cos(), - ) - .normalize() + let cos_yaw = yaw_rad.cos(); + let sin_yaw = yaw_rad.sin(); + let cos_pitch = pitch_rad.cos(); + let sin_pitch = pitch_rad.sin(); + + Vector3::new(sin_yaw * cos_pitch, -sin_pitch, cos_yaw * cos_pitch) } /// Changes this entity's pitch and yaw to look at target @@ -1602,8 +1602,12 @@ impl Entity { } else { b &= !(1 << index); } - self.send_meta_data(&[Metadata::new(0, MetaDataType::Byte, b)]) - .await; + self.send_meta_data(&[Metadata::new( + TrackedData::DATA_FLAGS, + MetaDataType::Byte, + b, + )]) + .await; } /// Plays sound at this entity's position with the entity's sound category @@ -1631,7 +1635,7 @@ impl Entity { self.pose.store(pose); let pose = pose as i32; self.send_meta_data(&[Metadata::new( - DATA_POSE, + TrackedData::DATA_POSE, MetaDataType::EntityPose, VarInt(pose), )]) diff --git a/pumpkin/src/entity/player.rs b/pumpkin/src/entity/player.rs index f769546f7..3a01b9841 100644 --- a/pumpkin/src/entity/player.rs +++ b/pumpkin/src/entity/player.rs @@ -11,6 +11,8 @@ use crossbeam::atomic::AtomicCell; use crossbeam::channel::Receiver; use log::warn; use pumpkin_data::dimension::Dimension; +use pumpkin_data::meta_data_type::MetaDataType; +use pumpkin_data::tracked_data::TrackedData; use pumpkin_inventory::player::ender_chest_inventory::EnderChestInventory; use pumpkin_protocol::bedrock::client::level_chunk::CLevelChunk; use pumpkin_protocol::bedrock::client::set_time::CSetTime; @@ -54,7 +56,7 @@ use pumpkin_protocol::java::client::play::{ CSetContainerContent, CSetContainerProperty, CSetContainerSlot, CSetCursorItem, CSetEquipment, CSetExperience, CSetHealth, CSetPlayerInventory, CSetSelectedSlot, CSoundEffect, CStopSound, CSubtitle, CSystemChatMessage, CTitleAnimation, CTitleText, CUnloadChunk, CUpdateMobEffect, - CUpdateTime, GameEvent, MetaDataType, Metadata, PlayerAction, PlayerInfoFlags, PreviousMessage, + CUpdateTime, GameEvent, Metadata, PlayerAction, PlayerInfoFlags, PreviousMessage, }; use pumpkin_protocol::java::server::play::SClickSlot; use pumpkin_util::math::{ @@ -68,7 +70,6 @@ use pumpkin_util::text::hover::HoverEvent; use pumpkin_util::{GameMode, Hand}; use pumpkin_world::biome; use pumpkin_world::cylindrical_chunk_iterator::Cylindrical; -use pumpkin_world::entity::entity_data_flags::SLEEPING_POS_ID; use pumpkin_world::item::ItemStack; use pumpkin_world::level::{Level, SyncChunk, SyncEntityChunk}; @@ -719,7 +720,7 @@ impl Player { .set_pos(bed_head_pos.to_f64().add_raw(0.5, 0.6875, 0.5)); self.get_entity() .send_meta_data(&[Metadata::new( - SLEEPING_POS_ID, + TrackedData::DATA_SLEEPING_POSITION, MetaDataType::OptionalBlockPos, Some(bed_head_pos), )]) @@ -770,7 +771,7 @@ impl Player { self.living_entity .entity .send_meta_data(&[Metadata::new( - SLEEPING_POS_ID, + TrackedData::DATA_SLEEPING_POSITION, MetaDataType::OptionalBlockPos, None::, )]) @@ -1511,24 +1512,23 @@ impl Player { } /// Send the player's skin layers and used hand to all players. - pub fn send_client_information(&self) { - //let config = self.config.read().await; - // TODO - // self.living_entity - // .entity - // .send_meta_data(&[ - // Metadata::new( - // DATA_PLAYER_MODE_CUSTOMISATION, - // MetaDataType::Byte, - // config.skin_parts, - // ), - // Metadata::new( - // DATA_PLAYER_MAIN_HAND, - // MetaDataType::Byte, - // config.main_hand as u8, - // ), - // ]) - // .await; + pub async fn send_client_information(&self) { + let config = self.config.read().await; + self.living_entity + .entity + .send_meta_data(&[ + Metadata::new( + TrackedData::DATA_PLAYER_MODE_CUSTOMIZATION_ID, + MetaDataType::Byte, + config.skin_parts, + ), + // Metadata::new( + // TrackedData::DATA_MAIN_ARM_ID, + // MetaDataType::Arm, + // VarInt(config.main_hand as u8 as i32), + // ), + ]) + .await; } pub async fn can_harvest(&self, state: &BlockState, block: &'static Block) -> bool { diff --git a/pumpkin/src/entity/projectile/firework_rocket.rs b/pumpkin/src/entity/projectile/firework_rocket.rs new file mode 100644 index 000000000..b55e7d27b --- /dev/null +++ b/pumpkin/src/entity/projectile/firework_rocket.rs @@ -0,0 +1,130 @@ +use std::sync::{ + Arc, + atomic::{AtomicU32, Ordering}, +}; + +use pumpkin_data::{entity::EntityStatus, meta_data_type::MetaDataType, tracked_data::TrackedData}; +use pumpkin_protocol::{codec::optional_int::OptionalInt, java::client::play::Metadata}; +use pumpkin_util::{ + math::vector3::Vector3, + random::{RandomGenerator, RandomImpl, get_seed, xoroshiro128::Xoroshiro}, +}; + +use crate::{ + entity::{Entity, EntityBase, EntityBaseFuture, NBTStorage, projectile::ThrownItemEntity}, + server::Server, + world::World, +}; + +pub struct FireworkRocketEntity { + entity: ThrownItemEntity, + shooter_id: Option, + life: AtomicU32, + life_time: AtomicU32, +} + +impl FireworkRocketEntity { + pub async fn new(entity: Entity) -> Self { + let mut random = RandomGenerator::Xoroshiro(Xoroshiro::from_seed(get_seed())); + + entity + .set_velocity(Vector3::new( + random.next_triangular(0.0, 0.002_297), + 0.05, + random.next_triangular(0.0, 0.002_297), + )) + .await; + Self { + entity: ThrownItemEntity { entity }, + shooter_id: None, + life: 0.into(), + // TODO + life_time: (10 + random.next_bounded_i32(6) as u32 + random.next_bounded_i32(7) as u32) + .into(), + } + } + + pub async fn new_shot(entity: Entity, shooter: &Entity) -> Self { + let mut entity = Self::new(entity).await; + entity.shooter_id = Some(shooter.entity_id); + + entity + .entity + .entity + .send_meta_data(&[Metadata::new( + TrackedData::DATA_SHOOTER_ENTITY_ID, + MetaDataType::OptionalInt, + OptionalInt(Some(shooter.entity_id)), + )]) + .await; + entity + } + + pub async fn explode_and_remove(&self, world: &World) { + let entity = self.get_entity(); + world + .send_entity_status(entity, EntityStatus::ExplodeFireworkClient) + .await; + // TODO: Explode + + entity.remove().await; + } +} + +impl NBTStorage for FireworkRocketEntity {} + +impl EntityBase for FireworkRocketEntity { + fn tick<'a>( + &'a self, + caller: Arc, + server: &'a Server, + ) -> EntityBaseFuture<'a, ()> { + Box::pin(async move { + self.entity.tick(caller, server).await; + + let entity = self.get_entity(); + let world = &entity.world; + let mut velocity = entity.velocity.load(); + + if let Some(shooter_id) = self.shooter_id { + if let Some(shooter) = world.get_entity_by_id(shooter_id).await { + let shooter = shooter.get_entity(); + if shooter.fall_flying.load(Ordering::Relaxed) { + let rotation = shooter.rotation().to_f64(); + let shooter_vel = shooter.velocity.load(); + + let new_shooter_vel = + shooter_vel + (rotation * 0.1 + (rotation * 1.5 - shooter_vel) * 0.5); + + shooter.set_velocity(new_shooter_vel).await; + + entity.set_pos(shooter.pos.load()); + entity.set_velocity(new_shooter_vel).await; + } + } + } else { + velocity.x *= 1.15; + velocity.z *= 1.15; + velocity.y += 0.04; + entity.set_velocity(velocity).await; + } + + let current_life = self.life.fetch_add(1, Ordering::Relaxed); + if current_life > self.life_time.load(Ordering::Relaxed) { + self.explode_and_remove(world).await; + } + }) + } + + fn get_entity(&self) -> &crate::entity::Entity { + &self.entity.entity + } + + fn get_living_entity(&self) -> Option<&crate::entity::living::LivingEntity> { + None + } + + fn as_nbt_storage(&self) -> &dyn crate::entity::NBTStorage { + self + } +} diff --git a/pumpkin/src/entity/projectile/mod.rs b/pumpkin/src/entity/projectile/mod.rs index c9718bcfb..5c2c96d85 100644 --- a/pumpkin/src/entity/projectile/mod.rs +++ b/pumpkin/src/entity/projectile/mod.rs @@ -6,10 +6,11 @@ use std::{ use super::{Entity, EntityBase, NBTStorage, living::LivingEntity}; use pumpkin_util::math::vector3::Vector3; +pub mod firework_rocket; pub mod wind_charge; pub struct ThrownItemEntity { - entity: Entity, + pub entity: Entity, } impl ThrownItemEntity { diff --git a/pumpkin/src/entity/projectile/wind_charge.rs b/pumpkin/src/entity/projectile/wind_charge.rs index 90156d553..3533cec6c 100644 --- a/pumpkin/src/entity/projectile/wind_charge.rs +++ b/pumpkin/src/entity/projectile/wind_charge.rs @@ -102,11 +102,11 @@ impl EntityBase for WindChargeEntity { server: &'a Server, ) -> EntityBaseFuture<'a, ()> { Box::pin(async move { + self.thrown_item_entity.tick(caller, server).await; + if self.get_deflect_cooldown() > 0 { self.set_deflect_cooldown(self.get_deflect_cooldown() - 1); } - - self.thrown_item_entity.tick(caller, server).await; }) } diff --git a/pumpkin/src/entity/tnt.rs b/pumpkin/src/entity/tnt.rs index 85c4fc22e..84d64a015 100644 --- a/pumpkin/src/entity/tnt.rs +++ b/pumpkin/src/entity/tnt.rs @@ -1,11 +1,8 @@ use super::{Entity, EntityBase, NBTStorage, living::LivingEntity}; use crate::{entity::EntityBaseFuture, server::Server}; use core::f32; -use pumpkin_data::Block; -use pumpkin_protocol::{ - codec::var_int::VarInt, - java::client::play::{MetaDataType, Metadata}, -}; +use pumpkin_data::{Block, meta_data_type::MetaDataType, tracked_data::TrackedData}; +use pumpkin_protocol::{codec::var_int::VarInt, java::client::play::Metadata}; use pumpkin_util::math::vector3::Vector3; use std::{ f64::consts::TAU, @@ -88,12 +85,12 @@ impl EntityBase for TNTEntity { self.entity .send_meta_data(&[ Metadata::new( - 8, + TrackedData::DATA_FUSE, MetaDataType::Integer, VarInt(self.fuse.load(Relaxed) as i32), ), Metadata::new( - 9, + TrackedData::DATA_BLOCK_STATE, MetaDataType::BlockState, VarInt(i32::from(Block::TNT.default_state.id)), ), diff --git a/pumpkin/src/item/items/armor_stand.rs b/pumpkin/src/item/items/armor_stand.rs index dc2ba37fd..5bff3f9eb 100644 --- a/pumpkin/src/item/items/armor_stand.rs +++ b/pumpkin/src/item/items/armor_stand.rs @@ -45,6 +45,7 @@ impl ItemBehaviour for ArmorStandItem { player: &'a Player, location: BlockPos, face: BlockDirection, + _cursor_pos: Vector3, _block: &'a Block, _server: &'a Server, ) -> Pin + Send + 'a>> { diff --git a/pumpkin/src/item/items/axe.rs b/pumpkin/src/item/items/axe.rs index 03734abc1..35a2ab7af 100644 --- a/pumpkin/src/item/items/axe.rs +++ b/pumpkin/src/item/items/axe.rs @@ -9,6 +9,7 @@ use pumpkin_data::block_properties::{OakDoorLikeProperties, PaleOakWoodLikePrope use pumpkin_data::tag::Taggable; use pumpkin_data::{Block, tag}; use pumpkin_util::math::position::BlockPos; +use pumpkin_util::math::vector3::Vector3; use pumpkin_world::item::ItemStack; use pumpkin_world::world::BlockFlags; @@ -27,6 +28,7 @@ impl ItemBehaviour for AxeItem { player: &'a Player, location: BlockPos, _face: BlockDirection, + _cursor_pos: Vector3, block: &'a Block, _server: &'a Server, ) -> Pin + Send + 'a>> { diff --git a/pumpkin/src/item/items/end_crystal.rs b/pumpkin/src/item/items/end_crystal.rs index 6697a7f5a..2da530269 100644 --- a/pumpkin/src/item/items/end_crystal.rs +++ b/pumpkin/src/item/items/end_crystal.rs @@ -10,6 +10,7 @@ use pumpkin_data::entity::EntityType; use pumpkin_data::item::Item; use pumpkin_data::{Block, BlockDirection}; use pumpkin_util::math::position::BlockPos; +use pumpkin_util::math::vector3::Vector3; use pumpkin_world::item::ItemStack; use uuid::Uuid; @@ -28,6 +29,7 @@ impl ItemBehaviour for EndCrystalItem { player: &'a Player, location: BlockPos, _face: BlockDirection, + _cursor_pos: Vector3, _block: &'a Block, _server: &'a Server, ) -> Pin + Send + 'a>> { diff --git a/pumpkin/src/item/items/ender_eye.rs b/pumpkin/src/item/items/ender_eye.rs index a458205e6..b443fada3 100644 --- a/pumpkin/src/item/items/ender_eye.rs +++ b/pumpkin/src/item/items/ender_eye.rs @@ -4,6 +4,7 @@ use std::sync::Arc; use crate::{server::Server, world::portal::end::EndPortal}; use pumpkin_data::{Block, BlockDirection, item::Item}; use pumpkin_util::math::position::BlockPos; +use pumpkin_util::math::vector3::Vector3; use pumpkin_world::item::ItemStack; use pumpkin_world::world::BlockFlags; @@ -25,6 +26,7 @@ impl ItemBehaviour for EnderEyeItem { player: &'a Player, location: BlockPos, _face: BlockDirection, + _cursor_pos: Vector3, block: &'a Block, _server: &'a Server, ) -> Pin + Send + 'a>> { diff --git a/pumpkin/src/item/items/firework_rocket.rs b/pumpkin/src/item/items/firework_rocket.rs new file mode 100644 index 000000000..586c84aa5 --- /dev/null +++ b/pumpkin/src/item/items/firework_rocket.rs @@ -0,0 +1,80 @@ +use std::pin::Pin; +use std::sync::Arc; +use std::sync::atomic::Ordering; + +use crate::entity::player::Player; +use crate::entity::projectile::firework_rocket::FireworkRocketEntity; +use crate::entity::{Entity, EntityBase}; +use crate::item::{ItemBehaviour, ItemMetadata}; +use crate::server::Server; +use pumpkin_data::Block; +use pumpkin_data::BlockDirection; +use pumpkin_data::entity::EntityType; +use pumpkin_data::item::Item; +use pumpkin_util::math::position::BlockPos; +use pumpkin_util::math::vector3::Vector3; +use pumpkin_world::item::ItemStack; +use uuid::Uuid; + +pub struct FireworkRocketItem; + +impl ItemMetadata for FireworkRocketItem { + fn ids() -> Box<[u16]> { + [Item::FIREWORK_ROCKET.id].into() + } +} + +impl ItemBehaviour for FireworkRocketItem { + fn use_on_block<'a>( + &'a self, + _item: &'a mut ItemStack, + player: &'a Player, + location: BlockPos, + _face: BlockDirection, + cursor_pos: Vector3, + _block: &'a Block, + _server: &'a Server, + ) -> Pin + Send + 'a>> { + Box::pin(async move { + let world = player.world(); + let entity = Entity::new( + Uuid::new_v4(), + world.clone(), + Vector3::new( + f64::from(location.0.x) + f64::from(cursor_pos.x), + f64::from(location.0.y) + f64::from(cursor_pos.y), + f64::from(location.0.z) + f64::from(cursor_pos.z), + ), + &EntityType::FIREWORK_ROCKET, + false, + ); + let entity = FireworkRocketEntity::new(entity).await; + world.spawn_entity(Arc::new(entity)).await; + }) + } + + fn normal_use<'a>( + &'a self, + _item: &'a Item, + player: &'a Player, + ) -> Pin + Send + 'a>> { + Box::pin(async { + if player.get_entity().fall_flying.load(Ordering::Relaxed) { + let world = player.world(); + let entity = Entity::new( + Uuid::new_v4(), + world.clone(), + player.get_entity().pos.load(), + &EntityType::FIREWORK_ROCKET, + false, + ); + let entity = FireworkRocketEntity::new_shot(entity, player.get_entity()).await; + world.spawn_entity(Arc::new(entity)).await; + } + }) + } + + fn as_any(&self) -> &dyn std::any::Any { + self + } +} diff --git a/pumpkin/src/item/items/hoe.rs b/pumpkin/src/item/items/hoe.rs index cd75bdf20..11ff75250 100644 --- a/pumpkin/src/item/items/hoe.rs +++ b/pumpkin/src/item/items/hoe.rs @@ -8,6 +8,7 @@ use pumpkin_data::entity::EntityType; use pumpkin_data::item::Item; use pumpkin_data::{Block, tag}; use pumpkin_util::math::position::BlockPos; +use pumpkin_util::math::vector3::Vector3; use pumpkin_world::item::ItemStack; use pumpkin_world::world::BlockFlags; use std::pin::Pin; @@ -29,6 +30,7 @@ impl ItemBehaviour for HoeItem { player: &'a Player, location: BlockPos, face: BlockDirection, + _cursor_pos: Vector3, block: &'a Block, _server: &'a Server, ) -> Pin + Send + 'a>> { diff --git a/pumpkin/src/item/items/honeycomb.rs b/pumpkin/src/item/items/honeycomb.rs index f050be81a..a9daf9455 100644 --- a/pumpkin/src/item/items/honeycomb.rs +++ b/pumpkin/src/item/items/honeycomb.rs @@ -15,6 +15,7 @@ use pumpkin_data::tag::Taggable; use pumpkin_data::world::WorldEvent; use pumpkin_data::{Block, tag}; use pumpkin_util::math::position::BlockPos; +use pumpkin_util::math::vector3::Vector3; use pumpkin_world::block::entities::BlockEntity; use pumpkin_world::block::entities::sign::SignBlockEntity; use pumpkin_world::item::ItemStack; @@ -35,6 +36,7 @@ impl ItemBehaviour for HoneyCombItem { player: &'a Player, location: BlockPos, _face: BlockDirection, + _cursor_pos: Vector3, block: &'a Block, _server: &'a Server, ) -> Pin + Send + 'a>> { diff --git a/pumpkin/src/item/items/ignite/fire_charge.rs b/pumpkin/src/item/items/ignite/fire_charge.rs index 7618b08ba..e323cdc16 100644 --- a/pumpkin/src/item/items/ignite/fire_charge.rs +++ b/pumpkin/src/item/items/ignite/fire_charge.rs @@ -7,6 +7,7 @@ use pumpkin_data::item::Item; use pumpkin_data::sound::Sound; use pumpkin_data::sound::SoundCategory; use pumpkin_util::math::position::BlockPos; +use pumpkin_util::math::vector3::Vector3; use pumpkin_world::item::ItemStack; use pumpkin_world::world::BlockFlags; @@ -31,6 +32,7 @@ impl ItemBehaviour for FireChargeItem { player: &'a Player, location: BlockPos, face: BlockDirection, + _cursor_pos: Vector3, block: &'a Block, _server: &'a Server, ) -> Pin + Send + 'a>> { diff --git a/pumpkin/src/item/items/ignite/flint_and_steel.rs b/pumpkin/src/item/items/ignite/flint_and_steel.rs index 05f88c025..da7aa47a2 100644 --- a/pumpkin/src/item/items/ignite/flint_and_steel.rs +++ b/pumpkin/src/item/items/ignite/flint_and_steel.rs @@ -7,6 +7,7 @@ use pumpkin_data::Block; use pumpkin_data::BlockDirection; use pumpkin_data::item::Item; use pumpkin_util::math::position::BlockPos; +use pumpkin_util::math::vector3::Vector3; use pumpkin_world::item::ItemStack; use pumpkin_world::world::BlockFlags; use std::pin::Pin; @@ -29,6 +30,7 @@ impl ItemBehaviour for FlintAndSteelItem { player: &'a Player, location: BlockPos, face: BlockDirection, + _cursor_pos: Vector3, block: &'a Block, _server: &'a Server, ) -> Pin + Send + 'a>> { diff --git a/pumpkin/src/item/items/minecart.rs b/pumpkin/src/item/items/minecart.rs index a2bac8cbe..300522c1c 100644 --- a/pumpkin/src/item/items/minecart.rs +++ b/pumpkin/src/item/items/minecart.rs @@ -55,6 +55,7 @@ impl ItemBehaviour for MinecartItem { player: &'a Player, location: BlockPos, _face: BlockDirection, + _cursor_pos: Vector3, block: &'a Block, _server: &'a Server, ) -> Pin + Send + 'a>> { diff --git a/pumpkin/src/item/items/mod.rs b/pumpkin/src/item/items/mod.rs index 434cf43d1..94cdd3a50 100644 --- a/pumpkin/src/item/items/mod.rs +++ b/pumpkin/src/item/items/mod.rs @@ -5,6 +5,7 @@ pub mod dye; pub mod egg; pub mod end_crystal; pub mod ender_eye; +pub mod firework_rocket; pub mod glowing_ink_sac; pub mod hoe; pub mod honeycomb; @@ -22,6 +23,7 @@ pub mod wind_charge; use crate::item::items::armor_stand::ArmorStandItem; use crate::item::items::end_crystal::EndCrystalItem; +use crate::item::items::firework_rocket::FireworkRocketItem; use crate::item::items::minecart::MinecartItem; use crate::item::items::name_tag::NameTagItem; use crate::item::items::spawn_egg::SpawnEggItem; @@ -69,6 +71,7 @@ pub fn default_registry() -> Arc { manager.register(EnderEyeItem); manager.register(FireChargeItem); manager.register(DyeItem); + manager.register(FireworkRocketItem); manager.register(InkSacItem); manager.register(GlowingInkSacItem); manager.register(ArmorStandItem); diff --git a/pumpkin/src/item/items/shovel.rs b/pumpkin/src/item/items/shovel.rs index 830c01d63..8c816635c 100644 --- a/pumpkin/src/item/items/shovel.rs +++ b/pumpkin/src/item/items/shovel.rs @@ -9,6 +9,7 @@ use pumpkin_data::sound::{Sound, SoundCategory}; use pumpkin_data::world::WorldEvent; use pumpkin_data::{Block, tag}; use pumpkin_util::math::position::BlockPos; +use pumpkin_util::math::vector3::Vector3; use pumpkin_world::item::ItemStack; use pumpkin_world::world::BlockFlags; use rand::{Rng, rng}; @@ -28,6 +29,7 @@ impl ItemBehaviour for ShovelItem { player: &'a Player, location: BlockPos, face: BlockDirection, + _cursor_pos: Vector3, block: &'a Block, _server: &'a Server, ) -> Pin + Send + 'a>> { diff --git a/pumpkin/src/item/items/spawn_egg.rs b/pumpkin/src/item/items/spawn_egg.rs index 2d5db05af..a846dd457 100644 --- a/pumpkin/src/item/items/spawn_egg.rs +++ b/pumpkin/src/item/items/spawn_egg.rs @@ -28,6 +28,7 @@ impl ItemBehaviour for SpawnEggItem { player: &'a Player, location: BlockPos, face: BlockDirection, + _cursor_pos: Vector3, _block: &'a Block, _server: &'a Server, ) -> Pin + Send + 'a>> { diff --git a/pumpkin/src/item/mod.rs b/pumpkin/src/item/mod.rs index f5ff0f31b..f60b895c1 100644 --- a/pumpkin/src/item/mod.rs +++ b/pumpkin/src/item/mod.rs @@ -28,12 +28,14 @@ pub trait ItemBehaviour: Send + Sync { Box::pin(async {}) } + #[expect(clippy::too_many_arguments)] fn use_on_block<'a>( &'a self, _item: &'a mut ItemStack, _player: &'a Player, _location: BlockPos, _face: BlockDirection, + _cursor_pos: Vector3, _block: &'a Block, _server: &'a Server, ) -> Pin + Send + 'a>> { diff --git a/pumpkin/src/item/registry.rs b/pumpkin/src/item/registry.rs index ab8b22e94..0023f357b 100644 --- a/pumpkin/src/item/registry.rs +++ b/pumpkin/src/item/registry.rs @@ -5,6 +5,7 @@ use pumpkin_data::Block; use pumpkin_data::BlockDirection; use pumpkin_data::item::Item; use pumpkin_util::math::position::BlockPos; +use pumpkin_util::math::vector3::Vector3; use pumpkin_world::item::ItemStack; use std::collections::HashMap; use std::sync::Arc; @@ -32,19 +33,21 @@ impl ItemRegistry { } } + #[expect(clippy::too_many_arguments)] pub async fn use_on_block( &self, stack: &mut ItemStack, player: &Player, location: BlockPos, face: BlockDirection, + cursor_pos: Vector3, block: &Block, server: &Server, ) { let pumpkin_item = self.get_pumpkin_item(stack.item); if let Some(pumpkin_item) = pumpkin_item { pumpkin_item - .use_on_block(stack, player, location, face, block, server) + .use_on_block(stack, player, location, face, cursor_pos, block, server) .await; } } diff --git a/pumpkin/src/net/bedrock/login.rs b/pumpkin/src/net/bedrock/login.rs index 1fc537f09..5ac92a84d 100644 --- a/pumpkin/src/net/bedrock/login.rs +++ b/pumpkin/src/net/bedrock/login.rs @@ -4,6 +4,7 @@ use crate::{ server::Server, }; use pumpkin_config::networking::compression::CompressionInfo; +use pumpkin_protocol::bedrock::server::resource_pack_response::SResourcePackResponse; use pumpkin_protocol::{ bedrock::{ client::{ @@ -48,12 +49,14 @@ struct CertificateChainPayload { impl BedrockClient { pub async fn handle_request_network_settings(&self, _packet: SRequestNetworkSettings) { + log::debug!("Bedrock: Sending Network settings"); self.send_game_packet(&CNetworkSettings::new(0, 0, false, 0, 0.0)) .await; self.set_compression(CompressionInfo::default()).await; } pub async fn handle_login(self: &Arc, packet: SLogin, server: &Server) -> Option<()> { + log::debug!("Bedrock: handle login"); match self.try_handle_login(packet, server).await { Ok(()) => Some(()), Err(error) => { @@ -104,7 +107,7 @@ impl BedrockClient { false, false, false, - false, + true, uuid::Uuid::default(), String::new(), Vec::new(), @@ -112,21 +115,6 @@ impl BedrockClient { &mut frame_set, ) .await; - self.write_game_packet_to_set( - &CResourcePackStackPacket::new( - false, - VarUInt(0), - VarUInt(0), - CURRENT_BEDROCK_MC_VERSION.to_string(), - Experiments { - names_size: 0, - experiments_ever_toggled: false, - }, - false, - ), - &mut frame_set, - ) - .await; self.send_frame_set(frame_set, 0x84).await; @@ -142,4 +130,28 @@ impl BedrockClient { Ok(()) } + + pub async fn handle_resource_pack_response(&self, packet: SResourcePackResponse) { + // TODO: Add all + if packet.response == SResourcePackResponse::STATUS_HAVE_ALL_PACKS { + log::debug!("Bedrock: STATUS_HAVE_ALL_PACKS"); + let mut frame_set = FrameSet::default(); + + self.write_game_packet_to_set( + &CResourcePackStackPacket::new( + false, + VarUInt(0), + CURRENT_BEDROCK_MC_VERSION.to_string(), + Experiments { + names_size: 0, + experiments_ever_toggled: false, + }, + false, + ), + &mut frame_set, + ) + .await; + self.send_frame_set(frame_set, 0x84).await; + } + } } diff --git a/pumpkin/src/net/bedrock/mod.rs b/pumpkin/src/net/bedrock/mod.rs index a7af0ad57..d0d96dbd3 100644 --- a/pumpkin/src/net/bedrock/mod.rs +++ b/pumpkin/src/net/bedrock/mod.rs @@ -489,6 +489,7 @@ impl BedrockClient { packet: RawPacket, ) -> Result<(), Error> { let payload = &mut Cursor::new(&packet.payload); + log::error!("packet id {}", packet.id); match packet.id { SRequestNetworkSettings::PACKET_ID => { self.handle_request_network_settings(SRequestNetworkSettings::read(payload)?) @@ -497,9 +498,13 @@ impl BedrockClient { SLogin::PACKET_ID => { self.handle_login(SLogin::read(payload)?, server).await; } - SClientCacheStatus::PACKET_ID | SResourcePackResponse::PACKET_ID => { + SClientCacheStatus::PACKET_ID => { // TODO } + SResourcePackResponse::PACKET_ID => { + self.handle_resource_pack_response(SResourcePackResponse::read(payload)?) + .await; + } _ => { self.handle_play_packet(self.player.lock().await.as_ref().unwrap(), server, packet) .await; diff --git a/pumpkin/src/net/bedrock/play.rs b/pumpkin/src/net/bedrock/play.rs index bdaa01348..eb078f61e 100644 --- a/pumpkin/src/net/bedrock/play.rs +++ b/pumpkin/src/net/bedrock/play.rs @@ -1,5 +1,5 @@ use std::{ - num::{NonZero, NonZeroU32}, + num::{NonZero, NonZeroI32}, sync::Arc, }; @@ -8,7 +8,6 @@ use pumpkin_protocol::{ bedrock::{ client::{ chunk_radius_update::CChunkRadiusUpdate, container_open::CContainerOpen, - network_chunk_publisher_update::CNetworkChunkPublisherUpdate, set_actor_motion::CSetActorMotion, }, server::{ @@ -20,7 +19,9 @@ use pumpkin_protocol::{ text::SText, }, }, - codec::{bedrock_block_pos::NetworkPos, var_long::VarLong, var_ulong::VarULong}, + codec::{ + bedrock_block_pos::NetworkPos, var_int::VarInt, var_long::VarLong, var_ulong::VarULong, + }, java::client::play::CSystemChatMessage, }; use pumpkin_util::{ @@ -34,7 +35,7 @@ use crate::{ net::{DisconnectReason, bedrock::BedrockClient}, plugin::player::{player_chat::PlayerChatEvent, player_command_send::PlayerCommandSendEvent}, server::{Server, seasonal_events}, - world::chunker, + world::chunker::{self}, }; impl BedrockClient { @@ -52,29 +53,30 @@ impl BedrockClient { .await; return; } + let server = player.world().server.upgrade().unwrap(); - self.send_game_packet(&CChunkRadiusUpdate { chunk_radius }) - .await; + let view_distance = + chunk_radius.clamp(2, NonZeroI32::from(server.basic_config.view_distance).get()); + + self.send_game_packet(&CChunkRadiusUpdate { + chunk_radius: VarInt(view_distance), + }) + .await; let old_view_distance = { let mut config = player.config.write().await; let old_view_distance = config.view_distance; - config.view_distance = NonZero::new(chunk_radius.0 as u8).unwrap(); + config.view_distance = NonZero::new(view_distance as u8).unwrap(); old_view_distance }; - if old_view_distance.get() != chunk_radius.0 as u8 { + if old_view_distance.get() != view_distance as u8 { log::debug!( "Player {} updated their render distance: {} -> {}.", player.gameprofile.name, old_view_distance, - chunk_radius.0 + view_distance ); - self.send_game_packet(&CNetworkChunkPublisherUpdate::new( - player.get_entity().block_pos.load(), - chunk_radius.0 as u32, - )) - .await; chunker::update_position(player).await; } } @@ -83,17 +85,6 @@ impl BedrockClient { if !player.has_client_loaded() { return; } - let config = player.config.read().await; - let view_distance = config.view_distance; - self.send_game_packet(&CNetworkChunkPublisherUpdate::new( - BlockPos::new( - packet.position.x.floor() as i32, - packet.position.y.floor() as i32, - packet.position.z.floor() as i32, - ), - NonZeroU32::from(view_distance).into(), - )) - .await; let new_pos = packet.position.to_f64(); let old_pos = player.position(); @@ -140,7 +131,7 @@ impl BedrockClient { self.send_game_packet(&CContainerOpen { container_id: 0, container_type: 0xff, - position: NetworkPos(packet.position.to_block_pos()), + position: NetworkPos(BlockPos::ZERO), target_entity_id: VarLong(-1), }) .await; diff --git a/pumpkin/src/net/bedrock/unconnected.rs b/pumpkin/src/net/bedrock/unconnected.rs index 1d9220887..9128eb538 100644 --- a/pumpkin/src/net/bedrock/unconnected.rs +++ b/pumpkin/src/net/bedrock/unconnected.rs @@ -7,7 +7,7 @@ use pumpkin_protocol::bedrock::{ use tokio::net::UdpSocket; use crate::{net::bedrock::BedrockClient, server::Server}; -use pumpkin_world::CURRENT_BEDROCK_MC_VERSION; +use pumpkin_world::{CURRENT_BEDROCK_MC_PROTOCOL, CURRENT_BEDROCK_MC_VERSION}; impl BedrockClient { pub async fn handle_unconnected_ping( @@ -31,7 +31,7 @@ impl BedrockClient { edition: "MCPE", // TODO The default motd is to long to be displayed completely motd_line_1: "Pumpkin Server", - protocol_version: 827, + protocol_version: CURRENT_BEDROCK_MC_PROTOCOL, version_name: CURRENT_BEDROCK_MC_VERSION, player_count, // A large number looks wreird on the client worlds window diff --git a/pumpkin/src/net/java/play.rs b/pumpkin/src/net/java/play.rs index a24cdab1f..6fdac78ec 100644 --- a/pumpkin/src/net/java/play.rs +++ b/pumpkin/src/net/java/play.rs @@ -1104,7 +1104,7 @@ impl JavaClient { player.gameprofile.name, self.id, ); - player.send_client_information(); + player.send_client_information().await; } } else { self.kick(TextComponent::text("Invalid hand or chat type")) @@ -1526,7 +1526,9 @@ impl JavaClient { server .item_registry - .use_on_block(&mut stack, player, position, face, block, server) + .use_on_block( + &mut stack, player, position, face, cursor_pos, block, server, + ) .await; // Check if the item is a block, because not every item can be placed :D diff --git a/pumpkin/src/net/mod.rs b/pumpkin/src/net/mod.rs index 34e94cc9d..b8aa59950 100644 --- a/pumpkin/src/net/mod.rs +++ b/pumpkin/src/net/mod.rs @@ -75,7 +75,7 @@ impl Default for PlayerConfig { fn default() -> Self { Self { locale: "en_us".to_string(), - view_distance: NonZeroU8::new(16).unwrap(), + view_distance: NonZeroU8::new(8).unwrap(), chat_mode: ChatMode::Enabled, chat_colors: true, skin_parts: 0, diff --git a/pumpkin/src/world/chunker.rs b/pumpkin/src/world/chunker.rs index 51f5eddc9..8c1535002 100644 --- a/pumpkin/src/world/chunker.rs +++ b/pumpkin/src/world/chunker.rs @@ -1,9 +1,15 @@ use std::{num::NonZeroU8, sync::Arc}; -use pumpkin_protocol::java::client::play::{CCenterChunk, CUnloadChunk}; +use pumpkin_protocol::{ + bedrock::client::network_chunk_publisher_update::CNetworkChunkPublisherUpdate, + java::client::play::{CCenterChunk, CUnloadChunk}, +}; use pumpkin_world::cylindrical_chunk_iterator::Cylindrical; -use crate::{entity::player::Player, net::ClientPlatform}; +use crate::{ + entity::{EntityBase, player::Player}, + net::ClientPlatform, +}; pub async fn get_view_distance(player: &Player) -> NonZeroU8 { let server = player.world().server.upgrade().unwrap(); @@ -24,12 +30,23 @@ pub async fn update_position(player: &Arc) { let new_cylindrical = Cylindrical::new(new_chunk_center, view_distance); if old_cylindrical != new_cylindrical { - if let ClientPlatform::Java(java) = &player.client { - java.send_packet_now(&CCenterChunk { - chunk_x: new_chunk_center.x.into(), - chunk_z: new_chunk_center.y.into(), - }) - .await; + match &player.client { + ClientPlatform::Java(java_client) => { + java_client + .send_packet_now(&CCenterChunk { + chunk_x: new_chunk_center.x.into(), + chunk_z: new_chunk_center.y.into(), + }) + .await; + } + ClientPlatform::Bedrock(bedrock_client) => { + bedrock_client + .send_game_packet(&CNetworkChunkPublisherUpdate::new( + player.get_entity().block_pos.load(), + u32::from(view_distance.get()) * 16, + )) + .await; + } } let mut loading_chunks = Vec::new(); let mut unloading_chunks = Vec::new(); diff --git a/pumpkin/src/world/mod.rs b/pumpkin/src/world/mod.rs index ef018039f..725c9ad2b 100644 --- a/pumpkin/src/world/mod.rs +++ b/pumpkin/src/world/mod.rs @@ -1,4 +1,3 @@ -use std::num::NonZeroU32; use std::pin::Pin; use std::sync::Weak; use std::sync::atomic::Ordering::Relaxed; @@ -35,6 +34,7 @@ use crate::{ }; use crate::{block::BlockEvent, entity::item::ItemEntity}; use border::Worldborder; +use bytes::BufMut; use crossbeam::queue::SegQueue; use explosion::Explosion; use pumpkin_config::BasicConfiguration; @@ -42,6 +42,8 @@ use pumpkin_data::data_component_impl::EquipmentSlot; use pumpkin_data::dimension::Dimension; use pumpkin_data::entity::MobCategory; use pumpkin_data::fluid::{Falling, FluidProperties, FluidState}; +use pumpkin_data::meta_data_type::MetaDataType; +use pumpkin_data::tracked_data::TrackedData; use pumpkin_data::{ Block, entity::{EntityStatus, EntityType}, @@ -53,10 +55,9 @@ use pumpkin_data::{ use pumpkin_data::{BlockDirection, BlockState}; use pumpkin_inventory::screen_handler::InventoryPlayer; use pumpkin_nbt::{compound::NbtCompound, to_bytes_unnamed}; -use pumpkin_protocol::bedrock::client::chunk_radius_update::CChunkRadiusUpdate; -use pumpkin_protocol::bedrock::client::network_chunk_publisher_update::CNetworkChunkPublisherUpdate; use pumpkin_protocol::bedrock::client::start_game::CStartGame; -use pumpkin_protocol::bedrock::frame_set::FrameSet; +use pumpkin_protocol::java::client::play::{CSetEntityMetadata, Metadata}; +use pumpkin_protocol::ser::serializer::Serializer; use pumpkin_protocol::{ BClientPacket, ClientPacket, IdOr, SoundEvent, bedrock::{ @@ -117,6 +118,7 @@ use pumpkin_world::{world::BlockFlags, world_info::LevelData}; use rand::seq::SliceRandom; use rand::{Rng, rng}; use scoreboard::Scoreboard; +use serde::Serialize; use time::LevelTime; use tokio::sync::Mutex; use tokio::sync::RwLock; @@ -1247,10 +1249,10 @@ impl World { yaw: 0.0, level_settings, level_id: String::new(), - level_name: "Pumpkin world".to_string(), + level_name: "World".to_string(), premium_world_template_id: String::new(), is_trial: false, - rewind_history_size: VarInt(40), + rewind_history_size: VarInt(0), server_authoritative_block_breaking: false, current_level_time: self.level_time.lock().await.world_age as _, enchantment_seed: VarInt(0), @@ -1271,16 +1273,10 @@ impl World { // TODO The client needs extra biome data for this enable_clientside_generation: false, blocknetwork_ids_are_hashed: false, - tick_death_system_enabled: false, - server_auth_sounds: false, + disable_client_sounds: false, }) .await; - client - .send_game_packet(&CChunkRadiusUpdate { - chunk_radius: VarInt(player.config.read().await.view_distance.get().into()), - }) - .await; - chunker::update_position(&player).await; + // chunker::update_position(&player).await; client .send_game_packet(&CreativeContent { groups: &[Group { @@ -1292,48 +1288,29 @@ impl World { }) .await; - let mut frame_set = FrameSet::default(); client - .write_game_packet_to_set( - &CNetworkChunkPublisherUpdate::new( - BlockPos::new(0, 100, 0), - NonZeroU32::from(player.config.read().await.view_distance).into(), - ), - &mut frame_set, - ) + .send_game_packet(&CUpdateAttributes { + runtime_id: VarULong(runtime_id), + attributes: vec![Attribute { + min_value: 0.0, + max_value: f32::MAX, + current_value: 0.1, + default_min_value: 0.0, + default_max_value: f32::MAX, + default_value: 0.1, + name: "minecraft:movement".to_string(), + modifiers_list_size: VarUInt(0), + }], + player_tick: VarULong(0), + }) .await; - - client - .write_game_packet_to_set( - &CUpdateAttributes { - runtime_id: VarULong(runtime_id), - attributes: vec![Attribute { - min_value: 0.0, - max_value: f32::MAX, - current_value: 0.1, - default_min_value: 0.0, - default_max_value: f32::MAX, - default_value: 0.1, - name: "minecraft:movement".to_string(), - modifiers_list_size: VarUInt(0), - }], - player_tick: VarULong(0), - }, - &mut frame_set, - ) - .await; - - client - .write_game_packet_to_set(&CPlayStatus::PlayerSpawn, &mut frame_set) - .await; - client.send_frame_set(frame_set, 0x84).await; - + player.send_abilities_update().await; { let mut abilities = player.abilities.lock().await; abilities.set_for_gamemode(player.gamemode.load()); }; - player.send_abilities_update().await; + client.send_game_packet(&CPlayStatus::PlayerSpawn).await; } #[expect(clippy::too_many_lines)] @@ -1553,36 +1530,29 @@ impl World { )) .await; { - // TODO - // let config = existing_player.config.read().await; - // let mut buf = Vec::new(); - // for meta in [ - // Metadata::new( - // DATA_PLAYER_MODE_CUSTOMISATION, - // MetaDataType::Byte, - // config.skin_parts, - // ), - // Metadata::new( - // DATA_PLAYER_MAIN_HAND, - // MetaDataType::Byte, - // config.main_hand as u8, - // ), - // ] { - // let mut serializer_buf = Vec::new(); + let config = existing_player.config.read().await; + let mut buf = Vec::new(); + { + let meta = Metadata::new( + TrackedData::DATA_PLAYER_MODE_CUSTOMIZATION_ID, + MetaDataType::Byte, + config.skin_parts, + ); + let mut serializer_buf = Vec::new(); - // let mut serializer = Serializer::new(&mut serializer_buf); - // meta.serialize(&mut serializer).unwrap(); - // buf.extend(serializer_buf); - // } - // drop(config); - // // END - // buf.put_u8(255); - // client - // .enqueue_packet(&CSetEntityMetadata::new( - // existing_player.get_entity().entity_id.into(), - // buf.into(), - // )) - // .await; + let mut serializer = Serializer::new(&mut serializer_buf); + meta.serialize(&mut serializer).unwrap(); + buf.extend(serializer_buf); + }; + drop(config); + // END + buf.put_u8(255); + client + .enqueue_packet(&CSetEntityMetadata::new( + existing_player.get_entity().entity_id.into(), + buf.into(), + )) + .await; }; { @@ -1617,7 +1587,7 @@ impl World { .await; } } - player.send_client_information(); + player.send_client_information().await; // Sync selected slot player @@ -1735,7 +1705,7 @@ impl World { ), ) .await; - player.send_client_information(); + player.send_client_information().await; chunker::update_position(player).await; // Update commands