Parse Items at Compile time
This commit is contained in:
parent
5c5bc67b3a
commit
8592d095f3
1
assets/spawn_egg.json
Normal file
1
assets/spawn_egg.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"1130":"wither_skeleton","1071":"creeper","1094":"ocelot","1114":"snow_golem","1125":"vindicator","1090":"llama","1129":"wither","1134":"zombie","1080":"fox","1085":"guardian","1076":"ender_dragon","1102":"polar_bear","1081":"frog","1131":"wolf","1070":"cow","1111":"skeleton_horse","1122":"turtle","1096":"parrot","1104":"rabbit","1093":"mule","1092":"mooshroom","1106":"salmon","1082":"ghast","1126":"wandering_trader","1109":"silverfish","1132":"zoglin","1065":"cat","1062":"blaze","1068":"chicken","1072":"dolphin","1103":"pufferfish","1108":"shulker","1119":"tadpole","1059":"axolotl","1069":"cod","1112":"slime","1113":"sniffer","1137":"zombified_piglin","1087":"horse","1105":"ravager","1110":"skeleton","1083":"glow_squid","1066":"camel","1067":"cave_spider","1057":"armadillo","1086":"hoglin","1118":"strider","1077":"enderman","1124":"villager","1128":"witch","1107":"sheep","1063":"bogged","1120":"trader_llama","1074":"drowned","1064":"breeze","1075":"elder_guardian","1115":"spider","1097":"phantom","1116":"squid","1101":"pillager","1127":"warden","1078":"endermite","1061":"bee","1089":"iron_golem","1098":"pig","1135":"zombie_horse","1117":"stray","1133":"creaking","1073":"donkey","1095":"panda","1136":"zombie_villager","1091":"magma_cube","1099":"piglin","1100":"piglin_brute","1084":"goat","1058":"allay","1121":"tropical_fish","1060":"bat","1079":"evoker","1088":"husk","1123":"vex"}
|
||||||
@ -5,7 +5,10 @@ edition.workspace = true
|
|||||||
build = "build/build.rs"
|
build = "build/build.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
pumpkin-util = { path = "../pumpkin-util" }
|
||||||
|
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
|
serde_json.workspace = true
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
pumpkin-util = { path = "../pumpkin-util" }
|
pumpkin-util = { path = "../pumpkin-util" }
|
||||||
|
|||||||
@ -7,8 +7,8 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
println!("cargo:rerun-if-changed=../assets/biome.json");
|
println!("cargo:rerun-if-changed=../assets/biome.json");
|
||||||
|
|
||||||
let biomes: Vec<String> = serde_json::from_str(include_str!("../../assets/biome.json"))
|
let biomes: Vec<String> = serde_json::from_str(include_str!("../../assets/biome.json"))
|
||||||
.expect("Failed to parse entity_pose.json");
|
.expect("Failed to parse biome.json");
|
||||||
let variants = array_to_tokenstream(biomes);
|
let variants = array_to_tokenstream(&biomes);
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
|||||||
@ -10,6 +10,7 @@ mod damage_type;
|
|||||||
mod entity_pose;
|
mod entity_pose;
|
||||||
mod entity_type;
|
mod entity_type;
|
||||||
mod game_event;
|
mod game_event;
|
||||||
|
mod item;
|
||||||
mod message_type;
|
mod message_type;
|
||||||
mod noise_parameter;
|
mod noise_parameter;
|
||||||
mod packet;
|
mod packet;
|
||||||
@ -18,6 +19,7 @@ mod scoreboard_slot;
|
|||||||
mod screen;
|
mod screen;
|
||||||
mod sound;
|
mod sound;
|
||||||
mod sound_category;
|
mod sound_category;
|
||||||
|
mod spawn_egg;
|
||||||
mod world_event;
|
mod world_event;
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
@ -36,9 +38,11 @@ pub fn main() {
|
|||||||
write_generated_file(biome::build(), "biome.rs");
|
write_generated_file(biome::build(), "biome.rs");
|
||||||
write_generated_file(damage_type::build(), "damage_type.rs");
|
write_generated_file(damage_type::build(), "damage_type.rs");
|
||||||
write_generated_file(message_type::build(), "message_type.rs");
|
write_generated_file(message_type::build(), "message_type.rs");
|
||||||
|
write_generated_file(spawn_egg::build(), "spawn_egg.rs");
|
||||||
|
write_generated_file(item::build(), "item.rs");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn array_to_tokenstream(array: Vec<String>) -> TokenStream {
|
pub fn array_to_tokenstream(array: &[String]) -> TokenStream {
|
||||||
let mut variants = TokenStream::new();
|
let mut variants = TokenStream::new();
|
||||||
|
|
||||||
for item in array.iter() {
|
for item in array.iter() {
|
||||||
|
|||||||
@ -3,7 +3,7 @@ use proc_macro2::TokenStream;
|
|||||||
use quote::{format_ident, quote};
|
use quote::{format_ident, quote};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use syn::LitInt;
|
use syn::{Ident, LitInt};
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct DamageTypeEntry {
|
struct DamageTypeEntry {
|
||||||
@ -13,10 +13,26 @@ struct DamageTypeEntry {
|
|||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct DamageTypeData {
|
pub struct DamageTypeData {
|
||||||
death_message_type: Option<String>,
|
death_message_type: Option<DeathMessageType>,
|
||||||
exhaustion: f32,
|
exhaustion: f32,
|
||||||
message_id: String,
|
message_id: String,
|
||||||
scaling: String,
|
scaling: DamageScaling,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum DamageScaling {
|
||||||
|
Never,
|
||||||
|
WhenCausedByLivingNonPlayer,
|
||||||
|
Always,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum DeathMessageType {
|
||||||
|
Default,
|
||||||
|
FallVariants,
|
||||||
|
IntentionalGameDesign,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn build() -> TokenStream {
|
pub(crate) fn build() -> TokenStream {
|
||||||
@ -36,13 +52,20 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
|
|
||||||
let data = &entry.components;
|
let data = &entry.components;
|
||||||
let death_message_type = match &data.death_message_type {
|
let death_message_type = match &data.death_message_type {
|
||||||
Some(msg) => quote! { Some(#msg) },
|
Some(msg) => {
|
||||||
|
let msg_ident = Ident::new(&format!("{:?}", msg), proc_macro2::Span::call_site());
|
||||||
|
quote! { Some(DeathMessageType::#msg_ident) }
|
||||||
|
}
|
||||||
None => quote! { None },
|
None => quote! { None },
|
||||||
};
|
};
|
||||||
|
|
||||||
let exhaustion = data.exhaustion;
|
let exhaustion = data.exhaustion;
|
||||||
let message_id = &data.message_id;
|
let message_id = &data.message_id;
|
||||||
let scaling = &data.scaling;
|
let scaling_ident = Ident::new(
|
||||||
|
&format!("{:?}", data.scaling),
|
||||||
|
proc_macro2::Span::call_site(),
|
||||||
|
);
|
||||||
|
let scaling = quote! {DamageScaling::#scaling_ident};
|
||||||
let id_lit = LitInt::new(&entry.id.to_string(), proc_macro2::Span::call_site());
|
let id_lit = LitInt::new(&entry.id.to_string(), proc_macro2::Span::call_site());
|
||||||
|
|
||||||
constants.push(quote! {
|
constants.push(quote! {
|
||||||
@ -68,13 +91,27 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
quote! {
|
quote! {
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
pub struct DamageType {
|
pub struct DamageType {
|
||||||
pub death_message_type: Option<&'static str>,
|
pub death_message_type: Option<DeathMessageType>,
|
||||||
pub exhaustion: f32,
|
pub exhaustion: f32,
|
||||||
pub message_id: &'static str,
|
pub message_id: &'static str,
|
||||||
pub scaling: &'static str,
|
pub scaling: DamageScaling,
|
||||||
pub id: u32,
|
pub id: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub enum DeathMessageType {
|
||||||
|
Default,
|
||||||
|
FallVariants,
|
||||||
|
IntentionalGameDesign,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub enum DamageScaling {
|
||||||
|
Never,
|
||||||
|
WhenCausedByLivingNonPlayer,
|
||||||
|
Always,
|
||||||
|
}
|
||||||
|
|
||||||
impl DamageType {
|
impl DamageType {
|
||||||
#(#constants)*
|
#(#constants)*
|
||||||
|
|
||||||
|
|||||||
@ -8,7 +8,7 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
|
|
||||||
let poses: Vec<String> = serde_json::from_str(include_str!("../../assets/entity_pose.json"))
|
let poses: Vec<String> = serde_json::from_str(include_str!("../../assets/entity_pose.json"))
|
||||||
.expect("Failed to parse entity_pose.json");
|
.expect("Failed to parse entity_pose.json");
|
||||||
let variants = array_to_tokenstream(poses);
|
let variants = array_to_tokenstream(&poses);
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
|||||||
@ -9,7 +9,7 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
let game_events: Vec<String> =
|
let game_events: Vec<String> =
|
||||||
serde_json::from_str(include_str!("../../assets/game_event.json"))
|
serde_json::from_str(include_str!("../../assets/game_event.json"))
|
||||||
.expect("Failed to parse game_event.json");
|
.expect("Failed to parse game_event.json");
|
||||||
let variants = array_to_tokenstream(game_events);
|
let variants = array_to_tokenstream(&game_events);
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
pub enum GameEvent {
|
pub enum GameEvent {
|
||||||
|
|||||||
239
pumpkin-data/build/item.rs
Normal file
239
pumpkin-data/build/item.rs
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
use heck::ToShoutySnakeCase;
|
||||||
|
use proc_macro2::{Span, TokenStream};
|
||||||
|
use quote::{format_ident, quote, ToTokens};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use syn::{Ident, LitInt, LitStr};
|
||||||
|
|
||||||
|
#[derive(Deserialize, Clone, Debug)]
|
||||||
|
pub struct Item {
|
||||||
|
pub id: u16,
|
||||||
|
pub components: ItemComponents,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Clone, Debug)]
|
||||||
|
pub struct ItemComponents {
|
||||||
|
#[serde(rename = "minecraft:item_name")]
|
||||||
|
// TODO: TextComponent
|
||||||
|
pub item_name: Option<String>,
|
||||||
|
#[serde(rename = "minecraft:max_stack_size")]
|
||||||
|
pub max_stack_size: u8,
|
||||||
|
#[serde(rename = "minecraft:jukebox_playable")]
|
||||||
|
pub jukebox_playable: Option<JukeboxPlayable>,
|
||||||
|
#[serde(rename = "minecraft:damage")]
|
||||||
|
pub damage: Option<u16>,
|
||||||
|
#[serde(rename = "minecraft:max_damage")]
|
||||||
|
pub max_damage: Option<u16>,
|
||||||
|
#[serde(rename = "minecraft:attribute_modifiers")]
|
||||||
|
pub attribute_modifiers: Option<AttributeModifiers>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToTokens for ItemComponents {
|
||||||
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
|
let max_stack_size = LitInt::new(&self.max_stack_size.to_string(), Span::call_site());
|
||||||
|
let jukebox_playable = match &self.jukebox_playable {
|
||||||
|
Some(playable) => {
|
||||||
|
let song = LitStr::new(&playable.song, Span::call_site());
|
||||||
|
quote! { Some(JukeboxPlayable { song: #song }) }
|
||||||
|
}
|
||||||
|
None => quote! { None },
|
||||||
|
};
|
||||||
|
|
||||||
|
let item_name = match &self.item_name {
|
||||||
|
Some(d) => {
|
||||||
|
let item_name = LitStr::new(d, Span::call_site());
|
||||||
|
quote! { Some(#item_name) }
|
||||||
|
}
|
||||||
|
None => quote! { None },
|
||||||
|
};
|
||||||
|
|
||||||
|
let damage = match self.damage {
|
||||||
|
Some(d) => {
|
||||||
|
let damage_lit = LitInt::new(&d.to_string(), Span::call_site());
|
||||||
|
quote! { Some(#damage_lit) }
|
||||||
|
}
|
||||||
|
None => quote! { None },
|
||||||
|
};
|
||||||
|
|
||||||
|
let max_damage = match self.max_damage {
|
||||||
|
Some(md) => {
|
||||||
|
let max_damage_lit = LitInt::new(&md.to_string(), Span::call_site());
|
||||||
|
quote! { Some(#max_damage_lit) }
|
||||||
|
}
|
||||||
|
None => quote! { None },
|
||||||
|
};
|
||||||
|
|
||||||
|
let attribute_modifiers = match &self.attribute_modifiers {
|
||||||
|
Some(modifiers) => {
|
||||||
|
let modifier_code = modifiers.modifiers.iter().map(|modifier| {
|
||||||
|
let r#type = LitStr::new(&modifier.r#type, Span::call_site());
|
||||||
|
let id = LitStr::new(&modifier.id, Span::call_site());
|
||||||
|
let amount = modifier.amount;
|
||||||
|
let operation =
|
||||||
|
Ident::new(&format!("{:?}", modifier.operation), Span::call_site());
|
||||||
|
let slot = LitStr::new(&modifier.slot, Span::call_site());
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
Modifier {
|
||||||
|
r#type: #r#type,
|
||||||
|
id: #id,
|
||||||
|
amount: #amount,
|
||||||
|
operation: Operation::#operation,
|
||||||
|
slot: #slot,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
quote! { Some(AttributeModifiers { modifiers: &[#(#modifier_code),*] }) }
|
||||||
|
}
|
||||||
|
None => quote! { None },
|
||||||
|
};
|
||||||
|
|
||||||
|
tokens.extend(quote! {
|
||||||
|
ItemComponents {
|
||||||
|
item_name: #item_name,
|
||||||
|
max_stack_size: #max_stack_size,
|
||||||
|
jukebox_playable: #jukebox_playable,
|
||||||
|
damage: #damage,
|
||||||
|
max_damage: #max_damage,
|
||||||
|
attribute_modifiers: #attribute_modifiers,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Clone, Debug)]
|
||||||
|
pub struct JukeboxPlayable {
|
||||||
|
pub song: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Clone, Debug)]
|
||||||
|
pub struct AttributeModifiers {
|
||||||
|
pub modifiers: Vec<Modifier>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Clone, Debug)]
|
||||||
|
pub struct Modifier {
|
||||||
|
pub r#type: String,
|
||||||
|
pub id: String,
|
||||||
|
pub amount: f64,
|
||||||
|
pub operation: Operation,
|
||||||
|
// TODO: Make this an enum
|
||||||
|
pub slot: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Clone, Debug, PartialEq)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
#[allow(clippy::enum_variant_names)]
|
||||||
|
pub enum Operation {
|
||||||
|
AddValue,
|
||||||
|
AddMultipliedBase,
|
||||||
|
AddMultipliedTotal,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn build() -> TokenStream {
|
||||||
|
println!("cargo:rerun-if-changed=../assets/items.json");
|
||||||
|
|
||||||
|
let items: HashMap<String, Item> =
|
||||||
|
serde_json::from_str(include_str!("../../assets/items.json"))
|
||||||
|
.expect("Failed to parse items.json");
|
||||||
|
|
||||||
|
let mut type_from_raw_id_arms = TokenStream::new();
|
||||||
|
let mut type_from_name = TokenStream::new();
|
||||||
|
|
||||||
|
let mut constants = TokenStream::new();
|
||||||
|
|
||||||
|
for (name, item) in items {
|
||||||
|
let const_ident = format_ident!("{}", name.to_shouty_snake_case());
|
||||||
|
|
||||||
|
let components = &item.components;
|
||||||
|
let components_tokens = components.to_token_stream();
|
||||||
|
|
||||||
|
let id_lit = LitInt::new(&item.id.to_string(), proc_macro2::Span::call_site());
|
||||||
|
|
||||||
|
constants.extend(quote! {
|
||||||
|
pub const #const_ident: Item = Item {
|
||||||
|
id: #id_lit,
|
||||||
|
components: #components_tokens
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
type_from_raw_id_arms.extend(quote! {
|
||||||
|
#id_lit => Some(Self::#const_ident),
|
||||||
|
});
|
||||||
|
|
||||||
|
type_from_name.extend(quote! {
|
||||||
|
#name => Some(Self::#const_ident),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
use pumpkin_util::text::TextComponent;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct Item {
|
||||||
|
pub id: u16,
|
||||||
|
pub components: ItemComponents,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct ItemComponents {
|
||||||
|
pub item_name: Option<&'static str>,
|
||||||
|
pub max_stack_size: u8,
|
||||||
|
pub jukebox_playable: Option<JukeboxPlayable>,
|
||||||
|
pub damage: Option<u16>,
|
||||||
|
pub max_damage: Option<u16>,
|
||||||
|
pub attribute_modifiers: Option<AttributeModifiers>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct JukeboxPlayable {
|
||||||
|
pub song: &'static str,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct AttributeModifiers {
|
||||||
|
pub modifiers: &'static [Modifier],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct Modifier {
|
||||||
|
pub r#type: &'static str,
|
||||||
|
pub id: &'static str,
|
||||||
|
pub amount: f64,
|
||||||
|
pub operation: Operation,
|
||||||
|
// TODO: Make this an enum
|
||||||
|
pub slot: &'static str,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub enum Operation {
|
||||||
|
AddValue,
|
||||||
|
AddMultipliedBase,
|
||||||
|
AddMultipliedTotal,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Item {
|
||||||
|
#constants
|
||||||
|
|
||||||
|
pub fn translated_name(&self) -> TextComponent {
|
||||||
|
serde_json::from_str(self.components.item_name.unwrap()).expect("Could not parse item name.")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc = r" Try to parse a Item from a resource location string"]
|
||||||
|
pub fn from_name(name: &str) -> Option<Self> {
|
||||||
|
match name {
|
||||||
|
#type_from_name
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[doc = r" Try to parse a Item from a raw id"]
|
||||||
|
pub const fn from_id(id: u16) -> Option<Self> {
|
||||||
|
match id {
|
||||||
|
#type_from_raw_id_arms
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -8,7 +8,7 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
|
|
||||||
let particle: Vec<String> = serde_json::from_str(include_str!("../../assets/particles.json"))
|
let particle: Vec<String> = serde_json::from_str(include_str!("../../assets/particles.json"))
|
||||||
.expect("Failed to parse particles.json");
|
.expect("Failed to parse particles.json");
|
||||||
let variants = array_to_tokenstream(particle);
|
let variants = array_to_tokenstream(&particle);
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
|||||||
@ -9,7 +9,7 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
let sound_categories: Vec<String> =
|
let sound_categories: Vec<String> =
|
||||||
serde_json::from_str(include_str!("../../assets/scoreboard_display_slot.json"))
|
serde_json::from_str(include_str!("../../assets/scoreboard_display_slot.json"))
|
||||||
.expect("Failed to parse scoreboard_display_slot.json");
|
.expect("Failed to parse scoreboard_display_slot.json");
|
||||||
let variants = array_to_tokenstream(sound_categories);
|
let variants = array_to_tokenstream(&sound_categories);
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
pub enum ScoreboardDisplaySlot {
|
pub enum ScoreboardDisplaySlot {
|
||||||
|
|||||||
@ -8,7 +8,7 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
|
|
||||||
let screens: Vec<String> = serde_json::from_str(include_str!("../../assets/screens.json"))
|
let screens: Vec<String> = serde_json::from_str(include_str!("../../assets/screens.json"))
|
||||||
.expect("Failed to parse screens.json");
|
.expect("Failed to parse screens.json");
|
||||||
let variants = array_to_tokenstream(screens);
|
let variants = array_to_tokenstream(&screens);
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
|||||||
@ -9,7 +9,7 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
|
|
||||||
let sound: Vec<String> = serde_json::from_str(include_str!("../../assets/sounds.json"))
|
let sound: Vec<String> = serde_json::from_str(include_str!("../../assets/sounds.json"))
|
||||||
.expect("Failed to parse sounds.json");
|
.expect("Failed to parse sounds.json");
|
||||||
let variants = array_to_tokenstream(sound.clone());
|
let variants = array_to_tokenstream(&sound);
|
||||||
|
|
||||||
let type_from_name = &sound
|
let type_from_name = &sound
|
||||||
.iter()
|
.iter()
|
||||||
|
|||||||
@ -9,7 +9,7 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
let sound_categories: Vec<String> =
|
let sound_categories: Vec<String> =
|
||||||
serde_json::from_str(include_str!("../../assets/sound_category.json"))
|
serde_json::from_str(include_str!("../../assets/sound_category.json"))
|
||||||
.expect("Failed to parse sound_category.json");
|
.expect("Failed to parse sound_category.json");
|
||||||
let variants = array_to_tokenstream(sound_categories);
|
let variants = array_to_tokenstream(&sound_categories);
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
|||||||
29
pumpkin-data/build/spawn_egg.rs
Normal file
29
pumpkin-data/build/spawn_egg.rs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use heck::ToShoutySnakeCase;
|
||||||
|
use proc_macro2::TokenStream;
|
||||||
|
use quote::{format_ident, quote};
|
||||||
|
|
||||||
|
pub(crate) fn build() -> TokenStream {
|
||||||
|
println!("cargo:rerun-if-changed=../assets/spawn_egg.json");
|
||||||
|
|
||||||
|
let eggs: HashMap<u16, String> =
|
||||||
|
serde_json::from_str(include_str!("../../assets/spawn_egg.json"))
|
||||||
|
.expect("Failed to parse spawn_egg.json");
|
||||||
|
let mut names = TokenStream::new();
|
||||||
|
|
||||||
|
for (egg, entity) in &eggs {
|
||||||
|
let entity = entity.to_shouty_snake_case();
|
||||||
|
let entity = format_ident!("{}", entity);
|
||||||
|
names.extend(quote! { #egg => Some(EntityType::#entity), });
|
||||||
|
}
|
||||||
|
quote! {
|
||||||
|
|
||||||
|
pub fn entity_from_egg(id: u16) -> Option<EntityType> {
|
||||||
|
match id {
|
||||||
|
#names
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,3 +1,7 @@
|
|||||||
|
pub mod item {
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/item.rs"));
|
||||||
|
}
|
||||||
|
|
||||||
pub mod packet {
|
pub mod packet {
|
||||||
include!(concat!(env!("OUT_DIR"), "/packet.rs"));
|
include!(concat!(env!("OUT_DIR"), "/packet.rs"));
|
||||||
}
|
}
|
||||||
@ -26,6 +30,7 @@ pub mod game_event {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub mod entity {
|
pub mod entity {
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/spawn_egg.rs"));
|
||||||
include!(concat!(env!("OUT_DIR"), "/entity_type.rs"));
|
include!(concat!(env!("OUT_DIR"), "/entity_type.rs"));
|
||||||
include!(concat!(env!("OUT_DIR"), "/entity_pose.rs"));
|
include!(concat!(env!("OUT_DIR"), "/entity_pose.rs"));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
|
use pumpkin_data::item::Item;
|
||||||
use pumpkin_registry::{
|
use pumpkin_registry::{
|
||||||
flatten_3x3, get_tag_values, IngredientSlot, IngredientType, RecipeResult, TagCategory, RECIPES,
|
flatten_3x3, get_tag_values, IngredientSlot, IngredientType, RecipeResult, TagCategory, RECIPES,
|
||||||
};
|
};
|
||||||
use pumpkin_world::item::registry::get_item;
|
|
||||||
use pumpkin_world::item::ItemStack;
|
use pumpkin_world::item::ItemStack;
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
|
|
||||||
@ -17,7 +17,9 @@ fn check_ingredient_type(ingredient_type: &IngredientType, input: ItemStack) ->
|
|||||||
.iter()
|
.iter()
|
||||||
.any(|tag| check_ingredient_type(&tag.to_ingredient_type(), input))
|
.any(|tag| check_ingredient_type(&tag.to_ingredient_type(), input))
|
||||||
}
|
}
|
||||||
IngredientType::Item(item) => get_item(item).is_some_and(|item| item.id == input.item_id),
|
IngredientType::Item(item) => {
|
||||||
|
Item::from_name(item).is_some_and(|item| item.id == input.item.id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,11 +54,11 @@ pub fn check_if_matches_crafting(input: [[Option<ItemStack>; 3]; 3]) -> Option<I
|
|||||||
})
|
})
|
||||||
.map(|recipe| match recipe.result() {
|
.map(|recipe| match recipe.result() {
|
||||||
RecipeResult::Single { id, .. } => Some(ItemStack {
|
RecipeResult::Single { id, .. } => Some(ItemStack {
|
||||||
item_id: get_item(id).unwrap().id,
|
item: Item::from_name(id).unwrap(),
|
||||||
item_count: 1,
|
item_count: 1,
|
||||||
}),
|
}),
|
||||||
RecipeResult::Many { id, count, .. } => Some(ItemStack {
|
RecipeResult::Many { id, count, .. } => Some(ItemStack {
|
||||||
item_id: get_item(id).unwrap().id,
|
item: Item::from_name(id).unwrap(),
|
||||||
item_count: *count,
|
item_count: *count,
|
||||||
}),
|
}),
|
||||||
RecipeResult::Special => None,
|
RecipeResult::Special => None,
|
||||||
|
|||||||
@ -91,7 +91,7 @@ impl DragHandler {
|
|||||||
single_item.item_count = 1;
|
single_item.item_count = 1;
|
||||||
|
|
||||||
let changing_slots =
|
let changing_slots =
|
||||||
drag.possibly_changing_slots(&slots_cloned, carried_item.item_id);
|
drag.possibly_changing_slots(&slots_cloned, carried_item.item.id);
|
||||||
changing_slots.for_each(|slot| {
|
changing_slots.for_each(|slot| {
|
||||||
if carried_item.item_count != 0 {
|
if carried_item.item_count != 0 {
|
||||||
carried_item.item_count -= 1;
|
carried_item.item_count -= 1;
|
||||||
@ -117,7 +117,7 @@ impl DragHandler {
|
|||||||
// In that specific case, follow MouseDragType::Right behaviours instead!
|
// In that specific case, follow MouseDragType::Right behaviours instead!
|
||||||
|
|
||||||
let changing_slots =
|
let changing_slots =
|
||||||
drag.possibly_changing_slots(&slots_cloned, carried_item.item_id);
|
drag.possibly_changing_slots(&slots_cloned, carried_item.item.id);
|
||||||
let amount_of_slots = changing_slots.clone().count();
|
let amount_of_slots = changing_slots.clone().count();
|
||||||
let (amount_per_slot, remainder) = if amount_of_slots == 0 {
|
let (amount_per_slot, remainder) = if amount_of_slots == 0 {
|
||||||
// TODO: please work lol
|
// TODO: please work lol
|
||||||
@ -160,7 +160,7 @@ impl Drag {
|
|||||||
|
|
||||||
match slot {
|
match slot {
|
||||||
Some(item_slot) => {
|
Some(item_slot) => {
|
||||||
if item_slot.item_id == carried_item_id {
|
if item_slot.item.id == carried_item_id {
|
||||||
Some(*slot_index)
|
Some(*slot_index)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|||||||
@ -36,7 +36,7 @@ pub trait Container: Sync + Send {
|
|||||||
if taking_crafted {
|
if taking_crafted {
|
||||||
match (all_slots[slot].as_mut(), carried_item.as_mut()) {
|
match (all_slots[slot].as_mut(), carried_item.as_mut()) {
|
||||||
(Some(s1), Some(s2)) => {
|
(Some(s1), Some(s2)) => {
|
||||||
if s1.item_id == s2.item_id {
|
if s1.item.id == s2.item.id {
|
||||||
handle_item_change(all_slots[slot], carried_item, mouse_click);
|
handle_item_change(all_slots[slot], carried_item, mouse_click);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -152,7 +152,7 @@ pub fn handle_item_change(
|
|||||||
match (current_slot.as_mut(), carried_slot.as_mut()) {
|
match (current_slot.as_mut(), carried_slot.as_mut()) {
|
||||||
// Swap or combine current and carried
|
// Swap or combine current and carried
|
||||||
(Some(current), Some(carried)) => {
|
(Some(current), Some(carried)) => {
|
||||||
if current.item_id == carried.item_id {
|
if current.item.id == carried.item.id {
|
||||||
combine_stacks(carried_slot, current, mouse_click);
|
combine_stacks(carried_slot, current, mouse_click);
|
||||||
} else if mouse_click == MouseClick::Left {
|
} else if mouse_click == MouseClick::Left {
|
||||||
let carried = *carried;
|
let carried = *carried;
|
||||||
|
|||||||
@ -135,7 +135,7 @@ impl PlayerInventory {
|
|||||||
pub fn get_slot_with_item(&self, item_id: u16, max_stack: u8) -> Option<usize> {
|
pub fn get_slot_with_item(&self, item_id: u16, max_stack: u8) -> Option<usize> {
|
||||||
for slot in 9..=44 {
|
for slot in 9..=44 {
|
||||||
match &self.items[slot - 9] {
|
match &self.items[slot - 9] {
|
||||||
Some(item) if item.item_id == item_id && item.item_count <= max_stack => {
|
Some(item) if item.item.id == item_id && item.item_count <= max_stack => {
|
||||||
return Some(slot)
|
return Some(slot)
|
||||||
}
|
}
|
||||||
_ => continue,
|
_ => continue,
|
||||||
|
|||||||
@ -7,6 +7,8 @@ edition.workspace = true
|
|||||||
proc-macro = true
|
proc-macro = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
pumpkin-data = { path = "../pumpkin-data" }
|
||||||
|
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
|
use pumpkin_data::item::Item;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
use syn::{
|
use syn::{
|
||||||
parse::{Nothing, Parser},
|
parse::{Nothing, Parser},
|
||||||
@ -222,18 +223,15 @@ pub fn pumpkin_item(input: TokenStream, item: TokenStream) -> TokenStream {
|
|||||||
|
|
||||||
let input_string = input.to_string();
|
let input_string = input.to_string();
|
||||||
let packet_name = input_string.trim_matches('"');
|
let packet_name = input_string.trim_matches('"');
|
||||||
let packet_name_split: Vec<&str> = packet_name.split(":").collect();
|
let item_id = Item::from_name(packet_name).unwrap();
|
||||||
|
let id = item_id.id;
|
||||||
let namespace = packet_name_split[0];
|
|
||||||
let id = packet_name_split[1];
|
|
||||||
|
|
||||||
let item: proc_macro2::TokenStream = item.into();
|
let item: proc_macro2::TokenStream = item.into();
|
||||||
|
|
||||||
let gen = quote! {
|
let gen = quote! {
|
||||||
#item
|
#item
|
||||||
impl #impl_generics crate::item::pumpkin_item::ItemMetadata for #name #ty_generics {
|
impl #impl_generics crate::item::pumpkin_item::ItemMetadata for #name #ty_generics {
|
||||||
const NAMESPACE: &'static str = #namespace;
|
const ID: u16 = #id;
|
||||||
const ID: &'static str = #id;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
use crate::VarInt;
|
use crate::VarInt;
|
||||||
|
use pumpkin_data::item::Item;
|
||||||
use pumpkin_world::item::ItemStack;
|
use pumpkin_world::item::ItemStack;
|
||||||
use serde::ser::SerializeSeq;
|
use serde::ser::SerializeSeq;
|
||||||
use serde::{
|
use serde::{
|
||||||
@ -131,8 +132,9 @@ impl Serialize for Slot {
|
|||||||
impl Slot {
|
impl Slot {
|
||||||
pub fn to_item(self) -> Option<ItemStack> {
|
pub fn to_item(self) -> Option<ItemStack> {
|
||||||
let item_id = self.item_id?.0.try_into().unwrap();
|
let item_id = self.item_id?.0.try_into().unwrap();
|
||||||
|
let item = Item::from_id(item_id)?;
|
||||||
Some(ItemStack {
|
Some(ItemStack {
|
||||||
item_id,
|
item,
|
||||||
item_count: self.item_count.0.try_into().unwrap(),
|
item_count: self.item_count.0.try_into().unwrap(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -153,7 +155,7 @@ impl From<&ItemStack> for Slot {
|
|||||||
fn from(item: &ItemStack) -> Self {
|
fn from(item: &ItemStack) -> Self {
|
||||||
Slot {
|
Slot {
|
||||||
item_count: item.item_count.into(),
|
item_count: item.item_count.into(),
|
||||||
item_id: Some(VarInt(item.item_id as i32)),
|
item_id: Some(VarInt(item.item.id as i32)),
|
||||||
// TODO: add these
|
// TODO: add these
|
||||||
num_components_to_add: None,
|
num_components_to_add: None,
|
||||||
num_components_to_remove: None,
|
num_components_to_remove: None,
|
||||||
|
|||||||
@ -10,7 +10,7 @@ impl ItemStack {
|
|||||||
838, // Diamond
|
838, // Diamond
|
||||||
843, // Netherite
|
843, // Netherite
|
||||||
]
|
]
|
||||||
.contains(&self.item_id)
|
.contains(&self.item.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_helmet(&self) -> bool {
|
pub fn is_helmet(&self) -> bool {
|
||||||
@ -24,7 +24,7 @@ impl ItemStack {
|
|||||||
872, // Iron
|
872, // Iron
|
||||||
864,
|
864,
|
||||||
]
|
]
|
||||||
.contains(&self.item_id)
|
.contains(&self.item.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_chestplate(&self) -> bool {
|
pub fn is_chestplate(&self) -> bool {
|
||||||
@ -38,7 +38,7 @@ impl ItemStack {
|
|||||||
865, // Elytra
|
865, // Elytra
|
||||||
773,
|
773,
|
||||||
]
|
]
|
||||||
.contains(&self.item_id)
|
.contains(&self.item.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_leggings(&self) -> bool {
|
pub fn is_leggings(&self) -> bool {
|
||||||
@ -51,7 +51,7 @@ impl ItemStack {
|
|||||||
874, // Iron
|
874, // Iron
|
||||||
866,
|
866,
|
||||||
]
|
]
|
||||||
.contains(&self.item_id)
|
.contains(&self.item.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_boots(&self) -> bool {
|
pub fn is_boots(&self) -> bool {
|
||||||
@ -64,6 +64,6 @@ impl ItemStack {
|
|||||||
875, // Iron
|
875, // Iron
|
||||||
867,
|
867,
|
||||||
]
|
]
|
||||||
.contains(&self.item_id)
|
.contains(&self.item.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
|
use pumpkin_data::item::Item;
|
||||||
|
|
||||||
mod categories;
|
mod categories;
|
||||||
pub mod registry;
|
|
||||||
pub use registry::ITEMS;
|
|
||||||
#[derive(serde::Deserialize, Debug, Clone, PartialEq, Eq)]
|
#[derive(serde::Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||||
#[serde(rename_all = "lowercase")]
|
#[serde(rename_all = "lowercase")]
|
||||||
/// Item Rarity
|
/// Item Rarity
|
||||||
@ -13,23 +13,18 @@ pub enum Rarity {
|
|||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct ItemStack {
|
pub struct ItemStack {
|
||||||
// This ID is the numerical protocol ID, not the usual minecraft::block ID.
|
|
||||||
pub item_id: u16,
|
|
||||||
pub item_count: u8,
|
pub item_count: u8,
|
||||||
// TODO: Add Item Components
|
pub item: Item,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for ItemStack {
|
impl PartialEq for ItemStack {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.item_id == other.item_id
|
self.item.id == other.item.id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ItemStack {
|
impl ItemStack {
|
||||||
pub fn new(item_count: u8, item_id: u16) -> Self {
|
pub fn new(item_count: u8, item: Item) -> Self {
|
||||||
Self {
|
Self { item_count, item }
|
||||||
item_count,
|
|
||||||
item_id,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,98 +0,0 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
use std::sync::LazyLock;
|
|
||||||
|
|
||||||
use pumpkin_util::text::TextComponent;
|
|
||||||
use serde::Deserialize;
|
|
||||||
|
|
||||||
const ITEMS_JSON: &str = include_str!("../../../assets/items.json");
|
|
||||||
|
|
||||||
pub static ITEMS: LazyLock<HashMap<String, Item>> = LazyLock::new(|| {
|
|
||||||
serde_json::from_str(ITEMS_JSON).expect("Could not parse items.json registry.")
|
|
||||||
});
|
|
||||||
|
|
||||||
pub static ITEMS_REGISTRY_NAME_BY_ID: LazyLock<HashMap<u16, String>> = LazyLock::new(|| {
|
|
||||||
let mut map = HashMap::new();
|
|
||||||
for item in ITEMS.clone() {
|
|
||||||
map.insert(item.1.id, item.0.clone());
|
|
||||||
}
|
|
||||||
map
|
|
||||||
});
|
|
||||||
|
|
||||||
pub fn get_item(name: &str) -> Option<&Item> {
|
|
||||||
ITEMS.get(&name.replace("minecraft:", ""))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_name_by_id<'a>(item_id: u16) -> Option<&'a String> {
|
|
||||||
ITEMS_REGISTRY_NAME_BY_ID.get(&item_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_item_by_id<'a>(item_id: u16) -> Option<&'a Item> {
|
|
||||||
ITEMS.values().find(|&item| item.id == item_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_spawn_egg(item_id: u16) -> Option<String> {
|
|
||||||
if let Some(item_name) = ITEMS_REGISTRY_NAME_BY_ID.get(&item_id) {
|
|
||||||
if item_name.ends_with("_spawn_egg") {
|
|
||||||
if let Some(res) = item_name.strip_suffix("_spawn_egg") {
|
|
||||||
return Some(res.to_owned());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Clone, Debug)]
|
|
||||||
pub struct Item {
|
|
||||||
pub id: u16,
|
|
||||||
pub components: ItemComponents,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Item {
|
|
||||||
pub fn translated_name(&self) -> TextComponent {
|
|
||||||
serde_json::from_str(&self.components.item_name).expect("Could not parse item name.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Clone, Debug)]
|
|
||||||
pub struct ItemComponents {
|
|
||||||
#[serde(rename = "minecraft:item_name")]
|
|
||||||
pub item_name: String,
|
|
||||||
#[serde(rename = "minecraft:max_stack_size")]
|
|
||||||
pub max_stack_size: u8,
|
|
||||||
#[serde(rename = "minecraft:jukebox_playable")]
|
|
||||||
pub jukebox_playable: Option<JukeboxPlayable>,
|
|
||||||
#[serde(rename = "minecraft:damage")]
|
|
||||||
pub damage: Option<u16>,
|
|
||||||
#[serde(rename = "minecraft:max_damage")]
|
|
||||||
pub max_damage: Option<u16>,
|
|
||||||
#[serde(rename = "minecraft:attribute_modifiers")]
|
|
||||||
pub attribute_modifiers: Option<AttributeModifiers>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Clone, Debug)]
|
|
||||||
pub struct JukeboxPlayable {
|
|
||||||
pub song: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Clone, Debug)]
|
|
||||||
pub struct AttributeModifiers {
|
|
||||||
pub modifiers: Vec<Modifier>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Clone, Debug)]
|
|
||||||
pub struct Modifier {
|
|
||||||
pub r#type: String,
|
|
||||||
pub id: String,
|
|
||||||
pub amount: f64,
|
|
||||||
pub operation: Operation,
|
|
||||||
// TODO: Make this an enum
|
|
||||||
pub slot: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Clone, Debug, PartialEq)]
|
|
||||||
#[serde(rename_all = "snake_case")]
|
|
||||||
pub enum Operation {
|
|
||||||
AddValue,
|
|
||||||
AddMultipliedBase,
|
|
||||||
AddMultipliedTotal,
|
|
||||||
}
|
|
||||||
@ -1,4 +1,5 @@
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use pumpkin_data::item::Item;
|
||||||
use pumpkin_data::{
|
use pumpkin_data::{
|
||||||
screen::WindowType,
|
screen::WindowType,
|
||||||
sound::{Sound, SoundCategory},
|
sound::{Sound, SoundCategory},
|
||||||
@ -7,10 +8,7 @@ use pumpkin_inventory::{Chest, OpenContainer};
|
|||||||
use pumpkin_macros::pumpkin_block;
|
use pumpkin_macros::pumpkin_block;
|
||||||
use pumpkin_protocol::{client::play::CBlockAction, codec::var_int::VarInt};
|
use pumpkin_protocol::{client::play::CBlockAction, codec::var_int::VarInt};
|
||||||
use pumpkin_util::math::position::BlockPos;
|
use pumpkin_util::math::position::BlockPos;
|
||||||
use pumpkin_world::{
|
use pumpkin_world::block::registry::{get_block, Block};
|
||||||
block::registry::{get_block, Block},
|
|
||||||
item::registry::Item,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
block::{pumpkin_block::PumpkinBlock, registry::BlockActionResult},
|
block::{pumpkin_block::PumpkinBlock, registry::BlockActionResult},
|
||||||
|
|||||||
@ -3,11 +3,12 @@ use crate::block::registry::BlockActionResult;
|
|||||||
use crate::entity::player::Player;
|
use crate::entity::player::Player;
|
||||||
use crate::server::Server;
|
use crate::server::Server;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use pumpkin_data::item::Item;
|
||||||
use pumpkin_data::screen::WindowType;
|
use pumpkin_data::screen::WindowType;
|
||||||
use pumpkin_inventory::{CraftingTable, OpenContainer};
|
use pumpkin_inventory::{CraftingTable, OpenContainer};
|
||||||
use pumpkin_macros::pumpkin_block;
|
use pumpkin_macros::pumpkin_block;
|
||||||
use pumpkin_util::math::position::BlockPos;
|
use pumpkin_util::math::position::BlockPos;
|
||||||
use pumpkin_world::{block::registry::Block, item::registry::Item};
|
use pumpkin_world::block::registry::Block;
|
||||||
|
|
||||||
#[pumpkin_block("minecraft:crafting_table")]
|
#[pumpkin_block("minecraft:crafting_table")]
|
||||||
pub struct CraftingTableBlock;
|
pub struct CraftingTableBlock;
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
use crate::block::registry::BlockActionResult;
|
use crate::block::registry::BlockActionResult;
|
||||||
use crate::entity::player::Player;
|
use crate::entity::player::Player;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use pumpkin_data::item::Item;
|
||||||
use pumpkin_data::screen::WindowType;
|
use pumpkin_data::screen::WindowType;
|
||||||
use pumpkin_inventory::Furnace;
|
use pumpkin_inventory::Furnace;
|
||||||
use pumpkin_macros::pumpkin_block;
|
use pumpkin_macros::pumpkin_block;
|
||||||
use pumpkin_util::math::position::BlockPos;
|
use pumpkin_util::math::position::BlockPos;
|
||||||
use pumpkin_world::block::registry::Block;
|
use pumpkin_world::block::registry::Block;
|
||||||
use pumpkin_world::item::registry::Item;
|
|
||||||
|
|
||||||
use crate::{block::pumpkin_block::PumpkinBlock, server::Server};
|
use crate::{block::pumpkin_block::PumpkinBlock, server::Server};
|
||||||
|
|
||||||
|
|||||||
@ -3,11 +3,11 @@ use crate::block::registry::BlockActionResult;
|
|||||||
use crate::entity::player::Player;
|
use crate::entity::player::Player;
|
||||||
use crate::server::Server;
|
use crate::server::Server;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use pumpkin_data::item::Item;
|
||||||
use pumpkin_macros::pumpkin_block;
|
use pumpkin_macros::pumpkin_block;
|
||||||
use pumpkin_registry::SYNCED_REGISTRIES;
|
use pumpkin_registry::SYNCED_REGISTRIES;
|
||||||
use pumpkin_util::math::position::BlockPos;
|
use pumpkin_util::math::position::BlockPos;
|
||||||
use pumpkin_world::block::registry::Block;
|
use pumpkin_world::block::registry::Block;
|
||||||
use pumpkin_world::item::registry::Item;
|
|
||||||
|
|
||||||
#[pumpkin_block("minecraft:jukebox")]
|
#[pumpkin_block("minecraft:jukebox")]
|
||||||
pub struct JukeboxBlock;
|
pub struct JukeboxBlock;
|
||||||
|
|||||||
@ -2,6 +2,7 @@ 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_data::entity::EntityType;
|
||||||
|
use pumpkin_data::item::Item;
|
||||||
use pumpkin_util::math::position::BlockPos;
|
use pumpkin_util::math::position::BlockPos;
|
||||||
use pumpkin_util::math::vector3::Vector3;
|
use pumpkin_util::math::vector3::Vector3;
|
||||||
use pumpkin_world::block::registry::Block;
|
use pumpkin_world::block::registry::Block;
|
||||||
@ -43,7 +44,10 @@ pub async fn drop_loot(server: &Server, world: &Arc<World>, block: &Block, pos:
|
|||||||
);
|
);
|
||||||
|
|
||||||
let entity = server.add_entity(pos, EntityType::ITEM, world);
|
let entity = server.add_entity(pos, EntityType::ITEM, world);
|
||||||
let item_entity = Arc::new(ItemEntity::new(entity, &ItemStack::new(1, block.item_id)));
|
let item_entity = Arc::new(ItemEntity::new(
|
||||||
|
entity,
|
||||||
|
&ItemStack::new(1, Item::from_id(block.item_id).unwrap()),
|
||||||
|
));
|
||||||
world.spawn_entity(item_entity.clone()).await;
|
world.spawn_entity(item_entity.clone()).await;
|
||||||
item_entity.send_meta_packet().await;
|
item_entity.send_meta_packet().await;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,10 +2,10 @@ use crate::block::registry::BlockActionResult;
|
|||||||
use crate::entity::player::Player;
|
use crate::entity::player::Player;
|
||||||
use crate::server::Server;
|
use crate::server::Server;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use pumpkin_data::item::Item;
|
||||||
use pumpkin_inventory::OpenContainer;
|
use pumpkin_inventory::OpenContainer;
|
||||||
use pumpkin_util::math::position::BlockPos;
|
use pumpkin_util::math::position::BlockPos;
|
||||||
use pumpkin_world::block::registry::Block;
|
use pumpkin_world::block::registry::Block;
|
||||||
use pumpkin_world::item::registry::Item;
|
|
||||||
|
|
||||||
pub trait BlockMetadata {
|
pub trait BlockMetadata {
|
||||||
const NAMESPACE: &'static str;
|
const NAMESPACE: &'static str;
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
use crate::block::pumpkin_block::{BlockMetadata, PumpkinBlock};
|
use crate::block::pumpkin_block::{BlockMetadata, PumpkinBlock};
|
||||||
use crate::entity::player::Player;
|
use crate::entity::player::Player;
|
||||||
use crate::server::Server;
|
use crate::server::Server;
|
||||||
|
use pumpkin_data::item::Item;
|
||||||
use pumpkin_inventory::OpenContainer;
|
use pumpkin_inventory::OpenContainer;
|
||||||
use pumpkin_util::math::position::BlockPos;
|
use pumpkin_util::math::position::BlockPos;
|
||||||
use pumpkin_world::block::registry::Block;
|
use pumpkin_world::block::registry::Block;
|
||||||
use pumpkin_world::item::registry::Item;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
|||||||
@ -52,7 +52,7 @@ impl ArgumentConsumer for DamageTypeArgumentConsumer {
|
|||||||
|
|
||||||
impl DefaultNameArgConsumer for DamageTypeArgumentConsumer {
|
impl DefaultNameArgConsumer for DamageTypeArgumentConsumer {
|
||||||
fn default_name(&self) -> &'static str {
|
fn default_name(&self) -> &'static str {
|
||||||
"damage_type"
|
"damageType"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use pumpkin_data::item::Item;
|
||||||
use pumpkin_protocol::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders};
|
use pumpkin_protocol::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders};
|
||||||
use pumpkin_world::item::registry::{self, Item};
|
|
||||||
|
|
||||||
use crate::{command::dispatcher::CommandError, server::Server};
|
use crate::{command::dispatcher::CommandError, server::Server};
|
||||||
|
|
||||||
@ -53,11 +53,11 @@ impl DefaultNameArgConsumer for ItemArgumentConsumer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> FindArg<'a> for ItemArgumentConsumer {
|
impl<'a> FindArg<'a> for ItemArgumentConsumer {
|
||||||
type Data = (&'a str, &'a Item);
|
type Data = (&'a str, Item);
|
||||||
|
|
||||||
fn find_arg(args: &'a super::ConsumedArgs, name: &str) -> Result<Self::Data, CommandError> {
|
fn find_arg(args: &'a super::ConsumedArgs, name: &str) -> Result<Self::Data, CommandError> {
|
||||||
match args.get(name) {
|
match args.get(name) {
|
||||||
Some(Arg::Item(name)) => registry::get_item(name).map_or_else(
|
Some(Arg::Item(name)) => Item::from_name(&name.replace("minecraft:", "")).map_or_else(
|
||||||
|| {
|
|| {
|
||||||
Err(CommandError::GeneralCommandIssue(format!(
|
Err(CommandError::GeneralCommandIssue(format!(
|
||||||
"Item {name} does not exist."
|
"Item {name} does not exist."
|
||||||
|
|||||||
@ -56,7 +56,6 @@ impl CommandExecutor for GiveExecutor {
|
|||||||
for target in targets {
|
for target in targets {
|
||||||
target.give_items(item, item_count as u32).await;
|
target.give_items(item, item_count as u32).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
let msg = if targets.len() == 1 {
|
let msg = if targets.len() == 1 {
|
||||||
TextComponent::translate(
|
TextComponent::translate(
|
||||||
"commands.give.success.single",
|
"commands.give.success.single",
|
||||||
|
|||||||
@ -22,7 +22,7 @@ impl ItemEntity {
|
|||||||
let slot = Slot::from(stack);
|
let slot = Slot::from(stack);
|
||||||
Self {
|
Self {
|
||||||
entity,
|
entity,
|
||||||
id: stack.item_id,
|
id: stack.item.id,
|
||||||
count: stack.item_count,
|
count: stack.item_count,
|
||||||
item: slot,
|
item: slot,
|
||||||
pickup_delay: AtomicI8::new(10), // Vanilla
|
pickup_delay: AtomicI8::new(10), // Vanilla
|
||||||
|
|||||||
@ -13,6 +13,7 @@ use pumpkin_config::{ADVANCED_CONFIG, BASIC_CONFIG};
|
|||||||
use pumpkin_data::{
|
use pumpkin_data::{
|
||||||
damage::DamageType,
|
damage::DamageType,
|
||||||
entity::EntityType,
|
entity::EntityType,
|
||||||
|
item::Operation,
|
||||||
sound::{Sound, SoundCategory},
|
sound::{Sound, SoundCategory},
|
||||||
};
|
};
|
||||||
use pumpkin_inventory::player::PlayerInventory;
|
use pumpkin_inventory::player::PlayerInventory;
|
||||||
@ -57,13 +58,7 @@ use pumpkin_util::{
|
|||||||
text::TextComponent,
|
text::TextComponent,
|
||||||
GameMode,
|
GameMode,
|
||||||
};
|
};
|
||||||
use pumpkin_world::{
|
use pumpkin_world::{cylindrical_chunk_iterator::Cylindrical, item::ItemStack};
|
||||||
cylindrical_chunk_iterator::Cylindrical,
|
|
||||||
item::{
|
|
||||||
registry::{get_item_by_id, Operation},
|
|
||||||
ItemStack,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
use tokio::sync::{Mutex, Notify, RwLock};
|
use tokio::sync::{Mutex, Notify, RwLock};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
@ -294,10 +289,9 @@ impl Player {
|
|||||||
|
|
||||||
// get attack damage
|
// get attack damage
|
||||||
if let Some(item_stack) = item_slot {
|
if let Some(item_stack) = item_slot {
|
||||||
if let Some(item) = get_item_by_id(item_stack.item_id) {
|
|
||||||
// TODO: this should be cached in memory
|
// TODO: this should be cached in memory
|
||||||
if let Some(modifiers) = &item.components.attribute_modifiers {
|
if let Some(modifiers) = &item_stack.item.components.attribute_modifiers {
|
||||||
for item_mod in &modifiers.modifiers {
|
for item_mod in modifiers.modifiers {
|
||||||
if item_mod.operation == Operation::AddValue {
|
if item_mod.operation == Operation::AddValue {
|
||||||
if item_mod.id == "minecraft:base_attack_damage" {
|
if item_mod.id == "minecraft:base_attack_damage" {
|
||||||
add_damage = item_mod.amount;
|
add_damage = item_mod.amount;
|
||||||
@ -309,7 +303,6 @@ impl Player {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
drop(inventory);
|
drop(inventory);
|
||||||
|
|
||||||
let attack_speed = base_attack_speed + add_speed;
|
let attack_speed = base_attack_speed + add_speed;
|
||||||
|
|||||||
@ -6,10 +6,11 @@ use crate::item::pumpkin_item::PumpkinItem;
|
|||||||
use crate::server::Server;
|
use crate::server::Server;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use pumpkin_data::entity::EntityType;
|
use pumpkin_data::entity::EntityType;
|
||||||
|
use pumpkin_data::item::Item;
|
||||||
use pumpkin_data::sound::Sound;
|
use pumpkin_data::sound::Sound;
|
||||||
use pumpkin_macros::pumpkin_item;
|
use pumpkin_macros::pumpkin_item;
|
||||||
use pumpkin_world::item::registry::Item;
|
|
||||||
#[pumpkin_item("minecraft:egg")]
|
#[pumpkin_item("egg")]
|
||||||
pub struct EggItem;
|
pub struct EggItem;
|
||||||
|
|
||||||
const POWER: f32 = 1.5;
|
const POWER: f32 = 1.5;
|
||||||
|
|||||||
@ -6,10 +6,11 @@ use crate::item::pumpkin_item::PumpkinItem;
|
|||||||
use crate::server::Server;
|
use crate::server::Server;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use pumpkin_data::entity::EntityType;
|
use pumpkin_data::entity::EntityType;
|
||||||
|
use pumpkin_data::item::Item;
|
||||||
use pumpkin_data::sound::Sound;
|
use pumpkin_data::sound::Sound;
|
||||||
use pumpkin_macros::pumpkin_item;
|
use pumpkin_macros::pumpkin_item;
|
||||||
use pumpkin_world::item::registry::Item;
|
|
||||||
#[pumpkin_item("minecraft:snowball")]
|
#[pumpkin_item("snowball")]
|
||||||
pub struct SnowBallItem;
|
pub struct SnowBallItem;
|
||||||
|
|
||||||
const POWER: f32 = 1.5;
|
const POWER: f32 = 1.5;
|
||||||
|
|||||||
@ -1,16 +1,12 @@
|
|||||||
use crate::entity::player::Player;
|
use crate::entity::player::Player;
|
||||||
use crate::server::Server;
|
use crate::server::Server;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use pumpkin_data::item::Item;
|
||||||
use pumpkin_util::math::position::BlockPos;
|
use pumpkin_util::math::position::BlockPos;
|
||||||
use pumpkin_world::block::registry::Block;
|
use pumpkin_world::block::registry::Block;
|
||||||
use pumpkin_world::item::registry::Item;
|
|
||||||
|
|
||||||
pub trait ItemMetadata {
|
pub trait ItemMetadata {
|
||||||
const NAMESPACE: &'static str;
|
const ID: u16;
|
||||||
const ID: &'static str;
|
|
||||||
fn name(&self) -> String {
|
|
||||||
format!("{}:{}", Self::NAMESPACE, Self::ID)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
use crate::entity::player::Player;
|
use crate::entity::player::Player;
|
||||||
use crate::server::Server;
|
use crate::server::Server;
|
||||||
|
use pumpkin_data::item::Item;
|
||||||
use pumpkin_util::math::position::BlockPos;
|
use pumpkin_util::math::position::BlockPos;
|
||||||
use pumpkin_world::block::registry::Block;
|
use pumpkin_world::block::registry::Block;
|
||||||
use pumpkin_world::item::registry::Item;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
@ -10,16 +10,16 @@ use super::pumpkin_item::{ItemMetadata, PumpkinItem};
|
|||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct ItemRegistry {
|
pub struct ItemRegistry {
|
||||||
blocks: HashMap<String, Arc<dyn PumpkinItem>>,
|
items: HashMap<u16, Arc<dyn PumpkinItem>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ItemRegistry {
|
impl ItemRegistry {
|
||||||
pub fn register<T: PumpkinItem + ItemMetadata + 'static>(&mut self, block: T) {
|
pub fn register<T: PumpkinItem + ItemMetadata + 'static>(&mut self, item: T) {
|
||||||
self.blocks.insert(block.name(), Arc::new(block));
|
self.items.insert(T::ID, Arc::new(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn on_use(&self, item_name: &str, item: &Item, player: &Player, server: &Server) {
|
pub async fn on_use(&self, item: &Item, player: &Player, server: &Server) {
|
||||||
let pumpkin_block = self.get_pumpkin_item(item_name);
|
let pumpkin_block = self.get_pumpkin_item(item.id);
|
||||||
if let Some(pumpkin_block) = pumpkin_block {
|
if let Some(pumpkin_block) = pumpkin_block {
|
||||||
pumpkin_block.normal_use(item, player, server).await;
|
pumpkin_block.normal_use(item, player, server).await;
|
||||||
}
|
}
|
||||||
@ -27,23 +27,22 @@ impl ItemRegistry {
|
|||||||
|
|
||||||
pub async fn use_on_block(
|
pub async fn use_on_block(
|
||||||
&self,
|
&self,
|
||||||
item_name: &str,
|
|
||||||
item: &Item,
|
item: &Item,
|
||||||
player: &Player,
|
player: &Player,
|
||||||
location: BlockPos,
|
location: BlockPos,
|
||||||
block: &Block,
|
block: &Block,
|
||||||
server: &Server,
|
server: &Server,
|
||||||
) {
|
) {
|
||||||
let pumpkin_block = self.get_pumpkin_item(item_name);
|
let pumpkin_item = self.get_pumpkin_item(item.id);
|
||||||
if let Some(pumpkin_block) = pumpkin_block {
|
if let Some(pumpkin_item) = pumpkin_item {
|
||||||
return pumpkin_block
|
return pumpkin_item
|
||||||
.use_on_block(item, player, location, block, server)
|
.use_on_block(item, player, location, block, server)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_pumpkin_item(&self, item_name: &str) -> Option<&Arc<dyn PumpkinItem>> {
|
pub fn get_pumpkin_item(&self, item_id: u16) -> Option<&Arc<dyn PumpkinItem>> {
|
||||||
self.blocks.get(format!("minecraft:{item_name}").as_str())
|
self.items.get(&item_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
use crate::entity::player::Player;
|
use crate::entity::player::Player;
|
||||||
use crate::server::Server;
|
use crate::server::Server;
|
||||||
|
use pumpkin_data::item::Item;
|
||||||
use pumpkin_data::screen::WindowType;
|
use pumpkin_data::screen::WindowType;
|
||||||
use pumpkin_inventory::container_click::{
|
use pumpkin_inventory::container_click::{
|
||||||
Click, ClickType, KeyClick, MouseClick, MouseDragState, MouseDragType,
|
Click, ClickType, KeyClick, MouseClick, MouseDragState, MouseDragType,
|
||||||
@ -16,7 +17,6 @@ use pumpkin_protocol::codec::var_int::VarInt;
|
|||||||
use pumpkin_protocol::server::play::SClickContainer;
|
use pumpkin_protocol::server::play::SClickContainer;
|
||||||
use pumpkin_util::text::TextComponent;
|
use pumpkin_util::text::TextComponent;
|
||||||
use pumpkin_util::GameMode;
|
use pumpkin_util::GameMode;
|
||||||
use pumpkin_world::item::registry::Item;
|
|
||||||
use pumpkin_world::item::ItemStack;
|
use pumpkin_world::item::ItemStack;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
@ -323,7 +323,7 @@ impl Player {
|
|||||||
let find_condition = |(slot_number, slot): (usize, &mut Option<ItemStack>)| {
|
let find_condition = |(slot_number, slot): (usize, &mut Option<ItemStack>)| {
|
||||||
// TODO: Check for max item count here
|
// TODO: Check for max item count here
|
||||||
match slot {
|
match slot {
|
||||||
Some(item) => (item.item_id == item_in_pressed_slot.item_id
|
Some(item) => (item.item.id == item_in_pressed_slot.item.id
|
||||||
&& item.item_count != 64)
|
&& item.item_count != 64)
|
||||||
.then_some(slot_number),
|
.then_some(slot_number),
|
||||||
None => Some(slot_number),
|
None => Some(slot_number),
|
||||||
@ -411,7 +411,7 @@ impl Player {
|
|||||||
**item = None;
|
**item = None;
|
||||||
|
|
||||||
for slot in slots.iter_mut().filter_map(|slot| slot.as_mut()) {
|
for slot in slots.iter_mut().filter_map(|slot| slot.as_mut()) {
|
||||||
if slot.item_id == carried_item.item_id {
|
if slot.item.id == carried_item.item.id {
|
||||||
// TODO: Check for max stack size
|
// TODO: Check for max stack size
|
||||||
if slot.item_count + carried_item.item_count <= 64 {
|
if slot.item_count + carried_item.item_count <= 64 {
|
||||||
slot.item_count = 0;
|
slot.item_count = 0;
|
||||||
@ -553,14 +553,14 @@ impl Player {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn pickup_items(&self, item: &Item, mut amount: u32) {
|
async fn pickup_items(&self, item: Item, mut amount: u32) {
|
||||||
let max_stack = item.components.max_stack_size;
|
let max_stack = item.components.max_stack_size;
|
||||||
let mut inventory = self.inventory().lock().await;
|
let mut inventory = self.inventory().lock().await;
|
||||||
let slots = inventory.slots_with_hotbar_first();
|
let slots = inventory.slots_with_hotbar_first();
|
||||||
|
|
||||||
let matching_slots = slots.filter_map(|slot| {
|
let matching_slots = slots.filter_map(|slot| {
|
||||||
if let Some(item_slot) = slot.as_mut() {
|
if let Some(item_slot) = slot.as_mut() {
|
||||||
(item_slot.item_id == item.id && item_slot.item_count < max_stack).then(|| {
|
(item_slot.item.id == item.id && item_slot.item_count < max_stack).then(|| {
|
||||||
let item_count = item_slot.item_count;
|
let item_count = item_slot.item_count;
|
||||||
(item_slot, item_count)
|
(item_slot, item_count)
|
||||||
})
|
})
|
||||||
@ -577,12 +577,12 @@ impl Player {
|
|||||||
if let Some(amount_left) = amount.checked_sub(u32::from(amount_to_add)) {
|
if let Some(amount_left) = amount.checked_sub(u32::from(amount_to_add)) {
|
||||||
amount = amount_left;
|
amount = amount_left;
|
||||||
*slot = ItemStack {
|
*slot = ItemStack {
|
||||||
item_id: item.id,
|
item,
|
||||||
item_count: item.components.max_stack_size,
|
item_count: item.components.max_stack_size,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
*slot = ItemStack {
|
*slot = ItemStack {
|
||||||
item_id: item.id,
|
item,
|
||||||
item_count: max_stack - (amount_to_add - amount as u8),
|
item_count: max_stack - (amount_to_add - amount as u8),
|
||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
@ -599,12 +599,12 @@ impl Player {
|
|||||||
if let Some(remaining_amount) = amount.checked_sub(u32::from(max_stack)) {
|
if let Some(remaining_amount) = amount.checked_sub(u32::from(max_stack)) {
|
||||||
amount = remaining_amount;
|
amount = remaining_amount;
|
||||||
*slot = Some(ItemStack {
|
*slot = Some(ItemStack {
|
||||||
item_id: item.id,
|
item,
|
||||||
item_count: max_stack,
|
item_count: max_stack,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
*slot = Some(ItemStack {
|
*slot = Some(ItemStack {
|
||||||
item_id: item.id,
|
item,
|
||||||
item_count: amount as u8,
|
item_count: amount as u8,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
@ -618,7 +618,7 @@ impl Player {
|
|||||||
/// Add items to inventory if there's space, else drop them to the ground.
|
/// Add items to inventory if there's space, else drop them to the ground.
|
||||||
///
|
///
|
||||||
/// This method automatically syncs changes with the client.
|
/// This method automatically syncs changes with the client.
|
||||||
pub async fn give_items(&self, item: &Item, amount: u32) {
|
pub async fn give_items(&self, item: Item, amount: u32) {
|
||||||
self.pickup_items(item, amount).await;
|
self.pickup_items(item, amount).await;
|
||||||
self.set_container_content(None).await;
|
self.set_container_content(None).await;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,7 +13,8 @@ use crate::{
|
|||||||
world::chunker,
|
world::chunker,
|
||||||
};
|
};
|
||||||
use pumpkin_config::ADVANCED_CONFIG;
|
use pumpkin_config::ADVANCED_CONFIG;
|
||||||
use pumpkin_data::entity::{EntityPose, EntityType};
|
use pumpkin_data::entity::{entity_from_egg, EntityPose, EntityType};
|
||||||
|
use pumpkin_data::item::Item;
|
||||||
use pumpkin_data::world::CHAT;
|
use pumpkin_data::world::CHAT;
|
||||||
use pumpkin_inventory::player::PlayerInventory;
|
use pumpkin_inventory::player::PlayerInventory;
|
||||||
use pumpkin_inventory::InventoryError;
|
use pumpkin_inventory::InventoryError;
|
||||||
@ -49,12 +50,8 @@ use pumpkin_util::{
|
|||||||
use pumpkin_world::block::interactive::sign::Sign;
|
use pumpkin_world::block::interactive::sign::Sign;
|
||||||
use pumpkin_world::block::registry::get_block_collision_shapes;
|
use pumpkin_world::block::registry::get_block_collision_shapes;
|
||||||
use pumpkin_world::block::registry::Block;
|
use pumpkin_world::block::registry::Block;
|
||||||
use pumpkin_world::item::registry::{get_item_by_id, get_name_by_id};
|
use pumpkin_world::block::{registry::get_block_by_item, BlockDirection};
|
||||||
use pumpkin_world::item::ItemStack;
|
use pumpkin_world::item::ItemStack;
|
||||||
use pumpkin_world::{
|
|
||||||
block::{registry::get_block_by_item, BlockDirection},
|
|
||||||
item::registry::get_spawn_egg,
|
|
||||||
};
|
|
||||||
|
|
||||||
use pumpkin_world::{WORLD_LOWEST_Y, WORLD_MAX_Y};
|
use pumpkin_world::{WORLD_LOWEST_Y, WORLD_MAX_Y};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
@ -464,7 +461,7 @@ impl Player {
|
|||||||
}
|
}
|
||||||
None if self.gamemode.load() == GameMode::Creative => {
|
None if self.gamemode.load() == GameMode::Creative => {
|
||||||
// Case where item is not present, if in creative mode create the item
|
// Case where item is not present, if in creative mode create the item
|
||||||
let item_stack = ItemStack::new(1, block.item_id);
|
let item_stack = ItemStack::new(1, Item::from_id(block.item_id).unwrap());
|
||||||
let slot_data = Slot::from(&item_stack);
|
let slot_data = Slot::from(&item_stack);
|
||||||
self.update_single_slot(&mut inventory, dest_slot as i16 + 36, slot_data)
|
self.update_single_slot(&mut inventory, dest_slot as i16 + 36, slot_data)
|
||||||
.await;
|
.await;
|
||||||
@ -975,11 +972,6 @@ impl Player {
|
|||||||
}
|
}
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
let Some(item) = get_item_by_id(stack.item_id) else {
|
|
||||||
// If there is an item stack, there should be an item
|
|
||||||
return Err(BlockPlacingError::InventoryInvalid.into());
|
|
||||||
};
|
|
||||||
|
|
||||||
if !self
|
if !self
|
||||||
.living_entity
|
.living_entity
|
||||||
.entity
|
.entity
|
||||||
@ -988,7 +980,7 @@ impl Player {
|
|||||||
{
|
{
|
||||||
let action_result = server
|
let action_result = server
|
||||||
.block_registry
|
.block_registry
|
||||||
.use_with_item(block, self, location, item, server)
|
.use_with_item(block, self, location, &stack.item, server)
|
||||||
.await;
|
.await;
|
||||||
match action_result {
|
match action_result {
|
||||||
BlockActionResult::Continue => {}
|
BlockActionResult::Continue => {}
|
||||||
@ -998,16 +990,16 @@ impl Player {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// check if item is a block, Because Not every item can be placed :D
|
// check if item is a block, Because Not every item can be placed :D
|
||||||
if let Some(block) = get_block_by_item(stack.item_id) {
|
if let Some(block) = get_block_by_item(stack.item.id) {
|
||||||
should_try_decrement = self
|
should_try_decrement = self
|
||||||
.run_is_block_place(block.clone(), server, use_item_on, location, &face)
|
.run_is_block_place(block.clone(), server, use_item_on, location, &face)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
// check if item is a spawn egg
|
// check if item is a spawn egg
|
||||||
if let Some(item_t) = get_spawn_egg(stack.item_id) {
|
if let Some(entity) = entity_from_egg(stack.item.id) {
|
||||||
should_try_decrement = self
|
self.spawn_entity_from_egg(entity, server, location, &face)
|
||||||
.run_is_spawn_egg(item_t, server, location, &face)
|
.await;
|
||||||
.await?;
|
should_try_decrement = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
if should_try_decrement {
|
if should_try_decrement {
|
||||||
@ -1062,11 +1054,7 @@ impl Player {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if let Some(held) = self.inventory().lock().await.held_item() {
|
if let Some(held) = self.inventory().lock().await.held_item() {
|
||||||
// this is so ugly and slow brooo...
|
server.item_registry.on_use(&held.item, self, server).await;
|
||||||
if let Some(item) = get_item_by_id(held.item_id) {
|
|
||||||
let name = get_name_by_id(item.id).unwrap();
|
|
||||||
server.item_registry.on_use(name, item, self, server).await;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1170,15 +1158,13 @@ impl Player {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run_is_spawn_egg(
|
async fn spawn_entity_from_egg(
|
||||||
&self,
|
&self,
|
||||||
item_t: String,
|
entity_type: EntityType,
|
||||||
server: &Server,
|
server: &Server,
|
||||||
location: BlockPos,
|
location: BlockPos,
|
||||||
face: &BlockDirection,
|
face: &BlockDirection,
|
||||||
) -> Result<bool, Box<dyn PumpkinError>> {
|
) {
|
||||||
// checks if spawn egg has a corresponding entity name
|
|
||||||
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(
|
||||||
@ -1206,12 +1192,6 @@ impl Player {
|
|||||||
world.spawn_entity(mob).await;
|
world.spawn_entity(mob).await;
|
||||||
|
|
||||||
// TODO: send/configure additional commands/data based on type of entity (horse, slime, etc)
|
// TODO: send/configure additional commands/data based on type of entity (horse, slime, etc)
|
||||||
} else {
|
|
||||||
// TODO: maybe include additional error types
|
|
||||||
return Ok(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_player_direction(&self) -> Direction {
|
fn get_player_direction(&self) -> Direction {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user