Initial Enchantment work
This commit is contained in:
parent
fcf2700d65
commit
85007547c4
2109
assets/enchantments.json
Normal file
2109
assets/enchantments.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -8,6 +8,7 @@ mod block;
|
||||
mod chunk_status;
|
||||
mod composter_increase_chance;
|
||||
mod damage_type;
|
||||
mod enchantments;
|
||||
mod entity_pose;
|
||||
mod entity_status;
|
||||
mod entity_type;
|
||||
@ -72,6 +73,7 @@ pub fn main() {
|
||||
"composter_increase_chance.rs",
|
||||
);
|
||||
write_generated_file(recipes::build(), "recipes.rs");
|
||||
write_generated_file(enchantments::build(), "enchantment.rs");
|
||||
}
|
||||
|
||||
pub fn array_to_tokenstream(array: &[String]) -> TokenStream {
|
||||
@ -99,7 +101,6 @@ pub fn write_generated_file(content: TokenStream, out_file: &str) {
|
||||
// Doesn't matter if rustfmt is unavailable.
|
||||
let _ = Command::new("rustfmt").arg(&path).output();
|
||||
// Try to auto optimize using clippy.
|
||||
// Doesn't matter if rustfmt is unavailable.
|
||||
let _ = Command::new("cargo clippy --fix --allow-dirty")
|
||||
.arg(&path)
|
||||
.output();
|
||||
|
||||
119
pumpkin-data/build/enchantments.rs
Normal file
119
pumpkin-data/build/enchantments.rs
Normal file
@ -0,0 +1,119 @@
|
||||
use std::{collections::HashMap, fs};
|
||||
|
||||
use heck::ToShoutySnakeCase;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Enchantment {
|
||||
anvil_cost: u32,
|
||||
supported_items: String,
|
||||
max_level: i32,
|
||||
slots: Vec<AttributeModifierSlot>, // TODO: add more
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Clone)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum AttributeModifierSlot {
|
||||
Any,
|
||||
MainHand,
|
||||
OffHand,
|
||||
Hand,
|
||||
Feet,
|
||||
Legs,
|
||||
Chest,
|
||||
Head,
|
||||
Armor,
|
||||
Body,
|
||||
Saddle,
|
||||
}
|
||||
|
||||
impl AttributeModifierSlot {
|
||||
fn to_tokens(&self) -> TokenStream {
|
||||
match self {
|
||||
AttributeModifierSlot::Any => quote! { AttributeModifierSlot::Any },
|
||||
AttributeModifierSlot::MainHand => quote! { AttributeModifierSlot::MainHand },
|
||||
AttributeModifierSlot::OffHand => quote! { AttributeModifierSlot::OffHand },
|
||||
AttributeModifierSlot::Hand => quote! { AttributeModifierSlot::Hand },
|
||||
AttributeModifierSlot::Feet => quote! { AttributeModifierSlot::Feet },
|
||||
AttributeModifierSlot::Legs => quote! { AttributeModifierSlot::Legs },
|
||||
AttributeModifierSlot::Chest => quote! { AttributeModifierSlot::Chest },
|
||||
AttributeModifierSlot::Head => quote! { AttributeModifierSlot::Head },
|
||||
AttributeModifierSlot::Armor => quote! { AttributeModifierSlot::Armor },
|
||||
AttributeModifierSlot::Body => quote! { AttributeModifierSlot::Body },
|
||||
AttributeModifierSlot::Saddle => quote! { AttributeModifierSlot::Saddle },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn build() -> TokenStream {
|
||||
println!("cargo:rerun-if-changed=../assets/enchantments.json");
|
||||
|
||||
let enchantments: HashMap<String, Enchantment> =
|
||||
serde_json::from_str(&fs::read_to_string("../assets/enchantments.json").unwrap())
|
||||
.expect("Failed to parse biome.json");
|
||||
|
||||
let mut variants = TokenStream::new();
|
||||
let mut name_to_type = TokenStream::new();
|
||||
|
||||
for (name, enchantment) in enchantments.iter() {
|
||||
let raw_name = name.strip_prefix("minecraft:").unwrap();
|
||||
let format_name = format_ident!("{}", raw_name.to_shouty_snake_case());
|
||||
let anvil_cost = enchantment.anvil_cost;
|
||||
let supported_items = enchantment.supported_items.clone();
|
||||
let max_level = enchantment.max_level;
|
||||
let slots = enchantment.slots.clone();
|
||||
let slots = slots.iter().map(|slot| slot.to_tokens());
|
||||
|
||||
variants.extend([quote! {
|
||||
pub const #format_name: Enchantment = Enchantment {
|
||||
name: #name,
|
||||
anvil_cost: #anvil_cost,
|
||||
supported_items: #supported_items,
|
||||
max_level: #max_level,
|
||||
slots: &[#(#slots),*]
|
||||
};
|
||||
}]);
|
||||
|
||||
name_to_type.extend(quote! { #name => Some(Self::#format_name), });
|
||||
}
|
||||
|
||||
quote! {
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Enchantment {
|
||||
pub name: &'static str,
|
||||
pub anvil_cost: u32,
|
||||
pub supported_items: &'static str,
|
||||
pub max_level: i32,
|
||||
pub slots: &'static [AttributeModifierSlot]
|
||||
// TODO: add more
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum AttributeModifierSlot {
|
||||
Any,
|
||||
MainHand,
|
||||
OffHand,
|
||||
Hand,
|
||||
Feet,
|
||||
Legs,
|
||||
Chest,
|
||||
Head,
|
||||
Armor,
|
||||
Body,
|
||||
Saddle,
|
||||
}
|
||||
|
||||
impl Enchantment {
|
||||
#variants
|
||||
|
||||
pub fn from_name(name: &str) -> Option<Self> {
|
||||
match name {
|
||||
#name_to_type
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -79,6 +79,11 @@ mod spawn_egg;
|
||||
#[path = "generated/status_effect.rs"]
|
||||
mod status_effect;
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[path = "generated/enchantment.rs"]
|
||||
mod enchantment;
|
||||
pub use enchantment::*;
|
||||
|
||||
pub mod entity {
|
||||
pub use super::entity_pose::*;
|
||||
pub use super::entity_status::*;
|
||||
|
||||
@ -2,6 +2,7 @@ use std::{collections::HashMap, hash::Hash, sync::Arc};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use bounded_num::{NotInBounds, Number};
|
||||
use pumpkin_data::Enchantment;
|
||||
use pumpkin_data::damage::DamageType;
|
||||
use pumpkin_data::entity::EffectType;
|
||||
use pumpkin_data::particle::Particle;
|
||||
@ -109,6 +110,7 @@ pub enum Arg<'a> {
|
||||
SoundCategory(SoundCategory),
|
||||
DamageType(DamageType),
|
||||
Effect(EffectType),
|
||||
Enchantment(Enchantment),
|
||||
}
|
||||
|
||||
/// see [`crate::commands::tree::builder::argument`] and [`CommandTree::execute`]/[`crate::commands::tree::builder::NonLeafNodeBuilder::execute`]
|
||||
|
||||
71
pumpkin/src/command/args/resource/enchantment.rs
Normal file
71
pumpkin/src/command/args/resource/enchantment.rs
Normal file
@ -0,0 +1,71 @@
|
||||
use async_trait::async_trait;
|
||||
use pumpkin_data::Enchantment;
|
||||
use pumpkin_protocol::java::client::play::{ArgumentType, CommandSuggestion, SuggestionProviders};
|
||||
|
||||
use crate::command::{
|
||||
CommandSender,
|
||||
args::{
|
||||
Arg, ArgumentConsumer, ConsumedArgs, DefaultNameArgConsumer, FindArg,
|
||||
GetClientSideArgParser,
|
||||
},
|
||||
dispatcher::CommandError,
|
||||
tree::RawArgs,
|
||||
};
|
||||
use crate::server::Server;
|
||||
|
||||
pub struct EnchantmentArgumentConsumer;
|
||||
|
||||
impl GetClientSideArgParser for EnchantmentArgumentConsumer {
|
||||
fn get_client_side_parser(&self) -> ArgumentType {
|
||||
ArgumentType::Resource {
|
||||
identifier: "enchantment",
|
||||
}
|
||||
}
|
||||
|
||||
fn get_client_side_suggestion_type_override(&self) -> Option<SuggestionProviders> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl ArgumentConsumer for EnchantmentArgumentConsumer {
|
||||
async fn consume<'a>(
|
||||
&'a self,
|
||||
_sender: &CommandSender,
|
||||
_server: &'a Server,
|
||||
args: &mut RawArgs<'a>,
|
||||
) -> Option<Arg<'a>> {
|
||||
let name = args.pop()?;
|
||||
|
||||
// Create a static damage type first
|
||||
let enchantment = Enchantment::from_name(name)?;
|
||||
// Find matching static damage type from values array
|
||||
Some(Arg::Enchantment(enchantment))
|
||||
}
|
||||
|
||||
async fn suggest<'a>(
|
||||
&'a self,
|
||||
_sender: &CommandSender,
|
||||
_server: &'a Server,
|
||||
_input: &'a str,
|
||||
) -> Result<Option<Vec<CommandSuggestion>>, CommandError> {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
impl DefaultNameArgConsumer for EnchantmentArgumentConsumer {
|
||||
fn default_name(&self) -> &'static str {
|
||||
"enchantment"
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FindArg<'a> for EnchantmentArgumentConsumer {
|
||||
type Data = &'a Enchantment;
|
||||
|
||||
fn find_arg(args: &'a ConsumedArgs, name: &str) -> Result<Self::Data, CommandError> {
|
||||
match args.get(name) {
|
||||
Some(Arg::Enchantment(data)) => Ok(data),
|
||||
_ => Err(CommandError::InvalidConsumption(Some(name.to_string()))),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,5 @@
|
||||
pub mod damage_type;
|
||||
pub mod effect;
|
||||
pub mod enchantment;
|
||||
pub mod item;
|
||||
pub mod particle;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user