---
title: "Version 8.0.0"
---


# Updating from `7.5.3` to `8.0.0`

## New Data Save/Sync System

A new system for saving and syncing object fields has been added. See [this page](../../Development/Data-Sync-System/Migrating-From-LDLib-SyncData.md) for migration instructions.

## Machine Refactor Part 1: `MetaMachine` and `MetaMachineBlockEntity` merge

Many aspects of the machine classes have been refactored and changed in order to streamline the machine system and remove legacy and unnecessary abstraction.

- The `MetaMachineBlockEntity`(MMBE) class has been removed, and `MetaMachine`(MM) is now a BlockEntity.
- Most methods and properties of MMBE have been moved onto MM.
- The `IMachineBlock` interface has been removed. Use `MetaMachineBlock` directly instead.
- The `IMachineBlockEntity` interface has been removed. Use `MetaMachine` directly instead.
- Many methods common to all block entities have been moved to the `IGregtechBlockEntity` interface.
- Machine instance creation functions have signature `(BlockEntityCreationInfo) -> MetaMachine` instead of `(IMachineBlockEntity) -> MetaMachine` 

References to MMBE can generally be replaced with references to MM:
```java
/////// OLD
if (level.getBlockEntity(getPos()) instanceof MetaMachineBlockEntity mmbe) {
    MetaMachine machine = mmbe.getMetaMachine();
    ...
}

////// NEW
if (level.getBlockEntity(getPos()) instanceof MetaMachine machine) {
    ... 
} 
```

The `IMachineBlockEntity holder` argument in machine constructors has been replaced with `BlockEntityCreationInfo info`:
```java
////// OLD
public MetaMachine(IMachineBlockEntity holder);
////// NEW
public MetaMachine(BlockEntityCreationInfo info);
```
A number of methods have been renamed across a number of different interfaces and classes to ensure consistency with default BlockEntity methods:

- `BlockPos getPipePos()` -> `BlockPos getBlockPos()`
- `Level getPipeLevel()` -> `Level getLevel()`
- `BlockPos getPos()` -> `BlockPos getBlockPos()`
- `BlockState getState()` -> `BlockState getBlockState()`
- `boolean isInvalid()` -> `boolean isRemoved()`
- `void markAsDirty()` -> `void markAsChanged()`

### Interfaces and behaviours merged into MetaMachine

Some interfaces have been removed with their methods now part of the MetaMachine class directly

- `IMachineLife` - Use `MetaMachine::onMachinePlaced` and `MetaMachine::onMachineDestroyed`.
- `IMachineModifyDrops` - Use `MetaMachine::modifyDrops`.
- `IInteractedMachine` - Use `MetaMachine::onUse` and `MetaMachine::onLeftClick`.

### Machine interaction refactor

Methods for processing machine interactions have changed, and all now take a single `ExtendedUseOnContext` argument. 
Machine interactions have been split into two methods: `MetaMachine::onUse` and `MetaMachine::onUseWithItem`.

## Machine Refactor Part 2: New Machine Trait System

A new system for attaching traits and custom behaviour to machines has been added, and many machine interfaces and traits now use this new system.

See [this page](../../Development/General-Topics/Machine-Trait-System.md) for an overview of the new system.

### Machine constructor and trait initialisation changes

The constructors for a large number of machines have changed in order to simply machine instance creation. Additionally, methods for trait creation have also been removed and now form part of the machine constructor.

#### **All Machines**
- Replace the first constructor argument `IMachineBlockEntity holder` with `BlockEntityCreationInfo info`
#### Machines with `createX` functions (e.g. `createEnergyContainer`, `createRecipeLogic`)
- Creation functions have been removed in favor of arguments being passed into the constructor.

#### IMPORTANT MIGRATION NOTE:

Traits must be attached to a machine directly by calling `attachTrait(MachineTrait trait)` on the trait being attached. 
Previously, all machine traits were constructed with the machine as the first argument.
```java
/////// OLD
this.itemHandler = new NotifiableItemStackHandler(this, 0, IO.BOTH);

////// NEW
this.itemHandler = attachTrait(new NotifiableItemStackHandler(0, IO.BOTH))
```
When migrating, remove the `this` argument from the machine trait constructor and instead attach the trait.

### Removed interfaces

A large number of machine feature interfaces have been removed, and have had their functionality merged into the standard MetaMachine class, or now use the new machine trait system:

- `IMultiPart` Use the `MultiblockPartMachine` class directly.
- `IWorkableMultiController` Use the `WorkableMultiblockMachine` class directly.
- `ITurbineMachine` Use the `LargeTurbineMachine` class directly.
- `IRotorHolderMachine` Use the `RotorHolderMachine` class directly.
- `IMultiController` Use the `MultiblockControllerMachine` class directly.
- `IMufflerMachine` Use the `MufflerMachine` class directly.
- `ICleanroomReceiver` & `ICleanroomProvider` - Use `CleanroomReceiverTrait` and `CleanroomProviderTrait`.
- `IAutoOutputBoth`, `IAutoOutputFluid`, `IAutoOutputItem` - Use `AutoOutputTrait`.
- `IExplosionMachine` - Use `EnvironmentalExplosionTrait`, `GTUtil::doExplosion`, and `GTUtil::setOnFire`
- `IEnvironmentalHazardCleaner` Use `EnvironmentalHazardCleanerTrait`
- `ILocalizedHazardEmitter` - Use `LocalizedHazardEmitterTrait`
- `IExhaustVentMachine` - Use `ExhaustVentMachineTrait`
- `IHPCAComponentHatch` - Use `HPCAComponentTrait`
- `IHPCAComputationProvider` - Use `HPCAComputationProviderTrait`
- `IHPCACoolantProvider` - Use `HPCACoolantProviderTrait`
- `IFluidRendererMulti` - Use `MultiblockFluidRendererTrait`
- `IMaintenanceMachine` Use `MaintenanceHatchPartMachine`

# Multiblock pattern changes

- `FactoryBlockPattern` has been renamed to `MultiblockPatternBuilder`
- `.aisle(...)` has been renamed to `.slice(...)`, and `.aisleRepeatable(...)` to `.sliceRepeatable(...)`.
- The three `RelativeDirection` arguments of `start` are taken in the opposite order. It used to be `start(charDir, stringDir, aisleDir)` and is now `start(sliceDir, stringDir, charDir)`, so an existing call has its arguments reversed:
```java
/////// OLD
FactoryBlockPattern.start(RelativeDirection.LEFT, RelativeDirection.UP, RelativeDirection.FRONT)
////// NEW
MultiblockPatternBuilder.start(RelativeDirection.FRONT, RelativeDirection.UP, RelativeDirection.LEFT)
```
- The no-argument `start()` does not use the same directions anymore. In `7.5.3` it was `(charDir = LEFT, stringDir = UP, aisleDir = FRONT)`, and in `8.0.0` it is `(sliceDir = BACK, stringDir = UP, charDir = RIGHT)`.

There are two ways to fix a pattern that broke this way. Either reverse the order of the slices, so that
```java
/////// OLD
.aisle(A).aisle(B).aisle(C)
////// NEW
.slice(C).slice(B).slice(A)
```
or leave the slices in their original order and pass the old directions to `start` instead:
```java
MultiblockPatternBuilder.start(RelativeDirection.FRONT, RelativeDirection.UP, RelativeDirection.LEFT)
        .slice(A).slice(B).slice(C)
```

# ModularUI changes

All your machines need to be migrated from LDLib's UI system to ModularUI's system. See [this category](../../Development/MUI2/index.md).

As part of this migration, your machine builder's  
`.additionalDisplay((controller, components) -> { components.add(...)})`  
is now  
`.additionalDisplay((controller, syncManager) -> { return List.of(... your widgets here) })`.

!!! note
    Do not forget that just like in your machine UI builders, you need to sync your data to the client. See [this page on syncing](../../Development/MUI2/Syncing/Sync-Basics.md).

Machines that opened a UI implemented `IUIMachine` (or a definition-level UI creator) before; they now implement `IMuiMachine`. See [Machine UIs](../../Development/MUI2/Machine-UI.md) for the methods to override.

## Recipe type UIs

Recipe type UI options have moved off `GTRecipeType` onto a `GTRecipeTypeUILayout`, declared with `.UI(builder -> ...)`. See [this page](../../Development/MUI2/Recipe-Type-UI.md).

The following changes can be made in java:

- `.setProgressBar(texture, fillDirection)` -> `.UI(builder -> builder.setProgressBar(textureSet))`. Size and fill direction are part of the `ProgressBarTextureSet`.
- `.setSlotOverlay(isOutput, isFluid, overlay)` is now per-capability and per-slot:
  ```java
  /////// OLD
  .setSlotOverlay(false, false, GuiTextures.ARROW_INPUT_OVERLAY)
  ////// NEW (for a recipe type that has 4 input item slots that we wanna set:)
  .UI(builder -> builder.setSlotsOverlay(IO.IN, 0, 3, ItemRecipeCapability.CAP, GTGuiTextures.ARROW_INPUT_OVERLAY))
  ```
  `setItemSlotsOverlay`/`setFluidSlotsOverlay` and the single-slot `setItemSlotOverlay`/`setFluidSlotOverlay` are shorthands for the item and fluid capabilities.
- `.addDataInfo(data -> string)` -> `.UI(builder -> builder.addRecipeUIModifier((recipe, widget) -> ...))`, which gives you the recipe viewer's widget tree instead of a string:
  ```java
  /////// OLD
  .addDataInfo(data -> I18n.get("emi_info.example.info", data.getByte("tier")))
  ////// NEW
  .UI(builder -> builder.addRecipeUIModifier((recipe, widget) -> widget.textComponents.child(
          Text.lang("emi_info.example.info", recipe.data.getByte("tier")).asWidget())))
  ```
  Filler calls such as `.addDataInfo(data -> " ")` can be deleted.
- Custom `RecipeCapability`s no longer draw themselves. Supply a `MachineCapabilityLayoutBuilder`, a `RecipeViewerCapabilityLayoutBuilder` and a `CapabilityContentBuilder`.

KubeJS scripts do not use `.UI()`; the recipe type builder exposes `setProgressBar`, the `setSlotOverlay`/`setSlotsOverlay` family and `addRecipeInfo` directly instead:
```js
/////// OLD
.setSlotOverlay(false, false, GuiTextures.ARROW_INPUT_OVERLAY)
.setProgressBar(GuiTextures.PROGRESS_BAR_ARROW, FillDirection.LEFT_TO_RIGHT)
.addDataInfo(data => `Temperature: ${data.getInt("RequiredTemp")}K`)
////// NEW
.setItemSlotsOverlay(IO.IN, 0, 3, GTGuiTextures.ARROW_INPUT_OVERLAY)
.setProgressBar(GTGuiTextures.PROGRESS_ARROW)
.addRecipeInfo(recipe => Text.literal(`Temperature: ${recipe.data.getInt("RequiredTemp")}K`))
```
`addRecipeInfo` is given the recipe and returns the component for it, built with KubeJS's `Text.literal` or `Text.translate`. Return `Text.empty()` to show no line.

# Registration changes

- `GTRegistrate#registerRegistrate` has been removed. `GTRegistrate.create(modId)` now registers the event listeners itself, so the call can simply be deleted.
- `MaterialRegistryEvent` has been removed, along with the per-addon material registries. Delete the listener that called `GTCEuAPI.materialManager.createRegistry(MOD_ID)`. `MaterialEvent` and `PostMaterialEvent` are unchanged.
- `GTElements.createAndRegister` takes a `ResourceLocation` id first, so addon elements register into your own namespace:
  ```java
  /////// OLD
  GTElements.createAndRegister(6, 6, -1, null, "Crystal Matrix", "C☆", false);
  ////// NEW
  GTElements.createAndRegister(MyAddon.id("crystal_matrix"), 6, 6, -1, null, "Crystal Matrix", "C☆", false);
  ```
- The deprecated `IGTAddon.registerX()` callbacks are replaced by generic `GTCEuAPI.RegisterEvent<ResourceLocation, T>` events on your mod event bus:
  ```java
  modEventBus.addGenericListener(Element.class, this::registerElements);

  private void registerElements(GTCEuAPI.RegisterEvent<ResourceLocation, Element> event) {
      MyElements.init();
  }
  ```
  Events exist for elements, material icon sets, tag prefixes, covers, recipe capabilities, recipe types, recipe categories, machines, sounds, placeholders, dimension markers, chance logics, medical conditions, pattern errors and worldgen layers.

# Client model and rendering changes

- `ModelUtils` has been split up:
    - `ModelUtils.register*EventListener` -> `ModelEventHelper.register*EventListener`
    - `ModelUtils.getModelForState` -> `RenderUtil.getModelForState`
    - `ModelUtils.getPropertyValueString` -> `GTStringUtils.getPropertyValueString`
    - `ModelUtils.getBakedModelQuads` has been removed, call `BakedModel::getQuads` directly.
- The bake listener no longer exposes the baked models, so look them up at render time instead of caching them from the event:
  ```java
  /////// OLD
  ModelUtils.registerBakeEventListener(true, event -> sphereModel = event.getModels().get(SPHERE));

  ////// NEW
  // at render time:
  Minecraft.getInstance().getModelManager().getModel(SPHERE); // do something with this
  ```
  Models are rebaked on every resource reload, so the lookup must stay refreshable.
- `registerBakeEventListener` is now a replacement function `(modelLocation, baked, rootModel, modelBakery) -> BakedModel` instead of an event consumer.
- `RenderUtil.vertex` and others take a `PoseStack.Pose` instead of a `Matrix4f`. Pass `poseStack.last()` rather than `poseStack.last().pose()`.

## Connected texture reimplementation
The mod's connected texture logic has been reimplemented in GTM proper.
Texture packs, addons, and modpacks will have to change their texture metadata files for connected texures slightly.  
A few regexes for fixing all the MCMeta files is follows, run them in order:

1. Match: `"ldlib":([\s\{]*)"connection"(:\s".*?")(?:,\s.*)?`  
   Replace with: `"gtceu":$1"connection_texture"$2` 
2. Match: `\s*\},\s*"shimmer":\s*\{(\s*"bloom":.*)`  
   Replace with: `,$1` 
3. Match: `(\{\s*)"shimmer":(\s*\{\s*"bloom":.*)`  
   Replace with: `$1"gtceu":$2` 

# Other API changes

## IRecipeHandler nullability
Previously, `handleRecipeInner` should return `null` when there's nothing left to process. This has been changed to requiring an empty list (e.g. the list of remaining ingredients). Returning `null` is now wrong and will crash (NPE).

## Empty content check for recipe capabilities
As a recipe-matching optimization, input handlers whose `getTotalContentAmount()` returns `0` are now skipped during recipe handling. If your `RecipeCapability` has handlers that legitimately report a total content amount of `0` but can still satisfy a recipe (e.g. rate-based capabilities like computation/CWU, where nothing is "stored" but the handler can still provide), you must now override `RecipeCapability#skipEmptyContentCheck()` to return `true`, otherwise these capabilities will break (their handlers will never be run).

## Removal of marker materials
Marker materials have been removed. This means that a few utils related to colored items have been moved. All GT color values are now located in `GTValues.COLORS`, and getting a colored lens should now be done using the `forge:lenses/<color>` tags.
## Other Changes

- `BlastingRecipeBuilder`, `CampfireRecipeBuilder`, `SmeltingRecipeBuilder` and `SmokingRecipeBuilder` have been merged into `SimpleCookingRecipeBuilder`
    - Example usage: `SimpleCookingRecipeBuilder.campfireCooking("cooking_chicken").input(new ItemStack(Items.CHICKEN)).output(new ItemStacks(Items.COOKED_CHICKEN)).cookingTime(100).experience(100).save(provider);`
- `GTFluidImpl` has been merged into `GTFluid`, use `GTFluid.Flowing` and `GTFluid.Source` instead of `GTFluidImpl.Flowing` and `GTFluidImpl.Source`.
- Item behaviors have been moved to `common/item/behavior`, and some items have been moved from `api/item` to `common/item`.
- Changed the minimum value of the `compat.minimap.surfaceRockProspectRange` and `compat.minimap.oreBlockProspectRange` configs from -1 to 0. The behavior is still disabled with 0. 
- All materials are now stored in a single registry, instead of a registry per addon. Replace references to `GTCEuAPI.materialManager` with `GTRegistries.MATERIALS`.
- `ChargerMachine` has been merged into `BatteryBufferMachine`.
  - Calling the battery buffer constructor with the following args gives the same behaviour as a charger machine: `(info, tier, inventorySize, BatteryBufferMachine.AMPS_PER_BATTERY_CHARGER, 0)`
- Refactored Jade provider code. Use the `MachineInfoProvider` class for jade providers for a specific machine type, and `MachineTraitProvider` for providers for a specific machine trait. 
- `GTUtil.getMoltenFluid(Material)` has been moved to `Material.getHotFluid()`.
- `ICopyable::copyConfig`'s `CompoundTag` argument should now be mutated by reference instead of a new one returned (and thus, the return type has been changed to `void`).
- Tiered Chance Boosting has been formally removed from the API (as it was deprecated in v7.0.) `ChancedInput` and `ChancedOutput` kubeJS calls will throw errors if they still had chance boost values as arguments.
- Any custom `IDistinctPart`'s will have to implement `supportsDistinct` if they don't extend `ItemBusPartMachine`.
- Runtime model generators (previously named `ArmorItemRenderer`, `TagPrefixItemRenderer`, `ToolItemRenderer`, `MaterialBlockRenderer`, `OreBlockRenderer`, and `SurfaceRockRenderer`) have been renamed and moved from various packages under `client.renderer` to their own package, `client.model.runtimegen`.  
  The classes' names are now as follows (all start with `com.gregtechceu.gtceu.client.`):
  - `renderer.item.ArmorItemRenderer` -> `model.runtimegen.ArmorItemModelGenerator`
  - `renderer.item.TagPrefixItemRenderer` -> `model.runtimegen.TagPrefixItemModelGenerator`
  - `renderer.item.ToolItemRenderer` -> `model.runtimegen.ToolItemModelGenerator`
  - `renderer.block.MaterialBlockRenderer` -> `model.runtimegen.MaterialBlockModelGenerator`
  - `renderer.block.OreBlockRenderer` -> `model.runtimegen.OreBlockModelGenerator`
  - `renderer.block.SurfaceRockRenderer` -> `model.runtimegen.SurfaceRockModelGenerator`
  
  The `#create` function common to all of them has also been renamed to `#add`. Simply changing the name is enough, as the functions' parameters weren't changed.
