Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
# 2.6.0
- Mining Level and Tool Suitability Adjustments for Blocks Added via Chisel [#343](https://github.com/GTModpackTeam/GTExpert-Core/pull/343)
- DEDA Integration Refactoring [#344](https://github.com/GTModpackTeam/GTExpert-Core/pull/344)

* * *

# 2.5.6
- Fix Implosion logic
- Mining Level and Tool Suitability Adjustments for Blocks Added via Chisel [#343](https://github.com/GTModpackTeam/GTExpert-Core/pull/343)

* * *

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.github.gtexpert.core.integration.ae.recipes;

import static com.github.gtexpert.core.integration.deda.recipes.DraconicMaterialsRecipe.ABFDurationMultiplier;
import static com.github.gtexpert.core.integration.deda.DEDAConstants.ABF_DURATION_MULTIPLIER;
import static gregtech.api.GTValues.*;
import static gregtech.api.unification.ore.OrePrefix.*;

Expand Down Expand Up @@ -348,7 +348,7 @@ public static void init() {
.fluidInputs(GTEMaterials.Pyrotheum.getFluid(GCYMFluidStorageKeys.MOLTEN, 200))
.fluidOutputs(GTEMaterials.FluixAlloy.getFluid(GCYMFluidStorageKeys.MOLTEN, 1152))
.blastFurnaceTemp(propertyFluixAlloy.getBlastTemperature())
.duration((int) ((durationFluixAlloy * 0.67 * ABFDurationMultiplier) / 2))
.duration((int) ((durationFluixAlloy * 0.67 * ABF_DURATION_MULTIPLIER) / 2))
.EUt(VA[GTEValues.ae2VoltageTier])
.buildAndRegister();
}
Expand All @@ -362,7 +362,7 @@ public static void init() {
.fluidInputs(Materials.Nitrogen.getFluid(6000))
.fluidOutputs(GTEMaterials.FluixAlloy.getFluid(GCYMFluidStorageKeys.MOLTEN, 1152))
.blastFurnaceTemp(propertyFluixAlloy.getBlastTemperature())
.duration((int) (durationFluixAlloy * 0.67 * ABFDurationMultiplier)).EUt(VA[GTEValues.ae2VoltageTier])
.duration((int) (durationFluixAlloy * 0.67 * ABF_DURATION_MULTIPLIER)).EUt(VA[GTEValues.ae2VoltageTier])
.buildAndRegister();
GCYMRecipeMaps.ALLOY_BLAST_RECIPES.recipeBuilder()
.circuitMeta(4)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,13 @@ public class DEDAConfigHolder {
"The material is also adjusted to each voltage.", "Default: 6 (LuV)" })
@Config.RangeInt(min = 3, max = 6)
public static int voltageTier = 6;

@Config.Comment({ "Enable verbose logging for upgrade recipe lookup debugging.",
"Useful for troubleshooting recipe matching issues.", "Default: false" })
public static boolean debugRecipeLookup = false;

@Config.Comment({ "Enable caching for upgrade recipe lookups.",
"Improves performance by indexing recipes by catalyst item type.",
"Disable if you experience recipe matching issues.", "Default: true" })
public static boolean enableUpgradeRecipeCache = true;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.github.gtexpert.core.integration.deda;

import net.minecraftforge.fluids.FluidStack;

import gregicality.multiblocks.api.fluids.GCYMFluidStorageKeys;

import com.github.gtexpert.core.api.unification.material.GTEMaterials;

/**
* Constants and helpers for DEDA (Draconic Evolution / Draconic Additions) integration.
*/
public final class DEDAConstants {

private DEDAConstants() {}

// Alloy Blast Furnace constants
public static final int ABF_PYROTHEUM_AMOUNT = 200;
public static final double ABF_DURATION_MULTIPLIER = 0.5;

// Recipe durations (ticks)
public static final int DURATION_WYVERN = 200;
public static final int DURATION_DRACONIC = 400;
public static final int DURATION_CHAOTIC = 600;

public static FluidStack getCryotheum(DraconicTier tier) {
return switch (tier) {
case WYVERN -> GTEMaterials.Cryotheum.getFluid(16000);
case DRACONIC -> GTEMaterials.Cryotheum.getFluid(32000);
case CHAOTIC -> GTEMaterials.Cryotheum.getFluid(48000);
};
}

public static FluidStack getPyrotheum(DraconicTier tier) {
return switch (tier) {
case WYVERN -> GTEMaterials.Pyrotheum.getFluid(GCYMFluidStorageKeys.MOLTEN, 4000);
case DRACONIC -> GTEMaterials.Pyrotheum.getFluid(GCYMFluidStorageKeys.MOLTEN, 8000);
case CHAOTIC -> GTEMaterials.Pyrotheum.getFluid(GCYMFluidStorageKeys.MOLTEN, 12000);
};
}

/**
* Draconic Evolution tool/armor tiers.
*/
public enum DraconicTier {

WYVERN(0),
DRACONIC(1),
CHAOTIC(2);

public final int voltageOffset;

DraconicTier(int voltageOffset) {
this.voltageOffset = voltageOffset;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.github.gtexpert.core.integration.deda;

import static gregtech.api.GTValues.VA;

import net.minecraft.item.ItemStack;
import net.minecraftforge.fluids.FluidStack;

import gregtech.api.recipes.ingredients.GTRecipeInput;
import gregtech.api.recipes.ingredients.GTRecipeItemInput;
import gregtech.api.recipes.ingredients.nbtmatch.NBTCondition;
import gregtech.api.recipes.ingredients.nbtmatch.NBTMatcher;

import com.github.gtexpert.core.api.GTEValues;
import com.github.gtexpert.core.integration.deda.DEDAConstants.DraconicTier;

/**
* Helper methods for DEDA integration recipes.
*/
public final class DEDARecipeHelper {

private DEDARecipeHelper() {}

public static int voltage(DraconicTier tier) {
return VA[GTEValues.dedaVoltageTier + tier.voltageOffset];
}

public static FluidStack cryotheum(DraconicTier tier) {
return DEDAConstants.getCryotheum(tier);
}

public static FluidStack pyrotheum(DraconicTier tier) {
return DEDAConstants.getPyrotheum(tier);
}

public static GTRecipeInput inputWithAnyNBT(ItemStack stack) {
return new GTRecipeItemInput(stack).setNBTMatchingCondition(NBTMatcher.ANY, NBTCondition.ANY);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,18 @@ public class DEDAJEIProvider implements IModPlugin {
@Override
public void register(@NotNull IModRegistry registry) {
if (GTEValues.isModLoadedDEDA()) {
registry.addRecipeCatalyst(DEDAMetaTileEntities.DRACONIUM_FUSION.getStackForm(),
GTValues.MODID + ":" + GTEDraconicRecipeMaps.DRACONIC_FUSION_TIER_UP_FAKE_RECIPES.unlocalizedName);
registry.addRecipeCatalyst(DEDAMetaTileEntities.AWAKENED_DRACONIUM_FUSION.getStackForm(), GTValues.MODID +
":" + GTEDraconicRecipeMaps.AWAKENED_DRACONIC_FUSION_TIER_UP_FAKE_RECIPES.unlocalizedName);
registry.addRecipeCatalyst(DEDAMetaTileEntities.DRACONIUM_FUSION.getStackForm(),
GTValues.MODID + ":" + GTEDraconicRecipeMaps.DRACONIC_FUSION_UPGRADE_FAKE_RECIPES.unlocalizedName);
registry.addRecipeCatalyst(DEDAMetaTileEntities.AWAKENED_DRACONIUM_FUSION.getStackForm(), GTValues.MODID +
":" + GTEDraconicRecipeMaps.AWAKENED_DRACONIC_FUSION_UPGRADE_FAKE_RECIPES.unlocalizedName);
String fusionCategory = GTValues.MODID + ":" +
GTEDraconicRecipeMaps.DRACONIUM_FUSION_RECIPES.unlocalizedName;
String tierUpCategory = GTValues.MODID + ":" +
GTEDraconicRecipeMaps.DRACONIC_FUSION_TIER_UP_RECIPES.unlocalizedName;
String upgradeCategory = GTValues.MODID + ":" +
GTEDraconicRecipeMaps.DRACONIC_FUSION_UPGRADE_RECIPES.unlocalizedName;

registry.addRecipeCatalyst(DEDAMetaTileEntities.AWAKENED_DRACONIUM_FUSION.getStackForm(), fusionCategory);
registry.addRecipeCatalyst(DEDAMetaTileEntities.DRACONIUM_FUSION.getStackForm(), tierUpCategory);
registry.addRecipeCatalyst(DEDAMetaTileEntities.AWAKENED_DRACONIUM_FUSION.getStackForm(), tierUpCategory);
registry.addRecipeCatalyst(DEDAMetaTileEntities.DRACONIUM_FUSION.getStackForm(), upgradeCategory);
registry.addRecipeCatalyst(DEDAMetaTileEntities.AWAKENED_DRACONIUM_FUSION.getStackForm(), upgradeCategory);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,68 +19,29 @@
public class GTEDraconicRecipeMaps {

/**
* Fake recipe map to show tier-up recipes for draconic fusion on JEI.
* In order to preserve upgrade info NBT, actual recipe is handled by {@link RecipeMapDraconicFusion}.
* Unified recipe map to show all tier-up recipes for draconic fusion on JEI.
* Consolidates recipes from both Draconic and Awakened fusion machines.
* Actual recipe execution is handled by {@link RecipeMapDraconicFusion}.
*/
public static final RecipeMap<TierUpRecipeBuilder> DRACONIC_FUSION_TIER_UP_FAKE_RECIPES = new RecipeMapDraconicUpgrade<>(
@ZenProperty
public static final RecipeMap<TierUpRecipeBuilder> DRACONIC_FUSION_TIER_UP_RECIPES = new RecipeMapDraconicUpgrade<>(
"draconic_fusion_tier_up", 6, 3, 3, 1, new TierUpRecipeBuilder(), false)
.setProgressBar(GuiTextures.PROGRESS_BAR_FUSION, ProgressWidget.MoveType.HORIZONTAL)
.onRecipeBuild(
recipeBuilder -> GTEDraconicRecipeMaps.AWAKENED_DRACONIC_FUSION_TIER_UP_FAKE_RECIPES
.recipeBuilder()
.inputs(recipeBuilder.getInputs().toArray(new GTRecipeInput[0]))
.fluidInputs(recipeBuilder.getFluidInputs())
.outputs(recipeBuilder.getOutputs())
.fluidOutputs(recipeBuilder.getFluidOutputs())
.duration(recipeBuilder.getDuration())
.EUt(recipeBuilder.getEUt())
.catalyst(recipeBuilder.getCatalyst())
.result(recipeBuilder.getResult())
.buildAndRegister());

/**
* Fake recipe map to show tier-up recipes for draconic fusion on JEI.
* In order to preserve upgrade info NBT, actual recipe is handled by {@link RecipeMapDraconicFusion}.
*/
public static final RecipeMap<TierUpRecipeBuilder> AWAKENED_DRACONIC_FUSION_TIER_UP_FAKE_RECIPES = new RecipeMapDraconicUpgrade<>(
"awakened_draconic_fusion_tier_up", 6, 3, 3, 1, new TierUpRecipeBuilder(), false)
.setProgressBar(GuiTextures.PROGRESS_BAR_FUSION, ProgressWidget.MoveType.HORIZONTAL)
.setSmallRecipeMap(DRACONIC_FUSION_TIER_UP_FAKE_RECIPES);
.setProgressBar(GuiTextures.PROGRESS_BAR_FUSION, ProgressWidget.MoveType.HORIZONTAL);

/**
* Fake recipe map to show upgrade recipes for draconic fusion on JEI.
* In order to preserve upgrade info NBT, actual recipe is handled by {@link RecipeMapDraconicFusion}.
* Unified recipe map to show all upgrade recipes for draconic fusion on JEI.
* Consolidates recipes from both Draconic and Awakened fusion machines.
* Actual recipe execution is handled by {@link RecipeMapDraconicFusion}.
*/
public static final RecipeMap<UpgradeRecipeBuilder> DRACONIC_FUSION_UPGRADE_FAKE_RECIPES = new RecipeMapDraconicUpgrade<>(
@ZenProperty
public static final RecipeMap<UpgradeRecipeBuilder> DRACONIC_FUSION_UPGRADE_RECIPES = new RecipeMapDraconicUpgrade<>(
"draconic_fusion_upgrade", 6, 3, 3, 1, new UpgradeRecipeBuilder(), false)
.setProgressBar(GuiTextures.PROGRESS_BAR_FUSION, ProgressWidget.MoveType.HORIZONTAL)
.onRecipeBuild(
recipeBuilder -> GTEDraconicRecipeMaps.AWAKENED_DRACONIC_FUSION_UPGRADE_FAKE_RECIPES
.recipeBuilder()
.inputs(recipeBuilder.getInputs().toArray(new GTRecipeInput[0]))
.fluidInputs(recipeBuilder.getFluidInputs())
.outputs(recipeBuilder.getOutputs())
.fluidOutputs(recipeBuilder.getFluidOutputs())
.duration(recipeBuilder.getDuration())
.EUt(recipeBuilder.getEUt())
.catalyst(recipeBuilder.getCatalyst())
.upgradeName(recipeBuilder.getUpgradeName())
.level(recipeBuilder.getCurrentLevel())
.buildAndRegister());

/**
* Fake recipe map to show upgrade recipes for draconic fusion on JEI.
* In order to preserve upgrade info NBT, actual recipe is handled by {@link RecipeMapDraconicFusion}.
*/
public static final RecipeMap<UpgradeRecipeBuilder> AWAKENED_DRACONIC_FUSION_UPGRADE_FAKE_RECIPES = new RecipeMapDraconicUpgrade<>(
"awakened_draconic_fusion_upgrade", 6, 3, 3, 1, new UpgradeRecipeBuilder(), false)
.setProgressBar(GuiTextures.PROGRESS_BAR_FUSION, ProgressWidget.MoveType.HORIZONTAL)
.setSmallRecipeMap(DRACONIC_FUSION_UPGRADE_FAKE_RECIPES);
.setProgressBar(GuiTextures.PROGRESS_BAR_FUSION, ProgressWidget.MoveType.HORIZONTAL);

@ZenProperty
public static final RecipeMap<SimpleRecipeBuilder> DRACONIUM_FUSION_RECIPES = new RecipeMapDraconicFusion(
"draconium_fusion", 6, 3, 3, 1, new SimpleRecipeBuilder(), false, DRACONIC_FUSION_TIER_UP_FAKE_RECIPES,
DRACONIC_FUSION_UPGRADE_FAKE_RECIPES)
"draconium_fusion", 6, 3, 3, 1, new SimpleRecipeBuilder(), false,
DRACONIC_FUSION_TIER_UP_RECIPES, DRACONIC_FUSION_UPGRADE_RECIPES)
.setProgressBar(GuiTextures.PROGRESS_BAR_FUSION, ProgressWidget.MoveType.HORIZONTAL)
.setSound(GTSoundEvents.ELECTROLYZER)
.onRecipeBuild(
Expand All @@ -96,9 +57,8 @@ public class GTEDraconicRecipeMaps {

@ZenProperty
public static final RecipeMap<SimpleRecipeBuilder> AWAKENED_DRACONIUM_FUSION_RECIPES = new RecipeMapDraconicFusion(
"awakened_draconium_fusion", 6, 3, 3, 1, new SimpleRecipeBuilder(), false,
AWAKENED_DRACONIC_FUSION_TIER_UP_FAKE_RECIPES, AWAKENED_DRACONIC_FUSION_UPGRADE_FAKE_RECIPES)
"awakened_draconium_fusion", 6, 3, 3, 1, new SimpleRecipeBuilder(), true,
DRACONIC_FUSION_TIER_UP_RECIPES, DRACONIC_FUSION_UPGRADE_RECIPES)
.setProgressBar(GuiTextures.PROGRESS_BAR_FUSION, ProgressWidget.MoveType.HORIZONTAL)
.setSound(GTSoundEvents.ELECTROLYZER)
.setSmallRecipeMap(DRACONIUM_FUSION_RECIPES);
.setSound(GTSoundEvents.ELECTROLYZER);
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import gregtech.api.recipes.builders.SimpleRecipeBuilder;

import com.github.gtexpert.core.api.util.GTELog;
import com.github.gtexpert.core.integration.deda.DEDAConfigHolder;
import com.github.gtexpert.core.integration.deda.recipemaps.tierup.TierUpRecipeBuilder;
import com.github.gtexpert.core.integration.deda.recipemaps.tierup.TierUpRecipeProperty;
import com.github.gtexpert.core.integration.deda.recipemaps.upgrade.UpgradeRecipeBuilder;
Expand All @@ -38,6 +39,9 @@ public class RecipeMapDraconicFusion extends RecipeMap<SimpleRecipeBuilder> {
private final RecipeMap<TierUpRecipeBuilder> tierUpRecipeMap;
private final RecipeMap<UpgradeRecipeBuilder> upgradeRecipeMap;

/** Cache for upgrade recipe lookups - improves O(n) to O(m) where m << n */
private final UpgradeRecipeCache upgradeCache = new UpgradeRecipeCache();

public RecipeMapDraconicFusion(@NotNull String unlocalizedName, int maxInputs, int maxOutputs, int maxFluidInputs,
int maxFluidOutputs, @NotNull SimpleRecipeBuilder defaultRecipeBuilder,
boolean isHidden, RecipeMap<TierUpRecipeBuilder> tierUpRecipeMap,
Expand All @@ -63,25 +67,51 @@ public Recipe findRecipe(long voltage, List<ItemStack> inputs, List<FluidStack>
tierUpRecipe.getProperty(TierUpRecipeProperty.getInstance(), null));
}

// We need to manually search RecipeMap here.
//
// RecipeMap#recurseIngredientTreeFindRecipe only searches branch first found (`Either<Recipe, Branch> result =
// targetMap.get(obj);`).
// This is fine in most of the situations, but here it's not;
//
// When recipes get added, many of the catalyst objects are not equal each other, as they don't have level-0 tag
// and UpgradeRecipeBuilder#EQUAL_TO_RECURSIVE returns false, hence all the recipes are added as separate nodes.
// example: #lookup -> [draconic_helm -> [tool_upgrade@9], draconic_helm -> [tool_upgrade@8], ...], instead of
// [draconic_helm -> [tool_upgrade@9, tool_upgrade@8]]
// But when searching recipe, an itemstack can match (`equals`) to multiple branches.
// example: when draconic_helm with no upgrade is passed as input, it can match to all branches accepts basic
// upgrade
// Use cached lookup for upgrade recipes if enabled
// This improves performance from O(n) to O(m) where m is the number of recipes
// for the specific catalyst item type, instead of all upgrade recipes
Recipe upgradeRecipe = findUpgradeRecipe(voltage, inputs, fluidInputs);
if (upgradeRecipe != null) {
return setupOutput(upgradeRecipe, inputs,
upgradeRecipe.getProperty(UpgradeRecipeProperty.getInstance(), null));
}

return null;
}

/**
* Find upgrade recipe using cache if enabled, otherwise fall back to linear search.
*/
@Nullable
private Recipe findUpgradeRecipe(long voltage, List<ItemStack> inputs, List<FluidStack> fluidInputs) {
if (DEDAConfigHolder.enableUpgradeRecipeCache) {
// Ensure cache is built (lazy initialization)
if (!upgradeCache.isInitialized()) {
upgradeCache.buildCache(upgradeRecipeMap);
}
return upgradeCache.findRecipe(voltage, inputs, fluidInputs);
} else {
// Fallback to original O(n) linear search
return findUpgradeRecipeLinear(voltage, inputs, fluidInputs);
}
}

/**
* Linear search for upgrade recipes.
* O(n) complexity where n is the total number of upgrade recipes.
* <p>
* We need to manually search RecipeMap here because:
* RecipeMap#recurseIngredientTreeFindRecipe only searches branch first found.
* When recipes get added, catalyst objects with different NBT states create separate branches.
* But when searching, an itemstack can match to multiple branches.
*/
@Nullable
private Recipe findUpgradeRecipeLinear(long voltage, List<ItemStack> inputs, List<FluidStack> fluidInputs) {
for (Recipe recipe : upgradeRecipeMap.getRecipeList()) {
if (recipe.getEUt() <= voltage && recipe.matches(false, inputs, fluidInputs)) {
return setupOutput(recipe, inputs, recipe.getProperty(UpgradeRecipeProperty.getInstance(), null));
return recipe;
}
}

return null;
}

Expand Down
Loading
Loading