From 2945d038c2b20606f2b9dd49109ad3a4efe6cb3f Mon Sep 17 00:00:00 2001 From: Kalle Struik Date: Sat, 5 Apr 2025 00:06:22 +0200 Subject: [PATCH] Items --- Cargo.lock | 46 ++- Cargo.toml | 9 +- README.md | 14 +- potato-data/Cargo.toml | 5 + potato-data/src/color.rs | 3 + potato-data/src/consume_effect.rs | 38 ++ potato-data/src/datapack.rs | 6 +- potato-data/src/identifier.rs | 32 +- potato-data/src/item_stack.rs | 12 +- potato-data/src/lib.rs | 3 + potato-data/src/predicate.rs | 8 + potato-data/src/registry/advancement.rs | 100 +++++ .../src/registry/item/component_map.rs | 73 ++++ .../item/components/attribute_modifiers.rs | 42 +++ .../item/components/axolotl_variant.rs | 8 + .../item/components/banner_patterns.rs | 14 + .../registry/item/components/base_color.rs | 6 + .../src/registry/item/components/bees.rs | 13 + .../item/components/block_entity_data.rs | 6 + .../registry/item/components/block_state.rs | 8 + .../item/components/blocks_attacks.rs | 50 +++ .../registry/item/components/break_sound.rs | 8 + .../item/components/bucket_entity_data.rs | 7 + .../item/components/bundle_contents.rs | 8 + .../src/registry/item/components/can_break.rs | 17 + .../registry/item/components/can_place_on.rs | 17 + .../registry/item/components/cat_collar.rs | 7 + .../registry/item/components/cat_variant.rs | 8 + .../item/components/charged_projectiles.rs | 8 + .../item/components/chicken_variant.rs | 8 + .../registry/item/components/consumable.rs | 52 +++ .../src/registry/item/components/container.rs | 14 + .../item/components/container_loot.rs | 16 + .../registry/item/components/cow_variant.rs | 8 + .../registry/item/components/custom_data.rs | 7 + .../item/components/custom_model_data.rs | 14 + .../registry/item/components/custom_name.rs | 8 + .../src/registry/item/components/damage.rs | 6 + .../item/components/damage_resistant.rs | 10 + .../item/components/death_protection.rs | 10 + .../item/components/debug_stick_state.rs | 10 + .../registry/item/components/dyed_color.rs | 9 + .../registry/item/components/enchantable.rs | 8 + .../components/enchantment_glint_override.rs | 6 + .../registry/item/components/enchantments.rs | 8 + .../registry/item/components/entity_data.rs | 6 + .../registry/item/components/equippable.rs | 45 +++ .../item/components/firework_explosion.rs | 24 ++ .../src/registry/item/components/fireworks.rs | 17 + .../src/registry/item/components/food.rs | 15 + .../registry/item/components/fox_variant.rs | 8 + .../registry/item/components/frog_variant.rs | 8 + .../src/registry/item/components/glider.rs | 6 + .../registry/item/components/horse_variant.rs | 8 + .../registry/item/components/instrument.rs | 21 ++ .../item/components/intangible_projectile.rs | 6 + .../registry/item/components/item_model.rs | 8 + .../src/registry/item/components/item_name.rs | 8 + .../item/components/jukebox_playable.rs | 8 + .../registry/item/components/llama_variant.rs | 8 + .../src/registry/item/components/lock.rs | 8 + .../item/components/lodestone_tracker.rs | 22 ++ .../src/registry/item/components/lore.rs | 8 + .../src/registry/item/components/map_color.rs | 8 + .../item/components/map_decorations.rs | 55 +++ .../src/registry/item/components/map_id.rs | 6 + .../registry/item/components/max_damage.rs | 6 + .../item/components/max_stack_size.rs | 7 + .../src/registry/item/components/mod.rs | 95 +++++ .../item/components/mooshroom_variant.rs | 8 + .../item/components/note_block_sound.rs | 8 + .../components/ominous_bottle_amplifier.rs | 7 + .../item/components/painting_variant.rs | 8 + .../item/components/parrot_variant.rs | 8 + .../registry/item/components/pig_variant.rs | 8 + .../item/components/pot_decorations.rs | 8 + .../item/components/potion_contents.rs | 15 + .../item/components/potion_duration_scale.rs | 10 + .../src/registry/item/components/profile.rs | 25 ++ .../components/provides_banner_patterns.rs | 8 + .../item/components/provides_trim_material.rs | 8 + .../item/components/rabbit_variant.rs | 8 + .../src/registry/item/components/rarity.rs | 12 + .../src/registry/item/components/recipes.rs | 8 + .../registry/item/components/repair_cost.rs | 10 + .../registry/item/components/repairable.rs | 10 + .../registry/item/components/salmon_size.rs | 11 + .../registry/item/components/sheep_color.rs | 7 + .../registry/item/components/shulker_color.rs | 7 + .../item/components/stored_enchantments.rs | 10 + .../components/suspicious_stew_effects.rs | 19 + .../src/registry/item/components/tool.rs | 40 ++ .../item/components/tooltip_display.rs | 12 + .../registry/item/components/tooltip_style.rs | 8 + .../src/registry/item/components/trim.rs | 11 + .../components/tropical_fish_base_color.rs | 7 + .../item/components/tropical_fish_pattern.rs | 20 + .../components/tropical_fish_pattern_color.rs | 7 + .../registry/item/components/unbreakable.rs | 6 + .../registry/item/components/use_cooldown.rs | 11 + .../registry/item/components/use_remainder.rs | 8 + .../item/components/villager_variant.rs | 8 + .../src/registry/item/components/weapon.rs | 19 + .../registry/item/components/wolf_collar.rs | 9 + .../item/components/wolf_sound_variant.rs | 7 + .../registry/item/components/wolf_variant.rs | 8 + .../item/components/writable_book_content.rs | 17 + .../item/components/written_book_content.rs | 42 +++ potato-data/src/registry/item/mod.rs | 65 ++++ potato-data/src/registry/mod.rs | 66 +++- potato-data/src/status_effect.rs | 34 ++ potato-data/src/tag.rs | 2 +- potato-data/src/text_component.rs | 79 ++-- .../Cargo.toml | 4 +- potato-derive/src/lib.rs | 86 +++++ .../lib.rs => potato-derive/src/protocol.rs | 43 +-- potato-protocol/Cargo.toml | 7 +- potato-protocol/src/datatypes/bit_set.rs | 79 ++++ potato-protocol/src/datatypes/mod.rs | 1 + potato-protocol/src/datatypes/pack.rs | 2 +- .../src/packet/clientbound/disconnect.rs | 13 + .../clientbound/finish_configuration.rs | 2 +- .../src/packet/clientbound/game_event.rs | 2 +- .../src/packet/clientbound/keep_alive.rs | 2 +- .../clientbound/level_chunk_with_light.rs | 52 +++ .../src/packet/clientbound/login.rs | 2 +- .../packet/clientbound/login_disconnect.rs | 2 +- .../src/packet/clientbound/login_finished.rs | 2 +- potato-protocol/src/packet/clientbound/mod.rs | 7 + .../src/packet/clientbound/player_position.rs | 18 + .../src/packet/clientbound/pong_response.rs | 2 +- .../src/packet/clientbound/registry_data.rs | 2 +- .../packet/clientbound/select_known_packs.rs | 2 +- .../clientbound/set_chunk_cache_center.rs | 2 +- .../src/packet/clientbound/status_response.rs | 2 +- .../src/packet/clientbound/update_tags.rs | 42 +++ potato-protocol/src/packet/mod.rs | 1 + .../serverbound/accept_teleportation.rs | 9 + .../packet/serverbound/client_information.rs | 2 +- .../src/packet/serverbound/client_tick_end.rs | 2 +- .../src/packet/serverbound/custom_payload.rs | 2 +- .../serverbound/finish_configuration.rs | 2 +- .../src/packet/serverbound/hello.rs | 2 +- .../src/packet/serverbound/intention.rs | 2 +- .../src/packet/serverbound/keep_alive.rs | 2 +- .../packet/serverbound/login_acknowledged.rs | 2 +- potato-protocol/src/packet/serverbound/mod.rs | 2 + .../src/packet/serverbound/move_player_pos.rs | 2 +- .../packet/serverbound/move_player_pos_rot.rs | 2 +- .../src/packet/serverbound/move_player_rot.rs | 2 +- .../src/packet/serverbound/ping_request.rs | 2 +- .../packet/serverbound/select_known_packs.rs | 2 +- .../src/packet/serverbound/status_request.rs | 2 +- potato-protocol/src/packet_encodable/mod.rs | 9 +- potato/Cargo.toml | 1 + potato/src/connection.rs | 233 +++++++----- potato/src/main.rs | 108 ++++-- potato/src/player.rs | 2 - potato/src/player/mod.rs | 354 ++++++++++++++++++ potato/src/server.rs | 141 ++++++- potato/src/world.rs | 61 +++ scripts/create_item_datapack.py | 42 +++ 162 files changed, 2958 insertions(+), 299 deletions(-) create mode 100644 potato-data/src/consume_effect.rs create mode 100644 potato-data/src/predicate.rs create mode 100644 potato-data/src/registry/advancement.rs create mode 100644 potato-data/src/registry/item/component_map.rs create mode 100644 potato-data/src/registry/item/components/attribute_modifiers.rs create mode 100644 potato-data/src/registry/item/components/axolotl_variant.rs create mode 100644 potato-data/src/registry/item/components/banner_patterns.rs create mode 100644 potato-data/src/registry/item/components/base_color.rs create mode 100644 potato-data/src/registry/item/components/bees.rs create mode 100644 potato-data/src/registry/item/components/block_entity_data.rs create mode 100644 potato-data/src/registry/item/components/block_state.rs create mode 100644 potato-data/src/registry/item/components/blocks_attacks.rs create mode 100644 potato-data/src/registry/item/components/break_sound.rs create mode 100644 potato-data/src/registry/item/components/bucket_entity_data.rs create mode 100644 potato-data/src/registry/item/components/bundle_contents.rs create mode 100644 potato-data/src/registry/item/components/can_break.rs create mode 100644 potato-data/src/registry/item/components/can_place_on.rs create mode 100644 potato-data/src/registry/item/components/cat_collar.rs create mode 100644 potato-data/src/registry/item/components/cat_variant.rs create mode 100644 potato-data/src/registry/item/components/charged_projectiles.rs create mode 100644 potato-data/src/registry/item/components/chicken_variant.rs create mode 100644 potato-data/src/registry/item/components/consumable.rs create mode 100644 potato-data/src/registry/item/components/container.rs create mode 100644 potato-data/src/registry/item/components/container_loot.rs create mode 100644 potato-data/src/registry/item/components/cow_variant.rs create mode 100644 potato-data/src/registry/item/components/custom_data.rs create mode 100644 potato-data/src/registry/item/components/custom_model_data.rs create mode 100644 potato-data/src/registry/item/components/custom_name.rs create mode 100644 potato-data/src/registry/item/components/damage.rs create mode 100644 potato-data/src/registry/item/components/damage_resistant.rs create mode 100644 potato-data/src/registry/item/components/death_protection.rs create mode 100644 potato-data/src/registry/item/components/debug_stick_state.rs create mode 100644 potato-data/src/registry/item/components/dyed_color.rs create mode 100644 potato-data/src/registry/item/components/enchantable.rs create mode 100644 potato-data/src/registry/item/components/enchantment_glint_override.rs create mode 100644 potato-data/src/registry/item/components/enchantments.rs create mode 100644 potato-data/src/registry/item/components/entity_data.rs create mode 100644 potato-data/src/registry/item/components/equippable.rs create mode 100644 potato-data/src/registry/item/components/firework_explosion.rs create mode 100644 potato-data/src/registry/item/components/fireworks.rs create mode 100644 potato-data/src/registry/item/components/food.rs create mode 100644 potato-data/src/registry/item/components/fox_variant.rs create mode 100644 potato-data/src/registry/item/components/frog_variant.rs create mode 100644 potato-data/src/registry/item/components/glider.rs create mode 100644 potato-data/src/registry/item/components/horse_variant.rs create mode 100644 potato-data/src/registry/item/components/instrument.rs create mode 100644 potato-data/src/registry/item/components/intangible_projectile.rs create mode 100644 potato-data/src/registry/item/components/item_model.rs create mode 100644 potato-data/src/registry/item/components/item_name.rs create mode 100644 potato-data/src/registry/item/components/jukebox_playable.rs create mode 100644 potato-data/src/registry/item/components/llama_variant.rs create mode 100644 potato-data/src/registry/item/components/lock.rs create mode 100644 potato-data/src/registry/item/components/lodestone_tracker.rs create mode 100644 potato-data/src/registry/item/components/lore.rs create mode 100644 potato-data/src/registry/item/components/map_color.rs create mode 100644 potato-data/src/registry/item/components/map_decorations.rs create mode 100644 potato-data/src/registry/item/components/map_id.rs create mode 100644 potato-data/src/registry/item/components/max_damage.rs create mode 100644 potato-data/src/registry/item/components/max_stack_size.rs create mode 100644 potato-data/src/registry/item/components/mod.rs create mode 100644 potato-data/src/registry/item/components/mooshroom_variant.rs create mode 100644 potato-data/src/registry/item/components/note_block_sound.rs create mode 100644 potato-data/src/registry/item/components/ominous_bottle_amplifier.rs create mode 100644 potato-data/src/registry/item/components/painting_variant.rs create mode 100644 potato-data/src/registry/item/components/parrot_variant.rs create mode 100644 potato-data/src/registry/item/components/pig_variant.rs create mode 100644 potato-data/src/registry/item/components/pot_decorations.rs create mode 100644 potato-data/src/registry/item/components/potion_contents.rs create mode 100644 potato-data/src/registry/item/components/potion_duration_scale.rs create mode 100644 potato-data/src/registry/item/components/profile.rs create mode 100644 potato-data/src/registry/item/components/provides_banner_patterns.rs create mode 100644 potato-data/src/registry/item/components/provides_trim_material.rs create mode 100644 potato-data/src/registry/item/components/rabbit_variant.rs create mode 100644 potato-data/src/registry/item/components/rarity.rs create mode 100644 potato-data/src/registry/item/components/recipes.rs create mode 100644 potato-data/src/registry/item/components/repair_cost.rs create mode 100644 potato-data/src/registry/item/components/repairable.rs create mode 100644 potato-data/src/registry/item/components/salmon_size.rs create mode 100644 potato-data/src/registry/item/components/sheep_color.rs create mode 100644 potato-data/src/registry/item/components/shulker_color.rs create mode 100644 potato-data/src/registry/item/components/stored_enchantments.rs create mode 100644 potato-data/src/registry/item/components/suspicious_stew_effects.rs create mode 100644 potato-data/src/registry/item/components/tool.rs create mode 100644 potato-data/src/registry/item/components/tooltip_display.rs create mode 100644 potato-data/src/registry/item/components/tooltip_style.rs create mode 100644 potato-data/src/registry/item/components/trim.rs create mode 100644 potato-data/src/registry/item/components/tropical_fish_base_color.rs create mode 100644 potato-data/src/registry/item/components/tropical_fish_pattern.rs create mode 100644 potato-data/src/registry/item/components/tropical_fish_pattern_color.rs create mode 100644 potato-data/src/registry/item/components/unbreakable.rs create mode 100644 potato-data/src/registry/item/components/use_cooldown.rs create mode 100644 potato-data/src/registry/item/components/use_remainder.rs create mode 100644 potato-data/src/registry/item/components/villager_variant.rs create mode 100644 potato-data/src/registry/item/components/weapon.rs create mode 100644 potato-data/src/registry/item/components/wolf_collar.rs create mode 100644 potato-data/src/registry/item/components/wolf_sound_variant.rs create mode 100644 potato-data/src/registry/item/components/wolf_variant.rs create mode 100644 potato-data/src/registry/item/components/writable_book_content.rs create mode 100644 potato-data/src/registry/item/components/written_book_content.rs create mode 100644 potato-data/src/registry/item/mod.rs create mode 100644 potato-data/src/status_effect.rs rename {potato-protocol-derive => potato-derive}/Cargo.toml (66%) create mode 100644 potato-derive/src/lib.rs rename potato-protocol-derive/src/lib.rs => potato-derive/src/protocol.rs (80%) create mode 100644 potato-protocol/src/datatypes/bit_set.rs create mode 100644 potato-protocol/src/packet/clientbound/disconnect.rs create mode 100644 potato-protocol/src/packet/clientbound/level_chunk_with_light.rs create mode 100644 potato-protocol/src/packet/clientbound/player_position.rs create mode 100644 potato-protocol/src/packet/clientbound/update_tags.rs create mode 100644 potato-protocol/src/packet/serverbound/accept_teleportation.rs delete mode 100644 potato/src/player.rs create mode 100644 potato/src/player/mod.rs create mode 100644 potato/src/world.rs create mode 100644 scripts/create_item_datapack.py diff --git a/Cargo.lock b/Cargo.lock index 2123afa..bbf2262 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -103,6 +103,16 @@ dependencies = [ "syn", ] +[[package]] +name = "erased-serde" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e004d887f51fcb9fef17317a2f3525c887d8aa3f4f50fed920816a688284a5b7" +dependencies = [ + "serde", + "typeid", +] + [[package]] name = "fastnbt" version = "2.5.0" @@ -223,6 +233,7 @@ name = "potato" version = "0.1.0" dependencies = [ "bytes", + "fastnbt", "potato-data", "potato-protocol", "serde", @@ -236,9 +247,23 @@ dependencies = [ name = "potato-data" version = "0.1.0" dependencies = [ + "erased-serde", + "fastnbt", + "potato-derive", "serde", "serde_json", "thiserror", + "uuid", +] + +[[package]] +name = "potato-derive" +version = "0.1.0" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -249,7 +274,7 @@ dependencies = [ "bytes", "fastnbt", "potato-data", - "potato-protocol-derive", + "potato-derive", "serde", "serde_json", "thiserror", @@ -257,16 +282,6 @@ dependencies = [ "uuid", ] -[[package]] -name = "potato-protocol-derive" -version = "0.1.0" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "proc-macro2" version = "1.0.94" @@ -444,6 +459,12 @@ dependencies = [ "syn", ] +[[package]] +name = "typeid" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" + [[package]] name = "unicode-ident" version = "1.0.18" @@ -455,6 +476,9 @@ name = "uuid" version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0f540e3240398cce6128b64ba83fdbdd86129c16a3aa1a3a252efd66eb3d587" +dependencies = [ + "serde", +] [[package]] name = "wasi" diff --git a/Cargo.toml b/Cargo.toml index 484f6df..c97df5d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace] resolver = "2" -members = ["potato", "potato-data", "potato-protocol", "potato-protocol-derive"] +members = ["potato", "potato-data", "potato-protocol", "potato-derive"] [workspace.package] version = "0.1.0" @@ -10,6 +10,11 @@ edition = "2024" serde = { version = "1.0.218", features = ["derive"] } serde_json = "1.0.140" thiserror = "2.0.11" -uuid = "1.15.1" +uuid = { version = "1.15.1", features = ["serde"] } bytes = "1" tokio = { version = "1.43.0", features = ["full"] } + +# Build from git, since there has not been a release in over a year +# Original repo: https://github.com/owengage/fastnbt.git Using a fork +# to fix an issue with boolean serialization. +fastnbt = { git = "https://github.com/CheAle14/fastnbt.git" } diff --git a/README.md b/README.md index 270c80c..a9192af 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ N/A = Not applicable | advancement | ❌ | ❌ | ❌ | ❌ | | banner_pattern | ✅ | ✅ | ❌ | ❌ | | chat_type | ✅ | ❌ | ❌ | ❌ | -| damage_type | ✅ | ✅ | ❌ | ❌ | +| damage_type | ✅ | ✅ | ❌ | ❌ | | dimension | ❌ | ❌ | ❌ | ❌ | | dimension_type | ✅ | ✅ | ❌ | ❌ | | enchantment | ❌ | ❌ | ❌ | ❌ | @@ -44,9 +44,9 @@ N/A = Not applicable | worldgen/world_preset | ❌ | ❌ | ❌ | ❌ | | worldgen/flat_level_generator_preset | ❌ | ❌ | ❌ | ❌ | | worldgen/multi_noise_biome_source_parameter_list | ❌ | ❌ | ❌ | ❌ | - - - - - - +| cat_variant | ❌ | ❌ | ❌ | ❌ | +| cow_variant | ❌ | ❌ | ❌ | ❌ | +| frog_variant | ❌ | ❌ | ❌ | ❌ | +| pig_variant | ❌ | ❌ | ❌ | ❌ | +| test_environment | ❌ | ❌ | ❌ | ❌ | +| test_instance | ❌ | ❌ | ❌ | ❌ | diff --git a/potato-data/Cargo.toml b/potato-data/Cargo.toml index 6351032..d79c3f9 100644 --- a/potato-data/Cargo.toml +++ b/potato-data/Cargo.toml @@ -4,6 +4,11 @@ version.workspace = true edition.workspace = true [dependencies] +potato-derive = { path = "../potato-derive" } + serde.workspace = true serde_json.workspace = true thiserror.workspace = true +fastnbt.workspace = true +uuid.workspace = true +erased-serde = "0.4.6" diff --git a/potato-data/src/color.rs b/potato-data/src/color.rs index dad2d89..c0168b5 100644 --- a/potato-data/src/color.rs +++ b/potato-data/src/color.rs @@ -1,5 +1,8 @@ use serde::{Deserialize, Serialize}; +#[derive(Debug, Clone, Copy, Serialize, Deserialize)] +pub struct Color(i32); + // TODO: Serialize as array of [red, green, blue] in NBT #[derive(Debug, Clone, Copy, Serialize, Deserialize)] pub struct RGBf32 { diff --git a/potato-data/src/consume_effect.rs b/potato-data/src/consume_effect.rs new file mode 100644 index 0000000..c2b5f1e --- /dev/null +++ b/potato-data/src/consume_effect.rs @@ -0,0 +1,38 @@ +use serde::{Deserialize, Serialize}; + +use crate::{ + Either, OneOrMany, identifier::Identifier, registry::worldgen::biome::SoundEvent, + status_effect::StatusEffect, +}; + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(tag = "type", rename_all = "snake_case")] +pub enum ConsumeEffect { + #[serde(alias = "minecraft:apply_effects")] + ApplyEffects { + effects: Vec, + #[serde(default = "one")] + probability: f32, + }, + #[serde(alias = "minecraft:remove_effects")] + RemoveEffects { effects: OneOrMany }, + #[serde(alias = "minecraft:clear_all_effects")] + ClearAllEffects, + #[serde(alias = "minecraft:teleport_randomly")] + TeleportRandomly { + #[serde(default = "sixteen")] + diameter: f32, + }, + #[serde(alias = "minecraft:play_sound")] + PlaySound { + sound: Either, + }, +} + +fn one() -> f32 { + 1.0 +} + +fn sixteen() -> f32 { + 16.0 +} diff --git a/potato-data/src/datapack.rs b/potato-data/src/datapack.rs index 83ffc58..8a489c9 100644 --- a/potato-data/src/datapack.rs +++ b/potato-data/src/datapack.rs @@ -35,6 +35,8 @@ impl Datapack { self.load_registry(&mut registries.painting_variants, "painting_variant")?; self.load_registry(&mut registries.chat_types, "chat_type")?; + self.load_registry(&mut registries.items, "item")?; + Ok(()) } @@ -60,13 +62,12 @@ impl Datapack { let path = namespace.join(path); let files = std::fs::read_dir(path)?; for file in files { - println!("Loading file: {:?}", file); let file = file?.path(); let name = file .file_stem() .and_then(OsStr::to_str) .ok_or(DatapackError::Utf8)?; - let identfiier = Identifier::new_str(namespace_str, name); + let identfiier = Identifier::new(namespace_str.to_owned(), name.to_owned()); let data: T = serde_json::from_str(&read_to_string(file)?)?; @@ -75,6 +76,7 @@ impl Datapack { } self.load_registry_tags(registry, path)?; + registry.flatten_tags(); Ok(()) } diff --git a/potato-data/src/identifier.rs b/potato-data/src/identifier.rs index 1542c41..4a447f2 100644 --- a/potato-data/src/identifier.rs +++ b/potato-data/src/identifier.rs @@ -1,4 +1,4 @@ -use std::fmt; +use std::{borrow::Cow, fmt}; use serde::{Deserialize, Serialize}; use thiserror::Error; @@ -7,26 +7,36 @@ use thiserror::Error; #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(try_from = "&str", into = "String")] pub struct Identifier { - pub namespace: String, - pub path: String, + pub namespace: Cow<'static, str>, + pub path: Cow<'static, str>, } impl Identifier { - pub fn new(namespace: String, path: String) -> Self { + pub const fn new_const(namespace: &'static str, path: &'static str) -> Self { // TODO: Validate namespace and path - Self { namespace, path } + Self { + namespace: Cow::Borrowed(namespace), + path: Cow::Borrowed(path), + } } - pub fn minecraft(path: String) -> Self { - Self::new("minecraft".to_string(), path) + pub fn new( + namespace: impl Into>, + path: impl Into>, + ) -> Self { + // TODO: Validate namespace and path + Self { + namespace: namespace.into(), + path: path.into(), + } } - pub fn new_str(namespace: &str, path: &str) -> Self { - Self::new(namespace.to_string(), path.to_string()) + pub const fn minecraft_const(path: &'static str) -> Self { + Self::new_const("minecraft", path) } - pub fn minecraft_str(path: &str) -> Self { - Self::minecraft(path.to_string()) + pub fn minecraft(path: impl Into>) -> Self { + Self::new("minecraft", path) } pub fn from_raw_str(raw: &str) -> Result { diff --git a/potato-data/src/item_stack.rs b/potato-data/src/item_stack.rs index a19e054..2fb3ac7 100644 --- a/potato-data/src/item_stack.rs +++ b/potato-data/src/item_stack.rs @@ -1,12 +1,12 @@ use serde::{Deserialize, Serialize}; -use crate::identifier::Identifier; +use crate::{identifier::Identifier, registry::item::component_map::ItemComponentMap}; #[derive(Debug, Serialize, Deserialize, Clone)] pub struct ItemStack { - id: Identifier, - components: Vec, + // TODO: Might need a default 1 on this + pub count: i32, + pub id: Identifier, + #[serde(default)] + pub components: ItemComponentMap, } - -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] -pub enum ItemComponent {} diff --git a/potato-data/src/lib.rs b/potato-data/src/lib.rs index efc66bb..fa38ba2 100644 --- a/potato-data/src/lib.rs +++ b/potato-data/src/lib.rs @@ -4,11 +4,14 @@ use tag::Tag; pub mod block_state; pub mod color; +pub mod consume_effect; pub mod datapack; pub mod identifier; pub mod item_stack; pub mod particle; +pub mod predicate; pub mod registry; +pub mod status_effect; pub mod tag; pub mod text_component; diff --git a/potato-data/src/predicate.rs b/potato-data/src/predicate.rs new file mode 100644 index 0000000..c31c282 --- /dev/null +++ b/potato-data/src/predicate.rs @@ -0,0 +1,8 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone)] +// TODO: Add the actual predicate data. +pub struct Predicate {} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct ItemPredicate {} diff --git a/potato-data/src/registry/advancement.rs b/potato-data/src/registry/advancement.rs new file mode 100644 index 0000000..deffc33 --- /dev/null +++ b/potato-data/src/registry/advancement.rs @@ -0,0 +1,100 @@ +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; + +use crate::{ + Either, OneOrMany, identifier::Identifier, predicate::Predicate, text_component::TextComponent, +}; + +use super::item::component_map::ItemComponentMap; + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct Advancement { + pub parent: Identifier, + pub display: AdvancementDisplay, + pub criteria: HashMap, + pub requirements: Vec>, + pub rewards: Option, + #[serde(default = "r#false")] + pub sends_telemetry_event: bool, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct AdvancementDisplay { + pub icon: AdvancementIcon, + pub title: TextComponent, + pub description: TextComponent, + #[serde(default)] + pub frame: AdvancementFrame, + // TODO: This is a bit weird. Its basically an identifier followed by .png + pub background: Option, + #[serde(default = "r#true")] + pub show_test: bool, + #[serde(default = "r#true")] + pub announce_to_chat: bool, + #[serde(default = "r#false")] + pub hidden: bool, +} + +fn r#true() -> bool { + true +} + +fn r#false() -> bool { + false +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct AdvancementIcon { + pub id: Identifier, + pub count: Option, + pub components: ItemComponentMap, +} + +#[derive(Debug, Serialize, Deserialize, Clone, Default)] +#[serde(rename_all = "snake_case")] +pub enum AdvancementFrame { + Challenge, + Goal, + #[default] + Task, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct AdvancementCriterion { + conditions: AdvancementConditions, + #[serde(flatten)] + trigger: AdvancementTrigger, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct AdvancementConditions { + pub player: Either>, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct AdvancementRewards { + pub experience: Option, + pub recipes: Option>, + pub function: Option, +} + +// NOTE: Predicates and advancements in general are way more complex then I expected. +// Need to figure out how they actually work before I can really do this. +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(tag = "trigger", content = "conditions", rename_all = "snake_case")] +pub enum AdvancementTrigger { + #[serde(rename = "minecraft:allay_drop_item_on_block")] + AllayDropItemOnBlock { location: Vec }, + #[serde(rename = "minecraft:any_block_use")] + AnyBlockUse { location: Vec }, + #[serde(rename = "minecraft:avoid_vibration")] + AvoidVibration, + // TODO: Finish this + // #[serde(rename = "minecraft:bee_nest_destroyed")] + // BeeNestDestroyed { block: Identifier, item: }, +} + +// TODO: Is this just a predicate? +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct EntityAdvancementCondition {} diff --git a/potato-data/src/registry/item/component_map.rs b/potato-data/src/registry/item/component_map.rs new file mode 100644 index 0000000..dec9648 --- /dev/null +++ b/potato-data/src/registry/item/component_map.rs @@ -0,0 +1,73 @@ +use std::{any::TypeId, collections::HashMap}; + +use serde::{ + de::{Error, MapAccess, Visitor}, + ser::SerializeMap, +}; + +use crate::{identifier::Identifier, registry::STATIC_REGISTRIES}; + +use super::ItemComponent; + +#[derive(Debug, Clone, Default)] +pub struct ItemComponentMap(HashMap>); + +impl serde::Serialize for ItemComponentMap { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let inner_map = &self.0; + let mut map = serializer.serialize_map(Some(inner_map.len()))?; + for v in inner_map.values() { + map.serialize_entry(&v.id(), v)?; + } + map.end() + } +} + +impl<'de> serde::Deserialize<'de> for ItemComponentMap { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + deserializer.deserialize_map(ItemComponentMapVisitor) + } +} + +struct ItemComponentMapVisitor; + +impl<'de> Visitor<'de> for ItemComponentMapVisitor { + type Value = ItemComponentMap; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("an item component map") + } + + fn visit_map(self, mut access: M) -> Result + where + M: MapAccess<'de>, + { + if let Some(registries) = STATIC_REGISTRIES.get() { + let mut map = HashMap::with_capacity(access.size_hint().unwrap_or(0)); + + // While there are entries remaining in the input, add them + // into our map. + while let Some(key) = access.next_key::()? { + if let Some(creator) = registries.item_components.by_key(&key) { + let component = access.next_value_seed(creator)?; + map.insert(component.type_id(), component); + } else { + return Err(Error::custom(format!( + "Unknown item component '{}'! Is the right plugin loaded?", + key + ))); + } + } + + Ok(ItemComponentMap(map)) + } else { + Err(Error::custom("Item component registry not present")) + } + } +} diff --git a/potato-data/src/registry/item/components/attribute_modifiers.rs b/potato-data/src/registry/item/components/attribute_modifiers.rs new file mode 100644 index 0000000..cf58cf8 --- /dev/null +++ b/potato-data/src/registry/item/components/attribute_modifiers.rs @@ -0,0 +1,42 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::identifier::Identifier; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "attribute_modifiers")] +pub struct AttributeModifiers(Vec); + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct AttributeModifier { + pub r#type: String, + #[serde(default)] + pub slot: AttributeModifierSlot, + pub id: Identifier, + pub amount: f64, + pub operation: AttributeModifierOperation, +} + +#[derive(Debug, Serialize, Deserialize, Clone, Default)] +#[serde(rename_all = "snake_case")] +pub enum AttributeModifierSlot { + #[default] + Any, + Hand, + Armor, + Mainhand, + Offhand, + Head, + Chest, + Legs, + Feet, + Body, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "snake_case")] +pub enum AttributeModifierOperation { + AddValue, + AddMultipliedBase, + AddMultipliedTotal, +} diff --git a/potato-data/src/registry/item/components/axolotl_variant.rs b/potato-data/src/registry/item/components/axolotl_variant.rs new file mode 100644 index 0000000..1370102 --- /dev/null +++ b/potato-data/src/registry/item/components/axolotl_variant.rs @@ -0,0 +1,8 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::identifier::Identifier; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "axolotl/variant")] +pub struct AxolotlVariant(pub Identifier); diff --git a/potato-data/src/registry/item/components/banner_patterns.rs b/potato-data/src/registry/item/components/banner_patterns.rs new file mode 100644 index 0000000..a76a86d --- /dev/null +++ b/potato-data/src/registry/item/components/banner_patterns.rs @@ -0,0 +1,14 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::{Either, identifier::Identifier, registry::banner_pattern}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "banner_patterns")] +pub struct BannerPatterns(Vec); + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct BannerPattern { + pub color: String, + pub pattern: Either, +} diff --git a/potato-data/src/registry/item/components/base_color.rs b/potato-data/src/registry/item/components/base_color.rs new file mode 100644 index 0000000..e45b7ba --- /dev/null +++ b/potato-data/src/registry/item/components/base_color.rs @@ -0,0 +1,6 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "base_color")] +pub struct BaseColor(String); diff --git a/potato-data/src/registry/item/components/bees.rs b/potato-data/src/registry/item/components/bees.rs new file mode 100644 index 0000000..aa4814d --- /dev/null +++ b/potato-data/src/registry/item/components/bees.rs @@ -0,0 +1,13 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "bees")] +pub struct Bees(Vec); + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct Bee { + pub entity_data: fastnbt::Value, + pub min_ticks_in_hive: i32, + pub ticks_in_hive: i32, +} diff --git a/potato-data/src/registry/item/components/block_entity_data.rs b/potato-data/src/registry/item/components/block_entity_data.rs new file mode 100644 index 0000000..b3faa78 --- /dev/null +++ b/potato-data/src/registry/item/components/block_entity_data.rs @@ -0,0 +1,6 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "block_entity_data")] +pub struct BlockEntityData(fastnbt::Value); diff --git a/potato-data/src/registry/item/components/block_state.rs b/potato-data/src/registry/item/components/block_state.rs new file mode 100644 index 0000000..4453aac --- /dev/null +++ b/potato-data/src/registry/item/components/block_state.rs @@ -0,0 +1,8 @@ +use potato_derive::ItemComponent; +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "block_state")] +pub struct BlockState(HashMap); diff --git a/potato-data/src/registry/item/components/blocks_attacks.rs b/potato-data/src/registry/item/components/blocks_attacks.rs new file mode 100644 index 0000000..81126c4 --- /dev/null +++ b/potato-data/src/registry/item/components/blocks_attacks.rs @@ -0,0 +1,50 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::{ + Either, OneOrMany, TagOrIdentifier, identifier::Identifier, + registry::worldgen::biome::SoundEvent, tag::Tag, +}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "blocks_attacks")] +pub struct BlocksAttacks { + #[serde(default = "zero")] + pub block_delay_seconds: f32, + #[serde(default = "one")] + pub disable_cooldown_scale: f32, + #[serde(default)] + pub damage_reductions: Vec, + pub item_damage: ItemDamage, + pub block_sound: Option>, + pub disabled_sound: Option>, + pub bypassed_by: Option, +} + +fn zero() -> f32 { + 0.0 +} + +fn one() -> f32 { + 1.0 +} + +fn ninety() -> f32 { + 90.0 +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct DamageReduction { + pub r#type: OneOrMany, + pub base: f32, + pub factor: f32, + #[serde(default = "ninety")] + pub horizontal_blocking_angle: f32, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct ItemDamage { + pub threshold: f32, + pub base: f32, + pub factor: f32, +} diff --git a/potato-data/src/registry/item/components/break_sound.rs b/potato-data/src/registry/item/components/break_sound.rs new file mode 100644 index 0000000..12e2df9 --- /dev/null +++ b/potato-data/src/registry/item/components/break_sound.rs @@ -0,0 +1,8 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::{Either, identifier::Identifier, registry::worldgen::biome::SoundEvent}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "break_sound")] +pub struct BreakSound(Either); diff --git a/potato-data/src/registry/item/components/bucket_entity_data.rs b/potato-data/src/registry/item/components/bucket_entity_data.rs new file mode 100644 index 0000000..cf5042b --- /dev/null +++ b/potato-data/src/registry/item/components/bucket_entity_data.rs @@ -0,0 +1,7 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +// TODO: Limit to some tags only https://minecraft.wiki/w/Data_component_format#bucket_entity_data +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "bucket_entity_data")] +pub struct BucketEntityData(fastnbt::Value); diff --git a/potato-data/src/registry/item/components/bundle_contents.rs b/potato-data/src/registry/item/components/bundle_contents.rs new file mode 100644 index 0000000..fd72143 --- /dev/null +++ b/potato-data/src/registry/item/components/bundle_contents.rs @@ -0,0 +1,8 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::item_stack::ItemStack; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "bundle_contents")] +pub struct BundleContents(Vec); diff --git a/potato-data/src/registry/item/components/can_break.rs b/potato-data/src/registry/item/components/can_break.rs new file mode 100644 index 0000000..66b94ce --- /dev/null +++ b/potato-data/src/registry/item/components/can_break.rs @@ -0,0 +1,17 @@ +use potato_derive::ItemComponent; +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; + +use crate::{OneOrMany, TagOrIdentifier}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "can_break")] +pub struct CanBreak(pub OneOrMany); + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct CanBreakPredicate { + pub blocks: OneOrMany, + pub nbt: fastnbt::Value, + pub state: HashMap, +} diff --git a/potato-data/src/registry/item/components/can_place_on.rs b/potato-data/src/registry/item/components/can_place_on.rs new file mode 100644 index 0000000..2b2faff --- /dev/null +++ b/potato-data/src/registry/item/components/can_place_on.rs @@ -0,0 +1,17 @@ +use potato_derive::ItemComponent; +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; + +use crate::{OneOrMany, TagOrIdentifier}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "can_place_on")] +pub struct CanPlaceOn(pub OneOrMany); + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct CanPlaceOnPredicate { + pub blocks: OneOrMany, + pub nbt: fastnbt::Value, + pub state: HashMap, +} diff --git a/potato-data/src/registry/item/components/cat_collar.rs b/potato-data/src/registry/item/components/cat_collar.rs new file mode 100644 index 0000000..ac3c371 --- /dev/null +++ b/potato-data/src/registry/item/components/cat_collar.rs @@ -0,0 +1,7 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "cat/collar")] +// TODO: dye color enum +pub struct CatCollar(pub String); diff --git a/potato-data/src/registry/item/components/cat_variant.rs b/potato-data/src/registry/item/components/cat_variant.rs new file mode 100644 index 0000000..be542bc --- /dev/null +++ b/potato-data/src/registry/item/components/cat_variant.rs @@ -0,0 +1,8 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::identifier::Identifier; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "cat/variant")] +pub struct CatVariant(pub Identifier); diff --git a/potato-data/src/registry/item/components/charged_projectiles.rs b/potato-data/src/registry/item/components/charged_projectiles.rs new file mode 100644 index 0000000..25a28c1 --- /dev/null +++ b/potato-data/src/registry/item/components/charged_projectiles.rs @@ -0,0 +1,8 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::item_stack::ItemStack; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "charged_projectiles")] +pub struct ChargedProjectiles(Vec); diff --git a/potato-data/src/registry/item/components/chicken_variant.rs b/potato-data/src/registry/item/components/chicken_variant.rs new file mode 100644 index 0000000..c38d381 --- /dev/null +++ b/potato-data/src/registry/item/components/chicken_variant.rs @@ -0,0 +1,8 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::identifier::Identifier; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "chicken/variant")] +pub struct ChickenVariant(pub Identifier); diff --git a/potato-data/src/registry/item/components/consumable.rs b/potato-data/src/registry/item/components/consumable.rs new file mode 100644 index 0000000..6cb037d --- /dev/null +++ b/potato-data/src/registry/item/components/consumable.rs @@ -0,0 +1,52 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::{ + Either, consume_effect::ConsumeEffect, identifier::Identifier, + registry::worldgen::biome::SoundEvent, +}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "consumable")] +pub struct Consumable { + #[serde(default = "one_point_six")] + pub consume_seconds: f32, + #[serde(default)] + pub animation: ConsumptionAnimation, + #[serde(default = "generic_eat")] + pub sound: Either, + #[serde(default)] + pub on_consume_effects: Vec, +} + +fn zero() -> u8 { + 0 +} + +fn one() -> i32 { + 1 +} + +fn one_point_six() -> f32 { + 1.6 +} + +fn generic_eat() -> Either { + Either::Left(Identifier::minecraft("entity.generic.eat")) +} + +#[derive(Debug, Serialize, Deserialize, Default, Clone)] +#[serde(rename_all = "snake_case")] +pub enum ConsumptionAnimation { + None, + #[default] + Eat, + Drink, + Block, + Bow, + Spear, + Crossbow, + Spyglass, + TootHorn, + Brush, +} diff --git a/potato-data/src/registry/item/components/container.rs b/potato-data/src/registry/item/components/container.rs new file mode 100644 index 0000000..b8f0fc2 --- /dev/null +++ b/potato-data/src/registry/item/components/container.rs @@ -0,0 +1,14 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::item_stack::ItemStack; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "container")] +pub struct Container(pub Vec); + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct ContainerSlot { + pub item: ItemStack, + pub slot: u8, +} diff --git a/potato-data/src/registry/item/components/container_loot.rs b/potato-data/src/registry/item/components/container_loot.rs new file mode 100644 index 0000000..0735aa0 --- /dev/null +++ b/potato-data/src/registry/item/components/container_loot.rs @@ -0,0 +1,16 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::identifier::Identifier; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "container_loot")] +pub struct ContainerLoot { + pub loot_table: Identifier, + #[serde(default = "zero")] + pub seed: i64, +} + +fn zero() -> i64 { + 0 +} diff --git a/potato-data/src/registry/item/components/cow_variant.rs b/potato-data/src/registry/item/components/cow_variant.rs new file mode 100644 index 0000000..5235963 --- /dev/null +++ b/potato-data/src/registry/item/components/cow_variant.rs @@ -0,0 +1,8 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::identifier::Identifier; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "cow/variant")] +pub struct CowVariant(pub Identifier); diff --git a/potato-data/src/registry/item/components/custom_data.rs b/potato-data/src/registry/item/components/custom_data.rs new file mode 100644 index 0000000..14e5ad8 --- /dev/null +++ b/potato-data/src/registry/item/components/custom_data.rs @@ -0,0 +1,7 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "custom_data")] +// TODO: Enforce as key-value map instead of any nbt value +pub struct CustomData(fastnbt::Value); diff --git a/potato-data/src/registry/item/components/custom_model_data.rs b/potato-data/src/registry/item/components/custom_model_data.rs new file mode 100644 index 0000000..16f89fd --- /dev/null +++ b/potato-data/src/registry/item/components/custom_model_data.rs @@ -0,0 +1,14 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::color::Color; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "custom_model_data")] +pub struct CustomModelData { + pub floats: Vec, + pub flags: Vec, + pub strings: Vec, + // TODO: Also parse float3 array here + pub colors: Vec, +} diff --git a/potato-data/src/registry/item/components/custom_name.rs b/potato-data/src/registry/item/components/custom_name.rs new file mode 100644 index 0000000..e90269d --- /dev/null +++ b/potato-data/src/registry/item/components/custom_name.rs @@ -0,0 +1,8 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::text_component::TextComponent; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "custom_name")] +pub struct CustomName(pub TextComponent); diff --git a/potato-data/src/registry/item/components/damage.rs b/potato-data/src/registry/item/components/damage.rs new file mode 100644 index 0000000..7acca24 --- /dev/null +++ b/potato-data/src/registry/item/components/damage.rs @@ -0,0 +1,6 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "damage")] +pub struct Damage(pub i32); diff --git a/potato-data/src/registry/item/components/damage_resistant.rs b/potato-data/src/registry/item/components/damage_resistant.rs new file mode 100644 index 0000000..53da9cd --- /dev/null +++ b/potato-data/src/registry/item/components/damage_resistant.rs @@ -0,0 +1,10 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::tag::Tag; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "damage_resistant")] +pub struct DamageResistant { + pub types: Tag, +} diff --git a/potato-data/src/registry/item/components/death_protection.rs b/potato-data/src/registry/item/components/death_protection.rs new file mode 100644 index 0000000..3cd6c44 --- /dev/null +++ b/potato-data/src/registry/item/components/death_protection.rs @@ -0,0 +1,10 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::consume_effect::ConsumeEffect; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "death_protection")] +pub struct DeathProtection { + pub death_effects: Vec, +} diff --git a/potato-data/src/registry/item/components/debug_stick_state.rs b/potato-data/src/registry/item/components/debug_stick_state.rs new file mode 100644 index 0000000..8704472 --- /dev/null +++ b/potato-data/src/registry/item/components/debug_stick_state.rs @@ -0,0 +1,10 @@ +use potato_derive::ItemComponent; +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; + +use crate::identifier::Identifier; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "debug_stick_state")] +pub struct DebugStickState(HashMap); diff --git a/potato-data/src/registry/item/components/dyed_color.rs b/potato-data/src/registry/item/components/dyed_color.rs new file mode 100644 index 0000000..a1a248e --- /dev/null +++ b/potato-data/src/registry/item/components/dyed_color.rs @@ -0,0 +1,9 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::color::Color; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "dyed_color")] +// TODO: Parse float3 as well +pub struct DyedColor(pub Color); diff --git a/potato-data/src/registry/item/components/enchantable.rs b/potato-data/src/registry/item/components/enchantable.rs new file mode 100644 index 0000000..3946993 --- /dev/null +++ b/potato-data/src/registry/item/components/enchantable.rs @@ -0,0 +1,8 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "enchantable")] +pub struct Enchantable { + pub value: i32, +} diff --git a/potato-data/src/registry/item/components/enchantment_glint_override.rs b/potato-data/src/registry/item/components/enchantment_glint_override.rs new file mode 100644 index 0000000..b38b9b1 --- /dev/null +++ b/potato-data/src/registry/item/components/enchantment_glint_override.rs @@ -0,0 +1,6 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "enchantment_glint_override")] +pub struct EnchantmentGlintOverride(pub bool); diff --git a/potato-data/src/registry/item/components/enchantments.rs b/potato-data/src/registry/item/components/enchantments.rs new file mode 100644 index 0000000..fed5a80 --- /dev/null +++ b/potato-data/src/registry/item/components/enchantments.rs @@ -0,0 +1,8 @@ +use potato_derive::ItemComponent; +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "enchantments")] +pub struct Enchantments(HashMap); diff --git a/potato-data/src/registry/item/components/entity_data.rs b/potato-data/src/registry/item/components/entity_data.rs new file mode 100644 index 0000000..c4db7f6 --- /dev/null +++ b/potato-data/src/registry/item/components/entity_data.rs @@ -0,0 +1,6 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "entity_data")] +pub struct EntityData(pub fastnbt::Value); diff --git a/potato-data/src/registry/item/components/equippable.rs b/potato-data/src/registry/item/components/equippable.rs new file mode 100644 index 0000000..541a440 --- /dev/null +++ b/potato-data/src/registry/item/components/equippable.rs @@ -0,0 +1,45 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::{ + Either, OneOrMany, TagOrIdentifier, identifier::Identifier, + registry::worldgen::biome::SoundEvent, +}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "equippable")] +pub struct Equippable { + pub slot: EquipmentSlot, + #[serde(default = "armor_equip_generic")] + pub equip_sound: Either, + pub asset_id: Option, + pub allowed_entities: Option>, + #[serde(default = "r#true")] + pub dispensable: bool, + #[serde(default = "r#true")] + pub damage_on_hurt: bool, + #[serde(default = "r#true")] + pub equip_on_interact: bool, + pub camera_overlay: Option, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "snake_case")] +pub enum EquipmentSlot { + Head, + Chest, + Legs, + Feet, + Body, + Mainhand, + Offhand, + Saddle, +} + +fn armor_equip_generic() -> Either { + Either::Left(Identifier::minecraft("item.armor.equip_generic")) +} + +fn r#true() -> bool { + true +} diff --git a/potato-data/src/registry/item/components/firework_explosion.rs b/potato-data/src/registry/item/components/firework_explosion.rs new file mode 100644 index 0000000..ff9fa78 --- /dev/null +++ b/potato-data/src/registry/item/components/firework_explosion.rs @@ -0,0 +1,24 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::color::Color; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "firework_explosion")] +pub struct FireworkExplosion { + pub shape: FireworkShape, + pub colors: Vec, + pub fade_colors: Vec, + pub has_trail: bool, + pub has_twinkle: bool, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "snake_case")] +pub enum FireworkShape { + SmallBall, + LargeBall, + Star, + Creeper, + Burst, +} diff --git a/potato-data/src/registry/item/components/fireworks.rs b/potato-data/src/registry/item/components/fireworks.rs new file mode 100644 index 0000000..1588f33 --- /dev/null +++ b/potato-data/src/registry/item/components/fireworks.rs @@ -0,0 +1,17 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use super::firework_explosion::FireworkExplosion; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "fireworks")] +pub struct Fireworks { + #[serde(default)] + pub explosions: Vec, + #[serde(default = "one")] + pub flight_duration: i8, +} + +fn one() -> i8 { + 1 +} diff --git a/potato-data/src/registry/item/components/food.rs b/potato-data/src/registry/item/components/food.rs new file mode 100644 index 0000000..554c3a3 --- /dev/null +++ b/potato-data/src/registry/item/components/food.rs @@ -0,0 +1,15 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "food")] +pub struct Food { + pub nutrition: i32, + pub saturation: f32, + #[serde(default = "r#false")] + pub can_always_eat: bool, +} + +fn r#false() -> bool { + false +} diff --git a/potato-data/src/registry/item/components/fox_variant.rs b/potato-data/src/registry/item/components/fox_variant.rs new file mode 100644 index 0000000..8153859 --- /dev/null +++ b/potato-data/src/registry/item/components/fox_variant.rs @@ -0,0 +1,8 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::identifier::Identifier; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "fox/variant")] +pub struct FoxVariant(pub Identifier); diff --git a/potato-data/src/registry/item/components/frog_variant.rs b/potato-data/src/registry/item/components/frog_variant.rs new file mode 100644 index 0000000..82edfb0 --- /dev/null +++ b/potato-data/src/registry/item/components/frog_variant.rs @@ -0,0 +1,8 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::identifier::Identifier; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "frog/variant")] +pub struct FrogVariant(pub Identifier); diff --git a/potato-data/src/registry/item/components/glider.rs b/potato-data/src/registry/item/components/glider.rs new file mode 100644 index 0000000..2f9fd8d --- /dev/null +++ b/potato-data/src/registry/item/components/glider.rs @@ -0,0 +1,6 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "glider")] +pub struct Glider {} diff --git a/potato-data/src/registry/item/components/horse_variant.rs b/potato-data/src/registry/item/components/horse_variant.rs new file mode 100644 index 0000000..e6a8080 --- /dev/null +++ b/potato-data/src/registry/item/components/horse_variant.rs @@ -0,0 +1,8 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::identifier::Identifier; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "horse/variant")] +pub struct HorseVariant(pub Identifier); diff --git a/potato-data/src/registry/item/components/instrument.rs b/potato-data/src/registry/item/components/instrument.rs new file mode 100644 index 0000000..56a4bb3 --- /dev/null +++ b/potato-data/src/registry/item/components/instrument.rs @@ -0,0 +1,21 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::{ + Either, identifier::Identifier, registry::worldgen::biome::SoundEvent, + text_component::TextComponent, +}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "instrument")] +pub struct Instrument(pub Either); + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct InstrumentDefinition { + pub sound_event: Either, + // TODO: Non negative only + pub use_duration: f32, + // TODO: Non negative only + pub range: f32, + pub description: TextComponent, +} diff --git a/potato-data/src/registry/item/components/intangible_projectile.rs b/potato-data/src/registry/item/components/intangible_projectile.rs new file mode 100644 index 0000000..34c0dfa --- /dev/null +++ b/potato-data/src/registry/item/components/intangible_projectile.rs @@ -0,0 +1,6 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "intangible_projectile")] +pub struct IntangibleProjectile; diff --git a/potato-data/src/registry/item/components/item_model.rs b/potato-data/src/registry/item/components/item_model.rs new file mode 100644 index 0000000..cdfe459 --- /dev/null +++ b/potato-data/src/registry/item/components/item_model.rs @@ -0,0 +1,8 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::identifier::Identifier; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "item_model")] +pub struct ItemModel(pub Identifier); diff --git a/potato-data/src/registry/item/components/item_name.rs b/potato-data/src/registry/item/components/item_name.rs new file mode 100644 index 0000000..a45660d --- /dev/null +++ b/potato-data/src/registry/item/components/item_name.rs @@ -0,0 +1,8 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::text_component::TextComponent; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "item_name")] +pub struct ItemName(pub TextComponent); diff --git a/potato-data/src/registry/item/components/jukebox_playable.rs b/potato-data/src/registry/item/components/jukebox_playable.rs new file mode 100644 index 0000000..74ade1e --- /dev/null +++ b/potato-data/src/registry/item/components/jukebox_playable.rs @@ -0,0 +1,8 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::identifier::Identifier; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "jukebox_playable")] +pub struct JukeboxPlayable(pub Identifier); diff --git a/potato-data/src/registry/item/components/llama_variant.rs b/potato-data/src/registry/item/components/llama_variant.rs new file mode 100644 index 0000000..9b46ef0 --- /dev/null +++ b/potato-data/src/registry/item/components/llama_variant.rs @@ -0,0 +1,8 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::identifier::Identifier; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "llama/variant")] +pub struct LlamaVariant(pub Identifier); diff --git a/potato-data/src/registry/item/components/lock.rs b/potato-data/src/registry/item/components/lock.rs new file mode 100644 index 0000000..51f61be --- /dev/null +++ b/potato-data/src/registry/item/components/lock.rs @@ -0,0 +1,8 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::predicate::ItemPredicate; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "lock")] +pub struct Lock(pub ItemPredicate); diff --git a/potato-data/src/registry/item/components/lodestone_tracker.rs b/potato-data/src/registry/item/components/lodestone_tracker.rs new file mode 100644 index 0000000..1322b68 --- /dev/null +++ b/potato-data/src/registry/item/components/lodestone_tracker.rs @@ -0,0 +1,22 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::identifier::Identifier; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "lodestone_tracker")] +pub struct LodestoneTracker { + pub target: Option, + #[serde(default = "r#true")] + pub tracked: bool, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct CompassTarget { + pub pos: (i32, i32, i32), + pub dimension: Identifier, +} + +fn r#true() -> bool { + true +} diff --git a/potato-data/src/registry/item/components/lore.rs b/potato-data/src/registry/item/components/lore.rs new file mode 100644 index 0000000..1396cd4 --- /dev/null +++ b/potato-data/src/registry/item/components/lore.rs @@ -0,0 +1,8 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::text_component::TextComponent; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "lore")] +pub struct Lore(pub Vec); diff --git a/potato-data/src/registry/item/components/map_color.rs b/potato-data/src/registry/item/components/map_color.rs new file mode 100644 index 0000000..8764840 --- /dev/null +++ b/potato-data/src/registry/item/components/map_color.rs @@ -0,0 +1,8 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::color::Color; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "map_color")] +pub struct MapColor(pub Color); diff --git a/potato-data/src/registry/item/components/map_decorations.rs b/potato-data/src/registry/item/components/map_decorations.rs new file mode 100644 index 0000000..ed7a202 --- /dev/null +++ b/potato-data/src/registry/item/components/map_decorations.rs @@ -0,0 +1,55 @@ +use potato_derive::ItemComponent; +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "map_decorations")] +pub struct MapDecorations(pub HashMap); + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct MapMarker { + pub r#type: MapMarkerType, + pub x: f64, + pub z: f64, + pub rotation: f32, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "snake_case")] +pub enum MapMarkerType { + Player, + Frame, + RedMarker, + BlueMarker, + TargetX, + TargetPoint, + PlayerOffMap, + PlayerOffLimits, + Mansion, + Monument, + BannerWhite, + BannerOrange, + BannerMagenta, + BannerLightBlue, + BannerYellow, + BannerLime, + BannerPink, + BannerGray, + BannerLightGray, + BannerCyan, + BannerPurple, + BannerBlue, + BannerBrown, + BannerGreen, + BannerRed, + BannerBlack, + RedX, + VillageDesert, + VillagePlains, + VillageSavanna, + VillageSnowy, + VillageTaiga, + JungleTemple, + SwampHut, +} diff --git a/potato-data/src/registry/item/components/map_id.rs b/potato-data/src/registry/item/components/map_id.rs new file mode 100644 index 0000000..6cec232 --- /dev/null +++ b/potato-data/src/registry/item/components/map_id.rs @@ -0,0 +1,6 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "map_id")] +pub struct MapId(pub i32); diff --git a/potato-data/src/registry/item/components/max_damage.rs b/potato-data/src/registry/item/components/max_damage.rs new file mode 100644 index 0000000..6e7b3ca --- /dev/null +++ b/potato-data/src/registry/item/components/max_damage.rs @@ -0,0 +1,6 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "max_damage")] +pub struct MaxDamage(pub i32); diff --git a/potato-data/src/registry/item/components/max_stack_size.rs b/potato-data/src/registry/item/components/max_stack_size.rs new file mode 100644 index 0000000..205e6d0 --- /dev/null +++ b/potato-data/src/registry/item/components/max_stack_size.rs @@ -0,0 +1,7 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "max_stack_size")] +// TODO: Limit range to 1-99 inclusive (Or maybe allow more if the client doesn't get mad?) +pub struct MaxStackSize(pub i32); diff --git a/potato-data/src/registry/item/components/mod.rs b/potato-data/src/registry/item/components/mod.rs new file mode 100644 index 0000000..f281e42 --- /dev/null +++ b/potato-data/src/registry/item/components/mod.rs @@ -0,0 +1,95 @@ +pub mod attribute_modifiers; +pub mod banner_patterns; +pub mod base_color; +pub mod bees; +pub mod block_entity_data; +pub mod block_state; +pub mod blocks_attacks; +pub mod break_sound; +pub mod bucket_entity_data; +pub mod bundle_contents; +pub mod can_break; +pub mod can_place_on; +pub mod charged_projectiles; +pub mod consumable; +pub mod container; +pub mod container_loot; +pub mod custom_data; +pub mod custom_model_data; +pub mod custom_name; +pub mod damage; +pub mod damage_resistant; +pub mod death_protection; +pub mod debug_stick_state; +pub mod dyed_color; +pub mod enchantable; +pub mod enchantment_glint_override; +pub mod enchantments; +pub mod entity_data; +pub mod equippable; +pub mod firework_explosion; +pub mod fireworks; +pub mod food; +pub mod glider; +pub mod instrument; +pub mod intangible_projectile; +pub mod item_model; +pub mod item_name; +pub mod jukebox_playable; +pub mod lock; +pub mod lodestone_tracker; +pub mod lore; +pub mod map_color; +pub mod map_decorations; +pub mod map_id; +pub mod max_damage; +pub mod max_stack_size; +pub mod note_block_sound; +pub mod ominous_bottle_amplifier; +pub mod pot_decorations; +pub mod potion_contents; +pub mod potion_duration_scale; +pub mod profile; +pub mod provides_banner_patterns; +pub mod provides_trim_material; +pub mod rarity; +pub mod recipes; +pub mod repair_cost; +pub mod repairable; +pub mod stored_enchantments; +pub mod suspicious_stew_effects; +pub mod tool; +pub mod tooltip_display; +pub mod tooltip_style; +pub mod trim; +pub mod unbreakable; +pub mod use_cooldown; +pub mod use_remainder; +pub mod weapon; +pub mod writable_book_content; +pub mod written_book_content; + +pub mod axolotl_variant; +pub mod cat_collar; +pub mod cat_variant; +pub mod chicken_variant; +pub mod cow_variant; +pub mod fox_variant; +pub mod frog_variant; +pub mod horse_variant; +pub mod llama_variant; +pub mod mooshroom_variant; +pub mod painting_variant; +pub mod parrot_variant; +pub mod pig_variant; +pub mod rabbit_variant; +pub mod salmon_size; +pub mod sheep_color; +pub mod shulker_color; +pub mod tropical_fish_base_color; +pub mod tropical_fish_pattern; +pub mod tropical_fish_pattern_color; +pub mod villager_variant; +pub mod wolf_collar; +pub mod wolf_sound_variant; +pub mod wolf_variant; diff --git a/potato-data/src/registry/item/components/mooshroom_variant.rs b/potato-data/src/registry/item/components/mooshroom_variant.rs new file mode 100644 index 0000000..3f22950 --- /dev/null +++ b/potato-data/src/registry/item/components/mooshroom_variant.rs @@ -0,0 +1,8 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::identifier::Identifier; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "mooshroom/variant")] +pub struct MooshroomVariant(pub Identifier); diff --git a/potato-data/src/registry/item/components/note_block_sound.rs b/potato-data/src/registry/item/components/note_block_sound.rs new file mode 100644 index 0000000..6d094f8 --- /dev/null +++ b/potato-data/src/registry/item/components/note_block_sound.rs @@ -0,0 +1,8 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::identifier::Identifier; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "note_block_sound")] +pub struct NoteBlockSound(pub Identifier); diff --git a/potato-data/src/registry/item/components/ominous_bottle_amplifier.rs b/potato-data/src/registry/item/components/ominous_bottle_amplifier.rs new file mode 100644 index 0000000..a10a635 --- /dev/null +++ b/potato-data/src/registry/item/components/ominous_bottle_amplifier.rs @@ -0,0 +1,7 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "ominous_bottle_amplifier")] +// TODO: Limit range to 0-4 inclusive +pub struct OminousBottleAmplifier(pub i32); diff --git a/potato-data/src/registry/item/components/painting_variant.rs b/potato-data/src/registry/item/components/painting_variant.rs new file mode 100644 index 0000000..78a53c8 --- /dev/null +++ b/potato-data/src/registry/item/components/painting_variant.rs @@ -0,0 +1,8 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::{Either, identifier::Identifier, registry::painting_variant}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "painting/variant")] +pub struct PaintingVariant(pub Either); diff --git a/potato-data/src/registry/item/components/parrot_variant.rs b/potato-data/src/registry/item/components/parrot_variant.rs new file mode 100644 index 0000000..b66551d --- /dev/null +++ b/potato-data/src/registry/item/components/parrot_variant.rs @@ -0,0 +1,8 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::identifier::Identifier; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "parrot/variant")] +pub struct ParrotVariant(pub Identifier); diff --git a/potato-data/src/registry/item/components/pig_variant.rs b/potato-data/src/registry/item/components/pig_variant.rs new file mode 100644 index 0000000..2e641a6 --- /dev/null +++ b/potato-data/src/registry/item/components/pig_variant.rs @@ -0,0 +1,8 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::identifier::Identifier; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "pig/variant")] +pub struct PigVariant(pub Identifier); diff --git a/potato-data/src/registry/item/components/pot_decorations.rs b/potato-data/src/registry/item/components/pot_decorations.rs new file mode 100644 index 0000000..5d6b228 --- /dev/null +++ b/potato-data/src/registry/item/components/pot_decorations.rs @@ -0,0 +1,8 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::identifier::Identifier; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "pot_decorations")] +pub struct PotDecorations(pub Vec); diff --git a/potato-data/src/registry/item/components/potion_contents.rs b/potato-data/src/registry/item/components/potion_contents.rs new file mode 100644 index 0000000..f0a6717 --- /dev/null +++ b/potato-data/src/registry/item/components/potion_contents.rs @@ -0,0 +1,15 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::{color::Color, identifier::Identifier, status_effect::StatusEffect}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "potion_contents")] +// TODO: Also parse string as only setting potion key +pub struct PotionContents { + pub potion: Option, + pub custom_color: Option, + pub custom_name: Option, + #[serde(default)] + pub custom_effects: Vec, +} diff --git a/potato-data/src/registry/item/components/potion_duration_scale.rs b/potato-data/src/registry/item/components/potion_duration_scale.rs new file mode 100644 index 0000000..9a4709e --- /dev/null +++ b/potato-data/src/registry/item/components/potion_duration_scale.rs @@ -0,0 +1,10 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "potion_duration_scale")] +pub struct PotionDurationScale(#[serde(default = "one")] pub f32); + +fn one() -> f32 { + 1.0 +} diff --git a/potato-data/src/registry/item/components/profile.rs b/potato-data/src/registry/item/components/profile.rs new file mode 100644 index 0000000..7357104 --- /dev/null +++ b/potato-data/src/registry/item/components/profile.rs @@ -0,0 +1,25 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "profile")] +// TODO: Parse string as if only name is specified +pub struct Profile { + pub name: Option, + pub id: Option, + pub properties: Vec, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct ProfileProperty { + pub name: ProfilePropertyName, + pub value: String, + pub signature: Option, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "snake_case")] +pub enum ProfilePropertyName { + Textures, +} diff --git a/potato-data/src/registry/item/components/provides_banner_patterns.rs b/potato-data/src/registry/item/components/provides_banner_patterns.rs new file mode 100644 index 0000000..2f64caa --- /dev/null +++ b/potato-data/src/registry/item/components/provides_banner_patterns.rs @@ -0,0 +1,8 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::tag::Tag; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "provides_banner_patterns")] +pub struct ProvidesBannerPatterns(pub Tag); diff --git a/potato-data/src/registry/item/components/provides_trim_material.rs b/potato-data/src/registry/item/components/provides_trim_material.rs new file mode 100644 index 0000000..369e565 --- /dev/null +++ b/potato-data/src/registry/item/components/provides_trim_material.rs @@ -0,0 +1,8 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::identifier::Identifier; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "provides_trim_material")] +pub struct ProvidesTrimMaterial(pub Identifier); diff --git a/potato-data/src/registry/item/components/rabbit_variant.rs b/potato-data/src/registry/item/components/rabbit_variant.rs new file mode 100644 index 0000000..25293d2 --- /dev/null +++ b/potato-data/src/registry/item/components/rabbit_variant.rs @@ -0,0 +1,8 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::identifier::Identifier; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "rabbit/variant")] +pub struct RabbitVariant(pub Identifier); diff --git a/potato-data/src/registry/item/components/rarity.rs b/potato-data/src/registry/item/components/rarity.rs new file mode 100644 index 0000000..7f9300b --- /dev/null +++ b/potato-data/src/registry/item/components/rarity.rs @@ -0,0 +1,12 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "rarity")] +#[serde(rename_all = "snake_case")] +pub enum Rarity { + Common, + Uncommon, + Rare, + Epic, +} diff --git a/potato-data/src/registry/item/components/recipes.rs b/potato-data/src/registry/item/components/recipes.rs new file mode 100644 index 0000000..4f604ac --- /dev/null +++ b/potato-data/src/registry/item/components/recipes.rs @@ -0,0 +1,8 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::identifier::Identifier; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "recipes")] +pub struct Recipes(pub Vec); diff --git a/potato-data/src/registry/item/components/repair_cost.rs b/potato-data/src/registry/item/components/repair_cost.rs new file mode 100644 index 0000000..25e887a --- /dev/null +++ b/potato-data/src/registry/item/components/repair_cost.rs @@ -0,0 +1,10 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "repair_cost")] +pub struct RepairCost(#[serde(default = "zero")] pub i32); + +fn zero() -> i32 { + 0 +} diff --git a/potato-data/src/registry/item/components/repairable.rs b/potato-data/src/registry/item/components/repairable.rs new file mode 100644 index 0000000..d959452 --- /dev/null +++ b/potato-data/src/registry/item/components/repairable.rs @@ -0,0 +1,10 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::{OneOrMany, TagOrIdentifier}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "repairable")] +pub struct Repairable { + pub items: OneOrMany, +} diff --git a/potato-data/src/registry/item/components/salmon_size.rs b/potato-data/src/registry/item/components/salmon_size.rs new file mode 100644 index 0000000..4b351b5 --- /dev/null +++ b/potato-data/src/registry/item/components/salmon_size.rs @@ -0,0 +1,11 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "salmon/size")] +#[serde(rename_all = "snake_case")] +pub enum SalmonSize { + Small, + Medium, + Large, +} diff --git a/potato-data/src/registry/item/components/sheep_color.rs b/potato-data/src/registry/item/components/sheep_color.rs new file mode 100644 index 0000000..e68b887 --- /dev/null +++ b/potato-data/src/registry/item/components/sheep_color.rs @@ -0,0 +1,7 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "sheep/color")] +// TODO: dye color type +pub struct SheepColor(pub String); diff --git a/potato-data/src/registry/item/components/shulker_color.rs b/potato-data/src/registry/item/components/shulker_color.rs new file mode 100644 index 0000000..a82156c --- /dev/null +++ b/potato-data/src/registry/item/components/shulker_color.rs @@ -0,0 +1,7 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "shulker/color")] +// TODO: dye color type +pub struct ShulkerColor(pub String); diff --git a/potato-data/src/registry/item/components/stored_enchantments.rs b/potato-data/src/registry/item/components/stored_enchantments.rs new file mode 100644 index 0000000..349e877 --- /dev/null +++ b/potato-data/src/registry/item/components/stored_enchantments.rs @@ -0,0 +1,10 @@ +use potato_derive::ItemComponent; +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; + +use crate::identifier::Identifier; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "stored_enchantments")] +pub struct StoredEnchantments(pub HashMap); diff --git a/potato-data/src/registry/item/components/suspicious_stew_effects.rs b/potato-data/src/registry/item/components/suspicious_stew_effects.rs new file mode 100644 index 0000000..ef64348 --- /dev/null +++ b/potato-data/src/registry/item/components/suspicious_stew_effects.rs @@ -0,0 +1,19 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::identifier::Identifier; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "suspicious_stew_effects")] +pub struct SuspiciousStewEffects(pub Vec); + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct SuspiciousStewEffect { + pub id: Identifier, + #[serde(default = "onesixty")] + pub duration: i32, +} + +fn onesixty() -> i32 { + 160 +} diff --git a/potato-data/src/registry/item/components/tool.rs b/potato-data/src/registry/item/components/tool.rs new file mode 100644 index 0000000..26bc968 --- /dev/null +++ b/potato-data/src/registry/item/components/tool.rs @@ -0,0 +1,40 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::{OneOrMany, TagOrIdentifier}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "tool")] +pub struct Tool { + #[serde(default = "onef")] + pub default_mining_speed: f32, + #[serde(default = "one")] + pub damage_per_block: i32, + #[serde(default = "r#true")] + pub can_destroy_blocks_in_creative: bool, + pub rules: Vec, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct ToolRule { + pub blocks: OneOrMany, + pub speed: Option, + #[serde(default = "r#false")] + pub corect_for_drops: bool, +} + +fn onef() -> f32 { + 1.0 +} + +fn one() -> i32 { + 1 +} + +fn r#true() -> bool { + true +} + +fn r#false() -> bool { + true +} diff --git a/potato-data/src/registry/item/components/tooltip_display.rs b/potato-data/src/registry/item/components/tooltip_display.rs new file mode 100644 index 0000000..bea0a18 --- /dev/null +++ b/potato-data/src/registry/item/components/tooltip_display.rs @@ -0,0 +1,12 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::identifier::Identifier; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "tooltip_display")] +pub struct TooltipDisplay { + pub hide_tooltip: Option, + #[serde(default)] + pub hidden_components: Vec, +} diff --git a/potato-data/src/registry/item/components/tooltip_style.rs b/potato-data/src/registry/item/components/tooltip_style.rs new file mode 100644 index 0000000..e146928 --- /dev/null +++ b/potato-data/src/registry/item/components/tooltip_style.rs @@ -0,0 +1,8 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::identifier::Identifier; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "tooltip_style")] +pub struct TooltipStyle(pub Identifier); diff --git a/potato-data/src/registry/item/components/trim.rs b/potato-data/src/registry/item/components/trim.rs new file mode 100644 index 0000000..727f8d0 --- /dev/null +++ b/potato-data/src/registry/item/components/trim.rs @@ -0,0 +1,11 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::identifier::Identifier; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "trim")] +pub struct Trim { + pub pattern: Identifier, + pub material: Identifier, +} diff --git a/potato-data/src/registry/item/components/tropical_fish_base_color.rs b/potato-data/src/registry/item/components/tropical_fish_base_color.rs new file mode 100644 index 0000000..88abb4d --- /dev/null +++ b/potato-data/src/registry/item/components/tropical_fish_base_color.rs @@ -0,0 +1,7 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "tropical_fish/base_color")] +// TODO: dye color type +pub struct TropicalFishBaseColor(pub String); diff --git a/potato-data/src/registry/item/components/tropical_fish_pattern.rs b/potato-data/src/registry/item/components/tropical_fish_pattern.rs new file mode 100644 index 0000000..e4d5f3d --- /dev/null +++ b/potato-data/src/registry/item/components/tropical_fish_pattern.rs @@ -0,0 +1,20 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "tropical_fish/pattern")] +#[serde(rename_all = "snake_case")] +pub enum TropicalFishPattern { + Kob, + Sunstreak, + Snooper, + Dasher, + Brinely, + Spotty, + Flopper, + Stripey, + Glitter, + Blockfish, + Betty, + Clayfish, +} diff --git a/potato-data/src/registry/item/components/tropical_fish_pattern_color.rs b/potato-data/src/registry/item/components/tropical_fish_pattern_color.rs new file mode 100644 index 0000000..93f90b7 --- /dev/null +++ b/potato-data/src/registry/item/components/tropical_fish_pattern_color.rs @@ -0,0 +1,7 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "tropical_fish/pattern_color")] +// TODO: dye color type +pub struct TropicalFishPatternColor(pub String); diff --git a/potato-data/src/registry/item/components/unbreakable.rs b/potato-data/src/registry/item/components/unbreakable.rs new file mode 100644 index 0000000..6902d37 --- /dev/null +++ b/potato-data/src/registry/item/components/unbreakable.rs @@ -0,0 +1,6 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "unbreakable")] +pub struct Unbreakable {} diff --git a/potato-data/src/registry/item/components/use_cooldown.rs b/potato-data/src/registry/item/components/use_cooldown.rs new file mode 100644 index 0000000..f93a5c0 --- /dev/null +++ b/potato-data/src/registry/item/components/use_cooldown.rs @@ -0,0 +1,11 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::identifier::Identifier; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "use_cooldown")] +pub struct UseCooldown { + pub seconds: f32, + pub cooldown_group: Option, +} diff --git a/potato-data/src/registry/item/components/use_remainder.rs b/potato-data/src/registry/item/components/use_remainder.rs new file mode 100644 index 0000000..aaf6670 --- /dev/null +++ b/potato-data/src/registry/item/components/use_remainder.rs @@ -0,0 +1,8 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::item_stack::ItemStack; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "use_remainder")] +pub struct UseRemainder(pub ItemStack); diff --git a/potato-data/src/registry/item/components/villager_variant.rs b/potato-data/src/registry/item/components/villager_variant.rs new file mode 100644 index 0000000..c9fe471 --- /dev/null +++ b/potato-data/src/registry/item/components/villager_variant.rs @@ -0,0 +1,8 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::identifier::Identifier; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "villager/variant")] +pub struct VillagerVariant(pub Identifier); diff --git a/potato-data/src/registry/item/components/weapon.rs b/potato-data/src/registry/item/components/weapon.rs new file mode 100644 index 0000000..09114b2 --- /dev/null +++ b/potato-data/src/registry/item/components/weapon.rs @@ -0,0 +1,19 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "weapon")] +pub struct Weapon { + #[serde(default = "one")] + pub item_damage_per_attack: i32, + #[serde(default = "zero")] + pub disable_blocking_for_seconds: f32, +} + +fn zero() -> f32 { + 0.0 +} + +fn one() -> i32 { + 1 +} diff --git a/potato-data/src/registry/item/components/wolf_collar.rs b/potato-data/src/registry/item/components/wolf_collar.rs new file mode 100644 index 0000000..38bb9a4 --- /dev/null +++ b/potato-data/src/registry/item/components/wolf_collar.rs @@ -0,0 +1,9 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::identifier::Identifier; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "wolf/collar")] +// TODO: dye color type +pub struct WolfCollar(pub String); diff --git a/potato-data/src/registry/item/components/wolf_sound_variant.rs b/potato-data/src/registry/item/components/wolf_sound_variant.rs new file mode 100644 index 0000000..2526534 --- /dev/null +++ b/potato-data/src/registry/item/components/wolf_sound_variant.rs @@ -0,0 +1,7 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "wolf/sound_variant")] +// TODO: What is the type of this? +pub struct WolfSoundVariant(pub String); diff --git a/potato-data/src/registry/item/components/wolf_variant.rs b/potato-data/src/registry/item/components/wolf_variant.rs new file mode 100644 index 0000000..99330fa --- /dev/null +++ b/potato-data/src/registry/item/components/wolf_variant.rs @@ -0,0 +1,8 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::identifier::Identifier; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "wolf/variant")] +pub struct WolfVariant(pub Identifier); diff --git a/potato-data/src/registry/item/components/writable_book_content.rs b/potato-data/src/registry/item/components/writable_book_content.rs new file mode 100644 index 0000000..04aaa4a --- /dev/null +++ b/potato-data/src/registry/item/components/writable_book_content.rs @@ -0,0 +1,17 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::Either; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "writable_book_content")] +pub struct WritableBookContent { + #[serde(default)] + pub pages: Vec>, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct WritableBookPage { + pub raw: String, + pub filtered: Option, +} diff --git a/potato-data/src/registry/item/components/written_book_content.rs b/potato-data/src/registry/item/components/written_book_content.rs new file mode 100644 index 0000000..0cb94fd --- /dev/null +++ b/potato-data/src/registry/item/components/written_book_content.rs @@ -0,0 +1,42 @@ +use potato_derive::ItemComponent; +use serde::{Deserialize, Serialize}; + +use crate::{Either, text_component::TextComponent}; + +#[derive(Debug, Serialize, Deserialize, Clone, ItemComponent)] +#[item_component(namespace = "minecraft", id = "written_book_content")] +pub struct WrittenBookContent { + pub pages: Vec>, + pub title: WrittenBookTitle, + pub author: String, + #[serde(default)] + pub generation: BookGeneration, + #[serde(default = "r#false")] + pub resolved: bool, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct WrittenBookPage { + pub raw: TextComponent, + pub filtered: Option, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct WrittenBookTitle { + pub raw: String, + pub filtered: Option, +} + +#[derive(Debug, Serialize, Deserialize, Default, Clone)] +#[repr(i32)] +pub enum BookGeneration { + #[default] + Original = 0, + CopyOfOriginal = 1, + CopyOfCopy = 2, + Tattered = 3, +} + +fn r#false() -> bool { + false +} diff --git a/potato-data/src/registry/item/mod.rs b/potato-data/src/registry/item/mod.rs new file mode 100644 index 0000000..50ad8be --- /dev/null +++ b/potato-data/src/registry/item/mod.rs @@ -0,0 +1,65 @@ +pub mod component_map; +pub mod components; + +use std::{any::Any, fmt::Debug, sync::Arc}; + +use component_map::ItemComponentMap; +use serde::{ + Deserialize, Deserializer, Serialize, + de::{self, DeserializeSeed}, +}; + +use crate::identifier::Identifier; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Item { + pub protocol_id: i32, + pub components: ItemComponentMap, +} + +pub trait ItemComponent: Debug + Any + erased_serde::Serialize + Send + Sync { + fn id(&self) -> Identifier; + + fn cloned(&self) -> Box; + + fn deserialize( + deserializer: &mut dyn erased_serde::Deserializer, + ) -> erased_serde::Result> + where + Self: Sized; +} + +erased_serde::serialize_trait_object!(ItemComponent); + +impl Clone for Box { + fn clone(&self) -> Self { + self.cloned() + } +} + +#[derive(Clone)] +pub struct ItemComponentCreator { + pub deserialize: Arc< + dyn Fn(&mut dyn erased_serde::Deserializer) -> erased_serde::Result> + + Send + + Sync, + >, +} + +impl Debug for ItemComponentCreator { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("ItemComponentCreator").finish() + } +} + +impl<'de> DeserializeSeed<'de> for &ItemComponentCreator { + type Value = Box; + + fn deserialize(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let mut deserializer = ::erase(deserializer); + (self.deserialize)(&mut deserializer).map_err(de::Error::custom) + } +} diff --git a/potato-data/src/registry/mod.rs b/potato-data/src/registry/mod.rs index 04333a3..6cea0e8 100644 --- a/potato-data/src/registry/mod.rs +++ b/potato-data/src/registry/mod.rs @@ -1,9 +1,11 @@ -use std::collections::HashMap; +use std::{collections::HashMap, sync::OnceLock}; +use advancement::Advancement; use banner_pattern::BannerPattern; use chat_type::ChatType; use damage_type::DamageType; use dimension_type::DimensionType; +use item::{Item, ItemComponentCreator}; use painting_variant::PaintingVariant; use thiserror::Error; use trim_material::TrimMaterial; @@ -13,19 +15,28 @@ use worldgen::biome::Biome; use crate::{TagOrIdentifier, identifier::Identifier, tag::Tag}; +pub mod advancement; pub mod banner_pattern; pub mod chat_type; pub mod damage_type; pub mod dimension_type; +pub mod item; pub mod painting_variant; pub mod trim_material; pub mod trim_pattern; pub mod wolf_variant; pub mod worldgen; +pub static STATIC_REGISTRIES: OnceLock = OnceLock::new(); + +#[derive(Default)] +pub struct StaticRegistries { + pub item_components: Registry, +} + #[derive(Default)] pub struct Registries { - // advancement + // pub advancements: Registry, pub banner_patterns: Registry, pub chat_types: Registry, pub damage_types: Registry, @@ -45,6 +56,8 @@ pub struct Registries { pub trim_patterns: Registry, pub wolf_variants: Registry, pub worldgen: WorldgenRegistries, + + pub items: Registry, } impl Registries { @@ -77,6 +90,7 @@ pub enum RegistryError { DuplicateKey(Identifier), } +#[derive(Debug)] pub struct Registry where T: Clone, @@ -90,7 +104,8 @@ where // Identifier -> T by_key: HashMap, - tags: HashMap>, + tags: HashMap>, + raw_tags: HashMap>, } impl Default for Registry @@ -104,6 +119,7 @@ where to_id: Default::default(), by_key: Default::default(), tags: Default::default(), + raw_tags: Default::default(), } } } @@ -112,6 +128,10 @@ impl Registry where T: Clone, { + pub fn by_key(&self, key: &Identifier) -> Option<&T> { + self.by_key.get(key) + } + pub fn register(&mut self, key: Identifier, value: T) -> Result<(), RegistryError> { if self.to_id.contains_key(&key) { return Err(RegistryError::DuplicateKey(key)); @@ -126,18 +146,40 @@ where } pub fn register_tag(&mut self, tag: Tag, entries: Vec) { - match self.tags.get_mut(&tag) { + match self.raw_tags.get_mut(&tag) { Some(values) => { values.extend(entries); } None => { - self.tags.insert(tag, entries); + self.raw_tags.insert(tag, entries); } } } pub fn replace_tag(&mut self, tag: Tag, entries: Vec) { - self.tags.insert(tag, entries); + self.raw_tags.insert(tag, entries); + } + + // TODO: Allow tags to reference other tags + pub fn flatten_tags(&mut self) { + self.raw_tags + .iter() + .map(|(tag, value)| { + ( + tag, + value.iter().flat_map(|value| match value { + TagOrIdentifier::Tag(_tag) => vec![], + TagOrIdentifier::Identifier(identifier) => vec![identifier.clone()], + }), + ) + }) + .for_each(|(tag, values)| { + self.tags.insert(tag.clone(), values.collect()); + }); + } + + pub fn get_tag(&self, tag: Tag) -> Option<&Vec> { + self.tags.get(&tag) } pub fn len(&self) -> usize { @@ -152,7 +194,19 @@ where self.by_id.is_empty() } + pub fn tags_is_empty(&self) -> bool { + self.tags.is_empty() + } + pub fn iter(&self) -> impl Iterator { self.id_to_key.iter().zip(self.by_id.iter()) } + + pub fn tags_iter(&self) -> impl Iterator)> { + self.tags.iter() + } + + pub fn get_id_for_key(&self, key: &Identifier) -> Option { + self.to_id.get(key).cloned() + } } diff --git a/potato-data/src/status_effect.rs b/potato-data/src/status_effect.rs new file mode 100644 index 0000000..664f72d --- /dev/null +++ b/potato-data/src/status_effect.rs @@ -0,0 +1,34 @@ +use serde::{Deserialize, Serialize}; + +use crate::identifier::Identifier; + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct StatusEffect { + pub id: Identifier, + #[serde(default = "zero")] + pub amplifier: u8, + #[serde(default = "one")] + pub duration: i32, + #[serde(default = "r#false")] + pub ambient: bool, + #[serde(default = "r#true")] + pub show_particles: bool, + #[serde(default = "r#true")] + pub show_icon: bool, +} + +fn zero() -> u8 { + 0 +} + +fn one() -> i32 { + 1 +} + +fn r#true() -> bool { + true +} + +fn r#false() -> bool { + false +} diff --git a/potato-data/src/tag.rs b/potato-data/src/tag.rs index eada051..9734d90 100644 --- a/potato-data/src/tag.rs +++ b/potato-data/src/tag.rs @@ -6,7 +6,7 @@ use crate::identifier::{Identifier, IdentifierError}; // TODO: Needs to serialize/deserialize as the identifier with a hash in front. #[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)] #[serde(try_from = "&str", into = "String")] -pub struct Tag(Identifier); +pub struct Tag(pub Identifier); impl Tag { pub fn new(namespace: String, path: String) -> Self { diff --git a/potato-data/src/text_component.rs b/potato-data/src/text_component.rs index 38794bc..f06b097 100644 --- a/potato-data/src/text_component.rs +++ b/potato-data/src/text_component.rs @@ -1,25 +1,41 @@ use serde::{Deserialize, Serialize}; -use crate::{Either, identifier::Identifier, item_stack::ItemComponent}; +use crate::{Either, identifier::Identifier, registry::item::component_map::ItemComponentMap}; -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct TextComponent { // Content #[serde(flatten)] pub content: TextComponentContent, // Children - #[serde(default)] - pub extra: Vec, + pub extra: Option>, // Formatting #[serde(flatten)] pub style: TextComponentStyle, // Interactivity pub insertion: Option, - #[serde(rename = "clickEvent")] pub click_event: Option, + pub hover_event: Option, } -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +impl TextComponent { + // This is not the same function + #[allow(clippy::should_implement_trait)] + pub fn from_str(str: &str) -> Self { + TextComponent { + content: TextComponentContent::Text(TextComponentText { + text: str.to_string(), + }), + extra: None, + style: Default::default(), + insertion: None, + click_event: None, + hover_event: None, + } + } +} + +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Default)] pub struct TextComponentStyle { pub color: Option, pub font: Option, @@ -41,7 +57,7 @@ pub enum ClickEvent { CopyToClipboard(String), } -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +#[derive(Debug, Serialize, Deserialize, Clone)] #[serde(tag = "action", content = "contents", rename_all = "snake_case")] pub enum HoverEvent { ShowText(Box), @@ -49,7 +65,7 @@ pub enum HoverEvent { id: Identifier, count: Option, #[serde(default)] - components: Vec, + components: ItemComponentMap, }, ShowEntity { // NOTE: Not sure if this is a TextComponent or just a string. @@ -60,7 +76,7 @@ pub enum HoverEvent { }, } -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +#[derive(Debug, Serialize, Deserialize, Clone)] #[serde(untagged)] pub enum TextComponentContent { Text(TextComponentText), @@ -77,7 +93,7 @@ pub struct TextComponentText { pub text: String, } -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +#[derive(Debug, Serialize, Deserialize, Clone)] #[serde(tag = "type", rename = "translatable")] pub struct TextComponentTranslatable { pub translate: String, @@ -97,7 +113,7 @@ pub struct TextComponentScoreInner { pub objective: String, } -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +#[derive(Debug, Serialize, Deserialize, Clone)] #[serde(tag = "type", rename = "selector")] pub struct TextComponentSelector { pub selector: String, @@ -112,7 +128,7 @@ pub struct TextComponentKeybind { // for the client. } -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +#[derive(Debug, Serialize, Deserialize, Clone)] #[serde(tag = "type", rename = "nbt")] pub struct TextComponentNbt { pub source: String, @@ -125,42 +141,3 @@ pub struct TextComponentNbt { pub entity: Option, pub storage: Option, } - -#[cfg(test)] -mod test { - use crate::text_component::*; - - #[test] - fn test_text_component() { - let text = r#"{"text":"Hello, world!"}"#; - let text_component: TextComponent = serde_json::from_str(text).unwrap(); - assert_eq!( - text_component, - TextComponent { - content: TextComponentContent::Text(TextComponentText { - text: "Hello, world!".to_string(), - }), - } - ); - } - - #[test] - fn test_translatable_text_component() { - let text = r#"{"translate":"chat.type.text","with":[{"text":"Hello, world!"}]}"#; - let text_component: TextComponent = serde_json::from_str(text).unwrap(); - assert_eq!( - text_component, - TextComponent { - content: TextComponentContent::Translatable(TextComponentTranslatable { - translate: "chat.type.text".to_string(), - fallback: None, - with: Some(vec![TextComponent { - content: TextComponentContent::Text(TextComponentText { - text: "Hello, world!".to_string(), - }), - }]), - }), - } - ); - } -} diff --git a/potato-protocol-derive/Cargo.toml b/potato-derive/Cargo.toml similarity index 66% rename from potato-protocol-derive/Cargo.toml rename to potato-derive/Cargo.toml index 2669da1..8b1184f 100644 --- a/potato-protocol-derive/Cargo.toml +++ b/potato-derive/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "potato-protocol-derive" +name = "potato-derive" version.workspace = true edition.workspace = true @@ -7,7 +7,7 @@ edition.workspace = true darling = "0.20.10" proc-macro2 = "1.0.94" quote = "1.0.39" -syn = "2.0.99" +syn = { version = "2.0.99", features = ["full", "visit"] } [lib] proc-macro = true diff --git a/potato-derive/src/lib.rs b/potato-derive/src/lib.rs new file mode 100644 index 0000000..0476ba1 --- /dev/null +++ b/potato-derive/src/lib.rs @@ -0,0 +1,86 @@ +#![recursion_limit = "128"] + +use darling::FromDeriveInput; +use protocol::{PacketOpts, generate_packet_encodable_impl, generate_packet_impl}; + +#[macro_use] +extern crate quote; + +mod protocol; + +#[proc_macro_derive(Packet, attributes(packet))] +pub fn packet_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let ast = syn::parse(input).unwrap(); + let opts = PacketOpts::from_derive_input(&ast).expect("Wrong options"); + let packet_encodable_impl = generate_packet_encodable_impl(&ast); + let packet_impl = generate_packet_impl(&ast, opts); + + quote! { + #packet_encodable_impl + #packet_impl + } + .into() +} + +#[proc_macro_derive(PacketEncodable, attributes(packet))] +pub fn packet_encodable_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let ast = syn::parse(input).unwrap(); + let generated = generate_packet_encodable_impl(&ast); + + generated.into() +} + +#[proc_macro_derive(JsonString)] +pub fn json_string_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let ast: syn::DeriveInput = syn::parse(input).unwrap(); + let ident = &ast.ident; + + quote! { + impl crate::packet_encodable::JsonString for #ident {} + } + .into() +} + +#[derive(FromDeriveInput)] +#[darling(attributes(item_component))] +struct ItemComponentOpts { + pub namespace: String, + pub id: String, +} + +#[proc_macro_derive(ItemComponent, attributes(item_component))] +pub fn item_component_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let ast: syn::DeriveInput = syn::parse(input).unwrap(); + let opts = ItemComponentOpts::from_derive_input(&ast).expect("Wrong options"); + let ident = &ast.ident; + + let namespace = opts.namespace; + let id = opts.id; + + quote! { + impl #ident { + pub const ID: crate::identifier::Identifier = crate::identifier::Identifier::new_const(#namespace, #id); + } + + impl crate::registry::item::ItemComponent for #ident { + fn id(&self) -> crate::identifier::Identifier { + Self::ID + + } + fn cloned(&self) -> Box { + Box::new(self.clone()) + } + + fn deserialize( + deserializer: &mut dyn erased_serde::Deserializer, + ) -> erased_serde::Result> + where + Self: Sized, + { + let deserialized: Self = erased_serde::deserialize(deserializer)?; + Ok(Box::new(deserialized)) + } + } + } + .into() +} diff --git a/potato-protocol-derive/src/lib.rs b/potato-derive/src/protocol.rs similarity index 80% rename from potato-protocol-derive/src/lib.rs rename to potato-derive/src/protocol.rs index 9b0170d..0126c14 100644 --- a/potato-protocol-derive/src/lib.rs +++ b/potato-derive/src/protocol.rs @@ -1,17 +1,13 @@ -#![recursion_limit = "128"] - use darling::{FromDeriveInput, FromVariant}; use quote::ToTokens; use syn::Path; extern crate proc_macro; extern crate syn; -#[macro_use] -extern crate quote; #[derive(FromDeriveInput)] #[darling(attributes(packet))] -struct PacketOpts { +pub struct PacketOpts { handshake_id: Option, status_id: Option, login_id: Option, @@ -19,40 +15,7 @@ struct PacketOpts { play_id: Option, } -#[proc_macro_derive(Packet, attributes(packet))] -pub fn packet_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - let ast = syn::parse(input).unwrap(); - let opts = PacketOpts::from_derive_input(&ast).expect("Wrong options"); - let packet_encodable_impl = generate_packet_encodable_impl(&ast); - let packet_impl = generate_packet_impl(&ast, opts); - - quote! { - #packet_encodable_impl - #packet_impl - } - .into() -} - -#[proc_macro_derive(PacketEncodable, attributes(packet))] -pub fn packet_encodable_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - let ast = syn::parse(input).unwrap(); - let generated = generate_packet_encodable_impl(&ast); - - generated.into() -} - -#[proc_macro_derive(JsonString)] -pub fn json_string_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - let ast: syn::DeriveInput = syn::parse(input).unwrap(); - let ident = &ast.ident; - - quote! { - impl crate::packet_encodable::JsonString for #ident {} - } - .into() -} - -fn generate_packet_impl( +pub fn generate_packet_impl( ast: &syn::DeriveInput, packet_opts: PacketOpts, ) -> proc_macro2::TokenStream { @@ -94,7 +57,7 @@ fn generate_packet_impl( } } -fn generate_packet_encodable_impl(ast: &syn::DeriveInput) -> proc_macro2::TokenStream { +pub fn generate_packet_encodable_impl(ast: &syn::DeriveInput) -> proc_macro2::TokenStream { match ast.data { syn::Data::Enum(syn::DataEnum { ref variants, .. }) => { generate_packet_encodable_enum_impl(ast, variants) diff --git a/potato-protocol/Cargo.toml b/potato-protocol/Cargo.toml index e6c7728..a511c31 100644 --- a/potato-protocol/Cargo.toml +++ b/potato-protocol/Cargo.toml @@ -5,7 +5,7 @@ edition.workspace = true [dependencies] potato-data = { path = "../potato-data" } -potato-protocol-derive = { path = "../potato-protocol-derive" } +potato-derive = { path = "../potato-derive" } serde.workspace = true serde_json.workspace = true @@ -13,13 +13,10 @@ thiserror.workspace = true uuid.workspace = true bytes.workspace = true tokio.workspace = true +fastnbt.workspace = true byteorder = "1.5.0" -# Build from git, since there has not been a release in over a year -# Original repo: https://github.com/owengage/fastnbt.git Using a fork -# to fix an issue with boolean serialization. -fastnbt = { git = "https://github.com/CheAle14/fastnbt.git" } [build-dependencies] serde.workspace = true diff --git a/potato-protocol/src/datatypes/bit_set.rs b/potato-protocol/src/datatypes/bit_set.rs new file mode 100644 index 0000000..f8e0646 --- /dev/null +++ b/potato-protocol/src/datatypes/bit_set.rs @@ -0,0 +1,79 @@ +use bytes::{Buf, BufMut}; + +use crate::packet_encodable::{PacketDecodeError, PacketEncodable, PacketEncodeError}; + +use super::var_int::VarInt; + +#[derive(Debug, Default)] +pub struct BitSet { + storage: Vec, +} + +fn position_for_index(i: usize) -> (usize, usize) { + // (Data[i / 64] & (1 << (i % 64))) != 0 + (i / 64, i % 64) +} + +impl BitSet { + pub fn new() -> BitSet { + Default::default() + } + + pub fn from_vec(vec: Vec) -> BitSet { + BitSet { storage: vec } + } + + pub fn insert(&mut self, i: usize) { + let (vec, bit) = position_for_index(i); + if self.storage.len() < vec { + let needed = vec - self.storage.len(); + self.storage.reserve(needed); + for _ in 0..needed { + self.storage.push(0); + } + } + + // The unwrap is safe here, since we ensure we have an entry at the position + let target = self.storage.get_mut(vec).unwrap(); + *target |= 1 << bit; + } + + pub fn remove(&mut self, i: usize) { + let (vec, bit) = position_for_index(i); + if let Some(target) = self.storage.get_mut(vec) { + *target &= !(1 << bit) + } + } + + pub fn contains(&mut self, i: usize) -> bool { + let (vec, bit) = position_for_index(i); + if let Some(target) = self.storage.get(vec) { + target & (1 << bit) != 0 + } else { + false + } + } +} + +impl PacketEncodable for BitSet { + fn encode_packet(&self, buf: &mut impl BufMut) -> Result<(), PacketEncodeError> { + let length: VarInt = self.storage.len().into(); + length.encode_packet(buf)?; + for block in self.storage.iter() { + block.encode_packet(buf)?; + } + + Ok(()) + } + + fn decode_packet(buf: &mut impl Buf) -> Result { + let length = VarInt::decode_packet(buf)?.into(); + + let mut storage = Vec::with_capacity(length); + for _ in 0..length { + storage.push(buf.get_u64()); + } + + Ok(BitSet { storage }) + } +} diff --git a/potato-protocol/src/datatypes/mod.rs b/potato-protocol/src/datatypes/mod.rs index fd16dcb..2878a27 100644 --- a/potato-protocol/src/datatypes/mod.rs +++ b/potato-protocol/src/datatypes/mod.rs @@ -1,3 +1,4 @@ +pub mod bit_set; pub mod byte_array; pub mod pack; pub mod position; diff --git a/potato-protocol/src/datatypes/pack.rs b/potato-protocol/src/datatypes/pack.rs index dde9a5d..a6bb33f 100644 --- a/potato-protocol/src/datatypes/pack.rs +++ b/potato-protocol/src/datatypes/pack.rs @@ -1,4 +1,4 @@ -use potato_protocol_derive::PacketEncodable; +use potato_derive::PacketEncodable; #[derive(Debug, PacketEncodable)] pub struct Pack { diff --git a/potato-protocol/src/packet/clientbound/disconnect.rs b/potato-protocol/src/packet/clientbound/disconnect.rs new file mode 100644 index 0000000..d8bfe94 --- /dev/null +++ b/potato-protocol/src/packet/clientbound/disconnect.rs @@ -0,0 +1,13 @@ +use potato_data::text_component::TextComponent; +use potato_derive::Packet; + +use crate::packet_encodable::Nbt; + +#[derive(Debug, Packet)] +#[packet( + configuration_id = crate::ids::configuration::clientbound::DISCONNECT, + play_id = crate::ids::play::clientbound::DISCONNECT, +)] +pub struct DisconnectPacket { + pub reason: Nbt, +} diff --git a/potato-protocol/src/packet/clientbound/finish_configuration.rs b/potato-protocol/src/packet/clientbound/finish_configuration.rs index 66031a5..38d2c84 100644 --- a/potato-protocol/src/packet/clientbound/finish_configuration.rs +++ b/potato-protocol/src/packet/clientbound/finish_configuration.rs @@ -1,4 +1,4 @@ -use potato_protocol_derive::Packet; +use potato_derive::Packet; #[derive(Debug, Packet)] #[packet(configuration_id = crate::ids::configuration::clientbound::FINISH_CONFIGURATION)] diff --git a/potato-protocol/src/packet/clientbound/game_event.rs b/potato-protocol/src/packet/clientbound/game_event.rs index b986b9f..1dbabb3 100644 --- a/potato-protocol/src/packet/clientbound/game_event.rs +++ b/potato-protocol/src/packet/clientbound/game_event.rs @@ -1,4 +1,4 @@ -use potato_protocol_derive::Packet; +use potato_derive::Packet; #[derive(Debug, Packet)] #[packet(play_id = crate::ids::play::clientbound::GAME_EVENT)] diff --git a/potato-protocol/src/packet/clientbound/keep_alive.rs b/potato-protocol/src/packet/clientbound/keep_alive.rs index 1ec362b..8b253de 100644 --- a/potato-protocol/src/packet/clientbound/keep_alive.rs +++ b/potato-protocol/src/packet/clientbound/keep_alive.rs @@ -1,4 +1,4 @@ -use potato_protocol_derive::Packet; +use potato_derive::Packet; #[derive(Debug, Packet)] #[packet( diff --git a/potato-protocol/src/packet/clientbound/level_chunk_with_light.rs b/potato-protocol/src/packet/clientbound/level_chunk_with_light.rs new file mode 100644 index 0000000..cdd68aa --- /dev/null +++ b/potato-protocol/src/packet/clientbound/level_chunk_with_light.rs @@ -0,0 +1,52 @@ +use fastnbt::LongArray; +use potato_derive::{Packet, PacketEncodable}; +use serde::{Deserialize, Serialize}; + +use crate::{ + datatypes::{bit_set::BitSet, var_int::VarInt}, + packet_encodable::Nbt, +}; + +#[derive(Debug, Packet)] +#[packet(play_id = crate::ids::play::clientbound::LEVEL_CHUNK_WITH_LIGHT)] +pub struct LevelChunkWithLightPacket { + pub chunk_x: i32, + pub chink_z: i32, + pub data: ChunkData, + pub light: LightData, +} + +#[derive(Debug, PacketEncodable)] +pub struct ChunkData { + pub heightmaps: Nbt, + pub data: Vec, + pub block_entities: Vec, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +pub struct ChunkHeightmaps { + // pub motion_blocking: LongArray, + // pub world_surface: LongArray, +} + +type Something = i32; + +#[derive(Debug, PacketEncodable)] +pub struct ChunkBlockEntity { + pub packed_xz: u8, + pub y: i16, + pub ty: VarInt, + // TODO: This needs an actual type + pub data: Nbt, +} + +#[derive(Debug, PacketEncodable)] +pub struct LightData { + pub sky_light_mask: BitSet, + pub block_light_mask: BitSet, + pub empty_sky_light_mask: BitSet, + pub empty_block_light_mask: BitSet, + pub sky_light: Vec>, + pub block_light: Vec>, +} diff --git a/potato-protocol/src/packet/clientbound/login.rs b/potato-protocol/src/packet/clientbound/login.rs index 7d2f9ad..6234446 100644 --- a/potato-protocol/src/packet/clientbound/login.rs +++ b/potato-protocol/src/packet/clientbound/login.rs @@ -1,5 +1,5 @@ use potato_data::identifier::Identifier; -use potato_protocol_derive::{Packet, PacketEncodable}; +use potato_derive::{Packet, PacketEncodable}; use crate::datatypes::{position::Position, var_int::VarInt}; diff --git a/potato-protocol/src/packet/clientbound/login_disconnect.rs b/potato-protocol/src/packet/clientbound/login_disconnect.rs index b9007a3..0dafd24 100644 --- a/potato-protocol/src/packet/clientbound/login_disconnect.rs +++ b/potato-protocol/src/packet/clientbound/login_disconnect.rs @@ -1,4 +1,4 @@ -use potato_protocol_derive::Packet; +use potato_derive::Packet; #[derive(Packet, Debug)] #[packet(login_id = crate::ids::login::clientbound::LOGIN_DISCONNECT)] diff --git a/potato-protocol/src/packet/clientbound/login_finished.rs b/potato-protocol/src/packet/clientbound/login_finished.rs index 3b3dc18..fc7a074 100644 --- a/potato-protocol/src/packet/clientbound/login_finished.rs +++ b/potato-protocol/src/packet/clientbound/login_finished.rs @@ -1,4 +1,4 @@ -use potato_protocol_derive::{Packet, PacketEncodable}; +use potato_derive::{Packet, PacketEncodable}; use uuid::Uuid; #[derive(Packet, Debug)] diff --git a/potato-protocol/src/packet/clientbound/mod.rs b/potato-protocol/src/packet/clientbound/mod.rs index 457caf2..47a1f54 100644 --- a/potato-protocol/src/packet/clientbound/mod.rs +++ b/potato-protocol/src/packet/clientbound/mod.rs @@ -1,23 +1,30 @@ +pub mod disconnect; pub mod finish_configuration; pub mod game_event; pub mod keep_alive; +pub mod level_chunk_with_light; pub mod login; pub mod login_disconnect; pub mod login_finished; +pub mod player_position; pub mod pong_response; pub mod registry_data; pub mod select_known_packs; pub mod set_chunk_cache_center; pub mod status_response; +pub mod update_tags; +pub use disconnect::DisconnectPacket; pub use finish_configuration::FinishConfigurationPacket; pub use game_event::GameEventPacket; pub use keep_alive::KeepAlivePacket; pub use login::LoginPacket; pub use login_disconnect::LoginDisconnectPacket; pub use login_finished::LoginFinishedPacket; +pub use player_position::PlayerPositionPacket; pub use pong_response::PongResponsePacket; pub use registry_data::RegistryDataPacket; pub use select_known_packs::SelectKnownPacksPacket; pub use set_chunk_cache_center::SetChunkCacheCenterPacket; pub use status_response::StatusResponsePacket; +pub use update_tags::UpdateTagsPacket; diff --git a/potato-protocol/src/packet/clientbound/player_position.rs b/potato-protocol/src/packet/clientbound/player_position.rs new file mode 100644 index 0000000..c06a04b --- /dev/null +++ b/potato-protocol/src/packet/clientbound/player_position.rs @@ -0,0 +1,18 @@ +use potato_derive::Packet; + +use crate::datatypes::var_int::VarInt; + +#[derive(Debug, Packet)] +#[packet(play_id = crate::ids::play::clientbound::PLAYER_POSITION)] +pub struct PlayerPositionPacket { + pub id: VarInt, + pub x: f64, + pub y: f64, + pub z: f64, + pub vx: f64, + pub vy: f64, + pub vz: f64, + pub yaw: f32, + pub pitch: f32, + pub flags: u32, +} diff --git a/potato-protocol/src/packet/clientbound/pong_response.rs b/potato-protocol/src/packet/clientbound/pong_response.rs index f446ee7..a0fbb49 100644 --- a/potato-protocol/src/packet/clientbound/pong_response.rs +++ b/potato-protocol/src/packet/clientbound/pong_response.rs @@ -1,4 +1,4 @@ -use potato_protocol_derive::Packet; +use potato_derive::Packet; #[derive(Packet, Debug)] #[packet(status_id = crate::ids::status::clientbound::PONG_RESPONSE)] diff --git a/potato-protocol/src/packet/clientbound/registry_data.rs b/potato-protocol/src/packet/clientbound/registry_data.rs index af71476..b25894f 100644 --- a/potato-protocol/src/packet/clientbound/registry_data.rs +++ b/potato-protocol/src/packet/clientbound/registry_data.rs @@ -17,7 +17,7 @@ use potato_data::{ }, }, }; -use potato_protocol_derive::{Packet, PacketEncodable}; +use potato_derive::{Packet, PacketEncodable}; use serde::{Deserialize, Serialize}; use crate::packet_encodable::Nbt; diff --git a/potato-protocol/src/packet/clientbound/select_known_packs.rs b/potato-protocol/src/packet/clientbound/select_known_packs.rs index ff850ec..6bb7961 100644 --- a/potato-protocol/src/packet/clientbound/select_known_packs.rs +++ b/potato-protocol/src/packet/clientbound/select_known_packs.rs @@ -1,4 +1,4 @@ -use potato_protocol_derive::Packet; +use potato_derive::Packet; use crate::datatypes::pack::Pack; diff --git a/potato-protocol/src/packet/clientbound/set_chunk_cache_center.rs b/potato-protocol/src/packet/clientbound/set_chunk_cache_center.rs index 7311efd..265e522 100644 --- a/potato-protocol/src/packet/clientbound/set_chunk_cache_center.rs +++ b/potato-protocol/src/packet/clientbound/set_chunk_cache_center.rs @@ -1,4 +1,4 @@ -use potato_protocol_derive::Packet; +use potato_derive::Packet; use crate::datatypes::var_int::VarInt; diff --git a/potato-protocol/src/packet/clientbound/status_response.rs b/potato-protocol/src/packet/clientbound/status_response.rs index 551a7f2..425ddb3 100644 --- a/potato-protocol/src/packet/clientbound/status_response.rs +++ b/potato-protocol/src/packet/clientbound/status_response.rs @@ -1,4 +1,4 @@ -use potato_protocol_derive::Packet; +use potato_derive::Packet; use serde::{Deserialize, Serialize}; use crate::packet_encodable::Json; diff --git a/potato-protocol/src/packet/clientbound/update_tags.rs b/potato-protocol/src/packet/clientbound/update_tags.rs new file mode 100644 index 0000000..fc24098 --- /dev/null +++ b/potato-protocol/src/packet/clientbound/update_tags.rs @@ -0,0 +1,42 @@ +use potato_data::{identifier::Identifier, registry::Registry}; +use potato_derive::{Packet, PacketEncodable}; + +use crate::datatypes::var_int::VarInt; + +#[derive(Debug, Packet)] +#[packet(configuration_id = crate::ids::configuration::clientbound::UPDATE_TAGS)] +pub struct UpdateTagsPacket { + pub registries: Vec, +} + +#[derive(Debug, PacketEncodable)] +pub struct TagsForRegistry { + pub registry: Identifier, + pub tags: Vec, +} + +#[derive(Debug, PacketEncodable)] +pub struct Tag { + pub name: Identifier, + pub entries: Vec, +} + +impl TagsForRegistry { + pub fn from_registry(identifier: Identifier, registry: &Registry) -> Self { + Self { + registry: identifier, + tags: registry + .tags_iter() + .map(|(name, entries)| Tag { + name: name.0.clone(), + entries: entries + .iter() + // Unwrapping here should always be safe, since the id comes from the + // iterator over all keys in the registry. + .map(|id| registry.get_id_for_key(id).unwrap().into()) + .collect(), + }) + .collect(), + } + } +} diff --git a/potato-protocol/src/packet/mod.rs b/potato-protocol/src/packet/mod.rs index 5574411..2ae573e 100644 --- a/potato-protocol/src/packet/mod.rs +++ b/potato-protocol/src/packet/mod.rs @@ -23,6 +23,7 @@ pub trait Packet: PacketEncodable { } } +#[derive(Debug)] pub struct RawPacket { pub id: VarInt, pub data: Bytes, diff --git a/potato-protocol/src/packet/serverbound/accept_teleportation.rs b/potato-protocol/src/packet/serverbound/accept_teleportation.rs new file mode 100644 index 0000000..76f44b9 --- /dev/null +++ b/potato-protocol/src/packet/serverbound/accept_teleportation.rs @@ -0,0 +1,9 @@ +use potato_derive::Packet; + +use crate::datatypes::var_int::VarInt; + +#[derive(Debug, Packet)] +#[packet(play_id = crate::ids::play::serverbound::ACCEPT_TELEPORTATION)] +pub struct AcceptTeleportationPacket { + pub id: VarInt, +} diff --git a/potato-protocol/src/packet/serverbound/client_information.rs b/potato-protocol/src/packet/serverbound/client_information.rs index c85f957..59ff396 100644 --- a/potato-protocol/src/packet/serverbound/client_information.rs +++ b/potato-protocol/src/packet/serverbound/client_information.rs @@ -1,5 +1,5 @@ use bytes::{Buf, BufMut}; -use potato_protocol_derive::{Packet, PacketEncodable}; +use potato_derive::{Packet, PacketEncodable}; use crate::packet_encodable::{PacketDecodeError, PacketEncodable, PacketEncodeError}; diff --git a/potato-protocol/src/packet/serverbound/client_tick_end.rs b/potato-protocol/src/packet/serverbound/client_tick_end.rs index 962ab6a..ffa46d5 100644 --- a/potato-protocol/src/packet/serverbound/client_tick_end.rs +++ b/potato-protocol/src/packet/serverbound/client_tick_end.rs @@ -1,4 +1,4 @@ -use potato_protocol_derive::Packet; +use potato_derive::Packet; #[derive(Debug, Packet)] #[packet(play_id = crate::ids::play::serverbound::CLIENT_TICK_END)] diff --git a/potato-protocol/src/packet/serverbound/custom_payload.rs b/potato-protocol/src/packet/serverbound/custom_payload.rs index a5aac5e..c770936 100644 --- a/potato-protocol/src/packet/serverbound/custom_payload.rs +++ b/potato-protocol/src/packet/serverbound/custom_payload.rs @@ -1,4 +1,4 @@ -use potato_protocol_derive::Packet; +use potato_derive::Packet; use crate::datatypes::byte_array::ByteArray; diff --git a/potato-protocol/src/packet/serverbound/finish_configuration.rs b/potato-protocol/src/packet/serverbound/finish_configuration.rs index 6c7aa79..f68ee01 100644 --- a/potato-protocol/src/packet/serverbound/finish_configuration.rs +++ b/potato-protocol/src/packet/serverbound/finish_configuration.rs @@ -1,4 +1,4 @@ -use potato_protocol_derive::Packet; +use potato_derive::Packet; #[derive(Debug, Packet)] #[packet(configuration_id = crate::ids::configuration::serverbound::FINISH_CONFIGURATION)] diff --git a/potato-protocol/src/packet/serverbound/hello.rs b/potato-protocol/src/packet/serverbound/hello.rs index 3025c8a..d516ccc 100644 --- a/potato-protocol/src/packet/serverbound/hello.rs +++ b/potato-protocol/src/packet/serverbound/hello.rs @@ -1,4 +1,4 @@ -use potato_protocol_derive::Packet; +use potato_derive::Packet; use uuid::Uuid; #[derive(Debug, Packet)] diff --git a/potato-protocol/src/packet/serverbound/intention.rs b/potato-protocol/src/packet/serverbound/intention.rs index e42c913..47988c9 100644 --- a/potato-protocol/src/packet/serverbound/intention.rs +++ b/potato-protocol/src/packet/serverbound/intention.rs @@ -1,4 +1,4 @@ -use potato_protocol_derive::Packet; +use potato_derive::Packet; use crate::datatypes::var_int::VarInt; diff --git a/potato-protocol/src/packet/serverbound/keep_alive.rs b/potato-protocol/src/packet/serverbound/keep_alive.rs index 3baa854..5ebb923 100644 --- a/potato-protocol/src/packet/serverbound/keep_alive.rs +++ b/potato-protocol/src/packet/serverbound/keep_alive.rs @@ -1,4 +1,4 @@ -use potato_protocol_derive::Packet; +use potato_derive::Packet; #[derive(Debug, Packet)] #[packet( diff --git a/potato-protocol/src/packet/serverbound/login_acknowledged.rs b/potato-protocol/src/packet/serverbound/login_acknowledged.rs index d99a0b5..12913c4 100644 --- a/potato-protocol/src/packet/serverbound/login_acknowledged.rs +++ b/potato-protocol/src/packet/serverbound/login_acknowledged.rs @@ -1,4 +1,4 @@ -use potato_protocol_derive::Packet; +use potato_derive::Packet; #[derive(Packet, Debug)] #[packet(login_id = crate::ids::login::serverbound::LOGIN_ACKNOWLEDGED)] diff --git a/potato-protocol/src/packet/serverbound/mod.rs b/potato-protocol/src/packet/serverbound/mod.rs index c8dd7fb..0b2168e 100644 --- a/potato-protocol/src/packet/serverbound/mod.rs +++ b/potato-protocol/src/packet/serverbound/mod.rs @@ -1,3 +1,4 @@ +pub mod accept_teleportation; pub mod client_information; pub mod client_tick_end; pub mod custom_payload; @@ -13,6 +14,7 @@ pub mod ping_request; pub mod select_known_packs; pub mod status_request; +pub use accept_teleportation::AcceptTeleportationPacket; pub use client_information::ClientInformationPacket; pub use client_tick_end::ClientTickEndPacket; pub use custom_payload::CustomPayloadPacket; diff --git a/potato-protocol/src/packet/serverbound/move_player_pos.rs b/potato-protocol/src/packet/serverbound/move_player_pos.rs index 3593efa..a7eb034 100644 --- a/potato-protocol/src/packet/serverbound/move_player_pos.rs +++ b/potato-protocol/src/packet/serverbound/move_player_pos.rs @@ -1,4 +1,4 @@ -use potato_protocol_derive::Packet; +use potato_derive::Packet; #[derive(Debug, Packet)] #[packet(play_id = crate::ids::play::serverbound::MOVE_PLAYER_POS)] diff --git a/potato-protocol/src/packet/serverbound/move_player_pos_rot.rs b/potato-protocol/src/packet/serverbound/move_player_pos_rot.rs index e925007..babc3d1 100644 --- a/potato-protocol/src/packet/serverbound/move_player_pos_rot.rs +++ b/potato-protocol/src/packet/serverbound/move_player_pos_rot.rs @@ -1,4 +1,4 @@ -use potato_protocol_derive::Packet; +use potato_derive::Packet; #[derive(Debug, Packet)] #[packet(play_id = crate::ids::play::serverbound::MOVE_PLAYER_POS_ROT)] diff --git a/potato-protocol/src/packet/serverbound/move_player_rot.rs b/potato-protocol/src/packet/serverbound/move_player_rot.rs index 20fa6a3..d597adb 100644 --- a/potato-protocol/src/packet/serverbound/move_player_rot.rs +++ b/potato-protocol/src/packet/serverbound/move_player_rot.rs @@ -1,4 +1,4 @@ -use potato_protocol_derive::Packet; +use potato_derive::Packet; #[derive(Debug, Packet)] #[packet(play_id = crate::ids::play::serverbound::MOVE_PLAYER_ROT)] diff --git a/potato-protocol/src/packet/serverbound/ping_request.rs b/potato-protocol/src/packet/serverbound/ping_request.rs index 10a7458..43d54ad 100644 --- a/potato-protocol/src/packet/serverbound/ping_request.rs +++ b/potato-protocol/src/packet/serverbound/ping_request.rs @@ -1,4 +1,4 @@ -use potato_protocol_derive::Packet; +use potato_derive::Packet; #[derive(Packet, Debug)] #[packet(status_id = crate::ids::status::serverbound::PING_REQUEST)] diff --git a/potato-protocol/src/packet/serverbound/select_known_packs.rs b/potato-protocol/src/packet/serverbound/select_known_packs.rs index d3ed1de..f00f7ff 100644 --- a/potato-protocol/src/packet/serverbound/select_known_packs.rs +++ b/potato-protocol/src/packet/serverbound/select_known_packs.rs @@ -1,4 +1,4 @@ -use potato_protocol_derive::Packet; +use potato_derive::Packet; use crate::datatypes::pack::Pack; diff --git a/potato-protocol/src/packet/serverbound/status_request.rs b/potato-protocol/src/packet/serverbound/status_request.rs index 9e4441d..6c6330f 100644 --- a/potato-protocol/src/packet/serverbound/status_request.rs +++ b/potato-protocol/src/packet/serverbound/status_request.rs @@ -1,4 +1,4 @@ -use potato_protocol_derive::Packet; +use potato_derive::Packet; #[derive(Packet, Debug)] #[packet(status_id = crate::ids::status::serverbound::STATUS_REQUEST)] diff --git a/potato-protocol/src/packet_encodable/mod.rs b/potato-protocol/src/packet_encodable/mod.rs index 8d80ada..a83651c 100644 --- a/potato-protocol/src/packet_encodable/mod.rs +++ b/potato-protocol/src/packet_encodable/mod.rs @@ -152,16 +152,15 @@ where impl PacketEncodable for String { fn encode_packet(&self, buf: &mut impl BufMut) -> Result<(), PacketEncodeError> { - let lenght: VarInt = self.len().into(); - lenght.encode_packet(buf)?; - + let length: VarInt = self.len().into(); + length.encode_packet(buf)?; buf.put_slice(self.as_bytes()); Ok(()) } fn decode_packet(buf: &mut impl Buf) -> Result { - let lenght: usize = VarInt::decode_packet(buf)?.into(); - let mut buffer = vec![0; lenght]; + let length: usize = VarInt::decode_packet(buf)?.into(); + let mut buffer = vec![0; length]; buf.copy_to_slice(&mut buffer); let value = String::from_utf8(buffer)?; diff --git a/potato/Cargo.toml b/potato/Cargo.toml index cafddb6..c8673d8 100644 --- a/potato/Cargo.toml +++ b/potato/Cargo.toml @@ -13,3 +13,4 @@ thiserror.workspace = true tokio.workspace = true uuid.workspace = true bytes.workspace = true +fastnbt.workspace = true diff --git a/potato/src/connection.rs b/potato/src/connection.rs index 98d4224..84d76a2 100644 --- a/potato/src/connection.rs +++ b/potato/src/connection.rs @@ -1,9 +1,17 @@ -use std::{collections::VecDeque, net::SocketAddr, sync::Arc}; +use std::{ + collections::VecDeque, + net::SocketAddr, + sync::{ + Arc, + atomic::{AtomicBool, Ordering}, + }, +}; use bytes::{Buf, BytesMut}; use potato_data::{ identifier::Identifier, registry::{Registries, Registry}, + text_component::TextComponent, }; use potato_protocol::{ datatypes::{pack::Pack, var_int::VarInt}, @@ -13,6 +21,7 @@ use potato_protocol::{ self, GameEventPacket, SetChunkCacheCenterPacket, registry_data::{RegistryData, RegistryDataEntry}, status_response, + update_tags::TagsForRegistry, }, serverbound, }, @@ -28,13 +37,16 @@ use tokio::{ // Max packet size is 2MB in vanilla const RECV_BUFFER_SIZE: usize = 1024 * 1024 * 2; +#[derive(Debug)] pub struct Client { - address: SocketAddr, + pub address: SocketAddr, packet_sender: Sender, readable_stream: Mutex, - state: RwLock, + pub state: RwLock, recv_buffer: Mutex, - packet_queue: Mutex>, + pub packet_queue: Mutex>, + pub connected: AtomicBool, + pub convert_to_player: AtomicBool, } #[derive(Debug, Eq, PartialEq, Clone, Copy)] @@ -57,8 +69,6 @@ pub enum ConnectionError { EncodeError(#[from] PacketEncodeError), #[error("Client provided invalid next state")] InvalidNextState, - #[error("Finished")] - Finished, } impl Client { @@ -73,9 +83,21 @@ impl Client { state: RwLock::new(ConnectionState::Handshaking), recv_buffer: Mutex::new(BytesMut::new()), packet_queue: Mutex::new(VecDeque::new()), + connected: true.into(), + convert_to_player: false.into(), }) } + pub async fn disconnect(&self, reason: TextComponent) { + // Ignore the error, since we are already terminating the connection. + let _ = self + .try_send_packet(&clientbound::DisconnectPacket { + reason: Nbt(reason), + }) + .await; + self.connected.store(false, Ordering::Relaxed); + } + pub async fn needs_keep_alive(&self) -> bool { let state = self.state.read().await; *state == ConnectionState::Configuration || *state == ConnectionState::Play @@ -123,9 +145,24 @@ impl Client { Ok(RawPacket { id, data }) } - pub async fn send_packet(&self, packet: &T) -> Result<(), ConnectionError> { + pub async fn send_packet(&self, packet: &T) { + if let Err(e) = self.try_send_packet(packet).await { + println!("[{}] Error while sending packet: {}", self.address, e); + self.disconnect(TextComponent::from_str( + "There was an error while sending a packet", + )) + .await; + } + } + + pub async fn try_send_packet(&self, packet: &T) -> Result<(), ConnectionError> { + if !self.connected.load(Ordering::Relaxed) { + println!("tried to send packet while connection was closed"); + return Ok(()); + } + let state = { *self.state.read().await }; - println!("[{} ({:?})] -> {:?}", self.address, state, packet); + // println!("[{} ({:?})] -> {:?}", self.address, state, packet); let mut buffer = BytesMut::new(); // Encode ID let packet_id: i32 = match state { @@ -140,21 +177,15 @@ impl Client { let packet_id: VarInt = packet_id.into(); packet.encode_packet(&mut buffer)?; - - match self + // println!("[{} ({:?})] -> {:#02x}", self.address, state, buffer); + // NOTE: Do we need to deal with this error? + let _ = self .packet_sender .send(RawPacket { id: packet_id, data: buffer.freeze(), }) - .await - { - Ok(_) => (), - Err(e) => { - println!("[{}] Error while sending packet: {}", self.address, e); - return Err(ConnectionError::Finished); - } - } + .await; Ok(()) } @@ -235,7 +266,7 @@ impl Client { enforce_secure_chat: false, }), }) - .await?; + .await; } serverbound::PingRequestPacket::STATUS_ID => { let packet = serverbound::PingRequestPacket::from_raw(raw_packet)?; @@ -243,10 +274,8 @@ impl Client { self.send_packet(&clientbound::PongResponsePacket { timestamp: packet.timestamp, }) - .await?; - // TODO: Signal to close connection - // self.stream.shutdown(Shutdown::Both)?; - return Err(ConnectionError::Finished); + .await; + self.connected.store(false, Ordering::Relaxed); } _ => { @@ -269,7 +298,7 @@ impl Client { username: packet.name, properties: vec![], }) - .await?; + .await; } serverbound::LoginAcknowledgedPacket::LOGIN_ID => { let packet = serverbound::LoginAcknowledgedPacket::from_raw(raw_packet)?; @@ -282,7 +311,7 @@ impl Client { version: "1.21.4".to_owned(), }], }) - .await?; + .await; } _ => { println!( @@ -312,15 +341,17 @@ impl Client { let packet = serverbound::SelectKnownPacksPacket::from_raw(raw_packet)?; println!("[{} (Configuration)] <- {:?}", self.address, packet); - self.sync_registries(registries).await?; + self.sync_registries(registries).await; + self.sync_tags(registries).await; self.send_packet(&clientbound::FinishConfigurationPacket) - .await?; + .await; } serverbound::FinishConfigurationPacket::CONFIGURATION_ID => { let packet = serverbound::finish_configuration::FinishConfigurationPacket; println!("[{} (Configuration)] <- {:?}", self.address, packet); self.change_state(ConnectionState::Play).await?; + self.convert_to_player.store(true, Ordering::Relaxed); self.send_packet(&clientbound::LoginPacket { entity_id: 0, is_hardcore: false, @@ -343,19 +374,19 @@ impl Client { sea_level: 63.into(), enforces_secure_chat: false, }) - .await?; + .await; self.send_packet(&GameEventPacket { event: 13, data: 0., }) - .await?; + .await; self.send_packet(&SetChunkCacheCenterPacket { x: 0.into(), z: 0.into(), }) - .await?; + .await; } serverbound::KeepAlivePacket::CONFIGURATION_ID => { let _ = serverbound::KeepAlivePacket::from_raw(raw_packet)?; @@ -370,78 +401,96 @@ impl Client { Ok(()) } - // fn handle_play(&mut self, length: usize) -> Result<(), ConnectionError> { - // let cursor = &mut Cursor::new(&self.recv_buffer[..length]); - // let id: i32 = VarInt::decode_packet(cursor)?.into(); - // - // match id { - // serverbound::ClientTickEndPacket::PLAY_ID => { - // serverbound::ClientTickEndPacket::decode_packet(cursor)?; - // } - // serverbound::MovePlayerPosPacket::PLAY_ID => { - // let _packet = serverbound::MovePlayerPosPacket::decode_packet(cursor)?; - // // println!("[{} (Play)] <- {:?}", self.address, packet); - // } - // serverbound::MovePlayerPosRotPacket::PLAY_ID => { - // let _packet = serverbound::MovePlayerPosRotPacket::decode_packet(cursor)?; - // // println!("[{} (Play)] <- {:?}", self.address, packet); - // } - // serverbound::MovePlayerRotPacket::PLAY_ID => { - // let _packet = serverbound::MovePlayerRotPacket::decode_packet(cursor)?; - // // println!("[{} (Play)] <- {:?}", self.address, packet); - // } - // _ => { - // println!( - // "[{} (Play)] <- Unknown packet id: {} with length {} data: {:X?}", - // self.address, - // id, - // length, - // &self.recv_buffer[..length] - // ); - // } - // } - // Ok(()) - // } - - async fn sync_registries(&self, registries: &Arc) -> Result<(), ConnectionError> { + async fn sync_registries(&self, registries: &Arc) { self.send_registry( - Identifier::minecraft_str("dimension_type"), - ®istries.dimension_types, + Identifier::minecraft("banner_pattern"), + ®istries.banner_patterns, ) - .await?; - + .await; + self.send_registry(Identifier::minecraft("chat_type"), ®istries.chat_types) + .await; self.send_registry( - Identifier::minecraft_str("painting_variant"), - ®istries.painting_variants, - ) - .await?; - - self.send_registry( - Identifier::minecraft_str("wolf_variant"), - ®istries.wolf_variants, - ) - .await?; - - self.send_registry( - Identifier::minecraft_str("damage_type"), + Identifier::minecraft("damage_type"), ®istries.damage_types, ) - .await?; - + .await; self.send_registry( - Identifier::minecraft_str("worldgen/biome"), + Identifier::minecraft("dimension_type"), + ®istries.dimension_types, + ) + .await; + self.send_registry( + Identifier::minecraft("painting_variant"), + ®istries.painting_variants, + ) + .await; + self.send_registry( + Identifier::minecraft("trim_material"), + ®istries.trim_materials, + ) + .await; + self.send_registry( + Identifier::minecraft("trim_pattern"), + ®istries.trim_patterns, + ) + .await; + self.send_registry( + Identifier::minecraft("wolf_variant"), + ®istries.wolf_variants, + ) + .await; + self.send_registry( + Identifier::minecraft("worldgen/biome"), ®istries.worldgen.biomes, ) - .await?; - - Ok(()) + .await; } - async fn send_registry( - &self, - identifier: Identifier, - registry: &Registry, - ) -> Result<(), ConnectionError> + async fn sync_tags(&self, registries: &Arc) { + self.send_packet(&clientbound::UpdateTagsPacket { + registries: vec![ + TagsForRegistry::from_registry( + Identifier::minecraft("banner_pattern"), + ®istries.banner_patterns, + ), + TagsForRegistry::from_registry( + Identifier::minecraft("chat_type"), + ®istries.chat_types, + ), + TagsForRegistry::from_registry( + Identifier::minecraft("damage_type"), + ®istries.damage_types, + ), + TagsForRegistry::from_registry( + Identifier::minecraft("dimension_type"), + ®istries.dimension_types, + ), + TagsForRegistry::from_registry( + Identifier::minecraft("painting_variant"), + ®istries.painting_variants, + ), + TagsForRegistry::from_registry( + Identifier::minecraft("trim_material"), + ®istries.trim_materials, + ), + TagsForRegistry::from_registry( + Identifier::minecraft("trim_pattern"), + ®istries.trim_patterns, + ), + TagsForRegistry::from_registry( + Identifier::minecraft("wolf_variant"), + ®istries.wolf_variants, + ), + TagsForRegistry::from_registry( + Identifier::minecraft("worldgen/biome"), + ®istries.worldgen.biomes, + ), + ], + }) + .await; + } + + async fn send_registry(&self, identifier: Identifier, registry: &Registry) where for<'a> &'a T: Into, { diff --git a/potato/src/main.rs b/potato/src/main.rs index 6a82744..38b3bc0 100644 --- a/potato/src/main.rs +++ b/potato/src/main.rs @@ -1,10 +1,17 @@ +#![feature(lock_value_accessors)] pub mod connection; pub mod player; pub mod server; +pub mod world; -use std::{sync::Arc, time::Duration}; +use std::{ + sync::{Arc, atomic::Ordering}, + time::Duration, +}; use connection::Client; +use player::Player; +use potato_data::text_component::TextComponent; use potato_protocol::packet::clientbound; use server::Server; use tokio::{net::TcpListener, time::interval}; @@ -43,37 +50,40 @@ impl PotatoServer { }; let client = Arc::new(client); - tokio::spawn(async move { - while let Some(packet) = rx.recv().await { - if let Err(e) = packet.write_to_stream(&mut stream_send).await { - println!("Error while sending packet: {}", e); - // TODO: Close connection with client here - break; + { + let client = client.clone(); + tokio::spawn(async move { + while let Some(packet) = rx.recv().await { + if let Err(e) = packet.write_to_stream(&mut stream_send).await { + client + .disconnect(TextComponent::from_str( + "Error while sending packet", + )) + .await; + println!("Error while sending packet: {}", e); + break; + } } - } - }); + }); + } // Keep alive task { let client = client.clone(); tokio::spawn(async move { let mut interval = interval(Duration::from_secs(10)); - // TODO: Terminate this when the client connection is closed. loop { interval.tick().await; + if !client.connected.load(Ordering::Relaxed) { + break; + } + if client.needs_keep_alive().await { - // TODO: Deal with this error by closing the connection. // TODO: Use a unique id for each keep alive packet (or at least a // timestamp) - match client + client .send_packet(&clientbound::KeepAlivePacket { id: 0 }) - .await - { - Ok(_) => {} - Err(e) => { - println!("Error while sending keep alive packet: {}", e) - } - }; + .await; } } }); @@ -81,17 +91,57 @@ impl PotatoServer { { let registries = self.server.registries.clone(); + let world = self.server.world.clone(); tokio::spawn(async move { - // TODO: Deal with errors - loop { - client - .read_packets() - .await - .expect("Error while reading packets"); - client - .handle_packets(®istries) - .await - .expect("Error while handling packets"); + while !client.convert_to_player.load(Ordering::Relaxed) + && client.connected.load(Ordering::Relaxed) + { + if let Err(e) = client.read_packets().await { + // Log the issue in the console and inform the client. + println!("Error while reading packet: {}", e); + client + .disconnect(TextComponent::from_str( + "Error while reading packets", + )) + .await; + break; + } + if let Err(e) = client.handle_packets(®istries).await { + // Log the issue in the console and inform the client. + println!("Error while handeling packet: {}", e); + client + .disconnect(TextComponent::from_str( + "Error while handeling packet", + )) + .await; + break; + } + } + + if client.connected.load(Ordering::Relaxed) { + let player = Player::upgrade_client(client, world).await; + while player.client.connected.load(Ordering::Relaxed) { + if let Err(e) = player.read_packets().await { + // Log the issue in the console and inform the client. + println!("Error while reading packet: {}", e); + player + .disconnect(TextComponent::from_str( + "Error while reading packets", + )) + .await; + break; + } + if let Err(e) = player.handle_packets().await { + // Log the issue in the console and inform the client. + println!("Error while handeling packet: {}", e); + player + .disconnect(TextComponent::from_str( + "Error while handeling packet", + )) + .await; + break; + } + } } }); } diff --git a/potato/src/player.rs b/potato/src/player.rs deleted file mode 100644 index 139597f..0000000 --- a/potato/src/player.rs +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/potato/src/player/mod.rs b/potato/src/player/mod.rs new file mode 100644 index 0000000..5267b9b --- /dev/null +++ b/potato/src/player/mod.rs @@ -0,0 +1,354 @@ +use std::{ + collections::HashSet, + sync::{Arc, Mutex}, +}; + +use fastnbt::LongArray; +use potato_data::text_component::TextComponent; +use potato_protocol::{ + datatypes::bit_set::BitSet, + packet::{ + Packet, RawPacket, + clientbound::{ + self, SetChunkCacheCenterPacket, + level_chunk_with_light::{ + ChunkData, ChunkHeightmaps, LevelChunkWithLightPacket, LightData, + }, + }, + serverbound, + }, + packet_encodable::Nbt, +}; + +use crate::{ + connection::{Client, ConnectionError, ConnectionState}, + world::{Chunk, ChunkPos, World}, +}; + +const RENDER_DISTANCE: i32 = 32; + +#[derive(Debug)] +pub struct Player { + pub client: Arc, + world: Arc, + pub position: Mutex, + pub velocity: Mutex, + + last_teleport_id: Mutex>, + next_teleport_id: Mutex, + + center_chunk: Mutex>, + sent_chunks: Mutex>, +} + +#[derive(Debug, Clone)] +pub struct Position { + pub x: f64, + pub y: f64, + pub z: f64, + pub yaw: f32, + pub pitch: f32, +} + +impl Default for Position { + fn default() -> Self { + Self { + x: Default::default(), + y: 203.0, + z: Default::default(), + yaw: Default::default(), + pitch: Default::default(), + } + } +} + +#[derive(Debug)] +pub struct PositionChange { + pub x: Option, + pub y: Option, + pub z: Option, + pub yaw: Option, + pub pitch: Option, +} + +impl PositionChange { + pub fn apply(&self, pos: &mut Position) { + if let Some(x) = self.x { + pos.x = x; + } + if let Some(y) = self.y { + pos.y = y; + } + if let Some(z) = self.z { + pos.z = z; + } + if let Some(yaw) = self.yaw { + pos.yaw = yaw; + } + if let Some(pitch) = self.pitch { + pos.pitch = pitch; + } + } +} + +#[derive(Debug, Default, Clone)] +pub struct Velocity { + pub x: f64, + pub y: f64, + pub z: f64, +} + +impl Player { + pub async fn upgrade_client(client: Arc, world: Arc) -> Player { + let player = Player { + client, + world: world.clone(), + position: Default::default(), + velocity: Default::default(), + last_teleport_id: Mutex::new(None), + next_teleport_id: Mutex::new(1), + center_chunk: Mutex::new(None), + sent_chunks: Default::default(), + }; + + // TODO: Deal with errors + let _ = player.sync_position().await; + player.update_chunk_position().await; + + player + } + + pub async fn read_packets(&self) -> Result<(), ConnectionError> { + self.client.read_packets().await + } + + pub async fn send_packet(&self, packet: &T) { + self.client.send_packet(packet).await + } + + pub async fn disconnect(&self, reason: TextComponent) { + self.client.disconnect(reason).await + } + + pub async fn sync_position(&self) { + let teleport_id = self.next_teleport_id.get_cloned().unwrap(); + self.last_teleport_id.set(Some(teleport_id)).unwrap(); + + { + let mut guard = self.next_teleport_id.lock().unwrap(); + *guard += 1; + } + + let position = { self.position.lock().unwrap().clone() }; + let velocity = { self.velocity.lock().unwrap().clone() }; + + self.send_packet(&clientbound::PlayerPositionPacket { + id: teleport_id.into(), + x: position.x, + y: position.y, + z: position.z, + vx: velocity.x, + vy: velocity.y, + vz: velocity.z, + yaw: position.yaw, + pitch: position.pitch, + flags: 0, + }) + .await + } + + pub async fn r#move(&self, new_position: PositionChange, sync: bool) { + { + let mut guard = self.position.lock().unwrap(); + new_position.apply(&mut guard); + } + + self.update_chunk_position().await; + + if sync { + self.sync_position().await; + } + } + + pub async fn handle_packets(&self) -> Result<(), ConnectionError> { + while let Some(raw_packet) = { + let mut packet_queue = self.client.packet_queue.lock().await; + packet_queue.pop_front() + } { + let state = { *self.client.state.read().await }; + match state { + ConnectionState::Handshaking => { + println!("Handshake packet on player. Ignoring for now") + } + ConnectionState::Status => { + println!("Status packet on player. Ignoring for now") + } + ConnectionState::Login => { + println!("Login packet on player. Ignoring for now") + } + ConnectionState::Configuration => { + println!("Configuration packet on player. Ignoring for now") + } + ConnectionState::Play => { + self.handle_play(raw_packet).await?; + } + } + } + + Ok(()) + } + + pub async fn handle_play(&self, raw_packet: RawPacket) -> Result<(), ConnectionError> { + match raw_packet.id.into() { + serverbound::ClientTickEndPacket::PLAY_ID => { + serverbound::ClientTickEndPacket::from_raw(raw_packet)?; + } + serverbound::AcceptTeleportationPacket::PLAY_ID => { + let packet = serverbound::AcceptTeleportationPacket::from_raw(raw_packet)?; + let mut guard = self.last_teleport_id.lock().unwrap(); + if *guard == Some(packet.id.into()) { + *guard = None; + } else { + println!( + "[{}] Accept teleportation packet recieved for wrong id!", + self.client.address + ); + } + } + serverbound::MovePlayerPosPacket::PLAY_ID => { + let packet = serverbound::MovePlayerPosPacket::from_raw(raw_packet)?; + self.r#move( + PositionChange { + x: Some(packet.x), + y: Some(packet.feet_y), + z: Some(packet.z), + yaw: None, + pitch: None, + }, + false, + ) + .await; + } + serverbound::MovePlayerPosRotPacket::PLAY_ID => { + let packet = serverbound::MovePlayerPosRotPacket::from_raw(raw_packet)?; + self.r#move( + PositionChange { + x: Some(packet.x), + y: Some(packet.feet_y), + z: Some(packet.z), + yaw: Some(packet.yaw), + pitch: Some(packet.pitch), + }, + false, + ) + .await; + } + serverbound::MovePlayerRotPacket::PLAY_ID => { + let packet = serverbound::MovePlayerRotPacket::from_raw(raw_packet)?; + self.r#move( + PositionChange { + x: None, + y: None, + z: None, + yaw: Some(packet.yaw), + pitch: Some(packet.pitch), + }, + false, + ) + .await; + } + + _ => { + println!( + "[{} (Play)] <- Unknown packet: {}", + self.client.address, raw_packet + ); + } + } + + Ok(()) + } +} + +impl Player { + async fn update_chunk_position(&self) { + let position = self.position.get_cloned().unwrap(); + let old_center = self.center_chunk.get_cloned().unwrap(); + let new_center = ChunkPos::new( + (position.x / 16.0).floor() as i32, + (position.z / 16.0).floor() as i32, + ); + + self.center_chunk.set(Some(new_center)).unwrap(); + + self.send_packet(&SetChunkCacheCenterPacket { + x: new_center.x.into(), + z: new_center.z.into(), + }) + .await; + + // Move chunk loading ticket + if let Some(old_center) = old_center { + self.world.remove_chunk_loading_ticket(old_center); + } + self.world.add_chunk_loading_ticket(new_center); + + // NOTE: This is probably the wrong way to do this + let mut old_chunks = HashSet::new(); + + if let Some(old_center) = old_center { + for x in -RENDER_DISTANCE..=RENDER_DISTANCE { + for z in -RENDER_DISTANCE..=RENDER_DISTANCE { + old_chunks.insert(ChunkPos::new(old_center.x + x, old_center.z + z)); + } + } + } + let mut new_chunks = HashSet::new(); + for x in -RENDER_DISTANCE..=RENDER_DISTANCE { + for z in -RENDER_DISTANCE..=RENDER_DISTANCE { + new_chunks.insert(ChunkPos::new(new_center.x + x, new_center.z + z)); + } + } + let removed = old_chunks.difference(&new_chunks); + let added = new_chunks.difference(&old_chunks); + + { + let mut guard = self.sent_chunks.lock().unwrap(); + for removed in removed { + guard.remove(removed); + } + } + + for added in added { + if let Some(chunk) = self.world.get_chunk_if_loaded(*added) { + self.send_chunk(&chunk).await + } + } + } + + pub async fn send_chunk(&self, chunk: &Chunk) { + // TODO: Actually send chunk + // self.send_packet(&LevelChunkWithLightPacket { + // chunk_x: chunk.pos.x, + // chink_z: chunk.pos.z, + // data: ChunkData { + // heightmaps: Nbt(ChunkHeightmaps { + // // motion_blocking: LongArray::new(vec![]), + // // world_surface: LongArray::new(vec![]), + // }), + // // TODO: Data needs a lot of data before it is valid, basically a full chunk + // data: vec![], + // block_entities: vec![], + // }, + // light: LightData { + // sky_light_mask: BitSet::new(), + // block_light_mask: BitSet::new(), + // empty_sky_light_mask: BitSet::new(), + // empty_block_light_mask: BitSet::new(), + // sky_light: vec![], + // block_light: vec![], + // }, + // }) + // .await + } +} diff --git a/potato/src/server.rs b/potato/src/server.rs index 37bed33..993a403 100644 --- a/potato/src/server.rs +++ b/potato/src/server.rs @@ -1,9 +1,18 @@ use std::sync::Arc; -use potato_data::{datapack::Datapack, registry::Registries}; +use potato_data::{ + datapack::Datapack, + registry::{ + Registries, STATIC_REGISTRIES, StaticRegistries, + item::{ItemComponent, ItemComponentCreator, components::damage::Damage}, + }, +}; + +use crate::world::World; pub struct Server { pub registries: Arc, + pub world: Arc, } macro_rules! print_registry_loaded { @@ -16,6 +25,13 @@ macro_rules! print_registry_loaded { impl Server { #[allow(clippy::new_without_default)] pub fn new() -> Server { + println!("Loading static registries..."); + load_static_registries(); + println!( + "Loaded {} item components", + STATIC_REGISTRIES.get().unwrap().item_components.len() + ); + println!("Looking for datapacks..."); let datapacks: Vec<_> = std::fs::read_dir("datapacks") .expect("Failed to read datapacks directory") @@ -41,8 +57,131 @@ impl Server { print_registry_loaded!(registries.damage_types, "damage_type"); print_registry_loaded!(registries.worldgen.biomes, "biome"); + print_registry_loaded!(registries.items, "item"); + Server { registries: Arc::new(registries), + world: Arc::new(Default::default()), } } } + +macro_rules! register_item_components { + ($registries:ident, [$($component:ty,)*]) => { + $( + let _ = $registries.item_components.register( + <$component>::ID, + ItemComponentCreator { + deserialize: Arc::new(<$component>::deserialize), + }, + ); + )* + }; +} + +fn load_static_registries() { + use potato_data::registry::item::components::*; + let mut static_registries = StaticRegistries::default(); + + register_item_components!( + static_registries, + [ + attribute_modifiers::AttributeModifiers, + banner_patterns::BannerPatterns, + base_color::BaseColor, + bees::Bees, + block_entity_data::BlockEntityData, + block_state::BlockState, + blocks_attacks::BlocksAttacks, + break_sound::BreakSound, + bucket_entity_data::BucketEntityData, + bundle_contents::BundleContents, + can_break::CanBreak, + can_place_on::CanPlaceOn, + charged_projectiles::ChargedProjectiles, + consumable::Consumable, + container::Container, + container_loot::ContainerLoot, + custom_data::CustomData, + custom_model_data::CustomModelData, + custom_name::CustomName, + damage::Damage, + damage_resistant::DamageResistant, + death_protection::DeathProtection, + debug_stick_state::DebugStickState, + dyed_color::DyedColor, + enchantable::Enchantable, + enchantment_glint_override::EnchantmentGlintOverride, + enchantments::Enchantments, + entity_data::EntityData, + equippable::Equippable, + firework_explosion::FireworkExplosion, + fireworks::Fireworks, + food::Food, + glider::Glider, + instrument::Instrument, + intangible_projectile::IntangibleProjectile, + item_model::ItemModel, + item_name::ItemName, + jukebox_playable::JukeboxPlayable, + lock::Lock, + lodestone_tracker::LodestoneTracker, + lore::Lore, + map_color::MapColor, + map_decorations::MapDecorations, + map_id::MapId, + max_damage::MaxDamage, + max_stack_size::MaxStackSize, + note_block_sound::NoteBlockSound, + ominous_bottle_amplifier::OminousBottleAmplifier, + pot_decorations::PotDecorations, + potion_contents::PotionContents, + potion_duration_scale::PotionDurationScale, + profile::Profile, + provides_banner_patterns::ProvidesBannerPatterns, + provides_trim_material::ProvidesTrimMaterial, + rarity::Rarity, + recipes::Recipes, + repair_cost::RepairCost, + repairable::Repairable, + stored_enchantments::StoredEnchantments, + suspicious_stew_effects::SuspiciousStewEffects, + tool::Tool, + tooltip_display::TooltipDisplay, + tooltip_style::TooltipStyle, + trim::Trim, + unbreakable::Unbreakable, + use_cooldown::UseCooldown, + use_remainder::UseRemainder, + weapon::Weapon, + writable_book_content::WritableBookContent, + written_book_content::WrittenBookContent, + axolotl_variant::AxolotlVariant, + cat_collar::CatCollar, + cat_variant::CatVariant, + chicken_variant::ChickenVariant, + cow_variant::CowVariant, + fox_variant::FoxVariant, + frog_variant::FrogVariant, + horse_variant::HorseVariant, + llama_variant::LlamaVariant, + mooshroom_variant::MooshroomVariant, + painting_variant::PaintingVariant, + parrot_variant::ParrotVariant, + pig_variant::PigVariant, + rabbit_variant::RabbitVariant, + salmon_size::SalmonSize, + sheep_color::SheepColor, + shulker_color::ShulkerColor, + tropical_fish_base_color::TropicalFishBaseColor, + tropical_fish_pattern::TropicalFishPattern, + tropical_fish_pattern_color::TropicalFishPatternColor, + villager_variant::VillagerVariant, + wolf_collar::WolfCollar, + wolf_sound_variant::WolfSoundVariant, + wolf_variant::WolfVariant, + ] + ); + + STATIC_REGISTRIES.get_or_init(|| static_registries); +} diff --git a/potato/src/world.rs b/potato/src/world.rs new file mode 100644 index 0000000..35e049b --- /dev/null +++ b/potato/src/world.rs @@ -0,0 +1,61 @@ +use std::{ + collections::{HashMap, hash_map::Entry}, + sync::Mutex, +}; + +#[derive(Debug, Default)] +pub struct World { + chunk_loading_tickets: Mutex>, +} + +impl World { + pub fn remove_chunk_loading_ticket(&self, pos: ChunkPos) { + let mut guard = self.chunk_loading_tickets.lock().unwrap(); + match guard.entry(pos) { + Entry::Occupied(e) if *e.get() <= 1 => { + e.remove(); + } + Entry::Occupied(mut e) => { + e.insert(e.get() - 1); + } + Entry::Vacant(_) => {} + }; + + // TODO: Actually do something here to load/unload chunks + } + + pub fn add_chunk_loading_ticket(&self, pos: ChunkPos) { + let mut guard = self.chunk_loading_tickets.lock().unwrap(); + match guard.entry(pos) { + Entry::Occupied(mut e) => { + e.insert(e.get() + 1); + } + Entry::Vacant(e) => { + e.insert(1); + } + }; + + // TODO: Actually do something here to load/unload chunks + } + + pub fn get_chunk_if_loaded(&self, pos: ChunkPos) -> Option { + // TODO: Actually implement this + Some(Chunk { pos }) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct ChunkPos { + pub x: i32, + pub z: i32, +} + +impl ChunkPos { + pub fn new(x: i32, z: i32) -> ChunkPos { + ChunkPos { x, z } + } +} + +pub struct Chunk { + pub pos: ChunkPos, +} diff --git a/scripts/create_item_datapack.py b/scripts/create_item_datapack.py new file mode 100644 index 0000000..643d0cb --- /dev/null +++ b/scripts/create_item_datapack.py @@ -0,0 +1,42 @@ +import json + +RAW_ITEM_FILE = "run/raw/items.json" +RAW_REGISTRIES_FILE = "run/raw/registries.json" + +OUTPUT_DIR = "run/datapacks/vanilla/data/minecraft/item" + +def main(): + raw_item_data = {} + raw_registry_data = [] + + with open(RAW_ITEM_FILE, "r") as item_file: + raw_item_data = json.load(item_file) + + with open(RAW_REGISTRIES_FILE, "r") as registries_file: + raw_registry_data = json.load(registries_file) + + + + total_items = len(raw_item_data) + i = 1 + + for id in raw_item_data: + print(f"Proccessing: {i}/{total_items}") + components = raw_item_data[id]["components"] + protocol_id = raw_registry_data["minecraft:item"]["entries"][id]["protocol_id"] + + data = { + "protocol_id": protocol_id, + "components": components, + } + + ident = id.split(":")[1] + + with open(f"{OUTPUT_DIR}/{ident}.json", "w") as out_file: + json.dump(data, out_file, indent=4) + + i += 1 + + +if __name__ == "__main__": + main()