feat: Implement fireworks
also fix: https://github.com/Pumpkin-MC/Pumpkin/issues/1217 also includes some bedrock work, but still broken
This commit is contained in:
parent
60d65f1f48
commit
e46459915c
32
Cargo.lock
generated
32
Cargo.lock
generated
@ -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"
|
||||
|
||||
@ -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"
|
||||
|
||||
41
assets/meta_data_type.json
Normal file
41
assets/meta_data_type.json
Normal file
@ -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
|
||||
}
|
||||
178
assets/tracked_data.json
Normal file
178
assets/tracked_data.json
Normal file
@ -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
|
||||
}
|
||||
@ -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"),
|
||||
|
||||
54
pumpkin-data/build/meta_data_type.rs
Normal file
54
pumpkin-data/build/meta_data_type.rs
Normal file
@ -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<String, i32> =
|
||||
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<Self> {
|
||||
match id {
|
||||
#(#from_id)*
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn id(&self) -> i32 {
|
||||
match self {
|
||||
#(#to_id)*
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
33
pumpkin-data/build/tracked_data.rs
Normal file
33
pumpkin-data/build/tracked_data.rs
Normal file
@ -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::<std::collections::HashMap<String, u8>>(
|
||||
&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)*
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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<W: 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)?;
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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<ResourcePack>,
|
||||
}
|
||||
|
||||
impl PacketWrite for CResourcePacksInfo {
|
||||
fn write<W: 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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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<f32>,
|
||||
}
|
||||
|
||||
impl PacketRead for SInteraction {
|
||||
fn read<R: Read>(reader: &mut R) -> Result<Self, Error> {
|
||||
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<Vector3<f32>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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<W: Write>(&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<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
|
||||
VarInt(self.0.0.x).write(writer)?;
|
||||
|
||||
@ -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;
|
||||
|
||||
17
pumpkin-protocol/src/codec/optional_int.rs
Normal file
17
pumpkin-protocol/src/codec/optional_int.rs
Normal file
@ -0,0 +1,17 @@
|
||||
use serde::{Serialize, Serializer};
|
||||
|
||||
use crate::codec::var_int::VarInt;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct OptionalInt(pub Option<i32>);
|
||||
|
||||
impl Serialize for OptionalInt {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
// Vanilla logic: empty is 0, otherwise value + 1
|
||||
let val = match self.0 {
|
||||
None => 0,
|
||||
Some(id) => id + 1,
|
||||
};
|
||||
VarInt(val).serialize(serializer)
|
||||
}
|
||||
}
|
||||
@ -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<T> Metadata<T> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
|
||||
@ -77,7 +77,9 @@ pub const fn smallest_encompassing_power_of_two(value: u32) -> u32 {
|
||||
#[inline]
|
||||
pub fn floor_div<T: PrimInt + Zero + One>(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
|
||||
|
||||
@ -233,6 +233,17 @@ impl<T: Math + Copy> Add for Vector3<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Math + Copy> Sub for Vector3<T> {
|
||||
type Output = Vector3<T>;
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
Self {
|
||||
x: self.x - rhs.x,
|
||||
y: self.y - rhs.y,
|
||||
z: self.z - rhs.z,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Math + Copy> AddAssign for Vector3<T> {
|
||||
fn add_assign(&mut self, other: Self) {
|
||||
self.x += other.x;
|
||||
@ -279,6 +290,16 @@ impl<T: Math + Copy + Into<f64>> Vector3<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Math + Copy + Into<f32>> Vector3<T> {
|
||||
pub fn to_f32(&self) -> Vector3<f32> {
|
||||
Vector3 {
|
||||
x: self.x.into(),
|
||||
y: self.y.into(),
|
||||
z: self.z.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Math + Copy + Into<f64>> Vector3<T> {
|
||||
pub fn to_i32(&self) -> Vector3<i32> {
|
||||
let x: f64 = self.x.into();
|
||||
|
||||
@ -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<Level>,
|
||||
) {
|
||||
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")
|
||||
|
||||
@ -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;
|
||||
@ -1 +0,0 @@
|
||||
pub mod entity_data_flags;
|
||||
@ -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!(),
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<u32>,
|
||||
inner: Option<NonZeroU32>,
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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<i32>) -> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<i32>, 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 {
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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() {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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<Item: Into<String>>,
|
||||
description: impl Into<String>,
|
||||
description: impl Into<Cow<'static, str>>,
|
||||
) -> Self {
|
||||
let names_vec = names.into_iter().map(Into::into).collect();
|
||||
|
||||
|
||||
@ -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<Node>,
|
||||
pub children: Vec<usize>,
|
||||
pub names: Vec<String>,
|
||||
pub description: String,
|
||||
pub description: Cow<'static, str>,
|
||||
}
|
||||
|
||||
impl CommandTree {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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(),
|
||||
)])
|
||||
|
||||
@ -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()),
|
||||
)])
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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<f32> {
|
||||
// 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),
|
||||
)])
|
||||
|
||||
@ -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::<BlockPos>,
|
||||
)])
|
||||
@ -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 {
|
||||
|
||||
130
pumpkin/src/entity/projectile/firework_rocket.rs
Normal file
130
pumpkin/src/entity/projectile/firework_rocket.rs
Normal file
@ -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<i32>,
|
||||
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<dyn EntityBase>,
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -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 {
|
||||
|
||||
@ -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;
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -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)),
|
||||
),
|
||||
|
||||
@ -45,6 +45,7 @@ impl ItemBehaviour for ArmorStandItem {
|
||||
player: &'a Player,
|
||||
location: BlockPos,
|
||||
face: BlockDirection,
|
||||
_cursor_pos: Vector3<f32>,
|
||||
_block: &'a Block,
|
||||
_server: &'a Server,
|
||||
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||
|
||||
@ -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<f32>,
|
||||
block: &'a Block,
|
||||
_server: &'a Server,
|
||||
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||
|
||||
@ -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<f32>,
|
||||
_block: &'a Block,
|
||||
_server: &'a Server,
|
||||
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||
|
||||
@ -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<f32>,
|
||||
block: &'a Block,
|
||||
_server: &'a Server,
|
||||
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||
|
||||
80
pumpkin/src/item/items/firework_rocket.rs
Normal file
80
pumpkin/src/item/items/firework_rocket.rs
Normal file
@ -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<f32>,
|
||||
_block: &'a Block,
|
||||
_server: &'a Server,
|
||||
) -> Pin<Box<dyn Future<Output = ()> + 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<Box<dyn Future<Output = ()> + 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
|
||||
}
|
||||
}
|
||||
@ -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<f32>,
|
||||
block: &'a Block,
|
||||
_server: &'a Server,
|
||||
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||
|
||||
@ -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<f32>,
|
||||
block: &'a Block,
|
||||
_server: &'a Server,
|
||||
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||
|
||||
@ -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<f32>,
|
||||
block: &'a Block,
|
||||
_server: &'a Server,
|
||||
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||
|
||||
@ -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<f32>,
|
||||
block: &'a Block,
|
||||
_server: &'a Server,
|
||||
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||
|
||||
@ -55,6 +55,7 @@ impl ItemBehaviour for MinecartItem {
|
||||
player: &'a Player,
|
||||
location: BlockPos,
|
||||
_face: BlockDirection,
|
||||
_cursor_pos: Vector3<f32>,
|
||||
block: &'a Block,
|
||||
_server: &'a Server,
|
||||
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||
|
||||
@ -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<ItemRegistry> {
|
||||
manager.register(EnderEyeItem);
|
||||
manager.register(FireChargeItem);
|
||||
manager.register(DyeItem);
|
||||
manager.register(FireworkRocketItem);
|
||||
manager.register(InkSacItem);
|
||||
manager.register(GlowingInkSacItem);
|
||||
manager.register(ArmorStandItem);
|
||||
|
||||
@ -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<f32>,
|
||||
block: &'a Block,
|
||||
_server: &'a Server,
|
||||
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||
|
||||
@ -28,6 +28,7 @@ impl ItemBehaviour for SpawnEggItem {
|
||||
player: &'a Player,
|
||||
location: BlockPos,
|
||||
face: BlockDirection,
|
||||
_cursor_pos: Vector3<f32>,
|
||||
_block: &'a Block,
|
||||
_server: &'a Server,
|
||||
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||
|
||||
@ -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<f32>,
|
||||
_block: &'a Block,
|
||||
_server: &'a Server,
|
||||
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||
|
||||
@ -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<f32>,
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<Self>, 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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<Player>) {
|
||||
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();
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user