Skip to content

Commit d01721e

Browse files
DilithiumThorideTarLaboratoriesjurrejelle
authored
Match Painted Output Busses to Painted Input Busses (#4273)
Co-authored-by: Tar Laboratories <159147059+TarLaboratories@users.noreply.github.com> Co-authored-by: Jurre Groenendijk <jurre@jilles.com>
1 parent d0e0e1a commit d01721e

9 files changed

Lines changed: 87 additions & 16 deletions

File tree

docs/content/Gameplay/Logistics/Machines.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,37 @@ the power button in its UI or by right-clicking it with a Soft Mallet.
4242

4343
Buses and Hatches can accept automated import or export from other sides, so long as something else is causing it.
4444

45+
### Distinct, Painted, and Filtered Inputs and Outputs
46+
Under normal circumstances, **all** input Buses and Hatches and on a multiblock machine will be checked for recipe
47+
inputs, and all output buses and hatches will be used to place recipe outputs. However, this can lead to unwanted behavior
48+
where a user wants a single machine to do multiple recipes, but the ingredients to those recipes can conflict and be used
49+
to run an unwanted third recipe. Additionally, when a machine is being used like this, the output bus/hatch to which
50+
produced items/fluids are delivered is chosen somewhat arbitrarily, making it difficult or unwieldy to plan pipes to carry
51+
specific output products away.
52+
53+
GTM offers three tools for this problem: Fluid Hatch Filter Locking, Distinct Buses and Painted Buses/Hatches.
54+
55+
* Fluid Hatch Filter Locking is a simple system for resolving the problem of deciding what output hatches receive what
56+
produced fluids. Using the same interface as a Super Tank, a Fluid Output Hatch can have its current contained fluid
57+
Locked, meaning that only that fluid will ever be placed in it; or the Hatch can be pre-emptively locked to a fluid by
58+
dragging that fluid from JEI/EMI into the Hatch's output slot.
59+
* Filter Locking only works with standard *single* fluid hatches, and cannot be done to the higher-tier Quadruple or
60+
Nonuple Fluid Hatches. (However, those Hatches also cannot contain a single fluid in more than one slot, so they do
61+
still allow for some degree of output separation when used with Quadruple or Nonuple Fluid Pipes.)
62+
* Distinct Buses is a toggle used on Input Buses (not Hatches), which causes the machine to look at this bus as being
63+
separate from all other Distinct Buses. (One distinct bus has no meaning, but two distinct buses on one machine will
64+
cause the machine to search each distinct bus separately).
65+
* Painted Buses/Hatches are hatches which have been Painted using a can of spray paint. Input Buses/Hatches which have been
66+
Painted in the same color are looked at together by the machine searching for recipe inputs, but any items/fluids stored
67+
in buses/hatches with a different color are not used for the search. The isolation works the same as for Distinct Buses,
68+
but it allows for multiple buses/hatches to be searched together as a group.
69+
* Prior to version 7.5.0, painting **Output** Buses/Hatches had no effect. Version 7.5.0 introduced machines pairing their
70+
Painted Outputs to their Painted Inputs, such that if a recipe pulls items from a Painted Input, it can only output the
71+
products of that recipe to a Painted Output of the same color (or an unpainted output).
72+
* Buses and Hatches that are not painted, or not set to Distinct, are always fair game for the machine - Distinct and
73+
Painted Inputs can always pull from other non-distinct and non-painted inputs; and recipes that used ingredients from
74+
Painted Inputs can always send their products to non-painted outputs.
75+
4576
## Passthrough Hatches and the Cleanroom
4677
The Cleanroom is a unique multiblock with unique restrictions. Because the Cleanroom must have solid walls, pipes, cables,
4778
and inventories outside cannot directly connect to machines inside. For this purpose, Passthrough Hatches exist.

docs/content/Modpacks/Changes/v7.5.0.md

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
title: "Version 7.5.0"
33
---
44

5-
65
# Updating from `7.4.1` to `7.5.0`
76
## Machine Builder Generics
87
We have added a second Generic argument to our (Multiblock)MachineBuilder. This effectively means that anywhere where you used to store a partially finished `MachineBuilder<?>`, you now need to store a `MachineBuilder<?, ?>`. The same holds for `MultiblockMachineBuilder<?, ?>`.
@@ -74,4 +73,23 @@ you should **NOT** use `PipeModel#dynamicModel()` and instead set the model with
7473
## Lamp Predicates
7574
Previously, lamps were not useable with the terminal in multiblocks. There are new lamp predicates that will help solve this problem.
7675
The predicate to use all lamps is: `Predicates.anyLamp()`
77-
The predicate to use a specific color is: `Predicates.lampsByColor(DyeColor.DYE_COLOR)`. Where DYE_COLOR is the name of the color you want.
76+
The predicate to use a specific color is: `Predicates.lampsByColor(DyeColor.DYE_COLOR)`. Where DYE_COLOR is the name of the color you want.
77+
78+
## Painted Output Buses/Hatches
79+
For some time, Spray Paint cans could be used to paint Input and Output Buses/Hatches on multiblock machines.
80+
Version 7.0.0 added the feature that Painted Input Buses/Hatches of different colors would not share their ingredients with
81+
each other when the machine ran recipes. This system is more fully explained at [Painted Inputs and Outputs](../../Gameplay/Logistics/Machines.md#distinct-painted-and-filtered-inputs-and-outputs).
82+
83+
7.5.0 also applies this logic to Output Buses/Hatches as well. Input Buses/Hatches which have been painted are now only
84+
allowed to send their outputs to Output Buses/Hatches that are of the same paint color, or unpainted. This may cause
85+
existing setups to stop running, if they had painted Output Buses/hatches on them.
86+
87+
## Change to GTRecipe constructor
88+
GTRecipe has had one new field added to it and its constructors: `int groupColor`. For new recipes, this parameter
89+
is set to `-1`; however for recipes that are being prepared and run, this field holds the Paint color of the
90+
Painted Input Group that the recipe drew its inputs from.
91+
92+
Addon mods which explicitly attempt to construct, copy, or apply their own ModifierFunctions to a GTRecipe
93+
(not using the standard builder or kjs functions) will need to either add the additional `int` parameter to the end of
94+
their constructor calls, or the additional `recipe.groupColor` to their copy calls.
95+

src/main/java/com/gregtechceu/gtceu/api/recipe/GTRecipe.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ public class GTRecipe implements net.minecraft.world.item.crafting.Recipe<Contai
6060
private final @NotNull EnergyStack inputEUt = calculateEUt(tickInputs);
6161
@Getter(lazy = true)
6262
private final @NotNull EnergyStack outputEUt = calculateEUt(tickOutputs);
63+
public int groupColor = -1;
6364

6465
public GTRecipe(GTRecipeType recipeType,
6566
Map<RecipeCapability<?>, List<Content>> inputs,
@@ -74,10 +75,11 @@ public GTRecipe(GTRecipeType recipeType,
7475
List<?> ingredientActions,
7576
@NotNull CompoundTag data,
7677
int duration,
77-
@NotNull GTRecipeCategory recipeCategory) {
78+
@NotNull GTRecipeCategory recipeCategory,
79+
int groupColor) {
7880
this(recipeType, null, inputs, outputs, tickInputs, tickOutputs,
7981
inputChanceLogics, outputChanceLogics, tickInputChanceLogics, tickOutputChanceLogics,
80-
conditions, ingredientActions, data, duration, recipeCategory);
82+
conditions, ingredientActions, data, duration, recipeCategory, groupColor);
8183
}
8284

8385
public GTRecipe(GTRecipeType recipeType,
@@ -94,7 +96,7 @@ public GTRecipe(GTRecipeType recipeType,
9496
List<?> ingredientActions,
9597
@NotNull CompoundTag data,
9698
int duration,
97-
@NotNull GTRecipeCategory recipeCategory) {
99+
@NotNull GTRecipeCategory recipeCategory, int groupColor) {
98100
this.recipeType = recipeType;
99101
this.id = id;
100102

@@ -113,6 +115,7 @@ public GTRecipe(GTRecipeType recipeType,
113115
this.data = data;
114116
this.duration = duration;
115117
this.recipeCategory = (recipeCategory != GTRecipeCategory.DEFAULT) ? recipeCategory : recipeType.getCategory();
118+
this.groupColor = groupColor;
116119
}
117120

118121
public GTRecipe copy() {
@@ -130,7 +133,7 @@ public GTRecipe copy(ContentModifier modifier, boolean modifyDuration) {
130133
new HashMap<>(inputChanceLogics), new HashMap<>(outputChanceLogics),
131134
new HashMap<>(tickInputChanceLogics), new HashMap<>(tickOutputChanceLogics),
132135
new ArrayList<>(conditions),
133-
new ArrayList<>(ingredientActions), data, duration, recipeCategory);
136+
new ArrayList<>(ingredientActions), data, duration, recipeCategory, groupColor);
134137
if (modifyDuration) {
135138
copied.duration = modifier.apply(this.duration);
136139
}

src/main/java/com/gregtechceu/gtceu/api/recipe/GTRecipeSerializer.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ public GTRecipe fromNetwork(@NotNull ResourceLocation id, @NotNull FriendlyByteB
131131
if (data == null) {
132132
data = new CompoundTag();
133133
}
134+
int groupColor = buf.readInt();
134135
ResourceLocation categoryLoc = buf.readResourceLocation();
135136

136137
GTRecipeType type = (GTRecipeType) BuiltInRegistries.RECIPE_TYPE.get(recipeType);
@@ -139,7 +140,7 @@ public GTRecipe fromNetwork(@NotNull ResourceLocation id, @NotNull FriendlyByteB
139140
GTRecipe recipe = new GTRecipe(type, id,
140141
inputs, outputs, tickInputs, tickOutputs,
141142
inputChanceLogics, outputChanceLogics, tickInputChanceLogics, tickOutputChanceLogics,
142-
conditions, ingredientActions, data, duration, category);
143+
conditions, ingredientActions, data, duration, category, groupColor);
143144

144145
recipe.recipeCategory.addRecipe(recipe);
145146

@@ -182,6 +183,7 @@ public void toNetwork(FriendlyByteBuf buf, GTRecipe recipe) {
182183
KJSCallWrapper.writeIngredientActions(recipe.ingredientActions, buf);
183184
}
184185
buf.writeNbt(recipe.data);
186+
buf.writeInt(recipe.groupColor);
185187
buf.writeResourceLocation(recipe.recipeCategory.registryKey);
186188
}
187189

@@ -205,14 +207,15 @@ private static Codec<GTRecipe> makeCodec(boolean isKubeLoaded) {
205207
RecipeCondition.CODEC.listOf().optionalFieldOf("recipeConditions", List.of()).forGetter(val -> val.conditions),
206208
CompoundTag.CODEC.optionalFieldOf("data", new CompoundTag()).forGetter(val -> val.data),
207209
ExtraCodecs.NON_NEGATIVE_INT.fieldOf("duration").forGetter(val -> val.duration),
208-
GTRegistries.RECIPE_CATEGORIES.codec().optionalFieldOf("category", GTRecipeCategory.DEFAULT).forGetter(val -> val.recipeCategory))
210+
GTRegistries.RECIPE_CATEGORIES.codec().optionalFieldOf("category", GTRecipeCategory.DEFAULT).forGetter(val -> val.recipeCategory),
211+
Codec.INT.fieldOf("groupColor").forGetter(val -> val.groupColor))
209212
.apply(instance, (type,
210213
inputs, outputs, tickInputs, tickOutputs,
211214
inputChanceLogics, outputChanceLogics, tickInputChanceLogics, tickOutputChanceLogics,
212-
conditions, data, duration, recipeCategory) ->
215+
conditions, data, duration, recipeCategory, groupColor) ->
213216
new GTRecipe(type, inputs, outputs, tickInputs, tickOutputs,
214217
inputChanceLogics, outputChanceLogics, tickInputChanceLogics, tickOutputChanceLogics,
215-
conditions, List.of(), data, duration, recipeCategory)));
218+
conditions, List.of(), data, duration, recipeCategory, groupColor)));
216219
} else {
217220
return RecordCodecBuilder.create(instance -> instance.group(
218221
GTRegistries.RECIPE_TYPES.codec().fieldOf("type").forGetter(val -> val.recipeType),
@@ -232,7 +235,8 @@ private static Codec<GTRecipe> makeCodec(boolean isKubeLoaded) {
232235
KJSCallWrapper.INGREDIENT_ACTION_CODEC.optionalFieldOf("kubejs:actions", List.of()).forGetter(val -> (List<IngredientAction>) val.ingredientActions),
233236
CompoundTag.CODEC.optionalFieldOf("data", new CompoundTag()).forGetter(val -> val.data),
234237
ExtraCodecs.NON_NEGATIVE_INT.fieldOf("duration").forGetter(val -> val.duration),
235-
GTRegistries.RECIPE_CATEGORIES.codec().optionalFieldOf("category", GTRecipeCategory.DEFAULT).forGetter(val -> val.recipeCategory))
238+
GTRegistries.RECIPE_CATEGORIES.codec().optionalFieldOf("category", GTRecipeCategory.DEFAULT).forGetter(val -> val.recipeCategory),
239+
Codec.INT.fieldOf("groupColor").forGetter(val -> val.groupColor))
236240
.apply(instance, GTRecipe::new));
237241
}
238242
// spotless:on

src/main/java/com/gregtechceu/gtceu/api/recipe/RecipeHelper.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,10 @@ public static ActionResult handleRecipe(IRecipeCapabilityHolder holder, GTRecipe
222222
RecipeRunner runner = new RecipeRunner(recipe, io, isTick, holder, chanceCaches, simulated);
223223
var result = runner.handle(contents);
224224

225-
if (result.isSuccess() || result.capability() == null) return result;
225+
if (result.isSuccess() || result.capability() == null) {
226+
recipe.groupColor = runner.getGroupColor();
227+
return result;
228+
}
226229

227230
if (!simulated && ConfigHolder.INSTANCE.dev.debug) {
228231
GTCEu.LOGGER.warn("IO {} Error while handling recipe {} outputs for {}",

src/main/java/com/gregtechceu/gtceu/api/recipe/RecipeRunner.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@
55
import com.gregtechceu.gtceu.api.capability.recipe.RecipeCapability;
66
import com.gregtechceu.gtceu.api.machine.feature.IVoidable;
77
import com.gregtechceu.gtceu.api.machine.trait.RecipeHandlerGroup;
8+
import com.gregtechceu.gtceu.api.machine.trait.RecipeHandlerGroupColor;
89
import com.gregtechceu.gtceu.api.machine.trait.RecipeHandlerList;
910
import com.gregtechceu.gtceu.api.recipe.chance.boost.ChanceBoostFunction;
1011
import com.gregtechceu.gtceu.api.recipe.chance.logic.ChanceLogic;
1112
import com.gregtechceu.gtceu.api.recipe.content.Content;
1213

1314
import it.unimi.dsi.fastutil.objects.Object2IntMap;
1415
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap;
16+
import lombok.Getter;
1517
import org.jetbrains.annotations.NotNull;
1618

1719
import java.util.ArrayList;
@@ -36,6 +38,8 @@ public class RecipeRunner {
3638
private Map<RecipeCapability<?>, List<Object>> recipeContents;
3739
private final Map<RecipeCapability<?>, List<Object>> searchRecipeContents;
3840
private final Predicate<RecipeCapability<?>> outputVoid;
41+
@Getter
42+
private int groupColor;
3943

4044
public RecipeRunner(GTRecipe recipe, IO io, boolean isTick,
4145
IRecipeCapabilityHolder holder, Map<RecipeCapability<?>, Object2IntMap<?>> chanceCaches,
@@ -49,6 +53,7 @@ public RecipeRunner(GTRecipe recipe, IO io, boolean isTick,
4953
this.searchRecipeContents = simulated ? recipeContents : new Reference2ObjectOpenHashMap<>();
5054
this.simulated = simulated;
5155
this.outputVoid = cap -> holder instanceof IVoidable voidable && voidable.canVoidRecipeOutputs(cap);
56+
this.groupColor = recipe.groupColor;
5257
}
5358

5459
@NotNull
@@ -163,6 +168,13 @@ private ActionResult handleContents() {
163168
for (Map.Entry<RecipeHandlerGroup, List<RecipeHandlerList>> handlerListEntry : handlerGroups.entrySet()) {
164169
if (handlerListEntry.getKey().equals(BUS_DISTINCT)) continue;
165170

171+
if (handlerListEntry.getKey() instanceof RecipeHandlerGroupColor coloredGroup) {
172+
if (io == IO.IN && simulated && !isTick) {
173+
groupColor = coloredGroup.color();
174+
} else if (coloredGroup.color() != -1 && coloredGroup.color() != groupColor) {
175+
continue;
176+
}
177+
}
166178
// List to keep track of the remaining items for this RecipeHandlerGroup
167179
Map<RecipeCapability<?>, List<Object>> copiedRecipeContents = searchRecipeContents;
168180

src/main/java/com/gregtechceu/gtceu/api/recipe/modifier/ModifierFunction.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public interface ModifierFunction {
4242
/**
4343
* Use this static to denote that the recipe doesn't get modified
4444
*/
45-
ModifierFunction IDENTITY = recipe -> recipe;
45+
ModifierFunction IDENTITY = ModifierFunction.builder().build();
4646

4747
/**
4848
* Applies this modifier to the passed recipe
@@ -159,7 +159,7 @@ public ModifierFunction build() {
159159
new HashMap<>(recipe.inputChanceLogics), new HashMap<>(recipe.outputChanceLogics),
160160
new HashMap<>(recipe.tickInputChanceLogics), new HashMap<>(recipe.tickOutputChanceLogics),
161161
newConditions, new ArrayList<>(recipe.ingredientActions),
162-
recipe.data, recipe.duration, recipe.recipeCategory);
162+
recipe.data, recipe.duration, recipe.recipeCategory, recipe.groupColor);
163163
copied.parallels = recipe.parallels * parallels;
164164
copied.subtickParallels = recipe.subtickParallels * subtickParallels;
165165
copied.ocLevel = recipe.ocLevel + addOCs;

src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/DistillationTowerMachine.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ private static GTRecipe modifyOutputs(GTRecipe recipe, ContentModifier cm) {
166166
recipe.outputChanceLogics,
167167
recipe.tickInputChanceLogics, recipe.tickOutputChanceLogics, recipe.conditions,
168168
recipe.ingredientActions,
169-
recipe.data, recipe.duration, recipe.recipeCategory);
169+
recipe.data, recipe.duration, recipe.recipeCategory, recipe.groupColor);
170170
}
171171

172172
public static class DistillationTowerLogic extends RecipeLogic {

src/main/java/com/gregtechceu/gtceu/data/recipe/builder/GTRecipeBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1692,7 +1692,7 @@ public GTRecipe buildRawRecipe() {
16921692
return new GTRecipe(recipeType, id.withPrefix(recipeType.registryName.getPath() + "/"),
16931693
input, output, tickInput, tickOutput,
16941694
inputChanceLogic, outputChanceLogic, tickInputChanceLogic, tickOutputChanceLogic,
1695-
conditions, List.of(), data, duration, recipeCategory);
1695+
conditions, List.of(), data, duration, recipeCategory, -1);
16961696
}
16971697

16981698
protected void warnTooManyIngredients(RecipeCapability<?> capability,

0 commit comments

Comments
 (0)