From 99bb95e4e9aa0968e932181857c2715785747e26 Mon Sep 17 00:00:00 2001 From: Daniel Date: Sat, 12 Jul 2025 05:16:49 +0300 Subject: [PATCH] Rework blast furnace validation (breaking change!) - Pattern-based validation - layer wise matching - Remove Reinforced fireproof bricks (breaking change!) - Add fullbright rendering for coke oven & blast furnace contents - Minor fix Copper spool (15x16 -> 16x16 texture) --- .../reinforced_fireproof_bricks.json | 7 - .../block/reinforced_fireproof_bricks.json | 6 - .../tags/blocks/mineable/pickaxe.json | 1 - .../tags/blocks/needs_stone_tool.json | 1 - .../blocks/reinforced_fireproof_bricks.json | 21 --- .../blocks/reinforced_blast_furnace_wall.json | 1 - .../tfmg/base/events/TFMGClientEvents.java | 8 +- .../BlastFurnaceLayerPatterns.java | 41 ----- .../BlastFurnaceOutputBlockEntity.java | 155 +++++------------- .../blast_furnace/BlastFurnaceRenderer.java | 16 +- .../BlastFurnaceReinforcementWallBlock.java | 53 +----- .../{ => util}/BlastFurnaceLayer.java | 86 +++++----- .../util/BlastFurnaceLayerPatterns.java | 130 +++++++++++++++ .../util/BlastFurnaceValidator.java | 140 ++++++++++++++++ .../coke_oven/CokeOvenRenderer.java | 89 +++++++--- .../drmangotea/tfmg/registry/TFMGBlocks.java | 12 +- .../tfmg/registry/TFMGPartialModels.java | 6 +- .../block/coal_coke_dust_layer_glowing.json | 20 +++ .../models/block/coke_oven/fire_bottom.json | 18 ++ .../models/block/coke_oven/fire_middle.json | 18 ++ .../tfmg/models/block/coke_oven/fire_top.json | 18 ++ .../textures/block/coal_coke_dust_glowing.png | Bin 0 -> 474 bytes .../coke_oven/coke_oven_front_bottom_fire.png | Bin 0 -> 555 bytes .../coke_oven_front_bottom_fire.png.mcmeta | 6 + .../coke_oven/coke_oven_front_bottom_off.png | Bin 259 -> 480 bytes .../coke_oven/coke_oven_front_bottom_on.png | Bin 619 -> 603 bytes .../coke_oven_front_bottom_on.png.mcmeta | 3 - .../coke_oven/coke_oven_front_middle_fire.png | Bin 0 -> 562 bytes .../coke_oven_front_middle_fire.png.mcmeta | 6 + .../coke_oven/coke_oven_front_middle_off.png | Bin 225 -> 455 bytes .../coke_oven/coke_oven_front_middle_on.png | Bin 634 -> 457 bytes .../coke_oven_front_middle_on.png.mcmeta | 3 - .../coke_oven/coke_oven_front_top_fire.png | Bin 0 -> 526 bytes .../coke_oven_front_top_fire.png.mcmeta | 6 + .../coke_oven/coke_oven_front_top_off.png | Bin 255 -> 477 bytes .../coke_oven/coke_oven_front_top_on.png | Bin 664 -> 692 bytes .../coke_oven_front_top_on.png.mcmeta | 3 - .../tfmg/textures/item/copper_spool.png | Bin 278 -> 542 bytes 38 files changed, 538 insertions(+), 336 deletions(-) delete mode 100644 src/generated/resources/assets/tfmg/blockstates/reinforced_fireproof_bricks.json delete mode 100644 src/generated/resources/assets/tfmg/models/block/reinforced_fireproof_bricks.json delete mode 100644 src/generated/resources/data/tfmg/loot_tables/blocks/reinforced_fireproof_bricks.json delete mode 100644 src/main/java/com/drmangotea/tfmg/content/machinery/metallurgy/blast_furnace/BlastFurnaceLayerPatterns.java rename src/main/java/com/drmangotea/tfmg/content/machinery/metallurgy/blast_furnace/{ => util}/BlastFurnaceLayer.java (53%) create mode 100644 src/main/java/com/drmangotea/tfmg/content/machinery/metallurgy/blast_furnace/util/BlastFurnaceLayerPatterns.java create mode 100644 src/main/java/com/drmangotea/tfmg/content/machinery/metallurgy/blast_furnace/util/BlastFurnaceValidator.java create mode 100644 src/main/resources/assets/tfmg/models/block/coal_coke_dust_layer_glowing.json create mode 100644 src/main/resources/assets/tfmg/models/block/coke_oven/fire_bottom.json create mode 100644 src/main/resources/assets/tfmg/models/block/coke_oven/fire_middle.json create mode 100644 src/main/resources/assets/tfmg/models/block/coke_oven/fire_top.json create mode 100644 src/main/resources/assets/tfmg/textures/block/coal_coke_dust_glowing.png create mode 100644 src/main/resources/assets/tfmg/textures/block/coke_oven/coke_oven_front_bottom_fire.png create mode 100644 src/main/resources/assets/tfmg/textures/block/coke_oven/coke_oven_front_bottom_fire.png.mcmeta delete mode 100644 src/main/resources/assets/tfmg/textures/block/coke_oven/coke_oven_front_bottom_on.png.mcmeta create mode 100644 src/main/resources/assets/tfmg/textures/block/coke_oven/coke_oven_front_middle_fire.png create mode 100644 src/main/resources/assets/tfmg/textures/block/coke_oven/coke_oven_front_middle_fire.png.mcmeta delete mode 100644 src/main/resources/assets/tfmg/textures/block/coke_oven/coke_oven_front_middle_on.png.mcmeta create mode 100644 src/main/resources/assets/tfmg/textures/block/coke_oven/coke_oven_front_top_fire.png create mode 100644 src/main/resources/assets/tfmg/textures/block/coke_oven/coke_oven_front_top_fire.png.mcmeta delete mode 100644 src/main/resources/assets/tfmg/textures/block/coke_oven/coke_oven_front_top_on.png.mcmeta diff --git a/src/generated/resources/assets/tfmg/blockstates/reinforced_fireproof_bricks.json b/src/generated/resources/assets/tfmg/blockstates/reinforced_fireproof_bricks.json deleted file mode 100644 index 09814b6b..00000000 --- a/src/generated/resources/assets/tfmg/blockstates/reinforced_fireproof_bricks.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "variants": { - "": { - "model": "tfmg:block/reinforced_fireproof_bricks" - } - } -} \ No newline at end of file diff --git a/src/generated/resources/assets/tfmg/models/block/reinforced_fireproof_bricks.json b/src/generated/resources/assets/tfmg/models/block/reinforced_fireproof_bricks.json deleted file mode 100644 index 3879b13b..00000000 --- a/src/generated/resources/assets/tfmg/models/block/reinforced_fireproof_bricks.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "minecraft:block/cube_all", - "textures": { - "all": "tfmg:block/fireproof_bricks" - } -} \ No newline at end of file diff --git a/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json b/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json index 1558f3be..0f4a9f38 100644 --- a/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json +++ b/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json @@ -81,7 +81,6 @@ "tfmg:blast_furnace_output", "tfmg:blast_furnace_hatch", "tfmg:fireproof_bricks", - "tfmg:reinforced_fireproof_bricks", "tfmg:blast_furnace_reinforcement", "tfmg:blast_furnace_reinforcement_wall", "tfmg:rusted_blast_furnace_reinforcement", diff --git a/src/generated/resources/data/minecraft/tags/blocks/needs_stone_tool.json b/src/generated/resources/data/minecraft/tags/blocks/needs_stone_tool.json index ab9d9704..7a35e82d 100644 --- a/src/generated/resources/data/minecraft/tags/blocks/needs_stone_tool.json +++ b/src/generated/resources/data/minecraft/tags/blocks/needs_stone_tool.json @@ -9,7 +9,6 @@ "tfmg:blast_furnace_output", "tfmg:blast_furnace_hatch", "tfmg:fireproof_bricks", - "tfmg:reinforced_fireproof_bricks", "tfmg:blast_furnace_reinforcement", "tfmg:blast_furnace_reinforcement_wall", "tfmg:rusted_blast_furnace_reinforcement", diff --git a/src/generated/resources/data/tfmg/loot_tables/blocks/reinforced_fireproof_bricks.json b/src/generated/resources/data/tfmg/loot_tables/blocks/reinforced_fireproof_bricks.json deleted file mode 100644 index 54ab8ad8..00000000 --- a/src/generated/resources/data/tfmg/loot_tables/blocks/reinforced_fireproof_bricks.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "type": "minecraft:block", - "pools": [ - { - "bonus_rolls": 0.0, - "conditions": [ - { - "condition": "minecraft:survives_explosion" - } - ], - "entries": [ - { - "type": "minecraft:item", - "name": "tfmg:fireproof_bricks" - } - ], - "rolls": 1.0 - } - ], - "random_sequence": "tfmg:blocks/reinforced_fireproof_bricks" -} \ No newline at end of file diff --git a/src/generated/resources/data/tfmg/tags/blocks/reinforced_blast_furnace_wall.json b/src/generated/resources/data/tfmg/tags/blocks/reinforced_blast_furnace_wall.json index 7ef490f9..ea4e4155 100644 --- a/src/generated/resources/data/tfmg/tags/blocks/reinforced_blast_furnace_wall.json +++ b/src/generated/resources/data/tfmg/tags/blocks/reinforced_blast_furnace_wall.json @@ -1,7 +1,6 @@ { "values": [ "tfmg:blast_furnace_hatch", - "tfmg:reinforced_fireproof_bricks", "tfmg:steel_block" ] } \ No newline at end of file diff --git a/src/main/java/com/drmangotea/tfmg/base/events/TFMGClientEvents.java b/src/main/java/com/drmangotea/tfmg/base/events/TFMGClientEvents.java index 3db188bf..04b92ce8 100644 --- a/src/main/java/com/drmangotea/tfmg/base/events/TFMGClientEvents.java +++ b/src/main/java/com/drmangotea/tfmg/base/events/TFMGClientEvents.java @@ -1,23 +1,17 @@ package com.drmangotea.tfmg.base.events; -import com.drmangotea.tfmg.TFMG; import com.drmangotea.tfmg.content.electricity.measurement.MultimeterOverlayRenderer; import com.drmangotea.tfmg.content.engines.engine_controller.EngineControllerClientHandler; import net.minecraft.client.Minecraft; import net.minecraft.world.entity.player.Player; import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.client.ConfigScreenHandler; -import net.minecraftforge.client.event.*; -import net.minecraftforge.client.event.RenderLevelStageEvent.Stage; +import net.minecraftforge.client.event.RegisterGuiOverlaysEvent; import net.minecraftforge.client.gui.overlay.VanillaGuiOverlay; import net.minecraftforge.event.TickEvent.ClientTickEvent; import net.minecraftforge.event.TickEvent.Phase; import net.minecraftforge.event.entity.player.PlayerEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.ModContainer; -import net.minecraftforge.fml.ModList; import net.minecraftforge.fml.common.Mod.EventBusSubscriber; -import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent; diff --git a/src/main/java/com/drmangotea/tfmg/content/machinery/metallurgy/blast_furnace/BlastFurnaceLayerPatterns.java b/src/main/java/com/drmangotea/tfmg/content/machinery/metallurgy/blast_furnace/BlastFurnaceLayerPatterns.java deleted file mode 100644 index 30054740..00000000 --- a/src/main/java/com/drmangotea/tfmg/content/machinery/metallurgy/blast_furnace/BlastFurnaceLayerPatterns.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.drmangotea.tfmg.content.machinery.metallurgy.blast_furnace; - -public final class BlastFurnaceLayerPatterns { - - // Fireproof bricks + corner brick reinforcements - public static final BlastFurnaceLayer THIN_REGULAR = new BlastFurnaceLayer("AAAAAAFBFAABABAAFBFAAAAAA"); - - // Fireproof bricks + corner brick reinforcements, 1 tuyere - public static final BlastFurnaceLayer THIN_REGULAR_TUYERE = new BlastFurnaceLayer("AA*AAAFTFAABABAAFBFAAAAAA"); - - // Fireproof bricks all around - public static final BlastFurnaceLayer THICK_REGULAR = new BlastFurnaceLayer("AAAAAABBBAABABAABBBAAAAAA"); - - // Fireproof bricks all around, 1 tuyere - public static final BlastFurnaceLayer THICK_REGULAR_TUYERE = new BlastFurnaceLayer("AA*AAABTBAABABAABBBAAAAAA"); - - // Reinforced walls + fireproof brick sides, corner blast furnace reinforcements - public static final BlastFurnaceLayer THIN_REINFORCED = new BlastFurnaceLayer("AARAAARBRARBABRARBRAAARAA"); - - // Reinforced walls + fireproof brick sides, corner blast furnace reinforcements, 1 tuyere - public static final BlastFurnaceLayer THIN_REINFORCED_TUYERE = new BlastFurnaceLayer("AA*AAARTRARBABRARBRAAARAA"); - - // Reinforced walls + fireproof bricks all around - public static final BlastFurnaceLayer THICK_REINFORCED = new BlastFurnaceLayer("ARRRARBBBRRBABRRBBBRARRRA"); - - // Reinforced walls + fireproof bricks all around, 1 tuyere - public static final BlastFurnaceLayer THICK_REINFORCED_TUYERE = new BlastFurnaceLayer("AR*RARBTBRRBABRRBBBRARRRA"); - - // Fireproof bricks + corner brick reinforcements, 1 output - public static final BlastFurnaceLayer THIN_REGULAR_OUTPUT = new BlastFurnaceLayer("AA*AAAFOFAABABAAFBFAAAAAA"); - - // Fireproof bricks all around, 1 output - public static final BlastFurnaceLayer THICK_REGULAR_OUTPUT = new BlastFurnaceLayer("AA*AAABOBAABABAABBBAAAAAA"); - - // Reinforced walls + fireproof brick sides, corner blast furnace reinforcements, 1 output - public static final BlastFurnaceLayer THIN_REINFORCED_BASE = new BlastFurnaceLayer("AA*AAARORARBABRARBRAAARAA"); - - // Reinforced walls + fireproof bricks all around, 1 output - public static final BlastFurnaceLayer THICK_REINFORCED_OUTPUT = new BlastFurnaceLayer("AR*RARBOBRRBABRRBBBRARRRA"); - -} diff --git a/src/main/java/com/drmangotea/tfmg/content/machinery/metallurgy/blast_furnace/BlastFurnaceOutputBlockEntity.java b/src/main/java/com/drmangotea/tfmg/content/machinery/metallurgy/blast_furnace/BlastFurnaceOutputBlockEntity.java index f4a58101..e27c8523 100644 --- a/src/main/java/com/drmangotea/tfmg/content/machinery/metallurgy/blast_furnace/BlastFurnaceOutputBlockEntity.java +++ b/src/main/java/com/drmangotea/tfmg/content/machinery/metallurgy/blast_furnace/BlastFurnaceOutputBlockEntity.java @@ -2,6 +2,7 @@ package com.drmangotea.tfmg.content.machinery.metallurgy.blast_furnace; import com.drmangotea.tfmg.base.TFMGUtils; import com.drmangotea.tfmg.config.TFMGConfigs; +import com.drmangotea.tfmg.content.machinery.metallurgy.blast_furnace.util.BlastFurnaceValidator; import com.drmangotea.tfmg.datagen.TFMGDamageSources; import com.drmangotea.tfmg.recipes.IndustrialBlastingRecipe; import com.drmangotea.tfmg.registry.TFMGBlocks; @@ -28,6 +29,7 @@ import net.minecraft.sounds.SoundEvents; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.item.ItemStack; +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.phys.AABB; @@ -66,6 +68,7 @@ public class BlastFurnaceOutputBlockEntity extends SmartBlockEntity implements I public static final int STORAGE_SPACE = 64; public LerpedFloat coalCokeHeight = LerpedFloat.linear(); boolean isReinforced = false; + boolean isActive = false; public BlastFurnaceOutputBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { @@ -112,10 +115,6 @@ public class BlastFurnaceOutputBlockEntity extends SmartBlockEntity implements I } } - public static int gcd(int a, int b) { - return b == 0 ? a : gcd(b, a % b); - } - private int calculateProcessingTime(IndustrialBlastingRecipe recipe) { int baseDuration = recipe.getProcessingDuration() * 20; double timeModifier = TFMGConfigs.common().machines.blastFurnaceMaxHeight.get() / @@ -215,8 +214,7 @@ public class BlastFurnaceOutputBlockEntity extends SmartBlockEntity implements I public void executeRecipe() { - RecipeWrapper inventoryIn = new RecipeWrapper(inputInventory); - Optional optional = TFMGRecipeTypes.INDUSTRIAL_BLASTING.find(inventoryIn, level); + Optional optional = TFMGRecipeTypes.INDUSTRIAL_BLASTING.find(new RecipeWrapper(inputInventory), level); if (optional.isEmpty()) return; @@ -240,6 +238,13 @@ public class BlastFurnaceOutputBlockEntity extends SmartBlockEntity implements I timer /= 2; } + private boolean isActuallyActive(IndustrialBlastingRecipe recipe) { + return timer > 0 && fuel > 0 + && (recipe.getFluidResults().isEmpty() || primaryTank.getSpace() >= recipe.getPrimaryResult().getAmount()) + && (recipe.getFluidResults().size() < 2 || secondaryTank.getSpace() >= recipe.getSecondaryResult().getAmount()) + && (recipe.hotAirUsage <= 0 || (tuyereBE != null && tuyereBE.tank.getFluidAmount() >= recipe.hotAirUsage && tuyereBE.tank.getFluid().getFluid().isSame(TFMGFluids.HOT_AIR.getSource()))); + } + @Override public void tick() { super.tick(); @@ -254,6 +259,8 @@ public class BlastFurnaceOutputBlockEntity extends SmartBlockEntity implements I if (getSize() < 3) return; + Optional optionalRecipe = TFMGRecipeTypes.INDUSTRIAL_BLASTING.find(new RecipeWrapper(inputInventory), level); + if (fuel <= 0 && !fuelInventory.getItem(0).isEmpty()) { ItemStack fuelStack = fuelInventory.getItem(0); if (fuelStack.is(TFMGTags.TFMGItemTags.BLAST_FURNACE_FUEL.tag)) { @@ -271,20 +278,16 @@ public class BlastFurnaceOutputBlockEntity extends SmartBlockEntity implements I } if (timer > -1) { - RecipeWrapper inventoryIn = new RecipeWrapper(inputInventory); - Optional optional = TFMGRecipeTypes.INDUSTRIAL_BLASTING.find(inventoryIn, level); - if (optional.isEmpty()) { + if (optionalRecipe.isEmpty()) { timer = -1; return; } - IndustrialBlastingRecipe recipe = optional.get(); + IndustrialBlastingRecipe recipe = optionalRecipe.get(); if (timer == 0) { if (canProcess(recipe)) { - int itemsUsed = 1; - int fluxUsed = 1; if (!(primaryTank.getSpace() >= recipe.getPrimaryResult().getAmount())) return; @@ -305,16 +308,24 @@ public class BlastFurnaceOutputBlockEntity extends SmartBlockEntity implements I setChanged(); } } - if (timer > 0 && fuel > 0) { - if (recipe.hotAirUsage > 0 && (tuyerePos == null || !level.getBlockState(tuyerePos).is(TFMGBlocks.BLAST_FURNACE_HATCH.get()))) { - tuyereBE = null; - return; - } - if (tuyereBE == null && tuyerePos != null) - tuyereBE = (BlastFurnaceHatchBlockEntity) level.getBlockEntity(tuyerePos); - if (tuyereBE.tank.getFluidAmount() < recipe.hotAirUsage || !tuyereBE.tank.getFluid().getFluid().isSame(TFMGFluids.HOT_AIR.getSource())) - return; + if (timer > 0 && fuel > 0) { + if (recipe.hotAirUsage > 0) { + if (tuyerePos == null || !level.getBlockState(tuyerePos).is(TFMGBlocks.BLAST_FURNACE_HATCH.get())) { + tuyereBE = null; + return; + } + + if (tuyereBE == null) { + if (!(level.getBlockEntity(tuyerePos) instanceof BlastFurnaceHatchBlockEntity hatch)) return; + tuyereBE = hatch; + } + + if (tuyereBE.tank.getFluidAmount() < recipe.hotAirUsage || + !tuyereBE.tank.getFluid().getFluid().isSame(TFMGFluids.HOT_AIR.getSource())) { + return; + } + } tuyereBE.tank.getFluidInTank(0).setAmount(Math.max(tuyereBE.tank.getFluidInTank(0).getAmount() - recipe.hotAirUsage, 0)); @@ -335,6 +346,7 @@ public class BlastFurnaceOutputBlockEntity extends SmartBlockEntity implements I } } } + isActive = optionalRecipe.map(this::isActuallyActive).orElse(false); } public void makeParticles() { @@ -348,14 +360,10 @@ public class BlastFurnaceOutputBlockEntity extends SmartBlockEntity implements I } private boolean canProcess(IndustrialBlastingRecipe recipe) { - //if (fuel == 0) - // return false; if (!primaryTank.getFluid().isEmpty() && !primaryTank.getFluid().getFluid().isSame(recipe.getPrimaryResult().getFluid())) return false; - if (!secondaryTank.getFluid().isEmpty() && !secondaryTank.getFluid().getFluid().isSame(recipe.getSecondaryResult().getFluid())) - return false; - return true; + return secondaryTank.getFluid().isEmpty() || secondaryTank.getFluid().getFluid().isSame(recipe.getSecondaryResult().getFluid()); } @Override @@ -479,88 +487,18 @@ public class BlastFurnaceOutputBlockEntity extends SmartBlockEntity implements I public int getSize() { - BlockPos middlePos = getBlockPos().relative(getBlockState().getValue(FACING).getOpposite()); - - tuyerePos = null; - - if ((isValidWall(middlePos) == FurnaceBlockType.NONE)) - return 0; - - int size = 0; - - int normalAmount = 0; - int reinforcedAmount = 0; - - for (int i = 0; i <= TFMGConfigs.common().machines.blastFurnaceMaxHeight.get(); i++) { - - BlockPos checkedPos = middlePos.above(i).east().south(); - - for (int j = 0; j < 3; j++) { - for (int y = 0; y < 3; y++) { - FurnaceBlockType wall = isValidWall(checkedPos); - FurnaceBlockType support = isValidSupport(checkedPos); - if (checkedPos.getX() == middlePos.getX() ^ checkedPos.getZ() == middlePos.getZ()) { - if (!(i == 0 && level.getBlockState(checkedPos).is(TFMGBlocks.BLAST_FURNACE_OUTPUT.get()))) { - if (wall == FurnaceBlockType.NONE) { - isReinforced = normalAmount == 0 && reinforcedAmount > 0; - return size; - } else { - if (wall == FurnaceBlockType.REGULAR) { - normalAmount++; - } else reinforcedAmount++; - } - } - } else if (checkedPos.getX() == middlePos.getX() && checkedPos.getZ() == middlePos.getZ()) { - if (!level.getBlockState(checkedPos).isAir() && i != 0) { - isReinforced = normalAmount == 0 && reinforcedAmount > 0; - - return size; - } - } else if (support == FurnaceBlockType.NONE) { - isReinforced = normalAmount == 0 && reinforcedAmount > 0; - return size; - } else { - if (support == FurnaceBlockType.REGULAR) { - normalAmount++; - } else reinforcedAmount++; - } - - checkedPos = checkedPos.west(); - } - checkedPos = checkedPos.north(); - checkedPos = checkedPos.east(3); - } - size++; + if (this.isRemoved()) { // Critical check + return 0; // Skip validation if block entity is destroyed } - return size; - } + // Create validator and validate the furnace structure + BlastFurnaceValidator validator = new BlastFurnaceValidator(getBlockPos(), level); + BlastFurnaceValidator.ValidationResult result = validator.validateFurnace(); - public FurnaceBlockType isValidWall(BlockPos pos) { + // Update entity state + this.isReinforced = result.isReinforced(); + this.tuyerePos = validator.getTuyerePos(); - BlockState state = level.getBlockState(pos); - - if (state.is(TFMGBlocks.BLAST_FURNACE_HATCH.get())) { - if (tuyerePos != null) - return FurnaceBlockType.NONE; - tuyerePos = pos; - } - - if (state.is(TFMGTags.TFMGBlockTags.REINFORCED_BLAST_FURNACE_WALL.tag)) - return FurnaceBlockType.REINFORCED; - if (state.is(TFMGTags.TFMGBlockTags.BLAST_FURNACE_WALL.tag)) - return FurnaceBlockType.REGULAR; - return FurnaceBlockType.NONE; - } - - public FurnaceBlockType isValidSupport(BlockPos pos) { - - BlockState state = level.getBlockState(pos); - - if (state.is(TFMGTags.TFMGBlockTags.REINFORCED_BLAST_FURNACE_SUPPORT.tag)) - return FurnaceBlockType.REINFORCED; - if (state.is(TFMGTags.TFMGBlockTags.BLAST_FURNACE_SUPPORT.tag)) - return FurnaceBlockType.REGULAR; - return FurnaceBlockType.NONE; + return result.height(); } @Nonnull @@ -572,11 +510,4 @@ public class BlastFurnaceOutputBlockEntity extends SmartBlockEntity implements I return fluidCapability.cast(); return super.getCapability(cap, side); } - - enum FurnaceBlockType { - NONE, - REGULAR, - REINFORCED - - } } diff --git a/src/main/java/com/drmangotea/tfmg/content/machinery/metallurgy/blast_furnace/BlastFurnaceRenderer.java b/src/main/java/com/drmangotea/tfmg/content/machinery/metallurgy/blast_furnace/BlastFurnaceRenderer.java index c9e9e731..cb1b4e60 100644 --- a/src/main/java/com/drmangotea/tfmg/content/machinery/metallurgy/blast_furnace/BlastFurnaceRenderer.java +++ b/src/main/java/com/drmangotea/tfmg/content/machinery/metallurgy/blast_furnace/BlastFurnaceRenderer.java @@ -4,8 +4,10 @@ import com.drmangotea.tfmg.registry.TFMGPartialModels; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; import com.simibubi.create.foundation.blockEntity.renderer.SafeBlockEntityRenderer; +import dev.engine_room.flywheel.lib.model.baked.PartialModel; import net.createmod.catnip.render.CachedBuffers; import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.client.renderer.LightTexture; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; @@ -23,18 +25,26 @@ public class BlastFurnaceRenderer extends SafeBlockEntityRenderer 0) if (be.getSize() >= 3) { - CachedBuffers.partial(TFMGPartialModels.COAL_COKE_DUST_LAYER, blockState) - .light(LevelRenderer.getLightColor(be.getLevel(), be.getBlockPos().above().relative(facing.getOpposite()))) + CachedBuffers.partial(cokeModel, blockState) + .light(lightLevel) .center() .rotateYDegrees(facing.getAxis() == Direction.Axis.X ? facing.getCounterClockWise().toYRot() : facing.getClockWise().toYRot()) .translateY(coalCokeLevel + 1.1f) diff --git a/src/main/java/com/drmangotea/tfmg/content/machinery/metallurgy/blast_furnace/reinforcement/BlastFurnaceReinforcementWallBlock.java b/src/main/java/com/drmangotea/tfmg/content/machinery/metallurgy/blast_furnace/reinforcement/BlastFurnaceReinforcementWallBlock.java index 1f4dfbc5..9febbf57 100644 --- a/src/main/java/com/drmangotea/tfmg/content/machinery/metallurgy/blast_furnace/reinforcement/BlastFurnaceReinforcementWallBlock.java +++ b/src/main/java/com/drmangotea/tfmg/content/machinery/metallurgy/blast_furnace/reinforcement/BlastFurnaceReinforcementWallBlock.java @@ -1,14 +1,9 @@ package com.drmangotea.tfmg.content.machinery.metallurgy.blast_furnace.reinforcement; -import com.drmangotea.tfmg.base.blocks.TFMGHorizontalDirectionalBlock; import com.drmangotea.tfmg.base.TFMGShapes; -import com.drmangotea.tfmg.registry.TFMGBlocks; +import com.drmangotea.tfmg.base.blocks.TFMGHorizontalDirectionalBlock; import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelReader; -import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; @@ -18,54 +13,8 @@ public class BlastFurnaceReinforcementWallBlock extends TFMGHorizontalDirectiona super(p_54120_); } - @Override - public void onPlace(BlockState blockState, Level level, BlockPos pos, BlockState blockState1, boolean b) { - changeFireproofBricks(level, pos, blockState.getValue(FACING).getOpposite(), true); - super.onPlace(blockState, level, pos, blockState1, b); - } - - @Override - public void onRemove(BlockState blockState, Level level, BlockPos pos, BlockState blockState1, boolean b) { - changeFireproofBricks(level, pos, blockState.getValue(FACING).getOpposite(), false); - super.onRemove(blockState, level, pos, blockState1, b); - } - @Override public VoxelShape getShape(BlockState p_60555_, BlockGetter p_60556_, BlockPos p_60557_, CollisionContext p_60558_) { return TFMGShapes.BLAST_FURNACE_REINFORCEMENT_WALL.get(p_60555_.getValue(FACING)); } - - @Override - public void neighborChanged(BlockState state, Level level, BlockPos pos, Block block, BlockPos neighbor, boolean b) { - - BlockState stateBehind = level.getBlockState(pos.relative(state.getValue(FACING).getOpposite())); - - if(stateBehind.is(TFMGBlocks.FIREPROOF_BRICKS.get())) - changeFireproofBricks((Level) level, pos, state.getValue(FACING).getOpposite(), true); - - - super.neighborChanged(state, level, pos, block, neighbor, b); - } - - @Override - public void onNeighborChange(BlockState state, LevelReader level, BlockPos pos, BlockPos neighbor) { - BlockState stateBehind = level.getBlockState(pos.relative(state.getValue(FACING).getOpposite())); - - if(stateBehind.is(TFMGBlocks.FIREPROOF_BRICKS.get())) - changeFireproofBricks((Level) level, pos, state.getValue(FACING).getOpposite(), false); - - super.onNeighborChange(state, level, pos, neighbor); - } - - public static void changeFireproofBricks(Level level, BlockPos pos, Direction direction, boolean reinforce){ - BlockState state = level.getBlockState(pos.relative(direction)); - if(reinforce&&state.is(TFMGBlocks.FIREPROOF_BRICKS.get())){ - level.setBlock(pos.relative(direction), TFMGBlocks.REINFORCED_FIREPROOF_BRICKS.getDefaultState(), 2); - } - if(!reinforce&&state.is(TFMGBlocks.REINFORCED_FIREPROOF_BRICKS.get())){ - - level.setBlock(pos.relative(direction), TFMGBlocks.FIREPROOF_BRICKS.getDefaultState(), 2); - } - - } } diff --git a/src/main/java/com/drmangotea/tfmg/content/machinery/metallurgy/blast_furnace/BlastFurnaceLayer.java b/src/main/java/com/drmangotea/tfmg/content/machinery/metallurgy/blast_furnace/util/BlastFurnaceLayer.java similarity index 53% rename from src/main/java/com/drmangotea/tfmg/content/machinery/metallurgy/blast_furnace/BlastFurnaceLayer.java rename to src/main/java/com/drmangotea/tfmg/content/machinery/metallurgy/blast_furnace/util/BlastFurnaceLayer.java index 3d728604..df7656a9 100644 --- a/src/main/java/com/drmangotea/tfmg/content/machinery/metallurgy/blast_furnace/BlastFurnaceLayer.java +++ b/src/main/java/com/drmangotea/tfmg/content/machinery/metallurgy/blast_furnace/util/BlastFurnaceLayer.java @@ -1,14 +1,7 @@ -package com.drmangotea.tfmg.content.machinery.metallurgy.blast_furnace; - -import com.drmangotea.tfmg.registry.TFMGBlocks; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.state.BlockState; +package com.drmangotea.tfmg.content.machinery.metallurgy.blast_furnace.util; +import java.util.Collections; import java.util.HashSet; -import java.util.Map; import java.util.Set; /** @@ -28,28 +21,21 @@ import java.util.Set; */ public class BlastFurnaceLayer { - private final Set validRotations; + private final Set layerRotations; + + public static final int LAYER_SIZE = 5; + public static final int LAYER_AREA = LAYER_SIZE * LAYER_SIZE; - private static final Map BLOCK_SYMBOLS = Map.of( - TFMGBlocks.BLAST_FURNACE_HATCH.get(), 'T', - TFMGBlocks.FIREPROOF_BRICKS.get(),'B', - TFMGBlocks.FIREPROOF_BRICK_REINFORCEMENT.get(), 'F', - TFMGBlocks.BLAST_FURNACE_REINFORCEMENT.get(), 'R', - TFMGBlocks.RUSTED_BLAST_FURNACE_REINFORCEMENT.get(), 'R', - TFMGBlocks.BLAST_FURNACE_REINFORCEMENT_WALL.get(), 'W', - TFMGBlocks.RUSTED_BLAST_FURNACE_REINFORCEMENT_WALL.get(), 'W', - TFMGBlocks.BLAST_FURNACE_OUTPUT.get(), 'O', - Blocks.AIR, 'A' - ); public BlastFurnaceLayer(String layer) { - if (layer == null || layer.length() != 25) { + if (layer == null || layer.length() != LAYER_AREA) { throw new IllegalArgumentException( - String.format("Layer must be a non-null 25 length string (got %s)", + String.format("Layer must be a non-null %s length string (got %s)", + LAYER_AREA, layer == null ? "null" : layer.length()) ); } - validRotations = computeRotations(layer); + layerRotations = Collections.unmodifiableSet(computeRotations(layer)); } private Set computeRotations(String baseLayer) { @@ -95,30 +81,44 @@ public class BlastFurnaceLayer { return new String(rotated); } - boolean isValidLayer(BlockPos center, Level level) { - String builtLayer = flattenLayer(center, level); - return validRotations.contains(builtLayer); + public boolean matchesAnyPattern(Set patterns) { + return patterns.stream().anyMatch(pattern -> + layerRotations.stream().anyMatch(rotation -> + matchesWithWildcards(rotation, pattern) + ) + ); } - /** - * Scans a 5x5 square of blocks in the world and converts it to a layer String. - * @param center center BlockPos of a layer. - * @param level Level (world). - * @return row-major String representation of the scanned layer. - */ - String flattenLayer(BlockPos center, Level level) { - int size = 5; // 5x5 layers max - StringBuilder sb = new StringBuilder(size * size); - for (int dz = -2; dz <= 2; dz++) { // Z = rows - for (int dx = -2; dx <= 2; dx++) { // X = columns - BlockPos pos = center.offset(dx, 0, dz); - sb.append(getBlockSymbol(level.getBlockState(pos))); + private boolean matchesWithWildcards(String actualLayer, String pattern) { + if (actualLayer.length() != pattern.length()) return false; + + for (int i = 0; i < actualLayer.length(); i++) { + char p = pattern.charAt(i); + char a = actualLayer.charAt(i); + + // '*' in pattern matches any character (including air) + if (p != '*' && p != a) { + return false; + } + if (pattern.contains("T") && !actualLayer.contains("T")) { + return false; // Tuyere required but missing + } + if (pattern.contains("O") && !actualLayer.contains("O")) { + return false; // Output required but missing } } - return sb.toString(); + return true; } - char getBlockSymbol(BlockState state) { - return BLOCK_SYMBOLS.getOrDefault(state.getBlock(), '*'); + public boolean isBaseLayer() { + return matchesAnyPattern(BlastFurnaceLayerPatterns.BASE_LAYERS); + } + + public boolean isWallLayer() { + return matchesAnyPattern(BlastFurnaceLayerPatterns.WALL_LAYERS); + } + + public boolean isReinforced() { + return matchesAnyPattern(BlastFurnaceLayerPatterns.REINFORCED_LAYERS); } } diff --git a/src/main/java/com/drmangotea/tfmg/content/machinery/metallurgy/blast_furnace/util/BlastFurnaceLayerPatterns.java b/src/main/java/com/drmangotea/tfmg/content/machinery/metallurgy/blast_furnace/util/BlastFurnaceLayerPatterns.java new file mode 100644 index 00000000..990ce3e5 --- /dev/null +++ b/src/main/java/com/drmangotea/tfmg/content/machinery/metallurgy/blast_furnace/util/BlastFurnaceLayerPatterns.java @@ -0,0 +1,130 @@ +package com.drmangotea.tfmg.content.machinery.metallurgy.blast_furnace.util; + +import java.util.Set; + +public final class BlastFurnaceLayerPatterns { + + // Fireproof bricks + corner brick reinforcements + public static final String THIN_REGULAR = + "*****" + // Row 1 + "*FBF*" + // Row 2 + "*BAB*" + // Row 3 + "*FBF*" + // Row 4 + "*****"; // Row 5 + + // Fireproof bricks + corner brick reinforcements, 1 tuyere + public static final String THIN_REGULAR_TUYERE = + "*****" + // Row 1 (wildcard for tuyere access) + "*FTF*" + // Row 2 (T = tuyere) + "*BAB*" + // Row 3 + "*FBF*" + // Row 4 + "*****"; // Row 5 + + // Fireproof bricks all around + public static final String THICK_REGULAR = + "*****" + // Row 1 + "*BBB*" + // Row 2 + "*BAB*" + // Row 3 + "*BBB*" + // Row 4 + "*****"; // Row 5 + + // Fireproof bricks all around, 1 tuyere + public static final String THICK_REGULAR_TUYERE = + "*****" + // Row 1 (wildcard for tuyere access) + "*BTB*" + // Row 2 (T = tuyere) + "*BAB*" + // Row 3 + "*BBB*" + // Row 4 + "*****"; // Row 5 + + // Reinforced walls + fireproof brick sides, corner blast furnace reinforcements + public static final String THIN_REINFORCED = + "**W**" + // Row 1 + "*RBR*" + // Row 2 + "WBABW" + // Row 3 + "*RBR*" + // Row 4 + "**W**"; // Row 5 + + // Reinforced walls + fireproof brick sides, corner blast furnace reinforcements, 1 tuyere + public static final String THIN_REINFORCED_TUYERE = + "*****" + // Row 1 (wildcard for tuyere access) + "*RTR*" + // Row 2 (T = tuyere) + "WBABW" + // Row 3 + "*RBR*" + // Row 4 + "**W**"; // Row 5 + + // Reinforced walls + fireproof bricks all around, 1 tuyere + public static final String THICK_REINFORCED = + "*WWW*" + // Row 1 + "WBBBW" + // Row 2 + "WBABW" + // Row 3 + "WBBBW" + // Row 4 + "*WWW*"; // Row 5 + + // Reinforced walls + fireproof bricks all around, 1 tuyere + public static final String THICK_REINFORCED_TUYERE = + "*W*W*" + // Row 1 (wildcard for tuyere access) + "WBTBW" + // Row 2 (T = tuyere) + "WBABW" + // Row 3 + "WBBBW" + // Row 4 + "*WWW*"; // Row 5 + + // Fireproof bricks + corner brick reinforcements, 1 output + public static final String THIN_REGULAR_OUTPUT = + "*****" + // Row 1 (wildcard for output access) + "*FOF*" + // Row 2 (O = output) + "*BBB*" + // Row 3 + "*FBF*" + // Row 4 + "*****"; // Row 5 + + // Fireproof bricks all around, 1 output + public static final String THICK_REGULAR_OUTPUT = + "*****" + // Row 1 (wildcard for output access) + "*BOB*" + // Row 2 (O = output) + "*BBB*" + // Row 3 + "*BBB*" + // Row 4 + "*****"; // Row 5 + + // Reinforced walls + fireproof brick sides, corner blast furnace reinforcements, 1 output + public static final String THIN_REINFORCED_OUTPUT = + "*****" + // Row 1 (wildcard for output access) + "*ROR*" + // Row 2 (O = output) + "WBBBW" + // Row 3 + "*RBR*" + // Row 4 + "**W**"; // Row 5 + + // Reinforced walls + fireproof bricks all around, 1 output + public static final String THICK_REINFORCED_OUTPUT = + "*W*W*" + // Row 1 (wildcard for output access) + "WBOBW" + // Row 2 (O = output) + "WBBBW" + // Row 3 + "WBBBW" + // Row 4 + "*WWW*"; // Row 5 + + public static final Set REINFORCED_LAYERS = Set.of( + THIN_REINFORCED, + THIN_REINFORCED_TUYERE, + THIN_REINFORCED_OUTPUT, + THICK_REINFORCED, + THICK_REINFORCED_TUYERE, + THICK_REINFORCED_OUTPUT + ); + + public static final Set BASE_LAYERS = Set.of( + THIN_REGULAR_OUTPUT, + THICK_REGULAR_OUTPUT, + THIN_REINFORCED_OUTPUT, + THICK_REINFORCED_OUTPUT + ); + + public static final Set WALL_LAYERS = Set.of( + THIN_REINFORCED, + THIN_REINFORCED_TUYERE, + THICK_REINFORCED, + THICK_REINFORCED_TUYERE, + THIN_REGULAR, + THIN_REGULAR_TUYERE, + THICK_REGULAR, + THICK_REGULAR_TUYERE + ); + +} diff --git a/src/main/java/com/drmangotea/tfmg/content/machinery/metallurgy/blast_furnace/util/BlastFurnaceValidator.java b/src/main/java/com/drmangotea/tfmg/content/machinery/metallurgy/blast_furnace/util/BlastFurnaceValidator.java new file mode 100644 index 00000000..92f26130 --- /dev/null +++ b/src/main/java/com/drmangotea/tfmg/content/machinery/metallurgy/blast_furnace/util/BlastFurnaceValidator.java @@ -0,0 +1,140 @@ +package com.drmangotea.tfmg.content.machinery.metallurgy.blast_furnace.util; + +import com.drmangotea.tfmg.config.TFMGConfigs; +import com.drmangotea.tfmg.registry.TFMGBlocks; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; + +import java.util.Map; + +import static com.drmangotea.tfmg.content.machinery.metallurgy.blast_furnace.util.BlastFurnaceLayer.LAYER_SIZE; +import static net.minecraft.world.level.block.HorizontalDirectionalBlock.FACING; + +public class BlastFurnaceValidator { + + private Level level; + private BlockPos tuyerePos; + private BlockPos outputPos; + private BlockPos startingOutputPos; + + private static final Map BLOCK_SYMBOLS = Map.of( + TFMGBlocks.BLAST_FURNACE_HATCH.get(), 'T', + TFMGBlocks.FIREPROOF_BRICKS.get(),'B', + TFMGBlocks.FIREPROOF_BRICK_REINFORCEMENT.get(), 'F', + TFMGBlocks.BLAST_FURNACE_REINFORCEMENT.get(), 'R', + TFMGBlocks.RUSTED_BLAST_FURNACE_REINFORCEMENT.get(), 'R', + TFMGBlocks.BLAST_FURNACE_REINFORCEMENT_WALL.get(), 'W', + TFMGBlocks.RUSTED_BLAST_FURNACE_REINFORCEMENT_WALL.get(), 'W', + TFMGBlocks.BLAST_FURNACE_OUTPUT.get(), 'O', + Blocks.AIR, 'A' + ); + + public BlastFurnaceValidator(BlockPos outputPos, Level levelIn) { + level = levelIn; + startingOutputPos = outputPos; + } + + public record ValidationResult(int height, boolean isReinforced) {} + public record LayerScanResult(String pattern, BlockPos tuyerePos, BlockPos outputPos) {} + + public ValidationResult validateFurnace() { + + // Early exit if the block is air or invalid + BlockState outputState = level.getBlockState(startingOutputPos); + if (!outputState.is(TFMGBlocks.BLAST_FURNACE_OUTPUT.get())) { + return new ValidationResult(0, false); + } + + resetState(); + + BlockPos baseCenterPos = startingOutputPos.relative(level.getBlockState(startingOutputPos).getValue(FACING).getOpposite()); + + // Validate base layer (must contain output) + LayerScanResult layerScan = scanLayer(baseCenterPos); + + // + BlastFurnaceLayer layer = new BlastFurnaceLayer(layerScan.pattern()); + + if (!layer.isBaseLayer() || !validSpecialBlocks(layerScan, true)) { + return new ValidationResult(0, false); + } + + int height = 1; + boolean isReinforced = layer.isReinforced(); + + // Validate stacked layers + int maxHeight = TFMGConfigs.common().machines.blastFurnaceMaxHeight.get(); + + for (int i = 1; i < maxHeight; i++) { + layerScan = scanLayer(baseCenterPos.above(i)); + layer = new BlastFurnaceLayer(layerScan.pattern()); + + if (!layer.isWallLayer() || !validSpecialBlocks(layerScan, false)) { + break; + } + + height++; + isReinforced &= layer.isReinforced(); + } + + return new ValidationResult(height, isReinforced); + } + + private void resetState() { + tuyerePos = null; + outputPos = null; + } + + /** + * Scans a 5x5 square of blocks in the world and converts it to a layer String. + * @param center center BlockPos of a layer. + * @return row-major String representation of the scanned layer. + */ + private LayerScanResult scanLayer(BlockPos center) { + StringBuilder pattern = new StringBuilder(25); + BlockPos tuyerePos = null; + BlockPos outputPos = null; + + for (int dz = -LAYER_SIZE / 2; dz <= LAYER_SIZE / 2; dz++) { // Z = rows + for (int dx = -LAYER_SIZE / 2; dx <= LAYER_SIZE / 2; dx++) { // X = columns + BlockPos pos = center.offset(dx, 0, dz); + char symbol = getBlockSymbol(level.getBlockState(pos)); + + if (symbol == 'T') tuyerePos = pos; + else if (symbol == 'O') outputPos = pos; + + pattern.append(symbol); + } + } + return new LayerScanResult(pattern.toString(), tuyerePos, outputPos); + } + + + + private boolean validSpecialBlocks(LayerScanResult scan, boolean isBaseLayer) { + // Handle output (only allowed in base layer) + if (scan.outputPos() != null) { + if (!isBaseLayer || outputPos != null) return false; // Output in wrong layer or duplicate + outputPos = scan.outputPos(); + } + + // Handle tuyere + if (scan.tuyerePos() != null) { + if (tuyerePos != null) return false; // Duplicate tuyere + tuyerePos = scan.tuyerePos(); + } + + return true; + } + + public BlockPos getTuyerePos() { + return tuyerePos; + } + + public static char getBlockSymbol(BlockState state) { + return BLOCK_SYMBOLS.getOrDefault(state.getBlock(), '*'); + } +} diff --git a/src/main/java/com/drmangotea/tfmg/content/machinery/metallurgy/coke_oven/CokeOvenRenderer.java b/src/main/java/com/drmangotea/tfmg/content/machinery/metallurgy/coke_oven/CokeOvenRenderer.java index 1ed0f4ca..6e462f15 100644 --- a/src/main/java/com/drmangotea/tfmg/content/machinery/metallurgy/coke_oven/CokeOvenRenderer.java +++ b/src/main/java/com/drmangotea/tfmg/content/machinery/metallurgy/coke_oven/CokeOvenRenderer.java @@ -2,33 +2,78 @@ package com.drmangotea.tfmg.content.machinery.metallurgy.coke_oven; import com.drmangotea.tfmg.registry.TFMGBlocks; import com.drmangotea.tfmg.registry.TFMGPartialModels; -import dev.engine_room.flywheel.lib.model.baked.PartialModel; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.foundation.blockEntity.renderer.SafeBlockEntityRenderer; +import dev.engine_room.flywheel.lib.model.baked.PartialModel; import net.createmod.catnip.render.CachedBuffers; import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.client.renderer.LightTexture; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; import net.minecraft.core.Direction; import net.minecraft.world.level.block.state.BlockState; -import static net.minecraft.world.level.block.HorizontalDirectionalBlock.FACING; import static com.drmangotea.tfmg.content.machinery.metallurgy.coke_oven.CokeOvenBlock.CONTROLLER_TYPE; +import static net.minecraft.world.level.block.HorizontalDirectionalBlock.FACING; public class CokeOvenRenderer extends SafeBlockEntityRenderer { + + public CokeOvenRenderer(BlockEntityRendererProvider.Context context) {} + @Override protected void renderSafe(CokeOvenBlockEntity be, float partialTicks, PoseStack ms, MultiBufferSource buffer, int light, int overlay) { + BlockState blockState = be.getBlockState(); - if(be.getLevel().getBlockState(be.getBlockPos().relative(blockState.getValue(FACING))).is(TFMGBlocks.COKE_OVEN.get())) + + if (be.getLevel() == null) return; + + if (be.getLevel().getBlockState(be.getBlockPos().relative(blockState.getValue(FACING))).is(TFMGBlocks.COKE_OVEN.get())) return; + + renderDoors(be, ms, buffer); + renderFire(be, ms, buffer); + + } + + private void renderFire(CokeOvenBlockEntity be, PoseStack ms, MultiBufferSource buffer) { + BlockState state = be.getBlockState(); + + // Pick model variant based on controller type + PartialModel fireModel = switch (state.getValue(CONTROLLER_TYPE)) { + case TOP_ON -> TFMGPartialModels.COKE_OVEN_FIRE_TOP; + case MIDDLE_ON -> TFMGPartialModels.COKE_OVEN_FIRE_MIDDLE; + case BOTTOM_ON -> TFMGPartialModels.COKE_OVEN_FIRE_BOTTOM; + default -> null; + }; + + if (fireModel == null) + return; + + ms.pushPose(); + + // Fullbright animated fire + CachedBuffers.partial(fireModel, state) + .light(LightTexture.FULL_BRIGHT) + .center() + .rotateYDegrees(state.getValue(FACING).getAxis() == Direction.Axis.Z ? Math.abs(state.getValue(FACING).toYRot()-180) : state.getValue(FACING).toYRot()) + .uncenter() + .renderInto(ms, buffer.getBuffer(RenderType.translucent())); + + ms.popPose(); + } + + private void renderDoors(CokeOvenBlockEntity be, PoseStack ms, MultiBufferSource buffer) { + + BlockState state = be.getBlockState(); int lightInFront = LevelRenderer.getLightColor(be.getLevel(), be.getBlockPos().relative(be.getBlockState().getValue(FACING))); + PartialModel right_door = TFMGPartialModels.COKE_OVEN_DOOR_RIGHT; PartialModel left_door = TFMGPartialModels.COKE_OVEN_DOOR_LEFT; - switch (blockState.getValue(CONTROLLER_TYPE)){ + switch (state.getValue(CONTROLLER_TYPE)){ case TOP_ON -> { right_door = TFMGPartialModels.COKE_OVEN_DOOR_RIGHT_TOP; left_door = TFMGPartialModels.COKE_OVEN_DOOR_LEFT_TOP; @@ -44,21 +89,24 @@ public class CokeOvenRenderer extends SafeBlockEntityRenderer {} } - CachedBuffers.partial(right_door, blockState) - .light(lightInFront) - .center() - .rotateYDegrees(blockState.getValue(FACING).getAxis() == Direction.Axis.Z ? Math.abs(blockState.getValue(FACING).toYRot()-180) : blockState.getValue(FACING).toYRot()) - .translateZ(-0.5f) - .translateX(-0.5f) - .rotateYDegrees(be.doorAngle.getValue()) - .translateZ(0.5f) - .translateX(0.5f) - .uncenter() - .renderInto(ms, buffer.getBuffer(RenderType.cutoutMipped())); - CachedBuffers.partial(left_door, blockState) - .light(lightInFront) + ms.pushPose(); + CachedBuffers.partial(right_door, state) + .light(lightInFront) .center() - .rotateYDegrees(blockState.getValue(FACING).getAxis() == Direction.Axis.Z ? Math.abs(blockState.getValue(FACING).toYRot()-180) : blockState.getValue(FACING).toYRot()) + .rotateYDegrees(state.getValue(FACING).getAxis() == Direction.Axis.Z ? Math.abs(state.getValue(FACING).toYRot()-180) : state.getValue(FACING).toYRot()) + .translateZ(-0.5f) + .translateX(-0.5f) + .rotateYDegrees(be.doorAngle.getValue()) + .translateZ(0.5f) + .translateX(0.5f) + .uncenter() + .renderInto(ms, buffer.getBuffer(RenderType.cutoutMipped())); + ms.popPose(); + ms.pushPose(); + CachedBuffers.partial(left_door, state) + .light(lightInFront) + .center() + .rotateYDegrees(state.getValue(FACING).getAxis() == Direction.Axis.Z ? Math.abs(state.getValue(FACING).toYRot()-180) : state.getValue(FACING).toYRot()) .translateZ(-0.5f) .translateX(0.5f) .rotateYDegrees(-be.doorAngle.getValue()) @@ -66,8 +114,7 @@ public class CokeOvenRenderer extends SafeBlockEntityRenderer>)' is deprecated and marked for removal ") public static final BlockEntry FIREBOX = REGISTRATE.block("firebox", FireboxBlock::new) @@ -781,16 +782,6 @@ public class TFMGBlocks { .build() .register(); - public static final BlockEntry REINFORCED_FIREPROOF_BRICKS = REGISTRATE.block("reinforced_fireproof_bricks", Block::new) - .initialProperties(() -> Blocks.NETHER_BRICKS) - .properties(p -> p.requiresCorrectToolForDrops()) - .transform(pickaxeOnly()) - .tag(TFMGTags.TFMGBlockTags.REINFORCED_BLAST_FURNACE_WALL.tag) - .tag(BlockTags.NEEDS_STONE_TOOL) - .blockstate(simpleCubeAll("fireproof_bricks")) - .loot((lt, block) -> lt.dropOther(block, TFMGBlocks.FIREPROOF_BRICKS.get().asItem())) - .register(); - public static final BlockEntry BLAST_FURNACE_REINFORCEMENT = REGISTRATE.block("blast_furnace_reinforcement", Block::new) .initialProperties(() -> Blocks.IRON_BLOCK) .properties(p -> p.requiresCorrectToolForDrops()) @@ -858,6 +849,7 @@ public class TFMGBlocks { .item() .transform(customItemModel()) .register(); + @SuppressWarnings("'addLayer(java.util.function.Supplier>)' is deprecated and marked for removal ") public static final BlockEntry BLAST_STOVE = REGISTRATE.block("blast_stove", BlastStoveBlock::new) diff --git a/src/main/java/com/drmangotea/tfmg/registry/TFMGPartialModels.java b/src/main/java/com/drmangotea/tfmg/registry/TFMGPartialModels.java index ac9eb3be..efc7a3b3 100644 --- a/src/main/java/com/drmangotea/tfmg/registry/TFMGPartialModels.java +++ b/src/main/java/com/drmangotea/tfmg/registry/TFMGPartialModels.java @@ -25,6 +25,9 @@ public class TFMGPartialModels { AIR_INTAKE_FRAME_CLOSED = block("air_intake/frame_closed"), AIR_INTAKE_MEDIUM = block("air_intake/block_medium"), AIR_INTAKE_LARGE = block("air_intake/block_large"), + COKE_OVEN_FIRE_BOTTOM = block("coke_oven/fire_bottom"), + COKE_OVEN_FIRE_MIDDLE = block("coke_oven/fire_middle"), + COKE_OVEN_FIRE_TOP = block("coke_oven/fire_top"), COKE_OVEN_DOOR_LEFT = block("coke_oven/door_left"), COKE_OVEN_DOOR_RIGHT = block("coke_oven/door_right"), COKE_OVEN_DOOR_LEFT_BOTTOM = block("coke_oven/door_left_bottom"), @@ -34,6 +37,7 @@ public class TFMGPartialModels { COKE_OVEN_DOOR_LEFT_TOP = block("coke_oven/door_left_top"), COKE_OVEN_DOOR_RIGHT_TOP = block("coke_oven/door_right_top"), COAL_COKE_DUST_LAYER = block("coal_coke_dust_layer"), + COAL_COKE_DUST_LAYER_GLOWING = block("coal_coke_dust_layer_glowing"), POLARIZER_DIAL = block("polarizer/dial"), STEEL_FLYWHEEL = block("steel_flywheel/block"), ALUMINUM_FLYWHEEL = block("aluminum_flywheel/block"), @@ -169,4 +173,4 @@ public class TFMGPartialModels { public static void init() { } -} \ No newline at end of file +} diff --git a/src/main/resources/assets/tfmg/models/block/coal_coke_dust_layer_glowing.json b/src/main/resources/assets/tfmg/models/block/coal_coke_dust_layer_glowing.json new file mode 100644 index 00000000..b8c614e8 --- /dev/null +++ b/src/main/resources/assets/tfmg/models/block/coal_coke_dust_layer_glowing.json @@ -0,0 +1,20 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "0": "tfmg:block/coal_coke_dust_glowing", + "particle": "tfmg:block/coal_coke_dust_glowing" + }, + "elements": [ + { + "from": [0, 0.1, 0], + "to": [16, 0.1, 16], + "faces": { + "north": {"uv": [0, 0, 16, 0], "texture": "#0"}, + "east": {"uv": [0, 0, 16, 0], "texture": "#0"}, + "south": {"uv": [0, 0, 16, 0], "texture": "#0"}, + "west": {"uv": [0, 0, 16, 0], "texture": "#0"}, + "up": {"uv": [0, 0, 16, 16], "texture": "#0"} + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/tfmg/models/block/coke_oven/fire_bottom.json b/src/main/resources/assets/tfmg/models/block/coke_oven/fire_bottom.json new file mode 100644 index 00000000..a958c259 --- /dev/null +++ b/src/main/resources/assets/tfmg/models/block/coke_oven/fire_bottom.json @@ -0,0 +1,18 @@ +{ + "format_version": "1.21.6", + "credit": "Made with Blockbench", + "textures": { + "0": "tfmg:block/coke_oven/coke_oven_front_bottom_fire", + "particle": "tfmg:block/coke_oven/coke_oven_front_bottom_fire" + }, + "elements": [ + { + "from": [4, 4, -0.1], + "to": [12, 16, -0.1], + "rotation": {"angle": 0, "axis": "y", "origin": [14, 0, -2]}, + "faces": { + "north": {"uv": [5, 0, 11, 12], "texture": "#0"} + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/tfmg/models/block/coke_oven/fire_middle.json b/src/main/resources/assets/tfmg/models/block/coke_oven/fire_middle.json new file mode 100644 index 00000000..07b65f61 --- /dev/null +++ b/src/main/resources/assets/tfmg/models/block/coke_oven/fire_middle.json @@ -0,0 +1,18 @@ +{ + "format_version": "1.21.6", + "credit": "Made with Blockbench", + "textures": { + "0": "tfmg:block/coke_oven/coke_oven_front_middle_fire", + "particle": "tfmg:block/coke_oven/coke_oven_front_middle_fire" + }, + "elements": [ + { + "from": [4, 0, -0.1], + "to": [12, 16, -0.1], + "rotation": {"angle": 0, "axis": "y", "origin": [14, 0, -2]}, + "faces": { + "north": {"uv": [5, 0, 11, 16], "texture": "#0"} + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/tfmg/models/block/coke_oven/fire_top.json b/src/main/resources/assets/tfmg/models/block/coke_oven/fire_top.json new file mode 100644 index 00000000..364c385a --- /dev/null +++ b/src/main/resources/assets/tfmg/models/block/coke_oven/fire_top.json @@ -0,0 +1,18 @@ +{ + "format_version": "1.21.6", + "credit": "Made with Blockbench", + "textures": { + "0": "tfmg:block/coke_oven/coke_oven_front_top_fire", + "particle": "tfmg:block/coke_oven/coke_oven_front_top_fire" + }, + "elements": [ + { + "from": [4, 0, -0.1], + "to": [12, 9, -0.1], + "rotation": {"angle": 0, "axis": "y", "origin": [14, 0, -2]}, + "faces": { + "north": {"uv": [5, 7, 11, 16], "texture": "#0"} + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/tfmg/textures/block/coal_coke_dust_glowing.png b/src/main/resources/assets/tfmg/textures/block/coal_coke_dust_glowing.png new file mode 100644 index 0000000000000000000000000000000000000000..4eb96c38ccadb81083af8e1dc7f0d8f0bf266a69 GIT binary patch literal 474 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPF*AN9$JwrVU>C9IvfNHj-MtG)qdTKFn06DA-QjDw& zj6jwb5KBYZAa`jnGK0mLfNVoXCa}Y!fb7h67O;30kPQN#$`~150R01_(JW;EN=;yA zU;(N$Ffuk^TmUf@WFzYWh)Gj`Y!F}qn#%-M8DwbzWI=Tq8W@0N&*X{Kcm=M?wKX}zWWx6p&1cdB#zS6iLeuIm56tDySkJTCoCZPkg3jJIl+ icok=|Z8S{f`NueM2miY-vdeFPT;b{J=d#Wzp$P!W&3qLA literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/tfmg/textures/block/coke_oven/coke_oven_front_bottom_fire.png b/src/main/resources/assets/tfmg/textures/block/coke_oven/coke_oven_front_bottom_fire.png new file mode 100644 index 0000000000000000000000000000000000000000..8a7e3529cf5238194d2c3ae7bc3df88678a54a5b GIT binary patch literal 555 zcmeAS@N?(olHy`uVBq!ia0vp^0ze$V!3-qTOIhuK6k~CayA#8@b22Z19F}xPUq=Rp zjs4tz5?O(Kp#Yx{*Z-}o|C3q&?@IW8Z_fXZM}Wd#EImVk6kAD+ zXMsm#F#`i1kj=NB(SkKt1t=&{;u=vBoS#-wo>-L15RjOeSEA?V8lqsTXQ*c(o%w17 zP|dc~2+uT6Pb~%xAcvJfijkFp5yEak-;eU0?L9QbTJTAvw{{NqDuBMlrv|?@hp=An( z7t1|cxaccmfWe}*3z#;o(0bP0l+XkKjDVtP literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/tfmg/textures/block/coke_oven/coke_oven_front_bottom_fire.png.mcmeta b/src/main/resources/assets/tfmg/textures/block/coke_oven/coke_oven_front_bottom_fire.png.mcmeta new file mode 100644 index 00000000..f5ea2c88 --- /dev/null +++ b/src/main/resources/assets/tfmg/textures/block/coke_oven/coke_oven_front_bottom_fire.png.mcmeta @@ -0,0 +1,6 @@ +{ + "animation": { + "frametime": 2, + "interpolate": true + } +} \ No newline at end of file diff --git a/src/main/resources/assets/tfmg/textures/block/coke_oven/coke_oven_front_bottom_off.png b/src/main/resources/assets/tfmg/textures/block/coke_oven/coke_oven_front_bottom_off.png index 8e438bb5aaff2ccc869466e25ae21a0004d44d9a..7bba5e383e5f841bb110b8b57fb9d7c29bfcd2c3 100644 GIT binary patch delta 370 zcmZo>dcZuvv0gpEC&bm**epLY)6>(hwz86efgv#=K~-5*TU+1V&CAEfComu&DJjj? z#$n#iD~v#C&H|6fVg?4j{UFR}!5XXr6qG1&jVKAuPb(=;EJ|evNX*PD(erZ+Q83jr z)U%Mze6<3oW?O26XPT#{76S*6!^$AV$jVR;GSCZ%rGXp}I|zt17@5IrCLr68k%>V7 zNJjy2W;+X5JPXJMfn{Zk3@?}wG@7jpK&c7r3@kvE21dpPj0+&9f^1=305NHbA&>(C zOhAK~z)FKGEr2YjHbVmgknAJR(uwCCralHTV(hwz86ggCj8^K~-5*TU+1V&CAEfComu&DJhMg zU%=MJfm87PS_TFN&H|6fVg?4jgCNYfV`BDOpkUJE0!Awv29bw_g_aB=iEq~Jt^WRt xZ^62}#N=dWh34p_XYcMBOPd?qVQt=B&Zv{4cIU<&FD0Nx22WQ%mvv4FO#mdoFx>zE diff --git a/src/main/resources/assets/tfmg/textures/block/coke_oven/coke_oven_front_bottom_on.png b/src/main/resources/assets/tfmg/textures/block/coke_oven/coke_oven_front_bottom_on.png index dccdf267e345b8111e92db0d3f3a36c998130211..1b1ca6ed5e12630f6c908dc0b6c0e22c06011523 100644 GIT binary patch delta 376 zcmV-;0f+wU1lt6V7YYyv0{{R3C@l|Dks%;|Y*0*8MKd!tZ)s^sNltxvc`GX~|7s8a zYY+cy5C3ZrVq#|hfGhuhEB}8iB_k#Ol}G=SNB@&YM@CBjsbc@BWB;gPQBY9-zJC9` zfB(FH|Gt0!(whI$oBz|A|IwTO=eGanxBuq1|MA2)fZz$|H5ZujLuaxNVO_@{sQ_XgCg zD1@+vPhFewt?7nE2dy-}jSa*z?QKE_NPmrd$gze?T?LReXh6ZHq;gWS$Q{k@iSY++ Wg$}&ypP{1w0000N2bPDNB8H7+qOG?QQfNq?R%@1r3&@_zsT0NzPNK~yNuV_;Nv z4NVO(5@29gbd5-D5h`HdoZmIZKuJLZqJPx#07*qoM6N<$f~hZ@SO5S3 diff --git a/src/main/resources/assets/tfmg/textures/block/coke_oven/coke_oven_front_bottom_on.png.mcmeta b/src/main/resources/assets/tfmg/textures/block/coke_oven/coke_oven_front_bottom_on.png.mcmeta deleted file mode 100644 index 4f0718ac..00000000 --- a/src/main/resources/assets/tfmg/textures/block/coke_oven/coke_oven_front_bottom_on.png.mcmeta +++ /dev/null @@ -1,3 +0,0 @@ -{ - "animation": {} -} \ No newline at end of file diff --git a/src/main/resources/assets/tfmg/textures/block/coke_oven/coke_oven_front_middle_fire.png b/src/main/resources/assets/tfmg/textures/block/coke_oven/coke_oven_front_middle_fire.png new file mode 100644 index 0000000000000000000000000000000000000000..75fc9dfe50f8d7f4acdd46447cf908cd6373c1ce GIT binary patch literal 562 zcmeAS@N?(olHy`uVBq!ia0vp^0ze$V!3-qTOIhuK6k~CayA#8@b22Z19F}xPUq=Rp zjs4tz5?O(Kp#Yx{*Z;|^|Ls`+x3ZpAmbj%Q3>5zVWX&xg#a0sJ7yKUt7&h-;vL7hI zS>O>_%)r10Wb^H3v|tTZ0SZc#xJHx&=ckpFCl;kL1SDqWmFW4ohA5co8R}U`XTDki zRI@EL!ZXd&Q;UHE$YEuWVq|4t1hTw2!0mM|0jjRhGCQSjdL4XNpE)!T~kfjBX z1=VF}U;vUm9mSRL-01}{$QU+yx;Tbd`0t$($aO@4$3bapD8BD7jrr(TXc*&#Euxu^UC71ngMID$KZ!*d;bjypC$_wu3uU&p> z!KcP~mkvF8&3DJ0Mb4hlAma4dR}c8@csBGKEdDl8bYAV6jgkGC${Tc8-d&bUS7>0j zQ#pR#&L`aFR5QOue7mXH>znRBmik0DUw?NTXhzR@yB~iq@SJd0ebM{F-ryMf%se5J Ton609gFNEt>gTe~DWM4fi%y-b literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/tfmg/textures/block/coke_oven/coke_oven_front_middle_fire.png.mcmeta b/src/main/resources/assets/tfmg/textures/block/coke_oven/coke_oven_front_middle_fire.png.mcmeta new file mode 100644 index 00000000..f5ea2c88 --- /dev/null +++ b/src/main/resources/assets/tfmg/textures/block/coke_oven/coke_oven_front_middle_fire.png.mcmeta @@ -0,0 +1,6 @@ +{ + "animation": { + "frametime": 2, + "interpolate": true + } +} \ No newline at end of file diff --git a/src/main/resources/assets/tfmg/textures/block/coke_oven/coke_oven_front_middle_off.png b/src/main/resources/assets/tfmg/textures/block/coke_oven/coke_oven_front_middle_off.png index f963f780c234c1463053bbd8b201b0db9f34f465..b8a2a7a857631227a4f8dfdf9b213fd531550f03 100644 GIT binary patch delta 288 zcmaFJc$|4cP(1?!Lt;XLsV7NJjy2W;+X5JPXJMfn{Zk3@?}wG@7jp zK&c7r3@kvE21dpPj0>2-xgCZG%xSY?o<1&}2M)n;g50Fr*>Svv8& K!_>zU8xjGuTQVvD delta 57 zcmX@k{E%@%kRAsIM`A*Psc_n&&t|1DhdWL!y zlNA{~vrk8HWjuF!;Rv+N+tbA{MB;LCLP!}eFR!6cLP9W$VT+K&jnj@jpP1SXnF%O6 z&skWY)S;+(F2F|e$OaR4gHzKQB_dyPuq~6?QMRM8K>NWor#Xo#3=AH#)PJur719S9 O%i!ti=d#Wzp$PzQ0!WLJ zJ_Y}U13+q*4i{b^!qB0{{S~ zk^dC|G?NtpNq?R%@1r3&@_zsT0PsmfK~yNuozk%ifS^M=-| z4sN|T!RL_H=7>m~a+eEwf=2NvdW-(r-AQT~ZQnt?55E(QW>_*hA0x*PASMUoW`SZf zyP)K;%9%KMC@HF#dMGV}n2F`0jZ{k$(}bpV5&NWXmbMo;=8QL*avN zh9Tex$FBko1qK8#Di1dvZaw1dQC~fHuRT~r#uHhO&>k+{9%(%CFOO_IwDtsDk78X9 z)gEs4;e-2-#QV0J5OE3=IrG zvZtfCGM+oV00tMsL{AsT5DWjSmjd}(6nIzyy6*fxQ>L*tAWKC}D%Z^7_lI<;;KI*( zH(a?p=L?ByF#J=zD$L-#O8x8v*(Y;u8ZiB-Z^@Hm-5tTMr?ipr*0%{Ze=_CGxXKFI zG?X^Z6^wb)e7cI`+s3OJ7tXFO*wNJK6jHCj{^CBzH%IN?KMs92y#9Q-3+s0N0|9ye g>|R{6;|Ms#cf?b0-M?13?;wYIy85}Sb4q9e0AMkSpa1{> literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/tfmg/textures/block/coke_oven/coke_oven_front_top_fire.png.mcmeta b/src/main/resources/assets/tfmg/textures/block/coke_oven/coke_oven_front_top_fire.png.mcmeta new file mode 100644 index 00000000..f5ea2c88 --- /dev/null +++ b/src/main/resources/assets/tfmg/textures/block/coke_oven/coke_oven_front_top_fire.png.mcmeta @@ -0,0 +1,6 @@ +{ + "animation": { + "frametime": 2, + "interpolate": true + } +} \ No newline at end of file diff --git a/src/main/resources/assets/tfmg/textures/block/coke_oven/coke_oven_front_top_off.png b/src/main/resources/assets/tfmg/textures/block/coke_oven/coke_oven_front_top_off.png index dd86326c14c95e374dcce19bd96e61134f6422e0..3c43a8918fef30759b1e8f8bd04b86022c0444bf 100644 GIT binary patch delta 389 zcmey*c$ayCW4(HSPl&6njf1hVSyED3erBe-o0pG|Pil*XMsm#F#`kNeh_A~U=3CQ3QCl?MwA5SrRCu_7y>yU zzyvgy39K~8(gMhWYBMx20Leb`ES-4XVd`TbGjd|Disu~5;v{$F<^Y3^#8n)kD>G6i z+~N_7JfX0M_lO7UE3U&QCls+6`iLoI+VdpcVAv|pY*@s@XtPY4SJ$vu24tY8tDnm{ Hr-UW|lT}ja delta 166 zcmcc1{GV}xqmNdAPl&6njf1hVSyED3erBe-o0pG|Pi9?DsWhA#b2q8iP;p445AbnI8?99u1==3!)|rqb3YdP*AQc z3#}~*tt|_zEeowJ47fB3xibp4Gz!8y3Bo!G!a51VItk4}3CuzX&Or&yLI})42-it6 z2-ryn*hvWEPzT~q2jfo%;!y_UPzFg!PVH9)>{kcuR|fc92KQYC_g)6~UInj=svD7j zGzB;tY3itvxo`nElPUp8f6H15Xy-!cK>z>%uSrBfR47wrjc*%)Fce33ciV0%ij)u{ z|AkWW{lA&5<(1#7J?A+)m;DVmT0(F&AuQy;04mLOvt8C8>Z+~?%Pv|JNykXCg@-ziB65pnSlPdvm z0W_1G0ZD(iJdj!mI*;7|009L_L_t(IPtDX}Zv!C+24Dd_6ga*9|3ABMw(IFNYqzXP z{rHApc!Gv7A3%yJAtI&}2_XPQq-8&Zk$S+rn0t^jLy=On0Ot$=FcB2dA_XXUkG(=w z?iG{Lq`vL=Fx+@hw9lw%?=)R3_jdLW)JmgfACNb^yo3~ zhmWtn^k~gq@VLCeLk16>JVdpO9<~D=Jp8>3`|-%*`+0bNS%G}r0G|+7Jy|hlT?Jng#Y6{rRdGR66-jkT;ao%8kE=_kczEoH33^bS^#4+C ztcEdA$EK3MoIr}dB*-uLKMG*Da%aXupcH3;M`SSr1K(i~W;~w1A_XWYQQ{g=5}cn_ zQl40p$`Fv4nOCCc=Nh75s%NNYA)WbZ1yIel)CkWsPfsld4j_k>L5h);ff2~^0%B<> z8{|U`MrN=$$d87MOkf{J0oj@DEMW00AR7c0PiA0v0aOH|(JW;EN=;yAU;(N$Ffuk^ zTmUf@WFzYWh)Gj`Y!F}qn#%-M8DwbzWI=Tq8W@0Ncgb5g|LoE01Trf@~z+SMR6kKN%hlS+VUP%Dck!-^IWjRU-b zCj-)i43;{!>^Sf$dDd*-*U!Daf82MtwoXstSzhri#xvIo%Qh6e?MQ6ah&ucJ<|;YU lOB)XUlWG4p=e&P*En|Te$Ar%4hXEi5dAj* zpeE3h75k45qpODlkfgJ&!hc^A#s7&8@?Z>N!!SrrRa_9$0FXvg6-lrnbxC0`hS>(= zgXBPJFbn`Gg4qC42vUTMVVXf0Lo-MK=451NqdOm~(?J3t40Ap<43dMXL(vQZxrVm? zKdvtQKgGl2|BjfT{|~B@z%&TM#6W7$^??CM0;B} c)vuHQ0Q4XUE=$sHy#N3J07*qoM6N<$f)Q+NWB>pF