From be704f07631e47903118c6a0315fee8092787389 Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Tue, 2 Jun 2026 12:24:15 +0300 Subject: [PATCH 01/18] Create smoke particles directly on the client --- .../common/blockentity/CableBlockEntity.java | 38 ++++++++++--------- 1 file changed, 21 insertions(+), 17 deletions(-) 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 ba3c179a040..b4447a79df1 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/blockentity/CableBlockEntity.java +++ b/src/main/java/com/gregtechceu/gtceu/common/blockentity/CableBlockEntity.java @@ -10,6 +10,7 @@ import com.gregtechceu.gtceu.api.item.tool.GTToolType; import com.gregtechceu.gtceu.api.machine.TickableSubscription; import com.gregtechceu.gtceu.api.machine.feature.IDataInfoProvider; +import com.gregtechceu.gtceu.api.sync_system.annotations.ClientFieldChangeListener; import com.gregtechceu.gtceu.api.sync_system.annotations.SaveField; import com.gregtechceu.gtceu.api.sync_system.annotations.SyncToClient; import com.gregtechceu.gtceu.client.particle.GTOverheatParticle; @@ -31,6 +32,7 @@ import net.minecraft.core.particles.ParticleTypes; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.Mth; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; @@ -323,23 +325,25 @@ public void setTemperature(int temperature) { this.temperature = temperature; syncDataHolder.markClientSyncFieldDirty("temperature"); level.getLightEngine().checkBlock(worldPosition); - if (!level.isClientSide && temperature >= meltTemp) { - var facing = Direction.UP; - float xPos = facing.getStepX() * 0.76F + worldPosition.getX() + 0.25F; - float yPos = facing.getStepY() * 0.76F + worldPosition.getY() + 0.25F; - float zPos = facing.getStepZ() * 0.76F + worldPosition.getZ() + 0.25F; - - float ySpd = facing.getStepY() * 0.1F + 0.2F + 0.1F * GTValues.RNG.nextFloat(); - float temp = GTValues.RNG.nextFloat() * 2 * (float) Math.PI; - float xSpd = (float) Math.sin(temp) * 0.1F; - float zSpd = (float) Math.cos(temp) * 0.1F; - - ((ServerLevel) level).sendParticles(ParticleTypes.SMOKE, - xPos + GTValues.RNG.nextFloat() * 0.5F, - yPos + GTValues.RNG.nextFloat() * 0.5F, - zPos + GTValues.RNG.nextFloat() * 0.5F, - 0, - xSpd, ySpd, zSpd, 1); + } + + @ClientFieldChangeListener(fieldName = "temperature") + public void onTemperatureUpdated() { + if (this.temperature >= meltTemp) { + float xPos = Direction.UP.getStepX() * 0.76f + getBlockPos().getX() + 0.25f; + float yPos = Direction.UP.getStepY() * 0.76f + getBlockPos().getY() + 0.25f; + float zPos = Direction.UP.getStepZ() * 0.76f + getBlockPos().getZ() + 0.25f; + + float horizontalDirection = level.random.nextFloat() * 2 * Mth.PI; + float xSpd = Mth.sin(horizontalDirection) * 0.1f; + float ySpd = Direction.UP.getStepY() * 0.1f + 0.2f + 0.1f * level.random.nextFloat(); + float zSpd = Mth.cos(horizontalDirection) * 0.1f; + + level.addParticle(ParticleTypes.SMOKE, + xPos + level.random.nextFloat() * 0.5f, + yPos + level.random.nextFloat() * 0.5f, + zPos + level.random.nextFloat() * 0.5f, + xSpd, ySpd, zSpd); } } From 929a2408e597ef5055241b3ba7228e4d28a9b354 Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Tue, 2 Jun 2026 12:29:13 +0300 Subject: [PATCH 02/18] Fix the overheat particle not being created --- .../common/blockentity/CableBlockEntity.java | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) 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 b4447a79df1..795ec61fb88 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/blockentity/CableBlockEntity.java +++ b/src/main/java/com/gregtechceu/gtceu/common/blockentity/CableBlockEntity.java @@ -41,8 +41,6 @@ import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; import lombok.Getter; import org.jetbrains.annotations.NotNull; @@ -61,7 +59,7 @@ public class CableBlockEntity extends PipeBlockEntity currentEnergyNet = new WeakReference<>(null); - @SideOnly(Side.CLIENT) + @OnlyIn(Dist.CLIENT) private GTOverheatParticle particle; private static final int meltTemp = 3000; @@ -174,7 +172,7 @@ public void onLoad() { private void subscribeHeat() { if (this.heatSubs == null) { - this.heatSubs = subscribeServerTick(this::update); + this.heatSubs = subscribeServerTick(this::updateHeat); } } @@ -266,7 +264,7 @@ public void applyHeat(int amount) { } } - private boolean update() { + private boolean updateHeat() { if (heatQueue > 0) { // if received heat from overvolting or overamping, add heat setTemperature(temperature + heatQueue); @@ -283,18 +281,17 @@ private boolean update() { return false; } - if (getPipeType().insulationLevel >= 0 && temperature >= 1500 && GTValues.RNG.nextFloat() < 0.1) { + if (getPipeType().insulationLevel >= 0 && temperature >= 1500 && GTValues.RNG.nextFloat() < 0.1f) { // insulation melted uninsulate(); return false; } - if (heatQueue == 0) { + if (heatQueue <= 0) { // otherwise cool down - setTemperature((int) (temperature - Math.pow(temperature - getDefaultTemp(), 0.35))); - } else { - heatQueue = 0; + setTemperature((int) (temperature - Math.pow(temperature - getDefaultTemp(), 0.35f))); } + heatQueue = 0; return true; } @@ -329,6 +326,17 @@ public void setTemperature(int temperature) { @ClientFieldChangeListener(fieldName = "temperature") public void onTemperatureUpdated() { + if (temperature <= getDefaultTemp()) { + if (isParticleAlive()) { + particle.setExpired(); + } + } else { + if (!isParticleAlive()) { + createParticle(); + } + particle.setTemperature(temperature); + } + if (this.temperature >= meltTemp) { float xPos = Direction.UP.getStepX() * 0.76f + getBlockPos().getX() + 0.25f; float yPos = Direction.UP.getStepY() * 0.76f + getBlockPos().getY() + 0.25f; From 63c879ecec7f0320d81bb506537f385dbfab8709 Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Tue, 2 Jun 2026 12:36:17 +0300 Subject: [PATCH 03/18] clean up GTOverheatParticle and reduce its allocation rate --- .../client/particle/GTOverheatParticle.java | 76 ++++++++----------- .../common/blockentity/CableBlockEntity.java | 4 +- 2 files changed, 33 insertions(+), 47 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java b/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java index b3e77131720..dd2d91ac350 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java +++ b/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java @@ -11,7 +11,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.particles.ParticleTypes; import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.shapes.Shapes; +import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; @@ -20,8 +20,6 @@ import com.mojang.blaze3d.vertex.*; import org.jetbrains.annotations.Nullable; -import java.util.List; - /** * @author brachy84 */ @@ -146,29 +144,37 @@ public static int getBlackBodyColor(int temperature) { protected final int meltTemp; protected int temperature = 293; - protected VoxelShape pipeBoxes; - protected boolean insulated; + protected final boolean insulated; + + protected VoxelShape pipeShape; + protected AABB pipeBounds; - protected float alpha = 0; + protected float alpha = 0.0f; protected int color = blackBodyColors[0]; - public GTOverheatParticle(CableBlockEntity blockEntity, int meltTemp, VoxelShape pipeBoxes, boolean insulated) { + public GTOverheatParticle(CableBlockEntity blockEntity, int meltTemp, boolean insulated) { super(blockEntity.getBlockPos().getX(), blockEntity.getBlockPos().getY(), blockEntity.getBlockPos().getZ()); this.blockEntity = blockEntity; this.meltTemp = meltTemp; - this.pipeBoxes = pipeBoxes; - updatePipeBoxes(pipeBoxes); this.insulated = insulated; + + this.pipeShape = blockEntity.getBlockState().getVisualShape(blockEntity.getLevel(), blockEntity.getBlockPos(), + CollisionContext.empty()); + this.pipeBounds = pipeShape.bounds().move(posX, posY, posZ); } public void setTemperature(int temperature) { this.temperature = temperature; - if (temperature <= 293 || temperature > meltTemp) { + updateColor(); + } + + public void updateColor() { + if (temperature <= TEMPERATURE_CUTOFF || temperature > meltTemp) { setExpired(); return; } if (temperature < 500) { - alpha = 0f; + alpha = 0.0f; } else if (temperature < 1000) { alpha = (temperature - 500f) / 500f; alpha *= 0.8f; @@ -178,36 +184,20 @@ public void setTemperature(int temperature) { color = getBlackBodyColor(temperature); } - public void updatePipeBoxes(VoxelShape pipeBoxes) { - List boxes = pipeBoxes.toAabbs(); - this.pipeBoxes = boxes.stream() - .map(aabb -> aabb.inflate(0.001)) - .map(Shapes::create) - .reduce(Shapes.empty(), Shapes::or) - .optimize(); - } - @Override public void onUpdate() { + // if this isn't the block entity's particle, remove both if (blockEntity.isRemoved() || !blockEntity.isParticleAlive()) { setExpired(); blockEntity.killParticle(); return; } + // update pipeShape every tick so it doesn't desync if the pipe is disconnected + pipeShape = blockEntity.getBlockState().getVisualShape(blockEntity.getLevel(), blockEntity.getBlockPos(), + CollisionContext.empty()); + pipeBounds = pipeShape.bounds().move(posX, posY, posZ); - if (temperature <= TEMPERATURE_CUTOFF || temperature > meltTemp) { - setExpired(); - return; - } - if (temperature < 500) { - alpha = 0f; - } else if (temperature < 1000) { - alpha = (temperature - 500f) / 500f; - alpha *= 0.8f; - } else { - alpha = 0.8f; - } - color = getBlackBodyColor(temperature); + updateColor(); if (GTValues.RNG.nextFloat() < 0.04) { spawnSmoke(); @@ -227,8 +217,8 @@ private void spawnSmoke() { @Override public String toString() { return "GTOverheatParticle{" + - "tileEntity=" + blockEntity + - ", pipeBoxes=" + pipeBoxes + + "blockEntity=" + blockEntity + + ", pipeShape=" + pipeShape + ", insulated=" + insulated + ", alpha=" + alpha + ", color=" + color + @@ -243,12 +233,7 @@ public String toString() { @Override public boolean shouldRender(EffectRenderContext context) { if (this.insulated) return false; - for (AABB cuboid : pipeBoxes.toAabbs()) { - if (!context.frustum().isVisible(cuboid.move(posX, posY, posZ))) { - return false; - } - } - return true; + return context.frustum().isVisible(pipeBounds); } @Override @@ -256,6 +241,7 @@ public boolean shouldRender(EffectRenderContext context) { return SETUP; } + @Override public void renderBloomEffect(PoseStack poseStack, BufferBuilder buffer, EffectRenderContext context) { float red = ((color >> 16) & 0xFF) / 255f; float green = ((color >> 8) & 0xFF) / 255f; @@ -263,9 +249,11 @@ public void renderBloomEffect(PoseStack poseStack, BufferBuilder buffer, EffectR poseStack.pushPose(); poseStack.translate(posX, posY, posZ); - for (AABB cuboid : pipeBoxes.toAabbs()) { - RenderBufferHelper.renderColorCube(poseStack, buffer, cuboid, red, green, blue, alpha, true); - } + pipeShape.forAllBoxes((x1, y1, z1, x2, y2, z2) -> { + RenderBufferHelper.renderColorCube(poseStack, buffer, + (float) x1, (float) y1, (float) z1, (float) x2, (float) y2, (float) z2, + red, green, blue, alpha, true); + }); poseStack.popPose(); } 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 795ec61fb88..283eb5c7b16 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/blockentity/CableBlockEntity.java +++ b/src/main/java/com/gregtechceu/gtceu/common/blockentity/CableBlockEntity.java @@ -243,9 +243,7 @@ public boolean isParticleAlive() { @OnlyIn(Dist.CLIENT) public void createParticle() { - particle = new GTOverheatParticle(this, meltTemp, - getPipeBlock().getShape(getBlockState(), level, getBlockPos(), CollisionContext.empty()), - getPipeType().insulationLevel >= 0); + particle = new GTOverheatParticle(this, meltTemp, getPipeType().insulationLevel >= 0); GTParticleManager.INSTANCE.addEffect(particle); } From 75e1b26e9a7185dcc223c240c712bcc80c7ffa6d Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Tue, 2 Jun 2026 12:37:57 +0300 Subject: [PATCH 04/18] Use the pipe's default temperature as the cutoff --- .../gtceu/client/particle/GTOverheatParticle.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java b/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java index dd2d91ac350..8ae58017064 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java +++ b/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java @@ -25,8 +25,6 @@ */ public class GTOverheatParticle extends GTBloomParticle { - public static final int TEMPERATURE_CUTOFF = 400; - /** * Source */ @@ -143,7 +141,7 @@ public static int getBlackBodyColor(int temperature) { private final CableBlockEntity blockEntity; protected final int meltTemp; - protected int temperature = 293; + protected int temperature; protected final boolean insulated; protected VoxelShape pipeShape; @@ -156,6 +154,7 @@ public GTOverheatParticle(CableBlockEntity blockEntity, int meltTemp, boolean in super(blockEntity.getBlockPos().getX(), blockEntity.getBlockPos().getY(), blockEntity.getBlockPos().getZ()); this.blockEntity = blockEntity; this.meltTemp = meltTemp; + this.setTemperature(blockEntity.getTemperature()); this.insulated = insulated; this.pipeShape = blockEntity.getBlockState().getVisualShape(blockEntity.getLevel(), blockEntity.getBlockPos(), @@ -169,7 +168,7 @@ public void setTemperature(int temperature) { } public void updateColor() { - if (temperature <= TEMPERATURE_CUTOFF || temperature > meltTemp) { + if (temperature <= blockEntity.getDefaultTemp() || temperature > meltTemp) { setExpired(); return; } From 2e2cc0d16c1a46472f27a0b73a7b6d6c3a75380b Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Tue, 2 Jun 2026 12:43:37 +0300 Subject: [PATCH 05/18] Deprecate `Insulation.isCable` in favor of the method with the same name --- .../gtceu/common/block/CableBlock.java | 4 +- .../common/blockentity/CableBlockEntity.java | 8 ++-- .../gtceu/common/data/GTMaterialBlocks.java | 2 +- .../common/pipelike/cable/Insulation.java | 39 ++++++++++--------- 4 files changed, 28 insertions(+), 25 deletions(-) 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 dacfeefdb21..db79322d62c 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/block/CableBlock.java +++ b/src/main/java/com/gregtechceu/gtceu/common/block/CableBlock.java @@ -55,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 || index == 2)) { + if (pipeType.isCable() && (index == 0 || index == 2)) { return 0x404040; } return super.tinted(state, level, pos, index); @@ -132,7 +132,7 @@ public void entityInside(BlockState state, Level level, BlockPos pos, Entity ent if (level.isClientSide) return; Insulation insulation = getPipeTile(level, pos).getPipeType(); - if (insulation.insulationLevel == -1 && entity instanceof LivingEntity entityLiving) { + if (!insulation.isCable() && entity instanceof LivingEntity entityLiving) { CableBlockEntity cable = (CableBlockEntity) getPipeTile(level, pos); if (cable != null && cable.getFrameMaterial().isNull() && cable.getNodeData().getLossPerBlock() > 0) { 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 283eb5c7b16..3877e41d33c 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/blockentity/CableBlockEntity.java +++ b/src/main/java/com/gregtechceu/gtceu/common/blockentity/CableBlockEntity.java @@ -6,6 +6,7 @@ import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; import com.gregtechceu.gtceu.api.capability.IEnergyContainer; import com.gregtechceu.gtceu.api.data.chemical.material.properties.WireProperties; +import com.gregtechceu.gtceu.api.data.tag.TagPrefix; import com.gregtechceu.gtceu.api.gui.GuiTextures; import com.gregtechceu.gtceu.api.item.tool.GTToolType; import com.gregtechceu.gtceu.api.machine.TickableSubscription; @@ -36,7 +37,6 @@ import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.common.capabilities.Capability; @@ -243,7 +243,7 @@ public boolean isParticleAlive() { @OnlyIn(Dist.CLIENT) public void createParticle() { - particle = new GTOverheatParticle(this, meltTemp, getPipeType().insulationLevel >= 0); + particle = new GTOverheatParticle(this, meltTemp, getPipeType().isCable()); GTParticleManager.INSTANCE.addEffect(particle); } @@ -279,7 +279,7 @@ private boolean updateHeat() { return false; } - if (getPipeType().insulationLevel >= 0 && temperature >= 1500 && GTValues.RNG.nextFloat() < 0.1f) { + if (getPipeType().isCable() && temperature >= 1500 && GTValues.RNG.nextFloat() < 0.1f) { // insulation melted uninsulate(); return false; @@ -370,7 +370,7 @@ public GTToolType getPipeTuneTool() { } @Override - public @NotNull List getDataInfo(PortableScannerBehavior.DisplayMode mode) { + public List getDataInfo(PortableScannerBehavior.DisplayMode mode) { List list = new ArrayList<>(); if (mode == PortableScannerBehavior.DisplayMode.SHOW_ALL || diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/GTMaterialBlocks.java b/src/main/java/com/gregtechceu/gtceu/common/data/GTMaterialBlocks.java index 4c21ff2b8a5..9d31c55a7c4 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/GTMaterialBlocks.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/GTMaterialBlocks.java @@ -188,7 +188,7 @@ public static void generateCableBlocks() { private static boolean allowCableBlock(Material material, Insulation insulation) { return material.hasProperty(PropertyKey.WIRE) && !insulation.tagPrefix.isIgnored(material) && - !(insulation.isCable && material.getProperty(PropertyKey.WIRE).isSuperconductor()); + !(insulation.isCable() && material.getProperty(PropertyKey.WIRE).isSuperconductor()); } private static void registerCableBlock(Material material, Insulation insulation, GTRegistrate registrate) { 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 fc543f04ff4..8bf88d4bce0 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 @@ -19,17 +19,17 @@ public enum Insulation implements IMaterialPipeType { - WIRE_SINGLE("single_wire", 0.1875f, 1, 2, wireGtSingle, -1, false), - WIRE_DOUBLE("double_wire", 0.3125f, 2, 2, wireGtDouble, -1, false), - WIRE_QUADRUPLE("quadruple_wire", 0.4375f, 4, 3, wireGtQuadruple, -1, false), - WIRE_OCTAL("octal_wire", 0.5625f, 8, 3, wireGtOctal, -1, false), - WIRE_HEX("hex_wire", 0.8125f, 16, 3, wireGtHex, -1, false), - - CABLE_SINGLE("single_cable", 0.25f, 1, 1, cableGtSingle, 0, true), - CABLE_DOUBLE("double_cable", 0.375f, 2, 1, cableGtDouble, 1, true), - CABLE_QUADRUPLE("quadruple_cable", 0.5f, 4, 1, cableGtQuadruple, 2, true), - CABLE_OCTAL("octal_cable", 0.625f, 8, 1, cableGtOctal, 3, true), - CABLE_HEX("hex_cable", 0.875f, 16, 1, cableGtHex, 4, true); + WIRE_SINGLE("single_wire", 0.1875f, 1, 2, wireGtSingle, -1), + WIRE_DOUBLE("double_wire", 0.3125f, 2, 2, wireGtDouble, -1), + WIRE_QUADRUPLE("quadruple_wire", 0.4375f, 4, 3, wireGtQuadruple, -1), + WIRE_OCTAL("octal_wire", 0.5625f, 8, 3, wireGtOctal, -1), + WIRE_HEX("hex_wire", 0.8125f, 16, 3, wireGtHex, -1), + + CABLE_SINGLE("single_cable", 0.25f, 1, 1, cableGtSingle, 0), + CABLE_DOUBLE("double_cable", 0.375f, 2, 1, cableGtDouble, 1), + CABLE_QUADRUPLE("quadruple_cable", 0.5f, 4, 1, cableGtQuadruple, 2), + CABLE_OCTAL("octal_cable", 0.625f, 8, 1, cableGtOctal, 3), + CABLE_HEX("hex_cable", 0.875f, 16, 1, cableGtHex, 4); public static final ResourceLocation TYPE_ID = GTCEu.id("insulation"); @@ -40,17 +40,20 @@ public enum Insulation implements IMaterialPipeType { @Getter public final TagPrefix tagPrefix; public final int insulationLevel; + /// @deprecated Use {@link #isCable() Insulation.isCable()} + @Deprecated(forRemoval = true, since = "8.0.0") public final boolean isCable; - Insulation(String name, float thickness, int amperage, int lossMultiplier, TagPrefix TagPrefix, int insulated, - boolean isCable) { + Insulation(String name, float thickness, int amperage, int lossMultiplier, TagPrefix TagPrefix, + int insulationLevel) { this.name = name; this.thickness = thickness; this.amperage = amperage; this.tagPrefix = TagPrefix; - this.insulationLevel = insulated; + this.insulationLevel = insulationLevel; this.lossMultiplier = lossMultiplier; - this.isCable = isCable; + + this.isCable = insulationLevel >= 0; } @Override @@ -70,7 +73,7 @@ public WireProperties modifyProperties(WireProperties baseProperties) { } public boolean isCable() { - return ordinal() > 4; + return insulationLevel >= 0; } @Override @@ -90,7 +93,7 @@ public PipeModel createPipeModel(PipeBlock block, Material material, GT .getBlockTexturePath(material.getMaterialIconSet(), "end", true); PipeModel model = new PipeModel(block, provider, thickness, - isCable ? GTCEu.id("block/cable/insulation_5") : side, end); + isCable() ? GTCEu.id("block/cable/insulation_5") : side, end); ResourceLocation sideSecondary = MaterialIconType.wire .getBlockTexturePath(material.getMaterialIconSet(), "side_overlay", true); @@ -103,7 +106,7 @@ public PipeModel createPipeModel(PipeBlock block, Material material, GT if (endSecondary != null && !endSecondary.equals(GTModels.BLANK_TEXTURE)) { model.setEndSecondary(endSecondary); } - if (isCable) { + if (isCable()) { model.setEndOverlay(GTCEu.id("block/cable/insulation_%s".formatted(insulationLevel))); } return model; From 8d8b8b056b5ccabcdcd7188afb64efb335d589b0 Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Tue, 2 Jun 2026 12:44:06 +0300 Subject: [PATCH 06/18] Use `@Getter` for `Insulation#getThickness` --- .../gregtechceu/gtceu/common/pipelike/cable/Insulation.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) 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 8bf88d4bce0..d4e05f89d81 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 @@ -34,6 +34,7 @@ public enum Insulation implements IMaterialPipeType { public static final ResourceLocation TYPE_ID = GTCEu.id("insulation"); public final String name; + @Getter public final float thickness; public final int amperage; public final int lossMultiplier; @@ -56,11 +57,6 @@ public enum Insulation implements IMaterialPipeType { this.isCable = insulationLevel >= 0; } - @Override - public float getThickness() { - return thickness; - } - @Override public WireProperties modifyProperties(WireProperties baseProperties) { int lossPerBlock; From 1e4b79d0de29a840590b32fc7b9e15c308deecd7 Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Tue, 2 Jun 2026 12:44:34 +0300 Subject: [PATCH 07/18] Add method for getting the uninsulated variant of a cable --- .../gtceu/common/blockentity/CableBlockEntity.java | 12 ++++++------ .../gtceu/common/pipelike/cable/Insulation.java | 8 ++++++++ 2 files changed, 14 insertions(+), 6 deletions(-) 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 3877e41d33c..c215d97225f 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/blockentity/CableBlockEntity.java +++ b/src/main/java/com/gregtechceu/gtceu/common/blockentity/CableBlockEntity.java @@ -294,16 +294,16 @@ private boolean updateHeat() { } private void uninsulate() { - int temp = temperature; + int oldTemperature = temperature; setTemperature(getDefaultTemp()); - int index = getPipeType().insulationLevel; - CableBlock newBlock = GTMaterialBlocks.CABLE_BLOCKS - .get(Insulation.values()[index].tagPrefix, getPipeBlock().material) - .get(); + + TagPrefix uninsulatedPrefix = getPipeType().getUninsulated().tagPrefix; + CableBlock newBlock = GTMaterialBlocks.CABLE_BLOCKS.get(uninsulatedPrefix, getPipeBlock().material).get(); level.setBlockAndUpdate(getBlockPos(), newBlock.defaultBlockState()); + CableBlockEntity newCable = (CableBlockEntity) level.getBlockEntity(getBlockPos()); if (newCable != null) { // should never be null - newCable.setTemperature(temp); + newCable.setTemperature(oldTemperature); newCable.subscribeHeat(); for (Direction facing : GTUtil.DIRECTIONS) { if (isConnected(facing)) { 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 d4e05f89d81..8ea7978ac6b 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 @@ -72,6 +72,14 @@ public boolean isCable() { return insulationLevel >= 0; } + public Insulation getUninsulated() { + if (isCable()) { + return values()[insulationLevel]; + } else { + return this; + } + } + @Override public boolean isPaintable() { return true; From 1c6e9d9d3d889e85e1529355eb95ea05619d3b6d Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Tue, 2 Jun 2026 12:46:50 +0300 Subject: [PATCH 08/18] Make GTParticleManager's event listeners instance methods --- .../gregtechceu/gtceu/client/ClientProxy.java | 4 ++ .../client/particle/GTParticleManager.java | 57 +++++++------------ 2 files changed, 25 insertions(+), 36 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java b/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java index 6fc9be86508..bb9a4ee089d 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java +++ b/src/main/java/com/gregtechceu/gtceu/client/ClientProxy.java @@ -13,6 +13,7 @@ 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.GTParticleManager; import com.gregtechceu.gtceu.client.particle.HazardParticle; import com.gregtechceu.gtceu.client.particle.MufflerParticle; import com.gregtechceu.gtceu.client.renderer.block.MaterialBlockRenderer; @@ -65,6 +66,7 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.Item; import net.minecraftforge.client.event.*; +import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; @@ -99,6 +101,8 @@ public static void init() { } initializeDynamicRenders(); ModelEventHelper.initInternalAssetReloadListeners(); + + MinecraftForge.EVENT_BUS.register(GTParticleManager.INSTANCE); } @SubscribeEvent diff --git a/src/main/java/com/gregtechceu/gtceu/client/particle/GTParticleManager.java b/src/main/java/com/gregtechceu/gtceu/client/particle/GTParticleManager.java index cf2c5ae5380..d542d9dd78d 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/particle/GTParticleManager.java +++ b/src/main/java/com/gregtechceu/gtceu/client/particle/GTParticleManager.java @@ -5,18 +5,14 @@ import com.gregtechceu.gtceu.client.bloom.IRenderSetup; import net.minecraft.ChatFormatting; -import net.minecraft.client.Camera; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.client.renderer.culling.Frustum; -import net.minecraft.world.entity.Entity; -import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.event.ClientPlayerNetworkEvent; import net.minecraftforge.client.event.CustomizeGuiOverlayEvent; import net.minecraftforge.client.event.RenderLevelStageEvent; +import net.minecraftforge.event.TickEvent; import net.minecraftforge.event.level.LevelEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem; @@ -31,8 +27,7 @@ /** * Singleton class responsible for managing, updating and rendering {@link GTParticle} instances. */ -@Mod.EventBusSubscriber(modid = GTCEu.MOD_ID, value = Dist.CLIENT) -public class GTParticleManager { +public final class GTParticleManager { public static final GTParticleManager INSTANCE = new GTParticleManager(); @@ -41,6 +36,8 @@ public class GTParticleManager { private final List newParticleQueue = new ArrayList<>(); + private GTParticleManager() {} + public void addEffect(GTParticle particles) { newParticleQueue.add(particles); } @@ -119,21 +116,22 @@ public void clearAllEffects(boolean cleanNewQueue) { this.depthDisabledParticles.clear(); } - public void renderParticles(PoseStack poseStack, Camera camera, Frustum frustum, float partialTicks) { + @SubscribeEvent + public void renderParticles(RenderLevelStageEvent event) { if (this.depthEnabledParticles.isEmpty() && this.depthDisabledParticles.isEmpty()) return; EffectRenderContext instance = EffectRenderContext.getInstance() - .update(camera, frustum, partialTicks); + .update(event.getCamera(), event.getFrustum(), event.getPartialTick()); RenderSystem.enableBlend(); RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA); if (!this.depthDisabledParticles.isEmpty()) { RenderSystem.depthMask(false); - renderParticlesInLayer(poseStack, this.depthDisabledParticles, instance); + renderParticlesInLayer(event.getPoseStack(), this.depthDisabledParticles, instance); RenderSystem.depthMask(true); } - renderParticlesInLayer(poseStack, this.depthEnabledParticles, instance); + renderParticlesInLayer(event.getPoseStack(), this.depthEnabledParticles, instance); RenderSystem.disableBlend(); } @@ -174,13 +172,13 @@ private static void renderParticlesInLayer(PoseStack poseStack, } @SubscribeEvent - public static void onClientLevelLoad(LevelEvent.Load event) { + public void onClientLevelLoad(LevelEvent.Load event) { if (!(event.getLevel() instanceof ClientLevel newLevel)) { return; } ClientLevel oldLevel = Minecraft.getInstance().level; if (oldLevel != newLevel) { - INSTANCE.clearAllEffects(oldLevel != null); + this.clearAllEffects(oldLevel != null); } if (oldLevel != null) { @@ -189,34 +187,21 @@ public static void onClientLevelLoad(LevelEvent.Load event) { } @SubscribeEvent - public static void onClientLevelUnload(ClientPlayerNetworkEvent.LoggingOut event) { + public void onClientLogout(ClientPlayerNetworkEvent.LoggingOut event) { if (event.getPlayer() != null) { - INSTANCE.clearAllEffects(true); - } - } - - @SubscribeEvent - public static void renderWorld(RenderLevelStageEvent event) { - if (event.getStage() == RenderLevelStageEvent.Stage.AFTER_CUTOUT_BLOCKS) { - Entity entity = Minecraft.getInstance().getCameraEntity(); - if (entity == null) { - entity = Minecraft.getInstance().player; - } - if (entity != null) { - INSTANCE.renderParticles(event.getPoseStack(), event.getCamera(), event.getFrustum(), - event.getPartialTick()); - } + this.clearAllEffects(true); } } @SubscribeEvent - public static void debugOverlay(CustomizeGuiOverlayEvent.DebugText event) { - if (event.getLeft().size() >= 5) { - String particleTxt = event.getLeft().get(4); - particleTxt += "." + ChatFormatting.GOLD + - " PARTICLE-BACK: " + count(INSTANCE.depthEnabledParticles) + - "PARTICLE-FRONT: " + count(INSTANCE.depthDisabledParticles); - event.getLeft().set(4, particleTxt); + public void debugOverlay(CustomizeGuiOverlayEvent.DebugText event) { + List gameInfo = event.getLeft(); + if (gameInfo.size() >= 5) { + String countStatsLine = gameInfo.get(4); + countStatsLine += ". " + ChatFormatting.GOLD + + "P-BACK: " + count(this.depthEnabledParticles) + + " P-FRONT: " + count(this.depthDisabledParticles); + gameInfo.set(4, countStatsLine); } } From a1b9018082b5e92d04ec4d04aa9a65e471d2e798 Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Tue, 2 Jun 2026 12:49:54 +0300 Subject: [PATCH 09/18] Fix GTParticleManager not updating the particle list(s) --- .../gtceu/client/particle/GTParticleManager.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/particle/GTParticleManager.java b/src/main/java/com/gregtechceu/gtceu/client/particle/GTParticleManager.java index d542d9dd78d..1fb6acdf366 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/particle/GTParticleManager.java +++ b/src/main/java/com/gregtechceu/gtceu/client/particle/GTParticleManager.java @@ -171,6 +171,16 @@ private static void renderParticlesInLayer(PoseStack poseStack, } } + @SubscribeEvent + public void clientTick(TickEvent.ClientTickEvent event) { + if (event.phase != TickEvent.Phase.END || Minecraft.getInstance().isPaused()) { + return; + } + if (Minecraft.getInstance().level != null) { + INSTANCE.updateEffects(); + } + } + @SubscribeEvent public void onClientLevelLoad(LevelEvent.Load event) { if (!(event.getLevel() instanceof ClientLevel newLevel)) { @@ -180,10 +190,6 @@ public void onClientLevelLoad(LevelEvent.Load event) { if (oldLevel != newLevel) { this.clearAllEffects(oldLevel != null); } - - if (oldLevel != null) { - INSTANCE.updateEffects(); - } } @SubscribeEvent From ad56421f84fcc1ad42bb9c315707baf16d09934b Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Tue, 2 Jun 2026 12:50:12 +0300 Subject: [PATCH 10/18] dont use concrete implementations because we don't need to --- .../client/particle/GTParticleManager.java | 30 ++++++++----------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/particle/GTParticleManager.java b/src/main/java/com/gregtechceu/gtceu/client/particle/GTParticleManager.java index 1fb6acdf366..7ac8f3871bf 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/particle/GTParticleManager.java +++ b/src/main/java/com/gregtechceu/gtceu/client/particle/GTParticleManager.java @@ -31,8 +31,8 @@ public final class GTParticleManager { public static final GTParticleManager INSTANCE = new GTParticleManager(); - private final Map<@Nullable IRenderSetup, ArrayDeque> depthEnabledParticles = new Object2ObjectLinkedOpenHashMap<>(); - private final Map<@Nullable IRenderSetup, ArrayDeque> depthDisabledParticles = new Object2ObjectLinkedOpenHashMap<>(); + private final Map<@Nullable IRenderSetup, Queue> depthEnabledParticles = new Object2ObjectLinkedOpenHashMap<>(); + private final Map<@Nullable IRenderSetup, Queue> depthDisabledParticles = new Object2ObjectLinkedOpenHashMap<>(); private final List newParticleQueue = new ArrayList<>(); @@ -54,11 +54,11 @@ public void updateEffects() { for (GTParticle particle : newParticleQueue) { var queue = particle.shouldDisableDepth() ? this.depthDisabledParticles : this.depthEnabledParticles; - ArrayDeque particles = queue.computeIfAbsent(particle.getRenderSetup(), + Queue particles = queue.computeIfAbsent(particle.getRenderSetup(), setup -> new ArrayDeque<>()); if (particles.size() > 6000) { - particles.removeFirst().setExpired(); + particles.remove().setExpired(); } particles.add(particle); } @@ -67,10 +67,10 @@ public void updateEffects() { } } - private void updateQueue(Map<@Nullable IRenderSetup, ArrayDeque> renderQueue) { - Iterator> it = renderQueue.values().iterator(); + private void updateQueue(Map<@Nullable IRenderSetup, Queue> renderQueue) { + Iterator> it = renderQueue.values().iterator(); while (it.hasNext()) { - ArrayDeque particlesForSetup = it.next(); + Queue particlesForSetup = it.next(); Iterator particles = particlesForSetup.iterator(); while (particles.hasNext()) { @@ -102,12 +102,12 @@ public void clearAllEffects(boolean cleanNewQueue) { } this.newParticleQueue.clear(); } - for (ArrayDeque particles : this.depthEnabledParticles.values()) { + for (Queue particles : this.depthEnabledParticles.values()) { for (GTParticle particle : particles) { particle.setExpired(); } } - for (ArrayDeque particles : this.depthDisabledParticles.values()) { + for (Queue particles : this.depthDisabledParticles.values()) { for (GTParticle particle : particles) { particle.setExpired(); } @@ -137,10 +137,10 @@ public void renderParticles(RenderLevelStageEvent event) { } private static void renderParticlesInLayer(PoseStack poseStack, - Map<@Nullable IRenderSetup, ArrayDeque> renderQueue, + Map<@Nullable IRenderSetup, Queue> renderQueue, EffectRenderContext context) { for (var entry : renderQueue.entrySet()) { - ArrayDeque particles = entry.getValue(); + Queue particles = entry.getValue(); if (particles.isEmpty()) continue; IRenderSetup handler = entry.getKey(); @@ -211,11 +211,7 @@ public void debugOverlay(CustomizeGuiOverlayEvent.DebugText event) { } } - private static int count(Map<@Nullable IRenderSetup, ArrayDeque> renderQueue) { - int total = 0; - for (Deque queue : renderQueue.values()) { - total += queue.size(); - } - return total; + private static int count(Map<@Nullable IRenderSetup, Queue> renderQueue) { + return renderQueue.values().stream().mapToInt(Queue::size).sum(); } } From 800b6c994f2ff414f55926bd5bad9b87e5c7a20e Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Tue, 2 Jun 2026 15:52:59 +0300 Subject: [PATCH 11/18] Fix some wrong depth funcs --- .../gtceu/client/bloom/BloomRenderer.java | 4 +- .../client/particle/GTOverheatParticle.java | 55 +++++++++++++++---- .../client/particle/GTParticleManager.java | 23 +++++--- 3 files changed, 59 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/bloom/BloomRenderer.java b/src/main/java/com/gregtechceu/gtceu/client/bloom/BloomRenderer.java index 56ca88d86ec..021fee74473 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/bloom/BloomRenderer.java +++ b/src/main/java/com/gregtechceu/gtceu/client/bloom/BloomRenderer.java @@ -140,9 +140,7 @@ static void processPostEffect(float partialTicks, ProfilerFiller profilerFiller) mainTarget.bindWrite(false); RenderSystem.enableBlend(); - RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, - GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, - GlStateManager.SourceFactor.ZERO, GlStateManager.DestFactor.ONE); + RenderSystem.blendFunc(GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); BLOOM_TARGET.blitToScreen(mainTarget.viewWidth, mainTarget.viewHeight, false); BLOOM_TARGET.unbindRead(); diff --git a/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java b/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java index 8ae58017064..b3b4026d9e3 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java +++ b/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java @@ -8,6 +8,7 @@ import com.gregtechceu.gtceu.client.util.RenderUtil; import com.gregtechceu.gtceu.common.blockentity.CableBlockEntity; +import net.minecraft.client.renderer.GameRenderer; import net.minecraft.core.BlockPos; import net.minecraft.core.particles.ParticleTypes; import net.minecraft.world.phys.AABB; @@ -18,7 +19,6 @@ import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.*; -import org.jetbrains.annotations.Nullable; /** * @author brachy84 @@ -159,7 +159,7 @@ public GTOverheatParticle(CableBlockEntity blockEntity, int meltTemp, boolean in this.pipeShape = blockEntity.getBlockState().getVisualShape(blockEntity.getLevel(), blockEntity.getBlockPos(), CollisionContext.empty()); - this.pipeBounds = pipeShape.bounds().move(posX, posY, posZ); + this.pipeBounds = pipeShape.bounds().inflate(0.001).move(posX, posY, posZ); } public void setTemperature(int temperature) { @@ -194,7 +194,7 @@ public void onUpdate() { // update pipeShape every tick so it doesn't desync if the pipe is disconnected pipeShape = blockEntity.getBlockState().getVisualShape(blockEntity.getLevel(), blockEntity.getBlockPos(), CollisionContext.empty()); - pipeBounds = pipeShape.bounds().move(posX, posY, posZ); + pipeBounds = pipeShape.bounds().inflate(0.001).move(posX, posY, posZ); updateColor(); @@ -225,19 +225,29 @@ public String toString() { } @Override - public @Nullable IRenderSetup getRenderSetup() { - return SETUP; + public boolean shouldRender(EffectRenderContext context) { + return this.shouldRenderBloomEffect(context); } @Override - public boolean shouldRender(EffectRenderContext context) { + public boolean shouldRenderBloomEffect(EffectRenderContext context) { if (this.insulated) return false; return context.frustum().isVisible(pipeBounds); } @Override - protected @Nullable IRenderSetup getBloomRenderSetup() { - return SETUP; + public IRenderSetup getRenderSetup() { + return NO_BLOOM_SETUP; + } + + @Override + protected IRenderSetup getBloomRenderSetup() { + return BLOOM_SETUP; + } + + @Override + public void renderParticle(PoseStack poseStack, BufferBuilder buffer, EffectRenderContext context) { + renderBloomEffect(poseStack, buffer, context); } @Override @@ -250,19 +260,23 @@ public void renderBloomEffect(PoseStack poseStack, BufferBuilder buffer, EffectR poseStack.translate(posX, posY, posZ); pipeShape.forAllBoxes((x1, y1, z1, x2, y2, z2) -> { RenderBufferHelper.renderColorCube(poseStack, buffer, - (float) x1, (float) y1, (float) z1, (float) x2, (float) y2, (float) z2, + (float) x1 - 0.001f, (float) y1 - 0.001f, (float) z1 - 0.001f, + (float) x2 + 0.001f, (float) y2 + 0.001f, (float) z2 + 0.001f, red, green, blue, alpha, true); }); poseStack.popPose(); } - private static final IRenderSetup SETUP = new IRenderSetup() { + private static final IRenderSetup NO_BLOOM_SETUP = new IRenderSetup() { @Override @OnlyIn(Dist.CLIENT) public void preDraw(BufferBuilder buffer) { - RenderSystem.setShaderColor(1, 1, 1, 1); RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + RenderSystem.setShader(GameRenderer::getPositionColorShader); + RenderSystem.setShaderColor(1, 1, 1, 1); + buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); } @@ -273,4 +287,23 @@ public void postDraw(BufferBuilder buffer) { RenderSystem.disableBlend(); } }; + + private static final IRenderSetup BLOOM_SETUP = new IRenderSetup() { + + @Override + @OnlyIn(Dist.CLIENT) + public void preDraw(BufferBuilder buffer) { + RenderSystem.disableBlend(); + RenderSystem.setShader(GameRenderer::getPositionColorShader); + RenderSystem.setShaderColor(1, 1, 1, 1); + + buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); + } + + @Override + @OnlyIn(Dist.CLIENT) + public void postDraw(BufferBuilder buffer) { + BufferUploader.drawWithShader(buffer.end()); + } + }; } diff --git a/src/main/java/com/gregtechceu/gtceu/client/particle/GTParticleManager.java b/src/main/java/com/gregtechceu/gtceu/client/particle/GTParticleManager.java index 7ac8f3871bf..e1a8ce45cdf 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/particle/GTParticleManager.java +++ b/src/main/java/com/gregtechceu/gtceu/client/particle/GTParticleManager.java @@ -5,6 +5,7 @@ import com.gregtechceu.gtceu.client.bloom.IRenderSetup; import net.minecraft.ChatFormatting; +import net.minecraft.client.Camera; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraftforge.client.event.ClientPlayerNetworkEvent; @@ -12,9 +13,9 @@ import net.minecraftforge.client.event.RenderLevelStageEvent; import net.minecraftforge.event.TickEvent; import net.minecraftforge.event.level.LevelEvent; +import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.SubscribeEvent; -import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.BufferBuilder; import com.mojang.blaze3d.vertex.PoseStack; @@ -116,24 +117,28 @@ public void clearAllEffects(boolean cleanNewQueue) { this.depthDisabledParticles.clear(); } - @SubscribeEvent + @SubscribeEvent(priority = EventPriority.HIGH) public void renderParticles(RenderLevelStageEvent event) { + if (event.getStage() != RenderLevelStageEvent.Stage.AFTER_PARTICLES) return; if (this.depthEnabledParticles.isEmpty() && this.depthDisabledParticles.isEmpty()) return; - EffectRenderContext instance = EffectRenderContext.getInstance() - .update(event.getCamera(), event.getFrustum(), event.getPartialTick()); + Camera camera = event.getCamera(); - RenderSystem.enableBlend(); - RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA); + PoseStack poseStack = event.getPoseStack(); + poseStack.pushPose(); + poseStack.translate(-camera.getPosition().x, -camera.getPosition().y, -camera.getPosition().z); + + EffectRenderContext instance = EffectRenderContext.getInstance() + .update(camera, event.getFrustum(), event.getPartialTick()); if (!this.depthDisabledParticles.isEmpty()) { RenderSystem.depthMask(false); - renderParticlesInLayer(event.getPoseStack(), this.depthDisabledParticles, instance); + renderParticlesInLayer(poseStack, this.depthDisabledParticles, instance); RenderSystem.depthMask(true); } - renderParticlesInLayer(event.getPoseStack(), this.depthEnabledParticles, instance); + renderParticlesInLayer(poseStack, this.depthEnabledParticles, instance); - RenderSystem.disableBlend(); + poseStack.popPose(); } private static void renderParticlesInLayer(PoseStack poseStack, From d1ba125b984ee9582af8a9b072324f7613406297 Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Tue, 2 Jun 2026 15:53:38 +0300 Subject: [PATCH 12/18] reset state after every bloom render group --- .../gtceu/client/bloom/BloomRenderer.java | 3 +++ .../renderer/machine/impl/FusionRingRender.java | 17 ++++------------- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/bloom/BloomRenderer.java b/src/main/java/com/gregtechceu/gtceu/client/bloom/BloomRenderer.java index 021fee74473..733b646923d 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/bloom/BloomRenderer.java +++ b/src/main/java/com/gregtechceu/gtceu/client/bloom/BloomRenderer.java @@ -220,6 +220,9 @@ public static boolean enabled() { private static void drawBlockBloom(Camera camera, PoseStack poseStack, Frustum frustum, Matrix4f projectionMatrix, LevelRenderer levelRenderer, ProfilerFiller profilerFiller) { + // re-setup in case someone touched-a my spaghetti + GTRenderTypes.bloom().setupRenderState(); + Vec3 camPos = camera.getPosition(); profilerFiller.push("safe_mode"); diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/FusionRingRender.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/FusionRingRender.java index 3879aea58c3..6b51548a228 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/FusionRingRender.java +++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/machine/impl/FusionRingRender.java @@ -11,7 +11,6 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.GameRenderer; import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.ShaderInstance; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.util.Mth; @@ -125,25 +124,19 @@ private final class FusionBloomEffect implements IBloomEffect { private final FusionReactorMachine machine; - private static final BufferBuilder lightRingBuffer = new BufferBuilder(GTRenderTypes.lightRing().bufferSize()); - private static final IRenderSetup SETUP = new IRenderSetup() { @Override @OnlyIn(Dist.CLIENT) public void preDraw(BufferBuilder buffer) { - lightRingBuffer.begin(GTRenderTypes.lightRing().mode(), GTRenderTypes.lightRing().format()); + RenderSystem.setShader(GameRenderer::getPositionColorShader); + buffer.begin(VertexFormat.Mode.TRIANGLE_STRIP, DefaultVertexFormat.POSITION_COLOR); } @Override @OnlyIn(Dist.CLIENT) public void postDraw(BufferBuilder buffer) { - ShaderInstance lastShader = RenderSystem.getShader(); - RenderSystem.setShader(GameRenderer::getPositionColorShader); - - BufferUploader.drawWithShader(lightRingBuffer.end()); - - RenderSystem.setShader(() -> lastShader); + BufferUploader.drawWithShader(buffer.end()); } }; @@ -153,9 +146,7 @@ public void renderBloomEffect(PoseStack poseStack, BufferBuilder buffer, EffectR poseStack.pushPose(); poseStack.translate(pos.getX(), pos.getY(), pos.getZ()); - - FusionRingRender.this.renderLightRing(machine, context.partialTicks(), poseStack, lightRingBuffer); - + FusionRingRender.this.renderLightRing(machine, context.partialTicks(), poseStack, buffer); poseStack.popPose(); } From 5401eee8d43c97e2bccbebda5770a74f8be85ed1 Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Tue, 2 Jun 2026 17:50:33 +0300 Subject: [PATCH 13/18] Only update the bloom particle's shape when the cable is changed --- .../gtceu/api/blockentity/PipeBlockEntity.java | 3 +-- .../client/particle/GTOverheatParticle.java | 16 +++++++++++++--- .../common/blockentity/CableBlockEntity.java | 7 +++++++ 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/api/blockentity/PipeBlockEntity.java b/src/main/java/com/gregtechceu/gtceu/api/blockentity/PipeBlockEntity.java index 0b65acbfab5..b4772f50d2a 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/blockentity/PipeBlockEntity.java +++ b/src/main/java/com/gregtechceu/gtceu/api/blockentity/PipeBlockEntity.java @@ -255,8 +255,7 @@ public void setConnection(Direction side, boolean connected, boolean fromNeighbo if (cover != null && cover.canPipePassThrough()) return; } - connections = withSideConnection(connections, side, connected); - syncDataHolder.markClientSyncFieldDirty("connections"); + setConnections(withSideConnection(connections, side, connected)); updateNetworkConnection(side, connected); // notify neighbor of change so Auto Output updates its ticking status getLevel().neighborChanged(getBlockPos().relative(side), getPipeBlock(), getBlockPos()); diff --git a/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java b/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java index b3b4026d9e3..cae05dc6438 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java +++ b/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java @@ -183,22 +183,32 @@ public void updateColor() { color = getBlackBodyColor(temperature); } - @Override - public void onUpdate() { + public void updateConnections() { // if this isn't the block entity's particle, remove both if (blockEntity.isRemoved() || !blockEntity.isParticleAlive()) { setExpired(); blockEntity.killParticle(); return; } + // update pipeShape every tick so it doesn't desync if the pipe is disconnected pipeShape = blockEntity.getBlockState().getVisualShape(blockEntity.getLevel(), blockEntity.getBlockPos(), CollisionContext.empty()); pipeBounds = pipeShape.bounds().inflate(0.001).move(posX, posY, posZ); + } + + @Override + public void onUpdate() { + // if this isn't the block entity's particle, remove both + if (blockEntity.isRemoved() || !blockEntity.isParticleAlive()) { + setExpired(); + blockEntity.killParticle(); + return; + } updateColor(); - if (GTValues.RNG.nextFloat() < 0.04) { + if (temperature > 400 && blockEntity.getLevel().random.nextFloat() < 0.04f) { spawnSmoke(); } } 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 c215d97225f..2f21957c4e9 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/blockentity/CableBlockEntity.java +++ b/src/main/java/com/gregtechceu/gtceu/common/blockentity/CableBlockEntity.java @@ -353,6 +353,13 @@ public void onTemperatureUpdated() { } } + @ClientFieldChangeListener(fieldName = "connections") + private void onConnectionsUpdated() { + if (isParticleAlive()) { + particle.updateConnections(); + } + } + public static void onBlockEntityRegister(BlockEntityType cableBlockEntityBlockEntityType) {} ////////////////////////////////////// From 7063be6438e088a2469e5163f24e9f51e05b08f3 Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Tue, 2 Jun 2026 17:53:18 +0300 Subject: [PATCH 14/18] No need to update color constantly either --- .../gtceu/client/particle/GTOverheatParticle.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java b/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java index cae05dc6438..6fc120cc08b 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java +++ b/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java @@ -164,10 +164,6 @@ public GTOverheatParticle(CableBlockEntity blockEntity, int meltTemp, boolean in public void setTemperature(int temperature) { this.temperature = temperature; - updateColor(); - } - - public void updateColor() { if (temperature <= blockEntity.getDefaultTemp() || temperature > meltTemp) { setExpired(); return; @@ -206,8 +202,6 @@ public void onUpdate() { return; } - updateColor(); - if (temperature > 400 && blockEntity.getLevel().random.nextFloat() < 0.04f) { spawnSmoke(); } From 738147679334a6e5c33dd34aa1e0463968ce006b Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Tue, 2 Jun 2026 18:09:24 +0300 Subject: [PATCH 15/18] Make bottom of alpha curve shallower --- .../gtceu/client/particle/GTOverheatParticle.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java b/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java index 6fc120cc08b..35b6ef00c36 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java +++ b/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java @@ -168,11 +168,12 @@ public void setTemperature(int temperature) { setExpired(); return; } - if (temperature < 500) { + if (temperature < 300) { alpha = 0.0f; + } else if (temperature < 600) { + alpha = 0.16f * (temperature - 300f) / 300f; } else if (temperature < 1000) { - alpha = (temperature - 500f) / 500f; - alpha *= 0.8f; + alpha = 0.8f * (temperature - 500f) / 500f; } else { alpha = 0.8f; } From 60239354a72edcd50d9e410f4b866e9398b4328a Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Tue, 2 Jun 2026 18:09:45 +0300 Subject: [PATCH 16/18] RAHH I LOVE PRIVATIZATION --- .../gtceu/client/particle/GTOverheatParticle.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java b/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java index 35b6ef00c36..e63c5bd7950 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java +++ b/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java @@ -140,15 +140,15 @@ public static int getBlackBodyColor(int temperature) { private final CableBlockEntity blockEntity; - protected final int meltTemp; - protected int temperature; - protected final boolean insulated; + private final int meltTemp; + private int temperature; + private final boolean insulated; - protected VoxelShape pipeShape; - protected AABB pipeBounds; + private VoxelShape pipeShape; + private AABB pipeBounds; - protected float alpha = 0.0f; - protected int color = blackBodyColors[0]; + private float alpha = 0.0f; + private int color = blackBodyColors[0]; public GTOverheatParticle(CableBlockEntity blockEntity, int meltTemp, boolean insulated) { super(blockEntity.getBlockPos().getX(), blockEntity.getBlockPos().getY(), blockEntity.getBlockPos().getZ()); From aeb4180e52d67446776b9bab145336d6a7b73511 Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Wed, 3 Jun 2026 10:16:46 +0300 Subject: [PATCH 17/18] undo --- .../gtceu/client/particle/GTOverheatParticle.java | 14 ++------------ .../gtceu/common/blockentity/CableBlockEntity.java | 7 ------- 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java b/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java index e63c5bd7950..6d47a5cb7c6 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java +++ b/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java @@ -180,28 +180,18 @@ public void setTemperature(int temperature) { color = getBlackBodyColor(temperature); } - public void updateConnections() { + @Override + public void onUpdate() { // if this isn't the block entity's particle, remove both if (blockEntity.isRemoved() || !blockEntity.isParticleAlive()) { setExpired(); blockEntity.killParticle(); return; } - // update pipeShape every tick so it doesn't desync if the pipe is disconnected pipeShape = blockEntity.getBlockState().getVisualShape(blockEntity.getLevel(), blockEntity.getBlockPos(), CollisionContext.empty()); pipeBounds = pipeShape.bounds().inflate(0.001).move(posX, posY, posZ); - } - - @Override - public void onUpdate() { - // if this isn't the block entity's particle, remove both - if (blockEntity.isRemoved() || !blockEntity.isParticleAlive()) { - setExpired(); - blockEntity.killParticle(); - return; - } if (temperature > 400 && blockEntity.getLevel().random.nextFloat() < 0.04f) { spawnSmoke(); 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 2f21957c4e9..c215d97225f 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/blockentity/CableBlockEntity.java +++ b/src/main/java/com/gregtechceu/gtceu/common/blockentity/CableBlockEntity.java @@ -353,13 +353,6 @@ public void onTemperatureUpdated() { } } - @ClientFieldChangeListener(fieldName = "connections") - private void onConnectionsUpdated() { - if (isParticleAlive()) { - particle.updateConnections(); - } - } - public static void onBlockEntityRegister(BlockEntityType cableBlockEntityBlockEntityType) {} ////////////////////////////////////// From 8bc39b30589473cff64f535793ca56c868823d48 Mon Sep 17 00:00:00 2001 From: screret <68943070+screret@users.noreply.github.com> Date: Wed, 3 Jun 2026 10:24:28 +0300 Subject: [PATCH 18/18] Use the same blend func RenderType.TRANSLUCENT uses so the cable can be seen a bit better when it's just started melting --- .../gtceu/client/particle/GTOverheatParticle.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java b/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java index 6d47a5cb7c6..d79073594b1 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java +++ b/src/main/java/com/gregtechceu/gtceu/client/particle/GTOverheatParticle.java @@ -1,6 +1,5 @@ package com.gregtechceu.gtceu.client.particle; -import com.gregtechceu.gtceu.api.GTValues; import com.gregtechceu.gtceu.client.bloom.EffectRenderContext; import com.gregtechceu.gtceu.client.bloom.IRenderSetup; import com.gregtechceu.gtceu.client.bloom.particle.GTBloomParticle; @@ -17,6 +16,7 @@ import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; +import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.*; @@ -268,7 +268,9 @@ public void renderBloomEffect(PoseStack poseStack, BufferBuilder buffer, EffectR @OnlyIn(Dist.CLIENT) public void preDraw(BufferBuilder buffer) { RenderSystem.enableBlend(); - RenderSystem.defaultBlendFunc(); + RenderSystem.blendFuncSeparate( + GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, + GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA); RenderSystem.setShader(GameRenderer::getPositionColorShader); RenderSystem.setShaderColor(1, 1, 1, 1); @@ -280,6 +282,7 @@ public void preDraw(BufferBuilder buffer) { public void postDraw(BufferBuilder buffer) { BufferUploader.drawWithShader(buffer.end()); RenderSystem.disableBlend(); + RenderSystem.defaultBlendFunc(); } };