diff --git a/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/GTToolType.java b/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/GTToolType.java index f73c15960d..d2cf8c523b 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/GTToolType.java +++ b/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/GTToolType.java @@ -26,7 +26,6 @@ public enum GTToolType { SHOVEL("shovel", "shovels", 1.5F, -3.0F, true), AXE("axe", "axes", 6.0F, -3.2F, true), HOE("hoe", "hoes", 0, -3.0F, true), - SAW("saw", "saws", 1, 1, GTSoundEntries.SAW_TOOL), HARD_HAMMER("hammer", "hammers", 1, 1, GTSoundEntries.FORGE_HAMMER), SOFT_MALLET("mallet", "mallets", 1, 1, GTSoundEntries.SOFT_MALLET_TOOL), diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/data/GTMachines.java b/common/src/main/java/com/gregtechceu/gtceu/common/data/GTMachines.java index ae222055ba..b783629704 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/common/data/GTMachines.java +++ b/common/src/main/java/com/gregtechceu/gtceu/common/data/GTMachines.java @@ -23,7 +23,6 @@ import com.gregtechceu.gtceu.api.registry.GTRegistries; import com.gregtechceu.gtceu.api.registry.registrate.MachineBuilder; import com.gregtechceu.gtceu.api.registry.registrate.MultiblockMachineBuilder; -import com.gregtechceu.gtceu.client.renderer.block.CTMModelRenderer; import com.gregtechceu.gtceu.client.renderer.machine.*; import com.gregtechceu.gtceu.common.block.BoilerFireboxType; import com.gregtechceu.gtceu.common.machine.electric.*; @@ -243,6 +242,34 @@ public class GTMachines { .register(), LV, MV, HV, EV); + public final static MachineDefinition[] FISHER = registerTieredMachines("fisher", FisherMachine::new, + (tier, builder) -> builder + .rotationState(RotationState.NON_Y_AXIS) + .editableUI(FisherMachine.EDITABLE_UI_CREATOR.apply(GTCEu.id("fisher"), (tier + 1) * (tier + 1))) + .renderer(() -> new TieredHullMachineRenderer(tier, GTCEu.id("block/machine/fisher_machine"))) + .langValue("%s Fisher %s".formatted(VLVH[tier], VLVT[tier])) + .tooltips(Component.translatable("gtceu.machine.fisher.tooltip"), + Component.translatable("gtceu.machine.fisher.speed", 1000 - tier * 200L), + Component.translatable("gtceu.machine.fisher.requirement", FisherMachine.WATER_CHECK_SIZE,FisherMachine.WATER_CHECK_SIZE), + Component.translatable("gtceu.universal.tooltip.voltage_in", GTValues.V[tier], GTValues.VNF[tier]), + Component.translatable("gtceu.universal.tooltip.energy_storage_capacity", GTValues.V[tier] * 64)) + .register(), + LV, MV, HV, EV); + + public final static MachineDefinition[] BLOCK_BREAKER = registerTieredMachines("block_breaker", BlockBreakerMachine::new, + (tier, builder) -> builder + .rotationState(RotationState.NON_Y_AXIS) + .editableUI(BlockBreakerMachine.EDITABLE_UI_CREATOR.apply(GTCEu.id("block_breaker"), (tier + 1) * (tier + 1))) + .renderer(() -> new TieredHullMachineRenderer(tier, GTCEu.id("block/machine/block_breaker_machine"))) + .langValue("%s Block Breaker %s".formatted(VLVH[tier], VLVT[tier])) + .tooltips(Component.translatable("gtceu.machine.block_breaker.tooltip"), + Component.translatable("gtceu.machine.block_breaker.speed_bonus", (int) (BlockBreakerMachine.getEfficiencyMultiplier(tier) * 100)), + Component.translatable("gtceu.universal.tooltip.voltage_in", GTValues.V[tier], GTValues.VNF[tier]), + Component.translatable("gtceu.universal.tooltip.energy_storage_capacity", GTValues.V[tier] * 64)) + .register(), + LV, MV, HV, EV); + + public static final MachineDefinition[] MINER = registerTieredMachines("miner", (holder, tier) -> new MinerMachine(holder, tier, 320 / (tier * 2), tier * 8, tier), (tier, builder) -> builder .rotationState(RotationState.NON_Y_AXIS) diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/machine/electric/BlockBreakerMachine.java b/common/src/main/java/com/gregtechceu/gtceu/common/machine/electric/BlockBreakerMachine.java new file mode 100644 index 0000000000..6b18e62bd4 --- /dev/null +++ b/common/src/main/java/com/gregtechceu/gtceu/common/machine/electric/BlockBreakerMachine.java @@ -0,0 +1,451 @@ +package com.gregtechceu.gtceu.common.machine.electric; + +import com.gregtechceu.gtceu.api.GTValues; +import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; +import com.gregtechceu.gtceu.api.capability.recipe.IO; +import com.gregtechceu.gtceu.api.gui.GuiTextures; +import com.gregtechceu.gtceu.api.gui.WidgetUtils; +import com.gregtechceu.gtceu.api.gui.editor.EditableMachineUI; +import com.gregtechceu.gtceu.api.gui.editor.EditableUI; +import com.gregtechceu.gtceu.api.item.tool.GTToolType; +import com.gregtechceu.gtceu.api.machine.IMachineBlockEntity; +import com.gregtechceu.gtceu.api.machine.TickableSubscription; +import com.gregtechceu.gtceu.api.machine.TieredEnergyMachine; +import com.gregtechceu.gtceu.api.machine.feature.IAutoOutputItem; +import com.gregtechceu.gtceu.api.machine.feature.IFancyUIMachine; +import com.gregtechceu.gtceu.api.machine.feature.IMachineModifyDrops; +import com.gregtechceu.gtceu.api.machine.trait.NotifiableItemStackHandler; +import com.gregtechceu.gtceu.api.syncdata.RequireRerender; +import com.gregtechceu.gtceu.data.lang.LangHandler; +import com.lowdragmc.lowdraglib.gui.texture.ResourceTexture; +import com.lowdragmc.lowdraglib.gui.widget.SlotWidget; +import com.lowdragmc.lowdraglib.gui.widget.WidgetGroup; +import com.lowdragmc.lowdraglib.misc.ItemStackTransfer; +import com.lowdragmc.lowdraglib.side.item.ItemTransferHelper; +import com.lowdragmc.lowdraglib.syncdata.ISubscription; +import com.lowdragmc.lowdraglib.syncdata.annotation.DescSynced; +import com.lowdragmc.lowdraglib.syncdata.annotation.Persisted; +import com.lowdragmc.lowdraglib.syncdata.field.ManagedFieldHolder; +import com.lowdragmc.lowdraglib.utils.Position; +import lombok.Getter; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.MethodsReturnNonnullByDefault; +import net.minecraft.Util; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.TickTask; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.material.Material; +import net.minecraft.world.phys.BlockHitResult; +import org.jetbrains.annotations.Nullable; + +import javax.annotation.ParametersAreNonnullByDefault; +import java.util.List; +import java.util.function.BiFunction; + +/** + * @author h3tr + * @date 2023/7/15 + * @implNote BlockBreakerMachine + */ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class BlockBreakerMachine extends TieredEnergyMachine implements IAutoOutputItem, IFancyUIMachine, IMachineModifyDrops { + protected static final ManagedFieldHolder MANAGED_FIELD_HOLDER = new ManagedFieldHolder(BlockBreakerMachine.class, TieredEnergyMachine.MANAGED_FIELD_HOLDER); + + @Getter + @Persisted + @DescSynced + @RequireRerender + protected Direction outputFacingItems; + @Getter + @Persisted + @DescSynced + @RequireRerender + protected boolean autoOutputItems; + @Persisted + protected final NotifiableItemStackHandler cache; + @Getter + @Persisted + protected final ItemStackTransfer chargerInventory; + @Nullable + protected TickableSubscription autoOutputSubs, batterySubs, breakerSubs; + @Nullable + protected ISubscription exportItemSubs, energySubs; + private final int inventorySize; + @DescSynced + private int blockBreakProgress = 0; + private float currentHardness; + private final long energyPerTick; + public final float efficiencyMultiplier; + + public BlockBreakerMachine(IMachineBlockEntity holder, int tier, Object... args) { + super(holder, tier); + this.inventorySize = (tier + 1) * (tier + 1); + this.cache = createCacheItemHandler(args); + this.chargerInventory = createChargerItemHandler(); + this.energyPerTick = GTValues.V[tier - 1]; + setOutputFacingItems(getFrontFacing().getOpposite()); + this.efficiencyMultiplier = 1.0f - getEfficiencyMultiplier(tier); + + } + + public static float getEfficiencyMultiplier(int tier) { + float efficiencyMultiplier = 1.0f - 0.2f * (tier - 1.0f); + //Clamp efficiencyMultiplier + if (efficiencyMultiplier > 1.0f) + efficiencyMultiplier = 1.0f; + else if (efficiencyMultiplier < .1f) + efficiencyMultiplier = .1f; + efficiencyMultiplier = 1.0f - efficiencyMultiplier; + return efficiencyMultiplier; + } + + ////////////////////////////////////// + //***** Initialization *****// + ////////////////////////////////////// + + @Override + public ManagedFieldHolder getFieldHolder() { + return MANAGED_FIELD_HOLDER; + } + + protected ItemStackTransfer createChargerItemHandler(Object... args) { + var transfer = new ItemStackTransfer(); + transfer.setFilter(item -> GTCapabilityHelper.getElectricItem(item) != null); + return transfer; + } + + protected NotifiableItemStackHandler createCacheItemHandler(Object... args) { + return new NotifiableItemStackHandler(this, inventorySize, IO.BOTH, IO.OUT); + } + + @Override + public void onLoad() { + super.onLoad(); + if (!isRemote()) { + if (getLevel() instanceof ServerLevel serverLevel) { + serverLevel.getServer().tell(new TickTask(0, this::updateAutoOutputSubscription)); + serverLevel.getServer().tell(new TickTask(0, this::updateBreakerUpdateSubscription)); + } + exportItemSubs = cache.addChangedListener(this::updateAutoOutputSubscription); + energySubs = energyContainer.addChangedListener(() -> { + this.updateBatterySubscription(); + this.updateBreakerUpdateSubscription(); + }); + chargerInventory.setOnContentsChanged(this::updateBatterySubscription); + } + } + + @Override + public void onUnload() { + super.onUnload(); + if (energySubs != null) { + energySubs.unsubscribe(); + energySubs = null; + } + if (exportItemSubs != null) { + exportItemSubs.unsubscribe(); + exportItemSubs = null; + } + } + + @Override + public void onDrops(List drops, Player entity) { + clearInventory(drops, chargerInventory); + clearInventory(drops, cache.storage); + } + + @Override + public void onNeighborChanged(Block block, BlockPos fromPos, boolean isMoving) { + super.onNeighborChanged(block, fromPos, isMoving); + updateBreakerUpdateSubscription(); + updateAutoOutputSubscription(); + } + + ////////////////////////////////////// + //********* Logic **********// + ////////////////////////////////////// + + public void updateBreakerUpdateSubscription() { + if (drainEnergy(true) && !getLevel().getBlockState(getPos().relative(getFrontFacing())).isAir() && getLevel().hasNeighborSignal(getPos())) { + breakerSubs = subscribeServerTick(breakerSubs, this::breakerUpdate); + } else if (breakerSubs != null) { + blockBreakProgress = 0; + breakerSubs.unsubscribe(); + breakerSubs = null; + } + } + + public void breakerUpdate() { + if (this.blockBreakProgress > 0) { + --this.blockBreakProgress; + drainEnergy(false); + + if (blockBreakProgress == 0) { + var pos = getPos().relative(getFrontFacing()); + var blockState = getLevel().getBlockState(pos); + float hardness = blockState.getBlock().defaultDestroyTime(); + if (hardness >= 0.0f && Math.abs(hardness - currentHardness) < .5f) { + var drops = tryDestroyBlockAndGetDrops(pos); + for (ItemStack drop : drops) { + var remainder = tryFillCache(drop); + if (!remainder.isEmpty()) { + if (getOutputFacingItems() == null) { + Block.popResource(getLevel(), getPos(), remainder); + } else { + Block.popResource(getLevel(), getPos().relative(getOutputFacingItems()), remainder); + } + } + } + } + this.currentHardness = 0f; + } + } + + if (blockBreakProgress == 0) { + var pos = getPos().relative(getFrontFacing()); + var blockState = getLevel().getBlockState(pos); + float hardness = blockState.getBlock().defaultDestroyTime(); + boolean skipBlock = blockState.getMaterial() == Material.AIR; + if (hardness >= 0f && !skipBlock) { + int ticksPerOneDurability = 5; + int totalTicksPerBlock = (int) Math.ceil(ticksPerOneDurability * hardness); + this.blockBreakProgress = (int) Math.ceil(totalTicksPerBlock * this.efficiencyMultiplier); + this.currentHardness = hardness; + } + } + + updateBreakerUpdateSubscription(); + } + + @Override + @Environment(EnvType.CLIENT) + public void clientTick() { + super.clientTick(); + if (blockBreakProgress > 0) { + var pos = getPos().relative(getFrontFacing()); + var blockState = getLevel().getBlockState(pos); + getLevel().addDestroyBlockEffect(pos, blockState); + } + } + + private List tryDestroyBlockAndGetDrops(BlockPos pos) { + List drops = Block.getDrops(getLevel().getBlockState(pos), (ServerLevel) getLevel(), pos, null, null, ItemStack.EMPTY); + getLevel().destroyBlock(pos, false); + return drops; + } + + private ItemStack tryFillCache(ItemStack stack) { + for (int i = 0; i < cache.getSlots(); i++) { + if (cache.insertItemInternal(i, stack, true).getCount() == stack.getCount()) + continue; + return tryFillCache(cache.insertItemInternal(i, stack, false)); + } + return stack; + } + + public boolean drainEnergy(boolean simulate) { + long resultEnergy = energyContainer.getEnergyStored() - energyPerTick; + if (resultEnergy >= 0L && resultEnergy <= energyContainer.getEnergyCapacity()) { + if (!simulate) + energyContainer.removeEnergy(energyPerTick); + return true; + } + return false; + } + + ////////////////////////////////////// + //******* Auto Output *******// + ////////////////////////////////////// + @Override + public void setAutoOutputItems(boolean allow) { + this.autoOutputItems = allow; + updateAutoOutputSubscription(); + } + + @Override + public boolean isAllowInputFromOutputSideItems() { + return false; + } + + @Override + public void setAllowInputFromOutputSideItems(boolean allow) { + } + + @Override + public void setOutputFacingItems(@Nullable Direction outputFacing) { + this.outputFacingItems = outputFacing; + updateAutoOutputSubscription(); + } + + protected void updateAutoOutputSubscription() { + var outputFacing = getOutputFacingItems(); + if ((isAutoOutputItems() && !cache.isEmpty()) && outputFacing != null + && ItemTransferHelper.getItemTransfer(getLevel(), getPos().relative(outputFacing), outputFacing.getOpposite()) != null) + autoOutputSubs = subscribeServerTick(autoOutputSubs, this::checkAutoOutput); + else if (autoOutputSubs != null) { + autoOutputSubs.unsubscribe(); + autoOutputSubs = null; + } + } + + protected void checkAutoOutput() { + if (getOffsetTimer() % 5 == 0) { + if (isAutoOutputItems() && getOutputFacingItems() != null) + cache.exportToNearby(getOutputFacingItems()); + updateAutoOutputSubscription(); + } + } + + protected void updateBatterySubscription() { + if (energyContainer.dischargeOrRechargeEnergyContainers(chargerInventory, 0, true)) + batterySubs = subscribeServerTick(batterySubs, this::chargeBattery); + else if (batterySubs != null) { + batterySubs.unsubscribe(); + batterySubs = null; + } + } + + protected void chargeBattery() { + if (!energyContainer.dischargeOrRechargeEnergyContainers(chargerInventory, 0, false)) + updateBatterySubscription(); + } + + @Override + public boolean shouldWeatherOrTerrainExplosion() { + return false; + } + + @Override + public boolean isFacingValid(Direction facing) { + if (facing == getOutputFacingItems()) { + return false; + } + return super.isFacingValid(facing); + } + + ////////////////////////////////////// + //********** GUI ***********// + ////////////////////////////////////// + public static BiFunction EDITABLE_UI_CREATOR = Util.memoize((path, inventorySize) -> new EditableMachineUI("misc", path, () -> { + var template = createTemplate(inventorySize).createDefault(); + var energyBar = createEnergyBar().createDefault(); + var batterySlot = createBatterySlot().createDefault(); + var energyGroup = new WidgetGroup(0, 0, energyBar.getSize().width, energyBar.getSize().height + 20); + batterySlot.setSelfPosition(new Position((energyBar.getSize().width - 18) / 2, energyBar.getSize().height + 1)); + energyGroup.addWidget(energyBar); + energyGroup.addWidget(batterySlot); + var group = new WidgetGroup(0, 0, + Math.max(energyGroup.getSize().width + template.getSize().width + 4 + 8, 172), + Math.max(template.getSize().height + 8, energyGroup.getSize().height + 8)); + var size = group.getSize(); + energyGroup.setSelfPosition(new Position(3, (size.height - energyGroup.getSize().height) / 2)); + + template.setSelfPosition(new Position( + (size.width - energyGroup.getSize().width - 4 - template.getSize().width) / 2 + 2 + energyGroup.getSize().width + 2, + (size.height - template.getSize().height) / 2)); + + group.addWidget(energyGroup); + group.addWidget(template); + return group; + }, (template, machine) -> { + if (machine instanceof BlockBreakerMachine blockBreakerMachine) { + createTemplate(inventorySize).setupUI(template, blockBreakerMachine); + createEnergyBar().setupUI(template, blockBreakerMachine); + createBatterySlot().setupUI(template, blockBreakerMachine); + } + })); + + protected static EditableUI createBatterySlot() { + return new EditableUI<>("battery_slot", SlotWidget.class, () -> { + var slotWidget = new SlotWidget(); + slotWidget.setBackground(GuiTextures.SLOT, GuiTextures.CHARGER_OVERLAY); + return slotWidget; + }, (slotWidget, machine) -> { + slotWidget.setHandlerSlot(machine.chargerInventory, 0); + slotWidget.setCanPutItems(true); + slotWidget.setCanTakeItems(true); + slotWidget.setHoverTooltips(LangHandler.getMultiLang("gtceu.gui.charger_slot.tooltip", GTValues.VNF[machine.getTier()], GTValues.VNF[machine.getTier()]).toArray(new MutableComponent[0])); + }); + } + + protected static EditableUI createTemplate(int inventorySize) { + return new EditableUI<>("functional_container", WidgetGroup.class, () -> { + int rowSize = (int) Math.sqrt(inventorySize); + WidgetGroup main = new WidgetGroup(0, 0, rowSize * 18 + 8, rowSize * 18 + 8); + for (int y = 0; y < rowSize; y++) { + for (int x = 0; x < rowSize; x++) { + int index = y * rowSize + x; + SlotWidget slotWidget = new SlotWidget(); + slotWidget.initTemplate(); + slotWidget.setSelfPosition(new Position(4 + x * 18, 4 + y * 18)); + slotWidget.setBackground(GuiTextures.SLOT); + slotWidget.setId("slot_" + index); + main.addWidget(slotWidget); + } + } + main.setBackground(GuiTextures.BACKGROUND_INVERSE); + return main; + }, (group, machine) -> { + WidgetUtils.widgetByIdForEach(group, "^slot_[0-9]+$", SlotWidget.class, slot -> { + var index = WidgetUtils.widgetIdIndex(slot); + if (index >= 0 && index < machine.cache.getSlots()) { + slot.setHandlerSlot(machine.cache, index); + slot.setCanTakeItems(true); + slot.setCanPutItems(false); + } + }); + }); + } + + ////////////////////////////////////// + //******* Rendering ********// + ////////////////////////////////////// + @Override + public ResourceTexture sideTips(Player player, GTToolType toolType, Direction side) { + if (toolType == GTToolType.WRENCH) { + if (!player.isCrouching()) { + if (!hasFrontFacing() || side != getFrontFacing()) { + return GuiTextures.TOOL_IO_FACING_ROTATION; + } + } + } + return super.sideTips(player, toolType, side); + } + + ////////////////////////////////////// + //******* Interactions ********// + ////////////////////////////////////// + @Override + protected InteractionResult onWrenchClick(Player playerIn, InteractionHand hand, Direction gridSide, BlockHitResult hitResult) { + if (!playerIn.isCrouching() && !isRemote()) { + var tool = playerIn.getItemInHand(hand); + if (tool.getDamageValue() >= tool.getMaxDamage()) return InteractionResult.PASS; + if (hasFrontFacing() && gridSide == getFrontFacing()) return InteractionResult.PASS; + + // important not to use getters here, which have different logic + Direction itemFacing = this.outputFacingItems; + + if (gridSide != itemFacing) { + // if it is a new side, move it + setOutputFacingItems(gridSide); + } else { + // remove the output facing when wrenching the current one to disable it + setOutputFacingItems(null); + } + + return InteractionResult.CONSUME; + } + + return super.onWrenchClick(playerIn, hand, gridSide, hitResult); + } +} diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/machine/electric/FisherMachine.java b/common/src/main/java/com/gregtechceu/gtceu/common/machine/electric/FisherMachine.java new file mode 100644 index 0000000000..b194c9903c --- /dev/null +++ b/common/src/main/java/com/gregtechceu/gtceu/common/machine/electric/FisherMachine.java @@ -0,0 +1,461 @@ +package com.gregtechceu.gtceu.common.machine.electric; + +import com.gregtechceu.gtceu.api.GTValues; +import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; +import com.gregtechceu.gtceu.api.capability.recipe.IO; +import com.gregtechceu.gtceu.api.gui.GuiTextures; +import com.gregtechceu.gtceu.api.gui.WidgetUtils; +import com.gregtechceu.gtceu.api.gui.editor.EditableMachineUI; +import com.gregtechceu.gtceu.api.gui.editor.EditableUI; +import com.gregtechceu.gtceu.api.item.tool.GTToolType; +import com.gregtechceu.gtceu.api.machine.IMachineBlockEntity; +import com.gregtechceu.gtceu.api.machine.TickableSubscription; +import com.gregtechceu.gtceu.api.machine.TieredEnergyMachine; +import com.gregtechceu.gtceu.api.machine.feature.IAutoOutputItem; +import com.gregtechceu.gtceu.api.machine.feature.IFancyUIMachine; +import com.gregtechceu.gtceu.api.machine.feature.IMachineModifyDrops; +import com.gregtechceu.gtceu.api.machine.trait.NotifiableItemStackHandler; +import com.gregtechceu.gtceu.api.syncdata.RequireRerender; +import com.gregtechceu.gtceu.data.lang.LangHandler; +import com.lowdragmc.lowdraglib.gui.texture.ResourceTexture; +import com.lowdragmc.lowdraglib.gui.widget.*; +import com.lowdragmc.lowdraglib.misc.ItemStackTransfer; +import com.lowdragmc.lowdraglib.side.item.ItemTransferHelper; +import com.lowdragmc.lowdraglib.syncdata.ISubscription; +import com.lowdragmc.lowdraglib.syncdata.annotation.DescSynced; +import com.lowdragmc.lowdraglib.syncdata.annotation.Persisted; +import com.lowdragmc.lowdraglib.syncdata.field.ManagedFieldHolder; +import com.lowdragmc.lowdraglib.utils.Position; +import lombok.Getter; +import lombok.Setter; +import net.minecraft.MethodsReturnNonnullByDefault; +import net.minecraft.Util; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.NonNullList; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.TickTask; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.projectile.FishingHook; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.material.Fluids; +import net.minecraft.world.level.storage.loot.BuiltInLootTables; +import net.minecraft.world.level.storage.loot.LootContext; +import net.minecraft.world.level.storage.loot.LootTable; +import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets; +import net.minecraft.world.level.storage.loot.parameters.LootContextParams; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +import org.jetbrains.annotations.Nullable; + +import javax.annotation.ParametersAreNonnullByDefault; +import java.util.List; +import java.util.function.BiFunction; + +/** + * @author h3tr + * @date 2023/7/13 + * @implNote FisherMachine + */ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class FisherMachine extends TieredEnergyMachine implements IAutoOutputItem, IFancyUIMachine, IMachineModifyDrops { + protected static final ManagedFieldHolder MANAGED_FIELD_HOLDER = new ManagedFieldHolder(FisherMachine.class, TieredEnergyMachine.MANAGED_FIELD_HOLDER); + + @Getter + @Persisted + @DescSynced + @RequireRerender + protected Direction outputFacingItems; + @Getter + @Persisted + @DescSynced + @RequireRerender + protected boolean autoOutputItems; + @Persisted + protected final NotifiableItemStackHandler cache; + @Getter + @Setter + @Persisted + protected boolean allowInputFromOutputSideItems; + @Persisted + protected final NotifiableItemStackHandler baitHandler; + + @Getter + @Persisted + protected final ItemStackTransfer chargerInventory; + @Nullable + protected TickableSubscription autoOutputSubs, batterySubs, fishingSubs; + @Nullable + protected ISubscription exportItemSubs, energySubs, baitSubs; + private final long energyPerTick; + + private final int inventorySize; + public final int fishingTicks; + public static final int WATER_CHECK_SIZE = 5; + private static final ItemStack fishingRod = new ItemStack(Items.FISHING_ROD); + + public FisherMachine(IMachineBlockEntity holder, int tier, Object... args) { + super(holder, tier); + this.inventorySize = (tier + 1) * (tier + 1); + this.fishingTicks = 1000 - tier * 200; + this.energyPerTick = GTValues.V[tier - 1]; + this.cache = createCacheItemHandler(args); + this.baitHandler = createBaitItemHandler(args); + this.chargerInventory = createChargerItemHandler(); + setOutputFacingItems(getFrontFacing()); + } + + ////////////////////////////////////// + //***** Initialization *****// + ////////////////////////////////////// + + protected ItemStackTransfer createChargerItemHandler(Object... args) { + var transfer = new ItemStackTransfer(); + transfer.setFilter(item -> GTCapabilityHelper.getElectricItem(item) != null); + return transfer; + } + + @Override + public ManagedFieldHolder getFieldHolder() { + return MANAGED_FIELD_HOLDER; + } + + protected NotifiableItemStackHandler createCacheItemHandler(Object... args) { + return new NotifiableItemStackHandler(this, inventorySize, IO.BOTH, IO.OUT); + } + + protected NotifiableItemStackHandler createBaitItemHandler(Object... args) { + var handler = new NotifiableItemStackHandler(this, 1, IO.BOTH, IO.IN); + handler.setFilter(item -> item.is(Items.STRING)); + return handler; + } + + @Override + public void onLoad() { + super.onLoad(); + if (!isRemote()) { + if (getLevel() instanceof ServerLevel serverLevel) { + serverLevel.getServer().tell(new TickTask(0, this::updateAutoOutputSubscription)); + } + exportItemSubs = cache.addChangedListener(this::updateAutoOutputSubscription); + energySubs = energyContainer.addChangedListener(() -> { + this.updateBatterySubscription(); + this.updateFishingUpdateSubscription(); + }); + baitSubs = baitHandler.addChangedListener(this::updateFishingUpdateSubscription); + chargerInventory.setOnContentsChanged(this::updateBatterySubscription); + this.updateFishingUpdateSubscription(); + } + } + + @Override + public void onUnload() { + super.onUnload(); + if (energySubs != null) { + energySubs.unsubscribe(); + energySubs = null; + } + if (exportItemSubs != null) { + exportItemSubs.unsubscribe(); + exportItemSubs = null; + } + if (baitSubs != null) { + baitSubs.unsubscribe(); + baitSubs = null; + } + } + + @Override + public boolean shouldWeatherOrTerrainExplosion() { + return false; + } + + @Override + public void onDrops(List drops, Player entity) { + clearInventory(drops, chargerInventory); + clearInventory(drops, baitHandler.storage); + clearInventory(drops, cache.storage); + } + + ////////////////////////////////////// + //********* Logic **********// + ////////////////////////////////////// + + public void updateFishingUpdateSubscription() { + if (drainEnergy(true) && this.baitHandler.getStackInSlot(0).is(Items.STRING)) { + fishingSubs = subscribeServerTick(fishingSubs, this::fishingUpdate); + } else if (fishingSubs != null) { + fishingSubs.unsubscribe(); + fishingSubs = null; + } + } + + public void fishingUpdate() { + drainEnergy(false); + if (this.getOffsetTimer() % this.fishingTicks == 0) { + int waterCount = 0; + int edgeSize = WATER_CHECK_SIZE; + for (int x = 0; x < edgeSize; x++) { + for (int z = 0; z < edgeSize; z++) { + BlockPos waterCheckPos = getPos().below().offset(x - edgeSize / 2, 0, z - edgeSize / 2); + if (getLevel().getBlockState(waterCheckPos).getFluidState().is(Fluids.WATER)) { + waterCount++; + } + } + } + if (waterCount < WATER_CHECK_SIZE * WATER_CHECK_SIZE) + return; + + LootTable lootTable = getLevel().getServer().getLootTables().get(BuiltInLootTables.FISHING); + + FishingHook simulatedHook = new FishingHook(EntityType.FISHING_BOBBER, getLevel()) { + public boolean isOpenWaterFishing() { + return true; + } + }; + + LootContext lootContext = new LootContext.Builder((ServerLevel) getLevel()) + .withOptionalParameter(LootContextParams.THIS_ENTITY, simulatedHook) + .withParameter(LootContextParams.TOOL, fishingRod) + .withParameter(LootContextParams.ORIGIN, new Vec3(getPos().getX(), getPos().getY(), getPos().getZ())) + .create(LootContextParamSets.FISHING); + + + NonNullList generatedLoot = NonNullList.create(); + generatedLoot.addAll(lootTable.getRandomItems(lootContext)); + + boolean useBait = false; + for (ItemStack itemStack : generatedLoot) + useBait |= tryFillCache(itemStack); + + if (useBait) + this.baitHandler.extractItem(0, 1, false); + updateFishingUpdateSubscription(); + } + } + + private boolean tryFillCache(ItemStack stack) { + for (int i = 0; i < cache.getSlots(); i++) { + if (cache.insertItemInternal(i, stack, false).getCount() < stack.getCount()) { + return true; + } + } + return false; + } + + public boolean drainEnergy(boolean simulate) { + long resultEnergy = energyContainer.getEnergyStored() - energyPerTick; + if (resultEnergy >= 0L && resultEnergy <= energyContainer.getEnergyCapacity()) { + if (!simulate) + energyContainer.removeEnergy(energyPerTick); + return true; + } + return false; + } + + + ////////////////////////////////////// + //******* Auto Output *******// + ////////////////////////////////////// + @Override + public void setAutoOutputItems(boolean allow) { + this.autoOutputItems = allow; + updateAutoOutputSubscription(); + } + + @Override + public void setOutputFacingItems(@Nullable Direction outputFacing) { + this.outputFacingItems = outputFacing; + updateAutoOutputSubscription(); + } + + protected void updateBatterySubscription() { + if (energyContainer.dischargeOrRechargeEnergyContainers(chargerInventory, 0, true)) + batterySubs = subscribeServerTick(batterySubs, this::chargeBattery); + else if (batterySubs != null) { + batterySubs.unsubscribe(); + batterySubs = null; + } + } + + protected void updateAutoOutputSubscription() { + var outputFacing = getOutputFacingItems(); + if ((isAutoOutputItems() && !cache.isEmpty()) && outputFacing != null + && ItemTransferHelper.getItemTransfer(getLevel(), getPos().relative(outputFacing), outputFacing.getOpposite()) != null) + autoOutputSubs = subscribeServerTick(autoOutputSubs, this::checkAutoOutput); + else if (autoOutputSubs != null) { + autoOutputSubs.unsubscribe(); + autoOutputSubs = null; + } + } + + protected void checkAutoOutput() { + if (getOffsetTimer() % 5 == 0) { + if (isAutoOutputItems() && getOutputFacingItems() != null) + cache.exportToNearby(getOutputFacingItems()); + updateAutoOutputSubscription(); + } + } + + protected void chargeBattery() { + if (!energyContainer.dischargeOrRechargeEnergyContainers(chargerInventory, 0, false)) + updateBatterySubscription(); + } + + @Override + public boolean isFacingValid(Direction facing) { + if (facing == getOutputFacingItems()) { + return false; + } + return super.isFacingValid(facing); + } + + @Override + public void onNeighborChanged(Block block, BlockPos fromPos, boolean isMoving) { + super.onNeighborChanged(block, fromPos, isMoving); + updateAutoOutputSubscription(); + } + + ////////////////////////////////////// + //********** GUI ***********// + ////////////////////////////////////// + + public static BiFunction EDITABLE_UI_CREATOR = Util.memoize((path, inventorySize) -> new EditableMachineUI("misc", path, () -> { + var template = createTemplate(inventorySize).createDefault(); + var energyBar = createEnergyBar().createDefault(); + var batterySlot = createBatterySlot().createDefault(); + var energyGroup = new WidgetGroup(0, 0, energyBar.getSize().width, energyBar.getSize().height + 20); + batterySlot.setSelfPosition(new Position((energyBar.getSize().width - 18) / 2, energyBar.getSize().height + 1)); + energyGroup.addWidget(energyBar); + energyGroup.addWidget(batterySlot); + var group = new WidgetGroup(0, 0, + Math.max(energyGroup.getSize().width + template.getSize().width + 4 + 8, 172), + Math.max(template.getSize().height + 8, energyGroup.getSize().height + 8)); + var size = group.getSize(); + energyGroup.setSelfPosition(new Position(3, (size.height - energyGroup.getSize().height) / 2)); + + template.setSelfPosition(new Position( + (size.width - energyGroup.getSize().width - 4 - template.getSize().width) / 2 + 2 + energyGroup.getSize().width + 2, + (size.height - template.getSize().height) / 2)); + + group.addWidget(energyGroup); + group.addWidget(template); + return group; + }, (template, machine) -> { + if (machine instanceof FisherMachine fisherMachine) { + createTemplate(inventorySize).setupUI(template, fisherMachine); + createEnergyBar().setupUI(template, fisherMachine); + createBatterySlot().setupUI(template, fisherMachine); + } + })); + + protected static EditableUI createBatterySlot() { + return new EditableUI<>("battery_slot", SlotWidget.class, () -> { + var slotWidget = new SlotWidget(); + slotWidget.setBackground(GuiTextures.SLOT, GuiTextures.CHARGER_OVERLAY); + return slotWidget; + }, (slotWidget, machine) -> { + slotWidget.setHandlerSlot(machine.chargerInventory, 0); + slotWidget.setCanPutItems(true); + slotWidget.setCanTakeItems(true); + slotWidget.setHoverTooltips(LangHandler.getMultiLang("gtceu.gui.charger_slot.tooltip", GTValues.VNF[machine.getTier()], GTValues.VNF[machine.getTier()]).toArray(new MutableComponent[0])); + }); + } + + protected static EditableUI createTemplate(int inventorySize) { + return new EditableUI<>("functional_container", WidgetGroup.class, () -> { + int rowSize = (int) Math.sqrt(inventorySize); + WidgetGroup main = new WidgetGroup(0, 0, rowSize * 18 + 8 + 20, rowSize * 18 + 8); + + for (int y = 0; y < rowSize; y++) { + for (int x = 0; x < rowSize; x++) { + int index = y * rowSize + x; + SlotWidget slotWidget = new SlotWidget(); + slotWidget.initTemplate(); + slotWidget.setSelfPosition(new Position(24 + x * 18, 4 + y * 18)); + slotWidget.setBackground(GuiTextures.SLOT); + slotWidget.setId("slot_" + index); + main.addWidget(slotWidget); + } + } + + SlotWidget baitSlotWidget = new SlotWidget(); + baitSlotWidget.initTemplate(); + baitSlotWidget.setSelfPosition(new Position(4, (main.getSize().height - baitSlotWidget.getSize().height) / 2)); + baitSlotWidget.setBackground(GuiTextures.SLOT, GuiTextures.STRING_SLOT_OVERLAY); + baitSlotWidget.setId("bait_slot"); + main.addWidget(baitSlotWidget); + main.setBackground(GuiTextures.BACKGROUND_INVERSE); + return main; + }, (group, machine) -> { + WidgetUtils.widgetByIdForEach(group, "^slot_[0-9]+$", SlotWidget.class, slot -> { + var index = WidgetUtils.widgetIdIndex(slot); + if (index >= 0 && index < machine.cache.getSlots()) { + slot.setHandlerSlot(machine.cache, index); + slot.setCanTakeItems(true); + slot.setCanPutItems(false); + } + }); + WidgetUtils.widgetByIdForEach(group, "^bait_slot$", SlotWidget.class, slot -> { + slot.setHandlerSlot(machine.baitHandler, 0); + slot.setCanTakeItems(true); + slot.setCanPutItems(true); + }); + }); + } + + ////////////////////////////////////// + //******* Rendering ********// + ////////////////////////////////////// + @Override + public ResourceTexture sideTips(Player player, GTToolType toolType, Direction side) { + if (toolType == GTToolType.WRENCH) { + if (!player.isCrouching()) { + if (!hasFrontFacing() || side != getFrontFacing()) { + return GuiTextures.TOOL_IO_FACING_ROTATION; + } + } + } + if (toolType == GTToolType.SCREWDRIVER) { + if (side == getOutputFacingItems()) { + return GuiTextures.TOOL_ALLOW_INPUT; + } + } + return super.sideTips(player, toolType, side); + } + + ////////////////////////////////////// + //******* Interactions ********// + ////////////////////////////////////// + @Override + protected InteractionResult onWrenchClick(Player playerIn, InteractionHand hand, Direction gridSide, BlockHitResult hitResult) { + if (!playerIn.isCrouching() && !isRemote()) { + var tool = playerIn.getItemInHand(hand); + if (tool.getDamageValue() >= tool.getMaxDamage()) return InteractionResult.PASS; + if (hasFrontFacing() && gridSide == getFrontFacing()) return InteractionResult.PASS; + + // important not to use getters here, which have different logic + Direction itemFacing = this.outputFacingItems; + + if (gridSide != itemFacing) { + // if it is a new side, move it + setOutputFacingItems(gridSide); + } else { + // remove the output facing when wrenching the current one to disable it + setOutputFacingItems(null); + } + + return InteractionResult.CONSUME; + } + + return super.onWrenchClick(playerIn, hand, gridSide, hitResult); + } +} diff --git a/common/src/main/java/com/gregtechceu/gtceu/data/recipe/misc/MetaTileEntityLoader.java b/common/src/main/java/com/gregtechceu/gtceu/data/recipe/misc/MetaTileEntityLoader.java index 4d74b03fee..f317cf261d 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/data/recipe/misc/MetaTileEntityLoader.java +++ b/common/src/main/java/com/gregtechceu/gtceu/data/recipe/misc/MetaTileEntityLoader.java @@ -285,9 +285,9 @@ public static void init(Consumer provider) { registerMachineRecipe(provider, GTMachines.ROCK_CRUSHER, "PMW", "CHC", "GGG", 'P', PISTON, 'M', MOTOR, 'W', GRINDER, 'C', CABLE, 'H', HULL, 'G', GLASS); registerMachineRecipe(provider, GTMachines.PUMP, "WGW", "GMG", "TGT", 'M', HULL, 'W', CIRCUIT, 'G', PUMP, 'T', PIPE_LARGE); // TODO Misc machines - //registerMachineRecipe(provider, GTMachines.FISHER, "WTW", "PMP", "TGT", 'M', HULL, 'W', CIRCUIT, 'G', PUMP, 'T', MOTOR, 'P', PISTON); + registerMachineRecipe(provider, GTMachines.FISHER, "WTW", "PMP", "TGT", 'M', HULL, 'W', CIRCUIT, 'G', PUMP, 'T', MOTOR, 'P', PISTON); //registerMachineRecipe(provider, GTMachines.ITEM_COLLECTOR, "MRM", "RHR", "CWC", 'M', MOTOR, 'R', ROTOR, 'H', HULL, 'C', CIRCUIT, 'W', CABLE); - //registerMachineRecipe(provider, GTMachines.BLOCK_BREAKER, "MGM", "CHC", "WSW", 'M', MOTOR, 'H', HULL, 'C', CIRCUIT, 'W', CABLE, 'S', OreDictNames.chestWood, 'G', GRINDER); + registerMachineRecipe(provider, GTMachines.BLOCK_BREAKER, "MGM", "CHC", "WSW", 'M', MOTOR, 'H', HULL, 'C', CIRCUIT, 'W', CABLE, 'S', CustomTags.TAG_WOODEN_CHESTS, 'G', GRINDER); //registerMachineRecipe(provider, GTMachines.WORLD_ACCELERATOR, "IGI", "FHF", "IGI", 'H', HULL, 'F', EMITTER, 'G', SENSOR, 'I', FIELD_GENERATOR); registerMachineRecipe(provider, GTMachines.MINER, "MMM", "WHW", "CSC", 'M', MOTOR, 'W', CABLE, 'H', HULL, 'C', CIRCUIT, 'S', SENSOR); diff --git a/common/src/main/resources/assets/gtceu/models/block/machine/block_breaker_machine.json b/common/src/main/resources/assets/gtceu/models/block/machine/block_breaker_machine.json new file mode 100644 index 0000000000..dd77cbbcd4 --- /dev/null +++ b/common/src/main/resources/assets/gtceu/models/block/machine/block_breaker_machine.json @@ -0,0 +1,31 @@ +{ + "parent": "block/block", + "textures": { + "particle": "gtceu:block/casings/voltage/lv/side", + "bottom": "gtceu:block/casings/voltage/lv/bottom", + "top": "gtceu:block/casings/voltage/lv/top", + "side": "gtceu:block/casings/voltage/lv/side", + "front": "gtceu:block/machines/rock_crusher/overlay_front" + }, + "elements": [ + { + "from": [ 0, 0, 0 ], + "to": [ 16, 16, 16 ], + "faces": { + "down": { "texture": "#bottom", "cullface": "down", "tintindex": 1 }, + "up": { "texture": "#top", "cullface": "up", "tintindex": 1 }, + "north": { "texture": "#side", "cullface": "north", "tintindex": 1 }, + "south": { "texture": "#side", "cullface": "south", "tintindex": 1 }, + "west": { "texture": "#side", "cullface": "west", "tintindex": 1 }, + "east": { "texture": "#side", "cullface": "east", "tintindex": 1 } + } + }, + { + "from": [0, 0, 0], + "to": [16, 16, 0], + "faces": { + "north": {"uv": [0, 0, 16, 16], "texture": "#front", "cullface": "north", "tintindex": 2} + } + } + ] +} diff --git a/common/src/main/resources/assets/gtceu/models/block/machine/fisher_machine.json b/common/src/main/resources/assets/gtceu/models/block/machine/fisher_machine.json new file mode 100644 index 0000000000..8ce686f341 --- /dev/null +++ b/common/src/main/resources/assets/gtceu/models/block/machine/fisher_machine.json @@ -0,0 +1,39 @@ +{ + "parent": "block/block", + "textures": { + "particle": "gtceu:block/casings/voltage/lv/side", + "bottom": "gtceu:block/casings/voltage/lv/bottom", + "top": "gtceu:block/casings/voltage/lv/top", + "side": "gtceu:block/casings/voltage/lv/side", + "screen": "gtceu:block/overlay/machine/overlay_screen", + "screen_emissive": "gtceu:block/overlay/machine/overlay_qtank_emissive" + }, + "elements": [ + { + "from": [ 0, 0, 0 ], + "to": [ 16, 16, 16 ], + "faces": { + "down": { "texture": "#bottom", "cullface": "down", "tintindex": 1 }, + "up": { "texture": "#top", "cullface": "up", "tintindex": 1 }, + "north": { "texture": "#side", "cullface": "north", "tintindex": 1 }, + "south": { "texture": "#side", "cullface": "south", "tintindex": 1 }, + "west": { "texture": "#side", "cullface": "west", "tintindex": 1 }, + "east": { "texture": "#side", "cullface": "east", "tintindex": 1 } + } + }, + { + "from": [0, 16, 0], + "to": [16, 16, 16], + "faces": { + "up": {"texture": "#screen", "cullface": "up" } + } + }, + { + "from": [0, 16, 0], + "to": [16, 16, 16], + "faces": { + "up": {"texture": "#screen_emissive", "cullface": "up", "emissivity": 15 } + } + } + ] +} diff --git a/fabric/src/generated/resources/assets/gtceu/lang/en_ud.json b/fabric/src/generated/resources/assets/gtceu/lang/en_ud.json index 72a03192e4..b4aeda8815 100644 --- a/fabric/src/generated/resources/assets/gtceu/lang/en_ud.json +++ b/fabric/src/generated/resources/assets/gtceu/lang/en_ud.json @@ -146,6 +146,7 @@ "block.gtceu.ev_battery_buffer_4x": "ɹǝɟɟnᗺ ʎɹǝʇʇɐᗺ xㄣ ǝbɐʇןoΛ ǝɯǝɹʇxƎ", "block.gtceu.ev_battery_buffer_8x": "ɹǝɟɟnᗺ ʎɹǝʇʇɐᗺ x8 ǝbɐʇןoΛ ǝɯǝɹʇxƎ", "block.gtceu.ev_bender": "ɹ§III ɹǝpuǝᗺ pǝɔuɐʌpⱯϛ§", + "block.gtceu.ev_block_breaker": "ɹ§III ɹǝʞɐǝɹᗺ ʞɔoןᗺ pǝɔuɐʌpⱯϛ§", "block.gtceu.ev_brewery": "ɹ§III ʎɹǝʍǝɹᗺ pǝɔuɐʌpⱯϛ§", "block.gtceu.ev_canner": "ɹ§III ɹǝuuɐƆ pǝɔuɐʌpⱯϛ§", "block.gtceu.ev_centrifuge": "ɹ§III ǝbnɟıɹʇuǝƆ pǝɔuɐʌpⱯϛ§", @@ -172,6 +173,7 @@ "block.gtceu.ev_extractor": "ɹ§III ɹoʇɔɐɹʇxƎ pǝɔuɐʌpⱯϛ§", "block.gtceu.ev_extruder": "ɹ§III ɹǝpnɹʇxƎ pǝɔuɐʌpⱯϛ§", "block.gtceu.ev_fermenter": "ɹ§III ɹǝʇuǝɯɹǝℲ pǝɔuɐʌpⱯϛ§", + "block.gtceu.ev_fisher": "ɹ§III ɹǝɥsıℲ pǝɔuɐʌpⱯϛ§", "block.gtceu.ev_fluid_drilling_rig": "bıᴚ buıןןıɹᗡ uoısnℲ pǝɔuɐʌpⱯϛ§", "block.gtceu.ev_fluid_heater": "ɹ§III ɹǝʇɐǝH pınןℲ pǝɔuɐʌpⱯϛ§", "block.gtceu.ev_fluid_passthrough_hatch": "ɥɔʇɐH ɥbnoɹɥʇssɐԀ pınןℲ ΛƎϛ§", @@ -246,6 +248,7 @@ "block.gtceu.hv_battery_buffer_4x": "ɹǝɟɟnᗺ ʎɹǝʇʇɐᗺ xㄣ ǝbɐʇןoΛ ɥbıH", "block.gtceu.hv_battery_buffer_8x": "ɹǝɟɟnᗺ ʎɹǝʇʇɐᗺ x8 ǝbɐʇןoΛ ɥbıH", "block.gtceu.hv_bender": "ɹ§II ɹǝpuǝᗺ pǝɔuɐʌpⱯ9§", + "block.gtceu.hv_block_breaker": "ɹ§II ɹǝʞɐǝɹᗺ ʞɔoןᗺ pǝɔuɐʌpⱯ9§", "block.gtceu.hv_brewery": "ɹ§II ʎɹǝʍǝɹᗺ pǝɔuɐʌpⱯ9§", "block.gtceu.hv_canner": "ɹ§II ɹǝuuɐƆ pǝɔuɐʌpⱯ9§", "block.gtceu.hv_centrifuge": "ɹ§II ǝbnɟıɹʇuǝƆ pǝɔuɐʌpⱯ9§", @@ -269,6 +272,7 @@ "block.gtceu.hv_extractor": "ɹ§II ɹoʇɔɐɹʇxƎ pǝɔuɐʌpⱯ9§", "block.gtceu.hv_extruder": "ɹ§II ɹǝpnɹʇxƎ pǝɔuɐʌpⱯ9§", "block.gtceu.hv_fermenter": "ɹ§II ɹǝʇuǝɯɹǝℲ pǝɔuɐʌpⱯ9§", + "block.gtceu.hv_fisher": "ɹ§II ɹǝɥsıℲ pǝɔuɐʌpⱯ9§", "block.gtceu.hv_fluid_drilling_rig": "bıᴚ buıןןıɹᗡ uoısnℲ pǝɔuɐʌpⱯ9§", "block.gtceu.hv_fluid_heater": "ɹ§II ɹǝʇɐǝH pınןℲ pǝɔuɐʌpⱯ9§", "block.gtceu.hv_fluid_passthrough_hatch": "ɥɔʇɐH ɥbnoɹɥʇssɐԀ pınןℲ ΛH9§", @@ -479,6 +483,7 @@ "block.gtceu.lv_battery_buffer_4x": "ɹǝɟɟnᗺ ʎɹǝʇʇɐᗺ xㄣ ǝbɐʇןoΛ ʍoꞀ", "block.gtceu.lv_battery_buffer_8x": "ɹǝɟɟnᗺ ʎɹǝʇʇɐᗺ x8 ǝbɐʇןoΛ ʍoꞀ", "block.gtceu.lv_bender": "ɹ§ ɹǝpuǝᗺ ɔısɐᗺ", + "block.gtceu.lv_block_breaker": "ɹ§ ɹǝʞɐǝɹᗺ ʞɔoןᗺ ɔısɐᗺ", "block.gtceu.lv_brewery": "ɹ§ ʎɹǝʍǝɹᗺ ɔısɐᗺ", "block.gtceu.lv_canner": "ɹ§ ɹǝuuɐƆ ɔısɐᗺ", "block.gtceu.lv_centrifuge": "ɹ§ ǝbnɟıɹʇuǝƆ ɔısɐᗺ", @@ -502,6 +507,7 @@ "block.gtceu.lv_extractor": "ɹ§ ɹoʇɔɐɹʇxƎ ɔısɐᗺ", "block.gtceu.lv_extruder": "ɹ§ ɹǝpnɹʇxƎ ɔısɐᗺ", "block.gtceu.lv_fermenter": "ɹ§ ɹǝʇuǝɯɹǝℲ ɔısɐᗺ", + "block.gtceu.lv_fisher": "ɹ§ ɹǝɥsıℲ ɔısɐᗺ", "block.gtceu.lv_fluid_heater": "ɹ§ ɹǝʇɐǝH pınןℲ ɔısɐᗺ", "block.gtceu.lv_fluid_passthrough_hatch": "ɥɔʇɐH ɥbnoɹɥʇssɐԀ pınןℲ ΛꞀㄥ§", "block.gtceu.lv_fluid_solidifier": "ɹ§ ɹǝıɟıpıןoS pınןℲ ɔısɐᗺ", @@ -556,6 +562,7 @@ "block.gtceu.mv_battery_buffer_4x": "ɹǝɟɟnᗺ ʎɹǝʇʇɐᗺ xㄣ ǝbɐʇןoΛ ɯnıpǝW", "block.gtceu.mv_battery_buffer_8x": "ɹǝɟɟnᗺ ʎɹǝʇʇɐᗺ x8 ǝbɐʇןoΛ ɯnıpǝW", "block.gtceu.mv_bender": "ɹ§ ɹǝpuǝᗺ pǝɔuɐʌpⱯq§", + "block.gtceu.mv_block_breaker": "ɹ§ ɹǝʞɐǝɹᗺ ʞɔoןᗺ pǝɔuɐʌpⱯq§", "block.gtceu.mv_brewery": "ɹ§ ʎɹǝʍǝɹᗺ pǝɔuɐʌpⱯq§", "block.gtceu.mv_canner": "ɹ§ ɹǝuuɐƆ pǝɔuɐʌpⱯq§", "block.gtceu.mv_centrifuge": "ɹ§ ǝbnɟıɹʇuǝƆ pǝɔuɐʌpⱯq§", @@ -579,6 +586,7 @@ "block.gtceu.mv_extractor": "ɹ§ ɹoʇɔɐɹʇxƎ pǝɔuɐʌpⱯq§", "block.gtceu.mv_extruder": "ɹ§ ɹǝpnɹʇxƎ pǝɔuɐʌpⱯq§", "block.gtceu.mv_fermenter": "ɹ§ ɹǝʇuǝɯɹǝℲ pǝɔuɐʌpⱯq§", + "block.gtceu.mv_fisher": "ɹ§ ɹǝɥsıℲ pǝɔuɐʌpⱯq§", "block.gtceu.mv_fluid_drilling_rig": "bıᴚ buıןןıɹᗡ uoısnℲ pǝɔuɐʌpⱯq§", "block.gtceu.mv_fluid_heater": "ɹ§ ɹǝʇɐǝH pınןℲ pǝɔuɐʌpⱯq§", "block.gtceu.mv_fluid_passthrough_hatch": "ɥɔʇɐH ɥbnoɹɥʇssɐԀ pınןℲ ΛWq§", diff --git a/fabric/src/generated/resources/assets/gtceu/lang/en_us.json b/fabric/src/generated/resources/assets/gtceu/lang/en_us.json index 7a4fead5c1..2069ebbf49 100644 --- a/fabric/src/generated/resources/assets/gtceu/lang/en_us.json +++ b/fabric/src/generated/resources/assets/gtceu/lang/en_us.json @@ -146,6 +146,7 @@ "block.gtceu.ev_battery_buffer_4x": "Extreme Voltage 4x Battery Buffer", "block.gtceu.ev_battery_buffer_8x": "Extreme Voltage 8x Battery Buffer", "block.gtceu.ev_bender": "§5Advanced Bender III§r", + "block.gtceu.ev_block_breaker": "§5Advanced Block Breaker III§r", "block.gtceu.ev_brewery": "§5Advanced Brewery III§r", "block.gtceu.ev_canner": "§5Advanced Canner III§r", "block.gtceu.ev_centrifuge": "§5Advanced Centrifuge III§r", @@ -172,6 +173,7 @@ "block.gtceu.ev_extractor": "§5Advanced Extractor III§r", "block.gtceu.ev_extruder": "§5Advanced Extruder III§r", "block.gtceu.ev_fermenter": "§5Advanced Fermenter III§r", + "block.gtceu.ev_fisher": "§5Advanced Fisher III§r", "block.gtceu.ev_fluid_drilling_rig": "§5Advanced Fusion Drilling Rig", "block.gtceu.ev_fluid_heater": "§5Advanced Fluid Heater III§r", "block.gtceu.ev_fluid_passthrough_hatch": "§5EV Fluid Passthrough Hatch", @@ -246,6 +248,7 @@ "block.gtceu.hv_battery_buffer_4x": "High Voltage 4x Battery Buffer", "block.gtceu.hv_battery_buffer_8x": "High Voltage 8x Battery Buffer", "block.gtceu.hv_bender": "§6Advanced Bender II§r", + "block.gtceu.hv_block_breaker": "§6Advanced Block Breaker II§r", "block.gtceu.hv_brewery": "§6Advanced Brewery II§r", "block.gtceu.hv_canner": "§6Advanced Canner II§r", "block.gtceu.hv_centrifuge": "§6Advanced Centrifuge II§r", @@ -269,6 +272,7 @@ "block.gtceu.hv_extractor": "§6Advanced Extractor II§r", "block.gtceu.hv_extruder": "§6Advanced Extruder II§r", "block.gtceu.hv_fermenter": "§6Advanced Fermenter II§r", + "block.gtceu.hv_fisher": "§6Advanced Fisher II§r", "block.gtceu.hv_fluid_drilling_rig": "§6Advanced Fusion Drilling Rig", "block.gtceu.hv_fluid_heater": "§6Advanced Fluid Heater II§r", "block.gtceu.hv_fluid_passthrough_hatch": "§6HV Fluid Passthrough Hatch", @@ -479,6 +483,7 @@ "block.gtceu.lv_battery_buffer_4x": "Low Voltage 4x Battery Buffer", "block.gtceu.lv_battery_buffer_8x": "Low Voltage 8x Battery Buffer", "block.gtceu.lv_bender": "Basic Bender §r", + "block.gtceu.lv_block_breaker": "Basic Block Breaker §r", "block.gtceu.lv_brewery": "Basic Brewery §r", "block.gtceu.lv_canner": "Basic Canner §r", "block.gtceu.lv_centrifuge": "Basic Centrifuge §r", @@ -502,6 +507,7 @@ "block.gtceu.lv_extractor": "Basic Extractor §r", "block.gtceu.lv_extruder": "Basic Extruder §r", "block.gtceu.lv_fermenter": "Basic Fermenter §r", + "block.gtceu.lv_fisher": "Basic Fisher §r", "block.gtceu.lv_fluid_heater": "Basic Fluid Heater §r", "block.gtceu.lv_fluid_passthrough_hatch": "§7LV Fluid Passthrough Hatch", "block.gtceu.lv_fluid_solidifier": "Basic Fluid Solidifier §r", @@ -556,6 +562,7 @@ "block.gtceu.mv_battery_buffer_4x": "Medium Voltage 4x Battery Buffer", "block.gtceu.mv_battery_buffer_8x": "Medium Voltage 8x Battery Buffer", "block.gtceu.mv_bender": "§bAdvanced Bender §r", + "block.gtceu.mv_block_breaker": "§bAdvanced Block Breaker §r", "block.gtceu.mv_brewery": "§bAdvanced Brewery §r", "block.gtceu.mv_canner": "§bAdvanced Canner §r", "block.gtceu.mv_centrifuge": "§bAdvanced Centrifuge §r", @@ -579,6 +586,7 @@ "block.gtceu.mv_extractor": "§bAdvanced Extractor §r", "block.gtceu.mv_extruder": "§bAdvanced Extruder §r", "block.gtceu.mv_fermenter": "§bAdvanced Fermenter §r", + "block.gtceu.mv_fisher": "§bAdvanced Fisher §r", "block.gtceu.mv_fluid_drilling_rig": "§bAdvanced Fusion Drilling Rig", "block.gtceu.mv_fluid_heater": "§bAdvanced Fluid Heater §r", "block.gtceu.mv_fluid_passthrough_hatch": "§bMV Fluid Passthrough Hatch", diff --git a/forge/src/generated/resources/assets/gtceu/lang/en_ud.json b/forge/src/generated/resources/assets/gtceu/lang/en_ud.json index 72a03192e4..b4aeda8815 100644 --- a/forge/src/generated/resources/assets/gtceu/lang/en_ud.json +++ b/forge/src/generated/resources/assets/gtceu/lang/en_ud.json @@ -146,6 +146,7 @@ "block.gtceu.ev_battery_buffer_4x": "ɹǝɟɟnᗺ ʎɹǝʇʇɐᗺ xㄣ ǝbɐʇןoΛ ǝɯǝɹʇxƎ", "block.gtceu.ev_battery_buffer_8x": "ɹǝɟɟnᗺ ʎɹǝʇʇɐᗺ x8 ǝbɐʇןoΛ ǝɯǝɹʇxƎ", "block.gtceu.ev_bender": "ɹ§III ɹǝpuǝᗺ pǝɔuɐʌpⱯϛ§", + "block.gtceu.ev_block_breaker": "ɹ§III ɹǝʞɐǝɹᗺ ʞɔoןᗺ pǝɔuɐʌpⱯϛ§", "block.gtceu.ev_brewery": "ɹ§III ʎɹǝʍǝɹᗺ pǝɔuɐʌpⱯϛ§", "block.gtceu.ev_canner": "ɹ§III ɹǝuuɐƆ pǝɔuɐʌpⱯϛ§", "block.gtceu.ev_centrifuge": "ɹ§III ǝbnɟıɹʇuǝƆ pǝɔuɐʌpⱯϛ§", @@ -172,6 +173,7 @@ "block.gtceu.ev_extractor": "ɹ§III ɹoʇɔɐɹʇxƎ pǝɔuɐʌpⱯϛ§", "block.gtceu.ev_extruder": "ɹ§III ɹǝpnɹʇxƎ pǝɔuɐʌpⱯϛ§", "block.gtceu.ev_fermenter": "ɹ§III ɹǝʇuǝɯɹǝℲ pǝɔuɐʌpⱯϛ§", + "block.gtceu.ev_fisher": "ɹ§III ɹǝɥsıℲ pǝɔuɐʌpⱯϛ§", "block.gtceu.ev_fluid_drilling_rig": "bıᴚ buıןןıɹᗡ uoısnℲ pǝɔuɐʌpⱯϛ§", "block.gtceu.ev_fluid_heater": "ɹ§III ɹǝʇɐǝH pınןℲ pǝɔuɐʌpⱯϛ§", "block.gtceu.ev_fluid_passthrough_hatch": "ɥɔʇɐH ɥbnoɹɥʇssɐԀ pınןℲ ΛƎϛ§", @@ -246,6 +248,7 @@ "block.gtceu.hv_battery_buffer_4x": "ɹǝɟɟnᗺ ʎɹǝʇʇɐᗺ xㄣ ǝbɐʇןoΛ ɥbıH", "block.gtceu.hv_battery_buffer_8x": "ɹǝɟɟnᗺ ʎɹǝʇʇɐᗺ x8 ǝbɐʇןoΛ ɥbıH", "block.gtceu.hv_bender": "ɹ§II ɹǝpuǝᗺ pǝɔuɐʌpⱯ9§", + "block.gtceu.hv_block_breaker": "ɹ§II ɹǝʞɐǝɹᗺ ʞɔoןᗺ pǝɔuɐʌpⱯ9§", "block.gtceu.hv_brewery": "ɹ§II ʎɹǝʍǝɹᗺ pǝɔuɐʌpⱯ9§", "block.gtceu.hv_canner": "ɹ§II ɹǝuuɐƆ pǝɔuɐʌpⱯ9§", "block.gtceu.hv_centrifuge": "ɹ§II ǝbnɟıɹʇuǝƆ pǝɔuɐʌpⱯ9§", @@ -269,6 +272,7 @@ "block.gtceu.hv_extractor": "ɹ§II ɹoʇɔɐɹʇxƎ pǝɔuɐʌpⱯ9§", "block.gtceu.hv_extruder": "ɹ§II ɹǝpnɹʇxƎ pǝɔuɐʌpⱯ9§", "block.gtceu.hv_fermenter": "ɹ§II ɹǝʇuǝɯɹǝℲ pǝɔuɐʌpⱯ9§", + "block.gtceu.hv_fisher": "ɹ§II ɹǝɥsıℲ pǝɔuɐʌpⱯ9§", "block.gtceu.hv_fluid_drilling_rig": "bıᴚ buıןןıɹᗡ uoısnℲ pǝɔuɐʌpⱯ9§", "block.gtceu.hv_fluid_heater": "ɹ§II ɹǝʇɐǝH pınןℲ pǝɔuɐʌpⱯ9§", "block.gtceu.hv_fluid_passthrough_hatch": "ɥɔʇɐH ɥbnoɹɥʇssɐԀ pınןℲ ΛH9§", @@ -479,6 +483,7 @@ "block.gtceu.lv_battery_buffer_4x": "ɹǝɟɟnᗺ ʎɹǝʇʇɐᗺ xㄣ ǝbɐʇןoΛ ʍoꞀ", "block.gtceu.lv_battery_buffer_8x": "ɹǝɟɟnᗺ ʎɹǝʇʇɐᗺ x8 ǝbɐʇןoΛ ʍoꞀ", "block.gtceu.lv_bender": "ɹ§ ɹǝpuǝᗺ ɔısɐᗺ", + "block.gtceu.lv_block_breaker": "ɹ§ ɹǝʞɐǝɹᗺ ʞɔoןᗺ ɔısɐᗺ", "block.gtceu.lv_brewery": "ɹ§ ʎɹǝʍǝɹᗺ ɔısɐᗺ", "block.gtceu.lv_canner": "ɹ§ ɹǝuuɐƆ ɔısɐᗺ", "block.gtceu.lv_centrifuge": "ɹ§ ǝbnɟıɹʇuǝƆ ɔısɐᗺ", @@ -502,6 +507,7 @@ "block.gtceu.lv_extractor": "ɹ§ ɹoʇɔɐɹʇxƎ ɔısɐᗺ", "block.gtceu.lv_extruder": "ɹ§ ɹǝpnɹʇxƎ ɔısɐᗺ", "block.gtceu.lv_fermenter": "ɹ§ ɹǝʇuǝɯɹǝℲ ɔısɐᗺ", + "block.gtceu.lv_fisher": "ɹ§ ɹǝɥsıℲ ɔısɐᗺ", "block.gtceu.lv_fluid_heater": "ɹ§ ɹǝʇɐǝH pınןℲ ɔısɐᗺ", "block.gtceu.lv_fluid_passthrough_hatch": "ɥɔʇɐH ɥbnoɹɥʇssɐԀ pınןℲ ΛꞀㄥ§", "block.gtceu.lv_fluid_solidifier": "ɹ§ ɹǝıɟıpıןoS pınןℲ ɔısɐᗺ", @@ -556,6 +562,7 @@ "block.gtceu.mv_battery_buffer_4x": "ɹǝɟɟnᗺ ʎɹǝʇʇɐᗺ xㄣ ǝbɐʇןoΛ ɯnıpǝW", "block.gtceu.mv_battery_buffer_8x": "ɹǝɟɟnᗺ ʎɹǝʇʇɐᗺ x8 ǝbɐʇןoΛ ɯnıpǝW", "block.gtceu.mv_bender": "ɹ§ ɹǝpuǝᗺ pǝɔuɐʌpⱯq§", + "block.gtceu.mv_block_breaker": "ɹ§ ɹǝʞɐǝɹᗺ ʞɔoןᗺ pǝɔuɐʌpⱯq§", "block.gtceu.mv_brewery": "ɹ§ ʎɹǝʍǝɹᗺ pǝɔuɐʌpⱯq§", "block.gtceu.mv_canner": "ɹ§ ɹǝuuɐƆ pǝɔuɐʌpⱯq§", "block.gtceu.mv_centrifuge": "ɹ§ ǝbnɟıɹʇuǝƆ pǝɔuɐʌpⱯq§", @@ -579,6 +586,7 @@ "block.gtceu.mv_extractor": "ɹ§ ɹoʇɔɐɹʇxƎ pǝɔuɐʌpⱯq§", "block.gtceu.mv_extruder": "ɹ§ ɹǝpnɹʇxƎ pǝɔuɐʌpⱯq§", "block.gtceu.mv_fermenter": "ɹ§ ɹǝʇuǝɯɹǝℲ pǝɔuɐʌpⱯq§", + "block.gtceu.mv_fisher": "ɹ§ ɹǝɥsıℲ pǝɔuɐʌpⱯq§", "block.gtceu.mv_fluid_drilling_rig": "bıᴚ buıןןıɹᗡ uoısnℲ pǝɔuɐʌpⱯq§", "block.gtceu.mv_fluid_heater": "ɹ§ ɹǝʇɐǝH pınןℲ pǝɔuɐʌpⱯq§", "block.gtceu.mv_fluid_passthrough_hatch": "ɥɔʇɐH ɥbnoɹɥʇssɐԀ pınןℲ ΛWq§", diff --git a/forge/src/generated/resources/assets/gtceu/lang/en_us.json b/forge/src/generated/resources/assets/gtceu/lang/en_us.json index 7a4fead5c1..2069ebbf49 100644 --- a/forge/src/generated/resources/assets/gtceu/lang/en_us.json +++ b/forge/src/generated/resources/assets/gtceu/lang/en_us.json @@ -146,6 +146,7 @@ "block.gtceu.ev_battery_buffer_4x": "Extreme Voltage 4x Battery Buffer", "block.gtceu.ev_battery_buffer_8x": "Extreme Voltage 8x Battery Buffer", "block.gtceu.ev_bender": "§5Advanced Bender III§r", + "block.gtceu.ev_block_breaker": "§5Advanced Block Breaker III§r", "block.gtceu.ev_brewery": "§5Advanced Brewery III§r", "block.gtceu.ev_canner": "§5Advanced Canner III§r", "block.gtceu.ev_centrifuge": "§5Advanced Centrifuge III§r", @@ -172,6 +173,7 @@ "block.gtceu.ev_extractor": "§5Advanced Extractor III§r", "block.gtceu.ev_extruder": "§5Advanced Extruder III§r", "block.gtceu.ev_fermenter": "§5Advanced Fermenter III§r", + "block.gtceu.ev_fisher": "§5Advanced Fisher III§r", "block.gtceu.ev_fluid_drilling_rig": "§5Advanced Fusion Drilling Rig", "block.gtceu.ev_fluid_heater": "§5Advanced Fluid Heater III§r", "block.gtceu.ev_fluid_passthrough_hatch": "§5EV Fluid Passthrough Hatch", @@ -246,6 +248,7 @@ "block.gtceu.hv_battery_buffer_4x": "High Voltage 4x Battery Buffer", "block.gtceu.hv_battery_buffer_8x": "High Voltage 8x Battery Buffer", "block.gtceu.hv_bender": "§6Advanced Bender II§r", + "block.gtceu.hv_block_breaker": "§6Advanced Block Breaker II§r", "block.gtceu.hv_brewery": "§6Advanced Brewery II§r", "block.gtceu.hv_canner": "§6Advanced Canner II§r", "block.gtceu.hv_centrifuge": "§6Advanced Centrifuge II§r", @@ -269,6 +272,7 @@ "block.gtceu.hv_extractor": "§6Advanced Extractor II§r", "block.gtceu.hv_extruder": "§6Advanced Extruder II§r", "block.gtceu.hv_fermenter": "§6Advanced Fermenter II§r", + "block.gtceu.hv_fisher": "§6Advanced Fisher II§r", "block.gtceu.hv_fluid_drilling_rig": "§6Advanced Fusion Drilling Rig", "block.gtceu.hv_fluid_heater": "§6Advanced Fluid Heater II§r", "block.gtceu.hv_fluid_passthrough_hatch": "§6HV Fluid Passthrough Hatch", @@ -479,6 +483,7 @@ "block.gtceu.lv_battery_buffer_4x": "Low Voltage 4x Battery Buffer", "block.gtceu.lv_battery_buffer_8x": "Low Voltage 8x Battery Buffer", "block.gtceu.lv_bender": "Basic Bender §r", + "block.gtceu.lv_block_breaker": "Basic Block Breaker §r", "block.gtceu.lv_brewery": "Basic Brewery §r", "block.gtceu.lv_canner": "Basic Canner §r", "block.gtceu.lv_centrifuge": "Basic Centrifuge §r", @@ -502,6 +507,7 @@ "block.gtceu.lv_extractor": "Basic Extractor §r", "block.gtceu.lv_extruder": "Basic Extruder §r", "block.gtceu.lv_fermenter": "Basic Fermenter §r", + "block.gtceu.lv_fisher": "Basic Fisher §r", "block.gtceu.lv_fluid_heater": "Basic Fluid Heater §r", "block.gtceu.lv_fluid_passthrough_hatch": "§7LV Fluid Passthrough Hatch", "block.gtceu.lv_fluid_solidifier": "Basic Fluid Solidifier §r", @@ -556,6 +562,7 @@ "block.gtceu.mv_battery_buffer_4x": "Medium Voltage 4x Battery Buffer", "block.gtceu.mv_battery_buffer_8x": "Medium Voltage 8x Battery Buffer", "block.gtceu.mv_bender": "§bAdvanced Bender §r", + "block.gtceu.mv_block_breaker": "§bAdvanced Block Breaker §r", "block.gtceu.mv_brewery": "§bAdvanced Brewery §r", "block.gtceu.mv_canner": "§bAdvanced Canner §r", "block.gtceu.mv_centrifuge": "§bAdvanced Centrifuge §r", @@ -579,6 +586,7 @@ "block.gtceu.mv_extractor": "§bAdvanced Extractor §r", "block.gtceu.mv_extruder": "§bAdvanced Extruder §r", "block.gtceu.mv_fermenter": "§bAdvanced Fermenter §r", + "block.gtceu.mv_fisher": "§bAdvanced Fisher §r", "block.gtceu.mv_fluid_drilling_rig": "§bAdvanced Fusion Drilling Rig", "block.gtceu.mv_fluid_heater": "§bAdvanced Fluid Heater §r", "block.gtceu.mv_fluid_passthrough_hatch": "§bMV Fluid Passthrough Hatch",