diff --git a/src/generated/resources/data/c/tags/block/mineable/crowbar.json b/src/generated/resources/data/c/tags/block/mineable/crowbar.json new file mode 100644 index 00000000000..f72d209df78 --- /dev/null +++ b/src/generated/resources/data/c/tags/block/mineable/crowbar.json @@ -0,0 +1,3 @@ +{ + "values": [] +} \ No newline at end of file diff --git a/src/generated/resources/data/c/tags/block/mineable/hammer.json b/src/generated/resources/data/c/tags/block/mineable/hammer.json new file mode 100644 index 00000000000..f72d209df78 --- /dev/null +++ b/src/generated/resources/data/c/tags/block/mineable/hammer.json @@ -0,0 +1,3 @@ +{ + "values": [] +} \ No newline at end of file diff --git a/src/generated/resources/data/c/tags/block/mineable/knife.json b/src/generated/resources/data/c/tags/block/mineable/knife.json new file mode 100644 index 00000000000..f72d209df78 --- /dev/null +++ b/src/generated/resources/data/c/tags/block/mineable/knife.json @@ -0,0 +1,3 @@ +{ + "values": [] +} \ No newline at end of file diff --git a/src/generated/resources/data/c/tags/block/mineable/saw.json b/src/generated/resources/data/c/tags/block/mineable/saw.json new file mode 100644 index 00000000000..ad211a820b2 --- /dev/null +++ b/src/generated/resources/data/c/tags/block/mineable/saw.json @@ -0,0 +1,5 @@ +{ + "values": [ + "#minecraft:ice" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/gtceu/tags/block/cleanroom_doors.json b/src/generated/resources/data/gtceu/tags/block/cleanroom_doors.json index 065692498ac..d04d629668e 100644 --- a/src/generated/resources/data/gtceu/tags/block/cleanroom_doors.json +++ b/src/generated/resources/data/gtceu/tags/block/cleanroom_doors.json @@ -1,6 +1,10 @@ { "values": [ "minecraft:iron_door", - "#minecraft:wooden_doors" + "#minecraft:wooden_doors", + "minecraft:waxed_copper_door", + "minecraft:waxed_exposed_copper_door", + "minecraft:waxed_weathered_copper_door", + "minecraft:waxed_oxidized_copper_door" ] } \ No newline at end of file diff --git a/src/main/java/com/gregtechceu/gtceu/api/capability/recipe/FluidRecipeCapability.java b/src/main/java/com/gregtechceu/gtceu/api/capability/recipe/FluidRecipeCapability.java index b855cb32445..3d950de8c56 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/capability/recipe/FluidRecipeCapability.java +++ b/src/main/java/com/gregtechceu/gtceu/api/capability/recipe/FluidRecipeCapability.java @@ -68,42 +68,37 @@ public IntProviderFluidIngredient copyWithModifier(IntProviderFluidIngredient co @Override public List compressIngredients(@Unmodifiable Collection ingredients) { - List list = new ObjectArrayList<>(ingredients.size()); - for (Object item : ingredients) { - if (item instanceof SizedFluidIngredient fluid) { - boolean isEqual = false; + List list = new ArrayList<>(ingredients.size()); + mainLoop: + for (Object entry : ingredients) { + if (entry instanceof SizedFluidIngredient ingredient) { for (Object obj : list) { - if (obj instanceof SizedFluidIngredient SizedFluidIngredient) { - if (fluid.equals(SizedFluidIngredient)) { - isEqual = true; - break; + if (obj instanceof SizedFluidIngredient other) { + if (ingredient.equals(other)) { + continue mainLoop; } - } else if (obj instanceof FluidStack fluidStack) { - if (fluid.ingredient().test(fluidStack)) { - isEqual = true; - break; + } else if (obj instanceof FluidStack other) { + if (ingredient.ingredient().test(other)) { + continue mainLoop; } } } - if (isEqual) continue; - list.add(fluid); - } else if (item instanceof FluidStack fluidStack) { - boolean isEqual = false; + + list.add(ingredient); + } else if (entry instanceof FluidStack stack) { for (Object obj : list) { - if (obj instanceof SizedFluidIngredient fluidIngredient) { - if (fluidIngredient.ingredient().test(fluidStack)) { - isEqual = true; - break; + if (obj instanceof SizedFluidIngredient other) { + if (other.ingredient().test(stack)) { + continue mainLoop; } - } else if (obj instanceof FluidStack stack) { - if (FluidStack.isSameFluidSameComponents(fluidStack, stack)) { - isEqual = true; - break; + } else if (obj instanceof FluidStack other) { + if (FluidStack.isSameFluidSameComponents(stack, other)) { + continue mainLoop; } } } - if (isEqual) continue; - list.add(fluidStack); + + list.add(stack); } } return list; diff --git a/src/main/java/com/gregtechceu/gtceu/api/capability/recipe/ItemRecipeCapability.java b/src/main/java/com/gregtechceu/gtceu/api/capability/recipe/ItemRecipeCapability.java index 5db061b9ec1..41c76d7813c 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/capability/recipe/ItemRecipeCapability.java +++ b/src/main/java/com/gregtechceu/gtceu/api/capability/recipe/ItemRecipeCapability.java @@ -69,47 +69,36 @@ public IntProviderIngredient copyWithModifier(IntProviderIngredient content, Con @Override public List compressIngredients(@Unmodifiable Collection ingredients) { - List list = new ObjectArrayList<>(ingredients.size()); - for (Object item : ingredients) { - if (item instanceof SizedIngredient ingredient) { - boolean isEqual = false; + List list = new ArrayList<>(ingredients.size()); + MAIN_LOOP: + for (Object entry : ingredients) { + if (entry instanceof SizedIngredient ingredient) { for (Object obj : list) { if (obj instanceof SizedIngredient ingredient1) { if (ingredient.ingredient().equals(ingredient1.ingredient())) { - isEqual = true; - break; + continue MAIN_LOOP; } } else if (obj instanceof ItemStack stack) { if (ingredient.ingredient().test(stack)) { - isEqual = true; - break; + continue MAIN_LOOP; } } } - if (isEqual) continue; - // spotless:off - if (ingredient.getContainedCustom() instanceof IntCircuitIngredient) { - list.addFirst(ingredient); - } else { - list.add(ingredient); - } - // spotless:on - } else if (item instanceof ItemStack stack) { - boolean isEqual = false; + + list.add(ingredient); + } else if (entry instanceof ItemStack stack) { for (Object obj : list) { - if (obj instanceof Ingredient ingredient) { - if (ingredient.test(stack)) { - isEqual = true; - break; + if (obj instanceof SizedIngredient ingredient) { + if (ingredient.ingredient().test(stack)) { + continue MAIN_LOOP; } } else if (obj instanceof ItemStack stack1) { if (ItemStack.isSameItemSameComponents(stack, stack1)) { - isEqual = true; - break; + continue MAIN_LOOP; } } } - if (isEqual) continue; + list.add(stack); } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/data/chemical/ChemicalHelper.java b/src/main/java/com/gregtechceu/gtceu/api/data/chemical/ChemicalHelper.java index 4a85ac25eab..9632383ec96 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/data/chemical/ChemicalHelper.java +++ b/src/main/java/com/gregtechceu/gtceu/api/data/chemical/ChemicalHelper.java @@ -19,6 +19,7 @@ import net.minecraft.tags.TagKey; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.level.ItemLike; import net.minecraft.world.level.block.Block; @@ -249,6 +250,16 @@ public static List getItems(MaterialEntry materialEntry) { }).stream().map(Supplier::get).collect(Collectors.toList()); } + public static Item getItem(MaterialEntry materialEntry) { + List items = getItems(materialEntry); + if (items.isEmpty()) return Items.AIR; + return items.get(0).asItem(); + } + + public static Item getItem(TagPrefix tagPrefix, Material material) { + return getItem(new MaterialEntry(tagPrefix, material)); + } + public static ItemStack get(MaterialEntry materialEntry, int size) { var list = getItems(materialEntry); if (list.isEmpty()) return ItemStack.EMPTY; diff --git a/src/main/java/com/gregtechceu/gtceu/api/data/tag/TagPrefix.java b/src/main/java/com/gregtechceu/gtceu/api/data/tag/TagPrefix.java index a07041b5781..ee4d4b68db0 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/data/tag/TagPrefix.java +++ b/src/main/java/com/gregtechceu/gtceu/api/data/tag/TagPrefix.java @@ -23,6 +23,7 @@ import com.gregtechceu.gtceu.data.recipe.CustomTags; import com.gregtechceu.gtceu.integration.recipeviewer.widgets.GTOreByProduct; import com.gregtechceu.gtceu.utils.FormattingUtil; +import com.gregtechceu.gtceu.utils.TagUtil; import com.gregtechceu.gtceu.utils.memoization.GTMemoizer; import net.minecraft.client.renderer.RenderType; @@ -195,8 +196,8 @@ public boolean isEmpty() { public static final TagPrefix rawOre = new TagPrefix(GTCEu.id("raw"), true) .idPattern("raw_%s") - .defaultTagPath("raw_materials/%s") - .unformattedTagPath("raw_materials") + .defaultTag("raw_materials/%s") + .unformattedTag("raw_materials") .langValue("Raw %s") .materialIconType(MaterialIconType.rawOre) .unificationEnabled(true) @@ -205,8 +206,8 @@ public boolean isEmpty() { public static final TagPrefix rawOreBlock = new TagPrefix(GTCEu.id("raw_ore_block")) .idPattern("raw_%s_block") - .defaultTagPath("storage_blocks/raw_%s") - .unformattedTagPath("storage_blocks") + .defaultTag("storage_blocks/raw_%s") + .unformattedTag("storage_blocks") .langValue("Block of Raw %s") .materialIconType(MaterialIconType.rawOreBlock) .miningToolTag(BlockTags.MINEABLE_WITH_PICKAXE) @@ -216,8 +217,8 @@ public boolean isEmpty() { public static final TagPrefix crushedRefined = new TagPrefix(GTCEu.id("refined_ore")) .idPattern("refined_%s_ore") - .defaultTagPath("refined_ores/%s") - .defaultTagPath("refined_ores") + .defaultTag("refined_ores/%s") + .unformattedTag("refined_ores") .langValue("Refined %s Ore") .materialIconType(MaterialIconType.crushedRefined) .unificationEnabled(true) @@ -226,8 +227,8 @@ public boolean isEmpty() { public static final TagPrefix crushedPurified = new TagPrefix(GTCEu.id("purified_ore")) .idPattern("purified_%s_ore") - .defaultTagPath("purified_ores/%s") - .defaultTagPath("purified_ores") + .defaultTag("purified_ores/%s") + .unformattedTag("purified_ores") .customTagPredicate("siftables", false, m -> m.hasProperty(PropertyKey.GEM)) .langValue("Purified %s Ore") .materialIconType(MaterialIconType.crushedPurified) @@ -237,8 +238,21 @@ public boolean isEmpty() { public static final TagPrefix crushed = new TagPrefix(GTCEu.id("crushed_ore")) .idPattern("crushed_%s_ore") - .defaultTagPath("crushed_ores/%s") - .unformattedTagPath("crushed_ores") + .defaultTag("crushed_ores/%s") + .unformattedTag("crushed_ores") + .filteredCustomTag("chemical_bath_washable/%s", mat -> { + if (!mat.hasProperty(PropertyKey.ORE)) return false; + Material washedIn = mat.getProperty(PropertyKey.ORE).getWashedIn().first(); + return !washedIn.isNull(); + }, (path, mat) -> { + Material washedIn = mat.getProperty(PropertyKey.ORE).getWashedIn().first(); + return TagUtil.createItemTag(path.formatted(washedIn.getName())); + }) + .filteredUnformattedTag("chemical_bath_washable", false, mat -> { + if (!mat.hasProperty(PropertyKey.ORE)) return false; + Material washedIn = mat.getProperty(PropertyKey.ORE).getWashedIn().first(); + return !washedIn.isNull(); + }) .langValue("Crushed %s Ore") .materialIconType(MaterialIconType.crushed) .unificationEnabled(true) @@ -249,8 +263,8 @@ public boolean isEmpty() { // A hot Ingot, which has to be cooled down by a Vacuum Freezer. public static final TagPrefix ingotHot = new TagPrefix(GTCEu.id("hot_ingot")) .idPattern("hot_%s_ingot") - .defaultTagPath("hot_ingots/%s") - .unformattedTagPath("hot_ingots") + .defaultTag("hot_ingots/%s") + .unformattedTag("hot_ingots") .langValue("Hot %s Ingot") .materialAmount(GTValues.M) .materialIconType(MaterialIconType.ingotHot) @@ -261,8 +275,8 @@ public boolean isEmpty() { // A regular Ingot. public static final TagPrefix ingot = new TagPrefix(GTCEu.id("ingot")) - .defaultTagPath("ingots/%s") - .unformattedTagPath("ingots") + .defaultTag("ingots/%s") + .unformattedTag("ingots") .materialAmount(GTValues.M) .materialIconType(MaterialIconType.ingot) .unificationEnabled(true) @@ -272,8 +286,8 @@ public boolean isEmpty() { // A regular Gem worth one Dust. public static final TagPrefix gem = new TagPrefix(GTCEu.id("gem")) - .defaultTagPath("gems/%s") - .unformattedTagPath("gems") + .defaultTag("gems/%s") + .unformattedTag("gems") .langValue("%s") .materialAmount(GTValues.M) .materialIconType(MaterialIconType.gem) @@ -285,8 +299,8 @@ public boolean isEmpty() { // A regular Gem worth one small Dust. public static final TagPrefix gemChipped = new TagPrefix(GTCEu.id("chipped_gem")) .idPattern("chipped_%s_gem") - .defaultTagPath("chipped_gems/%s") - .unformattedTagPath("chipped_gems") + .defaultTag("chipped_gems/%s") + .unformattedTag("chipped_gems") .langValue("Chipped %s") .materialAmount(GTValues.M / 4) .materialIconType(MaterialIconType.gemChipped) @@ -298,8 +312,8 @@ public boolean isEmpty() { // A regular Gem worth two small Dusts. public static final TagPrefix gemFlawed = new TagPrefix(GTCEu.id("flawed_gem")) .idPattern("flawed_%s_gem") - .defaultTagPath("flawed_gems/%s") - .unformattedTagPath("flawed_gems") + .defaultTag("flawed_gems/%s") + .unformattedTag("flawed_gems") .langValue("Flawed %s") .materialAmount(GTValues.M / 2) .materialIconType(MaterialIconType.gemFlawed) @@ -311,8 +325,8 @@ public boolean isEmpty() { // A regular Gem worth two Dusts. public static final TagPrefix gemFlawless = new TagPrefix(GTCEu.id("flawless_gem")) .idPattern("flawless_%s_gem") - .defaultTagPath("flawless_gems/%s") - .unformattedTagPath("flawless_gems") + .defaultTag("flawless_gems/%s") + .unformattedTag("flawless_gems") .langValue("Flawless %s") .materialAmount(GTValues.M * 2) .maxStackSize(32) @@ -325,8 +339,8 @@ public boolean isEmpty() { // A regular Gem worth four Dusts. public static final TagPrefix gemExquisite = new TagPrefix(GTCEu.id("exquisite_gem")) .idPattern("exquisite_%s_gem") - .defaultTagPath("exquisite_gems/%s") - .unformattedTagPath("exquisite_gems") + .defaultTag("exquisite_gems/%s") + .unformattedTag("exquisite_gems") .langValue("Exquisite %s") .materialAmount(GTValues.M * 4) .maxStackSize(16) @@ -339,8 +353,8 @@ public boolean isEmpty() { // 1/4th of a Dust. public static final TagPrefix dustSmall = new TagPrefix(GTCEu.id("small_dust")) .idPattern("small_%s_dust") - .defaultTagPath("small_dusts/%s") - .unformattedTagPath("small_dusts") + .defaultTag("small_dusts/%s") + .unformattedTag("small_dusts") .langValue("Small Pile of %s Dust") .materialAmount(GTValues.M / 4) .materialIconType(MaterialIconType.dustSmall) @@ -351,8 +365,8 @@ public boolean isEmpty() { // 1/9th of a Dust. public static final TagPrefix dustTiny = new TagPrefix(GTCEu.id("tiny_dust")) .idPattern("tiny_%s_dust") - .defaultTagPath("tiny_dusts/%s") - .unformattedTagPath("tiny_dusts") + .defaultTag("tiny_dusts/%s") + .unformattedTag("tiny_dusts") .langValue("Tiny Pile of %s Dust") .materialAmount(GTValues.M / 9) .materialIconType(MaterialIconType.dustTiny) @@ -363,8 +377,8 @@ public boolean isEmpty() { // Dust with impurities. 1 Unit of Main Material and 1/9 - 1/4 Unit of secondary Material public static final TagPrefix dustImpure = new TagPrefix(GTCEu.id("impure_dust")) .idPattern("impure_%s_dust") - .defaultTagPath("impure_dusts/%s") - .unformattedTagPath("impure_dusts") + .defaultTag("impure_dusts/%s") + .unformattedTag("impure_dusts") .langValue("Impure Pile of %s Dust") .materialAmount(GTValues.M) .materialIconType(MaterialIconType.dustImpure) @@ -376,8 +390,8 @@ public boolean isEmpty() { // Pure Dust worth of one Ingot or Gem. public static final TagPrefix dustPure = new TagPrefix(GTCEu.id("pure_dust")) .idPattern("pure_%s_dust") - .defaultTagPath("pure_dusts/%s") - .unformattedTagPath("pure_dusts") + .defaultTag("pure_dusts/%s") + .unformattedTag("pure_dusts") .langValue("Purified Pile of %s Dust") .materialAmount(GTValues.M) .materialIconType(MaterialIconType.dustPure) @@ -387,8 +401,8 @@ public boolean isEmpty() { .tooltip((mat, tooltips) -> tooltips.add(Component.translatable("metaitem.dust.tooltip.purify"))); public static final TagPrefix dust = new TagPrefix(GTCEu.id("dust")) - .defaultTagPath("dusts/%s") - .unformattedTagPath("dusts") + .defaultTag("dusts/%s") + .unformattedTag("dusts") .materialAmount(GTValues.M) .materialIconType(MaterialIconType.dust) .unificationEnabled(true) @@ -398,8 +412,8 @@ public boolean isEmpty() { // A Nugget. public static final TagPrefix nugget = new TagPrefix(GTCEu.id("nugget")) - .defaultTagPath("nuggets/%s") - .unformattedTagPath("nuggets") + .defaultTag("nuggets/%s") + .unformattedTag("nuggets") .materialAmount(GTValues.M / 9) .materialIconType(MaterialIconType.nugget) .unificationEnabled(true) @@ -410,8 +424,8 @@ public boolean isEmpty() { // 9 Plates combined in one Item. public static final TagPrefix plateDense = new TagPrefix(GTCEu.id("dense_plate")) .idPattern("dense_%s_plate") - .defaultTagPath("dense_plates/%s") - .unformattedTagPath("dense_plates") + .defaultTag("dense_plates/%s") + .unformattedTag("dense_plates") .langValue("Dense %s Plate") .materialAmount(GTValues.M * 9) .maxStackSize(7) @@ -424,8 +438,8 @@ public boolean isEmpty() { // 2 Plates combined in one Item public static final TagPrefix plateDouble = new TagPrefix(GTCEu.id("double_plate")) .idPattern("double_%s_plate") - .defaultTagPath("double_plates/%s") - .unformattedTagPath("double_plates") + .defaultTag("double_plates/%s") + .unformattedTag("double_plates") .langValue("Double %s Plate") .materialAmount(GTValues.M * 2) .maxStackSize(32) @@ -438,8 +452,8 @@ public boolean isEmpty() { // Regular Plate made of one Ingot/Dust. public static final TagPrefix plate = new TagPrefix(GTCEu.id("plate")) - .defaultTagPath("plates/%s") - .unformattedTagPath("plates") + .defaultTag("plates/%s") + .unformattedTag("plates") .materialAmount(GTValues.M) .materialIconType(MaterialIconType.plate) .unificationEnabled(true) @@ -449,8 +463,8 @@ public boolean isEmpty() { // Round made of 1 Nugget public static final TagPrefix round = new TagPrefix(GTCEu.id("round")) - .defaultTagPath("rounds/%s") - .unformattedTagPath("rounds") + .defaultTag("rounds/%s") + .unformattedTag("rounds") .materialAmount(GTValues.M / 9) .materialIconType(MaterialIconType.round) .unificationEnabled(true) @@ -460,8 +474,8 @@ public boolean isEmpty() { // Foil made of 1/4 Ingot/Dust. public static final TagPrefix foil = new TagPrefix(GTCEu.id("foil")) - .defaultTagPath("foils/%s") - .unformattedTagPath("foils") + .defaultTag("foils/%s") + .unformattedTag("foils") .materialAmount(GTValues.M / 4) .materialIconType(MaterialIconType.foil) .unificationEnabled(true) @@ -472,8 +486,8 @@ public boolean isEmpty() { // Stick made of an Ingot. public static final TagPrefix rodLong = new TagPrefix(GTCEu.id("long_rod")) .idPattern("long_%s_rod") - .defaultTagPath("rods/long/%s") - .unformattedTagPath("rods/long") + .defaultTag("rods/long/%s") + .unformattedTag("rods/long") .langValue("Long %s Rod") .materialAmount(GTValues.M) .materialIconType(MaterialIconType.rodLong) @@ -484,8 +498,8 @@ public boolean isEmpty() { // Stick made of half an Ingot. public static final TagPrefix rod = new TagPrefix(GTCEu.id("rod")) - .defaultTagPath("rods/%s") - .unformattedTagPath("rods") + .defaultTag("rods/%s") + .unformattedTag("rods") .langValue("%s Rod") .materialAmount(GTValues.M / 2) .materialIconType(MaterialIconType.rod) @@ -496,8 +510,8 @@ public boolean isEmpty() { // consisting out of 1/8 Ingot or 1/4 Stick. public static final TagPrefix bolt = new TagPrefix(GTCEu.id("bolt")) - .defaultTagPath("bolts/%s") - .unformattedTagPath("bolts") + .defaultTag("bolts/%s") + .unformattedTag("bolts") .materialAmount(GTValues.M / 8) .materialIconType(MaterialIconType.bolt) .unificationEnabled(true) @@ -507,8 +521,8 @@ public boolean isEmpty() { // consisting out of 1/9 Ingot. public static final TagPrefix screw = new TagPrefix(GTCEu.id("screw")) - .defaultTagPath("screws/%s") - .unformattedTagPath("screws") + .defaultTag("screws/%s") + .unformattedTag("screws") .materialAmount(GTValues.M / 9) .materialIconType(MaterialIconType.screw) .unificationEnabled(true) @@ -518,8 +532,8 @@ public boolean isEmpty() { // consisting out of 1/2 Stick. public static final TagPrefix ring = new TagPrefix(GTCEu.id("ring")) - .defaultTagPath("rings/%s") - .unformattedTagPath("rings") + .defaultTag("rings/%s") + .unformattedTag("rings") .materialAmount(GTValues.M / 4) .materialIconType(MaterialIconType.ring) .unificationEnabled(true) @@ -530,8 +544,8 @@ public boolean isEmpty() { // consisting out of 1 Fine Wire. public static final TagPrefix springSmall = new TagPrefix(GTCEu.id("small_spring")) .idPattern("small_%s_spring") - .defaultTagPath("small_springs/%s") - .unformattedTagPath("small_springs") + .defaultTag("small_springs/%s") + .unformattedTag("small_springs") .langValue("Small %s Spring") .materialAmount(GTValues.M / 4) .materialIconType(MaterialIconType.springSmall) @@ -543,8 +557,8 @@ public boolean isEmpty() { // consisting out of 2 Sticks. public static final TagPrefix spring = new TagPrefix(GTCEu.id("spring")) - .defaultTagPath("springs/%s") - .unformattedTagPath("springs") + .defaultTag("springs/%s") + .unformattedTag("springs") .materialAmount(GTValues.M) .materialIconType(MaterialIconType.spring) .unificationEnabled(true) @@ -556,8 +570,8 @@ public boolean isEmpty() { // consisting out of 1/8 Ingot or 1/4 Wire. public static final TagPrefix wireFine = new TagPrefix(GTCEu.id("fine_wire")) .idPattern("fine_%s_wire") - .defaultTagPath("fine_wires/%s") - .unformattedTagPath("fine_wires") + .defaultTag("fine_wires/%s") + .unformattedTag("fine_wires") .langValue("Fine %s Wire") .materialAmount(GTValues.M / 8) .materialIconType(MaterialIconType.wireFine) @@ -568,8 +582,8 @@ public boolean isEmpty() { // consisting out of 4 Plates, 1 Ring and 1 Screw. public static final TagPrefix rotor = new TagPrefix(GTCEu.id("rotor")) - .defaultTagPath("rotors/%s") - .unformattedTagPath("rotors") + .defaultTag("rotors/%s") + .unformattedTag("rotors") .materialAmount(GTValues.M * 4) .maxStackSize(16) .materialIconType(MaterialIconType.rotor) @@ -581,8 +595,8 @@ public boolean isEmpty() { // Consisting of 1 Plate. public static final TagPrefix gearSmall = new TagPrefix(GTCEu.id("small_gear")) .idPattern("small_%s_gear") - .defaultTagPath("small_gears/%s") - .unformattedTagPath("small_gears") + .defaultTag("small_gears/%s") + .unformattedTag("small_gears") .langValue("Small %s Gear") .materialAmount(GTValues.M) .materialIconType(MaterialIconType.gearSmall) @@ -593,8 +607,8 @@ public boolean isEmpty() { // Consisting of 4 Plates. public static final TagPrefix gear = new TagPrefix(GTCEu.id("gear")) - .defaultTagPath("gears/%s") - .unformattedTagPath("gears") + .defaultTag("gears/%s") + .unformattedTag("gears") .materialAmount(GTValues.M * 4) .maxStackSize(16) .materialIconType(MaterialIconType.gear) @@ -605,8 +619,8 @@ public boolean isEmpty() { // 3/4 of a Plate or Gem used to shape a Lens. Normally only used on Transparent Materials. public static final TagPrefix lens = new TagPrefix(GTCEu.id("lens")) - .defaultTagPath("lenses/%s") - .unformattedTagPath("lenses") + .defaultTag("lenses/%s") + .unformattedTag("lenses") .materialAmount((GTValues.M * 3) / 4) .materialIconType(MaterialIconType.lens) .unificationEnabled(true) @@ -615,8 +629,8 @@ public boolean isEmpty() { .generationCondition(mat -> mat.hasFlag(MaterialFlags.GENERATE_LENS)); public static final TagPrefix dye = new TagPrefix(GTCEu.id("dye")) - .defaultTagPath("dyes/%s") - .unformattedTagPath("dyes") + .defaultTag("dyes/%s") + .unformattedTag("dyes") .materialAmount(-1); // made of 4 Ingots. @@ -711,8 +725,8 @@ public boolean isEmpty() { // Storage Block consisting out of 9 Ingots/Gems/Dusts. public static final TagPrefix block = new TagPrefix(GTCEu.id("block")) - .defaultTagPath("storage_blocks/%s") - .unformattedTagPath("storage_blocks") + .defaultTag("storage_blocks/%s") + .unformattedTag("storage_blocks") .langValue("Block of %s") .materialAmount(GTValues.M * 9) .materialIconType(MaterialIconType.block) @@ -724,24 +738,25 @@ public boolean isEmpty() { .enableRecycling(); public static final TagPrefix log = new TagPrefix(GTCEu.id("log")) - .unformattedTagPath("logs", true); + .unformattedTag("logs", true); public static final TagPrefix planks = new TagPrefix(GTCEu.id("planks")) - .unformattedTagPath("planks", true); + .unformattedTag("planks", true); public static final TagPrefix slab = new TagPrefix(GTCEu.id("slab")) - .unformattedTagPath("slabs", true); + .unformattedTag("slabs", true); public static final TagPrefix stairs = new TagPrefix(GTCEu.id("stairs")) - .unformattedTagPath("stairs", true); + .unformattedTag("stairs", true); public static final TagPrefix fence = new TagPrefix(GTCEu.id("fence")) - .unformattedTagPath("fences"); + .unformattedTag("fences"); public static final TagPrefix fenceGate = new TagPrefix(GTCEu.id("fence_gate")) - .unformattedTagPath("fence_gates"); + .unformattedTag("fence_gates"); public static final TagPrefix door = new TagPrefix(GTCEu.id("door")) - .unformattedTagPath("doors", true); + .unformattedTag("doors", true); // Prefix to determine which kind of Rock this is. // Also has a base tag path of only the material, for things like obsidian etc. public static final TagPrefix rock = new TagPrefix(GTCEu.id("rock")) - .defaultTagPath("%s") + // the 2nd 's' makes the tag plural, which is what Common tags are expected to be. + .defaultTag("%ss") .langValue("%s") .miningToolTag(BlockTags.MINEABLE_WITH_PICKAXE) .unificationEnabled(false) @@ -749,8 +764,8 @@ public boolean isEmpty() { .generationCondition((material) -> false); public static final TagPrefix frameGt = new TagPrefix(GTCEu.id("frame")) - .defaultTagPath("frames/%s") - .unformattedTagPath("frames") + .defaultTag("frames/%s") + .unformattedTag("frames") .langValue("%s Frame") .materialAmount(GTValues.M * 2) .materialIconType(MaterialIconType.frameGt) @@ -945,8 +960,8 @@ public boolean isEmpty() { public static final TagPrefix surfaceRock = new TagPrefix(GTCEu.id("surface_rock")) .langValue("%s Surface Rock") - .defaultTagPath("surface_rocks/%s") - .unformattedTagPath("surface_rocks") + .defaultTag("surface_rocks/%s") + .unformattedTag("surface_rocks") .materialAmount(GTValues.M / 3); public static class Conditions { @@ -1077,9 +1092,9 @@ public static TagPrefix oreTagPrefix(String name, TagKey miningToolTag) { public static TagPrefix oreTagPrefix(ResourceLocation id, TagKey miningToolTag) { return new TagPrefix(id) - .defaultTagPath("ores/%s") - .prefixOnlyTagPath("ores_in_ground/%s") - .unformattedTagPath("ores") + .defaultTag("ores/%s") + .prefixOnlyTag("ores_in_ground/%s") + .unformattedTag("ores") .materialIconType(MaterialIconType.ore) .miningToolTag(miningToolTag) .unificationEnabled(true) @@ -1121,41 +1136,156 @@ public TagPrefix registerOre(Supplier stoneType, Supplier return this; } + /** + * @deprecated use {@link #defaultTag(String)} instead. + */ + @Deprecated(since = "8.0.0", forRemoval = true) public TagPrefix defaultTagPath(String path) { - return this.defaultTagPath(path, false); + return defaultTag(path); } + /** + * Create a tag with a specified path with the "default" formatter, meaning there should be one "%s" format + * specifier in the path, intended for the material name. + */ + public TagPrefix defaultTag(String path) { + return defaultTag(path, false); + } + + /** + * @deprecated use {@link #defaultTag(String, boolean)} instead. + */ + @Deprecated(since = "8.0.0", forRemoval = true) public TagPrefix defaultTagPath(String path, boolean isVanilla) { + return defaultTag(path, false); + } + + /** + * Create a tag with a specified path with the "default" formatter, meaning there should be one "%s" format + * specifier in the path, intended for the material name. + */ + public TagPrefix defaultTag(String path, boolean isVanilla) { this.tags.add(TagType.withDefaultFormatter(path, isVanilla)); return this; } + /** + * @deprecated use {@link #prefixTag(String)} instead. + */ + @Deprecated(since = "8.0.0", forRemoval = true) public TagPrefix prefixTagPath(String path) { + return prefixTag(path); + } + + /** + * Create a tag with a specified path with the "prefix" formatter, meaning there should be two "%s" format + * specifiers in the path, with the first being the prefix name and the second being the material name. + */ + public TagPrefix prefixTag(String path) { this.tags.add(TagType.withPrefixFormatter(path)); return this; } + /** + * @deprecated use {@link #prefixOnlyTag(String)} instead. + */ + @Deprecated(since = "8.0.0", forRemoval = true) public TagPrefix prefixOnlyTagPath(String path) { + return prefixOnlyTag(path); + } + + /** + * Create a tag with a specified path with the "prefix only" formatter, meaning there should be one "%s" format + * specifier in the path, intended for the prefix name. + */ + public TagPrefix prefixOnlyTag(String path) { this.tags.add(TagType.withPrefixOnlyFormatter(path)); return this; } + /** + * @deprecated use {@link #unformattedTag(String)} instead. + */ + @Deprecated(since = "8.0.0", forRemoval = true) public TagPrefix unformattedTagPath(String path) { - return unformattedTagPath(path, false); + return unformattedTag(path); + } + + /** + * Create a tag with a specified path with no formatter, meaning there should be no "%s" format specifiers in + * the path and that it's usable as a tag key's path as is. + */ + public TagPrefix unformattedTag(String path) { + return unformattedTag(path, false); } + /** + * @deprecated use {@link #unformattedTag(String)} instead. + */ + @Deprecated(since = "8.0.0", forRemoval = true) public TagPrefix unformattedTagPath(String path, boolean isVanilla) { + return unformattedTag(path, isVanilla); + } + + /** + * Create a tag with a specified path with no formatter, meaning there should be no "%s" format specifiers in + * the path and that it's usable as a tag key's path as is. + */ + public TagPrefix unformattedTag(String path, boolean isVanilla) { this.tags.add(TagType.withNoFormatter(path, isVanilla)); return this; } + /** + * @deprecated use {@link #customFormattedTag(String, BiFunction)} instead. + */ + @Deprecated(since = "8.0.0", forRemoval = true) public TagPrefix customTagPath(String path, BiFunction> formatter) { - this.tags.add(TagType.withCustomFormatter(path, formatter)); + this.tags.add(TagType.withCustomFormatter(formatter)); return this; } + /** + * Create a tag with a specified path with a custom formatter. + */ + public TagPrefix customFormattedTag(String path, BiFunction> formatter) { + this.tags.add(TagType.withCustomFormatter((self, mat) -> formatter.apply(path, mat))); + return this; + } + + /** + * @deprecated use {@link #filteredUnformattedTag(String, boolean, Predicate)} instead. + */ + @Deprecated(since = "8.0.0", forRemoval = true) public TagPrefix customTagPredicate(String path, boolean isVanilla, Predicate materialPredicate) { - this.tags.add(TagType.withCustomFilter(path, isVanilla, materialPredicate)); + return this.filteredUnformattedTag(path, isVanilla, materialPredicate); + } + + /** + * Create a tag with a specified path with no formatter, meaning there should be no "%s" format specifiers in + * the path and that it's usable as a tag key's path as is. + *

+ * This variant of the method accepts an additional argument for a filter that'll be used to decide whether a + * specific material should be added to the tag. + */ + public TagPrefix filteredUnformattedTag(String path, boolean isVanilla, Predicate materialPredicate) { + TagType entry = TagType.withNoFormatter(path, isVanilla); + entry.filter = materialPredicate; + this.tags.add(entry); + return this; + } + + /** + * Create a tag with a specified path with a custom formatter. + *

+ * This variant of the method accepts an additional argument for a filter that'll be used to decide whether a + * specific material should be added to the tag. + */ + public TagPrefix filteredCustomTag(String path, Predicate materialPredicate, + BiFunction> formatter) { + TagType entry = TagType.withCustomFormatter((self, mat) -> formatter.apply(path, mat)); + entry.filter = materialPredicate; + this.tags.add(entry); return this; } diff --git a/src/main/java/com/gregtechceu/gtceu/api/data/tag/TagType.java b/src/main/java/com/gregtechceu/gtceu/api/data/tag/TagType.java index 7d14384c0db..09429a8ea19 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/data/tag/TagType.java +++ b/src/main/java/com/gregtechceu/gtceu/api/data/tag/TagType.java @@ -8,35 +8,34 @@ import net.minecraft.world.item.Item; import lombok.Getter; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.function.BiFunction; import java.util.function.Predicate; -public class TagType { +@ApiStatus.Internal +public final class TagType { - private final String tagPath; @Getter private boolean isParentTag = false; // this is now memoized because creating tag keys interns them and that's slow - private BiFunction> formatter; - private Predicate filter; + private final @NotNull BiFunction> formatter; + @Nullable + /* package-private */ Predicate filter; - private TagType(String tagPath) { - this.tagPath = tagPath; + private TagType(BiFunction> formatter) { + this.formatter = Util.memoize(formatter); } - // formatter:off + // spotless:off /** * Create a tag with a specified path, with the "default" formatter, meaning * that there is 1 "%s" format character in the path, intended for the Material name. */ public static TagType withDefaultFormatter(String tagPath, boolean isVanilla) { - TagType type = new TagType(tagPath); - type.formatter = Util - .memoize((prefix, mat) -> TagUtil.createItemTag(type.tagPath.formatted(mat.getName()), isVanilla)); - return type; + return new TagType((prefix, mat) -> TagUtil.createItemTag(tagPath.formatted(mat.getName()), isVanilla)); } /** @@ -45,10 +44,7 @@ public static TagType withDefaultFormatter(String tagPath, boolean isVanilla) { * prefix name, and the second being the material name. */ public static TagType withPrefixFormatter(String tagPath) { - TagType type = new TagType(tagPath); - type.formatter = Util.memoize((prefix, mat) -> TagUtil.createItemTag( - type.tagPath.formatted(prefix.name, mat.getName()))); - return type; + return new TagType((prefix, mat) -> TagUtil.createItemTag(tagPath.formatted(prefix.name, mat.getName()))); } /** @@ -56,37 +52,24 @@ public static TagType withPrefixFormatter(String tagPath) { * that there is 1 "%s" format character in the path, intended for the prefix name. */ public static TagType withPrefixOnlyFormatter(String tagPath) { - TagType type = new TagType(tagPath); - type.formatter = Util.memoize((prefix, mat) -> TagUtil - .createItemTag(type.tagPath.formatted(prefix.name))); + TagType type = new TagType((prefix, mat) -> TagUtil.createItemTag(tagPath.formatted(prefix.name))); type.isParentTag = true; return type; } public static TagType withNoFormatter(String tagPath, boolean isVanilla) { - TagType type = new TagType(tagPath); - type.formatter = Util.memoize((prefix, material) -> TagUtil.createItemTag(type.tagPath, isVanilla)); + TagType type = new TagType((prefix, material) -> TagUtil.createItemTag(tagPath, isVanilla)); type.isParentTag = true; return type; } - public static TagType withCustomFormatter(String tagPath, BiFunction> formatter) { - TagType type = new TagType(tagPath); - type.formatter = Util.memoize(formatter); - return type; - } - - public static TagType withCustomFilter(String tagPath, boolean isVanilla, Predicate filter) { - TagType type = new TagType(tagPath); - type.filter = filter; - type.formatter = Util.memoize((prefix, material) -> TagUtil.createItemTag(type.tagPath, isVanilla)); - return type; + public static TagType withCustomFormatter(BiFunction> formatter) { + return new TagType(formatter); } // spotless:on - @Nullable - public TagKey getTag(TagPrefix prefix, @NotNull Material material) { - if (filter != null && !material.isNull() && !filter.test(material)) return null; - return formatter.apply(prefix, material); + public @Nullable TagKey getTag(TagPrefix prefix, @NotNull Material material) { + if (this.filter != null && !material.isNull() && !this.filter.test(material)) return null; + return this.formatter.apply(prefix, material); } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/recipe/GTRecipeType.java b/src/main/java/com/gregtechceu/gtceu/api/recipe/GTRecipeType.java index c89242c5c06..d07d40480a2 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/recipe/GTRecipeType.java +++ b/src/main/java/com/gregtechceu/gtceu/api/recipe/GTRecipeType.java @@ -327,6 +327,11 @@ public void beginStagingRecipes() { additionHandler.beginStaging(); } + @ApiStatus.Internal + public void completeStagingRecipes() { + additionHandler.completeStaging(); + } + public interface ICustomRecipeLogic { /** diff --git a/src/main/java/com/gregtechceu/gtceu/api/recipe/lookup/RecipeManagerHandler.java b/src/main/java/com/gregtechceu/gtceu/api/recipe/lookup/RecipeManagerHandler.java index f5e5bd08c5d..dd3c498aa74 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/recipe/lookup/RecipeManagerHandler.java +++ b/src/main/java/com/gregtechceu/gtceu/api/recipe/lookup/RecipeManagerHandler.java @@ -24,7 +24,7 @@ public final class RecipeManagerHandler { /** * Adds proxy recipes to an {@link GTRecipeType}'s {@link RecipeAdditionHandler} and adds them to a list. * - * @param recipes the recipes stored by their ID + * @param recipes the recipes * @param gtRecipeType the recipe type to add the recipes to, which owns the proxy recipes * @param proxyRecipes the list of proxy recipes to populate */ @@ -47,20 +47,19 @@ public static void addProxyRecipesToLookup(@NotNull Collection> /** * Adds recipes to an {@link GTRecipeType}'s {@link RecipeAdditionHandler} * - * @param recipes the recipes stored by their ID - * @param gtRecipeType the recipe type to add recipes to + * @param recipes the recipes + * @param recipeType the recipe type to add recipes to */ - public static void addRecipesToLookup(@NotNull Collection> recipes, - @NotNull GTRecipeType gtRecipeType) { - var lookup = gtRecipeType.getAdditionHandler(); - for (RecipeHolder r : recipes) { - if (r.value().getType() != gtRecipeType) { + public static void addRecipesToLookup(@NotNull Collection> recipes, + @NotNull GTRecipeType recipeType) { + var lookup = recipeType.getAdditionHandler(); + for (RecipeHolder r : recipes) { + GTRecipe recipe = r.value(); + if (recipe.getType() != recipeType) { // do not add recipes of incompatible type continue; } - if (r.value() instanceof GTRecipe recipe) { - lookup.addStaging(recipe); - } + lookup.addStaging(recipe); } } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/recipe/lookup/StagingRecipeDB.java b/src/main/java/com/gregtechceu/gtceu/api/recipe/lookup/StagingRecipeDB.java index cc8928f522e..4f282c5d73d 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/recipe/lookup/StagingRecipeDB.java +++ b/src/main/java/com/gregtechceu/gtceu/api/recipe/lookup/StagingRecipeDB.java @@ -68,12 +68,12 @@ public void populateDB(@NotNull RecipeDB db) { for (GTRecipe recipe : recipes) { recipe.inputs.forEach((cap, list) -> { for (var input : compressedContent(list, cap)) { - map.mergeInt(input, 1, Integer::sum); + map.addTo(input, 1); } }); recipe.tickInputs.forEach((cap, list) -> { for (var input : compressedContent(list, cap)) { - map.mergeInt(input, 1, Integer::sum); + map.addTo(input, 1); } }); } diff --git a/src/main/java/com/gregtechceu/gtceu/core/MixinHelpers.java b/src/main/java/com/gregtechceu/gtceu/core/MixinHelpers.java index 5a87016da76..42a0f6e41d7 100644 --- a/src/main/java/com/gregtechceu/gtceu/core/MixinHelpers.java +++ b/src/main/java/com/gregtechceu/gtceu/core/MixinHelpers.java @@ -1,387 +1,30 @@ package com.gregtechceu.gtceu.core; import com.gregtechceu.gtceu.GTCEu; -import com.gregtechceu.gtceu.api.GTValues; -import com.gregtechceu.gtceu.api.data.chemical.ChemicalHelper; -import com.gregtechceu.gtceu.api.data.chemical.material.ItemMaterialData; import com.gregtechceu.gtceu.api.data.chemical.material.Material; -import com.gregtechceu.gtceu.api.data.chemical.material.properties.FluidProperty; -import com.gregtechceu.gtceu.api.data.chemical.material.properties.OreProperty; -import com.gregtechceu.gtceu.api.data.chemical.material.properties.PropertyKey; -import com.gregtechceu.gtceu.api.data.chemical.material.stack.MaterialStack; -import com.gregtechceu.gtceu.api.data.tag.TagPrefix; import com.gregtechceu.gtceu.api.data.worldgen.GTOreDefinition; import com.gregtechceu.gtceu.api.data.worldgen.bedrockfluid.BedrockFluidDefinition; import com.gregtechceu.gtceu.api.data.worldgen.bedrockore.BedrockOreDefinition; -import com.gregtechceu.gtceu.api.fluids.FluidState; -import com.gregtechceu.gtceu.api.fluids.GTFluid; import com.gregtechceu.gtceu.api.fluids.store.FluidStorage; -import com.gregtechceu.gtceu.api.fluids.store.FluidStorageKey; import com.gregtechceu.gtceu.api.registry.GTRegistries; import com.gregtechceu.gtceu.api.registry.registrate.GTClientFluidTypeExtensions; -import com.gregtechceu.gtceu.common.data.GTMaterialBlocks; -import com.gregtechceu.gtceu.common.data.GTMaterialItems; -import com.gregtechceu.gtceu.config.ConfigHolder; -import com.gregtechceu.gtceu.core.mixins.BlockBehaviourAccessor; -import com.gregtechceu.gtceu.data.recipe.CustomTags; import com.gregtechceu.gtceu.integration.kjs.GTCEuServerEvents; import com.gregtechceu.gtceu.integration.kjs.events.GTBedrockFluidVeinEventJS; import com.gregtechceu.gtceu.integration.kjs.events.GTBedrockOreVeinEventJS; import com.gregtechceu.gtceu.integration.kjs.events.GTOreVeinEventJS; -import net.minecraft.client.Minecraft; import net.minecraft.core.*; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.core.registries.Registries; -import net.minecraft.data.loot.packs.VanillaBlockLoot; -import net.minecraft.resources.ResourceKey; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.tags.*; -import net.minecraft.world.item.ArmorItem; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; -import net.minecraft.world.item.enchantment.Enchantment; -import net.minecraft.world.item.enchantment.Enchantments; -import net.minecraft.world.level.ItemLike; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.material.Fluid; -import net.minecraft.world.level.storage.loot.IntRange; -import net.minecraft.world.level.storage.loot.LootPool; -import net.minecraft.world.level.storage.loot.LootTable; -import net.minecraft.world.level.storage.loot.entries.LootItem; -import net.minecraft.world.level.storage.loot.functions.ApplyBonusCount; -import net.minecraft.world.level.storage.loot.functions.ApplyExplosionDecay; -import net.minecraft.world.level.storage.loot.functions.LimitCount; -import net.minecraft.world.level.storage.loot.functions.SetItemCountFunction; -import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets; -import net.minecraft.world.level.storage.loot.providers.number.ConstantValue; -import net.minecraft.world.level.storage.loot.providers.number.UniformGenerator; import net.neoforged.neoforge.client.extensions.common.IClientFluidTypeExtensions; -import com.tterrag.registrate.util.entry.BlockEntry; import dev.latvian.mods.kubejs.util.RegistryAccessContainer; -import org.apache.logging.log4j.util.TriConsumer; import org.jetbrains.annotations.ApiStatus; -import java.util.*; import java.util.function.Consumer; -import java.util.function.Supplier; -import java.util.stream.Collector; -import java.util.stream.Collectors; @SuppressWarnings("deprecation") @ApiStatus.Internal public class MixinHelpers { - public static void generateGTDynamicTags(Map> tagMap, - Registry registry) { - if (registry == BuiltInRegistries.ITEM) { - ItemMaterialData.MATERIAL_ENTRY_ITEM_MAP.forEach((entry, itemLikes) -> { - if (itemLikes.isEmpty()) return; - var material = entry.material(); - if (material.isNull()) return; - var entries = itemLikes.stream() - .map(Supplier::get) - .map(MixinHelpers::makeItemEntry) - .collect(toArrayList()); - - var prefixTagKeys = entry.tagPrefix().getAllItemTags(material); - for (TagKey prefixTag : prefixTagKeys) { - tagMap.computeIfAbsent(prefixTag.location(), path -> new ArrayList<>()).addAll(entries); - } - for (TagKey materialTag : material.getItemTags()) { - tagMap.computeIfAbsent(materialTag.location(), path -> new ArrayList<>()).addAll(entries); - } - - if (entry.tagPrefix() == TagPrefix.crushed && material.hasProperty(PropertyKey.ORE)) { - OreProperty ore = material.getProperty(PropertyKey.ORE); - Material washedIn = ore.getWashedIn().first(); - if (washedIn.isNull()) return; - ResourceLocation generalTag = CustomTags.CHEM_BATH_WASHABLE.location(); - ResourceLocation specificTag = generalTag.withSuffix("/" + washedIn.getName()); - - tagMap.computeIfAbsent(generalTag, path -> new ArrayList<>()).addAll(entries); - tagMap.computeIfAbsent(specificTag, path -> new ArrayList<>()).addAll(entries); - } - }); - - GTMaterialItems.TOOL_ITEMS.rowMap().forEach((material, map) -> { - map.values().forEach(item -> { - if (item == null) return; - var entry = makeItemEntry(item); - for (TagKey tag : item.get().getToolType().itemTags) { - tagMap.computeIfAbsent(tag.location(), path -> new ArrayList<>()).add(entry); - } - }); - }); - - GTMaterialItems.ARMOR_ITEMS.rowMap().forEach((material, map) -> { - map.forEach((type, item) -> { - if (type == null || type == ArmorItem.Type.BODY) { - return; - } - if (item != null) { - var entry = new TagLoader.EntryWithSource(TagEntry.element(item.getId()), - GTValues.CUSTOM_TAG_SOURCE); - tagMap.computeIfAbsent(ItemTags.TRIMMABLE_ARMOR.location(), $ -> new ArrayList<>()) - .add(entry); - tagMap.computeIfAbsent(switch (type) { - case HELMET -> ItemTags.HEAD_ARMOR.location(); - case CHESTPLATE -> ItemTags.CHEST_ARMOR.location(); - case LEGGINGS -> ItemTags.LEG_ARMOR.location(); - case BOOTS -> ItemTags.FOOT_ARMOR.location(); - default -> throw new IllegalStateException("Unexpected value: " + type); - }, $ -> new ArrayList<>()).add(entry); - } - }); - }); - - if (!GTCEu.Mods.isAE2Loaded()) { - return; - } - // If AE2 is loaded, add the Fluid P2P attunement tag to all the buckets - var p2pFluidAttunements = ResourceLocation.fromNamespaceAndPath(GTValues.MODID_APPENG, - "p2p_attunements/fluid_p2p_tunnel"); - for (Material material : GTRegistries.MATERIALS) { - FluidProperty property = material.getProperty(PropertyKey.FLUID); - if (property == null) { - continue; - } - for (FluidStorageKey key : FluidStorageKey.allKeys()) { - Fluid fluid = property.get(key); - if (fluid == null || fluid.getBucket() == Items.AIR) { - continue; - } - var entry = makeItemEntry(fluid.getBucket()); - tagMap.computeIfAbsent(p2pFluidAttunements, path -> new ArrayList<>()).add(entry); - } - } - } else if (registry == BuiltInRegistries.BLOCK) { - ItemMaterialData.MATERIAL_ENTRY_BLOCK_MAP.forEach((entry, blocks) -> { - if (blocks.isEmpty()) return; - var material = entry.material(); - if (material.isNull()) return; - - var entries = blocks.stream().map(MixinHelpers::makeBlockEntry).collect(toArrayList()); - var materialTags = entry.tagPrefix().getAllBlockTags(material); - for (TagKey materialTag : materialTags) { - tagMap.computeIfAbsent(materialTag.location(), path -> new ArrayList<>()).addAll(entries); - } - // Add tool tags - if (!entry.isIgnored() && !entry.tagPrefix().miningToolTag().isEmpty()) { - tagMap.computeIfAbsent(CustomTags.TOOL_TIERS[material.getBlockHarvestLevel()].location(), - path -> new ArrayList<>()).addAll(entries); - if (material.hasProperty(PropertyKey.WOOD)) { - // Wood blocks with this tag always allow a Wrench, but only allow an Axe if the config is - // not set. Pickaxe is never allowed (special case) - if (entry.tagPrefix().miningToolTag() - .contains(CustomTags.MINEABLE_WITH_CONFIG_VALID_PICKAXE_WRENCH)) { - tagMap.computeIfAbsent(CustomTags.MINEABLE_WITH_WRENCH.location(), - path -> new ArrayList<>()).addAll(entries); - if (!ConfigHolder.INSTANCE.machines.requireGTToolsForBlocks) { - tagMap.computeIfAbsent(BlockTags.MINEABLE_WITH_AXE.location(), - path -> new ArrayList<>()) - .addAll(entries); - } - } else { - // Other wood stuff should still get the Axe tag - tagMap.computeIfAbsent(BlockTags.MINEABLE_WITH_AXE.location(), path -> new ArrayList<>()) - .addAll(entries); - } - } else { - for (var tag : entry.tagPrefix().miningToolTag()) { - tagMap.computeIfAbsent(tag.location(), path -> new ArrayList<>()).addAll(entries); - } - } - } - - if (entry.tagPrefix() == TagPrefix.oreEndstone) { - // Make endstone-based ores dragon-immune - tagMap.computeIfAbsent(BlockTags.DRAGON_IMMUNE.location(), $ -> new ArrayList<>()).addAll(entries); - } - - if (entry.tagPrefix() == TagPrefix.frameGt) { - tagMap.computeIfAbsent(CustomTags.SLOW_WALKABLE_BLOCKS.location(), path -> new ArrayList<>()) - .addAll(entries); - } - }); - - GTRegistries.MACHINES.forEach(machine -> { - tagMap.computeIfAbsent(CustomTags.MINEABLE_WITH_CONFIG_VALID_PICKAXE_WRENCH.location(), - path -> new ArrayList<>()).add(makeBlockEntry(machine.getBlock())); - }); - - // if config is NOT enabled, add the "configurable" mineability tags to the pickaxe tag - if (!ConfigHolder.INSTANCE.machines.requireGTToolsForBlocks) { - var tagList = tagMap.computeIfAbsent(BlockTags.MINEABLE_WITH_PICKAXE.location(), - path -> new ArrayList<>()); - - tagList.add(makeTagEntry(CustomTags.MINEABLE_WITH_CONFIG_VALID_PICKAXE_WRENCH)); - tagList.add(makeTagEntry(CustomTags.MINEABLE_WITH_CONFIG_VALID_PICKAXE_WIRE_CUTTER)); - } - } else if (registry == BuiltInRegistries.FLUID) { - for (Material material : GTRegistries.MATERIALS) { - FluidProperty property = material.getProperty(PropertyKey.FLUID); - if (property == null) { - continue; - } - for (FluidStorageKey key : FluidStorageKey.allKeys()) { - Fluid fluid = property.get(key); - if (fluid == null) { - continue; - } - ItemMaterialData.FLUID_MATERIAL.put(fluid, material); - - TagLoader.EntryWithSource entry = makeFluidEntry(fluid); - - ResourceLocation fluidIdTag = fluid.builtInRegistryHolder().key().location(); - fluidIdTag = ResourceLocation.fromNamespaceAndPath("c", fluidIdTag.getPath()); - tagMap.computeIfAbsent(fluidIdTag, path -> new ArrayList<>()).add(entry); - - FluidState state; - if (fluid instanceof GTFluid gtFluid) { - state = gtFluid.getState(); - } else { - state = key.getDefaultFluidState(); - } - if (state != null) { - tagMap.computeIfAbsent(state.getTagKey().location(), path -> new ArrayList<>()).add(entry); - } - - if (key.getExtraTag() != null) { - tagMap.computeIfAbsent(key.getExtraTag().location(), path -> new ArrayList<>()).add(entry); - } - } - } - } - } - - private static Collector> toArrayList() { - return Collectors.toCollection(ArrayList::new); - } - - public static TagLoader.EntryWithSource makeItemEntry(ItemLike item) { - return makeElementEntry(item.asItem().builtInRegistryHolder().key().location()); - } - - public static TagLoader.EntryWithSource makeBlockEntry(Supplier block) { - return makeBlockEntry(block.get()); - } - - public static TagLoader.EntryWithSource makeBlockEntry(Block block) { - return makeElementEntry(block.builtInRegistryHolder().key().location()); - } - - public static TagLoader.EntryWithSource makeFluidEntry(Fluid fluid) { - return makeElementEntry(fluid.builtInRegistryHolder().key().location()); - } - - public static TagLoader.EntryWithSource makeElementEntry(ResourceLocation id) { - return new TagLoader.EntryWithSource(TagEntry.element(id), GTValues.CUSTOM_TAG_SOURCE); - } - - public static TagLoader.EntryWithSource makeTagEntry(TagKey tag) { - return new TagLoader.EntryWithSource(TagEntry.tag(tag.location()), GTValues.CUSTOM_TAG_SOURCE); - } - - public static void generateGTDynamicLoot(TriConsumer lootTables, - final RegistryAccess.Frozen access) { - final VanillaBlockLoot blockLoot = new VanillaBlockLoot(access); - - Holder fortune = access.registryOrThrow(Registries.ENCHANTMENT) - .getHolderOrThrow(Enchantments.FORTUNE); - GTMaterialBlocks.MATERIAL_BLOCKS.rowMap().forEach((prefix, map) -> { - if (TagPrefix.ORES.containsKey(prefix)) { - final TagPrefix.OreType type = TagPrefix.ORES.get(prefix); - map.forEach((material, blockEntry) -> { - ResourceLocation lootTableId = blockEntry.getId().withPrefix("blocks/"); - Block block = blockEntry.get(); - - ItemStack dropItem = ChemicalHelper.get(TagPrefix.rawOre, material); - if (dropItem.isEmpty()) dropItem = ChemicalHelper.get(TagPrefix.gem, material); - if (dropItem.isEmpty()) dropItem = ChemicalHelper.get(TagPrefix.dust, material); - int oreMultiplier = type.isDoubleDrops() ? 2 : 1; - - LootTable.Builder builder = blockLoot.createSilkTouchDispatchTable(block, - blockLoot.applyExplosionDecay(block, - LootItem.lootTableItem(dropItem.getItem()) - .apply(SetItemCountFunction - .setCount(ConstantValue.exactly(oreMultiplier))))); - // disable fortune for balance reasons. (for now, until we can think of a better solution.) - // .apply(ApplyBonusCount.addOreBonusCount(Enchantments.BLOCK_FORTUNE)))); - - LootPool.Builder pool = LootPool.lootPool(); - boolean isEmpty = true; - for (MaterialStack secondaryMaterial : prefix.secondaryMaterials()) { - if (secondaryMaterial.material().hasProperty(PropertyKey.DUST)) { - ItemStack dustStack = ChemicalHelper.getGem(secondaryMaterial); - pool.add(LootItem.lootTableItem(dustStack.getItem()) - .when(blockLoot.doesNotHaveSilkTouch()) - .apply(SetItemCountFunction.setCount(UniformGenerator.between(0, 1))) - // .apply(ApplyBonusCount.addUniformBonusCount(fortune)) - .apply(LimitCount.limitCount(IntRange.range(0, 2))) - .apply(ApplyExplosionDecay.explosionDecay())); - isEmpty = false; - } - } - if (!isEmpty) { - builder.withPool(pool); - } - lootTables.accept(lootTableId, builder.setParamSet(LootContextParamSets.BLOCK).build(), access); - ((BlockBehaviourAccessor) blockEntry.get()) - .setDrops(ResourceKey.create(Registries.LOOT_TABLE, lootTableId)); - }); - } else { - MixinHelpers.addMaterialBlockLootTables(lootTables, prefix, map, blockLoot, access); - } - }); - GTMaterialBlocks.CABLE_BLOCKS.rowMap().forEach((prefix, map) -> { - MixinHelpers.addMaterialBlockLootTables(lootTables, prefix, map, blockLoot, access); - }); - GTMaterialBlocks.FLUID_PIPE_BLOCKS.rowMap().forEach((prefix, map) -> { - MixinHelpers.addMaterialBlockLootTables(lootTables, prefix, map, blockLoot, access); - }); - GTMaterialBlocks.ITEM_PIPE_BLOCKS.rowMap().forEach((prefix, map) -> { - MixinHelpers.addMaterialBlockLootTables(lootTables, prefix, map, blockLoot, access); - }); - GTMaterialBlocks.SURFACE_ROCK_BLOCKS.forEach((material, blockEntry) -> { - ResourceLocation lootTableId = ResourceLocation.fromNamespaceAndPath(blockEntry.getId().getNamespace(), - "blocks/" + blockEntry.getId().getPath()); - LootTable.Builder builder = blockLoot - .createSingleItemTable(ChemicalHelper.get(TagPrefix.dustTiny, material).getItem(), - UniformGenerator.between(3, 5)) - .apply(ApplyBonusCount.addUniformBonusCount(fortune)); - lootTables.accept(lootTableId, builder.setParamSet(LootContextParamSets.BLOCK).build(), access); - ((BlockBehaviourAccessor) blockEntry.get()) - .setDrops(ResourceKey.create(Registries.LOOT_TABLE, lootTableId)); - }); - GTRegistries.MACHINES.forEach(machine -> { - Block block = machine.getBlock(); - ResourceLocation id = machine.getId(); - ResourceLocation lootTableId = ResourceLocation.fromNamespaceAndPath(id.getNamespace(), - "blocks/" + id.getPath()); - ((BlockBehaviourAccessor) block).setDrops(ResourceKey.create(Registries.LOOT_TABLE, lootTableId)); - lootTables.accept(lootTableId, - blockLoot.createSingleItemTable(block).setParamSet(LootContextParamSets.BLOCK).build(), access); - }); - } - - public static void addMaterialBlockLootTables(TriConsumer lootTables, - TagPrefix prefix, - Map> map, - VanillaBlockLoot blockLoot, RegistryAccess.Frozen access) { - map.forEach((material, blockEntry) -> { - ResourceLocation lootTableId = blockEntry.getId().withPrefix("blocks/"); - ((BlockBehaviourAccessor) blockEntry.get()) - .setDrops(ResourceKey.create(Registries.LOOT_TABLE, lootTableId)); - lootTables.accept(lootTableId, - blockLoot.createSingleItemTable(blockEntry.get()).setParamSet(LootContextParamSets.BLOCK).build(), - access); - }); - } - public static void postKJSVeinEvents(RegistryAccess.Frozen registries) { if (!GTCEu.Mods.isKubeJSLoaded()) { return; @@ -439,11 +82,4 @@ private static void updateRegistryAccessContainer(RegistryAccess.Frozen registri } } } - - public static final class ClientCallWrapper { - - public static Level getClientLevel() { - return Minecraft.getInstance().level; - } - } } diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/RecipeManagerEarlyMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/RecipeManagerEarlyMixin.java index 2cb9557f2a8..3b56686e338 100644 --- a/src/main/java/com/gregtechceu/gtceu/core/mixins/RecipeManagerEarlyMixin.java +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/RecipeManagerEarlyMixin.java @@ -1,12 +1,14 @@ package com.gregtechceu.gtceu.core.mixins; -import com.gregtechceu.gtceu.common.data.GTRecipes; +import com.gregtechceu.gtceu.data.dynamic.DynamicRecipeHandler; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.resources.ResourceManager; +import net.minecraft.server.packs.resources.SimpleJsonResourceReloadListener; import net.minecraft.util.profiling.ProfilerFiller; import net.minecraft.world.item.crafting.RecipeManager; +import com.google.gson.Gson; import com.google.gson.JsonElement; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -16,12 +18,17 @@ import java.util.Map; @Mixin(value = RecipeManager.class, priority = 500) -public abstract class RecipeManagerEarlyMixin { +public abstract class RecipeManagerEarlyMixin extends SimpleJsonResourceReloadListener { + + private RecipeManagerEarlyMixin(Gson gson, String directory) { + super(gson, directory); + } @Inject(method = "apply(Ljava/util/Map;Lnet/minecraft/server/packs/resources/ResourceManager;Lnet/minecraft/util/profiling/ProfilerFiller;)V", at = @At("HEAD")) - private void gtceu$removeRecipes(Map map, ResourceManager pResourceManager, - ProfilerFiller pProfiler, CallbackInfo ci) { - GTRecipes.recipeRemoval(map::remove); + private void gtceu$handleDynamicRecipesEarly(Map map, + ResourceManager resourceManager, ProfilerFiller profiler, + CallbackInfo ci) { + DynamicRecipeHandler.handleRecipesEarly(map, this.getRegistryLookup(), this.getContext()); } } diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/RecipeManagerLateMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/RecipeManagerLateMixin.java index 28770123d8f..8e97a5239c2 100644 --- a/src/main/java/com/gregtechceu/gtceu/core/mixins/RecipeManagerLateMixin.java +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/RecipeManagerLateMixin.java @@ -1,99 +1,33 @@ package com.gregtechceu.gtceu.core.mixins; -import com.gregtechceu.gtceu.api.recipe.GTRecipe; -import com.gregtechceu.gtceu.api.recipe.GTRecipeType; -import com.gregtechceu.gtceu.api.recipe.lookup.MapIngredientPool; -import com.gregtechceu.gtceu.api.recipe.lookup.RecipeManagerHandler; -import com.gregtechceu.gtceu.data.recipe.builder.GTRecipeBuilder; +import com.gregtechceu.gtceu.data.dynamic.DynamicRecipeHandler; -import net.minecraft.advancements.Advancement; -import net.minecraft.advancements.AdvancementHolder; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.data.recipes.RecipeBuilder; -import net.minecraft.data.recipes.RecipeOutput; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.resources.ResourceManager; +import net.minecraft.server.packs.resources.SimpleJsonResourceReloadListener; import net.minecraft.util.profiling.ProfilerFiller; -import net.minecraft.world.item.crafting.Recipe; -import net.minecraft.world.item.crafting.RecipeHolder; import net.minecraft.world.item.crafting.RecipeManager; -import net.minecraft.world.item.crafting.RecipeType; -import net.neoforged.neoforge.common.conditions.ICondition; -import com.google.common.collect.Multimap; +import com.google.gson.Gson; import com.google.gson.JsonElement; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import java.util.Collection; -import java.util.LinkedHashMap; import java.util.Map; @Mixin(value = RecipeManager.class, priority = 1500) -public abstract class RecipeManagerLateMixin { +public abstract class RecipeManagerLateMixin extends SimpleJsonResourceReloadListener { - @Shadow - private Multimap, RecipeHolder> byType; - - @Shadow - private Map> byName; - - @Shadow - public abstract void replaceRecipes(Iterable> recipes); + public RecipeManagerLateMixin(Gson gson, String directory) { + super(gson, directory); + } @Inject(method = "apply(Ljava/util/Map;Lnet/minecraft/server/packs/resources/ResourceManager;Lnet/minecraft/util/profiling/ProfilerFiller;)V", at = @At(value = "TAIL")) - private void gtceu$cloneVanillaRecipes(Map map, ResourceManager resourceManager, - ProfilerFiller profiler, CallbackInfo ci) { - // use a linked hash map to keep the immutable map's order - Map> recipesByName = new LinkedHashMap<>(byName); - // regenerate child recipes - byName.values().forEach(holder -> { - if (holder.value() instanceof GTRecipe gtRecipe) { - new GTRecipeBuilder(gtRecipe, gtRecipe.recipeType) - .id(holder.id().withPath(path -> path.substring(path.indexOf('/') + 1))) - .onSave(gtRecipe.recipeType.getRecipeBuilder().onSave) - .save(new RecipeOutput() { - - @SuppressWarnings("removal") - @Override - public Advancement.@NotNull Builder advancement() { - return Advancement.Builder.recipeAdvancement() - .parent(RecipeBuilder.ROOT_RECIPE_ADVANCEMENT); - } - - @Override - public void accept(@NotNull ResourceLocation id, @NotNull Recipe recipe, - @Nullable AdvancementHolder advancement, - ICondition @NotNull... conditions) { - recipesByName.put(id, new RecipeHolder<>(id, recipe)); - } - }); - } - }); - replaceRecipes(recipesByName.values()); - - for (RecipeType recipeType : BuiltInRegistries.RECIPE_TYPE) { - if (!(recipeType instanceof GTRecipeType gtRecipeType)) { - continue; - } - gtRecipeType.beginStagingRecipes(); - gtRecipeType.getProxyRecipes().forEach((type, list) -> { - Collection> recipes = this.byType.get(type); - if (recipes.isEmpty()) { - return; - } - RecipeManagerHandler.addProxyRecipesToLookup(recipes, gtRecipeType, type, list); - }); - Collection> recipesByID = this.byType.get(gtRecipeType); - RecipeManagerHandler.addRecipesToLookup(recipesByID, gtRecipeType); - gtRecipeType.getAdditionHandler().completeStaging(); - } - MapIngredientPool.clear(); + private void gtceu$handleDynamicRecipesLate(Map map, ResourceManager resourceManager, + ProfilerFiller profiler, CallbackInfo ci) { + DynamicRecipeHandler.handleRecipesLate((RecipeManager) (Object) this); } } diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/ReloadableServerResourcesMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/ReloadableServerResourcesMixin.java index 6df3a51520e..6a2f1536199 100644 --- a/src/main/java/com/gregtechceu/gtceu/core/mixins/ReloadableServerResourcesMixin.java +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/ReloadableServerResourcesMixin.java @@ -1,30 +1,15 @@ package com.gregtechceu.gtceu.core.mixins; -import com.gregtechceu.gtceu.GTCEu; -import com.gregtechceu.gtceu.api.machine.trait.customlogic.SteamBoilerLogic; -import com.gregtechceu.gtceu.common.data.GTRecipes; -import com.gregtechceu.gtceu.core.MixinHelpers; -import com.gregtechceu.gtceu.data.loot.DungeonLootLoader; -import com.gregtechceu.gtceu.data.pack.GTDynamicDataPack; -import com.gregtechceu.gtceu.data.recipe.GTCraftingComponents; +import com.gregtechceu.gtceu.data.dynamic.DynamicLootHandler; -import net.minecraft.advancements.Advancement; -import net.minecraft.advancements.AdvancementHolder; import net.minecraft.commands.Commands; import net.minecraft.core.LayeredRegistryAccess; import net.minecraft.core.RegistryAccess; -import net.minecraft.data.recipes.RecipeBuilder; -import net.minecraft.data.recipes.RecipeOutput; -import net.minecraft.resources.ResourceLocation; import net.minecraft.server.RegistryLayer; import net.minecraft.server.ReloadableServerResources; import net.minecraft.server.packs.resources.ResourceManager; import net.minecraft.world.flag.FeatureFlagSet; -import net.minecraft.world.item.crafting.Recipe; -import net.neoforged.neoforge.common.conditions.ICondition; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -41,35 +26,13 @@ public abstract class ReloadableServerResourcesMixin { FeatureFlagSet featureFlags, Commands.CommandSelection commands, int functionCompilationLevel, Executor backgroundExecutor, Executor gameExecutor, CallbackInfoReturnable> cir) { - // load and loot tables recipes *before* other data so that we have the registries loaded - // before saving recipes to JSON. + // load loot tables *before* other data so we have the registries loaded before saving recipes to JSON. // because it breaks if we don't do that. - // this doesn't have dynamic registries available, by the way. - RegistryAccess.Frozen frozen = access.compositeAccess(); + // this doesn't have reloadable registries available, by the way. + RegistryAccess.Frozen registries = access.compositeAccess(); - // Register recipes & unification data again - long startTime = System.currentTimeMillis(); - GTCraftingComponents.init(); - SteamBoilerLogic.clearBoilerRecipeCaches(); - GTRecipes.recipeAddition(new RecipeOutput() { - - @Override - public Advancement.@NotNull Builder advancement() { - // noinspection removal - return Advancement.Builder.recipeAdvancement().parent(RecipeBuilder.ROOT_RECIPE_ADVANCEMENT); - } - - @Override - public void accept(@NotNull ResourceLocation id, @NotNull Recipe recipe, - @Nullable AdvancementHolder advancement, ICondition @NotNull... conditions) { - GTDynamicDataPack.addRecipe(id, recipe, advancement, frozen); - } - }); - MixinHelpers.generateGTDynamicLoot(GTDynamicDataPack::addLootTable, frozen); - // Initialize dungeon loot additions - DungeonLootLoader.init(); - - GTCEu.LOGGER.info("GregTech Data loading took {}ms", System.currentTimeMillis() - startTime); + // Register dynamic loot + DynamicLootHandler.generateDynamicLoot(registries); } } diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/TagLoaderMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/TagLoaderMixin.java index 062af0de349..35a2570f9fe 100644 --- a/src/main/java/com/gregtechceu/gtceu/core/mixins/TagLoaderMixin.java +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/TagLoaderMixin.java @@ -1,7 +1,7 @@ package com.gregtechceu.gtceu.core.mixins; import com.gregtechceu.gtceu.core.IGTTagLoader; -import com.gregtechceu.gtceu.core.MixinHelpers; +import com.gregtechceu.gtceu.data.dynamic.DynamicTagHandler; import net.minecraft.core.Registry; import net.minecraft.resources.ResourceLocation; @@ -29,7 +29,7 @@ public class TagLoaderMixin implements IGTTagLoader { public void gtceu$load(ResourceManager resourceManager, CallbackInfoReturnable>> cir) { if (gtceu$storedRegistry == null) return; - MixinHelpers.generateGTDynamicTags(cir.getReturnValue(), gtceu$storedRegistry); + DynamicTagHandler.generateDynamicTags(cir.getReturnValue(), gtceu$storedRegistry); } @Override diff --git a/src/main/java/com/gregtechceu/gtceu/data/dynamic/DynamicLootHandler.java b/src/main/java/com/gregtechceu/gtceu/data/dynamic/DynamicLootHandler.java new file mode 100644 index 00000000000..e35b8210b82 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/data/dynamic/DynamicLootHandler.java @@ -0,0 +1,174 @@ +package com.gregtechceu.gtceu.data.dynamic; + +import com.gregtechceu.gtceu.GTCEu; +import com.gregtechceu.gtceu.api.data.chemical.ChemicalHelper; +import com.gregtechceu.gtceu.api.data.chemical.material.Material; +import com.gregtechceu.gtceu.api.data.chemical.material.properties.PropertyKey; +import com.gregtechceu.gtceu.api.data.chemical.material.stack.MaterialStack; +import com.gregtechceu.gtceu.api.data.tag.TagPrefix; +import com.gregtechceu.gtceu.api.registry.GTRegistries; +import com.gregtechceu.gtceu.common.data.GTMaterialBlocks; +import com.gregtechceu.gtceu.core.mixins.BlockBehaviourAccessor; +import com.gregtechceu.gtceu.data.loot.DungeonLootLoader; +import com.gregtechceu.gtceu.data.pack.GTDynamicDataPack; + +import net.minecraft.core.HolderLookup; +import net.minecraft.core.registries.Registries; +import net.minecraft.data.loot.packs.VanillaBlockLoot; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.storage.loot.IntRange; +import net.minecraft.world.level.storage.loot.LootPool; +import net.minecraft.world.level.storage.loot.LootTable; +import net.minecraft.world.level.storage.loot.entries.LootItem; +import net.minecraft.world.level.storage.loot.functions.ApplyExplosionDecay; +import net.minecraft.world.level.storage.loot.functions.LimitCount; +import net.minecraft.world.level.storage.loot.functions.SetItemCountFunction; +import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets; +import net.minecraft.world.level.storage.loot.providers.number.ConstantValue; +import net.minecraft.world.level.storage.loot.providers.number.UniformGenerator; + +import com.google.gson.JsonElement; +import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.JsonOps; +import com.tterrag.registrate.util.entry.BlockEntry; +import org.jetbrains.annotations.ApiStatus; + +import java.util.Map; +import java.util.function.BiFunction; + +@ApiStatus.Internal +public final class DynamicLootHandler { + + private DynamicLootHandler() {} + + public static void generateDynamicLoot(HolderLookup.Provider registries) { + long startTime = System.currentTimeMillis(); + DynamicLootHandler.generateDynamicLoot0(registries); + // Initialize dungeon loot additions + DungeonLootLoader.init(); + + GTCEu.LOGGER.info("GregTech dynamic loot table generation took {}ms", System.currentTimeMillis() - startTime); + } + + private static void generateDynamicLoot0(final HolderLookup.Provider registries) { + final VanillaBlockLoot helpers = new VanillaBlockLoot(registries); + final DynamicOps serializationContext = registries.createSerializationContext(JsonOps.INSTANCE); + + GTMaterialBlocks.MATERIAL_BLOCKS.rowMap().forEach((prefix, map) -> { + if (TagPrefix.ORES.containsKey(prefix)) { + final TagPrefix.OreType oreType = TagPrefix.ORES.get(prefix); + map.forEach((material, block) -> { + generateOreBlockLoot(prefix, material, block, oreType, helpers, serializationContext); + }); + } else { + addMaterialBlockLootTables(map, helpers, serializationContext); + } + }); + + // spotless:off + GTMaterialBlocks.CABLE_BLOCKS.rowMap().values().forEach((map) -> addMaterialBlockLootTables(map, helpers, serializationContext)); + GTMaterialBlocks.FLUID_PIPE_BLOCKS.rowMap().values().forEach((map) -> addMaterialBlockLootTables(map, helpers, serializationContext)); + GTMaterialBlocks.ITEM_PIPE_BLOCKS.rowMap().values().forEach((map) -> addMaterialBlockLootTables(map, helpers, serializationContext)); + addMaterialBlockLootTables(GTMaterialBlocks.SURFACE_ROCK_BLOCKS, serializationContext, (material, block) -> { + Item tinyDust = ChemicalHelper.getItem(TagPrefix.dustTiny, material); + if (tinyDust != Items.AIR) { + return helpers.createSilkTouchDispatchTable(block.get(), + helpers.applyExplosionDecay(block, + LootItem.lootTableItem(tinyDust) + .apply(SetItemCountFunction.setCount(UniformGenerator.between(3, 5))) + ) + ); + } else { + // fallback if the tiny dust doesn't exist + return helpers.createSingleItemTable(block.get()); + } + }); + // spotless:on + + GTRegistries.MACHINES.forEach(machine -> { + Block block = machine.getBlock(); + ResourceLocation lootTableId = machine.getId().withPrefix("blocks/"); + ((BlockBehaviourAccessor) block).setDrops(ResourceKey.create(Registries.LOOT_TABLE, lootTableId)); + + LootTable lootTable = helpers.createSingleItemTable(block) + .setParamSet(LootContextParamSets.BLOCK) + .build(); + GTDynamicDataPack.addLootTable(lootTableId, lootTable, serializationContext); + }); + } + + private static void addMaterialBlockLootTables(Map> map, + VanillaBlockLoot blockLoot, + DynamicOps serializationContext) { + addMaterialBlockLootTables(map, serializationContext, + (material, block) -> blockLoot.createSingleItemTable(block.get())); + } + + private static void addMaterialBlockLootTables(Map> map, + DynamicOps serializationContext, + BiFunction, LootTable.Builder> lootTableBuilder) { + map.forEach((material, block) -> { + ResourceLocation lootTableId = block.getId().withPrefix("blocks/"); + ((BlockBehaviourAccessor) block.get()).setDrops(ResourceKey.create(Registries.LOOT_TABLE, lootTableId)); + + LootTable lootTable = lootTableBuilder.apply(material, block) + .setParamSet(LootContextParamSets.BLOCK) + .build(); + GTDynamicDataPack.addLootTable(lootTableId, lootTable, serializationContext); + }); + } + + private static void generateOreBlockLoot(TagPrefix prefix, Material material, BlockEntry blockEntry, + TagPrefix.OreType oreType, + VanillaBlockLoot helpers, DynamicOps serializationContext) { + ResourceLocation lootTableId = blockEntry.getId().withPrefix("blocks/"); + Block block = blockEntry.get(); + ((BlockBehaviourAccessor) block).setDrops(ResourceKey.create(Registries.LOOT_TABLE, lootTableId)); + + ItemStack dropItem = ChemicalHelper.get(TagPrefix.rawOre, material); + if (dropItem.isEmpty()) dropItem = ChemicalHelper.get(TagPrefix.gem, material); + if (dropItem.isEmpty()) dropItem = ChemicalHelper.get(TagPrefix.dust, material); + + int oreMultiplier = oreType.isDoubleDrops() ? 2 : 1; + + // spotless:off + LootTable.Builder builder = helpers.createSilkTouchDispatchTable(block, + helpers.applyExplosionDecay(block, + LootItem.lootTableItem(dropItem.getItem()) + .apply(SetItemCountFunction.setCount(ConstantValue.exactly(oreMultiplier))) + ) + ); + // disable fortune for balance reasons. (for now, until we can think of a better solution.) + //.apply(ApplyBonusCount.addOreBonusCount(Enchantments.BLOCK_FORTUNE)))); + // spotless:on + + LootPool.Builder pool = LootPool.lootPool(); + boolean isEmpty = true; + for (MaterialStack secondaryMaterial : prefix.secondaryMaterials()) { + if (!secondaryMaterial.material().hasProperty(PropertyKey.DUST)) { + continue; + } + ItemStack dustStack = ChemicalHelper.getGem(secondaryMaterial); + pool.add(LootItem.lootTableItem(dustStack.getItem()) + .when(helpers.doesNotHaveSilkTouch()) + .apply(SetItemCountFunction.setCount(UniformGenerator.between(0, 1))) + // .apply(ApplyBonusCount.addUniformBonusCount(fortune)) + .apply(LimitCount.limitCount(IntRange.range(0, 2))) + .apply(ApplyExplosionDecay.explosionDecay())); + isEmpty = false; + } + if (!isEmpty) { + builder.withPool(pool); + } + + LootTable lootTable = builder + .setParamSet(LootContextParamSets.BLOCK) + .build(); + GTDynamicDataPack.addLootTable(lootTableId, lootTable, serializationContext); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/data/dynamic/DynamicRecipeHandler.java b/src/main/java/com/gregtechceu/gtceu/data/dynamic/DynamicRecipeHandler.java new file mode 100644 index 00000000000..5fcdbda2b8e --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/data/dynamic/DynamicRecipeHandler.java @@ -0,0 +1,169 @@ +package com.gregtechceu.gtceu.data.dynamic; + +import com.gregtechceu.gtceu.GTCEu; +import com.gregtechceu.gtceu.api.machine.trait.customlogic.SteamBoilerLogic; +import com.gregtechceu.gtceu.api.recipe.GTRecipe; +import com.gregtechceu.gtceu.api.recipe.GTRecipeType; +import com.gregtechceu.gtceu.api.recipe.lookup.MapIngredientPool; +import com.gregtechceu.gtceu.api.recipe.lookup.RecipeManagerHandler; +import com.gregtechceu.gtceu.common.data.GTRecipes; +import com.gregtechceu.gtceu.config.ConfigHolder; +import com.gregtechceu.gtceu.data.loader.DeferredOwnerUnwrappingHolderLookupAdapter; +import com.gregtechceu.gtceu.data.pack.GTDynamicDataPack; +import com.gregtechceu.gtceu.data.recipe.GTCraftingComponents; +import com.gregtechceu.gtceu.data.recipe.builder.GTRecipeBuilder; + +import net.minecraft.advancements.Advancement; +import net.minecraft.advancements.AdvancementHolder; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.data.recipes.RecipeBuilder; +import net.minecraft.data.recipes.RecipeOutput; +import net.minecraft.resources.RegistryOps; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.crafting.*; +import net.neoforged.neoforge.common.conditions.ConditionalOps; +import net.neoforged.neoforge.common.conditions.ICondition; +import net.neoforged.neoforge.common.conditions.WithConditions; + +import com.google.gson.JsonElement; +import com.mojang.serialization.JsonOps; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Function; +import java.util.stream.Collectors; + +@ApiStatus.Internal +public final class DynamicRecipeHandler { + + private DynamicRecipeHandler() {} + + // reload time spent in handleRecipesEarly, in milliseconds. + private static final AtomicLong earlyLoadElapsed = new AtomicLong(); + + public static void handleRecipesEarly(Map recipes, + HolderLookup.Provider registryLookup, + ICondition.IContext conditionContext) { + long startTime = System.currentTimeMillis(); + // this has to be final, so... + final ConditionalOps serializationContext; + { + // using a block here removes the possibility of accidentally using the context without condition support. + RegistryOps registryOps = RegistryOps.create(JsonOps.INSTANCE, + new DeferredOwnerUnwrappingHolderLookupAdapter(registryLookup)); + serializationContext = new ConditionalOps<>(registryOps, conditionContext); + } + + // first, remove old recipes & clear caches + GTRecipes.recipeRemoval(recipes::remove); + SteamBoilerLogic.clearBoilerRecipeCaches(); + GTCraftingComponents.init(); + + GTRecipes.recipeAddition(new RecipeOutput() { + + @Override + public Advancement.@NotNull Builder advancement() { + // noinspection removal + return Advancement.Builder.recipeAdvancement().parent(RecipeBuilder.ROOT_RECIPE_ADVANCEMENT); + } + + @Override + public void accept(@NotNull ResourceLocation id, @NotNull Recipe recipe, + @Nullable AdvancementHolder advancement, ICondition @NotNull... conditions) { + JsonElement recipeJson = Recipe.CONDITIONAL_CODEC + .encodeStart(serializationContext, Optional.of(new WithConditions<>(recipe, conditions))) + .getOrThrow(); + recipes.put(id, recipeJson); + + if (ConfigHolder.INSTANCE.dev.dumpRecipes) { + // add the recipe JSON to the generated datapack if data dumping is enabled so it can be dumped + // immediately or with a command + GTDynamicDataPack.addResource(GTDynamicDataPack.RECIPE_ID_CONVERTER.idToFile(id), recipeJson); + } + + if (advancement != null) { + GTDynamicDataPack.addAdvancement(advancement, serializationContext); + } + } + }); + + earlyLoadElapsed.set(System.currentTimeMillis() - startTime); + } + + public static void handleRecipesLate(RecipeManager recipeManager) { + long startTime = System.currentTimeMillis(); + + cloneVanillaRecipes(recipeManager); + addRecipesToLookup(recipeManager); + + long elapsed = (System.currentTimeMillis() - startTime) + earlyLoadElapsed.get(); + GTCEu.LOGGER.info("GregTech dynamic recipe generation took {}ms", elapsed); + } + + private static void addRecipesToLookup(RecipeManager recipeManager) { + for (RecipeType t : BuiltInRegistries.RECIPE_TYPE) { + if (!(t instanceof GTRecipeType recipeType)) { + continue; + } + recipeType.beginStagingRecipes(); + + for (var entry : recipeType.getProxyRecipes().entrySet()) { + RecipeType proxyRecipeType = entry.getKey(); + // Bypass Java Generic Hellâ„¢ + @SuppressWarnings({ "unchecked", "rawtypes" }) + List> recipes = recipeManager.getAllRecipesFor((RecipeType) proxyRecipeType); + if (recipes.isEmpty()) { + continue; + } + List> proxyRecipes = entry.getValue(); + RecipeManagerHandler.addProxyRecipesToLookup(recipes, recipeType, proxyRecipeType, proxyRecipes); + } + + List> recipesByID = recipeManager.getAllRecipesFor(recipeType); + RecipeManagerHandler.addRecipesToLookup(recipesByID, recipeType); + recipeType.completeStagingRecipes(); + } + MapIngredientPool.clear(); + } + + private static void cloneVanillaRecipes(RecipeManager recipeManager) { + Collection> originalRecipes = recipeManager.getRecipes(); + + // use a linked map to keep the immutable map's order + // this is a map so duplicate recipes can replace older ones easily without adding a bunch of useless entries to + // a list or set + Map> replacementRecipes = originalRecipes.stream() + .collect(Collectors.toMap(RecipeHolder::id, Function.identity(), + (oldValue, value) -> value, LinkedHashMap::new)); + + // regenerate child recipes + originalRecipes.forEach(holder -> { + if (holder.value() instanceof GTRecipe gtRecipe) { + new GTRecipeBuilder(gtRecipe, gtRecipe.recipeType) + .id(holder.id().withPath(path -> path.substring(path.indexOf('/') + 1))) + .onSave(gtRecipe.recipeType.getRecipeBuilder().onSave) + .save(new RecipeOutput() { + + @SuppressWarnings("removal") + @Override + public Advancement.@NotNull Builder advancement() { + return Advancement.Builder.recipeAdvancement() + .parent(RecipeBuilder.ROOT_RECIPE_ADVANCEMENT); + } + + @Override + public void accept(@NotNull ResourceLocation id, @NotNull Recipe recipe, + @Nullable AdvancementHolder advancement, + ICondition @NotNull... conditions) { + replacementRecipes.put(id, new RecipeHolder<>(id, recipe)); + } + }); + } + }); + recipeManager.replaceRecipes(replacementRecipes.values()); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/data/dynamic/DynamicTagHandler.java b/src/main/java/com/gregtechceu/gtceu/data/dynamic/DynamicTagHandler.java new file mode 100644 index 00000000000..d20d159ddad --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/data/dynamic/DynamicTagHandler.java @@ -0,0 +1,278 @@ +package com.gregtechceu.gtceu.data.dynamic; + +import com.gregtechceu.gtceu.GTCEu; +import com.gregtechceu.gtceu.api.GTValues; +import com.gregtechceu.gtceu.api.data.chemical.material.ItemMaterialData; +import com.gregtechceu.gtceu.api.data.chemical.material.Material; +import com.gregtechceu.gtceu.api.data.chemical.material.properties.FluidProperty; +import com.gregtechceu.gtceu.api.data.chemical.material.properties.OreProperty; +import com.gregtechceu.gtceu.api.data.chemical.material.properties.PropertyKey; +import com.gregtechceu.gtceu.api.data.tag.TagPrefix; +import com.gregtechceu.gtceu.api.fluids.FluidState; +import com.gregtechceu.gtceu.api.fluids.GTFluid; +import com.gregtechceu.gtceu.api.fluids.store.FluidStorageKey; +import com.gregtechceu.gtceu.api.registry.GTRegistries; +import com.gregtechceu.gtceu.common.data.GTMaterialItems; +import com.gregtechceu.gtceu.config.ConfigHolder; +import com.gregtechceu.gtceu.data.recipe.CustomTags; + +import net.minecraft.core.Registry; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.*; +import net.minecraft.world.item.ArmorItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.ItemLike; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.material.Fluid; + +import org.jetbrains.annotations.ApiStatus; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.function.Supplier; +import java.util.stream.Collector; +import java.util.stream.Collectors; + +@SuppressWarnings("deprecation") +@ApiStatus.Internal +public final class DynamicTagHandler { + + private DynamicTagHandler() {} + + public static void generateDynamicTags(Map> parsedTags, + Registry registry) { + long startTime = System.currentTimeMillis(); + + if (registry == BuiltInRegistries.ITEM) { + generateItemTags(parsedTags); + } else if (registry == BuiltInRegistries.BLOCK) { + generateBlockTags(parsedTags); + } else if (registry == BuiltInRegistries.FLUID) { + generateFluidTags(parsedTags); + } else { + // skip printing the "tag generation took ..." message if this isn't one of the registries we're + // generating tags for + return; + } + + GTCEu.LOGGER.info("GregTech dynamic {} tag generation took {}ms", registry.key().location().getPath(), + System.currentTimeMillis() - startTime); + } + + private static void generateItemTags(Map> tags) { + ItemMaterialData.MATERIAL_ENTRY_ITEM_MAP.forEach((entry, itemLikes) -> { + if (itemLikes.isEmpty()) return; + Material material = entry.material(); + if (material.isNull()) return; + var entries = itemLikes.stream() + .map(Supplier::get) + .map(DynamicTagHandler::makeItemEntry) + .collect(toArrayList()); + + var prefixTagKeys = entry.tagPrefix().getAllItemTags(material); + for (TagKey prefixTag : prefixTagKeys) { + tags.computeIfAbsent(prefixTag.location(), path -> new ArrayList<>()).addAll(entries); + } + for (TagKey materialTag : material.getItemTags()) { + tags.computeIfAbsent(materialTag.location(), path -> new ArrayList<>()).addAll(entries); + } + + if (entry.tagPrefix() == TagPrefix.crushed && material.hasProperty(PropertyKey.ORE)) { + OreProperty ore = material.getProperty(PropertyKey.ORE); + Material washedIn = ore.getWashedIn().first(); + if (washedIn.isNull()) return; + ResourceLocation generalTag = CustomTags.CHEM_BATH_WASHABLE.location(); + ResourceLocation specificTag = generalTag.withSuffix("/" + washedIn.getName()); + + tags.computeIfAbsent(generalTag, path -> new ArrayList<>()).addAll(entries); + tags.computeIfAbsent(specificTag, path -> new ArrayList<>()).addAll(entries); + } + }); + + GTMaterialItems.TOOL_ITEMS.rowMap().forEach((material, map) -> { + map.values().forEach(item -> { + if (item == null) return; + var entry = makeItemEntry(item); + for (TagKey tag : item.get().getToolType().itemTags) { + tags.computeIfAbsent(tag.location(), path -> new ArrayList<>()).add(entry); + } + }); + }); + + GTMaterialItems.ARMOR_ITEMS.rowMap().forEach((material, map) -> { + map.forEach((type, item) -> { + if (type == null || type == ArmorItem.Type.BODY) { + return; + } + if (item != null) { + var entry = new TagLoader.EntryWithSource(TagEntry.element(item.getId()), + GTValues.CUSTOM_TAG_SOURCE); + tags.computeIfAbsent(ItemTags.TRIMMABLE_ARMOR.location(), $ -> new ArrayList<>()) + .add(entry); + tags.computeIfAbsent(switch (type) { + case HELMET -> ItemTags.HEAD_ARMOR.location(); + case CHESTPLATE -> ItemTags.CHEST_ARMOR.location(); + case LEGGINGS -> ItemTags.LEG_ARMOR.location(); + case BOOTS -> ItemTags.FOOT_ARMOR.location(); + default -> throw new IllegalStateException("Unexpected value: " + type); + }, $ -> new ArrayList<>()).add(entry); + } + }); + }); + + if (GTCEu.Mods.isAE2Loaded()) { + // If AE2 is loaded, add the Fluid P2P attunement tag to all the buckets + ResourceLocation p2pFluidAttunementsTag = ResourceLocation.fromNamespaceAndPath(GTValues.MODID_APPENG, + "p2p_attunements/fluid_p2p_tunnel"); + for (Material material : GTRegistries.MATERIALS) { + FluidProperty property = material.getProperty(PropertyKey.FLUID); + if (property == null) { + continue; + } + for (FluidStorageKey key : FluidStorageKey.allKeys()) { + Fluid fluid = property.get(key); + if (fluid == null || fluid.getBucket() == Items.AIR) { + continue; + } + var entry = makeItemEntry(fluid.getBucket()); + tags.computeIfAbsent(p2pFluidAttunementsTag, path -> new ArrayList<>()).add(entry); + } + } + } + } + + private static void generateBlockTags(Map> tags) { + ItemMaterialData.MATERIAL_ENTRY_BLOCK_MAP.forEach((entry, blocks) -> { + if (blocks.isEmpty()) return; + Material material = entry.material(); + if (material.isNull()) return; + var entries = blocks.stream() + .map(DynamicTagHandler::makeBlockEntry) + .collect(toArrayList()); + + var prefixTagKeys = entry.tagPrefix().getAllBlockTags(material); + for (TagKey prefixTag : prefixTagKeys) { + tags.computeIfAbsent(prefixTag.location(), path -> new ArrayList<>()).addAll(entries); + } + + // Add mineability tags + if (!entry.isIgnored() && !entry.tagPrefix().miningToolTag().isEmpty()) { + tags.computeIfAbsent(CustomTags.TOOL_TIERS[material.getBlockHarvestLevel()].location(), + path -> new ArrayList<>()).addAll(entries); + if (material.hasProperty(PropertyKey.WOOD)) { + // Wood blocks with this tag always allow a Wrench, but only allow an Axe if the config is + // not set. Pickaxe is never allowed (special case) + if (entry.tagPrefix().miningToolTag() + .contains(CustomTags.MINEABLE_WITH_CONFIG_VALID_PICKAXE_WRENCH)) { + tags.computeIfAbsent(CustomTags.MINEABLE_WITH_WRENCH.location(), + path -> new ArrayList<>()).addAll(entries); + if (!ConfigHolder.INSTANCE.machines.requireGTToolsForBlocks) { + tags.computeIfAbsent(BlockTags.MINEABLE_WITH_AXE.location(), + path -> new ArrayList<>()) + .addAll(entries); + } + } else { + // Other wood stuff should still get the Axe tag + tags.computeIfAbsent(BlockTags.MINEABLE_WITH_AXE.location(), path -> new ArrayList<>()) + .addAll(entries); + } + } else { + for (var tag : entry.tagPrefix().miningToolTag()) { + tags.computeIfAbsent(tag.location(), path -> new ArrayList<>()).addAll(entries); + } + } + } + + if (entry.tagPrefix() == TagPrefix.oreEndstone) { + // Make endstone-based ores dragon-immune + tags.computeIfAbsent(BlockTags.DRAGON_IMMUNE.location(), $ -> new ArrayList<>()).addAll(entries); + } + + if (entry.tagPrefix() == TagPrefix.frameGt) { + tags.computeIfAbsent(CustomTags.SLOW_WALKABLE_BLOCKS.location(), path -> new ArrayList<>()) + .addAll(entries); + } + }); + + GTRegistries.MACHINES.forEach(machine -> { + tags.computeIfAbsent(CustomTags.MINEABLE_WITH_CONFIG_VALID_PICKAXE_WRENCH.location(), + path -> new ArrayList<>()).add(makeBlockEntry(machine.getBlock())); + }); + + // if config is NOT enabled, add the "configurable" mineability tags to the pickaxe tag + if (!ConfigHolder.INSTANCE.machines.requireGTToolsForBlocks) { + var tagList = tags.computeIfAbsent(BlockTags.MINEABLE_WITH_PICKAXE.location(), + path -> new ArrayList<>()); + + tagList.add(makeTagEntry(CustomTags.MINEABLE_WITH_CONFIG_VALID_PICKAXE_WRENCH)); + tagList.add(makeTagEntry(CustomTags.MINEABLE_WITH_CONFIG_VALID_PICKAXE_WIRE_CUTTER)); + } + } + + private static void generateFluidTags(Map> tags) { + for (Material material : GTRegistries.MATERIALS) { + FluidProperty property = material.getProperty(PropertyKey.FLUID); + if (property == null) { + continue; + } + for (FluidStorageKey key : FluidStorageKey.allKeys()) { + Fluid fluid = property.get(key); + if (fluid == null) { + continue; + } + ItemMaterialData.FLUID_MATERIAL.put(fluid, material); + + TagLoader.EntryWithSource entry = makeFluidEntry(fluid); + + ResourceLocation fluidIdTag = fluid.builtInRegistryHolder().key().location(); + fluidIdTag = ResourceLocation.fromNamespaceAndPath("c", fluidIdTag.getPath()); + tags.computeIfAbsent(fluidIdTag, path -> new ArrayList<>()).add(entry); + + FluidState state; + if (fluid instanceof GTFluid gtFluid) { + state = gtFluid.getState(); + } else { + state = key.getDefaultFluidState(); + } + if (state != null) { + tags.computeIfAbsent(state.getTagKey().location(), path -> new ArrayList<>()).add(entry); + } + + if (key.getExtraTag() != null) { + tags.computeIfAbsent(key.getExtraTag().location(), path -> new ArrayList<>()).add(entry); + } + } + } + } + + private static Collector> toArrayList() { + return Collectors.toCollection(ArrayList::new); + } + + private static TagLoader.EntryWithSource makeItemEntry(ItemLike item) { + return makeElementEntry(item.asItem().builtInRegistryHolder().key().location()); + } + + private static TagLoader.EntryWithSource makeBlockEntry(Supplier block) { + return makeBlockEntry(block.get()); + } + + private static TagLoader.EntryWithSource makeBlockEntry(Block block) { + return makeElementEntry(block.builtInRegistryHolder().key().location()); + } + + private static TagLoader.EntryWithSource makeFluidEntry(Fluid fluid) { + return makeElementEntry(fluid.builtInRegistryHolder().key().location()); + } + + private static TagLoader.EntryWithSource makeElementEntry(ResourceLocation id) { + return new TagLoader.EntryWithSource(TagEntry.element(id), GTValues.CUSTOM_TAG_SOURCE); + } + + private static TagLoader.EntryWithSource makeTagEntry(TagKey tag) { + return new TagLoader.EntryWithSource(TagEntry.tag(tag.location()), GTValues.CUSTOM_TAG_SOURCE); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/data/loader/DeferredOwnerUnwrappingHolderLookupAdapter.java b/src/main/java/com/gregtechceu/gtceu/data/loader/DeferredOwnerUnwrappingHolderLookupAdapter.java new file mode 100644 index 00000000000..df71272b1a9 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/data/loader/DeferredOwnerUnwrappingHolderLookupAdapter.java @@ -0,0 +1,53 @@ +package com.gregtechceu.gtceu.data.loader; + +import net.minecraft.core.HolderLookup; +import net.minecraft.core.HolderOwner; +import net.minecraft.core.Registry; +import net.minecraft.resources.RegistryOps; +import net.minecraft.resources.ResourceKey; + +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + +public class DeferredOwnerUnwrappingHolderLookupAdapter implements RegistryOps.RegistryInfoLookup { + + public final HolderLookup.Provider lookupProvider; + private final Map>, Optional>> lookups = new ConcurrentHashMap<>(); + + public DeferredOwnerUnwrappingHolderLookupAdapter(HolderLookup.Provider lookupProvider) { + this.lookupProvider = lookupProvider; + } + + @SuppressWarnings("unchecked") + @Override + public Optional> lookup(ResourceKey> registryKey) { + return (Optional>) this.lookups.computeIfAbsent(registryKey, this::createLookup); + } + + // the special sauce + private Optional> createLookup(ResourceKey> registryKey) { + return this.lookupProvider.lookup(registryKey).map(registryLookup -> { + // unwrap the real holder *owner* from whatever delegates it might be buried in so using + // RegistryFileCodec#encode works with this RegistryOps + HolderOwner owner = registryLookup; + while (owner instanceof HolderLookup.RegistryLookup.Delegate delegate) { + owner = delegate.parent(); + } + // still hand vanilla the original holder *getter* so adding entries works if this is a tag adding lookup + return new RegistryOps.RegistryInfo<>(owner, registryLookup, registryLookup.registryLifecycle()); + }); + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + return other instanceof DeferredOwnerUnwrappingHolderLookupAdapter holderLookupAdapter && + this.lookupProvider.equals(holderLookupAdapter.lookupProvider); + } + + @Override + public int hashCode() { + return this.lookupProvider.hashCode(); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/data/loader/PostRegistryListener.java b/src/main/java/com/gregtechceu/gtceu/data/loader/PostRegistryListener.java index c51348f6f76..3daf3f47489 100644 --- a/src/main/java/com/gregtechceu/gtceu/data/loader/PostRegistryListener.java +++ b/src/main/java/com/gregtechceu/gtceu/data/loader/PostRegistryListener.java @@ -7,24 +7,18 @@ import com.gregtechceu.gtceu.integration.map.cache.server.ServerCache; import net.minecraft.core.HolderLookup; -import net.minecraft.server.packs.resources.PreparableReloadListener; import net.minecraft.server.packs.resources.ResourceManager; -import net.minecraft.util.profiling.ProfilerFiller; +import net.minecraft.server.packs.resources.ResourceManagerReloadListener; import net.neoforged.neoforge.resource.ContextAwareReloadListener; -import org.jetbrains.annotations.NotNullByDefault; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; - -@NotNullByDefault -public class PostRegistryListener extends ContextAwareReloadListener implements PreparableReloadListener { +public class PostRegistryListener extends ContextAwareReloadListener implements ResourceManagerReloadListener { public static final PostRegistryListener INSTANCE = new PostRegistryListener(); private PostRegistryListener() {} - protected void apply() { + @Override + public void onResourceManagerReload(ResourceManager resourceManager) { var lookup = getRegistryLookup().lookupOrThrow(GTRegistries.Keys.ORE_VEIN); buildVeinGenerators(lookup); GTOreVeins.updateLargestVeinSize(lookup); @@ -42,11 +36,4 @@ public static void buildVeinGenerators(HolderLookup.RegistryLookup reload(PreparationBarrier stage, ResourceManager resourceManager, - ProfilerFiller preparationsProfiler, ProfilerFiller reloadProfiler, - Executor backgroundExecutor, Executor gameExecutor) { - return stage.wait(null).thenRunAsync(this::apply); - } } diff --git a/src/main/java/com/gregtechceu/gtceu/data/loader/package-info.java b/src/main/java/com/gregtechceu/gtceu/data/loader/package-info.java new file mode 100644 index 00000000000..e790ffb39e2 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/data/loader/package-info.java @@ -0,0 +1,4 @@ +@NotNullByDefault +package com.gregtechceu.gtceu.data.loader; + +import org.jetbrains.annotations.NotNullByDefault; diff --git a/src/main/java/com/gregtechceu/gtceu/data/pack/GTDynamicDataPack.java b/src/main/java/com/gregtechceu/gtceu/data/pack/GTDynamicDataPack.java index 0b7246c2593..473e51587e7 100644 --- a/src/main/java/com/gregtechceu/gtceu/data/pack/GTDynamicDataPack.java +++ b/src/main/java/com/gregtechceu/gtceu/data/pack/GTDynamicDataPack.java @@ -2,12 +2,14 @@ import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.api.addon.AddonFinder; +import com.gregtechceu.gtceu.api.addon.IGTAddon; import com.gregtechceu.gtceu.config.ConfigHolder; import net.minecraft.SharedConstants; import net.minecraft.advancements.Advancement; import net.minecraft.advancements.AdvancementHolder; import net.minecraft.core.HolderLookup; +import net.minecraft.data.recipes.RecipeOutput; import net.minecraft.network.chat.Component; import net.minecraft.resources.FileToIdConverter; import net.minecraft.resources.ResourceLocation; @@ -22,6 +24,7 @@ import com.google.common.collect.Sets; import com.google.gson.JsonElement; +import com.mojang.serialization.DynamicOps; import com.mojang.serialization.JsonOps; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import it.unimi.dsi.fastutil.objects.ObjectSet; @@ -41,7 +44,7 @@ public class GTDynamicDataPack implements PackResources { protected static final ObjectSet SERVER_DOMAINS = new ObjectOpenHashSet<>(); protected static final GTDynamicPackContents CONTENTS = new GTDynamicPackContents(); - private static final FileToIdConverter RECIPE_ID_CONVERTER = FileToIdConverter.json("recipe"); + public static final FileToIdConverter RECIPE_ID_CONVERTER = FileToIdConverter.json("recipe"); private static final FileToIdConverter LOOT_TABLE_ID_CONVERTER = FileToIdConverter.json("loot_table"); private static final FileToIdConverter ADVANCEMENT_ID_CONVERTER = FileToIdConverter.json("advancement"); @@ -80,32 +83,45 @@ public static void addResource(ResourceLocation location, byte[] data) { CONTENTS.addToData(location, data); } + /** + * @deprecated API consumers shouldn't use this method. Instead, they should implement their recipe additions in + * {@link IGTAddon#addRecipes(RecipeOutput) IGTAddon.addRecipes}. + * @see IGTAddon#addRecipes(RecipeOutput) + */ + @Deprecated(since = "8.0.0", forRemoval = true) public static void addRecipe(ResourceLocation recipeId, Recipe recipe, @Nullable AdvancementHolder advancement, HolderLookup.Provider registries) { + DynamicOps serializationContext = registries.createSerializationContext(JsonOps.INSTANCE); JsonElement recipeJson = Recipe.CODEC - .encodeStart(registries.createSerializationContext(JsonOps.INSTANCE), recipe) + .encodeStart(serializationContext, recipe) .getOrThrow(); addResource(RECIPE_ID_CONVERTER.idToFile(recipeId), recipeJson); if (advancement != null) { - addAdvancement(advancement, registries); + addAdvancement(advancement, serializationContext); } } - public static void addAdvancement(AdvancementHolder advancement, HolderLookup.Provider registries) { - addAdvancement(advancement.id(), advancement.value(), registries); + public static void addAdvancement(AdvancementHolder advancement, DynamicOps serializationContext) { + addAdvancement(advancement.id(), advancement.value(), serializationContext); } - public static void addAdvancement(ResourceLocation loc, Advancement advancement, HolderLookup.Provider registries) { + public static void addAdvancement(ResourceLocation loc, Advancement advancement, + DynamicOps serializationContext) { JsonElement advancementJson = Advancement.CODEC - .encodeStart(registries.createSerializationContext(JsonOps.INSTANCE), advancement) + .encodeStart(serializationContext, advancement) .getOrThrow(); addResource(ADVANCEMENT_ID_CONVERTER.idToFile(loc), advancementJson); } - public static void addLootTable(ResourceLocation lootTableId, LootTable table, HolderLookup.Provider registries) { - JsonElement lootTableJson = LootTable.DIRECT_CODEC - .encodeStart(registries.createSerializationContext(JsonOps.INSTANCE), table).getOrThrow(); + public static void addLootTable(ResourceLocation lootTableId, LootTable table, + HolderLookup.Provider registries) { + addLootTable(lootTableId, table, registries.createSerializationContext(JsonOps.INSTANCE)); + } + + public static void addLootTable(ResourceLocation lootTableId, LootTable table, + DynamicOps serializationContext) { + JsonElement lootTableJson = LootTable.DIRECT_CODEC.encodeStart(serializationContext, table).getOrThrow(); ResourceLocation fileName = LOOT_TABLE_ID_CONVERTER.idToFile(lootTableId); if (CONTENTS.getResource(fileName) != null) { diff --git a/src/main/java/com/gregtechceu/gtceu/data/tags/BlockTagLoader.java b/src/main/java/com/gregtechceu/gtceu/data/tags/BlockTagLoader.java index 24392760845..ad719353c03 100644 --- a/src/main/java/com/gregtechceu/gtceu/data/tags/BlockTagLoader.java +++ b/src/main/java/com/gregtechceu/gtceu/data/tags/BlockTagLoader.java @@ -32,7 +32,6 @@ public static void init(RegistrateTagsProvider.IntrinsicImpl provider) { provider.addTag(CustomTags.NEEDS_NEUTRONIUM_TOOL); provider.addTag(CustomTags.NEEDS_DURANIUM_TOOL); - @SuppressWarnings("unchecked") TagKey[] newToolRequirements = new TagKey[] { CustomTags.NEEDS_NEUTRONIUM_TOOL, @@ -54,6 +53,12 @@ public static void init(RegistrateTagsProvider.IntrinsicImpl provider) { provider.addTag(CustomTags.INCORRECT_FOR_NEUTRONIUM_TOOL); provider.addTag(CustomTags.INCORRECT_FOR_DURANIUM_TOOL).addTag(CustomTags.NEEDS_NEUTRONIUM_TOOL); + provider.addTag(CustomTags.MINEABLE_WITH_SAW).addTag(BlockTags.ICE); + // create empty tag files for the (currently) unused ones so MC is happy + provider.addTag(CustomTags.MINEABLE_WITH_HAMMER); + provider.addTag(CustomTags.MINEABLE_WITH_CROWBAR); + provider.addTag(CustomTags.MINEABLE_WITH_KNIFE); + // this is awful. I don't care, though. provider.addTag(BlockTags.REPLACEABLE) .add(GTMaterials.Oil.getFluid().defaultFluidState().createLegacyBlock().getBlock()) @@ -95,6 +100,12 @@ public static void init(RegistrateTagsProvider.IntrinsicImpl provider) { .addTag(Tags.Blocks.SANDS).addTag(BlockTags.SAND) // any sand blocks .addTag(BlockTags.TERRACOTTA); // any terracotta - provider.addTag(CustomTags.CLEANROOM_DOORS).add(Blocks.IRON_DOOR).addTag(BlockTags.WOODEN_DOORS); + provider.addTag(CustomTags.CLEANROOM_DOORS) + .add(Blocks.IRON_DOOR).addTag(BlockTags.WOODEN_DOORS) + // disallow unwaxed copper doors specifically + .add(Blocks.WAXED_COPPER_DOOR, + Blocks.WAXED_EXPOSED_COPPER_DOOR, + Blocks.WAXED_WEATHERED_COPPER_DOOR, + Blocks.WAXED_OXIDIZED_COPPER_DOOR); } } diff --git a/src/main/java/com/gregtechceu/gtceu/integration/kjs/builders/prefix/OreTagPrefixBuilder.java b/src/main/java/com/gregtechceu/gtceu/integration/kjs/builders/prefix/OreTagPrefixBuilder.java index 73c4f1fb231..d9d232e844a 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/kjs/builders/prefix/OreTagPrefixBuilder.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/kjs/builders/prefix/OreTagPrefixBuilder.java @@ -43,9 +43,9 @@ public OreTagPrefixBuilder(ResourceLocation id) { @Override public TagPrefix create(String id) { return new TagPrefix(id) - .defaultTagPath("ores/%s") - .prefixOnlyTagPath("ores_in_ground/%s") - .unformattedTagPath("ores") + .defaultTag("ores/%s") + .prefixOnlyTag("ores_in_ground/%s") + .unformattedTag("ores") .materialIconType(MaterialIconType.ore) .unificationEnabled(true) .blockConstructor(OreBlock::new) diff --git a/src/main/java/com/gregtechceu/gtceu/integration/kjs/builders/prefix/TagPrefixBuilder.java b/src/main/java/com/gregtechceu/gtceu/integration/kjs/builders/prefix/TagPrefixBuilder.java index a51af258ec0..1bd14776e28 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/kjs/builders/prefix/TagPrefixBuilder.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/kjs/builders/prefix/TagPrefixBuilder.java @@ -15,6 +15,7 @@ import net.minecraft.world.level.block.state.BlockBehaviour; import dev.latvian.mods.kubejs.registry.BuilderBase; +import dev.latvian.mods.kubejs.typings.Info; import lombok.Getter; import lombok.experimental.Accessors; @@ -111,46 +112,104 @@ public TagPrefixBuilder addSecondaryMaterial(MaterialStack secondaryMaterial) { return this; } + @Info(""" + Deprecated. Use `defaultTag(path)` instead. + """) public TagPrefixBuilder defaultTagPath(String path) { - base.defaultTagPath(path); + return defaultTag(path); + } + + public TagPrefixBuilder defaultTag(String path) { + base.defaultTag(path); return this; } + @Info(""" + Deprecated. Use `defaultTag(path, isVanilla)` instead. + """) public TagPrefixBuilder defaultTagPath(String path, boolean isVanilla) { - base.defaultTagPath(path, isVanilla); + return defaultTag(path, isVanilla); + } + + public TagPrefixBuilder defaultTag(String path, boolean isVanilla) { + base.defaultTag(path, isVanilla); return this; } public TagPrefixBuilder prefixTagPath(String path) { - base.prefixTagPath(path); + return prefixTag(path); + } + + public TagPrefixBuilder prefixTag(String path) { + base.prefixTag(path); return this; } public TagPrefixBuilder prefixOnlyTagPath(String path) { - base.prefixOnlyTagPath(path); + return prefixOnlyTag(path); + } + + public TagPrefixBuilder prefixOnlyTag(String path) { + base.prefixOnlyTag(path); return this; } public TagPrefixBuilder unformattedTagPath(String path) { - base.unformattedTagPath(path); + return unformattedTag(path); + } + + public TagPrefixBuilder unformattedTag(String path) { + base.unformattedTag(path); return this; } + @Info(""" + Deprecated. Use `unformattedTag(path, isVanilla)` instead. + """) public TagPrefixBuilder unformattedTagPath(String path, boolean isVanilla) { - base.unformattedTagPath(path, isVanilla); + return unformattedTag(path, isVanilla); + } + + public TagPrefixBuilder unformattedTag(String path, boolean isVanilla) { + base.unformattedTag(path, isVanilla); return this; } + @Info(""" + Deprecated. Use `customFormattedTag(path, (path, mat) => ...)` instead. + """) + @SuppressWarnings("removal") public TagPrefixBuilder customTagPath(String path, BiFunction> formatter) { base.customTagPath(path, formatter); return this; } + public TagPrefixBuilder customFormattedTag(String path, BiFunction> formatter) { + base.customFormattedTag(path, formatter); + return this; + } + + @Info(""" + Deprecated. Use `filteredUnformattedTag(path, isVanilla, (mat) => ...shouldAdd...)` instead. + """) + @SuppressWarnings("removal") public TagPrefixBuilder customTagPredicate(String path, boolean isVanilla, Predicate materialPredicate) { base.customTagPredicate(path, isVanilla, materialPredicate); return this; } + public TagPrefixBuilder filteredUnformattedTag(String path, boolean isVanilla, + Predicate materialPredicate) { + base.filteredUnformattedTag(path, isVanilla, materialPredicate); + return this; + } + + public TagPrefixBuilder filteredCustomTag(String path, Predicate materialPredicate, + BiFunction> formatter) { + base.filteredCustomTag(path, materialPredicate, formatter); + return this; + } + public TagPrefixBuilder miningToolTag(TagKey tag) { base.miningToolTag(tag); return this;