From d64d1684bb1e2b3e57529ce95fc29e38bdfbec80 Mon Sep 17 00:00:00 2001 From: JohnBraham Date: Fri, 9 Oct 2026 15:16:46 +0100 Subject: [PATCH] Bring Base Metals to Minecraft 1.17.1 --- .github/workflows/ci.yml | 56 +- .github/workflows/codeql-analysis.yml | 14 +- .github/workflows/validate-gradle-build.yml | 4 +- CHANGELOG.txt | 26 + README.md | 70 +- build.gradle | 61 +- docs/COMPATIBILITY.md | 10 +- docs/CONTENT_MODES.md | 4 +- docs/MIGRATION.md | 29 +- docs/VERSIONS.md | 20 +- docs/WORLDGEN.md | 11 +- gradle.properties | 32 +- gradle/README.md | 7 +- gradle/ide/eclipse.gradle | 64 +- gradle/release/artifacts.gradle | 76 +- gradle/stage-orespawn-candidate.ps1 | 8 +- gradle/stage-orespawn-release.sh | 2 +- gradle/verification/development.gradle | 4 +- gradle/verification/generated-data.gradle | 124 +- gradle/verification/packaged-forge.gradle | 84 +- .../testmod/BaseMetalsClientProbe.java | 215 +- .../resources/META-INF/mods.toml | 10 +- .../resources/pack.mcmeta | 2 +- .../basemetals/data/BMBlockStateProvider.java | 80 + .../basemetals/data/HarvestTagProvider.java | 36 + .../assets/basemetals/lang/de_de.json | 14 +- .../assets/basemetals/lang/en_au.json | 14 +- .../assets/basemetals/lang/en_ca.json | 14 +- .../assets/basemetals/lang/en_en.json | 14 +- .../assets/basemetals/lang/en_gb.json | 14 +- .../assets/basemetals/lang/en_pt.json | 14 +- .../assets/basemetals/lang/en_us.json | 14 +- .../assets/basemetals/lang/es_es.json | 14 +- .../assets/basemetals/lang/es_mx.json | 14 +- .../assets/basemetals/lang/fr_ca.json | 14 +- .../assets/basemetals/lang/fr_fr.json | 14 +- .../assets/basemetals/lang/it_it.json | 14 +- .../assets/basemetals/lang/ja_jp.json | 14 +- .../assets/basemetals/lang/nl_nl.json | 14 +- .../assets/basemetals/lang/pt_br.json | 14 +- .../assets/basemetals/lang/ru_ru.json | 14 +- .../assets/basemetals/lang/zh_cn.json | 14 +- .../assets/basemetals/lang/zh_tw.json | 14 +- .../models/block/adamantine_ore.json | 14 +- .../basemetals/models/block/antimony_ore.json | 14 +- .../basemetals/models/block/bismuth_ore.json | 14 +- .../basemetals/models/block/coldiron_ore.json | 14 +- .../basemetals/models/block/copper_ore.json | 14 +- .../basemetals/models/block/lead_ore.json | 14 +- .../basemetals/models/block/mercury_ore.json | 14 +- .../basemetals/models/block/nickel_ore.json | 14 +- .../basemetals/models/block/platinum_ore.json | 14 +- .../basemetals/models/block/silver_ore.json | 14 +- .../models/block/starsteel_ore.json | 14 +- .../basemetals/models/block/tin_ore.json | 14 +- .../basemetals/models/block/zinc_ore.json | 14 +- .../models/item/adamantine_raw.json | 6 + .../basemetals/models/item/antimony_raw.json | 6 + .../basemetals/models/item/bismuth_raw.json | 6 + .../basemetals/models/item/coldiron_raw.json | 6 + .../basemetals/models/item/lead_raw.json | 6 + .../basemetals/models/item/mercury_raw.json | 6 + .../basemetals/models/item/nickel_raw.json | 6 + .../basemetals/models/item/platinum_raw.json | 6 + .../basemetals/models/item/silver_raw.json | 6 + .../basemetals/models/item/starsteel_raw.json | 6 + .../basemetals/models/item/tin_raw.json | 6 + .../basemetals/models/item/zinc_raw.json | 6 + .../advancements/angel_of_death.json | 2 +- .../advancements/aquarium_maker.json | 2 +- .../basemetals/advancements/blocktastic.json | 2 +- .../basemetals/advancements/brass_maker.json | 2 +- .../basemetals/advancements/bronze_maker.json | 2 +- .../advancements/cupronickel_maker.json | 2 +- .../basemetals/advancements/demon_slayer.json | 2 +- .../advancements/electrum_maker.json | 2 +- .../basemetals/advancements/geologist.json | 2 +- .../basemetals/advancements/invar_maker.json | 2 +- .../basemetals/advancements/juggernaut.json | 2 +- .../basemetals/advancements/metallurgy.json | 2 +- .../advancements/mithril_maker.json | 2 +- .../basemetals/advancements/moon_boots.json | 2 +- .../basemetals/advancements/pewter_maker.json | 2 +- .../advancements/recipes/activator_rail.json | 4 +- .../recipes/adamantine_raw_blasting.json | 32 + .../recipes/adamantine_raw_smelting.json | 32 + .../recipes/antimony_raw_blasting.json | 32 + .../recipes/antimony_raw_smelting.json | 32 + .../recipes/bismuth_raw_blasting.json | 32 + .../recipes/bismuth_raw_smelting.json | 32 + .../advancements/recipes/charcoal_block.json | 8 +- .../recipes/charcoal_block_dust.json | 4 +- .../advancements/recipes/charcoal_ingot.json | 4 +- .../advancements/recipes/charcoal_nugget.json | 8 +- .../recipes/charcoal_powder_from_small.json | 4 +- .../recipes/charcoal_smallpowder.json | 4 +- .../advancements/recipes/coal_block_dust.json | 4 +- .../advancements/recipes/coal_ingot.json | 4 +- .../advancements/recipes/coal_nugget.json | 8 +- .../recipes/coal_powder_from_small.json | 4 +- .../recipes/coal_smallpowder.json | 4 +- .../recipes/coldiron_raw_blasting.json | 32 + .../recipes/coldiron_raw_smelting.json | 32 + .../advancements/recipes/copper_block.json | 4 +- .../recipes/copper_block_ingot.json | 4 +- .../recipes/copper_ingot_from_nuggets.json | 4 +- .../advancements/recipes/copper_nuggets.json | 4 +- .../advancements/recipes/detector_rail.json | 4 +- .../advancements/recipes/flint_and_steel.json | 4 +- .../advancements/recipes/human_detector.json | 4 +- .../recipes/lead_raw_blasting.json | 32 + .../recipes/lead_raw_smelting.json | 32 + .../recipes/mercury_raw_blasting.json | 32 + .../recipes/mercury_raw_smelting.json | 32 + .../recipes/nickel_raw_blasting.json | 32 + .../recipes/nickel_raw_smelting.json | 32 + .../recipes/platinum_raw_blasting.json | 32 + .../recipes/platinum_raw_smelting.json | 32 + .../recipes/silver_raw_blasting.json | 32 + .../recipes/silver_raw_smelting.json | 32 + .../recipes/starsteel_raw_blasting.json | 32 + .../recipes/starsteel_raw_smelting.json | 32 + .../advancements/recipes/stone_anvil.json | 8 +- .../recipes/stone_crackhammer.json | 4 +- .../recipes/tin_raw_blasting.json | 32 + .../recipes/tin_raw_smelting.json | 32 + .../recipes/zinc_raw_blasting.json | 32 + .../recipes/zinc_raw_smelting.json | 32 + .../basemetals/advancements/scuba_diver.json | 2 +- .../basemetals/advancements/steel_maker.json | 2 +- .../basemetals/advancements/this_is_new.json | 2 +- .../loot_tables/blocks/adamantine_ore.json | 44 +- .../loot_tables/blocks/antimony_ore.json | 44 +- .../loot_tables/blocks/bismuth_ore.json | 44 +- .../loot_tables/blocks/coldiron_ore.json | 44 +- .../loot_tables/blocks/copper_ore.json | 52 +- .../loot_tables/blocks/lead_ore.json | 44 +- .../loot_tables/blocks/mercury_ore.json | 44 +- .../loot_tables/blocks/nickel_ore.json | 44 +- .../loot_tables/blocks/platinum_ore.json | 44 +- .../loot_tables/blocks/silver_ore.json | 44 +- .../loot_tables/blocks/starsteel_ore.json | 44 +- .../loot_tables/blocks/tin_ore.json | 44 +- .../loot_tables/blocks/zinc_ore.json | 44 +- .../recipes/adamantine_raw_blasting.json | 9 + .../recipes/adamantine_raw_crushing.json | 10 + .../recipes/adamantine_raw_smelting.json | 9 + .../recipes/antimony_raw_blasting.json | 9 + .../recipes/antimony_raw_crushing.json | 10 + .../recipes/antimony_raw_smelting.json | 9 + .../recipes/bismuth_raw_blasting.json | 9 + .../recipes/bismuth_raw_crushing.json | 10 + .../recipes/bismuth_raw_smelting.json | 9 + .../recipes/coldiron_raw_blasting.json | 9 + .../recipes/coldiron_raw_crushing.json | 10 + .../recipes/coldiron_raw_smelting.json | 9 + .../recipes/copper_raw_crushing.json | 10 + .../basemetals/recipes/gold_raw_crushing.json | 10 + .../basemetals/recipes/iron_raw_crushing.json | 10 + .../basemetals/recipes/lead_raw_blasting.json | 9 + .../basemetals/recipes/lead_raw_crushing.json | 10 + .../basemetals/recipes/lead_raw_smelting.json | 9 + .../recipes/mercury_raw_blasting.json | 9 + .../recipes/mercury_raw_crushing.json | 10 + .../recipes/mercury_raw_smelting.json | 9 + .../recipes/nickel_raw_blasting.json | 9 + .../recipes/nickel_raw_crushing.json | 10 + .../recipes/nickel_raw_smelting.json | 9 + .../recipes/platinum_raw_blasting.json | 9 + .../recipes/platinum_raw_crushing.json | 10 + .../recipes/platinum_raw_smelting.json | 9 + .../recipes/silver_raw_blasting.json | 9 + .../recipes/silver_raw_crushing.json | 10 + .../recipes/silver_raw_smelting.json | 9 + .../recipes/starsteel_raw_blasting.json | 9 + .../recipes/starsteel_raw_crushing.json | 10 + .../recipes/starsteel_raw_smelting.json | 9 + .../basemetals/recipes/tin_raw_blasting.json | 9 + .../basemetals/recipes/tin_raw_crushing.json | 10 + .../basemetals/recipes/tin_raw_smelting.json | 9 + .../basemetals/recipes/zinc_raw_blasting.json | 9 + .../basemetals/recipes/zinc_raw_crushing.json | 10 + .../basemetals/recipes/zinc_raw_smelting.json | 9 + .../data/basemetals/registry_manifest.json | 2016 +++++++++-------- .../data/forge/tags/blocks/ores/coal.json | 7 + .../data/forge/tags/blocks/ores/copper.json | 4 +- .../data/forge/tags/blocks/ores/diamond.json | 7 + .../data/forge/tags/blocks/ores/emerald.json | 7 + .../data/forge/tags/blocks/ores/gold.json | 1 + .../data/forge/tags/blocks/ores/iron.json | 7 + .../data/forge/tags/blocks/ores/lapis.json | 7 + .../data/forge/tags/blocks/ores/redstone.json | 7 + .../tags/blocks/storage_blocks/copper.json | 3 +- .../data/forge/tags/items/ingots/copper.json | 3 +- .../data/forge/tags/items/ores/coal.json | 7 + .../data/forge/tags/items/ores/copper.json | 4 +- .../data/forge/tags/items/ores/diamond.json | 7 + .../data/forge/tags/items/ores/emerald.json | 7 + .../data/forge/tags/items/ores/gold.json | 1 + .../data/forge/tags/items/ores/iron.json | 7 + .../data/forge/tags/items/ores/lapis.json | 7 + .../data/forge/tags/items/ores/redstone.json | 7 + .../data/forge/tags/items/raw_materials.json | 20 + .../tags/items/raw_materials/adamantine.json | 6 + .../tags/items/raw_materials/antimony.json | 6 + .../tags/items/raw_materials/bismuth.json | 6 + .../tags/items/raw_materials/coldiron.json | 6 + .../tags/items/raw_materials/copper.json | 6 + .../forge/tags/items/raw_materials/gold.json | 6 + .../forge/tags/items/raw_materials/iron.json | 6 + .../forge/tags/items/raw_materials/lead.json | 6 + .../tags/items/raw_materials/mercury.json | 6 + .../tags/items/raw_materials/nickel.json | 6 + .../tags/items/raw_materials/platinum.json | 6 + .../tags/items/raw_materials/silver.json | 6 + .../tags/items/raw_materials/starsteel.json | 6 + .../forge/tags/items/raw_materials/tin.json | 6 + .../forge/tags/items/raw_materials/zinc.json | 6 + .../tags/items/storage_blocks/copper.json | 3 +- .../tags/blocks/mineable/pickaxe.json | 329 +++ .../tags/blocks/needs_diamond_tool.json | 62 + .../tags/blocks/needs_iron_tool.json | 74 + .../tags/blocks/needs_stone_tool.json | 101 + .../testmod/BaseMetalsRuntimeProbe.java | 287 ++- .../testmod/BlockOcclusionChecks.java | 104 + .../basemetals/testmod/ContentModeChecks.java | 90 +- .../testmod/GameplayRegressionChecks.java | 202 +- ...ive116Checks.java => Native117Checks.java} | 106 +- .../testmod/OrePlacementChecks.java | 62 +- .../mc/basemetals/testmod/RawOreChecks.java | 190 ++ .../resources/META-INF/mods.toml | 10 +- src/integrationTest/resources/pack.mcmeta | 4 +- .../mc/basemetals/BaseMetalsAdvancements.java | 38 +- .../mc/basemetals/BaseMetalsEvents.java | 122 +- .../moddev/mc/basemetals/MissingMappings.java | 6 +- .../zone/moddev/mc/basemetals/ModTabs.java | 24 +- .../zone/moddev/mc/basemetals/ModTags.java | 10 +- .../client/BaseMetalsConfigScreen.java | 60 +- .../mc/basemetals/client/ClientSetup.java | 38 +- .../client/MaterialProjectileRenderer.java | 8 +- .../basemetals/config/BaseMetalsConfig.java | 3 +- .../mc/basemetals/config/ContentPolicy.java | 2 +- .../mc/basemetals/config/MaterialForm.java | 2 +- .../basemetals/content/BaseMetalAmmoItem.java | 16 +- .../content/BaseMetalAnvilBlock.java | 46 +- .../content/BaseMetalBucketItem.java | 6 +- .../content/CompatibilityDoubleSlabBlock.java | 10 +- .../basemetals/content/CrackhammerItem.java | 92 +- .../mc/basemetals/content/FluidContent.java | 12 +- .../content/HumanDetectorBlock.java | 18 +- .../mc/basemetals/content/MaterialArmor.java | 18 +- .../mc/basemetals/content/MaterialBacked.java | 4 +- .../basemetals/content/MaterialContent.java | 4 +- .../mc/basemetals/content/MaterialItems.java | 156 +- .../mc/basemetals/content/MaterialTier.java | 8 +- .../mc/basemetals/content/ModContent.java | 115 +- .../mc/basemetals/content/MoltenFluid.java | 40 +- .../basemetals/content/MoltenMetalBlock.java | 24 +- .../mc/basemetals/content/PlateBlock.java | 35 +- .../mc/basemetals/content/ScytheItem.java | 38 +- .../basemetals/entity/MaterialProjectile.java | 38 +- .../mc/basemetals/entity/ModEntities.java | 4 +- .../loot/ContentModeLootCondition.java | 25 +- .../moddev/mc/basemetals/loot/ModLoot.java | 12 +- .../material/MaterialDefinition.java | 4 +- .../migration/LegacyWorldDataHook.java | 312 ++- .../network/ContentModeNetwork.java | 24 +- .../recipe/ContentCraftingRecipe.java | 64 +- .../mc/basemetals/recipe/CrushingRecipe.java | 48 +- .../recipe/LegacySmeltingRecipe.java | 42 +- .../basemetals/recipe/PlateRepairRecipe.java | 44 +- .../mc/basemetals/trade/BaseMetalsTrades.java | 16 +- src/main/resources/META-INF/coremods.json | 2 +- src/main/resources/META-INF/mods.toml | 10 +- .../textures/item/adamantine_raw.png | Bin 0 -> 509 bytes .../basemetals/textures/item/antimony_raw.png | Bin 0 -> 476 bytes .../basemetals/textures/item/bismuth_raw.png | Bin 0 -> 541 bytes .../basemetals/textures/item/coldiron_raw.png | Bin 0 -> 506 bytes .../basemetals/textures/item/lead_raw.png | Bin 0 -> 498 bytes .../basemetals/textures/item/mercury_raw.png | Bin 0 -> 502 bytes .../basemetals/textures/item/nickel_raw.png | Bin 0 -> 512 bytes .../basemetals/textures/item/platinum_raw.png | Bin 0 -> 514 bytes .../basemetals/textures/item/silver_raw.png | Bin 0 -> 505 bytes .../textures/item/starsteel_raw.png | Bin 0 -> 518 bytes .../basemetals/textures/item/tin_raw.png | Bin 0 -> 532 bytes .../basemetals/textures/item/zinc_raw.png | Bin 0 -> 484 bytes ...ity.js => basemetals_117_compatibility.js} | 43 +- .../data/basemetals/orespawn/provider.json | 2 +- src/main/resources/pack.mcmeta | 2 +- .../basemetals/data/BMBlockStateProvider.java | 150 -- .../mc/basemetals/MechanicsContractTest.java | 8 +- ...ctTest.java => Native117ContractTest.java} | 29 +- .../config/ContentModeDataTest.java | 1 + .../basemetals/config/ContentPolicyTest.java | 2 +- .../basemetals/data/OreOverlayModelTest.java | 154 +- .../data/RawMaterialResourceTest.java | 85 + .../basemetals/data/RecipeRegressionTest.java | 5 +- .../data/ResourceIntegrityTest.java | 30 +- .../material/MaterialCatalogueTest.java | 14 +- .../migration/LegacyWorldSourceTest.java | 147 +- .../worldgen/OreSpawnProviderTest.java | 3 +- .../OreSpawnSchemaValidationTest.java | 10 +- ...resources.js => generate_117_resources.js} | 178 +- tools/test_content_modes.js | 31 +- tools/validation/compare_world_terrain.py | 121 +- tools/validation/forge_launcher.js | 65 + tools/validation/legacy-capture/README.md | 19 +- tools/validation/test_legacy_worlds.js | 26 +- tools/validation/test_world_terrain.py | 63 +- 309 files changed, 6799 insertions(+), 3244 deletions(-) create mode 100644 src/dataGenerator/java/zone/moddev/mc/basemetals/data/BMBlockStateProvider.java create mode 100644 src/dataGenerator/java/zone/moddev/mc/basemetals/data/HarvestTagProvider.java rename src/{main => generated}/resources/assets/basemetals/models/block/adamantine_ore.json (95%) rename src/{main => generated}/resources/assets/basemetals/models/block/antimony_ore.json (95%) rename src/{main => generated}/resources/assets/basemetals/models/block/bismuth_ore.json (95%) rename src/{main => generated}/resources/assets/basemetals/models/block/coldiron_ore.json (95%) rename src/{main => generated}/resources/assets/basemetals/models/block/copper_ore.json (95%) rename src/{main => generated}/resources/assets/basemetals/models/block/lead_ore.json (95%) rename src/{main => generated}/resources/assets/basemetals/models/block/mercury_ore.json (95%) rename src/{main => generated}/resources/assets/basemetals/models/block/nickel_ore.json (95%) rename src/{main => generated}/resources/assets/basemetals/models/block/platinum_ore.json (95%) rename src/{main => generated}/resources/assets/basemetals/models/block/silver_ore.json (95%) rename src/{main => generated}/resources/assets/basemetals/models/block/starsteel_ore.json (95%) rename src/{main => generated}/resources/assets/basemetals/models/block/tin_ore.json (95%) rename src/{main => generated}/resources/assets/basemetals/models/block/zinc_ore.json (95%) create mode 100644 src/generated/resources/assets/basemetals/models/item/adamantine_raw.json create mode 100644 src/generated/resources/assets/basemetals/models/item/antimony_raw.json create mode 100644 src/generated/resources/assets/basemetals/models/item/bismuth_raw.json create mode 100644 src/generated/resources/assets/basemetals/models/item/coldiron_raw.json create mode 100644 src/generated/resources/assets/basemetals/models/item/lead_raw.json create mode 100644 src/generated/resources/assets/basemetals/models/item/mercury_raw.json create mode 100644 src/generated/resources/assets/basemetals/models/item/nickel_raw.json create mode 100644 src/generated/resources/assets/basemetals/models/item/platinum_raw.json create mode 100644 src/generated/resources/assets/basemetals/models/item/silver_raw.json create mode 100644 src/generated/resources/assets/basemetals/models/item/starsteel_raw.json create mode 100644 src/generated/resources/assets/basemetals/models/item/tin_raw.json create mode 100644 src/generated/resources/assets/basemetals/models/item/zinc_raw.json create mode 100644 src/generated/resources/data/basemetals/advancements/recipes/adamantine_raw_blasting.json create mode 100644 src/generated/resources/data/basemetals/advancements/recipes/adamantine_raw_smelting.json create mode 100644 src/generated/resources/data/basemetals/advancements/recipes/antimony_raw_blasting.json create mode 100644 src/generated/resources/data/basemetals/advancements/recipes/antimony_raw_smelting.json create mode 100644 src/generated/resources/data/basemetals/advancements/recipes/bismuth_raw_blasting.json create mode 100644 src/generated/resources/data/basemetals/advancements/recipes/bismuth_raw_smelting.json create mode 100644 src/generated/resources/data/basemetals/advancements/recipes/coldiron_raw_blasting.json create mode 100644 src/generated/resources/data/basemetals/advancements/recipes/coldiron_raw_smelting.json create mode 100644 src/generated/resources/data/basemetals/advancements/recipes/lead_raw_blasting.json create mode 100644 src/generated/resources/data/basemetals/advancements/recipes/lead_raw_smelting.json create mode 100644 src/generated/resources/data/basemetals/advancements/recipes/mercury_raw_blasting.json create mode 100644 src/generated/resources/data/basemetals/advancements/recipes/mercury_raw_smelting.json create mode 100644 src/generated/resources/data/basemetals/advancements/recipes/nickel_raw_blasting.json create mode 100644 src/generated/resources/data/basemetals/advancements/recipes/nickel_raw_smelting.json create mode 100644 src/generated/resources/data/basemetals/advancements/recipes/platinum_raw_blasting.json create mode 100644 src/generated/resources/data/basemetals/advancements/recipes/platinum_raw_smelting.json create mode 100644 src/generated/resources/data/basemetals/advancements/recipes/silver_raw_blasting.json create mode 100644 src/generated/resources/data/basemetals/advancements/recipes/silver_raw_smelting.json create mode 100644 src/generated/resources/data/basemetals/advancements/recipes/starsteel_raw_blasting.json create mode 100644 src/generated/resources/data/basemetals/advancements/recipes/starsteel_raw_smelting.json create mode 100644 src/generated/resources/data/basemetals/advancements/recipes/tin_raw_blasting.json create mode 100644 src/generated/resources/data/basemetals/advancements/recipes/tin_raw_smelting.json create mode 100644 src/generated/resources/data/basemetals/advancements/recipes/zinc_raw_blasting.json create mode 100644 src/generated/resources/data/basemetals/advancements/recipes/zinc_raw_smelting.json create mode 100644 src/generated/resources/data/basemetals/recipes/adamantine_raw_blasting.json create mode 100644 src/generated/resources/data/basemetals/recipes/adamantine_raw_crushing.json create mode 100644 src/generated/resources/data/basemetals/recipes/adamantine_raw_smelting.json create mode 100644 src/generated/resources/data/basemetals/recipes/antimony_raw_blasting.json create mode 100644 src/generated/resources/data/basemetals/recipes/antimony_raw_crushing.json create mode 100644 src/generated/resources/data/basemetals/recipes/antimony_raw_smelting.json create mode 100644 src/generated/resources/data/basemetals/recipes/bismuth_raw_blasting.json create mode 100644 src/generated/resources/data/basemetals/recipes/bismuth_raw_crushing.json create mode 100644 src/generated/resources/data/basemetals/recipes/bismuth_raw_smelting.json create mode 100644 src/generated/resources/data/basemetals/recipes/coldiron_raw_blasting.json create mode 100644 src/generated/resources/data/basemetals/recipes/coldiron_raw_crushing.json create mode 100644 src/generated/resources/data/basemetals/recipes/coldiron_raw_smelting.json create mode 100644 src/generated/resources/data/basemetals/recipes/copper_raw_crushing.json create mode 100644 src/generated/resources/data/basemetals/recipes/gold_raw_crushing.json create mode 100644 src/generated/resources/data/basemetals/recipes/iron_raw_crushing.json create mode 100644 src/generated/resources/data/basemetals/recipes/lead_raw_blasting.json create mode 100644 src/generated/resources/data/basemetals/recipes/lead_raw_crushing.json create mode 100644 src/generated/resources/data/basemetals/recipes/lead_raw_smelting.json create mode 100644 src/generated/resources/data/basemetals/recipes/mercury_raw_blasting.json create mode 100644 src/generated/resources/data/basemetals/recipes/mercury_raw_crushing.json create mode 100644 src/generated/resources/data/basemetals/recipes/mercury_raw_smelting.json create mode 100644 src/generated/resources/data/basemetals/recipes/nickel_raw_blasting.json create mode 100644 src/generated/resources/data/basemetals/recipes/nickel_raw_crushing.json create mode 100644 src/generated/resources/data/basemetals/recipes/nickel_raw_smelting.json create mode 100644 src/generated/resources/data/basemetals/recipes/platinum_raw_blasting.json create mode 100644 src/generated/resources/data/basemetals/recipes/platinum_raw_crushing.json create mode 100644 src/generated/resources/data/basemetals/recipes/platinum_raw_smelting.json create mode 100644 src/generated/resources/data/basemetals/recipes/silver_raw_blasting.json create mode 100644 src/generated/resources/data/basemetals/recipes/silver_raw_crushing.json create mode 100644 src/generated/resources/data/basemetals/recipes/silver_raw_smelting.json create mode 100644 src/generated/resources/data/basemetals/recipes/starsteel_raw_blasting.json create mode 100644 src/generated/resources/data/basemetals/recipes/starsteel_raw_crushing.json create mode 100644 src/generated/resources/data/basemetals/recipes/starsteel_raw_smelting.json create mode 100644 src/generated/resources/data/basemetals/recipes/tin_raw_blasting.json create mode 100644 src/generated/resources/data/basemetals/recipes/tin_raw_crushing.json create mode 100644 src/generated/resources/data/basemetals/recipes/tin_raw_smelting.json create mode 100644 src/generated/resources/data/basemetals/recipes/zinc_raw_blasting.json create mode 100644 src/generated/resources/data/basemetals/recipes/zinc_raw_crushing.json create mode 100644 src/generated/resources/data/basemetals/recipes/zinc_raw_smelting.json create mode 100644 src/generated/resources/data/forge/tags/blocks/ores/coal.json create mode 100644 src/generated/resources/data/forge/tags/blocks/ores/diamond.json create mode 100644 src/generated/resources/data/forge/tags/blocks/ores/emerald.json create mode 100644 src/generated/resources/data/forge/tags/blocks/ores/iron.json create mode 100644 src/generated/resources/data/forge/tags/blocks/ores/lapis.json create mode 100644 src/generated/resources/data/forge/tags/blocks/ores/redstone.json create mode 100644 src/generated/resources/data/forge/tags/items/ores/coal.json create mode 100644 src/generated/resources/data/forge/tags/items/ores/diamond.json create mode 100644 src/generated/resources/data/forge/tags/items/ores/emerald.json create mode 100644 src/generated/resources/data/forge/tags/items/ores/iron.json create mode 100644 src/generated/resources/data/forge/tags/items/ores/lapis.json create mode 100644 src/generated/resources/data/forge/tags/items/ores/redstone.json create mode 100644 src/generated/resources/data/forge/tags/items/raw_materials.json create mode 100644 src/generated/resources/data/forge/tags/items/raw_materials/adamantine.json create mode 100644 src/generated/resources/data/forge/tags/items/raw_materials/antimony.json create mode 100644 src/generated/resources/data/forge/tags/items/raw_materials/bismuth.json create mode 100644 src/generated/resources/data/forge/tags/items/raw_materials/coldiron.json create mode 100644 src/generated/resources/data/forge/tags/items/raw_materials/copper.json create mode 100644 src/generated/resources/data/forge/tags/items/raw_materials/gold.json create mode 100644 src/generated/resources/data/forge/tags/items/raw_materials/iron.json create mode 100644 src/generated/resources/data/forge/tags/items/raw_materials/lead.json create mode 100644 src/generated/resources/data/forge/tags/items/raw_materials/mercury.json create mode 100644 src/generated/resources/data/forge/tags/items/raw_materials/nickel.json create mode 100644 src/generated/resources/data/forge/tags/items/raw_materials/platinum.json create mode 100644 src/generated/resources/data/forge/tags/items/raw_materials/silver.json create mode 100644 src/generated/resources/data/forge/tags/items/raw_materials/starsteel.json create mode 100644 src/generated/resources/data/forge/tags/items/raw_materials/tin.json create mode 100644 src/generated/resources/data/forge/tags/items/raw_materials/zinc.json create mode 100644 src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json create mode 100644 src/generated/resources/data/minecraft/tags/blocks/needs_diamond_tool.json create mode 100644 src/generated/resources/data/minecraft/tags/blocks/needs_iron_tool.json create mode 100644 src/generated/resources/data/minecraft/tags/blocks/needs_stone_tool.json create mode 100644 src/integrationTest/java/zone/moddev/mc/basemetals/testmod/BlockOcclusionChecks.java rename src/integrationTest/java/zone/moddev/mc/basemetals/testmod/{Native116Checks.java => Native117Checks.java} (71%) create mode 100644 src/integrationTest/java/zone/moddev/mc/basemetals/testmod/RawOreChecks.java create mode 100644 src/main/resources/assets/basemetals/textures/item/adamantine_raw.png create mode 100644 src/main/resources/assets/basemetals/textures/item/antimony_raw.png create mode 100644 src/main/resources/assets/basemetals/textures/item/bismuth_raw.png create mode 100644 src/main/resources/assets/basemetals/textures/item/coldiron_raw.png create mode 100644 src/main/resources/assets/basemetals/textures/item/lead_raw.png create mode 100644 src/main/resources/assets/basemetals/textures/item/mercury_raw.png create mode 100644 src/main/resources/assets/basemetals/textures/item/nickel_raw.png create mode 100644 src/main/resources/assets/basemetals/textures/item/platinum_raw.png create mode 100644 src/main/resources/assets/basemetals/textures/item/silver_raw.png create mode 100644 src/main/resources/assets/basemetals/textures/item/starsteel_raw.png create mode 100644 src/main/resources/assets/basemetals/textures/item/tin_raw.png create mode 100644 src/main/resources/assets/basemetals/textures/item/zinc_raw.png rename src/main/resources/coremods/{basemetals_116_compatibility.js => basemetals_117_compatibility.js} (75%) delete mode 100644 src/modelGenerator/java/zone/moddev/mc/basemetals/data/BMBlockStateProvider.java rename src/test/java/zone/moddev/mc/basemetals/{Native116ContractTest.java => Native117ContractTest.java} (75%) create mode 100644 src/test/java/zone/moddev/mc/basemetals/data/RawMaterialResourceTest.java rename tools/{generate_116_resources.js => generate_117_resources.js} (70%) create mode 100644 tools/validation/forge_launcher.js diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c477dd19f..30e213d0b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,19 +1,19 @@ -name: Base Metals 1.16.5 CI +name: Base Metals 1.17.1 CI on: push: branches: - - master-1.16.5 + - master-1.17.1 - 'feature/**' pull_request: branches: - - master-1.16.5 + - master-1.17.1 permissions: contents: read concurrency: - group: basemetals-1.16-${{ github.workflow }}-${{ github.ref }} + group: basemetals-1.17-${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: @@ -32,12 +32,18 @@ jobs: distribution: temurin java-version: '25.0.3+9.0.LTS' - - name: Install pinned Java 8 compilation toolchain + - name: Install Java 8 for the ForgeGradle renamer uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 with: distribution: temurin java-version: '8.0.502+7' + - name: Install pinned Java 16 compilation toolchain + uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 + with: + distribution: temurin + java-version: '16.0.2+7' + - name: Install pinned Java 17 Gradle runtime uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 with: @@ -65,7 +71,7 @@ jobs: classes test verifyReleaseDependencies -PorespawnVerificationRepository="${{ steps.orespawn.outputs.repository }}" --no-daemon --no-build-cache --stacktrace --max-workers=2 - -Dorg.gradle.java.installations.paths="$JAVA_HOME,$JAVA_HOME_8_X64,$JAVA_HOME_25_X64" + -Dorg.gradle.java.installations.paths="$JAVA_HOME,$JAVA_HOME_8_X64,$JAVA_HOME_16_X64,$JAVA_HOME_25_X64" -Dorg.gradle.java.installations.auto-detect=false -Dorg.gradle.java.installations.auto-download=false ) @@ -81,7 +87,7 @@ jobs: classes test verifyReleaseDependencies -PorespawnVerificationRepository="${{ steps.orespawn.outputs.repository }}" --rerun-tasks --offline --no-daemon --no-build-cache --stacktrace --max-workers=2 - -Dorg.gradle.java.installations.paths="$JAVA_HOME,$JAVA_HOME_8_X64,$JAVA_HOME_25_X64" + -Dorg.gradle.java.installations.paths="$JAVA_HOME,$JAVA_HOME_8_X64,$JAVA_HOME_16_X64,$JAVA_HOME_25_X64" -Dorg.gradle.java.installations.auto-detect=false -Dorg.gradle.java.installations.auto-download=false ) @@ -102,12 +108,18 @@ jobs: distribution: temurin java-version: '25.0.3+9.0.LTS' - - name: Install pinned Java 8 compilation toolchain + - name: Install Java 8 for the ForgeGradle renamer uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 with: distribution: temurin java-version: '8.0.502+7' + - name: Install pinned Java 16 compilation toolchain + uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 + with: + distribution: temurin + java-version: '16.0.2+7' + - name: Install pinned Java 17 Gradle runtime uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 with: @@ -134,16 +146,16 @@ jobs: verifyEclipseProductionClasspath -PorespawnVerificationRepository="${{ steps.orespawn.outputs.repository }}" --no-daemon --no-build-cache --stacktrace --max-workers=2 - -Dorg.gradle.java.installations.paths="$JAVA_HOME,$JAVA_HOME_8_X64,$JAVA_HOME_25_X64" + -Dorg.gradle.java.installations.paths="$JAVA_HOME,$JAVA_HOME_8_X64,$JAVA_HOME_16_X64,$JAVA_HOME_25_X64" -Dorg.gradle.java.installations.auto-detect=false -Dorg.gradle.java.installations.auto-download=false ) ./gradlew "${gradle_args[@]}" first="$RUNNER_TEMP/basemetals-first" mkdir -p "$first" - cp build/libs/BaseMetals-3.1.0.116051.jar "$first/" - cp build/libs/BaseMetals-3.1.0.116051-sources.jar "$first/" - cp build/libs/BaseMetals-3.1.0.116051-javadoc.jar "$first/" + cp build/libs/BaseMetals-3.1.0.117011.jar "$first/" + cp build/libs/BaseMetals-3.1.0.117011-sources.jar "$first/" + cp build/libs/BaseMetals-3.1.0.117011-javadoc.jar "$first/" cp build/release/SHA256SUMS "$first/" - name: Rebuild and prove byte-identical archives @@ -154,14 +166,14 @@ jobs: clean assemble verifyReleaseArtifacts writeReleaseChecksums -PorespawnVerificationRepository="${{ steps.orespawn.outputs.repository }}" --no-daemon --no-build-cache --stacktrace --max-workers=2 - -Dorg.gradle.java.installations.paths="$JAVA_HOME,$JAVA_HOME_8_X64,$JAVA_HOME_25_X64" + -Dorg.gradle.java.installations.paths="$JAVA_HOME,$JAVA_HOME_8_X64,$JAVA_HOME_16_X64,$JAVA_HOME_25_X64" -Dorg.gradle.java.installations.auto-detect=false -Dorg.gradle.java.installations.auto-download=false ) ./gradlew "${gradle_args[@]}" - cmp "$RUNNER_TEMP/basemetals-first/BaseMetals-3.1.0.116051.jar" build/libs/BaseMetals-3.1.0.116051.jar - cmp "$RUNNER_TEMP/basemetals-first/BaseMetals-3.1.0.116051-sources.jar" build/libs/BaseMetals-3.1.0.116051-sources.jar - cmp "$RUNNER_TEMP/basemetals-first/BaseMetals-3.1.0.116051-javadoc.jar" build/libs/BaseMetals-3.1.0.116051-javadoc.jar + cmp "$RUNNER_TEMP/basemetals-first/BaseMetals-3.1.0.117011.jar" build/libs/BaseMetals-3.1.0.117011.jar + cmp "$RUNNER_TEMP/basemetals-first/BaseMetals-3.1.0.117011-sources.jar" build/libs/BaseMetals-3.1.0.117011-sources.jar + cmp "$RUNNER_TEMP/basemetals-first/BaseMetals-3.1.0.117011-javadoc.jar" build/libs/BaseMetals-3.1.0.117011-javadoc.jar cmp "$RUNNER_TEMP/basemetals-first/SHA256SUMS" build/release/SHA256SUMS - name: Run exact-OreSpawn dedicated-server probe @@ -172,7 +184,7 @@ jobs: runRuntimeProbeServer -PorespawnVerificationRepository="${{ steps.orespawn.outputs.repository }}" --no-daemon --stacktrace --max-workers=2 - -Dorg.gradle.java.installations.paths="$JAVA_HOME,$JAVA_HOME_8_X64,$JAVA_HOME_25_X64" + -Dorg.gradle.java.installations.paths="$JAVA_HOME,$JAVA_HOME_8_X64,$JAVA_HOME_16_X64,$JAVA_HOME_25_X64" -Dorg.gradle.java.installations.auto-detect=false -Dorg.gradle.java.installations.auto-download=false ) @@ -181,13 +193,13 @@ jobs: - name: Upload audited release candidate uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: - name: BaseMetals-1.16.5-${{ github.sha }} + name: BaseMetals-1.17.1-${{ github.sha }} if-no-files-found: error retention-days: 30 path: | - build/libs/BaseMetals-3.1.0.116051.jar - build/libs/BaseMetals-3.1.0.116051-sources.jar - build/libs/BaseMetals-3.1.0.116051-javadoc.jar + build/libs/BaseMetals-3.1.0.117011.jar + build/libs/BaseMetals-3.1.0.117011-sources.jar + build/libs/BaseMetals-3.1.0.117011-javadoc.jar build/release/SHA256SUMS CHANGELOG.txt @@ -195,7 +207,7 @@ jobs: if: failure() uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: - name: BaseMetals-1.16.5-diagnostics-${{ github.sha }} + name: BaseMetals-1.17.1-diagnostics-${{ github.sha }} if-no-files-found: ignore retention-days: 14 path: | diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 2efbdcb33..82e8e9714 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -3,11 +3,11 @@ name: CodeQL on: push: branches: - - master-1.16.5 + - master-1.17.1 - 'feature/**' pull_request: branches: - - master-1.16.5 + - master-1.17.1 schedule: - cron: '37 7 * * 4' @@ -32,12 +32,18 @@ jobs: distribution: temurin java-version: '25.0.3+9.0.LTS' - - name: Install pinned Java 8 compilation toolchain + - name: Install Java 8 for the ForgeGradle renamer uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 with: distribution: temurin java-version: '8.0.502+7' + - name: Install pinned Java 16 compilation toolchain + uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 + with: + distribution: temurin + java-version: '16.0.2+7' + - name: Install pinned Java 17 Gradle runtime uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5 with: @@ -60,7 +66,7 @@ jobs: gradle_args=( clean classes --no-daemon --stacktrace --max-workers=2 - -Dorg.gradle.java.installations.paths="$JAVA_HOME,$JAVA_HOME_8_X64,$JAVA_HOME_25_X64" + -Dorg.gradle.java.installations.paths="$JAVA_HOME,$JAVA_HOME_8_X64,$JAVA_HOME_16_X64,$JAVA_HOME_25_X64" -Dorg.gradle.java.installations.auto-detect=false -Dorg.gradle.java.installations.auto-download=false ) diff --git a/.github/workflows/validate-gradle-build.yml b/.github/workflows/validate-gradle-build.yml index fc66575a5..0bf04b841 100644 --- a/.github/workflows/validate-gradle-build.yml +++ b/.github/workflows/validate-gradle-build.yml @@ -3,11 +3,11 @@ name: Validate Gradle Wrapper on: push: branches: - - master-1.16.5 + - master-1.17.1 - 'feature/**' pull_request: branches: - - master-1.16.5 + - master-1.17.1 permissions: contents: read diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 79aa51b5f..ad7cd02d9 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,3 +1,29 @@ +Base Metals 3.1.0.117011 + +- Bring Base Metals to Minecraft 1.17.1 and Forge 37.1.1, with Java 16 for the game. +- Add twelve raw metals. Ordinary ore mining drops raw material, Fortune gives + extra drops, and Silk Touch keeps the ore block. Copper uses vanilla raw copper. +- Keep direct hammer mining at two powders per ore. Each raw piece gives one + powder through ground hammering or crushing, and smelts or blasts to one ingot. + Raw metals cannot be used in powder blends. +- Support vanilla raw iron, gold and copper, and crushing vanilla deepslate ores. +- Leave Base Metals copper generation off in new OreSpawn profiles, without + changing saved profiles or explicit overrides. Keep the other ore rules as before. +- Use Forge's native model providers for Kiri's ore overlays, keeping the tested + gap between the overlay and its vanilla background. The generateResources task + updates saved output; ordinary builds check it without rewriting source files. +- Keep High/Low Fantasy, configuration screens, equipment effects, molten buckets, + material arrows and bolts, trades and recipes from the 1.16 release. +- Keep the floor and walls visible through holes in trapdoors, doors and bars. + Their collision shapes and placement behaviour are unchanged. +- Update old-world migration, custom anvils, IDE launches and release checks for + Forge 37. Test and datagen classes remain outside the published mod. +- Remove invalid bed entities that vanilla's old-world converter can create on + modded blocks. Real beds and their saved contents are left alone. +- Protect saved Nether, End and custom-dimension chunks as well as the Overworld + when neighbouring terrain is generated during an upgrade. +- Pin the published OreSpawn 4.1.0.117011 release from Curse Maven. + Base Metals 3.1.0.116051 - Bring the 1.15.2 release to Minecraft 1.16.5 and Forge 36.2.34. diff --git a/README.md b/README.md index 5338feb11..dd6498481 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ [![Discord](https://img.shields.io/badge/Discord-MMD-green.svg?style=flat&logo=Discord)](https://discord.moddev.zone) [![CurseForge downloads](https://cf.way2muchnoise.eu/full_base-metals_downloads.svg)](https://www.curseforge.com/minecraft/mc-mods/base-metals) [![Supported Minecraft versions](https://cf.way2muchnoise.eu/versions/Minecraft_base-metals_all.svg)](https://www.curseforge.com/minecraft/mc-mods/base-metals) -[![Build, test, and audit](https://github.com/MinecraftModDevelopmentMods/BaseMetals/actions/workflows/ci.yml/badge.svg?branch=master-1.16.5)](https://github.com/MinecraftModDevelopmentMods/BaseMetals/actions/workflows/ci.yml?query=branch%3Amaster-1.16.5) +[![Build, test, and audit](https://github.com/MinecraftModDevelopmentMods/BaseMetals/actions/workflows/ci.yml/badge.svg?branch=master-1.17.1)](https://github.com/MinecraftModDevelopmentMods/BaseMetals/actions/workflows/ci.yml?query=branch%3Amaster-1.17.1) # Base Metals @@ -12,10 +12,10 @@ shields, bows, crossbows, arrows, and bolts. The mod also includes Crack Hammers, scythes, metal anvils, the human detector, villager trades, advancements, and extra loot to find in chests. -This is Base Metals `3.1.0.116051` for Minecraft 1.16.5. It brings the 1.15.2 -release forward while keeping the same blocks, items and recipes. MMDLib and -Additional Loot Tables are no longer needed. OreSpawn places the ores, and -Base Metals supplies the metals and their recipes. +This is Base Metals `3.1.0.117011` for Minecraft 1.17.1. It brings the 1.16.5 +release forward and adds raw metals, while keeping existing blocks and items. +MMDLib and Additional Loot Tables are no longer needed. OreSpawn places the +ores, and Base Metals supplies the metals and their recipes. Ores use vanilla stone, netherrack and end-stone textures beneath Kiri's ore overlays, so resource packs can change their surroundings without making the @@ -25,16 +25,18 @@ Armorer, Weaponsmith and Toolsmith professions introduced in Minecraft 1.14. The 3.1 release reduces ore-overlay flickering and uses Forge's fluid-bucket icons, with names that clearly describe their contents. These improvements are not yet included in the 3.0.1 builds for Minecraft 1.13–1.15. +Doors, trapdoors and bars also leave the blocks behind their holes visible, +without changing their collision or placement. ## Requirements -- Minecraft `1.16.5` -- Forge `36.2.34` -- Java 8 -- OreSpawn `[4.1.0.116051,5.0.0)` on both client and server +- Minecraft `1.17.1` +- Forge `37.1.1` +- Java 16 +- OreSpawn `[4.1.0.117011,5.0.0)` on both client and server -Put `BaseMetals-3.1.0.116051.jar` and OreSpawn `4.1.0.116051` (or a later -compatible OreSpawn 4 build for 1.16.5) in the `mods` directory. MMDLib and +Put `BaseMetals-3.1.0.117011.jar` and OreSpawn `4.1.0.117011` (or a later +compatible OreSpawn 4 build for 1.17.1) in the `mods` directory. MMDLib and Additional Loot Tables are not dependencies. Mineralogy is optional. ## Materials and gameplay @@ -58,6 +60,12 @@ Notable mechanics include: allows. - Supported ore powders can be smelted into ingots, and alloy blends provide the historical furnace-based alloying route. +- Mining metal ores now drops raw metal, with extra drops from Fortune. Silk + Touch still gives the ore block. A hammer gives two powders when mining an + ore directly, or one powder per dropped raw piece. Raw metals smelt or blast + into ingots, but cannot replace powders in alloy blends. +- Copper ores drop vanilla raw copper. Recipes accept vanilla copper ingots + through shared tags, while existing Base Metals copper items remain usable. - Scythes harvest plants in a horizontal 3x3 area. They work with enchantments and land-protection mods, and wear out as you use them. - Upgrade a shield at an anvil with one plate of a harder metal. The shield @@ -106,8 +114,9 @@ full list of restrictions. Use OreSpawn to change where ores generate. only ore-placement engine used by this port. Base Metals contains no native or fallback world generator. -Fresh installations enable all eleven historical ore rules. Cold Iron and -Adamantine generate in the Nether, Starsteel generates in the End, and Copper, +Fresh installations retain eleven historical ore rules, with Base Metals copper +disabled so vanilla copper can generate on its own. Cold Iron and +Adamantine generate in the Nether, Starsteel generates in the End, and Silver, Tin, Lead, Zinc, Mercury, Nickel, and Platinum generate in ordinary dimensions. Antimony and Bismuth ore blocks remain registered but do not generate by default. @@ -128,14 +137,14 @@ items in containers are protected too. Always perform the first upgrade on a copy of the world and keep the untouched original. Read [Migration](docs/MIGRATION.md) before opening an old save. A -world already upgraded to Minecraft 1.17 or later must not be opened in this -older version. Worlds from the Base Metals 1.13.2, 1.14.4 and 1.15.2 ports can be -upgraded normally. +world already upgraded to Minecraft 1.18 or later must not be opened in this +older version. Worlds from the Base Metals 1.13.2, 1.14.4, 1.15.2 and 1.16.5 +ports can be upgraded normally. ## Compatibility Forge item, block, and fluid tags are Base Metals' public compatibility API. -The 1.16.5 line deliberately contains no version-specific Mekanism, Thermal, +The 1.17.1 line deliberately contains no version-specific Mekanism, Thermal, Tinkers' Construct, Ender IO, IC2, or Thaumcraft plugin code. Compatible mods can consume the common tags without linking to Base Metals internals. See [Compatibility](docs/COMPATIBILITY.md) and [Supported versions](docs/VERSIONS.md). @@ -144,8 +153,8 @@ can consume the common tags without linking to Base Metals internals. See Base Metals uses ForgeGradle `7.0.34` and Gradle `9.6.1`. Gradle runs on Java 17, ForgeGradle's legacy Minecraft transformation utility runs on Java 25, and -the mod compiles and runs on Java 8. Development builds accept newer Java 8 -updates; release auditing requires Temurin `8.0.502+7` for reproducibility. +the mod compiles and runs on Java 16. Development builds accept newer Java 16 +updates; release auditing requires Temurin `16.0.2+7` for reproducibility. Node.js is also needed to generate and check the resource files. The build scripts are divided by purpose; [Build scripts](gradle/README.md) @@ -160,13 +169,14 @@ For a normal development build and client launch, use: Run these tasks from IntelliJ's Gradle window or a terminal. ForgeGradle's launcher prepares the assets and native libraries; no manual asset paths are -needed. The Gradle JVM should be Java 17, not the Java 8 game runtime. +needed. The Gradle JVM should be Java 17, not the Java 16 game runtime. -Ore model JSONs update automatically when you build, launch with `runClient`, -or refresh the Gradle project in Eclipse. Put transparent ore textures under -`src/main/resources/assets/basemetals/textures/block/ore_overlays`; no separate -generation command is needed. Review and commit the updated models with the -textures. CI and release auditing still reject stale models. +After changing generated resources, run **generateResources** from the IDE's +Gradle task list, or use `./gradlew generateResources`. This runs Forge's native +model providers and updates recipes, loot, tags and translations. Put transparent +ore textures under `src/main/resources/assets/basemetals/textures/block/ore_overlays`. +Review the changed files before committing them. Normal builds check the saved +output without rewriting source resources. With the pinned release toolchain, run the full release checks: @@ -181,7 +191,7 @@ Generate and verify Eclipse launches with: ``` Release candidates can also be exercised as packaged mods in prepared official -Forge 36 client and server runtimes with `packagedRuntimeIntegrationTest`; pass +Forge 37 client and server runtimes with `packagedRuntimeIntegrationTest`; pass their directories through the `packagedForgeClientRuntime` and `packagedForgeServerRuntime` Gradle properties. These probes load the exact release JAR and OreSpawn dependency, create real worlds, validate client models @@ -193,7 +203,7 @@ messages in disposable multiplayer profiles. `packagedMineralogyIntegrationTest` checks ore placement alongside Mineralogy. It uses the server runtime above and a `mineralogyTestJar` property pointing to -the qualified Mineralogy 1.16.5 JAR. Mineralogy remains optional for players. +the qualified Mineralogy 1.17.1 JAR. Mineralogy remains optional for players. CI checks a fresh Forge setup, unit tests, generated files, a dedicated server with the pinned OreSpawn release, release-JAR contents, checksums, reproducible @@ -201,8 +211,8 @@ builds, CodeQL, wrapper validation, and Eclipse classpath isolation. Test probes and historical fixtures are excluded from the published JAR. Development and packaged tests use the published -[OreSpawn `4.1.0.116051` release](https://www.curseforge.com/minecraft/mc-mods/mmd-orespawn/files/9080646) -through Curse Maven: `curse.maven:mmd-orespawn-245586:9080646`. The build checks +[OreSpawn `4.1.0.117011` release](https://www.curseforge.com/minecraft/mc-mods/mmd-orespawn/files/9088186) +through Curse Maven: `curse.maven:mmd-orespawn-245586:9088186`. The build checks its checksum, Minecraft version and configuration-screen API. CI stages the same verified download with `gradle/stage-orespawn-release.sh` @@ -210,7 +220,7 @@ and passes its temporary repository through `orespawnVerificationRepository`. Normal development does not need a local OreSpawn checkout or repository. Release artifacts use Maven coordinate -`zone.moddev.mc.basemetals:BaseMetals:3.1.0.116051`. +`zone.moddev.mc.basemetals:BaseMetals:3.1.0.117011`. Report defects through the [Base Metals issue tracker](https://github.com/MinecraftModDevelopmentMods/BaseMetals/issues). diff --git a/build.gradle b/build.gradle index d7656d455..e2a0c5451 100644 --- a/build.gradle +++ b/build.gradle @@ -52,7 +52,7 @@ ext.release_tag = project.mod_version java { toolchain { - languageVersion = JavaLanguageVersion.of(8) + languageVersion = JavaLanguageVersion.of(16) } withSourcesJar() withJavadocJar() @@ -60,10 +60,10 @@ java { tasks.withType(JavaCompile).configureEach { javaCompiler = javaToolchains.compilerFor { - languageVersion = JavaLanguageVersion.of(8) + languageVersion = JavaLanguageVersion.of(16) } - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_16 + targetCompatibility = JavaVersion.VERSION_16 options.encoding = 'UTF-8' options.compilerArgs.addAll(['-Xmaxerrs', '1000']) } @@ -93,6 +93,7 @@ tasks.withType(AbstractArchiveTask).configureEach { sourceSets { // Build-only model generator; not part of the mod jar. modelGenerator { + java.setSrcDirs(['src/dataGenerator/java']) compileClasspath += files(tasks.named('compileJava').flatMap { it.destinationDirectory }) + sourceSets.main.compileClasspath runtimeClasspath += files(tasks.named('compileJava').flatMap { it.destinationDirectory }) + sourceSets.main.compileClasspath } @@ -119,36 +120,30 @@ println "Java: ${System.getProperty 'java.version'}, JVM: ${System.getProperty ' def forgeRunModClassesDirectory = layout.buildDirectory.dir('forge-run-mod-classes/main') def integrationTestModClassesDirectory = layout.buildDirectory.dir('forge-run-mod-classes/integration-test') def forgeMainOutputPath = forgeRunModClassesDirectory.get().asFile.absolutePath -def mainModClasses = "${mod_id}%%${forgeMainOutputPath}${File.pathSeparator}${mod_id}%%${forgeMainOutputPath}" +def mainModClasses = "${mod_id}%%${forgeMainOutputPath}" def forgeProbeOutputPath = integrationTestModClassesDirectory.get().asFile.absolutePath -def probeModClasses = mainModClasses + "${File.pathSeparator}basemetalsprobe%%${forgeProbeOutputPath}" + - "${File.pathSeparator}basemetalsprobe%%${forgeProbeOutputPath}" -def forge36RunTargets = [client: 'fmluserdevclient', server: 'fmluserdevserver', +def probeModClasses = mainModClasses + "${File.pathSeparator}basemetalsprobe%%${forgeProbeOutputPath}" +def forge37RunTargets = [client: 'fmluserdevclient', server: 'fmluserdevserver', data: 'fmluserdevdata', runtimeProbeServer: 'fmluserdevserver', legacyUpgradeServer: 'fmluserdevserver'] minecraft { mappings channel: project.mapping_channel, version: project.mapping_version runs { configureEach { - // Slime Launcher calls this entry point after preparing assets and natives. - mainClass = 'net.minecraftforge.userdev.LaunchTesting' workingDir.convention layout.projectDirectory.dir('run') + jvmArgs '--add-opens', 'java.base/java.lang.invoke=ALL-UNNAMED' systemProperty 'forge.logging.markers', 'REGISTRIES' systemProperty 'forge.logging.console.level', 'info' mods { basemetals { source sourceSets.main } } - environment 'target', forge36RunTargets[name] - environment 'MCP_MAPPINGS', "${mapping_channel}_${mapping_version}" - environment 'MCP_VERSION', mcp_version - environment 'FORGE_VERSION', forge_version - environment 'FORGE_GROUP', 'net.minecraftforge' - environment 'MC_VERSION', minecraft_version environment 'MOD_CLASSES', mainModClasses } register('client') register('server') { args '--nogui' } register('data') { workingDir.convention layout.projectDirectory.dir('run-data') - args '--mod', project.mod_id, '--all', '--output', file('src/generated/resources/'), + environment 'MOD_CLASSES', "${mod_id}%%${layout.buildDirectory.dir('forge-run-mod-classes/data').get().asFile}" + args '--mod', project.mod_id, '--all', '--output', + layout.buildDirectory.dir('native-generated-resources').get().asFile, '--existing', file('src/main/resources/') } register('runtimeProbeServer') { @@ -162,6 +157,23 @@ minecraft { systemProperty 'basemetalsprobe.mode', 'legacy-upgrade' args '--nogui' } + ['runtimeProbeServer', 'legacyUpgradeServer'].each { runName -> + named(runName) { + mainClass = 'cpw.mods.bootstraplauncher.BootstrapLauncher' + jvmArgs '-p', '{modules}', '--add-modules', 'ALL-MODULE-PATH', + '--add-opens', 'java.base/java.util.jar=cpw.mods.securejarhandler', + '--add-exports', 'java.base/sun.security.util=cpw.mods.securejarhandler', + '--add-exports', 'jdk.naming.dns/com.sun.jndi.dns=java.naming' + args '--launchTarget', 'forgeserveruserdev', '--gameDir', '.', + '--fml.forgeVersion', forge_version, '--fml.mcVersion', minecraft_version, + '--fml.forgeGroup', 'net.minecraftforge', '--fml.mcpVersion', mcp_version + systemProperty 'legacyClassPath.file', '{minecraft_classpath_file}' + systemProperty 'ignoreList', + 'bootstraplauncher,securejarhandler,asm-commons,asm-util,asm-analysis,asm-tree,asm,client-extra,fmlcore,javafmllanguage,mclanguage,forge-' + systemProperty 'mergeModules', 'jna-5.8.0.jar,jna-platform-58.0.jar,java-objc-bridge-1.0.0.jar' + environment 'MCP_MAPPINGS', '{mcp_mappings}' + } + } } } @@ -181,13 +193,24 @@ def prepareIntegrationTestModClasses = tasks.register('prepareIntegrationTestMod into integrationTestModClassesDirectory } +def prepareDataGeneratorModClasses = tasks.register('prepareDataGeneratorModClasses', Sync) { + dependsOn tasks.named('classes'), tasks.named('modelGeneratorClasses') + from sourceSets.main.output + from sourceSets.modelGenerator.output + into layout.buildDirectory.dir('forge-run-mod-classes/data') +} + tasks.withType(JavaExec).configureEach { JavaExec runTask -> - def runName = forge36RunTargets.keySet().find { runTask.name == 'run' + it.capitalize() } + def runName = forge37RunTargets.keySet().find { runTask.name == 'run' + it.capitalize() } if (runName != null) { runTask.dependsOn prepareForgeRunModClasses if (runTask.name in ['runRuntimeProbeServer', 'runLegacyUpgradeServer']) { runTask.dependsOn prepareIntegrationTestModClasses } + if (runTask.name == 'runData') { + runTask.dependsOn prepareDataGeneratorModClasses + runTask.environment 'MOD_CLASSES', "${mod_id}%%${layout.buildDirectory.dir('forge-run-mod-classes/data').get().asFile}" + } runTask.doFirst { File runDirectory = minecraft.runs.named(runName).get().workingDir.get().asFile File modsDirectory = new File(runDirectory, 'mods') @@ -275,7 +298,7 @@ tasks.named('jar', Jar) { 'Specification-Title': 'Base Metals', 'Specification-Vendor': project.mod_authors, 'Specification-Version': '1', 'Implementation-Title': 'Base Metals', 'Implementation-Version': project.version, 'Implementation-Vendor': project.mod_authors, - 'Built-On-Java': '8', 'Built-On': "${project.minecraft_version}-${project.forge_version}", + 'Built-On-Java': '16', 'Built-On': "${project.minecraft_version}-${project.forge_version}", 'OreSpawn-Dependency-Mode': project.orespawn_dependency_mode, 'Build-Target': "minecraft-${project.minecraft_version}-${project.loader_name}-" + "${project.forge_version}-java-${project.java_version}"]) diff --git a/docs/COMPATIBILITY.md b/docs/COMPATIBILITY.md index 718c02a9a..2dafe0674 100644 --- a/docs/COMPATIBILITY.md +++ b/docs/COMPATIBILITY.md @@ -8,14 +8,14 @@ ores, crystals, shards, clumps, dirty dusts, and molten fluids. Adamantite, Adamantium, Adamant, Quicksilver, and steel-sprocket names are forwarding tags. Copper-consuming recipes accept `forge:ingots/copper`, except Base Metals' own compacting and decompacting recipes, whose output must remain -the Base Metals item. On Minecraft 1.16.5 the copper ore, ingot, and storage -tags contain Base Metals entries; other mods can add their equivalents through -normal tag merging. +the Base Metals item. Copper ore, ingot and storage tags contain both Base Metals +and vanilla entries. Raw-material tags are separate from dust tags: processors +can accept raw ore, but alloy blends still require powders. This version has no mod-specific plugins for Mekanism, Thermal Expansion, Tinkers' Construct, Ender IO, IC2, Thaumcraft, Dense Ores, VeinMiner, or Constructs -Armory. Their version-specific 1.18 data and APIs are not valid on Forge -36. Generic processors and tools can interoperate through Forge tags. +Armory. Generic processors and tools can interoperate through Forge tags +without a separate Base Metals plugin. Mineralogy is optional. When installed, OreSpawn can place the same ores in Mineralogy's rocks. Base Metals does not need Mineralogy to run. diff --git a/docs/CONTENT_MODES.md b/docs/CONTENT_MODES.md index 30fac0e35..0205fcc3a 100644 --- a/docs/CONTENT_MODES.md +++ b/docs/CONTENT_MODES.md @@ -14,8 +14,8 @@ names and defaults: `specialEffects`, `starsteelRegeneration`, ## High Fantasy `contentMode = "high_fantasy"` is the default. All normal Base Metals recipes, -villager trades and chest loot remain available. An older 1.13 config without -this setting, or no config file at all, uses High Fantasy automatically. +villager trades and chest loot remain available. An older config without this +setting, or no config file at all, uses High Fantasy automatically. Unknown mode names fall back to High Fantasy and are corrected in the config. Picking up a metal ingot reveals that material's crafting recipes, including diff --git a/docs/MIGRATION.md b/docs/MIGRATION.md index a324bcdd7..31f99434c 100644 --- a/docs/MIGRATION.md +++ b/docs/MIGRATION.md @@ -6,7 +6,7 @@ blocks cannot be reconstructed by Mojang's vanilla fixer alone, so Base Metals installs a narrowly scoped migration hook before Forge reads an old world. Always upgrade a copy and retain the original 1.10/1.12 world. Install Base -Metals `3.1.0.116051`, OreSpawn `4.1.0.116051`, and any other 1.16.5 mods needed +Metals `3.1.0.117011`, OreSpawn `4.1.0.117011`, and any other 1.17.1 mods needed by that world. Do not carry MMDLib, Additional Loot Tables, the OreSpawn 3 plugin, or Base Metals' old fallback generator into the new instance. @@ -17,8 +17,8 @@ snapshot, Base Metals: Minecraft's flattening table before chunk conversion; - translates legacy metadata for slabs, double slabs, stairs, doors, trapdoors, buttons, levers, pressure plates, anvils, plates, and fluids; -- protects existing legacy chunks from population writes while they are being - converted; +- protects saved chunks in the Overworld, Nether, End and named custom + dimensions from neighbouring world-generation writes during conversion; - migrates Cyano and MMD registry aliases, including uppercase 1.10 names; - converts old `forge:bucketfilled` Base Metals fluid stacks to dedicated buckets; and @@ -37,8 +37,8 @@ nugget, and the MMDLib Vanilla Bits block/item/fluid names. The migration supports the original Cyano Base Metals 2.4 line and the later MMD Base Metals releases for Minecraft 1.10.2 and 1.12.2. It is not a downgrade -path: do not open a world already saved by Minecraft 1.17 or newer, including -the Base Metals 1.18.2 port, in Minecraft 1.16.5. +path: do not open a world already saved by Minecraft 1.18 or newer, including +the Base Metals 1.18.2 port, in Minecraft 1.17.1. ## Mod settings @@ -55,21 +55,28 @@ limit what you can make instead. See [Content modes and configuration](CONTENT_M ## OreSpawn configuration The Base Metals provider keeps the historical defaults documented in -[WORLDGEN.md](WORLDGEN.md), including enabled copper. OreSpawn configuration -migration remains OreSpawn's responsibility. Keep a copy of the old OreSpawn +[WORLDGEN.md](WORLDGEN.md), except that new profiles leave Base Metals copper +disabled in favour of vanilla copper. Existing profiles and explicit overrides +keep their values. OreSpawn handles its own configuration migration. +Keep a copy of the old OreSpawn configuration alongside the untouched source world when validating an upgrade. The generated manifests at `data/basemetals/registry_manifest_1_12.json` and `data/basemetals/registry_manifest.json` list the old registered names and their -1.16.5 counterparts. +1.17.1 counterparts. -## Moving from Minecraft 1.13.2, 1.14.4 or 1.15.2 +During a pre-flattening upgrade, vanilla can mistake the lower bits of a modded +block ID for a bed and create an invalid bed entity there. Base Metals removes +those stray entities only where the converted block belongs to Base Metals. +It does not remove real beds or change their blocks. -Use a copy of your 1.13.2, 1.14.4 or 1.15.2 world, with the 1.16.5 builds of Base Metals and +## Moving from Minecraft 1.13.2, 1.14.4, 1.15.2 or 1.16.5 + +Use a copy of your older world, with the 1.17.1 builds of Base Metals and OreSpawn. Keep `basemetals-common.toml` and your OreSpawn settings: this port uses the same configuration keys, registered names and ore-rule IDs. Existing items, recipe-book progress and terrain should remain unchanged. Once Minecraft -has saved the copy in 1.16.5, do not reopen it in the older game. +has saved the copy in 1.17.1, do not reopen it in the older game. Base Metals converts the old boolean wall connections to 1.16's low and absent connections. Existing tall connections and wall posts are left as they are. diff --git a/docs/VERSIONS.md b/docs/VERSIONS.md index 8f864c7c3..5586514b7 100644 --- a/docs/VERSIONS.md +++ b/docs/VERSIONS.md @@ -1,20 +1,22 @@ # Supported versions -Base Metals `3.1.0.116051` targets Minecraft `1.16.5`, Forge `36.2.34`, and -Java 8. The Gradle build itself runs on Java `17.0.1+12` and uses ForgeGradle +Base Metals `3.1.0.117011` targets Minecraft `1.17.1`, Forge `37.1.1`, and +Java 16. The Gradle build itself runs on Java `17.0.1+12` and uses ForgeGradle `7.0.34` with Gradle `9.6.1`; those build-time runtimes do not change the Java -8 requirement of the released mod. +16 requirement of the released mod. Release builds use Temurin `16.0.2+7`. +The ForgeGradle renamer also needs Java 8 as a build-time utility; it is not the +game runtime. Builds and tests use the published -[OreSpawn `4.1.0.116051` release](https://www.curseforge.com/minecraft/mc-mods/mmd-orespawn/files/9080646) with -SHA-256 `CDF59D83F191C5FBCD8921228DB577066A63A8FEB25CA79DB4EAEEA32D32DB04`. -At runtime, Base Metals requires OreSpawn `[4.1.0.116051,5.0.0)` for Minecraft 1.16.5. +[OreSpawn `4.1.0.117011` release](https://www.curseforge.com/minecraft/mc-mods/mmd-orespawn/files/9088186) with +SHA-256 `1BDEDCBB179CB5A3B169E5C8A6B301E3888AE15B94108B0AEC627D705CFAD833`. +At runtime, Base Metals requires OreSpawn `[4.1.0.117011,5.0.0)` for Minecraft 1.17.1. The configuration cog uses OreSpawn's public 4.1 client API. -The development coordinate is `curse.maven:mmd-orespawn-245586:9080646`: -CurseForge project `245586`, file `9080646`. CI downloads and checks the same +The development coordinate is `curse.maven:mmd-orespawn-245586:9088186`: +CurseForge project `245586`, file `9088186`. CI downloads and checks the same file before staging it in a temporary Maven repository. The schema-3 provider supports the OreSpawn versions in the runtime range above. Release artifacts use Maven coordinate -`zone.moddev.mc.basemetals:BaseMetals:3.1.0.116051`. +`zone.moddev.mc.basemetals:BaseMetals:3.1.0.117011`. diff --git a/docs/WORLDGEN.md b/docs/WORLDGEN.md index 19c3569ef..6f6dfa456 100644 --- a/docs/WORLDGEN.md +++ b/docs/WORLDGEN.md @@ -1,8 +1,8 @@ # OreSpawn world generation -Base Metals requires OreSpawn `[4.1.0.116051,5.0.0)` and packages provider +Base Metals requires OreSpawn `[4.1.0.117011,5.0.0)` and packages provider schema 3, revision 1 at `data/basemetals/orespawn/provider.json`. Builds and -tests use the published OreSpawn `4.1.0.116051` release, CurseForge file `9080646`. +tests use the published OreSpawn `4.1.0.117011` release, CurseForge file `9088186`. The provider declares ores only: it has no rocks, geomes, biome rules, terrain dimensions, formations, fluid deposits, vanilla suppression, or strata @@ -24,8 +24,11 @@ and `retrogen:false`. | Nickel | all except Nether/End | 32..95 | uniform | 1 | same | | Platinum | all except Nether/End | 1..31 | uniform | 0.125 | same | -Minecraft 1.16.5 has no vanilla copper ore, so Base Metals copper generates -by default. Antimony and Bismuth ores are available in creative mode and old +Minecraft 1.17 added vanilla copper. Base Metals copper is disabled by default +in new profiles, leaving vanilla copper enabled. Existing OreSpawn profiles and +explicit overrides keep their chosen copper setting; this update does not change +them. The copper row above describes the retained rule if you enable it. +Antimony and Bismuth ores are available in creative mode and old saves, but do not generate unless you add rules for them in OreSpawn. The ordinary-dimension selector includes modded dimensions while excluding the diff --git a/gradle.properties b/gradle.properties index 7075a3e34..c311e36d9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -# Memory for Forge's build tools. Gradle runs on Java 17; Minecraft runs on Java 8. +# Memory for Forge's build tools. Gradle runs on Java 17; Minecraft runs on Java 16. org.gradle.jvmargs=-Xmx3G org.gradle.daemon=false org.gradle.configuration-cache=false @@ -7,40 +7,40 @@ org.gradle.parallel=false net.minecraftforge.gradle.merge-source-sets=false # Minecraft, Forge and mappings must describe the same game version. -minecraft_version=1.16.5 -minecraft_version_range=[1.16.5] -forge_version=36.2.34 -forge_installer_sha256=53B73DBBCC486F38726E76CE923B13381044984C83C762847C7193340F97130F +minecraft_version=1.17.1 +minecraft_version_range=[1.17.1] +forge_version=37.1.1 +forge_installer_sha256=31F2319B1B9CA491AACCC020887240F8524A4FF2A8E0F8B795E17E889CBC043B # Target and Java versions used by release checks and publishing. loader_name=forge loader_code=1 -java_version=8 -java_toolchain_version=8.0.502+7 +java_version=16 +java_toolchain_version=16.0.2+7 gradle_java_version=17 curseforge_project_id=240967 # Exact OreSpawn release used for development, CI and packaged tests. orespawn_dependency_mode=release -orespawn_version=4.1.0.116051 +orespawn_version=4.1.0.117011 orespawn_curse_project_id=245586 -orespawn_curse_file_id=9080646 -orespawn_sha256=CDF59D83F191C5FBCD8921228DB577066A63A8FEB25CA79DB4EAEEA32D32DB04 +orespawn_curse_file_id=9088186 +orespawn_sha256=1BDEDCBB179CB5A3B169E5C8A6B301E3888AE15B94108B0AEC627D705CFAD833 # Versions accepted when players load the mod. -forge_version_range=[36,) -loader_version_range=[36,) +forge_version_range=[37,38) +loader_version_range=[37,38) -# MCP mappings for Forge 36. +# MCP mappings for Forge 37. mapping_channel=official -mapping_version=1.16.5 -mcp_version=20210115.111550 +mapping_version=1.17.1 +mcp_version=20210706.113038 # Mod identity. Keep mod_id unchanged so existing saves still load. mod_id=basemetals mod_name=Base Metals mod_license=LGPL-2.1 -mod_version=3.1.0.116051 +mod_version=3.1.0.117011 # Maven coordinates and credits. mod_group=zone.moddev.mc.basemetals diff --git a/gradle/README.md b/gradle/README.md index f6b255f2c..0fa9ea1be 100644 --- a/gradle/README.md +++ b/gradle/README.md @@ -14,11 +14,12 @@ They share a small `baseMetalsBuild` map of artifact helpers and build paths. | `ide/intellij.gradle` | Client and server shortcuts using IntelliJ's Gradle runner. | Use Java 17 to run Gradle. ForgeGradle uses Java 25 for its Mavenizer; Minecraft -and the mod run on Java 8. Development accepts newer Java 8 updates, while +and the mod run on Java 16. Development accepts newer Java 16 updates, while release auditing requires the pinned compiler in `gradle.properties`. +Keep a Java 8 installation available for ForgeGradle's build-time renamer. -The build resolves the published OreSpawn `4.1.0.116051` release through -`curse.maven:mmd-orespawn-245586:9080646`. `verifyReleaseDependencies` checks +The build resolves the published OreSpawn `4.1.0.117011` release through +`curse.maven:mmd-orespawn-245586:9088186`. `verifyReleaseDependencies` checks its checksum, mod metadata and configuration-screen API. No local OreSpawn checkout is needed. diff --git a/gradle/ide/eclipse.gradle b/gradle/ide/eclipse.gradle index c5bd43771..c8de2785d 100644 --- a/gradle/ide/eclipse.gradle +++ b/gradle/ide/eclipse.gradle @@ -16,11 +16,11 @@ eclipse { classpath.entries.findAll { entry -> String path = entry.path?.replace('\\', '/') ?: '' path.startsWith('src/test/') || path.startsWith('src/integrationTest/') - || path.startsWith('src/modelGenerator/') || path.endsWith('/modelGenerator') + || path.startsWith('src/dataGenerator/') || path.endsWith('/modelGenerator') }.each { entry -> entry.entryAttributes['test'] = 'true' } } } - synchronizationTasks generateOreModels, 'isolateEclipseProductionRuns' + synchronizationTasks 'isolateEclipseProductionRuns' } idea { module { @@ -48,6 +48,7 @@ def configureEclipseBuildship = tasks.register('configureEclipseBuildship') { } def eclipseLaunchPathBoundaries = [ + [option: '-DlegacyClassPath.file=', suffix: ' -DignoreList', joined: true], [option: '--cache', suffix: ' --metadata'], [option: '--metadata', suffix: ' --to-srg'], [option: '--to-srg', suffix: ' --to-obf'], @@ -61,13 +62,13 @@ def quoteEclipseLaunchPathArguments = { String contents -> String option = boundary.option String suffix = boundary.suffix java.util.regex.Pattern pattern = java.util.regex.Pattern.compile( - java.util.regex.Pattern.quote(option + ' ') + '(.+?)' + + java.util.regex.Pattern.quote(option + (boundary.joined ? '' : ' ')) + '(.+?)' + java.util.regex.Pattern.quote(suffix)) java.util.regex.Matcher matcher = pattern.matcher(contents) if (matcher.find()) { String value = matcher.group(1) if (!(value.startsWith('"') && value.endsWith('"'))) { - String replacement = option + ' "' + value + '"' + suffix + String replacement = option + (boundary.joined ? '' : ' ') + '"' + value + '"' + suffix contents = matcher.replaceFirst(java.util.regex.Matcher.quoteReplacement(replacement)) } } @@ -75,44 +76,33 @@ def quoteEclipseLaunchPathArguments = { String contents -> contents } -def syncForge36EclipseLaunches = tasks.register('syncForge36EclipseLaunches') { +def syncForge37EclipseLaunches = tasks.register('syncForge37EclipseLaunches') { group = 'ide' - dependsOn tasks.named('processResources') + dependsOn tasks.named('processResources'), tasks.named('prepareDataGeneratorModClasses') doLast { String mainClass = 'net.minecraftforge.launcher.Main' String mainOutput = new File(projectDir, 'bin/main').absolutePath - String ordinaryModClasses = "${mod_id}%%${mainOutput}${File.pathSeparator}${mod_id}%%${mainOutput}" - def environmentEntries = { String launchTarget -> - " \r\n" + - " \r\n" + - " \r\n" + - " \r\n" + - " \r\n" + - " \r\n" - } + String ordinaryModClasses = "${mod_id}%%${mainOutput}" File processedResources = layout.buildDirectory.dir('resources/main').get().asFile copy { from processedResources; into mainOutput } - [Client: 'fmluserdevclient', Server: 'fmluserdevserver', Data: 'fmluserdevdata'].each { - String runName, String launchTarget -> + ['Client', 'Server', 'Data'].each { String runName -> + String modClasses = runName == 'Data' + ? "${mod_id}%%${layout.buildDirectory.dir('forge-run-mod-classes/data').get().asFile}" + : ordinaryModClasses File launch = file("run${runName}.launch") if (!launch.isFile()) throw new GradleException("Missing generated Eclipse launch: ${launch}") String text = launch.getText('UTF-8') if (text.contains('')) { text = text.replace('', '\r\n' + - environmentEntries(launchTarget) + - " \r\n" + + " \r\n" + '') } text = text.replace('', "") text = text.replaceFirst(//, java.util.regex.Matcher.quoteReplacement( - "")) - if (!text.contains('key="target"')) { - text = text.replace(' ")) if (!text.contains('org.eclipse.jdt.launching.ATTR_EXCLUDE_TEST_CODE')) { text = text.replace('', ' \r\n' + @@ -126,13 +116,13 @@ def syncForge36EclipseLaunches = tasks.register('syncForge36EclipseLaunches') { } } } -tasks.matching { it.name == 'genEclipseRuns' }.configureEach { finalizedBy syncForge36EclipseLaunches } -tasks.matching { it.name == 'eclipse' }.configureEach { finalizedBy syncForge36EclipseLaunches } +tasks.matching { it.name == 'genEclipseRuns' }.configureEach { finalizedBy syncForge37EclipseLaunches } +tasks.matching { it.name == 'eclipse' }.configureEach { finalizedBy syncForge37EclipseLaunches } tasks.register('isolateEclipseProductionRuns') { group = 'ide' dependsOn tasks.named('genEclipseRuns') - dependsOn syncForge36EclipseLaunches + dependsOn syncForge37EclipseLaunches dependsOn configureEclipseBuildship } @@ -144,8 +134,8 @@ tasks.register('verifyEclipseProductionClasspath') { Set synchronizationTasks = eclipse.synchronizationTasks.getDependencies(delegate).collect { it.name } as Set - if (!synchronizationTasks.contains('generateOreModels')) { - throw new GradleException('Eclipse Gradle refresh must regenerate ore models') + if (synchronizationTasks.contains('generateOreModels')) { + throw new GradleException('Eclipse refresh must not rewrite source resources') } File prefs = file('.settings/org.eclipse.buildship.core.prefs') @@ -167,14 +157,13 @@ tasks.register('verifyEclipseProductionClasspath') { throw new GradleException('Eclipse does not expose generated production resources') } String mainOutput = new File(projectDir, 'bin/main').absolutePath - String expectedModClasses = "${mod_id}%%${mainOutput}${File.pathSeparator}${mod_id}%%${mainOutput}" def verifyQuotedPaths = { File launch, List> boundaries -> String contents = launch.getText('UTF-8') boundaries.each { Map boundary -> String option = boundary.option String suffix = boundary.suffix java.util.regex.Pattern quotedPath = java.util.regex.Pattern.compile( - java.util.regex.Pattern.quote(option + ' "') + '(.+?)' + + java.util.regex.Pattern.quote(option + (boundary.joined ? '' : ' ') + '"') + '(.+?)' + java.util.regex.Pattern.quote('"' + suffix)) java.util.regex.Matcher matcher = quotedPath.matcher(contents) if (!matcher.find()) { @@ -190,23 +179,26 @@ tasks.register('verifyEclipseProductionClasspath') { File launch = file(name) if (!launch.isFile()) throw new GradleException("Missing ${name}") String contents = launch.getText('UTF-8') - List forbidden = ['src/test', 'src/integrationTest', 'src/modelGenerator', 'junit-', 'opentest4j-', + String expectedModClasses = name == 'runData.launch' + ? "${mod_id}%%${layout.buildDirectory.dir('forge-run-mod-classes/data').get().asFile}" + : "${mod_id}%%${mainOutput}" + List forbidden = ['src/test', 'src/integrationTest', 'src/dataGenerator', 'junit-', 'opentest4j-', 'basemetalsprobe', 'C:\\Users\\John'] List leaked = forbidden.findAll { contents.contains(it) } if (!leaked.isEmpty() || !contents.contains('ATTR_EXCLUDE_TEST_CODE') || !contents.contains("PROJECT_ATTR\" value=\"${eclipseWorkspaceProjectName}\"") || !contents.contains("MOD_CLASSES\" value=\"${expectedModClasses}\"") || !contents.contains('MAIN_TYPE" value="net.minecraftforge.launcher.Main"') - || !contents.contains('--main net.minecraftforge.userdev.LaunchTesting')) { - throw new GradleException("${name} is not an isolated Forge 36 launch: ${leaked}") + || !contents.contains('--main cpw.mods.bootstraplauncher.BootstrapLauncher')) { + throw new GradleException("${name} is not an isolated Forge 37 launch: ${leaked}") } } List allLaunches = fileTree(projectDir) { include '*.launch' }.files.sort { it.name } allLaunches.each { File launch -> - verifyQuotedPaths(launch, eclipseLaunchPathBoundaries.take(4)) + verifyQuotedPaths(launch, eclipseLaunchPathBoundaries.take(5)) } allLaunches.findAll { it.name.endsWith('Data.launch') }.each { File launch -> - verifyQuotedPaths(launch, eclipseLaunchPathBoundaries.drop(4)) + verifyQuotedPaths(launch, eclipseLaunchPathBoundaries.drop(5)) } String clientLaunch = file('runClient.launch').getText('UTF-8') def launcherMatch = clientLaunch =~ /externalArchive="([^&]+[\\\/]slime-launcher-[^&]+\.jar)"/ diff --git a/gradle/release/artifacts.gradle b/gradle/release/artifacts.gradle index 04b3220f1..d206157ab 100644 --- a/gradle/release/artifacts.gradle +++ b/gradle/release/artifacts.gradle @@ -63,30 +63,30 @@ def configuredOreSpawnIdentity = [version: project.orespawn_version.toString(), curseProjectId: project.orespawn_curse_project_id.toString(), curseFileId: project.orespawn_curse_file_id.toString(), sha256: project.orespawn_sha256.toString()] -tasks.register('verifyJava8Toolchain') { +tasks.register('verifyJava16Toolchain') { group = 'verification' dependsOn tasks.named('compileJava') doLast { def metadata = tasks.named('compileJava', JavaCompile).get().javaCompiler.get().metadata - if (metadata.languageVersion.asInt() != 8) { - throw new GradleException("Minecraft 1.16.5 requires a Java 8 JDK, found " + + if (metadata.languageVersion.asInt() != 16) { + throw new GradleException("Minecraft 1.17.1 requires a Java 16 JDK, found " + "${metadata.vendor} ${metadata.javaRuntimeVersion} at ${metadata.installationPath}") } - logger.lifecycle("Java 8 development toolchain: ${metadata.vendor} ${metadata.javaRuntimeVersion}") + logger.lifecycle("Java 16 development toolchain: ${metadata.vendor} ${metadata.javaRuntimeVersion}") } } -tasks.register('verifyReleaseJava8Toolchain') { +tasks.register('verifyReleaseJava16Toolchain') { group = 'verification' description = 'Requires the pinned compiler for reproducible release artifacts.' - dependsOn tasks.named('verifyJava8Toolchain') + dependsOn tasks.named('verifyJava16Toolchain') doLast { def metadata = tasks.named('compileJava', JavaCompile).get().javaCompiler.get().metadata - if (configuredJavaToolchainVersion != '8.0.502+7' - || metadata.javaRuntimeVersion != '1.8.0_502-b07' - || !metadata.vendor.toString().toLowerCase(Locale.ROOT).contains('temurin')) { + if (configuredJavaToolchainVersion != '16.0.2+7' + || metadata.javaRuntimeVersion != '16.0.2+7' + || !(metadata.vendor.toString().toLowerCase(Locale.ROOT) =~ /temurin|eclipse/)) { throw new GradleException("Release auditing requires Eclipse Temurin ${configuredJavaToolchainVersion}; " + - "ordinary build and runClient tasks accept other Java 8 updates. Found " + + "ordinary build and runClient tasks accept other Java 16 updates. Found " + "${metadata.vendor} ${metadata.javaRuntimeVersion} at ${metadata.installationPath}") } } @@ -121,7 +121,7 @@ tasks.register('verifyMavenCoordinates') { tasks.register('verifyReleaseConfiguration') { group = 'verification' - dependsOn tasks.named('verifyJava8Toolchain') + dependsOn tasks.named('verifyJava16Toolchain') doLast { def actual = [modVersion: project.mod_version.toString(), modGroup: project.mod_group.toString(), minecraftVersion: project.minecraft_version.toString(), forgeVersion: project.forge_version.toString(), @@ -131,21 +131,21 @@ tasks.register('verifyReleaseConfiguration') { loaderCode: project.loader_code.toString(), javaVersion: project.java_version.toString(), gradleJavaVersion: project.gradle_java_version.toString(), curseForgeProjectId: project.curseforge_project_id.toString()] - def expected = [modVersion: '3.1.0.116051', modGroup: expectedMavenGroup, - minecraftVersion: '1.16.5', forgeVersion: '36.2.34', - forgeInstallerSha256: '53B73DBBCC486F38726E76CE923B13381044984C83C762847C7193340F97130F', - mappingChannel: 'official', mappingVersion: '1.16.5', - mcpVersion: '20210115.111550', loaderName: 'forge', loaderCode: '1', - javaVersion: '8', gradleJavaVersion: '17', curseForgeProjectId: '240967'] - if (actual != expected) throw new GradleException("Unexpected Base Metals 1.16.5 identity: ${actual}") + def expected = [modVersion: '3.1.0.117011', modGroup: expectedMavenGroup, + minecraftVersion: '1.17.1', forgeVersion: '37.1.1', + forgeInstallerSha256: '31F2319B1B9CA491AACCC020887240F8524A4FF2A8E0F8B795E17E889CBC043B', + mappingChannel: 'official', mappingVersion: '1.17.1', + mcpVersion: '20210706.113038', loaderName: 'forge', loaderCode: '1', + javaVersion: '16', gradleJavaVersion: '17', curseForgeProjectId: '240967'] + if (actual != expected) throw new GradleException("Unexpected Base Metals 1.17.1 identity: ${actual}") } } tasks.register('verifyReleaseDependencies') { group = 'verification' doLast { - def expected = [version: '4.1.0.116051', curseProjectId: '245586', curseFileId: '9080646', - sha256: 'CDF59D83F191C5FBCD8921228DB577066A63A8FEB25CA79DB4EAEEA32D32DB04'] + def expected = [version: '4.1.0.117011', curseProjectId: '245586', curseFileId: '9088186', + sha256: '1BDEDCBB179CB5A3B169E5C8A6B301E3888AE15B94108B0AEC627D705CFAD833'] if (configuredOreSpawnIdentity != expected) { throw new GradleException("Unexpected OreSpawn identity: ${configuredOreSpawnIdentity}") } @@ -160,11 +160,11 @@ tasks.register('verifyReleaseDependencies') { if (metadataEntry == null) throw new GradleException('OreSpawn mod metadata is missing') String metadata = zip.getInputStream(metadataEntry).getText('UTF-8') if (!metadata.contains('modId="orespawn"') - || !metadata.contains('version="4.1.0.116051"') - || !metadata.contains('versionRange="[1.16.5,1.17)"') + || !metadata.contains('version="4.1.0.117011"') + || !metadata.contains('versionRange="[1.17.1,1.18)"') || zip.getEntry('zone/moddev/mc/orespawn/api/OreSpawnApi.class') == null || zip.getEntry('zone/moddev/mc/orespawn/api/client/WorldSettingsExtensionRegistry.class') == null) { - throw new GradleException('Expected Minecraft 1.16.5 OreSpawn 4.1 and its configuration-screen API') + throw new GradleException('Expected Minecraft 1.17.1 OreSpawn 4.1 and its configuration-screen API') } } } @@ -187,7 +187,9 @@ def forbiddenReleasePath = { String entryName -> || name.endsWith('/ore_textures.md') || name.startsWith('src/integrationtest/') || name.startsWith('src/clientintegrationtest/') || name.startsWith('src/gametest/') - || name.startsWith('src/modelgenerator/') || name.endsWith('/bmblockstateprovider.class') + || name.startsWith('src/modelgenerator/') || name.startsWith('src/datagenerator/') + || name.endsWith('/bmblockstateprovider.class') + || name.startsWith('zone/moddev/mc/basemetals/data/') || name.startsWith('src/integratedsmoke/') || name.startsWith('src/packagedclientsmoke/') || name.startsWith('src/upgradesmoke/') || name.startsWith('src/packagedserversmoke/') || name.contains('minecraft-mavenizer') || name.contains('/smoke/') @@ -197,7 +199,7 @@ def forbiddenReleasePath = { String entryName -> tasks.register('verifyReleaseArtifacts') { group = 'verification' - dependsOn tasks.named('verifyReleaseJava8Toolchain') + dependsOn tasks.named('verifyReleaseJava16Toolchain') dependsOn tasks.named('verifyReleaseConfiguration') dependsOn tasks.named('verifyReleaseDependencies') dependsOn tasks.named('verifyMavenCoordinates') @@ -216,8 +218,8 @@ tasks.register('verifyReleaseArtifacts') { if (entry.name.endsWith('.class')) { byte[] header = zip.getInputStream(entry).withCloseable { it.readNBytes(8) } int major = ((header[6] & 0xff) << 8) | (header[7] & 0xff) - if (major != 52) { - throw new GradleException("${entry.name} uses bytecode major ${major}, not Java 8") + if (major != 60) { + throw new GradleException("${entry.name} uses bytecode major ${major}, not Java 16") } } if (entry.name ==~ /.*\.(class|java|json|md|toml|mcmeta|html)/) { @@ -243,7 +245,7 @@ tasks.register('verifyReleaseArtifacts') { new ZipFile(main).withCloseable { zip -> Set names = zip.entries().toList().collect { it.name } as Set ['META-INF/mods.toml', 'META-INF/MANIFEST.MF', 'META-INF/coremods.json', - 'coremods/basemetals_116_compatibility.js', 'pack.mcmeta', + 'coremods/basemetals_117_compatibility.js', 'pack.mcmeta', 'data/basemetals/orespawn/provider.json', 'data/basemetals/recipes/stone_crackhammer.json', 'data/minecraft/tags/blocks/anvil.json', 'assets/basemetals/lang/en_us.json', 'META-INF/basemetals/docs/VERSIONS.md'].each { required -> @@ -252,26 +254,26 @@ tasks.register('verifyReleaseArtifacts') { Manifest manifest = new Manifest(zip.getInputStream(zip.getEntry('META-INF/MANIFEST.MF'))) if (manifest.mainAttributes.getValue('Maven-Artifact') != expectedMavenCoordinate || manifest.mainAttributes.getValue('Build-Target') != - 'minecraft-1.16.5-forge-36.2.34-java-8') { + 'minecraft-1.17.1-forge-37.1.1-java-16') { throw new GradleException('Release manifest contains the wrong identity') } String modsToml = zip.getInputStream(zip.getEntry('META-INF/mods.toml')).getText('UTF-8') - if (modsToml.contains('${') || !modsToml.contains('version="3.1.0.116051"') - || !modsToml.contains('versionRange="[4.1.0.116051,5.0.0)"') - || !modsToml.contains('loaderVersion="[36,)"') - || !modsToml.contains('versionRange="[36,)"') - || !modsToml.contains('versionRange="[1.16.5]"')) { + if (modsToml.contains('${') || !modsToml.contains('version="3.1.0.117011"') + || !modsToml.contains('versionRange="[4.1.0.117011,5.0.0)"') + || !modsToml.contains('loaderVersion="[37,38)"') + || !modsToml.contains('versionRange="[37,38)"') + || !modsToml.contains('versionRange="[1.17.1]"')) { throw new GradleException('Release mods.toml contains unresolved or incompatible metadata') } def pack = new JsonSlurper().parse(zip.getInputStream(zip.getEntry('pack.mcmeta'))) - if (pack.pack.pack_format != 6) { - throw new GradleException('Release resources must use Minecraft 1.16 pack format 6') + if (pack.pack.pack_format != 7) { + throw new GradleException('Release resources must use Minecraft 1.17 pack format 7') } def provider = new JsonSlurper().parse(zip.getInputStream( zip.getEntry('data/basemetals/orespawn/provider.json'))) if (provider.schema_version != 3 || provider.provider_revision != 1 || provider.provider_modid != 'basemetals' || provider.ores.size() != 11 - || provider.ores['basemetals:ore/copper'].enabled != true) { + || provider.ores['basemetals:ore/copper'].enabled != false) { throw new GradleException('OreSpawn provider contract changed') } def locales = names.findAll { it ==~ /assets\/basemetals\/lang\/.+\.json/ } diff --git a/gradle/stage-orespawn-candidate.ps1 b/gradle/stage-orespawn-candidate.ps1 index 3565baf20..9213af51c 100644 --- a/gradle/stage-orespawn-candidate.ps1 +++ b/gradle/stage-orespawn-candidate.ps1 @@ -4,8 +4,8 @@ param( ) $ErrorActionPreference = 'Stop' -$candidateVersion = '4.1.0.116051' -$candidateSha256 = 'CDF59D83F191C5FBCD8921228DB577066A63A8FEB25CA79DB4EAEEA32D32DB04' +$candidateVersion = '4.1.0.117011' +$candidateSha256 = '1BDEDCBB179CB5A3B169E5C8A6B301E3888AE15B94108B0AEC627D705CFAD833' if ((Get-FileHash -LiteralPath $CandidateJar -Algorithm SHA256).Hash -ne $candidateSha256) { throw 'The OreSpawn candidate differs from the qualified build.' @@ -18,9 +18,9 @@ try { if ($null -eq $metadata) { throw 'OreSpawn mod metadata is missing.' } $reader = [IO.StreamReader]::new($metadata.Open()) try { $text = $reader.ReadToEnd() } finally { $reader.Dispose() } - if (!$text.Contains('version="4.1.0.116051"') -or !$text.Contains('versionRange="[1.16.5,1.17)"') -or + if (!$text.Contains('version="4.1.0.117011"') -or !$text.Contains('versionRange="[1.17.1,1.18)"') -or $null -eq $archive.GetEntry('zone/moddev/mc/orespawn/api/client/WorldSettingsExtensionRegistry.class')) { - throw 'Expected the OreSpawn 1.16.5 candidate with its configuration-screen API.' + throw 'Expected the OreSpawn 1.17.1 candidate with its configuration-screen API.' } } finally { $archive.Dispose() } diff --git a/gradle/stage-orespawn-release.sh b/gradle/stage-orespawn-release.sh index 77f599ddc..0587b7a86 100644 --- a/gradle/stage-orespawn-release.sh +++ b/gradle/stage-orespawn-release.sh @@ -5,7 +5,7 @@ repository="${1:?Usage: stage-orespawn-release.sh }" value() { sed -n "s/^$1=//p" gradle.properties; } if [[ "$(value orespawn_dependency_mode)" == "candidate" ]]; then - echo 'Publication is blocked: pin the public OreSpawn 1.16.5 release first.' >&2 + echo 'Publication is blocked: pin the public OreSpawn 1.17.1 release first.' >&2 exit 1 fi diff --git a/gradle/verification/development.gradle b/gradle/verification/development.gradle index 6e7c97cc8..7e48cf16f 100644 --- a/gradle/verification/development.gradle +++ b/gradle/verification/development.gradle @@ -133,8 +133,8 @@ def verifyLegacyUpgradeRun = tasks.register('verifyLegacyUpgradeRun') { if (fixtureManifest.isFile()) { boolean from110 = new File(runDirectory, 'world/BASEMETALS_1_10_FIXTURE_COMPLETE.txt').isFile() - String marker = from110 ? 'BASEMETALS_1_10_TO_1_16_UPGRADE PASS' - : 'BASEMETALS_1_12_TO_1_16_UPGRADE PASS' + String marker = from110 ? 'BASEMETALS_1_10_TO_1_17_UPGRADE PASS' + : 'BASEMETALS_1_12_TO_1_17_UPGRADE PASS' if (!text.contains(marker)) { throw new GradleException("Complete ${from110 ? '1.10' : '1.12'} fixture verification did not report PASS") } diff --git a/gradle/verification/generated-data.gradle b/gradle/verification/generated-data.gradle index f15ff566c..54e797b0d 100644 --- a/gradle/verification/generated-data.gradle +++ b/gradle/verification/generated-data.gradle @@ -1,95 +1,67 @@ import groovy.json.JsonSlurper -import groovy.xml.XmlSlurper -import java.security.MessageDigest -import java.util.jar.Manifest -import java.util.zip.ZipFile -def sha256 = project.ext.baseMetalsBuild.sha256 +def generateCatalogueResources = tasks.register('generateCatalogueResources', Exec) { + group = 'data generation' + description = 'Updates recipes, loot, tags and translations for Minecraft 1.17.1.' + commandLine 'node', 'tools/generate_117_resources.js' +} -def verifyGeneratedData = tasks.register('verifyGeneratedData', Exec) { - group = 'verification' - description = 'Regenerates and proves that the committed Minecraft 1.16.5 resource projection is current.' - commandLine 'node', 'tools/generate_116_resources.js' - def snapshot = { - Map result = new TreeMap<>() - [file('src/generated/resources'), - file('src/main/resources/data/basemetals/orespawn/provider.json')].each { File root -> - if (root.isFile()) { - result[project.relativePath(root).replace('\\', '/')] = sha256(root) - } else if (root.isDirectory()) { - fileTree(root) { exclude '.cache/**' }.files.findAll { it.isFile() }.each { File generated -> - result[project.relativePath(generated).replace('\\', '/')] = sha256(generated) - } - } - } - result - } - doFirst { ext.beforeGeneration = snapshot() } +tasks.matching { it.name == 'runData' }.configureEach { mustRunAfter generateCatalogueResources } +tasks.named('processResources') { mustRunAfter generateCatalogueResources } + +def generateResources = tasks.register('generateResources') { + group = 'data generation' + description = 'Updates the saved resources, including Kiri\'s native Forge ore models.' + dependsOn generateCatalogueResources, 'runData' doLast { - Map afterGeneration = snapshot() - if (ext.beforeGeneration != afterGeneration) { - Set beforePaths = ext.beforeGeneration.keySet() - Set afterPaths = afterGeneration.keySet() - List added = (afterPaths - beforePaths).toList().sort() - List removed = (beforePaths - afterPaths).toList().sort() - List changed = (beforePaths.intersect(afterPaths)).findAll { - ext.beforeGeneration[it] != afterGeneration[it] - }.toList().sort() - throw new GradleException('Generated resources were stale. Commit the generator output. ' + - "Added=${added.take(20)}, removed=${removed.take(20)}, changed=${changed.take(20)}") + File models = layout.buildDirectory.dir('native-generated-resources').get().asFile + if (fileTree(models) { include 'assets/basemetals/models/block/*_ore.json' }.files.size() != 13) { + throw new GradleException('Forge did not run the Base Metals model provider') + } + copy { + from layout.buildDirectory.dir('native-generated-resources') + into 'src/generated/resources' + exclude '.cache/**' } } } -def oreModelsDirectory = file('src/main/resources/assets/basemetals/models/block') -def oreModelSnapshot = { File directory -> - fileTree(directory) { include '*_ore.json' }.files.collectEntries { - [(it.name): sha256(it)] - } -} -def generateOreModels = tasks.register('generateOreModels', JavaExec) { + +tasks.register('generateOreModels') { group = 'data generation' - description = 'Uses vanilla host textures when an ore overlay is present, otherwise keeps the legacy model.' - dependsOn tasks.named('modelGeneratorClasses') - classpath = sourceSets.modelGenerator.runtimeClasspath - mainClass = 'zone.moddev.mc.basemetals.data.BMBlockStateProvider' - args file('src/main/resources').absolutePath + description = 'Alias for the native resource generator.' + dependsOn generateResources } -tasks.named('processResources') { dependsOn generateOreModels } -def oreModelVerificationDirectory = layout.buildDirectory.dir('ore-model-verification') -def verifyGeneratedOreModels = tasks.register('verifyGeneratedOreModels', JavaExec) { + +def verifyGeneratedData = tasks.register('verifyGeneratedData', Exec) { group = 'verification' - description = 'Checks the saved ore models without rewriting them.' - dependsOn tasks.named('modelGeneratorClasses') - classpath = sourceSets.modelGenerator.runtimeClasspath - mainClass = 'zone.moddev.mc.basemetals.data.BMBlockStateProvider' - args file('src/main/resources').absolutePath, '--output', oreModelVerificationDirectory.get().asFile.absolutePath + description = 'Checks generated catalogue resources without rewriting them.' + commandLine 'node', 'tools/generate_117_resources.js', '--verify' +} - doFirst { - File output = oreModelVerificationDirectory.get().asFile.canonicalFile - File buildDirectory = layout.buildDirectory.get().asFile.canonicalFile - if (!output.toPath().startsWith(buildDirectory.toPath()) || output.name != 'ore-model-verification') { - throw new GradleException("Unsafe ore-model verification directory: ${output}") - } - delete output - } +tasks.register('verifyGeneratedOreModels') { + group = 'verification' + description = 'Runs native datagen into build output and checks the committed models and mining tags.' + dependsOn 'runData' doLast { - File expectedModels = new File(oreModelVerificationDirectory.get().asFile, 'assets/basemetals/models/block') - if (oreModelSnapshot(oreModelsDirectory) != oreModelSnapshot(expectedModels)) { - throw new GradleException('Ore models are stale. Build the project and commit the updated JSON files.') + File generated = layout.buildDirectory.dir('native-generated-resources').get().asFile + fileTree(generated) { exclude '.cache/**' }.files.findAll { it.isFile() }.each { model -> + String relative = generated.toPath().relativize(model.toPath()).toString() + File committed = file("src/generated/resources/${relative}") + if (!committed.isFile() || new JsonSlurper().parse(model) != new JsonSlurper().parse(committed)) { + throw new GradleException("Native generated resource is stale: ${relative}. Run generateResources.") + } + } + if (fileTree(generated) { include 'assets/basemetals/models/block/*_ore.json' }.files.size() != 13) { + throw new GradleException('Native datagen must generate all thirteen ore models') } } } -// Release checks must see stale models before the normal build updates them. -generateOreModels.configure { mustRunAfter verifyGeneratedOreModels } -tasks.named('verifyReleaseArtifacts') { dependsOn verifyGeneratedOreModels } + +tasks.named('verifyReleaseArtifacts') { dependsOn tasks.named('verifyGeneratedOreModels') } tasks.named('check') { - dependsOn tasks.named('verifyDevelopmentLaunches') - dependsOn verifyGeneratedData - dependsOn tasks.named('verifyReleaseConfiguration') - dependsOn tasks.named('verifyReleaseDependencies') + dependsOn tasks.named('verifyDevelopmentLaunches'), verifyGeneratedData + dependsOn tasks.named('verifyReleaseConfiguration'), tasks.named('verifyReleaseDependencies') dependsOn tasks.named('verifyMavenCoordinates') } -project.ext.baseMetalsBuild.putAll([ - generateOreModels: generateOreModels -]) +project.ext.baseMetalsBuild.generateOreModels = tasks.named('generateOreModels') diff --git a/gradle/verification/packaged-forge.gradle b/gradle/verification/packaged-forge.gradle index e38c7dc61..4221bd0c0 100644 --- a/gradle/verification/packaged-forge.gradle +++ b/gradle/verification/packaged-forge.gradle @@ -26,8 +26,8 @@ def compileClientIntegrationTestMod = tasks.register('compileClientIntegrationTe source fileTree('src/clientIntegrationTest/java') classpath = files(sourceSets.main.output, sourceSets.main.compileClasspath) destinationDirectory = clientIntegrationClasses - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_16 + targetCompatibility = JavaVersion.VERSION_16 options.encoding = 'UTF-8' } def clientIntegrationTestModJar = tasks.register('clientIntegrationTestModJar', Jar) { @@ -38,11 +38,14 @@ def clientIntegrationTestModJar = tasks.register('clientIntegrationTestModJar', from 'src/clientIntegrationTest/resources' } def oreOverlayClientFixtures = layout.buildDirectory.dir('ore-overlay-client-fixtures') -def generateOreOverlayClientFixtures = tasks.register('generateOreOverlayClientFixtures', JavaExec) { - dependsOn tasks.named('modelGeneratorClasses') - classpath = sourceSets.modelGenerator.runtimeClasspath - mainClass = 'zone.moddev.mc.basemetals.data.BMBlockStateProvider' - args file('src/main/resources').absolutePath, '--client-fixtures', oreOverlayClientFixtures.get().asFile.absolutePath +def generateOreOverlayClientFixtures = tasks.register('generateOreOverlayClientFixtures', Copy) { + from('src/main/resources/assets/basemetals/textures/block') { + include 'tin_ore.png', 'coldiron_ore.png', 'starsteel_ore.png' + rename 'tin_ore.png', 'stone.png' + rename 'coldiron_ore.png', 'netherrack.png' + rename 'starsteel_ore.png', 'end_stone.png' + } + into oreOverlayClientFixtures.map { it.dir('assets/minecraft/textures/block') } } def packagedClientProbeJar = renamer.classes(clientIntegrationTestModJar) { map.from minecraft.dependency.toSrgFile @@ -54,7 +57,7 @@ def packagedForgeServerRuntime = providers.gradleProperty('packagedForgeServerRu def packagedForgeClientRuntime = providers.gradleProperty('packagedForgeClientRuntime') def requireRuntimeDirectory = { Provider configuredPath, String propertyName -> if (!configuredPath.isPresent()) { - throw new GradleException("Pass -P${propertyName}=") + throw new GradleException("Pass -P${propertyName}=") } File runtime = file(configuredPath.get()).canonicalFile if (!runtime.isDirectory()) { @@ -127,23 +130,28 @@ def packagedServerProcess = tasks.register('packagedServerProcess', Exec) { dependsOn preparePackagedServerIntegration doFirst { File runtime = requireRuntimeDirectory(packagedForgeServerRuntime, 'packagedForgeServerRuntime') - File launcher = new File(runtime, "forge-${minecraft_version}-${forge_version}.jar") - File vanillaServer = new File(runtime, "minecraft_server.${minecraft_version}.jar") - File libraries = new File(runtime, 'libraries') - [launcher, vanillaServer, libraries].each { - if (!it.exists()) throw new GradleException("Incomplete official server runtime: ${it}") - } + String platform = System.getProperty('os.name').toLowerCase().contains('windows') ? 'win' : 'unix' + File arguments = new File(runtime, + "libraries/net/minecraftforge/forge/${minecraft_version}-${forge_version}/${platform}_args.txt") + if (!arguments.isFile()) throw new GradleException("Missing official Forge arguments: ${arguments}") + String resolved = arguments.getText('UTF-8') + .replace('libraries/', runtime.absolutePath.replace('\\', '/') + '/libraries/') + .replace('-DlibraryDirectory=libraries', + '-DlibraryDirectory=' + runtime.absolutePath.replace('\\', '/') + '/libraries') + File stagedArguments = new File(packagedServerRunDirectory.get().asFile, 'forge-arguments.txt') + stagedArguments.setText(resolved, 'UTF-8') workingDir packagedServerRunDirectory.get().asFile commandLine javaToolchains.launcherFor { - languageVersion = JavaLanguageVersion.of(8) + languageVersion = JavaLanguageVersion.of(16) vendor = JvmVendorSpec.ADOPTIUM }.get().executablePath.asFile.absolutePath, - '-Xms512m', '-Xmx2g', '-Dbasemetalsprobe.sampleOres=true', '-jar', launcher.absolutePath, 'nogui' + '-Xms512m', '-Xmx2g', '--add-opens', 'java.base/java.lang.invoke=ALL-UNNAMED', + '-Dbasemetalsprobe.sampleOres=true', '@' + stagedArguments.absolutePath, 'nogui' } } tasks.register('packagedServerIntegrationTest') { group = 'verification' - description = 'Runs the exact release jars in an official Forge 36 dedicated-server runtime.' + description = 'Runs the exact release jars in an official Forge 37 dedicated-server runtime.' dependsOn packagedServerProcess doLast { assertPackagedRuntimePassed(packagedServerRunDirectory.get().asFile, @@ -189,7 +197,7 @@ def preparePackagedClientIntegration = tasks.register('preparePackagedClientInte File overlayPack = new File(runDirectory, 'resourcepacks/basemetals-ore-overlay-fixture') copy { from oreOverlayClientFixtures; into overlayPack } new File(overlayPack, 'pack.mcmeta').setText( - '{"pack":{"pack_format":6,"description":"Base Metals ore overlay test fixture"}}\n', 'UTF-8') + '{"pack":{"pack_format":7,"description":"Base Metals ore overlay test fixture"}}\n', 'UTF-8') new File(runDirectory, 'options.txt').setText( 'fullscreen:false\nlang:en_us\nresourcePacks:["file/basemetals-ore-overlay-fixture"]\n', 'UTF-8') } @@ -202,6 +210,7 @@ def packagedClientProcess = tasks.register('packagedClientProcess', Exec) { File runtime = requireRuntimeDirectory(packagedForgeClientRuntime, 'packagedForgeClientRuntime') File forgeJsonFile = new File(runtime, "versions/${minecraft_version}-forge-${forge_version}/${minecraft_version}-forge-${forge_version}.json") + if (!forgeJsonFile.isFile()) forgeJsonFile = new File(runtime, "versions/forge-${forge_version}/forge-${forge_version}.json") File baseJsonFile = new File(runtime, "versions/${minecraft_version}/${minecraft_version}.json") File baseJar = new File(runtime, "versions/${minecraft_version}/${minecraft_version}.jar") File libraries = new File(runtime, 'libraries') @@ -242,6 +251,13 @@ def packagedClientProcess = tasks.register('packagedClientProcess', Exec) { } List classpathFiles = new ArrayList<>(classpathByModule.values()) classpathFiles.add(baseJar) + Map replacements = [library_directory: libraries.absolutePath, + classpath_separator: File.pathSeparator, version_name: forgeJson.inheritsFrom] + List forgeJvmArguments = ((List) forgeJson.arguments.jvm).collect { value -> + replacements.each { key, replacement -> value = value.replace('${' + key + '}', replacement) } + if (value.contains('${')) throw new GradleException("Unresolved Forge launch argument: ${value}") + value + } List gameArguments = [] gameArguments.addAll((List) ((Map) forgeJson.arguments).game) gameArguments.addAll([ @@ -258,21 +274,25 @@ def packagedClientProcess = tasks.register('packagedClientProcess', Exec) { ]) workingDir packagedClientRunDirectory.get().asFile commandLine javaToolchains.launcherFor { - languageVersion = JavaLanguageVersion.of(8) + languageVersion = JavaLanguageVersion.of(16) vendor = JvmVendorSpec.ADOPTIUM }.get().executablePath.asFile.absolutePath, '-Xms512m', '-Xmx2g', '-Dbasemetalsclientprobe.enabled=true', + '--add-opens', 'java.base/java.lang.invoke=ALL-UNNAMED', "-Djava.library.path=${natives.absolutePath}", '-Dminecraft.launcher.brand=basemetals-validation', '-Dminecraft.launcher.version=1', '-cp', classpathFiles.collect { it.absolutePath }.join(File.pathSeparator), (String) forgeJson.mainClass + List launch = new ArrayList<>(commandLine) + launch.addAll(1, forgeJvmArguments) + commandLine launch args gameArguments } } tasks.register('packagedClientIntegrationTest') { group = 'verification' - description = 'Loads and renders the exact release jars in an official Forge 36 client runtime.' + description = 'Loads and renders the exact release jars in an official Forge 37 client runtime.' dependsOn packagedClientProcess doLast { File runDirectory = packagedClientRunDirectory.get().asFile @@ -323,7 +343,7 @@ tasks.register('packagedClientReloadTest') { tasks.register('packagedRuntimeIntegrationTest') { group = 'verification' - description = 'Runs the exact Base Metals and OreSpawn jars in official Forge 36 server and client runtimes.' + description = 'Runs the exact Base Metals and OreSpawn jars in official Forge 37 server and client runtimes.' dependsOn tasks.named('packagedServerReloadTest') dependsOn tasks.named('packagedClientReloadTest') } @@ -335,11 +355,11 @@ tasks.register('packagedMineralogyIntegrationTest', Exec) { timeout = java.time.Duration.ofMinutes(5) doFirst { String configuredJar = providers.gradleProperty('mineralogyTestJar').orNull - if (configuredJar == null) throw new GradleException('Pass -PmineralogyTestJar=') + if (configuredJar == null) throw new GradleException('Pass -PmineralogyTestJar=') File mineralogy = file(configuredJar) if (!mineralogy.isFile() || sha256(mineralogy) != - '6A22C97BC74338327C62B7A9DF42499BBCB6E6DF5C06BE33EECF2662E007BE1C') { - throw new GradleException('Expected the qualified Mineralogy 6.1.0.116051 artifact') + '79B2275A0E3F3A390DC29694206D37F8D1F1D48A4935A3B3E9B096CEB8A0ACFE') { + throw new GradleException('Expected the qualified Mineralogy 6.1.4.117011 artifact') } File runDirectory = prepareBuildOwnedRunDirectory( @@ -352,13 +372,21 @@ tasks.register('packagedMineralogyIntegrationTest', Exec) { 'level-name=world\nlevel-seed=8675309\nonline-mode=false\nserver-port=0\nview-distance=4\nmax-tick-time=-1\n', 'UTF-8') new File(runDirectory, 'eula.txt').setText('eula=true\n', 'UTF-8') File runtime = requireRuntimeDirectory(packagedForgeServerRuntime, 'packagedForgeServerRuntime') + String platform = System.getProperty('os.name').toLowerCase().contains('windows') ? 'win' : 'unix' + File arguments = new File(runtime, + "libraries/net/minecraftforge/forge/${minecraft_version}-${forge_version}/${platform}_args.txt") + File stagedArguments = new File(runDirectory, 'forge-arguments.txt') + stagedArguments.setText(arguments.getText('UTF-8') + .replace('libraries/', runtime.absolutePath.replace('\\', '/') + '/libraries/') + .replace('-DlibraryDirectory=libraries', + '-DlibraryDirectory=' + runtime.absolutePath.replace('\\', '/') + '/libraries'), 'UTF-8') workingDir runDirectory commandLine javaToolchains.launcherFor { - languageVersion = JavaLanguageVersion.of(8) + languageVersion = JavaLanguageVersion.of(16) vendor = JvmVendorSpec.ADOPTIUM }.get().executablePath.asFile.absolutePath, - '-Xms512m', '-Xmx2g', '-Dbasemetalsprobe.sampleOres=true', '-jar', - new File(runtime, "forge-${minecraft_version}-${forge_version}.jar").absolutePath, 'nogui' + '-Xms512m', '-Xmx2g', '--add-opens', 'java.base/java.lang.invoke=ALL-UNNAMED', + '-Dbasemetalsprobe.sampleOres=true', '@' + stagedArguments.absolutePath, 'nogui' } doLast { File runDirectory = file("${buildDir}/packaged-mineralogy-run") @@ -380,7 +408,7 @@ tasks.register('contentModeIntegrationTest', Exec) { into fixture } File java = javaToolchains.launcherFor { - languageVersion = JavaLanguageVersion.of(8) + languageVersion = JavaLanguageVersion.of(16) vendor = JvmVendorSpec.ADOPTIUM }.get().executablePath.asFile commandLine 'node', file('tools/test_content_modes.js').absolutePath, java.absolutePath, diff --git a/src/clientIntegrationTest/java/zone/moddev/mc/basemetals/testmod/BaseMetalsClientProbe.java b/src/clientIntegrationTest/java/zone/moddev/mc/basemetals/testmod/BaseMetalsClientProbe.java index f0c66779c..02b4ae39f 100644 --- a/src/clientIntegrationTest/java/zone/moddev/mc/basemetals/testmod/BaseMetalsClientProbe.java +++ b/src/clientIntegrationTest/java/zone/moddev/mc/basemetals/testmod/BaseMetalsClientProbe.java @@ -17,39 +17,39 @@ import zone.moddev.mc.basemetals.material.MaterialCatalogue; import zone.moddev.mc.basemetals.material.MaterialDefinition; -import net.minecraft.block.Block; +import net.minecraft.world.level.block.Block; import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.screen.MainMenuScreen; -import net.minecraft.client.renderer.model.BakedQuad; -import net.minecraft.client.renderer.model.IBakedModel; -import net.minecraft.item.ItemStack; -import net.minecraft.item.BowItem; -import net.minecraft.item.Items; -import net.minecraft.resources.IResource; +import net.minecraft.client.gui.screens.TitleScreen; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.BowItem; +import net.minecraft.world.item.Items; +import net.minecraft.server.packs.resources.Resource; import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.RenderTypeLookup; -import net.minecraft.util.Direction; -import net.minecraft.util.Hand; -import net.minecraft.util.ResourceLocation; -import net.minecraft.world.GameType; -import net.minecraft.world.WorldSettings; +import net.minecraft.client.renderer.ItemBlockRenderTypes; +import net.minecraft.core.Direction; +import net.minecraft.world.InteractionHand; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.GameType; +import net.minecraft.world.level.LevelSettings; import net.minecraft.world.Difficulty; -import net.minecraft.world.GameRules; -import net.minecraft.world.gen.settings.DimensionGeneratorSettings; -import net.minecraft.util.datafix.codec.DatapackCodec; -import net.minecraft.util.registry.DynamicRegistries; -import net.minecraft.util.registry.Registry; -import com.mojang.blaze3d.matrix.MatrixStack; +import net.minecraft.world.level.GameRules; +import net.minecraft.world.level.levelgen.WorldGenSettings; +import net.minecraft.world.level.DataPackConfig; +import net.minecraft.core.RegistryAccess; +import net.minecraft.core.Registry; +import com.mojang.blaze3d.vertex.PoseStack; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.ForgeHooksClient; import net.minecraftforge.client.event.RenderWorldLastEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.ModList; -import net.minecraftforge.fml.ExtensionPoint; +import net.minecraftforge.fmlclient.ConfigGuiHandler; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.event.TickEvent; -import net.minecraftforge.fml.client.gui.screen.ModListScreen; -import net.minecraftforge.fml.client.gui.widget.ModListWidget; +import net.minecraftforge.fmlclient.gui.screen.ModListScreen; +import net.minecraftforge.fmlclient.gui.widget.ModListWidget; import net.minecraftforge.registries.ForgeRegistries; import org.apache.logging.log4j.LogManager; @@ -58,10 +58,10 @@ import zone.moddev.mc.basemetals.client.BaseMetalsConfigScreen; import zone.moddev.mc.basemetals.config.BaseMetalsConfig; import zone.moddev.mc.basemetals.config.ContentMode; -import net.minecraft.client.gui.widget.button.Button; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.screen.ConfirmScreen; -import net.minecraft.client.resources.I18n; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.ConfirmScreen; +import net.minecraft.client.resources.language.I18n; /** Checks models and renders a disposable world in the packaged Forge client. */ @Mod(BaseMetalsClientProbe.MODID) @@ -87,12 +87,11 @@ public BaseMetalsClientProbe() { public static void onScreenRendered(net.minecraftforge.client.event.GuiScreenEvent.DrawScreenEvent.Post event) { BaseMetalsClientProbe probe = instance; if (probe == null || !probe.pendingCreativeBucketScreenshot - || !(event.getGui() instanceof net.minecraft.client.gui.screen.inventory.CreativeScreen)) return; + || !(event.getGui() instanceof net.minecraft.client.gui.screens.inventory.CreativeModeInventoryScreen)) return; Minecraft minecraft = Minecraft.getInstance(); - try (net.minecraft.client.renderer.texture.NativeImage screenshot = net.minecraft.util.ScreenShotHelper - .takeScreenshot(minecraft.getWindow().getWidth(), minecraft.getWindow().getHeight(), - minecraft.getMainRenderTarget())) { + try (com.mojang.blaze3d.platform.NativeImage screenshot = net.minecraft.client.Screenshot + .takeScreenshot(minecraft.getMainRenderTarget())) { screenshot.writeToFile(new File("creative-buckets.png")); LOGGER.info("BASEMETALS_CREATIVE_BUCKET_SCREENSHOT saved=creative-buckets.png"); } catch (IOException failure) { @@ -135,13 +134,13 @@ private void tick() { minecraft.screen == null ? "none" : minecraft.screen.getClass().getName()); if (++stateTicks > 3600) fail(minecraft, "Timed out in client probe state " + state); try { - if (state == 0 && minecraft.screen instanceof MainMenuScreen) { + if (state == 0 && minecraft.screen instanceof TitleScreen) { if (Boolean.getBoolean("basemetalsclientprobe.login")) { require(BaseMetalsConfig.activeMode().serializedName().equals( System.getProperty("basemetalsclientprobe.expectedMode")), "startup mode differs from profile"); - minecraft.setScreen(new net.minecraft.client.gui.screen.ConnectingScreen( - minecraft.screen, minecraft, "127.0.0.1", - Integer.getInteger("basemetalsclientprobe.port", 25565))); + net.minecraft.client.gui.screens.ConnectScreen.startConnecting(minecraft.screen, minecraft, + net.minecraft.client.multiplayer.resolver.ServerAddress.parseString( + "127.0.0.1:" + Integer.getInteger("basemetalsclientprobe.port", 25565)), null); nextState(3); return; } @@ -174,14 +173,14 @@ private static void createWorld(Minecraft minecraft) { return; } - DynamicRegistries.Impl registries = DynamicRegistries.builtin(); - DimensionGeneratorSettings generator = DimensionGeneratorSettings.makeDefault( + RegistryAccess.RegistryHolder registries = RegistryAccess.builtin(); + WorldGenSettings generator = WorldGenSettings.makeDefault( registries.registryOrThrow(Registry.DIMENSION_TYPE_REGISTRY), registries.registryOrThrow(Registry.BIOME_REGISTRY), registries.registryOrThrow(Registry.NOISE_GENERATOR_SETTINGS_REGISTRY)) .withSeed(false, java.util.OptionalLong.of(0L)); - WorldSettings settings = new WorldSettings("Base Metals Client Smoke", GameType.CREATIVE, - false, Difficulty.NORMAL, true, new GameRules(), DatapackCodec.DEFAULT); + LevelSettings settings = new LevelSettings("Base Metals Client Smoke", GameType.CREATIVE, + false, Difficulty.NORMAL, true, new GameRules(), DataPackConfig.DEFAULT); minecraft.createLevel(WORLD_DIRECTORY, settings, registries, generator); } @@ -189,12 +188,12 @@ private static void createWorld(Minecraft minecraft) { private static void spawnProjectileRenderChecks(Minecraft minecraft) { java.util.UUID playerId = minecraft.player.getUUID(); minecraft.getSingleplayerServer().execute(() -> { - net.minecraft.entity.player.ServerPlayerEntity player = minecraft.getSingleplayerServer() + net.minecraft.server.level.ServerPlayer player = minecraft.getSingleplayerServer() .getPlayerList().getPlayer(playerId); - net.minecraft.world.server.ServerWorld world = player.getLevel(); + net.minecraft.server.level.ServerLevel world = player.getLevel(); if (Boolean.getBoolean("basemetalsclientprobe.reload")) { java.util.Set savedAmmo = new java.util.HashSet<>(); - for (net.minecraft.entity.Entity entity : world.getAllEntities()) { + for (net.minecraft.world.entity.Entity entity : world.getAllEntities()) { if (entity instanceof zone.moddev.mc.basemetals.entity.MaterialProjectile) { savedAmmo.add(((zone.moddev.mc.basemetals.entity.MaterialProjectile) entity) .getAmmunition().getItem().getRegistryName().toString()); @@ -210,7 +209,7 @@ private static void spawnProjectileRenderChecks(Minecraft minecraft) { return; } - net.minecraft.util.math.vector.Vector3d look = player.getLookAngle(); + net.minecraft.world.phys.Vec3 look = player.getLookAngle(); int index = 0; for (String material : new String[] {"gold", "steel", "adamantine"}) { @@ -221,7 +220,7 @@ private static void spawnProjectileRenderChecks(Minecraft minecraft) { bolt ? zone.moddev.mc.basemetals.entity.ModEntities.CUSTOM_BOLT.get() : zone.moddev.mc.basemetals.entity.ModEntities.CUSTOM_ARROW.get(), world, player, new ItemStack(ModContent.item(name).get())); - net.minecraft.entity.Entity entity = projectile; + net.minecraft.world.entity.Entity entity = projectile; entity.setPos(player.getX() + look.x * 3 + (index++ - 2.5) * 0.25, player.getY() + player.getEyeHeight(), player.getZ() + look.z * 3); entity.setNoGravity(true); @@ -233,7 +232,7 @@ private static void spawnProjectileRenderChecks(Minecraft minecraft) { private static void validateCreativeCrossbows(Minecraft minecraft) { require(minecraft.level.isClientSide, "crossbow probe must run on the client"); - require(minecraft.player.abilities.instabuild, "crossbow probe needs a Creative player"); + require(minecraft.player.getAbilities().instabuild, "crossbow probe needs a Creative player"); int shots = 0; for (String name : ModContent.itemsById().keySet()) { @@ -244,11 +243,11 @@ private static void validateCreativeCrossbows(Minecraft minecraft) { new ItemStack(ModContent.item(boltName).get())}; for (ItemStack supply : ammunition) { - minecraft.player.inventory.clearContent(); + minecraft.player.getInventory().clearContent(); ItemStack launcher = new ItemStack(ModContent.item(name).get()); ItemStack original = supply.copy(); - minecraft.player.setItemInHand(Hand.MAIN_HAND, launcher); - minecraft.player.setItemInHand(Hand.OFF_HAND, supply); + minecraft.player.setItemInHand(InteractionHand.MAIN_HAND, launcher); + minecraft.player.setItemInHand(InteractionHand.OFF_HAND, supply); BowItem crossbow = (BowItem) launcher.getItem(); crossbow.releaseUsing(launcher, minecraft.level, minecraft.player, @@ -261,7 +260,7 @@ private static void validateCreativeCrossbows(Minecraft minecraft) { } } - minecraft.player.inventory.clearContent(); + minecraft.player.getInventory().clearContent(); require(shots == 108, "all 27 crossbows need four client ammunition cases"); LOGGER.info("BASEMETALS_CLIENT_CROSSBOWS PASS shots={}", Integer.valueOf(shots)); } @@ -270,7 +269,7 @@ private void checkLogin(Minecraft minecraft) throws IOException { boolean rejected = Boolean.getBoolean("basemetalsclientprobe.expectReject"); if (minecraft.level != null && minecraft.player != null && stateTicks > 60) { require(!rejected, "mismatched modes entered gameplay"); - net.minecraft.item.crafting.IRecipe bow = minecraft.level.getRecipeManager().byKey(new ResourceLocation("basemetals", "tin_bow")).orElse(null); + net.minecraft.world.item.crafting.Recipe bow = minecraft.level.getRecipeManager().byKey(new ResourceLocation("basemetals", "tin_bow")).orElse(null); require(bow != null, "recipe IDs changed during mode synchronization"); require(bow.isSpecial() == (BaseMetalsConfig.activeMode() == ContentMode.LOW_FANTASY), "client recipe policy did not match the server"); @@ -280,7 +279,7 @@ private void checkLogin(Minecraft minecraft) throws IOException { "earned recipe-book unlock did not survive the mode change"); for (String name : new String[] {"steel_bow", "adamantine_bow", "adamantine_crossbow", "adamantine_gear", "adamantine_arrow", "adamantine_rod", "adamantine_pickaxe"}) { - net.minecraft.item.crafting.IRecipe recipe = minecraft.level.getRecipeManager() + net.minecraft.world.item.crafting.Recipe recipe = minecraft.level.getRecipeManager() .byKey(new ResourceLocation("basemetals", name)).orElse(null); require(minecraft.player.getRecipeBook().contains(recipe) != recipe.isSpecial(), "material discovery did not synchronize to the client: " + name); @@ -289,16 +288,16 @@ private void checkLogin(Minecraft minecraft) throws IOException { .byKey(new ResourceLocation("basemetals", "gold_bow")).orElse(null)), "mode change unlocked an unearned recipe"); } - require(minecraft.player.inventory.getItem(0).getItem() == ModContent.item("tin_bow").get(), + require(minecraft.player.getInventory().getItem(0).getItem() == ModContent.item("tin_bow").get(), "existing restricted item did not synchronize"); finishLogin(minecraft, "connected"); - } else if (minecraft.screen instanceof net.minecraft.client.gui.screen.DisconnectedScreen) { + } else if (minecraft.screen instanceof net.minecraft.client.gui.screens.DisconnectedScreen) { StringBuilder message = new StringBuilder(); try { for (java.lang.reflect.Field field : minecraft.screen.getClass().getDeclaredFields()) { - if (net.minecraft.util.text.ITextComponent.class.isAssignableFrom(field.getType())) { + if (net.minecraft.network.chat.Component.class.isAssignableFrom(field.getType())) { field.setAccessible(true); - message.append(((net.minecraft.util.text.ITextComponent) field.get(minecraft.screen)).getString()); + message.append(((net.minecraft.network.chat.Component) field.get(minecraft.screen)).getString()); } } } catch (ReflectiveOperationException failure) { @@ -329,7 +328,7 @@ private static void validateClientContent(Minecraft minecraft) throws IOExceptio require(ModList.get().isLoaded("basemetals"), "Base Metals is not loaded"); require(ModList.get().isLoaded("orespawn"), "OreSpawn is not loaded"); require(ModList.get().getModContainerById("basemetals").get() - .getCustomExtension(ExtensionPoint.CONFIGGUIFACTORY).isPresent(), + .getCustomExtension(ConfigGuiHandler.ConfigGuiFactory.class).isPresent(), "Base Metals Mods-list configuration screen is missing"); require(WorldSettingsExtensionRegistry.extensions().stream() .filter(extension -> "basemetals".equals(extension.id().getNamespace())).count() == 1, @@ -337,28 +336,45 @@ private static void validateClientContent(Minecraft minecraft) throws IOExceptio validateConfigScreen(minecraft); require(MaterialCatalogue.ALL.size() == 22, "material catalogue size"); require(ModContent.blocksById().size() == 360, "block catalogue size"); - require(ModContent.itemsById().size() == 1115, "item catalogue size"); + require(ModContent.itemsById().size() == 1127, "item catalogue size"); require(ModContent.fluids().size() == 36, "fluid catalogue size"); require(ForgeRegistries.ITEMS.containsKey(new ResourceLocation("basemetals", "mercury_bucket")), "mercury bucket registration"); validateCreativeBuckets(minecraft); + int rawItems = 0; + for (String name : ModContent.itemsById().keySet()) { + if (!name.endsWith("_raw")) continue; + + ItemStack stack = new ItemStack(ModContent.item(name).get()); + BakedModel model = minecraft.getItemRenderer().getModel(stack, null, null, 0); + require(stack.getItem().getItemCategory() == ModTabs.ITEMS, name + " creative group"); + require(model != minecraft.getModelManager().getMissingModel(), name + " model is missing"); + require(model.getParticleIcon().getName().equals(new ResourceLocation("basemetals", "item/" + name)), + name + " uses the wrong raw-metal sprite"); + rawItems++; + } + require(rawItems == 12, "raw-metal item model count"); + for (FluidContent fluid : ModContent.fluids().values()) { require(fluid.bucket().get().getItemCategory() == ModTabs.ITEMS, "bucket creative group"); - require(RenderTypeLookup.canRenderInLayer(fluid.block().get().defaultBlockState(), + require(ItemBlockRenderTypes.canRenderInLayer(fluid.block().get().defaultBlockState(), RenderType.translucent()), "molten block render layer"); - require(RenderTypeLookup.canRenderInLayer(fluid.source().get().defaultFluidState(), + require(ItemBlockRenderTypes.canRenderInLayer(fluid.source().get().defaultFluidState(), RenderType.translucent()), "molten source render layer"); - require(RenderTypeLookup.canRenderInLayer(fluid.flowing().get().defaultFluidState(), + require(ItemBlockRenderTypes.canRenderInLayer(fluid.flowing().get().defaultFluidState(), RenderType.translucent()), "molten flowing render layer"); validateBucketModel(minecraft, fluid.bucket().get().getRegistryName().getPath()); } - for (net.minecraft.block.Block block : ForgeRegistries.BLOCKS) { + for (net.minecraft.world.level.block.Block block : ForgeRegistries.BLOCKS) { if (!"basemetals".equals(block.getRegistryName().getNamespace())) continue; - if (block instanceof net.minecraft.block.DoorBlock - || block instanceof net.minecraft.block.TrapDoorBlock - || block instanceof net.minecraft.block.PaneBlock) { - require(RenderTypeLookup.canRenderInLayer(block.defaultBlockState(), + if (block instanceof net.minecraft.world.level.block.DoorBlock + || block instanceof net.minecraft.world.level.block.TrapDoorBlock + || block instanceof net.minecraft.world.level.block.IronBarsBlock) { + require(ItemBlockRenderTypes.canRenderInLayer(block.defaultBlockState(), RenderType.cutoutMipped()), "transparent block render layer: " + block); + require(block.getStateDefinition().getPossibleStates().stream().noneMatch( + net.minecraft.world.level.block.state.BlockState::canOcclude), + "transparent block hides neighbouring faces: " + block); } } validateOreModels(minecraft); @@ -383,7 +399,7 @@ private static void validateConfigScreen(Minecraft minecraft) { } require(baseMetalsIndex >= 0, "Base Metals is missing from the Mods list"); selectMod(modsScreen, "basemetals"); - ForgeHooksClient.drawScreen(modsScreen, new MatrixStack(), 0, 0, 0.0F); + ForgeHooksClient.drawScreen(modsScreen, new PoseStack(), 0, 0, 0.0F); Button configButton = button(modsScreen, 20); require(configButton.active, "Base Metals Config button is disabled in the Mods list"); require(modsScreen.mouseClicked(configButton.x + 1, configButton.y + 1, 0), @@ -398,10 +414,10 @@ private static void validateConfigScreen(Minecraft minecraft) { require(originalMode.equals(BaseMetalsConfig.CONTENT_MODE.get()) && originalEffects == BaseMetalsConfig.SPECIAL_EFFECTS.get(), "Cancel changed the loaded config"); - ForgeHooksClient.drawScreen(modsScreen, new MatrixStack(), 0, 0, 0.0F); + ForgeHooksClient.drawScreen(modsScreen, new PoseStack(), 0, 0, 0.0F); require(button(modsScreen, 20).active, "Config button was disabled on returning from the settings"); modsScreen.setSelected(null); - ForgeHooksClient.drawScreen(modsScreen, new MatrixStack(), 0, 0, 0.0F); + ForgeHooksClient.drawScreen(modsScreen, new PoseStack(), 0, 0, 0.0F); require(!button(modsScreen, 20).active, "Config button stayed enabled with no mod selected"); int forgeIndex = -1; for (int index = 0; index < ModList.get().getMods().size(); index++) { @@ -409,7 +425,7 @@ private static void validateConfigScreen(Minecraft minecraft) { } require(forgeIndex >= 0, "Forge is missing from the Mods list"); selectMod(modsScreen, "forge"); - ForgeHooksClient.drawScreen(modsScreen, new MatrixStack(), 0, 0, 0.0F); + ForgeHooksClient.drawScreen(modsScreen, new PoseStack(), 0, 0, 0.0F); require(!button(modsScreen, 20).active, "Base Metals enabled the Config button for Forge"); click(modsScreen, 6); require(minecraft.screen == parent, "Mods-list Done did not return to the main menu"); @@ -490,11 +506,11 @@ private static void click(Screen screen, int id) { private static void validateWallModels(Minecraft minecraft) { int states = 0; for (Block block : ForgeRegistries.BLOCKS) { - if (!(block instanceof net.minecraft.block.WallBlock) + if (!(block instanceof net.minecraft.world.level.block.WallBlock) || !"basemetals".equals(block.getRegistryName().getNamespace())) continue; - for (net.minecraft.block.BlockState state : block.getStateDefinition().getPossibleStates()) { - IBakedModel model = minecraft.getBlockRenderer().getBlockModel(state); + for (net.minecraft.world.level.block.state.BlockState state : block.getStateDefinition().getPossibleStates()) { + BakedModel model = minecraft.getBlockRenderer().getBlockModel(state); require(!"missingno".equals(model.getParticleIcon().getName().getPath()), "wall model missing: " + state); List quads = new ArrayList<>(model.getQuads(state, null, new Random(0))); @@ -527,14 +543,14 @@ private static void validateOreModels(Minecraft minecraft) throws IOException { } Block block = ModContent.blocksById().get(name).get(); - require(RenderTypeLookup.canRenderInLayer(block.defaultBlockState(), RenderType.cutoutMipped()), + require(ItemBlockRenderTypes.canRenderInLayer(block.defaultBlockState(), RenderType.cutoutMipped()), name + " is not cutout-mipped"); String overlay = "basemetals:block/ore_overlays/" + name; - IBakedModel blockModel = minecraft.getBlockRenderer().getBlockModel(block.defaultBlockState()); + BakedModel blockModel = minecraft.getBlockRenderer().getBlockModel(block.defaultBlockState()); validateOreModel(blockModel, block, name, host, overlay); ItemStack stack = new ItemStack(ModContent.item(name).get()); - IBakedModel itemModel = minecraft.getItemRenderer().getModel(stack, null, null); + BakedModel itemModel = minecraft.getItemRenderer().getModel(stack, null, null, 0); validateOreModel(itemModel, null, name + " item", host, overlay); } @@ -546,7 +562,7 @@ private static void validateOreModels(Minecraft minecraft) throws IOException { Integer.valueOf(ores)); } - private static void validateOreModel(IBakedModel model, Block block, String name, String host, String overlay) { + private static void validateOreModel(BakedModel model, Block block, String name, String host, String overlay) { require(host.equals(model.getParticleIcon().getName().toString()), name + " particle host"); Random random = new Random(42L); require(model.getQuads(block == null ? null : block.defaultBlockState(), null, random).isEmpty(), @@ -598,9 +614,9 @@ private static void validateOreVertices(BakedQuad quad, boolean overlay, String } private static void validateHostOverride(Minecraft minecraft, String host, String source) throws IOException { - try (IResource replacement = minecraft.getResourceManager().getResource( + try (Resource replacement = minecraft.getResourceManager().getResource( new ResourceLocation("minecraft", "textures/block/" + host + ".png")); - IResource fixture = minecraft.getResourceManager().getResource( + Resource fixture = minecraft.getResourceManager().getResource( new ResourceLocation("basemetals", "textures/block/" + source + "_ore.png"))) { BufferedImage actual = ImageIO.read(replacement.getInputStream()); BufferedImage expected = ImageIO.read(fixture.getInputStream()); @@ -616,16 +632,16 @@ private static void validateHostOverride(Minecraft minecraft, String host, Strin } private static void validateCreativeBuckets(Minecraft minecraft) { - net.minecraft.util.NonNullList entries = net.minecraft.util.NonNullList.create(); + net.minecraft.core.NonNullList entries = net.minecraft.core.NonNullList.create(); ModTabs.ITEMS.fillItemList(entries); List missingFromTab = new ArrayList<>(); List missingFromSearch = new ArrayList<>(); for (FluidContent fluid : ModContent.fluids().values()) { - net.minecraft.item.Item bucket = fluid.bucket().get(); + net.minecraft.world.item.Item bucket = fluid.bucket().get(); String id = bucket.getRegistryName().toString(); if (entries.stream().noneMatch(stack -> stack.getItem() == bucket)) missingFromTab.add(id); - if (minecraft.getSearchTree(net.minecraft.client.util.SearchTreeManager.CREATIVE_NAMES) + if (minecraft.getSearchTree(net.minecraft.client.searchtree.SearchRegistry.CREATIVE_NAMES) .search(id).stream().noneMatch(stack -> stack.getItem() == bucket)) { missingFromSearch.add(id); } @@ -638,25 +654,32 @@ private static void validateCreativeBuckets(Minecraft minecraft) { } private static void validateCreativeBucketScreen(Minecraft minecraft) { - net.minecraft.client.gui.screen.inventory.CreativeScreen screen = - new net.minecraft.client.gui.screen.inventory.CreativeScreen(minecraft.player); + net.minecraft.client.gui.screens.inventory.CreativeModeInventoryScreen screen = + new net.minecraft.client.gui.screens.inventory.CreativeModeInventoryScreen(minecraft.player); minecraft.setScreen(screen); try { - java.lang.reflect.Method selectTab = net.minecraftforge.fml.common.ObfuscationReflectionHelper.findMethod( - net.minecraft.client.gui.screen.inventory.CreativeScreen.class, - "func_147050_b", net.minecraft.item.ItemGroup.class); - java.lang.reflect.Method refreshSearch = net.minecraftforge.fml.common.ObfuscationReflectionHelper.findMethod( - net.minecraft.client.gui.screen.inventory.CreativeScreen.class, "func_147053_i"); - java.lang.reflect.Field searchField = net.minecraftforge.fml.common.ObfuscationReflectionHelper.findField( - net.minecraft.client.gui.screen.inventory.CreativeScreen.class, "field_147062_A"); + java.lang.reflect.Method selectTab = net.minecraftforge.fml.util.ObfuscationReflectionHelper.findMethod( + net.minecraft.client.gui.screens.inventory.CreativeModeInventoryScreen.class, + "m_98560_", net.minecraft.world.item.CreativeModeTab.class); + java.lang.reflect.Method refreshSearch = net.minecraftforge.fml.util.ObfuscationReflectionHelper.findMethod( + net.minecraft.client.gui.screens.inventory.CreativeModeInventoryScreen.class, "m_98630_"); + java.lang.reflect.Field searchField = net.minecraftforge.fml.util.ObfuscationReflectionHelper.findField( + net.minecraft.client.gui.screens.inventory.CreativeModeInventoryScreen.class, "f_98510_"); selectTab.invoke(screen, ModTabs.ITEMS); requireCreativeBuckets(screen.getMenu().items, "Base Metals Items screen"); - selectTab.invoke(screen, net.minecraft.item.ItemGroup.TAB_SEARCH); + for (String name : ModContent.itemsById().keySet()) { + if (!name.endsWith("_raw")) continue; + + require(screen.getMenu().items.stream().anyMatch(stack -> + stack.getItem() == ModContent.item(name).get()), + "Base Metals Items screen is missing " + name); + } + selectTab.invoke(screen, net.minecraft.world.item.CreativeModeTab.TAB_SEARCH); - net.minecraft.client.gui.widget.TextFieldWidget search = - (net.minecraft.client.gui.widget.TextFieldWidget) searchField.get(screen); + net.minecraft.client.gui.components.EditBox search = + (net.minecraft.client.gui.components.EditBox) searchField.get(screen); search.setValue("bucket"); refreshSearch.invoke(screen); requireCreativeBuckets(screen.getMenu().items, "creative search for bucket"); @@ -682,7 +705,7 @@ private static void validateCreativeBucketScreen(Minecraft minecraft) { private static void requireCreativeBuckets(List entries, String label) { for (FluidContent fluid : ModContent.fluids().values()) { - net.minecraft.item.Item bucket = fluid.bucket().get(); + net.minecraft.world.item.Item bucket = fluid.bucket().get(); require(entries.stream().anyMatch(stack -> stack.getItem() == bucket), label + " is missing " + bucket.getRegistryName()); } @@ -690,7 +713,7 @@ private static void requireCreativeBuckets(List entries, String label private static void validateBucketModel(Minecraft minecraft, String name) { ItemStack stack = new ItemStack(ModContent.item(name).get()); - IBakedModel model = minecraft.getItemRenderer().getModel(stack, null, null); + BakedModel model = minecraft.getItemRenderer().getModel(stack, null, null, 0); String fluidName = name.substring(0, name.length() - "_bucket".length()); FluidContent fluid = ModContent.fluids().get(fluidName); require(fluid != null, name + " has no matching fluid content"); @@ -700,7 +723,7 @@ private static void validateBucketModel(Minecraft minecraft, String name) { int vertexColour = (colour & 0xFF00FF00) | ((colour & 0xFF) << 16) | ((colour >>> 16) & 0xFF); Random random = new Random(42L); List quads = new ArrayList(model.getQuads(null, null, random)); - for (net.minecraft.util.Direction side : net.minecraft.util.Direction.values()) { + for (net.minecraft.core.Direction side : net.minecraft.core.Direction.values()) { quads.addAll(model.getQuads(null, side, random)); } require(!quads.isEmpty(), name + " has no rendered quads"); diff --git a/src/clientIntegrationTest/resources/META-INF/mods.toml b/src/clientIntegrationTest/resources/META-INF/mods.toml index 90051ec4a..5b306c5d1 100644 --- a/src/clientIntegrationTest/resources/META-INF/mods.toml +++ b/src/clientIntegrationTest/resources/META-INF/mods.toml @@ -1,30 +1,30 @@ modLoader="javafml" -loaderVersion="[36,)" +loaderVersion="[37,38)" license="LGPL-2.1" [[mods]] modId="basemetalsclientprobe" version="1" displayName="Base Metals Client Probe" -description='''Build-only packaged-client checks for Base Metals 1.16.5.''' +description='''Build-only packaged-client checks for Base Metals 1.17.1.''' [[dependencies.basemetalsclientprobe]] modId="basemetals" mandatory=true -versionRange="[3.1.0.116051]" +versionRange="[3.1.0.117011]" ordering="AFTER" side="CLIENT" [[dependencies.basemetalsclientprobe]] modId="orespawn" mandatory=true -versionRange="[4.1.0.116051,5.0.0)" +versionRange="[4.1.0.117011,5.0.0)" ordering="AFTER" side="CLIENT" [[dependencies.basemetalsclientprobe]] modId="minecraft" mandatory=true -versionRange="[1.16.5]" +versionRange="[1.17.1]" ordering="NONE" side="CLIENT" diff --git a/src/clientIntegrationTest/resources/pack.mcmeta b/src/clientIntegrationTest/resources/pack.mcmeta index 6d4fc2704..ea8ab032c 100644 --- a/src/clientIntegrationTest/resources/pack.mcmeta +++ b/src/clientIntegrationTest/resources/pack.mcmeta @@ -3,6 +3,6 @@ "description": "Base Metals packaged-client qualification fixture", "forge:resource_pack_format": 6, "forge:data_pack_format": 6, - "pack_format": 6 + "pack_format": 7 } } diff --git a/src/dataGenerator/java/zone/moddev/mc/basemetals/data/BMBlockStateProvider.java b/src/dataGenerator/java/zone/moddev/mc/basemetals/data/BMBlockStateProvider.java new file mode 100644 index 000000000..da24fe891 --- /dev/null +++ b/src/dataGenerator/java/zone/moddev/mc/basemetals/data/BMBlockStateProvider.java @@ -0,0 +1,80 @@ +package zone.moddev.mc.basemetals.data; + +import net.minecraft.data.DataGenerator; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; +import net.minecraftforge.client.model.generators.BlockModelBuilder; +import net.minecraftforge.client.model.generators.BlockStateProvider; +import net.minecraftforge.common.data.ExistingFileHelper; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.forge.event.lifecycle.GatherDataEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.registries.ForgeRegistries; +import zone.moddev.mc.basemetals.content.ModContent; +import zone.moddev.mc.basemetals.material.MaterialCatalogue; +import zone.moddev.mc.basemetals.material.MaterialDefinition; + +/** + * Builds ores from a vanilla host texture and a transparent ore overlay. + * + * @author KiriCattus (Kiri), original two-layer model + */ +@Mod.EventBusSubscriber(modid = "basemetals", bus = Mod.EventBusSubscriber.Bus.MOD) +public final class BMBlockStateProvider extends BlockStateProvider { + private static final float OVERLAY_OFFSET = 0.05F; + + public BMBlockStateProvider(DataGenerator generator, ExistingFileHelper existingFiles) { + super(generator, "basemetals", existingFiles); + } + + @SubscribeEvent + public static void gatherData(GatherDataEvent event) { + if (event.includeServer()) { + event.getGenerator().addProvider(new HarvestTagProvider(event.getGenerator(), event.getExistingFileHelper())); + } + if (event.includeClient()) { + event.getGenerator().addProvider(new BMBlockStateProvider( + event.getGenerator(), event.getExistingFileHelper())); + } + } + + @Override + protected void registerStatesAndModels() { + for (MaterialDefinition material : MaterialCatalogue.ALL) { + if (!material.hasOre()) continue; + + Block block = ModContent.blocksById().get(material.name() + "_ore").get(); + String host = "stone"; + if (material.name().equals("adamantine") || material.name().equals("coldiron")) { + host = "netherrack"; + } else if (material.name().equals("starsteel")) { + host = "end_stone"; + } + + createOverlayOre(block, mcLoc("block/" + host), + modLoc("block/ore_overlays/" + material.name() + "_ore")); + } + } + + private void createOverlayOre(Block block, ResourceLocation baseTexture, ResourceLocation overlayTexture) { + String blockName = ForgeRegistries.BLOCKS.getKey(block).getPath(); + + BlockModelBuilder builder = models().withExistingParent(blockName, mcLoc("block/block")) + .texture("particle", baseTexture) + .texture("base", baseTexture) + .texture("overlay", overlayTexture) + .element() + .from(0, 0, 0) + .to(16, 16, 16) + .allFaces((direction, face) -> face.texture("#base").cullface(direction)) + .end() + // Keep the overlay clear of the host, including distant mip levels. + .element() + .from(-OVERLAY_OFFSET, -OVERLAY_OFFSET, -OVERLAY_OFFSET) + .to(16 + OVERLAY_OFFSET, 16 + OVERLAY_OFFSET, 16 + OVERLAY_OFFSET) + .allFaces((direction, face) -> face.texture("#overlay").cullface(direction)) + .end(); + + simpleBlock(block, builder); + } +} diff --git a/src/dataGenerator/java/zone/moddev/mc/basemetals/data/HarvestTagProvider.java b/src/dataGenerator/java/zone/moddev/mc/basemetals/data/HarvestTagProvider.java new file mode 100644 index 000000000..3a67b623b --- /dev/null +++ b/src/dataGenerator/java/zone/moddev/mc/basemetals/data/HarvestTagProvider.java @@ -0,0 +1,36 @@ +package zone.moddev.mc.basemetals.data; + +import net.minecraft.data.DataGenerator; +import net.minecraft.data.tags.BlockTagsProvider; +import net.minecraft.tags.BlockTags; +import net.minecraft.world.level.block.Block; +import net.minecraftforge.common.data.ExistingFileHelper; +import zone.moddev.mc.basemetals.BaseMetals; +import zone.moddev.mc.basemetals.content.ModContent; + +/** Uses the material catalogue for 1.17's mining and tool-tier tags. */ +public final class HarvestTagProvider extends BlockTagsProvider { + public HarvestTagProvider(DataGenerator generator, ExistingFileHelper existingFiles) { + super(generator, BaseMetals.MOD_ID, existingFiles); + } + + @Override + protected void addTags() { + ModContent.blocksById().forEach((name, handle) -> { + if (ModContent.fluids().containsKey(name)) return; + + Block block = handle.get(); + String materialName = name.replaceFirst("^double_", "").split("_")[0]; + if ("wood".equals(materialName)) { + tag(BlockTags.MINEABLE_WITH_AXE).add(block); + return; + } + + tag(BlockTags.MINEABLE_WITH_PICKAXE).add(block); + int level = ModContent.requiredHarvestLevel(materialName); + if (level >= 3) tag(BlockTags.NEEDS_DIAMOND_TOOL).add(block); + else if (level == 2) tag(BlockTags.NEEDS_IRON_TOOL).add(block); + else if (level == 1) tag(BlockTags.NEEDS_STONE_TOOL).add(block); + }); + } +} diff --git a/src/generated/resources/assets/basemetals/lang/de_de.json b/src/generated/resources/assets/basemetals/lang/de_de.json index dca4a4b89..f1f8b2bf3 100644 --- a/src/generated/resources/assets/basemetals/lang/de_de.json +++ b/src/generated/resources/assets/basemetals/lang/de_de.json @@ -1883,5 +1883,17 @@ "item.bucket.obsidian": "Eimer mit geschmolzenem Obsidian", "item.bucket.quartz": "Eimer mit geschmolzenem Quarz", "item.bucket.wood": "Eimer mit verflüssigtem Holz", - "item.bucket.stone": "Eimer mit geschmolzenem Stein" + "item.bucket.stone": "Eimer mit geschmolzenem Stein", + "item.basemetals.adamantine_raw": "Adamant-Erzbrocken", + "item.basemetals.antimony_raw": "Antimon-Erzbrocken", + "item.basemetals.bismuth_raw": "Bismuth-Erzbrocken", + "item.basemetals.coldiron_raw": "Kalteisen-Erzbrocken", + "item.basemetals.lead_raw": "Blei-Erzbrocken", + "item.basemetals.mercury_raw": "Quecksilber-Erzbrocken", + "item.basemetals.nickel_raw": "Nickel-Erzbrocken", + "item.basemetals.platinum_raw": "Platin-Erzbrocken", + "item.basemetals.silver_raw": "Silber-Erzbrocken", + "item.basemetals.starsteel_raw": "Sternenstahl-Erzbrocken", + "item.basemetals.tin_raw": "Zinn-Erzbrocken", + "item.basemetals.zinc_raw": "Zink-Erzbrocken" } diff --git a/src/generated/resources/assets/basemetals/lang/en_au.json b/src/generated/resources/assets/basemetals/lang/en_au.json index af49d5962..abdfbde5f 100644 --- a/src/generated/resources/assets/basemetals/lang/en_au.json +++ b/src/generated/resources/assets/basemetals/lang/en_au.json @@ -1634,5 +1634,17 @@ "item.bucket.quartz": "Bucket of Molten Quartz", "item.bucket.wood": "Bucket of Liquefied Wood", "item.bucket.redstone": "Bucket of Molten Redstone", - "item.bucket.stone": "Bucket of Molten Stone" + "item.bucket.stone": "Bucket of Molten Stone", + "item.basemetals.adamantine_raw": "Raw undefined", + "item.basemetals.antimony_raw": "Raw undefined", + "item.basemetals.bismuth_raw": "Raw undefined", + "item.basemetals.coldiron_raw": "Raw undefined", + "item.basemetals.lead_raw": "Raw undefined", + "item.basemetals.mercury_raw": "Raw undefined", + "item.basemetals.nickel_raw": "Raw undefined", + "item.basemetals.platinum_raw": "Raw undefined", + "item.basemetals.silver_raw": "Raw undefined", + "item.basemetals.starsteel_raw": "Raw undefined", + "item.basemetals.tin_raw": "Raw undefined", + "item.basemetals.zinc_raw": "Raw undefined" } diff --git a/src/generated/resources/assets/basemetals/lang/en_ca.json b/src/generated/resources/assets/basemetals/lang/en_ca.json index 794ceab14..ac747d6b6 100644 --- a/src/generated/resources/assets/basemetals/lang/en_ca.json +++ b/src/generated/resources/assets/basemetals/lang/en_ca.json @@ -1634,5 +1634,17 @@ "item.bucket.quartz": "Bucket of Molten Quartz", "item.bucket.wood": "Bucket of Liquefied Wood", "item.bucket.redstone": "Bucket of Molten Redstone", - "item.bucket.stone": "Bucket of Molten Stone" + "item.bucket.stone": "Bucket of Molten Stone", + "item.basemetals.adamantine_raw": "Raw undefined", + "item.basemetals.antimony_raw": "Raw undefined", + "item.basemetals.bismuth_raw": "Raw undefined", + "item.basemetals.coldiron_raw": "Raw undefined", + "item.basemetals.lead_raw": "Raw undefined", + "item.basemetals.mercury_raw": "Raw undefined", + "item.basemetals.nickel_raw": "Raw undefined", + "item.basemetals.platinum_raw": "Raw undefined", + "item.basemetals.silver_raw": "Raw undefined", + "item.basemetals.starsteel_raw": "Raw undefined", + "item.basemetals.tin_raw": "Raw undefined", + "item.basemetals.zinc_raw": "Raw undefined" } diff --git a/src/generated/resources/assets/basemetals/lang/en_en.json b/src/generated/resources/assets/basemetals/lang/en_en.json index 3347bea14..0583798cc 100644 --- a/src/generated/resources/assets/basemetals/lang/en_en.json +++ b/src/generated/resources/assets/basemetals/lang/en_en.json @@ -1634,5 +1634,17 @@ "item.bucket.quartz": "Bucket of Molten Quartz", "item.bucket.wood": "Bucket of Liquefied Wood", "item.bucket.redstone": "Bucket of Molten Redstone", - "item.bucket.stone": "Bucket of Molten Stone" + "item.bucket.stone": "Bucket of Molten Stone", + "item.basemetals.adamantine_raw": "Raw undefined", + "item.basemetals.antimony_raw": "Raw undefined", + "item.basemetals.bismuth_raw": "Raw undefined", + "item.basemetals.coldiron_raw": "Raw undefined", + "item.basemetals.lead_raw": "Raw undefined", + "item.basemetals.mercury_raw": "Raw undefined", + "item.basemetals.nickel_raw": "Raw undefined", + "item.basemetals.platinum_raw": "Raw undefined", + "item.basemetals.silver_raw": "Raw undefined", + "item.basemetals.starsteel_raw": "Raw undefined", + "item.basemetals.tin_raw": "Raw undefined", + "item.basemetals.zinc_raw": "Raw undefined" } diff --git a/src/generated/resources/assets/basemetals/lang/en_gb.json b/src/generated/resources/assets/basemetals/lang/en_gb.json index 41cc37c81..d044b6e9d 100644 --- a/src/generated/resources/assets/basemetals/lang/en_gb.json +++ b/src/generated/resources/assets/basemetals/lang/en_gb.json @@ -1634,5 +1634,17 @@ "item.bucket.quartz": "Bucket of Molten Quartz", "item.bucket.wood": "Bucket of Liquefied Wood", "item.bucket.redstone": "Bucket of Molten Redstone", - "item.bucket.stone": "Bucket of Molten Stone" + "item.bucket.stone": "Bucket of Molten Stone", + "item.basemetals.adamantine_raw": "Raw undefined", + "item.basemetals.antimony_raw": "Raw undefined", + "item.basemetals.bismuth_raw": "Raw undefined", + "item.basemetals.coldiron_raw": "Raw undefined", + "item.basemetals.lead_raw": "Raw undefined", + "item.basemetals.mercury_raw": "Raw undefined", + "item.basemetals.nickel_raw": "Raw undefined", + "item.basemetals.platinum_raw": "Raw undefined", + "item.basemetals.silver_raw": "Raw undefined", + "item.basemetals.starsteel_raw": "Raw undefined", + "item.basemetals.tin_raw": "Raw undefined", + "item.basemetals.zinc_raw": "Raw undefined" } diff --git a/src/generated/resources/assets/basemetals/lang/en_pt.json b/src/generated/resources/assets/basemetals/lang/en_pt.json index 6d73b40d3..a3a2ba5f9 100644 --- a/src/generated/resources/assets/basemetals/lang/en_pt.json +++ b/src/generated/resources/assets/basemetals/lang/en_pt.json @@ -1625,5 +1625,17 @@ "item.bucket.quartz": "Bucket of Molten Quartz", "item.bucket.wood": "Bucket of Liquefied Wood", "item.bucket.redstone": "Bucket of Molten Redstone", - "item.bucket.stone": "Bucket of Molten Stone" + "item.bucket.stone": "Bucket of Molten Stone", + "item.basemetals.adamantine_raw": "Raw undefined", + "item.basemetals.antimony_raw": "Raw undefined", + "item.basemetals.bismuth_raw": "Raw undefined", + "item.basemetals.coldiron_raw": "Raw undefined", + "item.basemetals.lead_raw": "Raw undefined", + "item.basemetals.mercury_raw": "Raw undefined", + "item.basemetals.nickel_raw": "Raw undefined", + "item.basemetals.platinum_raw": "Raw undefined", + "item.basemetals.silver_raw": "Raw undefined", + "item.basemetals.starsteel_raw": "Raw undefined", + "item.basemetals.tin_raw": "Raw undefined", + "item.basemetals.zinc_raw": "Raw undefined" } diff --git a/src/generated/resources/assets/basemetals/lang/en_us.json b/src/generated/resources/assets/basemetals/lang/en_us.json index a0dd78a26..d1db30d01 100644 --- a/src/generated/resources/assets/basemetals/lang/en_us.json +++ b/src/generated/resources/assets/basemetals/lang/en_us.json @@ -1897,5 +1897,17 @@ "item.bucket.obsidian": "Bucket of Molten Obsidian", "item.bucket.quartz": "Bucket of Molten Quartz", "item.bucket.wood": "Bucket of Liquefied Wood", - "item.bucket.stone": "Bucket of Molten Stone" + "item.bucket.stone": "Bucket of Molten Stone", + "item.basemetals.adamantine_raw": "Raw Adamantine", + "item.basemetals.antimony_raw": "Raw Antimony", + "item.basemetals.bismuth_raw": "Raw Bismuth", + "item.basemetals.coldiron_raw": "Raw Cold-Iron", + "item.basemetals.lead_raw": "Raw Lead", + "item.basemetals.mercury_raw": "Raw Mercury", + "item.basemetals.nickel_raw": "Raw Nickel", + "item.basemetals.platinum_raw": "Raw Platinum", + "item.basemetals.silver_raw": "Raw Silver", + "item.basemetals.starsteel_raw": "Raw Star-Steel", + "item.basemetals.tin_raw": "Raw Tin", + "item.basemetals.zinc_raw": "Raw Zinc" } diff --git a/src/generated/resources/assets/basemetals/lang/es_es.json b/src/generated/resources/assets/basemetals/lang/es_es.json index 7c44e6d78..475534892 100644 --- a/src/generated/resources/assets/basemetals/lang/es_es.json +++ b/src/generated/resources/assets/basemetals/lang/es_es.json @@ -1626,5 +1626,17 @@ "item.bucket.quartz": "Cubo de cuarzo fundido", "item.bucket.wood": "Cubo de madera licuada", "item.bucket.redstone": "Cubo de redstone fundida", - "item.bucket.stone": "Cubo de piedra fundida" + "item.bucket.stone": "Cubo de piedra fundida", + "item.basemetals.adamantine_raw": "undefined en bruto", + "item.basemetals.antimony_raw": "undefined en bruto", + "item.basemetals.bismuth_raw": "undefined en bruto", + "item.basemetals.coldiron_raw": "undefined en bruto", + "item.basemetals.lead_raw": "undefined en bruto", + "item.basemetals.mercury_raw": "undefined en bruto", + "item.basemetals.nickel_raw": "undefined en bruto", + "item.basemetals.platinum_raw": "undefined en bruto", + "item.basemetals.silver_raw": "undefined en bruto", + "item.basemetals.starsteel_raw": "undefined en bruto", + "item.basemetals.tin_raw": "undefined en bruto", + "item.basemetals.zinc_raw": "undefined en bruto" } diff --git a/src/generated/resources/assets/basemetals/lang/es_mx.json b/src/generated/resources/assets/basemetals/lang/es_mx.json index 7c44e6d78..475534892 100644 --- a/src/generated/resources/assets/basemetals/lang/es_mx.json +++ b/src/generated/resources/assets/basemetals/lang/es_mx.json @@ -1626,5 +1626,17 @@ "item.bucket.quartz": "Cubo de cuarzo fundido", "item.bucket.wood": "Cubo de madera licuada", "item.bucket.redstone": "Cubo de redstone fundida", - "item.bucket.stone": "Cubo de piedra fundida" + "item.bucket.stone": "Cubo de piedra fundida", + "item.basemetals.adamantine_raw": "undefined en bruto", + "item.basemetals.antimony_raw": "undefined en bruto", + "item.basemetals.bismuth_raw": "undefined en bruto", + "item.basemetals.coldiron_raw": "undefined en bruto", + "item.basemetals.lead_raw": "undefined en bruto", + "item.basemetals.mercury_raw": "undefined en bruto", + "item.basemetals.nickel_raw": "undefined en bruto", + "item.basemetals.platinum_raw": "undefined en bruto", + "item.basemetals.silver_raw": "undefined en bruto", + "item.basemetals.starsteel_raw": "undefined en bruto", + "item.basemetals.tin_raw": "undefined en bruto", + "item.basemetals.zinc_raw": "undefined en bruto" } diff --git a/src/generated/resources/assets/basemetals/lang/fr_ca.json b/src/generated/resources/assets/basemetals/lang/fr_ca.json index 74f86dd97..bbd1ae96a 100644 --- a/src/generated/resources/assets/basemetals/lang/fr_ca.json +++ b/src/generated/resources/assets/basemetals/lang/fr_ca.json @@ -1625,5 +1625,17 @@ "item.bucket.quartz": "Seau de quartz fondu", "item.bucket.wood": "Seau de bois liquéfié", "item.bucket.redstone": "Seau de redstone fondue", - "item.bucket.stone": "Seau de pierre fondue" + "item.bucket.stone": "Seau de pierre fondue", + "item.basemetals.adamantine_raw": "undefined brut", + "item.basemetals.antimony_raw": "undefined brut", + "item.basemetals.bismuth_raw": "undefined brut", + "item.basemetals.coldiron_raw": "undefined brut", + "item.basemetals.lead_raw": "undefined brut", + "item.basemetals.mercury_raw": "undefined brut", + "item.basemetals.nickel_raw": "undefined brut", + "item.basemetals.platinum_raw": "undefined brut", + "item.basemetals.silver_raw": "undefined brut", + "item.basemetals.starsteel_raw": "undefined brut", + "item.basemetals.tin_raw": "undefined brut", + "item.basemetals.zinc_raw": "undefined brut" } diff --git a/src/generated/resources/assets/basemetals/lang/fr_fr.json b/src/generated/resources/assets/basemetals/lang/fr_fr.json index f24f94c7e..6507f458d 100644 --- a/src/generated/resources/assets/basemetals/lang/fr_fr.json +++ b/src/generated/resources/assets/basemetals/lang/fr_fr.json @@ -1625,5 +1625,17 @@ "item.bucket.quartz": "Seau de quartz fondu", "item.bucket.wood": "Seau de bois liquéfié", "item.bucket.redstone": "Seau de redstone fondue", - "item.bucket.stone": "Seau de pierre fondue" + "item.bucket.stone": "Seau de pierre fondue", + "item.basemetals.adamantine_raw": "undefined brut", + "item.basemetals.antimony_raw": "undefined brut", + "item.basemetals.bismuth_raw": "undefined brut", + "item.basemetals.coldiron_raw": "undefined brut", + "item.basemetals.lead_raw": "undefined brut", + "item.basemetals.mercury_raw": "undefined brut", + "item.basemetals.nickel_raw": "undefined brut", + "item.basemetals.platinum_raw": "undefined brut", + "item.basemetals.silver_raw": "undefined brut", + "item.basemetals.starsteel_raw": "undefined brut", + "item.basemetals.tin_raw": "undefined brut", + "item.basemetals.zinc_raw": "undefined brut" } diff --git a/src/generated/resources/assets/basemetals/lang/it_it.json b/src/generated/resources/assets/basemetals/lang/it_it.json index 8d9a435ae..9c0097589 100644 --- a/src/generated/resources/assets/basemetals/lang/it_it.json +++ b/src/generated/resources/assets/basemetals/lang/it_it.json @@ -1644,5 +1644,17 @@ "item.bucket.quartz": "Secchio di quarzo fuso", "item.bucket.wood": "Secchio di legno liquefatto", "item.bucket.redstone": "Secchio di redstone fusa", - "item.bucket.stone": "Secchio di pietra fusa" + "item.bucket.stone": "Secchio di pietra fusa", + "item.basemetals.adamantine_raw": "undefined grezzo", + "item.basemetals.antimony_raw": "undefined grezzo", + "item.basemetals.bismuth_raw": "undefined grezzo", + "item.basemetals.coldiron_raw": "undefined grezzo", + "item.basemetals.lead_raw": "undefined grezzo", + "item.basemetals.mercury_raw": "undefined grezzo", + "item.basemetals.nickel_raw": "undefined grezzo", + "item.basemetals.platinum_raw": "undefined grezzo", + "item.basemetals.silver_raw": "undefined grezzo", + "item.basemetals.starsteel_raw": "undefined grezzo", + "item.basemetals.tin_raw": "undefined grezzo", + "item.basemetals.zinc_raw": "undefined grezzo" } diff --git a/src/generated/resources/assets/basemetals/lang/ja_jp.json b/src/generated/resources/assets/basemetals/lang/ja_jp.json index 921d04842..84013ed18 100644 --- a/src/generated/resources/assets/basemetals/lang/ja_jp.json +++ b/src/generated/resources/assets/basemetals/lang/ja_jp.json @@ -1906,5 +1906,17 @@ "item.bucket.obsidian": "溶融黒曜石入りバケツ", "item.bucket.quartz": "溶融石英入りバケツ", "item.bucket.wood": "液化木材入りバケツ", - "item.bucket.stone": "溶融石入りバケツ" + "item.bucket.stone": "溶融石入りバケツ", + "item.basemetals.adamantine_raw": "アダマントの原石", + "item.basemetals.antimony_raw": "アンチモンの原石", + "item.basemetals.bismuth_raw": "ビスマスの原石", + "item.basemetals.coldiron_raw": "コールドアイアンの原石", + "item.basemetals.lead_raw": "鉛の原石", + "item.basemetals.mercury_raw": "水銀の原石", + "item.basemetals.nickel_raw": "ニッケルの原石", + "item.basemetals.platinum_raw": "プラチナの原石", + "item.basemetals.silver_raw": "銀の原石", + "item.basemetals.starsteel_raw": "スタースチールの原石", + "item.basemetals.tin_raw": "錫の原石", + "item.basemetals.zinc_raw": "亜鉛の原石" } diff --git a/src/generated/resources/assets/basemetals/lang/nl_nl.json b/src/generated/resources/assets/basemetals/lang/nl_nl.json index a108a1fe3..e7df4cd2b 100644 --- a/src/generated/resources/assets/basemetals/lang/nl_nl.json +++ b/src/generated/resources/assets/basemetals/lang/nl_nl.json @@ -1625,5 +1625,17 @@ "item.bucket.quartz": "Emmer gesmolten kwarts", "item.bucket.wood": "Emmer vloeibaar hout", "item.bucket.redstone": "Emmer gesmolten redstone", - "item.bucket.stone": "Emmer gesmolten steen" + "item.bucket.stone": "Emmer gesmolten steen", + "item.basemetals.adamantine_raw": "Ruw undefined", + "item.basemetals.antimony_raw": "Ruw undefined", + "item.basemetals.bismuth_raw": "Ruw undefined", + "item.basemetals.coldiron_raw": "Ruw undefined", + "item.basemetals.lead_raw": "Ruw undefined", + "item.basemetals.mercury_raw": "Ruw undefined", + "item.basemetals.nickel_raw": "Ruw undefined", + "item.basemetals.platinum_raw": "Ruw undefined", + "item.basemetals.silver_raw": "Ruw undefined", + "item.basemetals.starsteel_raw": "Ruw undefined", + "item.basemetals.tin_raw": "Ruw undefined", + "item.basemetals.zinc_raw": "Ruw undefined" } diff --git a/src/generated/resources/assets/basemetals/lang/pt_br.json b/src/generated/resources/assets/basemetals/lang/pt_br.json index 89f3435d5..14b2bbc29 100644 --- a/src/generated/resources/assets/basemetals/lang/pt_br.json +++ b/src/generated/resources/assets/basemetals/lang/pt_br.json @@ -1626,5 +1626,17 @@ "item.bucket.quartz": "Balde de quartzo fundido", "item.bucket.wood": "Balde de madeira liquefeita", "item.bucket.redstone": "Balde de redstone fundida", - "item.bucket.stone": "Balde de pedra fundida" + "item.bucket.stone": "Balde de pedra fundida", + "item.basemetals.adamantine_raw": "undefined bruto", + "item.basemetals.antimony_raw": "undefined bruto", + "item.basemetals.bismuth_raw": "undefined bruto", + "item.basemetals.coldiron_raw": "undefined bruto", + "item.basemetals.lead_raw": "undefined bruto", + "item.basemetals.mercury_raw": "undefined bruto", + "item.basemetals.nickel_raw": "undefined bruto", + "item.basemetals.platinum_raw": "undefined bruto", + "item.basemetals.silver_raw": "undefined bruto", + "item.basemetals.starsteel_raw": "undefined bruto", + "item.basemetals.tin_raw": "undefined bruto", + "item.basemetals.zinc_raw": "undefined bruto" } diff --git a/src/generated/resources/assets/basemetals/lang/ru_ru.json b/src/generated/resources/assets/basemetals/lang/ru_ru.json index cd8744ca1..fc6a629c2 100644 --- a/src/generated/resources/assets/basemetals/lang/ru_ru.json +++ b/src/generated/resources/assets/basemetals/lang/ru_ru.json @@ -1879,5 +1879,17 @@ "item.bucket.lapis": "Ведро расплавленного лазурита", "item.bucket.quartz": "Ведро расплавленного кварца", "item.bucket.wood": "Ведро жидкой древесины", - "item.bucket.stone": "Ведро расплавленного камня" + "item.bucket.stone": "Ведро расплавленного камня", + "item.basemetals.adamantine_raw": "Рудное сырьё: Адамантин", + "item.basemetals.antimony_raw": "Рудное сырьё: Сурьма", + "item.basemetals.bismuth_raw": "Рудное сырьё: Висмут", + "item.basemetals.coldiron_raw": "Рудное сырьё: Хладо-железо", + "item.basemetals.lead_raw": "Рудное сырьё: Свинец", + "item.basemetals.mercury_raw": "Рудное сырьё: Ртуть", + "item.basemetals.nickel_raw": "Рудное сырьё: Никель", + "item.basemetals.platinum_raw": "Рудное сырьё: Платина", + "item.basemetals.silver_raw": "Рудное сырьё: Серебро", + "item.basemetals.starsteel_raw": "Рудное сырьё: Звёздная сталь", + "item.basemetals.tin_raw": "Рудное сырьё: Олово", + "item.basemetals.zinc_raw": "Рудное сырьё: Цинк" } diff --git a/src/generated/resources/assets/basemetals/lang/zh_cn.json b/src/generated/resources/assets/basemetals/lang/zh_cn.json index 69797d729..188dacbca 100644 --- a/src/generated/resources/assets/basemetals/lang/zh_cn.json +++ b/src/generated/resources/assets/basemetals/lang/zh_cn.json @@ -1850,5 +1850,17 @@ "item.bucket.obsidian": "熔融黑曜石桶", "item.bucket.quartz": "熔融石英桶", "item.bucket.wood": "液化木材桶", - "item.bucket.stone": "熔融石头桶" + "item.bucket.stone": "熔融石头桶", + "item.basemetals.adamantine_raw": "粗艾德曼金属", + "item.basemetals.antimony_raw": "粗锑", + "item.basemetals.bismuth_raw": "粗铋", + "item.basemetals.coldiron_raw": "粗寒铁", + "item.basemetals.lead_raw": "粗铅", + "item.basemetals.mercury_raw": "粗汞", + "item.basemetals.nickel_raw": "粗镍", + "item.basemetals.platinum_raw": "粗铂", + "item.basemetals.silver_raw": "粗银", + "item.basemetals.starsteel_raw": "粗星钢", + "item.basemetals.tin_raw": "粗锡", + "item.basemetals.zinc_raw": "粗锌" } diff --git a/src/generated/resources/assets/basemetals/lang/zh_tw.json b/src/generated/resources/assets/basemetals/lang/zh_tw.json index be6357d64..e8128404e 100644 --- a/src/generated/resources/assets/basemetals/lang/zh_tw.json +++ b/src/generated/resources/assets/basemetals/lang/zh_tw.json @@ -1884,5 +1884,17 @@ "item.bucket.obsidian": "熔融黑曜石桶", "item.bucket.quartz": "熔融石英桶", "item.bucket.wood": "液化木材桶", - "item.bucket.stone": "熔融石頭桶" + "item.bucket.stone": "熔融石頭桶", + "item.basemetals.adamantine_raw": "粗精金", + "item.basemetals.antimony_raw": "粗銻", + "item.basemetals.bismuth_raw": "粗鉍", + "item.basemetals.coldiron_raw": "粗寒鐵", + "item.basemetals.lead_raw": "粗鉛", + "item.basemetals.mercury_raw": "粗汞", + "item.basemetals.nickel_raw": "粗鎳", + "item.basemetals.platinum_raw": "粗白金", + "item.basemetals.silver_raw": "粗銀", + "item.basemetals.starsteel_raw": "粗星鋼", + "item.basemetals.tin_raw": "粗錫", + "item.basemetals.zinc_raw": "粗鋅" } diff --git a/src/main/resources/assets/basemetals/models/block/adamantine_ore.json b/src/generated/resources/assets/basemetals/models/block/adamantine_ore.json similarity index 95% rename from src/main/resources/assets/basemetals/models/block/adamantine_ore.json rename to src/generated/resources/assets/basemetals/models/block/adamantine_ore.json index 6caa5e15b..f2634d0d0 100644 --- a/src/main/resources/assets/basemetals/models/block/adamantine_ore.json +++ b/src/generated/resources/assets/basemetals/models/block/adamantine_ore.json @@ -8,14 +8,14 @@ "elements": [ { "from": [ - 0.0, - 0.0, - 0.0 + 0, + 0, + 0 ], "to": [ - 16.0, - 16.0, - 16.0 + 16, + 16, + 16 ], "faces": { "down": { @@ -83,4 +83,4 @@ } } ] -} +} \ No newline at end of file diff --git a/src/main/resources/assets/basemetals/models/block/antimony_ore.json b/src/generated/resources/assets/basemetals/models/block/antimony_ore.json similarity index 95% rename from src/main/resources/assets/basemetals/models/block/antimony_ore.json rename to src/generated/resources/assets/basemetals/models/block/antimony_ore.json index 8a35d178a..6f0aba4e0 100644 --- a/src/main/resources/assets/basemetals/models/block/antimony_ore.json +++ b/src/generated/resources/assets/basemetals/models/block/antimony_ore.json @@ -8,14 +8,14 @@ "elements": [ { "from": [ - 0.0, - 0.0, - 0.0 + 0, + 0, + 0 ], "to": [ - 16.0, - 16.0, - 16.0 + 16, + 16, + 16 ], "faces": { "down": { @@ -83,4 +83,4 @@ } } ] -} +} \ No newline at end of file diff --git a/src/main/resources/assets/basemetals/models/block/bismuth_ore.json b/src/generated/resources/assets/basemetals/models/block/bismuth_ore.json similarity index 95% rename from src/main/resources/assets/basemetals/models/block/bismuth_ore.json rename to src/generated/resources/assets/basemetals/models/block/bismuth_ore.json index bcd87159d..2bcc1ca12 100644 --- a/src/main/resources/assets/basemetals/models/block/bismuth_ore.json +++ b/src/generated/resources/assets/basemetals/models/block/bismuth_ore.json @@ -8,14 +8,14 @@ "elements": [ { "from": [ - 0.0, - 0.0, - 0.0 + 0, + 0, + 0 ], "to": [ - 16.0, - 16.0, - 16.0 + 16, + 16, + 16 ], "faces": { "down": { @@ -83,4 +83,4 @@ } } ] -} +} \ No newline at end of file diff --git a/src/main/resources/assets/basemetals/models/block/coldiron_ore.json b/src/generated/resources/assets/basemetals/models/block/coldiron_ore.json similarity index 95% rename from src/main/resources/assets/basemetals/models/block/coldiron_ore.json rename to src/generated/resources/assets/basemetals/models/block/coldiron_ore.json index 1a7562de6..76b8da88d 100644 --- a/src/main/resources/assets/basemetals/models/block/coldiron_ore.json +++ b/src/generated/resources/assets/basemetals/models/block/coldiron_ore.json @@ -8,14 +8,14 @@ "elements": [ { "from": [ - 0.0, - 0.0, - 0.0 + 0, + 0, + 0 ], "to": [ - 16.0, - 16.0, - 16.0 + 16, + 16, + 16 ], "faces": { "down": { @@ -83,4 +83,4 @@ } } ] -} +} \ No newline at end of file diff --git a/src/main/resources/assets/basemetals/models/block/copper_ore.json b/src/generated/resources/assets/basemetals/models/block/copper_ore.json similarity index 95% rename from src/main/resources/assets/basemetals/models/block/copper_ore.json rename to src/generated/resources/assets/basemetals/models/block/copper_ore.json index 2c201c3f7..9b127953d 100644 --- a/src/main/resources/assets/basemetals/models/block/copper_ore.json +++ b/src/generated/resources/assets/basemetals/models/block/copper_ore.json @@ -8,14 +8,14 @@ "elements": [ { "from": [ - 0.0, - 0.0, - 0.0 + 0, + 0, + 0 ], "to": [ - 16.0, - 16.0, - 16.0 + 16, + 16, + 16 ], "faces": { "down": { @@ -83,4 +83,4 @@ } } ] -} +} \ No newline at end of file diff --git a/src/main/resources/assets/basemetals/models/block/lead_ore.json b/src/generated/resources/assets/basemetals/models/block/lead_ore.json similarity index 95% rename from src/main/resources/assets/basemetals/models/block/lead_ore.json rename to src/generated/resources/assets/basemetals/models/block/lead_ore.json index 574552c95..5019a74b3 100644 --- a/src/main/resources/assets/basemetals/models/block/lead_ore.json +++ b/src/generated/resources/assets/basemetals/models/block/lead_ore.json @@ -8,14 +8,14 @@ "elements": [ { "from": [ - 0.0, - 0.0, - 0.0 + 0, + 0, + 0 ], "to": [ - 16.0, - 16.0, - 16.0 + 16, + 16, + 16 ], "faces": { "down": { @@ -83,4 +83,4 @@ } } ] -} +} \ No newline at end of file diff --git a/src/main/resources/assets/basemetals/models/block/mercury_ore.json b/src/generated/resources/assets/basemetals/models/block/mercury_ore.json similarity index 95% rename from src/main/resources/assets/basemetals/models/block/mercury_ore.json rename to src/generated/resources/assets/basemetals/models/block/mercury_ore.json index f12342e4b..2335dcbc3 100644 --- a/src/main/resources/assets/basemetals/models/block/mercury_ore.json +++ b/src/generated/resources/assets/basemetals/models/block/mercury_ore.json @@ -8,14 +8,14 @@ "elements": [ { "from": [ - 0.0, - 0.0, - 0.0 + 0, + 0, + 0 ], "to": [ - 16.0, - 16.0, - 16.0 + 16, + 16, + 16 ], "faces": { "down": { @@ -83,4 +83,4 @@ } } ] -} +} \ No newline at end of file diff --git a/src/main/resources/assets/basemetals/models/block/nickel_ore.json b/src/generated/resources/assets/basemetals/models/block/nickel_ore.json similarity index 95% rename from src/main/resources/assets/basemetals/models/block/nickel_ore.json rename to src/generated/resources/assets/basemetals/models/block/nickel_ore.json index 329957820..d198d4de0 100644 --- a/src/main/resources/assets/basemetals/models/block/nickel_ore.json +++ b/src/generated/resources/assets/basemetals/models/block/nickel_ore.json @@ -8,14 +8,14 @@ "elements": [ { "from": [ - 0.0, - 0.0, - 0.0 + 0, + 0, + 0 ], "to": [ - 16.0, - 16.0, - 16.0 + 16, + 16, + 16 ], "faces": { "down": { @@ -83,4 +83,4 @@ } } ] -} +} \ No newline at end of file diff --git a/src/main/resources/assets/basemetals/models/block/platinum_ore.json b/src/generated/resources/assets/basemetals/models/block/platinum_ore.json similarity index 95% rename from src/main/resources/assets/basemetals/models/block/platinum_ore.json rename to src/generated/resources/assets/basemetals/models/block/platinum_ore.json index 6969c40ce..59b8ee301 100644 --- a/src/main/resources/assets/basemetals/models/block/platinum_ore.json +++ b/src/generated/resources/assets/basemetals/models/block/platinum_ore.json @@ -8,14 +8,14 @@ "elements": [ { "from": [ - 0.0, - 0.0, - 0.0 + 0, + 0, + 0 ], "to": [ - 16.0, - 16.0, - 16.0 + 16, + 16, + 16 ], "faces": { "down": { @@ -83,4 +83,4 @@ } } ] -} +} \ No newline at end of file diff --git a/src/main/resources/assets/basemetals/models/block/silver_ore.json b/src/generated/resources/assets/basemetals/models/block/silver_ore.json similarity index 95% rename from src/main/resources/assets/basemetals/models/block/silver_ore.json rename to src/generated/resources/assets/basemetals/models/block/silver_ore.json index 945fae127..8b82f5172 100644 --- a/src/main/resources/assets/basemetals/models/block/silver_ore.json +++ b/src/generated/resources/assets/basemetals/models/block/silver_ore.json @@ -8,14 +8,14 @@ "elements": [ { "from": [ - 0.0, - 0.0, - 0.0 + 0, + 0, + 0 ], "to": [ - 16.0, - 16.0, - 16.0 + 16, + 16, + 16 ], "faces": { "down": { @@ -83,4 +83,4 @@ } } ] -} +} \ No newline at end of file diff --git a/src/main/resources/assets/basemetals/models/block/starsteel_ore.json b/src/generated/resources/assets/basemetals/models/block/starsteel_ore.json similarity index 95% rename from src/main/resources/assets/basemetals/models/block/starsteel_ore.json rename to src/generated/resources/assets/basemetals/models/block/starsteel_ore.json index fc085da09..d5b938cbd 100644 --- a/src/main/resources/assets/basemetals/models/block/starsteel_ore.json +++ b/src/generated/resources/assets/basemetals/models/block/starsteel_ore.json @@ -8,14 +8,14 @@ "elements": [ { "from": [ - 0.0, - 0.0, - 0.0 + 0, + 0, + 0 ], "to": [ - 16.0, - 16.0, - 16.0 + 16, + 16, + 16 ], "faces": { "down": { @@ -83,4 +83,4 @@ } } ] -} +} \ No newline at end of file diff --git a/src/main/resources/assets/basemetals/models/block/tin_ore.json b/src/generated/resources/assets/basemetals/models/block/tin_ore.json similarity index 95% rename from src/main/resources/assets/basemetals/models/block/tin_ore.json rename to src/generated/resources/assets/basemetals/models/block/tin_ore.json index b70c25d5a..d7156d8c5 100644 --- a/src/main/resources/assets/basemetals/models/block/tin_ore.json +++ b/src/generated/resources/assets/basemetals/models/block/tin_ore.json @@ -8,14 +8,14 @@ "elements": [ { "from": [ - 0.0, - 0.0, - 0.0 + 0, + 0, + 0 ], "to": [ - 16.0, - 16.0, - 16.0 + 16, + 16, + 16 ], "faces": { "down": { @@ -83,4 +83,4 @@ } } ] -} +} \ No newline at end of file diff --git a/src/main/resources/assets/basemetals/models/block/zinc_ore.json b/src/generated/resources/assets/basemetals/models/block/zinc_ore.json similarity index 95% rename from src/main/resources/assets/basemetals/models/block/zinc_ore.json rename to src/generated/resources/assets/basemetals/models/block/zinc_ore.json index 9c164a374..9e9debb63 100644 --- a/src/main/resources/assets/basemetals/models/block/zinc_ore.json +++ b/src/generated/resources/assets/basemetals/models/block/zinc_ore.json @@ -8,14 +8,14 @@ "elements": [ { "from": [ - 0.0, - 0.0, - 0.0 + 0, + 0, + 0 ], "to": [ - 16.0, - 16.0, - 16.0 + 16, + 16, + 16 ], "faces": { "down": { @@ -83,4 +83,4 @@ } } ] -} +} \ No newline at end of file diff --git a/src/generated/resources/assets/basemetals/models/item/adamantine_raw.json b/src/generated/resources/assets/basemetals/models/item/adamantine_raw.json new file mode 100644 index 000000000..6443934ee --- /dev/null +++ b/src/generated/resources/assets/basemetals/models/item/adamantine_raw.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "basemetals:item/adamantine_raw" + } +} diff --git a/src/generated/resources/assets/basemetals/models/item/antimony_raw.json b/src/generated/resources/assets/basemetals/models/item/antimony_raw.json new file mode 100644 index 000000000..812e50780 --- /dev/null +++ b/src/generated/resources/assets/basemetals/models/item/antimony_raw.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "basemetals:item/antimony_raw" + } +} diff --git a/src/generated/resources/assets/basemetals/models/item/bismuth_raw.json b/src/generated/resources/assets/basemetals/models/item/bismuth_raw.json new file mode 100644 index 000000000..4f34b966c --- /dev/null +++ b/src/generated/resources/assets/basemetals/models/item/bismuth_raw.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "basemetals:item/bismuth_raw" + } +} diff --git a/src/generated/resources/assets/basemetals/models/item/coldiron_raw.json b/src/generated/resources/assets/basemetals/models/item/coldiron_raw.json new file mode 100644 index 000000000..bf6ba2a47 --- /dev/null +++ b/src/generated/resources/assets/basemetals/models/item/coldiron_raw.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "basemetals:item/coldiron_raw" + } +} diff --git a/src/generated/resources/assets/basemetals/models/item/lead_raw.json b/src/generated/resources/assets/basemetals/models/item/lead_raw.json new file mode 100644 index 000000000..5a9758c78 --- /dev/null +++ b/src/generated/resources/assets/basemetals/models/item/lead_raw.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "basemetals:item/lead_raw" + } +} diff --git a/src/generated/resources/assets/basemetals/models/item/mercury_raw.json b/src/generated/resources/assets/basemetals/models/item/mercury_raw.json new file mode 100644 index 000000000..ff31c4641 --- /dev/null +++ b/src/generated/resources/assets/basemetals/models/item/mercury_raw.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "basemetals:item/mercury_raw" + } +} diff --git a/src/generated/resources/assets/basemetals/models/item/nickel_raw.json b/src/generated/resources/assets/basemetals/models/item/nickel_raw.json new file mode 100644 index 000000000..9fc5e9431 --- /dev/null +++ b/src/generated/resources/assets/basemetals/models/item/nickel_raw.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "basemetals:item/nickel_raw" + } +} diff --git a/src/generated/resources/assets/basemetals/models/item/platinum_raw.json b/src/generated/resources/assets/basemetals/models/item/platinum_raw.json new file mode 100644 index 000000000..0dd6565f8 --- /dev/null +++ b/src/generated/resources/assets/basemetals/models/item/platinum_raw.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "basemetals:item/platinum_raw" + } +} diff --git a/src/generated/resources/assets/basemetals/models/item/silver_raw.json b/src/generated/resources/assets/basemetals/models/item/silver_raw.json new file mode 100644 index 000000000..39b146fb2 --- /dev/null +++ b/src/generated/resources/assets/basemetals/models/item/silver_raw.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "basemetals:item/silver_raw" + } +} diff --git a/src/generated/resources/assets/basemetals/models/item/starsteel_raw.json b/src/generated/resources/assets/basemetals/models/item/starsteel_raw.json new file mode 100644 index 000000000..6deb8b859 --- /dev/null +++ b/src/generated/resources/assets/basemetals/models/item/starsteel_raw.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "basemetals:item/starsteel_raw" + } +} diff --git a/src/generated/resources/assets/basemetals/models/item/tin_raw.json b/src/generated/resources/assets/basemetals/models/item/tin_raw.json new file mode 100644 index 000000000..4b0055b48 --- /dev/null +++ b/src/generated/resources/assets/basemetals/models/item/tin_raw.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "basemetals:item/tin_raw" + } +} diff --git a/src/generated/resources/assets/basemetals/models/item/zinc_raw.json b/src/generated/resources/assets/basemetals/models/item/zinc_raw.json new file mode 100644 index 000000000..615a34f8d --- /dev/null +++ b/src/generated/resources/assets/basemetals/models/item/zinc_raw.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "basemetals:item/zinc_raw" + } +} diff --git a/src/generated/resources/data/basemetals/advancements/angel_of_death.json b/src/generated/resources/data/basemetals/advancements/angel_of_death.json index 47a632ba8..d10a7f24d 100644 --- a/src/generated/resources/data/basemetals/advancements/angel_of_death.json +++ b/src/generated/resources/data/basemetals/advancements/angel_of_death.json @@ -19,4 +19,4 @@ "trigger": "minecraft:impossible" } } -} \ No newline at end of file +} diff --git a/src/generated/resources/data/basemetals/advancements/aquarium_maker.json b/src/generated/resources/data/basemetals/advancements/aquarium_maker.json index cbfb1d422..f6b5ff9d8 100644 --- a/src/generated/resources/data/basemetals/advancements/aquarium_maker.json +++ b/src/generated/resources/data/basemetals/advancements/aquarium_maker.json @@ -19,4 +19,4 @@ "trigger": "minecraft:impossible" } } -} \ No newline at end of file +} diff --git a/src/generated/resources/data/basemetals/advancements/blocktastic.json b/src/generated/resources/data/basemetals/advancements/blocktastic.json index f1c43e671..2535bbaf6 100644 --- a/src/generated/resources/data/basemetals/advancements/blocktastic.json +++ b/src/generated/resources/data/basemetals/advancements/blocktastic.json @@ -19,4 +19,4 @@ "trigger": "minecraft:impossible" } } -} \ No newline at end of file +} diff --git a/src/generated/resources/data/basemetals/advancements/brass_maker.json b/src/generated/resources/data/basemetals/advancements/brass_maker.json index 733118290..cc7feb983 100644 --- a/src/generated/resources/data/basemetals/advancements/brass_maker.json +++ b/src/generated/resources/data/basemetals/advancements/brass_maker.json @@ -19,4 +19,4 @@ "trigger": "minecraft:impossible" } } -} \ No newline at end of file +} diff --git a/src/generated/resources/data/basemetals/advancements/bronze_maker.json b/src/generated/resources/data/basemetals/advancements/bronze_maker.json index 2b56c58a8..33f85d4e3 100644 --- a/src/generated/resources/data/basemetals/advancements/bronze_maker.json +++ b/src/generated/resources/data/basemetals/advancements/bronze_maker.json @@ -19,4 +19,4 @@ "trigger": "minecraft:impossible" } } -} \ No newline at end of file +} diff --git a/src/generated/resources/data/basemetals/advancements/cupronickel_maker.json b/src/generated/resources/data/basemetals/advancements/cupronickel_maker.json index a82be96af..dc12a02e2 100644 --- a/src/generated/resources/data/basemetals/advancements/cupronickel_maker.json +++ b/src/generated/resources/data/basemetals/advancements/cupronickel_maker.json @@ -19,4 +19,4 @@ "trigger": "minecraft:impossible" } } -} \ No newline at end of file +} diff --git a/src/generated/resources/data/basemetals/advancements/demon_slayer.json b/src/generated/resources/data/basemetals/advancements/demon_slayer.json index 07d3d9a87..bb2d1ff5a 100644 --- a/src/generated/resources/data/basemetals/advancements/demon_slayer.json +++ b/src/generated/resources/data/basemetals/advancements/demon_slayer.json @@ -19,4 +19,4 @@ "trigger": "minecraft:impossible" } } -} \ No newline at end of file +} diff --git a/src/generated/resources/data/basemetals/advancements/electrum_maker.json b/src/generated/resources/data/basemetals/advancements/electrum_maker.json index 132a310ef..6d4e08008 100644 --- a/src/generated/resources/data/basemetals/advancements/electrum_maker.json +++ b/src/generated/resources/data/basemetals/advancements/electrum_maker.json @@ -19,4 +19,4 @@ "trigger": "minecraft:impossible" } } -} \ No newline at end of file +} diff --git a/src/generated/resources/data/basemetals/advancements/geologist.json b/src/generated/resources/data/basemetals/advancements/geologist.json index 80eb6dad2..e87ac4084 100644 --- a/src/generated/resources/data/basemetals/advancements/geologist.json +++ b/src/generated/resources/data/basemetals/advancements/geologist.json @@ -19,4 +19,4 @@ "trigger": "minecraft:impossible" } } -} \ No newline at end of file +} diff --git a/src/generated/resources/data/basemetals/advancements/invar_maker.json b/src/generated/resources/data/basemetals/advancements/invar_maker.json index 5d1a6a537..b945cd015 100644 --- a/src/generated/resources/data/basemetals/advancements/invar_maker.json +++ b/src/generated/resources/data/basemetals/advancements/invar_maker.json @@ -19,4 +19,4 @@ "trigger": "minecraft:impossible" } } -} \ No newline at end of file +} diff --git a/src/generated/resources/data/basemetals/advancements/juggernaut.json b/src/generated/resources/data/basemetals/advancements/juggernaut.json index 19df9187a..84ede3378 100644 --- a/src/generated/resources/data/basemetals/advancements/juggernaut.json +++ b/src/generated/resources/data/basemetals/advancements/juggernaut.json @@ -19,4 +19,4 @@ "trigger": "minecraft:impossible" } } -} \ No newline at end of file +} diff --git a/src/generated/resources/data/basemetals/advancements/metallurgy.json b/src/generated/resources/data/basemetals/advancements/metallurgy.json index 450f5f013..9f9a38f26 100644 --- a/src/generated/resources/data/basemetals/advancements/metallurgy.json +++ b/src/generated/resources/data/basemetals/advancements/metallurgy.json @@ -19,4 +19,4 @@ "trigger": "minecraft:impossible" } } -} \ No newline at end of file +} diff --git a/src/generated/resources/data/basemetals/advancements/mithril_maker.json b/src/generated/resources/data/basemetals/advancements/mithril_maker.json index 30174aeab..89d90c2db 100644 --- a/src/generated/resources/data/basemetals/advancements/mithril_maker.json +++ b/src/generated/resources/data/basemetals/advancements/mithril_maker.json @@ -19,4 +19,4 @@ "trigger": "minecraft:impossible" } } -} \ No newline at end of file +} diff --git a/src/generated/resources/data/basemetals/advancements/moon_boots.json b/src/generated/resources/data/basemetals/advancements/moon_boots.json index 28c690cfe..829d2201c 100644 --- a/src/generated/resources/data/basemetals/advancements/moon_boots.json +++ b/src/generated/resources/data/basemetals/advancements/moon_boots.json @@ -19,4 +19,4 @@ "trigger": "minecraft:impossible" } } -} \ No newline at end of file +} diff --git a/src/generated/resources/data/basemetals/advancements/pewter_maker.json b/src/generated/resources/data/basemetals/advancements/pewter_maker.json index 5519272a4..f0dbcba7f 100644 --- a/src/generated/resources/data/basemetals/advancements/pewter_maker.json +++ b/src/generated/resources/data/basemetals/advancements/pewter_maker.json @@ -19,4 +19,4 @@ "trigger": "minecraft:impossible" } } -} \ No newline at end of file +} diff --git a/src/generated/resources/data/basemetals/advancements/recipes/activator_rail.json b/src/generated/resources/data/basemetals/advancements/recipes/activator_rail.json index 3108d71a1..5e72fb10f 100644 --- a/src/generated/resources/data/basemetals/advancements/recipes/activator_rail.json +++ b/src/generated/resources/data/basemetals/advancements/recipes/activator_rail.json @@ -22,7 +22,9 @@ "conditions": { "items": [ { - "item": "minecraft:redstone_torch" + "items": [ + "minecraft:redstone_torch" + ] } ] } diff --git a/src/generated/resources/data/basemetals/advancements/recipes/adamantine_raw_blasting.json b/src/generated/resources/data/basemetals/advancements/recipes/adamantine_raw_blasting.json new file mode 100644 index 000000000..44d06db6b --- /dev/null +++ b/src/generated/resources/data/basemetals/advancements/recipes/adamantine_raw_blasting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_raw": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:raw_materials/adamantine" + } + ] + } + }, + "has_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "basemetals:adamantine_raw_blasting" + } + } + }, + "requirements": [ + [ + "has_raw", + "has_recipe" + ] + ], + "rewards": { + "recipes": [ + "basemetals:adamantine_raw_blasting" + ] + } +} diff --git a/src/generated/resources/data/basemetals/advancements/recipes/adamantine_raw_smelting.json b/src/generated/resources/data/basemetals/advancements/recipes/adamantine_raw_smelting.json new file mode 100644 index 000000000..77f757b2d --- /dev/null +++ b/src/generated/resources/data/basemetals/advancements/recipes/adamantine_raw_smelting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_raw": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:raw_materials/adamantine" + } + ] + } + }, + "has_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "basemetals:adamantine_raw_smelting" + } + } + }, + "requirements": [ + [ + "has_raw", + "has_recipe" + ] + ], + "rewards": { + "recipes": [ + "basemetals:adamantine_raw_smelting" + ] + } +} diff --git a/src/generated/resources/data/basemetals/advancements/recipes/antimony_raw_blasting.json b/src/generated/resources/data/basemetals/advancements/recipes/antimony_raw_blasting.json new file mode 100644 index 000000000..2d61d1d76 --- /dev/null +++ b/src/generated/resources/data/basemetals/advancements/recipes/antimony_raw_blasting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_raw": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:raw_materials/antimony" + } + ] + } + }, + "has_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "basemetals:antimony_raw_blasting" + } + } + }, + "requirements": [ + [ + "has_raw", + "has_recipe" + ] + ], + "rewards": { + "recipes": [ + "basemetals:antimony_raw_blasting" + ] + } +} diff --git a/src/generated/resources/data/basemetals/advancements/recipes/antimony_raw_smelting.json b/src/generated/resources/data/basemetals/advancements/recipes/antimony_raw_smelting.json new file mode 100644 index 000000000..929cd8cfa --- /dev/null +++ b/src/generated/resources/data/basemetals/advancements/recipes/antimony_raw_smelting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_raw": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:raw_materials/antimony" + } + ] + } + }, + "has_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "basemetals:antimony_raw_smelting" + } + } + }, + "requirements": [ + [ + "has_raw", + "has_recipe" + ] + ], + "rewards": { + "recipes": [ + "basemetals:antimony_raw_smelting" + ] + } +} diff --git a/src/generated/resources/data/basemetals/advancements/recipes/bismuth_raw_blasting.json b/src/generated/resources/data/basemetals/advancements/recipes/bismuth_raw_blasting.json new file mode 100644 index 000000000..8208a2639 --- /dev/null +++ b/src/generated/resources/data/basemetals/advancements/recipes/bismuth_raw_blasting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_raw": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:raw_materials/bismuth" + } + ] + } + }, + "has_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "basemetals:bismuth_raw_blasting" + } + } + }, + "requirements": [ + [ + "has_raw", + "has_recipe" + ] + ], + "rewards": { + "recipes": [ + "basemetals:bismuth_raw_blasting" + ] + } +} diff --git a/src/generated/resources/data/basemetals/advancements/recipes/bismuth_raw_smelting.json b/src/generated/resources/data/basemetals/advancements/recipes/bismuth_raw_smelting.json new file mode 100644 index 000000000..f3e8543ab --- /dev/null +++ b/src/generated/resources/data/basemetals/advancements/recipes/bismuth_raw_smelting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_raw": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:raw_materials/bismuth" + } + ] + } + }, + "has_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "basemetals:bismuth_raw_smelting" + } + } + }, + "requirements": [ + [ + "has_raw", + "has_recipe" + ] + ], + "rewards": { + "recipes": [ + "basemetals:bismuth_raw_smelting" + ] + } +} diff --git a/src/generated/resources/data/basemetals/advancements/recipes/charcoal_block.json b/src/generated/resources/data/basemetals/advancements/recipes/charcoal_block.json index f03020268..47fc31a16 100644 --- a/src/generated/resources/data/basemetals/advancements/recipes/charcoal_block.json +++ b/src/generated/resources/data/basemetals/advancements/recipes/charcoal_block.json @@ -6,7 +6,9 @@ "conditions": { "items": [ { - "item": "minecraft:charcoal" + "items": [ + "minecraft:charcoal" + ] } ] } @@ -22,7 +24,9 @@ "conditions": { "items": [ { - "item": "minecraft:charcoal" + "items": [ + "minecraft:charcoal" + ] } ] } diff --git a/src/generated/resources/data/basemetals/advancements/recipes/charcoal_block_dust.json b/src/generated/resources/data/basemetals/advancements/recipes/charcoal_block_dust.json index 1edb98be2..bc52df0d7 100644 --- a/src/generated/resources/data/basemetals/advancements/recipes/charcoal_block_dust.json +++ b/src/generated/resources/data/basemetals/advancements/recipes/charcoal_block_dust.json @@ -6,7 +6,9 @@ "conditions": { "items": [ { - "item": "minecraft:charcoal" + "items": [ + "minecraft:charcoal" + ] } ] } diff --git a/src/generated/resources/data/basemetals/advancements/recipes/charcoal_ingot.json b/src/generated/resources/data/basemetals/advancements/recipes/charcoal_ingot.json index 6b35285a2..5badd3a33 100644 --- a/src/generated/resources/data/basemetals/advancements/recipes/charcoal_ingot.json +++ b/src/generated/resources/data/basemetals/advancements/recipes/charcoal_ingot.json @@ -6,7 +6,9 @@ "conditions": { "items": [ { - "item": "minecraft:charcoal" + "items": [ + "minecraft:charcoal" + ] } ] } diff --git a/src/generated/resources/data/basemetals/advancements/recipes/charcoal_nugget.json b/src/generated/resources/data/basemetals/advancements/recipes/charcoal_nugget.json index fb59b1659..ec675d1ee 100644 --- a/src/generated/resources/data/basemetals/advancements/recipes/charcoal_nugget.json +++ b/src/generated/resources/data/basemetals/advancements/recipes/charcoal_nugget.json @@ -6,7 +6,9 @@ "conditions": { "items": [ { - "item": "minecraft:charcoal" + "items": [ + "minecraft:charcoal" + ] } ] } @@ -22,7 +24,9 @@ "conditions": { "items": [ { - "item": "minecraft:charcoal" + "items": [ + "minecraft:charcoal" + ] } ] } diff --git a/src/generated/resources/data/basemetals/advancements/recipes/charcoal_powder_from_small.json b/src/generated/resources/data/basemetals/advancements/recipes/charcoal_powder_from_small.json index 6df61adc6..14fd71fe6 100644 --- a/src/generated/resources/data/basemetals/advancements/recipes/charcoal_powder_from_small.json +++ b/src/generated/resources/data/basemetals/advancements/recipes/charcoal_powder_from_small.json @@ -6,7 +6,9 @@ "conditions": { "items": [ { - "item": "minecraft:charcoal" + "items": [ + "minecraft:charcoal" + ] } ] } diff --git a/src/generated/resources/data/basemetals/advancements/recipes/charcoal_smallpowder.json b/src/generated/resources/data/basemetals/advancements/recipes/charcoal_smallpowder.json index 22d720a28..07efb2e5c 100644 --- a/src/generated/resources/data/basemetals/advancements/recipes/charcoal_smallpowder.json +++ b/src/generated/resources/data/basemetals/advancements/recipes/charcoal_smallpowder.json @@ -6,7 +6,9 @@ "conditions": { "items": [ { - "item": "minecraft:charcoal" + "items": [ + "minecraft:charcoal" + ] } ] } diff --git a/src/generated/resources/data/basemetals/advancements/recipes/coal_block_dust.json b/src/generated/resources/data/basemetals/advancements/recipes/coal_block_dust.json index 3c38a0be9..f6b39b2f6 100644 --- a/src/generated/resources/data/basemetals/advancements/recipes/coal_block_dust.json +++ b/src/generated/resources/data/basemetals/advancements/recipes/coal_block_dust.json @@ -6,7 +6,9 @@ "conditions": { "items": [ { - "item": "minecraft:coal" + "items": [ + "minecraft:coal" + ] } ] } diff --git a/src/generated/resources/data/basemetals/advancements/recipes/coal_ingot.json b/src/generated/resources/data/basemetals/advancements/recipes/coal_ingot.json index 1553238d3..6e46ed7cf 100644 --- a/src/generated/resources/data/basemetals/advancements/recipes/coal_ingot.json +++ b/src/generated/resources/data/basemetals/advancements/recipes/coal_ingot.json @@ -6,7 +6,9 @@ "conditions": { "items": [ { - "item": "minecraft:coal" + "items": [ + "minecraft:coal" + ] } ] } diff --git a/src/generated/resources/data/basemetals/advancements/recipes/coal_nugget.json b/src/generated/resources/data/basemetals/advancements/recipes/coal_nugget.json index 192b952a1..dcd725337 100644 --- a/src/generated/resources/data/basemetals/advancements/recipes/coal_nugget.json +++ b/src/generated/resources/data/basemetals/advancements/recipes/coal_nugget.json @@ -6,7 +6,9 @@ "conditions": { "items": [ { - "item": "minecraft:coal" + "items": [ + "minecraft:coal" + ] } ] } @@ -22,7 +24,9 @@ "conditions": { "items": [ { - "item": "minecraft:coal" + "items": [ + "minecraft:coal" + ] } ] } diff --git a/src/generated/resources/data/basemetals/advancements/recipes/coal_powder_from_small.json b/src/generated/resources/data/basemetals/advancements/recipes/coal_powder_from_small.json index a1698b7e7..b83470b45 100644 --- a/src/generated/resources/data/basemetals/advancements/recipes/coal_powder_from_small.json +++ b/src/generated/resources/data/basemetals/advancements/recipes/coal_powder_from_small.json @@ -6,7 +6,9 @@ "conditions": { "items": [ { - "item": "minecraft:coal" + "items": [ + "minecraft:coal" + ] } ] } diff --git a/src/generated/resources/data/basemetals/advancements/recipes/coal_smallpowder.json b/src/generated/resources/data/basemetals/advancements/recipes/coal_smallpowder.json index 2244319db..cc0d58dc7 100644 --- a/src/generated/resources/data/basemetals/advancements/recipes/coal_smallpowder.json +++ b/src/generated/resources/data/basemetals/advancements/recipes/coal_smallpowder.json @@ -6,7 +6,9 @@ "conditions": { "items": [ { - "item": "minecraft:coal" + "items": [ + "minecraft:coal" + ] } ] } diff --git a/src/generated/resources/data/basemetals/advancements/recipes/coldiron_raw_blasting.json b/src/generated/resources/data/basemetals/advancements/recipes/coldiron_raw_blasting.json new file mode 100644 index 000000000..8f555bd69 --- /dev/null +++ b/src/generated/resources/data/basemetals/advancements/recipes/coldiron_raw_blasting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_raw": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:raw_materials/coldiron" + } + ] + } + }, + "has_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "basemetals:coldiron_raw_blasting" + } + } + }, + "requirements": [ + [ + "has_raw", + "has_recipe" + ] + ], + "rewards": { + "recipes": [ + "basemetals:coldiron_raw_blasting" + ] + } +} diff --git a/src/generated/resources/data/basemetals/advancements/recipes/coldiron_raw_smelting.json b/src/generated/resources/data/basemetals/advancements/recipes/coldiron_raw_smelting.json new file mode 100644 index 000000000..1dac0021e --- /dev/null +++ b/src/generated/resources/data/basemetals/advancements/recipes/coldiron_raw_smelting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_raw": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:raw_materials/coldiron" + } + ] + } + }, + "has_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "basemetals:coldiron_raw_smelting" + } + } + }, + "requirements": [ + [ + "has_raw", + "has_recipe" + ] + ], + "rewards": { + "recipes": [ + "basemetals:coldiron_raw_smelting" + ] + } +} diff --git a/src/generated/resources/data/basemetals/advancements/recipes/copper_block.json b/src/generated/resources/data/basemetals/advancements/recipes/copper_block.json index 502957c2a..e37c28257 100644 --- a/src/generated/resources/data/basemetals/advancements/recipes/copper_block.json +++ b/src/generated/resources/data/basemetals/advancements/recipes/copper_block.json @@ -22,7 +22,9 @@ "conditions": { "items": [ { - "item": "basemetals:copper_ingot" + "items": [ + "basemetals:copper_ingot" + ] } ] } diff --git a/src/generated/resources/data/basemetals/advancements/recipes/copper_block_ingot.json b/src/generated/resources/data/basemetals/advancements/recipes/copper_block_ingot.json index 982eda65a..c8c72bccf 100644 --- a/src/generated/resources/data/basemetals/advancements/recipes/copper_block_ingot.json +++ b/src/generated/resources/data/basemetals/advancements/recipes/copper_block_ingot.json @@ -22,7 +22,9 @@ "conditions": { "items": [ { - "item": "basemetals:copper_block" + "items": [ + "basemetals:copper_block" + ] } ] } diff --git a/src/generated/resources/data/basemetals/advancements/recipes/copper_ingot_from_nuggets.json b/src/generated/resources/data/basemetals/advancements/recipes/copper_ingot_from_nuggets.json index d425cc696..5ff159ed9 100644 --- a/src/generated/resources/data/basemetals/advancements/recipes/copper_ingot_from_nuggets.json +++ b/src/generated/resources/data/basemetals/advancements/recipes/copper_ingot_from_nuggets.json @@ -22,7 +22,9 @@ "conditions": { "items": [ { - "item": "basemetals:copper_nugget" + "items": [ + "basemetals:copper_nugget" + ] } ] } diff --git a/src/generated/resources/data/basemetals/advancements/recipes/copper_nuggets.json b/src/generated/resources/data/basemetals/advancements/recipes/copper_nuggets.json index fb23050a0..6ee73af82 100644 --- a/src/generated/resources/data/basemetals/advancements/recipes/copper_nuggets.json +++ b/src/generated/resources/data/basemetals/advancements/recipes/copper_nuggets.json @@ -22,7 +22,9 @@ "conditions": { "items": [ { - "item": "basemetals:copper_ingot" + "items": [ + "basemetals:copper_ingot" + ] } ] } diff --git a/src/generated/resources/data/basemetals/advancements/recipes/detector_rail.json b/src/generated/resources/data/basemetals/advancements/recipes/detector_rail.json index 402bf3a8f..6ea5fbef3 100644 --- a/src/generated/resources/data/basemetals/advancements/recipes/detector_rail.json +++ b/src/generated/resources/data/basemetals/advancements/recipes/detector_rail.json @@ -22,7 +22,9 @@ "conditions": { "items": [ { - "item": "minecraft:redstone_torch" + "items": [ + "minecraft:redstone_torch" + ] } ] } diff --git a/src/generated/resources/data/basemetals/advancements/recipes/flint_and_steel.json b/src/generated/resources/data/basemetals/advancements/recipes/flint_and_steel.json index ce7c9725b..06e6a67b4 100644 --- a/src/generated/resources/data/basemetals/advancements/recipes/flint_and_steel.json +++ b/src/generated/resources/data/basemetals/advancements/recipes/flint_and_steel.json @@ -32,7 +32,9 @@ "conditions": { "items": [ { - "item": "minecraft:flint" + "items": [ + "minecraft:flint" + ] } ] } diff --git a/src/generated/resources/data/basemetals/advancements/recipes/human_detector.json b/src/generated/resources/data/basemetals/advancements/recipes/human_detector.json index 4dd28de5b..69c99eac0 100644 --- a/src/generated/resources/data/basemetals/advancements/recipes/human_detector.json +++ b/src/generated/resources/data/basemetals/advancements/recipes/human_detector.json @@ -32,7 +32,9 @@ "conditions": { "items": [ { - "item": "minecraft:brick" + "items": [ + "minecraft:brick" + ] } ] } diff --git a/src/generated/resources/data/basemetals/advancements/recipes/lead_raw_blasting.json b/src/generated/resources/data/basemetals/advancements/recipes/lead_raw_blasting.json new file mode 100644 index 000000000..53a188238 --- /dev/null +++ b/src/generated/resources/data/basemetals/advancements/recipes/lead_raw_blasting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_raw": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:raw_materials/lead" + } + ] + } + }, + "has_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "basemetals:lead_raw_blasting" + } + } + }, + "requirements": [ + [ + "has_raw", + "has_recipe" + ] + ], + "rewards": { + "recipes": [ + "basemetals:lead_raw_blasting" + ] + } +} diff --git a/src/generated/resources/data/basemetals/advancements/recipes/lead_raw_smelting.json b/src/generated/resources/data/basemetals/advancements/recipes/lead_raw_smelting.json new file mode 100644 index 000000000..29c5d6f9c --- /dev/null +++ b/src/generated/resources/data/basemetals/advancements/recipes/lead_raw_smelting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_raw": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:raw_materials/lead" + } + ] + } + }, + "has_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "basemetals:lead_raw_smelting" + } + } + }, + "requirements": [ + [ + "has_raw", + "has_recipe" + ] + ], + "rewards": { + "recipes": [ + "basemetals:lead_raw_smelting" + ] + } +} diff --git a/src/generated/resources/data/basemetals/advancements/recipes/mercury_raw_blasting.json b/src/generated/resources/data/basemetals/advancements/recipes/mercury_raw_blasting.json new file mode 100644 index 000000000..0341eaf00 --- /dev/null +++ b/src/generated/resources/data/basemetals/advancements/recipes/mercury_raw_blasting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_raw": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:raw_materials/mercury" + } + ] + } + }, + "has_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "basemetals:mercury_raw_blasting" + } + } + }, + "requirements": [ + [ + "has_raw", + "has_recipe" + ] + ], + "rewards": { + "recipes": [ + "basemetals:mercury_raw_blasting" + ] + } +} diff --git a/src/generated/resources/data/basemetals/advancements/recipes/mercury_raw_smelting.json b/src/generated/resources/data/basemetals/advancements/recipes/mercury_raw_smelting.json new file mode 100644 index 000000000..67fe712fc --- /dev/null +++ b/src/generated/resources/data/basemetals/advancements/recipes/mercury_raw_smelting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_raw": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:raw_materials/mercury" + } + ] + } + }, + "has_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "basemetals:mercury_raw_smelting" + } + } + }, + "requirements": [ + [ + "has_raw", + "has_recipe" + ] + ], + "rewards": { + "recipes": [ + "basemetals:mercury_raw_smelting" + ] + } +} diff --git a/src/generated/resources/data/basemetals/advancements/recipes/nickel_raw_blasting.json b/src/generated/resources/data/basemetals/advancements/recipes/nickel_raw_blasting.json new file mode 100644 index 000000000..9ea07e997 --- /dev/null +++ b/src/generated/resources/data/basemetals/advancements/recipes/nickel_raw_blasting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_raw": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:raw_materials/nickel" + } + ] + } + }, + "has_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "basemetals:nickel_raw_blasting" + } + } + }, + "requirements": [ + [ + "has_raw", + "has_recipe" + ] + ], + "rewards": { + "recipes": [ + "basemetals:nickel_raw_blasting" + ] + } +} diff --git a/src/generated/resources/data/basemetals/advancements/recipes/nickel_raw_smelting.json b/src/generated/resources/data/basemetals/advancements/recipes/nickel_raw_smelting.json new file mode 100644 index 000000000..067db53a3 --- /dev/null +++ b/src/generated/resources/data/basemetals/advancements/recipes/nickel_raw_smelting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_raw": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:raw_materials/nickel" + } + ] + } + }, + "has_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "basemetals:nickel_raw_smelting" + } + } + }, + "requirements": [ + [ + "has_raw", + "has_recipe" + ] + ], + "rewards": { + "recipes": [ + "basemetals:nickel_raw_smelting" + ] + } +} diff --git a/src/generated/resources/data/basemetals/advancements/recipes/platinum_raw_blasting.json b/src/generated/resources/data/basemetals/advancements/recipes/platinum_raw_blasting.json new file mode 100644 index 000000000..b69e1fcbf --- /dev/null +++ b/src/generated/resources/data/basemetals/advancements/recipes/platinum_raw_blasting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_raw": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:raw_materials/platinum" + } + ] + } + }, + "has_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "basemetals:platinum_raw_blasting" + } + } + }, + "requirements": [ + [ + "has_raw", + "has_recipe" + ] + ], + "rewards": { + "recipes": [ + "basemetals:platinum_raw_blasting" + ] + } +} diff --git a/src/generated/resources/data/basemetals/advancements/recipes/platinum_raw_smelting.json b/src/generated/resources/data/basemetals/advancements/recipes/platinum_raw_smelting.json new file mode 100644 index 000000000..8461d1256 --- /dev/null +++ b/src/generated/resources/data/basemetals/advancements/recipes/platinum_raw_smelting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_raw": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:raw_materials/platinum" + } + ] + } + }, + "has_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "basemetals:platinum_raw_smelting" + } + } + }, + "requirements": [ + [ + "has_raw", + "has_recipe" + ] + ], + "rewards": { + "recipes": [ + "basemetals:platinum_raw_smelting" + ] + } +} diff --git a/src/generated/resources/data/basemetals/advancements/recipes/silver_raw_blasting.json b/src/generated/resources/data/basemetals/advancements/recipes/silver_raw_blasting.json new file mode 100644 index 000000000..a60d3e3dc --- /dev/null +++ b/src/generated/resources/data/basemetals/advancements/recipes/silver_raw_blasting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_raw": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:raw_materials/silver" + } + ] + } + }, + "has_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "basemetals:silver_raw_blasting" + } + } + }, + "requirements": [ + [ + "has_raw", + "has_recipe" + ] + ], + "rewards": { + "recipes": [ + "basemetals:silver_raw_blasting" + ] + } +} diff --git a/src/generated/resources/data/basemetals/advancements/recipes/silver_raw_smelting.json b/src/generated/resources/data/basemetals/advancements/recipes/silver_raw_smelting.json new file mode 100644 index 000000000..ee120abd3 --- /dev/null +++ b/src/generated/resources/data/basemetals/advancements/recipes/silver_raw_smelting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_raw": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:raw_materials/silver" + } + ] + } + }, + "has_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "basemetals:silver_raw_smelting" + } + } + }, + "requirements": [ + [ + "has_raw", + "has_recipe" + ] + ], + "rewards": { + "recipes": [ + "basemetals:silver_raw_smelting" + ] + } +} diff --git a/src/generated/resources/data/basemetals/advancements/recipes/starsteel_raw_blasting.json b/src/generated/resources/data/basemetals/advancements/recipes/starsteel_raw_blasting.json new file mode 100644 index 000000000..40abc18f2 --- /dev/null +++ b/src/generated/resources/data/basemetals/advancements/recipes/starsteel_raw_blasting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_raw": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:raw_materials/starsteel" + } + ] + } + }, + "has_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "basemetals:starsteel_raw_blasting" + } + } + }, + "requirements": [ + [ + "has_raw", + "has_recipe" + ] + ], + "rewards": { + "recipes": [ + "basemetals:starsteel_raw_blasting" + ] + } +} diff --git a/src/generated/resources/data/basemetals/advancements/recipes/starsteel_raw_smelting.json b/src/generated/resources/data/basemetals/advancements/recipes/starsteel_raw_smelting.json new file mode 100644 index 000000000..d98a18369 --- /dev/null +++ b/src/generated/resources/data/basemetals/advancements/recipes/starsteel_raw_smelting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_raw": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:raw_materials/starsteel" + } + ] + } + }, + "has_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "basemetals:starsteel_raw_smelting" + } + } + }, + "requirements": [ + [ + "has_raw", + "has_recipe" + ] + ], + "rewards": { + "recipes": [ + "basemetals:starsteel_raw_smelting" + ] + } +} diff --git a/src/generated/resources/data/basemetals/advancements/recipes/stone_anvil.json b/src/generated/resources/data/basemetals/advancements/recipes/stone_anvil.json index 54f1aeb63..da757bfbc 100644 --- a/src/generated/resources/data/basemetals/advancements/recipes/stone_anvil.json +++ b/src/generated/resources/data/basemetals/advancements/recipes/stone_anvil.json @@ -22,7 +22,9 @@ "conditions": { "items": [ { - "item": "minecraft:stone_bricks" + "items": [ + "minecraft:stone_bricks" + ] } ] } @@ -42,7 +44,9 @@ "conditions": { "items": [ { - "item": "minecraft:stone_slab" + "items": [ + "minecraft:stone_slab" + ] } ] } diff --git a/src/generated/resources/data/basemetals/advancements/recipes/stone_crackhammer.json b/src/generated/resources/data/basemetals/advancements/recipes/stone_crackhammer.json index 4ddeaa472..0e0cadd64 100644 --- a/src/generated/resources/data/basemetals/advancements/recipes/stone_crackhammer.json +++ b/src/generated/resources/data/basemetals/advancements/recipes/stone_crackhammer.json @@ -22,7 +22,9 @@ "conditions": { "items": [ { - "item": "minecraft:stone_bricks" + "items": [ + "minecraft:stone_bricks" + ] } ] } diff --git a/src/generated/resources/data/basemetals/advancements/recipes/tin_raw_blasting.json b/src/generated/resources/data/basemetals/advancements/recipes/tin_raw_blasting.json new file mode 100644 index 000000000..25479d72f --- /dev/null +++ b/src/generated/resources/data/basemetals/advancements/recipes/tin_raw_blasting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_raw": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:raw_materials/tin" + } + ] + } + }, + "has_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "basemetals:tin_raw_blasting" + } + } + }, + "requirements": [ + [ + "has_raw", + "has_recipe" + ] + ], + "rewards": { + "recipes": [ + "basemetals:tin_raw_blasting" + ] + } +} diff --git a/src/generated/resources/data/basemetals/advancements/recipes/tin_raw_smelting.json b/src/generated/resources/data/basemetals/advancements/recipes/tin_raw_smelting.json new file mode 100644 index 000000000..b9463243d --- /dev/null +++ b/src/generated/resources/data/basemetals/advancements/recipes/tin_raw_smelting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_raw": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:raw_materials/tin" + } + ] + } + }, + "has_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "basemetals:tin_raw_smelting" + } + } + }, + "requirements": [ + [ + "has_raw", + "has_recipe" + ] + ], + "rewards": { + "recipes": [ + "basemetals:tin_raw_smelting" + ] + } +} diff --git a/src/generated/resources/data/basemetals/advancements/recipes/zinc_raw_blasting.json b/src/generated/resources/data/basemetals/advancements/recipes/zinc_raw_blasting.json new file mode 100644 index 000000000..bf1b23cfa --- /dev/null +++ b/src/generated/resources/data/basemetals/advancements/recipes/zinc_raw_blasting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_raw": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:raw_materials/zinc" + } + ] + } + }, + "has_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "basemetals:zinc_raw_blasting" + } + } + }, + "requirements": [ + [ + "has_raw", + "has_recipe" + ] + ], + "rewards": { + "recipes": [ + "basemetals:zinc_raw_blasting" + ] + } +} diff --git a/src/generated/resources/data/basemetals/advancements/recipes/zinc_raw_smelting.json b/src/generated/resources/data/basemetals/advancements/recipes/zinc_raw_smelting.json new file mode 100644 index 000000000..771982fef --- /dev/null +++ b/src/generated/resources/data/basemetals/advancements/recipes/zinc_raw_smelting.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_raw": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:raw_materials/zinc" + } + ] + } + }, + "has_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "basemetals:zinc_raw_smelting" + } + } + }, + "requirements": [ + [ + "has_raw", + "has_recipe" + ] + ], + "rewards": { + "recipes": [ + "basemetals:zinc_raw_smelting" + ] + } +} diff --git a/src/generated/resources/data/basemetals/advancements/scuba_diver.json b/src/generated/resources/data/basemetals/advancements/scuba_diver.json index a03156c95..045746abc 100644 --- a/src/generated/resources/data/basemetals/advancements/scuba_diver.json +++ b/src/generated/resources/data/basemetals/advancements/scuba_diver.json @@ -19,4 +19,4 @@ "trigger": "minecraft:impossible" } } -} \ No newline at end of file +} diff --git a/src/generated/resources/data/basemetals/advancements/steel_maker.json b/src/generated/resources/data/basemetals/advancements/steel_maker.json index d20115417..9da8436ca 100644 --- a/src/generated/resources/data/basemetals/advancements/steel_maker.json +++ b/src/generated/resources/data/basemetals/advancements/steel_maker.json @@ -19,4 +19,4 @@ "trigger": "minecraft:impossible" } } -} \ No newline at end of file +} diff --git a/src/generated/resources/data/basemetals/advancements/this_is_new.json b/src/generated/resources/data/basemetals/advancements/this_is_new.json index 7fa1b89a6..3ec088a72 100644 --- a/src/generated/resources/data/basemetals/advancements/this_is_new.json +++ b/src/generated/resources/data/basemetals/advancements/this_is_new.json @@ -19,4 +19,4 @@ "trigger": "minecraft:impossible" } } -} \ No newline at end of file +} diff --git a/src/generated/resources/data/basemetals/loot_tables/blocks/adamantine_ore.json b/src/generated/resources/data/basemetals/loot_tables/blocks/adamantine_ore.json index 45a3671c3..270390fec 100644 --- a/src/generated/resources/data/basemetals/loot_tables/blocks/adamantine_ore.json +++ b/src/generated/resources/data/basemetals/loot_tables/blocks/adamantine_ore.json @@ -4,16 +4,44 @@ { "name": "basemetals_adamantine_ore", "rolls": 1, - "conditions": [ - { - "condition": "minecraft:survives_explosion" - } - ], "entries": [ { - "type": "minecraft:item", - "name": "basemetals:adamantine_ore", - "functions": [] + "type": "minecraft:alternatives", + "children": [ + { + "type": "minecraft:item", + "name": "basemetals:adamantine_ore", + "conditions": [ + { + "condition": "minecraft:match_tool", + "predicate": { + "enchantments": [ + { + "enchantment": "minecraft:silk_touch", + "levels": { + "min": 1 + } + } + ] + } + } + ] + }, + { + "type": "minecraft:item", + "name": "basemetals:adamantine_raw", + "functions": [ + { + "function": "minecraft:apply_bonus", + "enchantment": "minecraft:fortune", + "formula": "minecraft:ore_drops" + }, + { + "function": "minecraft:explosion_decay" + } + ] + } + ] } ] } diff --git a/src/generated/resources/data/basemetals/loot_tables/blocks/antimony_ore.json b/src/generated/resources/data/basemetals/loot_tables/blocks/antimony_ore.json index 10ab1f65a..2e08b7675 100644 --- a/src/generated/resources/data/basemetals/loot_tables/blocks/antimony_ore.json +++ b/src/generated/resources/data/basemetals/loot_tables/blocks/antimony_ore.json @@ -4,16 +4,44 @@ { "name": "basemetals_antimony_ore", "rolls": 1, - "conditions": [ - { - "condition": "minecraft:survives_explosion" - } - ], "entries": [ { - "type": "minecraft:item", - "name": "basemetals:antimony_ore", - "functions": [] + "type": "minecraft:alternatives", + "children": [ + { + "type": "minecraft:item", + "name": "basemetals:antimony_ore", + "conditions": [ + { + "condition": "minecraft:match_tool", + "predicate": { + "enchantments": [ + { + "enchantment": "minecraft:silk_touch", + "levels": { + "min": 1 + } + } + ] + } + } + ] + }, + { + "type": "minecraft:item", + "name": "basemetals:antimony_raw", + "functions": [ + { + "function": "minecraft:apply_bonus", + "enchantment": "minecraft:fortune", + "formula": "minecraft:ore_drops" + }, + { + "function": "minecraft:explosion_decay" + } + ] + } + ] } ] } diff --git a/src/generated/resources/data/basemetals/loot_tables/blocks/bismuth_ore.json b/src/generated/resources/data/basemetals/loot_tables/blocks/bismuth_ore.json index 3c801fd6c..3c8bfb42d 100644 --- a/src/generated/resources/data/basemetals/loot_tables/blocks/bismuth_ore.json +++ b/src/generated/resources/data/basemetals/loot_tables/blocks/bismuth_ore.json @@ -4,16 +4,44 @@ { "name": "basemetals_bismuth_ore", "rolls": 1, - "conditions": [ - { - "condition": "minecraft:survives_explosion" - } - ], "entries": [ { - "type": "minecraft:item", - "name": "basemetals:bismuth_ore", - "functions": [] + "type": "minecraft:alternatives", + "children": [ + { + "type": "minecraft:item", + "name": "basemetals:bismuth_ore", + "conditions": [ + { + "condition": "minecraft:match_tool", + "predicate": { + "enchantments": [ + { + "enchantment": "minecraft:silk_touch", + "levels": { + "min": 1 + } + } + ] + } + } + ] + }, + { + "type": "minecraft:item", + "name": "basemetals:bismuth_raw", + "functions": [ + { + "function": "minecraft:apply_bonus", + "enchantment": "minecraft:fortune", + "formula": "minecraft:ore_drops" + }, + { + "function": "minecraft:explosion_decay" + } + ] + } + ] } ] } diff --git a/src/generated/resources/data/basemetals/loot_tables/blocks/coldiron_ore.json b/src/generated/resources/data/basemetals/loot_tables/blocks/coldiron_ore.json index 1e9595ba0..1c49bec8a 100644 --- a/src/generated/resources/data/basemetals/loot_tables/blocks/coldiron_ore.json +++ b/src/generated/resources/data/basemetals/loot_tables/blocks/coldiron_ore.json @@ -4,16 +4,44 @@ { "name": "basemetals_coldiron_ore", "rolls": 1, - "conditions": [ - { - "condition": "minecraft:survives_explosion" - } - ], "entries": [ { - "type": "minecraft:item", - "name": "basemetals:coldiron_ore", - "functions": [] + "type": "minecraft:alternatives", + "children": [ + { + "type": "minecraft:item", + "name": "basemetals:coldiron_ore", + "conditions": [ + { + "condition": "minecraft:match_tool", + "predicate": { + "enchantments": [ + { + "enchantment": "minecraft:silk_touch", + "levels": { + "min": 1 + } + } + ] + } + } + ] + }, + { + "type": "minecraft:item", + "name": "basemetals:coldiron_raw", + "functions": [ + { + "function": "minecraft:apply_bonus", + "enchantment": "minecraft:fortune", + "formula": "minecraft:ore_drops" + }, + { + "function": "minecraft:explosion_decay" + } + ] + } + ] } ] } diff --git a/src/generated/resources/data/basemetals/loot_tables/blocks/copper_ore.json b/src/generated/resources/data/basemetals/loot_tables/blocks/copper_ore.json index 9100ca1c2..4ef89c932 100644 --- a/src/generated/resources/data/basemetals/loot_tables/blocks/copper_ore.json +++ b/src/generated/resources/data/basemetals/loot_tables/blocks/copper_ore.json @@ -4,16 +4,52 @@ { "name": "basemetals_copper_ore", "rolls": 1, - "conditions": [ - { - "condition": "minecraft:survives_explosion" - } - ], "entries": [ { - "type": "minecraft:item", - "name": "basemetals:copper_ore", - "functions": [] + "type": "minecraft:alternatives", + "children": [ + { + "type": "minecraft:item", + "name": "basemetals:copper_ore", + "conditions": [ + { + "condition": "minecraft:match_tool", + "predicate": { + "enchantments": [ + { + "enchantment": "minecraft:silk_touch", + "levels": { + "min": 1 + } + } + ] + } + } + ] + }, + { + "type": "minecraft:item", + "name": "minecraft:raw_copper", + "functions": [ + { + "function": "minecraft:set_count", + "count": { + "type": "minecraft:uniform", + "min": 2, + "max": 3 + } + }, + { + "function": "minecraft:apply_bonus", + "enchantment": "minecraft:fortune", + "formula": "minecraft:ore_drops" + }, + { + "function": "minecraft:explosion_decay" + } + ] + } + ] } ] } diff --git a/src/generated/resources/data/basemetals/loot_tables/blocks/lead_ore.json b/src/generated/resources/data/basemetals/loot_tables/blocks/lead_ore.json index 76793ad39..465d836f4 100644 --- a/src/generated/resources/data/basemetals/loot_tables/blocks/lead_ore.json +++ b/src/generated/resources/data/basemetals/loot_tables/blocks/lead_ore.json @@ -4,16 +4,44 @@ { "name": "basemetals_lead_ore", "rolls": 1, - "conditions": [ - { - "condition": "minecraft:survives_explosion" - } - ], "entries": [ { - "type": "minecraft:item", - "name": "basemetals:lead_ore", - "functions": [] + "type": "minecraft:alternatives", + "children": [ + { + "type": "minecraft:item", + "name": "basemetals:lead_ore", + "conditions": [ + { + "condition": "minecraft:match_tool", + "predicate": { + "enchantments": [ + { + "enchantment": "minecraft:silk_touch", + "levels": { + "min": 1 + } + } + ] + } + } + ] + }, + { + "type": "minecraft:item", + "name": "basemetals:lead_raw", + "functions": [ + { + "function": "minecraft:apply_bonus", + "enchantment": "minecraft:fortune", + "formula": "minecraft:ore_drops" + }, + { + "function": "minecraft:explosion_decay" + } + ] + } + ] } ] } diff --git a/src/generated/resources/data/basemetals/loot_tables/blocks/mercury_ore.json b/src/generated/resources/data/basemetals/loot_tables/blocks/mercury_ore.json index b32e399ff..987b4301e 100644 --- a/src/generated/resources/data/basemetals/loot_tables/blocks/mercury_ore.json +++ b/src/generated/resources/data/basemetals/loot_tables/blocks/mercury_ore.json @@ -4,16 +4,44 @@ { "name": "basemetals_mercury_ore", "rolls": 1, - "conditions": [ - { - "condition": "minecraft:survives_explosion" - } - ], "entries": [ { - "type": "minecraft:item", - "name": "basemetals:mercury_ore", - "functions": [] + "type": "minecraft:alternatives", + "children": [ + { + "type": "minecraft:item", + "name": "basemetals:mercury_ore", + "conditions": [ + { + "condition": "minecraft:match_tool", + "predicate": { + "enchantments": [ + { + "enchantment": "minecraft:silk_touch", + "levels": { + "min": 1 + } + } + ] + } + } + ] + }, + { + "type": "minecraft:item", + "name": "basemetals:mercury_raw", + "functions": [ + { + "function": "minecraft:apply_bonus", + "enchantment": "minecraft:fortune", + "formula": "minecraft:ore_drops" + }, + { + "function": "minecraft:explosion_decay" + } + ] + } + ] } ] } diff --git a/src/generated/resources/data/basemetals/loot_tables/blocks/nickel_ore.json b/src/generated/resources/data/basemetals/loot_tables/blocks/nickel_ore.json index d6a00424f..4b0952e04 100644 --- a/src/generated/resources/data/basemetals/loot_tables/blocks/nickel_ore.json +++ b/src/generated/resources/data/basemetals/loot_tables/blocks/nickel_ore.json @@ -4,16 +4,44 @@ { "name": "basemetals_nickel_ore", "rolls": 1, - "conditions": [ - { - "condition": "minecraft:survives_explosion" - } - ], "entries": [ { - "type": "minecraft:item", - "name": "basemetals:nickel_ore", - "functions": [] + "type": "minecraft:alternatives", + "children": [ + { + "type": "minecraft:item", + "name": "basemetals:nickel_ore", + "conditions": [ + { + "condition": "minecraft:match_tool", + "predicate": { + "enchantments": [ + { + "enchantment": "minecraft:silk_touch", + "levels": { + "min": 1 + } + } + ] + } + } + ] + }, + { + "type": "minecraft:item", + "name": "basemetals:nickel_raw", + "functions": [ + { + "function": "minecraft:apply_bonus", + "enchantment": "minecraft:fortune", + "formula": "minecraft:ore_drops" + }, + { + "function": "minecraft:explosion_decay" + } + ] + } + ] } ] } diff --git a/src/generated/resources/data/basemetals/loot_tables/blocks/platinum_ore.json b/src/generated/resources/data/basemetals/loot_tables/blocks/platinum_ore.json index 2bda4ada8..0e34a21ed 100644 --- a/src/generated/resources/data/basemetals/loot_tables/blocks/platinum_ore.json +++ b/src/generated/resources/data/basemetals/loot_tables/blocks/platinum_ore.json @@ -4,16 +4,44 @@ { "name": "basemetals_platinum_ore", "rolls": 1, - "conditions": [ - { - "condition": "minecraft:survives_explosion" - } - ], "entries": [ { - "type": "minecraft:item", - "name": "basemetals:platinum_ore", - "functions": [] + "type": "minecraft:alternatives", + "children": [ + { + "type": "minecraft:item", + "name": "basemetals:platinum_ore", + "conditions": [ + { + "condition": "minecraft:match_tool", + "predicate": { + "enchantments": [ + { + "enchantment": "minecraft:silk_touch", + "levels": { + "min": 1 + } + } + ] + } + } + ] + }, + { + "type": "minecraft:item", + "name": "basemetals:platinum_raw", + "functions": [ + { + "function": "minecraft:apply_bonus", + "enchantment": "minecraft:fortune", + "formula": "minecraft:ore_drops" + }, + { + "function": "minecraft:explosion_decay" + } + ] + } + ] } ] } diff --git a/src/generated/resources/data/basemetals/loot_tables/blocks/silver_ore.json b/src/generated/resources/data/basemetals/loot_tables/blocks/silver_ore.json index 4d1114795..5d850496f 100644 --- a/src/generated/resources/data/basemetals/loot_tables/blocks/silver_ore.json +++ b/src/generated/resources/data/basemetals/loot_tables/blocks/silver_ore.json @@ -4,16 +4,44 @@ { "name": "basemetals_silver_ore", "rolls": 1, - "conditions": [ - { - "condition": "minecraft:survives_explosion" - } - ], "entries": [ { - "type": "minecraft:item", - "name": "basemetals:silver_ore", - "functions": [] + "type": "minecraft:alternatives", + "children": [ + { + "type": "minecraft:item", + "name": "basemetals:silver_ore", + "conditions": [ + { + "condition": "minecraft:match_tool", + "predicate": { + "enchantments": [ + { + "enchantment": "minecraft:silk_touch", + "levels": { + "min": 1 + } + } + ] + } + } + ] + }, + { + "type": "minecraft:item", + "name": "basemetals:silver_raw", + "functions": [ + { + "function": "minecraft:apply_bonus", + "enchantment": "minecraft:fortune", + "formula": "minecraft:ore_drops" + }, + { + "function": "minecraft:explosion_decay" + } + ] + } + ] } ] } diff --git a/src/generated/resources/data/basemetals/loot_tables/blocks/starsteel_ore.json b/src/generated/resources/data/basemetals/loot_tables/blocks/starsteel_ore.json index eb384c2fd..b9fb2d078 100644 --- a/src/generated/resources/data/basemetals/loot_tables/blocks/starsteel_ore.json +++ b/src/generated/resources/data/basemetals/loot_tables/blocks/starsteel_ore.json @@ -4,16 +4,44 @@ { "name": "basemetals_starsteel_ore", "rolls": 1, - "conditions": [ - { - "condition": "minecraft:survives_explosion" - } - ], "entries": [ { - "type": "minecraft:item", - "name": "basemetals:starsteel_ore", - "functions": [] + "type": "minecraft:alternatives", + "children": [ + { + "type": "minecraft:item", + "name": "basemetals:starsteel_ore", + "conditions": [ + { + "condition": "minecraft:match_tool", + "predicate": { + "enchantments": [ + { + "enchantment": "minecraft:silk_touch", + "levels": { + "min": 1 + } + } + ] + } + } + ] + }, + { + "type": "minecraft:item", + "name": "basemetals:starsteel_raw", + "functions": [ + { + "function": "minecraft:apply_bonus", + "enchantment": "minecraft:fortune", + "formula": "minecraft:ore_drops" + }, + { + "function": "minecraft:explosion_decay" + } + ] + } + ] } ] } diff --git a/src/generated/resources/data/basemetals/loot_tables/blocks/tin_ore.json b/src/generated/resources/data/basemetals/loot_tables/blocks/tin_ore.json index d73fbcf03..9da63e6f6 100644 --- a/src/generated/resources/data/basemetals/loot_tables/blocks/tin_ore.json +++ b/src/generated/resources/data/basemetals/loot_tables/blocks/tin_ore.json @@ -4,16 +4,44 @@ { "name": "basemetals_tin_ore", "rolls": 1, - "conditions": [ - { - "condition": "minecraft:survives_explosion" - } - ], "entries": [ { - "type": "minecraft:item", - "name": "basemetals:tin_ore", - "functions": [] + "type": "minecraft:alternatives", + "children": [ + { + "type": "minecraft:item", + "name": "basemetals:tin_ore", + "conditions": [ + { + "condition": "minecraft:match_tool", + "predicate": { + "enchantments": [ + { + "enchantment": "minecraft:silk_touch", + "levels": { + "min": 1 + } + } + ] + } + } + ] + }, + { + "type": "minecraft:item", + "name": "basemetals:tin_raw", + "functions": [ + { + "function": "minecraft:apply_bonus", + "enchantment": "minecraft:fortune", + "formula": "minecraft:ore_drops" + }, + { + "function": "minecraft:explosion_decay" + } + ] + } + ] } ] } diff --git a/src/generated/resources/data/basemetals/loot_tables/blocks/zinc_ore.json b/src/generated/resources/data/basemetals/loot_tables/blocks/zinc_ore.json index f32dd1d18..cff5bd828 100644 --- a/src/generated/resources/data/basemetals/loot_tables/blocks/zinc_ore.json +++ b/src/generated/resources/data/basemetals/loot_tables/blocks/zinc_ore.json @@ -4,16 +4,44 @@ { "name": "basemetals_zinc_ore", "rolls": 1, - "conditions": [ - { - "condition": "minecraft:survives_explosion" - } - ], "entries": [ { - "type": "minecraft:item", - "name": "basemetals:zinc_ore", - "functions": [] + "type": "minecraft:alternatives", + "children": [ + { + "type": "minecraft:item", + "name": "basemetals:zinc_ore", + "conditions": [ + { + "condition": "minecraft:match_tool", + "predicate": { + "enchantments": [ + { + "enchantment": "minecraft:silk_touch", + "levels": { + "min": 1 + } + } + ] + } + } + ] + }, + { + "type": "minecraft:item", + "name": "basemetals:zinc_raw", + "functions": [ + { + "function": "minecraft:apply_bonus", + "enchantment": "minecraft:fortune", + "formula": "minecraft:ore_drops" + }, + { + "function": "minecraft:explosion_decay" + } + ] + } + ] } ] } diff --git a/src/generated/resources/data/basemetals/recipes/adamantine_raw_blasting.json b/src/generated/resources/data/basemetals/recipes/adamantine_raw_blasting.json new file mode 100644 index 000000000..85f9ba35f --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/adamantine_raw_blasting.json @@ -0,0 +1,9 @@ +{ + "type": "minecraft:blasting", + "ingredient": { + "tag": "forge:raw_materials/adamantine" + }, + "result": "basemetals:adamantine_ingot", + "experience": 0.1, + "cookingtime": 100 +} diff --git a/src/generated/resources/data/basemetals/recipes/adamantine_raw_crushing.json b/src/generated/resources/data/basemetals/recipes/adamantine_raw_crushing.json new file mode 100644 index 000000000..8793d4cbc --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/adamantine_raw_crushing.json @@ -0,0 +1,10 @@ +{ + "type": "basemetals:crushing", + "ingredient": { + "tag": "forge:raw_materials/adamantine" + }, + "result": { + "item": "basemetals:adamantine_powder", + "count": 1 + } +} diff --git a/src/generated/resources/data/basemetals/recipes/adamantine_raw_smelting.json b/src/generated/resources/data/basemetals/recipes/adamantine_raw_smelting.json new file mode 100644 index 000000000..633c9710e --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/adamantine_raw_smelting.json @@ -0,0 +1,9 @@ +{ + "type": "minecraft:smelting", + "ingredient": { + "tag": "forge:raw_materials/adamantine" + }, + "result": "basemetals:adamantine_ingot", + "experience": 0.1, + "cookingtime": 200 +} diff --git a/src/generated/resources/data/basemetals/recipes/antimony_raw_blasting.json b/src/generated/resources/data/basemetals/recipes/antimony_raw_blasting.json new file mode 100644 index 000000000..3fc39a6e8 --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/antimony_raw_blasting.json @@ -0,0 +1,9 @@ +{ + "type": "minecraft:blasting", + "ingredient": { + "tag": "forge:raw_materials/antimony" + }, + "result": "basemetals:antimony_ingot", + "experience": 0.1, + "cookingtime": 100 +} diff --git a/src/generated/resources/data/basemetals/recipes/antimony_raw_crushing.json b/src/generated/resources/data/basemetals/recipes/antimony_raw_crushing.json new file mode 100644 index 000000000..6d1a1fd61 --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/antimony_raw_crushing.json @@ -0,0 +1,10 @@ +{ + "type": "basemetals:crushing", + "ingredient": { + "tag": "forge:raw_materials/antimony" + }, + "result": { + "item": "basemetals:antimony_powder", + "count": 1 + } +} diff --git a/src/generated/resources/data/basemetals/recipes/antimony_raw_smelting.json b/src/generated/resources/data/basemetals/recipes/antimony_raw_smelting.json new file mode 100644 index 000000000..4cf6e4e6c --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/antimony_raw_smelting.json @@ -0,0 +1,9 @@ +{ + "type": "minecraft:smelting", + "ingredient": { + "tag": "forge:raw_materials/antimony" + }, + "result": "basemetals:antimony_ingot", + "experience": 0.1, + "cookingtime": 200 +} diff --git a/src/generated/resources/data/basemetals/recipes/bismuth_raw_blasting.json b/src/generated/resources/data/basemetals/recipes/bismuth_raw_blasting.json new file mode 100644 index 000000000..0e1e53c78 --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/bismuth_raw_blasting.json @@ -0,0 +1,9 @@ +{ + "type": "minecraft:blasting", + "ingredient": { + "tag": "forge:raw_materials/bismuth" + }, + "result": "basemetals:bismuth_ingot", + "experience": 0.1, + "cookingtime": 100 +} diff --git a/src/generated/resources/data/basemetals/recipes/bismuth_raw_crushing.json b/src/generated/resources/data/basemetals/recipes/bismuth_raw_crushing.json new file mode 100644 index 000000000..07dcbaf37 --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/bismuth_raw_crushing.json @@ -0,0 +1,10 @@ +{ + "type": "basemetals:crushing", + "ingredient": { + "tag": "forge:raw_materials/bismuth" + }, + "result": { + "item": "basemetals:bismuth_powder", + "count": 1 + } +} diff --git a/src/generated/resources/data/basemetals/recipes/bismuth_raw_smelting.json b/src/generated/resources/data/basemetals/recipes/bismuth_raw_smelting.json new file mode 100644 index 000000000..5b9311170 --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/bismuth_raw_smelting.json @@ -0,0 +1,9 @@ +{ + "type": "minecraft:smelting", + "ingredient": { + "tag": "forge:raw_materials/bismuth" + }, + "result": "basemetals:bismuth_ingot", + "experience": 0.1, + "cookingtime": 200 +} diff --git a/src/generated/resources/data/basemetals/recipes/coldiron_raw_blasting.json b/src/generated/resources/data/basemetals/recipes/coldiron_raw_blasting.json new file mode 100644 index 000000000..f7a9bea00 --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/coldiron_raw_blasting.json @@ -0,0 +1,9 @@ +{ + "type": "minecraft:blasting", + "ingredient": { + "tag": "forge:raw_materials/coldiron" + }, + "result": "basemetals:coldiron_ingot", + "experience": 0.7, + "cookingtime": 100 +} diff --git a/src/generated/resources/data/basemetals/recipes/coldiron_raw_crushing.json b/src/generated/resources/data/basemetals/recipes/coldiron_raw_crushing.json new file mode 100644 index 000000000..276691aba --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/coldiron_raw_crushing.json @@ -0,0 +1,10 @@ +{ + "type": "basemetals:crushing", + "ingredient": { + "tag": "forge:raw_materials/coldiron" + }, + "result": { + "item": "basemetals:coldiron_powder", + "count": 1 + } +} diff --git a/src/generated/resources/data/basemetals/recipes/coldiron_raw_smelting.json b/src/generated/resources/data/basemetals/recipes/coldiron_raw_smelting.json new file mode 100644 index 000000000..2fb377202 --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/coldiron_raw_smelting.json @@ -0,0 +1,9 @@ +{ + "type": "minecraft:smelting", + "ingredient": { + "tag": "forge:raw_materials/coldiron" + }, + "result": "basemetals:coldiron_ingot", + "experience": 0.7, + "cookingtime": 200 +} diff --git a/src/generated/resources/data/basemetals/recipes/copper_raw_crushing.json b/src/generated/resources/data/basemetals/recipes/copper_raw_crushing.json new file mode 100644 index 000000000..16b7e0b80 --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/copper_raw_crushing.json @@ -0,0 +1,10 @@ +{ + "type": "basemetals:crushing", + "ingredient": { + "tag": "forge:raw_materials/copper" + }, + "result": { + "item": "basemetals:copper_powder", + "count": 1 + } +} diff --git a/src/generated/resources/data/basemetals/recipes/gold_raw_crushing.json b/src/generated/resources/data/basemetals/recipes/gold_raw_crushing.json new file mode 100644 index 000000000..dad351e33 --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/gold_raw_crushing.json @@ -0,0 +1,10 @@ +{ + "type": "basemetals:crushing", + "ingredient": { + "tag": "forge:raw_materials/gold" + }, + "result": { + "item": "basemetals:gold_powder", + "count": 1 + } +} diff --git a/src/generated/resources/data/basemetals/recipes/iron_raw_crushing.json b/src/generated/resources/data/basemetals/recipes/iron_raw_crushing.json new file mode 100644 index 000000000..84a9fee4a --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/iron_raw_crushing.json @@ -0,0 +1,10 @@ +{ + "type": "basemetals:crushing", + "ingredient": { + "tag": "forge:raw_materials/iron" + }, + "result": { + "item": "basemetals:iron_powder", + "count": 1 + } +} diff --git a/src/generated/resources/data/basemetals/recipes/lead_raw_blasting.json b/src/generated/resources/data/basemetals/recipes/lead_raw_blasting.json new file mode 100644 index 000000000..c860d49ca --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/lead_raw_blasting.json @@ -0,0 +1,9 @@ +{ + "type": "minecraft:blasting", + "ingredient": { + "tag": "forge:raw_materials/lead" + }, + "result": "basemetals:lead_ingot", + "experience": 0.1, + "cookingtime": 100 +} diff --git a/src/generated/resources/data/basemetals/recipes/lead_raw_crushing.json b/src/generated/resources/data/basemetals/recipes/lead_raw_crushing.json new file mode 100644 index 000000000..547d48ee3 --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/lead_raw_crushing.json @@ -0,0 +1,10 @@ +{ + "type": "basemetals:crushing", + "ingredient": { + "tag": "forge:raw_materials/lead" + }, + "result": { + "item": "basemetals:lead_powder", + "count": 1 + } +} diff --git a/src/generated/resources/data/basemetals/recipes/lead_raw_smelting.json b/src/generated/resources/data/basemetals/recipes/lead_raw_smelting.json new file mode 100644 index 000000000..bf034b1c2 --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/lead_raw_smelting.json @@ -0,0 +1,9 @@ +{ + "type": "minecraft:smelting", + "ingredient": { + "tag": "forge:raw_materials/lead" + }, + "result": "basemetals:lead_ingot", + "experience": 0.1, + "cookingtime": 200 +} diff --git a/src/generated/resources/data/basemetals/recipes/mercury_raw_blasting.json b/src/generated/resources/data/basemetals/recipes/mercury_raw_blasting.json new file mode 100644 index 000000000..c8d2aadc5 --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/mercury_raw_blasting.json @@ -0,0 +1,9 @@ +{ + "type": "minecraft:blasting", + "ingredient": { + "tag": "forge:raw_materials/mercury" + }, + "result": "basemetals:mercury_ingot", + "experience": 0.1, + "cookingtime": 100 +} diff --git a/src/generated/resources/data/basemetals/recipes/mercury_raw_crushing.json b/src/generated/resources/data/basemetals/recipes/mercury_raw_crushing.json new file mode 100644 index 000000000..d052f0d9e --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/mercury_raw_crushing.json @@ -0,0 +1,10 @@ +{ + "type": "basemetals:crushing", + "ingredient": { + "tag": "forge:raw_materials/mercury" + }, + "result": { + "item": "basemetals:mercury_powder", + "count": 1 + } +} diff --git a/src/generated/resources/data/basemetals/recipes/mercury_raw_smelting.json b/src/generated/resources/data/basemetals/recipes/mercury_raw_smelting.json new file mode 100644 index 000000000..6ccb2df59 --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/mercury_raw_smelting.json @@ -0,0 +1,9 @@ +{ + "type": "minecraft:smelting", + "ingredient": { + "tag": "forge:raw_materials/mercury" + }, + "result": "basemetals:mercury_ingot", + "experience": 0.1, + "cookingtime": 200 +} diff --git a/src/generated/resources/data/basemetals/recipes/nickel_raw_blasting.json b/src/generated/resources/data/basemetals/recipes/nickel_raw_blasting.json new file mode 100644 index 000000000..b1e3af74b --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/nickel_raw_blasting.json @@ -0,0 +1,9 @@ +{ + "type": "minecraft:blasting", + "ingredient": { + "tag": "forge:raw_materials/nickel" + }, + "result": "basemetals:nickel_ingot", + "experience": 0.7, + "cookingtime": 100 +} diff --git a/src/generated/resources/data/basemetals/recipes/nickel_raw_crushing.json b/src/generated/resources/data/basemetals/recipes/nickel_raw_crushing.json new file mode 100644 index 000000000..ec168f233 --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/nickel_raw_crushing.json @@ -0,0 +1,10 @@ +{ + "type": "basemetals:crushing", + "ingredient": { + "tag": "forge:raw_materials/nickel" + }, + "result": { + "item": "basemetals:nickel_powder", + "count": 1 + } +} diff --git a/src/generated/resources/data/basemetals/recipes/nickel_raw_smelting.json b/src/generated/resources/data/basemetals/recipes/nickel_raw_smelting.json new file mode 100644 index 000000000..84e94e08a --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/nickel_raw_smelting.json @@ -0,0 +1,9 @@ +{ + "type": "minecraft:smelting", + "ingredient": { + "tag": "forge:raw_materials/nickel" + }, + "result": "basemetals:nickel_ingot", + "experience": 0.7, + "cookingtime": 200 +} diff --git a/src/generated/resources/data/basemetals/recipes/platinum_raw_blasting.json b/src/generated/resources/data/basemetals/recipes/platinum_raw_blasting.json new file mode 100644 index 000000000..0989ea735 --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/platinum_raw_blasting.json @@ -0,0 +1,9 @@ +{ + "type": "minecraft:blasting", + "ingredient": { + "tag": "forge:raw_materials/platinum" + }, + "result": "basemetals:platinum_ingot", + "experience": 1.5, + "cookingtime": 100 +} diff --git a/src/generated/resources/data/basemetals/recipes/platinum_raw_crushing.json b/src/generated/resources/data/basemetals/recipes/platinum_raw_crushing.json new file mode 100644 index 000000000..cd7c8795f --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/platinum_raw_crushing.json @@ -0,0 +1,10 @@ +{ + "type": "basemetals:crushing", + "ingredient": { + "tag": "forge:raw_materials/platinum" + }, + "result": { + "item": "basemetals:platinum_powder", + "count": 1 + } +} diff --git a/src/generated/resources/data/basemetals/recipes/platinum_raw_smelting.json b/src/generated/resources/data/basemetals/recipes/platinum_raw_smelting.json new file mode 100644 index 000000000..a9b25ac34 --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/platinum_raw_smelting.json @@ -0,0 +1,9 @@ +{ + "type": "minecraft:smelting", + "ingredient": { + "tag": "forge:raw_materials/platinum" + }, + "result": "basemetals:platinum_ingot", + "experience": 1.5, + "cookingtime": 200 +} diff --git a/src/generated/resources/data/basemetals/recipes/silver_raw_blasting.json b/src/generated/resources/data/basemetals/recipes/silver_raw_blasting.json new file mode 100644 index 000000000..7e4b047b4 --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/silver_raw_blasting.json @@ -0,0 +1,9 @@ +{ + "type": "minecraft:blasting", + "ingredient": { + "tag": "forge:raw_materials/silver" + }, + "result": "basemetals:silver_ingot", + "experience": 0.6, + "cookingtime": 100 +} diff --git a/src/generated/resources/data/basemetals/recipes/silver_raw_crushing.json b/src/generated/resources/data/basemetals/recipes/silver_raw_crushing.json new file mode 100644 index 000000000..7ccc79c08 --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/silver_raw_crushing.json @@ -0,0 +1,10 @@ +{ + "type": "basemetals:crushing", + "ingredient": { + "tag": "forge:raw_materials/silver" + }, + "result": { + "item": "basemetals:silver_powder", + "count": 1 + } +} diff --git a/src/generated/resources/data/basemetals/recipes/silver_raw_smelting.json b/src/generated/resources/data/basemetals/recipes/silver_raw_smelting.json new file mode 100644 index 000000000..3d71702c9 --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/silver_raw_smelting.json @@ -0,0 +1,9 @@ +{ + "type": "minecraft:smelting", + "ingredient": { + "tag": "forge:raw_materials/silver" + }, + "result": "basemetals:silver_ingot", + "experience": 0.6, + "cookingtime": 200 +} diff --git a/src/generated/resources/data/basemetals/recipes/starsteel_raw_blasting.json b/src/generated/resources/data/basemetals/recipes/starsteel_raw_blasting.json new file mode 100644 index 000000000..84882a524 --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/starsteel_raw_blasting.json @@ -0,0 +1,9 @@ +{ + "type": "minecraft:blasting", + "ingredient": { + "tag": "forge:raw_materials/starsteel" + }, + "result": "basemetals:starsteel_ingot", + "experience": 1.2, + "cookingtime": 100 +} diff --git a/src/generated/resources/data/basemetals/recipes/starsteel_raw_crushing.json b/src/generated/resources/data/basemetals/recipes/starsteel_raw_crushing.json new file mode 100644 index 000000000..d025eed0b --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/starsteel_raw_crushing.json @@ -0,0 +1,10 @@ +{ + "type": "basemetals:crushing", + "ingredient": { + "tag": "forge:raw_materials/starsteel" + }, + "result": { + "item": "basemetals:starsteel_powder", + "count": 1 + } +} diff --git a/src/generated/resources/data/basemetals/recipes/starsteel_raw_smelting.json b/src/generated/resources/data/basemetals/recipes/starsteel_raw_smelting.json new file mode 100644 index 000000000..489be60b1 --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/starsteel_raw_smelting.json @@ -0,0 +1,9 @@ +{ + "type": "minecraft:smelting", + "ingredient": { + "tag": "forge:raw_materials/starsteel" + }, + "result": "basemetals:starsteel_ingot", + "experience": 1.2, + "cookingtime": 200 +} diff --git a/src/generated/resources/data/basemetals/recipes/tin_raw_blasting.json b/src/generated/resources/data/basemetals/recipes/tin_raw_blasting.json new file mode 100644 index 000000000..4326ccc4d --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/tin_raw_blasting.json @@ -0,0 +1,9 @@ +{ + "type": "minecraft:blasting", + "ingredient": { + "tag": "forge:raw_materials/tin" + }, + "result": "basemetals:tin_ingot", + "experience": 0.2, + "cookingtime": 100 +} diff --git a/src/generated/resources/data/basemetals/recipes/tin_raw_crushing.json b/src/generated/resources/data/basemetals/recipes/tin_raw_crushing.json new file mode 100644 index 000000000..b61cf0477 --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/tin_raw_crushing.json @@ -0,0 +1,10 @@ +{ + "type": "basemetals:crushing", + "ingredient": { + "tag": "forge:raw_materials/tin" + }, + "result": { + "item": "basemetals:tin_powder", + "count": 1 + } +} diff --git a/src/generated/resources/data/basemetals/recipes/tin_raw_smelting.json b/src/generated/resources/data/basemetals/recipes/tin_raw_smelting.json new file mode 100644 index 000000000..ccd3c982c --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/tin_raw_smelting.json @@ -0,0 +1,9 @@ +{ + "type": "minecraft:smelting", + "ingredient": { + "tag": "forge:raw_materials/tin" + }, + "result": "basemetals:tin_ingot", + "experience": 0.2, + "cookingtime": 200 +} diff --git a/src/generated/resources/data/basemetals/recipes/zinc_raw_blasting.json b/src/generated/resources/data/basemetals/recipes/zinc_raw_blasting.json new file mode 100644 index 000000000..031473fc4 --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/zinc_raw_blasting.json @@ -0,0 +1,9 @@ +{ + "type": "minecraft:blasting", + "ingredient": { + "tag": "forge:raw_materials/zinc" + }, + "result": "basemetals:zinc_ingot", + "experience": 0.1, + "cookingtime": 100 +} diff --git a/src/generated/resources/data/basemetals/recipes/zinc_raw_crushing.json b/src/generated/resources/data/basemetals/recipes/zinc_raw_crushing.json new file mode 100644 index 000000000..978fedf4b --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/zinc_raw_crushing.json @@ -0,0 +1,10 @@ +{ + "type": "basemetals:crushing", + "ingredient": { + "tag": "forge:raw_materials/zinc" + }, + "result": { + "item": "basemetals:zinc_powder", + "count": 1 + } +} diff --git a/src/generated/resources/data/basemetals/recipes/zinc_raw_smelting.json b/src/generated/resources/data/basemetals/recipes/zinc_raw_smelting.json new file mode 100644 index 000000000..f5739ef15 --- /dev/null +++ b/src/generated/resources/data/basemetals/recipes/zinc_raw_smelting.json @@ -0,0 +1,9 @@ +{ + "type": "minecraft:smelting", + "ingredient": { + "tag": "forge:raw_materials/zinc" + }, + "result": "basemetals:zinc_ingot", + "experience": 0.1, + "cookingtime": 200 +} diff --git a/src/generated/resources/data/basemetals/registry_manifest.json b/src/generated/resources/data/basemetals/registry_manifest.json index 20d759f94..b8d278538 100644 --- a/src/generated/resources/data/basemetals/registry_manifest.json +++ b/src/generated/resources/data/basemetals/registry_manifest.json @@ -1,6 +1,6 @@ { "format": 1, - "source": "Base Metals 1.16.5 catalogue", + "source": "Base Metals 1.17.1 catalogue", "blocks": [ "basemetals:adamantine_block", "basemetals:adamantine_plate", @@ -364,1121 +364,1133 @@ "basemetals:stone" ], "items": [ - "basemetals:adamantine_block", - "basemetals:adamantine_plate", - "basemetals:adamantine_bars", - "basemetals:adamantine_door", - "basemetals:adamantine_trapdoor", - "basemetals:adamantine_button", - "basemetals:adamantine_slab", - "basemetals:adamantine_lever", - "basemetals:adamantine_pressure_plate", - "basemetals:adamantine_stairs", - "basemetals:adamantine_wall", - "basemetals:adamantine_ore", - "basemetals:adamantine_ingot", - "basemetals:adamantine_nugget", - "basemetals:adamantine_powder", - "basemetals:adamantine_smallpowder", - "basemetals:adamantine_pickaxe", - "basemetals:adamantine_axe", - "basemetals:adamantine_shovel", - "basemetals:adamantine_hoe", - "basemetals:adamantine_sword", - "basemetals:adamantine_crackhammer", - "basemetals:adamantine_scythe", - "basemetals:adamantine_shears", - "basemetals:adamantine_fishing_rod", - "basemetals:adamantine_bow", - "basemetals:adamantine_crossbow", - "basemetals:adamantine_shield", + "basemetals:adamantine", + "basemetals:adamantine_anvil", "basemetals:adamantine_arrow", + "basemetals:adamantine_axe", + "basemetals:adamantine_bars", + "basemetals:adamantine_block", "basemetals:adamantine_bolt", - "basemetals:adamantine_rod", - "basemetals:adamantine_gear", - "basemetals:adamantine_horse_armor", - "basemetals:adamantine_helmet", - "basemetals:adamantine_chestplate", - "basemetals:adamantine_leggings", "basemetals:adamantine_boots", + "basemetals:adamantine_bow", + "basemetals:adamantine_bucket", + "basemetals:adamantine_button", "basemetals:adamantine_casing", - "basemetals:adamantine_dense_plate", + "basemetals:adamantine_chestplate", + "basemetals:adamantine_clump", + "basemetals:adamantine_crackhammer", + "basemetals:adamantine_crossbow", "basemetals:adamantine_crushed", "basemetals:adamantine_crushed_purified", "basemetals:adamantine_crystal", - "basemetals:adamantine_shard", - "basemetals:adamantine_clump", + "basemetals:adamantine_dense_plate", + "basemetals:adamantine_door", + "basemetals:adamantine_fishing_rod", + "basemetals:adamantine_gear", + "basemetals:adamantine_helmet", + "basemetals:adamantine_hoe", + "basemetals:adamantine_horse_armor", + "basemetals:adamantine_ingot", + "basemetals:adamantine_leggings", + "basemetals:adamantine_lever", + "basemetals:adamantine_nugget", + "basemetals:adamantine_ore", + "basemetals:adamantine_pickaxe", + "basemetals:adamantine_plate", + "basemetals:adamantine_powder", "basemetals:adamantine_powder_dirty", - "basemetals:antimony_block", - "basemetals:antimony_plate", - "basemetals:antimony_bars", - "basemetals:antimony_door", - "basemetals:antimony_trapdoor", - "basemetals:antimony_button", - "basemetals:antimony_slab", - "basemetals:antimony_lever", - "basemetals:antimony_pressure_plate", - "basemetals:antimony_stairs", - "basemetals:antimony_wall", - "basemetals:antimony_ore", - "basemetals:antimony_ingot", - "basemetals:antimony_nugget", - "basemetals:antimony_powder", - "basemetals:antimony_smallpowder", - "basemetals:antimony_pickaxe", - "basemetals:antimony_axe", - "basemetals:antimony_shovel", - "basemetals:antimony_hoe", - "basemetals:antimony_sword", - "basemetals:antimony_crackhammer", - "basemetals:antimony_scythe", - "basemetals:antimony_shears", - "basemetals:antimony_fishing_rod", - "basemetals:antimony_bow", - "basemetals:antimony_crossbow", - "basemetals:antimony_shield", + "basemetals:adamantine_pressure_plate", + "basemetals:adamantine_raw", + "basemetals:adamantine_rod", + "basemetals:adamantine_scythe", + "basemetals:adamantine_shard", + "basemetals:adamantine_shears", + "basemetals:adamantine_shield", + "basemetals:adamantine_shovel", + "basemetals:adamantine_slab", + "basemetals:adamantine_smallpowder", + "basemetals:adamantine_stairs", + "basemetals:adamantine_sword", + "basemetals:adamantine_trapdoor", + "basemetals:adamantine_wall", + "basemetals:antimony", "basemetals:antimony_arrow", + "basemetals:antimony_axe", + "basemetals:antimony_bars", + "basemetals:antimony_block", "basemetals:antimony_bolt", - "basemetals:antimony_rod", - "basemetals:antimony_gear", - "basemetals:antimony_horse_armor", - "basemetals:antimony_helmet", - "basemetals:antimony_chestplate", - "basemetals:antimony_leggings", "basemetals:antimony_boots", + "basemetals:antimony_bow", + "basemetals:antimony_bucket", + "basemetals:antimony_button", "basemetals:antimony_casing", - "basemetals:antimony_dense_plate", + "basemetals:antimony_chestplate", + "basemetals:antimony_clump", + "basemetals:antimony_crackhammer", + "basemetals:antimony_crossbow", "basemetals:antimony_crushed", "basemetals:antimony_crushed_purified", "basemetals:antimony_crystal", - "basemetals:antimony_shard", - "basemetals:antimony_clump", + "basemetals:antimony_dense_plate", + "basemetals:antimony_door", + "basemetals:antimony_fishing_rod", + "basemetals:antimony_gear", + "basemetals:antimony_helmet", + "basemetals:antimony_hoe", + "basemetals:antimony_horse_armor", + "basemetals:antimony_ingot", + "basemetals:antimony_leggings", + "basemetals:antimony_lever", + "basemetals:antimony_nugget", + "basemetals:antimony_ore", + "basemetals:antimony_pickaxe", + "basemetals:antimony_plate", + "basemetals:antimony_powder", "basemetals:antimony_powder_dirty", - "basemetals:aquarium_block", - "basemetals:aquarium_plate", + "basemetals:antimony_pressure_plate", + "basemetals:antimony_raw", + "basemetals:antimony_rod", + "basemetals:antimony_scythe", + "basemetals:antimony_shard", + "basemetals:antimony_shears", + "basemetals:antimony_shield", + "basemetals:antimony_shovel", + "basemetals:antimony_slab", + "basemetals:antimony_smallpowder", + "basemetals:antimony_stairs", + "basemetals:antimony_sword", + "basemetals:antimony_trapdoor", + "basemetals:antimony_wall", + "basemetals:aquarium", + "basemetals:aquarium_arrow", + "basemetals:aquarium_axe", "basemetals:aquarium_bars", - "basemetals:aquarium_door", - "basemetals:aquarium_trapdoor", + "basemetals:aquarium_blend", + "basemetals:aquarium_block", + "basemetals:aquarium_bolt", + "basemetals:aquarium_boots", + "basemetals:aquarium_bow", + "basemetals:aquarium_bucket", "basemetals:aquarium_button", - "basemetals:aquarium_slab", - "basemetals:aquarium_lever", - "basemetals:aquarium_pressure_plate", - "basemetals:aquarium_stairs", - "basemetals:aquarium_wall", + "basemetals:aquarium_chestplate", + "basemetals:aquarium_crackhammer", + "basemetals:aquarium_crossbow", + "basemetals:aquarium_door", + "basemetals:aquarium_fishing_rod", + "basemetals:aquarium_gear", + "basemetals:aquarium_helmet", + "basemetals:aquarium_hoe", + "basemetals:aquarium_horse_armor", "basemetals:aquarium_ingot", + "basemetals:aquarium_leggings", + "basemetals:aquarium_lever", "basemetals:aquarium_nugget", - "basemetals:aquarium_powder", - "basemetals:aquarium_smallpowder", - "basemetals:aquarium_blend", - "basemetals:aquarium_smallblend", "basemetals:aquarium_pickaxe", - "basemetals:aquarium_axe", - "basemetals:aquarium_shovel", - "basemetals:aquarium_hoe", - "basemetals:aquarium_sword", - "basemetals:aquarium_crackhammer", + "basemetals:aquarium_plate", + "basemetals:aquarium_powder", + "basemetals:aquarium_pressure_plate", + "basemetals:aquarium_rod", "basemetals:aquarium_scythe", "basemetals:aquarium_shears", - "basemetals:aquarium_fishing_rod", - "basemetals:aquarium_bow", - "basemetals:aquarium_crossbow", "basemetals:aquarium_shield", - "basemetals:aquarium_arrow", - "basemetals:aquarium_bolt", - "basemetals:aquarium_rod", - "basemetals:aquarium_gear", - "basemetals:aquarium_horse_armor", - "basemetals:aquarium_helmet", - "basemetals:aquarium_chestplate", - "basemetals:aquarium_leggings", - "basemetals:aquarium_boots", - "basemetals:bismuth_block", - "basemetals:bismuth_plate", + "basemetals:aquarium_shovel", + "basemetals:aquarium_slab", + "basemetals:aquarium_smallblend", + "basemetals:aquarium_smallpowder", + "basemetals:aquarium_stairs", + "basemetals:aquarium_sword", + "basemetals:aquarium_trapdoor", + "basemetals:aquarium_wall", + "basemetals:bismuth", + "basemetals:bismuth_arrow", + "basemetals:bismuth_axe", "basemetals:bismuth_bars", - "basemetals:bismuth_door", - "basemetals:bismuth_trapdoor", + "basemetals:bismuth_block", + "basemetals:bismuth_bolt", + "basemetals:bismuth_boots", + "basemetals:bismuth_bow", + "basemetals:bismuth_bucket", "basemetals:bismuth_button", - "basemetals:bismuth_slab", - "basemetals:bismuth_lever", - "basemetals:bismuth_pressure_plate", - "basemetals:bismuth_stairs", - "basemetals:bismuth_wall", - "basemetals:bismuth_ore", + "basemetals:bismuth_casing", + "basemetals:bismuth_chestplate", + "basemetals:bismuth_clump", + "basemetals:bismuth_crackhammer", + "basemetals:bismuth_crossbow", + "basemetals:bismuth_crushed", + "basemetals:bismuth_crushed_purified", + "basemetals:bismuth_crystal", + "basemetals:bismuth_dense_plate", + "basemetals:bismuth_door", + "basemetals:bismuth_fishing_rod", + "basemetals:bismuth_gear", + "basemetals:bismuth_helmet", + "basemetals:bismuth_hoe", + "basemetals:bismuth_horse_armor", "basemetals:bismuth_ingot", + "basemetals:bismuth_leggings", + "basemetals:bismuth_lever", "basemetals:bismuth_nugget", - "basemetals:bismuth_powder", - "basemetals:bismuth_smallpowder", + "basemetals:bismuth_ore", "basemetals:bismuth_pickaxe", - "basemetals:bismuth_axe", - "basemetals:bismuth_shovel", - "basemetals:bismuth_hoe", - "basemetals:bismuth_sword", - "basemetals:bismuth_crackhammer", + "basemetals:bismuth_plate", + "basemetals:bismuth_powder", + "basemetals:bismuth_powder_dirty", + "basemetals:bismuth_pressure_plate", + "basemetals:bismuth_raw", + "basemetals:bismuth_rod", "basemetals:bismuth_scythe", + "basemetals:bismuth_shard", "basemetals:bismuth_shears", - "basemetals:bismuth_fishing_rod", - "basemetals:bismuth_bow", - "basemetals:bismuth_crossbow", "basemetals:bismuth_shield", - "basemetals:bismuth_arrow", - "basemetals:bismuth_bolt", - "basemetals:bismuth_rod", - "basemetals:bismuth_gear", - "basemetals:bismuth_horse_armor", - "basemetals:bismuth_helmet", - "basemetals:bismuth_chestplate", - "basemetals:bismuth_leggings", - "basemetals:bismuth_boots", - "basemetals:bismuth_casing", - "basemetals:bismuth_dense_plate", - "basemetals:bismuth_crushed", - "basemetals:bismuth_crushed_purified", - "basemetals:bismuth_crystal", - "basemetals:bismuth_shard", - "basemetals:bismuth_clump", - "basemetals:bismuth_powder_dirty", - "basemetals:brass_block", - "basemetals:brass_plate", + "basemetals:bismuth_shovel", + "basemetals:bismuth_slab", + "basemetals:bismuth_smallpowder", + "basemetals:bismuth_stairs", + "basemetals:bismuth_sword", + "basemetals:bismuth_trapdoor", + "basemetals:bismuth_wall", + "basemetals:brass", + "basemetals:brass_arrow", + "basemetals:brass_axe", "basemetals:brass_bars", - "basemetals:brass_door", - "basemetals:brass_trapdoor", + "basemetals:brass_blend", + "basemetals:brass_block", + "basemetals:brass_bolt", + "basemetals:brass_boots", + "basemetals:brass_bow", + "basemetals:brass_bucket", "basemetals:brass_button", - "basemetals:brass_slab", - "basemetals:brass_lever", - "basemetals:brass_pressure_plate", - "basemetals:brass_stairs", - "basemetals:brass_wall", + "basemetals:brass_chestplate", + "basemetals:brass_crackhammer", + "basemetals:brass_crossbow", + "basemetals:brass_door", + "basemetals:brass_fishing_rod", + "basemetals:brass_gear", + "basemetals:brass_helmet", + "basemetals:brass_hoe", + "basemetals:brass_horse_armor", "basemetals:brass_ingot", + "basemetals:brass_leggings", + "basemetals:brass_lever", "basemetals:brass_nugget", - "basemetals:brass_powder", - "basemetals:brass_smallpowder", - "basemetals:brass_blend", - "basemetals:brass_smallblend", "basemetals:brass_pickaxe", - "basemetals:brass_axe", - "basemetals:brass_shovel", - "basemetals:brass_hoe", - "basemetals:brass_sword", - "basemetals:brass_crackhammer", + "basemetals:brass_plate", + "basemetals:brass_powder", + "basemetals:brass_pressure_plate", + "basemetals:brass_rod", "basemetals:brass_scythe", "basemetals:brass_shears", - "basemetals:brass_fishing_rod", - "basemetals:brass_bow", - "basemetals:brass_crossbow", "basemetals:brass_shield", - "basemetals:brass_arrow", - "basemetals:brass_bolt", - "basemetals:brass_rod", - "basemetals:brass_gear", - "basemetals:brass_horse_armor", - "basemetals:brass_helmet", - "basemetals:brass_chestplate", - "basemetals:brass_leggings", - "basemetals:brass_boots", - "basemetals:bronze_block", - "basemetals:bronze_plate", + "basemetals:brass_shovel", + "basemetals:brass_slab", + "basemetals:brass_smallblend", + "basemetals:brass_smallpowder", + "basemetals:brass_stairs", + "basemetals:brass_sword", + "basemetals:brass_trapdoor", + "basemetals:brass_wall", + "basemetals:bronze", + "basemetals:bronze_arrow", + "basemetals:bronze_axe", "basemetals:bronze_bars", - "basemetals:bronze_door", - "basemetals:bronze_trapdoor", + "basemetals:bronze_blend", + "basemetals:bronze_block", + "basemetals:bronze_bolt", + "basemetals:bronze_boots", + "basemetals:bronze_bow", + "basemetals:bronze_bucket", "basemetals:bronze_button", - "basemetals:bronze_slab", - "basemetals:bronze_lever", - "basemetals:bronze_pressure_plate", - "basemetals:bronze_stairs", - "basemetals:bronze_wall", + "basemetals:bronze_chestplate", + "basemetals:bronze_crackhammer", + "basemetals:bronze_crossbow", + "basemetals:bronze_door", + "basemetals:bronze_fishing_rod", + "basemetals:bronze_gear", + "basemetals:bronze_helmet", + "basemetals:bronze_hoe", + "basemetals:bronze_horse_armor", "basemetals:bronze_ingot", + "basemetals:bronze_leggings", + "basemetals:bronze_lever", "basemetals:bronze_nugget", - "basemetals:bronze_powder", - "basemetals:bronze_smallpowder", - "basemetals:bronze_blend", - "basemetals:bronze_smallblend", "basemetals:bronze_pickaxe", - "basemetals:bronze_axe", - "basemetals:bronze_shovel", - "basemetals:bronze_hoe", - "basemetals:bronze_sword", - "basemetals:bronze_crackhammer", + "basemetals:bronze_plate", + "basemetals:bronze_powder", + "basemetals:bronze_pressure_plate", + "basemetals:bronze_rod", "basemetals:bronze_scythe", "basemetals:bronze_shears", - "basemetals:bronze_fishing_rod", - "basemetals:bronze_bow", - "basemetals:bronze_crossbow", "basemetals:bronze_shield", - "basemetals:bronze_arrow", - "basemetals:bronze_bolt", - "basemetals:bronze_rod", - "basemetals:bronze_gear", - "basemetals:bronze_horse_armor", - "basemetals:bronze_helmet", - "basemetals:bronze_chestplate", - "basemetals:bronze_leggings", - "basemetals:bronze_boots", - "basemetals:coldiron_block", - "basemetals:coldiron_plate", - "basemetals:coldiron_bars", - "basemetals:coldiron_door", - "basemetals:coldiron_trapdoor", - "basemetals:coldiron_button", - "basemetals:coldiron_slab", - "basemetals:coldiron_lever", - "basemetals:coldiron_pressure_plate", - "basemetals:coldiron_stairs", - "basemetals:coldiron_wall", - "basemetals:coldiron_ore", - "basemetals:coldiron_ingot", - "basemetals:coldiron_nugget", - "basemetals:coldiron_powder", - "basemetals:coldiron_smallpowder", - "basemetals:coldiron_pickaxe", - "basemetals:coldiron_axe", - "basemetals:coldiron_shovel", - "basemetals:coldiron_hoe", - "basemetals:coldiron_sword", - "basemetals:coldiron_crackhammer", - "basemetals:coldiron_scythe", - "basemetals:coldiron_shears", - "basemetals:coldiron_fishing_rod", - "basemetals:coldiron_bow", - "basemetals:coldiron_crossbow", - "basemetals:coldiron_shield", + "basemetals:bronze_shovel", + "basemetals:bronze_slab", + "basemetals:bronze_smallblend", + "basemetals:bronze_smallpowder", + "basemetals:bronze_stairs", + "basemetals:bronze_sword", + "basemetals:bronze_trapdoor", + "basemetals:bronze_wall", + "basemetals:charcoal", + "basemetals:charcoal_block", + "basemetals:charcoal_bucket", + "basemetals:charcoal_nugget", + "basemetals:charcoal_powder", + "basemetals:charcoal_smallpowder", + "basemetals:coal", + "basemetals:coal_bucket", + "basemetals:coal_nugget", + "basemetals:coal_powder", + "basemetals:coal_smallpowder", + "basemetals:coldiron", "basemetals:coldiron_arrow", + "basemetals:coldiron_axe", + "basemetals:coldiron_bars", + "basemetals:coldiron_block", "basemetals:coldiron_bolt", - "basemetals:coldiron_rod", - "basemetals:coldiron_gear", - "basemetals:coldiron_horse_armor", - "basemetals:coldiron_helmet", - "basemetals:coldiron_chestplate", - "basemetals:coldiron_leggings", "basemetals:coldiron_boots", + "basemetals:coldiron_bow", + "basemetals:coldiron_bucket", + "basemetals:coldiron_button", "basemetals:coldiron_casing", - "basemetals:coldiron_dense_plate", + "basemetals:coldiron_chestplate", + "basemetals:coldiron_clump", + "basemetals:coldiron_crackhammer", + "basemetals:coldiron_crossbow", "basemetals:coldiron_crushed", "basemetals:coldiron_crushed_purified", "basemetals:coldiron_crystal", - "basemetals:coldiron_shard", - "basemetals:coldiron_clump", + "basemetals:coldiron_dense_plate", + "basemetals:coldiron_door", + "basemetals:coldiron_fishing_rod", + "basemetals:coldiron_gear", + "basemetals:coldiron_helmet", + "basemetals:coldiron_hoe", + "basemetals:coldiron_horse_armor", + "basemetals:coldiron_ingot", + "basemetals:coldiron_leggings", + "basemetals:coldiron_lever", + "basemetals:coldiron_nugget", + "basemetals:coldiron_ore", + "basemetals:coldiron_pickaxe", + "basemetals:coldiron_plate", + "basemetals:coldiron_powder", "basemetals:coldiron_powder_dirty", - "basemetals:copper_block", - "basemetals:copper_plate", + "basemetals:coldiron_pressure_plate", + "basemetals:coldiron_raw", + "basemetals:coldiron_rod", + "basemetals:coldiron_scythe", + "basemetals:coldiron_shard", + "basemetals:coldiron_shears", + "basemetals:coldiron_shield", + "basemetals:coldiron_shovel", + "basemetals:coldiron_slab", + "basemetals:coldiron_smallpowder", + "basemetals:coldiron_stairs", + "basemetals:coldiron_sword", + "basemetals:coldiron_trapdoor", + "basemetals:coldiron_wall", + "basemetals:copper", + "basemetals:copper_arrow", + "basemetals:copper_axe", "basemetals:copper_bars", - "basemetals:copper_door", - "basemetals:copper_trapdoor", - "basemetals:copper_button", - "basemetals:copper_slab", - "basemetals:copper_lever", - "basemetals:copper_pressure_plate", - "basemetals:copper_stairs", - "basemetals:copper_wall", - "basemetals:copper_ore", + "basemetals:copper_block", + "basemetals:copper_bolt", + "basemetals:copper_boots", + "basemetals:copper_bow", + "basemetals:copper_bucket", + "basemetals:copper_button", + "basemetals:copper_chestplate", + "basemetals:copper_crackhammer", + "basemetals:copper_crossbow", + "basemetals:copper_door", + "basemetals:copper_fishing_rod", + "basemetals:copper_gear", + "basemetals:copper_helmet", + "basemetals:copper_hoe", + "basemetals:copper_horse_armor", "basemetals:copper_ingot", + "basemetals:copper_leggings", + "basemetals:copper_lever", "basemetals:copper_nugget", - "basemetals:copper_powder", - "basemetals:copper_smallpowder", + "basemetals:copper_ore", "basemetals:copper_pickaxe", - "basemetals:copper_axe", - "basemetals:copper_shovel", - "basemetals:copper_hoe", - "basemetals:copper_sword", - "basemetals:copper_crackhammer", + "basemetals:copper_plate", + "basemetals:copper_powder", + "basemetals:copper_pressure_plate", + "basemetals:copper_rod", "basemetals:copper_scythe", "basemetals:copper_shears", - "basemetals:copper_fishing_rod", - "basemetals:copper_bow", - "basemetals:copper_crossbow", "basemetals:copper_shield", - "basemetals:copper_arrow", - "basemetals:copper_bolt", - "basemetals:copper_rod", - "basemetals:copper_gear", - "basemetals:copper_horse_armor", - "basemetals:copper_helmet", - "basemetals:copper_chestplate", - "basemetals:copper_leggings", - "basemetals:copper_boots", - "basemetals:cupronickel_block", - "basemetals:cupronickel_plate", + "basemetals:copper_shovel", + "basemetals:copper_slab", + "basemetals:copper_smallpowder", + "basemetals:copper_stairs", + "basemetals:copper_sword", + "basemetals:copper_trapdoor", + "basemetals:copper_wall", + "basemetals:cupronickel", + "basemetals:cupronickel_arrow", + "basemetals:cupronickel_axe", "basemetals:cupronickel_bars", - "basemetals:cupronickel_door", - "basemetals:cupronickel_trapdoor", + "basemetals:cupronickel_blend", + "basemetals:cupronickel_block", + "basemetals:cupronickel_bolt", + "basemetals:cupronickel_boots", + "basemetals:cupronickel_bow", + "basemetals:cupronickel_bucket", "basemetals:cupronickel_button", - "basemetals:cupronickel_slab", - "basemetals:cupronickel_lever", - "basemetals:cupronickel_pressure_plate", - "basemetals:cupronickel_stairs", - "basemetals:cupronickel_wall", + "basemetals:cupronickel_chestplate", + "basemetals:cupronickel_crackhammer", + "basemetals:cupronickel_crossbow", + "basemetals:cupronickel_door", + "basemetals:cupronickel_fishing_rod", + "basemetals:cupronickel_gear", + "basemetals:cupronickel_helmet", + "basemetals:cupronickel_hoe", + "basemetals:cupronickel_horse_armor", "basemetals:cupronickel_ingot", + "basemetals:cupronickel_leggings", + "basemetals:cupronickel_lever", "basemetals:cupronickel_nugget", - "basemetals:cupronickel_powder", - "basemetals:cupronickel_smallpowder", - "basemetals:cupronickel_blend", - "basemetals:cupronickel_smallblend", "basemetals:cupronickel_pickaxe", - "basemetals:cupronickel_axe", - "basemetals:cupronickel_shovel", - "basemetals:cupronickel_hoe", - "basemetals:cupronickel_sword", - "basemetals:cupronickel_crackhammer", + "basemetals:cupronickel_plate", + "basemetals:cupronickel_powder", + "basemetals:cupronickel_pressure_plate", + "basemetals:cupronickel_rod", "basemetals:cupronickel_scythe", "basemetals:cupronickel_shears", - "basemetals:cupronickel_fishing_rod", - "basemetals:cupronickel_bow", - "basemetals:cupronickel_crossbow", "basemetals:cupronickel_shield", - "basemetals:cupronickel_arrow", - "basemetals:cupronickel_bolt", - "basemetals:cupronickel_rod", - "basemetals:cupronickel_gear", - "basemetals:cupronickel_horse_armor", - "basemetals:cupronickel_helmet", - "basemetals:cupronickel_chestplate", - "basemetals:cupronickel_leggings", - "basemetals:cupronickel_boots", - "basemetals:electrum_block", - "basemetals:electrum_plate", + "basemetals:cupronickel_shovel", + "basemetals:cupronickel_slab", + "basemetals:cupronickel_smallblend", + "basemetals:cupronickel_smallpowder", + "basemetals:cupronickel_stairs", + "basemetals:cupronickel_sword", + "basemetals:cupronickel_trapdoor", + "basemetals:cupronickel_wall", + "basemetals:diamond", + "basemetals:diamond_arrow", + "basemetals:diamond_bars", + "basemetals:diamond_blend", + "basemetals:diamond_bolt", + "basemetals:diamond_bow", + "basemetals:diamond_bucket", + "basemetals:diamond_button", + "basemetals:diamond_crackhammer", + "basemetals:diamond_crossbow", + "basemetals:diamond_door", + "basemetals:diamond_fishing_rod", + "basemetals:diamond_gear", + "basemetals:diamond_lever", + "basemetals:diamond_nugget", + "basemetals:diamond_powder", + "basemetals:diamond_pressure_plate", + "basemetals:diamond_rod", + "basemetals:diamond_scythe", + "basemetals:diamond_shears", + "basemetals:diamond_shield", + "basemetals:diamond_slab", + "basemetals:diamond_smallblend", + "basemetals:diamond_smallpowder", + "basemetals:diamond_stairs", + "basemetals:diamond_trapdoor", + "basemetals:diamond_wall", + "basemetals:electrum", + "basemetals:electrum_arrow", + "basemetals:electrum_axe", "basemetals:electrum_bars", - "basemetals:electrum_door", - "basemetals:electrum_trapdoor", - "basemetals:electrum_button", - "basemetals:electrum_slab", - "basemetals:electrum_lever", - "basemetals:electrum_pressure_plate", - "basemetals:electrum_stairs", - "basemetals:electrum_wall", - "basemetals:electrum_ingot", - "basemetals:electrum_nugget", - "basemetals:electrum_powder", - "basemetals:electrum_smallpowder", "basemetals:electrum_blend", - "basemetals:electrum_smallblend", - "basemetals:electrum_pickaxe", - "basemetals:electrum_axe", - "basemetals:electrum_shovel", - "basemetals:electrum_hoe", - "basemetals:electrum_sword", - "basemetals:electrum_crackhammer", - "basemetals:electrum_scythe", - "basemetals:electrum_shears", - "basemetals:electrum_fishing_rod", + "basemetals:electrum_block", + "basemetals:electrum_bolt", + "basemetals:electrum_boots", "basemetals:electrum_bow", + "basemetals:electrum_bucket", + "basemetals:electrum_button", + "basemetals:electrum_chestplate", + "basemetals:electrum_crackhammer", "basemetals:electrum_crossbow", - "basemetals:electrum_shield", - "basemetals:electrum_arrow", - "basemetals:electrum_bolt", - "basemetals:electrum_rod", + "basemetals:electrum_door", + "basemetals:electrum_fishing_rod", "basemetals:electrum_gear", - "basemetals:electrum_horse_armor", "basemetals:electrum_helmet", - "basemetals:electrum_chestplate", + "basemetals:electrum_hoe", + "basemetals:electrum_horse_armor", + "basemetals:electrum_ingot", "basemetals:electrum_leggings", - "basemetals:electrum_boots", - "basemetals:invar_block", - "basemetals:invar_plate", - "basemetals:invar_bars", - "basemetals:invar_door", - "basemetals:invar_trapdoor", - "basemetals:invar_button", - "basemetals:invar_slab", - "basemetals:invar_lever", - "basemetals:invar_pressure_plate", - "basemetals:invar_stairs", - "basemetals:invar_wall", - "basemetals:invar_ingot", - "basemetals:invar_nugget", - "basemetals:invar_powder", - "basemetals:invar_smallpowder", - "basemetals:invar_blend", - "basemetals:invar_smallblend", - "basemetals:invar_pickaxe", - "basemetals:invar_axe", - "basemetals:invar_shovel", - "basemetals:invar_hoe", - "basemetals:invar_sword", - "basemetals:invar_crackhammer", - "basemetals:invar_scythe", - "basemetals:invar_shears", - "basemetals:invar_fishing_rod", - "basemetals:invar_bow", - "basemetals:invar_crossbow", - "basemetals:invar_shield", - "basemetals:invar_arrow", - "basemetals:invar_bolt", - "basemetals:invar_rod", - "basemetals:invar_gear", - "basemetals:invar_horse_armor", - "basemetals:invar_helmet", - "basemetals:invar_chestplate", - "basemetals:invar_leggings", - "basemetals:invar_boots", - "basemetals:lead_block", - "basemetals:lead_plate", - "basemetals:lead_bars", - "basemetals:lead_door", - "basemetals:lead_trapdoor", - "basemetals:lead_button", - "basemetals:lead_slab", - "basemetals:lead_lever", - "basemetals:lead_pressure_plate", - "basemetals:lead_stairs", - "basemetals:lead_wall", - "basemetals:lead_ore", - "basemetals:lead_ingot", - "basemetals:lead_nugget", - "basemetals:lead_powder", - "basemetals:lead_smallpowder", - "basemetals:lead_pickaxe", - "basemetals:lead_axe", - "basemetals:lead_shovel", - "basemetals:lead_hoe", - "basemetals:lead_sword", - "basemetals:lead_crackhammer", - "basemetals:lead_scythe", - "basemetals:lead_shears", - "basemetals:lead_fishing_rod", - "basemetals:lead_bow", - "basemetals:lead_crossbow", - "basemetals:lead_shield", - "basemetals:lead_arrow", - "basemetals:lead_bolt", - "basemetals:lead_rod", - "basemetals:lead_gear", - "basemetals:lead_horse_armor", - "basemetals:lead_helmet", - "basemetals:lead_chestplate", - "basemetals:lead_leggings", - "basemetals:lead_boots", - "basemetals:mercury_ore", - "basemetals:mercury_ingot", - "basemetals:mercury_nugget", - "basemetals:mercury_powder", - "basemetals:mercury_smallpowder", - "basemetals:mithril_block", - "basemetals:mithril_plate", - "basemetals:mithril_bars", - "basemetals:mithril_door", - "basemetals:mithril_trapdoor", - "basemetals:mithril_button", - "basemetals:mithril_slab", - "basemetals:mithril_lever", - "basemetals:mithril_pressure_plate", - "basemetals:mithril_stairs", - "basemetals:mithril_wall", - "basemetals:mithril_ingot", - "basemetals:mithril_nugget", - "basemetals:mithril_powder", - "basemetals:mithril_smallpowder", - "basemetals:mithril_blend", - "basemetals:mithril_smallblend", - "basemetals:mithril_pickaxe", - "basemetals:mithril_axe", - "basemetals:mithril_shovel", - "basemetals:mithril_hoe", - "basemetals:mithril_sword", - "basemetals:mithril_crackhammer", - "basemetals:mithril_scythe", - "basemetals:mithril_shears", - "basemetals:mithril_fishing_rod", - "basemetals:mithril_bow", - "basemetals:mithril_crossbow", - "basemetals:mithril_shield", - "basemetals:mithril_arrow", - "basemetals:mithril_bolt", - "basemetals:mithril_rod", - "basemetals:mithril_gear", - "basemetals:mithril_horse_armor", - "basemetals:mithril_helmet", - "basemetals:mithril_chestplate", - "basemetals:mithril_leggings", - "basemetals:mithril_boots", - "basemetals:nickel_block", - "basemetals:nickel_plate", - "basemetals:nickel_bars", - "basemetals:nickel_door", - "basemetals:nickel_trapdoor", - "basemetals:nickel_button", - "basemetals:nickel_slab", - "basemetals:nickel_lever", - "basemetals:nickel_pressure_plate", - "basemetals:nickel_stairs", - "basemetals:nickel_wall", - "basemetals:nickel_ore", - "basemetals:nickel_ingot", - "basemetals:nickel_nugget", - "basemetals:nickel_powder", - "basemetals:nickel_smallpowder", - "basemetals:nickel_pickaxe", - "basemetals:nickel_axe", - "basemetals:nickel_shovel", - "basemetals:nickel_hoe", - "basemetals:nickel_sword", - "basemetals:nickel_crackhammer", - "basemetals:nickel_scythe", - "basemetals:nickel_shears", - "basemetals:nickel_fishing_rod", - "basemetals:nickel_bow", - "basemetals:nickel_crossbow", - "basemetals:nickel_shield", - "basemetals:nickel_arrow", - "basemetals:nickel_bolt", - "basemetals:nickel_rod", - "basemetals:nickel_gear", - "basemetals:nickel_horse_armor", - "basemetals:nickel_helmet", - "basemetals:nickel_chestplate", - "basemetals:nickel_leggings", - "basemetals:nickel_boots", - "basemetals:nickel_casing", - "basemetals:nickel_dense_plate", - "basemetals:nickel_crushed", - "basemetals:nickel_crushed_purified", - "basemetals:nickel_crystal", - "basemetals:nickel_shard", - "basemetals:nickel_clump", - "basemetals:nickel_powder_dirty", - "basemetals:pewter_block", - "basemetals:pewter_plate", - "basemetals:pewter_bars", - "basemetals:pewter_door", - "basemetals:pewter_trapdoor", - "basemetals:pewter_button", - "basemetals:pewter_slab", - "basemetals:pewter_lever", - "basemetals:pewter_pressure_plate", - "basemetals:pewter_stairs", - "basemetals:pewter_wall", - "basemetals:pewter_ingot", - "basemetals:pewter_nugget", - "basemetals:pewter_powder", - "basemetals:pewter_smallpowder", - "basemetals:pewter_blend", - "basemetals:pewter_smallblend", - "basemetals:pewter_pickaxe", - "basemetals:pewter_axe", - "basemetals:pewter_shovel", - "basemetals:pewter_hoe", - "basemetals:pewter_sword", - "basemetals:pewter_crackhammer", - "basemetals:pewter_scythe", - "basemetals:pewter_shears", - "basemetals:pewter_fishing_rod", - "basemetals:pewter_bow", - "basemetals:pewter_crossbow", - "basemetals:pewter_shield", - "basemetals:pewter_arrow", - "basemetals:pewter_bolt", - "basemetals:pewter_rod", - "basemetals:pewter_gear", - "basemetals:pewter_horse_armor", - "basemetals:pewter_helmet", - "basemetals:pewter_chestplate", - "basemetals:pewter_leggings", - "basemetals:pewter_boots", - "basemetals:platinum_block", - "basemetals:platinum_plate", - "basemetals:platinum_bars", - "basemetals:platinum_door", - "basemetals:platinum_trapdoor", - "basemetals:platinum_button", - "basemetals:platinum_slab", - "basemetals:platinum_lever", - "basemetals:platinum_pressure_plate", - "basemetals:platinum_stairs", - "basemetals:platinum_wall", - "basemetals:platinum_ore", - "basemetals:platinum_ingot", - "basemetals:platinum_nugget", - "basemetals:platinum_powder", - "basemetals:platinum_smallpowder", - "basemetals:platinum_pickaxe", - "basemetals:platinum_axe", - "basemetals:platinum_shovel", - "basemetals:platinum_hoe", - "basemetals:platinum_sword", - "basemetals:platinum_crackhammer", - "basemetals:platinum_scythe", - "basemetals:platinum_shears", - "basemetals:platinum_fishing_rod", - "basemetals:platinum_bow", - "basemetals:platinum_crossbow", - "basemetals:platinum_shield", - "basemetals:platinum_arrow", - "basemetals:platinum_bolt", - "basemetals:platinum_rod", - "basemetals:platinum_gear", - "basemetals:platinum_horse_armor", - "basemetals:platinum_helmet", - "basemetals:platinum_chestplate", - "basemetals:platinum_leggings", - "basemetals:platinum_boots", - "basemetals:platinum_casing", - "basemetals:platinum_dense_plate", - "basemetals:platinum_crushed", - "basemetals:platinum_crushed_purified", - "basemetals:platinum_crystal", - "basemetals:platinum_shard", - "basemetals:platinum_clump", - "basemetals:platinum_powder_dirty", - "basemetals:silver_block", - "basemetals:silver_plate", - "basemetals:silver_bars", - "basemetals:silver_door", - "basemetals:silver_trapdoor", - "basemetals:silver_button", - "basemetals:silver_slab", - "basemetals:silver_lever", - "basemetals:silver_pressure_plate", - "basemetals:silver_stairs", - "basemetals:silver_wall", - "basemetals:silver_ore", - "basemetals:silver_ingot", - "basemetals:silver_nugget", - "basemetals:silver_powder", - "basemetals:silver_smallpowder", - "basemetals:silver_pickaxe", - "basemetals:silver_axe", - "basemetals:silver_shovel", - "basemetals:silver_hoe", - "basemetals:silver_sword", - "basemetals:silver_crackhammer", - "basemetals:silver_scythe", - "basemetals:silver_shears", - "basemetals:silver_fishing_rod", - "basemetals:silver_bow", - "basemetals:silver_crossbow", - "basemetals:silver_shield", - "basemetals:silver_arrow", - "basemetals:silver_bolt", - "basemetals:silver_rod", - "basemetals:silver_gear", - "basemetals:silver_horse_armor", - "basemetals:silver_helmet", - "basemetals:silver_chestplate", - "basemetals:silver_leggings", - "basemetals:silver_boots", - "basemetals:starsteel_block", - "basemetals:starsteel_plate", - "basemetals:starsteel_bars", - "basemetals:starsteel_door", - "basemetals:starsteel_trapdoor", - "basemetals:starsteel_button", - "basemetals:starsteel_slab", - "basemetals:starsteel_lever", - "basemetals:starsteel_pressure_plate", - "basemetals:starsteel_stairs", - "basemetals:starsteel_wall", - "basemetals:starsteel_ore", - "basemetals:starsteel_ingot", - "basemetals:starsteel_nugget", - "basemetals:starsteel_powder", - "basemetals:starsteel_smallpowder", - "basemetals:starsteel_pickaxe", - "basemetals:starsteel_axe", - "basemetals:starsteel_shovel", - "basemetals:starsteel_hoe", - "basemetals:starsteel_sword", - "basemetals:starsteel_crackhammer", - "basemetals:starsteel_scythe", - "basemetals:starsteel_shears", - "basemetals:starsteel_fishing_rod", - "basemetals:starsteel_bow", - "basemetals:starsteel_crossbow", - "basemetals:starsteel_shield", - "basemetals:starsteel_arrow", - "basemetals:starsteel_bolt", - "basemetals:starsteel_rod", - "basemetals:starsteel_gear", - "basemetals:starsteel_horse_armor", - "basemetals:starsteel_helmet", - "basemetals:starsteel_chestplate", - "basemetals:starsteel_leggings", - "basemetals:starsteel_boots", - "basemetals:starsteel_casing", - "basemetals:starsteel_dense_plate", - "basemetals:starsteel_crushed", - "basemetals:starsteel_crushed_purified", - "basemetals:starsteel_crystal", - "basemetals:starsteel_shard", - "basemetals:starsteel_clump", - "basemetals:starsteel_powder_dirty", - "basemetals:steel_block", - "basemetals:steel_plate", - "basemetals:steel_bars", - "basemetals:steel_door", - "basemetals:steel_trapdoor", - "basemetals:steel_button", - "basemetals:steel_slab", - "basemetals:steel_lever", - "basemetals:steel_pressure_plate", - "basemetals:steel_stairs", - "basemetals:steel_wall", - "basemetals:steel_ingot", - "basemetals:steel_nugget", - "basemetals:steel_powder", - "basemetals:steel_smallpowder", - "basemetals:steel_blend", - "basemetals:steel_smallblend", - "basemetals:steel_pickaxe", - "basemetals:steel_axe", - "basemetals:steel_shovel", - "basemetals:steel_hoe", - "basemetals:steel_sword", - "basemetals:steel_crackhammer", - "basemetals:steel_scythe", - "basemetals:steel_shears", - "basemetals:steel_fishing_rod", - "basemetals:steel_bow", - "basemetals:steel_crossbow", - "basemetals:steel_shield", - "basemetals:steel_arrow", - "basemetals:steel_bolt", - "basemetals:steel_rod", - "basemetals:steel_gear", - "basemetals:steel_horse_armor", - "basemetals:steel_helmet", - "basemetals:steel_chestplate", - "basemetals:steel_leggings", - "basemetals:steel_boots", - "basemetals:tin_block", - "basemetals:tin_plate", - "basemetals:tin_bars", - "basemetals:tin_door", - "basemetals:tin_trapdoor", - "basemetals:tin_button", - "basemetals:tin_slab", - "basemetals:tin_lever", - "basemetals:tin_pressure_plate", - "basemetals:tin_stairs", - "basemetals:tin_wall", - "basemetals:tin_ore", - "basemetals:tin_ingot", - "basemetals:tin_nugget", - "basemetals:tin_powder", - "basemetals:tin_smallpowder", - "basemetals:tin_pickaxe", - "basemetals:tin_axe", - "basemetals:tin_shovel", - "basemetals:tin_hoe", - "basemetals:tin_sword", - "basemetals:tin_crackhammer", - "basemetals:tin_scythe", - "basemetals:tin_shears", - "basemetals:tin_fishing_rod", - "basemetals:tin_bow", - "basemetals:tin_crossbow", - "basemetals:tin_shield", - "basemetals:tin_arrow", - "basemetals:tin_bolt", - "basemetals:tin_rod", - "basemetals:tin_gear", - "basemetals:tin_horse_armor", - "basemetals:tin_helmet", - "basemetals:tin_chestplate", - "basemetals:tin_leggings", - "basemetals:tin_boots", - "basemetals:zinc_block", - "basemetals:zinc_plate", - "basemetals:zinc_bars", - "basemetals:zinc_door", - "basemetals:zinc_trapdoor", - "basemetals:zinc_button", - "basemetals:zinc_slab", - "basemetals:zinc_lever", - "basemetals:zinc_pressure_plate", - "basemetals:zinc_stairs", - "basemetals:zinc_wall", - "basemetals:zinc_ore", - "basemetals:zinc_ingot", - "basemetals:zinc_nugget", - "basemetals:zinc_powder", - "basemetals:zinc_smallpowder", - "basemetals:zinc_pickaxe", - "basemetals:zinc_axe", - "basemetals:zinc_shovel", - "basemetals:zinc_hoe", - "basemetals:zinc_sword", - "basemetals:zinc_crackhammer", - "basemetals:zinc_scythe", - "basemetals:zinc_shears", - "basemetals:zinc_fishing_rod", - "basemetals:zinc_bow", - "basemetals:zinc_crossbow", - "basemetals:zinc_shield", - "basemetals:zinc_arrow", - "basemetals:zinc_bolt", - "basemetals:zinc_rod", - "basemetals:zinc_gear", - "basemetals:zinc_horse_armor", - "basemetals:zinc_helmet", - "basemetals:zinc_chestplate", - "basemetals:zinc_leggings", - "basemetals:zinc_boots", - "basemetals:zinc_casing", - "basemetals:zinc_dense_plate", - "basemetals:zinc_crushed", - "basemetals:zinc_crushed_purified", - "basemetals:zinc_crystal", - "basemetals:zinc_shard", - "basemetals:zinc_clump", - "basemetals:zinc_powder_dirty", - "basemetals:stone_anvil", - "basemetals:steel_anvil", - "basemetals:adamantine_anvil", - "basemetals:human_detector", - "basemetals:charcoal_block", - "basemetals:diamond_bars", - "basemetals:diamond_door", - "basemetals:diamond_trapdoor", - "basemetals:diamond_button", - "basemetals:diamond_slab", - "basemetals:diamond_lever", - "basemetals:diamond_pressure_plate", - "basemetals:diamond_stairs", - "basemetals:diamond_wall", - "basemetals:emerald_bars", - "basemetals:emerald_door", - "basemetals:emerald_trapdoor", - "basemetals:emerald_button", - "basemetals:emerald_slab", - "basemetals:emerald_lever", - "basemetals:emerald_pressure_plate", - "basemetals:emerald_stairs", - "basemetals:emerald_wall", - "basemetals:gold_bars", - "basemetals:gold_door", - "basemetals:gold_trapdoor", - "basemetals:gold_button", - "basemetals:gold_slab", - "basemetals:gold_lever", - "basemetals:gold_stairs", - "basemetals:gold_wall", - "basemetals:obsidian_bars", - "basemetals:obsidian_door", - "basemetals:obsidian_trapdoor", - "basemetals:obsidian_button", - "basemetals:obsidian_slab", - "basemetals:obsidian_lever", - "basemetals:obsidian_pressure_plate", - "basemetals:obsidian_stairs", - "basemetals:obsidian_wall", - "basemetals:iron_button", - "basemetals:iron_slab", - "basemetals:iron_lever", - "basemetals:iron_stairs", - "basemetals:iron_wall", - "basemetals:quartz_bars", - "basemetals:quartz_door", - "basemetals:quartz_trapdoor", - "basemetals:quartz_button", - "basemetals:quartz_lever", - "basemetals:quartz_pressure_plate", - "basemetals:quartz_wall", - "basemetals:gold_plate", - "basemetals:iron_plate", - "basemetals:diamond_arrow", - "basemetals:diamond_bolt", - "basemetals:diamond_bow", - "basemetals:diamond_crossbow", - "basemetals:diamond_fishing_rod", - "basemetals:diamond_rod", - "basemetals:diamond_shears", - "basemetals:diamond_shield", + "basemetals:electrum_lever", + "basemetals:electrum_nugget", + "basemetals:electrum_pickaxe", + "basemetals:electrum_plate", + "basemetals:electrum_powder", + "basemetals:electrum_pressure_plate", + "basemetals:electrum_rod", + "basemetals:electrum_scythe", + "basemetals:electrum_shears", + "basemetals:electrum_shield", + "basemetals:electrum_shovel", + "basemetals:electrum_slab", + "basemetals:electrum_smallblend", + "basemetals:electrum_smallpowder", + "basemetals:electrum_stairs", + "basemetals:electrum_sword", + "basemetals:electrum_trapdoor", + "basemetals:electrum_wall", + "basemetals:emerald", "basemetals:emerald_arrow", + "basemetals:emerald_axe", + "basemetals:emerald_bars", "basemetals:emerald_bolt", + "basemetals:emerald_boots", "basemetals:emerald_bow", + "basemetals:emerald_bucket", + "basemetals:emerald_button", + "basemetals:emerald_chestplate", + "basemetals:emerald_crackhammer", "basemetals:emerald_crossbow", + "basemetals:emerald_door", "basemetals:emerald_fishing_rod", + "basemetals:emerald_gear", + "basemetals:emerald_helmet", + "basemetals:emerald_hoe", + "basemetals:emerald_horse_armor", + "basemetals:emerald_leggings", + "basemetals:emerald_lever", + "basemetals:emerald_nugget", + "basemetals:emerald_pickaxe", + "basemetals:emerald_powder", + "basemetals:emerald_pressure_plate", "basemetals:emerald_rod", + "basemetals:emerald_scythe", "basemetals:emerald_shears", "basemetals:emerald_shield", - "basemetals:emerald_axe", - "basemetals:emerald_pickaxe", "basemetals:emerald_shovel", - "basemetals:emerald_hoe", - "basemetals:emerald_helmet", - "basemetals:emerald_chestplate", - "basemetals:emerald_leggings", - "basemetals:emerald_boots", - "basemetals:emerald_horse_armor", + "basemetals:emerald_slab", + "basemetals:emerald_smallpowder", + "basemetals:emerald_stairs", "basemetals:emerald_sword", + "basemetals:emerald_trapdoor", + "basemetals:emerald_wall", + "basemetals:ender", + "basemetals:ender_bucket", + "basemetals:gold", "basemetals:gold_arrow", + "basemetals:gold_bars", + "basemetals:gold_blend", "basemetals:gold_bolt", "basemetals:gold_bow", + "basemetals:gold_bucket", + "basemetals:gold_button", + "basemetals:gold_crackhammer", "basemetals:gold_crossbow", + "basemetals:gold_door", "basemetals:gold_fishing_rod", + "basemetals:gold_gear", + "basemetals:gold_lever", + "basemetals:gold_plate", + "basemetals:gold_powder", "basemetals:gold_rod", + "basemetals:gold_scythe", "basemetals:gold_shears", "basemetals:gold_shield", + "basemetals:gold_slab", + "basemetals:gold_smallblend", + "basemetals:gold_smallpowder", + "basemetals:gold_stairs", + "basemetals:gold_trapdoor", + "basemetals:gold_wall", + "basemetals:human_detector", + "basemetals:invar", + "basemetals:invar_arrow", + "basemetals:invar_axe", + "basemetals:invar_bars", + "basemetals:invar_blend", + "basemetals:invar_block", + "basemetals:invar_bolt", + "basemetals:invar_boots", + "basemetals:invar_bow", + "basemetals:invar_bucket", + "basemetals:invar_button", + "basemetals:invar_chestplate", + "basemetals:invar_crackhammer", + "basemetals:invar_crossbow", + "basemetals:invar_door", + "basemetals:invar_fishing_rod", + "basemetals:invar_gear", + "basemetals:invar_helmet", + "basemetals:invar_hoe", + "basemetals:invar_horse_armor", + "basemetals:invar_ingot", + "basemetals:invar_leggings", + "basemetals:invar_lever", + "basemetals:invar_nugget", + "basemetals:invar_pickaxe", + "basemetals:invar_plate", + "basemetals:invar_powder", + "basemetals:invar_pressure_plate", + "basemetals:invar_rod", + "basemetals:invar_scythe", + "basemetals:invar_shears", + "basemetals:invar_shield", + "basemetals:invar_shovel", + "basemetals:invar_slab", + "basemetals:invar_smallblend", + "basemetals:invar_smallpowder", + "basemetals:invar_stairs", + "basemetals:invar_sword", + "basemetals:invar_trapdoor", + "basemetals:invar_wall", + "basemetals:iron", "basemetals:iron_arrow", + "basemetals:iron_blend", "basemetals:iron_bolt", "basemetals:iron_bow", + "basemetals:iron_bucket", + "basemetals:iron_button", + "basemetals:iron_crackhammer", "basemetals:iron_crossbow", "basemetals:iron_fishing_rod", + "basemetals:iron_gear", + "basemetals:iron_lever", + "basemetals:iron_plate", + "basemetals:iron_powder", "basemetals:iron_rod", + "basemetals:iron_scythe", "basemetals:iron_shield", + "basemetals:iron_slab", + "basemetals:iron_smallblend", + "basemetals:iron_smallpowder", + "basemetals:iron_stairs", + "basemetals:iron_wall", + "basemetals:lapis", + "basemetals:lapis_bucket", + "basemetals:lapis_smallpowder", + "basemetals:lead", + "basemetals:lead_arrow", + "basemetals:lead_axe", + "basemetals:lead_bars", + "basemetals:lead_block", + "basemetals:lead_bolt", + "basemetals:lead_boots", + "basemetals:lead_bow", + "basemetals:lead_bucket", + "basemetals:lead_button", + "basemetals:lead_chestplate", + "basemetals:lead_crackhammer", + "basemetals:lead_crossbow", + "basemetals:lead_door", + "basemetals:lead_fishing_rod", + "basemetals:lead_gear", + "basemetals:lead_helmet", + "basemetals:lead_hoe", + "basemetals:lead_horse_armor", + "basemetals:lead_ingot", + "basemetals:lead_leggings", + "basemetals:lead_lever", + "basemetals:lead_nugget", + "basemetals:lead_ore", + "basemetals:lead_pickaxe", + "basemetals:lead_plate", + "basemetals:lead_powder", + "basemetals:lead_pressure_plate", + "basemetals:lead_raw", + "basemetals:lead_rod", + "basemetals:lead_scythe", + "basemetals:lead_shears", + "basemetals:lead_shield", + "basemetals:lead_shovel", + "basemetals:lead_slab", + "basemetals:lead_smallpowder", + "basemetals:lead_stairs", + "basemetals:lead_sword", + "basemetals:lead_trapdoor", + "basemetals:lead_wall", + "basemetals:mercury", + "basemetals:mercury_bucket", + "basemetals:mercury_ingot", + "basemetals:mercury_nugget", + "basemetals:mercury_ore", + "basemetals:mercury_powder", + "basemetals:mercury_raw", + "basemetals:mercury_smallpowder", + "basemetals:mithril", + "basemetals:mithril_arrow", + "basemetals:mithril_axe", + "basemetals:mithril_bars", + "basemetals:mithril_blend", + "basemetals:mithril_block", + "basemetals:mithril_bolt", + "basemetals:mithril_boots", + "basemetals:mithril_bow", + "basemetals:mithril_bucket", + "basemetals:mithril_button", + "basemetals:mithril_chestplate", + "basemetals:mithril_crackhammer", + "basemetals:mithril_crossbow", + "basemetals:mithril_door", + "basemetals:mithril_fishing_rod", + "basemetals:mithril_gear", + "basemetals:mithril_helmet", + "basemetals:mithril_hoe", + "basemetals:mithril_horse_armor", + "basemetals:mithril_ingot", + "basemetals:mithril_leggings", + "basemetals:mithril_lever", + "basemetals:mithril_nugget", + "basemetals:mithril_pickaxe", + "basemetals:mithril_plate", + "basemetals:mithril_powder", + "basemetals:mithril_pressure_plate", + "basemetals:mithril_rod", + "basemetals:mithril_scythe", + "basemetals:mithril_shears", + "basemetals:mithril_shield", + "basemetals:mithril_shovel", + "basemetals:mithril_slab", + "basemetals:mithril_smallblend", + "basemetals:mithril_smallpowder", + "basemetals:mithril_stairs", + "basemetals:mithril_sword", + "basemetals:mithril_trapdoor", + "basemetals:mithril_wall", + "basemetals:nickel", + "basemetals:nickel_arrow", + "basemetals:nickel_axe", + "basemetals:nickel_bars", + "basemetals:nickel_block", + "basemetals:nickel_bolt", + "basemetals:nickel_boots", + "basemetals:nickel_bow", + "basemetals:nickel_bucket", + "basemetals:nickel_button", + "basemetals:nickel_casing", + "basemetals:nickel_chestplate", + "basemetals:nickel_clump", + "basemetals:nickel_crackhammer", + "basemetals:nickel_crossbow", + "basemetals:nickel_crushed", + "basemetals:nickel_crushed_purified", + "basemetals:nickel_crystal", + "basemetals:nickel_dense_plate", + "basemetals:nickel_door", + "basemetals:nickel_fishing_rod", + "basemetals:nickel_gear", + "basemetals:nickel_helmet", + "basemetals:nickel_hoe", + "basemetals:nickel_horse_armor", + "basemetals:nickel_ingot", + "basemetals:nickel_leggings", + "basemetals:nickel_lever", + "basemetals:nickel_nugget", + "basemetals:nickel_ore", + "basemetals:nickel_pickaxe", + "basemetals:nickel_plate", + "basemetals:nickel_powder", + "basemetals:nickel_powder_dirty", + "basemetals:nickel_pressure_plate", + "basemetals:nickel_raw", + "basemetals:nickel_rod", + "basemetals:nickel_scythe", + "basemetals:nickel_shard", + "basemetals:nickel_shears", + "basemetals:nickel_shield", + "basemetals:nickel_shovel", + "basemetals:nickel_slab", + "basemetals:nickel_smallpowder", + "basemetals:nickel_stairs", + "basemetals:nickel_sword", + "basemetals:nickel_trapdoor", + "basemetals:nickel_wall", + "basemetals:obsidian", "basemetals:obsidian_arrow", + "basemetals:obsidian_axe", + "basemetals:obsidian_bars", "basemetals:obsidian_bolt", + "basemetals:obsidian_boots", "basemetals:obsidian_bow", + "basemetals:obsidian_bucket", + "basemetals:obsidian_button", + "basemetals:obsidian_chestplate", + "basemetals:obsidian_crackhammer", "basemetals:obsidian_crossbow", + "basemetals:obsidian_door", "basemetals:obsidian_fishing_rod", + "basemetals:obsidian_gear", + "basemetals:obsidian_helmet", + "basemetals:obsidian_hoe", + "basemetals:obsidian_horse_armor", + "basemetals:obsidian_ingot", + "basemetals:obsidian_leggings", + "basemetals:obsidian_lever", + "basemetals:obsidian_nugget", + "basemetals:obsidian_pickaxe", + "basemetals:obsidian_powder", + "basemetals:obsidian_pressure_plate", "basemetals:obsidian_rod", + "basemetals:obsidian_scythe", "basemetals:obsidian_shears", "basemetals:obsidian_shield", - "basemetals:obsidian_axe", - "basemetals:obsidian_pickaxe", "basemetals:obsidian_shovel", - "basemetals:obsidian_hoe", - "basemetals:obsidian_helmet", - "basemetals:obsidian_chestplate", - "basemetals:obsidian_leggings", - "basemetals:obsidian_boots", - "basemetals:obsidian_horse_armor", + "basemetals:obsidian_slab", + "basemetals:obsidian_smallpowder", + "basemetals:obsidian_stairs", "basemetals:obsidian_sword", + "basemetals:obsidian_trapdoor", + "basemetals:obsidian_wall", + "basemetals:pewter", + "basemetals:pewter_arrow", + "basemetals:pewter_axe", + "basemetals:pewter_bars", + "basemetals:pewter_blend", + "basemetals:pewter_block", + "basemetals:pewter_bolt", + "basemetals:pewter_boots", + "basemetals:pewter_bow", + "basemetals:pewter_bucket", + "basemetals:pewter_button", + "basemetals:pewter_chestplate", + "basemetals:pewter_crackhammer", + "basemetals:pewter_crossbow", + "basemetals:pewter_door", + "basemetals:pewter_fishing_rod", + "basemetals:pewter_gear", + "basemetals:pewter_helmet", + "basemetals:pewter_hoe", + "basemetals:pewter_horse_armor", + "basemetals:pewter_ingot", + "basemetals:pewter_leggings", + "basemetals:pewter_lever", + "basemetals:pewter_nugget", + "basemetals:pewter_pickaxe", + "basemetals:pewter_plate", + "basemetals:pewter_powder", + "basemetals:pewter_pressure_plate", + "basemetals:pewter_rod", + "basemetals:pewter_scythe", + "basemetals:pewter_shears", + "basemetals:pewter_shield", + "basemetals:pewter_shovel", + "basemetals:pewter_slab", + "basemetals:pewter_smallblend", + "basemetals:pewter_smallpowder", + "basemetals:pewter_stairs", + "basemetals:pewter_sword", + "basemetals:pewter_trapdoor", + "basemetals:pewter_wall", + "basemetals:platinum", + "basemetals:platinum_arrow", + "basemetals:platinum_axe", + "basemetals:platinum_bars", + "basemetals:platinum_block", + "basemetals:platinum_bolt", + "basemetals:platinum_boots", + "basemetals:platinum_bow", + "basemetals:platinum_bucket", + "basemetals:platinum_button", + "basemetals:platinum_casing", + "basemetals:platinum_chestplate", + "basemetals:platinum_clump", + "basemetals:platinum_crackhammer", + "basemetals:platinum_crossbow", + "basemetals:platinum_crushed", + "basemetals:platinum_crushed_purified", + "basemetals:platinum_crystal", + "basemetals:platinum_dense_plate", + "basemetals:platinum_door", + "basemetals:platinum_fishing_rod", + "basemetals:platinum_gear", + "basemetals:platinum_helmet", + "basemetals:platinum_hoe", + "basemetals:platinum_horse_armor", + "basemetals:platinum_ingot", + "basemetals:platinum_leggings", + "basemetals:platinum_lever", + "basemetals:platinum_nugget", + "basemetals:platinum_ore", + "basemetals:platinum_pickaxe", + "basemetals:platinum_plate", + "basemetals:platinum_powder", + "basemetals:platinum_powder_dirty", + "basemetals:platinum_pressure_plate", + "basemetals:platinum_raw", + "basemetals:platinum_rod", + "basemetals:platinum_scythe", + "basemetals:platinum_shard", + "basemetals:platinum_shears", + "basemetals:platinum_shield", + "basemetals:platinum_shovel", + "basemetals:platinum_slab", + "basemetals:platinum_smallpowder", + "basemetals:platinum_stairs", + "basemetals:platinum_sword", + "basemetals:platinum_trapdoor", + "basemetals:platinum_wall", + "basemetals:prismarine", + "basemetals:prismarine_bucket", + "basemetals:quartz", "basemetals:quartz_arrow", + "basemetals:quartz_axe", + "basemetals:quartz_bars", "basemetals:quartz_bolt", + "basemetals:quartz_boots", "basemetals:quartz_bow", + "basemetals:quartz_bucket", + "basemetals:quartz_button", + "basemetals:quartz_chestplate", + "basemetals:quartz_crackhammer", "basemetals:quartz_crossbow", + "basemetals:quartz_door", "basemetals:quartz_fishing_rod", + "basemetals:quartz_gear", + "basemetals:quartz_helmet", + "basemetals:quartz_hoe", + "basemetals:quartz_horse_armor", + "basemetals:quartz_leggings", + "basemetals:quartz_lever", + "basemetals:quartz_nugget", + "basemetals:quartz_pickaxe", + "basemetals:quartz_powder", + "basemetals:quartz_pressure_plate", "basemetals:quartz_rod", + "basemetals:quartz_scythe", "basemetals:quartz_shears", "basemetals:quartz_shield", - "basemetals:quartz_axe", - "basemetals:quartz_pickaxe", "basemetals:quartz_shovel", - "basemetals:quartz_hoe", - "basemetals:quartz_helmet", - "basemetals:quartz_chestplate", - "basemetals:quartz_leggings", - "basemetals:quartz_boots", - "basemetals:quartz_horse_armor", - "basemetals:quartz_sword", - "basemetals:diamond_crackhammer", - "basemetals:diamond_gear", - "basemetals:diamond_scythe", - "basemetals:emerald_crackhammer", - "basemetals:emerald_gear", - "basemetals:emerald_scythe", - "basemetals:gold_crackhammer", - "basemetals:gold_gear", - "basemetals:gold_scythe", - "basemetals:iron_crackhammer", - "basemetals:iron_gear", - "basemetals:iron_scythe", - "basemetals:obsidian_crackhammer", - "basemetals:obsidian_gear", - "basemetals:obsidian_scythe", - "basemetals:quartz_crackhammer", - "basemetals:quartz_gear", - "basemetals:quartz_scythe", - "basemetals:stone_crackhammer", - "basemetals:stone_gear", - "basemetals:stone_scythe", - "basemetals:wood_crackhammer", - "basemetals:wood_gear", - "basemetals:wood_scythe", - "basemetals:coal_powder", - "basemetals:coal_smallpowder", - "basemetals:charcoal_powder", - "basemetals:charcoal_smallpowder", - "basemetals:diamond_powder", - "basemetals:diamond_smallpowder", - "basemetals:emerald_powder", - "basemetals:emerald_smallpowder", - "basemetals:gold_powder", - "basemetals:gold_smallpowder", - "basemetals:iron_powder", - "basemetals:iron_smallpowder", - "basemetals:obsidian_powder", - "basemetals:obsidian_smallpowder", - "basemetals:quartz_powder", "basemetals:quartz_smallpowder", - "basemetals:redstone_smallpowder", - "basemetals:coal_nugget", - "basemetals:charcoal_nugget", - "basemetals:diamond_nugget", - "basemetals:emerald_nugget", - "basemetals:obsidian_nugget", - "basemetals:quartz_nugget", - "basemetals:diamond_blend", - "basemetals:diamond_smallblend", - "basemetals:gold_blend", - "basemetals:gold_smallblend", - "basemetals:iron_blend", - "basemetals:iron_smallblend", - "basemetals:lapis_smallpowder", - "basemetals:obsidian_ingot", + "basemetals:quartz_sword", + "basemetals:quartz_trapdoor", + "basemetals:quartz_wall", + "basemetals:redstone", + "basemetals:redstone_bucket", "basemetals:redstone_ingot", - "basemetals:stone_rod", - "basemetals:adamantine", - "basemetals:adamantine_bucket", - "basemetals:antimony", - "basemetals:antimony_bucket", - "basemetals:aquarium", - "basemetals:aquarium_bucket", - "basemetals:bismuth", - "basemetals:bismuth_bucket", - "basemetals:brass", - "basemetals:brass_bucket", - "basemetals:bronze", - "basemetals:bronze_bucket", - "basemetals:coldiron", - "basemetals:coldiron_bucket", - "basemetals:copper", - "basemetals:copper_bucket", - "basemetals:cupronickel", - "basemetals:cupronickel_bucket", - "basemetals:electrum", - "basemetals:electrum_bucket", - "basemetals:invar", - "basemetals:invar_bucket", - "basemetals:lead", - "basemetals:lead_bucket", - "basemetals:mercury", - "basemetals:mercury_bucket", - "basemetals:mithril", - "basemetals:mithril_bucket", - "basemetals:nickel", - "basemetals:nickel_bucket", - "basemetals:pewter", - "basemetals:pewter_bucket", - "basemetals:platinum", - "basemetals:platinum_bucket", + "basemetals:redstone_smallpowder", "basemetals:silver", + "basemetals:silver_arrow", + "basemetals:silver_axe", + "basemetals:silver_bars", + "basemetals:silver_block", + "basemetals:silver_bolt", + "basemetals:silver_boots", + "basemetals:silver_bow", "basemetals:silver_bucket", + "basemetals:silver_button", + "basemetals:silver_chestplate", + "basemetals:silver_crackhammer", + "basemetals:silver_crossbow", + "basemetals:silver_door", + "basemetals:silver_fishing_rod", + "basemetals:silver_gear", + "basemetals:silver_helmet", + "basemetals:silver_hoe", + "basemetals:silver_horse_armor", + "basemetals:silver_ingot", + "basemetals:silver_leggings", + "basemetals:silver_lever", + "basemetals:silver_nugget", + "basemetals:silver_ore", + "basemetals:silver_pickaxe", + "basemetals:silver_plate", + "basemetals:silver_powder", + "basemetals:silver_pressure_plate", + "basemetals:silver_raw", + "basemetals:silver_rod", + "basemetals:silver_scythe", + "basemetals:silver_shears", + "basemetals:silver_shield", + "basemetals:silver_shovel", + "basemetals:silver_slab", + "basemetals:silver_smallpowder", + "basemetals:silver_stairs", + "basemetals:silver_sword", + "basemetals:silver_trapdoor", + "basemetals:silver_wall", "basemetals:starsteel", + "basemetals:starsteel_arrow", + "basemetals:starsteel_axe", + "basemetals:starsteel_bars", + "basemetals:starsteel_block", + "basemetals:starsteel_bolt", + "basemetals:starsteel_boots", + "basemetals:starsteel_bow", "basemetals:starsteel_bucket", + "basemetals:starsteel_button", + "basemetals:starsteel_casing", + "basemetals:starsteel_chestplate", + "basemetals:starsteel_clump", + "basemetals:starsteel_crackhammer", + "basemetals:starsteel_crossbow", + "basemetals:starsteel_crushed", + "basemetals:starsteel_crushed_purified", + "basemetals:starsteel_crystal", + "basemetals:starsteel_dense_plate", + "basemetals:starsteel_door", + "basemetals:starsteel_fishing_rod", + "basemetals:starsteel_gear", + "basemetals:starsteel_helmet", + "basemetals:starsteel_hoe", + "basemetals:starsteel_horse_armor", + "basemetals:starsteel_ingot", + "basemetals:starsteel_leggings", + "basemetals:starsteel_lever", + "basemetals:starsteel_nugget", + "basemetals:starsteel_ore", + "basemetals:starsteel_pickaxe", + "basemetals:starsteel_plate", + "basemetals:starsteel_powder", + "basemetals:starsteel_powder_dirty", + "basemetals:starsteel_pressure_plate", + "basemetals:starsteel_raw", + "basemetals:starsteel_rod", + "basemetals:starsteel_scythe", + "basemetals:starsteel_shard", + "basemetals:starsteel_shears", + "basemetals:starsteel_shield", + "basemetals:starsteel_shovel", + "basemetals:starsteel_slab", + "basemetals:starsteel_smallpowder", + "basemetals:starsteel_stairs", + "basemetals:starsteel_sword", + "basemetals:starsteel_trapdoor", + "basemetals:starsteel_wall", "basemetals:steel", + "basemetals:steel_anvil", + "basemetals:steel_arrow", + "basemetals:steel_axe", + "basemetals:steel_bars", + "basemetals:steel_blend", + "basemetals:steel_block", + "basemetals:steel_bolt", + "basemetals:steel_boots", + "basemetals:steel_bow", "basemetals:steel_bucket", + "basemetals:steel_button", + "basemetals:steel_chestplate", + "basemetals:steel_crackhammer", + "basemetals:steel_crossbow", + "basemetals:steel_door", + "basemetals:steel_fishing_rod", + "basemetals:steel_gear", + "basemetals:steel_helmet", + "basemetals:steel_hoe", + "basemetals:steel_horse_armor", + "basemetals:steel_ingot", + "basemetals:steel_leggings", + "basemetals:steel_lever", + "basemetals:steel_nugget", + "basemetals:steel_pickaxe", + "basemetals:steel_plate", + "basemetals:steel_powder", + "basemetals:steel_pressure_plate", + "basemetals:steel_rod", + "basemetals:steel_scythe", + "basemetals:steel_shears", + "basemetals:steel_shield", + "basemetals:steel_shovel", + "basemetals:steel_slab", + "basemetals:steel_smallblend", + "basemetals:steel_smallpowder", + "basemetals:steel_stairs", + "basemetals:steel_sword", + "basemetals:steel_trapdoor", + "basemetals:steel_wall", + "basemetals:stone", + "basemetals:stone_anvil", + "basemetals:stone_bucket", + "basemetals:stone_crackhammer", + "basemetals:stone_gear", + "basemetals:stone_rod", + "basemetals:stone_scythe", "basemetals:tin", + "basemetals:tin_arrow", + "basemetals:tin_axe", + "basemetals:tin_bars", + "basemetals:tin_block", + "basemetals:tin_bolt", + "basemetals:tin_boots", + "basemetals:tin_bow", "basemetals:tin_bucket", - "basemetals:zinc", - "basemetals:zinc_bucket", - "basemetals:charcoal", - "basemetals:charcoal_bucket", - "basemetals:coal", - "basemetals:coal_bucket", - "basemetals:diamond", - "basemetals:diamond_bucket", - "basemetals:emerald", - "basemetals:emerald_bucket", - "basemetals:ender", - "basemetals:ender_bucket", - "basemetals:gold", - "basemetals:gold_bucket", - "basemetals:iron", - "basemetals:iron_bucket", - "basemetals:lapis", - "basemetals:lapis_bucket", - "basemetals:obsidian", - "basemetals:obsidian_bucket", - "basemetals:prismarine", - "basemetals:prismarine_bucket", - "basemetals:quartz", - "basemetals:quartz_bucket", + "basemetals:tin_button", + "basemetals:tin_chestplate", + "basemetals:tin_crackhammer", + "basemetals:tin_crossbow", + "basemetals:tin_door", + "basemetals:tin_fishing_rod", + "basemetals:tin_gear", + "basemetals:tin_helmet", + "basemetals:tin_hoe", + "basemetals:tin_horse_armor", + "basemetals:tin_ingot", + "basemetals:tin_leggings", + "basemetals:tin_lever", + "basemetals:tin_nugget", + "basemetals:tin_ore", + "basemetals:tin_pickaxe", + "basemetals:tin_plate", + "basemetals:tin_powder", + "basemetals:tin_pressure_plate", + "basemetals:tin_raw", + "basemetals:tin_rod", + "basemetals:tin_scythe", + "basemetals:tin_shears", + "basemetals:tin_shield", + "basemetals:tin_shovel", + "basemetals:tin_slab", + "basemetals:tin_smallpowder", + "basemetals:tin_stairs", + "basemetals:tin_sword", + "basemetals:tin_trapdoor", + "basemetals:tin_wall", "basemetals:wood", "basemetals:wood_bucket", - "basemetals:redstone", - "basemetals:redstone_bucket", - "basemetals:stone", - "basemetals:stone_bucket" + "basemetals:wood_crackhammer", + "basemetals:wood_gear", + "basemetals:wood_scythe", + "basemetals:zinc", + "basemetals:zinc_arrow", + "basemetals:zinc_axe", + "basemetals:zinc_bars", + "basemetals:zinc_block", + "basemetals:zinc_bolt", + "basemetals:zinc_boots", + "basemetals:zinc_bow", + "basemetals:zinc_bucket", + "basemetals:zinc_button", + "basemetals:zinc_casing", + "basemetals:zinc_chestplate", + "basemetals:zinc_clump", + "basemetals:zinc_crackhammer", + "basemetals:zinc_crossbow", + "basemetals:zinc_crushed", + "basemetals:zinc_crushed_purified", + "basemetals:zinc_crystal", + "basemetals:zinc_dense_plate", + "basemetals:zinc_door", + "basemetals:zinc_fishing_rod", + "basemetals:zinc_gear", + "basemetals:zinc_helmet", + "basemetals:zinc_hoe", + "basemetals:zinc_horse_armor", + "basemetals:zinc_ingot", + "basemetals:zinc_leggings", + "basemetals:zinc_lever", + "basemetals:zinc_nugget", + "basemetals:zinc_ore", + "basemetals:zinc_pickaxe", + "basemetals:zinc_plate", + "basemetals:zinc_powder", + "basemetals:zinc_powder_dirty", + "basemetals:zinc_pressure_plate", + "basemetals:zinc_raw", + "basemetals:zinc_rod", + "basemetals:zinc_scythe", + "basemetals:zinc_shard", + "basemetals:zinc_shears", + "basemetals:zinc_shield", + "basemetals:zinc_shovel", + "basemetals:zinc_slab", + "basemetals:zinc_smallpowder", + "basemetals:zinc_stairs", + "basemetals:zinc_sword", + "basemetals:zinc_trapdoor", + "basemetals:zinc_wall" ], "fluids": [ "basemetals:adamantine", @@ -1623,41 +1635,53 @@ ], "new_items": [ "basemetals:adamantine_bucket", + "basemetals:adamantine_raw", "basemetals:antimony_bucket", + "basemetals:antimony_raw", "basemetals:aquarium_bucket", "basemetals:bismuth_bucket", + "basemetals:bismuth_raw", "basemetals:brass_bucket", "basemetals:bronze_bucket", + "basemetals:charcoal_bucket", + "basemetals:coal_bucket", "basemetals:coldiron_bucket", + "basemetals:coldiron_raw", "basemetals:copper_bucket", "basemetals:cupronickel_bucket", + "basemetals:diamond_bucket", "basemetals:electrum_bucket", + "basemetals:emerald_bucket", + "basemetals:ender_bucket", + "basemetals:gold_bucket", "basemetals:invar_bucket", + "basemetals:iron_bucket", + "basemetals:lapis_bucket", "basemetals:lead_bucket", + "basemetals:lead_raw", "basemetals:mercury_bucket", + "basemetals:mercury_raw", "basemetals:mithril_bucket", "basemetals:nickel_bucket", + "basemetals:nickel_raw", + "basemetals:obsidian_bucket", "basemetals:pewter_bucket", "basemetals:platinum_bucket", + "basemetals:platinum_raw", + "basemetals:prismarine_bucket", + "basemetals:quartz_bucket", + "basemetals:redstone_bucket", "basemetals:silver_bucket", + "basemetals:silver_raw", "basemetals:starsteel_bucket", + "basemetals:starsteel_raw", "basemetals:steel_bucket", + "basemetals:stone_bucket", "basemetals:tin_bucket", - "basemetals:zinc_bucket", - "basemetals:charcoal_bucket", - "basemetals:coal_bucket", - "basemetals:diamond_bucket", - "basemetals:emerald_bucket", - "basemetals:ender_bucket", - "basemetals:gold_bucket", - "basemetals:iron_bucket", - "basemetals:lapis_bucket", - "basemetals:obsidian_bucket", - "basemetals:prismarine_bucket", - "basemetals:quartz_bucket", + "basemetals:tin_raw", "basemetals:wood_bucket", - "basemetals:redstone_bucket", - "basemetals:stone_bucket" + "basemetals:zinc_bucket", + "basemetals:zinc_raw" ], "new_fluids": [ "basemetals:flowing_adamantine", diff --git a/src/generated/resources/data/forge/tags/blocks/ores/coal.json b/src/generated/resources/data/forge/tags/blocks/ores/coal.json new file mode 100644 index 000000000..6d8e9392c --- /dev/null +++ b/src/generated/resources/data/forge/tags/blocks/ores/coal.json @@ -0,0 +1,7 @@ +{ + "replace": false, + "values": [ + "minecraft:coal_ore", + "minecraft:deepslate_coal_ore" + ] +} diff --git a/src/generated/resources/data/forge/tags/blocks/ores/copper.json b/src/generated/resources/data/forge/tags/blocks/ores/copper.json index 0d4ca07c6..3492aec8b 100644 --- a/src/generated/resources/data/forge/tags/blocks/ores/copper.json +++ b/src/generated/resources/data/forge/tags/blocks/ores/copper.json @@ -1,6 +1,8 @@ { "replace": false, "values": [ - "basemetals:copper_ore" + "basemetals:copper_ore", + "minecraft:copper_ore", + "minecraft:deepslate_copper_ore" ] } diff --git a/src/generated/resources/data/forge/tags/blocks/ores/diamond.json b/src/generated/resources/data/forge/tags/blocks/ores/diamond.json new file mode 100644 index 000000000..6c54d7775 --- /dev/null +++ b/src/generated/resources/data/forge/tags/blocks/ores/diamond.json @@ -0,0 +1,7 @@ +{ + "replace": false, + "values": [ + "minecraft:diamond_ore", + "minecraft:deepslate_diamond_ore" + ] +} diff --git a/src/generated/resources/data/forge/tags/blocks/ores/emerald.json b/src/generated/resources/data/forge/tags/blocks/ores/emerald.json new file mode 100644 index 000000000..4b500671d --- /dev/null +++ b/src/generated/resources/data/forge/tags/blocks/ores/emerald.json @@ -0,0 +1,7 @@ +{ + "replace": false, + "values": [ + "minecraft:emerald_ore", + "minecraft:deepslate_emerald_ore" + ] +} diff --git a/src/generated/resources/data/forge/tags/blocks/ores/gold.json b/src/generated/resources/data/forge/tags/blocks/ores/gold.json index dd9f44b8c..25cf9d5c7 100644 --- a/src/generated/resources/data/forge/tags/blocks/ores/gold.json +++ b/src/generated/resources/data/forge/tags/blocks/ores/gold.json @@ -2,6 +2,7 @@ "replace": false, "values": [ "minecraft:gold_ore", + "minecraft:deepslate_gold_ore", "minecraft:nether_gold_ore" ] } diff --git a/src/generated/resources/data/forge/tags/blocks/ores/iron.json b/src/generated/resources/data/forge/tags/blocks/ores/iron.json new file mode 100644 index 000000000..fd5992751 --- /dev/null +++ b/src/generated/resources/data/forge/tags/blocks/ores/iron.json @@ -0,0 +1,7 @@ +{ + "replace": false, + "values": [ + "minecraft:iron_ore", + "minecraft:deepslate_iron_ore" + ] +} diff --git a/src/generated/resources/data/forge/tags/blocks/ores/lapis.json b/src/generated/resources/data/forge/tags/blocks/ores/lapis.json new file mode 100644 index 000000000..29ad3297f --- /dev/null +++ b/src/generated/resources/data/forge/tags/blocks/ores/lapis.json @@ -0,0 +1,7 @@ +{ + "replace": false, + "values": [ + "minecraft:lapis_ore", + "minecraft:deepslate_lapis_ore" + ] +} diff --git a/src/generated/resources/data/forge/tags/blocks/ores/redstone.json b/src/generated/resources/data/forge/tags/blocks/ores/redstone.json new file mode 100644 index 000000000..fcd797af3 --- /dev/null +++ b/src/generated/resources/data/forge/tags/blocks/ores/redstone.json @@ -0,0 +1,7 @@ +{ + "replace": false, + "values": [ + "minecraft:redstone_ore", + "minecraft:deepslate_redstone_ore" + ] +} diff --git a/src/generated/resources/data/forge/tags/blocks/storage_blocks/copper.json b/src/generated/resources/data/forge/tags/blocks/storage_blocks/copper.json index df8cc0ba7..5b98368c7 100644 --- a/src/generated/resources/data/forge/tags/blocks/storage_blocks/copper.json +++ b/src/generated/resources/data/forge/tags/blocks/storage_blocks/copper.json @@ -1,6 +1,7 @@ { "replace": false, "values": [ - "basemetals:copper_block" + "basemetals:copper_block", + "minecraft:copper_block" ] } diff --git a/src/generated/resources/data/forge/tags/items/ingots/copper.json b/src/generated/resources/data/forge/tags/items/ingots/copper.json index 0bd4e9b4b..46885787a 100644 --- a/src/generated/resources/data/forge/tags/items/ingots/copper.json +++ b/src/generated/resources/data/forge/tags/items/ingots/copper.json @@ -1,6 +1,7 @@ { "replace": false, "values": [ - "basemetals:copper_ingot" + "basemetals:copper_ingot", + "minecraft:copper_ingot" ] } diff --git a/src/generated/resources/data/forge/tags/items/ores/coal.json b/src/generated/resources/data/forge/tags/items/ores/coal.json new file mode 100644 index 000000000..6d8e9392c --- /dev/null +++ b/src/generated/resources/data/forge/tags/items/ores/coal.json @@ -0,0 +1,7 @@ +{ + "replace": false, + "values": [ + "minecraft:coal_ore", + "minecraft:deepslate_coal_ore" + ] +} diff --git a/src/generated/resources/data/forge/tags/items/ores/copper.json b/src/generated/resources/data/forge/tags/items/ores/copper.json index 0d4ca07c6..3492aec8b 100644 --- a/src/generated/resources/data/forge/tags/items/ores/copper.json +++ b/src/generated/resources/data/forge/tags/items/ores/copper.json @@ -1,6 +1,8 @@ { "replace": false, "values": [ - "basemetals:copper_ore" + "basemetals:copper_ore", + "minecraft:copper_ore", + "minecraft:deepslate_copper_ore" ] } diff --git a/src/generated/resources/data/forge/tags/items/ores/diamond.json b/src/generated/resources/data/forge/tags/items/ores/diamond.json new file mode 100644 index 000000000..6c54d7775 --- /dev/null +++ b/src/generated/resources/data/forge/tags/items/ores/diamond.json @@ -0,0 +1,7 @@ +{ + "replace": false, + "values": [ + "minecraft:diamond_ore", + "minecraft:deepslate_diamond_ore" + ] +} diff --git a/src/generated/resources/data/forge/tags/items/ores/emerald.json b/src/generated/resources/data/forge/tags/items/ores/emerald.json new file mode 100644 index 000000000..4b500671d --- /dev/null +++ b/src/generated/resources/data/forge/tags/items/ores/emerald.json @@ -0,0 +1,7 @@ +{ + "replace": false, + "values": [ + "minecraft:emerald_ore", + "minecraft:deepslate_emerald_ore" + ] +} diff --git a/src/generated/resources/data/forge/tags/items/ores/gold.json b/src/generated/resources/data/forge/tags/items/ores/gold.json index dd9f44b8c..25cf9d5c7 100644 --- a/src/generated/resources/data/forge/tags/items/ores/gold.json +++ b/src/generated/resources/data/forge/tags/items/ores/gold.json @@ -2,6 +2,7 @@ "replace": false, "values": [ "minecraft:gold_ore", + "minecraft:deepslate_gold_ore", "minecraft:nether_gold_ore" ] } diff --git a/src/generated/resources/data/forge/tags/items/ores/iron.json b/src/generated/resources/data/forge/tags/items/ores/iron.json new file mode 100644 index 000000000..fd5992751 --- /dev/null +++ b/src/generated/resources/data/forge/tags/items/ores/iron.json @@ -0,0 +1,7 @@ +{ + "replace": false, + "values": [ + "minecraft:iron_ore", + "minecraft:deepslate_iron_ore" + ] +} diff --git a/src/generated/resources/data/forge/tags/items/ores/lapis.json b/src/generated/resources/data/forge/tags/items/ores/lapis.json new file mode 100644 index 000000000..29ad3297f --- /dev/null +++ b/src/generated/resources/data/forge/tags/items/ores/lapis.json @@ -0,0 +1,7 @@ +{ + "replace": false, + "values": [ + "minecraft:lapis_ore", + "minecraft:deepslate_lapis_ore" + ] +} diff --git a/src/generated/resources/data/forge/tags/items/ores/redstone.json b/src/generated/resources/data/forge/tags/items/ores/redstone.json new file mode 100644 index 000000000..fcd797af3 --- /dev/null +++ b/src/generated/resources/data/forge/tags/items/ores/redstone.json @@ -0,0 +1,7 @@ +{ + "replace": false, + "values": [ + "minecraft:redstone_ore", + "minecraft:deepslate_redstone_ore" + ] +} diff --git a/src/generated/resources/data/forge/tags/items/raw_materials.json b/src/generated/resources/data/forge/tags/items/raw_materials.json new file mode 100644 index 000000000..8681a8037 --- /dev/null +++ b/src/generated/resources/data/forge/tags/items/raw_materials.json @@ -0,0 +1,20 @@ +{ + "replace": false, + "values": [ + "#forge:raw_materials/adamantine", + "#forge:raw_materials/antimony", + "#forge:raw_materials/bismuth", + "#forge:raw_materials/coldiron", + "#forge:raw_materials/lead", + "#forge:raw_materials/mercury", + "#forge:raw_materials/nickel", + "#forge:raw_materials/platinum", + "#forge:raw_materials/silver", + "#forge:raw_materials/starsteel", + "#forge:raw_materials/tin", + "#forge:raw_materials/zinc", + "#forge:raw_materials/iron", + "#forge:raw_materials/gold", + "#forge:raw_materials/copper" + ] +} diff --git a/src/generated/resources/data/forge/tags/items/raw_materials/adamantine.json b/src/generated/resources/data/forge/tags/items/raw_materials/adamantine.json new file mode 100644 index 000000000..513108c4e --- /dev/null +++ b/src/generated/resources/data/forge/tags/items/raw_materials/adamantine.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "basemetals:adamantine_raw" + ] +} diff --git a/src/generated/resources/data/forge/tags/items/raw_materials/antimony.json b/src/generated/resources/data/forge/tags/items/raw_materials/antimony.json new file mode 100644 index 000000000..b2fd0cac8 --- /dev/null +++ b/src/generated/resources/data/forge/tags/items/raw_materials/antimony.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "basemetals:antimony_raw" + ] +} diff --git a/src/generated/resources/data/forge/tags/items/raw_materials/bismuth.json b/src/generated/resources/data/forge/tags/items/raw_materials/bismuth.json new file mode 100644 index 000000000..218512f5d --- /dev/null +++ b/src/generated/resources/data/forge/tags/items/raw_materials/bismuth.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "basemetals:bismuth_raw" + ] +} diff --git a/src/generated/resources/data/forge/tags/items/raw_materials/coldiron.json b/src/generated/resources/data/forge/tags/items/raw_materials/coldiron.json new file mode 100644 index 000000000..d927e9b78 --- /dev/null +++ b/src/generated/resources/data/forge/tags/items/raw_materials/coldiron.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "basemetals:coldiron_raw" + ] +} diff --git a/src/generated/resources/data/forge/tags/items/raw_materials/copper.json b/src/generated/resources/data/forge/tags/items/raw_materials/copper.json new file mode 100644 index 000000000..e8108835d --- /dev/null +++ b/src/generated/resources/data/forge/tags/items/raw_materials/copper.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "minecraft:raw_copper" + ] +} diff --git a/src/generated/resources/data/forge/tags/items/raw_materials/gold.json b/src/generated/resources/data/forge/tags/items/raw_materials/gold.json new file mode 100644 index 000000000..29d05c034 --- /dev/null +++ b/src/generated/resources/data/forge/tags/items/raw_materials/gold.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "minecraft:raw_gold" + ] +} diff --git a/src/generated/resources/data/forge/tags/items/raw_materials/iron.json b/src/generated/resources/data/forge/tags/items/raw_materials/iron.json new file mode 100644 index 000000000..a938582ee --- /dev/null +++ b/src/generated/resources/data/forge/tags/items/raw_materials/iron.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "minecraft:raw_iron" + ] +} diff --git a/src/generated/resources/data/forge/tags/items/raw_materials/lead.json b/src/generated/resources/data/forge/tags/items/raw_materials/lead.json new file mode 100644 index 000000000..0cae849a9 --- /dev/null +++ b/src/generated/resources/data/forge/tags/items/raw_materials/lead.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "basemetals:lead_raw" + ] +} diff --git a/src/generated/resources/data/forge/tags/items/raw_materials/mercury.json b/src/generated/resources/data/forge/tags/items/raw_materials/mercury.json new file mode 100644 index 000000000..9b01f7486 --- /dev/null +++ b/src/generated/resources/data/forge/tags/items/raw_materials/mercury.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "basemetals:mercury_raw" + ] +} diff --git a/src/generated/resources/data/forge/tags/items/raw_materials/nickel.json b/src/generated/resources/data/forge/tags/items/raw_materials/nickel.json new file mode 100644 index 000000000..d80809e1d --- /dev/null +++ b/src/generated/resources/data/forge/tags/items/raw_materials/nickel.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "basemetals:nickel_raw" + ] +} diff --git a/src/generated/resources/data/forge/tags/items/raw_materials/platinum.json b/src/generated/resources/data/forge/tags/items/raw_materials/platinum.json new file mode 100644 index 000000000..5fc645027 --- /dev/null +++ b/src/generated/resources/data/forge/tags/items/raw_materials/platinum.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "basemetals:platinum_raw" + ] +} diff --git a/src/generated/resources/data/forge/tags/items/raw_materials/silver.json b/src/generated/resources/data/forge/tags/items/raw_materials/silver.json new file mode 100644 index 000000000..158d764d7 --- /dev/null +++ b/src/generated/resources/data/forge/tags/items/raw_materials/silver.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "basemetals:silver_raw" + ] +} diff --git a/src/generated/resources/data/forge/tags/items/raw_materials/starsteel.json b/src/generated/resources/data/forge/tags/items/raw_materials/starsteel.json new file mode 100644 index 000000000..fb13c55c1 --- /dev/null +++ b/src/generated/resources/data/forge/tags/items/raw_materials/starsteel.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "basemetals:starsteel_raw" + ] +} diff --git a/src/generated/resources/data/forge/tags/items/raw_materials/tin.json b/src/generated/resources/data/forge/tags/items/raw_materials/tin.json new file mode 100644 index 000000000..81625b1aa --- /dev/null +++ b/src/generated/resources/data/forge/tags/items/raw_materials/tin.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "basemetals:tin_raw" + ] +} diff --git a/src/generated/resources/data/forge/tags/items/raw_materials/zinc.json b/src/generated/resources/data/forge/tags/items/raw_materials/zinc.json new file mode 100644 index 000000000..1336c03b2 --- /dev/null +++ b/src/generated/resources/data/forge/tags/items/raw_materials/zinc.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "basemetals:zinc_raw" + ] +} diff --git a/src/generated/resources/data/forge/tags/items/storage_blocks/copper.json b/src/generated/resources/data/forge/tags/items/storage_blocks/copper.json index df8cc0ba7..5b98368c7 100644 --- a/src/generated/resources/data/forge/tags/items/storage_blocks/copper.json +++ b/src/generated/resources/data/forge/tags/items/storage_blocks/copper.json @@ -1,6 +1,7 @@ { "replace": false, "values": [ - "basemetals:copper_block" + "basemetals:copper_block", + "minecraft:copper_block" ] } diff --git a/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json b/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json new file mode 100644 index 000000000..d218b60ee --- /dev/null +++ b/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json @@ -0,0 +1,329 @@ +{ + "replace": false, + "values": [ + "basemetals:adamantine_block", + "basemetals:adamantine_plate", + "basemetals:adamantine_bars", + "basemetals:adamantine_door", + "basemetals:adamantine_trapdoor", + "basemetals:adamantine_button", + "basemetals:adamantine_slab", + "basemetals:adamantine_lever", + "basemetals:adamantine_pressure_plate", + "basemetals:adamantine_stairs", + "basemetals:adamantine_wall", + "basemetals:double_adamantine_slab", + "basemetals:adamantine_ore", + "basemetals:antimony_block", + "basemetals:antimony_plate", + "basemetals:antimony_bars", + "basemetals:antimony_door", + "basemetals:antimony_trapdoor", + "basemetals:antimony_button", + "basemetals:antimony_slab", + "basemetals:antimony_lever", + "basemetals:antimony_pressure_plate", + "basemetals:antimony_stairs", + "basemetals:antimony_wall", + "basemetals:double_antimony_slab", + "basemetals:antimony_ore", + "basemetals:aquarium_block", + "basemetals:aquarium_plate", + "basemetals:aquarium_bars", + "basemetals:aquarium_door", + "basemetals:aquarium_trapdoor", + "basemetals:aquarium_button", + "basemetals:aquarium_slab", + "basemetals:aquarium_lever", + "basemetals:aquarium_pressure_plate", + "basemetals:aquarium_stairs", + "basemetals:aquarium_wall", + "basemetals:double_aquarium_slab", + "basemetals:bismuth_block", + "basemetals:bismuth_plate", + "basemetals:bismuth_bars", + "basemetals:bismuth_door", + "basemetals:bismuth_trapdoor", + "basemetals:bismuth_button", + "basemetals:bismuth_slab", + "basemetals:bismuth_lever", + "basemetals:bismuth_pressure_plate", + "basemetals:bismuth_stairs", + "basemetals:bismuth_wall", + "basemetals:double_bismuth_slab", + "basemetals:bismuth_ore", + "basemetals:brass_block", + "basemetals:brass_plate", + "basemetals:brass_bars", + "basemetals:brass_door", + "basemetals:brass_trapdoor", + "basemetals:brass_button", + "basemetals:brass_slab", + "basemetals:brass_lever", + "basemetals:brass_pressure_plate", + "basemetals:brass_stairs", + "basemetals:brass_wall", + "basemetals:double_brass_slab", + "basemetals:bronze_block", + "basemetals:bronze_plate", + "basemetals:bronze_bars", + "basemetals:bronze_door", + "basemetals:bronze_trapdoor", + "basemetals:bronze_button", + "basemetals:bronze_slab", + "basemetals:bronze_lever", + "basemetals:bronze_pressure_plate", + "basemetals:bronze_stairs", + "basemetals:bronze_wall", + "basemetals:double_bronze_slab", + "basemetals:coldiron_block", + "basemetals:coldiron_plate", + "basemetals:coldiron_bars", + "basemetals:coldiron_door", + "basemetals:coldiron_trapdoor", + "basemetals:coldiron_button", + "basemetals:coldiron_slab", + "basemetals:coldiron_lever", + "basemetals:coldiron_pressure_plate", + "basemetals:coldiron_stairs", + "basemetals:coldiron_wall", + "basemetals:double_coldiron_slab", + "basemetals:coldiron_ore", + "basemetals:copper_block", + "basemetals:copper_plate", + "basemetals:copper_bars", + "basemetals:copper_door", + "basemetals:copper_trapdoor", + "basemetals:copper_button", + "basemetals:copper_slab", + "basemetals:copper_lever", + "basemetals:copper_pressure_plate", + "basemetals:copper_stairs", + "basemetals:copper_wall", + "basemetals:double_copper_slab", + "basemetals:copper_ore", + "basemetals:cupronickel_block", + "basemetals:cupronickel_plate", + "basemetals:cupronickel_bars", + "basemetals:cupronickel_door", + "basemetals:cupronickel_trapdoor", + "basemetals:cupronickel_button", + "basemetals:cupronickel_slab", + "basemetals:cupronickel_lever", + "basemetals:cupronickel_pressure_plate", + "basemetals:cupronickel_stairs", + "basemetals:cupronickel_wall", + "basemetals:double_cupronickel_slab", + "basemetals:electrum_block", + "basemetals:electrum_plate", + "basemetals:electrum_bars", + "basemetals:electrum_door", + "basemetals:electrum_trapdoor", + "basemetals:electrum_button", + "basemetals:electrum_slab", + "basemetals:electrum_lever", + "basemetals:electrum_pressure_plate", + "basemetals:electrum_stairs", + "basemetals:electrum_wall", + "basemetals:double_electrum_slab", + "basemetals:invar_block", + "basemetals:invar_plate", + "basemetals:invar_bars", + "basemetals:invar_door", + "basemetals:invar_trapdoor", + "basemetals:invar_button", + "basemetals:invar_slab", + "basemetals:invar_lever", + "basemetals:invar_pressure_plate", + "basemetals:invar_stairs", + "basemetals:invar_wall", + "basemetals:double_invar_slab", + "basemetals:lead_block", + "basemetals:lead_plate", + "basemetals:lead_bars", + "basemetals:lead_door", + "basemetals:lead_trapdoor", + "basemetals:lead_button", + "basemetals:lead_slab", + "basemetals:lead_lever", + "basemetals:lead_pressure_plate", + "basemetals:lead_stairs", + "basemetals:lead_wall", + "basemetals:double_lead_slab", + "basemetals:lead_ore", + "basemetals:mercury_ore", + "basemetals:mithril_block", + "basemetals:mithril_plate", + "basemetals:mithril_bars", + "basemetals:mithril_door", + "basemetals:mithril_trapdoor", + "basemetals:mithril_button", + "basemetals:mithril_slab", + "basemetals:mithril_lever", + "basemetals:mithril_pressure_plate", + "basemetals:mithril_stairs", + "basemetals:mithril_wall", + "basemetals:double_mithril_slab", + "basemetals:nickel_block", + "basemetals:nickel_plate", + "basemetals:nickel_bars", + "basemetals:nickel_door", + "basemetals:nickel_trapdoor", + "basemetals:nickel_button", + "basemetals:nickel_slab", + "basemetals:nickel_lever", + "basemetals:nickel_pressure_plate", + "basemetals:nickel_stairs", + "basemetals:nickel_wall", + "basemetals:double_nickel_slab", + "basemetals:nickel_ore", + "basemetals:pewter_block", + "basemetals:pewter_plate", + "basemetals:pewter_bars", + "basemetals:pewter_door", + "basemetals:pewter_trapdoor", + "basemetals:pewter_button", + "basemetals:pewter_slab", + "basemetals:pewter_lever", + "basemetals:pewter_pressure_plate", + "basemetals:pewter_stairs", + "basemetals:pewter_wall", + "basemetals:double_pewter_slab", + "basemetals:platinum_block", + "basemetals:platinum_plate", + "basemetals:platinum_bars", + "basemetals:platinum_door", + "basemetals:platinum_trapdoor", + "basemetals:platinum_button", + "basemetals:platinum_slab", + "basemetals:platinum_lever", + "basemetals:platinum_pressure_plate", + "basemetals:platinum_stairs", + "basemetals:platinum_wall", + "basemetals:double_platinum_slab", + "basemetals:platinum_ore", + "basemetals:silver_block", + "basemetals:silver_plate", + "basemetals:silver_bars", + "basemetals:silver_door", + "basemetals:silver_trapdoor", + "basemetals:silver_button", + "basemetals:silver_slab", + "basemetals:silver_lever", + "basemetals:silver_pressure_plate", + "basemetals:silver_stairs", + "basemetals:silver_wall", + "basemetals:double_silver_slab", + "basemetals:silver_ore", + "basemetals:starsteel_block", + "basemetals:starsteel_plate", + "basemetals:starsteel_bars", + "basemetals:starsteel_door", + "basemetals:starsteel_trapdoor", + "basemetals:starsteel_button", + "basemetals:starsteel_slab", + "basemetals:starsteel_lever", + "basemetals:starsteel_pressure_plate", + "basemetals:starsteel_stairs", + "basemetals:starsteel_wall", + "basemetals:double_starsteel_slab", + "basemetals:starsteel_ore", + "basemetals:steel_block", + "basemetals:steel_plate", + "basemetals:steel_bars", + "basemetals:steel_door", + "basemetals:steel_trapdoor", + "basemetals:steel_button", + "basemetals:steel_slab", + "basemetals:steel_lever", + "basemetals:steel_pressure_plate", + "basemetals:steel_stairs", + "basemetals:steel_wall", + "basemetals:double_steel_slab", + "basemetals:tin_block", + "basemetals:tin_plate", + "basemetals:tin_bars", + "basemetals:tin_door", + "basemetals:tin_trapdoor", + "basemetals:tin_button", + "basemetals:tin_slab", + "basemetals:tin_lever", + "basemetals:tin_pressure_plate", + "basemetals:tin_stairs", + "basemetals:tin_wall", + "basemetals:double_tin_slab", + "basemetals:tin_ore", + "basemetals:zinc_block", + "basemetals:zinc_plate", + "basemetals:zinc_bars", + "basemetals:zinc_door", + "basemetals:zinc_trapdoor", + "basemetals:zinc_button", + "basemetals:zinc_slab", + "basemetals:zinc_lever", + "basemetals:zinc_pressure_plate", + "basemetals:zinc_stairs", + "basemetals:zinc_wall", + "basemetals:double_zinc_slab", + "basemetals:zinc_ore", + "basemetals:stone_anvil", + "basemetals:steel_anvil", + "basemetals:adamantine_anvil", + "basemetals:human_detector", + "basemetals:charcoal_block", + "basemetals:diamond_bars", + "basemetals:diamond_door", + "basemetals:diamond_trapdoor", + "basemetals:diamond_button", + "basemetals:diamond_slab", + "basemetals:diamond_lever", + "basemetals:diamond_pressure_plate", + "basemetals:diamond_stairs", + "basemetals:diamond_wall", + "basemetals:double_diamond_slab", + "basemetals:emerald_bars", + "basemetals:emerald_door", + "basemetals:emerald_trapdoor", + "basemetals:emerald_button", + "basemetals:emerald_slab", + "basemetals:emerald_lever", + "basemetals:emerald_pressure_plate", + "basemetals:emerald_stairs", + "basemetals:emerald_wall", + "basemetals:double_emerald_slab", + "basemetals:gold_bars", + "basemetals:gold_door", + "basemetals:gold_trapdoor", + "basemetals:gold_button", + "basemetals:gold_slab", + "basemetals:gold_lever", + "basemetals:gold_stairs", + "basemetals:gold_wall", + "basemetals:double_gold_slab", + "basemetals:obsidian_bars", + "basemetals:obsidian_door", + "basemetals:obsidian_trapdoor", + "basemetals:obsidian_button", + "basemetals:obsidian_slab", + "basemetals:obsidian_lever", + "basemetals:obsidian_pressure_plate", + "basemetals:obsidian_stairs", + "basemetals:obsidian_wall", + "basemetals:double_obsidian_slab", + "basemetals:iron_button", + "basemetals:iron_slab", + "basemetals:iron_lever", + "basemetals:iron_stairs", + "basemetals:iron_wall", + "basemetals:double_iron_slab", + "basemetals:quartz_bars", + "basemetals:quartz_door", + "basemetals:quartz_trapdoor", + "basemetals:quartz_button", + "basemetals:quartz_lever", + "basemetals:quartz_pressure_plate", + "basemetals:quartz_wall", + "basemetals:gold_plate", + "basemetals:iron_plate" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/minecraft/tags/blocks/needs_diamond_tool.json b/src/generated/resources/data/minecraft/tags/blocks/needs_diamond_tool.json new file mode 100644 index 000000000..8e8cdd60d --- /dev/null +++ b/src/generated/resources/data/minecraft/tags/blocks/needs_diamond_tool.json @@ -0,0 +1,62 @@ +{ + "replace": false, + "values": [ + "basemetals:adamantine_block", + "basemetals:adamantine_plate", + "basemetals:adamantine_bars", + "basemetals:adamantine_door", + "basemetals:adamantine_trapdoor", + "basemetals:adamantine_button", + "basemetals:adamantine_slab", + "basemetals:adamantine_lever", + "basemetals:adamantine_pressure_plate", + "basemetals:adamantine_stairs", + "basemetals:adamantine_wall", + "basemetals:double_adamantine_slab", + "basemetals:adamantine_ore", + "basemetals:starsteel_block", + "basemetals:starsteel_plate", + "basemetals:starsteel_bars", + "basemetals:starsteel_door", + "basemetals:starsteel_trapdoor", + "basemetals:starsteel_button", + "basemetals:starsteel_slab", + "basemetals:starsteel_lever", + "basemetals:starsteel_pressure_plate", + "basemetals:starsteel_stairs", + "basemetals:starsteel_wall", + "basemetals:double_starsteel_slab", + "basemetals:starsteel_ore", + "basemetals:adamantine_anvil", + "basemetals:diamond_bars", + "basemetals:diamond_door", + "basemetals:diamond_trapdoor", + "basemetals:diamond_button", + "basemetals:diamond_slab", + "basemetals:diamond_lever", + "basemetals:diamond_pressure_plate", + "basemetals:diamond_stairs", + "basemetals:diamond_wall", + "basemetals:double_diamond_slab", + "basemetals:emerald_bars", + "basemetals:emerald_door", + "basemetals:emerald_trapdoor", + "basemetals:emerald_button", + "basemetals:emerald_slab", + "basemetals:emerald_lever", + "basemetals:emerald_pressure_plate", + "basemetals:emerald_stairs", + "basemetals:emerald_wall", + "basemetals:double_emerald_slab", + "basemetals:obsidian_bars", + "basemetals:obsidian_door", + "basemetals:obsidian_trapdoor", + "basemetals:obsidian_button", + "basemetals:obsidian_slab", + "basemetals:obsidian_lever", + "basemetals:obsidian_pressure_plate", + "basemetals:obsidian_stairs", + "basemetals:obsidian_wall", + "basemetals:double_obsidian_slab" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/minecraft/tags/blocks/needs_iron_tool.json b/src/generated/resources/data/minecraft/tags/blocks/needs_iron_tool.json new file mode 100644 index 000000000..1e0b7a298 --- /dev/null +++ b/src/generated/resources/data/minecraft/tags/blocks/needs_iron_tool.json @@ -0,0 +1,74 @@ +{ + "replace": false, + "values": [ + "basemetals:bronze_block", + "basemetals:bronze_plate", + "basemetals:bronze_bars", + "basemetals:bronze_door", + "basemetals:bronze_trapdoor", + "basemetals:bronze_button", + "basemetals:bronze_slab", + "basemetals:bronze_lever", + "basemetals:bronze_pressure_plate", + "basemetals:bronze_stairs", + "basemetals:bronze_wall", + "basemetals:double_bronze_slab", + "basemetals:coldiron_block", + "basemetals:coldiron_plate", + "basemetals:coldiron_bars", + "basemetals:coldiron_door", + "basemetals:coldiron_trapdoor", + "basemetals:coldiron_button", + "basemetals:coldiron_slab", + "basemetals:coldiron_lever", + "basemetals:coldiron_pressure_plate", + "basemetals:coldiron_stairs", + "basemetals:coldiron_wall", + "basemetals:double_coldiron_slab", + "basemetals:coldiron_ore", + "basemetals:invar_block", + "basemetals:invar_plate", + "basemetals:invar_bars", + "basemetals:invar_door", + "basemetals:invar_trapdoor", + "basemetals:invar_button", + "basemetals:invar_slab", + "basemetals:invar_lever", + "basemetals:invar_pressure_plate", + "basemetals:invar_stairs", + "basemetals:invar_wall", + "basemetals:double_invar_slab", + "basemetals:mithril_block", + "basemetals:mithril_plate", + "basemetals:mithril_bars", + "basemetals:mithril_door", + "basemetals:mithril_trapdoor", + "basemetals:mithril_button", + "basemetals:mithril_slab", + "basemetals:mithril_lever", + "basemetals:mithril_pressure_plate", + "basemetals:mithril_stairs", + "basemetals:mithril_wall", + "basemetals:double_mithril_slab", + "basemetals:steel_block", + "basemetals:steel_plate", + "basemetals:steel_bars", + "basemetals:steel_door", + "basemetals:steel_trapdoor", + "basemetals:steel_button", + "basemetals:steel_slab", + "basemetals:steel_lever", + "basemetals:steel_pressure_plate", + "basemetals:steel_stairs", + "basemetals:steel_wall", + "basemetals:double_steel_slab", + "basemetals:steel_anvil", + "basemetals:iron_button", + "basemetals:iron_slab", + "basemetals:iron_lever", + "basemetals:iron_stairs", + "basemetals:iron_wall", + "basemetals:double_iron_slab", + "basemetals:iron_plate" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/minecraft/tags/blocks/needs_stone_tool.json b/src/generated/resources/data/minecraft/tags/blocks/needs_stone_tool.json new file mode 100644 index 000000000..c0ae3d2f5 --- /dev/null +++ b/src/generated/resources/data/minecraft/tags/blocks/needs_stone_tool.json @@ -0,0 +1,101 @@ +{ + "replace": false, + "values": [ + "basemetals:aquarium_block", + "basemetals:aquarium_plate", + "basemetals:aquarium_bars", + "basemetals:aquarium_door", + "basemetals:aquarium_trapdoor", + "basemetals:aquarium_button", + "basemetals:aquarium_slab", + "basemetals:aquarium_lever", + "basemetals:aquarium_pressure_plate", + "basemetals:aquarium_stairs", + "basemetals:aquarium_wall", + "basemetals:double_aquarium_slab", + "basemetals:brass_block", + "basemetals:brass_plate", + "basemetals:brass_bars", + "basemetals:brass_door", + "basemetals:brass_trapdoor", + "basemetals:brass_button", + "basemetals:brass_slab", + "basemetals:brass_lever", + "basemetals:brass_pressure_plate", + "basemetals:brass_stairs", + "basemetals:brass_wall", + "basemetals:double_brass_slab", + "basemetals:copper_block", + "basemetals:copper_plate", + "basemetals:copper_bars", + "basemetals:copper_door", + "basemetals:copper_trapdoor", + "basemetals:copper_button", + "basemetals:copper_slab", + "basemetals:copper_lever", + "basemetals:copper_pressure_plate", + "basemetals:copper_stairs", + "basemetals:copper_wall", + "basemetals:double_copper_slab", + "basemetals:copper_ore", + "basemetals:cupronickel_block", + "basemetals:cupronickel_plate", + "basemetals:cupronickel_bars", + "basemetals:cupronickel_door", + "basemetals:cupronickel_trapdoor", + "basemetals:cupronickel_button", + "basemetals:cupronickel_slab", + "basemetals:cupronickel_lever", + "basemetals:cupronickel_pressure_plate", + "basemetals:cupronickel_stairs", + "basemetals:cupronickel_wall", + "basemetals:double_cupronickel_slab", + "basemetals:electrum_block", + "basemetals:electrum_plate", + "basemetals:electrum_bars", + "basemetals:electrum_door", + "basemetals:electrum_trapdoor", + "basemetals:electrum_button", + "basemetals:electrum_slab", + "basemetals:electrum_lever", + "basemetals:electrum_pressure_plate", + "basemetals:electrum_stairs", + "basemetals:electrum_wall", + "basemetals:double_electrum_slab", + "basemetals:nickel_block", + "basemetals:nickel_plate", + "basemetals:nickel_bars", + "basemetals:nickel_door", + "basemetals:nickel_trapdoor", + "basemetals:nickel_button", + "basemetals:nickel_slab", + "basemetals:nickel_lever", + "basemetals:nickel_pressure_plate", + "basemetals:nickel_stairs", + "basemetals:nickel_wall", + "basemetals:double_nickel_slab", + "basemetals:nickel_ore", + "basemetals:silver_block", + "basemetals:silver_plate", + "basemetals:silver_bars", + "basemetals:silver_door", + "basemetals:silver_trapdoor", + "basemetals:silver_button", + "basemetals:silver_slab", + "basemetals:silver_lever", + "basemetals:silver_pressure_plate", + "basemetals:silver_stairs", + "basemetals:silver_wall", + "basemetals:double_silver_slab", + "basemetals:silver_ore", + "basemetals:stone_anvil", + "basemetals:charcoal_block", + "basemetals:quartz_bars", + "basemetals:quartz_door", + "basemetals:quartz_trapdoor", + "basemetals:quartz_button", + "basemetals:quartz_lever", + "basemetals:quartz_pressure_plate", + "basemetals:quartz_wall" + ] +} \ No newline at end of file diff --git a/src/integrationTest/java/zone/moddev/mc/basemetals/testmod/BaseMetalsRuntimeProbe.java b/src/integrationTest/java/zone/moddev/mc/basemetals/testmod/BaseMetalsRuntimeProbe.java index 774361206..cf385bd67 100644 --- a/src/integrationTest/java/zone/moddev/mc/basemetals/testmod/BaseMetalsRuntimeProbe.java +++ b/src/integrationTest/java/zone/moddev/mc/basemetals/testmod/BaseMetalsRuntimeProbe.java @@ -34,51 +34,51 @@ import zone.moddev.mc.basemetals.migration.LegacyWorldDataHook; import zone.moddev.mc.basemetals.recipe.CrushingRecipe; -import net.minecraft.block.AnvilBlock; -import net.minecraft.block.Block; -import net.minecraft.block.AbstractButtonBlock; -import net.minecraft.block.DoorBlock; -import net.minecraft.block.FlowingFluidBlock; -import net.minecraft.block.PressurePlateBlock; -import net.minecraft.block.SlabBlock; -import net.minecraft.enchantment.EnchantmentHelper; -import net.minecraft.entity.Entity; -import net.minecraft.entity.item.ArmorStandEntity; -import net.minecraft.block.BlockState; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.enchantment.Enchantments; -import net.minecraft.potion.Effects; -import net.minecraft.inventory.EquipmentSlotType; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.item.crafting.IRecipe; -import net.minecraft.nbt.CompressedStreamTools; -import net.minecraft.nbt.CompoundNBT; -import net.minecraft.nbt.ListNBT; -import net.minecraft.potion.EffectInstance; +import net.minecraft.world.level.block.AnvilBlock; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.ButtonBlock; +import net.minecraft.world.level.block.DoorBlock; +import net.minecraft.world.level.block.LiquidBlock; +import net.minecraft.world.level.block.PressurePlateBlock; +import net.minecraft.world.level.block.SlabBlock; +import net.minecraft.world.item.enchantment.EnchantmentHelper; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.enchantment.Enchantments; +import net.minecraft.world.effect.MobEffects; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.nbt.NbtIo; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.server.MinecraftServer; import net.minecraft.tags.ItemTags; -import net.minecraft.tileentity.TileEntity; -import net.minecraft.tileentity.ChestTileEntity; -import net.minecraft.util.Direction; -import net.minecraft.util.Hand; -import net.minecraft.util.ResourceLocation; -import net.minecraft.util.registry.Registry; -import net.minecraft.util.math.AxisAlignedBB; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.server.ServerWorld; -import net.minecraft.world.chunk.Chunk; -import net.minecraft.world.chunk.ChunkSection; -import net.minecraft.world.World; -import net.minecraft.util.RegistryKey; -import net.minecraft.loot.LootTable; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.ChestBlockEntity; +import net.minecraft.core.Direction; +import net.minecraft.world.InteractionHand; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.core.Registry; +import net.minecraft.world.phys.AABB; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.Level; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.level.storage.loot.LootTable; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.util.FakePlayer; import net.minecraftforge.common.util.FakePlayerFactory; import net.minecraftforge.event.AnvilUpdateEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.event.TickEvent; -import net.minecraftforge.fml.event.server.FMLServerStartedEvent; +import net.minecraftforge.fmlserverevents.FMLServerStartedEvent; import net.minecraftforge.registries.ForgeRegistries; import org.apache.logging.log4j.LogManager; @@ -90,27 +90,31 @@ public final class BaseMetalsRuntimeProbe { static final String MODID = "basemetalsprobe"; private static final Logger LOGGER = LogManager.getLogger(MODID); private int checks; + private MinecraftServer pendingUpgrade; + private final java.util.Set equipmentChunks = new java.util.HashSet<>(); + private int upgradeWaitTicks; public BaseMetalsRuntimeProbe() { MinecraftForge.EVENT_BUS.addListener(this::serverStarted); + MinecraftForge.EVENT_BUS.addListener(this::serverTick); MinecraftForge.EVENT_BUS.addListener(net.minecraftforge.eventbus.api.EventPriority.LOWEST, this::login); } private void login(net.minecraftforge.event.entity.player.PlayerEvent.PlayerLoggedInEvent event) { if (!"login".equals(System.getProperty("basemetalsprobe.mode"))) return; - event.getPlayer().inventory.setItem(0, + event.getPlayer().getInventory().setItem(0, new ItemStack(ModContent.item("tin_bow").get())); if (Boolean.getBoolean("basemetalsprobe.modeSwitch")) { - net.minecraft.entity.player.ServerPlayerEntity player = (net.minecraft.entity.player.ServerPlayerEntity) event.getPlayer(); + net.minecraft.server.level.ServerPlayer player = (net.minecraft.server.level.ServerPlayer) event.getPlayer(); if (zone.moddev.mc.basemetals.config.BaseMetalsConfig.activeMode() == zone.moddev.mc.basemetals.config.ContentMode.LOW_FANTASY) { - player.inventory.setItem(1, new ItemStack(ModContent.item("tin_ingot").get())); - player.inventory.setItem(2, new ItemStack(ModContent.item("adamantine_ingot").get())); + player.getInventory().setItem(1, new ItemStack(ModContent.item("tin_ingot").get())); + player.getInventory().setItem(2, new ItemStack(ModContent.item("adamantine_ingot").get())); // Also save progress earned through the original 1.13 rod criterion. - player.inventory.setItem(3, new ItemStack(ModContent.item("steel_rod").get())); + player.getInventory().setItem(3, new ItemStack(ModContent.item("steel_rod").get())); for (int slot = 1; slot <= 3; slot++) { net.minecraft.advancements.CriteriaTriggers.INVENTORY_CHANGED.trigger( - player, player.inventory, player.inventory.getItem(slot)); + player, player.getInventory(), player.getInventory().getItem(slot)); } } @@ -121,7 +125,7 @@ private void login(net.minecraftforge.event.entity.player.PlayerEvent.PlayerLogg if (!player.getAdvancements().getOrStartProgress(advancement).isDone()) { throw new IllegalStateException("Material discovery did not earn the recipe advancement: " + name); } - IRecipe recipe = player.getServer().getRecipeManager().byKey(new ResourceLocation("basemetals", name)).orElse(null); + Recipe recipe = player.getServer().getRecipeManager().byKey(new ResourceLocation("basemetals", name)).orElse(null); if (player.getRecipeBook().contains(recipe) == recipe.isSpecial()) { throw new IllegalStateException("Wrong recipe-book visibility after mode change: " + name); } @@ -137,7 +141,7 @@ private void serverStarted(FMLServerStartedEvent event) { MinecraftServer server = event.getServer(); if ("login".equals(System.getProperty("basemetalsprobe.mode"))) { try { - int count = ContentModeChecks.run(server) + Native116Checks.run(server); + int count = ContentModeChecks.run(server) + Native117Checks.run(server) + RawOreChecks.run(server); LOGGER.info("BASEMETALS_CONTENT_MODE_PROBE PASS mode={} checks={}", zone.moddev.mc.basemetals.config.BaseMetalsConfig.activeMode().serializedName(), count); } catch (Exception failure) { @@ -146,10 +150,59 @@ private void serverStarted(FMLServerStartedEvent event) { return; } boolean legacyUpgrade = "legacy-upgrade".equals(System.getProperty("basemetalsprobe.mode")); + if (legacyUpgrade) { + prepareEquipmentChunks(server); + pendingUpgrade = server; + return; + } + performServerChecks(server, false); + } + + private void prepareEquipmentChunks(MinecraftServer server) { + Path manifestFile = server.getWorldPath(net.minecraft.world.level.storage.LevelResource.ROOT) + .resolve("legacy_registry_manifest_runtime.json"); + if (!Files.isRegularFile(manifestFile)) return; + + try (Reader reader = Files.newBufferedReader(manifestFile, StandardCharsets.UTF_8)) { + JsonObject manifest = new JsonParser().parse(reader).getAsJsonObject(); + for (JsonElement entry : manifest.getAsJsonArray("items")) { + JsonObject item = entry.getAsJsonObject(); + if (!item.has("armor_stand")) continue; + + int x = (int) Math.floor(item.get("armor_x").getAsDouble()) >> 4; + int z = (int) Math.floor(item.get("armor_z").getAsDouble()) >> 4; + equipmentChunks.add(new net.minecraft.world.level.ChunkPos(x, z)); + server.overworld().setChunkForced(x, z, true); + server.overworld().getChunk(x, z); + } + } catch (IOException failure) { + throw new IllegalStateException("Cannot read the upgrade equipment manifest", failure); + } + } + + private void serverTick(TickEvent.ServerTickEvent event) { + if (event.phase != TickEvent.Phase.END || pendingUpgrade == null) return; + MinecraftServer server = pendingUpgrade; + if (++upgradeWaitTicks < 20) return; + boolean loaded = equipmentChunks.stream().allMatch(chunk -> server.overworld().areEntitiesLoaded(chunk.toLong())); + if (!loaded && upgradeWaitTicks < 200) return; + pendingUpgrade = null; + + // Entity storage is asynchronous in 1.17. Check equipment only after its chunks have loaded. + if (!loaded) throw new IllegalStateException("Timed out loading upgrade equipment chunks"); + performServerChecks(server, true); + } + + private void performServerChecks(MinecraftServer server, boolean legacyUpgrade) { try { runChecks(server); if (Boolean.getBoolean("basemetalsprobe.sampleOres")) checks += OrePlacementChecks.run(server); - if (legacyUpgrade) verifyLegacyWorld(server); + if (legacyUpgrade) { + verifyLegacyWorld(server); + // Keep distant fixture entities loaded until their checks and save have finished. + server.saveAllChunks(true, true, false); + equipmentChunks.forEach(chunk -> server.overworld().setChunkForced(chunk.x, chunk.z, false)); + } if (checks < 32) throw new IllegalStateException("Only ran " + checks + " runtime checks"); LOGGER.info(legacyUpgrade ? "BASEMETALS_LEGACY_UPGRADE_PROBE PASS checks={}" : "BASEMETALS_RUNTIME_PROBE PASS checks={}", Integer.valueOf(checks)); @@ -164,8 +217,8 @@ private void serverStarted(FMLServerStartedEvent event) { } private void verifyLegacyWorld(MinecraftServer server) throws IOException { - ServerWorld overworld = require(server.getLevel(World.OVERWORLD), "legacy overworld missing"); - Path root = server.getWorldPath(net.minecraft.world.storage.FolderName.ROOT); + ServerLevel overworld = require(server.getLevel(Level.OVERWORLD), "legacy overworld missing"); + Path root = server.getWorldPath(net.minecraft.world.level.storage.LevelResource.ROOT); if (Files.isRegularFile(root.resolve("legacy_registry_manifest_runtime.json"))) { verifyLegacyFixture(server, root); } else { @@ -174,7 +227,7 @@ private void verifyLegacyWorld(MinecraftServer server) throws IOException { verifySavedAdvancements(server, overworld, root); } - private void verifySavedAdvancements(MinecraftServer server, ServerWorld world, Path root) throws IOException { + private void verifySavedAdvancements(MinecraftServer server, ServerLevel world, Path root) throws IOException { Path fixtureFile = root.resolve("basemetals_advancement_upgrade_fixture.json"); if (!Files.isRegularFile(fixtureFile)) return; @@ -218,7 +271,7 @@ private void verifyLegacyFixture(MinecraftServer server, Path root) throws IOExc int checkedPlayerItems = 0; boolean source110 = Files.isRegularFile(root.resolve("BASEMETALS_1_10_FIXTURE_COMPLETE.txt")); - String upgradeMarker = source110 ? "BASEMETALS_1_10_TO_1_16_UPGRADE" : "BASEMETALS_1_12_TO_1_16_UPGRADE"; + String upgradeMarker = source110 ? "BASEMETALS_1_10_TO_1_17_UPGRADE" : "BASEMETALS_1_12_TO_1_17_UPGRADE"; if (!source110 && !Files.isRegularFile(root.resolve("BASEMETALS_1_12_FIXTURE_COMPLETE.txt"))) { failures.add("missing legacy fixture completion marker"); } @@ -239,7 +292,7 @@ private void verifyLegacyFixture(MinecraftServer server, Path root) throws IOExc for (JsonElement stateElement : block.getAsJsonArray("states")) { JsonObject oldState = stateElement.getAsJsonObject(); int dimension = oldState.has("dimension") ? oldState.get("dimension").getAsInt() : 0; - ServerWorld world = fixtureWorld(server, dimension); + ServerLevel world = fixtureWorld(server, dimension); BlockPos pos = new BlockPos(oldState.get("x").getAsInt(), oldState.get("y").getAsInt(), oldState.get("z").getAsInt()); BlockState actualState = world.getBlockState(pos); @@ -260,7 +313,7 @@ private void verifyLegacyFixture(MinecraftServer server, Path root) throws IOExc } } - ServerWorld overworld = fixtureWorld(server, 0); + ServerLevel overworld = fixtureWorld(server, 0); for (JsonElement itemElement : manifest.getAsJsonArray("items")) { JsonObject oldItem = itemElement.getAsJsonObject(); int chestIndex = oldItem.get("chest").getAsInt(); @@ -268,20 +321,20 @@ private void verifyLegacyFixture(MinecraftServer server, Path root) throws IOExc BlockPos pos = new BlockPos(oldItem.get("chest_x").getAsInt(), oldItem.get("chest_y").getAsInt(), oldItem.get("chest_z").getAsInt()); overworld.getBlockState(pos); // Force the legacy container chunk through datafixing before lookup. - TileEntity blockEntity = overworld.getBlockEntity(pos); - if (!(blockEntity instanceof ChestTileEntity)) { + BlockEntity blockEntity = overworld.getBlockEntity(pos); + if (!(blockEntity instanceof ChestBlockEntity)) { if (failures.size() < 20) failures.add("missing inventory chest " + chestIndex + " at " + pos + " state=" + overworld.getBlockState(pos) + " tile=" + (blockEntity == null ? "null" : blockEntity.getClass().getName())); itemMismatches++; continue; } - ItemStack stack = ((ChestTileEntity) blockEntity).getItem(slot); + ItemStack stack = ((ChestBlockEntity) blockEntity).getItem(slot); String expected = currentItemId(oldItem.get("id").getAsString()); String actual = String.valueOf(ForgeRegistries.ITEMS.getKey(stack.getItem())); int expectedCount = oldItem.has("count") ? oldItem.get("count").getAsInt() : 1; int expectedDamage = oldItem.has("damage") ? oldItem.get("damage").getAsInt() : 0; - CompoundNBT tag = stack.getTag(); + CompoundTag tag = stack.getTag(); boolean proofMatches = format < 2 || tag != null && tag.getCompound("basemetals_fixture").getString("proof") .equals(oldItem.get("id").getAsString()); @@ -305,14 +358,19 @@ private void verifyLegacyFixture(MinecraftServer server, Path root) throws IOExc (int) Math.floor(oldItem.get("armor_y").getAsDouble()), (int) Math.floor(oldItem.get("armor_z").getAsDouble())); overworld.getBlockState(armorPos); - List stands = overworld.getEntitiesOfClass(ArmorStandEntity.class, - new AxisAlignedBB(armorPos).inflate(0.75D)); - EquipmentSlotType equipmentSlot = equipmentSlot(oldItem.get("armor_slot").getAsString()); + // Some older fixtures have ordinary gravity, so the stand may fall within its column. + List stands = overworld.getEntitiesOfClass(ArmorStand.class, + new AABB(armorPos.getX() - 0.75D, overworld.getMinBuildHeight(), armorPos.getZ() - 0.75D, + armorPos.getX() + 1.75D, overworld.getMaxBuildHeight(), armorPos.getZ() + 1.75D)); + EquipmentSlot equipmentSlot = equipmentSlot(oldItem.get("armor_slot").getAsString()); boolean equipped = false; - for (ArmorStandEntity stand : stands) { + for (ArmorStand stand : stands) { ItemStack worn = stand.getItemBySlot(equipmentSlot); if (expected.equals(String.valueOf(ForgeRegistries.ITEMS.getKey(worn.getItem()))) - && worn.getDamageValue() == expectedDamage) { + && worn.getDamageValue() == expectedDamage + && worn.hasTag() && worn.getTag().getCompound("basemetals_fixture") + .getString("proof").equals(oldItem.get("id").getAsString()) + && EnchantmentHelper.getItemEnchantmentLevel(Enchantments.UNBREAKING, worn) == 2) { equipped = true; break; } @@ -335,12 +393,12 @@ private void verifyLegacyFixture(MinecraftServer server, Path root) throws IOExc BlockPos pos = new BlockPos(fluid.get("bucket_chest_x").getAsInt(), fluid.get("bucket_chest_y").getAsInt(), fluid.get("bucket_chest_z").getAsInt()); overworld.getBlockState(pos); // Load the chunk before looking up its tile entity. - TileEntity blockEntity = overworld.getBlockEntity(pos); + BlockEntity blockEntity = overworld.getBlockEntity(pos); String expected = BaseMetals.MOD_ID + ":" + MissingMappings.fluidTargetPath(fluid.get("name").getAsString()) + "_bucket"; - if (!(blockEntity instanceof ChestTileEntity) + if (!(blockEntity instanceof ChestBlockEntity) || !expected.equals(String.valueOf(ForgeRegistries.ITEMS.getKey( - ((ChestTileEntity) blockEntity).getItem(slot).getItem())))) { + ((ChestBlockEntity) blockEntity).getItem(slot).getItem())))) { if (failures.size() < 20) { failures.add("legacy filled bucket " + chestIndex + ":" + slot + " did not become " + expected); @@ -359,15 +417,15 @@ private void verifyLegacyFixture(MinecraftServer server, Path root) throws IOExc failures.add("fixture playerdata did not load: " + playerFile.getName()); continue; } - CompoundNBT playerData; + CompoundTag playerData; try (FileInputStream input = new FileInputStream(playerFile)) { - playerData = CompressedStreamTools.readCompressed(input); + playerData = NbtIo.readCompressed(input); } - ListNBT inventory = playerData.getList("Inventory", 10); + ListTag inventory = playerData.getList("Inventory", 10); for (JsonElement inventoryElement : savedPlayer.getAsJsonArray("inventory")) { JsonObject expectedItem = inventoryElement.getAsJsonObject(); int slot = expectedItem.get("slot").getAsInt(); - CompoundNBT actualItem = inventoryItem(inventory, slot); + CompoundTag actualItem = inventoryItem(inventory, slot); String expected = currentItemId(expectedItem.get("id").getAsString()); boolean proof = actualItem != null && actualItem.getCompound("tag") .getCompound("basemetals_fixture").getString("player_proof") @@ -405,7 +463,7 @@ private static boolean matchesSavedProperties(BlockState actual, JsonObject save if (!saved.has("saved_properties")) return true; JsonObject properties = saved.getAsJsonObject("saved_properties"); Map current = new java.util.LinkedHashMap(); - for (Map.Entry, Comparable> entry : actual.getValues().entrySet()) { + for (Map.Entry, Comparable> entry : actual.getValues().entrySet()) { current.put(entry.getKey().getName(), entry.getValue().toString().toLowerCase(java.util.Locale.ROOT)); } @@ -423,7 +481,7 @@ private static boolean matchesSavedProperties(BlockState actual, JsonObject save if ("variant".equals(key) || "shape".equals(key) || "powered".equals(key) || "level".equals(key) || "north".equals(key) || "south".equals(key) || "east".equals(key) || "west".equals(key) || "up".equals(key) || "down".equals(key)) continue; - if (actual.getBlock() instanceof AbstractButtonBlock || actual.getBlock() instanceof net.minecraft.block.LeverBlock) { + if (actual.getBlock() instanceof ButtonBlock || actual.getBlock() instanceof net.minecraft.world.level.block.LeverBlock) { continue; // These changed from a single attachment property to face plus horizontal facing. } if (!value.equals(current.get(key))) return false; @@ -431,21 +489,21 @@ private static boolean matchesSavedProperties(BlockState actual, JsonObject save return true; } - private static CompoundNBT inventoryItem(ListNBT inventory, int slot) { + private static CompoundTag inventoryItem(ListTag inventory, int slot) { for (int index = 0; index < inventory.size(); index++) { - CompoundNBT item = inventory.getCompound(index); + CompoundTag item = inventory.getCompound(index); if ((item.getByte("Slot") & 255) == slot) return item; } return null; } - private static EquipmentSlotType equipmentSlot(String name) { - if ("feet".equals(name)) return EquipmentSlotType.FEET; - if ("legs".equals(name)) return EquipmentSlotType.LEGS; - if ("chest".equals(name)) return EquipmentSlotType.CHEST; - if ("head".equals(name)) return EquipmentSlotType.HEAD; - if ("offhand".equals(name)) return EquipmentSlotType.OFFHAND; - return EquipmentSlotType.MAINHAND; + private static EquipmentSlot equipmentSlot(String name) { + if ("feet".equals(name)) return EquipmentSlot.FEET; + if ("legs".equals(name)) return EquipmentSlot.LEGS; + if ("chest".equals(name)) return EquipmentSlot.CHEST; + if ("head".equals(name)) return EquipmentSlot.HEAD; + if ("offhand".equals(name)) return EquipmentSlot.OFFHAND; + return EquipmentSlot.MAINHAND; } private static boolean matchesLegacyMetadata(BlockState actual, int meta) { @@ -475,17 +533,17 @@ private static boolean matchesLegacyMetadata(BlockState actual, int meta) { } // Buttons, pressure plates and fluids can change while the chunk prepares. - if (block instanceof AbstractButtonBlock || block instanceof PressurePlateBlock - || block instanceof FlowingFluidBlock) { + if (block instanceof ButtonBlock || block instanceof PressurePlateBlock + || block instanceof LiquidBlock) { return true; } return actual.equals(expected); } - private static ServerWorld fixtureWorld(MinecraftServer server, int dimension) { - RegistryKey type = dimension == -1 ? World.NETHER - : dimension == 1 ? World.END : World.OVERWORLD; + private static ServerLevel fixtureWorld(MinecraftServer server, int dimension) { + ResourceKey type = dimension == -1 ? Level.NETHER + : dimension == 1 ? Level.END : Level.OVERWORLD; return require(server.getLevel(type), "missing fixture dimension " + dimension); } @@ -507,7 +565,7 @@ private static String currentItemId(String legacy) { private static void writeFixtureResult(Path root, String result) { try { - Files.write(root.resolve("BASEMETALS_LEGACY_TO_1_16_UPGRADE_RESULT.txt"), + Files.write(root.resolve("BASEMETALS_LEGACY_TO_1_17_UPGRADE_RESULT.txt"), (result + System.lineSeparator()).getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); } catch (IOException exception) { @@ -516,17 +574,17 @@ private static void writeFixtureResult(Path root, String result) { } private void verifyLegacyBlocks(MinecraftServer server) { - ServerWorld world = require(server.getLevel(World.OVERWORLD), "legacy overworld missing"); + ServerLevel world = require(server.getLevel(Level.OVERWORLD), "legacy overworld missing"); Map expected = LegacyWorldDataHook.legacyPreparedBlockCounts(); int expectedBlocks = 0; int convertedBlocks = 0; int verifiedChunks = 0; for (Long position : new java.util.ArrayList<>(expected.keySet())) { - Chunk chunk = world.getChunk((int) position.longValue(), (int) (position.longValue() >> 32)); + LevelChunk chunk = world.getChunk((int) position.longValue(), (int) (position.longValue() >> 32)); Integer expectedInChunk = expected.get(Long.valueOf(chunkKey(chunk.getPos().x, chunk.getPos().z))); if (expectedInChunk == null) continue; int actualInChunk = 0; - for (ChunkSection section : chunk.getSections()) { + for (LevelChunkSection section : chunk.getSections()) { if (section == null || section.isEmpty()) continue; for (int x = 0; x < 16; x++) for (int y = 0; y < 16; y++) for (int z = 0; z < 16; z++) { ResourceLocation id = ForgeRegistries.BLOCKS.getKey(section.getBlockState(x, y, z).getBlock()); @@ -547,17 +605,17 @@ private void verifyLegacyBlocks(MinecraftServer server) { } private void runChecks(MinecraftServer server) throws Exception { - ServerWorld world = require(server.getLevel(World.OVERWORLD), "overworld missing"); + ServerLevel world = require(server.getLevel(Level.OVERWORLD), "overworld missing"); check(MaterialCatalogue.ALL.size() == 22, "material catalogue size"); check(ModContent.blocksById().size() == 360, "registered block catalogue size"); - check(ModContent.itemsById().size() == 1115, "registered item catalogue size"); + check(ModContent.itemsById().size() == 1127, "registered item catalogue size"); check(ModContent.fluids().size() == 36, "fluid family count"); check(ForgeRegistries.ENTITIES.getKey(ModEntities.CUSTOM_ARROW.get()).equals(id("custom_arrow")), "custom arrow entity id"); check(ForgeRegistries.ENTITIES.getKey(ModEntities.CUSTOM_BOLT.get()).equals(id("custom_bolt")), "custom bolt entity id"); - for (java.util.Map.Entry> + for (java.util.Map.Entry> entry : ModContent.blocksById().entrySet()) { check(ForgeRegistries.BLOCKS.getKey(entry.getValue().get()).equals(id(entry.getKey())), "block id " + entry.getKey()); @@ -599,8 +657,8 @@ private void runChecks(MinecraftServer server) throws Exception { Block plate = ModContent.blocksById().get("copper_plate").get(); BlockState up = plate.defaultBlockState().setValue(PlateBlock.FACING, Direction.UP); BlockPos origin = new BlockPos(0, 0, 0); - AxisAlignedBB plateBounds = plate.getShape(up, world, origin, net.minecraft.util.math.shapes.ISelectionContext.empty()).bounds(); - check(plateBounds.equals(new AxisAlignedBB(0, 0, 0, 1, 1.0D / 16.0D, 1)), + AABB plateBounds = plate.getShape(up, world, origin, net.minecraft.world.phys.shapes.CollisionContext.empty()).bounds(); + check(plateBounds.equals(new AABB(0, 0, 0, 1, 1.0D / 16.0D, 1)), "plate placement bounds"); Block detector = ModContent.HUMAN_DETECTOR.get(); @@ -660,16 +718,17 @@ private void runChecks(MinecraftServer server) throws Exception { testCrossbowContract(); checks += GameplayRegressionChecks.run(server); checks += ContentModeChecks.run(server); - checks += Native116Checks.run(server); + checks += Native117Checks.run(server); + checks += RawOreChecks.run(server); } - private void testProjectilePersistence(ServerWorld world) { + private void testProjectilePersistence(ServerLevel world) { ItemStack ammunition = new ItemStack(ModContent.item("copper_arrow").get(), 8); - PlayerEntity player = new QuietFakePlayer(world, + Player player = new QuietFakePlayer(world, new GameProfile(UUID.fromString("00000000-0000-0000-0000-000000000113"), "ArmorProbe")); MaterialProjectile original = new MaterialProjectile(ModEntities.CUSTOM_ARROW.get(), world, player, ammunition); - CompoundNBT tag = new CompoundNBT(); + CompoundTag tag = new CompoundTag(); ((Entity) original).saveWithoutId(tag); MaterialProjectile restored = new MaterialProjectile(ModEntities.CUSTOM_ARROW.get(), world); ((Entity) restored).load(tag); @@ -677,38 +736,38 @@ private void testProjectilePersistence(ServerWorld world) { && restored.getAmmunition().getCount() == 1, "projectile ammunition persistence"); } - private void testStarsteelRepair(ServerWorld world) { - PlayerEntity player = FakePlayerFactory.getMinecraft(world); + private void testStarsteelRepair(ServerLevel world) { + Player player = FakePlayerFactory.getMinecraft(world); ItemStack tool = new ItemStack(ModContent.item("starsteel_pickaxe").get()); tool.setDamageValue(5); - player.setItemInHand(Hand.MAIN_HAND, tool); + player.setItemInHand(InteractionHand.MAIN_HAND, tool); player.tickCount = 200; MinecraftForge.EVENT_BUS.post(new TickEvent.PlayerTickEvent(TickEvent.Phase.END, player)); check(tool.getDamageValue() == 4, "starsteel held repair"); } - private void testAdamantineArmor(ServerWorld world) { - PlayerEntity player = new QuietFakePlayer(world, + private void testAdamantineArmor(ServerLevel world) { + Player player = new QuietFakePlayer(world, new GameProfile(UUID.fromString("00000000-0000-0000-0000-000000000114"), "ArmorProbe")); - player.setItemSlot(EquipmentSlotType.HEAD, + player.setItemSlot(EquipmentSlot.HEAD, new ItemStack(ModContent.item("adamantine_helmet").get())); - player.setItemSlot(EquipmentSlotType.CHEST, + player.setItemSlot(EquipmentSlot.CHEST, new ItemStack(ModContent.item("adamantine_chestplate").get())); - player.setItemSlot(EquipmentSlotType.LEGS, + player.setItemSlot(EquipmentSlot.LEGS, new ItemStack(ModContent.item("adamantine_leggings").get())); - player.setItemSlot(EquipmentSlotType.FEET, + player.setItemSlot(EquipmentSlot.FEET, new ItemStack(ModContent.item("adamantine_boots").get())); player.tickCount = 20; MinecraftForge.EVENT_BUS.post(new TickEvent.PlayerTickEvent(TickEvent.Phase.END, player)); - check(player.hasEffect(Effects.DAMAGE_RESISTANCE) - && player.getEffect(Effects.DAMAGE_RESISTANCE).getAmplifier() == 1, + check(player.hasEffect(MobEffects.DAMAGE_RESISTANCE) + && player.getEffect(MobEffects.DAMAGE_RESISTANCE).getAmplifier() == 1, "adamantine full-set resistance II"); } private void testShieldUpgrade() { ItemStack shield = new ItemStack(ModContent.item("copper_shield").get()); ItemStack plate = new ItemStack(ModContent.item("steel_plate").get()); - AnvilUpdateEvent event = new AnvilUpdateEvent(shield, plate, "", 0); + AnvilUpdateEvent event = new AnvilUpdateEvent(shield, plate, "", 0, null); MinecraftForge.EVENT_BUS.post(event); check(event.getOutput().getItem() == ModContent.item("steel_shield").get() && event.getMaterialCost() == 1 && event.getCost() >= 5, "shield plate upgrade"); @@ -722,7 +781,7 @@ private void testCrossbowContract() throws Exception { } private void checkRecipe(MinecraftServer server, String recipeName, String resultName, int count) { - IRecipe recipe = require(server.getRecipeManager().byKey(id(recipeName)).orElse(null), + Recipe recipe = require(server.getRecipeManager().byKey(id(recipeName)).orElse(null), "missing recipe " + recipeName); ResourceLocation expected = resultName.indexOf(':') >= 0 ? new ResourceLocation(resultName) : id(resultName); @@ -757,9 +816,9 @@ private static T require(T value, String message) { /** FakePlayer has no network connection, so potion callbacks must not send packets. */ private static final class QuietFakePlayer extends FakePlayer { - private QuietFakePlayer(ServerWorld world, GameProfile profile) { super(world, profile); } - @Override protected void onEffectAdded(EffectInstance effect) {} - @Override protected void onEffectUpdated(EffectInstance effect, boolean reapply) {} - @Override protected void onEffectRemoved(EffectInstance effect) {} + private QuietFakePlayer(ServerLevel world, GameProfile profile) { super(world, profile); } + @Override protected void onEffectAdded(MobEffectInstance effect, net.minecraft.world.entity.Entity source) {} + @Override protected void onEffectUpdated(MobEffectInstance effect, boolean reapply, net.minecraft.world.entity.Entity source) {} + @Override protected void onEffectRemoved(MobEffectInstance effect) {} } } diff --git a/src/integrationTest/java/zone/moddev/mc/basemetals/testmod/BlockOcclusionChecks.java b/src/integrationTest/java/zone/moddev/mc/basemetals/testmod/BlockOcclusionChecks.java new file mode 100644 index 000000000..964ad5f5f --- /dev/null +++ b/src/integrationTest/java/zone/moddev/mc/basemetals/testmod/BlockOcclusionChecks.java @@ -0,0 +1,104 @@ +package zone.moddev.mc.basemetals.testmod; + +import java.util.Map; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.DoorBlock; +import net.minecraft.world.level.block.IronBarsBlock; +import net.minecraft.world.level.block.TrapDoorBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.phys.shapes.BooleanOp; +import net.minecraft.world.phys.shapes.Shapes; +import org.apache.logging.log4j.LogManager; + +import zone.moddev.mc.basemetals.content.ModContent; +import zone.moddev.mc.basemetals.content.RegistryHandle; + +/** Checks the face-culling decisions used by Minecraft's chunk renderer. */ +final class BlockOcclusionChecks { + private BlockOcclusionChecks() {} + + static int run() { + int checks = 0; + int blocks = 0; + int states = 0; + + for (Class family : new Class[] {TrapDoorBlock.class, DoorBlock.class, IronBarsBlock.class}) { + for (Map.Entry> entry : ModContent.blocksById().entrySet()) { + Block block = entry.getValue().get(); + if (!family.isInstance(block)) continue; + + Block vanilla = block instanceof TrapDoorBlock ? Blocks.IRON_TRAPDOOR + : block instanceof DoorBlock ? Blocks.IRON_DOOR : Blocks.IRON_BARS; + blocks++; + + if (block instanceof TrapDoorBlock) { + require(Block.shouldRenderFace(Blocks.STONE.defaultBlockState(), + new NeighbourView(block.defaultBlockState()), BlockPos.ZERO.below(), + Direction.UP, BlockPos.ZERO), "floor hidden by closed trapdoor: " + entry.getKey()); + checks++; + } + + for (BlockState state : block.getStateDefinition().getPossibleStates()) { + NeighbourView view = new NeighbourView(state); + states++; + + for (Direction face : Direction.values()) { + BlockPos stone = BlockPos.ZERO.relative(face.getOpposite()); + require(Block.shouldRenderFace(Blocks.STONE.defaultBlockState(), view, + stone, face, BlockPos.ZERO), "stone face hidden by " + state + " on " + face); + checks++; + } + + require(!state.canOcclude(), "transparent block still hides neighbours: " + state); + require(!Shapes.joinIsNotEmpty(state.getCollisionShape(view, BlockPos.ZERO), + vanilla.withPropertiesOf(state).getCollisionShape(view, BlockPos.ZERO), BooleanOp.NOT_SAME), + "collision shape differs from vanilla: " + state); + checks += 2; + } + } + } + + for (Map.Entry> entry : ModContent.blocksById().entrySet()) { + String name = entry.getKey(); + if (!name.endsWith("_block") && !name.endsWith("_ore") && !name.endsWith("_plate") + && !name.endsWith("_slab") && !name.endsWith("_stairs") && !name.endsWith("_wall")) continue; + + require(entry.getValue().get().defaultBlockState().canOcclude(), + "opaque block lost face culling: " + name); + checks++; + } + + require(blocks > 0 && states > blocks, "transparent block families were not checked"); + LogManager.getLogger("basemetalsprobe").info( + "BASEMETALS_OCCLUSION_PROBE PASS blocks={} states={} checks={}", blocks, states, checks); + return checks; + } + + private static void require(boolean condition, String message) { + if (!condition) throw new IllegalStateException("Block occlusion check failed: " + message); + } + + private static final class NeighbourView implements BlockGetter { + private final BlockState neighbour; + + private NeighbourView(BlockState neighbour) { + this.neighbour = neighbour; + } + + @Override public BlockState getBlockState(BlockPos pos) { + return pos.equals(BlockPos.ZERO) ? neighbour : Blocks.STONE.defaultBlockState(); + } + + @Override public FluidState getFluidState(BlockPos pos) { return getBlockState(pos).getFluidState(); } + @Override public BlockEntity getBlockEntity(BlockPos pos) { return null; } + @Override public int getHeight() { return 256; } + @Override public int getMinBuildHeight() { return 0; } + } +} diff --git a/src/integrationTest/java/zone/moddev/mc/basemetals/testmod/ContentModeChecks.java b/src/integrationTest/java/zone/moddev/mc/basemetals/testmod/ContentModeChecks.java index 2f19579f2..e9a34aeb6 100644 --- a/src/integrationTest/java/zone/moddev/mc/basemetals/testmod/ContentModeChecks.java +++ b/src/integrationTest/java/zone/moddev/mc/basemetals/testmod/ContentModeChecks.java @@ -7,28 +7,28 @@ import java.util.UUID; import com.mojang.authlib.GameProfile; import net.minecraft.advancements.Advancement; -import net.minecraft.advancements.criterion.InventoryChangeTrigger; -import net.minecraft.entity.merchant.villager.VillagerEntity; -import net.minecraft.item.Items; -import net.minecraft.inventory.container.Container; -import net.minecraft.inventory.Inventory; -import net.minecraft.inventory.CraftingInventory; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.item.crafting.IRecipe; -import net.minecraft.item.crafting.Ingredient; -import net.minecraft.item.crafting.ShapedRecipe; -import net.minecraft.network.PacketBuffer; +import net.minecraft.advancements.critereon.InventoryChangeTrigger; +import net.minecraft.world.entity.npc.Villager; +import net.minecraft.world.item.Items; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.SimpleContainer; +import net.minecraft.world.inventory.CraftingContainer; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.item.crafting.ShapedRecipe; +import net.minecraft.network.FriendlyByteBuf; import net.minecraft.server.MinecraftServer; -import net.minecraft.util.ResourceLocation; -import net.minecraft.util.text.StringTextComponent; -import net.minecraft.item.MerchantOffer; -import net.minecraft.entity.merchant.villager.VillagerTrades; -import net.minecraft.world.server.ServerWorld; -import net.minecraft.world.World; -import net.minecraft.util.RegistryKey; -import net.minecraft.loot.LootContext; -import net.minecraft.loot.LootTable; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.world.item.trading.MerchantOffer; +import net.minecraft.world.entity.npc.VillagerTrades; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.Level; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.level.storage.loot.LootContext; +import net.minecraft.world.level.storage.loot.LootTable; import io.netty.buffer.Unpooled; import zone.moddev.mc.basemetals.config.BaseMetalsConfig; import zone.moddev.mc.basemetals.config.ContentPolicy; @@ -45,20 +45,20 @@ /** Exercises the policy against loaded Forge recipes, trades and loot tables. */ final class ContentModeChecks { static int run(MinecraftServer server) throws Exception { - ServerWorld world = server.getLevel(World.OVERWORLD); + ServerLevel world = server.getLevel(Level.OVERWORLD); ContentPolicy policy = ContentPolicy.active(); int checks = 0; int recipes = 0; int restricted = 0; - for (IRecipe recipe : server.getRecipeManager().getRecipes()) { + for (Recipe recipe : server.getRecipeManager().getRecipes()) { if (recipe.getSerializer() != ContentCraftingRecipe.SERIALIZER) continue; recipes++; boolean allowed = policy.allows(recipe.getResultItem().getItem().getRegistryName().toString()); if (!allowed) restricted++; require(recipe.isSpecial() == !allowed, "recipe-book visibility " + recipe.getId()); - CraftingInventory grid = new CraftingInventory(new Container(null, 0) { - @Override public boolean stillValid(net.minecraft.entity.player.PlayerEntity player) { return true; } + CraftingContainer grid = new CraftingContainer(new AbstractContainerMenu(null, 0) { + @Override public boolean stillValid(net.minecraft.world.entity.player.Player player) { return true; } }, 3, 3); boolean available = true; int slot = 0; @@ -75,9 +75,9 @@ static int run(MinecraftServer server) throws Exception { require(recipe.matches(grid, world) == (allowed && available), "crafting policy " + recipe.getId()); if (!allowed) require(recipe.assemble(grid).isEmpty(), "restricted crafting result " + recipe.getId()); - PacketBuffer packet = new PacketBuffer(Unpooled.buffer()); + FriendlyByteBuf packet = new FriendlyByteBuf(Unpooled.buffer()); recipe.getSerializer().toNetwork(packet, recipe); - IRecipe restored = recipe.getSerializer().fromNetwork(recipe.getId(), packet); + Recipe restored = recipe.getSerializer().fromNetwork(recipe.getId(), packet); require(restored.getId().equals(recipe.getId()) && restored.isSpecial() == recipe.isSpecial(), "recipe packet identity " + recipe.getId()); require((restored instanceof ShapedRecipe) == (recipe instanceof ShapedRecipe), @@ -94,19 +94,19 @@ static int run(MinecraftServer server) throws Exception { require(restricted > 0 == (BaseMetalsConfig.activeMode() == zone.moddev.mc.basemetals.config.ContentMode.LOW_FANTASY), "expected restricted recipe count"); - IRecipe mercury = server.getRecipeManager().byKey(new ResourceLocation("basemetals", "mercury_smallpowder_smelting")).orElse(null); - Inventory furnace = new Inventory(3); + Recipe mercury = server.getRecipeManager().byKey(new ResourceLocation("basemetals", "mercury_smallpowder_smelting")).orElse(null); + SimpleContainer furnace = new SimpleContainer(3); furnace.setItem(0, new ItemStack(ModContent.item("mercury_smallpowder").get())); require(mercury.matches(furnace, world) == policy.allows("basemetals:mercury_nugget"), "mercury furnace policy"); - for (IRecipe recipe : server.getRecipeManager().getRecipes()) { + for (Recipe recipe : server.getRecipeManager().getRecipes()) { if (!(recipe instanceof PlateRepairRecipe)) continue; - IRecipe repair = (IRecipe) recipe; + Recipe repair = (Recipe) recipe; ItemStack[] plates = repair.getIngredients().get(1).getItems(); if (plates.length == 0) continue; - CraftingInventory grid = new CraftingInventory(new Container(null, 0) { - @Override public boolean stillValid(net.minecraft.entity.player.PlayerEntity player) { return true; } + CraftingContainer grid = new CraftingContainer(new AbstractContainerMenu(null, 0) { + @Override public boolean stillValid(net.minecraft.world.entity.player.Player player) { return true; } }, 3, 3); ItemStack damaged = repair.getResultItem().copy(); damaged.setDamageValue(7); @@ -121,7 +121,7 @@ static int run(MinecraftServer server) throws Exception { for (String material : new String[] {"tin", "steel"}) { AnvilUpdateEvent upgrade = new AnvilUpdateEvent(new ItemStack(ModContent.item("antimony_shield").get()), - new ItemStack(ModContent.item(material + "_plate").get()), "", 0); + new ItemStack(ModContent.item(material + "_plate").get()), "", 0, null); new BaseMetalsEvents().onShieldUpgrade(upgrade); require(upgrade.getOutput().isEmpty() == !policy.allows("basemetals:" + material + "_shield"), "shield upgrade policy " + material); @@ -133,10 +133,10 @@ static int run(MinecraftServer server) throws Exception { for (zone.moddev.mc.basemetals.content.RegistryHandle handle : ModContent.itemsById().values()) { Item item = handle.get(); String id = item.getRegistryName().toString(); - VillagerTrades.ITrade factory = (VillagerTrades.ITrade) sales.invoke(null, item, 1, 1, 1); + VillagerTrades.ItemListing factory = (VillagerTrades.ItemListing) sales.invoke(null, item, 1, 1, 1); MerchantOffer offer = factory.getOffer(null, new Random(0)); require((offer != null) == (BaseMetalsConfig.VILLAGER_TRADES.get() && policy.allows(id)), "trade policy " + id); - net.minecraft.loot.conditions.ILootCondition condition = new ContentModeLootCondition(id); + net.minecraft.world.level.storage.loot.predicates.LootItemCondition condition = new ContentModeLootCondition(id); require(condition.test(null) == policy.allows(id), "loot condition " + id); checks += 2; } @@ -147,7 +147,7 @@ static int run(MinecraftServer server) throws Exception { new ResourceLocation("basemetals", "chests/inject/" + name)); for (int seed = 0; seed < 100; seed++) { LootContext context = new LootContext.Builder(world).withOptionalRandomSeed(seed) - .create(net.minecraft.loot.LootParameterSets.EMPTY); + .create(net.minecraft.world.level.storage.loot.parameters.LootContextParamSets.EMPTY); for (ItemStack stack : table.getRandomItems(context)) { require(policy.allows(stack.getItem().getRegistryName().toString()), "chest policy " + name + " " + stack); checks++; @@ -158,7 +158,7 @@ static int run(MinecraftServer server) throws Exception { return checks + verifyMaterialDiscovery(server, world); } - private static int verifyMaterialDiscovery(MinecraftServer server, ServerWorld world) { + private static int verifyMaterialDiscovery(MinecraftServer server, ServerLevel world) { Map materials = new LinkedHashMap<>(); for (String metal : new String[] {"adamantine", "antimony", "aquarium", "bismuth", "brass", "bronze", "coldiron", "copper", "cupronickel", "electrum", "invar", "lead", "mercury", "mithril", @@ -178,7 +178,7 @@ private static int verifyMaterialDiscovery(MinecraftServer server, ServerWorld w FakePlayer player = new FakePlayer(world, new GameProfile(UUID.randomUUID(), "MaterialDiscovery")); int recipes = 0; - for (IRecipe recipe : server.getRecipeManager().getRecipes()) { + for (Recipe recipe : server.getRecipeManager().getRecipes()) { if (recipe.getSerializer() != ContentCraftingRecipe.SERIALIZER) continue; String name = recipe.getId().getPath(); @@ -189,14 +189,14 @@ private static int verifyMaterialDiscovery(MinecraftServer server, ServerWorld w new ResourceLocation("basemetals", "recipes/" + name)); require(advancement != null && advancement.getCriteria().containsKey("has_material"), "material discovery advancement " + name); - InventoryChangeTrigger.Instance condition = (InventoryChangeTrigger.Instance) + InventoryChangeTrigger.TriggerInstance condition = (InventoryChangeTrigger.TriggerInstance) advancement.getCriteria().get("has_material").getTrigger(); - player.inventory.clearContent(); - player.inventory.setItem(0, new ItemStack(materials.get(material))); - require(condition.matches(player.inventory, player.inventory.getItem(0), 1, 0, 35), "base material does not discover " + name); - player.inventory.setItem(0, new ItemStack(Items.STICK)); - require(!condition.matches(player.inventory, player.inventory.getItem(0), 1, 0, 35), "unrelated item discovers " + name); + player.getInventory().clearContent(); + player.getInventory().setItem(0, new ItemStack(materials.get(material))); + require(condition.matches(player.getInventory(), player.getInventory().getItem(0), 1, 0, 35), "base material does not discover " + name); + player.getInventory().setItem(0, new ItemStack(Items.STICK)); + require(!condition.matches(player.getInventory(), player.getInventory().getItem(0), 1, 0, 35), "unrelated item discovers " + name); recipes++; } require(recipes == 1024, "full material discovery catalogue tested"); diff --git a/src/integrationTest/java/zone/moddev/mc/basemetals/testmod/GameplayRegressionChecks.java b/src/integrationTest/java/zone/moddev/mc/basemetals/testmod/GameplayRegressionChecks.java index b3ec5a99c..eae7bbd22 100644 --- a/src/integrationTest/java/zone/moddev/mc/basemetals/testmod/GameplayRegressionChecks.java +++ b/src/integrationTest/java/zone/moddev/mc/basemetals/testmod/GameplayRegressionChecks.java @@ -15,34 +15,34 @@ import zone.moddev.mc.basemetals.material.MaterialDefinition; import zone.moddev.mc.basemetals.recipe.PlateRepairRecipe; -import net.minecraft.entity.Entity; -import net.minecraft.entity.ai.attributes.Attributes; -import net.minecraft.entity.projectile.AbstractArrowEntity; -import net.minecraft.enchantment.Enchantments; -import net.minecraft.item.Items; -import net.minecraft.potion.Effects; -import net.minecraft.inventory.EquipmentSlotType; -import net.minecraft.inventory.Inventory; -import net.minecraft.inventory.CraftingInventory; -import net.minecraft.inventory.container.Container; -import net.minecraft.item.Item; -import net.minecraft.item.ArrowItem; -import net.minecraft.item.BowItem; -import net.minecraft.item.ItemStack; -import net.minecraft.item.crafting.IRecipe; -import net.minecraft.nbt.CompoundNBT; -import net.minecraft.network.PacketBuffer; -import net.minecraft.potion.EffectInstance; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.entity.projectile.AbstractArrow; +import net.minecraft.world.item.enchantment.Enchantments; +import net.minecraft.world.item.Items; +import net.minecraft.world.effect.MobEffects; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.SimpleContainer; +import net.minecraft.world.inventory.CraftingContainer; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ArrowItem; +import net.minecraft.world.item.BowItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.server.MinecraftServer; -import net.minecraft.tileentity.AbstractFurnaceTileEntity; -import net.minecraft.util.Hand; -import net.minecraft.util.ResourceLocation; -import net.minecraft.util.text.StringTextComponent; -import net.minecraft.world.server.ServerWorld; -import net.minecraft.world.World; -import net.minecraft.util.RegistryKey; +import net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity; +import net.minecraft.world.InteractionHand; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.Level; +import net.minecraft.resources.ResourceKey; import net.minecraft.advancements.Advancement; -import net.minecraft.advancements.criterion.InventoryChangeTrigger; +import net.minecraft.advancements.critereon.InventoryChangeTrigger; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.util.FakePlayer; import net.minecraftforge.event.entity.EntityJoinWorldEvent; @@ -54,13 +54,13 @@ final class GameplayRegressionChecks { private final List failures = new ArrayList(); private int checks; - private AbstractArrowEntity firedArrow; + private AbstractArrow firedArrow; private String stage; private int stageFailures; static int run(MinecraftServer server) { GameplayRegressionChecks probe = new GameplayRegressionChecks(); - ServerWorld world = server.getLevel(World.OVERWORLD); + ServerLevel world = server.getLevel(Level.OVERWORLD); probe.begin("fuels"); probe.fuels(); @@ -98,27 +98,27 @@ private void fuels() { int expected = combustible ? (name.endsWith("_powder") ? 1600 : 200) : 0; int actual = furnaceBurnTime(stack); check(actual == expected, "fuel " + name + " expected=" + expected + " actual=" + actual); - check(AbstractFurnaceTileEntity.isFuel(stack) == combustible, "furnace accepts " + name); + check(AbstractFurnaceBlockEntity.isFuel(stack) == combustible, "furnace accepts " + name); } check(furnaceBurnTime(stack("charcoal_block")) == 16000, "charcoal block fuel"); } - private void repairs(MinecraftServer server, ServerWorld world) { + private void repairs(MinecraftServer server, ServerLevel world) { int repairs = 0; - for (IRecipe recipe : server.getRecipeManager().getRecipes()) { + for (Recipe recipe : server.getRecipeManager().getRecipes()) { if (!(recipe instanceof PlateRepairRecipe)) continue; repairs++; ItemStack original = recipe.getResultItem().copy(); original.setDamageValue(7); - original.setHoverName(new StringTextComponent("Keep my name")); + original.setHoverName(new TextComponent("Keep my name")); original.enchant(Enchantments.UNBREAKING, 2); original.getOrCreateTag().putString("custom_proof", "keep my data"); String targetName = recipe.getResultItem().getItem().getRegistryName().getPath(); String plateName = targetName.substring(0, targetName.indexOf('_')) + "_plate"; if (!ModContent.itemsById().containsKey(plateName)) { // Empty compatibility tags may be filled by another mod; they cannot repair anything alone. - CraftingInventory grid = grid(); + CraftingContainer grid = grid(); grid.setItem(0, original.copy()); check(!recipe.matches(grid, world), "unavailable repair plate " + recipe.getId()); check(recipe.isSpecial(), "unavailable repair stays hidden " + recipe.getId()); @@ -129,7 +129,7 @@ private void repairs(MinecraftServer server, ServerWorld world) { for (int targetSlot = 0; targetSlot < 9; targetSlot++) { for (int plateSlot = 0; plateSlot < 9; plateSlot++) { if (targetSlot == plateSlot) continue; - CraftingInventory grid = grid(); + CraftingContainer grid = grid(); grid.setItem(targetSlot, original.copy()); grid.setItem(plateSlot, plate.copy()); check(recipe.matches(grid, world), "repair slots " + recipe.getId()); @@ -140,7 +140,7 @@ private void repairs(MinecraftServer server, ServerWorld world) { } } - CraftingInventory grid = grid(); + CraftingContainer grid = grid(); grid.setItem(4, plate.copy()); check(!recipe.matches(grid, world), "plate alone " + recipe.getId()); grid.setItem(0, original.copy()); @@ -156,13 +156,13 @@ private void repairs(MinecraftServer server, ServerWorld world) { check(repairs == 110, "all 110 plate repairs tested"); } - private void crafting(MinecraftServer server, ServerWorld world) { + private void crafting(MinecraftServer server, ServerLevel world) { String[] materials = {"diamond", "emerald", "gold", "quartz"}; Item[] ingredients = {Items.DIAMOND, Items.EMERALD, Items.GOLD_INGOT, Items.QUARTZ}; for (int i = 0; i < materials.length; i++) { - IRecipe door = server.getRecipeManager().byKey(id(materials[i] + "_door")).orElse(null); - IRecipe trapdoor = server.getRecipeManager().byKey(id(materials[i] + "_trapdoor")).orElse(null); - CraftingInventory grid = craftingGrid(); + Recipe door = server.getRecipeManager().byKey(id(materials[i] + "_door")).orElse(null); + Recipe trapdoor = server.getRecipeManager().byKey(id(materials[i] + "_trapdoor")).orElse(null); + CraftingContainer grid = craftingGrid(); for (int slot : new int[] {0, 1, 3, 4, 6, 7}) { grid.setItem(slot, new ItemStack(ingredients[i])); } @@ -176,24 +176,24 @@ private void crafting(MinecraftServer server, ServerWorld world) { } QuietPlayer player = new QuietPlayer(world); - player.inventory.clearContent(); - player.inventory.setItem(0, stack("coldiron_ingot")); + player.getInventory().clearContent(); + player.getInventory().setItem(0, stack("coldiron_ingot")); Advancement unlock = server.getAdvancements().getAdvancement(id("recipes/coldiron_sword")); check(unlock != null, "Cold Iron recipe unlock loaded"); if (unlock != null) { - InventoryChangeTrigger.Instance condition = (InventoryChangeTrigger.Instance) + InventoryChangeTrigger.TriggerInstance condition = (InventoryChangeTrigger.TriggerInstance) unlock.getCriteria().get("has_ingredient_1").getTrigger(); - check(condition.matches(player.inventory, player.inventory.getItem(0), 1, 0, 35), "Cold Iron ingot matches recipe unlock"); - player.inventory.setItem(0, stack("copper_ingot")); - check(!condition.matches(player.inventory, player.inventory.getItem(0), 1, 0, 35), "unrelated ingot cannot unlock Cold Iron sword"); + check(condition.matches(player.getInventory(), player.getInventory().getItem(0), 1, 0, 35), "Cold Iron ingot matches recipe unlock"); + player.getInventory().setItem(0, stack("copper_ingot")); + check(!condition.matches(player.getInventory(), player.getInventory().getItem(0), 1, 0, 35), "unrelated ingot cannot unlock Cold Iron sword"); } check(server.getAdvancements().getAdvancement(id("recipes/coldiron_chestplate_plate_repair")) == null, "repair has no recipe-book unlock"); } - private void rangedWeapons(ServerWorld world) { + private void rangedWeapons(ServerLevel world) { QuietPlayer player = new QuietPlayer(world); - net.minecraft.util.math.BlockPos origin = world.getSharedSpawnPos().above(5); + net.minecraft.core.BlockPos origin = world.getSharedSpawnPos().above(5); world.getChunk(origin); player.setPos(origin.getX() + 0.5D, origin.getY(), origin.getZ() + 0.5D); int families = 0; @@ -204,7 +204,7 @@ private void rangedWeapons(ServerWorld world) { MaterialDefinition material = ((MaterialBacked) entry.getValue().get()).baseMetalsMaterial(); ItemStack arrow = stack(materialName + "_arrow"); ArrowItem arrowItem = (ArrowItem) arrow.getItem(); - AbstractArrowEntity projectile = arrowItem.createArrow(world, arrow, player); + AbstractArrow projectile = arrowItem.createArrow(world, arrow, player); check(close(projectile.getBaseDamage(), 1.0D + material.baseAttackDamage()), "vanilla bow + " + materialName + " arrow"); check(stack(materialName + "_fishing_rod").getMaxDamage() == material.toolDurability(), @@ -229,18 +229,18 @@ private void rangedWeapons(ServerWorld world) { damage("steel_bow") + damage("gold_arrow") + 2.0D, "Power after material damage"); ItemStack named = stack("adamantine_arrow"); - named.setHoverName(new StringTextComponent("Recovered arrow")); + named.setHoverName(new TextComponent("Recovered arrow")); named.getOrCreateTag().putString("ammo_proof", "preserved"); MaterialProjectile original = (MaterialProjectile) ((ArrowItem) named.getItem()) .createArrow(world, named, player); - CompoundNBT saved = new CompoundNBT(); + CompoundTag saved = new CompoundTag(); ((Entity) original).saveWithoutId(saved); MaterialProjectile restored = new MaterialProjectile(ModEntities.CUSTOM_ARROW.get(), world); ((Entity) restored).load(saved); check(ItemStack.matches(named, restored.getAmmunition()), "arrow pickup NBT after reload"); - check(close(((AbstractArrowEntity) original).getBaseDamage(), ((AbstractArrowEntity) restored).getBaseDamage()), + check(close(((AbstractArrow) original).getBaseDamage(), ((AbstractArrow) restored).getBaseDamage()), "arrow damage after reload"); - PacketBuffer buffer = new PacketBuffer(Unpooled.buffer()); + FriendlyByteBuf buffer = new FriendlyByteBuf(Unpooled.buffer()); try { original.writeSpawnData(buffer); restored.readSpawnData(buffer); @@ -250,13 +250,13 @@ private void rangedWeapons(ServerWorld world) { } } - private void fire(ServerWorld world, QuietPlayer player, ItemStack launcher, + private void fire(ServerLevel world, QuietPlayer player, ItemStack launcher, ItemStack ammunition, double expected, String label) { - player.inventory.clearContent(); + player.getInventory().clearContent(); ItemStack supply = ammunition.copy(); supply.setCount(8); - player.setItemInHand(Hand.MAIN_HAND, launcher); - player.setItemInHand(Hand.OFF_HAND, supply); + player.setItemInHand(InteractionHand.MAIN_HAND, launcher); + player.setItemInHand(InteractionHand.OFF_HAND, supply); firedArrow = null; BowItem bow = (BowItem) launcher.getItem(); @@ -271,9 +271,9 @@ private void fire(ServerWorld world, QuietPlayer player, ItemStack launcher, check(launcher.getDamageValue() == 1, label + " uses one durability"); } - private void crossbowAmmunition(ServerWorld world) { + private void crossbowAmmunition(ServerLevel world) { QuietPlayer player = new QuietPlayer(world); - net.minecraft.util.math.BlockPos origin = world.getSharedSpawnPos().above(5); + net.minecraft.core.BlockPos origin = world.getSharedSpawnPos().above(5); world.getChunk(origin); player.setPos(origin.getX() + 0.5D, origin.getY(), origin.getZ() + 0.5D); @@ -282,29 +282,29 @@ private void crossbowAmmunition(ServerWorld world) { String name = entry.getKey(); String boltName = name.substring(0, name.length() - "_crossbow".length()) + "_bolt"; - player.abilities.instabuild = true; - player.inventory.clearContent(); + player.getAbilities().instabuild = true; + player.getInventory().clearContent(); ItemStack launcher = stack(name); - player.setItemInHand(Hand.MAIN_HAND, launcher); + player.setItemInHand(InteractionHand.MAIN_HAND, launcher); release(world, player, launcher); checkBolt("iron_bolt", damage(name) + damage("iron_bolt"), name + " Creative without ammunition"); check(firedArrow != null - && firedArrow.pickup == AbstractArrowEntity.PickupStatus.CREATIVE_ONLY, + && firedArrow.pickup == AbstractArrow.Pickup.CREATIVE_ONLY, name + " virtual bolt cannot be collected in Survival"); check(launcher.getDamageValue() == 0, name + " Creative preserves durability"); for (boolean creative : new boolean[] {false, true}) { - player.abilities.instabuild = creative; - player.inventory.clearContent(); + player.getAbilities().instabuild = creative; + player.getInventory().clearContent(); launcher = stack(name); - player.setItemInHand(Hand.MAIN_HAND, launcher); + player.setItemInHand(InteractionHand.MAIN_HAND, launcher); ItemStack supply = stack(boltName); supply.setCount(8); - supply.setHoverName(new StringTextComponent("Inventory bolt")); + supply.setHoverName(new TextComponent("Inventory bolt")); supply.getOrCreateTag().putString("ammo_proof", "inventory"); - player.inventory.setItem(9, supply); + player.getInventory().setItem(9, supply); release(world, player, launcher); String label = name + " inventory bolt " + (creative ? "Creative" : "Survival"); @@ -323,14 +323,14 @@ private void crossbowAmmunition(ServerWorld world) { new ItemStack(Items.SPECTRAL_ARROW), stack("adamantine_arrow"), ItemStack.EMPTY}; for (boolean creative : new boolean[] {false, true}) { for (ItemStack wrong : wrongAmmunition) { - player.abilities.instabuild = creative; - player.inventory.clearContent(); + player.getAbilities().instabuild = creative; + player.getInventory().clearContent(); ItemStack launcher = stack("adamantine_crossbow"); ItemStack supply = wrong.copy(); if (!supply.isEmpty()) supply.setCount(8); ItemStack original = supply.copy(); - player.setItemInHand(Hand.MAIN_HAND, launcher); - player.setItemInHand(Hand.OFF_HAND, supply); + player.setItemInHand(InteractionHand.MAIN_HAND, launcher); + player.setItemInHand(InteractionHand.OFF_HAND, supply); release(world, player, launcher); String label = "wrong crossbow ammunition " + wrong + " " @@ -338,7 +338,7 @@ private void crossbowAmmunition(ServerWorld world) { if (creative) { checkBolt("iron_bolt", damage("adamantine_crossbow") + damage("iron_bolt"), label); check(firedArrow != null - && firedArrow.pickup == AbstractArrowEntity.PickupStatus.CREATIVE_ONLY, + && firedArrow.pickup == AbstractArrow.Pickup.CREATIVE_ONLY, label + " virtual bolt pickup"); } else { check(firedArrow == null, label + " does not fire"); @@ -349,10 +349,10 @@ private void crossbowAmmunition(ServerWorld world) { } // Bows still use Minecraft's virtual arrow when Creative players carry no ammunition. - player.abilities.instabuild = true; - player.inventory.clearContent(); + player.getAbilities().instabuild = true; + player.getInventory().clearContent(); ItemStack bow = stack("adamantine_bow"); - player.setItemInHand(Hand.MAIN_HAND, bow); + player.setItemInHand(InteractionHand.MAIN_HAND, bow); release(world, player, bow); check(firedArrow != null && !(firedArrow instanceof MaterialProjectile), "Creative bow keeps the vanilla arrow fallback"); @@ -360,7 +360,7 @@ private void crossbowAmmunition(ServerWorld world) { "Creative bow fallback retains launcher damage"); } - private void release(ServerWorld world, QuietPlayer player, ItemStack launcher) { + private void release(ServerLevel world, QuietPlayer player, ItemStack launcher) { firedArrow = null; BowItem bow = (BowItem) launcher.getItem(); bow.releaseUsing(launcher, world, player, bow.getUseDuration(launcher) - 20); @@ -379,43 +379,43 @@ private void checkBolt(String ammunition, double expected, String label) { @SubscribeEvent public void arrowSpawned(EntityJoinWorldEvent event) { - if (event.getEntity() instanceof AbstractArrowEntity) firedArrow = (AbstractArrowEntity) event.getEntity(); + if (event.getEntity() instanceof AbstractArrow) firedArrow = (AbstractArrow) event.getEntity(); } - private void armor(ServerWorld world) { + private void armor(ServerLevel world) { QuietPlayer player = new QuietPlayer(world); player.getAttribute(Attributes.MAX_HEALTH).setBaseValue(40.0D); player.setHealth(40.0F); equip(player, "adamantine"); tick(player); check(player.getHealth() == 40.0F, "Adamantine armor cannot hurt high-health wearer"); - check(player.hasEffect(Effects.DAMAGE_RESISTANCE) - && player.getEffect(Effects.DAMAGE_RESISTANCE).getAmplifier() == 1, + check(player.hasEffect(MobEffects.DAMAGE_RESISTANCE) + && player.getEffect(MobEffects.DAMAGE_RESISTANCE).getAmplifier() == 1, "damaged Adamantine armor gives Resistance II"); player.getActiveEffectsMap().clear(); equip(player, "starsteel"); tick(player); - check(player.hasEffect(Effects.JUMP) - && player.getEffect(Effects.JUMP).getAmplifier() == 3, + check(player.hasEffect(MobEffects.JUMP) + && player.getEffect(MobEffects.JUMP).getAmplifier() == 3, "damaged Starsteel armor gives Jump Boost IV"); - check(player.hasEffect(Effects.MOVEMENT_SPEED) - && player.getEffect(Effects.MOVEMENT_SPEED).getAmplifier() == 2, + check(player.hasEffect(MobEffects.MOVEMENT_SPEED) + && player.getEffect(MobEffects.MOVEMENT_SPEED).getAmplifier() == 2, "damaged Starsteel armor gives Speed III"); player.getActiveEffectsMap().clear(); equip(player, "aquarium"); player.submerge(); - player.addEffect(new EffectInstance(Effects.DIG_SLOWDOWN, 200)); + player.addEffect(new MobEffectInstance(MobEffects.DIG_SLOWDOWN, 200)); tick(player); - check(player.hasEffect(Effects.WATER_BREATHING) - && player.hasEffect(Effects.DAMAGE_RESISTANCE) - && !player.hasEffect(Effects.DIG_SLOWDOWN), "damaged submerged Aquarium armor"); + check(player.hasEffect(MobEffects.WATER_BREATHING) + && player.hasEffect(MobEffects.DAMAGE_RESISTANCE) + && !player.hasEffect(MobEffects.DIG_SLOWDOWN), "damaged submerged Aquarium armor"); } private static void equip(QuietPlayer player, String material) { - EquipmentSlotType[] slots = {EquipmentSlotType.HEAD, EquipmentSlotType.CHEST, - EquipmentSlotType.LEGS, EquipmentSlotType.FEET}; + EquipmentSlot[] slots = {EquipmentSlot.HEAD, EquipmentSlot.CHEST, + EquipmentSlot.LEGS, EquipmentSlot.FEET}; String[] forms = {"helmet", "chestplate", "leggings", "boots"}; for (int i = 0; i < slots.length; i++) { ItemStack piece = stack(material + "_" + forms[i]); @@ -448,23 +448,23 @@ private static boolean close(double actual, double expected) { } private static int furnaceBurnTime(ItemStack stack) { - int burnTime = stack.getBurnTime(); - int fallback = AbstractFurnaceTileEntity.getFuel().getOrDefault(stack.getItem(), 0); + int burnTime = stack.getBurnTime(net.minecraft.world.item.crafting.RecipeType.SMELTING); + int fallback = AbstractFurnaceBlockEntity.getFuel().getOrDefault(stack.getItem(), 0); return net.minecraftforge.event.ForgeEventFactory.getItemBurnTime(stack, - burnTime == -1 ? fallback : burnTime); + burnTime == -1 ? fallback : burnTime, net.minecraft.world.item.crafting.RecipeType.SMELTING); } private static ItemStack stack(String name) { return new ItemStack(ModContent.item(name).get()); } - private static CraftingInventory grid() { + private static CraftingContainer grid() { return craftingGrid(); } - private static CraftingInventory craftingGrid() { - return new CraftingInventory(new Container(null, 0) { - @Override public boolean stillValid(net.minecraft.entity.player.PlayerEntity player) { + private static CraftingContainer craftingGrid() { + return new CraftingContainer(new AbstractContainerMenu(null, 0) { + @Override public boolean stillValid(net.minecraft.world.entity.player.Player player) { return true; } }, 3, 3); @@ -475,13 +475,13 @@ private static ResourceLocation id(String name) { } private static final class QuietPlayer extends FakePlayer { - private QuietPlayer(ServerWorld world) { + private QuietPlayer(ServerLevel world) { super(world, new GameProfile(UUID.fromString("00000000-0000-0000-0000-000000000131"), "GameplayProbe")); } - @Override protected void onEffectAdded(EffectInstance effect) {} - @Override protected void onEffectUpdated(EffectInstance effect, boolean reapply) {} - @Override protected void onEffectRemoved(EffectInstance effect) {} + @Override protected void onEffectAdded(MobEffectInstance effect, net.minecraft.world.entity.Entity source) {} + @Override protected void onEffectUpdated(MobEffectInstance effect, boolean reapply, net.minecraft.world.entity.Entity source) {} + @Override protected void onEffectRemoved(MobEffectInstance effect) {} private void submerge() { wasTouchingWater = true; } } } diff --git a/src/integrationTest/java/zone/moddev/mc/basemetals/testmod/Native116Checks.java b/src/integrationTest/java/zone/moddev/mc/basemetals/testmod/Native117Checks.java similarity index 71% rename from src/integrationTest/java/zone/moddev/mc/basemetals/testmod/Native116Checks.java rename to src/integrationTest/java/zone/moddev/mc/basemetals/testmod/Native117Checks.java index bf78c8dc4..f47cde4d1 100644 --- a/src/integrationTest/java/zone/moddev/mc/basemetals/testmod/Native116Checks.java +++ b/src/integrationTest/java/zone/moddev/mc/basemetals/testmod/Native117Checks.java @@ -4,30 +4,30 @@ import java.util.Map; import java.util.Random; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.block.DoorBlock; -import net.minecraft.block.SlabBlock; -import net.minecraft.block.WallBlock; -import net.minecraft.nbt.CompoundNBT; -import net.minecraft.nbt.ListNBT; -import net.minecraft.nbt.NBTUtil; -import net.minecraft.inventory.Inventory; -import net.minecraft.entity.merchant.villager.VillagerProfession; -import net.minecraft.entity.merchant.villager.VillagerTrades; -import net.minecraft.item.ItemStack; -import net.minecraft.item.Items; -import net.minecraft.item.MerchantOffer; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.DoorBlock; +import net.minecraft.world.level.block.SlabBlock; +import net.minecraft.world.level.block.WallBlock; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.world.SimpleContainer; +import net.minecraft.world.entity.npc.VillagerProfession; +import net.minecraft.world.entity.npc.VillagerTrades; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.trading.MerchantOffer; import net.minecraft.server.MinecraftServer; -import net.minecraft.state.properties.DoubleBlockHalf; -import net.minecraft.state.properties.SlabType; -import net.minecraft.block.WallHeight; -import net.minecraft.util.ResourceLocation; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; -import net.minecraft.util.RegistryKey; -import net.minecraft.world.server.ServerWorld; -import net.minecraft.loot.LootTable; +import net.minecraft.world.level.block.state.properties.DoubleBlockHalf; +import net.minecraft.world.level.block.state.properties.SlabType; +import net.minecraft.world.level.block.state.properties.WallSide; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.Level; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.storage.loot.LootTable; import zone.moddev.mc.basemetals.config.BaseMetalsConfig; import zone.moddev.mc.basemetals.config.ContentPolicy; import zone.moddev.mc.basemetals.content.BaseMetalAnvilBlock; @@ -38,12 +38,12 @@ import zone.moddev.mc.basemetals.migration.LegacyWorldDataHook; /** Checks native loot, molten-fluid attributes and village smith trades. */ -final class Native116Checks { - private Native116Checks() {} +final class Native117Checks { + private Native117Checks() {} static int run(MinecraftServer server) { - ServerWorld world = server.getLevel(World.OVERWORLD); - int checks = 0; + ServerLevel world = server.getLevel(Level.OVERWORLD); + int checks = BlockOcclusionChecks.run(); for (Map.Entry> entry : ModContent.blocksById().entrySet()) { String name = entry.getKey(); @@ -53,7 +53,7 @@ static int run(MinecraftServer server) { BlockState state = block.defaultBlockState(); if (block instanceof WallBlock) { checks += checkOldWallConnections(block); - for (WallHeight height : WallHeight.values()) { + for (WallSide height : WallSide.values()) { BlockState connected = state.setValue(WallBlock.NORTH_WALL, height) .setValue(WallBlock.EAST_WALL, height) .setValue(WallBlock.SOUTH_WALL, height) @@ -64,8 +64,16 @@ static int run(MinecraftServer server) { } } if (block instanceof DoorBlock) state = state.setValue(DoorBlock.HALF, DoubleBlockHalf.LOWER); - String dropName = name.startsWith("double_") ? name.substring(7) : name; + String dropName = name.endsWith("_ore") ? name.replace("_ore", "_raw") + : name.startsWith("double_") ? name.substring(7) : name; int count = name.startsWith("double_") ? 2 : 1; + if (name.equals("copper_ore")) { + List copperDrops = drops(world, state); + require(copperDrops.size() == 1 && copperDrops.get(0).getItem() == Items.RAW_COPPER + && copperDrops.get(0).getCount() >= 2 && copperDrops.get(0).getCount() <= 3, "native copper loot"); + checks++; + continue; + } assertDrop(world, state, dropName, count); checks++; @@ -90,14 +98,14 @@ static int run(MinecraftServer server) { ModContent.item("gold_powder").get(), 2); checks += checkCrushing(world, Items.ANCIENT_DEBRIS, Items.NETHERITE_SCRAP, 2); require(!world.getRecipeManager().getRecipeFor(CrushingRecipe.TYPE, - new Inventory(new ItemStack(Items.GILDED_BLACKSTONE)), world).isPresent(), + new SimpleContainer(new ItemStack(Items.GILDED_BLACKSTONE)), world).isPresent(), "Gilded Blackstone must not have a crushing route"); checks++; - for (net.minecraft.item.Item item : net.minecraftforge.registries.ForgeRegistries.ITEMS) { + for (net.minecraft.world.item.Item item : net.minecraftforge.registries.ForgeRegistries.ITEMS) { if (!(item instanceof zone.moddev.mc.basemetals.content.MaterialItems.Hoe)) continue; - require(item.getDefaultAttributeModifiers(net.minecraft.inventory.EquipmentSlotType.MAINHAND) - .get(net.minecraft.entity.ai.attributes.Attributes.ATTACK_DAMAGE).stream() + require(item.getDefaultAttributeModifiers(net.minecraft.world.entity.EquipmentSlot.MAINHAND) + .get(net.minecraft.world.entity.ai.attributes.Attributes.ATTACK_DAMAGE).stream() .allMatch(modifier -> modifier.getAmount() == 0.0D), "hoe gained attack damage: " + item); checks++; } @@ -115,8 +123,8 @@ static int run(MinecraftServer server) { for (VillagerProfession profession : new VillagerProfession[] { VillagerProfession.ARMORER, VillagerProfession.TOOLSMITH, VillagerProfession.WEAPONSMITH}) { int baseMetalsOffers = 0; - for (Map.Entry level : VillagerTrades.TRADES.get(profession).entrySet()) { - for (VillagerTrades.ITrade factory : level.getValue()) { + for (Map.Entry level : VillagerTrades.TRADES.get(profession).entrySet()) { + for (VillagerTrades.ItemListing factory : level.getValue()) { if (!factory.getClass().getName().startsWith("zone.moddev.mc.basemetals.")) continue; MerchantOffer offer = factory.getOffer(null, new Random(1)); if (offer == null) continue; @@ -147,28 +155,28 @@ private static int checkOldWallConnections(Block block) { String[] directions = {"north", "east", "south", "west"}; for (int mask = 0; mask < 16; mask++) { - CompoundNBT properties = new CompoundNBT(); + CompoundTag properties = new CompoundTag(); properties.putString("up", "true"); for (int side = 0; side < directions.length; side++) { properties.putString(directions[side], String.valueOf((mask & (1 << side)) != 0)); } - CompoundNBT savedState = new CompoundNBT(); + CompoundTag savedState = new CompoundTag(); savedState.putString("Name", block.getRegistryName().toString()); savedState.put("Properties", properties); - ListNBT palette = new ListNBT(); + ListTag palette = new ListTag(); palette.add(savedState); - CompoundNBT section = new CompoundNBT(); + CompoundTag section = new CompoundTag(); section.put("Palette", palette); - ListNBT sections = new ListNBT(); + ListTag sections = new ListTag(); sections.add(section); - CompoundNBT level = new CompoundNBT(); + CompoundTag level = new CompoundTag(); level.put("Sections", sections); - CompoundNBT chunk = new CompoundNBT(); + CompoundTag chunk = new CompoundTag(); chunk.put("Level", level); LegacyWorldDataHook.prepareLegacyChunk(chunk); - BlockState converted = NBTUtil.readBlockState(savedState); + BlockState converted = NbtUtils.readBlockState(savedState); require(converted.getBlock() == block, "old wall became a different block: " + block); for (int side = 0; side < directions.length; side++) { String expected = (mask & (1 << side)) != 0 ? "low" : "none"; @@ -181,9 +189,9 @@ private static int checkOldWallConnections(Block block) { return 16 * 6; } - private static int checkCrushing(ServerWorld world, net.minecraft.item.Item input, - net.minecraft.item.Item output, int count) { - Inventory inventory = new Inventory(new ItemStack(input)); + private static int checkCrushing(ServerLevel world, net.minecraft.world.item.Item input, + net.minecraft.world.item.Item output, int count) { + SimpleContainer inventory = new SimpleContainer(new ItemStack(input)); CrushingRecipe recipe = world.getRecipeManager().getRecipeFor(CrushingRecipe.TYPE, inventory, world) .orElseThrow(() -> new IllegalStateException("No crushing recipe for " + input)); ItemStack result = recipe.assemble(inventory); @@ -192,19 +200,19 @@ private static int checkCrushing(ServerWorld world, net.minecraft.item.Item inpu return 1; } - private static List drops(ServerWorld world, BlockState state) { + private static List drops(ServerLevel world, BlockState state) { return Block.getDrops(state, world, new BlockPos(0, 100, 0), null, net.minecraftforge.common.util.FakePlayerFactory.getMinecraft(world), new ItemStack(Items.DIAMOND_PICKAXE)); } - private static void assertDrop(ServerWorld world, BlockState state, String item, int count) { + private static void assertDrop(ServerLevel world, BlockState state, String item, int count) { List drops = drops(world, state); require(drops.size() == 1 && drops.get(0).getItem() == ModContent.item(item).get() && drops.get(0).getCount() == count, "incorrect block loot: " + state + " " + drops); } private static void require(boolean condition, String message) { - if (!condition) throw new IllegalStateException("Native 1.16 check failed: " + message); + if (!condition) throw new IllegalStateException("Native 1.17 check failed: " + message); } } diff --git a/src/integrationTest/java/zone/moddev/mc/basemetals/testmod/OrePlacementChecks.java b/src/integrationTest/java/zone/moddev/mc/basemetals/testmod/OrePlacementChecks.java index a756ad8cf..bb5e27929 100644 --- a/src/integrationTest/java/zone/moddev/mc/basemetals/testmod/OrePlacementChecks.java +++ b/src/integrationTest/java/zone/moddev/mc/basemetals/testmod/OrePlacementChecks.java @@ -7,14 +7,14 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParser; -import net.minecraft.block.Block; +import net.minecraft.world.level.block.Block; import net.minecraft.server.MinecraftServer; -import net.minecraft.util.ResourceLocation; -import net.minecraft.world.chunk.Chunk; -import net.minecraft.world.chunk.ChunkSection; -import net.minecraft.world.World; -import net.minecraft.util.RegistryKey; -import net.minecraft.world.server.ServerWorld; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.Level; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.level.ServerLevel; import net.minecraftforge.registries.ForgeRegistries; import org.apache.logging.log4j.LogManager; import zone.moddev.mc.basemetals.content.ModContent; @@ -32,33 +32,43 @@ static int run(MinecraftServer server) throws Exception { + "; expected " + SAMPLE_WORLD_SEED); } + JsonObject activeOres = zone.moddev.mc.orespawn.api.OreSpawnApi.getActiveProfile(server) + .orElseThrow().toJson().getAsJsonObject("ores"); + boolean expectedCopper = Boolean.getBoolean("basemetalsprobe.expectCopperEnabled"); + if (activeOres.getAsJsonObject("basemetals:ore/copper").get("enabled").getAsBoolean() != expectedCopper) { + throw new IllegalStateException("The effective copper rule did not retain its expected setting"); + } + JsonObject ores; - try (InputStreamReader reader = new InputStreamReader(OrePlacementChecks.class.getResourceAsStream( + try (InputStreamReader reader = new InputStreamReader(zone.moddev.mc.basemetals.BaseMetals.class.getResourceAsStream( "/data/basemetals/orespawn/provider.json"), StandardCharsets.UTF_8)) { ores = new JsonParser().parse(reader).getAsJsonObject().getAsJsonObject("ores"); } Map rules = new LinkedHashMap<>(); ores.entrySet().forEach(entry -> { - JsonObject rule = entry.getValue().getAsJsonObject(); + JsonObject rule = activeOres.getAsJsonObject(entry.getKey()); rules.put(ForgeRegistries.BLOCKS.getValue(new ResourceLocation(rule.get("block").getAsString())), rule); }); int checks = 0; - for (ServerWorld world : server.getAllLevels()) { - RegistryKey dimension = world.dimension(); + for (ServerLevel world : server.getAllLevels()) { + ResourceKey dimension = world.dimension(); String dimensionId = dimension.location().toString(); Map counts = new LinkedHashMap<>(); int rockCount = 0; - int centerX = dimension == World.OVERWORLD ? world.getSharedSpawnPos().getX() >> 4 : 0; - int centerZ = dimension == World.OVERWORLD ? world.getSharedSpawnPos().getZ() >> 4 : 0; + int vanillaCopperCount = 0; + int centerX = dimension == Level.OVERWORLD ? world.getSharedSpawnPos().getX() >> 4 : 0; + int centerZ = dimension == Level.OVERWORLD ? world.getSharedSpawnPos().getZ() >> 4 : 0; for (int cx = centerX - 2; cx <= centerX + 2; cx++) { for (int cz = centerZ - 2; cz <= centerZ + 2; cz++) { - Chunk chunk = world.getChunk(cx, cz); - for (ChunkSection section : chunk.getSections()) { + LevelChunk chunk = world.getChunk(cx, cz); + for (LevelChunkSection section : chunk.getSections()) { if (section == null || section.isEmpty()) continue; for (int x = 0; x < 16; x++) for (int y = 0; y < 16; y++) for (int z = 0; z < 16; z++) { Block block = section.getBlockState(x, y, z).getBlock(); + if (block == net.minecraft.world.level.block.Blocks.COPPER_ORE + || block == net.minecraft.world.level.block.Blocks.DEEPSLATE_COPPER_ORE) vanillaCopperCount++; if ("mineralogy".equals(block.getRegistryName().getNamespace()) && !block.getRegistryName().getPath().endsWith("_ore")) rockCount++; if (!rules.containsKey(block)) { @@ -70,11 +80,16 @@ static int run(MinecraftServer server) throws Exception { } JsonObject rule = rules.get(block); + if (!rule.get("enabled").getAsBoolean()) { + throw new IllegalStateException("Default-disabled ore appeared: " + block); + } JsonObject placement = rule.has("dimensions") - ? rule.getAsJsonObject("dimensions").getAsJsonObject(dimensionId) - : dimension != World.NETHER && dimension != World.END - ? rule.getAsJsonObject("dimension_selectors") - .getAsJsonObject("orespawn:all_except_nether_end") : null; + ? rule.getAsJsonObject("dimensions").getAsJsonObject(dimensionId) : null; + if (placement == null && dimension != Level.NETHER && dimension != Level.END + && rule.has("dimension_selectors")) { + placement = rule.getAsJsonObject("dimension_selectors") + .getAsJsonObject("orespawn:all_except_nether_end"); + } int height = section.bottomBlockY() + y; if (placement == null || height < placement.get("min_y").getAsInt() || height > placement.get("max_y").getAsInt()) { @@ -89,7 +104,12 @@ static int run(MinecraftServer server) throws Exception { } if (counts.isEmpty()) throw new IllegalStateException("No Base Metals ore in " + dimensionId + " sample"); - if (dimension == World.OVERWORLD && net.minecraftforge.fml.ModList.get().isLoaded("mineralogy")) { + if (dimension == Level.OVERWORLD && !net.minecraftforge.fml.ModList.get().isLoaded("mineralogy")) { + if (vanillaCopperCount == 0) throw new IllegalStateException("Vanilla copper generation was disabled"); + LogManager.getLogger("basemetalsprobe").info("BASEMETALS_COPPER_DEFAULTS PASS vanilla={} basemetals_enabled={}", + vanillaCopperCount, expectedCopper); + } + if (dimension == Level.OVERWORLD && net.minecraftforge.fml.ModList.get().isLoaded("mineralogy")) { if (rockCount == 0) throw new IllegalStateException("Mineralogy strata are absent from the ore sample"); LogManager.getLogger("basemetalsprobe").info("BASEMETALS_MINERALOGY_COEXISTENCE PASS rocks={}", rockCount); } @@ -97,7 +117,7 @@ static int run(MinecraftServer server) throws Exception { dimensionId, counts); } - if (server.getLevel(RegistryKey.create(net.minecraft.util.registry.Registry.DIMENSION_REGISTRY, + if (server.getLevel(ResourceKey.create(net.minecraft.core.Registry.DIMENSION_REGISTRY, new ResourceLocation("basemetalsprobe", "test_overworld"))) == null) { throw new IllegalStateException("Custom-dimension ore sample was not loaded"); } diff --git a/src/integrationTest/java/zone/moddev/mc/basemetals/testmod/RawOreChecks.java b/src/integrationTest/java/zone/moddev/mc/basemetals/testmod/RawOreChecks.java new file mode 100644 index 000000000..130128ecd --- /dev/null +++ b/src/integrationTest/java/zone/moddev/mc/basemetals/testmod/RawOreChecks.java @@ -0,0 +1,190 @@ +package zone.moddev.mc.basemetals.testmod; + +import java.util.List; +import java.util.Random; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.SimpleContainer; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.world.item.crafting.RecipeType; +import net.minecraft.world.item.enchantment.Enchantments; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.storage.loot.LootContext; +import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets; +import net.minecraft.world.level.storage.loot.parameters.LootContextParams; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.common.util.FakePlayer; +import net.minecraftforge.common.util.FakePlayerFactory; +import net.minecraftforge.event.world.BlockEvent; +import zone.moddev.mc.basemetals.BaseMetalsEvents; +import zone.moddev.mc.basemetals.content.ModContent; +import zone.moddev.mc.basemetals.material.MaterialCatalogue; +import zone.moddev.mc.basemetals.material.MaterialDefinition; +import zone.moddev.mc.basemetals.recipe.CrushingRecipe; + +/** Checks ore loot and both ways of hammering each raw metal. */ +final class RawOreChecks { + private RawOreChecks() {} + + static int run(MinecraftServer server) { + ServerLevel world = server.overworld(); + BlockPos position = world.getSharedSpawnPos().above(12); + FakePlayer player = FakePlayerFactory.getMinecraft(world); + player.setPos(position.getX(), position.getY(), position.getZ()); + ItemStack pickaxe = new ItemStack(Items.NETHERITE_PICKAXE); + ItemStack fortune = pickaxe.copy(); + fortune.enchant(Enchantments.BLOCK_FORTUNE, 3); + ItemStack silk = pickaxe.copy(); + silk.enchant(Enchantments.SILK_TOUCH, 1); + int checks = 0; + + for (MaterialDefinition material : MaterialCatalogue.ALL) { + if (!material.hasOre()) continue; + String name = material.name(); + Block ore = ModContent.blocksById().get(name + "_ore").get(); + Item raw = name.equals("copper") ? Items.RAW_COPPER : ModContent.item(name + "_raw").get(); + Item powder = ModContent.item(name + "_powder").get(); + int ordinaryMaximum = name.equals("copper") ? 3 : 1; + int ordinaryMinimum = name.equals("copper") ? 2 : 1; + + require(pickaxe.isCorrectToolForDrops(ore.defaultBlockState()), "adequate pickaxe " + name); + require(!new ItemStack(Items.WOODEN_PICKAXE).isCorrectToolForDrops(ore.defaultBlockState()) + || ModContent.requiredHarvestLevel(name) == 0, "minimum mining tier " + name); + assertLoot(world, ore, position, pickaxe, raw, ordinaryMinimum, ordinaryMaximum); + assertLoot(world, ore, position, silk, ore.asItem(), 1, 1); + int highest = 0; + for (int sample = 0; sample < 32; sample++) { + highest = Math.max(highest, assertLoot(world, ore, position, fortune, raw, + ordinaryMinimum, ordinaryMaximum * 4)); + } + require(highest > ordinaryMaximum, "Fortune increases raw drops " + name); + + LootContext.Builder explosion = new LootContext.Builder(world).withRandom(new Random(123)) + .withParameter(LootContextParams.ORIGIN, Vec3.atCenterOf(position)) + .withParameter(LootContextParams.BLOCK_STATE, ore.defaultBlockState()) + .withParameter(LootContextParams.TOOL, pickaxe) + .withParameter(LootContextParams.EXPLOSION_RADIUS, 16.0F); + List exploded = server.getLootTables().get(ore.getLootTable()) + .getRandomItems(explosion.create(LootContextParamSets.BLOCK)); + require(exploded.stream().allMatch(stack -> stack.isEmpty() + || (stack.getItem() == raw && stack.getCount() <= ordinaryMaximum)), + "explosion cannot duplicate raw " + name); + + checkCrushing(world, ore.asItem(), powder, 2); + checkCrushing(world, raw, powder, 1); + if (!name.equals("copper")) { + Item ingot = ModContent.item(name + "_ingot").get(); + checkCooking(world, raw, ingot, RecipeType.SMELTING); + checkCooking(world, raw, ingot, RecipeType.BLASTING); + } + checkHammer(world, player, position, ore, raw, powder); + checkBlendRejection(world, raw); + checks += 42; + } + + for (String name : new String[] {"iron", "gold", "copper"}) { + Item raw = net.minecraftforge.registries.ForgeRegistries.ITEMS.getValue( + new net.minecraft.resources.ResourceLocation("minecraft", "raw_" + name)); + Item ingot = net.minecraftforge.registries.ForgeRegistries.ITEMS.getValue( + new net.minecraft.resources.ResourceLocation("minecraft", name + "_ingot")); + checkCrushing(world, raw, ModContent.item(name + "_powder").get(), 1); + checkCooking(world, raw, ingot, RecipeType.SMELTING); + checkCooking(world, raw, ingot, RecipeType.BLASTING); + checkBlendRejection(world, raw); + checks += 3; + } + for (String name : new String[] {"iron", "gold", "copper", "coal", "diamond", "emerald", "lapis", "redstone"}) { + Item ordinaryOre = net.minecraftforge.registries.ForgeRegistries.ITEMS.getValue( + new net.minecraft.resources.ResourceLocation("minecraft", name + "_ore")); + ItemStack expected = world.getRecipeManager().getRecipeFor(CrushingRecipe.TYPE, + new SimpleContainer(new ItemStack(ordinaryOre)), world).orElseThrow().getResultItem(); + Item ore = net.minecraftforge.registries.ForgeRegistries.ITEMS.getValue( + new net.minecraft.resources.ResourceLocation("minecraft", "deepslate_" + name + "_ore")); + checkCrushing(world, ore, expected.getItem(), expected.getCount()); + checks++; + } + org.apache.logging.log4j.LogManager.getLogger("basemetalsprobe") + .info("BASEMETALS_RAW_ORE_PROBE PASS checks={}", checks); + return checks; + } + + private static int assertLoot(ServerLevel world, Block ore, BlockPos position, ItemStack tool, + Item expected, int minimum, int maximum) { + List drops = Block.getDrops(ore.defaultBlockState(), world, position, null, null, tool); + require(drops.size() == 1 && drops.get(0).getItem() == expected, "ore drop identity " + ore); + int count = drops.get(0).getCount(); + require(count >= minimum && count <= maximum, "ore drop count " + ore + " " + count); + return count; + } + + private static void checkCrushing(ServerLevel world, Item input, Item output, int count) { + CrushingRecipe recipe = world.getRecipeManager().getRecipeFor(CrushingRecipe.TYPE, + new SimpleContainer(new ItemStack(input)), world).orElseThrow(); + require(recipe.getResultItem().getItem() == output && recipe.getResultItem().getCount() == count, + "crushing yield " + input); + } + + private static void checkBlendRejection(ServerLevel world, Item raw) { + ItemStack input = new ItemStack(raw); + for (Recipe recipe : world.getRecipeManager().getRecipes()) { + if (!recipe.getId().getNamespace().equals("basemetals") + || !recipe.getId().getPath().contains("blend")) continue; + require(recipe.getIngredients().stream().noneMatch(ingredient -> ingredient.test(input)), + "raw material cannot replace blend powder " + raw + " in " + recipe.getId()); + } + } + + private static void checkCooking(ServerLevel world, Item input, Item output, RecipeType type) { + Recipe recipe = (Recipe) world.getRecipeManager().getRecipeFor(type, + new SimpleContainer(new ItemStack(input)), world).orElseThrow(); + require(recipe.getResultItem().getItem() == output && recipe.getResultItem().getCount() == 1, + "cooking yield " + input + " " + type); + } + + private static void checkHammer(ServerLevel world, FakePlayer player, BlockPos position, + Block ore, Item raw, Item powder) { + AABB area = new AABB(position).inflate(1); + world.getEntitiesOfClass(ItemEntity.class, area).forEach(ItemEntity::discard); + player.setItemInHand(InteractionHand.MAIN_HAND, new ItemStack(ModContent.item("adamantine_crackhammer").get())); + world.setBlock(position, ore.defaultBlockState(), 3); + BlockEvent.BreakEvent broken = new BlockEvent.BreakEvent(world, position, ore.defaultBlockState(), player); + new BaseMetalsEvents().onBreak(broken); + require(broken.isCanceled() && world.isEmptyBlock(position), "direct hammer replaces normal drops " + ore); + require(world.getEntitiesOfClass(ItemEntity.class, area).stream() + .map(ItemEntity::getItem).filter(stack -> stack.getItem() == powder) + .mapToInt(ItemStack::getCount).sum() == 2, "direct hammer gives two powders " + ore); + + world.getEntitiesOfClass(ItemEntity.class, area).forEach(ItemEntity::discard); + world.setBlock(position, Blocks.STONE.defaultBlockState(), 3); + ItemEntity ground = new ItemEntity(world, position.getX() + 0.5, position.getY() + 1.2, + position.getZ() + 0.5, new ItemStack(raw)); + world.addFreshEntity(ground); + UseOnContext use = new UseOnContext(player, InteractionHand.MAIN_HAND, + new BlockHitResult(Vec3.atCenterOf(position), Direction.UP, position, false)); + require(player.getMainHandItem().getItem().useOn(use) == InteractionResult.SUCCESS, + "ground hammer accepts raw " + raw); + require(world.getEntitiesOfClass(ItemEntity.class, area).stream() + .map(ItemEntity::getItem).filter(stack -> stack.getItem() == powder) + .mapToInt(ItemStack::getCount).sum() == 1, "ground raw gives one powder " + raw); + world.getEntitiesOfClass(ItemEntity.class, area).forEach(ItemEntity::discard); + world.removeBlock(position, false); + } + + private static void require(boolean condition, String message) { + if (!condition) throw new IllegalStateException(message); + } +} diff --git a/src/integrationTest/resources/META-INF/mods.toml b/src/integrationTest/resources/META-INF/mods.toml index 2215b104f..bdd7f09e0 100644 --- a/src/integrationTest/resources/META-INF/mods.toml +++ b/src/integrationTest/resources/META-INF/mods.toml @@ -1,30 +1,30 @@ modLoader="javafml" -loaderVersion="[36,)" +loaderVersion="[37,38)" license="LGPL-2.1" [[mods]] modId="basemetalsprobe" version="1" displayName="Base Metals Runtime Probe" -description='''Build-only lifecycle checks for Base Metals 1.16.5.''' +description='''Build-only lifecycle checks for Base Metals 1.17.1.''' [[dependencies.basemetalsprobe]] modId="basemetals" mandatory=true -versionRange="[3.1.0.116051]" +versionRange="[3.1.0.117011]" ordering="AFTER" side="BOTH" [[dependencies.basemetalsprobe]] modId="orespawn" mandatory=true -versionRange="[4.1.0.116051,5.0.0)" +versionRange="[4.1.0.117011,5.0.0)" ordering="AFTER" side="BOTH" [[dependencies.basemetalsprobe]] modId="minecraft" mandatory=true -versionRange="[1.16.5]" +versionRange="[1.17.1]" ordering="NONE" side="BOTH" diff --git a/src/integrationTest/resources/pack.mcmeta b/src/integrationTest/resources/pack.mcmeta index 371a77b13..f7199ea0b 100644 --- a/src/integrationTest/resources/pack.mcmeta +++ b/src/integrationTest/resources/pack.mcmeta @@ -1,6 +1,6 @@ { "pack": { - "description": "Base Metals 1.16.5 build-only runtime probe", - "pack_format": 6 + "description": "Base Metals 1.17.1 build-only runtime probe", + "pack_format": 7 } } diff --git a/src/main/java/zone/moddev/mc/basemetals/BaseMetalsAdvancements.java b/src/main/java/zone/moddev/mc/basemetals/BaseMetalsAdvancements.java index 4be162a82..0343b1f0c 100644 --- a/src/main/java/zone/moddev/mc/basemetals/BaseMetalsAdvancements.java +++ b/src/main/java/zone/moddev/mc/basemetals/BaseMetalsAdvancements.java @@ -10,15 +10,15 @@ import net.minecraft.advancements.Advancement; import net.minecraft.advancements.AdvancementProgress; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.entity.player.ServerPlayerEntity; -import net.minecraft.inventory.EquipmentSlotType; -import net.minecraft.item.ArmorItem; -import net.minecraft.item.ItemStack; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.item.ArmorItem; +import net.minecraft.world.item.ItemStack; import net.minecraft.tags.BlockTags; -import net.minecraft.tags.ITag; -import net.minecraft.util.ResourceLocation; +import net.minecraft.tags.Tag; +import net.minecraft.resources.ResourceLocation; final class BaseMetalsAdvancements { private static final String CRITERION = "event"; @@ -41,7 +41,7 @@ final class BaseMetalsAdvancements { private BaseMetalsAdvancements() {} - static void onCrafted(ServerPlayerEntity player, ItemStack result) { + static void onCrafted(ServerPlayer player, ItemStack result) { if (result.getItem() instanceof CrackhammerItem) award(player, "geologist"); ResourceLocation id = result.getItem().getRegistryName(); if (baseMetals(id) && (id.getPath().endsWith("_blend") || id.getPath().endsWith("_smallblend"))) { @@ -49,7 +49,7 @@ static void onCrafted(ServerPlayerEntity player, ItemStack result) { } } - static void onSmelted(ServerPlayerEntity player, ItemStack result) { + static void onSmelted(ServerPlayer player, ItemStack result) { ResourceLocation id = result.getItem().getRegistryName(); if (!baseMetals(id) || !id.getPath().endsWith("_ingot")) return; award(player, "this_is_new"); @@ -58,32 +58,32 @@ static void onSmelted(ServerPlayerEntity player, ItemStack result) { if (advancement != null) award(player, advancement); } - static void onPlaced(ServerPlayerEntity player, BlockState state) { + static void onPlaced(ServerPlayer player, BlockState state) { ResourceLocation id = state.getBlock().getRegistryName(); if (baseMetals(id) && state.is(BlockTags.getAllTags().getTagOrEmpty(STORAGE_BLOCKS))) { award(player, "blocktastic"); } } - static void onEquipment(ServerPlayerEntity player) { + static void onEquipment(ServerPlayer player) { if (fullArmor(player, "coldiron") && mainHandSword(player, "coldiron")) award(player, "demon_slayer"); if (fullArmor(player, "mithril") && mainHandSword(player, "mithril")) award(player, "angel_of_death"); if (fullArmor(player, "aquarium") && player.isInWater()) award(player, "scuba_diver"); if (fullArmor(player, "adamantine")) award(player, "juggernaut"); - if (material(player.getItemBySlot(EquipmentSlotType.FEET), "starsteel")) award(player, "moon_boots"); + if (material(player.getItemBySlot(EquipmentSlot.FEET), "starsteel")) award(player, "moon_boots"); } - private static boolean fullArmor(ServerPlayerEntity player, String material) { - EquipmentSlotType[] slots = { EquipmentSlotType.HEAD, EquipmentSlotType.CHEST, - EquipmentSlotType.LEGS, EquipmentSlotType.FEET }; - for (EquipmentSlotType slot : slots) { + private static boolean fullArmor(ServerPlayer player, String material) { + EquipmentSlot[] slots = { EquipmentSlot.HEAD, EquipmentSlot.CHEST, + EquipmentSlot.LEGS, EquipmentSlot.FEET }; + for (EquipmentSlot slot : slots) { ItemStack stack = player.getItemBySlot(slot); if (!(stack.getItem() instanceof ArmorItem) || !material(stack, material)) return false; } return true; } - private static boolean mainHandSword(ServerPlayerEntity player, String material) { + private static boolean mainHandSword(ServerPlayer player, String material) { ItemStack stack = player.getMainHandItem(); return stack.getItem() instanceof MaterialItems.Sword && material(stack, material); } @@ -97,7 +97,7 @@ private static boolean baseMetals(ResourceLocation id) { return id != null && BaseMetals.MOD_ID.equals(id.getNamespace()); } - static boolean award(ServerPlayerEntity player, String id) { + static boolean award(ServerPlayer player, String id) { Advancement advancement = player.getServer().getAdvancements().getAdvancement( new ResourceLocation(BaseMetals.MOD_ID, id)); if (advancement == null) return false; diff --git a/src/main/java/zone/moddev/mc/basemetals/BaseMetalsEvents.java b/src/main/java/zone/moddev/mc/basemetals/BaseMetalsEvents.java index 729655cf7..6f394386e 100644 --- a/src/main/java/zone/moddev/mc/basemetals/BaseMetalsEvents.java +++ b/src/main/java/zone/moddev/mc/basemetals/BaseMetalsEvents.java @@ -16,28 +16,28 @@ import zone.moddev.mc.basemetals.material.MaterialDefinition; import zone.moddev.mc.basemetals.recipe.CrushingRecipe; -import net.minecraft.block.BlockState; +import net.minecraft.world.level.block.state.BlockState; import net.minecraft.advancements.Advancement; -import net.minecraft.item.crafting.IRecipe; -import net.minecraft.enchantment.EnchantmentHelper; -import net.minecraft.entity.CreatureAttribute; -import net.minecraft.entity.Entity; -import net.minecraft.entity.LivingEntity; -import net.minecraft.entity.item.ItemEntity; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.player.ServerPlayerEntity; -import net.minecraft.potion.Effects; -import net.minecraft.inventory.EquipmentSlotType; -import net.minecraft.inventory.Inventory; -import net.minecraft.item.ArmorItem; -import net.minecraft.item.ItemStack; -import net.minecraft.item.TieredItem; -import net.minecraft.potion.Effect; -import net.minecraft.potion.EffectInstance; +import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.world.item.enchantment.EnchantmentHelper; +import net.minecraft.world.entity.MobType; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.effect.MobEffects; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.SimpleContainer; +import net.minecraft.world.item.ArmorItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TieredItem; +import net.minecraft.world.effect.MobEffect; +import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.tags.ItemTags; -import net.minecraft.util.ResourceLocation; -import net.minecraft.util.text.StringTextComponent; -import net.minecraft.world.World; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.world.level.Level; import net.minecraftforge.event.AnvilUpdateEvent; import net.minecraftforge.event.entity.living.LivingHurtEvent; import net.minecraftforge.event.world.BlockEvent; @@ -50,12 +50,12 @@ public final class BaseMetalsEvents { @SubscribeEvent public void onPlayerLogin(PlayerEvent.PlayerLoggedInEvent event) { - if (!(event.getPlayer() instanceof ServerPlayerEntity)) return; - ServerPlayerEntity player = (ServerPlayerEntity) event.getPlayer(); + if (!(event.getPlayer() instanceof ServerPlayer)) return; + ServerPlayer player = (ServerPlayer) event.getPlayer(); // An advancement can be earned while its recipe is disabled. Restore the // unlock after a mode change without resetting the player's progress. - for (IRecipe recipe : player.getServer().getRecipeManager().getRecipes()) { + for (Recipe recipe : player.getServer().getRecipeManager().getRecipes()) { if (!BaseMetals.MOD_ID.equals(recipe.getId().getNamespace()) || recipe.isSpecial() || player.getRecipeBook().contains(recipe)) continue; @@ -69,8 +69,8 @@ public void onPlayerLogin(PlayerEvent.PlayerLoggedInEvent event) { @SubscribeEvent(priority = EventPriority.LOWEST) public void onBreak(BlockEvent.BreakEvent event) { - PlayerEntity player = event.getPlayer(); - World world = player.level; + Player player = event.getPlayer(); + Level world = player.level; ItemStack held = player.getMainHandItem(); if (world.isClientSide || player.isCreative() || !(held.getItem() instanceof CrackhammerItem) || !event.getState().canHarvestBlock(world, event.getPos(), player)) return; @@ -89,13 +89,13 @@ public void onBreak(BlockEvent.BreakEvent event) { world.addFreshEntity(drop); player.awardStat(net.minecraft.stats.Stats.BLOCK_MINED.get(state.getBlock())); player.causeFoodExhaustion(0.005F); - held.hurtAndBreak(1, player, entity -> entity.broadcastBreakEvent(net.minecraft.util.Hand.MAIN_HAND)); + held.hurtAndBreak(1, player, entity -> entity.broadcastBreakEvent(net.minecraft.world.InteractionHand.MAIN_HAND)); } - private static CrushingRecipe crushing(World world, ItemStack input) { - Inventory inventory = new Inventory(1); + private static CrushingRecipe crushing(Level world, ItemStack input) { + SimpleContainer inventory = new SimpleContainer(1); inventory.setItem(0, input); - for (net.minecraft.item.crafting.IRecipe candidate : world.getRecipeManager().getRecipes()) { + for (net.minecraft.world.item.crafting.Recipe candidate : world.getRecipeManager().getRecipes()) { if (candidate instanceof CrushingRecipe && candidate.matches(inventory, world)) { return (CrushingRecipe) candidate; } @@ -105,14 +105,14 @@ private static CrushingRecipe crushing(World world, ItemStack input) { @SubscribeEvent public void onPlayerTick(TickEvent.PlayerTickEvent event) { - PlayerEntity player = event.player; + Player player = event.player; if (event.phase != TickEvent.Phase.END || player.level.isClientSide) return; if (BaseMetalsConfig.STARSTEEL_REGENERATION.get() && player.tickCount % 200 == 0) { repairStarsteel(player.getMainHandItem()); repairStarsteel(player.getOffhandItem()); } if (player.tickCount % 20 != 0) return; - if (player instanceof ServerPlayerEntity) BaseMetalsAdvancements.onEquipment((ServerPlayerEntity) player); + if (player instanceof ServerPlayer) BaseMetalsAdvancements.onEquipment((ServerPlayer) player); if (BaseMetalsConfig.SPECIAL_EFFECTS.get()) applyArmorEffects(player, armorMaterials(player)); } @@ -122,11 +122,11 @@ private static void repairStarsteel(ItemStack stack) { && stack.isDamaged()) stack.setDamageValue(Math.max(0, stack.getDamageValue() - 1)); } - private static Map armorMaterials(PlayerEntity player) { - Map result = new EnumMap(EquipmentSlotType.class); - EquipmentSlotType[] slots = { EquipmentSlotType.HEAD, EquipmentSlotType.CHEST, - EquipmentSlotType.LEGS, EquipmentSlotType.FEET }; - for (EquipmentSlotType slot : slots) { + private static Map armorMaterials(Player player) { + Map result = new EnumMap(EquipmentSlot.class); + EquipmentSlot[] slots = { EquipmentSlot.HEAD, EquipmentSlot.CHEST, + EquipmentSlot.LEGS, EquipmentSlot.FEET }; + for (EquipmentSlot slot : slots) { ItemStack stack = player.getItemBySlot(slot); if (stack.getItem() instanceof ArmorItem && stack.getItem() instanceof MaterialBacked) { result.put(slot, ((MaterialBacked) stack.getItem()).baseMetalsMaterial().name()); @@ -135,35 +135,35 @@ private static Map armorMaterials(PlayerEntity player return result; } - private static int count(Map armor, String material) { + private static int count(Map armor, String material) { int count = 0; for (String entry : armor.values()) if (material.equals(entry)) count++; return count; } - private static void applyArmorEffects(PlayerEntity player, Map armor) { + private static void applyArmorEffects(Player player, Map armor) { int adamantine = count(armor, "adamantine"); - if (adamantine >= 2) add(player, Effects.DAMAGE_RESISTANCE, adamantine == 4 ? 1 : 0); + if (adamantine >= 2) add(player, MobEffects.DAMAGE_RESISTANCE, adamantine == 4 ? 1 : 0); int lead = count(armor, "lead"); - if (lead >= 2) add(player, Effects.MOVEMENT_SLOWDOWN, lead == 4 ? 1 : 0); - if (count(armor, "coldiron") == 4) add(player, Effects.FIRE_RESISTANCE, 0); + if (lead >= 2) add(player, MobEffects.MOVEMENT_SLOWDOWN, lead == 4 ? 1 : 0); + if (count(armor, "coldiron") == 4) add(player, MobEffects.FIRE_RESISTANCE, 0); if (count(armor, "aquarium") == 4 && player.isInWater()) { - add(player, Effects.WATER_BREATHING, 0); - add(player, Effects.DAMAGE_RESISTANCE, 0); - player.removeEffect(Effects.DIG_SLOWDOWN); + add(player, MobEffects.WATER_BREATHING, 0); + add(player, MobEffects.DAMAGE_RESISTANCE, 0); + player.removeEffect(MobEffects.DIG_SLOWDOWN); } if (count(armor, "mithril") == 4) { - for (EffectInstance effect : new ArrayList(player.getActiveEffects())) { - if (effect.getEffect().getCategory() == net.minecraft.potion.EffectType.HARMFUL) player.removeEffect(effect.getEffect()); + for (MobEffectInstance effect : new ArrayList(player.getActiveEffects())) { + if (effect.getEffect().getCategory() == net.minecraft.world.effect.MobEffectCategory.HARMFUL) player.removeEffect(effect.getEffect()); } } int starsteel = count(armor, "starsteel"); - if (starsteel > 0) add(player, Effects.JUMP, starsteel - 1); - if (starsteel >= 2) add(player, Effects.MOVEMENT_SPEED, Math.min(2, starsteel - 2)); + if (starsteel > 0) add(player, MobEffects.JUMP, starsteel - 1); + if (starsteel >= 2) add(player, MobEffects.MOVEMENT_SPEED, Math.min(2, starsteel - 2)); } - private static void add(PlayerEntity player, Effect potion, int amplifier) { - player.addEffect(new EffectInstance(potion, 45, amplifier, false, false, true)); + private static void add(Player player, MobEffect potion, int amplifier) { + player.addEffect(new MobEffectInstance(potion, 45, amplifier, false, false, true)); } @SubscribeEvent @@ -182,9 +182,9 @@ public void onLivingHurt(LivingHurtEvent event) { event.setAmount(event.getAmount() + 4.0F); } else if ("coldiron".equals(material) && target.fireImmune()) { event.setAmount(event.getAmount() + 3.0F); - } else if ("mithril".equals(material) && target.getMobType() == CreatureAttribute.UNDEAD) { - target.addEffect(new EffectInstance(Effects.WITHER, 60, 3)); - target.addEffect(new EffectInstance(Effects.BLINDNESS, 60, 1)); + } else if ("mithril".equals(material) && target.getMobType() == MobType.UNDEAD) { + target.addEffect(new MobEffectInstance(MobEffects.WITHER, 60, 3)); + target.addEffect(new MobEffectInstance(MobEffects.BLINDNESS, 60, 1)); } } @@ -197,7 +197,7 @@ public void onShieldUpgrade(AnvilUpdateEvent event) { for (MaterialDefinition candidate : shieldMaterials().values()) { if (!ContentPolicy.active().allows(candidate.name(), MaterialForm.SHIELD)) continue; if (candidate.hardness() <= current.hardness()) continue; - net.minecraft.tags.ITag plate = ItemTags.getAllTags().getTagOrEmpty( + net.minecraft.tags.Tag plate = ItemTags.getAllTags().getTagOrEmpty( new ResourceLocation("forge", "plates/" + candidate.name())); if (!plate.contains(event.getRight().getItem())) continue; if (upgrade == null || candidate.hardness() < upgrade.hardness() @@ -215,7 +215,7 @@ public void onShieldUpgrade(AnvilUpdateEvent event) { private static Map shieldMaterials() { Map result = new LinkedHashMap(); - for (zone.moddev.mc.basemetals.content.RegistryHandle reference + for (zone.moddev.mc.basemetals.content.RegistryHandle reference : ModContent.itemsById().values()) { if (reference.get() instanceof MaterialItems.Shield) { MaterialDefinition material = ((MaterialItems.Shield) reference.get()).baseMetalsMaterial(); @@ -231,15 +231,15 @@ static int shieldUpgradeCost(MaterialDefinition current, MaterialDefinition upgr } @SubscribeEvent public void onItemCrafted(PlayerEvent.ItemCraftedEvent event) { - if (event.getPlayer() instanceof ServerPlayerEntity) - BaseMetalsAdvancements.onCrafted((ServerPlayerEntity) event.getPlayer(), event.getCrafting()); + if (event.getPlayer() instanceof ServerPlayer) + BaseMetalsAdvancements.onCrafted((ServerPlayer) event.getPlayer(), event.getCrafting()); } @SubscribeEvent public void onItemSmelted(PlayerEvent.ItemSmeltedEvent event) { - if (event.getPlayer() instanceof ServerPlayerEntity) - BaseMetalsAdvancements.onSmelted((ServerPlayerEntity) event.getPlayer(), event.getSmelting()); + if (event.getPlayer() instanceof ServerPlayer) + BaseMetalsAdvancements.onSmelted((ServerPlayer) event.getPlayer(), event.getSmelting()); } @SubscribeEvent public void onBlockPlaced(BlockEvent.EntityPlaceEvent event) { - if (event.getEntity() instanceof ServerPlayerEntity) - BaseMetalsAdvancements.onPlaced((ServerPlayerEntity) event.getEntity(), event.getPlacedBlock()); + if (event.getEntity() instanceof ServerPlayer) + BaseMetalsAdvancements.onPlaced((ServerPlayer) event.getEntity(), event.getPlacedBlock()); } } diff --git a/src/main/java/zone/moddev/mc/basemetals/MissingMappings.java b/src/main/java/zone/moddev/mc/basemetals/MissingMappings.java index 3aa4a575f..1deb3491c 100644 --- a/src/main/java/zone/moddev/mc/basemetals/MissingMappings.java +++ b/src/main/java/zone/moddev/mc/basemetals/MissingMappings.java @@ -3,9 +3,9 @@ import zone.moddev.mc.basemetals.content.ModContent; import zone.moddev.mc.basemetals.content.RegistryHandle; -import net.minecraft.block.Block; -import net.minecraft.item.Item; -import net.minecraft.util.ResourceLocation; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.item.Item; +import net.minecraft.resources.ResourceLocation; import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; diff --git a/src/main/java/zone/moddev/mc/basemetals/ModTabs.java b/src/main/java/zone/moddev/mc/basemetals/ModTabs.java index 3e1749d36..5f97f6b36 100644 --- a/src/main/java/zone/moddev/mc/basemetals/ModTabs.java +++ b/src/main/java/zone/moddev/mc/basemetals/ModTabs.java @@ -1,25 +1,25 @@ package zone.moddev.mc.basemetals; -import net.minecraft.block.Blocks; -import net.minecraft.item.Items; -import net.minecraft.item.Item; -import net.minecraft.item.ItemGroup; -import net.minecraft.item.ItemStack; -import net.minecraft.util.ResourceLocation; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.CreativeModeTab; +import net.minecraft.world.item.ItemStack; +import net.minecraft.resources.ResourceLocation; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.registries.ForgeRegistries; public final class ModTabs { - public static final ItemGroup BLOCKS = tab("blocks", "starsteel_block", Item.byBlock(Blocks.IRON_BLOCK)); - public static final ItemGroup ITEMS = tab("items", "starsteel_gear", Items.IRON_INGOT); - public static final ItemGroup TOOLS = tab("tools", "starsteel_pickaxe", Items.IRON_PICKAXE); - public static final ItemGroup COMBAT = tab("combat", "starsteel_sword", Items.IRON_SWORD); + public static final CreativeModeTab BLOCKS = tab("blocks", "starsteel_block", Item.byBlock(Blocks.IRON_BLOCK)); + public static final CreativeModeTab ITEMS = tab("items", "starsteel_gear", Items.IRON_INGOT); + public static final CreativeModeTab TOOLS = tab("tools", "starsteel_pickaxe", Items.IRON_PICKAXE); + public static final CreativeModeTab COMBAT = tab("combat", "starsteel_sword", Items.IRON_SWORD); private ModTabs() {} - private static ItemGroup tab(String suffix, final String iconId, final Item fallback) { - return new ItemGroup(BaseMetals.MOD_ID + "." + suffix) { + private static CreativeModeTab tab(String suffix, final String iconId, final Item fallback) { + return new CreativeModeTab(BaseMetals.MOD_ID + "." + suffix) { @Override @OnlyIn(Dist.CLIENT) public ItemStack makeIcon() { diff --git a/src/main/java/zone/moddev/mc/basemetals/ModTags.java b/src/main/java/zone/moddev/mc/basemetals/ModTags.java index b24549b08..aab459394 100644 --- a/src/main/java/zone/moddev/mc/basemetals/ModTags.java +++ b/src/main/java/zone/moddev/mc/basemetals/ModTags.java @@ -1,14 +1,14 @@ package zone.moddev.mc.basemetals; -import net.minecraft.block.Block; +import net.minecraft.world.level.block.Block; import net.minecraft.tags.BlockTags; -import net.minecraft.tags.ITag; -import net.minecraft.util.ResourceLocation; +import net.minecraft.tags.Tag; +import net.minecraft.resources.ResourceLocation; public final class ModTags { - public static final ITag SCYTHE_HARVESTABLE = BlockTags.createOptional( + public static final Tag SCYTHE_HARVESTABLE = BlockTags.createOptional( new ResourceLocation(BaseMetals.MOD_ID, "scythe_harvestable")); - public static final ITag CRACKHAMMER_CRUSHABLE = BlockTags.createOptional( + public static final Tag CRACKHAMMER_CRUSHABLE = BlockTags.createOptional( new ResourceLocation(BaseMetals.MOD_ID, "crackhammer_crushable")); private ModTags() {} diff --git a/src/main/java/zone/moddev/mc/basemetals/client/BaseMetalsConfigScreen.java b/src/main/java/zone/moddev/mc/basemetals/client/BaseMetalsConfigScreen.java index ff7cf4564..7bdcc3c90 100644 --- a/src/main/java/zone/moddev/mc/basemetals/client/BaseMetalsConfigScreen.java +++ b/src/main/java/zone/moddev/mc/basemetals/client/BaseMetalsConfigScreen.java @@ -2,16 +2,16 @@ import java.util.ArrayList; import java.util.List; -import com.mojang.blaze3d.matrix.MatrixStack; -import net.minecraft.util.IReorderingProcessor; -import net.minecraft.util.text.StringTextComponent; - -import net.minecraft.client.gui.widget.button.Button; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.screen.ConfirmScreen; -import net.minecraft.client.gui.widget.Widget; -import net.minecraft.client.resources.I18n; -import net.minecraft.util.text.TranslationTextComponent; +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.util.FormattedCharSequence; +import net.minecraft.network.chat.TextComponent; + +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.ConfirmScreen; +import net.minecraft.client.gui.components.AbstractWidget; +import net.minecraft.client.resources.language.I18n; +import net.minecraft.network.chat.TranslatableComponent; import net.minecraftforge.common.ForgeConfigSpec; import zone.moddev.mc.basemetals.config.BaseMetalsConfig; import zone.moddev.mc.basemetals.config.ConfigEdits; @@ -34,7 +34,7 @@ public final class BaseMetalsConfigScreen extends Screen { private OptionButton modeButton; public BaseMetalsConfigScreen(Screen parent) { - super(new TranslationTextComponent(PREFIX + "title")); + super(new TranslatableComponent(PREFIX + "title")); this.parent = parent; this.edits = new ConfigEdits(ContentMode.parse(BaseMetalsConfig.CONTENT_MODE.get()), VALUES[0].get(), VALUES[1].get(), VALUES[2].get(), VALUES[3].get()); @@ -45,7 +45,7 @@ protected void init() { optionButtons.clear(); int left = width / 2 - 150; int top = Math.max(38, height / 2 - 90); - modeButton = addButton(new OptionButton(left, top, 300, modeLabel(), () -> { + modeButton = addRenderableWidget(new OptionButton(left, top, 300, modeLabel(), () -> { edits.cycleMode(); initLabels(); }, "contentMode")); @@ -58,19 +58,19 @@ protected void init() { initLabels(); }, OPTIONS[index]); optionButtons.add(button); - addButton(button); + addRenderableWidget(button); } - addButton(new OptionButton(left, top + 138, 145, I18n.get(PREFIX + "defaults"), () -> { + addRenderableWidget(new OptionButton(left, top + 138, 145, I18n.get(PREFIX + "defaults"), () -> { edits.defaults(); initLabels(); }, null)); - addButton(new OptionButton(left + 155, top + 138, 145, I18n.get(PREFIX + "undo"), () -> { + addRenderableWidget(new OptionButton(left + 155, top + 138, 145, I18n.get(PREFIX + "undo"), () -> { edits.undo(); initLabels(); }, null)); - addButton(new OptionButton(left, height - 28, 145, I18n.get("gui.done"), this::done, null)); - addButton(new OptionButton(left + 155, height - 28, 145, I18n.get("gui.cancel"), this::onClose, null)); + addRenderableWidget(new OptionButton(left, height - 28, 145, I18n.get("gui.done"), this::done, null)); + addRenderableWidget(new OptionButton(left + 155, height - 28, 145, I18n.get("gui.cancel"), this::onClose, null)); } private String modeLabel() { @@ -83,18 +83,18 @@ private String optionLabel(int index) { } private void initLabels() { - modeButton.setMessage(new StringTextComponent(modeLabel())); + modeButton.setMessage(new TextComponent(modeLabel())); for (int index = 0; index < optionButtons.size(); index++) { - optionButtons.get(index).setMessage(new StringTextComponent(optionLabel(index))); + optionButtons.get(index).setMessage(new TextComponent(optionLabel(index))); } } private void done() { if (edits.modeChanged()) { minecraft.setScreen(new ConfirmScreen(this::confirmResult, - new TranslationTextComponent(PREFIX + "confirm.title"), - new TranslationTextComponent(PREFIX + "confirm.message"))); + new TranslatableComponent(PREFIX + "confirm.title"), + new TranslatableComponent(PREFIX + "confirm.message"))); } else { saveAndClose(); } @@ -121,20 +121,20 @@ public void onClose() { } @Override - public void render(MatrixStack matrices, int mouseX, int mouseY, float partialTicks) { + public void render(PoseStack matrices, int mouseX, int mouseY, float partialTicks) { renderBackground(matrices); drawCenteredString(matrices, font, title, width / 2, 12, 0xFFFFFF); super.render(matrices, mouseX, mouseY, partialTicks); - for (Widget button : buttons) { - if (button instanceof OptionButton && button.isHovered()) { - String key = ((OptionButton) button).option; + for (net.minecraft.client.gui.components.events.GuiEventListener child : children()) { + if (child instanceof OptionButton && ((OptionButton) child).isHovered()) { + String key = ((OptionButton) child).option; if (key != null) { - List help = new ArrayList<>(font.split( - new TranslationTextComponent(PREFIX + key + ".tooltip"), 280)); + List help = new ArrayList<>(font.split( + new TranslatableComponent(PREFIX + key + ".tooltip"), 280)); if ("contentMode".equals(key)) { - help.addAll(font.split(new TranslationTextComponent(edits.mode().translationKey() + ".description"), 280)); - help.addAll(font.split(new TranslationTextComponent(PREFIX + "restart"), 280)); + help.addAll(font.split(new TranslatableComponent(edits.mode().translationKey() + ".description"), 280)); + help.addAll(font.split(new TranslatableComponent(PREFIX + "restart"), 280)); } renderTooltip(matrices, help, mouseX, mouseY); } @@ -146,7 +146,7 @@ private static final class OptionButton extends Button { private final String option; private OptionButton(int x, int y, int width, String label, Runnable click, String option) { - super(x, y, width, 20, new StringTextComponent(label), button -> click.run()); + super(x, y, width, 20, new TextComponent(label), button -> click.run()); this.option = option; } diff --git a/src/main/java/zone/moddev/mc/basemetals/client/ClientSetup.java b/src/main/java/zone/moddev/mc/basemetals/client/ClientSetup.java index 5aac2240e..ae586c2f9 100644 --- a/src/main/java/zone/moddev/mc/basemetals/client/ClientSetup.java +++ b/src/main/java/zone/moddev/mc/basemetals/client/ClientSetup.java @@ -4,49 +4,53 @@ import zone.moddev.mc.basemetals.content.ModContent; import zone.moddev.mc.basemetals.entity.ModEntities; -import net.minecraftforge.fml.client.registry.RenderingRegistry; -import net.minecraftforge.fml.ExtensionPoint; +import net.minecraftforge.client.event.EntityRenderersEvent; +import net.minecraftforge.fmlclient.ConfigGuiHandler; import net.minecraftforge.fml.ModLoadingContext; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.RenderTypeLookup; -import net.minecraft.block.Block; -import net.minecraft.block.DoorBlock; -import net.minecraft.block.PaneBlock; -import net.minecraft.block.TrapDoorBlock; +import net.minecraft.client.renderer.ItemBlockRenderTypes; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.DoorBlock; +import net.minecraft.world.level.block.IronBarsBlock; +import net.minecraft.world.level.block.TrapDoorBlock; import zone.moddev.mc.orespawn.api.client.WorldSettingsExtensionRegistry; public final class ClientSetup { private ClientSetup() {} public static void register() { - ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.CONFIGGUIFACTORY, - () -> (minecraft, parent) -> new BaseMetalsConfigScreen(parent)); + ModLoadingContext.get().registerExtensionPoint(ConfigGuiHandler.ConfigGuiFactory.class, + () -> new ConfigGuiHandler.ConfigGuiFactory((minecraft, parent) -> new BaseMetalsConfigScreen(parent))); WorldSettingsExtensionRegistry.registerConfigScreen("basemetals", BaseMetalsConfigScreen::new); net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext.get().getModEventBus() .addListener(ClientSetup::setupRendering); + net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext.get().getModEventBus() + .addListener(ClientSetup::registerEntityRenderers); } private static void setupRendering(FMLClientSetupEvent event) { - RenderingRegistry.registerEntityRenderingHandler(ModEntities.CUSTOM_ARROW.get(), MaterialProjectileRenderer::new); - RenderingRegistry.registerEntityRenderingHandler(ModEntities.CUSTOM_BOLT.get(), MaterialProjectileRenderer::new); - event.enqueueWork(ClientSetup::registerRenderLayers); } + private static void registerEntityRenderers(EntityRenderersEvent.RegisterRenderers event) { + event.registerEntityRenderer(ModEntities.CUSTOM_ARROW.get(), MaterialProjectileRenderer::new); + event.registerEntityRenderer(ModEntities.CUSTOM_BOLT.get(), MaterialProjectileRenderer::new); + } + private static void registerRenderLayers() { ModContent.blocksById().forEach((name, handle) -> { Block block = handle.get(); if (name.endsWith("_ore") || block instanceof DoorBlock - || block instanceof TrapDoorBlock || block instanceof PaneBlock) { - RenderTypeLookup.setRenderLayer(block, RenderType.cutoutMipped()); + || block instanceof TrapDoorBlock || block instanceof IronBarsBlock) { + ItemBlockRenderTypes.setRenderLayer(block, RenderType.cutoutMipped()); } }); for (FluidContent fluid : ModContent.fluids().values()) { - RenderTypeLookup.setRenderLayer(fluid.source().get(), RenderType.translucent()); - RenderTypeLookup.setRenderLayer(fluid.flowing().get(), RenderType.translucent()); - RenderTypeLookup.setRenderLayer(fluid.block().get(), RenderType.translucent()); + ItemBlockRenderTypes.setRenderLayer(fluid.source().get(), RenderType.translucent()); + ItemBlockRenderTypes.setRenderLayer(fluid.flowing().get(), RenderType.translucent()); + ItemBlockRenderTypes.setRenderLayer(fluid.block().get(), RenderType.translucent()); } } diff --git a/src/main/java/zone/moddev/mc/basemetals/client/MaterialProjectileRenderer.java b/src/main/java/zone/moddev/mc/basemetals/client/MaterialProjectileRenderer.java index ddc4b4a82..d38138e6a 100644 --- a/src/main/java/zone/moddev/mc/basemetals/client/MaterialProjectileRenderer.java +++ b/src/main/java/zone/moddev/mc/basemetals/client/MaterialProjectileRenderer.java @@ -3,15 +3,15 @@ import zone.moddev.mc.basemetals.entity.MaterialProjectile; import net.minecraft.client.renderer.entity.ArrowRenderer; -import net.minecraft.client.renderer.entity.EntityRendererManager; -import net.minecraft.util.ResourceLocation; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; public final class MaterialProjectileRenderer extends ArrowRenderer { private static final ResourceLocation ARROW_TEXTURE = new ResourceLocation("textures/entity/projectiles/arrow.png"); - public MaterialProjectileRenderer(EntityRendererManager manager) { - super(manager); + public MaterialProjectileRenderer(EntityRendererProvider.Context context) { + super(context); } @Override diff --git a/src/main/java/zone/moddev/mc/basemetals/config/BaseMetalsConfig.java b/src/main/java/zone/moddev/mc/basemetals/config/BaseMetalsConfig.java index 713739465..f7d129557 100644 --- a/src/main/java/zone/moddev/mc/basemetals/config/BaseMetalsConfig.java +++ b/src/main/java/zone/moddev/mc/basemetals/config/BaseMetalsConfig.java @@ -2,6 +2,7 @@ import net.minecraftforge.common.ForgeConfigSpec; import net.minecraftforge.fml.config.ModConfig; +import net.minecraftforge.fml.event.config.ModConfigEvent; import zone.moddev.mc.basemetals.BaseMetals; public final class BaseMetalsConfig { @@ -35,7 +36,7 @@ public final class BaseMetalsConfig { private BaseMetalsConfig() {} - public static void onConfigLoading(ModConfig.Loading event) { + public static void onConfigLoading(ModConfigEvent.Loading event) { if (event.getConfig().getSpec() != SPEC || modeLoaded) return; loadedConfig = event.getConfig(); String value = CONTENT_MODE.get(); diff --git a/src/main/java/zone/moddev/mc/basemetals/config/ContentPolicy.java b/src/main/java/zone/moddev/mc/basemetals/config/ContentPolicy.java index d7fe917ac..bacfd9708 100644 --- a/src/main/java/zone/moddev/mc/basemetals/config/ContentPolicy.java +++ b/src/main/java/zone/moddev/mc/basemetals/config/ContentPolicy.java @@ -80,7 +80,7 @@ public boolean allows(String material, MaterialForm form) { if (form == MaterialForm.GEAR) return GEARS.contains(material); if (form == MaterialForm.ANVIL) return ANVILS.contains(material); if ("mercury".equals(material)) { - return form == MaterialForm.ORE || form == MaterialForm.POWDER || form == MaterialForm.SMALLPOWDER + return form == MaterialForm.ORE || form == MaterialForm.RAW || form == MaterialForm.POWDER || form == MaterialForm.SMALLPOWDER || form == MaterialForm.FLUID || form == MaterialForm.INGOT; } diff --git a/src/main/java/zone/moddev/mc/basemetals/config/MaterialForm.java b/src/main/java/zone/moddev/mc/basemetals/config/MaterialForm.java index 0d38dad1a..98f14e81c 100644 --- a/src/main/java/zone/moddev/mc/basemetals/config/MaterialForm.java +++ b/src/main/java/zone/moddev/mc/basemetals/config/MaterialForm.java @@ -10,7 +10,7 @@ public enum MaterialForm { SMALLPOWDER, SWORD, CASING, CLUMP, CRUSHED, CRUSHED_PURIFIED, CRYSTAL, DENSE_PLATE, DIRTY_POWDER, SHARD, ANVIL, BARS, BLOCK, BOOKSHELF, BUTTON, DOOR, DOUBLE_SLAB, FENCE, FENCE_GATE, FLOWER_POT, LADDER, LEVER, PLATE, - PRESSURE_PLATE, SLAB, STAIRS, TRAPDOOR, TRIPWIRE_HOOK, WALL, ORE, FLUID, OTHER; + PRESSURE_PLATE, SLAB, STAIRS, TRAPDOOR, TRIPWIRE_HOOK, WALL, ORE, RAW, FLUID, OTHER; public static MaterialForm fromPath(String path) { MaterialForm result = OTHER; diff --git a/src/main/java/zone/moddev/mc/basemetals/content/BaseMetalAmmoItem.java b/src/main/java/zone/moddev/mc/basemetals/content/BaseMetalAmmoItem.java index ffe103b35..738b5c544 100644 --- a/src/main/java/zone/moddev/mc/basemetals/content/BaseMetalAmmoItem.java +++ b/src/main/java/zone/moddev/mc/basemetals/content/BaseMetalAmmoItem.java @@ -5,13 +5,13 @@ import zone.moddev.mc.basemetals.entity.MaterialProjectile; import zone.moddev.mc.basemetals.material.MaterialDefinition; -import net.minecraft.entity.LivingEntity; -import net.minecraft.entity.EntityType; -import net.minecraft.entity.projectile.AbstractArrowEntity; -import net.minecraft.item.Item; -import net.minecraft.item.ArrowItem; -import net.minecraft.item.ItemStack; -import net.minecraft.world.World; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.projectile.AbstractArrow; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ArrowItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; public final class BaseMetalAmmoItem extends ArrowItem implements MaterialBacked { public enum Kind { ARROW, BOLT } @@ -31,7 +31,7 @@ public BaseMetalAmmoItem(MaterialDefinition material, Kind kind, @Override public MaterialDefinition baseMetalsMaterial() { return material; } @Override - public AbstractArrowEntity createArrow(World world, ItemStack stack, LivingEntity shooter) { + public AbstractArrow createArrow(Level world, ItemStack stack, LivingEntity shooter) { MaterialProjectile projectile = new MaterialProjectile(entityType.get(), world, shooter, stack); // A vanilla bow adds one damage. Material bows replace that with their own damage. diff --git a/src/main/java/zone/moddev/mc/basemetals/content/BaseMetalAnvilBlock.java b/src/main/java/zone/moddev/mc/basemetals/content/BaseMetalAnvilBlock.java index bfc1990a9..f9ea8d30d 100644 --- a/src/main/java/zone/moddev/mc/basemetals/content/BaseMetalAnvilBlock.java +++ b/src/main/java/zone/moddev/mc/basemetals/content/BaseMetalAnvilBlock.java @@ -1,20 +1,20 @@ package zone.moddev.mc.basemetals.content; -import net.minecraft.block.AnvilBlock; -import net.minecraft.block.BlockState; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.inventory.container.Container; -import net.minecraft.inventory.container.RepairContainer; -import net.minecraft.item.BlockItemUseContext; -import net.minecraft.state.IntegerProperty; -import net.minecraft.state.StateContainer; -import net.minecraft.util.Direction; -import net.minecraft.util.Hand; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.text.ITextComponent; -import net.minecraft.util.text.TranslationTextComponent; -import net.minecraft.world.World; +import net.minecraft.world.level.block.AnvilBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.AnvilMenu; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.block.state.properties.IntegerProperty; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.core.Direction; +import net.minecraft.world.InteractionHand; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.world.level.Level; /** Uses the vanilla repair screen and keeps the same block ID as the anvil wears out. */ public final class BaseMetalAnvilBlock extends AnvilBlock { @@ -27,12 +27,12 @@ public BaseMetalAnvilBlock(Properties properties) { } @Override - public BlockState getStateForPlacement(BlockItemUseContext context) { + public BlockState getStateForPlacement(BlockPlaceContext context) { return defaultBlockState().setValue(FACING, context.getHorizontalDirection().getClockWise()); } @Override - protected void createBlockStateDefinition(StateContainer.Builder builder) { + protected void createBlockStateDefinition(StateDefinition.Builder builder) { builder.add(FACING, DAMAGE); } @@ -47,15 +47,15 @@ public static BlockState damageBaseMetalAnvil(BlockState state) { } @Override - public net.minecraft.inventory.container.INamedContainerProvider getMenuProvider( - BlockState state, World world, BlockPos pos) { - return new net.minecraft.inventory.container.SimpleNamedContainerProvider((windowId, inventory, player) -> - new RepairContainer(windowId, inventory, net.minecraft.util.IWorldPosCallable.create(world, pos)) { - @Override public boolean stillValid(PlayerEntity candidate) { + public net.minecraft.world.MenuProvider getMenuProvider( + BlockState state, Level world, BlockPos pos) { + return new net.minecraft.world.SimpleMenuProvider((windowId, inventory, player) -> + new AnvilMenu(windowId, inventory, net.minecraft.world.inventory.ContainerLevelAccess.create(world, pos)) { + @Override public boolean stillValid(Player candidate) { return world.getBlockState(pos).getBlock() == BaseMetalAnvilBlock.this && candidate.distanceToSqr(pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D) <= 64.0D; } - }, new TranslationTextComponent(getDescriptionId())); + }, new TranslatableComponent(getDescriptionId())); } } diff --git a/src/main/java/zone/moddev/mc/basemetals/content/BaseMetalBucketItem.java b/src/main/java/zone/moddev/mc/basemetals/content/BaseMetalBucketItem.java index 9384af570..2a9c44cf2 100644 --- a/src/main/java/zone/moddev/mc/basemetals/content/BaseMetalBucketItem.java +++ b/src/main/java/zone/moddev/mc/basemetals/content/BaseMetalBucketItem.java @@ -1,8 +1,8 @@ package zone.moddev.mc.basemetals.content; -import net.minecraft.fluid.Fluid; -import net.minecraft.item.Item; -import net.minecraft.item.BucketItem; +import net.minecraft.world.level.material.Fluid; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.BucketItem; /** A dedicated filled bucket for each molten fluid. */ public final class BaseMetalBucketItem extends BucketItem { diff --git a/src/main/java/zone/moddev/mc/basemetals/content/CompatibilityDoubleSlabBlock.java b/src/main/java/zone/moddev/mc/basemetals/content/CompatibilityDoubleSlabBlock.java index 5f457b402..1c9ffcf63 100644 --- a/src/main/java/zone/moddev/mc/basemetals/content/CompatibilityDoubleSlabBlock.java +++ b/src/main/java/zone/moddev/mc/basemetals/content/CompatibilityDoubleSlabBlock.java @@ -1,9 +1,8 @@ package zone.moddev.mc.basemetals.content; -import net.minecraft.block.SlabBlock; -import net.minecraft.block.BlockState; -import net.minecraft.state.properties.SlabType; -import net.minecraftforge.common.ToolType; +import net.minecraft.world.level.block.SlabBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.SlabType; /** Keeps old double slabs intact when a 1.10 or 1.12 world is upgraded. */ public final class CompatibilityDoubleSlabBlock extends SlabBlock { @@ -14,7 +13,4 @@ public CompatibilityDoubleSlabBlock(Properties properties, int harvestLevel) { this.harvestLevel = harvestLevel; registerDefaultState(defaultBlockState().setValue(TYPE, SlabType.DOUBLE).setValue(WATERLOGGED, Boolean.FALSE)); } - - @Override public ToolType getHarvestTool(BlockState state) { return ToolType.PICKAXE; } - @Override public int getHarvestLevel(BlockState state) { return harvestLevel; } } diff --git a/src/main/java/zone/moddev/mc/basemetals/content/CrackhammerItem.java b/src/main/java/zone/moddev/mc/basemetals/content/CrackhammerItem.java index 5458cedec..6b97a08e8 100644 --- a/src/main/java/zone/moddev/mc/basemetals/content/CrackhammerItem.java +++ b/src/main/java/zone/moddev/mc/basemetals/content/CrackhammerItem.java @@ -9,37 +9,38 @@ import zone.moddev.mc.basemetals.material.MaterialDefinition; import zone.moddev.mc.basemetals.recipe.CrushingRecipe; -import net.minecraft.block.Block; -import net.minecraft.block.material.Material; -import net.minecraft.block.BlockState; -import net.minecraft.entity.LivingEntity; -import net.minecraft.entity.item.ItemEntity; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.inventory.Inventory; -import net.minecraft.item.Item; -import net.minecraft.item.BlockItem; -import net.minecraft.item.ItemStack; -import net.minecraft.item.ToolItem; -import net.minecraft.item.ItemUseContext; -import net.minecraft.client.util.ITooltipFlag; -import net.minecraft.util.ActionResultType; -import net.minecraft.util.Direction; -import net.minecraft.util.SoundCategory; -import net.minecraft.util.math.AxisAlignedBB; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.text.ITextComponent; -import net.minecraft.util.text.StringTextComponent; -import net.minecraft.world.World; -import net.minecraftforge.common.ToolType; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.material.Material; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.SimpleContainer; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.DiggerItem; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.InteractionResult; +import net.minecraft.core.Direction; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.phys.AABB; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.world.level.Level; +import net.minecraft.tags.BlockTags; +import net.minecraftforge.common.ToolActions; +import net.minecraftforge.common.ToolAction; -public final class CrackhammerItem extends ToolItem implements MaterialBacked { +public final class CrackhammerItem extends DiggerItem implements MaterialBacked { private final MaterialDefinition material; public CrackhammerItem(MaterialDefinition material, Item.Properties properties) { super(material.crackhammerAttackDamage() - material.baseAttackDamage(), -3.5F, - new MaterialTier(material), Collections.emptySet(), - properties.defaultDurability(material.crackhammerDurability()) - .addToolType(ToolType.PICKAXE, material.toolLevel())); + new MaterialTier(material), BlockTags.MINEABLE_WITH_PICKAXE, + properties.defaultDurability(material.crackhammerDurability())); this.material = material; } @@ -50,23 +51,20 @@ public CrackhammerItem(MaterialDefinition material, Item.Properties properties) ? material.crackhammerDestroySpeed() : 1.0F; } - @Override public boolean isCorrectToolForDrops(BlockState state) { - if (state.getHarvestTool() == ToolType.PICKAXE) return material.toolLevel() >= state.getHarvestLevel(); - Material blockMaterial = state.getMaterial(); - return blockMaterial == Material.STONE || blockMaterial == Material.METAL - || blockMaterial == Material.HEAVY_METAL; + @Override public boolean canPerformAction(ItemStack stack, ToolAction action) { + return action == ToolActions.PICKAXE_DIG; } - @Override public void appendHoverText(ItemStack stack, @Nullable World world, - List tooltip, ITooltipFlag flag) { MaterialItems.addToolTooltip(material, tooltip); } + @Override public void appendHoverText(ItemStack stack, @Nullable Level world, + List tooltip, TooltipFlag flag) { MaterialItems.addToolTooltip(material, tooltip); } @Override - public ActionResultType useOn(ItemUseContext context) { - World world = context.getLevel(); - PlayerEntity player = context.getPlayer(); - if (context.getClickedFace() != Direction.UP || world.isClientSide || player == null) return ActionResultType.PASS; + public InteractionResult useOn(UseOnContext context) { + Level world = context.getLevel(); + Player player = context.getPlayer(); + if (context.getClickedFace() != Direction.UP || world.isClientSide || player == null) return InteractionResult.PASS; - AxisAlignedBB area = new AxisAlignedBB(context.getClickedPos().above()); + AABB area = new AABB(context.getClickedPos().above()); List entities = world.getEntitiesOfClass(ItemEntity.class, area); for (ItemEntity entity : entities) { ItemStack input = entity.getItem(); @@ -80,21 +78,21 @@ public ActionResultType useOn(ItemUseContext context) { if (operations <= 0) break; ItemStack output = recipe.getResultItem().copy(); input.shrink(operations); - if (input.isEmpty()) entity.remove(); else entity.setItem(input); + if (input.isEmpty()) entity.discard(); else entity.setItem(input); spawnOutputs(world, entity, output, operations); hammer.hurtAndBreak(operations, player, holder -> holder.broadcastBreakEvent(context.getHand())); - world.playSound(null, context.getClickedPos(), net.minecraft.util.SoundEvents.GRAVEL_BREAK, - SoundCategory.BLOCKS, 0.5F, 0.5F + world.random.nextFloat() * 0.3F); - return ActionResultType.SUCCESS; + world.playSound(null, context.getClickedPos(), net.minecraft.sounds.SoundEvents.GRAVEL_BREAK, + SoundSource.BLOCKS, 0.5F, 0.5F + world.random.nextFloat() * 0.3F); + return InteractionResult.SUCCESS; } - return ActionResultType.PASS; + return InteractionResult.PASS; } @Nullable - private static CrushingRecipe findRecipe(World world, ItemStack input) { - Inventory inventory = new Inventory(1); + private static CrushingRecipe findRecipe(Level world, ItemStack input) { + SimpleContainer inventory = new SimpleContainer(1); inventory.setItem(0, input); - for (net.minecraft.item.crafting.IRecipe candidate : world.getRecipeManager().getRecipes()) { + for (net.minecraft.world.item.crafting.Recipe candidate : world.getRecipeManager().getRecipes()) { if (candidate instanceof CrushingRecipe && candidate.matches(inventory, world)) { return (CrushingRecipe) candidate; } @@ -107,7 +105,7 @@ private boolean canCrushDroppedBlock(ItemStack input) { return isCorrectToolForDrops(((BlockItem) input.getItem()).getBlock().defaultBlockState()); } - private static void spawnOutputs(World world, ItemEntity source, ItemStack result, int operations) { + private static void spawnOutputs(Level world, ItemEntity source, ItemStack result, int operations) { int remaining = result.getCount() * operations; while (remaining > 0) { ItemStack output = result.copy(); diff --git a/src/main/java/zone/moddev/mc/basemetals/content/FluidContent.java b/src/main/java/zone/moddev/mc/basemetals/content/FluidContent.java index 1652eddd4..05aae2ec5 100644 --- a/src/main/java/zone/moddev/mc/basemetals/content/FluidContent.java +++ b/src/main/java/zone/moddev/mc/basemetals/content/FluidContent.java @@ -1,17 +1,17 @@ package zone.moddev.mc.basemetals.content; -import net.minecraft.block.FlowingFluidBlock; -import net.minecraft.fluid.FlowingFluid; -import net.minecraft.item.Item; +import net.minecraft.world.level.block.LiquidBlock; +import net.minecraft.world.level.material.FlowingFluid; +import net.minecraft.world.item.Item; public final class FluidContent { private final RegistryHandle source; private final RegistryHandle flowing; - private final RegistryHandle block; + private final RegistryHandle block; private final RegistryHandle bucket; public FluidContent(RegistryHandle source, RegistryHandle flowing, - RegistryHandle block, RegistryHandle bucket) { + RegistryHandle block, RegistryHandle bucket) { this.source = source; this.flowing = flowing; this.block = block; @@ -20,6 +20,6 @@ public FluidContent(RegistryHandle source, RegistryHandle source() { return source; } public RegistryHandle flowing() { return flowing; } - public RegistryHandle block() { return block; } + public RegistryHandle block() { return block; } public RegistryHandle bucket() { return bucket; } } diff --git a/src/main/java/zone/moddev/mc/basemetals/content/HumanDetectorBlock.java b/src/main/java/zone/moddev/mc/basemetals/content/HumanDetectorBlock.java index 35afb96cd..abd8c63b1 100644 --- a/src/main/java/zone/moddev/mc/basemetals/content/HumanDetectorBlock.java +++ b/src/main/java/zone/moddev/mc/basemetals/content/HumanDetectorBlock.java @@ -2,11 +2,11 @@ import java.util.List; -import net.minecraft.block.PressurePlateBlock; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.util.math.AxisAlignedBB; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; +import net.minecraft.world.level.block.PressurePlateBlock; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.phys.AABB; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.Level; /** A pressure plate which responds to players only. */ public final class HumanDetectorBlock extends PressurePlateBlock { @@ -15,10 +15,10 @@ public HumanDetectorBlock(Properties properties) { } @Override - public int getSignalStrength(World world, BlockPos pos) { - AxisAlignedBB box = TOUCH_AABB.move(pos); - List players = world.getEntitiesOfClass(PlayerEntity.class, box); - for (PlayerEntity player : players) { + public int getSignalStrength(Level world, BlockPos pos) { + AABB box = TOUCH_AABB.move(pos); + List players = world.getEntitiesOfClass(Player.class, box); + for (Player player : players) { if (!player.isSpectator() && !player.isIgnoringBlockTriggers()) return 15; } return 0; diff --git a/src/main/java/zone/moddev/mc/basemetals/content/MaterialArmor.java b/src/main/java/zone/moddev/mc/basemetals/content/MaterialArmor.java index d7bf91d06..e18d07e9b 100644 --- a/src/main/java/zone/moddev/mc/basemetals/content/MaterialArmor.java +++ b/src/main/java/zone/moddev/mc/basemetals/content/MaterialArmor.java @@ -2,15 +2,15 @@ import zone.moddev.mc.basemetals.material.MaterialDefinition; -import net.minecraft.util.SoundEvents; -import net.minecraft.inventory.EquipmentSlotType; -import net.minecraft.item.IArmorMaterial; -import net.minecraft.item.crafting.Ingredient; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.item.ArmorMaterial; +import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.tags.ItemTags; -import net.minecraft.util.ResourceLocation; -import net.minecraft.util.SoundEvent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.sounds.SoundEvent; -public final class MaterialArmor implements IArmorMaterial { +public final class MaterialArmor implements ArmorMaterial { private static final int[] DURABILITY = {13, 15, 16, 11}; private final MaterialDefinition material; @@ -19,10 +19,10 @@ public MaterialArmor(MaterialDefinition material) { } public MaterialDefinition material() { return material; } - @Override public int getDurabilityForSlot(EquipmentSlotType slot) { + @Override public int getDurabilityForSlot(EquipmentSlot slot) { return DURABILITY[slot.getIndex()] * material.armorDurabilityFactor(); } - @Override public int getDefenseForSlot(EquipmentSlotType slot) { return material.armorProtection(slot); } + @Override public int getDefenseForSlot(EquipmentSlot slot) { return material.armorProtection(slot); } @Override public int getEnchantmentValue() { return material.enchantability(); } @Override public SoundEvent getEquipSound() { return SoundEvents.ARMOR_EQUIP_IRON; } @Override public Ingredient getRepairIngredient() { diff --git a/src/main/java/zone/moddev/mc/basemetals/content/MaterialBacked.java b/src/main/java/zone/moddev/mc/basemetals/content/MaterialBacked.java index c93373752..2ffe07621 100644 --- a/src/main/java/zone/moddev/mc/basemetals/content/MaterialBacked.java +++ b/src/main/java/zone/moddev/mc/basemetals/content/MaterialBacked.java @@ -2,9 +2,9 @@ import zone.moddev.mc.basemetals.material.MaterialDefinition; -import net.minecraft.util.ResourceLocation; +import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.ItemTags; -import net.minecraft.item.ItemStack; +import net.minecraft.world.item.ItemStack; public interface MaterialBacked { MaterialDefinition baseMetalsMaterial(); diff --git a/src/main/java/zone/moddev/mc/basemetals/content/MaterialContent.java b/src/main/java/zone/moddev/mc/basemetals/content/MaterialContent.java index 348fb120b..1c2a8e492 100644 --- a/src/main/java/zone/moddev/mc/basemetals/content/MaterialContent.java +++ b/src/main/java/zone/moddev/mc/basemetals/content/MaterialContent.java @@ -5,8 +5,8 @@ import java.util.Map; import zone.moddev.mc.basemetals.material.MaterialDefinition; -import net.minecraft.block.Block; -import net.minecraft.item.Item; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.item.Item; public final class MaterialContent { private final MaterialDefinition definition; diff --git a/src/main/java/zone/moddev/mc/basemetals/content/MaterialItems.java b/src/main/java/zone/moddev/mc/basemetals/content/MaterialItems.java index 2d2102c76..3036fb716 100644 --- a/src/main/java/zone/moddev/mc/basemetals/content/MaterialItems.java +++ b/src/main/java/zone/moddev/mc/basemetals/content/MaterialItems.java @@ -10,38 +10,38 @@ import zone.moddev.mc.basemetals.BaseMetals; import zone.moddev.mc.basemetals.material.MaterialDefinition; -import net.minecraft.item.HorseArmorItem; -import net.minecraft.entity.LivingEntity; -import net.minecraft.entity.ai.attributes.Attribute; -import net.minecraft.entity.ai.attributes.AttributeModifier; -import net.minecraft.entity.ai.attributes.Attributes; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.projectile.AbstractArrowEntity; -import net.minecraft.enchantment.EnchantmentHelper; -import net.minecraft.enchantment.Enchantments; -import net.minecraft.util.SoundEvents; -import net.minecraft.inventory.EquipmentSlotType; -import net.minecraft.item.Item; -import net.minecraft.item.ArmorItem; -import net.minecraft.item.ArrowItem; -import net.minecraft.item.AxeItem; -import net.minecraft.item.BlockItem; -import net.minecraft.item.BowItem; -import net.minecraft.item.FishingRodItem; -import net.minecraft.item.HoeItem; -import net.minecraft.item.PickaxeItem; -import net.minecraft.item.ShearsItem; -import net.minecraft.item.ShieldItem; -import net.minecraft.item.ShovelItem; -import net.minecraft.item.ItemStack; -import net.minecraft.item.SwordItem; -import net.minecraft.client.util.ITooltipFlag; +import net.minecraft.world.item.HorseArmorItem; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.ai.attributes.Attribute; +import net.minecraft.world.entity.ai.attributes.AttributeModifier; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.projectile.AbstractArrow; +import net.minecraft.world.item.enchantment.EnchantmentHelper; +import net.minecraft.world.item.enchantment.Enchantments; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ArmorItem; +import net.minecraft.world.item.ArrowItem; +import net.minecraft.world.item.AxeItem; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.BowItem; +import net.minecraft.world.item.FishingRodItem; +import net.minecraft.world.item.HoeItem; +import net.minecraft.world.item.PickaxeItem; +import net.minecraft.world.item.ShearsItem; +import net.minecraft.world.item.ShieldItem; +import net.minecraft.world.item.ShovelItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.SwordItem; +import net.minecraft.world.item.TooltipFlag; import net.minecraft.stats.Stats; -import net.minecraft.util.SoundCategory; -import net.minecraft.util.ResourceLocation; -import net.minecraft.util.text.ITextComponent; -import net.minecraft.util.text.TranslationTextComponent; -import net.minecraft.world.World; +import net.minecraft.sounds.SoundSource; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.world.level.Level; import net.minecraftforge.event.ForgeEventFactory; public final class MaterialItems { @@ -56,7 +56,7 @@ public Basic(MaterialDefinition material, int burnTime, Properties properties) { this.burnTime = burnTime; } @Override public MaterialDefinition baseMetalsMaterial() { return material; } - @Override public int getBurnTime(ItemStack stack) { return burnTime; } + @Override public int getBurnTime(ItemStack stack, net.minecraft.world.item.crafting.RecipeType recipeType) { return burnTime; } } public static final class Pickaxe extends PickaxeItem implements MaterialBacked { @@ -66,8 +66,8 @@ public Pickaxe(MaterialDefinition material, Properties properties) { this.material = material; } @Override public MaterialDefinition baseMetalsMaterial() { return material; } - @Override public void appendHoverText(ItemStack stack, @Nullable World world, - List tooltip, ITooltipFlag flag) { addToolTooltip(material, tooltip); } + @Override public void appendHoverText(ItemStack stack, @Nullable Level world, + List tooltip, TooltipFlag flag) { addToolTooltip(material, tooltip); } } public static final class Axe extends AxeItem implements MaterialBacked { @@ -78,8 +78,8 @@ public Axe(MaterialDefinition material, Properties properties) { this.material = material; } @Override public MaterialDefinition baseMetalsMaterial() { return material; } - @Override public void appendHoverText(ItemStack stack, @Nullable World world, - List tooltip, ITooltipFlag flag) { addToolTooltip(material, tooltip); } + @Override public void appendHoverText(ItemStack stack, @Nullable Level world, + List tooltip, TooltipFlag flag) { addToolTooltip(material, tooltip); } } public static final class Shovel extends ShovelItem implements MaterialBacked { @@ -89,8 +89,8 @@ public Shovel(MaterialDefinition material, Properties properties) { this.material = material; } @Override public MaterialDefinition baseMetalsMaterial() { return material; } - @Override public void appendHoverText(ItemStack stack, @Nullable World world, - List tooltip, ITooltipFlag flag) { addToolTooltip(material, tooltip); } + @Override public void appendHoverText(ItemStack stack, @Nullable Level world, + List tooltip, TooltipFlag flag) { addToolTooltip(material, tooltip); } } public static final class Hoe extends HoeItem implements MaterialBacked { @@ -102,8 +102,8 @@ public Hoe(MaterialDefinition material, Properties properties) { } @Override public MaterialDefinition baseMetalsMaterial() { return material; } @Override public float getAttackDamage() { return 0.0F; } - @Override public Multimap getDefaultAttributeModifiers(EquipmentSlotType slot) { - if (slot != EquipmentSlotType.MAINHAND) return super.getDefaultAttributeModifiers(slot); + @Override public Multimap getDefaultAttributeModifiers(EquipmentSlot slot) { + if (slot != EquipmentSlot.MAINHAND) return super.getDefaultAttributeModifiers(slot); // Hoes had no attack-damage bonus before 1.16, even for hard materials. return ImmutableMultimap.of( @@ -116,8 +116,8 @@ public Hoe(MaterialDefinition material, Properties properties) { "Weapon modifier", material.baseAttackDamage() - 3.0F, AttributeModifier.Operation.ADDITION)); } - @Override public void appendHoverText(ItemStack stack, @Nullable World world, - List tooltip, ITooltipFlag flag) { addToolTooltip(material, tooltip); } + @Override public void appendHoverText(ItemStack stack, @Nullable Level world, + List tooltip, TooltipFlag flag) { addToolTooltip(material, tooltip); } } public static class Sword extends SwordItem implements MaterialBacked { @@ -127,19 +127,19 @@ public Sword(MaterialDefinition material, Properties properties) { this.material = material; } @Override public MaterialDefinition baseMetalsMaterial() { return material; } - @Override public void appendHoverText(ItemStack stack, @Nullable World world, - List tooltip, ITooltipFlag flag) { addToolTooltip(material, tooltip); } + @Override public void appendHoverText(ItemStack stack, @Nullable Level world, + List tooltip, TooltipFlag flag) { addToolTooltip(material, tooltip); } } public static final class Armor extends ArmorItem implements MaterialBacked { private final MaterialDefinition material; - public Armor(MaterialDefinition material, EquipmentSlotType slot, Properties properties) { + public Armor(MaterialDefinition material, EquipmentSlot slot, Properties properties) { super(new MaterialArmor(material), slot, properties); this.material = material; } @Override public MaterialDefinition baseMetalsMaterial() { return material; } - @Override public void appendHoverText(ItemStack stack, @Nullable World world, - List tooltip, ITooltipFlag flag) { addArmorTooltip(material, tooltip); } + @Override public void appendHoverText(ItemStack stack, @Nullable Level world, + List tooltip, TooltipFlag flag) { addArmorTooltip(material, tooltip); } } public static final class HorseArmor extends HorseArmorItem implements MaterialBacked { @@ -155,11 +155,11 @@ public HorseArmor(MaterialDefinition material, Properties properties) { public static final class BurnableBlock extends BlockItem { private final int burnTime; - public BurnableBlock(net.minecraft.block.Block block, int burnTime, Properties properties) { + public BurnableBlock(net.minecraft.world.level.block.Block block, int burnTime, Properties properties) { super(block, properties); this.burnTime = burnTime; } - @Override public int getBurnTime(ItemStack stack) { return burnTime; } + @Override public int getBurnTime(ItemStack stack, net.minecraft.world.item.crafting.RecipeType recipeType) { return burnTime; } } public static final class Shears extends ShearsItem implements MaterialBacked { @@ -172,8 +172,8 @@ public Shears(MaterialDefinition material, Properties properties) { @Override public boolean isValidRepairItem(ItemStack toRepair, ItemStack repair) { return new MaterialTier(material).getRepairIngredient().test(repair) || super.isValidRepairItem(toRepair, repair); } - @Override public void appendHoverText(ItemStack stack, @Nullable World world, - List tooltip, ITooltipFlag flag) { addToolTooltip(material, tooltip); } + @Override public void appendHoverText(ItemStack stack, @Nullable Level world, + List tooltip, TooltipFlag flag) { addToolTooltip(material, tooltip); } } public static class Shield extends ShieldItem implements MaterialBacked { @@ -186,8 +186,8 @@ public Shield(MaterialDefinition material, Properties properties) { @Override public boolean isValidRepairItem(ItemStack toRepair, ItemStack repair) { return new MaterialTier(material).getRepairIngredient().test(repair) || super.isValidRepairItem(toRepair, repair); } - @Override public void appendHoverText(ItemStack stack, @Nullable World world, - List tooltip, ITooltipFlag flag) { addToolTooltip(material, tooltip); } + @Override public void appendHoverText(ItemStack stack, @Nullable Level world, + List tooltip, TooltipFlag flag) { addToolTooltip(material, tooltip); } } public static class Bow extends BowItem implements MaterialBacked { @@ -201,7 +201,7 @@ public Bow(MaterialDefinition material, Properties properties) { @Override public MaterialDefinition baseMetalsMaterial() { return material; } @Override - public AbstractArrowEntity customArrow(AbstractArrowEntity arrow) { + public AbstractArrow customArrow(AbstractArrow arrow) { // Forge calls this before applying Power, so enchantment bonuses stay unchanged. arrow.setBaseDamage(arrow.getBaseDamage() + material.baseAttackDamage() - 1.0D); @@ -220,8 +220,8 @@ protected boolean isArrow(ItemStack stack) { @Override public boolean isValidRepairItem(ItemStack toRepair, ItemStack repair) { return new MaterialTier(material).getRepairIngredient().test(repair) || super.isValidRepairItem(toRepair, repair); } - @Override public void appendHoverText(ItemStack stack, @Nullable World world, - List tooltip, ITooltipFlag flag) { addToolTooltip(material, tooltip); } + @Override public void appendHoverText(ItemStack stack, @Nullable Level world, + List tooltip, TooltipFlag flag) { addToolTooltip(material, tooltip); } } public static final class Crossbow extends Bow { @@ -234,10 +234,10 @@ public Crossbow(MaterialDefinition material, Properties properties) { && ((BaseMetalAmmoItem) stack.getItem()).kind() == BaseMetalAmmoItem.Kind.BOLT; } @Override - public void releaseUsing(ItemStack bow, World world, LivingEntity user, int timeLeft) { - if (!(user instanceof PlayerEntity)) return; - PlayerEntity player = (PlayerEntity) user; - boolean hasInfiniteAmmo = player.abilities.instabuild + public void releaseUsing(ItemStack bow, Level world, LivingEntity user, int timeLeft) { + if (!(user instanceof Player)) return; + Player player = (Player) user; + boolean hasInfiniteAmmo = player.getAbilities().instabuild || EnchantmentHelper.getItemEnchantmentLevel(Enchantments.INFINITY_ARROWS, bow) > 0; ItemStack ammunition = player.getProjectile(bow); @@ -254,11 +254,11 @@ public void releaseUsing(ItemStack bow, World world, LivingEntity user, int time if (power < 0.1F) return; BaseMetalAmmoItem bolt = (BaseMetalAmmoItem) ammunition.getItem(); - boolean infiniteShot = player.abilities.instabuild + boolean infiniteShot = player.getAbilities().instabuild || bolt.isInfinite(ammunition, bow, player); if (!world.isClientSide) { - AbstractArrowEntity projectile = customArrow(bolt.createArrow(world, ammunition, player)); - projectile.shootFromRotation(player, player.xRot, player.yRot, 0.0F, + AbstractArrow projectile = customArrow(bolt.createArrow(world, ammunition, player)); + projectile.shootFromRotation(player, player.getXRot(), player.getYRot(), 0.0F, power * 3.0F, 1.0F); if (power == 1.0F) projectile.setCritArrow(true); int powerLevel = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.POWER_ARROWS, bow); @@ -271,15 +271,15 @@ public void releaseUsing(ItemStack bow, World world, LivingEntity user, int time projectile.setSecondsOnFire(100); } bow.hurtAndBreak(1, player, entity -> entity.broadcastBreakEvent(player.getUsedItemHand())); - if (infiniteShot) projectile.pickup = AbstractArrowEntity.PickupStatus.CREATIVE_ONLY; + if (infiniteShot) projectile.pickup = AbstractArrow.Pickup.CREATIVE_ONLY; world.addFreshEntity(projectile); } world.playSound(null, player.getX(), player.getY(), player.getZ(), - SoundEvents.ARROW_SHOOT, SoundCategory.PLAYERS, 1.0F, - 1.0F / (random.nextFloat() * 0.4F + 1.2F) + power * 0.5F); - if (!infiniteShot && !player.abilities.instabuild) { + SoundEvents.ARROW_SHOOT, SoundSource.PLAYERS, 1.0F, + 1.0F / (world.random.nextFloat() * 0.4F + 1.2F) + power * 0.5F); + if (!infiniteShot && !player.getAbilities().instabuild) { ammunition.shrink(1); - if (ammunition.isEmpty()) player.inventory.removeItem(ammunition); + if (ammunition.isEmpty()) player.getInventory().removeItem(ammunition); } player.awardStat(Stats.ITEM_USED.get(this)); } @@ -295,29 +295,29 @@ public FishingRod(MaterialDefinition material, Properties properties) { @Override public boolean isValidRepairItem(ItemStack toRepair, ItemStack repair) { return new MaterialTier(material).getRepairIngredient().test(repair) || super.isValidRepairItem(toRepair, repair); } - @Override public void appendHoverText(ItemStack stack, @Nullable World world, - List tooltip, ITooltipFlag flag) { addToolTooltip(material, tooltip); } + @Override public void appendHoverText(ItemStack stack, @Nullable Level world, + List tooltip, TooltipFlag flag) { addToolTooltip(material, tooltip); } } - static void addToolTooltip(MaterialDefinition material, List tooltip) { + static void addToolTooltip(MaterialDefinition material, List tooltip) { if ("adamantine".equals(material.name())) { - tooltip.add(new TranslationTextComponent("tooltip.adamantine.tool", 4)); + tooltip.add(new TranslatableComponent("tooltip.adamantine.tool", 4)); } else if ("aquarium".equals(material.name())) { - tooltip.add(new TranslationTextComponent("tooltip.aquarium.tool", 4)); + tooltip.add(new TranslatableComponent("tooltip.aquarium.tool", 4)); } else if ("coldiron".equals(material.name())) { - tooltip.add(new TranslationTextComponent("tooltip.coldiron.tool", 3)); + tooltip.add(new TranslatableComponent("tooltip.coldiron.tool", 3)); } else if ("mithril".equals(material.name())) { - tooltip.add(new TranslationTextComponent("tooltip.mithril.tool")); + tooltip.add(new TranslatableComponent("tooltip.mithril.tool")); } else if ("starsteel".equals(material.name())) { - tooltip.add(new TranslationTextComponent("tooltip.starsteel.tool", 10)); + tooltip.add(new TranslatableComponent("tooltip.starsteel.tool", 10)); } } - private static void addArmorTooltip(MaterialDefinition material, List tooltip) { + private static void addArmorTooltip(MaterialDefinition material, List tooltip) { if ("adamantine".equals(material.name()) || "aquarium".equals(material.name()) || "coldiron".equals(material.name()) || "mithril".equals(material.name()) || "starsteel".equals(material.name())) { - tooltip.add(new TranslationTextComponent("tooltip." + material.name() + ".armor")); + tooltip.add(new TranslatableComponent("tooltip." + material.name() + ".armor")); } } } diff --git a/src/main/java/zone/moddev/mc/basemetals/content/MaterialTier.java b/src/main/java/zone/moddev/mc/basemetals/content/MaterialTier.java index 706553acd..7257d903a 100644 --- a/src/main/java/zone/moddev/mc/basemetals/content/MaterialTier.java +++ b/src/main/java/zone/moddev/mc/basemetals/content/MaterialTier.java @@ -2,12 +2,12 @@ import zone.moddev.mc.basemetals.material.MaterialDefinition; -import net.minecraft.item.IItemTier; -import net.minecraft.item.crafting.Ingredient; +import net.minecraft.world.item.Tier; +import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.tags.ItemTags; -import net.minecraft.util.ResourceLocation; +import net.minecraft.resources.ResourceLocation; -public final class MaterialTier implements IItemTier { +public final class MaterialTier implements Tier { private final MaterialDefinition material; public MaterialTier(MaterialDefinition material) { diff --git a/src/main/java/zone/moddev/mc/basemetals/content/ModContent.java b/src/main/java/zone/moddev/mc/basemetals/content/ModContent.java index 1e4d5da42..fccff8b0a 100644 --- a/src/main/java/zone/moddev/mc/basemetals/content/ModContent.java +++ b/src/main/java/zone/moddev/mc/basemetals/content/ModContent.java @@ -14,31 +14,30 @@ import zone.moddev.mc.basemetals.material.MaterialCatalogue; import zone.moddev.mc.basemetals.material.MaterialDefinition; -import net.minecraft.block.Block; -import net.minecraft.block.StoneButtonBlock; -import net.minecraft.block.DoorBlock; -import net.minecraft.block.LeverBlock; -import net.minecraft.block.PaneBlock; -import net.minecraft.block.PressurePlateBlock; -import net.minecraft.block.SlabBlock; -import net.minecraft.block.StairsBlock; -import net.minecraft.block.TrapDoorBlock; -import net.minecraft.block.WallBlock; -import net.minecraft.block.FlowingFluidBlock; -import net.minecraft.block.SoundType; -import net.minecraft.block.material.Material; -import net.minecraft.fluid.FlowingFluid; -import net.minecraft.fluid.Fluid; -import net.minecraft.fluid.FluidState; -import net.minecraft.block.Blocks; -import net.minecraft.item.Items; -import net.minecraft.inventory.EquipmentSlotType; -import net.minecraft.item.Item; -import net.minecraft.item.BlockItem; -import net.minecraft.item.ItemGroup; -import net.minecraft.util.ResourceLocation; -import net.minecraft.util.registry.Registry; -import net.minecraftforge.common.ToolType; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.StoneButtonBlock; +import net.minecraft.world.level.block.DoorBlock; +import net.minecraft.world.level.block.LeverBlock; +import net.minecraft.world.level.block.IronBarsBlock; +import net.minecraft.world.level.block.PressurePlateBlock; +import net.minecraft.world.level.block.SlabBlock; +import net.minecraft.world.level.block.StairBlock; +import net.minecraft.world.level.block.TrapDoorBlock; +import net.minecraft.world.level.block.WallBlock; +import net.minecraft.world.level.block.LiquidBlock; +import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.material.Material; +import net.minecraft.world.level.material.FlowingFluid; +import net.minecraft.world.level.material.Fluid; +import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.item.Items; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.CreativeModeTab; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.core.Registry; import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; @@ -206,6 +205,9 @@ private static void registerMaterial(MaterialDefinition material) { @Override public Block get() { return new HarvestOre(oreProperties(material), material.requiredHarvestLevel()); } }, true)); items.put("ore", ITEMS_BY_ID.get(id)); + if (!material.name().equals("copper")) { + items.put("raw", registerSimpleMaterialItem(material.name() + "_raw", material)); + } } for (String form : BASIC_ITEM_FORMS) { items.put(form, registerSimpleMaterialItem(material.name() + "_" + form, material)); @@ -230,11 +232,12 @@ private static RegistryHandle registerMaterialBlock(String id, String for if ("plate".equals(form)) { factory = new Supplier() { @Override public Block get() { return new PlateBlock(properties.get(), material.requiredHarvestLevel()); } }; } else if ("bars".equals(form)) { - factory = new Supplier() { @Override public Block get() { return new HarvestPane(properties.get().dynamicShape(), material.requiredHarvestLevel()); } }; + // Texture holes must leave the block behind them visible. + factory = new Supplier() { @Override public Block get() { return new HarvestPane(properties.get().noOcclusion().dynamicShape(), material.requiredHarvestLevel()); } }; } else if ("door".equals(form)) { - factory = new Supplier() { @Override public Block get() { return new HarvestDoor(properties.get().dynamicShape(), material.requiredHarvestLevel()); } }; + factory = new Supplier() { @Override public Block get() { return new HarvestDoor(properties.get().noOcclusion().dynamicShape(), material.requiredHarvestLevel()); } }; } else if ("trapdoor".equals(form)) { - factory = new Supplier() { @Override public Block get() { return new HarvestTrapDoor(properties.get().dynamicShape(), material.requiredHarvestLevel()); } }; + factory = new Supplier() { @Override public Block get() { return new HarvestTrapDoor(properties.get().noOcclusion().dynamicShape(), material.requiredHarvestLevel()); } }; } else if ("button".equals(form)) { factory = new Supplier() { @Override public Block get() { return new HarvestButton(properties.get().noCollission(), material.requiredHarvestLevel()); } }; } else if ("slab".equals(form)) { @@ -275,10 +278,10 @@ private static void registerEquipment(final MaterialDefinition material, items.put("rod", registerSimpleMaterialItem(material.name() + "_rod", material)); items.put("gear", registerSimpleMaterialItem(material.name() + "_gear", material)); items.put("horse_armor", registerItem(material.name() + "_horse_armor", new Supplier() { @Override public Item get() { return new MaterialItems.HorseArmor(material, combatProperties()); } })); - items.put("helmet", registerArmor(material, EquipmentSlotType.HEAD)); - items.put("chestplate", registerArmor(material, EquipmentSlotType.CHEST)); - items.put("leggings", registerArmor(material, EquipmentSlotType.LEGS)); - items.put("boots", registerArmor(material, EquipmentSlotType.FEET)); + items.put("helmet", registerArmor(material, EquipmentSlot.HEAD)); + items.put("chestplate", registerArmor(material, EquipmentSlot.CHEST)); + items.put("leggings", registerArmor(material, EquipmentSlot.LEGS)); + items.put("boots", registerArmor(material, EquipmentSlot.FEET)); } private static RegistryHandle registerAmmo(final MaterialDefinition material, final BaseMetalAmmoItem.Kind kind) { @@ -293,7 +296,7 @@ private static RegistryHandle registerAmmo(final MaterialDefinition materi } private static RegistryHandle registerArmor(final MaterialDefinition material, - final EquipmentSlotType slot) { + final EquipmentSlot slot) { String suffix; switch (slot) { case HEAD: suffix = "helmet"; break; @@ -406,15 +409,21 @@ private static void registerVanillaCombatAndUtility(final MaterialDefinition mat registerItem(name + "_pickaxe", new Supplier() { @Override public Item get() { return new MaterialItems.Pickaxe(material, toolProperties()); } }); registerItem(name + "_shovel", new Supplier() { @Override public Item get() { return new MaterialItems.Shovel(material, toolProperties()); } }); registerItem(name + "_hoe", new Supplier() { @Override public Item get() { return new MaterialItems.Hoe(material, toolProperties()); } }); - registerArmor(material, EquipmentSlotType.HEAD); - registerArmor(material, EquipmentSlotType.CHEST); - registerArmor(material, EquipmentSlotType.LEGS); - registerArmor(material, EquipmentSlotType.FEET); + registerArmor(material, EquipmentSlot.HEAD); + registerArmor(material, EquipmentSlot.CHEST); + registerArmor(material, EquipmentSlot.LEGS); + registerArmor(material, EquipmentSlot.FEET); registerItem(name + "_horse_armor", new Supplier() { @Override public Item get() { return new MaterialItems.HorseArmor(material, combatProperties()); } }); registerItem(name + "_sword", new Supplier() { @Override public Item get() { return new MaterialItems.Sword(material, combatProperties()); } }); } } + public static int requiredHarvestLevel(String name) { + MaterialDefinition material = MaterialCatalogue.BY_NAME.get(name); + if (material == null) material = vanillaDefinitions().get(name); + return material == null ? 0 : material.requiredHarvestLevel(); + } + private static Map vanillaDefinitions() { Map map = new LinkedHashMap(); addVanilla(map, "wood", 2, 2, 6, 0x695433); @@ -441,7 +450,7 @@ private static void addVanilla(Map map, String name, private static void registerFluid(final String name, int colour, final boolean mercury) { final RegistryHandle source = new RegistryHandle(name); final RegistryHandle flowing = new RegistryHandle("flowing_" + name); - final RegistryHandle block = new RegistryHandle(name); + final RegistryHandle block = new RegistryHandle(name); final RegistryHandle bucket = new RegistryHandle(name + "_bucket"); FLUID_CONTENT.put(name, new FluidContent(source, flowing, block, bucket)); FLUID_COLOURS.put(name, Integer.valueOf(colour)); @@ -509,11 +518,11 @@ private static RegistryHandle registerItem(String id, Supplier list(String... values) { @@ -523,66 +532,46 @@ private static List list(String... values) { private static class HarvestBlock extends Block { private final int level; HarvestBlock(Properties properties, int level) { super(properties); this.level = level; } - @Override public ToolType getHarvestTool(net.minecraft.block.BlockState state) { return ToolType.PICKAXE; } - @Override public int getHarvestLevel(net.minecraft.block.BlockState state) { return level; } } private static class HarvestOre extends HarvestBlock { HarvestOre(Properties properties, int level) { super(properties, level); } } - private static class HarvestPane extends PaneBlock { + private static class HarvestPane extends IronBarsBlock { private final int level; HarvestPane(Properties properties, int level) { super(properties); this.level = level; } - @Override public ToolType getHarvestTool(net.minecraft.block.BlockState state) { return ToolType.PICKAXE; } - @Override public int getHarvestLevel(net.minecraft.block.BlockState state) { return level; } } private static class HarvestDoor extends DoorBlock { private final int level; HarvestDoor(Properties properties, int level) { super(properties); this.level = level; } - @Override public ToolType getHarvestTool(net.minecraft.block.BlockState state) { return ToolType.PICKAXE; } - @Override public int getHarvestLevel(net.minecraft.block.BlockState state) { return level; } } private static class HarvestTrapDoor extends TrapDoorBlock { private final int level; HarvestTrapDoor(Properties properties, int level) { super(properties); this.level = level; } - @Override public ToolType getHarvestTool(net.minecraft.block.BlockState state) { return ToolType.PICKAXE; } - @Override public int getHarvestLevel(net.minecraft.block.BlockState state) { return level; } } private static class HarvestButton extends StoneButtonBlock { private final int level; HarvestButton(Properties properties, int level) { super(properties); this.level = level; } - @Override public ToolType getHarvestTool(net.minecraft.block.BlockState state) { return ToolType.PICKAXE; } - @Override public int getHarvestLevel(net.minecraft.block.BlockState state) { return level; } } private static class HarvestSlab extends SlabBlock { private final int level; HarvestSlab(Properties properties, int level) { super(properties); this.level = level; } - @Override public ToolType getHarvestTool(net.minecraft.block.BlockState state) { return ToolType.PICKAXE; } - @Override public int getHarvestLevel(net.minecraft.block.BlockState state) { return level; } } private static class HarvestLever extends LeverBlock { private final int level; HarvestLever(Properties properties, int level) { super(properties); this.level = level; } - @Override public ToolType getHarvestTool(net.minecraft.block.BlockState state) { return ToolType.PICKAXE; } - @Override public int getHarvestLevel(net.minecraft.block.BlockState state) { return level; } } private static class HarvestPressurePlate extends PressurePlateBlock { private final int level; HarvestPressurePlate(Properties properties, int level) { super(Sensitivity.MOBS, properties); this.level = level; } - @Override public ToolType getHarvestTool(net.minecraft.block.BlockState state) { return ToolType.PICKAXE; } - @Override public int getHarvestLevel(net.minecraft.block.BlockState state) { return level; } } - private static class HarvestStairs extends StairsBlock { + private static class HarvestStairs extends StairBlock { private final int level; - HarvestStairs(net.minecraft.block.BlockState base, Properties properties, int level) { super(base, properties); this.level = level; } - @Override public ToolType getHarvestTool(net.minecraft.block.BlockState state) { return ToolType.PICKAXE; } - @Override public int getHarvestLevel(net.minecraft.block.BlockState state) { return level; } + HarvestStairs(net.minecraft.world.level.block.state.BlockState base, Properties properties, int level) { super(base, properties); this.level = level; } } private static class HarvestWall extends WallBlock { private final int level; HarvestWall(Properties properties, int level) { super(properties); this.level = level; } - @Override public ToolType getHarvestTool(net.minecraft.block.BlockState state) { return ToolType.PICKAXE; } - @Override public int getHarvestLevel(net.minecraft.block.BlockState state) { return level; } } } diff --git a/src/main/java/zone/moddev/mc/basemetals/content/MoltenFluid.java b/src/main/java/zone/moddev/mc/basemetals/content/MoltenFluid.java index 3d6a33c92..2b459b7b6 100644 --- a/src/main/java/zone/moddev/mc/basemetals/content/MoltenFluid.java +++ b/src/main/java/zone/moddev/mc/basemetals/content/MoltenFluid.java @@ -1,18 +1,18 @@ package zone.moddev.mc.basemetals.content; -import net.minecraft.block.FlowingFluidBlock; -import net.minecraft.block.BlockState; -import net.minecraft.fluid.FlowingFluid; -import net.minecraft.fluid.Fluid; -import net.minecraft.fluid.FluidState; -import net.minecraft.item.Item; -import net.minecraft.state.StateContainer; -import net.minecraft.util.Direction; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.IWorld; -import net.minecraft.world.IWorldReader; +import net.minecraft.world.level.block.LiquidBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.FlowingFluid; +import net.minecraft.world.level.material.Fluid; +import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.core.Direction; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.LevelReader; import net.minecraftforge.fluids.FluidAttributes; -import net.minecraft.util.ResourceLocation; +import net.minecraft.resources.ResourceLocation; /** Common flow behaviour for the molten metals. */ public abstract class MoltenFluid extends FlowingFluid { @@ -35,28 +35,28 @@ protected FluidAttributes createAttributes() { @Override public Item getBucket() { return content().bucket().get(); } @Override protected boolean canConvertToSource() { return false; } - @Override protected void beforeDestroyingBlock(IWorld world, BlockPos pos, BlockState state) { - net.minecraft.block.Block.dropResources(state, world, pos, world.getBlockEntity(pos)); + @Override protected void beforeDestroyingBlock(LevelAccessor world, BlockPos pos, BlockState state) { + net.minecraft.world.level.block.Block.dropResources(state, world, pos, world.getBlockEntity(pos)); } - @Override public int getSlopeFindDistance(IWorldReader world) { return 2; } - @Override public int getDropOff(IWorldReader world) { return 2; } - @Override public int getTickDelay(IWorldReader world) { return 30; } + @Override public int getSlopeFindDistance(LevelReader world) { return 2; } + @Override public int getDropOff(LevelReader world) { return 2; } + @Override public int getTickDelay(LevelReader world) { return 30; } @Override protected float getExplosionResistance() { return 100.0F; } @Override public boolean isSame(Fluid fluid) { return fluid == content().source().get() || fluid == content().flowing().get(); } - @Override protected boolean canBeReplacedWith(FluidState state, net.minecraft.world.IBlockReader world, + @Override protected boolean canBeReplacedWith(FluidState state, net.minecraft.world.level.BlockGetter world, BlockPos pos, Fluid fluid, Direction direction) { return direction == Direction.DOWN && !fluid.isSame(this); } @Override public BlockState createLegacyBlock(FluidState state) { return content().block().get().defaultBlockState() - .setValue(FlowingFluidBlock.LEVEL, Integer.valueOf(getLegacyLevel(state))); + .setValue(LiquidBlock.LEVEL, Integer.valueOf(getLegacyLevel(state))); } public static final class Flowing extends MoltenFluid { public Flowing(String name) { super(name); } - @Override protected void createFluidStateDefinition(StateContainer.Builder builder) { + @Override protected void createFluidStateDefinition(StateDefinition.Builder builder) { super.createFluidStateDefinition(builder); builder.add(LEVEL); } diff --git a/src/main/java/zone/moddev/mc/basemetals/content/MoltenMetalBlock.java b/src/main/java/zone/moddev/mc/basemetals/content/MoltenMetalBlock.java index 63d31a4ac..19e189d25 100644 --- a/src/main/java/zone/moddev/mc/basemetals/content/MoltenMetalBlock.java +++ b/src/main/java/zone/moddev/mc/basemetals/content/MoltenMetalBlock.java @@ -2,17 +2,17 @@ import zone.moddev.mc.basemetals.config.BaseMetalsConfig; -import net.minecraft.block.FlowingFluidBlock; -import net.minecraft.block.BlockState; -import net.minecraft.entity.Entity; -import net.minecraft.entity.LivingEntity; -import net.minecraft.fluid.FlowingFluid; -import net.minecraft.potion.Effects; -import net.minecraft.potion.EffectInstance; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; +import net.minecraft.world.level.block.LiquidBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.level.material.FlowingFluid; +import net.minecraft.world.effect.MobEffects; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.Level; -public final class MoltenMetalBlock extends FlowingFluidBlock { +public final class MoltenMetalBlock extends LiquidBlock { private final boolean mercury; public MoltenMetalBlock(FlowingFluid fluid, Properties properties, boolean mercury) { @@ -21,11 +21,11 @@ public MoltenMetalBlock(FlowingFluid fluid, Properties properties, boolean mercu } @Override - public void entityInside(BlockState state, World world, BlockPos pos, Entity entity) { + public void entityInside(BlockState state, Level world, BlockPos pos, Entity entity) { super.entityInside(state, world, pos, entity); if (mercury && !world.isClientSide && BaseMetalsConfig.MERCURY_EFFECTS.get() && entity instanceof LivingEntity && world.random.nextInt(32) == 0) { - ((LivingEntity) entity).addEffect(new EffectInstance(Effects.CONFUSION, 30 * 20, 2)); + ((LivingEntity) entity).addEffect(new MobEffectInstance(MobEffects.CONFUSION, 30 * 20, 2)); } } } diff --git a/src/main/java/zone/moddev/mc/basemetals/content/PlateBlock.java b/src/main/java/zone/moddev/mc/basemetals/content/PlateBlock.java index e9d0b750d..0061855a1 100644 --- a/src/main/java/zone/moddev/mc/basemetals/content/PlateBlock.java +++ b/src/main/java/zone/moddev/mc/basemetals/content/PlateBlock.java @@ -1,18 +1,17 @@ package zone.moddev.mc.basemetals.content; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.item.BlockItemUseContext; -import net.minecraft.state.DirectionProperty; -import net.minecraft.state.StateContainer; -import net.minecraft.state.properties.BlockStateProperties; -import net.minecraft.util.Direction; -import net.minecraft.util.Mirror; -import net.minecraft.util.Rotation; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.shapes.VoxelShape; -import net.minecraft.world.IBlockReader; -import net.minecraftforge.common.ToolType; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.block.state.properties.DirectionProperty; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.Mirror; +import net.minecraft.world.level.block.Rotation; +import net.minecraft.core.BlockPos; +import net.minecraft.world.phys.shapes.VoxelShape; +import net.minecraft.world.level.BlockGetter; /** A one-pixel-thick plate attached flush to the selected block face. */ public final class PlateBlock extends Block { @@ -30,12 +29,12 @@ public PlateBlock(Properties properties, int harvestLevel) { } @Override - public BlockState getStateForPlacement(BlockItemUseContext context) { + public BlockState getStateForPlacement(BlockPlaceContext context) { return defaultBlockState().setValue(FACING, context.getClickedFace()); } - @Override public VoxelShape getShape(BlockState state, IBlockReader world, BlockPos pos, - net.minecraft.util.math.shapes.ISelectionContext context) { + @Override public VoxelShape getShape(BlockState state, BlockGetter world, BlockPos pos, + net.minecraft.world.phys.shapes.CollisionContext context) { return SHAPES[state.getValue(FACING).get3DDataValue()]; } @Override public BlockState rotate(BlockState state, Rotation rotation) { @@ -44,9 +43,7 @@ public BlockState getStateForPlacement(BlockItemUseContext context) { @Override public BlockState mirror(BlockState state, Mirror mirror) { return rotate(state, mirror.getRotation(state.getValue(FACING))); } - @Override protected void createBlockStateDefinition(StateContainer.Builder builder) { + @Override protected void createBlockStateDefinition(StateDefinition.Builder builder) { builder.add(FACING); } - @Override public ToolType getHarvestTool(BlockState state) { return ToolType.PICKAXE; } - @Override public int getHarvestLevel(BlockState state) { return harvestLevel; } } diff --git a/src/main/java/zone/moddev/mc/basemetals/content/ScytheItem.java b/src/main/java/zone/moddev/mc/basemetals/content/ScytheItem.java index c5279c001..6134fe4bc 100644 --- a/src/main/java/zone/moddev/mc/basemetals/content/ScytheItem.java +++ b/src/main/java/zone/moddev/mc/basemetals/content/ScytheItem.java @@ -8,26 +8,26 @@ import zone.moddev.mc.basemetals.ModTags; import zone.moddev.mc.basemetals.material.MaterialDefinition; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.player.ServerPlayerEntity; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.item.ToolItem; -import net.minecraft.client.util.ITooltipFlag; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.text.ITextComponent; -import net.minecraft.world.World; - -public final class ScytheItem extends ToolItem implements MaterialBacked { +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.entity.player.Player; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.DiggerItem; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.world.level.Level; + +public final class ScytheItem extends DiggerItem implements MaterialBacked { private static final ThreadLocal HARVESTING = new ThreadLocal() { @Override protected Boolean initialValue() { return Boolean.FALSE; } }; private final MaterialDefinition material; public ScytheItem(MaterialDefinition material, Item.Properties properties) { - super(0.0F, 0.0F, new MaterialTier(material), Collections.emptySet(), properties); + super(0.0F, 0.0F, new MaterialTier(material), ModTags.SCYTHE_HARVESTABLE, properties); this.material = material; } @@ -37,12 +37,12 @@ public ScytheItem(MaterialDefinition material, Item.Properties properties) { } @Override - public boolean onBlockStartBreak(ItemStack stack, BlockPos position, PlayerEntity player) { - if (player.level.isClientSide || !(player instanceof ServerPlayerEntity) || HARVESTING.get()) return false; + public boolean onBlockStartBreak(ItemStack stack, BlockPos position, Player player) { + if (player.level.isClientSide || !(player instanceof ServerPlayer) || HARVESTING.get()) return false; if (!player.level.getBlockState(position).is(ModTags.SCYTHE_HARVESTABLE)) return false; HARVESTING.set(Boolean.TRUE); try { - ServerPlayerEntity serverPlayer = (ServerPlayerEntity) player; + ServerPlayer serverPlayer = (ServerPlayer) player; for (int dx = -1; dx <= 1; dx++) { for (int dz = -1; dz <= 1; dz++) { BlockPos target = position.offset(dx, 0, dz); @@ -57,6 +57,6 @@ public boolean onBlockStartBreak(ItemStack stack, BlockPos position, PlayerEntit return true; } - @Override public void appendHoverText(ItemStack stack, @Nullable World world, - List tooltip, ITooltipFlag flag) { MaterialItems.addToolTooltip(material, tooltip); } + @Override public void appendHoverText(ItemStack stack, @Nullable Level world, + List tooltip, TooltipFlag flag) { MaterialItems.addToolTooltip(material, tooltip); } } diff --git a/src/main/java/zone/moddev/mc/basemetals/entity/MaterialProjectile.java b/src/main/java/zone/moddev/mc/basemetals/entity/MaterialProjectile.java index 341c4afd4..9572a1e7d 100644 --- a/src/main/java/zone/moddev/mc/basemetals/entity/MaterialProjectile.java +++ b/src/main/java/zone/moddev/mc/basemetals/entity/MaterialProjectile.java @@ -2,23 +2,23 @@ import zone.moddev.mc.basemetals.content.ModContent; -import net.minecraft.entity.LivingEntity; -import net.minecraft.entity.EntityType; -import net.minecraft.entity.projectile.AbstractArrowEntity; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.CompoundNBT; -import net.minecraft.network.PacketBuffer; -import net.minecraft.world.World; -import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; - -public final class MaterialProjectile extends AbstractArrowEntity implements IEntityAdditionalSpawnData { +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.projectile.AbstractArrow; +import net.minecraft.world.item.ItemStack; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.level.Level; +import net.minecraftforge.fmllegacy.common.registry.IEntityAdditionalSpawnData; + +public final class MaterialProjectile extends AbstractArrow implements IEntityAdditionalSpawnData { private ItemStack ammunition = ItemStack.EMPTY; - public MaterialProjectile(EntityType type, World world) { + public MaterialProjectile(EntityType type, Level world) { super(type, world); } - public MaterialProjectile(EntityType type, World world, LivingEntity shooter, ItemStack ammunition) { + public MaterialProjectile(EntityType type, Level world, LivingEntity shooter, ItemStack ammunition) { super(type, shooter, world); this.ammunition = single(ammunition); } @@ -39,23 +39,23 @@ public ItemStack getAmmunition() { } @Override - public net.minecraft.network.IPacket getAddEntityPacket() { - return net.minecraftforge.fml.network.NetworkHooks.getEntitySpawningPacket(this); + public net.minecraft.network.protocol.Packet getAddEntityPacket() { + return net.minecraftforge.fmllegacy.network.NetworkHooks.getEntitySpawningPacket(this); } @Override - public void addAdditionalSaveData(CompoundNBT tag) { + public void addAdditionalSaveData(CompoundTag tag) { super.addAdditionalSaveData(tag); - if (!ammunition.isEmpty()) tag.put("Ammunition", ammunition.save(new CompoundNBT())); + if (!ammunition.isEmpty()) tag.put("Ammunition", ammunition.save(new CompoundTag())); } @Override - public void readAdditionalSaveData(CompoundNBT tag) { + public void readAdditionalSaveData(CompoundTag tag) { super.readAdditionalSaveData(tag); ammunition = tag.contains("Ammunition", 10) ? ItemStack.of(tag.getCompound("Ammunition")) : ItemStack.EMPTY; } - @Override public void writeSpawnData(PacketBuffer buffer) { buffer.writeItem(ammunition); } - @Override public void readSpawnData(PacketBuffer buffer) { ammunition = buffer.readItem(); } + @Override public void writeSpawnData(FriendlyByteBuf buffer) { buffer.writeItem(ammunition); } + @Override public void readSpawnData(FriendlyByteBuf buffer) { ammunition = buffer.readItem(); } } diff --git a/src/main/java/zone/moddev/mc/basemetals/entity/ModEntities.java b/src/main/java/zone/moddev/mc/basemetals/entity/ModEntities.java index 900a52918..1490fbd62 100644 --- a/src/main/java/zone/moddev/mc/basemetals/entity/ModEntities.java +++ b/src/main/java/zone/moddev/mc/basemetals/entity/ModEntities.java @@ -3,7 +3,7 @@ import zone.moddev.mc.basemetals.BaseMetals; import zone.moddev.mc.basemetals.content.RegistryHandle; -import net.minecraft.entity.EntityType; +import net.minecraft.world.entity.EntityType; import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; @@ -30,7 +30,7 @@ public static void registerEntities(RegistryEvent.Register> event) private static EntityType register(RegistryEvent.Register> event, String name, final RegistryHandle> self) { EntityType type = EntityType.Builder - .of(MaterialProjectile::new, net.minecraft.entity.EntityClassification.MISC) + .of(MaterialProjectile::new, net.minecraft.world.entity.MobCategory.MISC) .sized(0.5F, 0.5F).setTrackingRange(64).setUpdateInterval(20) .setShouldReceiveVelocityUpdates(true) .build(BaseMetals.MOD_ID + ":" + name); diff --git a/src/main/java/zone/moddev/mc/basemetals/loot/ContentModeLootCondition.java b/src/main/java/zone/moddev/mc/basemetals/loot/ContentModeLootCondition.java index 76e0f95f1..6d51c0eea 100644 --- a/src/main/java/zone/moddev/mc/basemetals/loot/ContentModeLootCondition.java +++ b/src/main/java/zone/moddev/mc/basemetals/loot/ContentModeLootCondition.java @@ -3,27 +3,26 @@ import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonObject; import com.google.gson.JsonSerializationContext; -import net.minecraft.util.JSONUtils; -import net.minecraft.util.ResourceLocation; -import net.minecraft.loot.LootContext; -import net.minecraft.loot.conditions.ILootCondition; -import net.minecraft.loot.ILootSerializer; -import net.minecraft.loot.LootConditionType; -import net.minecraft.util.registry.Registry; +import net.minecraft.util.GsonHelper; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.storage.loot.LootContext; +import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; +import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType; +import net.minecraft.core.Registry; import zone.moddev.mc.basemetals.config.ContentPolicy; /** Filters only the auxiliary chest entries supplied by Base Metals. */ -public final class ContentModeLootCondition implements ILootCondition { - private static LootConditionType type; +public final class ContentModeLootCondition implements LootItemCondition { + private static LootItemConditionType type; private final String item; public static void register() { type = Registry.register(Registry.LOOT_CONDITION_TYPE, - new ResourceLocation("basemetals", "content_mode"), new LootConditionType(new Serializer())); + new ResourceLocation("basemetals", "content_mode"), new LootItemConditionType(new Serializer())); } @Override - public LootConditionType getType() { + public LootItemConditionType getType() { return type; } @@ -36,7 +35,7 @@ public boolean test(LootContext context) { return ContentPolicy.active().allows(item); } - public static final class Serializer implements ILootSerializer { + public static final class Serializer implements net.minecraft.world.level.storage.loot.Serializer { @Override public void serialize(JsonObject json, ContentModeLootCondition value, JsonSerializationContext context) { json.addProperty("item", value.item); @@ -44,7 +43,7 @@ public void serialize(JsonObject json, ContentModeLootCondition value, JsonSeria @Override public ContentModeLootCondition deserialize(JsonObject json, JsonDeserializationContext context) { - return new ContentModeLootCondition(JSONUtils.getAsString(json, "item")); + return new ContentModeLootCondition(GsonHelper.getAsString(json, "item")); } } } diff --git a/src/main/java/zone/moddev/mc/basemetals/loot/ModLoot.java b/src/main/java/zone/moddev/mc/basemetals/loot/ModLoot.java index d12a07775..fcafb507a 100644 --- a/src/main/java/zone/moddev/mc/basemetals/loot/ModLoot.java +++ b/src/main/java/zone/moddev/mc/basemetals/loot/ModLoot.java @@ -6,11 +6,11 @@ import zone.moddev.mc.basemetals.BaseMetals; -import net.minecraft.util.ResourceLocation; -import net.minecraft.loot.LootEntry; -import net.minecraft.loot.TableLootEntry; -import net.minecraft.loot.LootPool; -import net.minecraft.loot.RandomValueRange; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.storage.loot.entries.LootPoolEntryContainer; +import net.minecraft.world.level.storage.loot.entries.LootTableReference; +import net.minecraft.world.level.storage.loot.LootPool; +import net.minecraft.world.level.storage.loot.providers.number.ConstantValue; import net.minecraftforge.event.LootTableLoadEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; @@ -44,7 +44,7 @@ public static void onLootTableLoad(LootTableLoadEvent event) { ResourceLocation auxiliary = INJECTIONS.get(event.getName()); if (auxiliary == null || event.getTable().getPool("basemetals_injection") != null) return; event.getTable().addPool(LootPool.lootPool().name("basemetals_injection") - .setRolls(new RandomValueRange(1.0F)).add(TableLootEntry.lootTableReference(auxiliary)).build()); + .setRolls(ConstantValue.exactly(1.0F)).add(LootTableReference.lootTableReference(auxiliary)).build()); } private static void inject(Map injections, String vanilla, String auxiliary) { diff --git a/src/main/java/zone/moddev/mc/basemetals/material/MaterialDefinition.java b/src/main/java/zone/moddev/mc/basemetals/material/MaterialDefinition.java index 24ae0a979..b197f771d 100644 --- a/src/main/java/zone/moddev/mc/basemetals/material/MaterialDefinition.java +++ b/src/main/java/zone/moddev/mc/basemetals/material/MaterialDefinition.java @@ -2,7 +2,7 @@ import java.util.Objects; -import net.minecraft.inventory.EquipmentSlotType; +import net.minecraft.world.entity.EquipmentSlot; /** Material statistics and form availability used by registration and recipes. */ public final class MaterialDefinition { @@ -84,7 +84,7 @@ public String repairIngredientTag() { public int armorDurabilityFactor() { return Math.max(1, (int) (2.0D * strength)); } public float armorToughness() { return hardness > 10.0D ? (int) (hardness / 5.0D) : 0.0F; } - public int armorProtection(EquipmentSlotType slot) { + public int armorProtection(EquipmentSlot slot) { double total = (1.25D * hardness) + 5.0D; double fraction; switch (slot) { diff --git a/src/main/java/zone/moddev/mc/basemetals/migration/LegacyWorldDataHook.java b/src/main/java/zone/moddev/mc/basemetals/migration/LegacyWorldDataHook.java index 6ecae3d34..2b09fceaa 100644 --- a/src/main/java/zone/moddev/mc/basemetals/migration/LegacyWorldDataHook.java +++ b/src/main/java/zone/moddev/mc/basemetals/migration/LegacyWorldDataHook.java @@ -9,6 +9,7 @@ import java.lang.reflect.Modifier; import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.util.ArrayList; import java.util.Arrays; @@ -18,8 +19,11 @@ import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Stream; + +import it.unimi.dsi.fastutil.longs.LongOpenHashSet; +import it.unimi.dsi.fastutil.longs.LongSet; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -34,37 +38,37 @@ import zone.moddev.mc.basemetals.content.ModContent; import zone.moddev.mc.basemetals.content.PlateBlock; -import net.minecraft.block.Block; -import net.minecraft.block.AnvilBlock; -import net.minecraft.block.AbstractButtonBlock; -import net.minecraft.block.DoorBlock; -import net.minecraft.block.HorizontalBlock; -import net.minecraft.block.HorizontalFaceBlock; -import net.minecraft.block.LeverBlock; -import net.minecraft.block.PressurePlateBlock; -import net.minecraft.block.SlabBlock; -import net.minecraft.block.StairsBlock; -import net.minecraft.block.TrapDoorBlock; -import net.minecraft.block.FlowingFluidBlock; -import net.minecraft.block.BlockState; -import net.minecraft.nbt.CompressedStreamTools; -import net.minecraft.nbt.INBT; -import net.minecraft.nbt.CompoundNBT; -import net.minecraft.nbt.ListNBT; -import net.minecraft.nbt.NBTUtil; -import net.minecraft.state.properties.AttachFace; -import net.minecraft.state.properties.DoorHingeSide; -import net.minecraft.state.properties.DoubleBlockHalf; -import net.minecraft.state.properties.Half; -import net.minecraft.state.properties.SlabType; -import net.minecraft.state.properties.StairsShape; -import net.minecraft.util.Direction; -import net.minecraft.util.ResourceLocation; -import net.minecraft.util.datafix.fixes.BlockStateFlatteningMap; -import net.minecraft.world.storage.SaveFormat.LevelSave; -import net.minecraft.world.storage.IServerConfiguration; -import net.minecraftforge.fml.WorldPersistenceHooks; -import net.minecraftforge.fml.common.ObfuscationReflectionHelper; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.AnvilBlock; +import net.minecraft.world.level.block.ButtonBlock; +import net.minecraft.world.level.block.DoorBlock; +import net.minecraft.world.level.block.HorizontalDirectionalBlock; +import net.minecraft.world.level.block.FaceAttachedHorizontalDirectionalBlock; +import net.minecraft.world.level.block.LeverBlock; +import net.minecraft.world.level.block.PressurePlateBlock; +import net.minecraft.world.level.block.SlabBlock; +import net.minecraft.world.level.block.StairBlock; +import net.minecraft.world.level.block.TrapDoorBlock; +import net.minecraft.world.level.block.LiquidBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.nbt.NbtIo; +import net.minecraft.nbt.Tag; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.world.level.block.state.properties.AttachFace; +import net.minecraft.world.level.block.state.properties.DoorHingeSide; +import net.minecraft.world.level.block.state.properties.DoubleBlockHalf; +import net.minecraft.world.level.block.state.properties.Half; +import net.minecraft.world.level.block.state.properties.SlabType; +import net.minecraft.world.level.block.state.properties.StairsShape; +import net.minecraft.core.Direction; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.datafix.fixes.BlockStateData; +import net.minecraft.world.level.storage.LevelStorageSource.LevelStorageAccess; +import net.minecraft.world.level.storage.WorldData; +import net.minecraftforge.fmllegacy.WorldPersistenceHooks; +import net.minecraftforge.fml.util.ObfuscationReflectionHelper; import net.minecraftforge.registries.ForgeRegistries; /** @@ -75,15 +79,14 @@ public final class LegacyWorldDataHook implements WorldPersistenceHooks.WorldPersistenceHook { private static final LegacyWorldDataHook INSTANCE = new LegacyWorldDataHook(); private static final ResourceLocation BLOCK_REGISTRY = new ResourceLocation("minecraft", "blocks"); - private static final Map LEGACY_WORLD_DATA = new ConcurrentHashMap(); + private static final Map LEGACY_WORLD_DATA = new ConcurrentHashMap(); private static final BitSet LEGACY_BASE_METALS_BLOCK_IDS = new BitSet(); - private static final Set LEGACY_BASE_METALS_CHUNKS = Collections.newSetFromMap( - new ConcurrentHashMap()); + private static volatile Map legacyTerrainChunks = Collections.emptyMap(); private static final Map LEGACY_BASE_METALS_BLOCK_COUNTS = new ConcurrentHashMap(); private static final Map VANILLA_BLOCK_ENTITY_IDS = vanillaBlockEntityIds(); private static final String PRESERVE_CHUNK_MARKER = "BaseMetalsLegacyPreserveChunk"; - private static boolean legacyWorldActive; + private static volatile boolean legacyWorldActive; private static boolean registered; private LegacyWorldDataHook() {} @@ -98,13 +101,13 @@ public static synchronized void register() { /** Called by the coremod before Forge reads level.dat. */ public static synchronized void prepareLegacyWorld(File levelDat) { legacyWorldActive = false; - LEGACY_BASE_METALS_CHUNKS.clear(); + legacyTerrainChunks = Collections.emptyMap(); LEGACY_BASE_METALS_BLOCK_COUNTS.clear(); removeRetiredProfessionSnapshot(levelDat); File source = legacyRegistrySource(levelDat); if (source == null) return; try (FileInputStream input = new FileInputStream(source)) { - CompoundNBT root = CompressedStreamTools.readCompressed(input); + CompoundTag root = NbtIo.readCompressed(input); if (!root.contains("FML", 10)) return; prepareLegacyData(levelDat.getParentFile(), root.getCompound("FML")); migrateLoosePlayerData(levelDat, root); @@ -116,9 +119,9 @@ public static synchronized void prepareLegacyWorld(File levelDat) { private static void removeRetiredProfessionSnapshot(File levelDat) { if (!levelDat.isFile()) return; try { - CompoundNBT root; + CompoundTag root; try (FileInputStream input = new FileInputStream(levelDat)) { - root = CompressedStreamTools.readCompressed(input); + root = NbtIo.readCompressed(input); } if (removeRetiredVanillaProfessionRegistry(root)) writeWithBackup(levelDat, root); } catch (IOException exception) { @@ -126,28 +129,28 @@ private static void removeRetiredProfessionSnapshot(File levelDat) { } } - static boolean removeRetiredVanillaProfessionRegistry(CompoundNBT root) { + static boolean removeRetiredVanillaProfessionRegistry(CompoundTag root) { boolean changed = false; for (String namespace : new String[] {"fml", "FML"}) { - CompoundNBT registries = root.getCompound(namespace).getCompound("Registries"); + CompoundTag registries = root.getCompound(namespace).getCompound("Registries"); String key = "minecraft:villagerprofessions"; if (!registries.contains(key, 10)) continue; - CompoundNBT snapshot = registries.getCompound(key); + CompoundTag snapshot = registries.getCompound(key); if (!snapshot.contains("ids", 9)) continue; boolean vanillaOnly = true; - for (INBT entry : (ListNBT) snapshot.get("ids")) { - if (!(entry instanceof CompoundNBT)) { + for (Tag entry : (ListTag) snapshot.get("ids")) { + if (!(entry instanceof CompoundTag)) { vanillaOnly = false; continue; } - String name = ((CompoundNBT) entry).getString("K"); + String name = ((CompoundTag) entry).getString("K"); if (!Arrays.asList("minecraft:farmer", "minecraft:librarian", "minecraft:priest", "minecraft:smith", "minecraft:butcher", "minecraft:nitwit").contains(name)) { vanillaOnly = false; } } for (String list : new String[] {"aliases", "overrides", "dummied"}) { - if (snapshot.contains(list, 9) && !((ListNBT) snapshot.get(list)).isEmpty()) vanillaOnly = false; + if (snapshot.contains(list, 9) && !((ListTag) snapshot.get(list)).isEmpty()) vanillaOnly = false; } if (snapshot.getIntArray("blocked").length > 0) vanillaOnly = false; if (!vanillaOnly) continue; @@ -161,12 +164,12 @@ static boolean removeRetiredVanillaProfessionRegistry(CompoundNBT root) { } /** Called by the coremod immediately after a legacy chunk NBT is read. */ - public static synchronized void prepareLegacyChunk(CompoundNBT root) { + public static synchronized void prepareLegacyChunk(CompoundTag root) { if (root == null) return; migrateLegacyItems(root); migrateWallStates(root); if (!legacyWorldActive || !root.contains("Level", 10)) return; - CompoundNBT level = root.getCompound("Level"); + CompoundTag level = root.getCompound("Level"); int legacyBlocks = countLegacyBaseMetalsBlocks(level); if (legacyBlocks > 0) { LEGACY_BASE_METALS_BLOCK_COUNTS.put(Long.valueOf(chunkKey(level.getInt("xPos"), level.getInt("zPos"))), @@ -180,13 +183,13 @@ public static synchronized void prepareLegacyChunk(CompoundNBT root) { } /** Old wall connections were booleans; 1.16 expects none, low or tall. */ - static int migrateWallStates(INBT value) { + static int migrateWallStates(Tag value) { int changed = 0; - if (value instanceof CompoundNBT) { - CompoundNBT compound = (CompoundNBT) value; + if (value instanceof CompoundTag) { + CompoundTag compound = (CompoundTag) value; String name = compound.getString("Name"); if (name.startsWith("basemetals:") && name.endsWith("_wall")) { - CompoundNBT properties = compound.getCompound("Properties"); + CompoundTag properties = compound.getCompound("Properties"); for (String direction : new String[] {"north", "east", "south", "west"}) { String connection = properties.getString(direction); if ("true".equals(connection) || "false".equals(connection)) { @@ -196,17 +199,18 @@ static int migrateWallStates(INBT value) { } } for (String key : compound.getAllKeys()) changed += migrateWallStates(compound.get(key)); - } else if (value instanceof ListNBT) { - for (INBT entry : (ListNBT) value) changed += migrateWallStates(entry); + } else if (value instanceof ListTag) { + for (Tag entry : (ListTag) value) changed += migrateWallStates(entry); } return changed; } /** Called after vanilla datafixing, before a legacy chunk is returned. */ - public static CompoundNBT finalizeLegacyChunk(CompoundNBT root) { + public static CompoundTag finalizeLegacyChunk(CompoundTag root) { if (root != null && root.contains("Level", 10)) { - CompoundNBT level = root.getCompound("Level"); + CompoundTag level = root.getCompound("Level"); if (level.getBoolean(PRESERVE_CHUNK_MARKER)) { + removePhantomBedEntities(level); level.putString("Status", "full"); level.remove(PRESERVE_CHUNK_MARKER); } @@ -214,27 +218,75 @@ public static CompoundNBT finalizeLegacyChunk(CompoundNBT root) { return root; } - public static boolean shouldBlockWorldgenWrite(net.minecraft.util.math.BlockPos position) { + static int removePhantomBedEntities(CompoundTag level) { + ListTag entities = level.getList("TileEntities", 10); + int removed = 0; + + for (int index = entities.size() - 1; index >= 0; index--) { + CompoundTag entity = entities.getCompound(index); + if (!"minecraft:bed".equals(entity.getString("id"))) continue; + + // Vanilla's pre-flattening bed fixer ignores the high bits of modded block IDs. + // A bed entity cannot belong to a Base Metals block; real beds are left alone. + String block = paletteBlockAt(level, entity.getInt("x"), entity.getInt("y"), entity.getInt("z")); + if (block.startsWith("basemetals:")) { + entities.remove(index); + removed++; + } + } + + return removed; + } + + private static String paletteBlockAt(CompoundTag level, int x, int y, int z) { + for (Tag entry : level.getList("Sections", 10)) { + CompoundTag section = (CompoundTag) entry; + if (section.getByte("Y") != (y >> 4)) continue; + + ListTag palette = section.getList("Palette", 10); + if (palette.isEmpty()) return ""; + int state = 0; + if (palette.size() > 1) { + int bits = Math.max(4, 32 - Integer.numberOfLeadingZeros(palette.size() - 1)); + int perWord = 64 / bits; + int position = ((y & 15) << 8) | ((z & 15) << 4) | (x & 15); + long[] states = section.getLongArray("BlockStates"); + int word = position / perWord; + if (word >= states.length) return ""; + state = (int) ((states[word] >>> ((position % perWord) * bits)) & ((1L << bits) - 1)); + } + return state < palette.size() ? palette.getCompound(state).getString("Name") : ""; + } + return ""; + } + + public static boolean shouldBlockWorldgenWrite(net.minecraft.server.level.WorldGenRegion region, + net.minecraft.core.BlockPos position) { return legacyWorldActive && position != null - && LEGACY_BASE_METALS_CHUNKS.contains(chunkKey(position.getX() >> 4, position.getZ() >> 4)); + && isProtectedChunk(region.getLevel().dimension().location(), position); + } + + static boolean isProtectedChunk(ResourceLocation dimension, net.minecraft.core.BlockPos position) { + LongSet chunks = legacyTerrainChunks.get(dimension); + return chunks != null && chunks.contains(chunkKey(position.getX() >> 4, position.getZ() >> 4)); } @Override public String getModId() { return "FML"; } @Override - public CompoundNBT getDataForWriting(LevelSave handler, IServerConfiguration info) { - CompoundNBT legacy = LEGACY_WORLD_DATA.get(worldKey(handler.getWorldDir().toFile())); - return legacy == null ? new CompoundNBT() : legacy.copy(); + public CompoundTag getDataForWriting(LevelStorageAccess handler, WorldData info) { + CompoundTag legacy = LEGACY_WORLD_DATA.get(worldKey(handler.getWorldDir().toFile())); + return legacy == null ? new CompoundTag() : legacy.copy(); } @Override - public void readData(LevelSave handler, IServerConfiguration info, CompoundNBT tag) { + public void readData(LevelStorageAccess handler, WorldData info, CompoundTag tag) { prepareLegacyData(handler.getWorldDir().toFile(), tag); } - private static synchronized void prepareLegacyData(File worldDirectory, CompoundNBT tag) { + private static synchronized void prepareLegacyData(File worldDirectory, CompoundTag tag) { if (!tag.contains("Registries", 10)) return; - CompoundNBT registries = tag.getCompound("Registries"); + CompoundTag registries = tag.getCompound("Registries"); if (!registries.contains(BLOCK_REGISTRY.toString(), 10)) return; String key = worldKey(worldDirectory); boolean first = !LEGACY_WORLD_DATA.containsKey(key); @@ -248,13 +300,13 @@ private static synchronized void prepareLegacyData(File worldDirectory, Compound } } - private static int installLegacyBlockStates(CompoundNBT snapshot) { + private static int installLegacyBlockStates(CompoundTag snapshot) { LEGACY_BASE_METALS_BLOCK_IDS.clear(); Map ids = new LinkedHashMap(); - ListNBT savedIds = snapshot.getList("ids", 10); + ListTag savedIds = snapshot.getList("ids", 10); int highestState = 0; for (int index = 0; index < savedIds.size(); index++) { - CompoundNBT entry = savedIds.getCompound(index); + CompoundTag entry = savedIds.getCompound(index); String normalized = normalizeLegacyRegistryName(entry.getString("K")); int separator = normalized.indexOf(':'); if (separator < 0) continue; @@ -274,7 +326,7 @@ private static int installLegacyBlockStates(CompoundNBT snapshot) { for (int meta = 0; meta < 16; meta++) { BlockState state = legacyState(block, entry.getKey().getPath(), meta); table[(entry.getValue().intValue() << 4) | meta] = - BlockStateFlatteningMap.parse(NBTUtil.writeBlockState(state).toString()); + BlockStateData.parse(NbtUtils.writeBlockState(state).toString()); mapped++; } } @@ -294,12 +346,12 @@ static BlockState legacyState(Block block, String path, int meta) { if (block instanceof CompatibilityDoubleSlabBlock) return state.setValue(SlabBlock.TYPE, SlabType.DOUBLE); if (block instanceof SlabBlock) return state.setValue(SlabBlock.TYPE, (meta & 8) == 0 ? SlabType.BOTTOM : SlabType.TOP); - if (block instanceof StairsBlock) { + if (block instanceof StairBlock) { Direction facing = Direction.from3DDataValue(5 - (meta & 3)); - return state.setValue(StairsBlock.FACING, facing) - .setValue(StairsBlock.HALF, (meta & 4) == 0 ? Half.BOTTOM : Half.TOP) - .setValue(StairsBlock.SHAPE, StairsShape.STRAIGHT) - .setValue(StairsBlock.WATERLOGGED, Boolean.FALSE); + return state.setValue(StairBlock.FACING, facing) + .setValue(StairBlock.HALF, (meta & 4) == 0 ? Half.BOTTOM : Half.TOP) + .setValue(StairBlock.SHAPE, StairsShape.STRAIGHT) + .setValue(StairBlock.WATERLOGGED, Boolean.FALSE); } if (block instanceof DoorBlock) { if ((meta & 8) != 0) { @@ -313,7 +365,7 @@ static BlockState legacyState(Block block, String path, int meta) { } if (block instanceof TrapDoorBlock) { Direction[] facing = { Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST }; - return state.setValue(HorizontalBlock.FACING, facing[meta & 3]) + return state.setValue(HorizontalDirectionalBlock.FACING, facing[meta & 3]) .setValue(TrapDoorBlock.OPEN, Boolean.valueOf((meta & 4) != 0)) .setValue(TrapDoorBlock.HALF, (meta & 8) == 0 ? Half.BOTTOM : Half.TOP) .setValue(TrapDoorBlock.POWERED, Boolean.FALSE) @@ -323,17 +375,17 @@ static BlockState legacyState(Block block, String path, int meta) { return state.setValue(AnvilBlock.FACING, Direction.from2DDataValue(meta & 3)) .setValue(BaseMetalAnvilBlock.DAMAGE, Integer.valueOf(Math.min(2, (meta & 15) >> 2))); } - if (block instanceof AbstractButtonBlock) return attachedState(state, meta, AbstractButtonBlock.POWERED); + if (block instanceof ButtonBlock) return attachedState(state, meta, ButtonBlock.POWERED); if (block instanceof LeverBlock) return legacyLeverState(state, meta); if (block instanceof PressurePlateBlock) return state.setValue(PressurePlateBlock.POWERED, Boolean.valueOf(meta > 0)); - if (block instanceof FlowingFluidBlock) return state.setValue(FlowingFluidBlock.LEVEL, + if (block instanceof LiquidBlock) return state.setValue(LiquidBlock.LEVEL, Integer.valueOf(Math.min(15, meta))); return state; } private static BlockState attachedState(BlockState state, int meta, - net.minecraft.state.BooleanProperty powered) { + net.minecraft.world.level.block.state.properties.BooleanProperty powered) { Direction oldFacing; switch (meta & 7) { case 0: oldFacing = Direction.DOWN; break; @@ -346,8 +398,8 @@ private static BlockState attachedState(BlockState state, int meta, AttachFace face = oldFacing == Direction.DOWN ? AttachFace.CEILING : oldFacing == Direction.UP ? AttachFace.FLOOR : AttachFace.WALL; Direction horizontal = oldFacing.getAxis().isHorizontal() ? oldFacing : Direction.NORTH; - return state.setValue(HorizontalFaceBlock.FACE, face) - .setValue(HorizontalBlock.FACING, horizontal) + return state.setValue(FaceAttachedHorizontalDirectionalBlock.FACE, face) + .setValue(HorizontalDirectionalBlock.FACING, horizontal) .setValue(powered, Boolean.valueOf((meta & 8) != 0)); } @@ -366,8 +418,8 @@ private static BlockState legacyLeverState(BlockState state, int meta) { horizontal = new Direction[] { Direction.NORTH, Direction.EAST, Direction.WEST, Direction.SOUTH, Direction.NORTH }[orientation]; } - return state.setValue(HorizontalFaceBlock.FACE, face) - .setValue(HorizontalBlock.FACING, horizontal) + return state.setValue(FaceAttachedHorizontalDirectionalBlock.FACE, face) + .setValue(HorizontalDirectionalBlock.FACING, horizontal) .setValue(LeverBlock.POWERED, Boolean.valueOf((meta & 8) != 0)); } @@ -375,19 +427,19 @@ static Map legacyBlockIdsForTest(java.nio.file.Path root) throw File source = legacyRegistrySource(root.resolve("level.dat").toFile()); if (source != null) { try (FileInputStream input = new FileInputStream(source)) { - Map result = idsFromRoot(CompressedStreamTools.readCompressed(input)); + Map result = idsFromRoot(NbtIo.readCompressed(input)); if (!result.isEmpty()) return result; } } return embeddedBlockIds(); } - private static Map idsFromRoot(CompoundNBT root) { + private static Map idsFromRoot(CompoundTag root) { Map result = new LinkedHashMap(); - ListNBT ids = root.getCompound("FML").getCompound("Registries") + ListTag ids = root.getCompound("FML").getCompound("Registries") .getCompound(BLOCK_REGISTRY.toString()).getList("ids", 10); for (int index = 0; index < ids.size(); index++) { - CompoundNBT entry = ids.getCompound(index); + CompoundTag entry = ids.getCompound(index); result.put(Integer.valueOf(entry.getInt("V")), normalizeLegacyRegistryName(entry.getString("K"))); } return result; @@ -414,7 +466,7 @@ public static String normalizeLegacyRegistryName(String name) { return value.indexOf(':') < 0 ? BaseMetals.MOD_ID + ":" + value : value; } - private static void migrateLoosePlayerData(File levelDat, CompoundNBT root) throws IOException { + private static void migrateLoosePlayerData(File levelDat, CompoundTag root) throws IOException { boolean changed = migrateLegacyItems(root) > 0; if (changed && levelDat.isFile()) writeWithBackup(levelDat, root); File playerData = new File(levelDat.getParentFile(), "playerdata"); @@ -423,16 +475,16 @@ private static void migrateLoosePlayerData(File levelDat, CompoundNBT root) thro Arrays.sort(files); for (File file : files) { try (FileInputStream input = new FileInputStream(file)) { - CompoundNBT player = CompressedStreamTools.readCompressed(input); + CompoundTag player = NbtIo.readCompressed(input); if (migrateLegacyItems(player) > 0) writeWithBackup(file, player); } } } - private static int migrateLegacyItems(INBT value) { + private static int migrateLegacyItems(Tag value) { int changed = 0; - if (value instanceof CompoundNBT) { - CompoundNBT compound = (CompoundNBT) value; + if (value instanceof CompoundTag) { + CompoundTag compound = (CompoundTag) value; String id = compound.getString("id"); String vanillaBlockEntity = VANILLA_BLOCK_ENTITY_IDS.get(id); if (vanillaBlockEntity != null) { @@ -441,7 +493,7 @@ private static int migrateLegacyItems(INBT value) { changed++; } if ("forge:bucketfilled".equalsIgnoreCase(id) && compound.contains("tag", 10)) { - CompoundNBT tag = compound.getCompound("tag"); + CompoundTag tag = compound.getCompound("tag"); String target = MissingMappings.fluidTargetPath(tag.getString("FluidName")); if (ModContent.fluids().containsKey(target)) { compound.putString("id", BaseMetals.MOD_ID + ":" + target + "_bucket"); @@ -460,8 +512,8 @@ private static int migrateLegacyItems(INBT value) { changed++; } if (compound.contains("Damage", 99) && compound.getInt("Damage") > 0) { - CompoundNBT tag = compound.contains("tag", 10) - ? compound.getCompound("tag") : new CompoundNBT(); + CompoundTag tag = compound.contains("tag", 10) + ? compound.getCompound("tag") : new CompoundTag(); if (!tag.contains("Damage", 99)) { tag.putInt("Damage", compound.getInt("Damage")); compound.put("tag", tag); @@ -471,11 +523,11 @@ private static int migrateLegacyItems(INBT value) { } } for (String key : new ArrayList(compound.getAllKeys())) { - INBT child = compound.get(key); + Tag child = compound.get(key); if (child != null) changed += migrateLegacyItems(child); } - } else if (value instanceof ListNBT) { - ListNBT list = (ListNBT) value; + } else if (value instanceof ListTag) { + ListTag list = (ListTag) value; for (int index = 0; index < list.size(); index++) changed += migrateLegacyItems(list.get(index)); } return changed; @@ -493,7 +545,7 @@ private static Map vanillaBlockEntityIds() { ids.put("DLDetector", "minecraft:daylight_detector"); ids.put("Dropper", "minecraft:dropper"); ids.put("EnchantTable", "minecraft:enchanting_table"); - ids.put("EndGateway", "minecraft:end_gateway"); + ids.put("EndGatewayPlacementDecorator", "minecraft:end_gateway"); ids.put("EnderChest", "minecraft:ender_chest"); ids.put("FlowerPot", "minecraft:flower_pot"); ids.put("Furnace", "minecraft:furnace"); @@ -504,7 +556,7 @@ private static Map vanillaBlockEntityIds() { ids.put("RecordPlayer", "minecraft:jukebox"); ids.put("Sign", "minecraft:sign"); ids.put("Skull", "minecraft:skull"); - ids.put("Structure", "minecraft:structure_block"); + ids.put("StructureFeature", "minecraft:structure_block"); ids.put("Trap", "minecraft:dispenser"); return Collections.unmodifiableMap(ids); } @@ -514,12 +566,12 @@ private static ResourceLocation safeId(String value) { catch (RuntimeException ignored) { return null; } } - private static void writeWithBackup(File file, CompoundNBT data) throws IOException { + private static void writeWithBackup(File file, CompoundTag data) throws IOException { File backup = new File(file.getParentFile(), file.getName() + ".basemetals-legacy-backup"); if (!backup.exists()) Files.copy(file.toPath(), backup.toPath(), StandardCopyOption.COPY_ATTRIBUTES); File temporary = new File(file.getParentFile(), file.getName() + ".basemetals.tmp"); try (FileOutputStream output = new FileOutputStream(temporary)) { - CompressedStreamTools.writeCompressed(data, output); + NbtIo.writeCompressed(data, output); } try { Files.move(temporary.toPath(), file.toPath(), StandardCopyOption.REPLACE_EXISTING, @@ -533,14 +585,14 @@ private static File legacyRegistrySource(File levelDat) { for (File candidate : new File[] { levelDat, new File(levelDat.getParentFile(), "level.dat_old") }) { if (!candidate.isFile()) continue; try (FileInputStream input = new FileInputStream(candidate)) { - CompoundNBT root = CompressedStreamTools.readCompressed(input); + CompoundTag root = NbtIo.readCompressed(input); if (root.contains("FML", 10) && containsLegacyBaseMetalsRegistryEntry(root)) return candidate; } catch (IOException ignored) {} } return null; } - private static boolean containsLegacyBaseMetalsRegistryEntry(CompoundNBT root) { + private static boolean containsLegacyBaseMetalsRegistryEntry(CompoundTag root) { for (String id : idsFromRoot(root).values()) { int separator = id.indexOf(':'); String namespace = separator < 0 ? BaseMetals.MOD_ID : id.substring(0, separator); @@ -549,11 +601,11 @@ private static boolean containsLegacyBaseMetalsRegistryEntry(CompoundNBT root) { return false; } - private static int countLegacyBaseMetalsBlocks(CompoundNBT level) { + private static int countLegacyBaseMetalsBlocks(CompoundTag level) { int found = 0; - ListNBT sections = level.getList("Sections", 10); + ListTag sections = level.getList("Sections", 10); for (int sectionIndex = 0; sectionIndex < sections.size(); sectionIndex++) { - CompoundNBT section = sections.getCompound(sectionIndex); + CompoundTag section = sections.getCompound(sectionIndex); byte[] blocks = section.getByteArray("Blocks"); if (blocks.length != 4096) continue; byte[] add = section.getByteArray("Add"); @@ -570,11 +622,37 @@ public static Map legacyPreparedBlockCounts() { return new LinkedHashMap(LEGACY_BASE_METALS_BLOCK_COUNTS); } - private static int indexLegacyChunks(File worldDirectory) { - LEGACY_BASE_METALS_CHUNKS.clear(); - File regionDirectory = new File(worldDirectory, "region"); + static int indexLegacyChunks(File worldDirectory) { + Map indexed = new LinkedHashMap<>(); + indexRegionDirectory(indexed, new ResourceLocation("minecraft:overworld"), new File(worldDirectory, "region")); + indexRegionDirectory(indexed, new ResourceLocation("minecraft:the_nether"), new File(worldDirectory, "DIM-1/region")); + indexRegionDirectory(indexed, new ResourceLocation("minecraft:the_end"), new File(worldDirectory, "DIM1/region")); + + Path dimensions = worldDirectory.toPath().resolve("dimensions"); + if (Files.isDirectory(dimensions)) { + try (Stream directories = Files.walk(dimensions)) { + directories.filter(path -> Files.isDirectory(path) && path.getFileName().toString().equals("region")) + .forEach(path -> { + Path relative = dimensions.relativize(path.getParent()); + if (relative.getNameCount() < 2) return; + String namespace = relative.getName(0).toString(); + String name = relative.subpath(1, relative.getNameCount()).toString().replace(File.separatorChar, '/'); + indexRegionDirectory(indexed, new ResourceLocation(namespace, name), path.toFile()); + }); + } catch (IOException exception) { + throw new IllegalStateException("Could not inspect saved dimensions in " + dimensions, exception); + } + } + + legacyTerrainChunks = Collections.unmodifiableMap(indexed); + return indexed.values().stream().mapToInt(LongSet::size).sum(); + } + + private static void indexRegionDirectory(Map indexed, + ResourceLocation dimension, File regionDirectory) { File[] regions = regionDirectory.listFiles((directory, name) -> name.matches("r\\.-?\\d+\\.-?\\d+\\.mc[ar]")); - if (regions == null) return 0; + if (regions == null) return; + LongSet chunks = indexed.computeIfAbsent(dimension, key -> new LongOpenHashSet()); byte[] locations = new byte[4096]; for (File region : regions) { String[] parts = region.getName().split("\\."); @@ -591,15 +669,13 @@ private static int indexLegacyChunks(File worldDirectory) { for (int index = 0; index < read / 4; index++) { int offset = index * 4; if ((locations[offset] | locations[offset + 1] | locations[offset + 2] | locations[offset + 3]) != 0) { - LEGACY_BASE_METALS_CHUNKS.add(Long.valueOf(chunkKey( - regionX * 32 + (index & 31), regionZ * 32 + (index >> 5)))); + chunks.add(chunkKey(regionX * 32 + (index & 31), regionZ * 32 + (index >> 5))); } } } catch (IOException | NumberFormatException exception) { BaseMetals.LOGGER.warn("Could not inspect legacy chunk locations in '{}'", region, exception); } } - return LEGACY_BASE_METALS_CHUNKS.size(); } private static long chunkKey(int x, int z) { @@ -609,12 +685,12 @@ private static long chunkKey(int x, int z) { @SuppressWarnings("unchecked") private static Dynamic[] expandFlatteningTable(int requiredLength) { try { - String fieldName = ObfuscationReflectionHelper.remapName(INameMappingService.Domain.FIELD, "field_199200_b"); - Field valuesField = BlockStateFlatteningMap.class.getDeclaredField(fieldName); + String fieldName = ObfuscationReflectionHelper.remapName(INameMappingService.Domain.FIELD, "f_14934_"); + Field valuesField = BlockStateData.class.getDeclaredField(fieldName); valuesField.setAccessible(true); - Field modifiersField = Field.class.getDeclaredField("modifiers"); - modifiersField.setAccessible(true); - modifiersField.setInt(valuesField, valuesField.getModifiers() & ~Modifier.FINAL); + if (Modifier.isFinal(valuesField.getModifiers())) { + throw new IllegalStateException("The Base Metals flattening-table hook did not run"); + } Dynamic[] current = (Dynamic[]) valuesField.get(null); if (current.length >= requiredLength) return current; Dynamic[] expanded = Arrays.copyOf(current, requiredLength); diff --git a/src/main/java/zone/moddev/mc/basemetals/network/ContentModeNetwork.java b/src/main/java/zone/moddev/mc/basemetals/network/ContentModeNetwork.java index 18b59cbc3..99285b98b 100644 --- a/src/main/java/zone/moddev/mc/basemetals/network/ContentModeNetwork.java +++ b/src/main/java/zone/moddev/mc/basemetals/network/ContentModeNetwork.java @@ -4,14 +4,14 @@ import java.util.function.IntSupplier; import java.util.function.Supplier; import org.apache.commons.lang3.tuple.Pair; -import net.minecraft.network.PacketBuffer; -import net.minecraft.util.ResourceLocation; -import net.minecraft.util.text.TranslationTextComponent; -import net.minecraftforge.fml.network.FMLHandshakeHandler; -import net.minecraftforge.fml.network.NetworkDirection; -import net.minecraftforge.fml.network.NetworkEvent; -import net.minecraftforge.fml.network.NetworkRegistry; -import net.minecraftforge.fml.network.simple.SimpleChannel; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraftforge.fmllegacy.network.FMLHandshakeHandler; +import net.minecraftforge.fmllegacy.network.NetworkDirection; +import net.minecraftforge.fmllegacy.network.NetworkEvent; +import net.minecraftforge.fmllegacy.network.NetworkRegistry; +import net.minecraftforge.fmllegacy.network.simple.SimpleChannel; import zone.moddev.mc.basemetals.config.BaseMetalsConfig; import zone.moddev.mc.basemetals.config.ContentMode; @@ -56,10 +56,10 @@ private static void receive(ModeMessage message, Supplier ContentMode clientMode = BaseMetalsConfig.activeMode(); if (message.mode != clientMode) { - context.getNetworkManager().disconnect(new TranslationTextComponent( + context.getNetworkManager().disconnect(new TranslatableComponent( "config.basemetals.connection.mismatch", - new TranslationTextComponent(message.mode.translationKey()), - new TranslationTextComponent(clientMode.translationKey()))); + new TranslatableComponent(message.mode.translationKey()), + new TranslatableComponent(clientMode.translationKey()))); return; } @@ -72,7 +72,7 @@ private static final class ModeMessage implements IntSupplier { private ModeMessage(ContentMode mode) { this.mode = mode; } - private static ModeMessage read(PacketBuffer buffer) { + private static ModeMessage read(FriendlyByteBuf buffer) { String value = buffer.readUtf(32); if (!ContentMode.isValid(value)) throw new IllegalArgumentException("Unknown server content mode " + value); return new ModeMessage(ContentMode.parse(value)); diff --git a/src/main/java/zone/moddev/mc/basemetals/recipe/ContentCraftingRecipe.java b/src/main/java/zone/moddev/mc/basemetals/recipe/ContentCraftingRecipe.java index ed5f1754f..20041d3a4 100644 --- a/src/main/java/zone/moddev/mc/basemetals/recipe/ContentCraftingRecipe.java +++ b/src/main/java/zone/moddev/mc/basemetals/recipe/ContentCraftingRecipe.java @@ -2,30 +2,30 @@ import com.google.gson.JsonObject; import com.google.gson.JsonSyntaxException; -import net.minecraft.inventory.CraftingInventory; -import net.minecraft.item.ItemStack; -import net.minecraft.item.crafting.IRecipe; -import net.minecraft.item.crafting.IRecipeSerializer; -import net.minecraft.item.crafting.RecipeManager; +import net.minecraft.world.inventory.CraftingContainer; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.world.item.crafting.RecipeSerializer; +import net.minecraft.world.item.crafting.RecipeManager; import net.minecraftforge.registries.ForgeRegistries; -import net.minecraft.item.crafting.ShapedRecipe; -import net.minecraft.item.crafting.ShapelessRecipe; -import net.minecraft.network.PacketBuffer; -import net.minecraft.util.JSONUtils; -import net.minecraft.util.ResourceLocation; -import net.minecraft.world.World; +import net.minecraft.world.item.crafting.ShapedRecipe; +import net.minecraft.world.item.crafting.ShapelessRecipe; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.util.GsonHelper; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.Level; import zone.moddev.mc.basemetals.config.ContentPolicy; /** Keeps recipe IDs stable between modes, including IDs stored in an old recipe book. */ public final class ContentCraftingRecipe { - public static final IRecipeSerializer> SERIALIZER = new Serializer(); + public static final RecipeSerializer> SERIALIZER = new Serializer(); private ContentCraftingRecipe() {} - private static boolean allowed(IRecipe recipe) { + private static boolean allowed(Recipe recipe) { return ContentPolicy.active().allows(recipe.getResultItem().getItem().getRegistryName().toString()); } - private static IRecipe wrap(IRecipe recipe) { + private static Recipe wrap(Recipe recipe) { // Recipe-book placement needs the shaped recipe's width and height, not just its ingredients. if (recipe instanceof ShapedRecipe) return new Shaped((ShapedRecipe) recipe); if (recipe instanceof ShapelessRecipe) return new Shapeless((ShapelessRecipe) recipe); @@ -42,12 +42,12 @@ private Shaped(ShapedRecipe plain) { } @Override - public boolean matches(CraftingInventory inventory, World world) { + public boolean matches(CraftingContainer inventory, Level world) { return allowed(this) && super.matches(inventory, world); } @Override - public ItemStack assemble(CraftingInventory inventory) { + public ItemStack assemble(CraftingContainer inventory) { return allowed(this) ? super.assemble(inventory) : ItemStack.EMPTY; } @@ -57,7 +57,7 @@ public boolean isSpecial() { } @Override - public IRecipeSerializer getSerializer() { + public RecipeSerializer getSerializer() { return SERIALIZER; } } @@ -71,12 +71,12 @@ private Shapeless(ShapelessRecipe plain) { } @Override - public boolean matches(CraftingInventory inventory, World world) { + public boolean matches(CraftingContainer inventory, Level world) { return allowed(this) && super.matches(inventory, world); } @Override - public ItemStack assemble(CraftingInventory inventory) { + public ItemStack assemble(CraftingContainer inventory) { return allowed(this) ? super.assemble(inventory) : ItemStack.EMPTY; } @@ -86,19 +86,19 @@ public boolean isSpecial() { } @Override - public IRecipeSerializer getSerializer() { + public RecipeSerializer getSerializer() { return SERIALIZER; } } - private static final class Serializer extends net.minecraftforge.registries.ForgeRegistryEntry> - implements IRecipeSerializer> { + private static final class Serializer extends net.minecraftforge.registries.ForgeRegistryEntry> + implements RecipeSerializer> { private Serializer() { setRegistryName("basemetals", "content_crafting"); } @Override - public IRecipe fromJson(ResourceLocation id, JsonObject json) { - JsonObject nested = JSONUtils.getAsJsonObject(json, "recipe"); - String type = JSONUtils.getAsString(nested, "type"); + public Recipe fromJson(ResourceLocation id, JsonObject json) { + JsonObject nested = GsonHelper.getAsJsonObject(json, "recipe"); + String type = GsonHelper.getAsString(nested, "type"); if (!"minecraft:crafting_shaped".equals(type) && !"minecraft:crafting_shapeless".equals(type)) { throw new JsonSyntaxException("Content-mode crafting requires an ordinary shaped or shapeless recipe"); } @@ -107,14 +107,14 @@ public IRecipe fromJson(ResourceLocation id, JsonObject json) { } @Override - public IRecipe fromNetwork(ResourceLocation id, PacketBuffer buffer) { + public Recipe fromNetwork(ResourceLocation id, FriendlyByteBuf buffer) { ResourceLocation serializerId = buffer.readResourceLocation(); ResourceLocation recipeId = buffer.readResourceLocation(); - IRecipeSerializer serializer = ForgeRegistries.RECIPE_SERIALIZERS.getValue(serializerId); + RecipeSerializer serializer = ForgeRegistries.RECIPE_SERIALIZERS.getValue(serializerId); if (serializer == null || serializer == SERIALIZER) { throw new IllegalArgumentException("Invalid nested recipe serializer " + serializerId); } - IRecipe nested = serializer.fromNetwork(recipeId, buffer); + Recipe nested = serializer.fromNetwork(recipeId, buffer); if (!nested.getId().equals(id) || nested.getSerializer() == SERIALIZER) { throw new IllegalArgumentException("Invalid nested content-mode recipe " + id); } @@ -122,16 +122,16 @@ public IRecipe fromNetwork(ResourceLocation id, PacketBuffer buffer) { } @Override - public void toNetwork(PacketBuffer buffer, IRecipe value) { - IRecipe plain = value instanceof Shaped ? ((Shaped) value).plain : ((Shapeless) value).plain; + public void toNetwork(FriendlyByteBuf buffer, Recipe value) { + Recipe plain = value instanceof Shaped ? ((Shaped) value).plain : ((Shapeless) value).plain; buffer.writeResourceLocation(plain.getSerializer().getRegistryName()); buffer.writeResourceLocation(plain.getId()); writePlain(buffer, plain); } @SuppressWarnings({"rawtypes", "unchecked"}) - private static void writePlain(PacketBuffer buffer, IRecipe plain) { - ((IRecipeSerializer) plain.getSerializer()).toNetwork(buffer, plain); + private static void writePlain(FriendlyByteBuf buffer, Recipe plain) { + ((RecipeSerializer) plain.getSerializer()).toNetwork(buffer, plain); } } } diff --git a/src/main/java/zone/moddev/mc/basemetals/recipe/CrushingRecipe.java b/src/main/java/zone/moddev/mc/basemetals/recipe/CrushingRecipe.java index a41eeb497..756f2ba51 100644 --- a/src/main/java/zone/moddev/mc/basemetals/recipe/CrushingRecipe.java +++ b/src/main/java/zone/moddev/mc/basemetals/recipe/CrushingRecipe.java @@ -5,26 +5,26 @@ import zone.moddev.mc.basemetals.BaseMetals; import zone.moddev.mc.basemetals.config.ContentPolicy; -import net.minecraft.inventory.IInventory; -import net.minecraft.item.ItemStack; -import net.minecraft.item.crafting.IRecipe; -import net.minecraft.item.crafting.IRecipeSerializer; -import net.minecraft.item.crafting.Ingredient; -import net.minecraft.network.PacketBuffer; -import net.minecraft.util.NonNullList; -import net.minecraft.util.ResourceLocation; -import net.minecraft.world.World; -import net.minecraft.item.crafting.IRecipeType; +import net.minecraft.world.Container; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.world.item.crafting.RecipeSerializer; +import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.core.NonNullList; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.Level; +import net.minecraft.world.item.crafting.RecipeType; import net.minecraftforge.common.crafting.CraftingHelper; @net.minecraftforge.fml.common.Mod.EventBusSubscriber(modid = BaseMetals.MOD_ID, bus = net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus.MOD) -public final class CrushingRecipe implements IRecipe { - public static final IRecipeType TYPE = IRecipeType.register("basemetals:crushing"); - public static final IRecipeSerializer SERIALIZER = new Serializer("crushing"); - public static final IRecipeSerializer LEGACY_SMELTING_SERIALIZER = +public final class CrushingRecipe implements Recipe { + public static final RecipeType TYPE = RecipeType.register("basemetals:crushing"); + public static final RecipeSerializer SERIALIZER = new Serializer("crushing"); + public static final RecipeSerializer LEGACY_SMELTING_SERIALIZER = new LegacySmeltingRecipe.Serializer(); - public static final IRecipeSerializer PLATE_REPAIR_SERIALIZER = + public static final RecipeSerializer PLATE_REPAIR_SERIALIZER = new PlateRepairRecipe.Serializer(); private final ResourceLocation id; @@ -38,21 +38,21 @@ public CrushingRecipe(ResourceLocation id, Ingredient ingredient, ItemStack resu } @net.minecraftforge.eventbus.api.SubscribeEvent - public static void register(net.minecraftforge.event.RegistryEvent.Register> event) { + public static void register(net.minecraftforge.event.RegistryEvent.Register> event) { event.getRegistry().registerAll(SERIALIZER, LEGACY_SMELTING_SERIALIZER, PLATE_REPAIR_SERIALIZER, ContentCraftingRecipe.SERIALIZER); } - @Override public boolean matches(IInventory inventory, World world) { + @Override public boolean matches(Container inventory, Level world) { return ContentPolicy.active().allows(result.getItem().getRegistryName().toString()) && inventory.getContainerSize() > 0 && ingredient.test(inventory.getItem(0)); } - @Override public ItemStack assemble(IInventory inventory) { return result.copy(); } + @Override public ItemStack assemble(Container inventory) { return result.copy(); } @Override public boolean canCraftInDimensions(int width, int height) { return width * height >= 1; } @Override public ItemStack getResultItem() { return result.copy(); } @Override public ResourceLocation getId() { return id; } - @Override public IRecipeSerializer getSerializer() { return SERIALIZER; } - @Override public IRecipeType getType() { return TYPE; } + @Override public RecipeSerializer getSerializer() { return SERIALIZER; } + @Override public RecipeType getType() { return TYPE; } @Override public NonNullList getIngredients() { NonNullList ingredients = NonNullList.create(); ingredients.add(ingredient); @@ -60,18 +60,18 @@ public static void register(net.minecraftforge.event.RegistryEvent.Register> - implements IRecipeSerializer { + public static final class Serializer extends net.minecraftforge.registries.ForgeRegistryEntry> + implements RecipeSerializer { private Serializer(String name) { setRegistryName(BaseMetals.MOD_ID, name); } @Override public CrushingRecipe fromJson(ResourceLocation id, JsonObject json) { Ingredient ingredient = Ingredient.fromJson(json.get("ingredient")); ItemStack result = CraftingHelper.getItemStack(json.getAsJsonObject("result"), true); return new CrushingRecipe(id, ingredient, result); } - @Override public CrushingRecipe fromNetwork(ResourceLocation id, PacketBuffer buffer) { + @Override public CrushingRecipe fromNetwork(ResourceLocation id, FriendlyByteBuf buffer) { return new CrushingRecipe(id, Ingredient.fromNetwork(buffer), buffer.readItem()); } - @Override public void toNetwork(PacketBuffer buffer, CrushingRecipe recipe) { + @Override public void toNetwork(FriendlyByteBuf buffer, CrushingRecipe recipe) { recipe.ingredient.toNetwork(buffer); buffer.writeItem(recipe.result); } diff --git a/src/main/java/zone/moddev/mc/basemetals/recipe/LegacySmeltingRecipe.java b/src/main/java/zone/moddev/mc/basemetals/recipe/LegacySmeltingRecipe.java index 51571aafb..2b774a541 100644 --- a/src/main/java/zone/moddev/mc/basemetals/recipe/LegacySmeltingRecipe.java +++ b/src/main/java/zone/moddev/mc/basemetals/recipe/LegacySmeltingRecipe.java @@ -4,34 +4,34 @@ import zone.moddev.mc.basemetals.BaseMetals; import zone.moddev.mc.basemetals.config.ContentPolicy; -import net.minecraft.inventory.IInventory; -import net.minecraft.world.World; +import net.minecraft.world.Container; +import net.minecraft.world.level.Level; -import net.minecraft.item.ItemStack; -import net.minecraft.item.crafting.FurnaceRecipe; -import net.minecraft.item.crafting.IRecipeSerializer; -import net.minecraft.item.crafting.Ingredient; -import net.minecraft.network.PacketBuffer; -import net.minecraft.util.JSONUtils; -import net.minecraft.util.ResourceLocation; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.SmeltingRecipe; +import net.minecraft.world.item.crafting.RecipeSerializer; +import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.util.GsonHelper; +import net.minecraft.resources.ResourceLocation; import net.minecraftforge.common.crafting.CraftingHelper; /** Smelting recipes that can produce more than one item. */ -public final class LegacySmeltingRecipe extends FurnaceRecipe { +public final class LegacySmeltingRecipe extends SmeltingRecipe { public LegacySmeltingRecipe(ResourceLocation id, String group, Ingredient ingredient, ItemStack result, float experience, int cookingTime) { super(id, group, ingredient, result, experience, cookingTime); } - @Override public IRecipeSerializer getSerializer() { + @Override public RecipeSerializer getSerializer() { return CrushingRecipe.LEGACY_SMELTING_SERIALIZER; } - @Override public boolean matches(IInventory inventory, World world) { + @Override public boolean matches(Container inventory, Level world) { return allowed() && super.matches(inventory, world); } - @Override public ItemStack assemble(IInventory inventory) { + @Override public ItemStack assemble(Container inventory) { return allowed() ? super.assemble(inventory) : ItemStack.EMPTY; } @@ -41,22 +41,22 @@ private boolean allowed() { return ContentPolicy.active().allows(getResultItem().getItem().getRegistryName().toString()); } - public static final class Serializer extends net.minecraftforge.registries.ForgeRegistryEntry> - implements IRecipeSerializer { + public static final class Serializer extends net.minecraftforge.registries.ForgeRegistryEntry> + implements RecipeSerializer { public Serializer() { setRegistryName(BaseMetals.MOD_ID, "legacy_smelting"); } @Override public LegacySmeltingRecipe fromJson(ResourceLocation id, JsonObject json) { - String group = JSONUtils.getAsString(json, "group", ""); + String group = GsonHelper.getAsString(json, "group", ""); Ingredient ingredient = Ingredient.fromJson(json.get("ingredient")); - ItemStack result = CraftingHelper.getItemStack(JSONUtils.getAsJsonObject(json, "result"), true); + ItemStack result = CraftingHelper.getItemStack(GsonHelper.getAsJsonObject(json, "result"), true); return new LegacySmeltingRecipe(id, group, ingredient, result, - JSONUtils.getAsFloat(json, "experience", 0.0F), - JSONUtils.getAsInt(json, "cookingtime", 200)); + GsonHelper.getAsFloat(json, "experience", 0.0F), + GsonHelper.getAsInt(json, "cookingtime", 200)); } - @Override public LegacySmeltingRecipe fromNetwork(ResourceLocation id, PacketBuffer buffer) { + @Override public LegacySmeltingRecipe fromNetwork(ResourceLocation id, FriendlyByteBuf buffer) { return new LegacySmeltingRecipe(id, buffer.readUtf(32767), Ingredient.fromNetwork(buffer), buffer.readItem(), buffer.readFloat(), buffer.readVarInt()); } - @Override public void toNetwork(PacketBuffer buffer, LegacySmeltingRecipe recipe) { + @Override public void toNetwork(FriendlyByteBuf buffer, LegacySmeltingRecipe recipe) { buffer.writeUtf(recipe.getGroup()); recipe.getIngredients().get(0).toNetwork(buffer); buffer.writeItem(recipe.getResultItem()); diff --git a/src/main/java/zone/moddev/mc/basemetals/recipe/PlateRepairRecipe.java b/src/main/java/zone/moddev/mc/basemetals/recipe/PlateRepairRecipe.java index 52f68f476..d8592dd59 100644 --- a/src/main/java/zone/moddev/mc/basemetals/recipe/PlateRepairRecipe.java +++ b/src/main/java/zone/moddev/mc/basemetals/recipe/PlateRepairRecipe.java @@ -6,21 +6,21 @@ import zone.moddev.mc.basemetals.BaseMetals; import zone.moddev.mc.basemetals.config.ContentPolicy; -import net.minecraft.item.Items; -import net.minecraft.inventory.CraftingInventory; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.item.crafting.SpecialRecipe; -import net.minecraft.item.crafting.IRecipeSerializer; -import net.minecraft.item.crafting.Ingredient; -import net.minecraft.network.PacketBuffer; -import net.minecraft.util.JSONUtils; -import net.minecraft.util.NonNullList; -import net.minecraft.util.ResourceLocation; -import net.minecraft.world.World; +import net.minecraft.world.item.Items; +import net.minecraft.world.inventory.CraftingContainer; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.CustomRecipe; +import net.minecraft.world.item.crafting.RecipeSerializer; +import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.util.GsonHelper; +import net.minecraft.core.NonNullList; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.Level; import net.minecraftforge.registries.ForgeRegistries; -public final class PlateRepairRecipe extends SpecialRecipe { +public final class PlateRepairRecipe extends CustomRecipe { private final Item target; private final Ingredient plate; @@ -31,7 +31,7 @@ public PlateRepairRecipe(ResourceLocation id, Item target, Ingredient plate) { } @Override - public boolean matches(CraftingInventory inventory, World world) { + public boolean matches(CraftingContainer inventory, Level world) { if (!ContentPolicy.active().allows(target.getRegistryName().toString())) return false; ItemStack foundTarget = ItemStack.EMPTY; boolean foundPlate = false; @@ -56,7 +56,7 @@ public boolean matches(CraftingInventory inventory, World world) { } @Override - public ItemStack assemble(CraftingInventory inventory) { + public ItemStack assemble(CraftingContainer inventory) { if (!matches(inventory, null)) { return ItemStack.EMPTY; } @@ -95,25 +95,25 @@ public NonNullList getIngredients() { } @Override - public IRecipeSerializer getSerializer() { + public RecipeSerializer getSerializer() { return CrushingRecipe.PLATE_REPAIR_SERIALIZER; } - public static final class Serializer extends net.minecraftforge.registries.ForgeRegistryEntry> - implements IRecipeSerializer { + public static final class Serializer extends net.minecraftforge.registries.ForgeRegistryEntry> + implements RecipeSerializer { public Serializer() { setRegistryName(BaseMetals.MOD_ID, "plate_repair"); } @Override public PlateRepairRecipe fromJson(ResourceLocation id, JsonObject json) { - ResourceLocation targetId = new ResourceLocation(JSONUtils.getAsString(json, "target")); + ResourceLocation targetId = new ResourceLocation(GsonHelper.getAsString(json, "target")); Item target = ForgeRegistries.ITEMS.getValue(targetId); if (target == null || target == Items.AIR) throw new JsonSyntaxException("Unknown target " + targetId); - return new PlateRepairRecipe(id, target, Ingredient.fromJson(JSONUtils.getAsJsonObject(json, "plate"))); + return new PlateRepairRecipe(id, target, Ingredient.fromJson(GsonHelper.getAsJsonObject(json, "plate"))); } - @Override public PlateRepairRecipe fromNetwork(ResourceLocation id, PacketBuffer buffer) { + @Override public PlateRepairRecipe fromNetwork(ResourceLocation id, FriendlyByteBuf buffer) { Item target = ForgeRegistries.ITEMS.getValue(buffer.readResourceLocation()); if (target == null || target == Items.AIR) throw new IllegalStateException("Missing target"); return new PlateRepairRecipe(id, target, Ingredient.fromNetwork(buffer)); } - @Override public void toNetwork(PacketBuffer buffer, PlateRepairRecipe recipe) { + @Override public void toNetwork(FriendlyByteBuf buffer, PlateRepairRecipe recipe) { buffer.writeResourceLocation(recipe.target.getRegistryName()); recipe.plate.toNetwork(buffer); } diff --git a/src/main/java/zone/moddev/mc/basemetals/trade/BaseMetalsTrades.java b/src/main/java/zone/moddev/mc/basemetals/trade/BaseMetalsTrades.java index ada4f7508..556b6f264 100644 --- a/src/main/java/zone/moddev/mc/basemetals/trade/BaseMetalsTrades.java +++ b/src/main/java/zone/moddev/mc/basemetals/trade/BaseMetalsTrades.java @@ -1,11 +1,11 @@ package zone.moddev.mc.basemetals.trade; -import net.minecraft.entity.merchant.villager.VillagerProfession; -import net.minecraft.entity.merchant.villager.VillagerTrades; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.item.Items; -import net.minecraft.item.MerchantOffer; +import net.minecraft.world.entity.npc.VillagerProfession; +import net.minecraft.world.entity.npc.VillagerTrades; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.trading.MerchantOffer; import net.minecraftforge.event.village.VillagerTradesEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; @@ -16,7 +16,7 @@ import zone.moddev.mc.basemetals.material.MaterialCatalogue; import zone.moddev.mc.basemetals.material.MaterialDefinition; -/** Adds the old smith offers to the three Village & Pillage smith professions. */ +/** Adds the old smith offers to the three village smith professions. */ @Mod.EventBusSubscriber(modid = BaseMetals.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE) public final class BaseMetalsTrades { private BaseMetalsTrades() {} @@ -62,7 +62,7 @@ private static void addSale(VillagerTradesEvent event, int level, Item item, int event.getTrades().get(level).add(selling(item, count, emeralds, level)); } - public static VillagerTrades.ITrade selling(Item item, int count, int emeralds, int level) { + public static VillagerTrades.ItemListing selling(Item item, int count, int emeralds, int level) { return (merchant, random) -> { if (!BaseMetalsConfig.VILLAGER_TRADES.get() || !ContentPolicy.active().allows(item.getRegistryName().toString())) return null; diff --git a/src/main/resources/META-INF/coremods.json b/src/main/resources/META-INF/coremods.json index c84b17c4d..ed8f31b35 100644 --- a/src/main/resources/META-INF/coremods.json +++ b/src/main/resources/META-INF/coremods.json @@ -1,3 +1,3 @@ { - "basemetals_116_compatibility": "coremods/basemetals_116_compatibility.js" + "basemetals_117_compatibility": "coremods/basemetals_117_compatibility.js" } diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index 3a4ae89ed..1a18c233b 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -1,11 +1,11 @@ modLoader="javafml" -loaderVersion="[36,)" +loaderVersion="[37,38)" license="LGPL-2.1" issueTrackerURL="https://github.com/MinecraftModDevelopmentMods/BaseMetals/issues" [[mods]] modId="basemetals" -version="3.1.0.116051" +version="3.1.0.117011" displayName="Base Metals" displayURL="https://www.curseforge.com/minecraft/mc-mods/base-metals" authors="Cyanobacterium, jriwanek, dshadowwolf, GetDizzy611, SkyBlade1978, the MMD Team" @@ -14,20 +14,20 @@ description='''Adds real and fantasy metals, alloys, tools and armour. Crush ore [[dependencies.basemetals]] modId="orespawn" mandatory=true -versionRange="[4.1.0.116051,5.0.0)" +versionRange="[4.1.0.117011,5.0.0)" ordering="AFTER" side="BOTH" [[dependencies.basemetals]] modId="forge" mandatory=true -versionRange="[36,)" +versionRange="[37,38)" ordering="NONE" side="BOTH" [[dependencies.basemetals]] modId="minecraft" mandatory=true -versionRange="[1.16.5]" +versionRange="[1.17.1]" ordering="NONE" side="BOTH" diff --git a/src/main/resources/assets/basemetals/textures/item/adamantine_raw.png b/src/main/resources/assets/basemetals/textures/item/adamantine_raw.png new file mode 100644 index 0000000000000000000000000000000000000000..0cf48c4bacdbfdc9bdb9ad382a3dfb1a0552edde GIT binary patch literal 509 zcmVPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0g_2XK~y+T&5>U- z0s$1o`w%GGVr%b#+wv{RCPa8!VFa8We8kJIc&c;TBUFQ$9O z^uUai@y74*-aF^aJx8be*Ub84w9bCbj7P#trHY`{L9M$VnRX91YSjmvXNz>2Eh6Uj zlfAc}B$NG3wmKTE_g|QFdK-6VmndfnRIl7&dn$o}ZiW^jF|3Bhp~+z~>)FmCO@Tr* zfuyM5>ZpX$MwYl9hGd5qD9sc zu`;TX#1FR5Mf3RSV0j%8F+}O`6h+;BI^EjA;aUcvAwM$X8k*tCyzpH>;sv@nyP$bd z!EP)`b|Z(yU>Mqv2;RWLq-QbaRUjA#+P@%M1S+TVRJ*=~><|$Uyof6*@dlP^Hx)!( zKJ;}N5Oj*)-9K0wiO@+Vk4;rWVnihy!{O!O5#`)2jyH0caQVo}aGhIdV$!pe3TvM( zip_;)GevC<5^wM9-U+UoA=x4zzzgkv|8w2}6{NQ3@(ybT00000NkvXXu0mjf+VkFL literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/basemetals/textures/item/antimony_raw.png b/src/main/resources/assets/basemetals/textures/item/antimony_raw.png new file mode 100644 index 0000000000000000000000000000000000000000..037e46b4c8024ecb1919b2376b7a884bff2b5043 GIT binary patch literal 476 zcmV<20VDp2P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0dYx0K~y+T&5uh< z0$~(}(_fg(=nS?k@-hwDNLWJB-N7aT11qWycJ$@1*39_-Rb!3y>}t^Wuz*3 z)Y}b6?Itu@tuo2dnw?~-1vEP?q{@Y%Ae1;K6w6?c8!V>ZMFy)G$x;rl?=r%PD0aLe zwnZ;Y0!QS27o3eB$|geTbi^$1NSE`F+7h~NFWB;kunKnc`aMXUCW7$@(X#AhNv%}} zGoy!z7l=O=M7H*b`0W*3hi=dei<@E^v)ugT8l1qB`m=;arwN*2z*%evT!i2{a3fPG zz#lmq?#J)Gv3KMp$#M>-(IA zZ1n-x`8xzI!`MIZ4TO^`jG%Tpo$8TUPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0kTO%K~y+T&5_+} zQgIl^_ZM{8zf;R}$CosndN>_jrO`rGPLqyl%yeEf>_%cNn~>Imy%ZD$f&^QM;Y+ox za<(-s@>ac^gg#&52n9R7&|UjnJv_hP=g0GWe?Y8I%?lG z!Snnv>G@E?-f3zd)KU48!+t3bR<9+o&&U;|W|ZA}AmN)XYPT9_A2d+e$)j2>;_j@E z3}@72KX0S_Mha%Vwk`GkB3}Mfctf@77VUn1hnG*6z!}dX{bB{zt~k*7)kLkbJv^6j ztp>UERCk5%Hd&4&Ju%=)k6vh5ND1sAP7T10j|)g4={ zR3ejpj+JB#cS1g54Z7Ye>{gD%y`L?`VdYq?CS%CHeg%ikN`l)%7S4j(egRM7^S$yP zlJ}!je4B=a;}M+;fj1c-{z#|Qgw4WX^u)=*vdBfACDv#r-wiKj1UJr^^z?J@BT64K zNGwDtbW4DWQFf%>A!MVns}mgW6lsf%|L^<;2F&^nh^J1000000NkvXXu0mjflt}iO literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/basemetals/textures/item/coldiron_raw.png b/src/main/resources/assets/basemetals/textures/item/coldiron_raw.png new file mode 100644 index 0000000000000000000000000000000000000000..93ef81d6714ef00ee1666c7a32566b199004e3f7 GIT binary patch literal 506 zcmVPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0gp*UK~y+T&5=t> z0&x_@?NbF&K~b4nMB-QpskQ3?kz^Spj!9PP$`(DO2SH{*7(I!!p;h$2A|lEVOnPrx zm@qTV{}j$5au|B7>bJbybMCqKDir@3=WrC#+K+GyML-Wnz;XgKl=XKe{XT|p{3|$K zz~N~Ilfg@9sGgsj?Cw1yk>bGfz~agc3d$Nmdl@vfPrUWHw^3uTzezPY%r0D#wa6o4 zXBlLZD76+iy$tqZX|Vh&)*=s3>8wPm`#`C+2&>xArt@yfNIElLE0hroGP*hL31q3%S&3TT4VA9z>*;^OJ0<{907*qoM6N<$f?`tQMF0Q* literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/basemetals/textures/item/lead_raw.png b/src/main/resources/assets/basemetals/textures/item/lead_raw.png new file mode 100644 index 0000000000000000000000000000000000000000..c15d8c5c72bf87820b0d2994d2710ca09d85d32f GIT binary patch literal 498 zcmVPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0f$LMK~y+T&5-RY zLje@V$^Rqn-ZV*K%G((&Owgu4uO0zTAK z*O7bDMG{6138Nq>Bd1n_iJElU{4dN*x+uIILPvWSG-?i#QW-tvZXo2c=;<_*R3fM1 zVrE^O`-D~3kSr8);!R2 o?APCaqrO%}O*-B8#r+Fj0HsOVPO$@{z5oCK07*qoM6N<$f=prI6aWAK literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/basemetals/textures/item/mercury_raw.png b/src/main/resources/assets/basemetals/textures/item/mercury_raw.png new file mode 100644 index 0000000000000000000000000000000000000000..94b55e7215752e9b55b5ca7fe2e650c12ee437e8 GIT binary patch literal 502 zcmVPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0gFjQK~y+T&63MY z0s#=lgZ{C6R2EX1>zb8j3e~C7)y+0)$tWV|(7iB9@X!P5V9>+zP0^t;5Dl$M*GNxF zJ72M$N|PQC^g9lG-^_e74GsSqufS7v?b~=~1mrU}F!!)OGZ6(|l1fG7GuM;|A0x2g zgKK=042+SCtm$jBmr?;zxrlr=1;1|00(a_K7)+#J-Z7D(knWva_$9Bg;j z=c|aqgf#D6B#YUK^Vk{1PLJ?#cZ+D~5Y6gV_}AC4Fe}2u=xe927!8z8T_AjX0Ijxz zhV3I14~MWF@I$FkktohW(WIma&RHv#k2Ao5chYtC>agGYO#SE&R*MZgjQvBz<0cDH#{Ru^M^#A|>07*qoM6N<$f`0Vkp8x;= literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/basemetals/textures/item/nickel_raw.png b/src/main/resources/assets/basemetals/textures/item/nickel_raw.png new file mode 100644 index 0000000000000000000000000000000000000000..d1ac58c4dd6496286c37b41a2c92b63093cda645 GIT binary patch literal 512 zcmV+b0{{JqP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0hLKaK~y+T&5zwH zLva|#`72zxSFV+|&VJ7CYzHkbi-~eU+1XB`SYZx%Nur!_A+xZx6tz)8B<+Rd#)TUf z-ZrjgaxFLW`z9{bPA6}reD0p7=kq+zx1iwP;&!(Nq>cur?SGp@d;`g&6;?rvKVDKO zIU3o0_6*mzNvN|5nrmu`n(Xz^4(j5R>`2`m;^;Vn)rbmZ$PJIj!;}FpW_&&-id?bQ z$%9f8TUZ)HCVPg`3JT<|ZB!r|zEi7Ut8paRiC^{?A(R(5i_jOYP~!tB}|rG zOceR{x7uJRV+V;a`n(c2u3SI+R|oEt8; literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/basemetals/textures/item/platinum_raw.png b/src/main/resources/assets/basemetals/textures/item/platinum_raw.png new file mode 100644 index 0000000000000000000000000000000000000000..d4fa43c560bd9363d9009d32817862710c852c38 GIT binary patch literal 514 zcmV+d0{#7oP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0hdWcK~y+T&5+$M zf?*iO`HQ^8yk*YP+s86xHA;F_n2%XYHfF*J#(@pfETq}2B%9{Id>k1kIG~x2)*1(~ zm?L$P=egLM*{qdy=y!NOyMFie++}6|7L(OUTI~JEpO=K$?nE}5rMnjiX!KT^|6Y_P zOV43E{)og|2I13ttc4EYSq?xXk(VX`fcuvW2qBp8Y++z*0qRC8IvkVK*yf-HbMN1x z>*sguoW*dJdHw3}P_7TL=y5dI^U|1Q|=5Di=vOh$P(Suh~E03qThAZVLvum;e9(07*qoM6N<$ Ef(?4)YybcN literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/basemetals/textures/item/silver_raw.png b/src/main/resources/assets/basemetals/textures/item/silver_raw.png new file mode 100644 index 0000000000000000000000000000000000000000..9eccd035fdc13be0233b41c110b3d98d6d4e0345 GIT binary patch literal 505 zcmVPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0gg#TK~y+T&5(O5 z!*LYGy&UG}Qf_nGer&Uw`;;)Ywl=q=Sj(bNA`OWZV>XuZB9v?H@mtJ2%9}vV_dIDt znz{YO=f870&pFR?;^O`-7GoVXn~jL>{|Kw8o)}{|KN66eo&UQfO=bfa15SenxCjL? zF)|EsW)4Nq#l&i?Cotgb=n&_}0zB>s>gjZ%L|aO{q!0xX`PXjBw8hw1Uc$}QC4ev% z1AaK|c4VfDDN^5FUt-=n4UI-q8LfRIB{>y7&lFCA`*;lBVQ$9r>|n6351XsY)a`JP zS}ukm*8iKAuM=FIDi3v%_NXv@-helHag@k=D_JH25F63oPsl{r8Szn9C@I8dx zE#!#vK3;xLu}aAnd|v3vtI5{XMw}>#BI4u2JzDV3A~5TPR;7&X;1y8Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0h>ugK~y+T&5%h; zLID(o+x7z*^bJ0rnN~Jpv(GF`n+xTEHei$3Gb$*vGNeVrx}BAaN~CRnqg7C?>JPMu zAPO4b9zvl_^`u>W%X{xRoOAQ?{xv?k6JKY);^pB9m+2Ie(HN$@GxT+z6IpW5bvlLp zl{Lfy3g*V=A+jaeB&C9xj5?FLp|`b--e2F4h^!(uHbe8{3*_mRAuwWAbdfs3L3CZc zmY@;H>y|0Gv_j{}L%3|cC^uAMS`N}>>KO3}1zYJGh>WOi!fW-|+t@*TQo+mPGrFX1 zVhTA7b$Za}7{qXw7XqXIUc+baptJ2=^tTV8w#*76Z$dl}$_lw+9e9m^0p~E7BJR65 zgI{tYu^6G9(_4i63hFBAi7n(&W~{?G@_+Wf=OSF`l@CGeIZILN8yrs;j;BWU<~R8 z8MtDeETz??Enu>Tdai^#ZW*&9VVDgT^$NM*HJK;oi2kR103uJig8giT;Q#;t07*qo IM6N<$g3smSk^lez literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/basemetals/textures/item/tin_raw.png b/src/main/resources/assets/basemetals/textures/item/tin_raw.png new file mode 100644 index 0000000000000000000000000000000000000000..3990c0d250e92fd86fb88a8711b89a21fabf7bf3 GIT binary patch literal 532 zcmV+v0_**WP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0jWtuK~y+T&63Sa zDq$4H`#bI*)AS+1-AFY!evD%_QP3ArcXKC=DbvD~f)*`WWE9x9RQChY0?C5PLa1yL zlon`F=qj@8JjA#Nnk?GY56Mi_KwN^_?sQX{xaY&a(`r-&#lVG=|HwL*#QA49MNsiv$akjgNX@<+Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0eMM8K~y+T&5^w? z192F~`L7&F%R+j0ze8ICch|e~)_Pe=BP6&)qLWC3YR~&57Hb=oiePFCv=&P{RARuQ zQU=dAa-BGh+W3sm%lCPn@6*umZwbgU837f}_^;3um7dELBvWZ--~F9id_B%vG^9OjXjvrI5@Xp3p7gpq547tx=!ii3>8Wbh$XfW90}9B z8AWp|gBeYrSMIMb61R3Jb8?DYE{~<<7&JXZEo~BR3->rXzaT;M);8Br)z^Tmym>lx z1Vdr6&&Xs>5w~_QIvzoXq#>Y(YHu)L81Kc>6SCP$a4sHAE)T7(Zz3F-g)ulrlH|9| zv?n(@d#eb{hm} or --client-fixtures "); - } - - Path resources = Paths.get(args[0]); - boolean clientFixture = args.length == 3 && "--client-fixtures".equals(args[1]); - Path output = args.length == 3 ? Paths.get(args[2]) : resources; - - for (MaterialDefinition material : MaterialCatalogue.ALL) { - if (!material.hasOre()) continue; - - String blockName = material.name() + "_ore"; - String baseTexture = baseTexture(material.name()); - String overlayTexture = "basemetals:block/ore_overlays/" + blockName; - Path overlay = resources.resolve("assets/basemetals/textures/block/ore_overlays/" - + blockName + ".png"); - - boolean hasOverlay = Files.isRegularFile(overlay); - JsonObject model = clientFixture && !hasOverlay - ? createOverlayOre(baseTexture, "minecraft:block/glass") - : modelFor(blockName, baseTexture, overlayTexture, hasOverlay); - - write(output.resolve("assets/basemetals/models/block/" + blockName + ".json"), model); - } - - if (clientFixture) { - // The client probe enables these host replacements in a test-only resource pack. - copyHostFixture(resources, output, "tin", "stone"); - copyHostFixture(resources, output, "coldiron", "netherrack"); - copyHostFixture(resources, output, "starsteel", "end_stone"); - } - } - - public static String baseTexture(String material) { - if ("adamantine".equals(material) || "coldiron".equals(material)) { - return "minecraft:block/netherrack"; - } - if ("starsteel".equals(material)) return "minecraft:block/end_stone"; - - return "minecraft:block/stone"; - } - - public static JsonObject modelFor(String blockName, String baseTexture, - String overlayTexture, boolean hasOverlay) { - if (hasOverlay) return createOverlayOre(baseTexture, overlayTexture); - - // Use the original texture when an overlay is absent. - JsonObject model = new JsonObject(); - model.addProperty("parent", "block/cube_all"); - JsonObject textures = new JsonObject(); - textures.addProperty("all", "basemetals:block/" + blockName); - model.add("textures", textures); - return model; - } - - public static JsonObject createOverlayOre(String baseTexture, String overlayTexture) { - JsonObject model = new JsonObject(); - model.addProperty("parent", "minecraft:block/block"); - - JsonObject textures = new JsonObject(); - textures.addProperty("particle", baseTexture); - textures.addProperty("base", baseTexture); - textures.addProperty("overlay", overlayTexture); - model.add("textures", textures); - - JsonArray elements = new JsonArray(); - - // Element 1: base block (Stone, Netherrack or End Stone). - elements.add(element(0, 16, "#base")); - - // Element 2: a small gap reduces depth fighting when viewed from a distance. - elements.add(element(-OVERLAY_OFFSET, 16 + OVERLAY_OFFSET, "#overlay")); - - model.add("elements", elements); - return model; - } - - private static JsonObject element(float from, float to, String texture) { - JsonObject element = new JsonObject(); - element.add("from", point(from)); - element.add("to", point(to)); - - JsonObject faces = new JsonObject(); - for (String direction : FACES) { - JsonObject face = new JsonObject(); - face.addProperty("texture", texture); - face.addProperty("cullface", direction); - faces.add(direction, face); - } - - element.add("faces", faces); - return element; - } - - private static JsonArray point(float coordinate) { - JsonArray point = new JsonArray(); - for (int axis = 0; axis < 3; axis++) point.add(coordinate); - return point; - } - - private static void write(Path file, JsonObject model) throws IOException { - byte[] contents = (GSON.toJson(model) + "\n").getBytes(StandardCharsets.UTF_8); - if (Files.isRegularFile(file) && Arrays.equals(contents, Files.readAllBytes(file))) return; - - Files.createDirectories(file.getParent()); - Files.write(file, contents); - } - - private static void copyHostFixture(Path resources, Path output, String ore, String host) - throws IOException { - Path target = output.resolve("assets/minecraft/textures/block/" + host + ".png"); - Files.createDirectories(target.getParent()); - Files.copy(resources.resolve("assets/basemetals/textures/block/" + ore + "_ore.png"), - target, StandardCopyOption.REPLACE_EXISTING); - } -} diff --git a/src/test/java/zone/moddev/mc/basemetals/MechanicsContractTest.java b/src/test/java/zone/moddev/mc/basemetals/MechanicsContractTest.java index 6fd003c17..531db1da7 100644 --- a/src/test/java/zone/moddev/mc/basemetals/MechanicsContractTest.java +++ b/src/test/java/zone/moddev/mc/basemetals/MechanicsContractTest.java @@ -21,7 +21,7 @@ void historicalAliasesResolveToTheirPreservedIds() { assertEquals("adamantine_door", MissingMappings.itemTargetPath("adamantine_door_item")); assertEquals("minecraft:iron_nugget", MissingMappings.itemTargetId("iron_nugget").toString()); assertEquals("mercury", MissingMappings.blockTargetPath( - new net.minecraft.util.ResourceLocation("mmdlib", "liquid_mercury").getPath())); + new net.minecraft.resources.ResourceLocation("mmdlib", "liquid_mercury").getPath())); assertEquals("double_diamond_slab", MissingMappings.blockTargetPath("double_diamond_slab")); assertEquals("human_detector", MissingMappings.blockTargetPath("human_detector")); assertEquals("emerald_bow", MissingMappings.itemTargetPath("emerald_bow")); @@ -47,9 +47,9 @@ void mapsOnlyKnownVanillaNamesRetiredIn114() { {"dandelion_yellow", "yellow_dye"}}; for (String[] alias : aliases) { assertEquals("minecraft:" + alias[1], MissingMappings.vanilla114Target( - new net.minecraft.util.ResourceLocation("minecraft", alias[0])).toString()); + new net.minecraft.resources.ResourceLocation("minecraft", alias[0])).toString()); } - assertNull(MissingMappings.vanilla114Target(new net.minecraft.util.ResourceLocation("anothermod", "sign"))); - assertNull(MissingMappings.vanilla114Target(new net.minecraft.util.ResourceLocation("minecraft", "unknown"))); + assertNull(MissingMappings.vanilla114Target(new net.minecraft.resources.ResourceLocation("anothermod", "sign"))); + assertNull(MissingMappings.vanilla114Target(new net.minecraft.resources.ResourceLocation("minecraft", "unknown"))); } } diff --git a/src/test/java/zone/moddev/mc/basemetals/Native116ContractTest.java b/src/test/java/zone/moddev/mc/basemetals/Native117ContractTest.java similarity index 75% rename from src/test/java/zone/moddev/mc/basemetals/Native116ContractTest.java rename to src/test/java/zone/moddev/mc/basemetals/Native117ContractTest.java index cbf17b2ac..ad786b920 100644 --- a/src/test/java/zone/moddev/mc/basemetals/Native116ContractTest.java +++ b/src/test/java/zone/moddev/mc/basemetals/Native117ContractTest.java @@ -11,16 +11,16 @@ import java.util.Properties; import org.junit.jupiter.api.Test; -class Native116ContractTest { +class Native117ContractTest { @Test - void targetsForge36InEveryModDescriptor() throws Exception { + void targetsForge37InEveryModDescriptor() throws Exception { for (String sourceSet : new String[] {"main", "integrationTest", "clientIntegrationTest"}) { String metadata = source("src/" + sourceSet + "/resources/META-INF/mods.toml"); - assertTrue(metadata.contains("loaderVersion=\"[36,)\""), sourceSet); + assertTrue(metadata.contains("loaderVersion=\"[37,38)\""), sourceSet); } String metadata = source("src/main/resources/META-INF/mods.toml"); - assertTrue(metadata.contains("versionRange=\"[36,)\"")); - assertTrue(metadata.contains("versionRange=\"[1.16.5]\"")); + assertTrue(metadata.contains("versionRange=\"[37,38)\"")); + assertTrue(metadata.contains("versionRange=\"[1.17.1]\"")); } @Test @@ -28,7 +28,7 @@ void registersBothProjectileTypesAndNativeRenderLayers() throws Exception { String setup = source("src/main/java/zone/moddev/mc/basemetals/client/ClientSetup.java"); assertTrue(setup.contains("ModEntities.CUSTOM_ARROW.get()")); assertTrue(setup.contains("ModEntities.CUSTOM_BOLT.get()")); - assertTrue(setup.contains("RenderTypeLookup.setRenderLayer")); + assertTrue(setup.contains("ItemBlockRenderTypes.setRenderLayer")); assertTrue(setup.contains("RenderType.cutoutMipped()")); assertTrue(setup.contains("RenderType.translucent()")); assertFalse(setup.contains("registerEntityRenderingHandler(MaterialProjectile.class")); @@ -47,10 +47,10 @@ void pinsThePublishedOreSpawnRelease() throws Exception { } assertEquals("release", properties.getProperty("orespawn_dependency_mode")); - assertEquals("4.1.0.116051", properties.getProperty("orespawn_version")); + assertEquals("4.1.0.117011", properties.getProperty("orespawn_version")); assertEquals("245586", properties.getProperty("orespawn_curse_project_id")); - assertEquals("9080646", properties.getProperty("orespawn_curse_file_id")); - assertEquals("CDF59D83F191C5FBCD8921228DB577066A63A8FEB25CA79DB4EAEEA32D32DB04", + assertEquals("9088186", properties.getProperty("orespawn_curse_file_id")); + assertEquals("1BDEDCBB179CB5A3B169E5C8A6B301E3888AE15B94108B0AEC627D705CFAD833", properties.getProperty("orespawn_sha256")); assertTrue(source("build.gradle").contains("curse.maven:${orespawnModule}:${orespawn_curse_file_id}")); assertTrue(source("build.gradle").contains("zone.moddev.mc.orespawn:OreSpawn:${orespawn_version}")); @@ -77,6 +77,17 @@ void samplesOresWithANonzeroFixedWorldSeed() throws Exception { assertTrue(probe.contains("worldSeed != SAMPLE_WORLD_SEED")); } + @Test + void guardsThePermissionCheckUsedByDirectOreWrites() throws Exception { + String coremod = source("src/main/resources/coremods/basemetals_117_compatibility.js"); + String guard = coremod.substring(coremod.indexOf("'basemetals_legacy_worldgen_guard'"), + coremod.indexOf("'basemetals_durable_anvils'")); + + assertTrue(guard.contains("'(Lnet/minecraft/core/BlockPos;)Z'")); + assertTrue(guard.contains("'shouldBlockWorldgenWrite'")); + assertFalse(guard.contains("STATE + 'II)Z'")); + } + private static String source(String path) throws Exception { return new String(Files.readAllBytes(Paths.get(path)), StandardCharsets.UTF_8); } diff --git a/src/test/java/zone/moddev/mc/basemetals/config/ContentModeDataTest.java b/src/test/java/zone/moddev/mc/basemetals/config/ContentModeDataTest.java index 4bd7db7a6..dde955fd4 100644 --- a/src/test/java/zone/moddev/mc/basemetals/config/ContentModeDataTest.java +++ b/src/test/java/zone/moddev/mc/basemetals/config/ContentModeDataTest.java @@ -34,6 +34,7 @@ private static void assertDigest(Path directory, JsonObject expected) throws Exc try (Stream paths = Files.walk(directory)) { files = paths.filter(p -> p.toString().endsWith(".json")) .filter(p -> !p.getFileName().toString().equals("ancient_debris_crushing.json")) + .filter(p -> !p.getFileName().toString().matches(".*_raw_(crushing|smelting|blasting)\\.json")) .sorted(java.util.Comparator.comparing(p -> directory.relativize(p).toString().replace('\\', '/'))) .collect(Collectors.toList()); } diff --git a/src/test/java/zone/moddev/mc/basemetals/config/ContentPolicyTest.java b/src/test/java/zone/moddev/mc/basemetals/config/ContentPolicyTest.java index 0110e9b13..2a58f2215 100644 --- a/src/test/java/zone/moddev/mc/basemetals/config/ContentPolicyTest.java +++ b/src/test/java/zone/moddev/mc/basemetals/config/ContentPolicyTest.java @@ -42,7 +42,7 @@ private static boolean expectedLow(String material, MaterialForm form) { case CRACKHAMMER: return FULL.contains(material) || names("diamond stone wood").contains(material); default: if (!material.equals("mercury")) return true; - return form == MaterialForm.ORE || form == MaterialForm.POWDER || form == MaterialForm.SMALLPOWDER + return form == MaterialForm.ORE || form == MaterialForm.RAW || form == MaterialForm.POWDER || form == MaterialForm.SMALLPOWDER || form == MaterialForm.FLUID || form == MaterialForm.INGOT; } } diff --git a/src/test/java/zone/moddev/mc/basemetals/data/OreOverlayModelTest.java b/src/test/java/zone/moddev/mc/basemetals/data/OreOverlayModelTest.java index 2de86813a..b81d489e2 100644 --- a/src/test/java/zone/moddev/mc/basemetals/data/OreOverlayModelTest.java +++ b/src/test/java/zone/moddev/mc/basemetals/data/OreOverlayModelTest.java @@ -4,156 +4,60 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Map; -import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; - import zone.moddev.mc.basemetals.material.MaterialCatalogue; import zone.moddev.mc.basemetals.material.MaterialDefinition; class OreOverlayModelTest { - @TempDir Path resources; - - @Test - void kirisTwoLayerGeometryKeepsTheOffsetAndAllSixCullFaces() { - JsonObject model = BMBlockStateProvider.createOverlayOre( - "minecraft:block/stone", "basemetals:block/ore_overlays/tin_ore"); - - assertEquals("minecraft:block/block", model.get("parent").getAsString()); - JsonObject textures = model.getAsJsonObject("textures"); - assertEquals("minecraft:block/stone", textures.get("particle").getAsString()); - assertEquals("minecraft:block/stone", textures.get("base").getAsString()); - assertEquals("basemetals:block/ore_overlays/tin_ore", textures.get("overlay").getAsString()); - - JsonArray elements = model.getAsJsonArray("elements"); - assertEquals(2, elements.size()); - assertElement(elements.get(0).getAsJsonObject(), 0, 16, "#base"); - assertElement(elements.get(1).getAsJsonObject(), -0.05, 16.05, "#overlay"); - } - @Test - void everyOreUsesItsVanillaHostTexture() { + void allThirteenNativeModelsKeepKirisTwoLayerGeometry() throws Exception { int ores = 0; for (MaterialDefinition material : MaterialCatalogue.ALL) { if (!material.hasOre()) continue; ores++; - String expected = "minecraft:block/stone"; + String name = material.name() + "_ore"; + String host = "minecraft:block/stone"; if ("adamantine".equals(material.name()) || "coldiron".equals(material.name())) { - expected = "minecraft:block/netherrack"; + host = "minecraft:block/netherrack"; } else if ("starsteel".equals(material.name())) { - expected = "minecraft:block/end_stone"; + host = "minecraft:block/end_stone"; } - assertEquals(expected, BMBlockStateProvider.baseTexture(material.name())); - JsonObject model = BMBlockStateProvider.modelFor(material.name() + "_ore", expected, - "basemetals:block/ore_overlays/" + material.name() + "_ore", true); - assertEquals(expected, model.getAsJsonObject("textures").get("base").getAsString()); - } - - assertEquals(13, ores); - } - - @Test - void shippedOreModelsUseKirisOverlays() throws Exception { - Path mainResources = Paths.get("src/main/resources"); - int ores = 0; - - for (MaterialDefinition material : MaterialCatalogue.ALL) { - if (!material.hasOre()) continue; - ores++; - - String name = material.name() + "_ore"; - Path texture = mainResources.resolve("assets/basemetals/textures/block/ore_overlays/" + name + ".png"); - assertTrue(Files.isRegularFile(texture), name + " overlay is in the wrong directory or missing"); - - Path modelPath = mainResources.resolve("assets/basemetals/models/block/" + name + ".json"); - JsonObject model = new JsonParser().parse(new String(Files.readAllBytes(modelPath), - StandardCharsets.UTF_8)).getAsJsonObject(); - - assertEquals(BMBlockStateProvider.baseTexture(material.name()), - model.getAsJsonObject("textures").get("base").getAsString(), name); - assertEquals("basemetals:block/ore_overlays/" + name, - model.getAsJsonObject("textures").get("overlay").getAsString(), name); - assertEquals(2, model.getAsJsonArray("elements").size(), name); + Path modelPath = Paths.get("src/generated/resources/assets/basemetals/models/block/" + name + ".json"); + JsonObject model = new JsonParser().parse(Files.readString(modelPath)).getAsJsonObject(); + assertEquals("minecraft:block/block", model.get("parent").getAsString()); + JsonObject textures = model.getAsJsonObject("textures"); + assertEquals(host, textures.get("base").getAsString()); + assertEquals(host, textures.get("particle").getAsString()); + assertEquals("basemetals:block/ore_overlays/" + name, textures.get("overlay").getAsString()); + assertEquals(2, model.getAsJsonArray("elements").size()); assertElement(model.getAsJsonArray("elements").get(0).getAsJsonObject(), 0, 16, "#base"); assertElement(model.getAsJsonArray("elements").get(1).getAsJsonObject(), -0.05, 16.05, "#overlay"); - } + assertTrue(Files.isRegularFile(Paths.get("src/main/resources/assets/basemetals/textures/block/ore_overlays/" + name + ".png"))); + assertFalse(Files.exists(Paths.get("src/main/resources/assets/basemetals/models/block/" + name + ".json")), + "Ore models must have one authoritative location"); + } assertEquals(13, ores); } @Test - void missingOverlaysKeepTheCurrentArtworkWithoutMissingTextureReferences() { - JsonObject model = BMBlockStateProvider.modelFor("tin_ore", "minecraft:block/stone", - "basemetals:block/ore_overlays/tin_ore", false); - - assertEquals("block/cube_all", model.get("parent").getAsString()); - assertEquals("basemetals:block/tin_ore", model.getAsJsonObject("textures").get("all").getAsString()); - assertFalse(model.has("elements")); - assertFalse(model.toString().contains("ore_overlays")); - } - - @Test - void generationEnablesOnlySuppliedOverlaysAndCanReturnToTheLegacyModel() throws Exception { - Path overlay = resources.resolve("assets/basemetals/textures/block/ore_overlays/tin_ore.png"); - Files.createDirectories(overlay.getParent()); - Files.copy(Paths.get("src/main/resources/assets/basemetals/textures/block/tin_ore.png"), overlay); - - BMBlockStateProvider.main(new String[] {resources.toString()}); - assertTrue(readModel("tin_ore").has("elements")); - assertFalse(readModel("copper_ore").has("elements")); - byte[] first = Files.readAllBytes(modelPath("tin_ore")); - BMBlockStateProvider.main(new String[] {resources.toString()}); - org.junit.jupiter.api.Assertions.assertArrayEquals(first, Files.readAllBytes(modelPath("tin_ore"))); - - Files.delete(overlay); - BMBlockStateProvider.main(new String[] {resources.toString()}); - assertFalse(readModel("tin_ore").has("elements")); - } - - @Test - void generationRepairsInvalidJsonAndKeepsLineEndingsStable() throws Exception { - BMBlockStateProvider.main(new String[] {resources.toString()}); - byte[] expected = Files.readAllBytes(modelPath("tin_ore")); - - Files.write(modelPath("tin_ore"), "{unfinished model".getBytes(StandardCharsets.UTF_8)); - BMBlockStateProvider.main(new String[] {resources.toString()}); - org.junit.jupiter.api.Assertions.assertArrayEquals(expected, Files.readAllBytes(modelPath("tin_ore"))); - - String windowsModel = new String(expected, StandardCharsets.UTF_8).replace("\n", "\r\n"); - Files.write(modelPath("tin_ore"), windowsModel.getBytes(StandardCharsets.UTF_8)); - BMBlockStateProvider.main(new String[] {resources.toString()}); - org.junit.jupiter.api.Assertions.assertArrayEquals(expected, Files.readAllBytes(modelPath("tin_ore"))); - } - - @Test - void verificationOutputDoesNotRewriteTheSourceModels() throws Exception { - BMBlockStateProvider.main(new String[] {resources.toString()}); - byte[] original = Files.readAllBytes(modelPath("tin_ore")); - - Path overlay = resources.resolve("assets/basemetals/textures/block/ore_overlays/tin_ore.png"); - Files.createDirectories(overlay.getParent()); - Files.copy(Paths.get("src/main/resources/assets/basemetals/textures/block/ore_overlays/tin_ore.png"), overlay); - - Path output = resources.resolve("verification-output"); - BMBlockStateProvider.main(new String[] {resources.toString(), "--output", output.toString()}); - - org.junit.jupiter.api.Assertions.assertArrayEquals(original, Files.readAllBytes(modelPath("tin_ore"))); - JsonObject generated = new JsonParser().parse(new String(Files.readAllBytes(output.resolve( - "assets/basemetals/models/block/tin_ore.json")), StandardCharsets.UTF_8)).getAsJsonObject(); - assertEquals("basemetals:block/ore_overlays/tin_ore", - generated.getAsJsonObject("textures").get("overlay").getAsString()); - assertFalse(Files.exists(output.resolve("assets/minecraft")), "Verification must not add client fixtures"); + void providerUsesForgeAndRemainsOutsideTheProductionSourceSet() throws Exception { + String provider = Files.readString(Paths.get("src/dataGenerator/java/zone/moddev/mc/basemetals/data/BMBlockStateProvider.java")); + assertTrue(provider.contains("extends BlockStateProvider")); + assertTrue(provider.contains(".allFaces((direction, face) -> face.texture(\"#overlay\").cullface(direction))")); + assertTrue(provider.contains("@author KiriCattus")); + assertFalse(Files.isRegularFile(Paths.get("src/modelGenerator/java/zone/moddev/mc/basemetals/data/BMBlockStateProvider.java"))); + assertFalse(Files.exists(Paths.get("src/main/java/zone/moddev/mc/basemetals/data/BMBlockStateProvider.java"))); } private static void assertElement(JsonObject element, double from, double to, String texture) { @@ -161,7 +65,6 @@ private static void assertElement(JsonObject element, double from, double to, St assertEquals(from, element.getAsJsonArray("from").get(axis).getAsDouble(), 0.000001); assertEquals(to, element.getAsJsonArray("to").get(axis).getAsDouble(), 0.000001); } - JsonObject faces = element.getAsJsonObject("faces"); assertEquals(6, faces.entrySet().size()); for (Map.Entry face : faces.entrySet()) { @@ -169,13 +72,4 @@ private static void assertElement(JsonObject element, double from, double to, St assertEquals(face.getKey(), face.getValue().getAsJsonObject().get("cullface").getAsString()); } } - - private Path modelPath(String name) { - return resources.resolve("assets/basemetals/models/block/" + name + ".json"); - } - - private JsonObject readModel(String name) throws Exception { - return new JsonParser().parse(new String(Files.readAllBytes(modelPath(name)), - StandardCharsets.UTF_8)).getAsJsonObject(); - } } diff --git a/src/test/java/zone/moddev/mc/basemetals/data/RawMaterialResourceTest.java b/src/test/java/zone/moddev/mc/basemetals/data/RawMaterialResourceTest.java new file mode 100644 index 000000000..7517476b8 --- /dev/null +++ b/src/test/java/zone/moddev/mc/basemetals/data/RawMaterialResourceTest.java @@ -0,0 +1,85 @@ +package zone.moddev.mc.basemetals.data; + +import static org.junit.jupiter.api.Assertions.*; + +import java.awt.image.BufferedImage; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.stream.Stream; +import javax.imageio.ImageIO; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.junit.jupiter.api.Test; + +/** Keeps raw metals separate from the powders used to blend alloys. */ +class RawMaterialResourceTest { + private static final Path GENERATED = Path.of("src/generated/resources"); + private static final Path MAIN = Path.of("src/main/resources"); + private static final List METALS = List.of("adamantine", "antimony", "bismuth", "coldiron", + "lead", "mercury", "nickel", "platinum", "silver", "starsteel", "tin", "zinc"); + + @Test + void allRawMetalsHaveOneToOneProcessingAndDistinctTags() throws Exception { + for (String metal : METALS) { + JsonObject crushing = read("data/basemetals/recipes/" + metal + "_raw_crushing.json"); + assertEquals("basemetals:" + metal + "_powder", crushing.getAsJsonObject("result").get("item").getAsString()); + assertEquals(1, crushing.getAsJsonObject("result").get("count").getAsInt()); + + for (String cooking : List.of("smelting", "blasting")) { + JsonObject recipe = read("data/basemetals/recipes/" + metal + "_raw_" + cooking + ".json"); + assertEquals("basemetals:" + metal + "_ingot", recipe.get("result").getAsString()); + } + + String rawTag = Files.readString(GENERATED.resolve("data/forge/tags/items/raw_materials/" + metal + ".json")); + assertTrue(rawTag.contains("basemetals:" + metal + "_raw")); + assertFalse(Files.readString(GENERATED.resolve("data/forge/tags/items/dusts/" + metal + ".json")).contains("_raw")); + } + + try (Stream recipes = Files.list(GENERATED.resolve("data/basemetals/recipes"))) { + for (Path recipe : recipes.filter(file -> file.getFileName().toString().contains("blend")).toList()) { + assertFalse(Files.readString(recipe).contains("raw_materials"), recipe.toString()); + assertFalse(Files.readString(recipe).contains("_raw"), recipe.toString()); + } + } + } + + @Test + void allRawSpritesAreSmallTransparentItems() throws Exception { + for (String metal : METALS) { + BufferedImage image = ImageIO.read(MAIN.resolve("assets/basemetals/textures/item/" + metal + "_raw.png").toFile()); + assertEquals(16, image.getWidth(), metal); + assertEquals(16, image.getHeight(), metal); + assertTrue(image.getColorModel().hasAlpha(), metal); + int visible = 0; + int transparent = 0; + for (int y = 0; y < 16; y++) { + for (int x = 0; x < 16; x++) { + if ((image.getRGB(x, y) >>> 24) == 0) transparent++; + else visible++; + } + } + assertTrue(visible > 30 && transparent > 30, metal); + } + } + + @Test + void everyLocaleNamesAllTwelveRawItems() throws Exception { + try (Stream paths = Files.list(GENERATED.resolve("assets/basemetals/lang"))) { + List languages = paths.filter(file -> file.toString().endsWith(".json")).toList(); + assertEquals(18, languages.size()); + for (Path language : languages) { + JsonObject text = new JsonParser().parse(Files.readString(language)).getAsJsonObject(); + for (String metal : METALS) { + assertTrue(text.has("item.basemetals." + metal + "_raw"), language + " " + metal); + assertFalse(text.get("item.basemetals." + metal + "_raw").getAsString().isBlank()); + } + } + } + } + + private static JsonObject read(String relative) throws Exception { + return new JsonParser().parse(Files.readString(GENERATED.resolve(relative))).getAsJsonObject(); + } +} diff --git a/src/test/java/zone/moddev/mc/basemetals/data/RecipeRegressionTest.java b/src/test/java/zone/moddev/mc/basemetals/data/RecipeRegressionTest.java index 0e808489d..0a64d779b 100644 --- a/src/test/java/zone/moddev/mc/basemetals/data/RecipeRegressionTest.java +++ b/src/test/java/zone/moddev/mc/basemetals/data/RecipeRegressionTest.java @@ -87,7 +87,10 @@ void everyCraftingRecipeHasThe112MaterialDiscoveryTrigger() throws Exception { String[] expected = discovery.get(material).split("=", 2); JsonObject predicate = acquired.getAsJsonObject("conditions").getAsJsonArray("items") .get(0).getAsJsonObject(); - assertEquals(expected[1], predicate.get(expected[0]).getAsString(), name); + String actual = expected[0].equals("item") + ? predicate.getAsJsonArray("items").get(0).getAsString() + : predicate.get(expected[0]).getAsString(); + assertEquals(expected[1], actual, name); assertEquals(1, advancement.getAsJsonArray("requirements").size(), name); assertTrue(advancement.getAsJsonArray("requirements").get(0).getAsJsonArray().toString() .contains("\"has_material\""), "Material discovery is not an alternative for " + name); diff --git a/src/test/java/zone/moddev/mc/basemetals/data/ResourceIntegrityTest.java b/src/test/java/zone/moddev/mc/basemetals/data/ResourceIntegrityTest.java index 5d18767a8..f18876d9c 100644 --- a/src/test/java/zone/moddev/mc/basemetals/data/ResourceIntegrityTest.java +++ b/src/test/java/zone/moddev/mc/basemetals/data/ResourceIntegrityTest.java @@ -34,7 +34,7 @@ import com.google.gson.JsonParser; import org.junit.jupiter.api.Test; -/** Resource contract for the flattened Minecraft 1.16.5 data pack. */ +/** Resource contract for the Minecraft 1.17.1 data pack. */ class ResourceIntegrityTest { private static final Path MAIN = Paths.get("src", "main", "resources"); private static final Path GENERATED = Paths.get("src", "generated", "resources"); @@ -60,9 +60,9 @@ void manifestHasModelsAndTranslationsForEveryRegisteredId() throws Exception { Set blocks = strings(manifest.getAsJsonArray("blocks")); Set items = strings(manifest.getAsJsonArray("items")); Set fluids = strings(manifest.getAsJsonArray("fluids")); - assertEquals("Base Metals 1.16.5 catalogue", manifest.get("source").getAsString()); + assertEquals("Base Metals 1.17.1 catalogue", manifest.get("source").getAsString()); assertEquals(360, blocks.size()); - assertEquals(1115, items.size()); + assertEquals(1127, items.size()); assertEquals(72, fluids.size()); assertEquals(2, manifest.getAsJsonArray("entities").size()); assertTrue(manifest.getAsJsonArray("loot_modifier_serializers").size() == 0); @@ -168,7 +168,8 @@ void modelsUseFlattenedNamesAndWallsHaveLowAndTallSides() throws Exception { @Test void fluidBucketModelsUseTheForgeFluidRenderer() throws Exception { - Set buckets = strings(manifest().getAsJsonArray("new_items")); + Set buckets = strings(manifest().getAsJsonArray("new_items")).stream() + .filter(id -> id.endsWith("_bucket")).collect(Collectors.toSet()); assertEquals(36, buckets.size(), "Unexpected fluid bucket count"); for (String bucket : buckets) { String id = path(bucket); @@ -183,7 +184,8 @@ void fluidBucketModelsUseTheForgeFluidRenderer() throws Exception { @Test void filledBucketNamesDescribeTheirContentsInEveryLocale() throws Exception { - Set buckets = strings(manifest().getAsJsonArray("new_items")); + Set buckets = strings(manifest().getAsJsonArray("new_items")).stream() + .filter(id -> id.endsWith("_bucket")).collect(Collectors.toSet()); List languages = files(GENERATED.resolve("assets/basemetals/lang"), ".json"); assertEquals(18, languages.size()); @@ -224,12 +226,9 @@ void transparentBlockTexturesRemainInKnownCutoutFamilies() throws Exception { for (Path texture : files(MAIN.resolve("assets/basemetals/textures/block"), ".png")) { if (hasTransparentPixel(texture)) transparent.add(texture.getFileName().toString()); } - Set missedByJava8ImageIo = new LinkedHashSet(expected); - missedByJava8ImageIo.removeAll(transparent); - assertEquals(new LinkedHashSet(Arrays.asList("zinc_bars.png", "zinc_door_upper.png")), - missedByJava8ImageIo, - "Unexpected cutout textures lost transparency; the two indexed Zinc PNGs are rendered correctly " - + "but Java 8 ImageIO does not expose their tRNS alpha channel"); + Set missingAlpha = new LinkedHashSet(expected); + missingAlpha.removeAll(transparent); + assertTrue(missingAlpha.isEmpty(), "Cutout textures lost transparency: " + missingAlpha); } @Test @@ -348,7 +347,7 @@ void everyHistoricalPlateRepairRecipeUsesTheTypedSerializer() throws Exception { } @Test - void targetTagsContainNoPost113VanillaContent() throws Exception { + void targetTagsUseNative117CopperAndMiningRules() throws Exception { Set arrows = strings(read(resource("data/minecraft/tags/items/arrows.json")) .getAsJsonObject().getAsJsonArray("values")); assertTrue(arrows.contains("basemetals:tin_arrow")); @@ -362,9 +361,10 @@ void targetTagsContainNoPost113VanillaContent() throws Exception { } Set copperBlocks = strings(read(resource("data/forge/tags/blocks/ores/copper.json")) .getAsJsonObject().getAsJsonArray("values")); - assertEquals(Collections.singleton("basemetals:copper_ore"), copperBlocks); - assertFalse(Files.exists(GENERATED.resolve("data/minecraft/tags/blocks/mineable"))); - assertFalse(Files.exists(GENERATED.resolve("data/minecraft/tags/blocks/needs_stone_tool.json"))); + assertEquals(new LinkedHashSet<>(Arrays.asList("basemetals:copper_ore", "minecraft:copper_ore", + "minecraft:deepslate_copper_ore")), copperBlocks); + assertTrue(Files.exists(GENERATED.resolve("data/minecraft/tags/blocks/mineable/pickaxe.json"))); + assertTrue(Files.exists(GENERATED.resolve("data/minecraft/tags/blocks/needs_stone_tool.json"))); } @Test diff --git a/src/test/java/zone/moddev/mc/basemetals/material/MaterialCatalogueTest.java b/src/test/java/zone/moddev/mc/basemetals/material/MaterialCatalogueTest.java index 377232f78..4fb4ffbbe 100644 --- a/src/test/java/zone/moddev/mc/basemetals/material/MaterialCatalogueTest.java +++ b/src/test/java/zone/moddev/mc/basemetals/material/MaterialCatalogueTest.java @@ -8,7 +8,7 @@ import org.junit.jupiter.api.Test; -import net.minecraft.inventory.EquipmentSlotType; +import net.minecraft.world.entity.EquipmentSlot; class MaterialCatalogueTest { @Test @@ -29,10 +29,10 @@ void derivesHistoricalAdamantineStatisticsWithinModernBounds() { assertEquals(3200, adamantine.toolDurability()); assertEquals(200, adamantine.armorDurabilityFactor()); assertEquals(0, adamantine.enchantability()); - assertEquals(2, adamantine.armorProtection(EquipmentSlotType.HEAD)); - assertEquals(8, adamantine.armorProtection(EquipmentSlotType.CHEST)); - assertEquals(7, adamantine.armorProtection(EquipmentSlotType.LEGS)); - assertEquals(3, adamantine.armorProtection(EquipmentSlotType.FEET)); + assertEquals(2, adamantine.armorProtection(EquipmentSlot.HEAD)); + assertEquals(8, adamantine.armorProtection(EquipmentSlot.CHEST)); + assertEquals(7, adamantine.armorProtection(EquipmentSlot.LEGS)); + assertEquals(3, adamantine.armorProtection(EquipmentSlot.FEET)); } @Test @@ -75,8 +75,8 @@ void everyDerivedValueUsesTheHistoricalFormulaAndModernBounds() { material.name()); assertEquals(material.hardness() > 10.0D ? (float) (int) (material.hardness() / 5.0D) : 0.0F, material.armorToughness(), material.name()); - for (EquipmentSlotType slot : Arrays.asList(EquipmentSlotType.HEAD, EquipmentSlotType.CHEST, - EquipmentSlotType.LEGS, EquipmentSlotType.FEET)) { + for (EquipmentSlot slot : Arrays.asList(EquipmentSlot.HEAD, EquipmentSlot.CHEST, + EquipmentSlot.LEGS, EquipmentSlot.FEET)) { assertTrue(material.armorProtection(slot) >= 0 && material.armorProtection(slot) <= 30, material.name() + " " + slot); } diff --git a/src/test/java/zone/moddev/mc/basemetals/migration/LegacyWorldSourceTest.java b/src/test/java/zone/moddev/mc/basemetals/migration/LegacyWorldSourceTest.java index 178dc737f..d660df297 100644 --- a/src/test/java/zone/moddev/mc/basemetals/migration/LegacyWorldSourceTest.java +++ b/src/test/java/zone/moddev/mc/basemetals/migration/LegacyWorldSourceTest.java @@ -14,19 +14,82 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; -import net.minecraft.nbt.CompressedStreamTools; -import net.minecraft.nbt.CompoundNBT; -import net.minecraft.nbt.ListNBT; -import net.minecraft.nbt.StringNBT; +import net.minecraft.nbt.NbtIo; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.StringTag; class LegacyWorldSourceTest { @TempDir Path temporaryWorld; + @Test + void protectsSavedChunksWithoutMixingDimensions() throws IOException { + String[] directories = {"region", "DIM-1/region", "DIM1/region", "dimensions/example/nested/cavern/region"}; + String[] dimensions = {"minecraft:overworld", "minecraft:the_nether", "minecraft:the_end", "example:nested/cavern"}; + for (int index = 0; index < directories.length; index++) { + Path directory = Files.createDirectories(temporaryWorld.resolve(directories[index])); + byte[] locations = new byte[4096]; + locations[index * 4 + 3] = 1; + Files.write(directory.resolve("r.0.0.mca"), locations); + } + + assertEquals(4, LegacyWorldDataHook.indexLegacyChunks(temporaryWorld.toFile())); + for (int dimension = 0; dimension < dimensions.length; dimension++) { + for (int chunk = 0; chunk < directories.length; chunk++) { + assertEquals(dimension == chunk, LegacyWorldDataHook.isProtectedChunk( + new net.minecraft.resources.ResourceLocation(dimensions[dimension]), + new net.minecraft.core.BlockPos(chunk * 16, 64, 0))); + } + } + assertTrue(!LegacyWorldDataHook.isProtectedChunk(new net.minecraft.resources.ResourceLocation("example:new"), + new net.minecraft.core.BlockPos(0, 64, 0))); + } + + @Test + void removesOnlyPhantomBedEntitiesOnBaseMetalsBlocks() { + ListTag palette = new ListTag(); + for (String name : new String[] {"basemetals:tin_ore", "minecraft:red_bed", "anothermod:ore"}) { + CompoundTag state = new CompoundTag(); + state.putString("Name", name); + palette.add(state); + } + net.minecraft.util.BitStorage states = new net.minecraft.util.BitStorage(4, 4096); + states.set(0x112, 1); + states.set(0x113, 2); + CompoundTag section = new CompoundTag(); + section.putByte("Y", (byte) 0); + section.put("Palette", palette); + section.putLongArray("BlockStates", states.getRaw()); + ListTag sections = new ListTag(); + sections.add(section); + ListTag entities = new ListTag(); + for (int x = 1; x <= 3; x++) { + CompoundTag bed = new CompoundTag(); + bed.putString("id", "minecraft:bed"); + bed.putInt("x", x); + bed.putInt("y", 1); + bed.putInt("z", 1); + entities.add(bed); + } + CompoundTag chest = entities.getCompound(0).copy(); + chest.putString("id", "minecraft:chest"); + entities.add(chest); + CompoundTag level = new CompoundTag(); + level.put("Sections", sections); + level.put("TileEntities", entities); + + assertEquals(1, LegacyWorldDataHook.removePhantomBedEntities(level)); + assertEquals(3, entities.size()); + assertEquals(2, entities.getCompound(0).getInt("x")); + assertEquals("minecraft:chest", entities.getCompound(2).getString("id")); + assertEquals(0, LegacyWorldDataHook.removePhantomBedEntities(level)); + } + @Test void removesOnlyTheRetiredVanillaProfessionIndex() { - CompoundNBT root = professionSnapshot("minecraft:smith"); - CompoundNBT entity = new CompoundNBT(); + CompoundTag root = professionSnapshot("minecraft:smith"); + CompoundTag entity = new CompoundTag(); entity.putInt("Profession", 3); root.put("VillagerProof", entity); @@ -36,42 +99,42 @@ void removesOnlyTheRetiredVanillaProfessionIndex() { assertEquals(3, root.getCompound("VillagerProof").getInt("Profession")); assertTrue(!LegacyWorldDataHook.removeRetiredVanillaProfessionRegistry(root)); - CompoundNBT custom = professionSnapshot("anothermod:smith"); + CompoundTag custom = professionSnapshot("anothermod:smith"); assertTrue(!LegacyWorldDataHook.removeRetiredVanillaProfessionRegistry(custom)); assertTrue(custom.getCompound("fml").getCompound("Registries") .contains("minecraft:villagerprofessions")); - CompoundNBT blocked = professionSnapshot("minecraft:smith"); + CompoundTag blocked = professionSnapshot("minecraft:smith"); blocked.getCompound("fml").getCompound("Registries") .getCompound("minecraft:villagerprofessions").putIntArray("blocked", new int[] {7}); assertTrue(!LegacyWorldDataHook.removeRetiredVanillaProfessionRegistry(blocked)); - CompoundNBT aliased = professionSnapshot("minecraft:smith"); - ListNBT aliases = new ListNBT(); - aliases.add(StringNBT.valueOf("anothermod:smith")); + CompoundTag aliased = professionSnapshot("minecraft:smith"); + ListTag aliases = new ListTag(); + aliases.add(StringTag.valueOf("anothermod:smith")); aliased.getCompound("fml").getCompound("Registries") .getCompound("minecraft:villagerprofessions").put("aliases", aliases); assertTrue(!LegacyWorldDataHook.removeRetiredVanillaProfessionRegistry(aliased)); - CompoundNBT malformed = professionSnapshot("minecraft:smith"); + CompoundTag malformed = professionSnapshot("minecraft:smith"); malformed.getCompound("fml").getCompound("Registries") .getCompound("minecraft:villagerprofessions").put("ids", aliases); assertTrue(!LegacyWorldDataHook.removeRetiredVanillaProfessionRegistry(malformed)); } - private static CompoundNBT professionSnapshot(String name) { - CompoundNBT entry = new CompoundNBT(); + private static CompoundTag professionSnapshot(String name) { + CompoundTag entry = new CompoundTag(); entry.putString("K", name); entry.putInt("V", 3); - ListNBT ids = new ListNBT(); + ListTag ids = new ListTag(); ids.add(entry); - CompoundNBT snapshot = new CompoundNBT(); + CompoundTag snapshot = new CompoundTag(); snapshot.put("ids", ids); - CompoundNBT registries = new CompoundNBT(); + CompoundTag registries = new CompoundTag(); registries.put("minecraft:villagerprofessions", snapshot); - CompoundNBT fml = new CompoundNBT(); + CompoundTag fml = new CompoundTag(); fml.put("Registries", registries); - CompoundNBT root = new CompoundNBT(); + CompoundTag root = new CompoundTag(); root.put("fml", fml); return root; } @@ -95,23 +158,23 @@ void normalizesRegistryPathsThatWereLegalInMinecraft110() { } @Test - void targetsNative116ChunkLoadingWithoutTheOldLeavesPatch() throws IOException { + void targetsNative117ChunkLoadingWithoutTheOldLeavesPatch() throws IOException { String coremod = new String(Files.readAllBytes(Paths.get( - "src/main/resources/coremods/basemetals_116_compatibility.js")), "UTF-8"); - assertTrue(coremod.contains("net.minecraft.world.chunk.storage.ChunkLoader")); + "src/main/resources/coremods/basemetals_117_compatibility.js")), "UTF-8"); + assertTrue(coremod.contains("net.minecraft.world.level.chunk.storage.ChunkStorage")); assertTrue(coremod.contains("Ljava/util/function/Supplier;")); assertTrue(coremod.contains("Lcom/mojang/serialization/DynamicOps;")); - assertTrue(coremod.contains("Lnet/minecraft/util/RegistryKey;")); - assertTrue(coremod.contains("STATE + 'II)Z'")); + assertTrue(coremod.contains("Lnet/minecraft/resources/ResourceKey;")); + assertTrue(coremod.contains("'(Lnet/minecraft/core/BlockPos;)Z'")); assertTrue(!coremod.contains("leaves_fixer")); assertTrue(!coremod.contains("fluid_renderer")); } @Test void convertsOnlyOldBaseMetalsWallConnections() { - CompoundNBT state = new CompoundNBT(); + CompoundTag state = new CompoundTag(); state.putString("Name", "basemetals:steel_wall"); - CompoundNBT properties = new CompoundNBT(); + CompoundTag properties = new CompoundTag(); properties.putString("north", "true"); properties.putString("east", "false"); properties.putString("south", "tall"); @@ -140,28 +203,28 @@ void preservesAChunkWhoseOnlyLegacyBaseMetalsContentIsInAContainer() throws Exce boolean previous = active.getBoolean(null); try { active.setBoolean(null, true); - CompoundNBT stack = new CompoundNBT(); + CompoundTag stack = new CompoundTag(); stack.putString("id", "basemetals:carbon_powder"); stack.putByte("Count", (byte) 1); - ListNBT items = new ListNBT(); + ListTag items = new ListTag(); items.add(stack); - CompoundNBT chest = new CompoundNBT(); + CompoundTag chest = new CompoundTag(); chest.putString("id", "Chest"); chest.put("Items", items); - ListNBT tileEntities = new ListNBT(); + ListTag tileEntities = new ListTag(); tileEntities.add(chest); - CompoundNBT level = new CompoundNBT(); + CompoundTag level = new CompoundTag(); level.putInt("xPos", 12); level.putInt("zPos", -7); level.put("TileEntities", tileEntities); - CompoundNBT root = new CompoundNBT(); + CompoundTag root = new CompoundTag(); root.put("Level", level); LegacyWorldDataHook.prepareLegacyChunk(root); - CompoundNBT finalized = LegacyWorldDataHook.finalizeLegacyChunk(root); + CompoundTag finalized = LegacyWorldDataHook.finalizeLegacyChunk(root); assertEquals("full", finalized.getCompound("Level").getString("Status")); - CompoundNBT migratedChest = finalized.getCompound("Level") + CompoundTag migratedChest = finalized.getCompound("Level") .getList("TileEntities", 10).getCompound(0); assertEquals("minecraft:chest", migratedChest.getString("id")); assertEquals("basemetals:coal_powder", @@ -172,26 +235,26 @@ void preservesAChunkWhoseOnlyLegacyBaseMetalsContentIsInAContainer() throws Exce } private void writeLevel(String name, int dataVersion, int blockId, String blockName) throws IOException { - CompoundNBT entry = new CompoundNBT(); + CompoundTag entry = new CompoundTag(); entry.putInt("V", blockId); entry.putString("K", blockName); - ListNBT ids = new ListNBT(); + ListTag ids = new ListTag(); ids.add(entry); - CompoundNBT blocks = new CompoundNBT(); + CompoundTag blocks = new CompoundTag(); blocks.put("ids", ids); - CompoundNBT registries = new CompoundNBT(); + CompoundTag registries = new CompoundTag(); registries.put("minecraft:blocks", blocks); - CompoundNBT fml = new CompoundNBT(); + CompoundTag fml = new CompoundTag(); fml.put("Registries", registries); - CompoundNBT data = new CompoundNBT(); + CompoundTag data = new CompoundTag(); data.putInt("DataVersion", dataVersion); - CompoundNBT level = new CompoundNBT(); + CompoundTag level = new CompoundTag(); level.put("FML", fml); level.put("Data", data); try (FileOutputStream output = new FileOutputStream(temporaryWorld.resolve(name).toFile())) { - CompressedStreamTools.writeCompressed(level, output); + NbtIo.writeCompressed(level, output); } } } diff --git a/src/test/java/zone/moddev/mc/basemetals/worldgen/OreSpawnProviderTest.java b/src/test/java/zone/moddev/mc/basemetals/worldgen/OreSpawnProviderTest.java index da4507ea7..a58cb54ee 100644 --- a/src/test/java/zone/moddev/mc/basemetals/worldgen/OreSpawnProviderTest.java +++ b/src/test/java/zone/moddev/mc/basemetals/worldgen/OreSpawnProviderTest.java @@ -61,7 +61,8 @@ void everyRuleUsesTheSharedVeinContract() throws IOException { assertEquals(16, rule.get("length").getAsInt(), entry.getKey()); assertEquals(0.0D, rule.get("discard_chance_on_air_exposure").getAsDouble(), 0.0D, entry.getKey()); - assertTrue(ore.get("enabled").getAsBoolean(), entry.getKey()); + assertEquals(!entry.getKey().equals("basemetals:ore/copper"), + ore.get("enabled").getAsBoolean(), entry.getKey()); assertFalse(ore.get("retrogen").getAsBoolean(), entry.getKey()); } } diff --git a/src/test/java/zone/moddev/mc/basemetals/worldgen/OreSpawnSchemaValidationTest.java b/src/test/java/zone/moddev/mc/basemetals/worldgen/OreSpawnSchemaValidationTest.java index 65291b306..4ddb5ea74 100644 --- a/src/test/java/zone/moddev/mc/basemetals/worldgen/OreSpawnSchemaValidationTest.java +++ b/src/test/java/zone/moddev/mc/basemetals/worldgen/OreSpawnSchemaValidationTest.java @@ -38,7 +38,7 @@ private static void assertValid(String schemaName, Path value) { private static void validate(JsonObject schema, JsonElement value, Document document, String path, boolean probe) throws Exception { if (schema.has("$ref")) { - Reference reference = resolve(document, schema.get("$ref").getAsString()); + ConditionReference reference = resolve(document, schema.get("$ref").getAsString()); validate(reference.schema, value, reference.document, path, probe); return; } @@ -160,7 +160,7 @@ private static boolean matches(JsonObject schema, JsonElement value, Document do } } - private static Reference resolve(Document current, String reference) throws Exception { + private static ConditionReference resolve(Document current, String reference) throws Exception { String[] parts = reference.split("#", 2); Document target = parts[0].isEmpty() ? current : document(SCHEMAS.resolve(parts[0])); JsonElement value = target.root; @@ -169,7 +169,7 @@ private static Reference resolve(Document current, String reference) throws Exce value = value.getAsJsonObject().get(token.replace("~1", "/").replace("~0", "~")); } } - return new Reference(target, value.getAsJsonObject()); + return new ConditionReference(target, value.getAsJsonObject()); } private static Document document(Path path) throws Exception { @@ -192,10 +192,10 @@ private static final class Document { Document(Path path, JsonObject root) { this.path = path; this.root = root; } } - private static final class Reference { + private static final class ConditionReference { final Document document; final JsonObject schema; - Reference(Document document, JsonObject schema) { this.document = document; this.schema = schema; } + ConditionReference(Document document, JsonObject schema) { this.document = document; this.schema = schema; } } private static final class ValidationFailure extends RuntimeException { diff --git a/tools/generate_116_resources.js b/tools/generate_117_resources.js similarity index 70% rename from tools/generate_116_resources.js rename to tools/generate_117_resources.js index a2414374b..17cac8cee 100644 --- a/tools/generate_116_resources.js +++ b/tools/generate_117_resources.js @@ -1,7 +1,6 @@ /* - * Converts the catalogue-generated resources to Minecraft 1.16 formats. - * Removes unsupported recipes and integrations, and converts block states, - * item models and tags to the names and formats used by Forge 36. + * Builds the recipes, drops and tags used by the Minecraft 1.17 port. + * Ore models are generated separately by Forge's native model provider. */ 'use strict'; @@ -11,6 +10,7 @@ const path = require('path'); const root = path.resolve(__dirname, '..'); const generated = path.join(root, 'src', 'generated', 'resources'); const main = path.join(root, 'src', 'main', 'resources'); +const verify = process.argv.includes('--verify'); function inside(base, target) { const relative = path.relative(base, target); @@ -22,10 +22,20 @@ function inside(base, target) { function remove(relative) { const target = inside(root, path.join(root, relative)); + if (verify) { + if (fs.existsSync(target)) throw new Error(`Obsolete generated resource: ${relative}`); + return; + } fs.rmSync(target, { recursive: true, force: true }); } function writeJson(file, value) { + if (verify) { + if (!fs.existsSync(file) || JSON.stringify(JSON.parse(fs.readFileSync(file, 'utf8'))) !== JSON.stringify(value)) { + throw new Error(`Generated resource is stale: ${path.relative(root, file)}. Run generateResources.`); + } + return; + } fs.mkdirSync(path.dirname(file), { recursive: true }); fs.writeFileSync(file, JSON.stringify(value, null, 2) + '\n', 'utf8'); } @@ -53,10 +63,6 @@ for (const relative of [ 'src/generated/resources/data/basemetals/recipes/compat', 'src/generated/resources/data/basemetals/loot_modifiers', 'src/generated/resources/data/forge/loot_modifiers', - 'src/generated/resources/data/minecraft/tags/blocks/mineable', - 'src/generated/resources/data/minecraft/tags/blocks/needs_stone_tool.json', - 'src/generated/resources/data/minecraft/tags/blocks/needs_iron_tool.json', - 'src/generated/resources/data/minecraft/tags/blocks/needs_diamond_tool.json', 'src/generated/resources/data/minecraft/tags/blocks/beacon_base_blocks.json' ]) remove(relative); @@ -71,16 +77,18 @@ writeJson(path.join(generated, 'data', 'minecraft', 'tags', 'blocks', 'anvil.jso ] }); -for (const file of filesUnder(path.join(generated, 'data', 'basemetals', 'recipes'), '.json')) { - const recipe = JSON.parse(fs.readFileSync(file, 'utf8')); - if (recipe.type === 'minecraft:blasting') { - fs.rmSync(file); - } -} - const manifestFile = path.join(generated, 'data', 'basemetals', 'registry_manifest.json'); const manifest = JSON.parse(fs.readFileSync(manifestFile, 'utf8')); -manifest.source = 'Base Metals 1.16.5 catalogue'; +manifest.source = 'Base Metals 1.17.1 catalogue'; +const oreMaterials = manifest.blocks.filter(id => id.endsWith('_ore')).map(id => id.split(':')[1].replace(/_ore$/, '')); +const rawMaterials = oreMaterials.filter(name => name !== 'copper'); +for (const material of rawMaterials) { + const id = `basemetals:${material}_raw`; + for (const key of ['items', 'new_items']) { + if (!manifest[key].includes(id)) manifest[key].push(id); + manifest[key].sort(); + } +} manifest.loot_modifier_serializers = []; manifest.new_loot_modifier_serializers = []; for (const key of ['recipe_serializers', 'new_recipe_serializers']) { @@ -94,6 +102,23 @@ const fluidIds = new Set(manifest.fluids); for (const block of manifest.blocks) { if (fluidIds.has(block)) continue; const id = block.split(':')[1]; + if (id.endsWith('_ore')) { + const material = id.replace(/_ore$/, ''); + const raw = material === 'copper' ? 'minecraft:raw_copper' : `basemetals:${material}_raw`; + const functions = material === 'copper' ? [{ function: 'minecraft:set_count', count: { + type: 'minecraft:uniform', min: 2, max: 3 + }}] : []; + functions.push({ function: 'minecraft:apply_bonus', enchantment: 'minecraft:fortune', formula: 'minecraft:ore_drops' }, + { function: 'minecraft:explosion_decay' }); + writeJson(path.join(generated, 'data', 'basemetals', 'loot_tables', 'blocks', `${id}.json`), { + type: 'minecraft:block', pools: [{ name: `basemetals_${id}`, rolls: 1, entries: [{ + type: 'minecraft:alternatives', children: [{ type: 'minecraft:item', name: block, conditions: [{ + condition: 'minecraft:match_tool', predicate: { enchantments: [{ enchantment: 'minecraft:silk_touch', levels: { min: 1 } }] } + }] }, { type: 'minecraft:item', name: raw, functions }] + }] }] + }); + continue; + } const compatibilitySlab = id.startsWith('double_') && id.endsWith('_slab'); const drop = compatibilitySlab ? id.substring('double_'.length) : id; const functions = []; @@ -124,7 +149,7 @@ for (const block of manifest.blocks) { } // Forge draws the actual fluid texture inside the bucket, as it does in 1.18. -for (const bucket of manifest.new_items) { +for (const bucket of manifest.new_items.filter(id => id.endsWith('_bucket'))) { const id = bucket.substring(bucket.indexOf(':') + 1); writeJson(path.join(generated, 'assets', 'basemetals', 'models', 'item', `${id}.json`), { parent: 'forge:item/bucket', @@ -134,21 +159,25 @@ for (const bucket of manifest.new_items) { } remove('src/generated/resources/assets/basemetals/textures/item/bucket_fluid.png'); -// Vanilla copper and the modern Nether/Caves & Cliffs plants do not exist in -// 1.16.5. Keep Base Metals copper in the common tags and retain only plants -// present in the target registry. -for (const relative of [ - 'data/forge/tags/blocks/ores/copper.json', - 'data/forge/tags/blocks/storage_blocks/copper.json', - 'data/forge/tags/items/ingots/copper.json', - 'data/forge/tags/items/ores/copper.json', - 'data/forge/tags/items/storage_blocks/copper.json' -]) { - const file = path.join(generated, relative); - const tag = JSON.parse(fs.readFileSync(file, 'utf8')); - tag.values = tag.values.filter(value => typeof value !== 'string' || !value.startsWith('minecraft:copper')) - .filter(value => value !== 'minecraft:deepslate_copper_ore'); - writeJson(file, tag); +// Keep copper ingredients interchangeable without replacing saved Base Metals items. +for (const kind of ['blocks', 'items']) { + for (const [tagName, additions] of Object.entries({ + 'ores/copper': ['minecraft:copper_ore', 'minecraft:deepslate_copper_ore'], + 'storage_blocks/copper': ['minecraft:copper_block'], + ...(kind === 'items' ? { 'ingots/copper': ['minecraft:copper_ingot'] } : {}) + })) { + const file = path.join(generated, 'data/forge/tags', kind, `${tagName}.json`); + const tag = JSON.parse(fs.readFileSync(file, 'utf8')); + tag.values = [...new Set([...tag.values, ...additions])]; + writeJson(file, tag); + } + for (const material of ['iron', 'gold', 'coal', 'diamond', 'emerald', 'lapis', 'redstone']) { + const file = path.join(generated, 'data/forge/tags', kind, `ores/${material}.json`); + const tag = fs.existsSync(file) ? JSON.parse(fs.readFileSync(file, 'utf8')) + : { replace: false, values: [`minecraft:${material}_ore`] }; + tag.values = [...new Set([...tag.values, `minecraft:deepslate_${material}_ore`])]; + writeJson(file, tag); + } } writeJson(path.join(generated, 'data', 'basemetals', 'tags', 'blocks', 'scythe_harvestable.json'), { @@ -205,8 +234,7 @@ writeJson(gravelCrushingFile, gravelCrushing); // grammar. They preserve the exact historical weights and enchanted-item rolls. const legacyChests = path.join(root, 'reference', '1.12', 'alt', 'chests'); const targetChests = path.join(generated, 'data', 'basemetals', 'loot_tables', 'chests', 'inject'); -remove('src/generated/resources/data/basemetals/loot_tables/chests/inject'); -fs.mkdirSync(targetChests, { recursive: true }); +if (!verify) fs.mkdirSync(targetChests, { recursive: true }); for (const file of filesUnder(legacyChests, '.json')) { const target = path.join(targetChests, path.basename(file)); const table = JSON.parse(fs.readFileSync(file, 'utf8')); @@ -244,13 +272,13 @@ for (const file of filesUnder(path.join(generated, 'assets', 'basemetals', 'bloc } writeJson(path.join(generated, 'data', 'forge', 'tags', 'items', 'ores', 'gold.json'), { - replace: false, values: ['minecraft:gold_ore', 'minecraft:nether_gold_ore'] + replace: false, values: ['minecraft:gold_ore', 'minecraft:deepslate_gold_ore', 'minecraft:nether_gold_ore'] }); writeJson(path.join(generated, 'data', 'forge', 'tags', 'items', 'ores', 'netherite_scrap.json'), { replace: false, values: ['minecraft:ancient_debris'] }); writeJson(path.join(generated, 'data', 'forge', 'tags', 'blocks', 'ores', 'gold.json'), { - replace: false, values: ['minecraft:gold_ore', 'minecraft:nether_gold_ore'] + replace: false, values: ['minecraft:gold_ore', 'minecraft:deepslate_gold_ore', 'minecraft:nether_gold_ore'] }); writeJson(path.join(generated, 'data', 'forge', 'tags', 'blocks', 'ores', 'netherite_scrap.json'), { replace: false, values: ['minecraft:ancient_debris'] @@ -282,7 +310,7 @@ const rule = (minY, maxY, frequency, hosts, tags, families) => Object.assign({}, }); const ore = (name, dimensions, selectors) => ({ block: `basemetals:${name}_ore`, - enabled: true, + enabled: name !== 'copper', source_mod: 'basemetals', retrogen: false, ...(dimensions ? { dimensions } : { dimension_selectors: selectors }) @@ -328,6 +356,35 @@ writeJson(path.join(main, 'data', 'basemetals', 'orespawn', 'provider.json'), { const recipesDirectory = path.join(generated, 'data', 'basemetals', 'recipes'); const unlockDirectory = path.join(generated, 'data', 'basemetals', 'advancements', 'recipes'); +// Raw ore is a processing ingredient, not a substitute for powder in alloys. +for (const material of [...rawMaterials, 'iron', 'gold', 'copper']) { + const raw = rawMaterials.includes(material) ? `basemetals:${material}_raw` : `minecraft:raw_${material}`; + writeJson(path.join(generated, 'data/forge/tags/items/raw_materials', `${material}.json`), { + replace: false, values: [raw] + }); + writeJson(path.join(recipesDirectory, `${material}_raw_crushing.json`), { + type: 'basemetals:crushing', ingredient: { tag: `forge:raw_materials/${material}` }, + result: { item: `basemetals:${material}_powder`, count: 1 } + }); + if (!rawMaterials.includes(material)) continue; + + writeJson(path.join(generated, 'assets/basemetals/models/item', `${material}_raw.json`), { + parent: 'minecraft:item/generated', textures: { layer0: `basemetals:item/${material}_raw` } + }); + const oldSmelting = JSON.parse(fs.readFileSync(path.join(recipesDirectory, `${material}_powder_smelting.json`), 'utf8')); + for (const [method, ticks] of [['smelting', 200], ['blasting', 100]]) { + writeJson(path.join(recipesDirectory, `${material}_raw_${method}.json`), { + type: `minecraft:${method}`, ingredient: { tag: `forge:raw_materials/${material}` }, + result: `basemetals:${material}_ingot`, experience: oldSmelting.experience, cookingtime: ticks + }); + } +} +writeJson(path.join(generated, 'data/forge/tags/items/raw_materials.json'), { + replace: false, values: [...rawMaterials, 'iron', 'gold', 'copper'].map(name => `#forge:raw_materials/${name}`) +}); + +const itemPredicate = ingredient => ingredient.tag ? { tag: ingredient.tag } : { items: [ingredient.item] }; + // As in 1.12, finding the base material reveals its crafting recipes. const discoveryIngredients = {}; for (const metal of [ @@ -383,7 +440,7 @@ for (const file of filesUnder(recipesDirectory, '.json')) { if (!recipe.type.startsWith('minecraft:crafting_')) { const oldUnlock = path.join(unlockDirectory, `${name}.json`); - if (fs.existsSync(oldUnlock)) fs.rmSync(oldUnlock); + if (fs.existsSync(oldUnlock) && !name.includes('_raw_')) remove(path.relative(root, oldUnlock)); continue; } @@ -403,7 +460,7 @@ for (const file of filesUnder(recipesDirectory, '.json')) { const criteria = { has_material: { trigger: 'minecraft:inventory_changed', - conditions: { items: [discovery] } + conditions: { items: [itemPredicate(discovery)] } }, has_recipe: { trigger: 'minecraft:recipe_unlocked', @@ -416,7 +473,7 @@ for (const file of filesUnder(recipesDirectory, '.json')) { const key = JSON.stringify(ingredient); if (seen.has(key)) continue; seen.add(key); - const predicate = ingredient.tag ? { tag: ingredient.tag } : { item: ingredient.item }; + const predicate = itemPredicate(ingredient); criteria[`has_ingredient_${seen.size}`] = { trigger: 'minecraft:inventory_changed', conditions: { items: [predicate] } @@ -430,9 +487,43 @@ for (const file of filesUnder(recipesDirectory, '.json')) { }); } +for (const material of rawMaterials) { + for (const method of ['smelting', 'blasting']) { + const name = `${material}_raw_${method}`; + writeJson(path.join(unlockDirectory, `${name}.json`), { + parent: 'minecraft:recipes/root', criteria: { + has_raw: { trigger: 'minecraft:inventory_changed', conditions: { items: [{ tag: `forge:raw_materials/${material}` }] } }, + has_recipe: { trigger: 'minecraft:recipe_unlocked', conditions: { recipe: `basemetals:${name}` } } + }, requirements: [['has_raw', 'has_recipe']], rewards: { recipes: [`basemetals:${name}`] } + }); + } +} + +// Item predicates changed from "item" to "items" in 1.17, including old story advancements. +function updatePredicates(value) { + if (Array.isArray(value)) return value.forEach(updatePredicates); + if (!value || typeof value !== 'object') return; + if (value.item && !value.type && !value.condition) { + value.items = [value.item]; + delete value.item; + } + Object.values(value).forEach(updatePredicates); +} +for (const file of filesUnder(path.join(generated, 'data/basemetals/advancements'), '.json')) { + const advancement = JSON.parse(fs.readFileSync(file, 'utf8')); + // Icons still use "item"; only criterion conditions are predicates. + Object.values(advancement.criteria || {}).forEach(criterion => updatePredicates(criterion.conditions)); + writeJson(file, advancement); +} + const configTranslations = require('./config_translations.json'); const playerTranslations = require('./player_translations.json'); const bucketTranslations = require('./bucket_translations.json'); +const rawNameTemplates = { + en_us: 'Raw %s', de_de: '%s-Erzbrocken', es_es: '%s en bruto', fr_fr: '%s brut', + it_it: '%s grezzo', ja_jp: '%sの原石', nl_nl: 'Ruw %s', pt_br: '%s bruto', + ru_ru: 'Рудное сырьё: %s', zh_cn: '粗%s', zh_tw: '粗%s' +}; for (const file of filesUnder(path.join(generated, 'assets', 'basemetals', 'lang'), '.json')) { const locale = path.basename(file, '.json'); const source = configTranslations.aliases[locale] || locale; @@ -442,10 +533,15 @@ for (const file of filesUnder(path.join(generated, 'assets', 'basemetals', 'lang if (!playerText) throw new Error(`Missing player translation: ${locale}`); const language = JSON.parse(fs.readFileSync(file, 'utf8')); Object.assign(language, text, playerText); + const rawTemplate = rawNameTemplates[source]; + if (!rawTemplate) throw new Error(`Missing raw-material translation: ${locale}`); + for (const material of rawMaterials) { + language[`item.basemetals.${material}_raw`] = rawTemplate.replace('%s', language[`material.${material}.name`]); + } const buckets = bucketTranslations.locales[source]; if (!buckets) throw new Error(`Missing bucket translations: ${locale}`); - for (const bucket of manifest.new_items) { + for (const bucket of manifest.new_items.filter(id => id.endsWith('_bucket'))) { const id = bucket.substring(bucket.indexOf(':') + 1); const material = id.replace(/_bucket$/, ''); const name = buckets[material]; @@ -457,4 +553,4 @@ for (const file of filesUnder(path.join(generated, 'assets', 'basemetals', 'lang writeJson(file, language); } -console.log('Generated Minecraft 1.16.5-compatible Base Metals resources.'); +console.log(verify ? 'Minecraft 1.17.1 generated resources are current.' : 'Generated Minecraft 1.17.1 Base Metals resources.'); diff --git a/tools/test_content_modes.js b/tools/test_content_modes.js index 21a138ecd..6ea0af42a 100644 --- a/tools/test_content_modes.js +++ b/tools/test_content_modes.js @@ -11,27 +11,12 @@ if (path.dirname(root) !== build || path.basename(root) !== 'content-mode-tests' throw new Error(`Content-mode profiles must be inside the build directory: ${root}`); } -const version = '1.16.5'; -const forge = '36.2.34'; -const forgeMetadata = JSON.parse(fs.readFileSync(path.join(clientRuntime, 'versions', `${version}-forge-${forge}`, `${version}-forge-${forge}.json`))); -const vanillaMetadata = JSON.parse(fs.readFileSync(path.join(clientRuntime, 'versions', version, `${version}.json`))); -const libraries = new Map(); -const osName = process.platform === 'win32' ? 'windows' : process.platform === 'darwin' ? 'osx' : 'linux'; -for (const metadata of [vanillaMetadata, forgeMetadata]) { - for (const library of metadata.libraries) { - let allowed = !library.rules || library.rules.length === 0; - for (const rule of library.rules || []) { - if (!rule.os || (rule.os.name === osName && (!rule.os.arch || rule.os.arch === 'x86_64'))) { - allowed = rule.action === 'allow'; - } - } - if (allowed) libraries.set(library.name.split(':').slice(0, 2).join(':'), path.join(clientRuntime, 'libraries', library.downloads.artifact.path)); - } -} -const classpath = [...libraries.values(), path.join(clientRuntime, 'versions', version, `${version}.jar`)].join(path.delimiter); -const versionNatives = [path.join(clientRuntime, 'natives', `${version}-forge-${forge}`), - path.join(clientRuntime, 'natives', `forge-${forge}`)].find(directory => fs.existsSync(directory)); -const natives = versionNatives || path.join(clientRuntime, 'natives'); +const version = '1.17.1'; +const forge = '37.1.1'; +const { serverArguments, clientLaunch } = require('./validation/forge_launcher'); +const clientConfiguration = clientLaunch(clientRuntime, version, forge); +const forgeMetadata = clientConfiguration.metadata; +const vanillaMetadata = clientConfiguration.vanilla; const sleep = milliseconds => new Promise(resolve => setTimeout(resolve, milliseconds)); function profile(directory, client, mode, oldConfig) { @@ -109,7 +94,7 @@ async function scenario(test, reload = false) { fs.writeFileSync(path.join(server, 'server.properties'), `level-name=world\nonline-mode=false\nserver-ip=127.0.0.1\nserver-port=${port}\nview-distance=2\nspawn-protection=0\nmax-tick-time=-1\n`); const serverProcess = launch(['-Xms256m', '-Xmx2g', '-Dbasemetalsprobe.mode=login', `-Dbasemetalsprobe.modeSwitch=${!!test.cycle}`, - '-jar', path.join(serverRuntime, `forge-${version}-${forge}.jar`), 'nogui'], server, reload ? 'server-reload' : 'server-console'); + ...serverArguments(serverRuntime, server, version, forge)], server, reload ? 'server-reload' : 'server-console'); let clientProcess; try { // A reload can leave the previous latest.log in place until Forge starts. @@ -119,7 +104,7 @@ async function scenario(test, reload = false) { '-Dbasemetalsclientprobe.login=true', `-Dbasemetalsclientprobe.expectedMode=${test.client === 'low_fantasy' ? 'low_fantasy' : 'high_fantasy'}`, `-Dbasemetalsclientprobe.modeSwitch=${!!test.cycle}`, `-Dbasemetalsclientprobe.expectReject=${!!test.reject}`, `-Dbasemetalsclientprobe.port=${port}`, - `-Djava.library.path=${natives}`, '-cp', classpath, forgeMetadata.mainClass, + ...clientConfiguration.args, ...forgeMetadata.arguments.game, '--username', 'ModeValidation', '--version', `${version}-forge-${forge}`, '--gameDir', client, '--assetsDir', path.join(clientRuntime, fs.existsSync(path.join(clientRuntime, 'assets-local')) ? 'assets-local' : 'assets'), diff --git a/tools/validation/compare_world_terrain.py b/tools/validation/compare_world_terrain.py index e2e79f18d..8464fce3a 100644 --- a/tools/validation/compare_world_terrain.py +++ b/tools/validation/compare_world_terrain.py @@ -3,6 +3,7 @@ import argparse import gzip import io +import math import struct import zlib from pathlib import Path @@ -25,6 +26,11 @@ 121: ["end_stone"], } TERRAIN_NAMES = {"minecraft:" + name for variants in LEGACY_TERRAIN.values() for name in variants} +FALLING_BLOCKS = {"minecraft:gravel", "minecraft:sand", "minecraft:red_sand"} +AIR = {None, "minecraft:air", "minecraft:cave_air", "minecraft:void_air"} +FALL_THROUGH = AIR | {"minecraft:water", "minecraft:lava", "minecraft:grass", "minecraft:tall_grass", + "minecraft:fern", "minecraft:large_fern", "minecraft:dead_bush", + "minecraft:seagrass", "minecraft:tall_seagrass"} def chunks(world): @@ -85,27 +91,130 @@ def block_names(section): yield palette[value & mask] +def falling_blocks(world, loaded_chunks, dropped_items=None): + result = {} + seen = set() + + def collect(dimension, entities): + for entity in entities: + identity = tuple(entity.get("UUID", [])) + if identity and identity in seen: + continue + if identity: + seen.add(identity) + if str(entity.get("id", "")) == "minecraft:item" and dropped_items is not None: + item = entity.get("Item", {}) + name = str(item.get("id", "")) + if name in FALLING_BLOCKS: + dropped_items.append({"dimension": dimension, "name": name, + "count": int(item.get("Count", 0)), + "position": tuple(float(value) for value in entity["Pos"]), + "uuid": tuple(entity.get("UUID", []))}) + continue + if str(entity.get("id", "")) != "minecraft:falling_block": + continue + name = str(entity.get("BlockState", {}).get("Name", "")) + if name not in FALLING_BLOCKS: + continue + x, y, z = [math.floor(float(value)) for value in entity["Pos"]] + key = (dimension, x >> 4, z >> 4, ((z & 15) << 4) | (x & 15)) + result.setdefault(key, []).append((y, name)) + + for (dimension, _, _), chunk in loaded_chunks.items(): + collect(dimension, chunk.get("Entities", [])) + for dimension in ["", "DIM-1", "DIM1"]: + for region in (world / dimension / "entities").glob("*.mca"): + data = region.read_bytes() + for slot in range(1024): + offset = int.from_bytes(data[slot * 4:slot * 4 + 3], "big") * 4096 + if not offset: + continue + length = struct.unpack_from(">I", data, offset)[0] + payload = data[offset + 5:offset + 4 + length] + payload = gzip.decompress(payload) if data[offset + 4] == 1 else zlib.decompress(payload) + root = nbtlib.File.parse(io.BytesIO(payload)) + collect(dimension, root.get("Entities", [])) + return result + + +def match_fallen_blocks(missing, recovered): + # A falling block may land, remain in flight, or become a dropped item. + # Match each original grain once; nearby stacks cannot cover several losses. + # Falling entities and merged item stacks can drift into neighbouring columns. + neighbours = [] + for dimension, name, x, y, z in missing: + candidates = [] + for index, (other_dimension, other_name, px, py, pz) in enumerate(recovered): + if other_dimension != dimension or other_name != name: + continue + distance = math.hypot(px - x, pz - z) + if distance <= 4 and 0 <= py <= y + 1: + candidates.append((distance, -py, index)) + neighbours.append([index for _, _, index in sorted(candidates)]) + + owners = {} + + def assign(source, visited): + for target in neighbours[source]: + if target in visited: + continue + visited.add(target) + if target not in owners or assign(owners[target], visited): + owners[target] = source + return True + return False + + for source in sorted(range(len(missing)), key=lambda index: len(neighbours[index])): + if not assign(source, set()): + raise AssertionError(f"Fallen terrain block was not recovered: {missing[source]}") + + def compare(original, upgraded): before, after = chunks(original), chunks(upgraded) + original_drops, current_drops = [], [] + falling_blocks(original, before, original_drops) + current_falling = falling_blocks(upgraded, after, current_drops) + old_drop_ids = {drop["uuid"] for drop in original_drops} + current_drops = [drop for drop in current_drops if drop["uuid"] not in old_drop_ids] checked = 0 + missing, recovered = [], [] + + for (dimension, chunk_x, chunk_z, column), entries in current_falling.items(): + for y, name in entries: + recovered.append((dimension, name, chunk_x * 16 + (column & 15) + 0.5, + y, chunk_z * 16 + (column >> 4) + 0.5)) + for drop in current_drops: + x, y, z = drop["position"] + recovered.extend([(drop["dimension"], drop["name"], x, y, z)] * drop["count"]) + for key, chunk in before.items(): if key not in after: raise AssertionError(f"Original chunk is missing after upgrade: {key}") - sections = {int(section["Y"]): section for section in after[key]["Sections"]} - for section in chunk["Sections"]: - height = int(section["Y"]) - actual = list(block_names(sections[height])) if height in sections else [None] * 4096 - for index, expected in enumerate(block_names(section)): + sections = {int(section["Y"]): list(block_names(section)) for section in after[key]["Sections"]} + original_sections = {int(section["Y"]): list(block_names(section)) for section in chunk["Sections"]} + for height in original_sections.keys() | sections.keys(): + actual = sections.get(height, [None] * 4096) + for index, expected in enumerate(original_sections.get(height, [None] * 4096)): + x = key[1] * 16 + (index & 15) + 0.5 + y = height * 16 + (index >> 8) + z = key[2] * 16 + ((index >> 4) & 15) + 0.5 + if actual[index] in FALLING_BLOCKS and actual[index] != expected: + recovered.append((key[0], actual[index], x, y, z)) if expected not in TERRAIN_NAMES: continue checked += 1 if actual[index] != expected: + if expected in FALLING_BLOCKS and actual[index] in FALL_THROUGH | FALLING_BLOCKS: + missing.append((key[0], expected, x, y, z)) + continue raise AssertionError(f"Terrain changed at {key}, section {height}, index {index}: " f"{expected} became {actual[index]}") if not checked: raise AssertionError("The fixture contains no solid vanilla terrain to compare") - print(f"TERRAIN_UPGRADE PASS chunks={len(before)} solid_blocks={checked}") + match_fallen_blocks(missing, recovered) + print(f"TERRAIN_UPGRADE PASS chunks={len(before)} solid_blocks={checked} " + f"recovered_falling_blocks={len(missing)}") if __name__ == "__main__": diff --git a/tools/validation/forge_launcher.js b/tools/validation/forge_launcher.js new file mode 100644 index 000000000..4ca031af3 --- /dev/null +++ b/tools/validation/forge_launcher.js @@ -0,0 +1,65 @@ +'use strict'; + +const fs = require('fs'); +const path = require('path'); + +// Forge 37 supplies the module-path launch arguments in its installed metadata. +function serverArguments(runtime, directory, version, forge) { + const platform = process.platform === 'win32' ? 'win' : 'unix'; + const source = path.join(runtime, 'libraries/net/minecraftforge/forge', + `${version}-${forge}`, `${platform}_args.txt`); + const libraries = path.join(runtime, 'libraries').replace(/\\/g, '/'); + let contents = fs.readFileSync(source, 'utf8') + .replaceAll('libraries/', libraries + '/') + .replace('-DlibraryDirectory=libraries', '-DlibraryDirectory=' + libraries); + contents = contents.split(/\r?\n/).map(line => { + if (line.startsWith('-p ')) return '-p "' + line.substring(3) + '"'; + if (line.startsWith('-D') && line.includes(libraries)) return '"' + line + '"'; + return line; + }).join('\n'); + const staged = path.join(directory, 'forge-arguments.txt'); + fs.writeFileSync(staged, contents); + return ['--add-opens', 'java.base/java.lang.invoke=ALL-UNNAMED', '@' + staged, 'nogui']; +} + +function clientLaunch(runtime, version, forge) { + const candidates = [`${version}-forge-${forge}`, `forge-${forge}`]; + const id = candidates.find(value => fs.existsSync(path.join(runtime, 'versions', value, value + '.json'))); + if (!id) throw new Error('Missing installed Forge client metadata.'); + const metadata = JSON.parse(fs.readFileSync(path.join(runtime, 'versions', id, id + '.json'))); + const vanilla = JSON.parse(fs.readFileSync(path.join(runtime, 'versions', version, version + '.json'))); + const libraries = new Map(); + const osName = process.platform === 'win32' ? 'windows' : process.platform === 'darwin' ? 'osx' : 'linux'; + for (const item of [vanilla, metadata]) { + for (const library of item.libraries) { + let allowed = !library.rules || library.rules.length === 0; + for (const rule of library.rules || []) { + if (!rule.os || (rule.os.name === osName && (!rule.os.arch || rule.os.arch === 'x86_64'))) { + allowed = rule.action === 'allow'; + } + } + if (allowed) { + const artifact = path.join(runtime, 'libraries', library.downloads.artifact.path); + if (!fs.existsSync(artifact)) throw new Error('Missing client library: ' + artifact); + libraries.set(library.name.split(':').slice(0, 2).join(':'), artifact); + } + } + } + const classpath = [...libraries.values(), path.join(runtime, 'versions', version, `${version}.jar`)].join(path.delimiter); + const replacements = { library_directory: path.join(runtime, 'libraries'), + classpath_separator: path.delimiter, version_name: metadata.inheritsFrom }; + const jvm = metadata.arguments.jvm.map(value => { + for (const [key, replacement] of Object.entries(replacements)) { + value = value.replaceAll('${' + key + '}', replacement); + } + if (value.includes('${')) throw new Error('Unresolved client argument: ' + value); + return value; + }); + const natives = candidates.map(value => path.join(runtime, 'natives', value)) + .find(directory => fs.existsSync(directory)) || path.join(runtime, 'natives'); + return { metadata, vanilla, natives, + args: [...jvm, '--add-opens', 'java.base/java.lang.invoke=ALL-UNNAMED', + `-Djava.library.path=${natives}`, '-cp', classpath, metadata.mainClass] }; +} + +module.exports = { serverArguments, clientLaunch }; diff --git a/tools/validation/legacy-capture/README.md b/tools/validation/legacy-capture/README.md index 7c9e712b1..560291448 100644 --- a/tools/validation/legacy-capture/README.md +++ b/tools/validation/legacy-capture/README.md @@ -12,7 +12,7 @@ equipment and playerdata checks. The first run saves a registry manifest and stops the server. A second run checks that the original Minecraft version can reload the fixture. Only then -should a copy be opened in Minecraft 1.16.5. +should a copy be opened in Minecraft 1.17.1. ## Build @@ -40,9 +40,11 @@ node tools/validation/test_legacy_worlds.js build/legacy-world-test-spec.json up Keep that specification under ignored build output. It supplies these paths: - `output`: a new, empty directory for disposable test servers and results; -- `java8`: the Java 8 executable; -- `runtime110` and `runtime116`: installed Forge server directories, including - their launcher, Minecraft server JAR and `libraries` directory; +- `java8`: the Java 8 executable used to capture historical worlds; +- `java16`: the Java 16 executable used to upgrade them; +- `runtime110`: the installed historical Forge server directory; +- `runtime117`: the installed Forge 37 server directory, including its + native argument files and `libraries` directory; - `captureJar`, `modJar` and `probeJar`: the fixture generator, packaged Base Metals candidate and packaged runtime probe; - `oreSpawn`: the release dependency, with `path` and `sha256`; @@ -68,7 +70,7 @@ Minecraft's player-advancement manager before checking it again on reload. `src/integrationTest/resources/upgrade/advancement_progress_113.json` covers an armour achievement and both ingot- and rod-based recipe discovery. -The 1.16 probe checks block identities and saved orientation/state, item +The 1.17 probe checks block identities and saved orientation/state, item identity and count, durability, names, enchantments, proof NBT, worn armour, playerdata and converted fluid buckets. Connected faces, powered states and flowing-fluid levels can change normally when Minecraft ticks the world; @@ -77,3 +79,10 @@ these are not treated as migration failures. `compare_world_terrain.py` compares solid vanilla terrain across the same world copies, including old numeric palettes and flattened palettes. It requires Python and `nbtlib`; it never writes either world. +Sand and gravel can fall when the upgraded world ticks. The comparison accounts +for each moved grain as a nearby landed block, falling entity or dropped item, +without allowing fixed terrain to change. Run its regression tests with: + +```sh +python -m unittest discover -s tools/validation -p test_world_terrain.py +``` diff --git a/tools/validation/test_legacy_worlds.js b/tools/validation/test_legacy_worlds.js index b675bb263..4fbe0f7c7 100644 --- a/tools/validation/test_legacy_worlds.js +++ b/tools/validation/test_legacy_worlds.js @@ -3,6 +3,7 @@ const fs = require('fs'); const path = require('path'); const crypto = require('crypto'); const { spawn } = require('child_process'); +const { serverArguments } = require('./forge_launcher'); const spec = JSON.parse(fs.readFileSync(process.argv[2], 'utf8')); const phase = process.argv[3] || 'upgrade'; @@ -37,10 +38,12 @@ function treeDigest(directory) { function prepare(directory, runtime, launcher, mods) { if (fs.existsSync(directory)) throw new Error('Refusing to overwrite ' + directory); fs.mkdirSync(path.join(directory, 'mods'), { recursive: true }); - for (const file of [launcher, 'minecraft_server.' + (phase === 'capture' ? captureVersion : '1.16.5') + '.jar']) { - fs.copyFileSync(path.join(runtime, file), path.join(directory, file)); + if (phase === 'capture') { + for (const file of [launcher, 'minecraft_server.' + captureVersion + '.jar']) { + fs.copyFileSync(path.join(runtime, file), path.join(directory, file)); + } + fs.cpSync(path.join(runtime, 'libraries'), path.join(directory, 'libraries'), { recursive: true }); } - fs.cpSync(path.join(runtime, 'libraries'), path.join(directory, 'libraries'), { recursive: true }); for (const mod of mods) { const file = typeof mod === 'string' ? mod : mod.path; if (mod.sha256 && digest(file).toLowerCase() !== mod.sha256.toLowerCase()) { @@ -64,11 +67,12 @@ function prepare(directory, runtime, launcher, mods) { function checkUpgradeLog(log) { // Forge reports these removed vanilla names when it reads an older registry snapshot. const retiredVanillaEntries = new Set([ + 'minecraft:grass_path', 'minecraft:zombie_pigman', 'minecraft:zombie_pigman_spawn_egg', 'minecraft:golem_last_seen_time', 'minecraft:opened_doors', 'minecraft:entity.zombie_pigman.ambient', 'minecraft:entity.zombie_pigman.angry', 'minecraft:entity.zombie_pigman.death', 'minecraft:entity.zombie_pigman.hurt', - 'minecraft:music.nether' + 'minecraft:music.nether', 'minecraft:item.sweet_berries.pick_from_bush' ]); const acceptedEntries = new Set(); const lines = log.split(/\r?\n/); @@ -77,8 +81,7 @@ function checkUpgradeLog(log) { const line = lines[index]; if (!/\/(?:ERROR|FATAL)\]/.test(line)) continue; - if (phase === 'upgrade' && line.includes('GameData/REGISTRIES') - && line.includes('Unidentified mapping from registry minecraft:')) { + if (phase === 'upgrade' && line.includes('Unidentified mapping from registry minecraft:')) { const entries = []; for (let next = index + 1; next < lines.length && lines[next].trim(); next++) { const entry = /^\s+(minecraft:[\w.]+): \d+$/.exec(lines[next]); @@ -92,7 +95,7 @@ function checkUpgradeLog(log) { } } - if (acceptedEntries.size && line.includes('GameData/REGISTRIES') + if (acceptedEntries.size && line.endsWith('There are unidentified mappings in this world - we are going to attempt to process anyway')) { continue; } @@ -106,7 +109,10 @@ function checkUpgradeLog(log) { async function run(directory, launcher, label, marker, properties = []) { console.log('Starting ' + label); const output = fs.createWriteStream(path.join(directory, label + '.log')); - const child = spawn(spec.java8, ['-Xms256m', '-Xmx2g', ...properties, '-jar', launcher, 'nogui'], + const executable = phase === 'capture' ? spec.java8 : spec.java16; + const launchArguments = phase === 'capture' ? ['-jar', launcher, 'nogui'] + : serverArguments(spec.runtime117, directory, '1.17.1', '37.1.1'); + const child = spawn(executable, ['-Xms256m', '-Xmx2g', ...properties, ...launchArguments], { cwd: directory, windowsHide: true, stdio: ['ignore', 'pipe', 'pipe'] }); child.stdout.pipe(output, { end: false }); child.stderr.pipe(output, { end: false }); @@ -152,8 +158,8 @@ async function run(directory, launcher, label, marker, properties = []) { } else { const source = profile.world || path.join(root, 'capture', profile.id, 'world'); const before = treeDigest(source); - const launcher = 'forge-1.16.5-36.2.34.jar'; - prepare(directory, spec.runtime116, launcher, [spec.modJar, spec.probeJar, spec.oreSpawn]); + const launcher = null; + prepare(directory, spec.runtime117, launcher, [spec.modJar, spec.probeJar, spec.oreSpawn]); fs.cpSync(source, path.join(directory, 'world'), { recursive: true }); if (profile.advancementFixture) { const fixture = JSON.parse(fs.readFileSync(profile.advancementFixture, 'utf8')); diff --git a/tools/validation/test_world_terrain.py b/tools/validation/test_world_terrain.py index f1e38b711..ea185b462 100644 --- a/tools/validation/test_world_terrain.py +++ b/tools/validation/test_world_terrain.py @@ -1,8 +1,10 @@ -"""Check both palette layouts used by the upgrade fixtures.""" +"""Regression tests for the read-only world-terrain comparison.""" import unittest +from pathlib import Path +from unittest.mock import patch -from compare_world_terrain import block_names +import compare_world_terrain as terrain class PaletteLayoutTest(unittest.TestCase): @@ -27,7 +29,62 @@ def test_contiguous_and_padded_palettes(self): section = {"Palette": [{"Name": str(index)} for index in range(palette_size)], "BlockStates": words} - self.assertEqual([str(value) for value in expected], list(block_names(section))) + self.assertEqual([str(value) for value in expected], list(terrain.block_names(section))) + + +def gravel(x=0.5, y=35, z=0.5, dimension=""): + return dimension, "minecraft:gravel", x, y, z + + +class FallingTerrainTest(unittest.TestCase): + def test_landed_block_is_recovered(self): + terrain.match_fallen_blocks([gravel()], [gravel(y=20)]) + + def test_in_flight_block_is_recovered(self): + terrain.match_fallen_blocks([gravel()], [gravel(y=32)]) + + def test_dropped_stack_can_drift(self): + terrain.match_fallen_blocks([gravel()], [gravel(x=3, y=20, z=2)]) + + def test_neighbouring_columns_do_not_greedily_take_each_others_blocks(self): + terrain.match_fallen_blocks([gravel(x=0), gravel(x=4)], + [gravel(x=4, y=20), gravel(x=8, y=20)]) + + def test_deleted_grain_is_rejected(self): + with self.assertRaises(AssertionError): + terrain.match_fallen_blocks([gravel()], []) + + def test_one_grain_cannot_cover_two_losses(self): + with self.assertRaises(AssertionError): + terrain.match_fallen_blocks([gravel(), gravel(y=36)], [gravel(y=20)]) + + def test_different_material_is_rejected(self): + with self.assertRaises(AssertionError): + terrain.match_fallen_blocks([gravel()], [("", "minecraft:sand", 0.5, 20, 0.5)]) + + def test_different_dimension_is_rejected(self): + with self.assertRaises(AssertionError): + terrain.match_fallen_blocks([gravel()], [gravel(y=20, dimension="DIM-1")]) + + def test_upward_replacement_is_rejected(self): + with self.assertRaises(AssertionError): + terrain.match_fallen_blocks([gravel()], [gravel(y=40)]) + + def test_distant_replacement_is_rejected(self): + with self.assertRaises(AssertionError): + terrain.match_fallen_blocks([gravel()], [gravel(x=5, y=20)]) + + def test_ore_replacing_fixed_terrain_is_rejected(self): + def chunk(name): + return {("DIM-1", 0, 0): {"Sections": [ + {"Y": 0, "Palette": [{"Name": name}]} + ]}} + + with patch.object(terrain, "chunks", side_effect=[chunk("minecraft:netherrack"), + chunk("minecraft:nether_quartz_ore")]), \ + patch.object(terrain, "falling_blocks", return_value={}): + with self.assertRaisesRegex(AssertionError, "netherrack became minecraft:nether_quartz_ore"): + terrain.compare(Path("original"), Path("upgraded")) if __name__ == "__main__":