370 lines
12 KiB
Rust
370 lines
12 KiB
Rust
#[cfg(feature = "codegen")]
|
|
use proc_macro2::TokenStream;
|
|
#[cfg(feature = "codegen")]
|
|
use quote::{ToTokens, quote};
|
|
use serde::Deserialize;
|
|
|
|
use crate::random::RandomImpl;
|
|
|
|
/// Represents a loot table used to generate items or rewards.
|
|
#[derive(Clone, Copy, Debug)]
|
|
pub struct LootTable {
|
|
/// The type of loot table (e.g., `Entity`, `Block`, `Chest`).
|
|
pub r#type: LootTableType,
|
|
/// Optional random sequence identifier for deterministic rolls.
|
|
pub random_sequence: Option<&'static str>,
|
|
/// Optional array of loot pools that define item generation.
|
|
pub pools: Option<&'static [LootPool]>,
|
|
}
|
|
|
|
/// Defines a loot pool containing entries, rolls, and conditions.
|
|
#[derive(Clone, Debug)]
|
|
pub struct LootPool {
|
|
/// Entries contained in this loot pool.
|
|
pub entries: &'static [LootPoolEntry],
|
|
/// Number of rolls, specified using a number provider.
|
|
pub rolls: LootNumberProviderTypes,
|
|
/// Additional bonus rolls to apply.
|
|
pub bonus_rolls: LootNumberProviderTypes,
|
|
/// Optional conditions that must be met for this pool to be applied.
|
|
pub conditions: Option<&'static [LootCondition]>,
|
|
/// Optional functions applied to each entry in the pool.
|
|
pub functions: Option<&'static [LootFunction]>,
|
|
}
|
|
|
|
/// Represents an individual item entry in a loot pool.
|
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
|
pub struct ItemEntry {
|
|
/// Name of the item.
|
|
pub name: &'static str,
|
|
}
|
|
|
|
/// Represents an alternative loot entry, which chooses one of its children.
|
|
#[derive(Clone, Debug)]
|
|
pub struct AlternativeEntry {
|
|
/// Child entries for this alternative.
|
|
pub children: &'static [LootPoolEntry],
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct TagEntry {
|
|
pub name: &'static str,
|
|
pub expand: bool,
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct SequenceEntry {
|
|
pub children: &'static [LootPoolEntry],
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct GroupEntry {
|
|
pub children: &'static [LootPoolEntry],
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct LootTableEntry {
|
|
pub value: &'static str,
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct DynamicEntry {
|
|
pub name: &'static str,
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub enum LootPoolEntryTypes {
|
|
Empty,
|
|
Item(ItemEntry),
|
|
LootTable(LootTableEntry),
|
|
Dynamic(DynamicEntry),
|
|
Tag(TagEntry),
|
|
Alternatives(AlternativeEntry),
|
|
Sequence(SequenceEntry),
|
|
Group(GroupEntry),
|
|
}
|
|
|
|
/// Conditions that can modify whether loot entries are applied.
|
|
#[derive(Clone, PartialEq, Debug)]
|
|
pub enum LootCondition {
|
|
/// Inverts the result of another condition.
|
|
Inverted(&'static Self),
|
|
/// Passes if any of the given conditions are met.
|
|
AnyOf(&'static [Self]),
|
|
/// Passes only if all the given conditions are met.
|
|
AllOf(&'static [Self]),
|
|
/// Passes based on a random chance.
|
|
RandomChance { chance: f32 },
|
|
/// Passes based on a random chance modified by item enchantments.
|
|
RandomChanceWithEnchantedBonus {
|
|
enchantment: &'static str,
|
|
chances: Option<&'static [f32]>,
|
|
},
|
|
/// Checks properties of the entity (e.g. type, flags, equipment).
|
|
/// Mirrors vanilla `LootItemEntityPropertyCondition`.
|
|
EntityProperties {
|
|
/// The entity target to check: "this", "attacker", or "`direct_attacker`".
|
|
entity: &'static str,
|
|
/// Expected entity type (e.g. "minecraft:cow").
|
|
expected_type: Option<&'static str>,
|
|
/// When `Some`, the entity must be on fire for the condition to pass.
|
|
/// Mirrors vanilla `EntityFlagsPredicate.isOnFire`.
|
|
is_on_fire: Option<bool>,
|
|
/// When `Some`, the entity's mainhand item must have an enchantment in this tag.
|
|
/// Mirrors vanilla `EntityEquipmentPredicate.mainhand` with enchantment tag lookup.
|
|
mainhand_enchantment_tag: Option<&'static str>,
|
|
},
|
|
/// Requires the entity to have been killed by a player.
|
|
KilledByPlayer,
|
|
/// Checks entity scores against specified criteria.
|
|
EntityScores { entity: &'static str },
|
|
/// Checks block state properties.
|
|
BlockStateProperty {
|
|
/// The block to check.
|
|
block: &'static str,
|
|
/// Key-value pairs of properties and their expected values.
|
|
properties: &'static [(&'static str, &'static str)],
|
|
},
|
|
/// Requires a specific tool to match certain criteria.
|
|
MatchTool {
|
|
items: Option<&'static [&'static str]>,
|
|
},
|
|
/// Applies a bonus based on a table.
|
|
TableBonus {
|
|
enchantment: &'static str,
|
|
chances: &'static [f32],
|
|
},
|
|
/// Survives explosion damage.
|
|
SurvivesExplosion,
|
|
/// Checks properties of the damage source.
|
|
DamageSourceProperties {
|
|
expected_source_type: Option<&'static str>,
|
|
expected_direct_type: Option<&'static str>,
|
|
},
|
|
/// Checks the location of the entity.
|
|
LocationCheck {
|
|
offset_x: i32,
|
|
offset_y: i32,
|
|
offset_z: i32,
|
|
expected_biome: Option<&'static str>,
|
|
},
|
|
/// Checks weather conditions.
|
|
WeatherCheck {
|
|
raining: Option<bool>,
|
|
thundering: Option<bool>,
|
|
},
|
|
/// References to another condition or table.
|
|
Reference { name: &'static str },
|
|
/// Checks the in-game time.
|
|
TimeCheck {
|
|
range: (Option<f32>, Option<f32>),
|
|
period: Option<u64>,
|
|
},
|
|
/// Checks against a specific value or range.
|
|
ValueCheck {
|
|
value: LootNumberProviderTypes,
|
|
range: (Option<f32>, Option<f32>),
|
|
},
|
|
/// Checks if a specific enchantment is active.
|
|
EnchantmentActiveCheck { active: bool },
|
|
}
|
|
|
|
/// Functions applied to loot entries.
|
|
#[derive(Clone, PartialEq, Debug)]
|
|
pub struct LootFunction {
|
|
/// The type of function to apply.
|
|
pub content: LootFunctionTypes,
|
|
/// Optional conditions for the function.
|
|
pub conditions: Option<&'static [LootCondition]>,
|
|
}
|
|
|
|
/// Specific types of loot functions.
|
|
#[derive(Clone, PartialEq, Debug)]
|
|
pub enum LootFunctionTypes {
|
|
/// Sets the number of items in the stack, optionally adding to an existing count.
|
|
SetCount {
|
|
count: LootFunctionNumberProvider,
|
|
add: bool,
|
|
},
|
|
/// Increases the count of items based on the item's enchantments.
|
|
EnchantedCountIncrease {
|
|
enchantment: &'static str,
|
|
count: LootFunctionNumberProvider,
|
|
limit: Option<f32>,
|
|
},
|
|
/// Smelts the item as if it passed through a furnace.
|
|
FurnaceSmelt,
|
|
/// Sets the potion type for potion items.
|
|
SetPotion { id: &'static str },
|
|
/// Sets the amplifier for ominous bottles.
|
|
SetOminousBottleAmplifier,
|
|
/// Limits the count of items to a minimum and/or maximum value.
|
|
LimitCount { min: Option<f32>, max: Option<f32> },
|
|
/// Applies a bonus based on an enchantment and a formula, optionally with extra parameters.
|
|
ApplyBonus {
|
|
enchantment: &'static str,
|
|
formula: &'static str,
|
|
parameters: Option<LootFunctionBonusParameter>,
|
|
},
|
|
/// Copies specified components from a source entity or item.
|
|
CopyComponents {
|
|
source: &'static str,
|
|
include: &'static [&'static str],
|
|
},
|
|
/// Copies state or properties from a block.
|
|
CopyState {
|
|
block: &'static str,
|
|
properties: &'static [&'static str],
|
|
},
|
|
/// Applies decay to items in case of an explosion.
|
|
ExplosionDecay,
|
|
}
|
|
|
|
/// Numeric providers for loot function counts.
|
|
#[derive(Clone, PartialEq, Debug)]
|
|
pub enum LootFunctionNumberProvider {
|
|
/// Constant value.
|
|
Constant { value: f32 },
|
|
/// Uniform random value between min and max.
|
|
Uniform { min: f32, max: f32 },
|
|
/// Binomial distribution.
|
|
Binomial { n: f32, p: f32 },
|
|
}
|
|
|
|
/// Parameters for loot bonus functions.
|
|
#[derive(Clone, PartialEq, Debug)]
|
|
pub enum LootFunctionBonusParameter {
|
|
/// Multiplier applied to bonus rolls.
|
|
Multiplier { bonus_multiplier: i32 },
|
|
/// Probability-based bonus application.
|
|
Probability { extra: i32, probability: f32 },
|
|
}
|
|
|
|
/// Single entry in a loot pool with optional conditions and functions.
|
|
#[derive(Clone, Debug)]
|
|
pub struct LootPoolEntry {
|
|
/// The type of entry.
|
|
pub content: LootPoolEntryTypes,
|
|
/// Relative probability weight; higher values are more likely.
|
|
pub weight: i32,
|
|
/// Quality of the entry, used to modify weight based on luck.
|
|
pub quality: i32,
|
|
/// Optional conditions for this entry.
|
|
pub conditions: Option<&'static [LootCondition]>,
|
|
/// Optional functions for this entry.
|
|
pub functions: Option<&'static [LootFunction]>,
|
|
}
|
|
|
|
/// Categories of loot tables.
|
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
|
pub enum LootTableType {
|
|
/// Empty loot table.
|
|
Empty,
|
|
/// Entity loot table.
|
|
Entity,
|
|
/// Block loot table.
|
|
Block,
|
|
/// Chest loot table.
|
|
Chest,
|
|
}
|
|
|
|
/// Represents structured number providers used in loot rolls.
|
|
#[derive(Deserialize, PartialEq, Clone, Copy, Debug)]
|
|
#[serde(tag = "type")]
|
|
pub enum LootNumberProviderTypesProvider {
|
|
/// Uniformly distributes a random number between `min` and `max` (inclusive).
|
|
#[serde(rename = "minecraft:uniform")]
|
|
Uniform(UniformLootNumberProvider),
|
|
}
|
|
|
|
#[cfg(feature = "codegen")]
|
|
impl ToTokens for LootNumberProviderTypesProvider {
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
match self {
|
|
Self::Uniform(uniform) => {
|
|
tokens.extend(quote! {
|
|
LootNumberProviderTypesProvider::Uniform(#uniform)
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Uniform numeric provider for loot rolls.
|
|
#[derive(Deserialize, PartialEq, Clone, Copy, Debug)]
|
|
pub struct UniformLootNumberProvider {
|
|
/// Minimum value (inclusive).
|
|
pub min: f32,
|
|
/// Maximum value (inclusive).
|
|
pub max: f32,
|
|
}
|
|
|
|
#[cfg(feature = "codegen")]
|
|
impl ToTokens for UniformLootNumberProvider {
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
let min_inclusive = self.min;
|
|
let max_inclusive = self.max;
|
|
|
|
tokens.extend(quote! {
|
|
UniformLootNumberProvider { min: #min_inclusive, max: #max_inclusive }
|
|
});
|
|
}
|
|
}
|
|
|
|
impl UniformLootNumberProvider {
|
|
/// Generates a random number within the uniform range.
|
|
///
|
|
/// # Parameters
|
|
/// - `random`: A random number generator implementing `RandomImpl`.
|
|
///
|
|
/// # Returns
|
|
/// A `f32` between `min` and `max`.
|
|
pub fn get(&self, random: &mut impl RandomImpl) -> f32 {
|
|
random.next_f32().mul_add(self.max - self.min, self.min)
|
|
}
|
|
}
|
|
|
|
/// Numeric providers for loot table rolls (either object or constant).
|
|
#[derive(Deserialize, PartialEq, Clone, Copy, Debug)]
|
|
#[serde(untagged)]
|
|
pub enum LootNumberProviderTypes {
|
|
/// A structured provider object (e.g., uniform).
|
|
Object(LootNumberProviderTypesProvider),
|
|
/// Constant numeric value.
|
|
Constant(f32),
|
|
}
|
|
|
|
#[cfg(feature = "codegen")]
|
|
impl ToTokens for LootNumberProviderTypes {
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
match self {
|
|
Self::Object(provider) => {
|
|
tokens.extend(quote! {
|
|
LootNumberProviderTypes::Object(#provider)
|
|
});
|
|
}
|
|
Self::Constant(i) => tokens.extend(quote! {
|
|
LootNumberProviderTypes::Constant(#i)
|
|
}),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl LootNumberProviderTypes {
|
|
/// Computes a numeric value from this provider.
|
|
///
|
|
/// # Parameters
|
|
/// - `random`: A random number generator implementing `RandomImpl`.
|
|
///
|
|
/// # Returns
|
|
/// A `f32` value as determined by the provider (constant or computed).
|
|
pub fn get(&self, random: &mut impl RandomImpl) -> f32 {
|
|
match self {
|
|
Self::Object(int_provider) => match int_provider {
|
|
LootNumberProviderTypesProvider::Uniform(uniform) => uniform.get(random),
|
|
},
|
|
Self::Constant(i) => *i,
|
|
}
|
|
}
|
|
}
|