Drop item when destroying blocks
Also make EntityType consts
This commit is contained in:
parent
2e2fe83720
commit
8a5a0cdee8
@ -1,9 +1,8 @@
|
|||||||
use quote::quote;
|
use quote::{format_ident, quote};
|
||||||
use std::{env, fs, path::Path, process::Command};
|
use std::{env, fs, path::Path, process::Command};
|
||||||
|
|
||||||
use heck::ToPascalCase;
|
use heck::ToPascalCase;
|
||||||
use proc_macro2::{Span, TokenStream};
|
use proc_macro2::TokenStream;
|
||||||
use syn::Ident;
|
|
||||||
|
|
||||||
mod biome;
|
mod biome;
|
||||||
mod chunk_status;
|
mod chunk_status;
|
||||||
@ -43,7 +42,7 @@ pub fn array_to_tokenstream(array: Vec<String>) -> TokenStream {
|
|||||||
let mut variants = TokenStream::new();
|
let mut variants = TokenStream::new();
|
||||||
|
|
||||||
for item in array.iter() {
|
for item in array.iter() {
|
||||||
let name = ident(item.to_pascal_case());
|
let name = format_ident!("{}", item.to_pascal_case());
|
||||||
variants.extend([quote! {
|
variants.extend([quote! {
|
||||||
#name,
|
#name,
|
||||||
}]);
|
}]);
|
||||||
@ -62,12 +61,3 @@ pub fn write_generated_file(content: TokenStream, out_file: &str) {
|
|||||||
// Doesn't matter if rustfmt is unavailable.
|
// Doesn't matter if rustfmt is unavailable.
|
||||||
let _ = Command::new("rustfmt").arg(path).output();
|
let _ = Command::new("rustfmt").arg(path).output();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ident<I: AsRef<str>>(s: I) -> Ident {
|
|
||||||
let s = s.as_ref().trim();
|
|
||||||
|
|
||||||
// Parse the ident from a str. If the string is a Rust keyword, stick an
|
|
||||||
// underscore in front.
|
|
||||||
syn::parse_str::<Ident>(s)
|
|
||||||
.unwrap_or_else(|_| Ident::new(format!("_{s}").as_str(), Span::call_site()))
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
use heck::ToPascalCase;
|
use heck::ToPascalCase;
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use quote::quote;
|
use quote::{format_ident, quote};
|
||||||
|
|
||||||
use crate::ident;
|
|
||||||
|
|
||||||
pub(crate) fn build() -> TokenStream {
|
pub(crate) fn build() -> TokenStream {
|
||||||
println!("cargo:rerun-if-changed=../assets/chunk_status.json");
|
println!("cargo:rerun-if-changed=../assets/chunk_status.json");
|
||||||
@ -14,7 +12,7 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
|
|
||||||
for status in chunk_status.iter() {
|
for status in chunk_status.iter() {
|
||||||
let full_name = format!("minecraft:{status}");
|
let full_name = format!("minecraft:{status}");
|
||||||
let name = ident(status.to_pascal_case());
|
let name = format_ident!("{}", status.to_pascal_case());
|
||||||
variants.extend([quote! {
|
variants.extend([quote! {
|
||||||
#[serde(rename = #full_name)]
|
#[serde(rename = #full_name)]
|
||||||
#name,
|
#name,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use heck::{ToPascalCase, ToShoutySnakeCase};
|
use heck::{ToPascalCase, ToShoutySnakeCase};
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use quote::quote;
|
use quote::{format_ident, quote};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
@ -29,8 +29,8 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
let mut enum_variants = Vec::new();
|
let mut enum_variants = Vec::new();
|
||||||
|
|
||||||
for (name, entry) in damage_types {
|
for (name, entry) in damage_types {
|
||||||
let const_ident = crate::ident(name.to_shouty_snake_case());
|
let const_ident = format_ident!("{}", name.to_shouty_snake_case());
|
||||||
let enum_ident = crate::ident(name.to_pascal_case());
|
let enum_ident = format_ident!("{}", name.to_pascal_case());
|
||||||
|
|
||||||
enum_variants.push(enum_ident.clone());
|
enum_variants.push(enum_ident.clone());
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
|
|
||||||
let enum_arms = enum_variants.iter().map(|variant| {
|
let enum_arms = enum_variants.iter().map(|variant| {
|
||||||
let const_name = variant.to_string().to_shouty_snake_case();
|
let const_name = variant.to_string().to_shouty_snake_case();
|
||||||
let const_ident = crate::ident(&const_name);
|
let const_ident = format_ident!("{}", &const_name);
|
||||||
quote! {
|
quote! {
|
||||||
DamageType::#variant => &#const_ident,
|
DamageType::#variant => &#const_ident,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,66 +1,101 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use heck::ToPascalCase;
|
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use quote::quote;
|
use quote::{format_ident, quote, ToTokens};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use syn::LitInt;
|
use syn::LitInt;
|
||||||
|
|
||||||
use crate::ident;
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct JSONStruct {
|
pub struct EntityType {
|
||||||
id: u16,
|
pub id: u16,
|
||||||
|
pub max_health: Option<f32>,
|
||||||
|
pub attackable: Option<bool>,
|
||||||
|
pub summonable: bool,
|
||||||
|
pub fire_immune: bool,
|
||||||
|
pub dimension: [f32; 2],
|
||||||
|
pub eye_height: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToTokens for EntityType {
|
||||||
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
|
let id = LitInt::new(&self.id.to_string(), proc_macro2::Span::call_site());
|
||||||
|
|
||||||
|
let max_health = match self.max_health {
|
||||||
|
Some(mh) => quote! { Some(#mh) },
|
||||||
|
None => quote! { None },
|
||||||
|
};
|
||||||
|
|
||||||
|
let attackable = match self.attackable {
|
||||||
|
Some(a) => quote! { Some(#a) },
|
||||||
|
None => quote! { None },
|
||||||
|
};
|
||||||
|
|
||||||
|
let summonable = self.summonable;
|
||||||
|
let fire_immune = self.fire_immune;
|
||||||
|
let eye_height = self.eye_height;
|
||||||
|
|
||||||
|
let dimension0 = self.dimension[0];
|
||||||
|
let dimension1 = self.dimension[1];
|
||||||
|
|
||||||
|
tokens.extend(quote! {
|
||||||
|
EntityType {
|
||||||
|
id: #id,
|
||||||
|
max_health: #max_health,
|
||||||
|
attackable: #attackable,
|
||||||
|
summonable: #summonable,
|
||||||
|
fire_immune: #fire_immune,
|
||||||
|
dimension: [#dimension0, #dimension1], // Correctly construct the array
|
||||||
|
eye_height: #eye_height,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn build() -> TokenStream {
|
pub(crate) fn build() -> TokenStream {
|
||||||
println!("cargo:rerun-if-changed=../assets/entities.json");
|
println!("cargo:rerun-if-changed=../assets/entities.json");
|
||||||
|
|
||||||
let json: HashMap<String, JSONStruct> =
|
let json: HashMap<String, EntityType> =
|
||||||
serde_json::from_str(include_str!("../../assets/entities.json"))
|
serde_json::from_str(include_str!("../../assets/entities.json"))
|
||||||
.expect("Failed to parse sound_category.json");
|
.expect("Failed to parse entities.json");
|
||||||
let mut variants = TokenStream::new();
|
|
||||||
|
|
||||||
for (item, id) in json.iter() {
|
let mut consts = TokenStream::new();
|
||||||
let id = id.id as u8;
|
let mut type_from_raw_id_arms = TokenStream::new();
|
||||||
|
let mut type_from_name = TokenStream::new();
|
||||||
|
|
||||||
|
for (name, entity) in json.iter() {
|
||||||
|
let id = entity.id as u8;
|
||||||
let id_lit = LitInt::new(&id.to_string(), proc_macro2::Span::call_site());
|
let id_lit = LitInt::new(&id.to_string(), proc_macro2::Span::call_site());
|
||||||
let name = ident(item.to_pascal_case());
|
let upper_name = format_ident!("{}", name.to_uppercase());
|
||||||
variants.extend([quote! {
|
|
||||||
#name = #id_lit,
|
let entity_tokens = entity.to_token_stream();
|
||||||
}]);
|
|
||||||
|
consts.extend(quote! {
|
||||||
|
pub const #upper_name: EntityType = #entity_tokens;
|
||||||
|
});
|
||||||
|
|
||||||
|
type_from_raw_id_arms.extend(quote! {
|
||||||
|
#id_lit => Some(Self::#upper_name),
|
||||||
|
});
|
||||||
|
|
||||||
|
type_from_name.extend(quote! {
|
||||||
|
#name => Some(Self::#upper_name),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let type_from_raw_id_arms = json
|
|
||||||
.iter()
|
|
||||||
.map(|sound| {
|
|
||||||
let id = &sound.1.id;
|
|
||||||
let name = ident(sound.0.to_pascal_case());
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
#id => Some(Self::#name),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<TokenStream>();
|
|
||||||
|
|
||||||
let type_from_name = json
|
|
||||||
.iter()
|
|
||||||
.map(|sound| {
|
|
||||||
let id = &sound.0;
|
|
||||||
let name = ident(sound.0.to_pascal_case());
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
#id => Some(Self::#name),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<TokenStream>();
|
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
pub enum EntityType {
|
pub struct EntityType {
|
||||||
#variants
|
pub id: u16,
|
||||||
|
pub max_health: Option<f32>,
|
||||||
|
pub attackable: Option<bool>,
|
||||||
|
pub summonable: bool,
|
||||||
|
pub fire_immune: bool,
|
||||||
|
pub dimension: [f32; 2],
|
||||||
|
pub eye_height: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EntityType {
|
impl EntityType {
|
||||||
|
#consts
|
||||||
|
|
||||||
pub const fn from_raw(id: u16) -> Option<Self> {
|
pub const fn from_raw(id: u16) -> Option<Self> {
|
||||||
match id {
|
match id {
|
||||||
#type_from_raw_id_arms
|
#type_from_raw_id_arms
|
||||||
|
|||||||
@ -2,11 +2,9 @@ use std::collections::HashMap;
|
|||||||
|
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use pumpkin_util::text::style::Style;
|
use pumpkin_util::text::style::Style;
|
||||||
use quote::quote;
|
use quote::{format_ident, quote};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::ident;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct RawChatType {
|
pub struct RawChatType {
|
||||||
id: u32,
|
id: u32,
|
||||||
@ -37,7 +35,7 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
|
|
||||||
for (name, typee) in json.iter() {
|
for (name, typee) in json.iter() {
|
||||||
let i = typee.id;
|
let i = typee.id;
|
||||||
let name = ident(name.to_uppercase());
|
let name = format_ident!("{}", name.to_uppercase());
|
||||||
variants.extend([quote! {
|
variants.extend([quote! {
|
||||||
pub const #name: u32 = #i;
|
pub const #name: u32 = #i;
|
||||||
}]);
|
}]);
|
||||||
|
|||||||
@ -1,11 +1,9 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use quote::quote;
|
use quote::{format_ident, quote};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::ident;
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct DoublePerlinNoiseParameters {
|
pub struct DoublePerlinNoiseParameters {
|
||||||
#[serde(rename = "firstOctave")]
|
#[serde(rename = "firstOctave")]
|
||||||
@ -23,7 +21,7 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
|
|
||||||
for (name, parameter) in json.iter() {
|
for (name, parameter) in json.iter() {
|
||||||
let raw_name = format!("minecraft:{name}");
|
let raw_name = format!("minecraft:{name}");
|
||||||
let name = ident(name.to_uppercase());
|
let name = format_ident!("{}", name.to_uppercase());
|
||||||
let first_octave = parameter.first_octave;
|
let first_octave = parameter.first_octave;
|
||||||
let amplitudes = ¶meter.amplitudes;
|
let amplitudes = ¶meter.amplitudes;
|
||||||
variants.extend([quote! {
|
variants.extend([quote! {
|
||||||
|
|||||||
@ -1,11 +1,9 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use quote::quote;
|
use quote::{format_ident, quote};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::ident;
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct Packets {
|
pub struct Packets {
|
||||||
serverbound: HashMap<String, Vec<String>>,
|
serverbound: HashMap<String, Vec<String>>,
|
||||||
@ -40,7 +38,7 @@ pub(crate) fn parse_packets(packets: HashMap<String, Vec<String>>) -> proc_macro
|
|||||||
for (id, packet_name) in packet.1.iter().enumerate() {
|
for (id, packet_name) in packet.1.iter().enumerate() {
|
||||||
let packet_id = id as i32;
|
let packet_id = id as i32;
|
||||||
let name = format!("{phase}_{packet_name}").to_uppercase();
|
let name = format!("{phase}_{packet_name}").to_uppercase();
|
||||||
let name = ident(name);
|
let name = format_ident!("{}", name);
|
||||||
consts.extend([quote! {
|
consts.extend([quote! {
|
||||||
pub const #name: i32 = #packet_id;
|
pub const #name: i32 = #packet_id;
|
||||||
}]);
|
}]);
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
use heck::ToPascalCase;
|
use heck::ToPascalCase;
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use quote::quote;
|
use quote::{format_ident, quote};
|
||||||
|
|
||||||
use crate::{array_to_tokenstream, ident};
|
use crate::array_to_tokenstream;
|
||||||
|
|
||||||
pub(crate) fn build() -> TokenStream {
|
pub(crate) fn build() -> TokenStream {
|
||||||
println!("cargo:rerun-if-changed=../assets/sounds.json");
|
println!("cargo:rerun-if-changed=../assets/sounds.json");
|
||||||
@ -15,7 +15,7 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|sound| {
|
.map(|sound| {
|
||||||
let id = &sound;
|
let id = &sound;
|
||||||
let name = ident(sound.to_pascal_case());
|
let name = format_ident!("{}", sound.to_pascal_case());
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
#id => Some(Self::#name),
|
#id => Some(Self::#name),
|
||||||
@ -27,7 +27,7 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|sound| {
|
.map(|sound| {
|
||||||
let id = &sound;
|
let id = &sound;
|
||||||
let name = ident(sound.to_pascal_case());
|
let name = format_ident!("{}", sound.to_pascal_case());
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
Self::#name => #id,
|
Self::#name => #id,
|
||||||
|
|||||||
@ -2,9 +2,7 @@ use std::collections::HashMap;
|
|||||||
|
|
||||||
use heck::ToPascalCase;
|
use heck::ToPascalCase;
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use quote::quote;
|
use quote::{format_ident, quote};
|
||||||
|
|
||||||
use crate::ident;
|
|
||||||
|
|
||||||
pub(crate) fn build() -> TokenStream {
|
pub(crate) fn build() -> TokenStream {
|
||||||
println!("cargo:rerun-if-changed=../assets/world_event.json");
|
println!("cargo:rerun-if-changed=../assets/world_event.json");
|
||||||
@ -15,7 +13,7 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
let mut variants = TokenStream::new();
|
let mut variants = TokenStream::new();
|
||||||
|
|
||||||
for (event, id) in events.iter() {
|
for (event, id) in events.iter() {
|
||||||
let name = ident(event.to_pascal_case());
|
let name = format_ident!("{}", event.to_pascal_case());
|
||||||
variants.extend([quote! {
|
variants.extend([quote! {
|
||||||
#name = #id,
|
#name = #id,
|
||||||
}]);
|
}]);
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
use pumpkin_data::packet::clientbound::PLAY_SET_ENTITY_MOTION;
|
use pumpkin_data::packet::clientbound::PLAY_SET_ENTITY_MOTION;
|
||||||
use pumpkin_macros::client_packet;
|
use pumpkin_macros::client_packet;
|
||||||
|
use pumpkin_util::math::vector3::Vector3;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::VarInt;
|
use crate::VarInt;
|
||||||
@ -8,18 +9,18 @@ use crate::VarInt;
|
|||||||
#[client_packet(PLAY_SET_ENTITY_MOTION)]
|
#[client_packet(PLAY_SET_ENTITY_MOTION)]
|
||||||
pub struct CEntityVelocity<'a> {
|
pub struct CEntityVelocity<'a> {
|
||||||
entity_id: &'a VarInt,
|
entity_id: &'a VarInt,
|
||||||
velocity_x: i16,
|
velocity: Vector3<i16>,
|
||||||
velocity_y: i16,
|
|
||||||
velocity_z: i16,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> CEntityVelocity<'a> {
|
impl<'a> CEntityVelocity<'a> {
|
||||||
pub fn new(entity_id: &'a VarInt, velocity_x: f64, velocity_y: f64, velocity_z: f64) -> Self {
|
pub fn new(entity_id: &'a VarInt, velocity_x: f64, velocity_y: f64, velocity_z: f64) -> Self {
|
||||||
Self {
|
Self {
|
||||||
entity_id,
|
entity_id,
|
||||||
velocity_x: (velocity_x.clamp(-3.9, 3.9) * 8000.0) as i16,
|
velocity: Vector3::new(
|
||||||
velocity_y: (velocity_y.clamp(-3.9, 3.9) * 8000.0) as i16,
|
(velocity_x.clamp(-3.9, 3.9) * 8000.0) as i16,
|
||||||
velocity_z: (velocity_z.clamp(-3.9, 3.9) * 8000.0) as i16,
|
(velocity_y.clamp(-3.9, 3.9) * 8000.0) as i16,
|
||||||
|
(velocity_z.clamp(-3.9, 3.9) * 8000.0) as i16,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
use bytes::BufMut;
|
use bytes::BufMut;
|
||||||
use pumpkin_data::{packet::clientbound::PLAY_SOUND, sound::SoundCategory};
|
use pumpkin_data::{packet::clientbound::PLAY_SOUND, sound::SoundCategory};
|
||||||
use pumpkin_macros::client_packet;
|
use pumpkin_macros::client_packet;
|
||||||
|
use pumpkin_util::math::vector3::Vector3;
|
||||||
|
|
||||||
use crate::{bytebuf::ByteBufMut, ClientPacket, IDOrSoundEvent, SoundEvent, VarInt};
|
use crate::{bytebuf::ByteBufMut, ClientPacket, IDOrSoundEvent, SoundEvent, VarInt};
|
||||||
|
|
||||||
@ -8,23 +9,18 @@ use crate::{bytebuf::ByteBufMut, ClientPacket, IDOrSoundEvent, SoundEvent, VarIn
|
|||||||
pub struct CSoundEffect {
|
pub struct CSoundEffect {
|
||||||
sound_event: IDOrSoundEvent,
|
sound_event: IDOrSoundEvent,
|
||||||
sound_category: VarInt,
|
sound_category: VarInt,
|
||||||
effect_position_x: i32,
|
position: Vector3<i32>,
|
||||||
effect_position_y: i32,
|
|
||||||
effect_position_z: i32,
|
|
||||||
volume: f32,
|
volume: f32,
|
||||||
pitch: f32,
|
pitch: f32,
|
||||||
seed: f64,
|
seed: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CSoundEffect {
|
impl CSoundEffect {
|
||||||
#[allow(clippy::too_many_arguments)]
|
|
||||||
pub fn new(
|
pub fn new(
|
||||||
sound_id: VarInt,
|
sound_id: VarInt,
|
||||||
sound_event: Option<SoundEvent>,
|
sound_event: Option<SoundEvent>,
|
||||||
sound_category: SoundCategory,
|
sound_category: SoundCategory,
|
||||||
effect_position_x: f64,
|
position: &Vector3<f64>,
|
||||||
effect_position_y: f64,
|
|
||||||
effect_position_z: f64,
|
|
||||||
volume: f32,
|
volume: f32,
|
||||||
pitch: f32,
|
pitch: f32,
|
||||||
seed: f64,
|
seed: f64,
|
||||||
@ -35,9 +31,11 @@ impl CSoundEffect {
|
|||||||
sound_event,
|
sound_event,
|
||||||
},
|
},
|
||||||
sound_category: VarInt(sound_category as i32),
|
sound_category: VarInt(sound_category as i32),
|
||||||
effect_position_x: (effect_position_x * 8.0) as i32,
|
position: Vector3::new(
|
||||||
effect_position_y: (effect_position_y * 8.0) as i32,
|
(position.x * 8.0) as i32,
|
||||||
effect_position_z: (effect_position_z * 8.0) as i32,
|
(position.y * 8.0) as i32,
|
||||||
|
(position.z * 8.0) as i32,
|
||||||
|
),
|
||||||
volume,
|
volume,
|
||||||
pitch,
|
pitch,
|
||||||
seed,
|
seed,
|
||||||
@ -58,9 +56,9 @@ impl ClientPacket for CSoundEffect {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
bytebuf.put_var_int(&self.sound_category);
|
bytebuf.put_var_int(&self.sound_category);
|
||||||
bytebuf.put_i32(self.effect_position_x);
|
bytebuf.put_i32(self.position.x);
|
||||||
bytebuf.put_i32(self.effect_position_y);
|
bytebuf.put_i32(self.position.y);
|
||||||
bytebuf.put_i32(self.effect_position_z);
|
bytebuf.put_i32(self.position.z);
|
||||||
bytebuf.put_f32(self.volume);
|
bytebuf.put_f32(self.volume);
|
||||||
bytebuf.put_f32(self.pitch);
|
bytebuf.put_f32(self.pitch);
|
||||||
bytebuf.put_f64(self.seed);
|
bytebuf.put_f64(self.seed);
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
use pumpkin_data::packet::clientbound::PLAY_ADD_ENTITY;
|
use pumpkin_data::packet::clientbound::PLAY_ADD_ENTITY;
|
||||||
use pumpkin_macros::client_packet;
|
use pumpkin_macros::client_packet;
|
||||||
|
use pumpkin_util::math::vector3::Vector3;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::VarInt;
|
use crate::VarInt;
|
||||||
@ -11,16 +12,12 @@ pub struct CSpawnEntity {
|
|||||||
#[serde(with = "uuid::serde::compact")]
|
#[serde(with = "uuid::serde::compact")]
|
||||||
entity_uuid: uuid::Uuid,
|
entity_uuid: uuid::Uuid,
|
||||||
typ: VarInt,
|
typ: VarInt,
|
||||||
x: f64,
|
position: Vector3<f64>,
|
||||||
y: f64,
|
|
||||||
z: f64,
|
|
||||||
pitch: u8, // angle
|
pitch: u8, // angle
|
||||||
yaw: u8, // angle
|
yaw: u8, // angle
|
||||||
head_yaw: u8, // angle
|
head_yaw: u8, // angle
|
||||||
data: VarInt,
|
data: VarInt,
|
||||||
velocity_x: i16,
|
velocity: Vector3<i16>,
|
||||||
velocity_y: i16,
|
|
||||||
velocity_z: i16,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CSpawnEntity {
|
impl CSpawnEntity {
|
||||||
@ -29,31 +26,27 @@ impl CSpawnEntity {
|
|||||||
entity_id: VarInt,
|
entity_id: VarInt,
|
||||||
entity_uuid: uuid::Uuid,
|
entity_uuid: uuid::Uuid,
|
||||||
typ: VarInt,
|
typ: VarInt,
|
||||||
x: f64,
|
position: Vector3<f64>,
|
||||||
y: f64,
|
|
||||||
z: f64,
|
|
||||||
pitch: f32, // angle
|
pitch: f32, // angle
|
||||||
yaw: f32, // angle
|
yaw: f32, // angle
|
||||||
head_yaw: f32, // angle
|
head_yaw: f32, // angle
|
||||||
data: VarInt,
|
data: VarInt,
|
||||||
velocity_x: f32,
|
velocity: Vector3<f64>,
|
||||||
velocity_y: f32,
|
|
||||||
velocity_z: f32,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
entity_id,
|
entity_id,
|
||||||
entity_uuid,
|
entity_uuid,
|
||||||
typ,
|
typ,
|
||||||
x,
|
position,
|
||||||
y,
|
|
||||||
z,
|
|
||||||
pitch: (pitch * 256.0 / 360.0).floor() as u8,
|
pitch: (pitch * 256.0 / 360.0).floor() as u8,
|
||||||
yaw: (yaw * 256.0 / 360.0).floor() as u8,
|
yaw: (yaw * 256.0 / 360.0).floor() as u8,
|
||||||
head_yaw: (head_yaw * 256.0 / 360.0).floor() as u8,
|
head_yaw: (head_yaw * 256.0 / 360.0).floor() as u8,
|
||||||
data,
|
data,
|
||||||
velocity_x: (velocity_x.clamp(-3.9, 3.9) * 8000.0) as i16,
|
velocity: Vector3::new(
|
||||||
velocity_y: (velocity_y.clamp(-3.9, 3.9) * 8000.0) as i16,
|
(velocity.x.clamp(-3.9, 3.9) * 8000.0) as i16,
|
||||||
velocity_z: (velocity_z.clamp(-3.9, 3.9) * 8000.0) as i16,
|
(velocity.x.clamp(-3.9, 3.9) * 8000.0) as i16,
|
||||||
|
(velocity.x.clamp(-3.9, 3.9) * 8000.0) as i16,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,15 +7,15 @@ pub struct BoundingBox {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl BoundingBox {
|
impl BoundingBox {
|
||||||
pub fn new_default(size: &BoundingBoxSize) -> Self {
|
pub fn new_default(size: &EntityDimensions) -> Self {
|
||||||
Self::new_from_pos(0., 0., 0., size)
|
Self::new_from_pos(0., 0., 0., size)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_from_pos(x: f64, y: f64, z: f64, size: &BoundingBoxSize) -> Self {
|
pub fn new_from_pos(x: f64, y: f64, z: f64, size: &EntityDimensions) -> Self {
|
||||||
let f = size.width / 2.;
|
let f = size.width as f64 / 2.;
|
||||||
Self {
|
Self {
|
||||||
min: Vector3::new(x - f, y, z - f),
|
min: Vector3::new(x - f, y, z - f),
|
||||||
max: Vector3::new(x + f, y + size.height, z + f),
|
max: Vector3::new(x + f, y + size.height as f64, z + f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,7 +75,7 @@ impl BoundingBox {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct BoundingBoxSize {
|
pub struct EntityDimensions {
|
||||||
pub width: f64,
|
pub width: f32,
|
||||||
pub height: f64,
|
pub height: f32,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1 +0,0 @@
|
|||||||
pub mod registry;
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
use std::{collections::HashMap, sync::LazyLock};
|
|
||||||
|
|
||||||
use serde::Deserialize;
|
|
||||||
|
|
||||||
const ENTITIES_JSON: &str = include_str!("../../../assets/entities.json");
|
|
||||||
|
|
||||||
pub static ENTITIES: LazyLock<HashMap<String, Entity>> = LazyLock::new(|| {
|
|
||||||
serde_json::from_str(ENTITIES_JSON).expect("Could not parse entity.json registry.")
|
|
||||||
});
|
|
||||||
|
|
||||||
pub static ENTITIES_BY_ID: LazyLock<HashMap<String, u16>> = LazyLock::new(|| {
|
|
||||||
let mut map = HashMap::new();
|
|
||||||
for (entity_name, entity) in ENTITIES.iter() {
|
|
||||||
map.insert(entity_name.clone(), entity.id);
|
|
||||||
}
|
|
||||||
map
|
|
||||||
});
|
|
||||||
|
|
||||||
pub fn get_entity_id(name: &str) -> Option<&u16> {
|
|
||||||
ENTITIES_BY_ID.get(&name.replace("minecraft:", ""))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_entity_by_id<'a>(entity_id: u16) -> Option<&'a Entity> {
|
|
||||||
ENTITIES.values().find(|&entity| entity.id == entity_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Clone, Debug)]
|
|
||||||
pub struct Entity {
|
|
||||||
pub id: u16,
|
|
||||||
pub max_health: Option<f32>,
|
|
||||||
pub attackable: Option<bool>,
|
|
||||||
pub summonable: bool,
|
|
||||||
pub fire_immune: bool,
|
|
||||||
pub dimension: [f32; 2],
|
|
||||||
}
|
|
||||||
@ -13,7 +13,6 @@ pub mod chunk;
|
|||||||
pub mod coordinates;
|
pub mod coordinates;
|
||||||
pub mod cylindrical_chunk_iterator;
|
pub mod cylindrical_chunk_iterator;
|
||||||
pub mod dimension;
|
pub mod dimension;
|
||||||
pub mod entity;
|
|
||||||
mod generation;
|
mod generation;
|
||||||
pub mod item;
|
pub mod item;
|
||||||
pub mod level;
|
pub mod level;
|
||||||
|
|||||||
@ -1,10 +1,19 @@
|
|||||||
use blocks::chest::ChestBlock;
|
use blocks::chest::ChestBlock;
|
||||||
use blocks::furnace::FurnaceBlock;
|
use blocks::furnace::FurnaceBlock;
|
||||||
use properties::BlockPropertiesManager;
|
use properties::BlockPropertiesManager;
|
||||||
|
use pumpkin_data::entity::EntityType;
|
||||||
|
use pumpkin_util::math::position::BlockPos;
|
||||||
|
use pumpkin_util::math::vector3::Vector3;
|
||||||
|
use pumpkin_world::block::registry::Block;
|
||||||
|
use pumpkin_world::item::ItemStack;
|
||||||
|
use rand::Rng;
|
||||||
|
|
||||||
use crate::block::blocks::crafting_table::CraftingTableBlock;
|
use crate::block::blocks::crafting_table::CraftingTableBlock;
|
||||||
use crate::block::blocks::jukebox::JukeboxBlock;
|
use crate::block::blocks::jukebox::JukeboxBlock;
|
||||||
use crate::block::registry::BlockRegistry;
|
use crate::block::registry::BlockRegistry;
|
||||||
|
use crate::entity::item::ItemEntity;
|
||||||
|
use crate::server::Server;
|
||||||
|
use crate::world::World;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
mod blocks;
|
mod blocks;
|
||||||
@ -24,6 +33,21 @@ pub fn default_registry() -> Arc<BlockRegistry> {
|
|||||||
Arc::new(manager)
|
Arc::new(manager)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn drop_loot(server: &Server, world: &Arc<World>, block: &Block, pos: &BlockPos) {
|
||||||
|
// TODO: Currently only the item block is droped, We should drop the loop table
|
||||||
|
let height = EntityType::ITEM.dimension[1] / 2.0;
|
||||||
|
let pos = Vector3::new(
|
||||||
|
f64::from(pos.0.x) + 0.5 + rand::thread_rng().gen_range(-0.25..0.25),
|
||||||
|
f64::from(pos.0.y) + 0.5 + rand::thread_rng().gen_range(-0.25..0.25) - f64::from(height),
|
||||||
|
f64::from(pos.0.z) + 0.5 + rand::thread_rng().gen_range(-0.25..0.25),
|
||||||
|
);
|
||||||
|
|
||||||
|
let entity = server.add_entity(pos, EntityType::ITEM, world);
|
||||||
|
let item_entity = Arc::new(ItemEntity::new(entity, &ItemStack::new(1, block.item_id)));
|
||||||
|
world.spawn_entity(item_entity.clone()).await;
|
||||||
|
item_entity.send_meta_packet().await;
|
||||||
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn default_block_properties_manager() -> Arc<BlockPropertiesManager> {
|
pub fn default_block_properties_manager() -> Arc<BlockPropertiesManager> {
|
||||||
let mut manager = BlockPropertiesManager::default();
|
let mut manager = BlockPropertiesManager::default();
|
||||||
|
|||||||
@ -41,7 +41,7 @@ impl CommandExecutor for SetblockExecutor {
|
|||||||
async fn execute<'a>(
|
async fn execute<'a>(
|
||||||
&self,
|
&self,
|
||||||
sender: &mut CommandSender<'a>,
|
sender: &mut CommandSender<'a>,
|
||||||
_server: &crate::server::Server,
|
server: &crate::server::Server,
|
||||||
args: &ConsumedArgs<'a>,
|
args: &ConsumedArgs<'a>,
|
||||||
) -> Result<(), CommandError> {
|
) -> Result<(), CommandError> {
|
||||||
let block = BlockArgumentConsumer::find_arg(args, ARG_BLOCK)?;
|
let block = BlockArgumentConsumer::find_arg(args, ARG_BLOCK)?;
|
||||||
@ -67,7 +67,9 @@ impl CommandExecutor for SetblockExecutor {
|
|||||||
for y in start_y..=end_y {
|
for y in start_y..=end_y {
|
||||||
for z in start_z..=end_z {
|
for z in start_z..=end_z {
|
||||||
let block_position = BlockPos(Vector3 { x, y, z });
|
let block_position = BlockPos(Vector3 { x, y, z });
|
||||||
world.break_block(&block_position, None).await;
|
world
|
||||||
|
.break_block(server, &block_position, None, false)
|
||||||
|
.await;
|
||||||
world.set_block_state(&block_position, block_state_id).await;
|
world.set_block_state(&block_position, block_state_id).await;
|
||||||
placed_blocks += 1;
|
placed_blocks += 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -46,7 +46,7 @@ impl CommandExecutor for KillExecutor {
|
|||||||
Some(TextComponent::text(name.clone())),
|
Some(TextComponent::text(name.clone())),
|
||||||
));
|
));
|
||||||
|
|
||||||
if entity.entity_type == entity::EntityType::Player {
|
if entity.entity_type == entity::EntityType::PLAYER {
|
||||||
entity_display = entity_display.click_event(ClickEvent::SuggestCommand(
|
entity_display = entity_display.click_event(ClickEvent::SuggestCommand(
|
||||||
format!("/tell {} ", name.clone()).into(),
|
format!("/tell {} ", name.clone()).into(),
|
||||||
));
|
));
|
||||||
|
|||||||
@ -34,7 +34,7 @@ impl CommandExecutor for SetblockExecutor {
|
|||||||
async fn execute<'a>(
|
async fn execute<'a>(
|
||||||
&self,
|
&self,
|
||||||
sender: &mut CommandSender<'a>,
|
sender: &mut CommandSender<'a>,
|
||||||
_server: &crate::server::Server,
|
server: &crate::server::Server,
|
||||||
args: &ConsumedArgs<'a>,
|
args: &ConsumedArgs<'a>,
|
||||||
) -> Result<(), CommandError> {
|
) -> Result<(), CommandError> {
|
||||||
let block = BlockArgumentConsumer::find_arg(args, ARG_BLOCK)?;
|
let block = BlockArgumentConsumer::find_arg(args, ARG_BLOCK)?;
|
||||||
@ -46,7 +46,7 @@ impl CommandExecutor for SetblockExecutor {
|
|||||||
|
|
||||||
let success = match mode {
|
let success = match mode {
|
||||||
Mode::Destroy => {
|
Mode::Destroy => {
|
||||||
world.break_block(&pos, None).await;
|
world.clone().break_block(server, &pos, None, false).await;
|
||||||
world.set_block_state(&pos, block_state_id).await;
|
world.set_block_state(&pos, block_state_id).await;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,8 +43,8 @@ fn yaw_pitch_facing_position(
|
|||||||
let yaw_radians = -direction_vector.x.atan2(direction_vector.z);
|
let yaw_radians = -direction_vector.x.atan2(direction_vector.z);
|
||||||
let pitch_radians = (-direction_vector.y).asin();
|
let pitch_radians = (-direction_vector.y).asin();
|
||||||
|
|
||||||
let yaw_degrees = yaw_radians * 180.0 / std::f64::consts::PI;
|
let yaw_degrees = yaw_radians.to_degrees();
|
||||||
let pitch_degrees = pitch_radians * 180.0 / std::f64::consts::PI;
|
let pitch_degrees = pitch_radians.to_degrees();
|
||||||
|
|
||||||
(yaw_degrees as f32, pitch_degrees as f32)
|
(yaw_degrees as f32, pitch_degrees as f32)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -97,7 +97,7 @@ impl CommandSender<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn world(&self) -> Option<&World> {
|
pub fn world(&self) -> Option<&Arc<World>> {
|
||||||
match self {
|
match self {
|
||||||
// TODO: maybe return first world when console
|
// TODO: maybe return first world when console
|
||||||
CommandSender::Console | CommandSender::Rcon(..) => None,
|
CommandSender::Console | CommandSender::Rcon(..) => None,
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
use std::f32::consts::PI;
|
|
||||||
|
|
||||||
use pumpkin_data::{
|
use pumpkin_data::{
|
||||||
particle::Particle,
|
particle::Particle,
|
||||||
sound::{Sound, SoundCategory},
|
sound::{Sound, SoundCategory},
|
||||||
@ -74,8 +72,8 @@ pub async fn handle_knockback(
|
|||||||
let saved_velo = victim_entity.velocity.load();
|
let saved_velo = victim_entity.velocity.load();
|
||||||
victim_entity.knockback(
|
victim_entity.knockback(
|
||||||
strength * 0.5,
|
strength * 0.5,
|
||||||
f64::from((yaw * (PI / 180.0)).sin()),
|
f64::from((yaw.to_radians()).sin()),
|
||||||
f64::from(-(yaw * (PI / 180.0)).cos()),
|
f64::from(-(yaw.to_radians()).cos()),
|
||||||
);
|
);
|
||||||
|
|
||||||
let entity_id = VarInt(victim_entity.entity_id);
|
let entity_id = VarInt(victim_entity.entity_id);
|
||||||
@ -98,8 +96,8 @@ pub async fn handle_knockback(
|
|||||||
|
|
||||||
pub async fn spawn_sweep_particle(attacker_entity: &Entity, world: &World, pos: &Vector3<f64>) {
|
pub async fn spawn_sweep_particle(attacker_entity: &Entity, world: &World, pos: &Vector3<f64>) {
|
||||||
let yaw = attacker_entity.yaw.load();
|
let yaw = attacker_entity.yaw.load();
|
||||||
let d = -f64::from((yaw * (PI / 180.0)).sin());
|
let d = -f64::from((yaw.to_radians()).sin());
|
||||||
let e = f64::from((yaw * (PI / 180.0)).cos());
|
let e = f64::from((yaw.to_radians()).cos());
|
||||||
|
|
||||||
let scale = 0.5;
|
let scale = 0.5;
|
||||||
// TODO: use entity height
|
// TODO: use entity height
|
||||||
|
|||||||
@ -64,7 +64,7 @@ pub async fn from_type(
|
|||||||
};
|
};
|
||||||
#[expect(clippy::single_match)]
|
#[expect(clippy::single_match)]
|
||||||
match entity_type {
|
match entity_type {
|
||||||
EntityType::Zombie => Zombie::make(&mob).await,
|
EntityType::ZOMBIE => Zombie::make(&mob).await,
|
||||||
// TODO
|
// TODO
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,5 @@
|
|||||||
use core::f32;
|
use core::f32;
|
||||||
use std::{
|
use std::sync::{atomic::AtomicBool, Arc};
|
||||||
f32::consts::PI,
|
|
||||||
sync::{atomic::AtomicBool, Arc},
|
|
||||||
};
|
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use crossbeam::atomic::AtomicCell;
|
use crossbeam::atomic::AtomicCell;
|
||||||
@ -22,7 +19,7 @@ use pumpkin_protocol::{
|
|||||||
codec::var_int::VarInt,
|
codec::var_int::VarInt,
|
||||||
};
|
};
|
||||||
use pumpkin_util::math::{
|
use pumpkin_util::math::{
|
||||||
boundingbox::{BoundingBox, BoundingBoxSize},
|
boundingbox::{BoundingBox, EntityDimensions},
|
||||||
get_section_cord,
|
get_section_cord,
|
||||||
position::BlockPos,
|
position::BlockPos,
|
||||||
vector2::Vector2,
|
vector2::Vector2,
|
||||||
@ -94,7 +91,7 @@ pub struct Entity {
|
|||||||
/// The bounding box of an entity (hitbox)
|
/// The bounding box of an entity (hitbox)
|
||||||
pub bounding_box: AtomicCell<BoundingBox>,
|
pub bounding_box: AtomicCell<BoundingBox>,
|
||||||
///The size (width and height) of the bounding box
|
///The size (width and height) of the bounding box
|
||||||
pub bounding_box_size: AtomicCell<BoundingBoxSize>,
|
pub bounding_box_size: AtomicCell<EntityDimensions>,
|
||||||
/// Whether this entity is invulnerable to all damage
|
/// Whether this entity is invulnerable to all damage
|
||||||
pub invulnerable: AtomicBool,
|
pub invulnerable: AtomicBool,
|
||||||
/// List of damage types this entity is immune to
|
/// List of damage types this entity is immune to
|
||||||
@ -111,7 +108,7 @@ impl Entity {
|
|||||||
entity_type: EntityType,
|
entity_type: EntityType,
|
||||||
standing_eye_height: f32,
|
standing_eye_height: f32,
|
||||||
bounding_box: AtomicCell<BoundingBox>,
|
bounding_box: AtomicCell<BoundingBox>,
|
||||||
bounding_box_size: AtomicCell<BoundingBoxSize>,
|
bounding_box_size: AtomicCell<EntityDimensions>,
|
||||||
invulnerable: bool,
|
invulnerable: bool,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let floor_x = position.x.floor() as i32;
|
let floor_x = position.x.floor() as i32;
|
||||||
@ -187,8 +184,8 @@ impl Entity {
|
|||||||
/// Returns entity rotation as vector
|
/// Returns entity rotation as vector
|
||||||
pub fn rotation(&self) -> Vector3<f32> {
|
pub fn rotation(&self) -> Vector3<f32> {
|
||||||
// Convert degrees to radians if necessary
|
// Convert degrees to radians if necessary
|
||||||
let yaw_rad = self.yaw.load() * (PI / 180.0);
|
let yaw_rad = self.yaw.load().to_radians();
|
||||||
let pitch_rad = self.pitch.load() * (PI / 180.0);
|
let pitch_rad = self.pitch.load().to_radians();
|
||||||
|
|
||||||
Vector3::new(
|
Vector3::new(
|
||||||
yaw_rad.cos() * pitch_rad.cos(),
|
yaw_rad.cos() * pitch_rad.cos(),
|
||||||
@ -260,17 +257,13 @@ impl Entity {
|
|||||||
CSpawnEntity::new(
|
CSpawnEntity::new(
|
||||||
VarInt(self.entity_id),
|
VarInt(self.entity_id),
|
||||||
self.entity_uuid,
|
self.entity_uuid,
|
||||||
VarInt((self.entity_type) as i32),
|
VarInt(i32::from(self.entity_type.id)),
|
||||||
entity_loc.x,
|
entity_loc,
|
||||||
entity_loc.y,
|
|
||||||
entity_loc.z,
|
|
||||||
self.pitch.load(),
|
self.pitch.load(),
|
||||||
self.yaw.load(),
|
self.yaw.load(),
|
||||||
self.head_yaw.load(), // todo: head_yaw and yaw are swapped, find out why
|
self.head_yaw.load(), // todo: head_yaw and yaw are swapped, find out why
|
||||||
0.into(),
|
0.into(),
|
||||||
entity_vel.x as f32,
|
entity_vel,
|
||||||
entity_vel.y as f32,
|
|
||||||
entity_vel.z as f32,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -47,7 +47,7 @@ use pumpkin_protocol::{
|
|||||||
};
|
};
|
||||||
use pumpkin_util::{
|
use pumpkin_util::{
|
||||||
math::{
|
math::{
|
||||||
boundingbox::{BoundingBox, BoundingBoxSize},
|
boundingbox::{BoundingBox, EntityDimensions},
|
||||||
experience,
|
experience,
|
||||||
position::BlockPos,
|
position::BlockPos,
|
||||||
vector2::Vector2,
|
vector2::Vector2,
|
||||||
@ -169,9 +169,9 @@ impl Player {
|
|||||||
|
|
||||||
let gameprofile_clone = gameprofile.clone();
|
let gameprofile_clone = gameprofile.clone();
|
||||||
let config = client.config.lock().await.clone().unwrap_or_default();
|
let config = client.config.lock().await.clone().unwrap_or_default();
|
||||||
let bounding_box_size = BoundingBoxSize {
|
let bounding_box_size = EntityDimensions {
|
||||||
width: 0.6,
|
width: EntityType::PLAYER.dimension[0],
|
||||||
height: 1.8,
|
height: EntityType::PLAYER.dimension[1],
|
||||||
};
|
};
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
@ -180,8 +180,8 @@ impl Player {
|
|||||||
player_uuid,
|
player_uuid,
|
||||||
world,
|
world,
|
||||||
Vector3::new(0.0, 0.0, 0.0),
|
Vector3::new(0.0, 0.0, 0.0),
|
||||||
EntityType::Player,
|
EntityType::PLAYER,
|
||||||
1.62,
|
EntityType::PLAYER.eye_height,
|
||||||
AtomicCell::new(BoundingBox::new_default(&bounding_box_size)),
|
AtomicCell::new(BoundingBox::new_default(&bounding_box_size)),
|
||||||
AtomicCell::new(bounding_box_size),
|
AtomicCell::new(bounding_box_size),
|
||||||
matches!(gamemode, GameMode::Creative | GameMode::Spectator),
|
matches!(gamemode, GameMode::Creative | GameMode::Spectator),
|
||||||
@ -404,9 +404,7 @@ impl Player {
|
|||||||
VarInt(i32::from(sound_id)),
|
VarInt(i32::from(sound_id)),
|
||||||
None,
|
None,
|
||||||
category,
|
category,
|
||||||
position.x,
|
position,
|
||||||
position.y,
|
|
||||||
position.z,
|
|
||||||
volume,
|
volume,
|
||||||
pitch,
|
pitch,
|
||||||
seed,
|
seed,
|
||||||
@ -791,7 +789,7 @@ impl Player {
|
|||||||
if let Some(item) = inv.held_item_mut() {
|
if let Some(item) = inv.held_item_mut() {
|
||||||
let entity = server.add_entity(
|
let entity = server.add_entity(
|
||||||
self.living_entity.entity.pos.load(),
|
self.living_entity.entity.pos.load(),
|
||||||
EntityType::Item,
|
EntityType::ITEM,
|
||||||
self.world(),
|
self.world(),
|
||||||
);
|
);
|
||||||
let item_entity = Arc::new(ItemEntity::new(entity, &item.clone()));
|
let item_entity = Arc::new(ItemEntity::new(entity, &item.clone()));
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use std::f32::{self, consts::PI};
|
use std::f32::{self};
|
||||||
|
|
||||||
use pumpkin_util::math::vector3::Vector3;
|
use pumpkin_util::math::vector3::Vector3;
|
||||||
|
|
||||||
@ -8,8 +8,6 @@ pub struct ThrownItemEntity {
|
|||||||
entity: Entity,
|
entity: Entity,
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEG_PER_RAD_F32: f32 = 180.0 / PI;
|
|
||||||
|
|
||||||
impl ThrownItemEntity {
|
impl ThrownItemEntity {
|
||||||
pub fn new(entity: Entity, owner: &Entity) -> Self {
|
pub fn new(entity: Entity, owner: &Entity) -> Self {
|
||||||
let mut owner_pos = owner.pos.load();
|
let mut owner_pos = owner.pos.load();
|
||||||
@ -69,8 +67,8 @@ impl ThrownItemEntity {
|
|||||||
self.entity.velocity.store(velocity);
|
self.entity.velocity.store(velocity);
|
||||||
let len = velocity.horizontal_length();
|
let len = velocity.horizontal_length();
|
||||||
self.entity.set_rotation(
|
self.entity.set_rotation(
|
||||||
velocity.x.atan2(velocity.z) as f32 * DEG_PER_RAD_F32,
|
velocity.x.atan2(velocity.z).to_degrees() as f32,
|
||||||
velocity.y.atan2(len) as f32 * DEG_PER_RAD_F32,
|
velocity.y.atan2(len).to_degrees() as f32,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,7 +27,7 @@ impl PumpkinItem for EggItem {
|
|||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
// TODO: Implement eggs the right way, so there is a chance of spawning chickens
|
// TODO: Implement eggs the right way, so there is a chance of spawning chickens
|
||||||
let entity = server.add_entity(position, EntityType::Egg, world);
|
let entity = server.add_entity(position, EntityType::EGG, world);
|
||||||
let snowball = ThrownItemEntity::new(entity, &player.living_entity.entity);
|
let snowball = ThrownItemEntity::new(entity, &player.living_entity.entity);
|
||||||
let yaw = player.living_entity.entity.yaw.load();
|
let yaw = player.living_entity.entity.yaw.load();
|
||||||
let pitch = player.living_entity.entity.pitch.load();
|
let pitch = player.living_entity.entity.pitch.load();
|
||||||
|
|||||||
@ -26,7 +26,7 @@ impl PumpkinItem for SnowBallItem {
|
|||||||
&position,
|
&position,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
let entity = server.add_entity(position, EntityType::Snowball, world);
|
let entity = server.add_entity(position, EntityType::SNOWBALL, world);
|
||||||
let snowball = ThrownItemEntity::new(entity, &player.living_entity.entity);
|
let snowball = ThrownItemEntity::new(entity, &player.living_entity.entity);
|
||||||
let yaw = player.living_entity.entity.yaw.load();
|
let yaw = player.living_entity.entity.yaw.load();
|
||||||
let pitch = player.living_entity.entity.pitch.load();
|
let pitch = player.living_entity.entity.pitch.load();
|
||||||
|
|||||||
@ -53,7 +53,6 @@ use pumpkin_world::item::registry::{get_item_by_id, get_name_by_id};
|
|||||||
use pumpkin_world::item::ItemStack;
|
use pumpkin_world::item::ItemStack;
|
||||||
use pumpkin_world::{
|
use pumpkin_world::{
|
||||||
block::{registry::get_block_by_item, BlockDirection},
|
block::{registry::get_block_by_item, BlockDirection},
|
||||||
entity::registry::get_entity_id,
|
|
||||||
item::registry::get_spawn_egg,
|
item::registry::get_spawn_egg,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -820,8 +819,9 @@ impl Player {
|
|||||||
let world = &entity.world;
|
let world = &entity.world;
|
||||||
let block = world.get_block(&location).await;
|
let block = world.get_block(&location).await;
|
||||||
|
|
||||||
world.break_block(&location, Some(self.clone())).await;
|
world
|
||||||
|
.break_block(server, &location, Some(self.clone()), false)
|
||||||
|
.await;
|
||||||
if let Ok(block) = block {
|
if let Ok(block) = block {
|
||||||
server
|
server
|
||||||
.block_registry
|
.block_registry
|
||||||
@ -864,7 +864,14 @@ impl Player {
|
|||||||
let world = &entity.world;
|
let world = &entity.world;
|
||||||
let block = world.get_block(&location).await;
|
let block = world.get_block(&location).await;
|
||||||
|
|
||||||
world.break_block(&location, Some(self.clone())).await;
|
world
|
||||||
|
.break_block(
|
||||||
|
server,
|
||||||
|
&location,
|
||||||
|
Some(self.clone()),
|
||||||
|
self.gamemode.load() != GameMode::Creative,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
if let Ok(block) = block {
|
if let Ok(block) = block {
|
||||||
server
|
server
|
||||||
@ -1171,7 +1178,7 @@ impl Player {
|
|||||||
face: &BlockDirection,
|
face: &BlockDirection,
|
||||||
) -> Result<bool, Box<dyn PumpkinError>> {
|
) -> Result<bool, Box<dyn PumpkinError>> {
|
||||||
// checks if spawn egg has a corresponding entity name
|
// checks if spawn egg has a corresponding entity name
|
||||||
if let Some(spawn_item_id) = get_entity_id(&item_t) {
|
if let Some(entity_type) = EntityType::from_name(&item_t) {
|
||||||
let world_pos = BlockPos(location.0 + face.to_offset());
|
let world_pos = BlockPos(location.0 + face.to_offset());
|
||||||
// align position like Vanilla does
|
// align position like Vanilla does
|
||||||
let pos = Vector3::new(
|
let pos = Vector3::new(
|
||||||
@ -1185,7 +1192,7 @@ impl Player {
|
|||||||
let world = self.world();
|
let world = self.world();
|
||||||
// create new mob and uuid based on spawn egg id
|
// create new mob and uuid based on spawn egg id
|
||||||
let mob = mob::from_type(
|
let mob = mob::from_type(
|
||||||
EntityType::from_raw(*spawn_item_id).unwrap(),
|
EntityType::from_raw(entity_type.id).unwrap(),
|
||||||
server,
|
server,
|
||||||
pos,
|
pos,
|
||||||
world,
|
world,
|
||||||
|
|||||||
@ -8,14 +8,13 @@ use pumpkin_inventory::{Container, OpenContainer};
|
|||||||
use pumpkin_protocol::client::login::CEncryptionRequest;
|
use pumpkin_protocol::client::login::CEncryptionRequest;
|
||||||
use pumpkin_protocol::{client::config::CPluginMessage, ClientPacket};
|
use pumpkin_protocol::{client::config::CPluginMessage, ClientPacket};
|
||||||
use pumpkin_registry::{DimensionType, Registry};
|
use pumpkin_registry::{DimensionType, Registry};
|
||||||
use pumpkin_util::math::boundingbox::{BoundingBox, BoundingBoxSize};
|
use pumpkin_util::math::boundingbox::{BoundingBox, EntityDimensions};
|
||||||
use pumpkin_util::math::position::BlockPos;
|
use pumpkin_util::math::position::BlockPos;
|
||||||
use pumpkin_util::math::vector2::Vector2;
|
use pumpkin_util::math::vector2::Vector2;
|
||||||
use pumpkin_util::math::vector3::Vector3;
|
use pumpkin_util::math::vector3::Vector3;
|
||||||
use pumpkin_util::text::TextComponent;
|
use pumpkin_util::text::TextComponent;
|
||||||
use pumpkin_world::block::registry::Block;
|
use pumpkin_world::block::registry::Block;
|
||||||
use pumpkin_world::dimension::Dimension;
|
use pumpkin_world::dimension::Dimension;
|
||||||
use pumpkin_world::entity::registry::get_entity_by_id;
|
|
||||||
use rand::prelude::SliceRandom;
|
use rand::prelude::SliceRandom;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::net::IpAddr;
|
use std::net::IpAddr;
|
||||||
@ -221,16 +220,10 @@ impl Server {
|
|||||||
let entity_id = self.new_entity_id();
|
let entity_id = self.new_entity_id();
|
||||||
|
|
||||||
// TODO: this should be resolved to a integer using a macro when calling this function
|
// TODO: this should be resolved to a integer using a macro when calling this function
|
||||||
let bounding_box_size = get_entity_by_id(entity_type as u16).map_or(
|
let bounding_box_size = EntityDimensions {
|
||||||
BoundingBoxSize {
|
width: entity_type.dimension[0],
|
||||||
width: 0.6,
|
height: entity_type.dimension[1],
|
||||||
height: 1.8,
|
};
|
||||||
},
|
|
||||||
|entity| BoundingBoxSize {
|
|
||||||
width: f64::from(entity.dimension[0]),
|
|
||||||
height: f64::from(entity.dimension[1]),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
// TODO: standing eye height should be per mob
|
// TODO: standing eye height should be per mob
|
||||||
let new_uuid = uuid::Uuid::new_v4();
|
let new_uuid = uuid::Uuid::new_v4();
|
||||||
@ -240,7 +233,7 @@ impl Server {
|
|||||||
world.clone(),
|
world.clone(),
|
||||||
position,
|
position,
|
||||||
entity_type,
|
entity_type,
|
||||||
1.62,
|
entity_type.eye_height,
|
||||||
AtomicCell::new(BoundingBox::new_from_pos(
|
AtomicCell::new(BoundingBox::new_from_pos(
|
||||||
position.x,
|
position.x,
|
||||||
position.y,
|
position.y,
|
||||||
|
|||||||
@ -7,6 +7,7 @@ pub mod chunker;
|
|||||||
pub mod time;
|
pub mod time;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
block,
|
||||||
command::client_suggestions,
|
command::client_suggestions,
|
||||||
entity::{player::Player, Entity, EntityBase, EntityId},
|
entity::{player::Player, Entity, EntityBase, EntityId},
|
||||||
error::PumpkinError,
|
error::PumpkinError,
|
||||||
@ -423,17 +424,13 @@ impl World {
|
|||||||
&CSpawnEntity::new(
|
&CSpawnEntity::new(
|
||||||
entity_id.into(),
|
entity_id.into(),
|
||||||
gameprofile.id,
|
gameprofile.id,
|
||||||
(EntityType::Player as i32).into(),
|
i32::from(EntityType::PLAYER.id).into(),
|
||||||
position.x,
|
position,
|
||||||
position.y,
|
|
||||||
position.z,
|
|
||||||
pitch,
|
pitch,
|
||||||
yaw,
|
yaw,
|
||||||
yaw,
|
yaw,
|
||||||
0.into(),
|
0.into(),
|
||||||
0.0,
|
Vector3::new(0.0, 0.0, 0.0),
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
@ -449,17 +446,13 @@ impl World {
|
|||||||
.send_packet(&CSpawnEntity::new(
|
.send_packet(&CSpawnEntity::new(
|
||||||
existing_player.entity_id().into(),
|
existing_player.entity_id().into(),
|
||||||
gameprofile.id,
|
gameprofile.id,
|
||||||
(EntityType::Player as i32).into(),
|
i32::from(EntityType::PLAYER.id).into(),
|
||||||
pos.x,
|
pos,
|
||||||
pos.y,
|
|
||||||
pos.z,
|
|
||||||
entity.yaw.load(),
|
entity.yaw.load(),
|
||||||
entity.pitch.load(),
|
entity.pitch.load(),
|
||||||
entity.head_yaw.load(),
|
entity.head_yaw.load(),
|
||||||
0.into(),
|
0.into(),
|
||||||
0.0,
|
Vector3::new(0.0, 0.0, 0.0),
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
))
|
))
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
@ -594,17 +587,13 @@ impl World {
|
|||||||
&CSpawnEntity::new(
|
&CSpawnEntity::new(
|
||||||
entity.entity_id.into(),
|
entity.entity_id.into(),
|
||||||
player.gameprofile.id,
|
player.gameprofile.id,
|
||||||
(EntityType::Player as i32).into(),
|
i32::from(EntityType::PLAYER.id).into(),
|
||||||
position.x,
|
position,
|
||||||
position.y,
|
|
||||||
position.z,
|
|
||||||
pitch,
|
pitch,
|
||||||
yaw,
|
yaw,
|
||||||
yaw,
|
yaw,
|
||||||
0.into(),
|
0.into(),
|
||||||
0.0,
|
Vector3::new(0.0, 0.0, 0.0),
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
@ -1025,7 +1014,13 @@ impl World {
|
|||||||
chunk
|
chunk
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn break_block(&self, position: &BlockPos, cause: Option<Arc<Player>>) {
|
pub async fn break_block(
|
||||||
|
self: &Arc<Self>,
|
||||||
|
server: &Server,
|
||||||
|
position: &BlockPos,
|
||||||
|
cause: Option<Arc<Player>>,
|
||||||
|
drop: bool,
|
||||||
|
) {
|
||||||
let block = self.get_block(position).await.unwrap();
|
let block = self.get_block(position).await.unwrap();
|
||||||
let event = BlockBreakEvent::new(cause.clone(), block.clone(), 0, false);
|
let event = BlockBreakEvent::new(cause.clone(), block.clone(), 0, false);
|
||||||
|
|
||||||
@ -1045,6 +1040,10 @@ impl World {
|
|||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if drop {
|
||||||
|
block::drop_loot(server, self, block, position).await;
|
||||||
|
}
|
||||||
|
|
||||||
match cause {
|
match cause {
|
||||||
Some(player) => {
|
Some(player) => {
|
||||||
self.broadcast_packet_except(&[player.gameprofile.id], &particles_packet)
|
self.broadcast_packet_except(&[player.gameprofile.id], &particles_packet)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user