Skip to content
Closed
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
42 changes: 12 additions & 30 deletions .github/workflows/deploy-pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@ name: Publish docs via GitHub Pages
on:
workflow_dispatch:
push:
branches: [1.20.1]
branches: ["1.20.1", "1.21"]
paths: ['docs/**']

permissions:
contents: read
pages: write
id-token: write
contents: write

concurrency:
group: 'pages'
Expand All @@ -24,33 +22,17 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
ref: '1.20.1'
sparse-checkout: './docs'
ref: '${{ github.ref_name }}'
fetch-depth: 0
- uses: actions/setup-python@v4
with:
python-version: '3.11'
cache: 'pip'
- run: pip install -r ./requirements.txt
- uses: actions/cache@v4
with:
key: 'mkdocs-cache'
path: './docs/.cache'
- name: Build static files
id: mkdocs
run: mkdocs build
- name: Upload pages as artifact
id: artifact
uses: actions/upload-pages-artifact@v3
with:
path: './docs/site/'

deploy:
runs-on: ubuntu-latest
needs: build
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy Pages
id: deployment
uses: actions/deploy-pages@v4
- name: Install packages
run: pip install -r ./requirements.txt
- name: Set git username and password
run: git config user.name 'github-actions[bot]'; git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
- name: Deploy pages to gh-pages branch
run: mike deploy "${{ github.ref_name }}" --push
- name: Ensure 1.20.1 is the default version
run: mike set-default 1.20.1 --push
5 changes: 5 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,8 @@ mkdocs serve
The following plugins for MkDocs are being used:
- https://squidfunk.github.io/mkdocs-material/
- https://github.com/lukasgeiter/mkdocs-awesome-pages-plugin

## Deployment
The hosted documentation is found on the `gh-pages` branch of the repository. [Mike](https://github.com/jimporter/mike) is used to deploy both the 1.20.1 and 1.21.1 documentation on the same site through Github Actions.

When working on the docs locally, the plain `mkdocs` commands should be used to view the changes made to the version of the docs you are currently working on, like the previously mentioned `mkdocs serve`.
3 changes: 1 addition & 2 deletions docs/content/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ hide:
title: Home
---


# Welcome to GregTech CEu Modern's Documentation!
# Welcome to GregTech CEu Modern's Documentation for 1.21.1!

GregTech CEu Modern is a port of [GregTech Community Edition Unofficial](https://github.com/GregTechCEu/GregTech)
to modern Minecraft versions.
Expand Down
2 changes: 2 additions & 0 deletions docs/mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ extra_css:
- stylesheets/extra.css

extra:
version:
provider: mike
social:
- icon: fontawesome/brands/discord
link: https://discord.gg/bWSWuYvURP
Expand Down
1 change: 1 addition & 0 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
mkdocs-material
mkdocs-awesome-pages-plugin
mike
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
import com.gregtechceu.gtceu.api.GTValues;
import com.gregtechceu.gtceu.api.item.tool.GTToolType;
import com.gregtechceu.gtceu.api.machine.IMachineBlockEntity;
import com.gregtechceu.gtceu.api.machine.MachineRenderState;
import com.gregtechceu.gtceu.api.machine.MetaMachine;
import com.gregtechceu.gtceu.client.model.machine.MachineRenderState;

import com.lowdragmc.lowdraglib.gui.texture.ResourceTexture;
import com.lowdragmc.lowdraglib.syncdata.IManaged;
Expand All @@ -25,6 +25,7 @@
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.Property;

import lombok.Getter;
import org.jetbrains.annotations.Nullable;
Expand Down Expand Up @@ -117,10 +118,50 @@ public void removeComponentsFromTag(CompoundTag tag) {

@Override
public void setRenderState(MachineRenderState state) {
if (state != null) {
// Validate that the state belongs to this block entity's definition
if (!state.is(getDefinition())) {
state = correctRenderStateDefinition(state);
}
// Ensure we're using the interned (canonical) state instance
state = state.intern();
}
this.renderState = state;
scheduleRenderUpdate();
}

/**
* Corrects a render state that belongs to the wrong definition by creating a new state
* from this block entity's definition while preserving any compatible property values.
*/
private MachineRenderState correctRenderStateDefinition(MachineRenderState wrongState) {
MachineRenderState correctedState = getDefinition().defaultRenderState();
// Copy any property values that exist in both the wrong state and this definition's state
for (Property<?> property : wrongState.getProperties()) {
if (correctedState.hasProperty(property)) {
correctedState = copyProperty(correctedState, wrongState, property);
}
}
return correctedState; // intern() will be called by setRenderState
}

/**
* Helper method to copy a single property value from one state to another.
* Uses a type parameter to satisfy the generic constraints of setValue().
*/
@SuppressWarnings("unchecked")
private static <T extends Comparable<T>> MachineRenderState copyProperty(
MachineRenderState target,
MachineRenderState source,
Property<T> property) {
T value = source.getValue(property);
// Verify the value is valid for the target state's property
if (property.getPossibleValues().contains(value)) {
return target.setValue(property, value);
}
return target;
}

@Override
public long getOffset() {
return offset;
Expand All @@ -135,6 +176,16 @@ public void setRemoved() {
@Override
public void onLoad() {
super.onLoad();
// Validate and intern render state after NBT load - @Persisted writes directly to field via reflection,
// bypassing setRenderState(), so we need to validate and intern here as well
if (renderState != null) {
if (!renderState.is(getDefinition())) {
this.renderState = correctRenderStateDefinition(renderState).intern();
} else {
// Ensure the state is properly interned even if definition is correct
this.renderState = renderState.intern();
}
}
metaMachine.onLoad();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import com.gregtechceu.gtceu.api.block.IMachineBlock;
import com.gregtechceu.gtceu.api.blockentity.IPaintable;
import com.gregtechceu.gtceu.api.item.tool.IToolGridHighLight;
import com.gregtechceu.gtceu.client.model.machine.MachineRenderState;
import com.gregtechceu.gtceu.core.mixins.LevelAccessor;

import com.lowdragmc.lowdraglib.syncdata.blockentity.IAsyncAutoSyncBlockEntity;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import com.gregtechceu.gtceu.api.recipe.GTRecipeType;
import com.gregtechceu.gtceu.api.recipe.kind.GTRecipe;
import com.gregtechceu.gtceu.api.recipe.modifier.RecipeModifier;
import com.gregtechceu.gtceu.client.model.machine.MachineRenderState;

import com.lowdragmc.lowdraglib.utils.ShapeUtils;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.gregtechceu.gtceu.api.machine;

import com.gregtechceu.gtceu.GTCEu;
import com.gregtechceu.gtceu.api.registry.GTRegistries;

import net.minecraft.world.level.block.state.StateHolder;
import net.minecraft.world.level.block.state.properties.Property;

import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap;

import java.util.function.Function;

public class MachineRenderState extends StateHolder<MachineDefinition, MachineRenderState> {

private static boolean hasLoggedInternFallback = false;

/**
* CODEC that always returns interned (canonical) state instances.
* This is critical because StateHolder uses identity-based lookups internally.
*/
public static final Codec<MachineRenderState> CODEC = codec(GTRegistries.MACHINES.byNameCodec(),
MachineDefinition::defaultRenderState)
.xmap(MachineRenderState::intern, Function.identity())
.stable();

/**
* Returns the interned (canonical) instance of this state from the definition's StateDefinition.
* This ensures identity-based lookups work correctly.
*/
public MachineRenderState intern() {
for (MachineRenderState interned : getDefinition().getStateDefinition().getPossibleStates()) {
if (interned.getValues().equals(this.getValues())) {
return interned;
}
}
// Fallback if not found (shouldn't happen)
if (!hasLoggedInternFallback) {
hasLoggedInternFallback = true;
GTCEu.LOGGER.debug("MachineRenderState.intern() fallback triggered for definition: {}, values: {}",
getDefinition().getId(), getValues());
}
return this;
}

public MachineRenderState(MachineDefinition owner, Reference2ObjectArrayMap<Property<?>, Comparable<?>> values,
MapCodec<MachineRenderState> propertiesCodec) {
super(owner, values, propertiesCodec);
}

public MachineDefinition getDefinition() {
return this.owner;
}

public boolean is(MetaMachine machine) {
return this.is(machine.getDefinition());
}

public boolean is(MachineDefinition definition) {
return this.getDefinition() == definition;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import com.gregtechceu.gtceu.api.misc.IOFluidHandlerList;
import com.gregtechceu.gtceu.api.multiblock.util.RelativeDirection;
import com.gregtechceu.gtceu.api.transfer.fluid.IFluidHandlerModifiable;
import com.gregtechceu.gtceu.client.model.machine.MachineRenderState;
import com.gregtechceu.gtceu.client.util.ModelUtils;
import com.gregtechceu.gtceu.common.cover.FluidFilterCover;
import com.gregtechceu.gtceu.common.cover.ItemFilterCover;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@
import com.gregtechceu.gtceu.api.block.property.GTBlockStateProperties;
import com.gregtechceu.gtceu.api.capability.IParallelHatch;
import com.gregtechceu.gtceu.api.machine.IMachineBlockEntity;
import com.gregtechceu.gtceu.api.machine.MachineRenderState;
import com.gregtechceu.gtceu.api.machine.MetaMachine;
import com.gregtechceu.gtceu.api.machine.MultiblockMachineDefinition;
import com.gregtechceu.gtceu.api.machine.feature.multiblock.IMultiController;
import com.gregtechceu.gtceu.api.machine.feature.multiblock.IMultiPart;
import com.gregtechceu.gtceu.api.machine.property.GTMachineModelProperties;
import com.gregtechceu.gtceu.api.multiblock.MultiblockState;
import com.gregtechceu.gtceu.api.multiblock.MultiblockWorldSavedData;
import com.gregtechceu.gtceu.client.model.machine.MachineRenderState;

import com.lowdragmc.lowdraglib.syncdata.annotation.DescSynced;
import com.lowdragmc.lowdraglib.syncdata.annotation.Persisted;
Expand All @@ -23,7 +23,6 @@
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.block.state.BlockState;

import lombok.Getter;
import lombok.Setter;
Expand Down Expand Up @@ -204,16 +203,20 @@ public void onStructureInvalid() {
}

/**
* mark multiblockState as unload error first.
* if it's actually cuz by block breaking.
* {@link #onStructureInvalid()} will be called from
* {@link MultiblockState#onBlockStateChanged(BlockPos, BlockState)}
* Called when a part is unloaded (chunk unload or block broken).
* If the structure is currently formed, immediately invalidate it to ensure
* all remaining parts have their render state updated.
*/
@Override
public void onPartUnload() {
parts.removeIf(part -> part.self().isInValid());
getMultiblockState().setError(MultiblockState.UNLOAD_ERROR);
if (getLevel() instanceof ServerLevel serverLevel) {
// If structure is formed, invalidate it immediately to update all parts' render states
if (isFormed) {
onStructureInvalid();
MultiblockWorldSavedData.getOrCreate(serverLevel).removeMapping(getMultiblockState());
}
MultiblockWorldSavedData.getOrCreate(serverLevel).addAsyncLogic(this);
}
updatePartPositions();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.gregtechceu.gtceu.api.capability.recipe.IRecipeHandler;
import com.gregtechceu.gtceu.api.capability.recipe.RecipeCapability;
import com.gregtechceu.gtceu.api.machine.IMachineBlockEntity;
import com.gregtechceu.gtceu.api.machine.MachineRenderState;
import com.gregtechceu.gtceu.api.machine.feature.ICleanroomProvider;
import com.gregtechceu.gtceu.api.machine.feature.IMufflableMachine;
import com.gregtechceu.gtceu.api.machine.feature.multiblock.IMultiPart;
Expand All @@ -17,7 +18,6 @@
import com.gregtechceu.gtceu.api.machine.trait.RecipeLogic;
import com.gregtechceu.gtceu.api.recipe.GTRecipeType;
import com.gregtechceu.gtceu.api.recipe.kind.GTRecipe;
import com.gregtechceu.gtceu.client.model.machine.MachineRenderState;

import com.lowdragmc.lowdraglib.syncdata.ISubscription;
import com.lowdragmc.lowdraglib.syncdata.annotation.DescSynced;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@
import com.gregtechceu.gtceu.api.capability.recipe.IO;
import com.gregtechceu.gtceu.api.capability.recipe.IRecipeHandler;
import com.gregtechceu.gtceu.api.machine.IMachineBlockEntity;
import com.gregtechceu.gtceu.api.machine.MachineRenderState;
import com.gregtechceu.gtceu.api.machine.MetaMachine;
import com.gregtechceu.gtceu.api.machine.feature.multiblock.IMultiController;
import com.gregtechceu.gtceu.api.machine.feature.multiblock.IMultiPart;
import com.gregtechceu.gtceu.api.machine.property.GTMachineModelProperties;
import com.gregtechceu.gtceu.api.machine.trait.IRecipeHandlerTrait;
import com.gregtechceu.gtceu.api.machine.trait.RecipeHandlerList;
import com.gregtechceu.gtceu.client.model.machine.MachineRenderState;

import com.lowdragmc.lowdraglib.syncdata.annotation.DescSynced;
import com.lowdragmc.lowdraglib.syncdata.annotation.Persisted;
import com.lowdragmc.lowdraglib.syncdata.annotation.RequireRerender;
import com.lowdragmc.lowdraglib.syncdata.annotation.UpdateListener;
import com.lowdragmc.lowdraglib.syncdata.field.ManagedFieldHolder;
Expand All @@ -38,6 +39,7 @@ public class MultiblockPartMachine extends MetaMachine implements IMultiPart {
protected static final ManagedFieldHolder MANAGED_FIELD_HOLDER = new ManagedFieldHolder(MultiblockPartMachine.class,
MetaMachine.MANAGED_FIELD_HOLDER);

@Persisted
@DescSynced
@RequireRerender
@UpdateListener(methodName = "onControllersUpdated")
Expand Down Expand Up @@ -114,6 +116,26 @@ protected RecipeHandlerList getHandlerList() {
return handlerList;
}

@Override
public void onLoad() {
super.onLoad();
// Rebuild controllers from persisted positions on load
// @UpdateListener only fires on sync updates, not on NBT load
if (!controllerPositions.isEmpty()) {
onControllersUpdated(controllerPositions, Collections.emptySet());
// If we couldn't resolve controllers (loading order or cross-chunk),
// clear the formed state to avoid inconsistent visuals (overlays without texture overrides).
// The async multiblock validation will restore formed state properly when ready.
if (controllers.isEmpty()) {
MachineRenderState renderState = getRenderState();
if (renderState.hasProperty(GTMachineModelProperties.IS_FORMED) &&
renderState.getValue(GTMachineModelProperties.IS_FORMED)) {
setRenderState(renderState.setValue(GTMachineModelProperties.IS_FORMED, false));
}
}
}
}

@Override
public void onUnload() {
super.onUnload();
Expand Down
Loading
Loading