Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
bcb52ce
initial rework
ghzdude Aug 1, 2024
783e5f3
a bit more work
ghzdude Aug 1, 2024
c29e0b1
:todayiwill:
ghzdude Aug 1, 2024
bf67868
apply to all logic types
ghzdude Aug 1, 2024
2752019
fix OR logic and handle overflow
ghzdude Aug 1, 2024
3fca554
fix tests
ghzdude Aug 1, 2024
c843bb2
remove commented code
ghzdude Aug 1, 2024
be2b58e
allow null and null check
ghzdude Aug 1, 2024
ff83c37
add default roll method
ghzdude Aug 1, 2024
beeb7be
improve XOR
ghzdude Aug 1, 2024
75c1238
not actually useful to seperate the fraction
ghzdude Aug 1, 2024
c9ea878
forgor + less spots
ghzdude Aug 1, 2024
a54a1fb
clear chance cache on new recipe
ghzdude Aug 1, 2024
c89bb0e
nvm we still need fraction split for handling irrational fractions
ghzdude Aug 3, 2024
f6acf90
more fixed to logic
ghzdude Aug 3, 2024
8bc2378
add methods to RecipeBuilder
ghzdude Aug 3, 2024
86c2f90
forgor fluids
ghzdude Aug 3, 2024
a95311f
fix and improve RecipeBuilder methods
ghzdude Aug 3, 2024
9e4a068
convert certain chances to fraction form
ghzdude Aug 3, 2024
2889654
fix copy
ghzdude Aug 3, 2024
7b7c3bc
also apply to chanced fluids
ghzdude Aug 3, 2024
0374153
fix chances on tooltips
ghzdude Aug 3, 2024
6c58623
move cache clear after recipe is valid and checked
ghzdude Aug 3, 2024
0443100
move BaseChanceEntry up into ChancedOutput
ghzdude Aug 3, 2024
376d19b
spotless
ghzdude Aug 3, 2024
d688f33
try to make chance boost work correctly
ghzdude Aug 3, 2024
64920f8
rip formatter
ghzdude Aug 3, 2024
3732ae0
move cache clear
ghzdude Aug 3, 2024
be0cdf1
serialize chance cache
ghzdude Aug 3, 2024
aaeb90e
add rng starting value for chance
ghzdude Aug 4, 2024
fc4e13b
update cache getter method
ghzdude Aug 4, 2024
f8ffbf3
remove plus one + javadocs
ghzdude Aug 4, 2024
9cfa1c2
create and implement FluidStackHashStrategy
ghzdude Aug 4, 2024
eb3d5f0
try to correct boost w/ javadoc
ghzdude Aug 4, 2024
779ec16
fix todo
ghzdude Aug 4, 2024
9f4280b
simplify roll by moving cache handling into `passesChance()`
ghzdude Aug 4, 2024
faefdf2
remove while loop
ghzdude Aug 4, 2024
c85d0d7
update chance lang
ghzdude Aug 4, 2024
3ab625a
simplify initial rng slightly
ghzdude Aug 5, 2024
7cbcb5f
try to make xor better
ghzdude Oct 7, 2024
2cb3f2a
what's this? committing to a pr that's very old and supposedly finished?
ghzdude Nov 16, 2024
cfb212f
fix issues with chance passing
ghzdude Nov 16, 2024
929f27c
simplify xor and make passesChance static again
ghzdude Nov 16, 2024
b33fafb
put cache construction into context
ghzdude Nov 16, 2024
e0de8fa
fix null strategy
ghzdude Nov 22, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,19 @@
import gregtech.api.metatileentity.multiblock.ParallelLogicType;
import gregtech.api.recipes.Recipe;
import gregtech.api.recipes.RecipeBuilder;
import gregtech.api.recipes.RecipeContext;
import gregtech.api.recipes.RecipeMap;
import gregtech.api.recipes.logic.IParallelableRecipeLogic;
import gregtech.api.recipes.logic.OCParams;
import gregtech.api.recipes.logic.OCResult;
import gregtech.api.recipes.properties.RecipePropertyStorage;
import gregtech.api.recipes.properties.impl.CleanroomProperty;
import gregtech.api.recipes.properties.impl.DimensionProperty;
import gregtech.api.util.FluidStackHashStrategy;
import gregtech.api.util.GTLog;
import gregtech.api.util.GTTransferUtils;
import gregtech.api.util.GTUtility;
import gregtech.api.util.ItemStackHashStrategy;
import gregtech.common.ConfigHolder;

import net.minecraft.item.ItemStack;
Expand Down Expand Up @@ -72,6 +75,14 @@ public abstract class AbstractRecipeLogic extends MTETrait implements IWorkable,
protected List<FluidStack> fluidOutputs;
protected List<ItemStack> itemOutputs;

private final RecipeContext<ItemStack> itemContext = new RecipeContext<>(ItemStackHashStrategy.builder()
.compareItem(true)
.compareDamage(true)
.build());
private final RecipeContext<FluidStack> fluidContext = new RecipeContext<>(FluidStackHashStrategy.builder()
.compareFluid(true)
.build());

protected boolean isActive;
protected boolean workingEnabled = true;
protected boolean hasNotEnoughEnergy;
Expand Down Expand Up @@ -390,6 +401,12 @@ protected void trySearchNewRecipe() {
}
// If a recipe was found, then inputs were valid. Cache found recipe.
if (currentRecipe != null) {

// we found a new recipe, clear the cache
if (this.previousRecipe != null && !currentRecipe.equals(this.previousRecipe)) {
this.itemContext.getCache().clear();
this.fluidContext.getCache().clear();
}
this.previousRecipe = currentRecipe;
}
this.invalidInputsForRecipes = (currentRecipe == null);
Expand Down Expand Up @@ -949,9 +966,11 @@ protected void setupRecipe(@NotNull Recipe recipe) {
RecipeMap<?> map = getRecipeMap();
if (map != null) {
this.fluidOutputs = GTUtility
.copyFluidList(recipe.getResultFluidOutputs(recipeTier, machineTier, map));
.copyFluidList(recipe.getResultFluidOutputs(
fluidContext.update(map.getChanceFunction(), recipeTier, machineTier)));
this.itemOutputs = GTUtility
.copyStackList(recipe.getResultItemOutputs(recipeTier, machineTier, map));
.copyStackList(recipe.getResultItemOutputs(
itemContext.update(map.getChanceFunction(), recipeTier, machineTier)));
}

if (this.wasActiveAndNeedsUpdate) {
Expand Down Expand Up @@ -1211,6 +1230,21 @@ public NBTTagCompound serializeNBT() {
}
compound.setTag("ItemOutputs", itemOutputsList);
compound.setTag("FluidOutputs", fluidOutputsList);

NBTTagList itemCache = new NBTTagList();
for (var entry : itemContext.getCache().entrySet()) {
var tag = entry.getKey().serializeNBT();
tag.setInteger("CachedChance", entry.getValue());
itemCache.appendTag(tag);
}
NBTTagList fluidCache = new NBTTagList();
for (var entry : fluidContext.getCache().entrySet()) {
var tag = entry.getKey().writeToNBT(new NBTTagCompound());
tag.setInteger("CachedChance", entry.getValue());
fluidCache.appendTag(tag);
}
compound.setTag("ItemChanceCache", itemCache);
compound.setTag("FluidChanceCache", fluidCache);
}
return compound;
}
Expand All @@ -1237,6 +1271,20 @@ public void deserializeNBT(@NotNull NBTTagCompound compound) {
for (int i = 0; i < fluidOutputsList.tagCount(); i++) {
this.fluidOutputs.add(FluidStack.loadFluidStackFromNBT(fluidOutputsList.getCompoundTagAt(i)));
}

NBTTagList itemCache = compound.getTagList("ItemChanceCache", Constants.NBT.TAG_COMPOUND);
for (int i = 0; i < itemCache.tagCount(); i++) {
var stack = itemCache.getCompoundTagAt(i);
int cache = stack.getInteger("CachedChance");
this.itemContext.updateCachedChance(new ItemStack(stack), cache);
}

NBTTagList fluidCache = compound.getTagList("FluidChanceCache", Constants.NBT.TAG_COMPOUND);
for (int i = 0; i < fluidCache.tagCount(); i++) {
var stack = fluidCache.getCompoundTagAt(i);
int cache = stack.getInteger("CachedChance");
this.fluidContext.updateCachedChance(FluidStack.loadFluidStackFromNBT(stack), cache);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import gregtech.api.capability.IMiner;
import gregtech.api.metatileentity.MetaTileEntity;
import gregtech.api.recipes.Recipe;
import gregtech.api.recipes.RecipeContext;
import gregtech.api.recipes.RecipeMap;
import gregtech.api.unification.OreDictUnifier;
import gregtech.api.unification.ore.OrePrefix;
Expand Down Expand Up @@ -451,8 +452,9 @@ protected static void applyTieredHammerNoRandomDrops(@NotNull IBlockState blockS
Recipe recipe = map.findRecipe(Long.MAX_VALUE, Collections.singletonList(itemStack), Collections.emptyList());
if (recipe != null && !recipe.getOutputs().isEmpty()) {
drops.clear();
for (ItemStack outputStack : recipe.getResultItemOutputs(GTUtility.getTierByVoltage(recipe.getEUt()), tier,
map)) {
var context = new RecipeContext<ItemStack>()
.update(map.getChanceFunction(), GTUtility.getTierByVoltage(recipe.getEUt()), tier);
for (ItemStack outputStack : recipe.getResultItemOutputs(context)) {
outputStack = outputStack.copy();
if (OreDictUnifier.getPrefix(outputStack) == OrePrefix.crushed) {
if (fortuneLevel > 0) {
Expand Down
60 changes: 26 additions & 34 deletions src/main/java/gregtech/api/recipes/Recipe.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import gregtech.api.capability.IMultipleTankHandler;
import gregtech.api.recipes.category.GTRecipeCategory;
import gregtech.api.recipes.chance.boost.ChanceBoostFunction;
import gregtech.api.recipes.chance.output.ChancedOutputList;
import gregtech.api.recipes.chance.output.ChancedOutputLogic;
import gregtech.api.recipes.chance.output.impl.ChancedFluidOutput;
Expand All @@ -18,7 +17,6 @@
import net.minecraft.item.ItemStack;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.items.IItemHandlerModifiable;
import net.minecraftforge.items.ItemHandlerHelper;
import net.minecraftforge.oredict.OreDictionary;

import com.google.common.collect.ImmutableList;
Expand Down Expand Up @@ -464,37 +462,34 @@ public List<ItemStack> getOutputs() {
* The Recipe should be trimmed by calling {@link Recipe#getItemAndChanceOutputs(int)} before calling this method,
* if trimming is required.
*
* @param recipeTier The Voltage Tier of the Recipe, used for chanced output calculation
* @param machineTier The Voltage Tier of the Machine, used for chanced output calculation
* @param recipeMap The RecipeMap that the recipe is being performed upon, used for chanced output calculation
* @param context Context containing machine and recipe tier, the boost function, and the chance cache
* @return A list of all resulting ItemStacks from the recipe, after chance has been applied to any chanced outputs
*/
public List<ItemStack> getResultItemOutputs(int recipeTier, int machineTier, RecipeMap<?> recipeMap) {
public List<ItemStack> getResultItemOutputs(RecipeContext<ItemStack> context) {
List<ItemStack> outputs = new ArrayList<>(getOutputs());
ChanceBoostFunction function = recipeMap.getChanceFunction();
List<ChancedItemOutput> chancedOutputsList = getChancedOutputs().roll(function, recipeTier, machineTier);
var chancedOutputsList = getChancedOutputs().roll(context);

if (chancedOutputsList == null) return outputs;

Collection<ItemStack> resultChanced = new ArrayList<>();
for (ChancedItemOutput chancedOutput : chancedOutputsList) {
ItemStack stackToAdd = chancedOutput.getIngredient().copy();
for (ItemStack stackInList : resultChanced) {
int insertable = stackInList.getMaxStackSize() - stackInList.getCount();
if (insertable > 0 && ItemHandlerHelper.canItemStacksStack(stackInList, stackToAdd)) {
if (insertable >= stackToAdd.getCount()) {
stackInList.grow(stackToAdd.getCount());
stackToAdd = ItemStack.EMPTY;
break;
} else {
stackInList.grow(insertable);
stackToAdd.shrink(insertable);
}
}
}
if (!stackToAdd.isEmpty()) {
resultChanced.add(stackToAdd);
}
for (var chancedOutput : chancedOutputsList) {
ItemStack stackToAdd = chancedOutput.createStack((output, count) -> GTUtility.copy(count, output));
// for (ItemStack stackInList : resultChanced) {
// int insertable = stackInList.getMaxStackSize() - stackInList.getCount();
// if (insertable > 0 && ItemHandlerHelper.canItemStacksStack(stackInList, stackToAdd)) {
// if (insertable >= stackToAdd.getCount()) {
// stackInList.grow(stackToAdd.getCount());
// stackToAdd = ItemStack.EMPTY;
// break;
// } else {
// stackInList.grow(insertable);
// stackToAdd.shrink(insertable);
// }
// }
// }
// if (!stackToAdd.isEmpty()) {
// }
resultChanced.add(stackToAdd);
}

outputs.addAll(resultChanced);
Expand Down Expand Up @@ -659,22 +654,19 @@ public List<FluidStack> getAllFluidOutputs() {
* The Recipe should be trimmed by calling {@link Recipe#getFluidAndChanceOutputs(int)} before calling this method,
* if trimming is required.
*
* @param recipeTier The Voltage Tier of the Recipe, used for chanced output calculation
* @param machineTier The Voltage Tier of the Machine, used for chanced output calculation
* @param recipeMap The RecipeMap that the recipe is being performed upon, used for chanced output calculation
* @param context Context containing machine and recipe tier, the boost function, and the chance cache
* @return A list of all resulting ItemStacks from the recipe, after chance has been applied to any chanced outputs
*/
public List<FluidStack> getResultFluidOutputs(int recipeTier, int machineTier, RecipeMap<?> recipeMap) {
public List<FluidStack> getResultFluidOutputs(RecipeContext<FluidStack> context) {
List<FluidStack> outputs = new ArrayList<>(GTUtility.copyFluidList(getFluidOutputs()));

ChanceBoostFunction function = recipeMap.getChanceFunction();
List<ChancedFluidOutput> chancedOutputsList = getChancedFluidOutputs().roll(function, recipeTier, machineTier);
var chancedOutputsList = getChancedFluidOutputs().roll(context);

if (chancedOutputsList == null) return outputs;

Collection<FluidStack> resultChanced = new ArrayList<>();
for (ChancedFluidOutput chancedOutput : chancedOutputsList) {
FluidStack stackToAdd = chancedOutput.getIngredient().copy();
for (var chancedOutput : chancedOutputsList) {
FluidStack stackToAdd = chancedOutput.createStack(FluidStack::new);
for (FluidStack stackInList : resultChanced) {
int insertable = stackInList.amount;
if (insertable > 0 && stackInList.getFluid() == stackToAdd.getFluid()) {
Expand Down
116 changes: 112 additions & 4 deletions src/main/java/gregtech/api/recipes/RecipeBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,68 @@ public R chancedOutput(MetaItem<?>.MetaValueItem item, int chance, int tierChanc
return chancedOutput(item, 1, chance, tierChanceBoost);
}

public R chancedOutput(ItemStack stack, String fraction, int tierChanceBoost) {
if (stack == null || stack.isEmpty()) {
return (R) this;
}

String[] split = fraction.split("/");
if (split.length != 2) {
GTLog.logger.error("Fraction was not parsed correctly! Expected format is \"1/3\". Actual: \"{}\".",
fraction, new Throwable());
recipeStatus = EnumValidationResult.INVALID;
return (R) this;
}

int chance;
int maxChance;
try {
chance = Integer.parseInt(split[0]);
maxChance = Integer.parseInt(split[1]);
} catch (NumberFormatException e) {
GTLog.logger.error("Fraction was not parsed correctly! Expected format is \"1/3\". Actual: \"{}\".",
fraction, new Throwable());
recipeStatus = EnumValidationResult.INVALID;
return (R) this;
}

if (0 >= chance || chance > ChancedOutputLogic.getMaxChancedValue()) {
GTLog.logger.error("Chance cannot be less or equal to 0 or more than {}. Actual: {}.",
ChancedOutputLogic.getMaxChancedValue(), chance, new Throwable());
recipeStatus = EnumValidationResult.INVALID;
return (R) this;
}
if (chance >= maxChance || maxChance > ChancedOutputLogic.getMaxChancedValue()) {
GTLog.logger.error("Max Chance cannot be less or equal to Chance or more than {}. Actual: {}.",
ChancedOutputLogic.getMaxChancedValue(), maxChance, new Throwable());
recipeStatus = EnumValidationResult.INVALID;
return (R) this;
}

int scalar = Math.floorDiv(ChancedOutputLogic.getMaxChancedValue(), maxChance);
chance *= scalar;
maxChance *= scalar;

this.chancedOutputs.add(new ChancedItemOutput(stack.copy(), chance, maxChance, tierChanceBoost));
return (R) this;
}

public R chancedOutput(OrePrefix prefix, Material material, int count, String fraction, int tierChanceBoost) {
return chancedOutput(OreDictUnifier.get(prefix, material, count), fraction, tierChanceBoost);
}

public R chancedOutput(OrePrefix prefix, Material material, String fraction, int tierChanceBoost) {
return chancedOutput(prefix, material, 1, fraction, tierChanceBoost);
}

public R chancedOutput(MetaItem<?>.MetaValueItem item, int count, String fraction, int tierChanceBoost) {
return chancedOutput(item.getStackForm(count), fraction, tierChanceBoost);
}

public R chancedOutput(MetaItem<?>.MetaValueItem item, String fraction, int tierChanceBoost) {
return chancedOutput(item, 1, fraction, tierChanceBoost);
}

public R chancedOutputs(List<ChancedItemOutput> chancedOutputs) {
for (ChancedItemOutput output : chancedOutputs) {
this.chancedOutputs.add(output.copy());
Expand Down Expand Up @@ -681,6 +743,52 @@ public R chancedFluidOutput(FluidStack stack, int chance, int tierChanceBoost) {
return (R) this;
}

public R chancedFluidOutput(FluidStack stack, String fraction, int tierChanceBoost) {
if (stack == null || stack.amount == 0) {
return (R) this;
}

String[] split = fraction.split("/");
if (split.length != 2) {
GTLog.logger.error("Fraction was not parsed correctly! Expected format is \"1/3\". Actual: \"{}\".",
fraction, new Throwable());
recipeStatus = EnumValidationResult.INVALID;
return (R) this;
}

int chance;
int maxChance;
try {
chance = Integer.parseInt(split[0]);
maxChance = Integer.parseInt(split[1]);
} catch (NumberFormatException e) {
GTLog.logger.error("Fraction was not parsed correctly! Expected format is \"1/3\". Actual: \"{}\".",
fraction, new Throwable());
recipeStatus = EnumValidationResult.INVALID;
return (R) this;
}

if (0 >= chance || chance > ChancedOutputLogic.getMaxChancedValue()) {
GTLog.logger.error("Chance cannot be less or equal to 0 or more than {}. Actual: {}.",
ChancedOutputLogic.getMaxChancedValue(), chance, new Throwable());
recipeStatus = EnumValidationResult.INVALID;
return (R) this;
}
if (chance >= maxChance || maxChance > ChancedOutputLogic.getMaxChancedValue()) {
GTLog.logger.error("Max Chance cannot be less or equal to Chance or more than {}. Actual: {}.",
ChancedOutputLogic.getMaxChancedValue(), maxChance, new Throwable());
recipeStatus = EnumValidationResult.INVALID;
return (R) this;
}

int scalar = Math.floorDiv(ChancedOutputLogic.getMaxChancedValue(), maxChance);
chance *= scalar;
maxChance *= scalar;

this.chancedFluidOutputs.add(new ChancedFluidOutput(stack.copy(), chance, maxChance, tierChanceBoost));
return (R) this;
}

public R chancedFluidOutputs(List<ChancedFluidOutput> chancedOutputs) {
for (ChancedFluidOutput output : chancedOutputs) {
this.chancedFluidOutputs.add(output.copy());
Expand Down Expand Up @@ -749,25 +857,25 @@ private static GTRecipeInput ofGroovyIngredient(IIngredient ingredient) {

public void chancedOutputsMultiply(Recipe chancedOutputsFrom, int numberOfOperations) {
for (ChancedItemOutput entry : chancedOutputsFrom.getChancedOutputs().getChancedEntries()) {
int chance = entry.getChance();
String fraction = String.format("%d/%d", entry.getChance(), entry.getMaxChance());
int boost = entry.getChanceBoost();

// Add individual chanced outputs per number of parallel operations performed, to mimic regular recipes.
// This is done instead of simply batching the chanced outputs by the number of parallel operations
// performed
for (int i = 0; i < numberOfOperations; i++) {
this.chancedOutput(entry.getIngredient().copy(), chance, boost);
this.chancedOutput(entry.getIngredient().copy(), fraction, boost);
}
}
for (ChancedFluidOutput entry : chancedOutputsFrom.getChancedFluidOutputs().getChancedEntries()) {
int chance = entry.getChance();
String fraction = String.format("%d/%d", entry.getChance(), entry.getMaxChance());
int boost = entry.getChanceBoost();

// Add individual chanced outputs per number of parallel operations performed, to mimic regular recipes.
// This is done instead of simply batching the chanced outputs by the number of parallel operations
// performed
for (int i = 0; i < numberOfOperations; i++) {
this.chancedFluidOutput(entry.getIngredient().copy(), chance, boost);
this.chancedFluidOutput(entry.getIngredient().copy(), fraction, boost);
}
}
}
Expand Down
Loading