use yog_data::Schema;
use yog_data::Ordered;
use yog_data::with::{Opt, RefTo};
pub use yog_registry::{ArmorMaterial, SoundGroup, ToolMaterial};
yog_data::kind! {
LadderKind = "ladder",
LevelKind = "level",
SoundGroupKind = "sound_group",
ToolMaterialKind = "tool_material",
ArmorMaterialKind = "armor_material",
}
#[derive(Schema, Debug, Clone)]
#[data(tag = "kind")]
pub enum Def {
Ladder { id: String },
Level {
id: String,
#[data(with = "RefTo<LadderKind>")]
ladder: String,
#[data(with = "Opt<RefTo<LevelKind>>")]
above: Option<String>,
},
SoundGroup(SoundGroup),
RecipeKind(RecipeKindDef),
ToolMaterial(ToolMaterialDef),
ArmorMaterial(ArmorMaterialDef),
Ore(OreDef),
Dimension(DimensionDef),
Table(TableDef),
Tag(TagDef),
DamageType(DamageTypeDef),
Tree(TreeDef),
}
#[derive(Schema, Debug, Clone)]
pub struct TreeDef {
pub id: String,
pub trunk: TreeTrunk,
pub leaves: TreeLeaves,
pub dirt: Option<yog_data::BlockId>,
pub min_clipped_height: Option<u32>,
#[data(default)]
pub ignore_vines: bool,
#[data(default)]
pub force_dirt: bool,
}
#[derive(Schema, Debug, Clone)]
pub struct TreeTrunk {
pub blocks: Vec<WeightedBlock>,
pub shape: String,
pub base_height: u32,
#[data(default)]
pub random_a: u32,
#[data(default)]
pub random_b: u32,
}
#[derive(Schema, Debug, Clone)]
pub struct TreeLeaves {
pub blocks: Vec<WeightedBlock>,
pub shape: String,
pub radius: u32,
#[data(default)]
pub offset: i32,
pub height: Option<u32>,
}
#[derive(Schema, Debug, Clone)]
pub struct WeightedBlock {
pub block: yog_data::BlockId,
#[data(default = "one")]
pub weight: u32,
}
#[derive(Schema, Debug, Clone)]
pub struct TagDef {
pub of: String,
pub id: String,
#[data(default)]
pub values: Vec<yog_data::AnyRefOrTag>,
#[data(default)]
pub optional: Vec<yog_data::AnyRefOrTag>,
}
fn scaled_by_mobs() -> String {
"when_caused_by_living_non_player".into()
}
#[derive(Schema, Debug, Clone)]
pub struct DamageTypeDef {
pub id: String,
#[data(default = "scaled_by_mobs")]
pub scaling: String,
#[data(default)]
pub exhaustion: f32,
pub message_id: Option<String>,
pub effects: Option<String>,
pub death_message_type: Option<String>,
#[data(default)]
pub tags: Vec<String>,
}
#[derive(Schema, Debug, Clone)]
pub struct TableDef {
pub id: String,
pub columns: Ordered<String>,
pub rows: Ordered<yog_data::Value>,
#[data(default)]
pub serde: bool,
}
#[derive(Schema, Debug, Clone)]
pub struct DimensionDef {
pub id: String,
#[data(default)]
pub dimension_type: DimensionTypeProps,
pub biome: Option<yog_data::Id<yog_data::kinds::Biome>>,
#[data(default = "yes")]
pub structures: bool,
#[data(default = "yes")]
pub features: bool,
#[data(default = "yes")]
pub mob_spawning: bool,
pub terrain: Option<yog_worldgen::Terrain>,
pub generator: Option<String>,
}
fn yes() -> bool {
true
}
#[derive(Schema, Debug, Clone, Default)]
pub struct DimensionTypeProps {
pub min_y: Option<i32>,
pub height: Option<i32>,
pub logical_height: Option<i32>,
pub has_sky_light: Option<bool>,
pub has_ceiling: Option<bool>,
#[data(range = "0..=1")]
pub ambient_light: Option<f32>,
pub coordinate_scale: Option<f64>,
pub ultrawarm: Option<bool>,
pub natural: Option<bool>,
pub beds_explode: Option<bool>,
pub respawn_anchors_explode: Option<bool>,
pub piglin_safe: Option<bool>,
pub effects: Option<String>,
}
#[derive(Schema, Debug, Clone)]
pub struct OreDef {
pub id: String,
pub targets: Vec<OreTarget>,
#[data(range = "1..=64")]
pub size: u32,
#[data(range = "0..=256")]
pub per_chunk: u32,
pub height: OreHeight,
#[data(default, range = "0..=1")]
pub air_exposure: f32,
pub biomes: Option<yog_data::TagId<yog_data::kinds::Biome>>,
}
#[derive(Schema, Debug, Clone)]
pub struct OreTarget {
#[data(with = "OreReplaces")]
pub replaces: String,
pub block: yog_data::BlockId,
}
#[derive(Schema, Debug, Clone)]
pub struct OreHeight {
pub min: i32,
pub max: i32,
#[data(default)]
pub shape: HeightShape,
}
#[derive(Schema, Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum HeightShape {
#[default]
Uniform,
Triangle,
}
pub struct OreReplaces;
pub const ORE_STONES: [(&str, &str); 4] = [
("stone", "#minecraft:stone_ore_replaceables"),
("deepslate", "#minecraft:deepslate_ore_replaceables"),
("netherrack", "minecraft:netherrack"),
("end_stone", "minecraft:end_stone"),
];
impl yog_data::with::With<String> for OreReplaces {
fn shape() -> yog_data::Shape {
yog_data::Shape::RefOrTag(&["block"])
}
fn read(v: &yog_data::ValueRef<'_>, cx: &mut yog_data::Reader) -> Option<String> {
use yog_data::ValueRef;
match v {
ValueRef::Str(s) if !s.starts_with('@') => ORE_STONES.iter().find(|(n, _)| n == s).map(|(_, t)| t.to_string()).or_else(|| {
let names: Vec<&str> = ORE_STONES.iter().map(|(n, _)| *n).collect();
cx.problem(format!("`{s}`: one of {} — or a tag of blocks (`@tag:block:…`) or a block (`@block:…`)", names.join(", ")));
None
}),
ValueRef::Tag { .. } => yog_data::TagId::<yog_data::kinds::Block>::read(v, cx).map(|t| format!("#{}", t.id)),
ValueRef::Str(s) if s.starts_with("@tag:") => yog_data::TagId::<yog_data::kinds::Block>::read(v, cx).map(|t| format!("#{}", t.id)),
_ => yog_data::with::RefTo::<yog_data::kinds::Block>::read(v, cx),
}
}
fn write(f: &String) -> yog_data::Value {
if let Some((n, _)) = ORE_STONES.iter().find(|(_, t)| t == f) {
return yog_data::Value::from(*n);
}
match f.strip_prefix('#') {
Some(t) => yog_data::Value::Tag(yog_data::Ref::new("block", t)),
None => yog_data::Value::Ref(yog_data::Ref::new("block", f.clone())),
}
}
}
#[derive(Schema, Debug, Clone)]
pub struct ToolMaterialDef {
pub id: String,
#[data(range = "1..=1000000")]
pub durability: u32,
pub speed: f32,
pub attack_damage: f32,
#[data(range = "0..=1000")]
pub enchantability: u32,
#[data(with = "crate::content::LevelRef")]
pub level: String,
pub repair: yog_data::ItemIdOrTag,
}
#[derive(Schema, Debug, Clone)]
pub struct ArmorMaterialDef {
pub id: String,
#[data(range = "1..=10000")]
pub durability: u32,
pub defense: yog_registry::ArmorDefense,
#[data(range = "0..=1000")]
pub enchantability: u32,
pub equip_sound: String,
#[data(default)]
pub toughness: f32,
#[data(default, range = "0..=1")]
pub knockback_resistance: f32,
pub repair: yog_data::ItemIdOrTag,
pub texture: Option<String>,
}
#[derive(Schema, Debug, Clone, PartialEq)]
pub struct SlotSpec {
#[data(default = "one", range = "1..=64")]
pub max: u32,
#[data(default)]
pub required: bool,
}
fn one() -> u32 {
1
}
#[derive(Schema, Debug, Clone, Copy, PartialEq, Eq)]
pub enum ValueType {
Number,
Text,
Bool,
}
#[derive(Schema, Debug, Clone, PartialEq)]
pub struct RecipeKindDef {
pub id: String,
#[data(default)]
pub slots: Ordered<SlotSpec>,
#[data(default)]
pub values: Ordered<ValueType>,
}
pub const TOOL_LADDER: &str = "minecraft:tool";
pub const TOOL_LEVELS: [&str; 5] = ["wood", "stone", "iron", "diamond", "netherite"];