/* * spotless:off * KubaTech - Gregtech Addon * Copyright (C) 2022 - 2024 kuba6000 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see . * spotless:on */ package kubatech.api.implementations; import static gregtech.api.metatileentity.BaseTileEntity.TOOLTIP_DELAY; import static kubatech.api.Variables.ln2; import static kubatech.api.Variables.ln4; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.function.Function; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumChatFormatting; import net.minecraftforge.fluids.FluidStack; import com.gtnewhorizons.modularui.api.drawable.IDrawable; import com.gtnewhorizons.modularui.api.drawable.Text; import com.gtnewhorizons.modularui.api.drawable.UITexture; import com.gtnewhorizons.modularui.api.math.Color; import com.gtnewhorizons.modularui.api.math.MainAxisAlignment; import com.gtnewhorizons.modularui.api.math.Pos2d; import com.gtnewhorizons.modularui.api.screen.ITileWithModularUI; import com.gtnewhorizons.modularui.api.screen.ModularUIContext; import com.gtnewhorizons.modularui.api.screen.ModularWindow; import com.gtnewhorizons.modularui.api.screen.UIBuildContext; import com.gtnewhorizons.modularui.api.widget.Widget; import com.gtnewhorizons.modularui.common.builder.UIBuilder; import com.gtnewhorizons.modularui.common.builder.UIInfo; import com.gtnewhorizons.modularui.common.internal.wrapper.ModularGui; import com.gtnewhorizons.modularui.common.internal.wrapper.ModularUIContainer; import com.gtnewhorizons.modularui.common.widget.Column; import com.gtnewhorizons.modularui.common.widget.DrawableWidget; import com.gtnewhorizons.modularui.common.widget.DynamicPositionedColumn; import com.gtnewhorizons.modularui.common.widget.DynamicPositionedRow; import com.gtnewhorizons.modularui.common.widget.SlotWidget; import gregtech.api.enums.GT_Values; import gregtech.api.gui.modularui.GT_UITextures; import gregtech.api.interfaces.metatileentity.IMetaTileEntity; import gregtech.api.metatileentity.BaseMetaTileEntity; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_ExtendedPowerMultiBlockBase; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_OutputBus; import gregtech.common.tileentities.machines.GT_MetaTileEntity_Hatch_OutputBus_ME; import kubatech.Tags; public abstract class KubaTechGTMultiBlockBase> extends GT_MetaTileEntity_ExtendedPowerMultiBlockBase { @Deprecated public final int mEUt = 0; @SuppressWarnings("unchecked") protected static > UIInfo createKTMetaTileEntityUI( KTContainerConstructor containerConstructor) { return UIBuilder.of() .container((player, world, x, y, z) -> { TileEntity te = world.getTileEntity(x, y, z); if (te instanceof BaseMetaTileEntity) { IMetaTileEntity mte = ((BaseMetaTileEntity) te).getMetaTileEntity(); if (!(mte instanceof KubaTechGTMultiBlockBase)) return null; final UIBuildContext buildContext = new UIBuildContext(player); final ModularWindow window = ((ITileWithModularUI) te).createWindow(buildContext); return containerConstructor.of(new ModularUIContext(buildContext, te::markDirty), window, (K) mte); } return null; }) .gui(((player, world, x, y, z) -> { if (!world.isRemote) return null; TileEntity te = world.getTileEntity(x, y, z); if (te instanceof BaseMetaTileEntity) { IMetaTileEntity mte = ((BaseMetaTileEntity) te).getMetaTileEntity(); if (!(mte instanceof KubaTechGTMultiBlockBase)) return null; final UIBuildContext buildContext = new UIBuildContext(player); final ModularWindow window = ((ITileWithModularUI) te).createWindow(buildContext); return new ModularGui( containerConstructor.of(new ModularUIContext(buildContext, null), window, (K) mte)); } return null; })) .build(); } @FunctionalInterface protected interface KTContainerConstructor> { ModularUIContainer of(ModularUIContext context, ModularWindow mainWindow, T multiBlock); } protected KubaTechGTMultiBlockBase(int aID, String aName, String aNameRegional) { super(aID, aName, aNameRegional); } protected KubaTechGTMultiBlockBase(String aName) { super(aName); } /** * Enables infinite overclocking (will give more outputs with more energy past 1 tick) Currently doesn't support * recipe inputs * * @return If this supports infinite overclock */ protected boolean isOverclockingInfinite() { return false; } /** * @return The minimum amount of ticks this multiblock can overclock to */ protected int getOverclockTimeLimit() { return 1; } @Override protected void calculateOverclockedNessMultiInternal(long aEUt, int aDuration, int mAmperage, long maxInputVoltage, boolean perfectOC) { calculateOverclock(aEUt, aDuration, getMaxInputEu(), perfectOC); } /** * @param aEUt Recipe EU/t * @param aDuration Recipe duration (in ticks) * @param maxInputEU The amount of energy we want to overclock to * @param isPerfect Is this overclock perfect ? * @return The amount of overclocks */ protected int calculateOverclock(long aEUt, int aDuration, final long maxInputEU, final boolean isPerfect) { final int minDuration = getOverclockTimeLimit(); int tiers = (int) (Math.log((double) maxInputEU / (double) aEUt) / ln4); if (tiers <= 0) { this.lEUt = aEUt; this.mMaxProgresstime = aDuration; return 0; } int durationTiers = (int) Math .ceil(Math.log((double) aDuration / (double) minDuration) / (isPerfect ? ln4 : ln2)); if (durationTiers < 0) durationTiers = 0; // We do not support downclocks (yet) if (durationTiers > tiers) durationTiers = tiers; if (!isOverclockingInfinite()) { tiers = durationTiers; if (tiers == 0) { this.lEUt = aEUt; this.mMaxProgresstime = aDuration; return 0; } this.lEUt = aEUt << (tiers << 1); aDuration >>= isPerfect ? (tiers << 1) : tiers; if (aDuration < minDuration) aDuration = minDuration; this.mMaxProgresstime = aDuration; return tiers; } this.lEUt = aEUt << (tiers << 1); aDuration >>= isPerfect ? (durationTiers << 1) : durationTiers; int dMulti = tiers - durationTiers; if (dMulti > 0) { dMulti = 1 << (isPerfect ? (dMulti << 1) : dMulti); // TODO: Use more inputs??? for (ItemStack mOutputItem : this.mOutputItems) mOutputItem.stackSize *= dMulti; for (FluidStack mOutputFluid : this.mOutputFluids) mOutputFluid.amount *= dMulti; } if (aDuration < minDuration) aDuration = minDuration; this.mMaxProgresstime = aDuration; return tiers; } protected int calculateOverclock(long aEUt, int aDuration, boolean isPerfect) { return calculateOverclock(aEUt, aDuration, getMaxInputEu(), isPerfect); } protected int calculateOverclock(long aEUt, int aDuration) { return calculateOverclock(aEUt, aDuration, false); } protected int calculatePerfectOverclock(long aEUt, int aDuration) { return calculateOverclock(aEUt, aDuration, true); } public int getVoltageTier() { return (int) getVoltageTierExact(); } public double getVoltageTierExact() { return Math.log((double) getMaxInputEu() / 8d) / ln4 + 1e-8d; } protected boolean tryOutputAll(List list) { return tryOutputAll(list, l -> Collections.singletonList((ItemStack) l)); } protected boolean tryOutputAll(List list, Function> mappingFunction) { if (list == null || list.isEmpty() || mappingFunction == null) return false; int emptySlots = 0; boolean ignoreEmptiness = false; for (GT_MetaTileEntity_Hatch_OutputBus i : mOutputBusses) { if (i instanceof GT_MetaTileEntity_Hatch_OutputBus_ME) { ignoreEmptiness = true; break; } for (int j = 0; j < i.getSizeInventory(); j++) if (i.isValidSlot(j)) if (i.getStackInSlot(j) == null) emptySlots++; } if (emptySlots == 0 && !ignoreEmptiness) return false; boolean wasSomethingRemoved = false; while (!list.isEmpty()) { List toOutputNow = mappingFunction.apply(list.get(0)); if (toOutputNow == null) { list.remove(0); continue; } if (!ignoreEmptiness && emptySlots < toOutputNow.size()) break; emptySlots -= toOutputNow.size(); list.remove(0); wasSomethingRemoved = true; for (ItemStack stack : toOutputNow) { addOutput(stack); } } return wasSomethingRemoved; } @Override public boolean isCorrectMachinePart(ItemStack aStack) { return true; } @Override public int getMaxEfficiency(ItemStack aStack) { return 10000; } @Override public int getDamageToComponent(ItemStack aStack) { return 0; } @Override public boolean explodesOnComponentBreak(ItemStack aStack) { return false; } // UI stuff public static final UITexture PICTURE_KUBATECH_LOGO = UITexture.fullImage(Tags.MODID, "gui/logo_13x15_dark"); @Override public void addGregTechLogo(ModularWindow.Builder builder) { builder.widget( new DrawableWidget().setDrawable(PICTURE_KUBATECH_LOGO) .setSize(13, 15) .setPos(191 - 13, 86 - 15) .addTooltip(new Text(Tags.MODNAME).color(Color.GRAY.normal)) .setTooltipShowUpDelay(TOOLTIP_DELAY)); } protected List slotWidgets = new ArrayList<>(1); public void createInventorySlots() { final SlotWidget inventorySlot = new SlotWidget(inventoryHandler, 1); inventorySlot.setBackground(GT_UITextures.SLOT_DARK_GRAY); slotWidgets.add(inventorySlot); } @Override public Pos2d getPowerSwitchButtonPos() { return new Pos2d(174, 166 - (slotWidgets.size() * 18)); } @Override public void addUIWidgets(ModularWindow.Builder builder, UIBuildContext buildContext) { builder.widget( new DrawableWidget().setDrawable(GT_UITextures.PICTURE_SCREEN_BLACK) .setPos(4, 4) .setSize(190, 85)); slotWidgets.clear(); createInventorySlots(); Column slotsColumn = new Column(); for (int i = slotWidgets.size() - 1; i >= 0; i--) { slotsColumn.widget(slotWidgets.get(i)); } builder.widget( slotsColumn.setAlignment(MainAxisAlignment.END) .setPos(173, 167 - 1)); final DynamicPositionedColumn screenElements = new DynamicPositionedColumn(); drawTexts(screenElements, slotWidgets.size() > 0 ? slotWidgets.get(0) : null); builder.widget(screenElements); builder.widget(createPowerSwitchButton(builder)) .widget(createVoidExcessButton(builder)) .widget(createInputSeparationButton(builder)) .widget(createBatchModeButton(builder)) .widget(createLockToSingleRecipeButton(builder)); DynamicPositionedRow configurationElements = new DynamicPositionedRow(); addConfigurationWidgets(configurationElements, buildContext); builder.widget( configurationElements.setSpace(2) .setAlignment(MainAxisAlignment.SPACE_BETWEEN) .setPos(getRecipeLockingButtonPos().add(18, 0))); } protected void addConfigurationWidgets(DynamicPositionedRow configurationElements, UIBuildContext buildContext) { } protected static String voltageTooltipFormatted(int tier) { return GT_Values.TIER_COLORS[tier] + GT_Values.VN[tier] + EnumChatFormatting.GRAY; } protected final Function isFixed = widget -> getIdealStatus() == getRepairStatus() && mMachine; protected static final Function toggleButtonTextureGetter = val -> val == 0 ? GT_UITextures.OVERLAY_BUTTON_CROSS : GT_UITextures.OVERLAY_BUTTON_CHECKMARK; protected static final Function toggleButtonBackgroundGetter = val -> new IDrawable[] { val == 0 ? GT_UITextures.BUTTON_STANDARD : GT_UITextures.BUTTON_STANDARD_PRESSED }; }