recipe;
+ ModifierFunction IDENTITY = ModifierFunction.builder().build();
+
+ static ModifierFunction cancel(Component reason) {
+ return new ModifierFunction() {
+
+ @Override
+ public @Nullable GTRecipe apply(@NotNull GTRecipe recipe) {
+ return null;
+ }
+
+ @Override
+ public Component getFailReason() {
+ return reason;
+ }
+ };
+ }
/**
* Applies this modifier to the passed recipe
@@ -79,6 +97,12 @@ private GTRecipe applySafe(@Nullable GTRecipe recipe) {
return apply(recipe);
}
+ static final Component DEFAULT_FAILURE = Component.translatable("gtceu.recipe_modifier.default_fail");
+
+ default Component getFailReason() {
+ return DEFAULT_FAILURE;
+ }
+
/**
* Creates a FunctionBuilder to easily build a ModifierFunction that modifies parts of a recipe.
*
@@ -159,7 +183,7 @@ public ModifierFunction build() {
new HashMap<>(recipe.inputChanceLogics), new HashMap<>(recipe.outputChanceLogics),
new HashMap<>(recipe.tickInputChanceLogics), new HashMap<>(recipe.tickOutputChanceLogics),
newConditions, new ArrayList<>(recipe.ingredientActions),
- recipe.data, recipe.duration, recipe.recipeCategory);
+ recipe.data, recipe.duration, recipe.recipeCategory, recipe.groupColor);
copied.parallels = recipe.parallels * parallels;
copied.subtickParallels = recipe.subtickParallels * subtickParallels;
copied.ocLevel = recipe.ocLevel + addOCs;
diff --git a/src/main/java/com/gregtechceu/gtceu/api/recipe/modifier/ParallelLogic.java b/src/main/java/com/gregtechceu/gtceu/api/recipe/modifier/ParallelLogic.java
index b8a65588451..a1e903a2883 100644
--- a/src/main/java/com/gregtechceu/gtceu/api/recipe/modifier/ParallelLogic.java
+++ b/src/main/java/com/gregtechceu/gtceu/api/recipe/modifier/ParallelLogic.java
@@ -3,11 +3,13 @@
import com.gregtechceu.gtceu.api.capability.recipe.*;
import com.gregtechceu.gtceu.api.machine.MetaMachine;
import com.gregtechceu.gtceu.api.machine.feature.IRecipeLogicMachine;
+import com.gregtechceu.gtceu.api.machine.trait.RecipeLogic;
import com.gregtechceu.gtceu.api.recipe.GTRecipe;
import com.gregtechceu.gtceu.api.recipe.RecipeHelper;
import com.gregtechceu.gtceu.api.recipe.content.ContentModifier;
import net.minecraft.MethodsReturnNonnullByDefault;
+import net.minecraft.network.chat.Component;
import org.jetbrains.annotations.NotNull;
@@ -57,7 +59,15 @@ public static int getMaxByInput(IRecipeCapabilityHolder holder, GTRecipe recipe,
for (RecipeCapability> cap : recipe.inputs.keySet()) {
if (cap.doMatchInRecipe() && !capsToSkip.contains(cap)) {
// Find the maximum number of recipes that can be performed from the contents of the input inventories
- minimum = Math.min(minimum, cap.getMaxParallelByInput(holder, recipe, parallelLimit, false));
+ var capParallel = cap.getMaxParallelByInput(holder, recipe, parallelLimit, false);
+ if (capParallel == 0) {
+ Component reason = Component.translatable("gtceu.recipe_logic.insufficient_in")
+ .append(": ")
+ .append(cap.getName());
+ RecipeLogic.putFailureReason(holder, recipe, reason);
+ return 0;
+ }
+ minimum = Math.min(minimum, capParallel);
}
}
@@ -65,10 +75,24 @@ public static int getMaxByInput(IRecipeCapabilityHolder holder, GTRecipe recipe,
for (RecipeCapability> cap : recipe.tickInputs.keySet()) {
if (cap.doMatchInRecipe() && !capsToSkip.contains(cap)) {
// Find the maximum number of recipes that can be performed from the contents of the input inventories
- minimum = Math.min(minimum, cap.getMaxParallelByInput(holder, recipe, parallelLimit, true));
+ var capParallel = cap.getMaxParallelByInput(holder, recipe, parallelLimit, true);
+ if (capParallel == 0) {
+ Component reason = Component.translatable("gtceu.recipe_logic.insufficient_in")
+ .append(": ")
+ .append(cap.getName());
+ RecipeLogic.putFailureReason(holder, recipe, reason);
+ return 0;
+ }
+ minimum = Math.min(minimum, capParallel);
}
}
- if (minimum == Integer.MAX_VALUE) return 0;
+ if (minimum == Integer.MAX_VALUE) {
+ Component reason = Component.translatable("gtceu.recipe_logic.no_capabilities")
+ .append(Component.literal(": "))
+ .append(Component.translatable(IO.IN.tooltip));
+ RecipeLogic.putFailureReason(holder, recipe, reason);
+ return 0;
+ }
return minimum;
}
@@ -93,6 +117,10 @@ public static int limitByOutputMerging(IRecipeCapabilityHolder holder, GTRecipe
int limit = cap.limitMaxParallelByOutput(holder, recipe, parallelLimit, false);
// If we are not voiding, and cannot fit any items, return 0
if (limit == 0) {
+ Component reason = Component.translatable("gtceu.recipe_logic.insufficient_out")
+ .append(": ")
+ .append(cap.getName());
+ RecipeLogic.putFailureReason(holder, recipe, reason);
return 0;
}
max = Math.min(max, limit);
@@ -107,6 +135,10 @@ public static int limitByOutputMerging(IRecipeCapabilityHolder holder, GTRecipe
int limit = cap.limitMaxParallelByOutput(holder, recipe, parallelLimit, true);
// If we are not voiding, and cannot fit any items, return 0
if (limit == 0) {
+ Component reason = Component.translatable("gtceu.recipe_logic.insufficient_out")
+ .append(": ")
+ .append(cap.getName());
+ RecipeLogic.putFailureReason(holder, recipe, reason);
return 0;
}
max = Math.min(max, limit);
diff --git a/src/main/java/com/gregtechceu/gtceu/api/recipe/modifier/RecipeModifierList.java b/src/main/java/com/gregtechceu/gtceu/api/recipe/modifier/RecipeModifierList.java
index 020ce9e4f10..533b131e481 100644
--- a/src/main/java/com/gregtechceu/gtceu/api/recipe/modifier/RecipeModifierList.java
+++ b/src/main/java/com/gregtechceu/gtceu/api/recipe/modifier/RecipeModifierList.java
@@ -1,6 +1,7 @@
package com.gregtechceu.gtceu.api.recipe.modifier;
import com.gregtechceu.gtceu.api.machine.MetaMachine;
+import com.gregtechceu.gtceu.api.machine.trait.RecipeLogic;
import com.gregtechceu.gtceu.api.recipe.GTRecipe;
import lombok.Getter;
@@ -37,7 +38,10 @@ public RecipeModifierList(RecipeModifier... modifiers) {
for (RecipeModifier modifier : modifiers) {
var func = modifier.getModifier(machine, runningRecipe);
runningRecipe = func.apply(runningRecipe);
- if (runningRecipe == null) return ModifierFunction.NULL;
+ if (runningRecipe == null) {
+ RecipeLogic.putFailureReason(machine, recipe, func.getFailReason());
+ return ModifierFunction.NULL;
+ }
result = func.compose(result);
}
return result;
diff --git a/src/main/java/com/gregtechceu/gtceu/api/registry/registrate/GTBlockBuilder.java b/src/main/java/com/gregtechceu/gtceu/api/registry/registrate/GTBlockBuilder.java
index c1ba8744fb0..17dfee8d336 100644
--- a/src/main/java/com/gregtechceu/gtceu/api/registry/registrate/GTBlockBuilder.java
+++ b/src/main/java/com/gregtechceu/gtceu/api/registry/registrate/GTBlockBuilder.java
@@ -38,6 +38,10 @@ public GTBlockBuilder exBlockstate(NonNullBiConsumer cons.accept(ctx, (GTBlockstateProvider) prov));
}
+ public GTBlockBuilder gtBlockstate(NonNullBiConsumer, GTBlockstateProvider> cons) {
+ return setData(ProviderType.BLOCKSTATE, (ctx, prov) -> cons.accept(ctx, (GTBlockstateProvider) prov));
+ }
+
// region default overrides
@Override
@@ -122,6 +126,11 @@ public GTBlockBuilder setDataGeneric(Provid
return this;
}
+ @Override
+ public GTBlockBuilder setData(ProviderType extends D> type, NonNullBiConsumer, D> cons) {
+ return (GTBlockBuilder) super.setData(type, cons);
+ }
+
// spotless:on
// endregion
}
diff --git a/src/main/java/com/gregtechceu/gtceu/api/registry/registrate/MachineBuilder.java b/src/main/java/com/gregtechceu/gtceu/api/registry/registrate/MachineBuilder.java
index e4c212484d6..c1b59704aa3 100644
--- a/src/main/java/com/gregtechceu/gtceu/api/registry/registrate/MachineBuilder.java
+++ b/src/main/java/com/gregtechceu/gtceu/api/registry/registrate/MachineBuilder.java
@@ -27,6 +27,7 @@
import com.gregtechceu.gtceu.common.data.models.GTMachineModels;
import com.gregtechceu.gtceu.config.ConfigHolder;
import com.gregtechceu.gtceu.data.model.builder.MachineModelBuilder;
+import com.gregtechceu.gtceu.utils.data.RuntimeBlockstateProvider;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.client.renderer.RenderType;
@@ -74,7 +75,6 @@
import javax.annotation.ParametersAreNonnullByDefault;
import static com.gregtechceu.gtceu.common.data.models.GTMachineModels.*;
-import static com.gregtechceu.gtceu.integration.kjs.GregTechKubeJSPlugin.RUNTIME_BLOCKSTATE_PROVIDER;
@SuppressWarnings("unused")
@ParametersAreNonnullByDefault
@@ -804,9 +804,10 @@ public static void generateAssetJsons(@Nullable As
// Fake a data provider for the GT model builders
var context = new DataGenContext<>(definition::getBlock, definition.getName(), id);
if (builder.blockModel() != null) {
- builder.blockModel().accept(context, RUNTIME_BLOCKSTATE_PROVIDER);
+ builder.blockModel().accept(context, RuntimeBlockstateProvider.INSTANCE);
} else {
- GTMachineModels.createMachineModel(builder.model()).accept(context, RUNTIME_BLOCKSTATE_PROVIDER);
+ GTMachineModels.createMachineModel(builder.model())
+ .accept(context, RuntimeBlockstateProvider.INSTANCE);
}
} else {
generator.itemModel(id, gen -> gen.parent(id.withPrefix("block/machine/").toString()));
diff --git a/src/main/java/com/gregtechceu/gtceu/api/registry/registrate/provider/GTBlockstateProvider.java b/src/main/java/com/gregtechceu/gtceu/api/registry/registrate/provider/GTBlockstateProvider.java
index 40bf8542286..6b7789b5159 100644
--- a/src/main/java/com/gregtechceu/gtceu/api/registry/registrate/provider/GTBlockstateProvider.java
+++ b/src/main/java/com/gregtechceu/gtceu/api/registry/registrate/provider/GTBlockstateProvider.java
@@ -78,14 +78,17 @@ public MultiVariantGenerator multiVariantGenerator(Block block) {
public MultiVariantGenerator multiVariantGenerator(Block block, Variant baseVariant) {
var multiVariant = MultiVariantGenerator.multiVariant(block, baseVariant);
- registeredBlocks.put(block, new BlockStateGeneratorWrapper(multiVariant));
- return multiVariant;
+ return addVanillaGenerator(block, multiVariant);
}
public MultiPartGenerator multiPartGenerator(Block block) {
var multiPart = MultiPartGenerator.multiPart(block);
- registeredBlocks.put(block, new BlockStateGeneratorWrapper(multiPart));
- return multiPart;
+ return addVanillaGenerator(block, multiPart);
+ }
+
+ public T addVanillaGenerator(Block block, T generator) {
+ registeredBlocks.put(block, new BlockStateGeneratorWrapper(generator));
+ return generator;
}
public static @Nullable PropertyDispatch createFacingDispatch(MachineDefinition definition) {
diff --git a/src/main/java/com/gregtechceu/gtceu/api/sync_system/data_transformers/gtceu/MonitorGroupTransformer.java b/src/main/java/com/gregtechceu/gtceu/api/sync_system/data_transformers/gtceu/MonitorGroupTransformer.java
index 57e1e770937..0f49c89c9ab 100644
--- a/src/main/java/com/gregtechceu/gtceu/api/sync_system/data_transformers/gtceu/MonitorGroupTransformer.java
+++ b/src/main/java/com/gregtechceu/gtceu/api/sync_system/data_transformers/gtceu/MonitorGroupTransformer.java
@@ -16,7 +16,7 @@ public CompoundTag serializeNBT(MonitorGroup value, ValueTransformer.Transformer
CompoundTag tag = new CompoundTag();
tag.putString("name", value.getName());
ListTag list = new ListTag();
- value.getRelativePositions().forEach(pos -> list.add(NbtUtils.writeBlockPos(pos)));
+ value.getMonitorPositions().forEach(pos -> list.add(NbtUtils.writeBlockPos(pos)));
if (value.getTargetRaw() != null) {
tag.put("targetPos", NbtUtils.writeBlockPos(value.getTargetRaw()));
if (value.getTargetCoverSide() != null) {
diff --git a/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java b/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java
index 0f3b72535e4..c4bc0f934da 100644
--- a/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java
+++ b/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java
@@ -13,10 +13,18 @@
import com.gregtechceu.gtceu.api.item.QuantumTankMachineItem;
import com.gregtechceu.gtceu.client.model.item.FacadeUnbakedModel;
import com.gregtechceu.gtceu.client.model.machine.MachineModelLoader;
+import com.gregtechceu.gtceu.client.model.pipe.PipeModel;
+import com.gregtechceu.gtceu.client.model.pipe.PipeModelLoader;
import com.gregtechceu.gtceu.client.particle.HazardParticle;
import com.gregtechceu.gtceu.client.particle.MufflerParticle;
+import com.gregtechceu.gtceu.client.renderer.block.MaterialBlockRenderer;
+import com.gregtechceu.gtceu.client.renderer.block.OreBlockRenderer;
+import com.gregtechceu.gtceu.client.renderer.block.SurfaceRockRenderer;
import com.gregtechceu.gtceu.client.renderer.entity.GTBoatRenderer;
import com.gregtechceu.gtceu.client.renderer.entity.GTExplosiveRenderer;
+import com.gregtechceu.gtceu.client.renderer.item.ArmorItemRenderer;
+import com.gregtechceu.gtceu.client.renderer.item.TagPrefixItemRenderer;
+import com.gregtechceu.gtceu.client.renderer.item.ToolItemRenderer;
import com.gregtechceu.gtceu.client.renderer.item.decorator.GTComponentItemDecorator;
import com.gregtechceu.gtceu.client.renderer.item.decorator.GTLampItemOverlayRenderer;
import com.gregtechceu.gtceu.client.renderer.item.decorator.GTTankItemFluidPreview;
@@ -27,17 +35,23 @@
import com.gregtechceu.gtceu.common.CommonProxy;
import com.gregtechceu.gtceu.common.data.GTBlockEntities;
import com.gregtechceu.gtceu.common.data.GTEntityTypes;
+import com.gregtechceu.gtceu.common.data.GTMaterialBlocks;
import com.gregtechceu.gtceu.common.data.GTParticleTypes;
+import com.gregtechceu.gtceu.common.data.models.GTModels;
import com.gregtechceu.gtceu.common.entity.GTBoat;
import com.gregtechceu.gtceu.common.machine.owner.MachineOwner;
import com.gregtechceu.gtceu.config.ConfigHolder;
+import com.gregtechceu.gtceu.data.model.builder.PipeModelBuilder;
+import com.gregtechceu.gtceu.data.pack.event.RegisterDynamicResourcesEvent;
import com.gregtechceu.gtceu.forge.ForgeCommonEventListener;
+import com.gregtechceu.gtceu.integration.kjs.GregTechKubeJSPlugin;
import com.gregtechceu.gtceu.integration.map.ClientCacheManager;
import com.gregtechceu.gtceu.integration.map.cache.client.GTClientCache;
import com.gregtechceu.gtceu.integration.map.ftbchunks.FTBChunksPlugin;
import com.gregtechceu.gtceu.integration.map.layer.Layers;
import com.gregtechceu.gtceu.integration.map.layer.builtin.FluidRenderLayer;
import com.gregtechceu.gtceu.integration.map.layer.builtin.OreRenderLayer;
+import com.gregtechceu.gtceu.utils.data.RuntimeBlockstateProvider;
import com.gregtechceu.gtceu.utils.input.SyncedKeyMapping;
import net.minecraft.client.model.BoatModel;
@@ -49,6 +63,7 @@
import net.minecraft.world.item.Item;
import net.minecraftforge.client.ForgeHooksClient;
import net.minecraftforge.client.event.*;
+import net.minecraftforge.eventbus.api.EventPriority;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import net.minecraftforge.registries.ForgeRegistries;
@@ -158,6 +173,50 @@ public static void initializeDynamicRenders() {
@SubscribeEvent
public void onRegisterModelLoaders(ModelEvent.RegisterGeometryLoaders event) {
event.register(MachineModelLoader.ID.getPath(), MachineModelLoader.INSTANCE);
+ event.register(PipeModelLoader.ID.getPath(), PipeModelLoader.INSTANCE);
event.register("facade", FacadeUnbakedModel.Loader.INSTANCE);
}
+
+ @SubscribeEvent(priority = EventPriority.HIGHEST)
+ public void preRegisterDynamicAssets(RegisterDynamicResourcesEvent event) {
+ PipeModel.DYNAMIC_MODELS.clear();
+ }
+
+ @SubscribeEvent
+ public void registerDynamicAssets(RegisterDynamicResourcesEvent event) {
+ // regenerate all pipe models in case their textures changed
+ // cables may do this, others too if something's removed
+ for (var block : GTMaterialBlocks.CABLE_BLOCKS.values()) {
+ if (block == null) continue;
+ block.get().createPipeModel(RuntimeBlockstateProvider.INSTANCE).dynamicModel();
+ }
+ for (var block : GTMaterialBlocks.FLUID_PIPE_BLOCKS.values()) {
+ if (block == null) continue;
+ block.get().createPipeModel(RuntimeBlockstateProvider.INSTANCE).dynamicModel();
+ }
+ for (var block : GTMaterialBlocks.ITEM_PIPE_BLOCKS.values()) {
+ if (block == null) continue;
+ block.get().createPipeModel(RuntimeBlockstateProvider.INSTANCE).dynamicModel();
+ }
+
+ MaterialBlockRenderer.reinitModels();
+ TagPrefixItemRenderer.reinitModels();
+ OreBlockRenderer.reinitModels();
+ ToolItemRenderer.reinitModels();
+ ArmorItemRenderer.reinitModels();
+ SurfaceRockRenderer.reinitModels();
+ GTModels.registerMaterialFluidModels();
+ }
+
+ @SubscribeEvent(priority = EventPriority.LOWEST)
+ public void postRegisterDynamicAssets(RegisterDynamicResourcesEvent event) {
+ // do this last so addons can easily add new variants to the registered model set
+ PipeModel.initDynamicModels();
+
+ if (GTCEu.Mods.isKubeJSLoaded()) {
+ GregTechKubeJSPlugin.generateMachineBlockModels();
+ }
+ RuntimeBlockstateProvider.INSTANCE.run();
+ PipeModelBuilder.clearRestrictorModelCache();
+ }
}
diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/BaseBakedModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/BaseBakedModel.java
index f91a52c0b2a..484ee5656e2 100644
--- a/src/main/java/com/gregtechceu/gtceu/client/model/BaseBakedModel.java
+++ b/src/main/java/com/gregtechceu/gtceu/client/model/BaseBakedModel.java
@@ -9,8 +9,6 @@
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.client.model.IDynamicBakedModel;
-import org.jetbrains.annotations.NotNull;
-
public abstract class BaseBakedModel implements IDynamicBakedModel {
public BaseBakedModel() {}
@@ -37,13 +35,13 @@ public boolean isCustomRenderer() {
@Override
@OnlyIn(Dist.CLIENT)
- public @NotNull ItemOverrides getOverrides() {
+ public ItemOverrides getOverrides() {
return ItemOverrides.EMPTY;
}
@Override
@OnlyIn(Dist.CLIENT)
- public @NotNull TextureAtlasSprite getParticleIcon() {
+ public TextureAtlasSprite getParticleIcon() {
return Minecraft.getInstance().getTextureAtlas(InventoryMenu.BLOCK_ATLAS)
.apply(MissingTextureAtlasSprite.getLocation());
}
diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/GTModelProperties.java b/src/main/java/com/gregtechceu/gtceu/client/model/GTModelProperties.java
new file mode 100644
index 00000000000..547af6d647e
--- /dev/null
+++ b/src/main/java/com/gregtechceu/gtceu/client/model/GTModelProperties.java
@@ -0,0 +1,14 @@
+package com.gregtechceu.gtceu.client.model;
+
+import net.minecraft.core.BlockPos;
+import net.minecraft.world.level.BlockAndTintGetter;
+import net.minecraftforge.client.model.data.ModelProperty;
+
+public class GTModelProperties {
+
+ public static final ModelProperty LEVEL = new ModelProperty<>();
+ public static final ModelProperty POS = new ModelProperty<>();
+
+ public static final ModelProperty PIPE_CONNECTION_MASK = new ModelProperty<>();
+ public static final ModelProperty PIPE_BLOCKED_MASK = new ModelProperty<>();
+}
diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/IBlockEntityRendererBakedModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/IBlockEntityRendererBakedModel.java
index 6a59d976574..001442720cc 100644
--- a/src/main/java/com/gregtechceu/gtceu/client/model/IBlockEntityRendererBakedModel.java
+++ b/src/main/java/com/gregtechceu/gtceu/client/model/IBlockEntityRendererBakedModel.java
@@ -12,21 +12,21 @@
import net.minecraftforge.client.model.IDynamicBakedModel;
import com.mojang.blaze3d.vertex.PoseStack;
-import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
public interface IBlockEntityRendererBakedModel
extends IDynamicBakedModel, BlockEntityRenderer {
+ @Nullable
BlockEntityType extends T> getBlockEntityType();
- void render(@NotNull T blockEntity, float partialTick,
- @NotNull PoseStack poseStack, @NotNull MultiBufferSource buffer,
+ void render(T blockEntity, float partialTick, PoseStack poseStack, MultiBufferSource buffer,
int packedLight, int packedOverlay);
default void renderByItem(ItemStack stack, ItemDisplayContext displayContext,
PoseStack poseStack, MultiBufferSource buffer, int packedLight, int packedOverlay) {}
- default boolean shouldRender(T blockEntity, @NotNull Vec3 cameraPos) {
+ default boolean shouldRender(T blockEntity, Vec3 cameraPos) {
return Vec3.atCenterOf(blockEntity.getBlockPos()).closerThan(cameraPos, this.getViewDistance());
}
diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/PipeModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/PipeModel.java
deleted file mode 100644
index efdff6bb28b..00000000000
--- a/src/main/java/com/gregtechceu/gtceu/client/model/PipeModel.java
+++ /dev/null
@@ -1,357 +0,0 @@
-package com.gregtechceu.gtceu.client.model;
-
-import com.gregtechceu.gtceu.GTCEu;
-import com.gregtechceu.gtceu.api.blockentity.PipeBlockEntity;
-import com.gregtechceu.gtceu.client.util.ModelUtils;
-import com.gregtechceu.gtceu.common.data.models.GTModels;
-import com.gregtechceu.gtceu.utils.GTUtil;
-import com.gregtechceu.gtceu.utils.memoization.GTMemoizer;
-import com.gregtechceu.gtceu.utils.memoization.MemoizedSupplier;
-
-import com.lowdragmc.lowdraglib.client.bakedpipeline.FaceQuad;
-import com.lowdragmc.lowdraglib.client.renderer.IItemRendererProvider;
-
-import net.minecraft.Util;
-import net.minecraft.client.Minecraft;
-import net.minecraft.client.renderer.MultiBufferSource;
-import net.minecraft.client.renderer.block.model.BakedQuad;
-import net.minecraft.client.renderer.texture.TextureAtlas;
-import net.minecraft.client.renderer.texture.TextureAtlasSprite;
-import net.minecraft.client.resources.model.BakedModel;
-import net.minecraft.core.Direction;
-import net.minecraft.resources.ResourceLocation;
-import net.minecraft.world.inventory.InventoryMenu;
-import net.minecraft.world.item.ItemDisplayContext;
-import net.minecraft.world.item.ItemStack;
-import net.minecraft.world.phys.AABB;
-import net.minecraft.world.phys.shapes.Shapes;
-import net.minecraft.world.phys.shapes.VoxelShape;
-import net.minecraftforge.api.distmarker.Dist;
-import net.minecraftforge.api.distmarker.OnlyIn;
-
-import com.mojang.blaze3d.vertex.PoseStack;
-import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
-import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
-import lombok.Setter;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.function.Consumer;
-import java.util.function.Function;
-import java.util.function.Supplier;
-
-public class PipeModel {
-
- public static final ResourceLocation PIPE_BLOCKED_OVERLAY = GTCEu.id("block/pipe/blocked/pipe_blocked");
- public static final ResourceLocation PIPE_BLOCKED_OVERLAY_UP = GTCEu.id("block/pipe/blocked/pipe_blocked_up");
- public static final ResourceLocation PIPE_BLOCKED_OVERLAY_DOWN = GTCEu.id("block/pipe/blocked/pipe_blocked_down");
- public static final ResourceLocation PIPE_BLOCKED_OVERLAY_LEFT = GTCEu.id("block/pipe/blocked/pipe_blocked_left");
- public static final ResourceLocation PIPE_BLOCKED_OVERLAY_RIGHT = GTCEu.id("block/pipe/blocked/pipe_blocked_right");
- public static final ResourceLocation PIPE_BLOCKED_OVERLAY_NU = GTCEu.id("block/pipe/blocked/pipe_blocked_nu");
- public static final ResourceLocation PIPE_BLOCKED_OVERLAY_ND = GTCEu.id("block/pipe/blocked/pipe_blocked_nd");
- public static final ResourceLocation PIPE_BLOCKED_OVERLAY_NL = GTCEu.id("block/pipe/blocked/pipe_blocked_nl");
- public static final ResourceLocation PIPE_BLOCKED_OVERLAY_NR = GTCEu.id("block/pipe/blocked/pipe_blocked_nr");
- public static final ResourceLocation PIPE_BLOCKED_OVERLAY_UD = GTCEu.id("block/pipe/blocked/pipe_blocked_ud");
- public static final ResourceLocation PIPE_BLOCKED_OVERLAY_UL = GTCEu.id("block/pipe/blocked/pipe_blocked_ul");
- public static final ResourceLocation PIPE_BLOCKED_OVERLAY_UR = GTCEu.id("block/pipe/blocked/pipe_blocked_ur");
- public static final ResourceLocation PIPE_BLOCKED_OVERLAY_DL = GTCEu.id("block/pipe/blocked/pipe_blocked_dl");
- public static final ResourceLocation PIPE_BLOCKED_OVERLAY_DR = GTCEu.id("block/pipe/blocked/pipe_blocked_dr");
- public static final ResourceLocation PIPE_BLOCKED_OVERLAY_LR = GTCEu.id("block/pipe/blocked/pipe_blocked_lr");
- private static final Int2ObjectMap RESTRICTOR_MAP = new Int2ObjectOpenHashMap<>();
- private static boolean isRestrictorInitialized;
-
- protected static void initializeRestrictor(Function atlas) {
- addRestrictor(atlas.apply(PIPE_BLOCKED_OVERLAY_UP), Border.TOP);
- addRestrictor(atlas.apply(PIPE_BLOCKED_OVERLAY_DOWN), Border.BOTTOM);
- addRestrictor(atlas.apply(PIPE_BLOCKED_OVERLAY_UD), Border.TOP, Border.BOTTOM);
- addRestrictor(atlas.apply(PIPE_BLOCKED_OVERLAY_LEFT), Border.LEFT);
- addRestrictor(atlas.apply(PIPE_BLOCKED_OVERLAY_UL), Border.TOP, Border.LEFT);
- addRestrictor(atlas.apply(PIPE_BLOCKED_OVERLAY_DL), Border.BOTTOM, Border.LEFT);
- addRestrictor(atlas.apply(PIPE_BLOCKED_OVERLAY_NR), Border.TOP, Border.BOTTOM, Border.LEFT);
- addRestrictor(atlas.apply(PIPE_BLOCKED_OVERLAY_RIGHT), Border.RIGHT);
- addRestrictor(atlas.apply(PIPE_BLOCKED_OVERLAY_UR), Border.TOP, Border.RIGHT);
- addRestrictor(atlas.apply(PIPE_BLOCKED_OVERLAY_DR), Border.BOTTOM, Border.RIGHT);
- addRestrictor(atlas.apply(PIPE_BLOCKED_OVERLAY_NL), Border.TOP, Border.BOTTOM, Border.RIGHT);
- addRestrictor(atlas.apply(PIPE_BLOCKED_OVERLAY_LR), Border.LEFT, Border.RIGHT);
- addRestrictor(atlas.apply(PIPE_BLOCKED_OVERLAY_ND), Border.TOP, Border.LEFT, Border.RIGHT);
- addRestrictor(atlas.apply(PIPE_BLOCKED_OVERLAY_NU), Border.BOTTOM, Border.LEFT, Border.RIGHT);
- addRestrictor(atlas.apply(PIPE_BLOCKED_OVERLAY), Border.TOP, Border.BOTTOM, Border.LEFT, Border.RIGHT);
- }
-
- private static final EnumMap> FACE_BORDER_MAP = Util.make(() -> {
- EnumMap> map = new EnumMap<>(Direction.class);
-
- map.put(Direction.DOWN, borderMap(Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST));
- map.put(Direction.UP, borderMap(Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST));
- map.put(Direction.NORTH, borderMap(Direction.DOWN, Direction.UP, Direction.WEST, Direction.EAST));
- map.put(Direction.SOUTH, borderMap(Direction.DOWN, Direction.UP, Direction.WEST, Direction.EAST));
- map.put(Direction.WEST, borderMap(Direction.DOWN, Direction.UP, Direction.NORTH, Direction.SOUTH));
- map.put(Direction.EAST, borderMap(Direction.DOWN, Direction.UP, Direction.NORTH, Direction.SOUTH));
-
- return map;
- });
-
- public final static int ITEM_CONNECTIONS = 0b001100;
- public final float thickness;
- public final AABB coreCube;
- public final Map sideCubes;
-
- public MemoizedSupplier sideTexture, endTexture;
- @Nullable
- public MemoizedSupplier secondarySideTexture, secondaryEndTexture;
- @Setter
- public @Nullable ResourceLocation sideOverlayTexture, endOverlayTexture;
-
- @OnlyIn(Dist.CLIENT)
- private @Nullable TextureAtlasSprite sideSprite, endSprite;
- @OnlyIn(Dist.CLIENT)
- private @Nullable TextureAtlasSprite secondarySideSprite, secondaryEndSprite;
- @OnlyIn(Dist.CLIENT)
- private @Nullable TextureAtlasSprite sideOverlaySprite, endOverlaySprite;
-
- public PipeModel(float thickness, Supplier sideTexture, Supplier endTexture,
- @Nullable Supplier secondarySideTexture,
- @Nullable Supplier secondaryEndTexture) {
- this.sideTexture = GTMemoizer.memoize(sideTexture);
- this.endTexture = GTMemoizer.memoize(endTexture);
- this.secondarySideTexture = secondarySideTexture != null ? GTMemoizer.memoize(secondarySideTexture) :
- null;
- this.secondaryEndTexture = secondaryEndTexture != null ? GTMemoizer.memoize(secondaryEndTexture) : null;
- this.thickness = thickness;
- double min = (1d - thickness) / 2;
- double max = min + thickness;
- this.coreCube = new AABB(min, min, min, max, max, max);
- this.sideCubes = new EnumMap<>(Direction.class);
- for (Direction side : GTUtil.DIRECTIONS) {
- var normal = side.getNormal();
- sideCubes.put(side, new AABB(
- normal.getX() == 0 ? min : normal.getX() > 0 ? max : 0,
- normal.getY() == 0 ? min : normal.getY() > 0 ? max : 0,
- normal.getZ() == 0 ? min : normal.getZ() > 0 ? max : 0,
- normal.getX() == 0 ? max : normal.getX() > 0 ? 1 : min,
- normal.getY() == 0 ? max : normal.getY() > 0 ? 1 : min,
- normal.getZ() == 0 ? max : normal.getZ() > 0 ? 1 : min));
- }
-
- if (!isRestrictorInitialized) {
- ModelUtils.registerAtlasStitchedEventListener(false, InventoryMenu.BLOCK_ATLAS, event -> {
- initializeRestrictor(event.getAtlas()::getSprite);
- });
-
- isRestrictorInitialized = true;
- }
- ModelUtils.registerAtlasStitchedEventListener(false, InventoryMenu.BLOCK_ATLAS, event -> {
- TextureAtlas atlas = event.getAtlas();
-
- sideSprite = atlas.getSprite(sideTexture.get());
- endSprite = atlas.getSprite(endTexture.get());
- if (secondarySideTexture != null) {
- secondarySideSprite = atlas.getSprite(secondarySideTexture.get());
- }
- if (secondaryEndTexture != null) {
- secondaryEndSprite = atlas.getSprite(secondaryEndTexture.get());
- }
- if (sideOverlayTexture != null) {
- sideOverlaySprite = atlas.getSprite(sideOverlayTexture);
- }
- if (endOverlayTexture != null) {
- endOverlaySprite = atlas.getSprite(endOverlayTexture);
- }
- });
- }
-
- public VoxelShape getShapes(int connections) {
- var shapes = new ArrayList(7);
- shapes.add(Shapes.create(coreCube));
- for (Direction side : GTUtil.DIRECTIONS) {
- if (PipeBlockEntity.isConnected(connections, side)) {
- shapes.add(Shapes.create(sideCubes.get(side)));
- }
- }
- return shapes.stream().reduce(Shapes.empty(), Shapes::or);
- }
-
- @OnlyIn(Dist.CLIENT)
- public List bakeQuads(@Nullable Direction side, int connections, int blockedConnections) {
- if (side != null) {
- if (thickness == 1) { // full block
- List quads = new LinkedList<>();
- quads.add(FaceQuad.builder(side, sideSprite).cube(coreCube).cubeUV().tintIndex(0).bake());
- if (secondarySideSprite != null) {
- quads.add(FaceQuad.builder(side, secondarySideSprite).cube(coreCube).cubeUV().tintIndex(0).bake());
- }
- return quads;
- }
-
- if (PipeBlockEntity.isConnected(connections, side)) { // side connected
- List quads = new LinkedList<>();
- quads.add(FaceQuad.builder(side, endSprite).cube(sideCubes.get(side).inflate(-0.001)).cubeUV()
- .tintIndex(1).bake());
- if (secondaryEndSprite != null) {
- quads.add(FaceQuad.builder(side, secondaryEndSprite).cube(sideCubes.get(side)).cubeUV().tintIndex(1)
- .bake());
- }
- if (endOverlaySprite != null) {
- quads.add(FaceQuad.builder(side, endOverlaySprite).cube(sideCubes.get(side)).cubeUV().tintIndex(0)
- .bake());
- }
- if (sideOverlaySprite != null) {
- for (Direction face : GTUtil.DIRECTIONS) {
- if (face.getAxis() != side.getAxis()) {
- quads.add(FaceQuad.builder(face, sideOverlaySprite).cube(sideCubes.get(side)).cubeUV()
- .tintIndex(2).bake());
- }
- }
- }
- int borderMask = computeBorderMask(blockedConnections, connections, side);
- if (borderMask != 0) {
- quads.add(FaceQuad.builder(side, RESTRICTOR_MAP.get(borderMask)).cube(sideCubes.get(side)).cubeUV()
- .bake());
- }
- return quads;
- }
-
- return Collections.emptyList();
- }
-
- List quads = new LinkedList<>();
- if (thickness < 1) { // non full block
- // render core cube
- for (Direction face : GTUtil.DIRECTIONS) {
- if (!PipeBlockEntity.isConnected(connections, face)) {
- quads.add(FaceQuad.builder(face, sideSprite).cube(coreCube).cubeUV().tintIndex(0).bake());
- if (secondarySideSprite != null) {
- quads.add(FaceQuad.builder(face, secondarySideSprite).cube(coreCube).cubeUV().tintIndex(0)
- .bake());
- }
- }
- // render each connected side
- for (Direction facing : GTUtil.DIRECTIONS) {
- if (facing.getAxis() != face.getAxis()) {
- if (PipeBlockEntity.isConnected(connections, facing)) {
- quads.add(FaceQuad.builder(face, sideSprite).cube(sideCubes.get(facing)).cubeUV()
- .tintIndex(0).bake());
- if (secondarySideSprite != null) {
- quads.add(FaceQuad.builder(face, secondarySideSprite).cube(sideCubes.get(facing))
- .cubeUV().tintIndex(0).bake());
- }
- if (sideOverlaySprite != null) {
- quads.add(FaceQuad.builder(face, sideOverlaySprite)
- .cube(sideCubes.get(facing).inflate(0.001)).cubeUV().tintIndex(2).bake());
- }
- int borderMask = computeBorderMask(blockedConnections, connections, face);
- if (borderMask != 0) {
- quads.add(FaceQuad.builder(face, RESTRICTOR_MAP.get(borderMask))
- .cube(coreCube).cubeUV().bake());
- quads.add(FaceQuad.builder(face, RESTRICTOR_MAP.get(borderMask))
- .cube(sideCubes.get(facing)).cubeUV().bake());
- }
- }
- }
- }
- }
- }
- return quads;
- }
-
- @SuppressWarnings("DataFlowIssue")
- @OnlyIn(Dist.CLIENT)
- public @NotNull TextureAtlasSprite getParticleTexture() {
- return sideSprite;
- }
-
- private final Map, List> itemModelCache = new ConcurrentHashMap<>();
-
- @OnlyIn(Dist.CLIENT)
- public void renderItem(ItemStack stack, ItemDisplayContext transformType, boolean leftHand, PoseStack matrixStack,
- MultiBufferSource buffer, int combinedLight, int combinedOverlay, BakedModel model) {
- IItemRendererProvider.disabled.set(true);
- Minecraft.getInstance().getItemRenderer().render(stack, transformType, leftHand, matrixStack, buffer,
- combinedLight, combinedOverlay,
- (ItemBakedModel) (state, direction, random) -> itemModelCache.computeIfAbsent(
- Optional.ofNullable(direction),
- direction1 -> bakeQuads(direction1.orElse(null), ITEM_CONNECTIONS, 0)));
- IItemRendererProvider.disabled.set(false);
- }
-
- @OnlyIn(Dist.CLIENT)
- public void registerTextureAtlas(Consumer register) {
- itemModelCache.clear();
- sideTexture.invalidate();
- register.accept(sideTexture.get());
- endTexture.invalidate();
- register.accept(endTexture.get());
- if (secondarySideTexture != null) {
- secondarySideTexture.invalidate();
- if (secondarySideTexture.get() != GTModels.BLANK_TEXTURE) {
- register.accept(secondarySideTexture.get());
- }
- }
- if (secondaryEndTexture != null) {
- secondaryEndTexture.invalidate();
- if (secondaryEndTexture.get() != GTModels.BLANK_TEXTURE) {
- register.accept(secondaryEndTexture.get());
- }
- }
- if (sideOverlayTexture != null) register.accept(sideOverlayTexture);
- if (endOverlayTexture != null) register.accept(endOverlayTexture);
- sideSprite = null;
- endSprite = null;
- endOverlaySprite = null;
- }
-
- private static EnumMap borderMap(Direction topSide, Direction bottomSide, Direction leftSide,
- Direction rightSide) {
- EnumMap sideMap = new EnumMap<>(Border.class);
- sideMap.put(Border.TOP, topSide);
- sideMap.put(Border.BOTTOM, bottomSide);
- sideMap.put(Border.LEFT, leftSide);
- sideMap.put(Border.RIGHT, rightSide);
- return sideMap;
- }
-
- private static void addRestrictor(TextureAtlasSprite sprite, Border... borders) {
- int mask = 0;
- for (Border border : borders) {
- mask |= border.mask;
- }
- RESTRICTOR_MAP.put(mask, sprite);
- }
-
- protected static Direction getSideAtBorder(Direction side, Border border) {
- return FACE_BORDER_MAP.get(side).get(border);
- }
-
- protected static int computeBorderMask(int blockedConnections, int connections, Direction side) {
- int borderMask = 0;
- if (blockedConnections != 0) {
- for (Border border : Border.VALUES) {
- Direction borderSide = getSideAtBorder(side, border);
- if (PipeBlockEntity.isFaceBlocked(blockedConnections, borderSide) &&
- PipeBlockEntity.isConnected(connections, borderSide)) {
- // only render when the side is blocked *and* connected
- borderMask |= border.mask;
- }
- }
- }
- return borderMask;
- }
-
- public enum Border {
-
- TOP,
- BOTTOM,
- LEFT,
- RIGHT;
-
- public static final Border[] VALUES = values();
-
- public final int mask;
-
- Border() {
- mask = 1 << this.ordinal();
- }
- }
-}
diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java
index c09820be6fe..701a0fd1130 100644
--- a/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java
+++ b/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModel.java
@@ -7,6 +7,7 @@
import com.gregtechceu.gtceu.api.machine.multiblock.MultiblockControllerMachine;
import com.gregtechceu.gtceu.api.machine.trait.AutoOutputTrait;
import com.gregtechceu.gtceu.client.model.BaseBakedModel;
+import com.gregtechceu.gtceu.client.model.GTModelProperties;
import com.gregtechceu.gtceu.client.model.IBlockEntityRendererBakedModel;
import com.gregtechceu.gtceu.client.model.TextureOverrideModel;
import com.gregtechceu.gtceu.client.model.machine.multipart.MultiPartBakedModel;
@@ -50,7 +51,6 @@
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
-import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
@@ -136,7 +136,7 @@ public static void initSprites(TextureAtlas atlas) {
@SuppressWarnings("deprecation")
@Override
- public @NotNull TextureAtlasSprite getParticleIcon() {
+ public TextureAtlasSprite getParticleIcon() {
if (particleIcon != null) {
return particleIcon;
} else if (multiPart != null) {
@@ -150,9 +150,9 @@ public static void initSprites(TextureAtlas atlas) {
}
@Override
- public TextureAtlasSprite getParticleIcon(@NotNull ModelData modelData) {
- BlockAndTintGetter level = modelData.get(MODEL_DATA_LEVEL);
- BlockPos pos = modelData.get(MODEL_DATA_POS);
+ public TextureAtlasSprite getParticleIcon(ModelData modelData) {
+ BlockAndTintGetter level = modelData.get(GTModelProperties.LEVEL);
+ BlockPos pos = modelData.get(GTModelProperties.POS);
MetaMachine machine = (level == null || pos == null) ? null : MetaMachine.getMachine(level, pos);
MachineRenderState renderState = machine != null ? machine.getRenderState() :
@@ -169,11 +169,11 @@ public TextureAtlasSprite getParticleIcon(@NotNull ModelData modelData) {
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
- public @NotNull ModelData getModelData(@NotNull BlockAndTintGetter level, @NotNull BlockPos pos,
- @NotNull BlockState state, @NotNull ModelData modelData) {
+ public ModelData getModelData(BlockAndTintGetter level, BlockPos pos,
+ BlockState state, ModelData modelData) {
ModelData.Builder builder = modelData.derive()
- .with(MODEL_DATA_LEVEL, level)
- .with(MODEL_DATA_POS, pos);
+ .with(GTModelProperties.LEVEL, level)
+ .with(GTModelProperties.POS, pos);
MetaMachine machine = MetaMachine.getMachine(level, pos);
MachineRenderState renderState = machine == null ? definition.defaultRenderState() : machine.getRenderState();
@@ -191,9 +191,9 @@ public TextureAtlasSprite getParticleIcon(@NotNull ModelData modelData) {
}
@Override
- public @NotNull List getQuads(@Nullable BlockState state, @Nullable Direction side,
- @NotNull RandomSource rand,
- @NotNull ModelData modelData, @Nullable RenderType renderType) {
+ public List getQuads(@Nullable BlockState state, @Nullable Direction side,
+ RandomSource rand,
+ ModelData modelData, @Nullable RenderType renderType) {
// If there is a root transform, undo the ModelState transform, apply it,
// then re-apply the ModelState transform.
// This is necessary because of things like UV locking, which should only respond to the ModelState,
@@ -204,7 +204,7 @@ public TextureAtlasSprite getParticleIcon(@NotNull ModelData modelData) {
}
List quads;
- if (modelData.has(MODEL_DATA_LEVEL) && modelData.has(MODEL_DATA_POS)) {
+ if (modelData.has(GTModelProperties.LEVEL) && modelData.has(GTModelProperties.POS)) {
quads = getMachineQuads(state, side, rand, modelData, renderType);
} else {
// if it doesn't have either of those properties, we're rendering an item.
@@ -215,10 +215,10 @@ public TextureAtlasSprite getParticleIcon(@NotNull ModelData modelData) {
}
public List getMachineQuads(@Nullable BlockState blockState, @Nullable Direction side,
- @NotNull RandomSource rand, @NotNull ModelData modelData,
+ RandomSource rand, ModelData modelData,
@Nullable RenderType renderType) {
- BlockAndTintGetter level = modelData.get(MODEL_DATA_LEVEL);
- BlockPos pos = modelData.get(MODEL_DATA_POS);
+ BlockAndTintGetter level = modelData.get(GTModelProperties.LEVEL);
+ BlockPos pos = modelData.get(GTModelProperties.POS);
MetaMachine machine = (level == null || pos == null) ? null : MetaMachine.getMachine(level, pos);
// render machine quads
@@ -260,7 +260,7 @@ public List getMachineQuads(@Nullable BlockState blockState, @Nullabl
public List renderMachine(@Nullable MetaMachine machine, @Nullable BlockAndTintGetter level,
@Nullable BlockPos pos, @Nullable BlockState blockState,
@Nullable Direction side, RandomSource rand,
- @NotNull ModelData modelData, @Nullable RenderType renderType) {
+ ModelData modelData, @Nullable RenderType renderType) {
List quads = new LinkedList<>();
MachineRenderState renderState = machine != null ? machine.getRenderState() : definition.defaultRenderState();
@@ -282,9 +282,9 @@ public List renderMachine(@Nullable MetaMachine machine, @Nullable Bl
return quads;
}
- public void renderBaseModel(List quads, @NotNull MachineRenderState renderState,
+ public void renderBaseModel(List quads, MachineRenderState renderState,
@Nullable BlockState blockState, @Nullable Direction side, RandomSource rand,
- @NotNull ModelData modelData, @Nullable RenderType renderType) {
+ ModelData modelData, @Nullable RenderType renderType) {
if (multiPart != null) {
quads.addAll(multiPart.getMachineQuads(definition, renderState, blockState,
side, rand, modelData, renderType));
@@ -299,7 +299,7 @@ public List replacePartBaseModel(List originalQuads, IMult
ModelData modelData, @Nullable RenderType renderType) {
var controllers = part.getControllers();
for (MultiblockControllerMachine controller : controllers) {
- var state = controller.self().getBlockState();
+ var state = controller.getBlockState();
BakedModel model = Minecraft.getInstance().getBlockRenderer().getBlockModel(state);
List newQuads = null;
@@ -386,8 +386,8 @@ public boolean isCustomRenderer() {
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
- public void render(@NotNull BlockEntity blockEntity, float partialTick,
- @NotNull PoseStack poseStack, @NotNull MultiBufferSource buffer,
+ public void render(BlockEntity blockEntity, float partialTick,
+ PoseStack poseStack, MultiBufferSource buffer,
int packedLight, int packedOverlay) {
if (!(blockEntity instanceof MetaMachine machine)) return;
if (machine.getDefinition() != getDefinition()) return;
@@ -445,7 +445,7 @@ public boolean shouldRenderOffScreen(BlockEntity blockEntity) {
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
- public boolean shouldRender(BlockEntity blockEntity, @NotNull Vec3 cameraPos) {
+ public boolean shouldRender(BlockEntity blockEntity, Vec3 cameraPos) {
if (!(blockEntity instanceof MetaMachine machine)) return false;
if (machine.getDefinition() != getDefinition()) return false;
if (machine.getCoverContainer().hasDynamicCovers()) return true;
diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModelLoader.java b/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModelLoader.java
index 934b511a0ea..9dc6e3e532a 100644
--- a/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModelLoader.java
+++ b/src/main/java/com/gregtechceu/gtceu/client/model/machine/MachineModelLoader.java
@@ -63,7 +63,7 @@ public class MachineModelLoader implements IGeometryLoader
private static final Splitter COMMA_SPLITTER = Splitter.on(',');
private static final Splitter EQUAL_SPLITTER = Splitter.on('=').limit(2);
- private static final UnbakedModel MISSING_MARKER = new BasicUnbakedModel();
+ public static final UnbakedModel MISSING_MARKER = new BasicUnbakedModel();
private MachineModelLoader() {}
diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/machine/multipart/MultiPartBakedModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/machine/multipart/MultiPartBakedModel.java
index 07d643cfa62..90b49b40e5e 100644
--- a/src/main/java/com/gregtechceu/gtceu/client/model/machine/multipart/MultiPartBakedModel.java
+++ b/src/main/java/com/gregtechceu/gtceu/client/model/machine/multipart/MultiPartBakedModel.java
@@ -2,6 +2,7 @@
import com.gregtechceu.gtceu.api.machine.MachineDefinition;
import com.gregtechceu.gtceu.api.machine.MetaMachine;
+import com.gregtechceu.gtceu.client.model.GTModelProperties;
import com.gregtechceu.gtceu.client.model.machine.MachineRenderState;
import net.minecraft.Util;
@@ -115,8 +116,8 @@ public List getMachineQuads(MachineDefinition definition, MachineRend
@Override
public ChunkRenderTypeSet getRenderTypes(BlockState state, RandomSource rand, ModelData modelData) {
- BlockAndTintGetter level = modelData.get(MODEL_DATA_LEVEL);
- BlockPos pos = modelData.get(MODEL_DATA_POS);
+ BlockAndTintGetter level = modelData.get(GTModelProperties.LEVEL);
+ BlockPos pos = modelData.get(GTModelProperties.POS);
var machine = (level == null || pos == null) ? null : MetaMachine.getMachine(level, pos);
if (machine == null) return IDynamicBakedModel.super.getRenderTypes(state, rand, modelData);
@@ -137,8 +138,8 @@ public ChunkRenderTypeSet getRenderTypes(BlockState state, RandomSource rand, Mo
@Override
public ModelData getModelData(BlockAndTintGetter level, BlockPos pos, BlockState state, ModelData modelData) {
ModelData.Builder builder = modelData.derive()
- .with(MODEL_DATA_LEVEL, level)
- .with(MODEL_DATA_POS, pos);
+ .with(GTModelProperties.LEVEL, level)
+ .with(GTModelProperties.POS, pos);
var machine = MetaMachine.getMachine(level, pos);
if (machine == null) return builder.build();
@@ -183,8 +184,8 @@ public boolean isCustomRenderer() {
@Override
public TextureAtlasSprite getParticleIcon(ModelData modelData) {
- BlockAndTintGetter level = modelData.get(MODEL_DATA_LEVEL);
- BlockPos pos = modelData.get(MODEL_DATA_POS);
+ BlockAndTintGetter level = modelData.get(GTModelProperties.LEVEL);
+ BlockPos pos = modelData.get(GTModelProperties.POS);
var machine = (level == null || pos == null) ? null : MetaMachine.getMachine(level, pos);
if (machine != null) return getParticleIcon(machine.getRenderState(), modelData);
diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/machine/overlays/HPCAOverlay.java b/src/main/java/com/gregtechceu/gtceu/client/model/machine/overlays/HPCAOverlay.java
index 3ea09f9003c..ed8de15bb92 100644
--- a/src/main/java/com/gregtechceu/gtceu/client/model/machine/overlays/HPCAOverlay.java
+++ b/src/main/java/com/gregtechceu/gtceu/client/model/machine/overlays/HPCAOverlay.java
@@ -3,6 +3,7 @@
import com.gregtechceu.gtceu.api.machine.trait.RecipeLogic.Status;
import com.gregtechceu.gtceu.api.registry.registrate.provider.GTBlockstateProvider;
import com.gregtechceu.gtceu.common.data.models.GTModels;
+import com.gregtechceu.gtceu.utils.data.RuntimeExistingFileHelper;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.resources.ResourceLocation;
@@ -23,31 +24,47 @@ public class HPCAOverlay {
// spotless:off
public static HPCAOverlay get(ResourceLocation normalSprite, ResourceLocation damagedSprite,
ExistingFileHelper fileHelper) {
- // normal
- if (!fileHelper.exists(normalSprite, GTBlockstateProvider.TEXTURE)) {
- return HPCAOverlay.EMPTY;
+ if (fileHelper instanceof RuntimeExistingFileHelper runtimeFileHelper) {
+ // if fileHelper is an instance of RuntimeExistingFileHelper, we have to enable its existence checking.
+ // the AutoCloseable warning is suppressed here because there's no clean way to
+ // use a try-with-resources statement in this.
+ //noinspection resource
+ fileHelper = runtimeFileHelper.activeHelper();
}
- ResourceLocation activeSprite = normalSprite.withSuffix("_active");
- if (!fileHelper.exists(activeSprite, GTBlockstateProvider.TEXTURE)) activeSprite = normalSprite;
- ResourceLocation damagedActiveSprite = damagedSprite.withSuffix("_active");
- if (!fileHelper.exists(damagedActiveSprite, GTBlockstateProvider.TEXTURE)) damagedActiveSprite = damagedSprite;
-
- // emissive
- ResourceLocation normalSpriteEmissive = normalSprite.withSuffix("_emissive");
- if (!fileHelper.exists(normalSpriteEmissive, GTBlockstateProvider.TEXTURE)) normalSpriteEmissive = null;
-
- ResourceLocation activeSpriteEmissive = activeSprite.withSuffix("_emissive");
- if (!fileHelper.exists(activeSpriteEmissive, GTBlockstateProvider.TEXTURE)) activeSpriteEmissive = null;
-
- ResourceLocation damagedSpriteEmissive = damagedSprite.withSuffix("_emissive");
- if (!fileHelper.exists(damagedSpriteEmissive, GTBlockstateProvider.TEXTURE)) damagedSpriteEmissive = null;
-
- ResourceLocation damagedActiveSpriteEmissive = damagedActiveSprite.withSuffix("_emissive");
- if (!fileHelper.exists(damagedActiveSpriteEmissive, GTBlockstateProvider.TEXTURE)) damagedActiveSpriteEmissive = null;
-
- return new HPCAOverlay(normalSprite, activeSprite, damagedSprite, damagedActiveSprite,
- normalSpriteEmissive, activeSpriteEmissive, damagedSpriteEmissive, damagedActiveSpriteEmissive);
+ try {
+ // normal
+ if (!fileHelper.exists(normalSprite, GTBlockstateProvider.TEXTURE)) {
+ return HPCAOverlay.EMPTY;
+ }
+ ResourceLocation activeSprite = normalSprite.withSuffix("_active");
+ if (!fileHelper.exists(activeSprite, GTBlockstateProvider.TEXTURE)) activeSprite = normalSprite;
+
+ ResourceLocation damagedActiveSprite = damagedSprite.withSuffix("_active");
+ if (!fileHelper.exists(damagedActiveSprite, GTBlockstateProvider.TEXTURE)) damagedActiveSprite = damagedSprite;
+
+ // emissive
+ ResourceLocation normalSpriteEmissive = normalSprite.withSuffix("_emissive");
+ if (!fileHelper.exists(normalSpriteEmissive, GTBlockstateProvider.TEXTURE)) normalSpriteEmissive = null;
+
+ ResourceLocation activeSpriteEmissive = activeSprite.withSuffix("_emissive");
+ if (!fileHelper.exists(activeSpriteEmissive, GTBlockstateProvider.TEXTURE)) activeSpriteEmissive = null;
+
+ ResourceLocation damagedSpriteEmissive = damagedSprite.withSuffix("_emissive");
+ if (!fileHelper.exists(damagedSpriteEmissive, GTBlockstateProvider.TEXTURE)) damagedSpriteEmissive = null;
+
+ ResourceLocation damagedActiveSpriteEmissive = damagedActiveSprite.withSuffix("_emissive");
+ if (!fileHelper.exists(damagedActiveSpriteEmissive, GTBlockstateProvider.TEXTURE)) damagedActiveSpriteEmissive = null;
+
+ return new HPCAOverlay(normalSprite, activeSprite, damagedSprite, damagedActiveSprite,
+ normalSpriteEmissive, activeSpriteEmissive, damagedSpriteEmissive, damagedActiveSpriteEmissive);
+ } finally {
+ if (fileHelper instanceof RuntimeExistingFileHelper.Active activeHelper) {
+ // close the active helper, just for good measure.
+ // Also in case we ever make it do anything, this won't be forgotten.
+ activeHelper.close();
+ }
+ }
}
// spotless:on
diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/machine/overlays/WorkableOverlays.java b/src/main/java/com/gregtechceu/gtceu/client/model/machine/overlays/WorkableOverlays.java
index bf09a89f026..373ab7b33c6 100644
--- a/src/main/java/com/gregtechceu/gtceu/client/model/machine/overlays/WorkableOverlays.java
+++ b/src/main/java/com/gregtechceu/gtceu/client/model/machine/overlays/WorkableOverlays.java
@@ -4,6 +4,7 @@
import com.gregtechceu.gtceu.api.registry.registrate.provider.GTBlockstateProvider;
import com.gregtechceu.gtceu.common.data.models.GTMachineModels;
import com.gregtechceu.gtceu.common.data.models.GTModels;
+import com.gregtechceu.gtceu.utils.data.RuntimeExistingFileHelper;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.core.Direction;
@@ -25,6 +26,14 @@
public class WorkableOverlays {
public static WorkableOverlays get(ResourceLocation textureDir, ExistingFileHelper fileHelper) {
+ if (fileHelper instanceof RuntimeExistingFileHelper runtimeFileHelper) {
+ // if fileHelper is an instance of RuntimeExistingFileHelper, we have to enable its existence checking.
+ // the AutoCloseable warning is suppressed here because there's no clean way to
+ // use a try-with-resources statement in this.
+ // noinspection resource
+ fileHelper = runtimeFileHelper.activeHelper();
+ }
+
WorkableOverlays model = new WorkableOverlays(textureDir);
for (OverlayFace overlayFace : OverlayFace.VALUES) {
@@ -55,6 +64,13 @@ public static WorkableOverlays get(ResourceLocation textureDir, ExistingFileHelp
model.textures.put(overlayFace, new StatusTextures(normalSprite, activeSprite, pausedSprite,
normalSpriteEmissive, activeSpriteEmissive, pausedSpriteEmissive));
}
+
+ if (fileHelper instanceof RuntimeExistingFileHelper.Active activeHelper) {
+ // close the active helper, just for good measure.
+ // Also in case we ever make it do anything, this won't be forgotten.
+ activeHelper.close();
+ }
+
return model;
}
diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/machine/variant/MultiVariantModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/machine/variant/MultiVariantModel.java
index dcf7da73340..57e7defb97a 100644
--- a/src/main/java/com/gregtechceu/gtceu/client/model/machine/variant/MultiVariantModel.java
+++ b/src/main/java/com/gregtechceu/gtceu/client/model/machine/variant/MultiVariantModel.java
@@ -70,8 +70,8 @@ public void resolveParents(@NotNull Function res
@OnlyIn(Dist.CLIENT)
public static class Deserializer implements JsonDeserializer {
- public MultiVariantModel deserialize(JsonElement json, Type type, JsonDeserializationContext context)
- throws JsonParseException {
+ public MultiVariantModel deserialize(JsonElement json, Type type,
+ JsonDeserializationContext context) throws JsonParseException {
List variants = new ArrayList<>();
if (json.isJsonArray()) {
JsonArray array = json.getAsJsonArray();
diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/pipe/ActivablePipeModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/pipe/ActivablePipeModel.java
new file mode 100644
index 00000000000..46331b3fb90
--- /dev/null
+++ b/src/main/java/com/gregtechceu/gtceu/client/model/pipe/ActivablePipeModel.java
@@ -0,0 +1,236 @@
+package com.gregtechceu.gtceu.client.model.pipe;
+
+import com.gregtechceu.gtceu.api.block.PipeBlock;
+import com.gregtechceu.gtceu.api.block.property.GTBlockStateProperties;
+import com.gregtechceu.gtceu.api.registry.registrate.provider.GTBlockstateProvider;
+import com.gregtechceu.gtceu.data.model.builder.PipeModelBuilder;
+
+import net.minecraft.core.Direction;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraftforge.client.model.generators.BlockModelBuilder;
+import net.minecraftforge.client.model.generators.IGeneratedBlockState;
+import net.minecraftforge.client.model.generators.ModelBuilder;
+import net.minecraftforge.client.model.generators.ModelFile;
+
+import it.unimi.dsi.fastutil.objects.Reference2FloatMap;
+import lombok.Setter;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Objects;
+
+public class ActivablePipeModel extends PipeModel {
+
+ @Setter
+ public @Nullable ResourceLocation sideActive, endActive;
+ @Setter
+ public @Nullable ResourceLocation sideSecondaryActive, endSecondaryActive;
+ @Setter
+ public @Nullable ResourceLocation sideOverlayActive, endOverlayActive;
+ @Setter
+ public int activeEmissivity = 15;
+
+ /// Use {@link #getOrCreateActiveBlockModel()} instead of referencing this field directly.
+ private BlockModelBuilder activeBlockModel;
+ /// Use {@link #getOrCreateActiveCenterElement()} instead of referencing this field directly.
+ private BlockModelBuilder activeCenterElement;
+ /// Use {@link #getOrCreateActiveConnectionElement()} instead of referencing this field directly.
+ private BlockModelBuilder activeConnectionElement;
+
+ public ActivablePipeModel(PipeBlock, ?, ?> block, float thickness, ResourceLocation side, ResourceLocation end,
+ GTBlockstateProvider provider) {
+ super(block, provider, thickness, side, end);
+ }
+
+ /**
+ * @see #getOrCreateActiveBlockModel()
+ * @see #getOrCreateConnectionElement()
+ * @see #getOrCreateActiveCenterElement()
+ * @see #getOrCreateActiveConnectionElement()
+ */
+ @Override
+ public void initModels() {
+ getOrCreateActiveCenterElement();
+ getOrCreateActiveConnectionElement();
+ getOrCreateActiveBlockModel();
+
+ super.initModels();
+ }
+
+ /**
+ * Override this to change the active model {@link #block this.block} will use.
+ *
+ * @return A model builder for the block's actual model.
+ * @see #getOrCreateBlockModel()
+ * @see #getOrCreateActiveCenterElement()
+ * @see #getOrCreateActiveConnectionElement()
+ */
+ @ApiStatus.OverrideOnly
+ protected BlockModelBuilder getOrCreateActiveBlockModel() {
+ if (this.activeBlockModel != null) {
+ return this.activeBlockModel;
+ }
+ // spotless:off
+ return this.activeBlockModel = this.provider.models().getBuilder(this.blockId.withSuffix("_active").toString())
+ .parent(this.getOrCreateActiveCenterElement())
+ .customLoader(PipeModelBuilder.begin(this.thickness, this.provider))
+ .centerModels(this.getOrCreateActiveCenterElement().getLocation())
+ .connectionModels(this.getOrCreateActiveConnectionElement().getLocation())
+ .end();
+ // spotless:on
+ }
+
+ /**
+ * Override this to change the center element's model for when the pipe is active.
+ *
+ * @return A model builder for the center element's model.
+ * @see #getOrCreateCenterElement()
+ * @see #getOrCreateActiveConnectionElement()
+ */
+ @ApiStatus.OverrideOnly
+ protected BlockModelBuilder getOrCreateActiveCenterElement() {
+ if (this.activeCenterElement != null) {
+ return this.activeCenterElement;
+ }
+ return this.activeCenterElement = makeActiveElementModel(
+ this.blockId.withPath(path -> "block/pipe/" + path + "/center_active"),
+ null, minCoord, minCoord, minCoord, maxCoord, maxCoord, maxCoord);
+ }
+
+ /**
+ * Override this to change the 'connection' element's model for when the pipe is active.
+ * By default, this is rotated & used for all connected sides of the pipe.
+ * Note that that is not a hard requirement, and that you may set a model per side in
+ * {@link #getOrCreateBlockModel()}.
+ *
+ * @return A model builder for the connection element's model.
+ * @see #getOrCreateConnectionElement()
+ * @see #getOrCreateActiveCenterElement()
+ */
+ @ApiStatus.OverrideOnly
+ protected BlockModelBuilder getOrCreateActiveConnectionElement() {
+ if (this.activeConnectionElement != null) {
+ return this.activeConnectionElement;
+ }
+ return this.activeConnectionElement = makeActiveElementModel(
+ this.blockId.withPath(path -> "block/pipe/" + path + "/connection_active"),
+ Direction.DOWN, minCoord, 0, minCoord, maxCoord, minCoord, maxCoord);
+ }
+
+ /**
+ * Fills out a model builder with applicable pipe model elements and returns it for further use
+ *
+ * This method is a copy of {@linkplain #makeElementModel} with the texture references changed for active variants.
+ *
+ * @param name the resulting model's path
+ * @param endFace the model face that's being created
+ * @param x1 min X coordinate in the range [-16,32]
+ * @param y1 min Y coordinate in the range [-16,32]
+ * @param z1 min Z coordinate in the range [-16,32]
+ * @param x2 max X coordinate in the range [-16,32]
+ * @param y2 max Y coordinate in the range [-16,32]
+ * @param z2 max Z coordinate in the range [-16,32]
+ * @implNote The coordinates must be in the correct order or the resulting model's cubes will be inside out!
+ * @see #makeElementModel
+ */
+ protected BlockModelBuilder makeActiveElementModel(ResourceLocation name, @Nullable Direction endFace,
+ final float x1, final float y1, final float z1,
+ final float x2, final float y2, final float z2) {
+ Reference2FloatMap faceEndpoints = makeFaceEndpointMap(x1, y1, z1, x2, y2, z2);
+
+ BlockModelBuilder model = this.provider.models().getBuilder(name.toString())
+ .parent(new ModelFile.UncheckedModelFile("block/block"))
+ .texture("particle", "#" + (this.side != null ? SIDE_KEY : END_KEY))
+ .renderType(RENDERTYPE_CUTOUT_MIPPED);
+
+ ResourceLocation side = this.sideActive != null ? this.sideActive : this.side;
+ ResourceLocation end = this.endActive != null ? this.endActive : this.end;
+ ResourceLocation sideSecondary = this.sideSecondaryActive != null ? this.sideSecondaryActive :
+ this.sideSecondary;
+ ResourceLocation endSecondary = this.endSecondaryActive != null ? this.endSecondaryActive : this.endSecondary;
+ ResourceLocation sideOverlay = this.sideOverlayActive != null ? this.sideOverlayActive : this.sideOverlay;
+ ResourceLocation endOverlay = this.endOverlayActive != null ? this.endOverlayActive : this.endOverlay;
+
+ makePartModelElement(model, endFace, false, faceEndpoints, 0.0f, 0, 1,
+ x1, y1, z1, x2, y2, z2, side, end, SIDE_KEY, END_KEY,
+ this.sideActive != null, this.endActive != null);
+
+ makePartModelElement(model, endFace, true, faceEndpoints, 0.001f, 0, 1,
+ x1, y1, z1, x2, y2, z2, sideSecondary, endSecondary, SIDE_SECONDARY_KEY, END_SECONDARY_KEY,
+ this.sideSecondaryActive != null, this.endSecondaryActive != null);
+
+ makePartModelElement(model, endFace, true, faceEndpoints, 0.002f, 2, 2,
+ x1, y1, z1, x2, y2, z2, sideOverlay, endOverlay, SIDE_OVERLAY_KEY, END_OVERLAY_KEY,
+ this.sideOverlayActive != null, this.endOverlayActive != null);
+
+ return model;
+ }
+
+ protected > void makePartModelElement(T model, @Nullable Direction endFace,
+ boolean useEndWithFullCube,
+ Reference2FloatMap faceEndpoints,
+ float offset, int sideTintIndex, int endTintIndex,
+ final float x1, final float y1, final float z1,
+ final float x2, final float y2, final float z2,
+ @Nullable ResourceLocation sideTexture,
+ @Nullable ResourceLocation endTexture,
+ String sideKey, String endKey,
+ boolean sideEmissive, boolean endEmissive) {
+ this.makePartModelElement(model, endFace, useEndWithFullCube, faceEndpoints, offset,
+ sideTintIndex, endTintIndex, x1, y1, z1, x2, y2, z2, sideTexture, endTexture, sideKey, endKey,
+ (face, textureKey, builder) -> {
+ if (activeEmissivity == 0) {
+ return;
+ }
+ if (sideEmissive && textureKey.equals(sideKey)) {
+ builder.emissivity(activeEmissivity, activeEmissivity).ao(false);
+ } else if (endEmissive && textureKey.equals(endKey)) {
+ builder.emissivity(activeEmissivity, activeEmissivity).ao(false);
+ }
+ });
+ }
+
+ @Override
+ public IGeneratedBlockState createBlockState() {
+ if (!this.getBlock().defaultBlockState().hasProperty(GTBlockStateProperties.ACTIVE)) {
+ return super.createBlockState();
+ }
+ // spotless:off
+ return this.provider.getVariantBuilder(this.getBlock())
+ .partialState()
+ .with(GTBlockStateProperties.ACTIVE, false)
+ .modelForState()
+ .modelFile(this.provider.models().getExistingFile(this.blockId))
+ .addModel()
+ .partialState()
+ .with(GTBlockStateProperties.ACTIVE, true)
+ .modelForState()
+ .modelFile(this.provider.models().getExistingFile(this.blockId.withSuffix("_active")))
+ .addModel();
+ // spotless:on
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof ActivablePipeModel pipeModel)) return false;
+ return super.equals(o) &&
+ Objects.equals(sideActive, pipeModel.sideActive) &&
+ Objects.equals(endActive, pipeModel.endActive) &&
+ Objects.equals(sideSecondaryActive, pipeModel.sideSecondaryActive) &&
+ Objects.equals(endSecondaryActive, pipeModel.endSecondaryActive) &&
+ Objects.equals(sideOverlayActive, pipeModel.sideOverlayActive) &&
+ Objects.equals(endOverlayActive, pipeModel.endOverlayActive);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = super.hashCode();
+ result = 31 * result + Objects.hashCode(sideActive);
+ result = 31 * result + Objects.hashCode(endActive);
+ result = 31 * result + Objects.hashCode(sideSecondaryActive);
+ result = 31 * result + Objects.hashCode(endSecondaryActive);
+ result = 31 * result + Objects.hashCode(sideOverlayActive);
+ result = 31 * result + Objects.hashCode(endOverlayActive);
+ return result;
+ }
+}
diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/pipe/BakedPipeModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/pipe/BakedPipeModel.java
new file mode 100644
index 00000000000..3553bd37510
--- /dev/null
+++ b/src/main/java/com/gregtechceu/gtceu/client/model/pipe/BakedPipeModel.java
@@ -0,0 +1,161 @@
+package com.gregtechceu.gtceu.client.model.pipe;
+
+import com.gregtechceu.gtceu.api.blockentity.PipeBlockEntity;
+import com.gregtechceu.gtceu.api.data.tag.TagPrefix;
+import com.gregtechceu.gtceu.api.pipenet.IPipeNode;
+import com.gregtechceu.gtceu.api.pipenet.Node;
+import com.gregtechceu.gtceu.client.model.BaseBakedModel;
+import com.gregtechceu.gtceu.client.model.GTModelProperties;
+import com.gregtechceu.gtceu.client.model.IBlockEntityRendererBakedModel;
+import com.gregtechceu.gtceu.client.renderer.cover.ICoverableRenderer;
+import com.gregtechceu.gtceu.client.util.GTQuadTransformers;
+import com.gregtechceu.gtceu.common.data.GTMaterialBlocks;
+import com.gregtechceu.gtceu.utils.GTUtil;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.color.block.BlockColors;
+import net.minecraft.client.renderer.MultiBufferSource;
+import net.minecraft.client.renderer.RenderType;
+import net.minecraft.client.renderer.block.model.BakedQuad;
+import net.minecraft.client.renderer.texture.TextureAtlasSprite;
+import net.minecraft.client.resources.model.BakedModel;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.Direction;
+import net.minecraft.util.RandomSource;
+import net.minecraft.world.level.BlockAndTintGetter;
+import net.minecraft.world.level.block.entity.BlockEntityType;
+import net.minecraft.world.level.block.state.BlockState;
+import net.minecraftforge.client.model.data.ModelData;
+
+import com.mojang.blaze3d.vertex.PoseStack;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+public class BakedPipeModel extends BaseBakedModel implements ICoverableRenderer,
+ IBlockEntityRendererBakedModel> {
+
+ public final static int ITEM_CONNECTIONS = 0b001100;
+
+ private final Map parts;
+ private final Map restrictors;
+
+ public BakedPipeModel(Map parts, Map restrictors) {
+ this.parts = parts;
+ this.restrictors = restrictors;
+ }
+
+ @Override
+ public List getQuads(@Nullable BlockState state, @Nullable Direction side,
+ RandomSource rand, ModelData modelData, @Nullable RenderType renderType) {
+ List quads = new ArrayList<>();
+
+ BlockAndTintGetter level = modelData.get(GTModelProperties.LEVEL);
+ BlockPos pos = modelData.get(GTModelProperties.POS);
+ Integer connectionMask = modelData.get(GTModelProperties.PIPE_CONNECTION_MASK);
+ Integer blockedMask = modelData.get(GTModelProperties.PIPE_BLOCKED_MASK);
+
+ if (state == null) {
+ connectionMask = ITEM_CONNECTIONS;
+ blockedMask = Node.ALL_CLOSED;
+ }
+ if (connectionMask == null || connectionMask != Node.ALL_OPENED) {
+ BakedModel centerModel = parts.get(null);
+ if (renderType == null ||
+ state != null && centerModel.getRenderTypes(state, rand, modelData).contains(renderType)) {
+ quads.addAll(centerModel.getQuads(state, side, rand, modelData, renderType));
+ }
+ if (connectionMask == null) {
+ // return unconnected base model if the model property isn't set
+ return quads;
+ }
+ }
+ for (Direction dir : GTUtil.DIRECTIONS) {
+ if (PipeBlockEntity.isConnected(connectionMask, dir)) {
+ BakedModel model = parts.get(dir);
+ if (renderType == null ||
+ (state != null && model.getRenderTypes(state, rand, modelData).contains(renderType))) {
+ quads.addAll(model.getQuads(state, side, rand, modelData, renderType));
+ }
+ if (blockedMask != null && PipeBlockEntity.isFaceBlocked(blockedMask, dir)) {
+ model = restrictors.get(dir);
+ if (renderType == null ||
+ (state != null && model.getRenderTypes(state, rand, modelData).contains(renderType))) {
+ quads.addAll(model.getQuads(state, side, rand, modelData, renderType));
+ }
+ }
+ }
+ }
+ if (level == null || pos == null || !(level.getBlockEntity(pos) instanceof IPipeNode, ?> pipeNode)) {
+ return quads;
+ }
+ ICoverableRenderer.super.renderCovers(quads, pipeNode.getCoverContainer(), pos, level, side, rand,
+ modelData, renderType);
+
+ if (pipeNode.getFrameMaterial().isNull()) {
+ return quads;
+ }
+ var frameBlockEntry = GTMaterialBlocks.MATERIAL_BLOCKS.get(TagPrefix.frameGt, pipeNode.getFrameMaterial());
+ if (frameBlockEntry == null) {
+ return quads;
+ }
+ BlockState frameState = frameBlockEntry.getDefaultState();
+ BakedModel frameModel = Minecraft.getInstance().getBlockRenderer().getBlockModel(frameState);
+
+ modelData = frameModel.getModelData(level, pos, frameState, modelData);
+
+ List frameQuads = new LinkedList<>();
+ if (side == null || pipeNode.getCoverContainer().getCoverAtSide(side) == null) {
+ frameQuads.addAll(frameModel.getQuads(state, side, rand, modelData, renderType));
+ }
+
+ if (side == null) {
+ for (Direction face : GTUtil.DIRECTIONS) {
+ if (pipeNode.getCoverContainer().getCoverAtSide(face) != null) {
+ continue;
+ }
+ frameQuads.addAll(frameModel.getQuads(state, face, rand, modelData, renderType));
+ }
+ }
+
+ // bake all the quads' tint colors into the vertices
+ BlockColors blockColors = Minecraft.getInstance().getBlockColors();
+ for (BakedQuad frameQuad : frameQuads) {
+ if (frameQuad.isTinted()) {
+ int color = blockColors.getColor(frameState, level, pos, frameQuad.getTintIndex());
+ frameQuad = GTQuadTransformers.setColor(frameQuad, color, true);
+ }
+ quads.add(frameQuad);
+ }
+ return quads;
+ }
+
+ @Override
+ public ModelData getModelData(BlockAndTintGetter level, BlockPos pos, BlockState state, ModelData modelData) {
+ for (BakedModel part : this.parts.values()) {
+ modelData = part.getModelData(level, pos, state, modelData);
+ }
+ for (BakedModel restrictor : this.restrictors.values()) {
+ modelData = restrictor.getModelData(level, pos, state, modelData);
+ }
+ return modelData;
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override
+ public TextureAtlasSprite getParticleIcon() {
+ return parts.get(null).getParticleIcon();
+ }
+
+ @Override
+ public @Nullable BlockEntityType extends PipeBlockEntity, ?>> getBlockEntityType() {
+ return null;
+ }
+
+ @Override
+ public void render(PipeBlockEntity, ?> blockEntity, float partialTick, PoseStack poseStack,
+ MultiBufferSource buffer, int packedLight, int packedOverlay) {}
+}
diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/pipe/PipeModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/pipe/PipeModel.java
new file mode 100644
index 00000000000..5f440b0214f
--- /dev/null
+++ b/src/main/java/com/gregtechceu/gtceu/client/model/pipe/PipeModel.java
@@ -0,0 +1,436 @@
+package com.gregtechceu.gtceu.client.model.pipe;
+
+import com.gregtechceu.gtceu.api.block.PipeBlock;
+import com.gregtechceu.gtceu.api.block.property.GTBlockStateProperties;
+import com.gregtechceu.gtceu.api.registry.registrate.GTBlockBuilder;
+import com.gregtechceu.gtceu.api.registry.registrate.provider.GTBlockstateProvider;
+import com.gregtechceu.gtceu.data.model.builder.PipeModelBuilder;
+import com.gregtechceu.gtceu.data.pack.event.RegisterDynamicResourcesEvent;
+import com.gregtechceu.gtceu.utils.GTMath;
+import com.gregtechceu.gtceu.utils.GTUtil;
+
+import net.minecraft.core.Direction;
+import net.minecraft.core.registries.BuiltInRegistries;
+import net.minecraft.data.models.blockstates.MultiVariantGenerator;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraftforge.client.model.generators.*;
+
+import com.tterrag.registrate.util.nullness.NonNullBiConsumer;
+import it.unimi.dsi.fastutil.objects.Reference2FloatMap;
+import it.unimi.dsi.fastutil.objects.Reference2FloatOpenHashMap;
+import lombok.Getter;
+import lombok.Setter;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.MustBeInvokedByOverriders;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.*;
+
+/**
+ * This is an automatic pipe model generator.
+ *
+ * For material pipes
+ * If the pipe this model belongs to is generated from a material property (or equivalent),
+ * you should call {@link #dynamicModel()}, which adds the model to {@link #DYNAMIC_MODELS}
+ * and automatically processes it as a part of runtime asset generation.
+ *
+ * NOTE:
+ * You must also initialize the models in an {@link RegisterDynamicResourcesEvent} listener as such:
+ *
+ *
+ * {@code
+ *
+ * // in a @EventBusSubscriber-annotated class
+ * @SubscribeEvent
+ * public static void registerDynamicAssets(RegisterDynamicResourcesEvent event) {
+ * for (var block : YourBlocks.YOUR_PIPE_BLOCKS.values()) {
+ * if (block == null) continue;
+ * block.get().createPipeModel(RuntimeExistingFileHelper.INSTANCE).dynamicModel();
+ * }
+ * }
+ * }
+ *
+ *
+ * Remember to replace {@code YourBlocks.YOUR_PIPE_BLOCKS.values()} with a reference to your pipe block collection!
+ *
+ *
+ * For non-material pipes
+ * Conversely, if the pipe is not generated, but has a constant set of variants (such as optical fiber
+ * cables),
+ * you should NOT use {@link #dynamicModel()} and instead set the model with
+ * {@link GTBlockBuilder#gtBlockstate(NonNullBiConsumer)} as such:
+ *
+ *
+ * {@code
+ * // on your pipe block builder
+ * ... = REGISTRATE.block(...)
+ * .properties(...)
+ * .gtBlockstate(GTModels::createPipeBlockModel)
+ * ...more builder things...
+ * .item(...)
+ * .model(NonNullBiConsumer.noop())
+ * ...more builder things...
+ * }
+ *
+ *
+ * This makes the pipe model(s) be generated for you without having to process them at runtime.
+ *
+ */
+public class PipeModel {
+
+ // spotless:off
+ public static final String
+ SIDE_KEY = "side",
+ END_KEY = "end",
+ SIDE_SECONDARY_KEY = "side_secondary",
+ END_SECONDARY_KEY = "end_secondary",
+ SIDE_OVERLAY_KEY = "side_overlay",
+ END_OVERLAY_KEY = "end_overlay";
+ // spotless:on
+ protected static final ResourceLocation RENDERTYPE_CUTOUT_MIPPED = new ResourceLocation("cutout_mipped");
+
+ public static final Set DYNAMIC_MODELS = new HashSet<>();
+
+ public static void initDynamicModels() {
+ for (PipeModel generator : DYNAMIC_MODELS) {
+ generator.initModels();
+ }
+ }
+
+ @Getter
+ protected final PipeBlock, ?, ?> block;
+ public final @NotNull ResourceLocation blockId;
+ protected final GTBlockstateProvider provider;
+
+ /**
+ * The pipe's "thickness" in the (0,16] voxel range, where 1 is 1 voxel and 16 is a full block thick
+ */
+ protected final float thickness;
+ /**
+ * The pipe model's 'minimum' coordinate in the (0,16] voxel range.
+ * This is ex. the height of the center part's bottom edge.
+ */
+ protected final float minCoord;
+ /**
+ * The pipe model's 'maximum' coordinate in the (0,16] voxel range.
+ * This is ex. the height of the center part's top edge.
+ */
+ protected final float maxCoord;
+ @Setter
+ public ResourceLocation side, end;
+ @Setter
+ public @Nullable ResourceLocation sideSecondary, endSecondary;
+ @Setter
+ public @Nullable ResourceLocation sideOverlay, endOverlay;
+
+ /// Use {@link #getOrCreateBlockModel()} instead of referencing this field directly.
+ private BlockModelBuilder blockModel;
+ /// Use {@link #getOrCreateItemModel()} instead of referencing this field directly.
+ private ItemModelBuilder itemModel;
+
+ /// Use {@link #getOrCreateCenterElement()} instead of referencing this field directly.
+ private BlockModelBuilder centerElement;
+ /// Use {@link #getOrCreateConnectionElement()} instead of referencing this field directly.
+ private BlockModelBuilder connectionElement;
+
+ public PipeModel(PipeBlock, ?, ?> block, GTBlockstateProvider provider,
+ float thickness, ResourceLocation side, ResourceLocation end) {
+ this.block = block;
+ this.blockId = BuiltInRegistries.BLOCK.getKey(this.block);
+ this.provider = provider;
+
+ // assume thickness is in the 0-1 range
+ this.thickness = thickness * 16.0f;
+ this.side = side;
+ this.end = end;
+
+ this.minCoord = (16.0f - this.thickness) / 2.0f;
+ this.maxCoord = this.minCoord + this.thickness;
+ }
+
+ public final void dynamicModel() {
+ DYNAMIC_MODELS.add(this);
+ }
+
+ /**
+ * Initialize all models that are required for this block model to exist.
+ * Order is important! Dependent models must be initialized after their dependencies.
+ *
+ * @see #getOrCreateBlockModel()
+ * @see #getOrCreateCenterElement()
+ * @see #getOrCreateConnectionElement()
+ */
+ @MustBeInvokedByOverriders
+ public void initModels() {
+ getOrCreateCenterElement();
+ getOrCreateConnectionElement();
+ getOrCreateBlockModel();
+ createBlockState();
+
+ getOrCreateItemModel();
+ }
+
+ /**
+ * Override this to change the actual model {@link #block this.block} will use.
+ *
+ * @return A model builder for the block's actual model.
+ * @see #getOrCreateCenterElement()
+ * @see #getOrCreateConnectionElement()
+ */
+ @ApiStatus.OverrideOnly
+ protected BlockModelBuilder getOrCreateBlockModel() {
+ if (this.blockModel != null) {
+ return this.blockModel;
+ }
+ // spotless:off
+ return this.blockModel = this.provider.models().getBuilder(this.blockId.toString())
+ // make the "default" model be based on the center part's model
+ .parent(this.getOrCreateCenterElement())
+ .customLoader(PipeModelBuilder.begin(this.thickness, this.provider))
+ .centerModels(this.getOrCreateCenterElement().getLocation())
+ .connectionModels(this.getOrCreateConnectionElement().getLocation())
+ .end();
+ // spotless:on
+ }
+
+ /**
+ * Override this to change the center element's model.
+ *
+ * @return A model builder for the center element's model.
+ * @see #getOrCreateBlockModel()
+ * @see #getOrCreateConnectionElement()
+ */
+ @ApiStatus.OverrideOnly
+ protected BlockModelBuilder getOrCreateCenterElement() {
+ if (this.centerElement != null) {
+ return this.centerElement;
+ }
+ return this.centerElement = makeElementModel(this.blockId.withPath(path -> "block/pipe/" + path + "/center"),
+ null, minCoord, minCoord, minCoord, maxCoord, maxCoord, maxCoord);
+ }
+
+ /**
+ * Override this to change the 'connection' element's model.
+ * By default, this is rotated & used for all connected sides of the pipe.
+ * Note that that is not a hard requirement, and that you may set a model per side in
+ * {@link #getOrCreateBlockModel()}.
+ *
+ * @return A model builder for the connection element's model.
+ * @see #getOrCreateBlockModel()
+ * @see #getOrCreateCenterElement()
+ */
+ @ApiStatus.OverrideOnly
+ protected BlockModelBuilder getOrCreateConnectionElement() {
+ if (this.connectionElement != null) {
+ return this.connectionElement;
+ }
+ return this.connectionElement = makeElementModel(
+ this.blockId.withPath(path -> "block/pipe/" + path + "/connection"),
+ Direction.DOWN, minCoord, 0, minCoord, maxCoord, minCoord, maxCoord);
+ }
+
+ /**
+ * Override this to change the item model.
+ * By default, this creates a version of the pipe block model with the north & south sides 'connected'.
+ *
+ * @return The item model builder.
+ * @see #getOrCreateBlockModel()
+ */
+ @ApiStatus.OverrideOnly
+ protected ItemModelBuilder getOrCreateItemModel() {
+ if (this.itemModel != null) {
+ return this.itemModel;
+ }
+ return this.itemModel = createItemModel(this.blockId, this.minCoord, this.maxCoord);
+ }
+
+ /**
+ * Override this to change the block state set {@link #block this.block} will use.
+ * By default, this creates a simple block state with no properties.
+ * The activable pipes (laser & optical) use this to add a model for the
+ * {@link GTBlockStateProperties#ACTIVE "active"} state of the blocks.
+ *
+ * @return The block state generator, usually a {@link MultiVariantGenerator}.
+ * @see #getOrCreateBlockModel()
+ * @see ActivablePipeModel#createBlockState()
+ */
+ @ApiStatus.OverrideOnly
+ public IGeneratedBlockState createBlockState() {
+ // spotless:off
+ return this.provider.getVariantBuilder(this.getBlock())
+ .partialState()
+ .modelForState()
+ .modelFile(this.provider.models().getExistingFile(this.blockId))
+ .addModel();
+ // spotless:on
+ }
+
+ /**
+ * Creates an item model based on the block model that extends to the north/south end of the block space.
+ *
+ * @param name The resulting model's path.
+ * @param min The minimum X/Y coordinate.
+ * @param max The maximum X/Y coordinate.
+ * @return An item model builder.
+ */
+ protected ItemModelBuilder createItemModel(ResourceLocation name, float min, float max) {
+ Reference2FloatMap faceEndpoints = new Reference2FloatOpenHashMap<>();
+ faceEndpoints.put(Direction.DOWN, min);
+ faceEndpoints.put(Direction.UP, max);
+ faceEndpoints.put(Direction.NORTH, 0);
+ faceEndpoints.put(Direction.SOUTH, 16);
+ faceEndpoints.put(Direction.WEST, min);
+ faceEndpoints.put(Direction.EAST, max);
+
+ ItemModelBuilder model = this.provider.itemModels().getBuilder(name.toString())
+ .parent(this.getOrCreateCenterElement());
+ makePartModelElement(model, Direction.NORTH, false, faceEndpoints, 0.0f, 0, 1,
+ min, min, 0, max, max, 16, this.side, this.end, SIDE_KEY, END_KEY);
+ makePartModelElement(model, Direction.NORTH, true, faceEndpoints, 0.001f, 0, 1,
+ min, min, 0, max, max, 16, this.sideSecondary, this.endSecondary, SIDE_SECONDARY_KEY,
+ END_SECONDARY_KEY);
+ makePartModelElement(model, Direction.NORTH, true, faceEndpoints, 0.002f, 2, 2,
+ min, min, 0, max, max, 16, this.sideOverlay, this.endOverlay, SIDE_OVERLAY_KEY, END_OVERLAY_KEY);
+ return model;
+ }
+
+ /**
+ * Fills out a model builder with applicable pipe model elements and returns it for further use
+ *
+ * @param name the resulting model's path
+ * @param endFace the model face that's being created
+ * @param x1 min X coordinate in the range [-16,32]
+ * @param y1 min Y coordinate in the range [-16,32]
+ * @param z1 min Z coordinate in the range [-16,32]
+ * @param x2 max X coordinate in the range [-16,32]
+ * @param y2 max Y coordinate in the range [-16,32]
+ * @param z2 max Z coordinate in the range [-16,32]
+ * @implNote The coordinates must be in the correct order or the resulting model's cubes will be inside out!
+ */
+ protected BlockModelBuilder makeElementModel(ResourceLocation name, @Nullable Direction endFace,
+ final float x1, final float y1, final float z1,
+ final float x2, final float y2, final float z2) {
+ Reference2FloatMap faceEndpoints = makeFaceEndpointMap(x1, y1, z1, x2, y2, z2);
+
+ BlockModelBuilder model = this.provider.models().getBuilder(name.toString())
+ .parent(new ModelFile.UncheckedModelFile("block/block"))
+ .texture("particle", "#" + (this.side != null ? SIDE_KEY : END_KEY))
+ .renderType(RENDERTYPE_CUTOUT_MIPPED);
+ makePartModelElement(model, endFace, false, faceEndpoints, 0.0f, 0, 1,
+ x1, y1, z1, x2, y2, z2, this.side, this.end, SIDE_KEY, END_KEY);
+ makePartModelElement(model, endFace, true, faceEndpoints, 0.001f, 0, 1,
+ x1, y1, z1, x2, y2, z2, this.sideSecondary, this.endSecondary, "side_secondary", "end_secondary");
+ makePartModelElement(model, endFace, true, faceEndpoints, 0.002f, 2, 2,
+ x1, y1, z1, x2, y2, z2, this.sideOverlay, this.endOverlay, "side_overlay", "end_overlay");
+ return model;
+ }
+
+ protected > void makePartModelElement(T model, @Nullable Direction endFace,
+ boolean useEndWithFullCube,
+ Reference2FloatMap faceEndpoints,
+ float offset, int sideTintIndex, int endTintIndex,
+ final float x1, final float y1, final float z1,
+ final float x2, final float y2, final float z2,
+ @Nullable ResourceLocation sideTexture,
+ @Nullable ResourceLocation endTexture,
+ String sideKey, String endKey) {
+ makePartModelElement(model, endFace, useEndWithFullCube, faceEndpoints,
+ offset, sideTintIndex, endTintIndex, x1, y1, z1, x2, y2, z2,
+ sideTexture, endTexture, sideKey, endKey, (face, texture, builder) -> {});
+ }
+
+ protected > void makePartModelElement(T model, @Nullable Direction endFace,
+ boolean useEndWithFullCube,
+ Reference2FloatMap faceEndpoints,
+ float offset, int sideTintIndex, int endTintIndex,
+ final float x1, final float y1, final float z1,
+ final float x2, final float y2, final float z2,
+ @Nullable ResourceLocation sideTexture,
+ @Nullable ResourceLocation endTexture,
+ String sideKey, String endKey,
+ FaceConfigurator faceConfigurator) {
+ if (sideTexture == null && (endFace == null || endTexture == null)) {
+ return;
+ }
+ if (sideTexture != null) model.texture(sideKey, sideTexture);
+ if (endFace != null && endTexture != null) model.texture(endKey, endTexture);
+
+ boolean fullCube = !useEndWithFullCube &&
+ (x1 == y1 && x1 == z1 && x1 <= 0.0f) &&
+ (x2 == y2 && x2 == z2 && x2 >= 16.0f);
+
+ ModelBuilder.ElementBuilder element = model.element()
+ .from(x1 - offset, y1 - offset, z1 - offset)
+ .to(x2 + offset, y2 + offset, z2 + offset);
+
+ for (Direction dir : GTUtil.DIRECTIONS) {
+ ModelBuilder.ElementBuilder.FaceBuilder face = null;
+ boolean isEnd = !fullCube && endFace != null && (endFace == dir || endFace == dir.getOpposite());
+ if (isEnd && endTexture != null) {
+ face = element.face(dir).texture("#" + endKey).tintindex(endTintIndex);
+ faceConfigurator.accept(dir, endKey, face);
+ } else if (!isEnd && sideTexture != null) {
+ face = element.face(dir).texture("#" + sideKey).tintindex(sideTintIndex);
+ faceConfigurator.accept(dir, sideKey, face);
+ }
+
+ float faceEnd = faceEndpoints.getFloat(dir);
+ if (face != null && (faceEnd >= 16.0f || faceEnd <= 0.0f)) {
+ face.cullface(dir);
+ }
+ }
+ }
+
+ protected final Reference2FloatMap makeFaceEndpointMap(final float x1, final float y1, final float z1,
+ final float x2, final float y2, final float z2) {
+ Reference2FloatMap faceEndpoints = new Reference2FloatOpenHashMap<>();
+ faceEndpoints.defaultReturnValue(GTMath.max(x1, y1, z1, x2, y2, z2));
+ for (Direction dir : GTUtil.DIRECTIONS) {
+ faceEndpoints.put(dir, switch (dir) {
+ case DOWN -> Math.min(y1, y2);
+ case UP -> Math.max(y1, y2);
+ case NORTH -> Math.min(z1, z2);
+ case SOUTH -> Math.max(z1, z2);
+ case WEST -> Math.min(x1, x2);
+ case EAST -> Math.max(x1, x2);
+ });
+ }
+ return faceEndpoints;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof PipeModel pipeModel)) return false;
+ return block == pipeModel.block &&
+ Objects.equals(side, pipeModel.side) &&
+ Objects.equals(end, pipeModel.end) &&
+ Objects.equals(sideSecondary, pipeModel.sideSecondary) &&
+ Objects.equals(endSecondary, pipeModel.endSecondary) &&
+ Objects.equals(sideOverlay, pipeModel.sideOverlay) &&
+ Objects.equals(endOverlay, pipeModel.endOverlay);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(block, side, end, sideSecondary, endSecondary, sideOverlay, endOverlay);
+ }
+
+ @FunctionalInterface
+ public interface FaceConfigurator> {
+
+ /**
+ * This is a callback for modifying a block element face builder in ways not supported by "basic" API.
+ * For example, you can make faces emissive, like {@link ActivablePipeModel#makePartModelElement}.
+ *
+ * @param face The normal direction of this face.
+ * @param texture The texture of the face, usually in {@code #reference} format.
+ * Note that the String does NOT begin with {@code #}.
+ * @param builder The face builder.
+ * @see ActivablePipeModel#makePartModelElement(ModelBuilder, Direction, boolean, Reference2FloatMap, float,
+ * int, int, float, float, float, float, float, float, ResourceLocation, ResourceLocation, String, String,
+ * boolean, boolean) ActivablePipeModel.makePartModelElement
+ */
+ void accept(Direction face, String texture, ModelBuilder.ElementBuilder.FaceBuilder builder);
+ }
+}
diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/pipe/PipeModelLoader.java b/src/main/java/com/gregtechceu/gtceu/client/model/pipe/PipeModelLoader.java
new file mode 100644
index 00000000000..9465b8f8471
--- /dev/null
+++ b/src/main/java/com/gregtechceu/gtceu/client/model/pipe/PipeModelLoader.java
@@ -0,0 +1,62 @@
+package com.gregtechceu.gtceu.client.model.pipe;
+
+import com.gregtechceu.gtceu.GTCEu;
+import com.gregtechceu.gtceu.client.model.machine.MachineModelLoader;
+import com.gregtechceu.gtceu.client.model.machine.variant.MultiVariantModel;
+
+import net.minecraft.client.resources.model.UnbakedModel;
+import net.minecraft.core.Direction;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.util.GsonHelper;
+import net.minecraftforge.client.model.geometry.IGeometryLoader;
+
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.*;
+
+public class PipeModelLoader implements IGeometryLoader {
+
+ public static final PipeModelLoader INSTANCE = new PipeModelLoader();
+ public static final ResourceLocation ID = GTCEu.id("pipe");
+ public static final String PRIMARY_CENTER_KEY = "center";
+ public static final Set CENTER_KEYS = Set.of(PRIMARY_CENTER_KEY, "core", "null", "none");
+
+ @Override
+ public @Nullable UnbakedPipeModel read(JsonObject json,
+ JsonDeserializationContext context) throws JsonParseException {
+ // load the inner models
+ final Map parts = new HashMap<>();
+ if (json.has("parts")) {
+ JsonObject variantsJson = GsonHelper.getAsJsonObject(json, "parts");
+ for (Map.Entry entry : variantsJson.entrySet()) {
+ Direction direction = Direction.byName(entry.getKey());
+ if (direction == null && !CENTER_KEYS.contains(entry.getKey().toLowerCase(Locale.ROOT))) {
+ throw new JsonParseException("Invalid pipe model part specifier " + entry.getKey());
+ }
+ if (direction == null && parts.get(null) != null) {
+ throw new JsonParseException("Cannot specify more than one 'center' model for a pipe model");
+ }
+
+ parts.put(direction, MachineModelLoader.GSON.fromJson(entry.getValue(), MultiVariantModel.class));
+ }
+ }
+ // and the restrictors
+ final Map restrictors = new HashMap<>();
+ if (json.has("restrictors")) {
+ JsonObject variantsJson = GsonHelper.getAsJsonObject(json, "restrictors");
+ for (Map.Entry entry : variantsJson.entrySet()) {
+ Direction direction = Direction.byName(entry.getKey());
+ if (direction == null) {
+ throw new JsonParseException("Invalid pipe model part specifier " + entry.getKey());
+ }
+ restrictors.put(direction, MachineModelLoader.GSON.fromJson(entry.getValue(), MultiVariantModel.class));
+ }
+ }
+
+ return new UnbakedPipeModel(parts, restrictors);
+ }
+}
diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/pipe/UnbakedPipeModel.java b/src/main/java/com/gregtechceu/gtceu/client/model/pipe/UnbakedPipeModel.java
new file mode 100644
index 00000000000..5ea5e68ac76
--- /dev/null
+++ b/src/main/java/com/gregtechceu/gtceu/client/model/pipe/UnbakedPipeModel.java
@@ -0,0 +1,71 @@
+package com.gregtechceu.gtceu.client.model.pipe;
+
+import net.minecraft.client.renderer.block.model.ItemOverrides;
+import net.minecraft.client.renderer.texture.TextureAtlasSprite;
+import net.minecraft.client.resources.model.*;
+import net.minecraft.core.Direction;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraftforge.client.model.geometry.IGeometryBakingContext;
+import net.minecraftforge.client.model.geometry.IUnbakedGeometry;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.IdentityHashMap;
+import java.util.Map;
+import java.util.function.Function;
+
+import static com.gregtechceu.gtceu.client.model.machine.MachineModelLoader.MISSING_MARKER;
+
+public class UnbakedPipeModel implements IUnbakedGeometry {
+
+ private final Map<@Nullable Direction, UnbakedModel> parts;
+ private final Map<@NotNull Direction, UnbakedModel> restrictors;
+
+ public UnbakedPipeModel(Map<@Nullable Direction, UnbakedModel> parts,
+ Map<@NotNull Direction, UnbakedModel> restrictors) {
+ this.parts = parts;
+ this.restrictors = restrictors;
+ }
+
+ @Override
+ public BakedModel bake(IGeometryBakingContext context, ModelBaker baker,
+ Function spriteGetter, ModelState modelState,
+ ItemOverrides overrides, ResourceLocation modelLocation) {
+ Map bakedParts = new IdentityHashMap<>();
+ this.parts.forEach((direction, unbaked) -> {
+ bakedParts.put(direction, unbaked.bake(baker, spriteGetter, modelState, modelLocation));
+ });
+ Map bakedRestrictors = new IdentityHashMap<>();
+ this.restrictors.forEach((direction, unbaked) -> {
+ bakedRestrictors.put(direction, unbaked.bake(baker, spriteGetter, modelState, modelLocation));
+ });
+ return new BakedPipeModel(bakedParts, bakedRestrictors);
+ }
+
+ @Override
+ public void resolveParents(Function resolver, IGeometryBakingContext context) {
+ UnbakedModel missingModel = resolver.apply(ModelBakery.MISSING_MODEL_LOCATION);
+
+ Map copy = new IdentityHashMap<>(this.parts);
+ copy.forEach((side, variant) -> {
+ if (variant == null || variant == MISSING_MARKER) {
+ // replace null & markers with the actual missing model
+ this.parts.put(side, missingModel);
+ } else {
+ variant.resolveParents(resolver);
+ this.parts.put(side, variant);
+ }
+ });
+ copy = new IdentityHashMap<>(this.restrictors);
+ copy.forEach((side, variant) -> {
+ if (variant == null || variant == MISSING_MARKER) {
+ // replace null & markers with the actual missing model
+ this.restrictors.put(side, missingModel);
+ } else {
+ variant.resolveParents(resolver);
+ this.restrictors.put(side, variant);
+ }
+ });
+ }
+}
diff --git a/src/main/java/com/gregtechceu/gtceu/client/model/pipe/package-info.java b/src/main/java/com/gregtechceu/gtceu/client/model/pipe/package-info.java
new file mode 100644
index 00000000000..481c46780dc
--- /dev/null
+++ b/src/main/java/com/gregtechceu/gtceu/client/model/pipe/package-info.java
@@ -0,0 +1,7 @@
+@ParametersAreNonnullByDefault
+@MethodsReturnNonnullByDefault
+package com.gregtechceu.gtceu.client.model.pipe;
+
+import net.minecraft.MethodsReturnNonnullByDefault;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/BlockEntityWithBERModelRenderer.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/BlockEntityWithBERModelRenderer.java
index 3508a6e860e..511730ca9aa 100644
--- a/src/main/java/com/gregtechceu/gtceu/client/renderer/BlockEntityWithBERModelRenderer.java
+++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/BlockEntityWithBERModelRenderer.java
@@ -45,7 +45,7 @@ public void render(T blockEntity, float partialTick,
BakedModel model = blockRenderDispatcher.getBlockModel(blockState);
if (model instanceof IBlockEntityRendererBakedModel> berModel) {
- if (berModel.getBlockEntityType() != blockEntity.getType()) return;
+ if (berModel.getBlockEntityType() != null && berModel.getBlockEntityType() != blockEntity.getType()) return;
((IBlockEntityRendererBakedModel) berModel).render(blockEntity, partialTick,
poseStack, buffer, packedLight, packedOverlay);
@@ -79,7 +79,7 @@ public boolean shouldRenderOffScreen(T blockEntity) {
BakedModel model = blockRenderDispatcher.getBlockModel(blockState);
if (model instanceof IBlockEntityRendererBakedModel> berModel) {
- if (berModel.getBlockEntityType() == blockEntity.getType()) {
+ if (berModel.getBlockEntityType() != null && berModel.getBlockEntityType() == blockEntity.getType()) {
return ((IBlockEntityRendererBakedModel) berModel).shouldRenderOffScreen(blockEntity);
}
}
@@ -92,7 +92,7 @@ public boolean shouldRender(T blockEntity, Vec3 cameraPos) {
BakedModel model = blockRenderDispatcher.getBlockModel(blockState);
if (model instanceof IBlockEntityRendererBakedModel> berModel) {
- if (berModel.getBlockEntityType() == blockEntity.getType()) {
+ if (berModel.getBlockEntityType() != null && berModel.getBlockEntityType() == blockEntity.getType()) {
return ((IBlockEntityRendererBakedModel) berModel).shouldRender(blockEntity, cameraPos);
}
}
diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/GTRenderTypes.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/GTRenderTypes.java
index c36a41a91e6..ce3fea89a5d 100644
--- a/src/main/java/com/gregtechceu/gtceu/client/renderer/GTRenderTypes.java
+++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/GTRenderTypes.java
@@ -22,6 +22,13 @@ public class GTRenderTypes extends RenderType {
.setShaderState(RenderStateShard.POSITION_COLOR_SHADER)
.setTransparencyState(RenderStateShard.TRANSLUCENT_TRANSPARENCY)
.createCompositeState(false));
+ private static final RenderType MONITOR = RenderType.create("central_monitor",
+ DefaultVertexFormat.POSITION_COLOR, VertexFormat.Mode.QUADS, 256, false, false,
+ RenderType.CompositeState.builder()
+ .setCullState(NO_CULL)
+ .setShaderState(POSITION_COLOR_SHADER)
+ .setTransparencyState(TRANSLUCENT_TRANSPARENCY)
+ .createCompositeState(false));
private static final Function GUI_TEXTURE = Util.memoize((texture) -> {
return create("gui_texture", DefaultVertexFormat.POSITION_COLOR_TEX_LIGHTMAP, VertexFormat.Mode.QUADS,
RenderType.TRANSIENT_BUFFER_SIZE, false, true,
@@ -42,6 +49,10 @@ public static RenderType getLightRing() {
return LIGHT_RING;
}
+ public static RenderType getMonitor() {
+ return MONITOR;
+ }
+
public static RenderType guiTexture(ResourceLocation texture) {
return GUI_TEXTURE.apply(texture);
}
diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/block/LampItemRenderer.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/block/LampItemRenderer.java
new file mode 100644
index 00000000000..853f9a3e361
--- /dev/null
+++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/block/LampItemRenderer.java
@@ -0,0 +1,61 @@
+package com.gregtechceu.gtceu.client.renderer.block;
+
+import com.gregtechceu.gtceu.api.item.LampBlockItem;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer;
+import net.minecraft.client.renderer.MultiBufferSource;
+import net.minecraft.client.renderer.block.BlockRenderDispatcher;
+import net.minecraft.client.renderer.entity.ItemRenderer;
+import net.minecraft.client.resources.model.BakedModel;
+import net.minecraft.world.item.ItemDisplayContext;
+import net.minecraft.world.item.ItemStack;
+import net.minecraft.world.level.block.state.BlockState;
+
+import com.mojang.blaze3d.vertex.PoseStack;
+import com.mojang.blaze3d.vertex.VertexConsumer;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * All this renderer does is refer rendering to the correct block model based on the lamp item's NBT.
+ * Without it, all item variants would look like the default 'lit, with bloom' one.
+ */
+public class LampItemRenderer extends BlockEntityWithoutLevelRenderer {
+
+ private static LampItemRenderer INSTANCE = null;
+
+ public static LampItemRenderer getInstance() {
+ if (INSTANCE == null) {
+ INSTANCE = new LampItemRenderer();
+ }
+ return INSTANCE;
+ }
+
+ protected final ItemRenderer itemRenderer;
+ protected final BlockRenderDispatcher blockRenderer;
+
+ protected LampItemRenderer() {
+ super(Minecraft.getInstance().getBlockEntityRenderDispatcher(),
+ Minecraft.getInstance().getEntityModels());
+ this.itemRenderer = Minecraft.getInstance().getItemRenderer();
+ this.blockRenderer = Minecraft.getInstance().getBlockRenderer();
+ }
+
+ @Override
+ public void renderByItem(@NotNull ItemStack stack, @NotNull ItemDisplayContext displayContext,
+ @NotNull PoseStack poseStack, @NotNull MultiBufferSource buffer,
+ int packedLight, int packedOverlay) {
+ if (!(stack.getItem() instanceof LampBlockItem item)) {
+ return;
+ }
+ BlockState state = item.getStateFromStack(stack, null);
+ BakedModel p_model = blockRenderer.getBlockModel(state);
+
+ for (var model : p_model.getRenderPasses(stack, true)) {
+ for (var rendertype : model.getRenderTypes(stack, true)) {
+ VertexConsumer foilBuffer = ItemRenderer.getFoilBufferDirect(buffer, rendertype, true, stack.hasFoil());
+ itemRenderer.renderModelLists(model, stack, packedLight, packedOverlay, poseStack, foilBuffer);
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/block/LampRenderer.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/block/LampRenderer.java
deleted file mode 100644
index a9552b7ea83..00000000000
--- a/src/main/java/com/gregtechceu/gtceu/client/renderer/block/LampRenderer.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package com.gregtechceu.gtceu.client.renderer.block;
-
-import com.gregtechceu.gtceu.GTCEu;
-import com.gregtechceu.gtceu.common.block.LampBlock;
-
-import com.lowdragmc.lowdraglib.client.model.custommodel.ICTMPredicate;
-import com.lowdragmc.lowdraglib.client.renderer.impl.IModelRenderer;
-
-import net.minecraft.core.BlockPos;
-import net.minecraft.core.Direction;
-import net.minecraft.world.level.BlockAndTintGetter;
-import net.minecraft.world.level.block.state.BlockState;
-import net.minecraftforge.api.distmarker.Dist;
-import net.minecraftforge.api.distmarker.OnlyIn;
-
-public class LampRenderer extends IModelRenderer implements ICTMPredicate {
-
- public LampRenderer(LampBlock lamp, BlockState state) {
- super(GTCEu.id("block/%s%s_lamp%s%s".formatted(
- lamp.color,
- lamp.bordered ? "" : "_borderless",
- state.getValue(LampBlock.LIGHT) ? "" : "_off",
- state.getValue(LampBlock.LIGHT) && state.getValue(LampBlock.BLOOM) ? "_bloom" : "")));
- }
-
- @Override
- public boolean isConnected(BlockAndTintGetter level, BlockState state, BlockPos pos,
- BlockState sourceState, BlockPos sourcePos, Direction side) {
- var stateAppearance = state.getAppearance(level, pos, side, sourceState, sourcePos);
- var sourceStateAppearance = sourceState.getAppearance(level, sourcePos, side, state, pos);
- return stateAppearance.getBlock() == sourceStateAppearance.getBlock();
- }
-
- @Override
- @OnlyIn(Dist.CLIENT)
- public boolean useAO() {
- return true;
- }
-
- @Override
- public boolean reBakeCustomQuads() {
- return true;
- }
-
- @Override
- public float reBakeCustomQuadsOffset() {
- return 0.0f;
- }
-}
diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/block/MaterialBlockRenderer.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/block/MaterialBlockRenderer.java
index 193c889179f..f6559abfce2 100644
--- a/src/main/java/com/gregtechceu/gtceu/client/renderer/block/MaterialBlockRenderer.java
+++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/block/MaterialBlockRenderer.java
@@ -15,7 +15,6 @@
public class MaterialBlockRenderer {
- public static final String LAYER_2_SUFFIX = "_layer2";
private static final Set MODELS = new HashSet<>();
public static void create(Block block, MaterialIconType type, MaterialIconSet iconSet) {
@@ -25,12 +24,11 @@ public static void create(Block block, MaterialIconType type, MaterialIconSet ic
public static void reinitModels() {
for (MaterialBlockRenderer model : MODELS) {
ResourceLocation blockId = BuiltInRegistries.BLOCK.getKey(model.block);
- ResourceLocation modelId = blockId.withPrefix("block/");
- GTDynamicResourcePack.addBlockModel(blockId,
- new DelegatedModel(model.type.getBlockModelPath(model.iconSet, true)));
+ ResourceLocation modelId = model.type.getBlockModelPath(model.iconSet, true);
+
GTDynamicResourcePack.addBlockState(blockId, BlockModelGenerators.createSimpleBlock(model.block, modelId));
GTDynamicResourcePack.addItemModel(BuiltInRegistries.ITEM.getKey(model.block.asItem()),
- new DelegatedModel(ModelLocationUtils.getModelLocation(model.block)));
+ new DelegatedModel(modelId));
}
}
diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/block/OreBlockRenderer.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/block/OreBlockRenderer.java
index 563f1bc6682..8453f93fbce 100644
--- a/src/main/java/com/gregtechceu/gtceu/client/renderer/block/OreBlockRenderer.java
+++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/block/OreBlockRenderer.java
@@ -3,10 +3,12 @@
import com.gregtechceu.gtceu.GTCEu;
import com.gregtechceu.gtceu.api.block.MaterialBlock;
import com.gregtechceu.gtceu.api.data.chemical.material.Material;
-import com.gregtechceu.gtceu.api.data.chemical.material.properties.OreProperty;
-import com.gregtechceu.gtceu.api.data.chemical.material.properties.PropertyKey;
+import com.gregtechceu.gtceu.api.data.chemical.material.info.MaterialIconSet;
+import com.gregtechceu.gtceu.api.data.chemical.material.info.MaterialIconType;
import com.gregtechceu.gtceu.api.data.tag.TagPrefix;
import com.gregtechceu.gtceu.data.pack.GTDynamicResourcePack;
+import com.gregtechceu.gtceu.utils.memoization.GTMemoizer;
+import com.gregtechceu.gtceu.utils.memoization.function.MemoizedBiFunction;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.client.Minecraft;
@@ -14,22 +16,32 @@
import net.minecraft.data.models.BlockModelGenerators;
import net.minecraft.data.models.model.*;
import net.minecraft.resources.ResourceLocation;
+import net.minecraft.server.packs.resources.Resource;
+import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.util.GsonHelper;
-import com.google.common.base.Preconditions;
import com.google.gson.JsonObject;
+import org.jetbrains.annotations.ApiStatus;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.HashSet;
+import java.util.Optional;
import java.util.Set;
@MethodsReturnNonnullByDefault
public class OreBlockRenderer {
- private static final Set MODELS = new HashSet<>();
+ protected static final Set MODELS = new HashSet<>();
- private final MaterialBlock block;
+ protected static final JsonObject NULL_ELEMENT_MARKER = new JsonObject();
+ protected static final MemoizedBiFunction TEMPLATE_MODEL_CACHE = GTMemoizer
+ .memoizeFunctionWeakIdent(OreBlockRenderer::loadTemplateOreModel);
+
+ // First format key is material set name, 2nd is stone type prefix's name, 3rd is icon type's name
+ public static final String ORE_MODEL_NAME_FORMAT = "block/material_sets/%s/ores/%s/%s";
+
+ protected final MaterialBlock block;
public static void create(MaterialBlock block) {
MODELS.add(new OreBlockRenderer(block));
@@ -39,54 +51,81 @@ public OreBlockRenderer(MaterialBlock block) {
this.block = block;
}
+ @ApiStatus.Internal
public static void reinitModels() {
+ // first set up all the stone types for all tag prefixes
+ for (MaterialIconSet iconSet : MaterialIconSet.ICON_SETS.values()) {
+ for (var entry : TagPrefix.ORES.entrySet()) {
+ copyOreModelWithBaseStone(entry.getKey(), entry.getValue(), MaterialIconType.ore, iconSet);
+ copyOreModelWithBaseStone(entry.getKey(), entry.getValue(), MaterialIconType.oreEmissive, iconSet);
+ // TODO uncomment if/when small ores are added
+ // copyOreModelWithBaseStone(entry.getKey(), entry.getValue(), MaterialIconType.oreSmall, iconSet);
+ }
+ }
+
+ // then create block state JSONs for all ore blocks with those models
for (OreBlockRenderer model : MODELS) {
+ Material material = model.block.material;
+ TagPrefix tagPrefix = model.block.tagPrefix;
+ MaterialIconSet iconSet = material.getMaterialIconSet();
+ MaterialIconType iconType = tagPrefix.getMaterialIconType(material);
+
ResourceLocation blockId = BuiltInRegistries.BLOCK.getKey(model.block);
- ResourceLocation modelId = blockId.withPrefix("block/");
- OreBlockRenderer.cloneBlockModel(blockId, model.block.tagPrefix, model.block.material);
+ ResourceLocation modelId = GTCEu.id(ORE_MODEL_NAME_FORMAT
+ .formatted(iconSet.name, tagPrefix.name, iconType.name()));
+
GTDynamicResourcePack.addBlockState(blockId, BlockModelGenerators.createSimpleBlock(model.block, modelId));
GTDynamicResourcePack.addItemModel(BuiltInRegistries.ITEM.getKey(model.block.asItem()),
- new DelegatedModel(ModelLocationUtils.getModelLocation(model.block)));
+ new DelegatedModel(modelId));
}
- }
- /**
- * Clones & modifies the base JSON for a single ore block.
- *
- * @param modelId the model id (usually {@code gtceu:block/})
- * @param prefix the TagPrefix of the block being added.
- * @param material the material of the block being added. must have an ore property.
- */
- public static void cloneBlockModel(ResourceLocation modelId, TagPrefix prefix, Material material) {
- OreProperty prop = material.getProperty(PropertyKey.ORE);
- Preconditions.checkNotNull(prop,
- "material %s has no ore property, but needs one for an ore model!".formatted(material.getName()));
+ TEMPLATE_MODEL_CACHE.getCache().clear();
+ }
+ /// This is called for every combination of tag prefix + icon type + icon set
+ protected static void copyOreModelWithBaseStone(TagPrefix tagPrefix, TagPrefix.OreType oreType,
+ MaterialIconType iconType, MaterialIconSet iconSet) {
// read the base ore model JSON
JsonObject original;
- try (BufferedReader reader = Minecraft.getInstance().getResourceManager()
- .openAsReader(GTCEu.id("models/block/ore%s.json".formatted(prop.isEmissive() ? "_emissive" : "")))) {
- original = GsonHelper.parse(reader, true);
- } catch (IOException e) {
- throw new RuntimeException(e);
+ try {
+ original = TEMPLATE_MODEL_CACHE.apply(iconType, iconSet);
+ } catch (RuntimeException e) {
+ GTCEu.LOGGER.error("Could not load template block model for ore type {}, icon type '{}', icon set '{}'",
+ tagPrefix.name, iconType.name(), iconSet.name, e);
+ return;
+ }
+ if (original == NULL_ELEMENT_MARKER) {
+ // if the icon set doesn't have an ore model (somehow...), skip it
+ return;
}
- // clone it
+ // copy it
JsonObject newJson = original.deepCopy();
- JsonObject children = newJson.getAsJsonObject("children");
- // add the base stone texture.
- children.getAsJsonObject("base_stone").addProperty("parent",
- TagPrefix.ORES.get(prefix).baseModelLocation().toString());
+ // add the base stone model.
+ newJson.getAsJsonObject("children")
+ .getAsJsonObject("base_stone")
+ .addProperty("parent", oreType.baseModelLocation().toString());
+
+ GTDynamicResourcePack.addBlockModel(
+ GTCEu.id(ORE_MODEL_NAME_FORMAT.formatted(iconSet.name, tagPrefix.name, iconType.name())), newJson);
+ }
- ResourceLocation layer0 = prefix.materialIconType().getBlockTexturePath(material.getMaterialIconSet(), true);
- ResourceLocation layer1 = prefix.materialIconType().getBlockTexturePath(material.getMaterialIconSet(), "layer2",
- true);
- JsonObject oresTextures = children.getAsJsonObject("ore_texture").getAsJsonObject("textures");
- oresTextures.addProperty("layer0", layer0.toString());
- oresTextures.addProperty("layer1", layer1.toString());
+ private static JsonObject loadTemplateOreModel(MaterialIconType iconType, MaterialIconSet iconSet) {
+ ResourceLocation baseModelPath = iconType.getBlockModelPath(iconSet, true);
+ baseModelPath = GTDynamicResourcePack.MODEL_ID_CONVERTER.idToFile(baseModelPath);
- newJson.getAsJsonObject("textures").addProperty("particle", layer0.toString());
+ ResourceManager resourceManager = Minecraft.getInstance().getResourceManager();
+ Optional modelResource = resourceManager.getResource(baseModelPath);
- GTDynamicResourcePack.addBlockModel(modelId, newJson);
+ if (modelResource.isEmpty()) {
+ // if the icon set doesn't have an ore model (somehow...), skip it gracefully
+ return NULL_ELEMENT_MARKER;
+ }
+ // read & cache the base ore model JSON
+ try (BufferedReader reader = modelResource.get().openAsReader()) {
+ return GsonHelper.parse(reader, true);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
}
}
diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/block/PipeBlockRenderer.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/block/PipeBlockRenderer.java
deleted file mode 100644
index b06ac84c7ce..00000000000
--- a/src/main/java/com/gregtechceu/gtceu/client/renderer/block/PipeBlockRenderer.java
+++ /dev/null
@@ -1,149 +0,0 @@
-package com.gregtechceu.gtceu.client.renderer.block;
-
-import com.gregtechceu.gtceu.GTCEu;
-import com.gregtechceu.gtceu.api.data.tag.TagPrefix;
-import com.gregtechceu.gtceu.api.pipenet.IPipeNode;
-import com.gregtechceu.gtceu.client.model.PipeModel;
-import com.gregtechceu.gtceu.client.renderer.cover.ICoverableRenderer;
-import com.gregtechceu.gtceu.client.util.GTQuadTransformers;
-import com.gregtechceu.gtceu.common.data.GTMaterialBlocks;
-import com.gregtechceu.gtceu.utils.GTUtil;
-
-import com.lowdragmc.lowdraglib.client.renderer.IRenderer;
-
-import net.minecraft.client.Minecraft;
-import net.minecraft.client.color.block.BlockColors;
-import net.minecraft.client.renderer.MultiBufferSource;
-import net.minecraft.client.renderer.RenderType;
-import net.minecraft.client.renderer.block.model.BakedQuad;
-import net.minecraft.client.renderer.texture.TextureAtlas;
-import net.minecraft.client.renderer.texture.TextureAtlasSprite;
-import net.minecraft.client.resources.model.BakedModel;
-import net.minecraft.core.BlockPos;
-import net.minecraft.core.Direction;
-import net.minecraft.resources.ResourceLocation;
-import net.minecraft.util.RandomSource;
-import net.minecraft.world.item.ItemDisplayContext;
-import net.minecraft.world.item.ItemStack;
-import net.minecraft.world.level.BlockAndTintGetter;
-import net.minecraft.world.level.block.state.BlockState;
-import net.minecraftforge.api.distmarker.Dist;
-import net.minecraftforge.api.distmarker.OnlyIn;
-import net.minecraftforge.client.model.data.ModelData;
-
-import com.mojang.blaze3d.vertex.PoseStack;
-import lombok.Getter;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.LinkedList;
-import java.util.List;
-import java.util.function.Consumer;
-
-import static com.lowdragmc.lowdraglib.client.model.forge.LDLRendererModel.RendererBakedModel.*;
-
-public class PipeBlockRenderer implements IRenderer, ICoverableRenderer {
-
- @Getter
- PipeModel pipeModel;
-
- public PipeBlockRenderer(PipeModel pipeModel) {
- this.pipeModel = pipeModel;
- if (GTCEu.isClientSide()) {
- registerEvent();
- }
- }
-
- @Override
- @OnlyIn(Dist.CLIENT)
- public void renderItem(ItemStack stack,
- ItemDisplayContext transformType,
- boolean leftHand, PoseStack matrixStack,
- MultiBufferSource buffer, int combinedLight,
- int combinedOverlay, BakedModel model) {
- pipeModel.renderItem(stack, transformType, leftHand, matrixStack, buffer, combinedLight, combinedOverlay,
- model);
- }
-
- @Override
- public boolean useAO() {
- return true;
- }
-
- @Override
- @OnlyIn(Dist.CLIENT)
- public boolean useBlockLight(ItemStack stack) {
- return true;
- }
-
- @Override
- @OnlyIn(Dist.CLIENT)
- public List renderModel(BlockAndTintGetter level, BlockPos pos, BlockState state, Direction side,
- RandomSource rand) {
- if (level == null) {
- return pipeModel.bakeQuads(side, PipeModel.ITEM_CONNECTIONS, 0);
- }
- if (!(level.getBlockEntity(pos) instanceof IPipeNode, ?> pipeNode)) {
- return pipeModel.bakeQuads(side, 0, 0);
- }
- RenderType renderType = CURRENT_RENDER_TYPE.get();
- ModelData modelData = CURRENT_MODEL_DATA.get().get(MODEL_DATA);
- if (modelData == null) modelData = ModelData.EMPTY;
-
- List quads = new LinkedList<>();
-
- if (renderType == null || renderType == RenderType.cutoutMipped()) {
- quads.addAll(pipeModel.bakeQuads(side, pipeNode.getVisualConnections(), pipeNode.getBlockedConnections()));
- }
- ICoverableRenderer.super.renderCovers(quads, pipeNode.getCoverContainer(), pos, level, side, rand,
- modelData, renderType);
-
- if (pipeNode.getFrameMaterial().isNull() || (renderType != null && renderType != RenderType.translucent())) {
- return quads;
- }
-
- BlockState frameState = GTMaterialBlocks.MATERIAL_BLOCKS.get(TagPrefix.frameGt, pipeNode.getFrameMaterial())
- .getDefaultState();
- BakedModel frameModel = Minecraft.getInstance().getBlockRenderer().getBlockModel(frameState);
-
- modelData = frameModel.getModelData(level, pos, frameState, modelData);
-
- List frameQuads = new LinkedList<>();
- if (side == null || pipeNode.getCoverContainer().getCoverAtSide(side) == null) {
- frameQuads.addAll(frameModel.getQuads(state, side, rand, modelData, renderType));
- }
- if (side == null) {
- for (Direction face : GTUtil.DIRECTIONS) {
- if (pipeNode.getCoverContainer().getCoverAtSide(face) != null) {
- continue;
- }
- frameQuads.addAll(frameModel.getQuads(state, face, rand, modelData, renderType));
- }
- }
-
- // bake all the quads' tint colors into the vertices
- BlockColors blockColors = Minecraft.getInstance().getBlockColors();
- for (BakedQuad frameQuad : frameQuads) {
- if (frameQuad.isTinted()) {
- int color = blockColors.getColor(frameState, level, pos, frameQuad.getTintIndex());
- frameQuad = GTQuadTransformers.setColor(frameQuad, color, true);
- }
- quads.add(frameQuad);
- }
- return quads;
- }
-
- @NotNull
- @Override
- @OnlyIn(Dist.CLIENT)
- public TextureAtlasSprite getParticleTexture() {
- return pipeModel.getParticleTexture();
- }
-
- @Override
- @OnlyIn(Dist.CLIENT)
- public void onPrepareTextureAtlas(ResourceLocation atlasName, Consumer register) {
- if (atlasName.equals(TextureAtlas.LOCATION_BLOCKS)) {
- pipeModel.registerTextureAtlas(register);
- }
- }
-}
diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/CentralMonitorRender.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/CentralMonitorRender.java
index 6e04229890f..68719e58cba 100644
--- a/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/CentralMonitorRender.java
+++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/CentralMonitorRender.java
@@ -54,7 +54,7 @@ public void render(CentralMonitorMachine machine, float partialTick, PoseStack p
continue;
}
poseStack.pushPose();
- module.getRenderer(group.getItemStackHandler().getStackInSlot(0), machine, group)
+ module.getRenderer(group.getItemStackHandler().getStackInSlot(0))
.render(machine, group, partialTick, poseStack, buffer, packedLight, packedOverlay);
poseStack.popPose();
}
diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/monitor/MonitorTextRenderer.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/monitor/MonitorTextRenderer.java
index 029a85b5223..01865761749 100644
--- a/src/main/java/com/gregtechceu/gtceu/client/renderer/monitor/MonitorTextRenderer.java
+++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/monitor/MonitorTextRenderer.java
@@ -1,5 +1,7 @@
package com.gregtechceu.gtceu.client.renderer.monitor;
+import com.gregtechceu.gtceu.api.placeholder.GraphicsComponent;
+import com.gregtechceu.gtceu.api.placeholder.MultiLineComponent;
import com.gregtechceu.gtceu.common.machine.multiblock.electric.CentralMonitorMachine;
import com.gregtechceu.gtceu.common.machine.multiblock.electric.monitor.MonitorGroup;
@@ -10,18 +12,17 @@
import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.Component;
import net.minecraft.util.FormattedCharSequence;
+import net.minecraft.util.Mth;
import com.mojang.blaze3d.vertex.PoseStack;
-import java.util.List;
-
public class MonitorTextRenderer implements IMonitorRenderer {
private static final float TEXT_SCALE = 1 / 144f;
- private final List text;
+ private final MultiLineComponent text;
private final float scale;
- public MonitorTextRenderer(List text, double scale) {
+ public MonitorTextRenderer(MultiLineComponent text, double scale) {
this.text = text;
this.scale = (float) scale;
}
@@ -34,6 +35,23 @@ public void render(CentralMonitorMachine machine, MonitorGroup group, float part
int row = 0;
int columns = group.getRow(0, machine::toRelative).size();
poseStack.translate(rel.getX(), rel.getY(), rel.getZ());
+ int layer = 0;
+ for (GraphicsComponent graphics : text.getGraphics()) {
+ if (graphics.x() < 0 || graphics.y() < 0) continue;
+ float maxX = graphics.x2();
+ float maxY = graphics.y2();
+ if (maxX == Math.floor(maxX)) maxX--;
+ if (maxY == Math.floor(maxY)) maxY--;
+ BlockPos relativePos = rel.offset(Mth.floor(maxX), -Mth.floor(maxY), 0);
+ if (!group.getMonitorPositions().stream().map(machine::toRelative).toList().contains(relativePos))
+ continue;
+ poseStack.pushPose();
+ poseStack.translate(graphics.x(), graphics.y(), layer * .001f);
+ graphics.get().render(machine, group, partialTick, poseStack, buffer, packedLight, packedOverlay);
+ poseStack.popPose();
+ layer++;
+ }
+ poseStack.translate(0, 0, layer * .001f);
poseStack.scale(TEXT_SCALE * scale, TEXT_SCALE * scale, TEXT_SCALE * scale);
float y = 9;
for (Component s : text) {
diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/placeholder/ModulePlaceholderRenderer.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/placeholder/ModulePlaceholderRenderer.java
new file mode 100644
index 00000000000..1df2c9ef08f
--- /dev/null
+++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/placeholder/ModulePlaceholderRenderer.java
@@ -0,0 +1,31 @@
+package com.gregtechceu.gtceu.client.renderer.placeholder;
+
+import com.gregtechceu.gtceu.api.item.IComponentItem;
+import com.gregtechceu.gtceu.api.item.component.IItemComponent;
+import com.gregtechceu.gtceu.api.item.component.IMonitorModuleItem;
+import com.gregtechceu.gtceu.api.placeholder.IPlaceholderRenderer;
+import com.gregtechceu.gtceu.common.machine.multiblock.electric.CentralMonitorMachine;
+import com.gregtechceu.gtceu.common.machine.multiblock.electric.monitor.MonitorGroup;
+
+import net.minecraft.client.renderer.MultiBufferSource;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.world.item.ItemStack;
+
+import com.mojang.blaze3d.vertex.PoseStack;
+
+public class ModulePlaceholderRenderer implements IPlaceholderRenderer {
+
+ @Override
+ public void render(CentralMonitorMachine machine, MonitorGroup group, float partialTick, PoseStack poseStack,
+ MultiBufferSource buffer, int packedLight, int packedOverlay, CompoundTag tag) {
+ ItemStack stack = ItemStack.of(tag);
+ if (stack.getItem() instanceof IComponentItem componentItem) {
+ for (IItemComponent component : componentItem.getComponents()) {
+ if (component instanceof IMonitorModuleItem module) {
+ module.getRenderer(stack).render(machine, group, partialTick, poseStack, buffer, packedLight,
+ packedOverlay);
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/placeholder/QuadPlaceholderRenderer.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/placeholder/QuadPlaceholderRenderer.java
new file mode 100644
index 00000000000..2d347e1d960
--- /dev/null
+++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/placeholder/QuadPlaceholderRenderer.java
@@ -0,0 +1,35 @@
+package com.gregtechceu.gtceu.client.renderer.placeholder;
+
+import com.gregtechceu.gtceu.api.placeholder.IPlaceholderRenderer;
+import com.gregtechceu.gtceu.client.renderer.GTRenderTypes;
+import com.gregtechceu.gtceu.common.machine.multiblock.electric.CentralMonitorMachine;
+import com.gregtechceu.gtceu.common.machine.multiblock.electric.monitor.MonitorGroup;
+
+import net.minecraft.client.renderer.LightTexture;
+import net.minecraft.client.renderer.MultiBufferSource;
+import net.minecraft.nbt.CompoundTag;
+
+import com.mojang.blaze3d.vertex.PoseStack;
+import com.mojang.blaze3d.vertex.VertexConsumer;
+import org.joml.Matrix4f;
+
+public class QuadPlaceholderRenderer implements IPlaceholderRenderer {
+
+ @Override
+ public void render(CentralMonitorMachine machine, MonitorGroup group, float partialTick, PoseStack poseStack,
+ MultiBufferSource buffer, int packedLight, int packedOverlay, CompoundTag tag) {
+ poseStack.pushPose();
+ VertexConsumer consumer = buffer.getBuffer(GTRenderTypes.getMonitor());
+ Matrix4f pose = poseStack.last().pose();
+
+ consumer.vertex(pose, tag.getFloat("x1"), tag.getFloat("y1"), 0).color(tag.getInt("color1"))
+ .uv2(LightTexture.FULL_BRIGHT).endVertex();
+ consumer.vertex(pose, tag.getFloat("x2"), tag.getFloat("y2"), 0).color(tag.getInt("color2"))
+ .uv2(LightTexture.FULL_BRIGHT).endVertex();
+ consumer.vertex(pose, tag.getFloat("x3"), tag.getFloat("y3"), 0).color(tag.getInt("color3"))
+ .uv2(LightTexture.FULL_BRIGHT).endVertex();
+ consumer.vertex(pose, tag.getFloat("x4"), tag.getFloat("y4"), 0).color(tag.getInt("color4"))
+ .uv2(LightTexture.FULL_BRIGHT).endVertex();
+ poseStack.popPose();
+ }
+}
diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/placeholder/RectPlaceholderRenderer.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/placeholder/RectPlaceholderRenderer.java
new file mode 100644
index 00000000000..1e2c5dbff8b
--- /dev/null
+++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/placeholder/RectPlaceholderRenderer.java
@@ -0,0 +1,34 @@
+package com.gregtechceu.gtceu.client.renderer.placeholder;
+
+import com.gregtechceu.gtceu.api.placeholder.IPlaceholderRenderer;
+import com.gregtechceu.gtceu.client.renderer.GTRenderTypes;
+import com.gregtechceu.gtceu.common.machine.multiblock.electric.CentralMonitorMachine;
+import com.gregtechceu.gtceu.common.machine.multiblock.electric.monitor.MonitorGroup;
+
+import net.minecraft.client.renderer.LightTexture;
+import net.minecraft.client.renderer.MultiBufferSource;
+import net.minecraft.nbt.CompoundTag;
+
+import com.mojang.blaze3d.vertex.PoseStack;
+import com.mojang.blaze3d.vertex.VertexConsumer;
+import org.joml.Matrix4f;
+
+public class RectPlaceholderRenderer implements IPlaceholderRenderer {
+
+ @Override
+ public void render(CentralMonitorMachine machine, MonitorGroup group, float partialTick, PoseStack poseStack,
+ MultiBufferSource buffer, int packedLight, int packedOverlay, CompoundTag tag) {
+ poseStack.pushPose();
+ VertexConsumer consumer = buffer.getBuffer(GTRenderTypes.getMonitor());
+ Matrix4f pose = poseStack.last().pose();
+ float minX = 0, maxX = tag.getFloat("width");
+ float minY = 0, maxY = tag.getFloat("height");
+ int color = tag.getInt("color");
+
+ consumer.vertex(pose, minX, maxY, 0).color(color).uv2(LightTexture.FULL_BRIGHT).endVertex();
+ consumer.vertex(pose, maxX, maxY, 0).color(color).uv2(LightTexture.FULL_BRIGHT).endVertex();
+ consumer.vertex(pose, maxX, minY, 0).color(color).uv2(LightTexture.FULL_BRIGHT).endVertex();
+ consumer.vertex(pose, minX, minY, 0).color(color).uv2(LightTexture.FULL_BRIGHT).endVertex();
+ poseStack.popPose();
+ }
+}
diff --git a/src/main/java/com/gregtechceu/gtceu/common/block/CableBlock.java b/src/main/java/com/gregtechceu/gtceu/common/block/CableBlock.java
index e1542d349f3..1abacd672cb 100644
--- a/src/main/java/com/gregtechceu/gtceu/common/block/CableBlock.java
+++ b/src/main/java/com/gregtechceu/gtceu/common/block/CableBlock.java
@@ -11,7 +11,8 @@
import com.gregtechceu.gtceu.api.data.tag.TagPrefix;
import com.gregtechceu.gtceu.api.item.tool.GTToolType;
import com.gregtechceu.gtceu.api.pipenet.IPipeNode;
-import com.gregtechceu.gtceu.client.model.PipeModel;
+import com.gregtechceu.gtceu.api.registry.registrate.provider.GTBlockstateProvider;
+import com.gregtechceu.gtceu.client.model.pipe.PipeModel;
import com.gregtechceu.gtceu.common.blockentity.CableBlockEntity;
import com.gregtechceu.gtceu.common.data.GTBlockEntities;
import com.gregtechceu.gtceu.common.data.GTDamageTypes;
@@ -54,7 +55,7 @@ public CableBlock(Properties properties, Insulation insulation, Material materia
@Override
public int tinted(BlockState state, @Nullable BlockAndTintGetter level, @Nullable BlockPos pos, int index) {
- if (pipeType.isCable && index == 0) {
+ if (pipeType.isCable && (index == 0 || index == 2)) {
return 0x404040;
}
return super.tinted(state, level, pos, index);
@@ -94,8 +95,8 @@ public boolean canPipeConnectToBlock(IPipeNode selfT
}
@Override
- protected PipeModel createPipeModel() {
- return pipeType.createPipeModel(material);
+ public PipeModel createPipeModel(GTBlockstateProvider provider) {
+ return pipeType.createPipeModel(this, material, provider);
}
@Override
diff --git a/src/main/java/com/gregtechceu/gtceu/common/block/DuctPipeBlock.java b/src/main/java/com/gregtechceu/gtceu/common/block/DuctPipeBlock.java
index c7e7fd5b683..95cffc6ee83 100644
--- a/src/main/java/com/gregtechceu/gtceu/common/block/DuctPipeBlock.java
+++ b/src/main/java/com/gregtechceu/gtceu/common/block/DuctPipeBlock.java
@@ -1,5 +1,6 @@
package com.gregtechceu.gtceu.common.block;
+import com.gregtechceu.gtceu.GTCEu;
import com.gregtechceu.gtceu.api.block.PipeBlock;
import com.gregtechceu.gtceu.api.blockentity.PipeBlockEntity;
import com.gregtechceu.gtceu.api.capability.forge.GTCapability;
@@ -7,8 +8,8 @@
import com.gregtechceu.gtceu.api.machine.feature.IEnvironmentalHazardCleaner;
import com.gregtechceu.gtceu.api.machine.feature.IEnvironmentalHazardEmitter;
import com.gregtechceu.gtceu.api.pipenet.IPipeNode;
-import com.gregtechceu.gtceu.client.model.PipeModel;
-import com.gregtechceu.gtceu.client.renderer.block.PipeBlockRenderer;
+import com.gregtechceu.gtceu.api.registry.registrate.provider.GTBlockstateProvider;
+import com.gregtechceu.gtceu.client.model.pipe.PipeModel;
import com.gregtechceu.gtceu.common.blockentity.DuctPipeBlockEntity;
import com.gregtechceu.gtceu.common.data.GTBlockEntities;
import com.gregtechceu.gtceu.common.pipelike.duct.DuctPipeProperties;
@@ -36,15 +37,11 @@
@MethodsReturnNonnullByDefault
public class DuctPipeBlock extends PipeBlock {
- public final PipeBlockRenderer renderer;
- public final PipeModel model;
private final DuctPipeProperties properties;
public DuctPipeBlock(Properties properties, DuctPipeType type) {
super(properties, type);
this.properties = new DuctPipeProperties(type.getRateMultiplier());
- this.model = type.createPipeModel();
- this.renderer = new PipeBlockRenderer(this.model);
}
@Override
@@ -75,13 +72,9 @@ public DuctPipeProperties getFallbackType() {
}
@Override
- public @Nullable PipeBlockRenderer getRenderer(BlockState state) {
- return renderer;
- }
-
- @Override
- protected PipeModel getPipeModel() {
- return model;
+ public PipeModel createPipeModel(GTBlockstateProvider provider) {
+ return new PipeModel(this, provider, this.pipeType.getThickness(),
+ GTCEu.id("block/pipe/pipe_duct_side"), GTCEu.id("block/pipe/pipe_duct_in"));
}
@Override
diff --git a/src/main/java/com/gregtechceu/gtceu/common/block/FluidPipeBlock.java b/src/main/java/com/gregtechceu/gtceu/common/block/FluidPipeBlock.java
index 3b0173a574b..1af49f770c2 100644
--- a/src/main/java/com/gregtechceu/gtceu/common/block/FluidPipeBlock.java
+++ b/src/main/java/com/gregtechceu/gtceu/common/block/FluidPipeBlock.java
@@ -8,7 +8,8 @@
import com.gregtechceu.gtceu.api.data.chemical.material.properties.PropertyKey;
import com.gregtechceu.gtceu.api.data.tag.TagPrefix;
import com.gregtechceu.gtceu.api.pipenet.IPipeNode;
-import com.gregtechceu.gtceu.client.model.PipeModel;
+import com.gregtechceu.gtceu.api.registry.registrate.provider.GTBlockstateProvider;
+import com.gregtechceu.gtceu.client.model.pipe.PipeModel;
import com.gregtechceu.gtceu.common.blockentity.FluidPipeBlockEntity;
import com.gregtechceu.gtceu.common.data.GTBlockEntities;
import com.gregtechceu.gtceu.common.data.GTMaterialBlocks;
@@ -82,8 +83,8 @@ public boolean canPipeConnectToBlock(IPipeNode renderers = new IdentityHashMap<>();
public LampBlock(Properties properties, DyeColor color, boolean bordered) {
super(properties);
@@ -65,9 +60,6 @@ public LampBlock(Properties properties, DyeColor color, boolean bordered) {
.setValue(LIGHT, true)
.setValue(INVERTED, false)
.setValue(POWERED, false));
- for (BlockState state : getStateDefinition().getPossibleStates()) {
- renderers.put(state, new LampRenderer(this, state));
- }
}
public static boolean isLightActive(BlockState state) {
@@ -126,6 +118,12 @@ public int getLightEmission(BlockState state, BlockGetter level, BlockPos pos) {
return state.getValue(LIGHT) && isLightActive(state) ? 15 : 0;
}
+ @Override
+ public BlockState getAppearance(BlockState state, BlockAndTintGetter level, BlockPos pos, Direction side,
+ @Nullable BlockState queryState, @Nullable BlockPos queryPos) {
+ return state.getBlock().defaultBlockState();
+ }
+
@Override
@SuppressWarnings("deprecation")
public void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) {
@@ -192,10 +190,4 @@ public List getDrops(BlockState state, LootParams.Builder params) {
}
return returnValue;
}
-
- @Nullable
- @Override
- public IRenderer getRenderer(BlockState state) {
- return renderers.get(state);
- }
}
diff --git a/src/main/java/com/gregtechceu/gtceu/common/block/LaserPipeBlock.java b/src/main/java/com/gregtechceu/gtceu/common/block/LaserPipeBlock.java
index 4b99ed7cdeb..311338b6a1f 100644
--- a/src/main/java/com/gregtechceu/gtceu/common/block/LaserPipeBlock.java
+++ b/src/main/java/com/gregtechceu/gtceu/common/block/LaserPipeBlock.java
@@ -2,12 +2,14 @@
import com.gregtechceu.gtceu.GTCEu;
import com.gregtechceu.gtceu.api.block.PipeBlock;
+import com.gregtechceu.gtceu.api.block.property.GTBlockStateProperties;
import com.gregtechceu.gtceu.api.blockentity.PipeBlockEntity;
import com.gregtechceu.gtceu.api.capability.forge.GTCapability;
import com.gregtechceu.gtceu.api.item.tool.GTToolType;
import com.gregtechceu.gtceu.api.pipenet.IPipeNode;
-import com.gregtechceu.gtceu.client.model.PipeModel;
-import com.gregtechceu.gtceu.client.renderer.block.PipeBlockRenderer;
+import com.gregtechceu.gtceu.api.registry.registrate.provider.GTBlockstateProvider;
+import com.gregtechceu.gtceu.client.model.pipe.ActivablePipeModel;
+import com.gregtechceu.gtceu.client.model.pipe.PipeModel;
import com.gregtechceu.gtceu.common.blockentity.LaserPipeBlockEntity;
import com.gregtechceu.gtceu.common.data.GTBlockEntities;
import com.gregtechceu.gtceu.common.pipelike.laser.LaserPipeProperties;
@@ -19,9 +21,11 @@
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.item.ItemStack;
+import net.minecraft.world.level.block.Block;
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.StateDefinition;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@@ -33,23 +37,20 @@
@MethodsReturnNonnullByDefault
public class LaserPipeBlock extends PipeBlock {
- public final PipeBlockRenderer renderer;
- public final PipeModel model;
private final LaserPipeProperties properties;
public LaserPipeBlock(Properties properties, LaserPipeType type) {
super(properties, type);
this.properties = LaserPipeProperties.INSTANCE;
- this.model = new PipeModel(LaserPipeType.NORMAL.getThickness(), () -> GTCEu.id("block/pipe/pipe_laser_side"),
- () -> GTCEu.id("block/pipe/pipe_laser_in"), null, null);
- this.renderer = new PipeBlockRenderer(this.model);
+
+ registerDefaultState(defaultBlockState().setValue(GTBlockStateProperties.ACTIVE, false));
}
@OnlyIn(Dist.CLIENT)
public static BlockColor tintedColor() {
- return (blockState, level, blockPos, index) -> {
- if (blockPos != null && level != null &&
- level.getBlockEntity(blockPos) instanceof PipeBlockEntity, ?> pipe) {
+ return (state, level, pos, index) -> {
+ if (pos != null && level != null &&
+ level.getBlockEntity(pos) instanceof PipeBlockEntity, ?> pipe) {
if (!pipe.getFrameMaterial().isNull()) {
if (index == 3) {
return pipe.getFrameMaterial().getMaterialRGB();
@@ -65,6 +66,12 @@ public static BlockColor tintedColor() {
};
}
+ @Override
+ protected void createBlockStateDefinition(StateDefinition.Builder builder) {
+ super.createBlockStateDefinition(builder);
+ builder.add(GTBlockStateProperties.ACTIVE);
+ }
+
@Override
public LevelLaserPipeNet getWorldPipeNet(ServerLevel world) {
return LevelLaserPipeNet.getOrCreate(world);
@@ -93,12 +100,12 @@ public LaserPipeProperties getFallbackType() {
}
@Override
- public @Nullable PipeBlockRenderer getRenderer(BlockState state) {
- return renderer;
- }
-
- @Override
- protected PipeModel getPipeModel() {
+ public PipeModel createPipeModel(GTBlockstateProvider provider) {
+ ActivablePipeModel model = new ActivablePipeModel(this, LaserPipeType.NORMAL.getThickness(),
+ GTCEu.id("block/pipe/pipe_laser_side"), GTCEu.id("block/pipe/pipe_laser_in"),
+ provider);
+ model.setSideOverlay(GTCEu.id("block/pipe/pipe_laser_side_overlay"));
+ model.setSideOverlayActive(GTCEu.id("block/pipe/pipe_laser_side_overlay_emissive"));
return model;
}
diff --git a/src/main/java/com/gregtechceu/gtceu/common/block/OpticalPipeBlock.java b/src/main/java/com/gregtechceu/gtceu/common/block/OpticalPipeBlock.java
index 07d7e22be23..c710e296547 100644
--- a/src/main/java/com/gregtechceu/gtceu/common/block/OpticalPipeBlock.java
+++ b/src/main/java/com/gregtechceu/gtceu/common/block/OpticalPipeBlock.java
@@ -2,12 +2,14 @@
import com.gregtechceu.gtceu.GTCEu;
import com.gregtechceu.gtceu.api.block.PipeBlock;
+import com.gregtechceu.gtceu.api.block.property.GTBlockStateProperties;
import com.gregtechceu.gtceu.api.blockentity.PipeBlockEntity;
import com.gregtechceu.gtceu.api.capability.forge.GTCapability;
import com.gregtechceu.gtceu.api.item.tool.GTToolType;
import com.gregtechceu.gtceu.api.pipenet.IPipeNode;
-import com.gregtechceu.gtceu.client.model.PipeModel;
-import com.gregtechceu.gtceu.client.renderer.block.PipeBlockRenderer;
+import com.gregtechceu.gtceu.api.registry.registrate.provider.GTBlockstateProvider;
+import com.gregtechceu.gtceu.client.model.pipe.ActivablePipeModel;
+import com.gregtechceu.gtceu.client.model.pipe.PipeModel;
import com.gregtechceu.gtceu.common.blockentity.OpticalPipeBlockEntity;
import com.gregtechceu.gtceu.common.data.GTBlockEntities;
import com.gregtechceu.gtceu.common.pipelike.optical.LevelOpticalPipeNet;
@@ -18,14 +20,15 @@
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.item.ItemStack;
+import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
-import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -34,20 +37,29 @@
@ParametersAreNonnullByDefault
public class OpticalPipeBlock extends PipeBlock {
- public final PipeBlockRenderer renderer;
- @Getter
- public final PipeModel pipeModel;
-
- private final OpticalPipeType pipeType;
private final OpticalPipeProperties properties;
- public OpticalPipeBlock(BlockBehaviour.Properties properties, @NotNull OpticalPipeType pipeType) {
+ public OpticalPipeBlock(BlockBehaviour.Properties properties, OpticalPipeType pipeType) {
super(properties, pipeType);
- this.pipeType = pipeType;
this.properties = OpticalPipeProperties.INSTANCE;
- this.pipeModel = new PipeModel(pipeType.getThickness(), () -> GTCEu.id("block/pipe/pipe_optical_side"),
- () -> GTCEu.id("block/pipe/pipe_optical_in"), null, null);
- this.renderer = new PipeBlockRenderer(this.pipeModel);
+
+ registerDefaultState(defaultBlockState().setValue(GTBlockStateProperties.ACTIVE, false));
+ }
+
+ @Override
+ protected void createBlockStateDefinition(StateDefinition.Builder builder) {
+ super.createBlockStateDefinition(builder);
+ builder.add(GTBlockStateProperties.ACTIVE);
+ }
+
+ @Override
+ public @NotNull PipeModel createPipeModel(GTBlockstateProvider provider) {
+ ActivablePipeModel pipeModel = new ActivablePipeModel(this, pipeType.getThickness(),
+ GTCEu.id("block/pipe/pipe_optical_side"), GTCEu.id("block/pipe/pipe_optical_in"),
+ provider);
+ pipeModel.setSideOverlay(GTCEu.id("block/pipe/pipe_optical_side_overlay"));
+ pipeModel.setSideOverlayActive(GTCEu.id("block/pipe/pipe_optical_side_overlay_active"));
+ return pipeModel;
}
@Override
@@ -77,11 +89,6 @@ public OpticalPipeProperties getFallbackType() {
return OpticalPipeProperties.INSTANCE;
}
- @Override
- public @Nullable PipeBlockRenderer getRenderer(BlockState state) {
- return renderer;
- }
-
@OnlyIn(Dist.CLIENT)
public static BlockColor tintedColor() {
return (blockState, level, blockPos, index) -> {
diff --git a/src/main/java/com/gregtechceu/gtceu/common/blockentity/CableBlockEntity.java b/src/main/java/com/gregtechceu/gtceu/common/blockentity/CableBlockEntity.java
index b6787e54fa0..8d33f3c08f4 100644
--- a/src/main/java/com/gregtechceu/gtceu/common/blockentity/CableBlockEntity.java
+++ b/src/main/java/com/gregtechceu/gtceu/common/blockentity/CableBlockEntity.java
@@ -70,10 +70,6 @@ public CableBlockEntity(BlockEntityType> type, BlockPos pos, BlockState blockS
super(type, pos, blockState);
}
- public static CableBlockEntity create(BlockEntityType> type, BlockPos pos, BlockState blockState) {
- return new CableBlockEntity(type, pos, blockState);
- }
-
@Override
public @NotNull LazyOptional getCapability(@NotNull Capability cap, @Nullable Direction side) {
if (cap == GTCapability.CAPABILITY_ENERGY_CONTAINER) {
diff --git a/src/main/java/com/gregtechceu/gtceu/common/blockentity/DuctPipeBlockEntity.java b/src/main/java/com/gregtechceu/gtceu/common/blockentity/DuctPipeBlockEntity.java
index 1136349e1bb..6a4a060339f 100644
--- a/src/main/java/com/gregtechceu/gtceu/common/blockentity/DuctPipeBlockEntity.java
+++ b/src/main/java/com/gregtechceu/gtceu/common/blockentity/DuctPipeBlockEntity.java
@@ -35,14 +35,10 @@ public class DuctPipeBlockEntity extends PipeBlockEntity type, BlockPos pos, BlockState blockState) {
+ public DuctPipeBlockEntity(BlockEntityType> type, BlockPos pos, BlockState blockState) {
super(type, pos, blockState);
}
- public static DuctPipeBlockEntity create(BlockEntityType> type, BlockPos pos, BlockState blockState) {
- return new DuctPipeBlockEntity(type, pos, blockState);
- }
-
public static void onBlockEntityRegister(BlockEntityType ductBlockEntityBlockEntityType) {}
@Override
diff --git a/src/main/java/com/gregtechceu/gtceu/common/blockentity/ItemPipeBlockEntity.java b/src/main/java/com/gregtechceu/gtceu/common/blockentity/ItemPipeBlockEntity.java
index 5fa341fd83e..f222c06da11 100644
--- a/src/main/java/com/gregtechceu/gtceu/common/blockentity/ItemPipeBlockEntity.java
+++ b/src/main/java/com/gregtechceu/gtceu/common/blockentity/ItemPipeBlockEntity.java
@@ -50,10 +50,6 @@ public ItemPipeBlockEntity(BlockEntityType> type, BlockPos pos, BlockState blo
super(type, pos, blockState);
}
- public static ItemPipeBlockEntity create(BlockEntityType> type, BlockPos pos, BlockState blockState) {
- return new ItemPipeBlockEntity(type, pos, blockState);
- }
-
public long getLevelTime() {
return hasLevel() ? Objects.requireNonNull(getLevel()).getGameTime() : 0L;
}
diff --git a/src/main/java/com/gregtechceu/gtceu/common/blockentity/LaserPipeBlockEntity.java b/src/main/java/com/gregtechceu/gtceu/common/blockentity/LaserPipeBlockEntity.java
index d3dde82340b..4e66ec19415 100644
--- a/src/main/java/com/gregtechceu/gtceu/common/blockentity/LaserPipeBlockEntity.java
+++ b/src/main/java/com/gregtechceu/gtceu/common/blockentity/LaserPipeBlockEntity.java
@@ -1,13 +1,12 @@
package com.gregtechceu.gtceu.common.blockentity;
+import com.gregtechceu.gtceu.api.block.property.GTBlockStateProperties;
import com.gregtechceu.gtceu.api.blockentity.PipeBlockEntity;
import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper;
import com.gregtechceu.gtceu.api.capability.ILaserContainer;
import com.gregtechceu.gtceu.api.capability.forge.GTCapability;
import com.gregtechceu.gtceu.api.item.tool.GTToolType;
import com.gregtechceu.gtceu.api.pipenet.IPipeNode;
-import com.gregtechceu.gtceu.api.sync_system.annotations.SaveField;
-import com.gregtechceu.gtceu.api.sync_system.annotations.SyncToClient;
import com.gregtechceu.gtceu.common.pipelike.laser.*;
import com.gregtechceu.gtceu.utils.GTUtil;
import com.gregtechceu.gtceu.utils.TaskHandler;
@@ -15,6 +14,8 @@
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
+import net.minecraft.world.level.Level;
+import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
@@ -38,21 +39,10 @@ public class LaserPipeBlockEntity extends PipeBlockEntity type, BlockPos pos, BlockState blockState) {
+ public LaserPipeBlockEntity(BlockEntityType> type, BlockPos pos, BlockState blockState) {
super(type, pos, blockState);
}
- public static LaserPipeBlockEntity create(BlockEntityType> type, BlockPos pos, BlockState blockState) {
- return new LaserPipeBlockEntity(type, pos, blockState);
- }
-
public static void onBlockEntityRegister(BlockEntityType cableBlockEntityBlockEntityType) {}
@Override
@@ -122,29 +112,11 @@ public LaserPipeNet getLaserPipeNet() {
* @param duration how long the pipe should be active for
*/
public void setActive(boolean active, int duration) {
- if (this.active != active) {
- this.active = active;
- syncDataHolder.markClientSyncFieldDirty("active");
- notifyBlockUpdate();
- setChanged();
- if (active && duration != this.activeDuration) {
- TaskHandler.enqueueServerTask((ServerLevel) getLevel(), this::queueDisconnect, 0);
- }
- }
-
- this.activeDuration = duration;
- if (duration > 0 && active) {
- this.ticksActive = 0;
- }
+ setPipeActive(this, this.getBlockState(), active, duration);
}
- public boolean queueDisconnect() {
- if (++this.ticksActive % activeDuration == 0) {
- this.ticksActive = 0;
- setActive(false, -1);
- return false;
- }
- return true;
+ public boolean isActive() {
+ return this.getBlockState().getValue(GTBlockStateProperties.ACTIVE);
}
@Override
@@ -185,6 +157,28 @@ public GTToolType getPipeTuneTool() {
return GTToolType.WIRE_CUTTER;
}
+ public static BlockState setPipeActive(PipeBlockEntity, ?> blockEntity,
+ BlockState state, boolean newActive, int duration) {
+ if (!state.hasProperty(GTBlockStateProperties.ACTIVE) ||
+ state.getValue(GTBlockStateProperties.ACTIVE) == newActive) {
+ return state;
+ }
+ BlockState newState = state.setValue(GTBlockStateProperties.ACTIVE, newActive);
+ if (blockEntity == null || blockEntity.getLevel() == null || blockEntity.isRemoved()) {
+ return newState;
+ }
+ Level level = blockEntity.getLevel();
+
+ level.setBlock(blockEntity.getBlockPos(), newState, Block.UPDATE_CLIENTS | Block.UPDATE_KNOWN_SHAPE);
+ blockEntity.notifyBlockUpdate();
+ blockEntity.setChanged();
+
+ if (newActive && level instanceof ServerLevel serverLevel) {
+ TaskHandler.enqueueServerTask(serverLevel, () -> setPipeActive(blockEntity, newState, false, -1), duration);
+ }
+ return newState;
+ }
+
private static class DefaultLaserContainer implements ILaserContainer {
@Override
diff --git a/src/main/java/com/gregtechceu/gtceu/common/blockentity/OpticalPipeBlockEntity.java b/src/main/java/com/gregtechceu/gtceu/common/blockentity/OpticalPipeBlockEntity.java
index 142301b164c..f6d28f19418 100644
--- a/src/main/java/com/gregtechceu/gtceu/common/blockentity/OpticalPipeBlockEntity.java
+++ b/src/main/java/com/gregtechceu/gtceu/common/blockentity/OpticalPipeBlockEntity.java
@@ -1,5 +1,6 @@
package com.gregtechceu.gtceu.common.blockentity;
+import com.gregtechceu.gtceu.api.block.property.GTBlockStateProperties;
import com.gregtechceu.gtceu.api.blockentity.PipeBlockEntity;
import com.gregtechceu.gtceu.api.capability.IDataAccessHatch;
import com.gregtechceu.gtceu.api.capability.IOpticalComputationProvider;
@@ -7,12 +8,8 @@
import com.gregtechceu.gtceu.api.item.tool.GTToolType;
import com.gregtechceu.gtceu.api.pipenet.IPipeNode;
import com.gregtechceu.gtceu.api.recipe.GTRecipe;
-import com.gregtechceu.gtceu.api.sync_system.annotations.RerenderOnChanged;
-import com.gregtechceu.gtceu.api.sync_system.annotations.SaveField;
-import com.gregtechceu.gtceu.api.sync_system.annotations.SyncToClient;
import com.gregtechceu.gtceu.common.pipelike.optical.*;
import com.gregtechceu.gtceu.utils.GTUtil;
-import com.gregtechceu.gtceu.utils.TaskHandler;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
@@ -23,7 +20,6 @@
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.LazyOptional;
-import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -40,12 +36,6 @@ public class OpticalPipeBlockEntity extends PipeBlockEntity currentPipeNet = new WeakReference<>(null);
private OpticalNetHandler defaultHandler;
- @Getter
- @SaveField
- @SyncToClient
- @RerenderOnChanged
- private boolean isActive;
-
public OpticalPipeBlockEntity(BlockEntityType> type, BlockPos pos, BlockState blockState) {
super(type, pos, blockState);
}
@@ -152,22 +142,11 @@ public void setConnection(Direction side, boolean connected, boolean fromNeighbo
* @param duration how long the pipe should be active for
*/
public void setActive(boolean active, int duration) {
- boolean stateChanged = false;
- if (this.isActive && !active) {
- this.isActive = false;
- syncDataHolder.markClientSyncFieldDirty("isActive");
- stateChanged = true;
- } else if (!this.isActive && active) {
- this.isActive = true;
- syncDataHolder.markClientSyncFieldDirty("isActive");
- stateChanged = true;
- TaskHandler.enqueueServerTask((ServerLevel) getLevel(), () -> setActive(false, -1), duration);
- }
+ LaserPipeBlockEntity.setPipeActive(this, this.getBlockState(), active, duration);
+ }
- if (stateChanged) {
- notifyBlockUpdate();
- setChanged();
- }
+ public boolean isActive() {
+ return this.getBlockState().getValue(GTBlockStateProperties.ACTIVE);
}
@Override
diff --git a/src/main/java/com/gregtechceu/gtceu/common/commands/GTCommands.java b/src/main/java/com/gregtechceu/gtceu/common/commands/GTCommands.java
index 14e31f25adb..3b9463eb764 100644
--- a/src/main/java/com/gregtechceu/gtceu/common/commands/GTCommands.java
+++ b/src/main/java/com/gregtechceu/gtceu/common/commands/GTCommands.java
@@ -293,7 +293,7 @@ private static int setActiveCape(CommandSourceStack source, ServerPlayer player,
private static int dumpDataRegistry(CommandContext context,
GTRegistry registry, Codec codec, String folder) {
- Path parent = GTCEu.getGameDir().resolve("gtceu/dumped/data");
+ Path parent = GTCEu.GTCEU_FOLDER.resolve("dumped/data");
var ops = RegistryOps.create(JsonOps.INSTANCE, context.getSource().registryAccess());
int dumpedCount = 0;
for (ResourceLocation id : registry.keys()) {
diff --git a/src/main/java/com/gregtechceu/gtceu/common/cover/package-info.java b/src/main/java/com/gregtechceu/gtceu/common/cover/package-info.java
new file mode 100644
index 00000000000..c4a7187c0ac
--- /dev/null
+++ b/src/main/java/com/gregtechceu/gtceu/common/cover/package-info.java
@@ -0,0 +1,4 @@
+@NotNullByDefault
+package com.gregtechceu.gtceu.common.cover;
+
+import org.jetbrains.annotations.NotNullByDefault;
diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/GTBlockEntities.java b/src/main/java/com/gregtechceu/gtceu/common/data/GTBlockEntities.java
index 4355206d72f..c4330ecb17b 100644
--- a/src/main/java/com/gregtechceu/gtceu/common/data/GTBlockEntities.java
+++ b/src/main/java/com/gregtechceu/gtceu/common/data/GTBlockEntities.java
@@ -13,7 +13,7 @@ public class GTBlockEntities {
@SuppressWarnings("unchecked")
public static final BlockEntityEntry CABLE = REGISTRATE
- .blockEntity("cable", CableBlockEntity::create)
+ .blockEntity("cable", CableBlockEntity::new)
.onRegister(CableBlockEntity::onBlockEntityRegister)
.validBlocks(GTMaterialBlocks.CABLE_BLOCKS.values().toArray(BlockEntry[]::new))
.register();
@@ -27,13 +27,13 @@ public class GTBlockEntities {
@SuppressWarnings("unchecked")
public static final BlockEntityEntry ITEM_PIPE = REGISTRATE
- .blockEntity("item_pipe", ItemPipeBlockEntity::create)
+ .blockEntity("item_pipe", ItemPipeBlockEntity::new)
.onRegister(ItemPipeBlockEntity::onBlockEntityRegister)
.validBlocks(GTMaterialBlocks.ITEM_PIPE_BLOCKS.values().toArray(BlockEntry[]::new))
.register();
public static final BlockEntityEntry LASER_PIPE = REGISTRATE
- .blockEntity("laser_pipe", LaserPipeBlockEntity::create)
+ .blockEntity("laser_pipe", LaserPipeBlockEntity::new)
.onRegister(LaserPipeBlockEntity::onBlockEntityRegister)
.validBlocks(GTBlocks.LASER_PIPES)
.register();
@@ -44,7 +44,7 @@ public class GTBlockEntities {
.register();
public static final BlockEntityEntry DUCT_PIPE = REGISTRATE
- .blockEntity("duct_pipe", DuctPipeBlockEntity::create)
+ .blockEntity("duct_pipe", DuctPipeBlockEntity::new)
.onRegister(DuctPipeBlockEntity::onBlockEntityRegister)
.validBlocks(GTBlocks.DUCT_PIPES)
.register();
diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/GTBlocks.java b/src/main/java/com/gregtechceu/gtceu/common/data/GTBlocks.java
index a91932797f8..241aa9101ff 100644
--- a/src/main/java/com/gregtechceu/gtceu/common/data/GTBlocks.java
+++ b/src/main/java/com/gregtechceu/gtceu/common/data/GTBlocks.java
@@ -115,7 +115,7 @@ private static void registerLaserPipeBlock(int index) {
.block("%s_laser_pipe".formatted(type.getSerializedName()), (p) -> new LaserPipeBlock(p, type))
.initialProperties(() -> Blocks.IRON_BLOCK)
.properties(p -> p.dynamicShape().noOcclusion().forceSolidOn())
- .blockstate(NonNullBiConsumer.noop())
+ .gtBlockstate(GTModels::createPipeBlockModel)
.defaultLoot()
.tag(CustomTags.MINEABLE_WITH_CONFIG_VALID_PICKAXE_WIRE_CUTTER)
.addLayer(() -> RenderType::cutoutMipped)
@@ -145,13 +145,13 @@ private static void registerOpticalPipeBlock(int index) {
.lang("Optical Fiber Cable")
.initialProperties(() -> Blocks.IRON_BLOCK)
.properties(p -> p.dynamicShape().noOcclusion().forceSolidOn())
- .blockstate(NonNullBiConsumer.noop())
+ .gtBlockstate(GTModels::createPipeBlockModel)
.defaultLoot()
.tag(CustomTags.MINEABLE_WITH_CONFIG_VALID_PICKAXE_WIRE_CUTTER)
.addLayer(() -> RenderType::cutoutMipped)
.addLayer(() -> RenderType::translucent)
.color(() -> OpticalPipeBlock::tintedColor)
- .item(OpticalPipeBlockItem::new)
+ .item(PipeBlockItem::new)
.model(NonNullBiConsumer.noop())
.build()
.register();
@@ -173,12 +173,12 @@ private static void registerDuctPipeBlock(int index) {
.block("%s_duct_pipe".formatted(type.getSerializedName()), (p) -> new DuctPipeBlock(p, type))
.initialProperties(() -> Blocks.IRON_BLOCK)
.properties(p -> p.dynamicShape().noOcclusion().forceSolidOn())
- .blockstate(NonNullBiConsumer.noop())
+ .gtBlockstate(GTModels::createPipeBlockModel)
.defaultLoot()
.tag(CustomTags.MINEABLE_WITH_CONFIG_VALID_PICKAXE_WRENCH)
.addLayer(() -> RenderType::cutoutMipped)
.addLayer(() -> RenderType::translucent)
- .item(DuctPipeBlockItem::new)
+ .item(PipeBlockItem::new)
.model(NonNullBiConsumer.noop())
.build()
.register();
diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/GTPlaceholders.java b/src/main/java/com/gregtechceu/gtceu/common/data/GTPlaceholders.java
index b27505a4854..45fccd4f5de 100644
--- a/src/main/java/com/gregtechceu/gtceu/common/data/GTPlaceholders.java
+++ b/src/main/java/com/gregtechceu/gtceu/common/data/GTPlaceholders.java
@@ -7,16 +7,23 @@
import com.gregtechceu.gtceu.api.capability.IWorkable;
import com.gregtechceu.gtceu.api.cover.filter.ItemFilter;
import com.gregtechceu.gtceu.api.item.ComponentItem;
+import com.gregtechceu.gtceu.api.item.IComponentItem;
import com.gregtechceu.gtceu.api.item.component.IDataItem;
import com.gregtechceu.gtceu.api.item.component.IItemComponent;
+import com.gregtechceu.gtceu.api.item.component.IMonitorModuleItem;
import com.gregtechceu.gtceu.api.machine.MetaMachine;
import com.gregtechceu.gtceu.api.machine.feature.multiblock.IMaintenanceMachine;
import com.gregtechceu.gtceu.api.misc.virtualregistry.EntryTypes;
import com.gregtechceu.gtceu.api.misc.virtualregistry.VirtualEnderRegistry;
import com.gregtechceu.gtceu.api.placeholder.*;
import com.gregtechceu.gtceu.api.placeholder.exceptions.*;
+import com.gregtechceu.gtceu.client.renderer.placeholder.ModulePlaceholderRenderer;
+import com.gregtechceu.gtceu.client.renderer.placeholder.QuadPlaceholderRenderer;
+import com.gregtechceu.gtceu.client.renderer.placeholder.RectPlaceholderRenderer;
import com.gregtechceu.gtceu.common.blockentity.CableBlockEntity;
+import com.gregtechceu.gtceu.common.item.modules.ImageModuleBehaviour;
import com.gregtechceu.gtceu.common.machine.multiblock.part.monitor.AdvancedMonitorPartMachine;
+import com.gregtechceu.gtceu.utils.GTMath;
import com.gregtechceu.gtceu.utils.GTStringUtils;
import com.gregtechceu.gtceu.utils.GTTransferUtils;
@@ -37,8 +44,11 @@
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.phys.Vec2;
import net.minecraft.world.phys.Vec3;
+import net.minecraftforge.api.distmarker.Dist;
+import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidHandler;
+import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.registries.ForgeRegistries;
@@ -84,6 +94,7 @@ public static int countItems(@Nullable ItemFilter filter, @Nullable IItemHandler
}
public static void initPlaceholders() {
+ DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> GTPlaceholders::initRenderers);
PlaceholderHandler.addPlaceholder(new Placeholder("energy") {
@Override
@@ -130,10 +141,10 @@ public MultiLineComponent apply(PlaceholderContext ctx,
.literal(countItems(GTStringUtils.componentsToString(args.get(0)), itemHandler));
if (GTStringUtils.equals(args.get(0), "filter")) {
int slot = PlaceholderUtils.toInt(args.get(1));
- PlaceholderUtils.checkRange("slot index", 1, 8, slot);
+ if (ctx.itemStackHandler() == null)
+ throw new NotSupportedException();
+ PlaceholderUtils.checkRange("slot index", 1, ctx.itemStackHandler().getSlots(), slot);
try {
- if (ctx.itemStackHandler() == null)
- throw new NotSupportedException();
return MultiLineComponent.literal(countItems(
ItemFilter.loadFilter(ctx.itemStackHandler().getStackInSlot(slot - 1)), itemHandler));
} catch (NullPointerException e) {
@@ -253,9 +264,7 @@ public MultiLineComponent apply(PlaceholderContext ctx,
public MultiLineComponent apply(PlaceholderContext ctx,
List args) throws PlaceholderException {
PlaceholderUtils.checkArgs(args, 0);
- if (ctx.cover() instanceof IPlaceholderInfoProviderCover cover)
- return MultiLineComponent.literal(cover.getTicksSincePlaced());
- throw new NotSupportedException();
+ return MultiLineComponent.literal(ctx.level().getGameTime());
}
});
PlaceholderHandler.addPlaceholder(new Placeholder("select") {
@@ -281,7 +290,7 @@ public MultiLineComponent apply(PlaceholderContext ctx,
throw new InvalidArgsException();
return MultiLineComponent.literal(ctx.level()
.getSignal(ctx.pos().relative(direction), direction));
- } else if (GTStringUtils.equals(args.get(1), "set")) {
+ } else if (GTStringUtils.equals(args.get(0), "set")) {
int power = PlaceholderUtils.toInt(args.get(1));
PlaceholderUtils.checkRange("redstone power", 0, 15, power);
if (ctx.cover() == null) throw new NotSupportedException();
@@ -397,8 +406,8 @@ public MultiLineComponent apply(PlaceholderContext ctx,
PlaceholderUtils.checkArgs(args, 2, true);
try {
int slot = PlaceholderUtils.toInt(args.get(1));
- PlaceholderUtils.checkRange("slot index", 1, 8, slot);
if (ctx.itemStackHandler() == null) throw new NotSupportedException();
+ PlaceholderUtils.checkRange("slot index", 1, ctx.itemStackHandler().getSlots(), slot);
ItemStack stack = ctx.itemStackHandler().getStackInSlot(slot - 1);
int capacity = -1;
if (stack.getItem() instanceof ComponentItem componentItem) {
@@ -459,8 +468,8 @@ public MultiLineComponent apply(PlaceholderContext ctx,
List args) throws PlaceholderException {
PlaceholderUtils.checkArgs(args, 1, true);
int slot = GTStringUtils.toInt(args.get(0));
- PlaceholderUtils.checkRange("slot index", 1, 8, slot);
if (ctx.itemStackHandler() == null) throw new NotSupportedException();
+ PlaceholderUtils.checkRange("slot index", 1, ctx.itemStackHandler().getSlots(), slot);
Tag tag = ctx.itemStackHandler().getStackInSlot(slot - 1).getOrCreateTag();
for (int i = 1; i < args.size() - 1; i++) {
if (!(tag instanceof CompoundTag compoundTag)) return MultiLineComponent.empty();
@@ -544,8 +553,8 @@ public MultiLineComponent apply(PlaceholderContext ctx,
List args) throws PlaceholderException {
PlaceholderUtils.checkArgs(args, 2);
int slot = PlaceholderUtils.toInt(args.get(0));
- PlaceholderUtils.checkRange("slot index", 1, 8, slot);
if (ctx.itemStackHandler() == null) throw new NotSupportedException();
+ PlaceholderUtils.checkRange("slot index", 1, ctx.itemStackHandler().getSlots(), slot);
ItemStack stack = ctx.itemStackHandler().getStackInSlot(slot - 1);
int capacity = -1;
if (stack.getItem() instanceof ComponentItem componentItem) {
@@ -557,6 +566,9 @@ public MultiLineComponent apply(PlaceholderContext ctx,
}
}
if (capacity == -1) throw new MissingItemException("any data item", slot);
+ if (!stack.getOrCreateTag().contains("computer_monitor_cover_data")) {
+ stack.getOrCreateTag().put("computer_monitor_cover_data", new ListTag());
+ }
ListTag tag = stack.getOrCreateTag().getList("computer_monitor_cover_data", Tag.TAG_STRING);
int operationsLeft = 5000;
int p = 0, start = 0, cnt = 0;
@@ -584,19 +596,27 @@ public MultiLineComponent apply(PlaceholderContext ctx,
if (cur != null) codeBuilder.append(cnt).append(cur);
String code = codeBuilder.toString();
Stack loops = new Stack<>();
- if (!getData(ctx).getBoolean("completed")) {
- p = getData(ctx).getInt("pointer");
- start = getData(ctx).getInt("index");
+ if (!getData(ctx).contains(String.valueOf(ctx.index()))) {
+ getData(ctx).put(String.valueOf(ctx.index()), new CompoundTag());
}
- getData(ctx).putBoolean("completed", true);
+ CompoundTag data = getData(ctx).getCompound(String.valueOf(ctx.index()));
int num = 0;
+ if (!data.getBoolean("completed")) {
+ p = data.getInt("pointer");
+ start = data.getInt("index");
+ num = data.getInt("num");
+ }
+ data.putBoolean("completed", true);
for (int i = start; i < code.length(); i++) {
if (operationsLeft <= 0) {
- getData(ctx).putBoolean("completed", false);
- getData(ctx).putInt("pointer", p);
- getData(ctx).putInt("index", i);
+ data.putBoolean("completed", false);
+ data.putInt("pointer", p);
+ data.putInt("index", i);
+ data.putInt("num", num);
break;
}
+ if (p > capacity) p = p % capacity;
+ if (p < 0) p = (capacity - ((-p) % capacity)) % capacity;
while (tag.size() <= p) tag.add(StringTag.valueOf("0"));
if (tag.getString(p).isEmpty()) tag.set(i, StringTag.valueOf("0"));
switch (code.charAt(i)) {
@@ -612,7 +632,7 @@ public MultiLineComponent apply(PlaceholderContext ctx,
case '[' -> loops.push(i);
case ']' -> {
if (Integer.parseInt(tag.getString(p)) == 0) loops.pop();
- else i = loops.peek();
+ else i = loops.peek() + 1;
}
}
if (Character.isDigit(code.charAt(i))) {
@@ -631,7 +651,7 @@ public MultiLineComponent apply(PlaceholderContext ctx,
PlaceholderUtils.checkArgs(args, 2);
if (ctx.itemStackHandler() == null) throw new NotSupportedException();
int slot = PlaceholderUtils.toInt(args.get(0));
- PlaceholderUtils.checkRange("slot index", 1, 8, slot);
+ PlaceholderUtils.checkRange("slot index", 1, ctx.itemStackHandler().getSlots(), slot);
ItemStack stack = ctx.itemStackHandler().getStackInSlot(slot - 1);
if (!stack.getOrCreateTag().contains("boundPlayerPermLevel"))
throw new MissingItemException("any data item bound to player", slot);
@@ -706,10 +726,11 @@ public MultiLineComponent apply(PlaceholderContext ctx,
1000000000L, "B",
1000000000000L, "T");
long max = 1;
- for (Long i : suffixes.keySet()) {
+ for (long i : suffixes.keySet()) {
if (n >= i && max < i) max = i;
}
- return MultiLineComponent.literal("%.2f%s".formatted(((double) n) / max, suffixes.get(max)));
+ return MultiLineComponent.literal(String.format(Locale.ROOT, "%.2f%s",
+ ((double) n) / max, suffixes.get(max)));
}
});
PlaceholderHandler.addPlaceholder(new Placeholder("click") {
@@ -739,7 +760,7 @@ public MultiLineComponent apply(PlaceholderContext ctx,
if (args.size() > 2 && !args.get(2).toString().isEmpty()) {
if (ctx.itemStackHandler() == null) throw new NotSupportedException();
int slot = PlaceholderUtils.toInt(args.get(2));
- PlaceholderUtils.checkRange("slot index", 1, 8, slot);
+ PlaceholderUtils.checkRange("slot index", 1, ctx.itemStackHandler().getSlots(), slot);
ItemStack stack = ctx.itemStackHandler().getStackInSlot(slot - 1);
if (stack.getOrCreateTag().contains("boundPlayerUUID"))
owner = UUID.fromString(stack.getOrCreateTag().getString("boundPlayerUUID"));
@@ -753,7 +774,7 @@ public MultiLineComponent apply(PlaceholderContext ctx,
if (args.size() > 4) {
if (ctx.itemStackHandler() == null) throw new NotSupportedException();
int slot = PlaceholderUtils.toInt(args.get(3));
- PlaceholderUtils.checkRange("slot index", 1, 8, slot);
+ PlaceholderUtils.checkRange("slot index", 1, ctx.itemStackHandler().getSlots(), slot);
ItemStack stack = ctx.itemStackHandler().getStackInSlot(slot - 1);
UUID uuid;
if (stack.getOrCreateTag().contains("enderRedstoneLinkTransmitterUUID")) {
@@ -827,6 +848,127 @@ public MultiLineComponent apply(PlaceholderContext ctx,
return PlaceholderHandler.processPlaceholders(args.get(0).toString(), ctx);
}
});
+ PlaceholderHandler.addPlaceholder(new Placeholder("module") {
+
+ @Override
+ public MultiLineComponent apply(PlaceholderContext ctx,
+ List args) throws PlaceholderException {
+ PlaceholderUtils.checkArgs(args, 3);
+ int slot = PlaceholderUtils.toInt(args.get(0));
+ double x = PlaceholderUtils.toDouble(args.get(1));
+ double y = PlaceholderUtils.toDouble(args.get(2));
+ if (ctx.itemStackHandler() == null) throw new NotSupportedException();
+ PlaceholderUtils.checkRange("slot index", 1, ctx.itemStackHandler().getSlots(), slot);
+ ItemStack stack = ctx.itemStackHandler().getStackInSlot(slot);
+ if (stack.getItem() instanceof IComponentItem componentItem) {
+ for (IItemComponent component : componentItem.getComponents()) {
+ if (component instanceof IMonitorModuleItem module) module.tickInPlaceholder(stack, ctx);
+ }
+ }
+ return MultiLineComponent.empty().addGraphics(new GraphicsComponent(
+ x, y, x, y,
+ "module",
+ stack.serializeNBT()));
+ }
+ });
+ PlaceholderHandler.addPlaceholder(new Placeholder("setImage") {
+
+ @Override
+ public MultiLineComponent apply(PlaceholderContext ctx,
+ List args) throws PlaceholderException {
+ PlaceholderUtils.checkArgs(args, 2);
+ int slot = PlaceholderUtils.toInt(args.get(0));
+ String url = args.get(1).toString();
+ if (ctx.itemStackHandler() == null) throw new NotSupportedException();
+ PlaceholderUtils.checkRange("slot index", 1, ctx.itemStackHandler().getSlots(), slot);
+ ItemStack stack = ctx.itemStackHandler().getStackInSlot(slot);
+ if (stack.getItem() instanceof IComponentItem componentItem) {
+ for (IItemComponent component : componentItem.getComponents()) {
+ if (component instanceof ImageModuleBehaviour module) {
+ module.setUrl(stack, url);
+ }
+ }
+ }
+ return MultiLineComponent.empty();
+ }
+ });
+ PlaceholderHandler.addPlaceholder(new Placeholder("rect") {
+
+ @Override
+ public MultiLineComponent apply(PlaceholderContext ctx,
+ List args) throws PlaceholderException {
+ PlaceholderUtils.checkArgs(args, 5);
+ double x = PlaceholderUtils.toDouble(args.get(0));
+ double y = PlaceholderUtils.toDouble(args.get(1));
+ double width = PlaceholderUtils.toDouble(args.get(2));
+ double height = PlaceholderUtils.toDouble(args.get(3));
+ if (x < 0) x = 0;
+ if (y < 0) y = 0;
+ CompoundTag renderData = new CompoundTag();
+ renderData.putDouble("x", x);
+ renderData.putDouble("y", y);
+ renderData.putDouble("width", width);
+ renderData.putDouble("height", height);
+ renderData.putInt("color", 0xFF000000 | PlaceholderUtils.toInt(args.get(4)));
+ return MultiLineComponent.empty().addGraphics(new GraphicsComponent(
+ x, y, x + width, y + height,
+ "rect",
+ renderData));
+ }
+ });
+ PlaceholderHandler.addPlaceholder(new Placeholder("quad") {
+
+ @Override
+ public MultiLineComponent apply(PlaceholderContext ctx,
+ List args) throws PlaceholderException {
+ PlaceholderUtils.checkArgs(args, 12);
+ CompoundTag renderData = new CompoundTag();
+ float x1 = PlaceholderUtils.toFloat(args.get(0));
+ float y1 = PlaceholderUtils.toFloat(args.get(1));
+ float x2 = PlaceholderUtils.toFloat(args.get(2));
+ float y2 = PlaceholderUtils.toFloat(args.get(3));
+ float x3 = PlaceholderUtils.toFloat(args.get(4));
+ float y3 = PlaceholderUtils.toFloat(args.get(5));
+ float x4 = PlaceholderUtils.toFloat(args.get(6));
+ float y4 = PlaceholderUtils.toFloat(args.get(7));
+ renderData.putFloat("x1", 0);
+ renderData.putFloat("y1", 0);
+ renderData.putFloat("x2", x2 - x1);
+ renderData.putFloat("y2", y2 - y1);
+ renderData.putFloat("x3", x3 - x1);
+ renderData.putFloat("y3", y3 - y1);
+ renderData.putFloat("x4", x4 - x1);
+ renderData.putFloat("y4", y4 - y1);
+ renderData.putInt("color1", 0xFF000000 + PlaceholderUtils.toInt(args.get(8)));
+ renderData.putInt("color2", 0xFF000000 + PlaceholderUtils.toInt(args.get(9)));
+ renderData.putInt("color3", 0xFF000000 + PlaceholderUtils.toInt(args.get(10)));
+ renderData.putInt("color4", 0xFF000000 + PlaceholderUtils.toInt(args.get(11)));
+ return MultiLineComponent.empty().addGraphics(new GraphicsComponent(
+ GTMath.min(x1, x2, x3, x4), GTMath.min(y1, y2, y3, y4), GTMath.max(x1, x2, x3, x4),
+ GTMath.max(y1, y2, y3, y4),
+ "quad",
+ renderData));
+ }
+ });
+ PlaceholderHandler.addPlaceholder(new Placeholder("item") {
+
+ @Override
+ public MultiLineComponent apply(PlaceholderContext ctx,
+ List args) throws PlaceholderException {
+ PlaceholderUtils.checkArgs(args, 1);
+ int slot = PlaceholderUtils.toInt(args.get(0));
+ if (ctx.itemStackHandler() == null) throw new NotSupportedException();
+ PlaceholderUtils.checkRange("slot index", 1, ctx.itemStackHandler().getSlots(), slot);
+ return MultiLineComponent.literal(ctx.itemStackHandler().getStackInSlot(slot - 1).toString());
+ }
+ });
+ }
+
+ @OnlyIn(Dist.CLIENT)
+ public static void initRenderers() {
+ PlaceholderHandler.addRenderer("module", new ModulePlaceholderRenderer());
+ PlaceholderHandler.addRenderer("rect", new RectPlaceholderRenderer());
+ PlaceholderHandler.addRenderer("quad", new QuadPlaceholderRenderer());
PlaceholderHandler.addPlaceholder(new Placeholder("blockNbt") {
@Override
diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/GTRecipeConditions.java b/src/main/java/com/gregtechceu/gtceu/common/data/GTRecipeConditions.java
index c0576da5752..cb655156172 100644
--- a/src/main/java/com/gregtechceu/gtceu/common/data/GTRecipeConditions.java
+++ b/src/main/java/com/gregtechceu/gtceu/common/data/GTRecipeConditions.java
@@ -21,6 +21,7 @@ private GTRecipeConditions() {}
// spotless:off
public static final RecipeConditionType BIOME = register("biome", BiomeCondition::new, BiomeCondition.CODEC);
+ public static final RecipeConditionType BIOME_TAG = register("biome_tag", BiomeTagCondition::new, BiomeTagCondition.CODEC);
public static final RecipeConditionType DIMENSION = register("dimension", DimensionCondition::new, DimensionCondition.CODEC);
public static final RecipeConditionType POSITION_Y = register("pos_y", PositionYCondition::new, PositionYCondition.CODEC);
public static final RecipeConditionType RAINING = register("rain", RainingCondition::new, RainingCondition.CODEC);
diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/GTRecipeModifiers.java b/src/main/java/com/gregtechceu/gtceu/common/data/GTRecipeModifiers.java
index 21005394fc8..cea3cf40f93 100644
--- a/src/main/java/com/gregtechceu/gtceu/common/data/GTRecipeModifiers.java
+++ b/src/main/java/com/gregtechceu/gtceu/common/data/GTRecipeModifiers.java
@@ -20,6 +20,7 @@
import net.minecraft.Util;
import net.minecraft.core.BlockPos;
+import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel;
import org.jetbrains.annotations.NotNull;
@@ -38,7 +39,8 @@ public class GTRecipeModifiers {
.memoize(logic -> (machine, recipe) -> {
if (!(machine instanceof IOverclockMachine overclockMachine)) return ModifierFunction.IDENTITY;
if (RecipeHelper.getRecipeEUtTier(recipe) > overclockMachine.getMaxOverclockTier()) {
- return ModifierFunction.NULL;
+ return ModifierFunction
+ .cancel(Component.translatable("gtceu.recipe_modifier.insufficient_voltage"));
}
return logic.getModifier(machine, recipe, overclockMachine.getOverclockVoltage());
});
@@ -175,11 +177,11 @@ public class GTRecipeModifiers {
(100 * Math.max(0, coilMachine.getTier() - GTValues.MV));
int recipeTemp = recipe.data.getInt("ebf_temp");
if (!recipe.data.contains("ebf_temp") || recipeTemp > blastFurnaceTemperature) {
- return ModifierFunction.NULL;
+ return ModifierFunction.cancel(Component.translatable("gtceu.recipe_modifier.coil_temperature_too_low"));
}
if (RecipeHelper.getRecipeEUtTier(recipe) > coilMachine.getTier()) {
- return ModifierFunction.NULL;
+ return ModifierFunction.cancel(Component.translatable("gtceu.recipe_modifier.insufficient_voltage"));
}
var discount = ModifierFunction.builder()
diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GCYMMachines.java b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GCYMMachines.java
index f460eb19aee..b8ec948322f 100644
--- a/src/main/java/com/gregtechceu/gtceu/common/data/machines/GCYMMachines.java
+++ b/src/main/java/com/gregtechceu/gtceu/common/data/machines/GCYMMachines.java
@@ -283,9 +283,9 @@ public static void init() {}
.multiblock("large_assembler", WorkableElectricMultiblockMachine::new)
.langValue("Large Assembling Factory")
.tooltips(Component.translatable("gtceu.multiblock.parallelizable.tooltip"))
- .tooltips(Component.translatable("gtceu.multiblock.exact_hatch_1.tooltip"))
.tooltips(Component.translatable("gtceu.machine.available_recipe_map_1.tooltip",
Component.translatable("gtceu.assembler")))
+ .tooltips(Component.translatable("gtceu.multiblock.exact_hatch_1.tooltip"))
.conditionalTooltip(GTMachineUtils.defaultEnvironmentRequirement(),
ConfigHolder.INSTANCE.gameplay.environmentalHazards)
.rotationState(RotationState.ALL)
@@ -636,7 +636,7 @@ public static void init() {}
.aisle("#YYY#", "YYYYY", "YYYYY", "YYYYY", "#YYY#")
.aisle("#YSY#", "YAAAY", "YAAAY", "YAAAY", "#YYY#")
.aisle("##X##", "#XAX#", "XAPAX", "#XAX#", "##X##").setRepeatable(1, 12)
- .aisle("#####", "#ZZZ#", "#ZCZ#", "#ZZZ#", "#####")
+ .aisle("#####", "#ZZZ#", "#ZZZ#", "#ZZZ#", "#####")
.where('S', controller(blocks(definition.get())))
.where('Y', casingPredicate.or(abilities(IMPORT_ITEMS))
.or(abilities(INPUT_ENERGY).setMinGlobalLimited(1).setMaxGlobalLimited(2))
@@ -646,7 +646,6 @@ public static void init() {}
.where('X', casingPredicate.or(exportPredicate))
.where('Z', casingPredicate)
.where('P', blocks(CASING_STEEL_PIPE.get()))
- .where('C', abilities(MUFFLER))
.where('A', air())
.where('#', any())
.build();
@@ -656,7 +655,6 @@ public static void init() {}
var builder = MultiblockShapeInfo.builder()
.where('S', definition, Direction.NORTH)
.where('C', CASING_WATERTIGHT.getDefaultState())
- .where('M', MUFFLER_HATCH[IV], Direction.UP)
.where('X', PARALLEL_HATCH[IV], Direction.NORTH)
.where('H', FLUID_IMPORT_HATCH[IV], Direction.NORTH)
.where('B', ITEM_EXPORT_BUS[IV], Direction.NORTH)
@@ -676,7 +674,7 @@ public static void init() {}
List aisle3 = new ArrayList<>(16);
aisle3.add("CCCCC");
aisle3.add("C###C");
- aisle3.add("#CMC#");
+ aisle3.add("#CCC#");
List aisle4 = new ArrayList<>(16);
aisle4.add("CCCCC");
aisle4.add("C###C");
@@ -923,7 +921,7 @@ public static void init() {}
.pattern(definition -> FactoryBlockPattern.start()
.aisle("XXXXXXX#KKK", "XXXXXXX#KVK", "XXXXXXX#KVK", "XXXXXXX#KVK", "XXXXXXX#KKK", "XXXXXXX####", "XXXXXXX####")
.aisle("XXXXXXX#KVK", "XPPPPPPPPPV", "XPAPAPX#VPV", "XPPPPPPPPPV", "XPAPAPX#KVK", "XPPPPPX####", "XXXXXXX####")
- .aisle("XXXXXXX#KVK", "XPAPAPXAVPV", "XAAAAAX#VPV", "XPAAAPX#VPV", "XAAAAAX#KVK", "XPAPAPX####", "XXXXXXX####")
+ .aisle("XXXXXXX#KVK", "XPAPAPX#VPV", "XAAAAAX#VPV", "XPAAAPX#VPV", "XAAAAAX#KVK", "XPAPAPX####", "XXXXXXX####")
.aisle("XXXXXXX#KVK", "XPAPAPPPPPV", "XAAAAAX#VPV", "XPAAAPPPPPV", "XAAAAAX#KVK", "XPAPAPX####", "XXXXXXX####")
.aisle("XXXXXXX#KKK", "XPPPPPX#KVK", "XPA#APX#KVK", "XPAAAPX#KVK", "XPAAAPX#KKK", "XPPPPPX####", "XXXXXXX####")
.aisle("#XXXXX#####", "#XXSXX#####", "#XGGGX#####", "#XGGGX#####", "#XGGGX#####", "#XXXXX#####", "###########")
diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/materials/ElementMaterials.java b/src/main/java/com/gregtechceu/gtceu/common/data/materials/ElementMaterials.java
index d006d0cd977..62409787155 100644
--- a/src/main/java/com/gregtechceu/gtceu/common/data/materials/ElementMaterials.java
+++ b/src/main/java/com/gregtechceu/gtceu/common/data/materials/ElementMaterials.java
@@ -1026,7 +1026,7 @@ public static void register() {
Trinium = new Material.Builder(GTCEu.id("trinium"))
.ingot(7).fluid()
.color(0x81808a).secondaryColor(0x351d4b).iconSet(SHINY)
- .flags(GENERATE_FOIL, GENERATE_BOLT_SCREW, GENERATE_GEAR)
+ .flags(GENERATE_FOIL, GENERATE_BOLT_SCREW, GENERATE_GEAR, GENERATE_SPRING)
.element(GTElements.Ke)
.cableProperties(V[ZPM], 6, 4)
.blast(b -> b.temp(7200, GasTier.HIGH)
diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/materials/OrganicChemistryMaterials.java b/src/main/java/com/gregtechceu/gtceu/common/data/materials/OrganicChemistryMaterials.java
index 545e3030f6e..b581ac7cf73 100644
--- a/src/main/java/com/gregtechceu/gtceu/common/data/materials/OrganicChemistryMaterials.java
+++ b/src/main/java/com/gregtechceu/gtceu/common/data/materials/OrganicChemistryMaterials.java
@@ -509,7 +509,7 @@ public static void register() {
.color(0x353529).secondaryColor(0x080808)
.toolStats(
ToolProperty.Builder.of(1.0F, 1.0F, 256, 1, GTToolType.SOFT_MALLET, GTToolType.PLUNGER).build())
- .flags(GENERATE_GEAR, GENERATE_RING, GENERATE_FOIL, GENERATE_BOLT_SCREW)
+ .flags(GENERATE_RING, GENERATE_FOIL)
.components(Carbon, 5, Hydrogen, 8)
.buildAndRegister();
diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/materials/SecondDegreeMaterials.java b/src/main/java/com/gregtechceu/gtceu/common/data/materials/SecondDegreeMaterials.java
index 0bd7ea7c667..4ece776f76b 100644
--- a/src/main/java/com/gregtechceu/gtceu/common/data/materials/SecondDegreeMaterials.java
+++ b/src/main/java/com/gregtechceu/gtceu/common/data/materials/SecondDegreeMaterials.java
@@ -107,7 +107,7 @@ public static void register() {
Apatite = new Material.Builder(GTCEu.id("apatite"))
.gem(1).ore(4, 2)
.color(0x06cdf1).secondaryColor(0x701c07).iconSet(DIAMOND)
- .flags(NO_SMASHING, NO_SMELTING, CRYSTALLIZABLE, GENERATE_BOLT_SCREW, DISABLE_DECOMPOSITION)
+ .flags(NO_SMASHING, NO_SMELTING, CRYSTALLIZABLE, DISABLE_DECOMPOSITION)
.components(Calcium, 5, Phosphate, 3, Chlorine, 1)
.buildAndRegister();
diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/models/GTModels.java b/src/main/java/com/gregtechceu/gtceu/common/data/models/GTModels.java
index c33890e76d7..6065874b12c 100644
--- a/src/main/java/com/gregtechceu/gtceu/common/data/models/GTModels.java
+++ b/src/main/java/com/gregtechceu/gtceu/common/data/models/GTModels.java
@@ -39,6 +39,8 @@ public class GTModels {
public static final ResourceLocation BLANK_TEXTURE = GTCEu.id("block/void");
+ public static final String ACTIVE_SUFFIX = "_active";
+
// region BLOCK MODELS
public static NonNullBiConsumer, GTBlockstateProvider> createModelBlockState(ResourceLocation modelLocation) {
@@ -273,6 +275,12 @@ public static NonNullBiConsumer, RegistrateBl
};
}
+ public static void createPipeBlockModel(DataGenContext> ctx,
+ GTBlockstateProvider prov) {
+ // the pipe model generator handles adding its models to the provider by itself
+ ctx.getEntry().createPipeModel(prov).initModels();
+ }
+
// endregion
// region RUNTIME GEN
diff --git a/src/main/java/com/gregtechceu/gtceu/common/item/modules/ImageModuleBehaviour.java b/src/main/java/com/gregtechceu/gtceu/common/item/modules/ImageModuleBehaviour.java
index fd560be54a5..b21ee3a4750 100644
--- a/src/main/java/com/gregtechceu/gtceu/common/item/modules/ImageModuleBehaviour.java
+++ b/src/main/java/com/gregtechceu/gtceu/common/item/modules/ImageModuleBehaviour.java
@@ -19,7 +19,7 @@
public class ImageModuleBehaviour implements IMonitorModuleItem {
@Override
- public IMonitorRenderer getRenderer(ItemStack stack, CentralMonitorMachine machine, MonitorGroup group) {
+ public IMonitorRenderer getRenderer(ItemStack stack) {
return new MonitorImageRenderer(getUrl(stack));
}
diff --git a/src/main/java/com/gregtechceu/gtceu/common/item/modules/TextModuleBehaviour.java b/src/main/java/com/gregtechceu/gtceu/common/item/modules/TextModuleBehaviour.java
index d745051fe54..beb0f1289f3 100644
--- a/src/main/java/com/gregtechceu/gtceu/common/item/modules/TextModuleBehaviour.java
+++ b/src/main/java/com/gregtechceu/gtceu/common/item/modules/TextModuleBehaviour.java
@@ -39,32 +39,42 @@
public class TextModuleBehaviour implements IMonitorModuleItem, IAddInformation {
- private void updateText(ItemStack stack, CentralMonitorMachine machine, MonitorGroup group) {
+ private void updateText(ItemStack stack, PlaceholderContext ctx) {
if (!stack.getOrCreateTag().contains("placeholderUUID")) {
stack.getOrCreateTag().putUUID("placeholderUUID", UUID.randomUUID());
}
MultiLineComponent text = PlaceholderHandler.processPlaceholders(
getPlaceholderText(stack),
- new PlaceholderContext(
- group.getTargetLevel(machine.getLevel()),
- group.getTarget(machine.getLevel()),
- group.getTargetCoverSide(),
- group.getPlaceholderSlotsHandler(),
- group.getTargetCover(machine.getLevel()),
- null,
- stack.getOrCreateTag().getUUID("placeholderUUID")));
+ ctx);
stack.getOrCreateTag().put("text", text.toTag());
}
+ private PlaceholderContext makeContext(ItemStack stack, CentralMonitorMachine machine, MonitorGroup group) {
+ return new PlaceholderContext(
+ group.getTargetLevel(machine.getLevel()),
+ group.getTarget(machine.getLevel()),
+ group.getTargetCoverSide(),
+ group.getPlaceholderSlotsHandler(),
+ group.getTargetCover(machine.getLevel()),
+ null,
+ stack.getOrCreateTag().contains("placeholderUUID") ? stack.getOrCreateTag().getUUID("placeholderUUID") :
+ null);
+ }
+
@Override
public void tick(ItemStack stack, CentralMonitorMachine machine, MonitorGroup group) {
- this.updateText(stack, machine, group);
+ this.updateText(stack, makeContext(stack, machine, group));
+ }
+
+ @Override
+ public void tickInPlaceholder(ItemStack stack, PlaceholderContext context) {
+ this.updateText(stack, context);
}
@Override
- public IMonitorRenderer getRenderer(ItemStack stack, CentralMonitorMachine machine, MonitorGroup group) {
+ public IMonitorRenderer getRenderer(ItemStack stack) {
return new MonitorTextRenderer(
- getText(stack).toImmutable(),
+ getText(stack),
Math.max(getScale(stack), .0001));
}
@@ -81,7 +91,7 @@ public Widget createUIWidget(ItemStack stack, CentralMonitorMachine machine, Mon
ButtonWidget saveButton = new ButtonWidget(-40, 22, 20, 20, click -> {
if (!click.isRemote) return;
ListTag listTag = new ListTag();
- editor.getLines().forEach(line -> listTag.add(StringTag.valueOf(line)));
+ editor.getLines().forEach(line -> listTag.add(StringTag.valueOf(line.replaceAll("\r", ""))));
CompoundTag tag2 = stack.getOrCreateTag();
tag2.put("formatStringLines", listTag);
try {
@@ -123,7 +133,7 @@ public String getType() {
}
public MultiLineComponent getText(ItemStack stack) {
- return MultiLineComponent.fromTag(stack.getOrCreateTag().getList("text", Tag.TAG_STRING));
+ return MultiLineComponent.fromTag(stack.getOrCreateTag().get("text"));
}
public double getScale(ItemStack stack) {
@@ -136,7 +146,7 @@ public void setScale(ItemStack stack, double scale) {
public void setPlaceholderText(ItemStack stack, String text) {
ListTag listTag = new ListTag();
- for (String line : text.split("\n")) listTag.add(StringTag.valueOf(line));
+ for (String line : text.split("\n")) listTag.add(StringTag.valueOf(line.replaceAll("\r", "")));
stack.getOrCreateTag().put("formatStringLines", listTag);
}
diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CentralMonitorMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CentralMonitorMachine.java
index 4c18fd64f73..84cf9d94b28 100644
--- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CentralMonitorMachine.java
+++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CentralMonitorMachine.java
@@ -391,7 +391,7 @@ public Widget createUIWidget() {
text.setType(TextTexture.TextType.LEFT);
label.setButtonTexture(text);
label.setOnPressCallback(click -> {
- group.getRelativePositions().forEach(pos -> {
+ group.getMonitorPositions().forEach(pos -> {
BlockPos rel = toRelative(pos);
if (imageButtons.size() - 1 < rel.getY()) return;
if (imageButtons.get(rel.getY()).size() - 1 < rel.getX()) return;
diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/DistillationTowerMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/DistillationTowerMachine.java
index b0ad0b7bf7c..f783a7d5d99 100644
--- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/DistillationTowerMachine.java
+++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/DistillationTowerMachine.java
@@ -160,7 +160,7 @@ private static GTRecipe modifyOutputs(GTRecipe recipe, ContentModifier cm) {
recipe.outputChanceLogics,
recipe.tickInputChanceLogics, recipe.tickOutputChanceLogics, recipe.conditions,
recipe.ingredientActions,
- recipe.data, recipe.duration, recipe.recipeCategory);
+ recipe.data, recipe.duration, recipe.recipeCategory, recipe.groupColor);
}
public static class DistillationTowerLogic extends RecipeLogic {
diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/FusionReactorMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/FusionReactorMachine.java
index 11331b040d7..d22921206a8 100644
--- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/FusionReactorMachine.java
+++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/FusionReactorMachine.java
@@ -177,7 +177,8 @@ public static ModifierFunction recipeModifier(@NotNull MetaMachine machine, @Not
if (RecipeHelper.getRecipeEUtTier(recipe) > fusionReactorMachine.getTier() ||
!recipe.data.contains("eu_to_start") ||
recipe.data.getLong("eu_to_start") > fusionReactorMachine.energyContainer.getEnergyCapacity()) {
- return ModifierFunction.NULL;
+ return ModifierFunction
+ .cancel(Component.translatable("gtceu.recipe_modifier.insufficient_eu_to_start_fusion"));
}
long heatDiff = recipe.data.getLong("eu_to_start") - fusionReactorMachine.heat;
@@ -187,7 +188,9 @@ public static ModifierFunction recipeModifier(@NotNull MetaMachine machine, @Not
return FUSION_OC.getModifier(machine, recipe, fusionReactorMachine.getMaxVoltage(), false);
}
// if the remaining energy needed is more than stored, do not run
- if (fusionReactorMachine.energyContainer.getEnergyStored() < heatDiff) return ModifierFunction.NULL;
+ if (fusionReactorMachine.energyContainer.getEnergyStored() < heatDiff)
+ return ModifierFunction
+ .cancel(Component.translatable("gtceu.recipe_modifier.insufficient_eu_to_start_fusion"));
// remove the energy needed
fusionReactorMachine.energyContainer.removeEnergy(heatDiff);
diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/monitor/MonitorGroup.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/monitor/MonitorGroup.java
index c2e0c35dafe..2977aca420f 100644
--- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/monitor/MonitorGroup.java
+++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/monitor/MonitorGroup.java
@@ -30,6 +30,7 @@
public class MonitorGroup {
+ @Getter
private final Set monitorPositions = new HashSet<>();
@Getter
private final String name;
@@ -105,10 +106,6 @@ public boolean isEmpty() {
return monitorPositions.isEmpty();
}
- public Set getRelativePositions() {
- return monitorPositions;
- }
-
public @Nullable CoverBehavior getTargetCover(Level level) {
if (getTarget(level) != null && targetCoverSide != null) {
ICoverable coverable = GTCapabilityHelper.getCoverable(level, getTarget(level), targetCoverSide);
diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/part/ItemBusPartMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/part/ItemBusPartMachine.java
index c3b0e7345c7..871f9236356 100644
--- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/part/ItemBusPartMachine.java
+++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/part/ItemBusPartMachine.java
@@ -3,6 +3,9 @@
import com.gregtechceu.gtceu.api.blockentity.BlockEntityCreationInfo;
import com.gregtechceu.gtceu.api.blockentity.IPaintable;
import com.gregtechceu.gtceu.api.capability.recipe.IO;
+import com.gregtechceu.gtceu.api.cover.filter.FilterHandler;
+import com.gregtechceu.gtceu.api.cover.filter.FilterHandlers;
+import com.gregtechceu.gtceu.api.cover.filter.ItemFilter;
import com.gregtechceu.gtceu.api.gui.GuiTextures;
import com.gregtechceu.gtceu.api.gui.fancy.ConfiguratorPanel;
import com.gregtechceu.gtceu.api.gui.widget.SlotWidget;
@@ -70,12 +73,18 @@ public class ItemBusPartMachine extends TieredIOPartMachine
@SaveField
@SyncToClient
private boolean isDistinct = false;
+ @SaveField
+ @SyncToClient
+ @Getter
+ protected final FilterHandler filterHandler;
public ItemBusPartMachine(BlockEntityCreationInfo info, int tier, IO io) {
super(info, tier, io);
this.inventory = createInventory();
this.circuitSlotEnabled = true;
this.circuitInventory = createCircuitItemHandler(io).shouldSearchContent(false);
+ filterHandler = FilterHandlers.item(this);
+ inventory.setFilter(this::matchesFilter);
}
//////////////////////////////////////
@@ -91,6 +100,12 @@ protected NotifiableItemStackHandler createInventory() {
return new NotifiableItemStackHandler(this, getInventorySize(), io);
}
+ protected boolean matchesFilter(ItemStack stack) {
+ if (filterHandler.isFilterPresent())
+ return filterHandler.getFilter().test(stack);
+ return true;
+ }
+
protected NotifiableItemStackHandler createCircuitItemHandler(IO io) {
if (io == IO.IN) {
return new NotifiableItemStackHandler(this, 1, IO.IN, IO.NONE)
@@ -261,7 +276,7 @@ public boolean swapIO() {
getLevel().setBlockAndUpdate(blockPos, newBlockState);
if (getLevel().getBlockEntity(blockPos) instanceof ItemBusPartMachine newMachine) {
- // We don't set the circuit or distinct busses, since
+ // We don't set the circuit or distinct buses, since
// that doesn't make sense on an output bus.
// Furthermore, existing inventory items
// and conveyors will drop to the floor on block override.
@@ -298,6 +313,7 @@ public Widget createUIWidget() {
var group = new WidgetGroup(0, 0, 18 * rowSize + 16, 18 * colSize + 16);
var container = new WidgetGroup(4, 4, 18 * rowSize + 8, 18 * colSize + 8);
int index = 0;
+ group.addWidget(filterHandler.createFilterSlotUI(-115 + (18 * rowSize) / 2, 35 + 11 * rowSize));
for (int y = 0; y < colSize; y++) {
for (int x = 0; x < rowSize; x++) {
container.addWidget(
@@ -309,7 +325,6 @@ public Widget createUIWidget() {
container.setBackground(GuiTextures.BACKGROUND_INVERSE);
group.addWidget(container);
-
return group;
}
}
diff --git a/src/main/java/com/gregtechceu/gtceu/common/pipelike/cable/Insulation.java b/src/main/java/com/gregtechceu/gtceu/common/pipelike/cable/Insulation.java
index b149d5df98c..fc543f04ff4 100644
--- a/src/main/java/com/gregtechceu/gtceu/common/pipelike/cable/Insulation.java
+++ b/src/main/java/com/gregtechceu/gtceu/common/pipelike/cable/Insulation.java
@@ -1,19 +1,19 @@
package com.gregtechceu.gtceu.common.pipelike.cable;
import com.gregtechceu.gtceu.GTCEu;
+import com.gregtechceu.gtceu.api.block.PipeBlock;
import com.gregtechceu.gtceu.api.data.chemical.material.Material;
import com.gregtechceu.gtceu.api.data.chemical.material.info.MaterialIconType;
import com.gregtechceu.gtceu.api.data.chemical.material.properties.WireProperties;
import com.gregtechceu.gtceu.api.data.tag.TagPrefix;
import com.gregtechceu.gtceu.api.pipenet.IMaterialPipeType;
-import com.gregtechceu.gtceu.client.model.PipeModel;
+import com.gregtechceu.gtceu.api.registry.registrate.provider.GTBlockstateProvider;
+import com.gregtechceu.gtceu.client.model.pipe.PipeModel;
+import com.gregtechceu.gtceu.common.data.models.GTModels;
import net.minecraft.resources.ResourceLocation;
import lombok.Getter;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.function.Supplier;
import static com.gregtechceu.gtceu.api.data.tag.TagPrefix.*;
@@ -83,20 +83,28 @@ public ResourceLocation type() {
return TYPE_ID;
}
- public PipeModel createPipeModel(Material material) {
- Supplier wireSideTexturePath = () -> MaterialIconType.wire
+ public PipeModel createPipeModel(PipeBlock, ?, ?> block, Material material, GTBlockstateProvider provider) {
+ ResourceLocation side = MaterialIconType.wire
.getBlockTexturePath(material.getMaterialIconSet(), "side", true);
- Supplier wireEndTexturePath = () -> MaterialIconType.wire
+ ResourceLocation end = MaterialIconType.wire
.getBlockTexturePath(material.getMaterialIconSet(), "end", true);
- Supplier<@Nullable ResourceLocation> wireSideOverlayTexturePath = () -> MaterialIconType.wire
+
+ PipeModel model = new PipeModel(block, provider, thickness,
+ isCable ? GTCEu.id("block/cable/insulation_5") : side, end);
+
+ ResourceLocation sideSecondary = MaterialIconType.wire
.getBlockTexturePath(material.getMaterialIconSet(), "side_overlay", true);
- Supplier<@Nullable ResourceLocation> wireEndOverlayTexturePath = () -> MaterialIconType.wire
+ ResourceLocation endSecondary = MaterialIconType.wire
.getBlockTexturePath(material.getMaterialIconSet(), "end_overlay", true);
- PipeModel model = new PipeModel(thickness,
- isCable ? () -> GTCEu.id("block/cable/insulation_5") : wireSideTexturePath, wireEndTexturePath,
- wireSideOverlayTexturePath, wireEndOverlayTexturePath);
+
+ if (sideSecondary != null && !sideSecondary.equals(GTModels.BLANK_TEXTURE)) {
+ model.setSideSecondary(sideSecondary);
+ }
+ if (endSecondary != null && !endSecondary.equals(GTModels.BLANK_TEXTURE)) {
+ model.setEndSecondary(endSecondary);
+ }
if (isCable) {
- model.setEndOverlayTexture(GTCEu.id("block/cable/insulation_%s".formatted(insulationLevel)));
+ model.setEndOverlay(GTCEu.id("block/cable/insulation_%s".formatted(insulationLevel)));
}
return model;
}
diff --git a/src/main/java/com/gregtechceu/gtceu/common/pipelike/duct/DuctPipeType.java b/src/main/java/com/gregtechceu/gtceu/common/pipelike/duct/DuctPipeType.java
index 1323fa297f1..feebae0b7ca 100644
--- a/src/main/java/com/gregtechceu/gtceu/common/pipelike/duct/DuctPipeType.java
+++ b/src/main/java/com/gregtechceu/gtceu/common/pipelike/duct/DuctPipeType.java
@@ -2,7 +2,6 @@
import com.gregtechceu.gtceu.GTCEu;
import com.gregtechceu.gtceu.api.pipenet.IPipeType;
-import com.gregtechceu.gtceu.client.model.PipeModel;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.StringRepresentable;
@@ -54,10 +53,4 @@ public ResourceLocation type() {
public String getSerializedName() {
return name().toLowerCase(Locale.ROOT);
}
-
- public PipeModel createPipeModel() {
- return new PipeModel(thickness, () -> GTCEu.id("block/pipe/pipe_duct_side"),
- () -> GTCEu.id("block/pipe/pipe_duct_in"),
- null, null);
- }
}
diff --git a/src/main/java/com/gregtechceu/gtceu/common/pipelike/fluidpipe/FluidPipeType.java b/src/main/java/com/gregtechceu/gtceu/common/pipelike/fluidpipe/FluidPipeType.java
index 8ad5940e500..f068dd69236 100644
--- a/src/main/java/com/gregtechceu/gtceu/common/pipelike/fluidpipe/FluidPipeType.java
+++ b/src/main/java/com/gregtechceu/gtceu/common/pipelike/fluidpipe/FluidPipeType.java
@@ -1,12 +1,14 @@
package com.gregtechceu.gtceu.common.pipelike.fluidpipe;
import com.gregtechceu.gtceu.GTCEu;
+import com.gregtechceu.gtceu.api.block.PipeBlock;
import com.gregtechceu.gtceu.api.data.chemical.material.Material;
import com.gregtechceu.gtceu.api.data.chemical.material.properties.FluidPipeProperties;
import com.gregtechceu.gtceu.api.data.chemical.material.properties.PropertyKey;
import com.gregtechceu.gtceu.api.data.tag.TagPrefix;
import com.gregtechceu.gtceu.api.pipenet.IMaterialPipeType;
-import com.gregtechceu.gtceu.client.model.PipeModel;
+import com.gregtechceu.gtceu.api.registry.registrate.provider.GTBlockstateProvider;
+import com.gregtechceu.gtceu.client.model.pipe.PipeModel;
import net.minecraft.resources.ResourceLocation;
@@ -72,26 +74,20 @@ public ResourceLocation type() {
return TYPE_ID;
}
- public PipeModel createPipeModel(Material material) {
+ public PipeModel createPipeModel(PipeBlock, ?, ?> block, Material material, GTBlockstateProvider provider) {
+ String side = "block/pipe/pipe%s_side";
+ String end = "block/pipe/pipe_%s_in".formatted(name);
if (material.hasProperty(PropertyKey.WOOD)) {
- return new PipeModel(thickness, () -> GTCEu.id("block/pipe/pipe_side_wood"),
- () -> GTCEu.id("block/pipe/pipe_%s_in_wood".formatted(name)), null, null);
+ side += "_wood";
+ end += "_wood";
}
if (channels == 9) {
- return new PipeModel(thickness, () -> GTCEu.id("block/pipe/pipe_non_side"),
- () -> GTCEu.id("block/pipe/pipe_%s_in".formatted(name)),
- null, null);
+ side = side.formatted("_non");
} else if (channels == 4) {
- return new PipeModel(thickness, () -> GTCEu.id("block/pipe/pipe_quad_side"),
- () -> GTCEu.id("block/pipe/pipe_%s_in".formatted(name)),
- null, null);
+ side = side.formatted("_quad");
+ } else {
+ side = side.formatted("");
}
- return new PipeModel(thickness, () -> GTCEu.id("block/pipe/pipe_side"),
- () -> GTCEu.id("block/pipe/pipe_%s_in".formatted(name)),
- null, null/*
- * () -> GTCEu.id("block/pipe/pipe_side_secondary"), () ->
- * GTCEu.id("block/pipe/pipe_%s_in_secondary".formatted(name)) TODO enable once the textures
- * are added
- */);
+ return new PipeModel(block, provider, thickness, GTCEu.id(side), GTCEu.id(end));
}
}
diff --git a/src/main/java/com/gregtechceu/gtceu/common/pipelike/item/ItemPipeType.java b/src/main/java/com/gregtechceu/gtceu/common/pipelike/item/ItemPipeType.java
index 68e5c37d016..8c6a4f78083 100644
--- a/src/main/java/com/gregtechceu/gtceu/common/pipelike/item/ItemPipeType.java
+++ b/src/main/java/com/gregtechceu/gtceu/common/pipelike/item/ItemPipeType.java
@@ -1,12 +1,14 @@
package com.gregtechceu.gtceu.common.pipelike.item;
import com.gregtechceu.gtceu.GTCEu;
+import com.gregtechceu.gtceu.api.block.PipeBlock;
import com.gregtechceu.gtceu.api.data.chemical.material.Material;
import com.gregtechceu.gtceu.api.data.chemical.material.properties.ItemPipeProperties;
import com.gregtechceu.gtceu.api.data.chemical.material.properties.PropertyKey;
import com.gregtechceu.gtceu.api.data.tag.TagPrefix;
import com.gregtechceu.gtceu.api.pipenet.IMaterialPipeType;
-import com.gregtechceu.gtceu.client.model.PipeModel;
+import com.gregtechceu.gtceu.api.registry.registrate.provider.GTBlockstateProvider;
+import com.gregtechceu.gtceu.client.model.pipe.PipeModel;
import net.minecraft.resources.ResourceLocation;
@@ -72,25 +74,18 @@ public ResourceLocation type() {
return TYPE_ID;
}
- public PipeModel createPipeModel(Material material) {
- PipeModel model;
+ public PipeModel createPipeModel(PipeBlock, ?, ?> block, Material material, GTBlockstateProvider provider) {
+ ResourceLocation sideTexture = GTCEu.id("block/pipe/pipe_side");
+ ResourceLocation endTexture = GTCEu.id("block/pipe/pipe_%s_in"
+ .formatted(this.isRestrictive() ? values()[this.ordinal() - 4].name : name));
if (material.hasProperty(PropertyKey.WOOD)) {
- model = new PipeModel(thickness, () -> GTCEu.id("block/pipe/pipe_side_wood"),
- () -> GTCEu.id("block/pipe/pipe_%s_in_wood"
- .formatted(this.isRestrictive() ? values()[this.ordinal() - 4].name : name)),
- null, null);
- } else {
- model = new PipeModel(thickness, () -> GTCEu.id("block/pipe/pipe_side"),
- () -> GTCEu.id("block/pipe/pipe_%s_in"
- .formatted(this.isRestrictive() ? values()[this.ordinal() - 4].name : name)),
- null, null/*
- * () -> GTCEu.id("block/pipe/pipe_side_secondary"), () ->
- * GTCEu.id("block/pipe/pipe_%s_in_secondary".formatted(this.isRestrictive() ?
- * values()[this.ordinal() - 4].name : name)) TODO enable once the textures are added
- */);
+ sideTexture = sideTexture.withSuffix("_wood");
+ endTexture = endTexture.withSuffix("_wood");
}
+
+ PipeModel model = new PipeModel(block, provider, thickness, sideTexture, endTexture);
if (isRestrictive()) {
- model.setSideOverlayTexture(GTCEu.id("block/pipe/pipe_restrictive"));
+ model.setSideOverlay(GTCEu.id("block/pipe/pipe_restrictive"));
}
return model;
}
diff --git a/src/main/java/com/gregtechceu/gtceu/common/recipe/condition/AdjacentFluidCondition.java b/src/main/java/com/gregtechceu/gtceu/common/recipe/condition/AdjacentFluidCondition.java
index a1c2217d086..8efbde197a2 100644
--- a/src/main/java/com/gregtechceu/gtceu/common/recipe/condition/AdjacentFluidCondition.java
+++ b/src/main/java/com/gregtechceu/gtceu/common/recipe/condition/AdjacentFluidCondition.java
@@ -93,7 +93,12 @@ public RecipeConditionType getType() {
@Override
public Component getTooltips() {
- return Component.translatable("recipe.condition.adjacent_fluid.tooltip");
+ var tooltips = Component.translatable("recipe.condition.adjacent_fluid.tooltip");
+ fluids.forEach(set -> {
+ var id = set.get().get(0).get().getFluidType().getDescription();
+ tooltips.append(" ").append(id);
+ });
+ return tooltips;
}
@Override
diff --git a/src/main/java/com/gregtechceu/gtceu/common/recipe/condition/BiomeTagCondition.java b/src/main/java/com/gregtechceu/gtceu/common/recipe/condition/BiomeTagCondition.java
new file mode 100644
index 00000000000..8e78c454778
--- /dev/null
+++ b/src/main/java/com/gregtechceu/gtceu/common/recipe/condition/BiomeTagCondition.java
@@ -0,0 +1,73 @@
+package com.gregtechceu.gtceu.common.recipe.condition;
+
+import com.gregtechceu.gtceu.api.machine.trait.RecipeLogic;
+import com.gregtechceu.gtceu.api.recipe.GTRecipe;
+import com.gregtechceu.gtceu.api.recipe.RecipeCondition;
+import com.gregtechceu.gtceu.api.recipe.condition.RecipeConditionType;
+import com.gregtechceu.gtceu.common.data.GTRecipeConditions;
+
+import net.minecraft.core.Holder;
+import net.minecraft.core.registries.Registries;
+import net.minecraft.network.chat.Component;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.tags.TagKey;
+import net.minecraft.world.level.Level;
+import net.minecraft.world.level.biome.Biome;
+
+import com.mojang.serialization.Codec;
+import com.mojang.serialization.codecs.RecordCodecBuilder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import org.jetbrains.annotations.NotNull;
+
+@NoArgsConstructor
+public class BiomeTagCondition extends RecipeCondition {
+
+ public static final Codec CODEC = RecordCodecBuilder
+ .create(instance -> RecipeCondition.isReverse(instance)
+ .and(TagKey.codec(Registries.BIOME).fieldOf("biome_tag").forGetter(val -> val.biome))
+ .apply(instance, BiomeTagCondition::new));
+
+ public final static BiomeTagCondition INSTANCE = new BiomeTagCondition();
+ @Getter
+ private TagKey biome = TagKey.create(Registries.BIOME, new ResourceLocation("dummy"));
+
+ public BiomeTagCondition(boolean isReverse, TagKey biome) {
+ super(isReverse);
+ this.biome = biome;
+ }
+
+ public BiomeTagCondition(TagKey biome) {
+ this.biome = biome;
+ }
+
+ @Override
+ public RecipeConditionType getType() {
+ return GTRecipeConditions.BIOME_TAG;
+ }
+
+ @Override
+ public boolean isOr() {
+ return true;
+ }
+
+ @Override
+ public Component getTooltips() {
+ return Component.translatable("recipe.condition.biome.tooltip",
+ Component.translatableWithFallback(biome.location().toLanguageKey("biome"),
+ biome.location().toString()));
+ }
+
+ @Override
+ public boolean testCondition(@NotNull GTRecipe recipe, @NotNull RecipeLogic recipeLogic) {
+ Level level = recipeLogic.machine.self().getLevel();
+ if (level == null) return false;
+ Holder biome = level.getBiome(recipeLogic.machine.self().getBlockPos());
+ return biome.is(this.biome);
+ }
+
+ @Override
+ public BiomeTagCondition createTemplate() {
+ return new BiomeTagCondition();
+ }
+}
diff --git a/src/main/java/com/gregtechceu/gtceu/common/recipe/condition/DimensionCondition.java b/src/main/java/com/gregtechceu/gtceu/common/recipe/condition/DimensionCondition.java
index 84b2f9d86c8..d046376bdd0 100644
--- a/src/main/java/com/gregtechceu/gtceu/common/recipe/condition/DimensionCondition.java
+++ b/src/main/java/com/gregtechceu/gtceu/common/recipe/condition/DimensionCondition.java
@@ -82,7 +82,7 @@ public SlotWidget setupDimensionMarkers(int xOffset, int yOffset) {
@Override
public boolean testCondition(@NotNull GTRecipe recipe, @NotNull RecipeLogic recipeLogic) {
Level level = recipeLogic.machine.self().getLevel();
- return level != null && dimension.equals(level.dimension().location());
+ return level != null && dimension.location().equals(level.dimension().location());
}
@Override
diff --git a/src/main/java/com/gregtechceu/gtceu/config/ConfigHolder.java b/src/main/java/com/gregtechceu/gtceu/config/ConfigHolder.java
index c15a4275e3f..3248f0c11be 100644
--- a/src/main/java/com/gregtechceu/gtceu/config/ConfigHolder.java
+++ b/src/main/java/com/gregtechceu/gtceu/config/ConfigHolder.java
@@ -846,6 +846,10 @@ public static class DeveloperConfigs {
@Configurable
@Configurable.Comment({ "Dump all registered GT models/blockstates/etc?", "Default: false" })
public boolean dumpAssets = false;
+ @Configurable
+ @Configurable.Comment({ "Executes ./gradlew :processResources when F3+T is pressed",
+ "Only works in a development environment", "Default: false" })
+ public boolean autoRebuildResources = false;
}
public static class RendererConfigs {
@@ -858,13 +862,18 @@ public static class RendererConfigs {
@Configurable.Comment({ "Render growing plants in multiblocks that support them?", "Default: true" })
public boolean renderGrowingPlants = true;
+ @Configurable
+ @Configurable.Comment({ "Whether or not to color material/ore block highlights in the material color",
+ "Default: true" })
+ public boolean coloredMaterialBlockOutline = true;
+
@Configurable
@Configurable.Comment({ "Whether or not to color tiered machine highlights in the tier color",
"Default: true" })
public boolean coloredTieredMachineOutline = true;
@Configurable
- @Configurable.Comment({ "Whether or not to color wire/cable highlights based on voltage tier",
+ @Configurable.Comment({ "Whether or not to color wire/cable highlights based on voltage tier or material color",
"Default: true" })
public boolean coloredWireOutline = true;
}
diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/SmithingTransformRecipeMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/SmithingTransformRecipeMixin.java
new file mode 100644
index 00000000000..d349dc17cb2
--- /dev/null
+++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/SmithingTransformRecipeMixin.java
@@ -0,0 +1,63 @@
+package com.gregtechceu.gtceu.core.mixins;
+
+import com.gregtechceu.gtceu.api.item.IGTTool;
+import com.gregtechceu.gtceu.api.item.tool.ToolHelper;
+
+import net.minecraft.core.RegistryAccess;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.nbt.Tag;
+import net.minecraft.world.Container;
+import net.minecraft.world.item.ItemStack;
+import net.minecraft.world.item.crafting.SmithingTransformRecipe;
+
+import com.llamalad7.mixinextras.sugar.Share;
+import com.llamalad7.mixinextras.sugar.ref.LocalRef;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.Redirect;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+
+@Mixin(SmithingTransformRecipe.class)
+public class SmithingTransformRecipeMixin {
+
+ @Shadow
+ @Final
+ ItemStack result;
+
+ @Inject(method = "assemble",
+ at = @At(value = "INVOKE",
+ target = "Lnet/minecraft/world/item/ItemStack;setTag(Lnet/minecraft/nbt/CompoundTag;)V"))
+ private void gtceu$gtToolSmithingTransform1(Container container, RegistryAccess registryAccess,
+ CallbackInfoReturnable cir,
+ @Share("newTag") LocalRef sharedTag) {
+ ItemStack output = this.result.copy();
+
+ if (!(output.getItem() instanceof IGTTool igtTool)) return;
+
+ CompoundTag originalTag = container.getItem(1).getTag();
+ CompoundTag newTag = originalTag != null ? originalTag.copy() : null;
+ if (newTag == null) return;
+
+ // Remove old tool stats
+ newTag.remove("GT.Tool");
+
+ // Copy stats from the upgraded tool
+ ItemStack newStack = ToolHelper.get(igtTool.getToolType(), igtTool.getMaterial());
+ Tag newStats = newStack.getTag() != null ? newStack.getTag().get("GT.Tool") : null;
+ if (newStats != null) {
+ newTag.put("GT.Tool", newStats);
+ sharedTag.set(newTag);
+ }
+ }
+
+ @Redirect(method = "assemble",
+ at = @At(value = "INVOKE",
+ target = "Lnet/minecraft/world/item/ItemStack;setTag(Lnet/minecraft/nbt/CompoundTag;)V"))
+ private void gtceu$gtToolSmithingTransform2(ItemStack itemStack, CompoundTag tag,
+ @Share("newTag") LocalRef sharedTag) {
+ itemStack.setTag(sharedTag.get());
+ }
+}
diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/LevelRendererMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/LevelRendererMixin.java
index c79852c7beb..fe2adab665c 100644
--- a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/LevelRendererMixin.java
+++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/LevelRendererMixin.java
@@ -7,7 +7,6 @@
import com.gregtechceu.gtceu.api.data.chemical.material.stack.MaterialEntry;
import com.gregtechceu.gtceu.api.item.tool.ToolHelper;
import com.gregtechceu.gtceu.api.item.tool.aoe.AoESymmetrical;
-import com.gregtechceu.gtceu.api.machine.MetaMachine;
import com.gregtechceu.gtceu.api.machine.feature.ITieredMachine;
import com.gregtechceu.gtceu.api.machine.steam.SteamMachine;
import com.gregtechceu.gtceu.api.pipenet.IPipeNode;
@@ -19,7 +18,6 @@
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.*;
-import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.client.resources.model.ModelBakery;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.BlockDestructionProgress;
@@ -44,7 +42,6 @@
import com.mojang.blaze3d.vertex.SheetedDecalTextureGenerator;
import com.mojang.blaze3d.vertex.VertexConsumer;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
-import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.joml.Matrix4f;
import org.spongepowered.asm.mixin.Final;
@@ -177,26 +174,23 @@ private static void renderShape(PoseStack poseStack, VertexConsumer consumer, Vo
assert level != null;
var rendererCfg = ConfigHolder.INSTANCE.client.renderer;
int rgb = 0;
- boolean doRenderColoredOutline = false;
+ boolean renderColoredOutline = false;
// spotless:off
- // if it's translucent and a material block, always do the colored outline
- MaterialEntry materialEntry = gtceu$getTranslucentBlockMaterial(state, pos);
- if (!materialEntry.isEmpty()) {
- doRenderColoredOutline = true;
+ MaterialEntry materialEntry = ChemicalHelper.getMaterialEntry(state.getBlock());
+ if (rendererCfg.coloredMaterialBlockOutline && !materialEntry.isEmpty()) {
+ renderColoredOutline = true;
rgb = materialEntry.material().getMaterialRGB();
- } else if (level.getBlockEntity(pos) instanceof MetaMachine mbe) {
- if (rendererCfg.coloredTieredMachineOutline) {
- if (mbe instanceof SteamMachine steam) {
- doRenderColoredOutline = true;
+ } else if (rendererCfg.coloredTieredMachineOutline) {
+ if (level.getBlockEntity(pos) instanceof SteamMachine steam) {
+ renderColoredOutline = true;
rgb = steam.isHighPressure() ? GTValues.VC_HP_STEAM : GTValues.VC_LP_STEAM;
- } else if (mbe instanceof ITieredMachine tiered) {
- doRenderColoredOutline = true;
+ } else if (level.getBlockEntity(pos) instanceof ITieredMachine tiered) {
+ renderColoredOutline = true;
rgb = GTValues.VCM[tiered.getTier()];
}
- }
} else if (rendererCfg.coloredWireOutline && level.getBlockEntity(pos) instanceof IPipeNode, ?> pipe) {
- doRenderColoredOutline = true;
+ renderColoredOutline = true;
if (!pipe.getFrameMaterial().isNull()) {
rgb = pipe.getFrameMaterial().getMaterialRGB();
} else if (pipe instanceof CableBlockEntity cable) {
@@ -205,48 +199,18 @@ private static void renderShape(PoseStack poseStack, VertexConsumer consumer, Vo
rgb = materialPipe.material.getMaterialRGB();
}
}
-
- VoxelShape blockShape = state.getShape(level, pos, CollisionContext.of(entity));
// spotless:on
- if (doRenderColoredOutline) {
+ VoxelShape blockShape = state.getShape(level, pos, CollisionContext.of(entity));
+
+ if (renderColoredOutline) {
float red = FastColor.ARGB32.red(rgb) / 255f;
float green = FastColor.ARGB32.green(rgb) / 255f;
float blue = FastColor.ARGB32.blue(rgb) / 255f;
renderShape(poseStack, consumer, blockShape,
pos.getX() - camX, pos.getY() - camY, pos.getZ() - camZ,
- red, green, blue, 1f);
+ red, green, blue, 0.4f);
return;
}
- BlockPos.MutableBlockPos mutable = pos.mutable();
- for (BlockPos o : GTUtil.NON_CORNER_NEIGHBOURS) {
- BlockPos offset = mutable.setWithOffset(pos, o);
- if (!gtceu$getTranslucentBlockMaterial(level.getBlockState(offset), offset).isEmpty()) {
- renderShape(poseStack, consumer, blockShape,
- pos.getX() - camX, pos.getY() - camY, pos.getZ() - camZ,
- 0, 0, 0, 1f);
- return;
- }
- }
original.call(instance, poseStack, consumer, entity, camX, camY, camZ, pos, state);
}
-
- @Unique
- private @NotNull MaterialEntry gtceu$getTranslucentBlockMaterial(BlockState state, BlockPos pos) {
- assert level != null;
- // skip non-solid blocks from other mods (like vanilla ice blocks)
- if (!state.isSolidRender(level, pos) && !(state.getBlock() instanceof MaterialBlock)) {
- return MaterialEntry.NULL_ENTRY;
- }
-
- BakedModel blockModel = minecraft.getBlockRenderer().getBlockModel(state);
- ModelData modelData = level.getModelDataManager().getAt(pos);
- if (modelData == null) modelData = ModelData.EMPTY;
- modelData = blockModel.getModelData(level, pos, state, modelData);
-
- gtceu$modelRandom.setSeed(state.getSeed(pos));
- if (blockModel.getRenderTypes(state, gtceu$modelRandom, modelData).contains(RenderType.translucent())) {
- return ChemicalHelper.getMaterialEntry(state.getBlock());
- }
- return MaterialEntry.NULL_ENTRY;
- }
}
diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/ModelManagerMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/ModelManagerMixin.java
index 24605160b28..9c8a8ec19f1 100644
--- a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/ModelManagerMixin.java
+++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/ModelManagerMixin.java
@@ -1,14 +1,7 @@
package com.gregtechceu.gtceu.core.mixins.client;
import com.gregtechceu.gtceu.GTCEu;
-import com.gregtechceu.gtceu.client.renderer.block.MaterialBlockRenderer;
-import com.gregtechceu.gtceu.client.renderer.block.OreBlockRenderer;
-import com.gregtechceu.gtceu.client.renderer.block.SurfaceRockRenderer;
-import com.gregtechceu.gtceu.client.renderer.item.ArmorItemRenderer;
-import com.gregtechceu.gtceu.client.renderer.item.TagPrefixItemRenderer;
-import com.gregtechceu.gtceu.client.renderer.item.ToolItemRenderer;
-import com.gregtechceu.gtceu.common.data.models.GTModels;
-import com.gregtechceu.gtceu.integration.kjs.GregTechKubeJSPlugin;
+import com.gregtechceu.gtceu.data.pack.event.RegisterDynamicResourcesEvent;
import com.gregtechceu.gtceu.integration.modernfix.GTModernFixIntegration;
import net.minecraft.client.resources.model.ModelManager;
@@ -37,17 +30,8 @@ public abstract class ModelManagerMixin {
long startTime = System.currentTimeMillis();
// turns out these do have to be init in here after all, as they check for asset existence. whoops.
- MaterialBlockRenderer.reinitModels();
- TagPrefixItemRenderer.reinitModels();
- OreBlockRenderer.reinitModels();
- ToolItemRenderer.reinitModels();
- ArmorItemRenderer.reinitModels();
- SurfaceRockRenderer.reinitModels();
- GTModels.registerMaterialFluidModels();
-
- if (GTCEu.Mods.isKubeJSLoaded()) {
- GregTechKubeJSPlugin.generateMachineBlockModels();
- }
+ ModLoader.get().postEventWrapContainerInModOrder(new RegisterDynamicResourcesEvent());
+
if (GTCEu.Mods.isModernFixLoaded()) {
GTModernFixIntegration.setAsLast();
}
diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/dev/client/KeyboardHandlerMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/dev/client/KeyboardHandlerMixin.java
new file mode 100644
index 00000000000..e06b0e59053
--- /dev/null
+++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/dev/client/KeyboardHandlerMixin.java
@@ -0,0 +1,25 @@
+package com.gregtechceu.gtceu.core.mixins.dev.client;
+
+import com.gregtechceu.gtceu.utils.dev.ResourceReloadDetector;
+
+import net.minecraft.client.KeyboardHandler;
+import net.minecraft.client.Minecraft;
+
+import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
+import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+
+import java.util.concurrent.CompletableFuture;
+
+@Mixin(KeyboardHandler.class)
+public abstract class KeyboardHandlerMixin {
+
+ @WrapOperation(method = "handleDebugKeys",
+ at = @At(value = "INVOKE",
+ target = "Lnet/minecraft/client/Minecraft;reloadResourcePacks()Ljava/util/concurrent/CompletableFuture;"))
+ private CompletableFuture gtceu$hookResourceReload(Minecraft instance,
+ Operation> original) {
+ return ResourceReloadDetector.regenerateResourcesOnReload(() -> original.call(instance));
+ }
+}
diff --git a/src/main/java/com/gregtechceu/gtceu/data/lang/LangHandler.java b/src/main/java/com/gregtechceu/gtceu/data/lang/LangHandler.java
index 7aabc341492..f36f4b91036 100644
--- a/src/main/java/com/gregtechceu/gtceu/data/lang/LangHandler.java
+++ b/src/main/java/com/gregtechceu/gtceu/data/lang/LangHandler.java
@@ -28,6 +28,7 @@ public static void init(RegistrateLangProvider provider) {
MachineLang.init(provider);
ToolLang.init(provider);
ConfigurationLang.init(provider);
+ RecipeLogicLang.init(provider);
provider.add("gtceu.gui.editor.tips.citation", "Number of citations");
provider.add("gtceu.gui.editor.group.recipe_type", "cap");
@@ -1234,6 +1235,9 @@ public static void init(RegistrateLangProvider provider) {
provider.add("gtceu.key.enable_step_assist", "Enable StepAssist");
provider.add("gtceu.debug.f3_h.enabled",
"GregTech has modified the debug info! For Developers: enable the misc:debug config option in the GregTech config file to see more");
+ provider.add("gtceu.debug.resource_rebuild.done", "Gradle resource rebuild done in %s");
+ provider.add("gtceu.debug.resource_rebuild.start",
+ "Invoking gradle resource rebuild (./gradlew :processResources)");
provider.add("config.jade.plugin_gtceu.controllable_provider", "[GTCEu] Controllable");
provider.add("config.jade.plugin_gtceu.workable_provider", "[GTCEu] Workable");
provider.add("config.jade.plugin_gtceu.battery_info", "[GTCEu] Battery info");
@@ -1264,12 +1268,7 @@ public static void init(RegistrateLangProvider provider) {
provider.add("gtceu.button.hide_depleted", "Hide Depleted Veins");
provider.add("gtceu.button.show_depleted", "Show Depleted Veins");
provider.add("gtceu.recipe_type.show_recipes", "Show Recipes");
- provider.add("gtceu.recipe_logic.insufficient_fuel", "Insufficient Fuel");
- provider.add("gtceu.recipe_logic.insufficient_in", "Insufficient Inputs");
- provider.add("gtceu.recipe_logic.insufficient_out", "Insufficient Outputs");
- provider.add("gtceu.recipe_logic.condition_fails", "Condition Fails");
- provider.add("gtceu.recipe_logic.no_contents", "Recipe has no Contents");
- provider.add("gtceu.recipe_logic.no_capabilities", "Machine has no Capabilities");
+
provider.add("gtceu.gui.cover_setting.title", "Cover Settings");
provider.add("gtceu.gui.output_setting.title", "Output Settings");
provider.add("gtceu.gui.circuit.title", "Circuit Settings");
@@ -1669,6 +1668,27 @@ public static void init(RegistrateLangProvider provider) {
" {eval \"repeating a: {repeat 5 \\\"a \\\"}\" -> repeating a: a a a a a ",
" {eval \\\"\"{some random text}\"\\\" -> {some random text}",
" {eval \"text \"\\\"\"{something with spaces}\"\\\"\" more text\" -> text {something with spaces} more text");
+ multiLang(provider, "gtceu.placeholder_info.module",
+ "Renders the module in the specified slot onto the central monitor (does not work in a cover)",
+ "Usage:",
+ " {module } -> empty string");
+ multiLang(provider, "gtceu.placeholder_info.setImage",
+ "Sets the image URL in an image module in the specified slot",
+ "Usage:",
+ " {setImage } -> empty string");
+ multiLang(provider, "gtceu.placeholder_info.rect",
+ "Draws a rectangle at the specified position with the specified coordinates and size",
+ "Usage:",
+ " {rect } -> empty string",
+ " {rect 0.5 0.25 2 1 0xFFFFFFFF} -> draws a white rectangle at (0.5, 0.25) with the size (2, 1)");
+ multiLang(provider, "gtceu.placeholder_info.quad",
+ "Draws a quad (must specify parameters for all 4 vertices)",
+ "Usage:",
+ " {quad } -> empty string");
+ multiLang(provider, "gtceu.placeholder_info.item",
+ "Returns the amount and id of the item in a specified slot",
+ "Usage:",
+ " {item } -> \"31 minecraft:diamond\" (for example)");
multiLang(provider, "gtceu.placeholder_info.bufferText",
"Returns the text from a buffer accessible by ComputerCraft",
"Usage:",
diff --git a/src/main/java/com/gregtechceu/gtceu/data/lang/RecipeLogicLang.java b/src/main/java/com/gregtechceu/gtceu/data/lang/RecipeLogicLang.java
new file mode 100644
index 00000000000..3146df4ba7b
--- /dev/null
+++ b/src/main/java/com/gregtechceu/gtceu/data/lang/RecipeLogicLang.java
@@ -0,0 +1,31 @@
+package com.gregtechceu.gtceu.data.lang;
+
+import com.tterrag.registrate.providers.RegistrateLangProvider;
+
+public class RecipeLogicLang {
+
+ public static void init(RegistrateLangProvider provider) {
+ initGenericLang(provider);
+ initModifierLang(provider);
+ }
+
+ private static void initGenericLang(RegistrateLangProvider provider) {
+ provider.add("gtceu.recipe_logic.setup_fail", "Fail to setup recipe: ");
+ provider.add("gtceu.recipe_logic.recipe_waiting", "Recipe Waiting: ");
+
+ provider.add("gtceu.recipe_logic.insufficient_fuel", "Insufficient Fuel");
+ provider.add("gtceu.recipe_logic.insufficient_in", "Insufficient Inputs");
+ provider.add("gtceu.recipe_logic.insufficient_out", "Insufficient Outputs");
+ provider.add("gtceu.recipe_logic.condition_fails", "Condition Fails");
+ provider.add("gtceu.recipe_logic.no_contents", "Recipe has no Contents");
+ provider.add("gtceu.recipe_logic.no_capabilities", "Machine has no Capabilities");
+ }
+
+ private static void initModifierLang(RegistrateLangProvider provider) {
+ provider.add("gtceu.recipe_modifier.default_fail", "Recipe Modifier Fail");
+ provider.add("gtceu.recipe_modifier.insufficient_voltage", "Voltage Tier Too Low");
+ provider.add("gtceu.recipe_modifier.insufficient_eu_to_start_fusion",
+ "Insufficient Energy to Initiate Fusion Reaction");
+ provider.add("gtceu.recipe_modifier.coil_temperature_too_low", "Coil Temperature Too Low");
+ }
+}
diff --git a/src/main/java/com/gregtechceu/gtceu/data/model/builder/PipeModelBuilder.java b/src/main/java/com/gregtechceu/gtceu/data/model/builder/PipeModelBuilder.java
new file mode 100644
index 00000000000..57ffd1f470c
--- /dev/null
+++ b/src/main/java/com/gregtechceu/gtceu/data/model/builder/PipeModelBuilder.java
@@ -0,0 +1,475 @@
+package com.gregtechceu.gtceu.data.model.builder;
+
+import com.gregtechceu.gtceu.GTCEu;
+import com.gregtechceu.gtceu.api.blockentity.PipeBlockEntity;
+import com.gregtechceu.gtceu.api.registry.registrate.provider.GTBlockstateProvider;
+import com.gregtechceu.gtceu.client.model.pipe.PipeModelLoader;
+import com.gregtechceu.gtceu.core.mixins.forge.ConfiguredModelBuilderAccessor;
+import com.gregtechceu.gtceu.utils.GTMath;
+import com.gregtechceu.gtceu.utils.GTUtil;
+import com.gregtechceu.gtceu.utils.memoization.GTMemoizer;
+import com.gregtechceu.gtceu.utils.memoization.function.MemoizedBiFunction;
+
+import net.minecraft.Util;
+import net.minecraft.core.Direction;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraftforge.client.model.generators.*;
+import net.minecraftforge.client.model.generators.BlockStateProvider.ConfiguredModelList;
+import net.minecraftforge.common.data.ExistingFileHelper;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.gson.JsonObject;
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
+import lombok.Getter;
+import lombok.experimental.Accessors;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.Range;
+import org.joml.Vector3f;
+
+import java.util.*;
+import java.util.function.BiFunction;
+
+import static com.gregtechceu.gtceu.data.model.builder.MachineModelBuilder.configuredModelListToJSON;
+import static com.gregtechceu.gtceu.data.model.builder.MachineModelBuilder.configuredModelToJSON;
+
+@Accessors(fluent = true, chain = true)
+@SuppressWarnings("UnusedReturnValue")
+public class PipeModelBuilder> extends CustomLoaderBuilder {
+
+ // spotless:off
+ public static > BiFunction> begin(@Range(from = 0, to = 16) float thickness,
+ GTBlockstateProvider provider) {
+ return (parent, existingFileHelper) -> new PipeModelBuilder<>(parent, existingFileHelper, thickness, provider);
+ }
+ // spotless:on
+
+ @Accessors(fluent = false)
+ @Getter
+ private final Map<@Nullable Direction, ConfiguredModelList> parts = new IdentityHashMap<>();
+ private final float thickness;
+ private final GTBlockstateProvider provider;
+ private BlockModelBuilder @Nullable [] restrictors = null;
+
+ protected PipeModelBuilder(T parent, ExistingFileHelper existingFileHelper,
+ float thickness, GTBlockstateProvider provider) {
+ super(PipeModelLoader.ID, parent, existingFileHelper);
+
+ Preconditions.checkArgument(thickness > 0.0f && thickness <= 16.0f,
+ "Thickness must be between 0 (exclusive) and 16 (inclusive). It is %s", thickness);
+ this.thickness = thickness;
+ this.provider = provider;
+ }
+
+ /**
+ * Set the models for all pipe elements at the same time
+ *
+ * @param centerModel The model to use for the center part of the pipe
+ * @param connectionModels The models to use for all the connection elements
+ * @return {@code this}
+ * @see #allModels(ModelFile, ModelFile...)
+ * @see #allModels(ResourceLocation, ResourceLocation...)
+ */
+ public PipeModelBuilder allModels(ConfiguredModel centerModel, ConfiguredModel... connectionModels) {
+ centerModels(centerModel);
+ connectionModels(connectionModels);
+ return this;
+ }
+
+ /**
+ * Set the models for all pipe elements at the same time
+ *
+ * @param centerModel The model to use for the center part of the pipe
+ * @param connectionModels The models to use for all the connection elements
+ * @return {@code this}
+ * @see #allModels(ModelFile, ModelFile...)
+ * @see #allModels(ResourceLocation, ResourceLocation...)
+ */
+ public PipeModelBuilder allModels(ModelFile centerModel, ModelFile... connectionModels) {
+ centerModels(centerModel);
+ connectionModels(connectionModels);
+ return this;
+ }
+
+ /**
+ * Set the models for all pipe elements at the same time
+ *
+ * @param centerModel The model to use for the center part of the pipe
+ * @param connectionModels The models to use for all the connection elements
+ * @return {@code this}
+ * @see #allModels(ConfiguredModel, ConfiguredModel...)
+ * @see #allModels(ModelFile, ModelFile...)
+ */
+ public PipeModelBuilder allModels(ResourceLocation centerModel, ResourceLocation... connectionModels) {
+ centerModels(centerModel);
+ connectionModels(connectionModels);
+ return this;
+ }
+
+ /**
+ * Set the models for all connection elements
+ *
+ * @param connectionModels The models to use for all the connection elements
+ * @return {@code this}
+ * @see #connectionModels(ModelFile...)
+ * @see #connectionModels(ResourceLocation...)
+ */
+ public PipeModelBuilder connectionModels(ConfiguredModel... connectionModels) {
+ for (Direction dir : GTUtil.DIRECTIONS) {
+ ConfiguredModel[] rotatedModels = Arrays.stream(connectionModels)
+ .map(model -> ConfiguredModel.builder()
+ .modelFile(model.model).uvLock(model.uvLock).weight(model.weight)
+ .rotationX(dir == Direction.DOWN ? 90 : dir == Direction.UP ? 270 : 0)
+ .rotationY(dir.getAxis().isVertical() ? 0 : ((int) dir.toYRot() + 180) % 360)
+ .buildLast())
+ .toArray(ConfiguredModel[]::new);
+ modelsForDirection(dir, rotatedModels);
+ }
+ return this;
+ }
+
+ /**
+ * Set the models for all connection elements
+ *
+ * @param connectionModels The models to use for all the connection elements
+ * @return {@code this}
+ * @see #connectionModels(ConfiguredModel...)
+ * @see #connectionModels(ResourceLocation...)
+ */
+ public PipeModelBuilder connectionModels(ModelFile... connectionModels) {
+ for (Direction dir : GTUtil.DIRECTIONS) {
+ ConfiguredModel[] rotatedModels = Arrays.stream(connectionModels)
+ .map(model -> ConfiguredModel.builder()
+ .modelFile(model)
+ .rotationX(dir == Direction.DOWN ? 0 : dir == Direction.UP ? 180 : 90)
+ .rotationY(dir.getAxis().isVertical() ? 0 : (int) dir.toYRot())
+ .buildLast())
+ .toArray(ConfiguredModel[]::new);
+ modelsForDirection(dir, rotatedModels);
+ }
+ return this;
+ }
+
+ /**
+ * Set the models for all connection elements
+ *
+ * @param connectionModels The models to use for all the connection elements
+ * @return {@code this}
+ * @see #connectionModels(ConfiguredModel...)
+ * @see #connectionModels(ModelFile...)
+ */
+ public PipeModelBuilder connectionModels(ResourceLocation... connectionModels) {
+ return connectionModels(Arrays.stream(connectionModels)
+ .map(loc -> new ModelFile.ExistingModelFile(loc, this.existingFileHelper))
+ .toArray(ModelFile[]::new));
+ }
+
+ /**
+ * Set the models for all connection elements with a builder
+ *
+ * @return A model builder
+ * @see #connectionModels(ConfiguredModel...)
+ * @see #connectionModels(ModelFile...)
+ * @see #connectionModels(ResourceLocation...)
+ */
+ public ConfiguredModel.Builder> connectionModels() {
+ return ConfiguredModelBuilderAccessor.builder(this::connectionModels, ImmutableList.of());
+ }
+
+ /**
+ * Set the models for the center element
+ *
+ * @param centerModels The model to use for the center part of the pipe
+ * @return {@code this}
+ * @see #centerModels(ModelFile...)
+ * @see #centerModels(ResourceLocation...)
+ */
+ public PipeModelBuilder centerModels(ConfiguredModel... centerModels) {
+ return modelsForDirection(null, centerModels);
+ }
+
+ /**
+ * Set the models for the center element
+ *
+ * @param centerModels The model to use for the center part of the pipe
+ * @return {@code this}
+ * @see #centerModels(ConfiguredModel...)
+ * @see #centerModels(ResourceLocation...)
+ */
+ public PipeModelBuilder centerModels(ModelFile... centerModels) {
+ return modelsForDirection(null, centerModels);
+ }
+
+ /**
+ * Set the models for the center element
+ *
+ * @param centerModels The model to use for the center part of the pipe
+ * @return {@code this}
+ * @see #centerModels(ConfiguredModel...)
+ * @see #centerModels(ModelFile...)
+ */
+ public PipeModelBuilder centerModels(ResourceLocation... centerModels) {
+ return modelsForDirection(null, centerModels);
+ }
+
+ /**
+ * Set the models for the center element with a builder
+ *
+ * @return A model builder
+ * @see #centerModels(ConfiguredModel...)
+ * @see #centerModels(ModelFile...)
+ * @see #centerModels(ResourceLocation...)
+ */
+ public ConfiguredModel.Builder> centerModel() {
+ return ConfiguredModelBuilderAccessor.builder(this::centerModels, ImmutableList.of());
+ }
+
+ /**
+ * Set the models for the given direction
+ *
+ * @param direction The direction that'll use the model(s)
+ * @param models The models to set for the direction.
+ * @return {@code this}
+ * @see #modelsForDirection(Direction, ModelFile...)
+ * @see #modelsForDirection(Direction, ResourceLocation...)
+ */
+ public PipeModelBuilder modelsForDirection(@Nullable Direction direction, ConfiguredModel... models) {
+ parts.put(direction, new ConfiguredModelList(models));
+ return this;
+ }
+
+ /**
+ * Set the models for the given direction
+ *
+ * @param direction The direction that'll use the model(s)
+ * @param models The models to set for the direction.
+ * @return {@code this}
+ * @see #modelsForDirection(Direction, ConfiguredModel...)
+ * @see #modelsForDirection(Direction, ResourceLocation...)
+ */
+ public PipeModelBuilder modelsForDirection(@Nullable Direction direction, ModelFile... models) {
+ return modelsForDirection(direction, Arrays.stream(models)
+ .map(model -> ConfiguredModel.builder().modelFile(model).buildLast())
+ .toArray(ConfiguredModel[]::new));
+ }
+
+ /**
+ * Set the models for the given direction
+ *
+ * @param direction The direction that'll use the model(s)
+ * @param models The models to set for the direction.
+ * @return {@code this}
+ * @see #modelsForDirection(Direction, ConfiguredModel...)
+ * @see #modelsForDirection(Direction, ModelFile...)
+ */
+ public PipeModelBuilder modelsForDirection(@Nullable Direction direction, ResourceLocation... models) {
+ return modelsForDirection(direction, Arrays.stream(models)
+ .map(model -> ConfiguredModel.builder()
+ .modelFile(new ModelFile.ExistingModelFile(model, this.existingFileHelper))
+ .buildLast())
+ .toArray(ConfiguredModel[]::new));
+ }
+
+ /**
+ * Set the models for the given direction with a builder
+ *
+ * @return A model builder
+ * @see #modelsForDirection(Direction, ConfiguredModel...)
+ * @see #modelsForDirection(Direction, ModelFile...)
+ * @see #modelsForDirection(Direction, ResourceLocation...)
+ */
+ public ConfiguredModel.Builder> modelsForDirection(@Nullable Direction direction) {
+ return ConfiguredModelBuilderAccessor.builder(models -> this.modelsForDirection(direction, models),
+ ImmutableList.of());
+ }
+
+ @Override
+ public T end() {
+ this.restrictors = getOrCreateRestrictorModels(this.provider.models(), this.thickness);
+ return super.end();
+ }
+
+ @Override
+ public JsonObject toJson(JsonObject json) {
+ json = super.toJson(json);
+
+ if (!getParts().isEmpty()) {
+ final JsonObject parts = new JsonObject();
+ getParts().entrySet().stream()
+ .sorted(Map.Entry.comparingByKey(Comparator.nullsFirst(Direction::compareTo)))
+ .forEach(entry -> {
+ String key = entry.getKey() != null ? entry.getKey().getName() :
+ PipeModelLoader.PRIMARY_CENTER_KEY;
+ parts.add(key, configuredModelListToJSON(entry.getValue()));
+ });
+
+ json.add("parts", parts);
+ }
+
+ if (this.restrictors != null) {
+ final JsonObject restrictors = new JsonObject();
+ for (int i = 0; i < GTUtil.DIRECTIONS.length; i++) {
+ Direction dir = GTUtil.DIRECTIONS[i];
+ restrictors.add(dir.getName(),
+ configuredModelToJSON(ConfiguredModel.builder()
+ .modelFile(new ModelFile.UncheckedModelFile(this.restrictors[i].getLocation()))
+ .buildLast(), false));
+ }
+ json.add("restrictors", restrictors);
+ }
+
+ return json;
+ }
+
+ private static final ResourceLocation PIPE_BLOCKED_OVERLAY = GTCEu.id("block/pipe/blocked/pipe_blocked");
+ private static final ResourceLocation PIPE_BLOCKED_OVERLAY_UP = GTCEu.id("block/pipe/blocked/pipe_blocked_up");
+ private static final ResourceLocation PIPE_BLOCKED_OVERLAY_DOWN = GTCEu.id("block/pipe/blocked/pipe_blocked_down");
+ private static final ResourceLocation PIPE_BLOCKED_OVERLAY_LEFT = GTCEu.id("block/pipe/blocked/pipe_blocked_left");
+ private static final ResourceLocation PIPE_BLOCKED_OVERLAY_RIGHT = GTCEu
+ .id("block/pipe/blocked/pipe_blocked_right");
+ private static final ResourceLocation PIPE_BLOCKED_OVERLAY_NU = GTCEu.id("block/pipe/blocked/pipe_blocked_nu");
+ private static final ResourceLocation PIPE_BLOCKED_OVERLAY_ND = GTCEu.id("block/pipe/blocked/pipe_blocked_nd");
+ private static final ResourceLocation PIPE_BLOCKED_OVERLAY_NL = GTCEu.id("block/pipe/blocked/pipe_blocked_nl");
+ private static final ResourceLocation PIPE_BLOCKED_OVERLAY_NR = GTCEu.id("block/pipe/blocked/pipe_blocked_nr");
+ private static final ResourceLocation PIPE_BLOCKED_OVERLAY_UD = GTCEu.id("block/pipe/blocked/pipe_blocked_ud");
+ private static final ResourceLocation PIPE_BLOCKED_OVERLAY_UL = GTCEu.id("block/pipe/blocked/pipe_blocked_ul");
+ private static final ResourceLocation PIPE_BLOCKED_OVERLAY_UR = GTCEu.id("block/pipe/blocked/pipe_blocked_ur");
+ private static final ResourceLocation PIPE_BLOCKED_OVERLAY_DL = GTCEu.id("block/pipe/blocked/pipe_blocked_dl");
+ private static final ResourceLocation PIPE_BLOCKED_OVERLAY_DR = GTCEu.id("block/pipe/blocked/pipe_blocked_dr");
+ private static final ResourceLocation PIPE_BLOCKED_OVERLAY_LR = GTCEu.id("block/pipe/blocked/pipe_blocked_lr");
+
+ private static final Int2ObjectMap RESTRICTOR_MAP = Util.make(() -> {
+ Int2ObjectMap map = new Int2ObjectOpenHashMap<>();
+
+ addRestrictor(map, PIPE_BLOCKED_OVERLAY_UP, Border.TOP);
+ addRestrictor(map, PIPE_BLOCKED_OVERLAY_DOWN, Border.BOTTOM);
+ addRestrictor(map, PIPE_BLOCKED_OVERLAY_UD, Border.TOP, Border.BOTTOM);
+ addRestrictor(map, PIPE_BLOCKED_OVERLAY_LEFT, Border.LEFT);
+ addRestrictor(map, PIPE_BLOCKED_OVERLAY_UL, Border.TOP, Border.LEFT);
+ addRestrictor(map, PIPE_BLOCKED_OVERLAY_DL, Border.BOTTOM, Border.LEFT);
+ addRestrictor(map, PIPE_BLOCKED_OVERLAY_NR, Border.TOP, Border.BOTTOM, Border.LEFT);
+ addRestrictor(map, PIPE_BLOCKED_OVERLAY_RIGHT, Border.RIGHT);
+ addRestrictor(map, PIPE_BLOCKED_OVERLAY_UR, Border.TOP, Border.RIGHT);
+ addRestrictor(map, PIPE_BLOCKED_OVERLAY_DR, Border.BOTTOM, Border.RIGHT);
+ addRestrictor(map, PIPE_BLOCKED_OVERLAY_NL, Border.TOP, Border.BOTTOM, Border.RIGHT);
+ addRestrictor(map, PIPE_BLOCKED_OVERLAY_LR, Border.LEFT, Border.RIGHT);
+ addRestrictor(map, PIPE_BLOCKED_OVERLAY_ND, Border.TOP, Border.LEFT, Border.RIGHT);
+ addRestrictor(map, PIPE_BLOCKED_OVERLAY_NU, Border.BOTTOM, Border.LEFT, Border.RIGHT);
+ addRestrictor(map, PIPE_BLOCKED_OVERLAY, Border.TOP, Border.BOTTOM, Border.LEFT, Border.RIGHT);
+
+ return map;
+ });
+
+ private static BlockModelBuilder[] getOrCreateRestrictorModels(BlockModelProvider provider, float thickness) {
+ return RESTRICTOR_MODEL_CACHE.apply(provider, thickness);
+ }
+
+ private static final MemoizedBiFunction RESTRICTOR_MODEL_CACHE = GTMemoizer
+ .memoizeFunctionWeakIdent(PipeModelBuilder::makeRestrictorModels);
+
+ private static BlockModelBuilder[] makeRestrictorModels(BlockModelProvider provider, float thickness) {
+ BlockModelBuilder[] models = new BlockModelBuilder[GTUtil.DIRECTIONS.length];
+
+ float min = (16.0f - thickness) / 2.0f - 0.003f;
+ float max = min + thickness + 0.006f; // offset by 0.003 * 2
+ for (Direction dir : GTUtil.DIRECTIONS) {
+ String modelPath = "block/pipe/restrictor/" + dir.getName() + "/thickness_" + thickness;
+ ResourceLocation modelName = GTCEu.id(modelPath);
+ if (provider.generatedModels.containsKey(modelName)) {
+ models[dir.ordinal()] = provider.generatedModels.get(modelName);
+ continue;
+ }
+
+ var coords = GTMath.getCoordinates(dir, min, max);
+ Vector3f minPos = coords.getLeft();
+ Vector3f maxPos = coords.getRight();
+ BlockModelBuilder model = provider.getBuilder(modelPath);
+ model.texture("restrictor", PIPE_BLOCKED_OVERLAY)
+ .element()
+ .from(minPos.x, minPos.y, minPos.z)
+ .to(maxPos.x, maxPos.y, maxPos.z)
+ .face(getSideAtBorder(dir, Border.BOTTOM)).end()
+ .face(getSideAtBorder(dir, Border.TOP)).end()
+ .face(getSideAtBorder(dir, Border.LEFT)).end()
+ .face(getSideAtBorder(dir, Border.RIGHT)).end()
+ .faces((face, builder) -> builder.texture("#restrictor"))
+ .end();
+ models[dir.ordinal()] = model;
+ }
+ return models;
+ }
+
+ @ApiStatus.Internal
+ public static void clearRestrictorModelCache() {
+ RESTRICTOR_MODEL_CACHE.getCache().clear();
+ }
+
+ private static final EnumMap> FACE_BORDER_MAP = Util.make(() -> {
+ EnumMap> map = new EnumMap<>(Direction.class);
+
+ map.put(Direction.DOWN, borderMap(Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST));
+ map.put(Direction.UP, borderMap(Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST));
+ map.put(Direction.NORTH, borderMap(Direction.DOWN, Direction.UP, Direction.WEST, Direction.EAST));
+ map.put(Direction.SOUTH, borderMap(Direction.DOWN, Direction.UP, Direction.WEST, Direction.EAST));
+ map.put(Direction.WEST, borderMap(Direction.DOWN, Direction.UP, Direction.NORTH, Direction.SOUTH));
+ map.put(Direction.EAST, borderMap(Direction.DOWN, Direction.UP, Direction.NORTH, Direction.SOUTH));
+
+ return map;
+ });
+
+ private static EnumMap borderMap(Direction topSide, Direction bottomSide,
+ Direction leftSide, Direction rightSide) {
+ EnumMap sideMap = new EnumMap<>(Border.class);
+ sideMap.put(Border.TOP, topSide);
+ sideMap.put(Border.BOTTOM, bottomSide);
+ sideMap.put(Border.LEFT, leftSide);
+ sideMap.put(Border.RIGHT, rightSide);
+ return sideMap;
+ }
+
+ private static void addRestrictor(Int2ObjectMap map, ResourceLocation texture,
+ Border... borders) {
+ int mask = 0;
+ for (Border border : borders) {
+ mask |= border.mask;
+ }
+ map.put(mask, texture);
+ }
+
+ private static Direction getSideAtBorder(Direction side, Border border) {
+ return FACE_BORDER_MAP.get(side).get(border);
+ }
+
+ private static int computeBorderMask(int blockedConnections, int connections, Direction side) {
+ int borderMask = 0;
+ if (blockedConnections != 0) {
+ for (Border border : Border.VALUES) {
+ Direction borderSide = getSideAtBorder(side, border);
+ if (PipeBlockEntity.isFaceBlocked(blockedConnections, borderSide) &&
+ PipeBlockEntity.isConnected(connections, borderSide)) {
+ // only render when the side is blocked *and* connected
+ borderMask |= border.mask;
+ }
+ }
+ }
+ return borderMask;
+ }
+
+ private enum Border {
+
+ TOP,
+ BOTTOM,
+ LEFT,
+ RIGHT;
+
+ public static final Border[] VALUES = values();
+
+ public final int mask;
+
+ Border() {
+ mask = 1 << this.ordinal();
+ }
+ }
+}
diff --git a/src/main/java/com/gregtechceu/gtceu/data/model/builder/package-info.java b/src/main/java/com/gregtechceu/gtceu/data/model/builder/package-info.java
new file mode 100644
index 00000000000..2f6102b3cd1
--- /dev/null
+++ b/src/main/java/com/gregtechceu/gtceu/data/model/builder/package-info.java
@@ -0,0 +1,4 @@
+@NotNullByDefault
+package com.gregtechceu.gtceu.data.model.builder;
+
+import org.jetbrains.annotations.NotNullByDefault;
diff --git a/src/main/java/com/gregtechceu/gtceu/data/pack/GTDynamicDataPack.java b/src/main/java/com/gregtechceu/gtceu/data/pack/GTDynamicDataPack.java
index cbf7560b4f3..103ffba6b4d 100644
--- a/src/main/java/com/gregtechceu/gtceu/data/pack/GTDynamicDataPack.java
+++ b/src/main/java/com/gregtechceu/gtceu/data/pack/GTDynamicDataPack.java
@@ -68,7 +68,7 @@ private static void addToData(ResourceLocation location, byte[] bytes) {
public static void addRecipe(FinishedRecipe recipe) {
JsonObject recipeJson = recipe.serializeRecipe();
byte[] recipeBytes = recipeJson.toString().getBytes(StandardCharsets.UTF_8);
- Path parent = GTCEu.getGameDir().resolve("gtceu/dumped/data");
+ Path parent = GTCEu.GTCEU_FOLDER.resolve("dumped/data");
ResourceLocation recipeId = recipe.getId();
if (ConfigHolder.INSTANCE.dev.dumpRecipes) {
writeJson(recipeId, "recipes", parent, recipeBytes);
diff --git a/src/main/java/com/gregtechceu/gtceu/data/pack/GTDynamicResourcePack.java b/src/main/java/com/gregtechceu/gtceu/data/pack/GTDynamicResourcePack.java
index bb5522a00f3..986d7be8744 100644
--- a/src/main/java/com/gregtechceu/gtceu/data/pack/GTDynamicResourcePack.java
+++ b/src/main/java/com/gregtechceu/gtceu/data/pack/GTDynamicResourcePack.java
@@ -9,6 +9,8 @@
import net.minecraft.SharedConstants;
import net.minecraft.client.renderer.texture.atlas.SpriteSource;
import net.minecraft.client.renderer.texture.atlas.SpriteSources;
+import net.minecraft.core.registries.BuiltInRegistries;
+import net.minecraft.data.models.blockstates.BlockStateGenerator;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.FileToIdConverter;
import net.minecraft.resources.ResourceLocation;
@@ -17,6 +19,9 @@
import net.minecraft.server.packs.metadata.MetadataSectionSerializer;
import net.minecraft.server.packs.metadata.pack.PackMetadataSection;
import net.minecraft.server.packs.resources.IoSupplier;
+import net.minecraftforge.client.model.generators.BlockModelBuilder;
+import net.minecraftforge.client.model.generators.ItemModelBuilder;
+import net.minecraftforge.client.model.generators.ModelBuilder;
import com.google.common.collect.Sets;
import com.google.gson.JsonElement;
@@ -51,10 +56,9 @@ public class GTDynamicResourcePack implements PackResources {
protected static final GTDynamicPackContents CONTENTS = new GTDynamicPackContents();
private static final FileToIdConverter ATLAS_ID_CONVERTER = FileToIdConverter.json("atlases");
- private static final FileToIdConverter TEXTURE_ID_CONVERTER = SpriteSource.TEXTURE_ID_CONVERTER;
- private static final FileToIdConverter BLOCKSTATE_ID_CONVERTER = FileToIdConverter.json("blockstates");
- private static final FileToIdConverter BLOCK_MODEL_ID_CONVERTER = FileToIdConverter.json("models/block");
- private static final FileToIdConverter ITEM_MODEL_ID_CONVERTER = FileToIdConverter.json("models/item");
+ public static final FileToIdConverter TEXTURE_ID_CONVERTER = SpriteSource.TEXTURE_ID_CONVERTER;
+ public static final FileToIdConverter BLOCKSTATE_ID_CONVERTER = FileToIdConverter.json("blockstates");
+ public static final FileToIdConverter MODEL_ID_CONVERTER = FileToIdConverter.json("models");
private final String name;
@@ -81,89 +85,83 @@ public static void addResource(ResourceLocation location, JsonElement obj) {
public static void addResource(ResourceLocation location, byte[] data) {
if (ConfigHolder.INSTANCE.dev.dumpAssets) {
- Path parent = GTCEu.getGameDir().resolve("gtceu/dumped/assets");
+ Path parent = GTCEu.GTCEU_FOLDER.resolve("dumped/assets");
writeJson(location, null, parent, data);
}
CONTENTS.addToData(location, data);
}
public static void addBlockModel(ResourceLocation loc, JsonElement obj) {
- ResourceLocation l = getBlockModelLocation(loc);
- byte[] modelBytes = obj.toString().getBytes(StandardCharsets.UTF_8);
-
- if (ConfigHolder.INSTANCE.dev.dumpAssets) {
- Path parent = GTCEu.getGameDir().resolve("gtceu/dumped/assets");
- writeJson(l, null, parent, modelBytes);
+ if (!loc.getPath().startsWith("block/")) {
+ loc = loc.withPrefix("block/");
}
- CONTENTS.addToData(l, modelBytes);
+ addModel(loc, obj);
}
public static void addBlockModel(ResourceLocation loc, Supplier obj) {
addBlockModel(loc, obj.get());
}
- public static void addItemModel(ResourceLocation loc, JsonElement obj) {
- ResourceLocation l = getItemModelLocation(loc);
- byte[] modelBytes = obj.toString().getBytes(StandardCharsets.UTF_8);
+ public static void addBlockModel(BlockModelBuilder builder) {
+ addBlockModel(builder.getLocation(), builder.toJson());
+ }
- if (ConfigHolder.INSTANCE.dev.dumpAssets) {
- Path parent = GTCEu.getGameDir().resolve("gtceu/dumped/assets");
- writeJson(l, null, parent, modelBytes);
+ public static void addItemModel(ResourceLocation loc, JsonElement obj) {
+ if (!loc.getPath().startsWith("item/")) {
+ loc = loc.withPrefix("item/");
}
- CONTENTS.addToData(l, modelBytes);
+ addModel(loc, obj);
+ }
+
+ public static void addItemModel(ItemModelBuilder builder) {
+ addItemModel(builder.getLocation(), builder.toJson());
}
public static void addItemModel(ResourceLocation loc, Supplier obj) {
addItemModel(loc, obj.get());
}
- public static void addBlockState(ResourceLocation loc, JsonElement stateJson) {
- ResourceLocation l = getBlockStateLocation(loc);
- byte[] stateBytes = stateJson.toString().getBytes(StandardCharsets.UTF_8);
+ public static void addModel(ResourceLocation loc, JsonElement obj) {
+ loc = MODEL_ID_CONVERTER.idToFile(loc);
+ addResource(loc, obj);
+ }
- if (ConfigHolder.INSTANCE.dev.dumpAssets) {
- Path parent = GTCEu.getGameDir().resolve("gtceu/dumped/assets");
- writeJson(l, null, parent, stateBytes);
- }
- CONTENTS.addToData(l, stateBytes);
+ public static void addModel(ResourceLocation loc, Supplier obj) {
+ addModel(loc, obj.get());
+ }
+
+ public static > void addModel(T builder) {
+ addModel(builder.getLocation(), builder.toJson());
+ }
+
+ public static void addBlockState(ResourceLocation loc, JsonElement stateJson) {
+ loc = BLOCKSTATE_ID_CONVERTER.idToFile(loc);
+ addResource(loc, stateJson);
}
public static void addBlockState(ResourceLocation loc, Supplier generator) {
addBlockState(loc, generator.get());
}
- public static void addAtlasSpriteSource(ResourceLocation atlasLoc, SpriteSource source) {
- ResourceLocation l = getAtlasLocation(atlasLoc);
- JsonElement sourceJson = SpriteSources.FILE_CODEC
- .encodeStart(JsonOps.INSTANCE, Collections.singletonList(source))
- .getOrThrow(false,
- error -> GTCEu.LOGGER.error("Failed to encode atlas sprite source. {}", error));
- byte[] sourceBytes = sourceJson.toString().getBytes(StandardCharsets.UTF_8);
-
- if (ConfigHolder.INSTANCE.dev.dumpAssets) {
- Path parent = GTCEu.getGameDir().resolve("gtceu/dumped/assets");
- writeJson(l, null, parent, sourceBytes);
- }
- CONTENTS.addToData(l, sourceBytes);
+ public static void addBlockState(BlockStateGenerator generator) {
+ addBlockState(BuiltInRegistries.BLOCK.getKey(generator.getBlock()), generator.get());
}
- public static void addAtlasSpriteSourceList(ResourceLocation atlasLoc, List sources) {
- ResourceLocation l = getAtlasLocation(atlasLoc);
- JsonElement sourceJson = SpriteSources.FILE_CODEC.encodeStart(JsonOps.INSTANCE, sources).getOrThrow(false,
- error -> GTCEu.LOGGER.error("Failed to encode atlas sprite source. {}", error));
- byte[] sourceBytes = sourceJson.toString().getBytes(StandardCharsets.UTF_8);
+ public static void addAtlasSpriteSource(ResourceLocation atlasLoc, SpriteSource source) {
+ addAtlasSpriteSourceList(atlasLoc, Collections.singletonList(source));
+ }
- if (ConfigHolder.INSTANCE.dev.dumpAssets) {
- Path parent = GTCEu.getGameDir().resolve("gtceu/dumped/assets");
- writeJson(l, null, parent, sourceBytes);
- }
- CONTENTS.addToData(l, sourceBytes);
+ public static void addAtlasSpriteSourceList(ResourceLocation loc, List sources) {
+ loc = ATLAS_ID_CONVERTER.idToFile(loc);
+ JsonElement sourceJson = SpriteSources.FILE_CODEC.encodeStart(JsonOps.INSTANCE, sources)
+ .getOrThrow(false, error -> GTCEu.LOGGER.error("Failed to encode atlas sprite source. {}", error));
+ addResource(loc, sourceJson);
}
public static void addBlockTexture(ResourceLocation loc, byte[] data) {
ResourceLocation l = getTextureLocation("block", loc);
if (ConfigHolder.INSTANCE.dev.dumpAssets) {
- Path parent = GTCEu.getGameDir().resolve("gtceu/dumped/assets");
+ Path parent = GTCEu.GTCEU_FOLDER.resolve("dumped/assets");
writeByteArray(l, null, parent, data);
}
CONTENTS.addToData(l, data);
@@ -172,7 +170,7 @@ public static void addBlockTexture(ResourceLocation loc, byte[] data) {
public static void addItemTexture(ResourceLocation loc, byte[] data) {
ResourceLocation l = getTextureLocation("item", loc);
if (ConfigHolder.INSTANCE.dev.dumpAssets) {
- Path parent = GTCEu.getGameDir().resolve("gtceu/dumped/assets");
+ Path parent = GTCEu.GTCEU_FOLDER.resolve("dumped/assets");
writeByteArray(l, null, parent, data);
}
CONTENTS.addToData(l, data);
@@ -252,26 +250,10 @@ public void close() {
// NOOP
}
- public static ResourceLocation getBlockStateLocation(ResourceLocation blockId) {
- return BLOCKSTATE_ID_CONVERTER.idToFile(blockId);
- }
-
- public static ResourceLocation getBlockModelLocation(ResourceLocation blockId) {
- return BLOCK_MODEL_ID_CONVERTER.idToFile(blockId);
- }
-
- public static ResourceLocation getItemModelLocation(ResourceLocation itemId) {
- return ITEM_MODEL_ID_CONVERTER.idToFile(itemId);
- }
-
public static ResourceLocation getTextureLocation(@Nullable String path, ResourceLocation textureId) {
if (path == null) {
return TEXTURE_ID_CONVERTER.idToFile(textureId);
}
return TEXTURE_ID_CONVERTER.idToFile(textureId.withPrefix(path + "/"));
}
-
- public static ResourceLocation getAtlasLocation(ResourceLocation atlasId) {
- return ATLAS_ID_CONVERTER.idToFile(atlasId);
- }
}
diff --git a/src/main/java/com/gregtechceu/gtceu/data/pack/event/RegisterDynamicResourcesEvent.java b/src/main/java/com/gregtechceu/gtceu/data/pack/event/RegisterDynamicResourcesEvent.java
new file mode 100644
index 00000000000..92f9eaa1d9a
--- /dev/null
+++ b/src/main/java/com/gregtechceu/gtceu/data/pack/event/RegisterDynamicResourcesEvent.java
@@ -0,0 +1,12 @@
+package com.gregtechceu.gtceu.data.pack.event;
+
+import net.minecraftforge.eventbus.api.Event;
+import net.minecraftforge.fml.event.IModBusEvent;
+
+import org.jetbrains.annotations.ApiStatus;
+
+public class RegisterDynamicResourcesEvent extends Event implements IModBusEvent {
+
+ @ApiStatus.Internal
+ public RegisterDynamicResourcesEvent() {}
+}
diff --git a/src/main/java/com/gregtechceu/gtceu/data/recipe/VanillaRecipeHelper.java b/src/main/java/com/gregtechceu/gtceu/data/recipe/VanillaRecipeHelper.java
index ce0db2d32f6..4b3bb603ab6 100644
--- a/src/main/java/com/gregtechceu/gtceu/data/recipe/VanillaRecipeHelper.java
+++ b/src/main/java/com/gregtechceu/gtceu/data/recipe/VanillaRecipeHelper.java
@@ -10,10 +10,14 @@
import com.gregtechceu.gtceu.api.data.chemical.material.stack.MaterialEntry;
import com.gregtechceu.gtceu.api.data.chemical.material.stack.MaterialStack;
import com.gregtechceu.gtceu.api.data.tag.TagPrefix;
+import com.gregtechceu.gtceu.api.item.tool.GTToolType;
import com.gregtechceu.gtceu.api.item.tool.ToolHelper;
import com.gregtechceu.gtceu.data.recipe.builder.*;
+import net.minecraft.advancements.critereon.InventoryChangeTrigger;
import net.minecraft.data.recipes.FinishedRecipe;
+import net.minecraft.data.recipes.RecipeCategory;
+import net.minecraft.data.recipes.SmithingTransformRecipeBuilder;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey;
import net.minecraft.world.item.Item;
@@ -22,7 +26,9 @@
import net.minecraft.world.level.ItemLike;
import com.tterrag.registrate.util.entry.ItemProviderEntry;
-import it.unimi.dsi.fastutil.chars.*;
+import it.unimi.dsi.fastutil.chars.Char2IntOpenHashMap;
+import it.unimi.dsi.fastutil.chars.CharArraySet;
+import it.unimi.dsi.fastutil.chars.CharSet;
import it.unimi.dsi.fastutil.objects.Reference2LongOpenHashMap;
import org.jetbrains.annotations.NotNull;
@@ -224,7 +230,7 @@ public static void addShapedNBTClearingRecipe(Consumer provider,
}
/**
- * @see #addShapedRecipe(Consumer, boolean, boolean, ResourceLocation, ItemStack, Object...)
+ * @see #addShapedRecipe(Consumer, boolean, boolean, boolean, ResourceLocation, ItemStack, Object...)
*/
public static void addShapedRecipe(Consumer provider, @NotNull String regName,
@NotNull ItemStack result, @NotNull Object... recipe) {
@@ -232,7 +238,7 @@ public static void addShapedRecipe(Consumer provider, @NotNull S
}
/**
- * @see #addShapedRecipe(Consumer, boolean, boolean, ResourceLocation, ItemStack, Object...)
+ * @see #addShapedRecipe(Consumer, boolean, boolean, boolean, ResourceLocation, ItemStack, Object...)
*/
public static void addShapedRecipe(Consumer provider, @NotNull ResourceLocation regName,
@NotNull ItemStack result, @NotNull Object... recipe) {
@@ -240,7 +246,7 @@ public static void addShapedRecipe(Consumer provider, @NotNull R
}
/**
- * @see #addShapedRecipe(Consumer, boolean, boolean, ResourceLocation, ItemStack, Object...)
+ * @see #addShapedRecipe(Consumer, boolean, boolean, boolean, ResourceLocation, ItemStack, Object...)
*/
public static void addStrictShapedRecipe(Consumer provider, @NotNull String regName,
@NotNull ItemStack result, @NotNull Object... recipe) {
@@ -248,7 +254,7 @@ public static void addStrictShapedRecipe(Consumer