---
title: "Version 7.5.0"
---

# Updating from `7.4.1` to `7.5.0`
!!! note
    Because of these changes, when using GTM 7.5.0+ you can not compile your mod(pack) against addons or coremods that are compiled for 7.4.1 and touch anything related to machines.
    Make sure that your dependencies have updated.


## Machine Builder Generics
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<?, ?>`.

## Machine & Cover Copy/Paste System
A new system for copying machines using the Machine Memory Card has been added, see [this page](../Other-Topics/Cover-Machine-Copy-Paste-Support.md) if you want to add extra copy/paste behaviour to your own machines and covers.

## Multiblock Structure Change
The Large Fractionating Still no longer requires a muffler hatch, allowing it to be used in cleanrooms.

## RecipeCondition Generics
We have added a Generic argument to `RecipeCondition` describing the condition.  
This means that your custom recipe conditions now need to extend `RecipeCondition<MyCondition>` (whereas before they just extended `RecipeCondition`).
For example, if you have a custom recipe condition class like so: `public class ExampleCondition extends RecipeCondition`, it should now be `public class ExampleCondition extends RecipeCondition<ExampleCondition>`.  
You also need to adjust the generics of `getType()` and `createTemplate()` to match this change, like so:
```patch
- public RecipeConditionType<?> getType() {
+ public RecipeConditionType<ExampleCondition> getType() {

- public RecipeCondition createTemplate() {
+ public ExampleCondition createTemplate() {
```
## Mortar Recipe Fix
Previously, adding GTToolType.MORTAR to your tool did not automatically generate the recipe. This has been fixed. If you previously generated a recipe using this, you need to remove your manual recipe.

## Pipe rendering changes
_This is only relevant to add-on mods with custom pipe types._
Addons with custom pipe implementations will have to tweak their code slightly to function with the new rendering code (see example below).

```patch
-public final PipeModel model = new PipeModel(pipeType.getThickness(), () -> [side texture], () -> [end texture], null, null); 
-@Getter
-private final PipeBlockRenderer renderer = new PipeBlockRenderer(model);
 
 ...
 
 @Override
-public PipeModel getPipeModel() {
-    return model;
+public PipeModel createPipeModel(GTBlockstateProvider provider) {
+    return new PipeModel(this, pipeType.getThickness(), [side texture], [end texture], provider);
 }
```
If your pipe is generated from a material property (or equivalent), you should also call `PipeModel#dynamicModel()`
to have models be generated at runtime.  
If so, must also add a **Mod bus** event listener for `RegisterDynamicResourcesEvent`, like so:
```java
@SubscribeEvent
public static void registerDynamicResources(RegisterDynamicResourcesEvent event) {
   for (var block : MyBlocks.MY_PIPE_BLOCKS) block.get().createPipeModel(RuntimeExistingFileHelper.INSTANCE).dynamicModel();
}
```
Replace `MyBlocks.MY_PIPE_BLOCKS` with a reference to your pipe block array/map value collection.


Conversely, if the pipe is **not** generated, but has a constant set of variants (such as optical fiber cables or laser pipes),
you should **NOT** use `PipeModel#dynamicModel()` and instead set the model with `GTBlockBuilder#gtBlockstate` as such:
```java
    // on your pipe block builder
    ... = REGISTRATE.block(...)
             .properties(...)
             .gtBlockstate(GTModels::createPipeBlockModel)
             ...more builder things...
             .item(...)
             .model(NonNullBiConsumer.noop())
             ...more builder things...
```

## Lamp Predicates
Previously, lamps were not useable with the terminal in multiblocks. There are new lamp predicates that will help solve this problem.
The predicate to use all lamps is: `Predicates.anyLamp()`
The predicate to use a specific color is: `Predicates.lampsByColor(DyeColor.DYE_COLOR)`. Where DYE_COLOR is the name of the color you want.

## `GTRecipeBuilder#adjacentFluidTag()` and `GTRecipeBuilder#adjacentBlockTag()`
_This is only relevant to **add-on mods** with custom recipe types that use the condition(s). **KubeJS recipes are not affected.**_

The renames of `GTRecipeBuilder#adjacentFluid(TagKey<Fluid>...)` -> `#adjacentFluidTag(TagKey<Fluid>...)` and `GTRecipeBuilder#adjacentBlock(TagKey<Block>...)` -> `#adjacentBlockTag(TagKey<Block>...)`
have been deprecated in favor of naming every variant `adjacentFluids` and `adjacentBlocks`, respectively.  
Please update your addon mods' recipes to use these new methods, as the now deprecated methods will be removed come 8.0.0.

A full list of all deprecated methods & their replacement is as follows:  
Fluids: `adjacentFluid`, `adjacentFluidTag` -> `adjacentFluids`  
Blocks: `adjacentBlock`, `adjacentBlockTag` -> `adjacentBlocks`

## Machine Recipe Failure Diagnostics
Machines now provide detailed diagnostics explaining why recipes fail to start.

Failure reasons are displayed in:
- the sidebar of simple machines
- the UI of multiblock machines
- the Jade tooltip for all machines

You are supposed to replace `ModifierFunction.NULL` with `ModifierFunction.cancel(reason)` to tell the machine why the recipe fails to start.
```patch
- return ModifierFunction.NULL;
+ return ModifierFunction.cancel(Component.translatable("gtceu.recipe_modifier.xxx"));
```

Also, if you cancel a recipe in `IRecipeLogicMachine#beforeWorking()`, you are supposed to add some custom reason info like:
```
@Override
public boolean beforeWorking(@Nullable GTRecipe recipe) {
    if(xxx){
        RecipeLogic.putFailureReason(this, recipe, Component.literal("Machine spirit is displeased"));
        return false
    }
    return true;
}
```

## Painted Output Buses/Hatches
For some time, Spray Paint cans could be used to paint Input and Output Buses/Hatches on multiblock machines.
Version 7.0.0  added the feature that Painted Input Buses/Hatches of different colors would not share their ingredients with
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).

7.5.0 also applies this logic to Output Buses/Hatches as well. Input Buses/Hatches which have been painted are now only
allowed to send their outputs to Output Buses/Hatches that are of the same paint color, or unpainted. This may cause
existing setups to stop running, if they had painted Output Buses/hatches on them.

## Change to GTRecipe constructor
GTRecipe has had one new field added to it and its constructors: `int groupColor`. For new recipes, this parameter
is set to `-1`; however for recipes that are being prepared and run, this field holds the Paint color of the 
Painted Input Group that the recipe drew its inputs from.

Addon mods which explicitly attempt to construct, copy, or apply their own ModifierFunctions to a GTRecipe 
(not using the standard builder or kjs functions) will need to either add the additional `int` parameter to the end of 
their constructor calls, or the additional `recipe.groupColor` to their copy calls.

## Added BiomeTagCondition
Added a new RecipeCondition called BiomeTagCondition for needing a specific biome tag. This can be used with KubeJS using `.biomeTag("biome")`.
