diff options
author | Raven Szewczyk <git@eigenraven.me> | 2024-05-25 14:42:41 +0100 |
---|---|---|
committer | Raven Szewczyk <git@eigenraven.me> | 2024-05-25 14:42:41 +0100 |
commit | 8aa595f083b5c3e43246119fca5f4263f81e851b (patch) | |
tree | 157d2b528e4b4ea0321022ebfee398f559a9e121 /src/main/java/kubatech/api | |
parent | 14a97a5a177399cd8df7f246856c08fcda441afd (diff) | |
download | GT5-Unofficial-8aa595f083b5c3e43246119fca5f4263f81e851b.tar.gz GT5-Unofficial-8aa595f083b5c3e43246119fca5f4263f81e851b.tar.bz2 GT5-Unofficial-8aa595f083b5c3e43246119fca5f4263f81e851b.zip |
Migrate kubatech source code
Diffstat (limited to 'src/main/java/kubatech/api')
-rw-r--r-- | src/main/java/kubatech/api/DynamicInventory.java | 469 | ||||
-rw-r--r-- | src/main/java/kubatech/api/LoaderReference.java | 23 | ||||
-rw-r--r-- | src/main/java/kubatech/api/Variables.java | 63 | ||||
-rw-r--r-- | src/main/java/kubatech/api/enums/ItemList.java | 226 | ||||
-rw-r--r-- | src/main/java/kubatech/api/helpers/GTHelper.java | 99 | ||||
-rw-r--r-- | src/main/java/kubatech/api/helpers/ReflectionHelper.java | 205 | ||||
-rw-r--r-- | src/main/java/kubatech/api/helpers/UUIDFinder.java | 43 | ||||
-rw-r--r-- | src/main/java/kubatech/api/implementations/KubaTechGTMultiBlockBase.java | 341 | ||||
-rw-r--r-- | src/main/java/kubatech/api/tea/TeaNetwork.java | 93 | ||||
-rw-r--r-- | src/main/java/kubatech/api/tileentity/CustomTileEntityPacketHandler.java | 28 | ||||
-rw-r--r-- | src/main/java/kubatech/api/utils/ItemUtils.java | 26 | ||||
-rw-r--r-- | src/main/java/kubatech/api/utils/ModUtils.java | 38 | ||||
-rw-r--r-- | src/main/java/kubatech/api/utils/StringUtils.java | 52 |
13 files changed, 1706 insertions, 0 deletions
diff --git a/src/main/java/kubatech/api/DynamicInventory.java b/src/main/java/kubatech/api/DynamicInventory.java new file mode 100644 index 0000000000..ef89c3a341 --- /dev/null +++ b/src/main/java/kubatech/api/DynamicInventory.java @@ -0,0 +1,469 @@ +package kubatech.api; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Supplier; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumChatFormatting; + +import org.lwjgl.opengl.GL11; + +import com.gtnewhorizons.modularui.api.GlStateManager; +import com.gtnewhorizons.modularui.api.ModularUITextures; +import com.gtnewhorizons.modularui.api.drawable.IDrawable; +import com.gtnewhorizons.modularui.api.drawable.ItemDrawable; +import com.gtnewhorizons.modularui.api.drawable.Text; +import com.gtnewhorizons.modularui.api.drawable.UITexture; +import com.gtnewhorizons.modularui.api.math.Alignment; +import com.gtnewhorizons.modularui.api.math.Color; +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.internal.Theme; +import com.gtnewhorizons.modularui.common.internal.wrapper.ModularGui; +import com.gtnewhorizons.modularui.common.widget.ButtonWidget; +import com.gtnewhorizons.modularui.common.widget.ChangeableWidget; +import com.gtnewhorizons.modularui.common.widget.DynamicPositionedRow; +import com.gtnewhorizons.modularui.common.widget.FakeSyncWidget; +import com.gtnewhorizons.modularui.common.widget.Scrollable; +import com.kuba6000.mobsinfo.api.utils.ItemID; + +import kubatech.api.helpers.GTHelper; +import kubatech.api.utils.ModUtils; + +public class DynamicInventory<T> { + + int width, height; + Supplier<Integer> slotsGetter; + private int slots = 0; + private int usedSlots = 0; + List<T> inventory; + TInventoryGetter<T> inventoryGetter; + TInventoryInjector inventoryInjector = null; + TInventoryExtractor<T> inventoryExtractor = null; + TInventoryReplacerOrMerger inventoryReplacer = null; + Supplier<Boolean> isEnabledGetter = null; + boolean isEnabled = true; + + public DynamicInventory(int width, int height, Supplier<Integer> slotsGetter, List<T> inventory, + TInventoryGetter<T> inventoryGetter) { + this.width = width; + this.height = height; + this.slotsGetter = slotsGetter; + this.inventory = inventory; + this.inventoryGetter = inventoryGetter; + } + + public DynamicInventory<T> allowInventoryInjection(TInventoryInjector inventoryInjector) { + this.inventoryInjector = inventoryInjector; + return this; + } + + public DynamicInventory<T> allowInventoryExtraction(TInventoryExtractor<T> inventoryExtractor) { + this.inventoryExtractor = inventoryExtractor; + return this; + } + + public DynamicInventory<T> allowInventoryReplace(TInventoryReplacerOrMerger inventoryReplacer) { + this.inventoryReplacer = inventoryReplacer; + return this; + } + + public DynamicInventory<T> setEnabled(Supplier<Boolean> isEnabled) { + this.isEnabledGetter = isEnabled; + return this; + } + + public UITexture getItemSlot() { + return ModularUITextures.ITEM_SLOT; + } + + @SuppressWarnings("UnstableApiUsage") + public Widget asWidget(ModularWindow.Builder builder, UIBuildContext buildContext) { + ChangeableWidget container = new ChangeableWidget(() -> createWidget(buildContext.getPlayer())); + + // TODO: Only reset the widget when there are more slot stacks, otherwise just refresh them somehow + + container.attachSyncer(new FakeSyncWidget.IntegerSyncer(() -> { + if (slots != slotsGetter.get()) { + slots = slotsGetter.get(); + container.notifyChangeNoSync(); + } + return slots; + }, i -> { + if (slots != i) { + slots = i; + container.notifyChangeNoSync(); + } + }), builder) + .attachSyncer(new FakeSyncWidget.IntegerSyncer(() -> { + if (usedSlots != inventory.size()) { + usedSlots = inventory.size(); + container.notifyChangeNoSync(); + } + return usedSlots; + }, i -> { + if (usedSlots != i) { + usedSlots = i; + container.notifyChangeNoSync(); + } + }), builder) + .attachSyncer(new FakeSyncWidget.ListSyncer<>(() -> { + HashMap<ItemID, Integer> itemMap = new HashMap<>(); + HashMap<ItemID, ItemStack> stackMap = new HashMap<>(); + HashMap<ItemID, ArrayList<Integer>> realSlotMap = new HashMap<>(); + for (int i = 0, mStorageSize = inventory.size(); i < mStorageSize; i++) { + ItemStack stack = inventoryGetter.get(inventory.get(i)); + ItemID id = ItemID.createNoCopy(stack, false); + itemMap.merge(id, 1, Integer::sum); + stackMap.putIfAbsent(id, stack); + realSlotMap.computeIfAbsent(id, unused -> new ArrayList<>()) + .add(i); + } + List<GTHelper.StackableItemSlot> newDrawables = new ArrayList<>(); + for (Map.Entry<ItemID, Integer> entry : itemMap.entrySet()) { + newDrawables.add( + new GTHelper.StackableItemSlot( + entry.getValue(), + stackMap.get(entry.getKey()), + realSlotMap.get(entry.getKey()))); + } + if (!Objects.equals(newDrawables, drawables)) { + drawables = newDrawables; + container.notifyChangeNoSync(); + } + return drawables; + }, l -> { + drawables.clear(); + drawables.addAll(l); + container.notifyChangeNoSync(); + }, (buffer, i) -> { + try { + i.write(buffer); + } catch (IOException e) { + throw new RuntimeException(e); + } + }, buffer -> { + try { + return GTHelper.StackableItemSlot.read(buffer); + } catch (IOException e) { + throw new RuntimeException(e); + } + }), builder); + if (isEnabledGetter != null) { + container.attachSyncer(new FakeSyncWidget.BooleanSyncer(isEnabledGetter, i -> isEnabled = i), builder); + } + return container; + } + + List<GTHelper.StackableItemSlot> drawables = new ArrayList<>(); + + private Widget createWidget(EntityPlayer player) { + Scrollable dynamicInventoryWidget = new Scrollable().setVerticalScroll(); + + ArrayList<Widget> buttons = new ArrayList<>(); + + if (!ModUtils.isClientThreaded()) { + HashMap<ItemID, Integer> itemMap = new HashMap<>(); + HashMap<ItemID, ItemStack> stackMap = new HashMap<>(); + HashMap<ItemID, ArrayList<Integer>> realSlotMap = new HashMap<>(); + for (int i = 0, inventorySize = inventory.size(); i < inventorySize; i++) { + ItemStack stack = inventoryGetter.get(inventory.get(i)); + ItemID id = ItemID.createNoCopy(stack, false); + itemMap.merge(id, 1, Integer::sum); + stackMap.putIfAbsent(id, stack); + realSlotMap.computeIfAbsent(id, unused -> new ArrayList<>()) + .add(i); + } + drawables = new ArrayList<>(); + for (Map.Entry<ItemID, Integer> entry : itemMap.entrySet()) { + drawables.add( + new GTHelper.StackableItemSlot( + entry.getValue(), + stackMap.get(entry.getKey()), + realSlotMap.get(entry.getKey()))); + } + } + + for (int ID = 0; ID < drawables.size(); ID++) { + final int finalID = ID; + buttons.add(new ButtonWidget() { + + @Override + public void drawBackground(float partialTicks) { + super.drawBackground(partialTicks); + if (!isEnabled) { + GL11.glDisable(GL11.GL_LIGHTING); + GL11.glEnable(GL11.GL_BLEND); + GlStateManager.colorMask(true, true, true, false); + ModularGui.drawSolidRect(1, 1, 16, 16, Color.withAlpha(Color.BLACK.normal, 0x80)); + GlStateManager.colorMask(true, true, true, true); + GL11.glDisable(GL11.GL_BLEND); + } + // Copied from SlotWidget#draw + else if (isHovering() && !getContext().getCursor() + .hasDraggable()) { + GL11.glDisable(GL11.GL_LIGHTING); + GL11.glEnable(GL11.GL_BLEND); + GlStateManager.colorMask(true, true, true, false); + ModularGui.drawSolidRect(1, 1, 16, 16, Theme.INSTANCE.getSlotHighlight()); + GlStateManager.colorMask(true, true, true, true); + GL11.glDisable(GL11.GL_BLEND); + } + } + }.setPlayClickSound(false) + .setOnClick((clickData, widget) -> { + if (!(player instanceof EntityPlayerMP)) return; + if (!isEnabledGetter.get()) return; + + if (clickData.mouseButton == 2) { + // special button handler goes here + if (drawables.size() <= finalID) return; + if (player.capabilities.isCreativeMode && player.inventory.getItemStack() == null) { + int realID = drawables.get(finalID).realSlots.get(0); + ItemStack stack = inventoryGetter.get(inventory.get(realID)) + .copy(); + stack.stackSize = stack.getMaxStackSize(); + player.inventory.setItemStack(stack); + ((EntityPlayerMP) player).isChangingQuantityOnly = false; + ((EntityPlayerMP) player).updateHeldItem(); + return; + } + } else if (clickData.shift) { + if (inventoryExtractor == null) return; + if (drawables.size() <= finalID) return; + int realID = drawables.get(finalID).realSlots.get(0); + T removed = inventoryExtractor.extract(realID); + if (removed != null) { + ItemStack stack = inventoryGetter.get(removed); + if (player.inventory.addItemStackToInventory(stack)) + player.inventoryContainer.detectAndSendChanges(); + else player.entityDropItem(stack, 0.f); + return; + } + } else { + ItemStack input = player.inventory.getItemStack(); + if (input != null) { + if (drawables.size() > finalID) { + if (inventoryReplacer == null) return; + int realID = drawables.get(finalID).realSlots.get(0); + ItemStack removed = inventoryReplacer.replaceOrMerge(realID, input); + if (removed == null) return; + player.inventory.setItemStack(removed.stackSize == 0 ? null : removed); + } else { + if (inventoryInjector == null) return; + if (clickData.mouseButton == 1) { + ItemStack copy = input.copy(); + copy.stackSize = 1; + ItemStack leftover = inventoryInjector.inject(copy); + if (leftover == null) return; + input.stackSize--; + if (input.stackSize > 0) { + ((EntityPlayerMP) player).isChangingQuantityOnly = true; + ((EntityPlayerMP) player).updateHeldItem(); + return; + } else player.inventory.setItemStack(null); + } else { + ItemStack leftover = inventoryInjector.inject(input); + if (leftover == null) return; + if (input.stackSize > 0) { + ((EntityPlayerMP) player).isChangingQuantityOnly = true; + ((EntityPlayerMP) player).updateHeldItem(); + return; + } else player.inventory.setItemStack(null); + } + } + ((EntityPlayerMP) player).isChangingQuantityOnly = false; + ((EntityPlayerMP) player).updateHeldItem(); + return; + } + if (drawables.size() > finalID) { + if (inventoryExtractor == null) return; + int realID = drawables.get(finalID).realSlots.get(0); + T removed = inventoryExtractor.extract(realID); + if (removed != null) { + ItemStack stack = inventoryGetter.get(removed); + player.inventory.setItemStack(stack); + ((EntityPlayerMP) player).isChangingQuantityOnly = false; + ((EntityPlayerMP) player).updateHeldItem(); + return; + } + } + } + }) + .setBackground( + () -> new IDrawable[] { getItemSlot(), + new ItemDrawable(drawables.size() > finalID ? drawables.get(finalID).stack : null) + .withFixedSize(16, 16, 1, 1), + new Text( + (drawables.size() > finalID && drawables.get(finalID).count > 1) + ? (drawables.get(finalID).count > 99 ? "+99" + : String.valueOf(drawables.get(finalID).count)) + : "").color(Color.WHITE.normal) + .alignment(Alignment.TopLeft) + .withOffset(1, 1), + new Text( + (drawables.size() > finalID && drawables.get(finalID).stack.stackSize > 1) + ? String.valueOf(drawables.get(finalID).stack.stackSize) + : "").color(Color.WHITE.normal) + .shadow() + .alignment(Alignment.BottomRight) }) + .dynamicTooltip(() -> { + if (drawables.size() > finalID) { + List<String> tip = new ArrayList<>( + Collections.singletonList(drawables.get(finalID).stack.getDisplayName())); + if (drawables.get(finalID).count > 1) tip.add( + EnumChatFormatting.DARK_PURPLE + "There are " + + drawables.get(finalID).count + + " identical slots"); + return tip; + } + return Collections.emptyList(); + }) + .setSize(18, 18)); + } + + buttons.add(new ButtonWidget() { + + @Override + public void drawBackground(float partialTicks) { + super.drawBackground(partialTicks); + if (!isEnabled) { + GL11.glDisable(GL11.GL_LIGHTING); + GL11.glEnable(GL11.GL_BLEND); + GlStateManager.colorMask(true, true, true, false); + ModularGui.drawSolidRect(1, 1, 16, 16, Color.withAlpha(Color.BLACK.normal, 0x80)); + GlStateManager.colorMask(true, true, true, true); + GL11.glDisable(GL11.GL_BLEND); + } + // Copied from SlotWidget#draw + else if (isHovering() && !getContext().getCursor() + .hasDraggable()) { + GL11.glDisable(GL11.GL_LIGHTING); + GL11.glEnable(GL11.GL_BLEND); + GlStateManager.colorMask(true, true, true, false); + ModularGui.drawSolidRect(1, 1, 16, 16, Theme.INSTANCE.getSlotHighlight()); + GlStateManager.colorMask(true, true, true, true); + GL11.glDisable(GL11.GL_BLEND); + } + } + }.setPlayClickSound(false) + .setOnClick((clickData, widget) -> { + if (!(player instanceof EntityPlayerMP)) return; + if (!isEnabledGetter.get()) return; + ItemStack input = player.inventory.getItemStack(); + if (input != null) { + if (clickData.mouseButton == 1) { + ItemStack copy = input.copy(); + copy.stackSize = 1; + ItemStack leftover = inventoryInjector.inject(copy); + if (leftover == null) return; + input.stackSize--; + if (input.stackSize > 0) { + ((EntityPlayerMP) player).isChangingQuantityOnly = true; + ((EntityPlayerMP) player).updateHeldItem(); + return; + } else player.inventory.setItemStack(null); + } else { + ItemStack leftover = inventoryInjector.inject(input); + if (leftover == null) return; + if (input.stackSize > 0) { + ((EntityPlayerMP) player).isChangingQuantityOnly = true; + ((EntityPlayerMP) player).updateHeldItem(); + return; + } else player.inventory.setItemStack(null); + } + ((EntityPlayerMP) player).isChangingQuantityOnly = false; + ((EntityPlayerMP) player).updateHeldItem(); + return; + } + }) + .setBackground( + () -> new IDrawable[] { getItemSlot(), + new Text( + (slots - usedSlots) <= 1 ? "" + : ((slots - usedSlots) > 99 ? "+99" : String.valueOf((slots - usedSlots)))) + .color(Color.WHITE.normal) + .alignment(Alignment.TopLeft) + .withOffset(1, 1) }) + .dynamicTooltip(() -> { + List<String> tip = new ArrayList<>(Collections.singleton(EnumChatFormatting.GRAY + "Empty slot")); + if (slots - usedSlots > 1) + tip.add(EnumChatFormatting.DARK_PURPLE + "There are " + (slots - usedSlots) + " identical slots"); + return tip; + }) + .setSize(18, 18)); + + final int perRow = width / 18; + for (int i = 0, imax = ((buttons.size() - 1) / perRow); i <= imax; i++) { + DynamicPositionedRow row = new DynamicPositionedRow().setSynced(false); + for (int j = 0, jmax = (i == imax ? (buttons.size() - 1) % perRow : (perRow - 1)); j <= jmax; j++) { + final int finalI = i * perRow; + final int finalJ = j; + final int ID = finalI + finalJ; + row.widget(buttons.get(ID)); + } + dynamicInventoryWidget.widget(row.setPos(0, i * 18)); + } + + return dynamicInventoryWidget.setSize(width, height); + } + + @FunctionalInterface + public interface TInventoryGetter<T> { + + /** + * Allows to get an ItemStack from the dynamic inventory + * + * @param from Dynamic inventory item from which we want to take an item out + * @return ItemStack or null if inaccessible + */ + ItemStack get(T from); + } + + @FunctionalInterface + public interface TInventoryInjector { + + /** + * Allows to insert an item to the dynamic inventory + * + * @param what ItemStack which we are trying to insert + * @return Leftover ItemStack (stackSize == 0 if everything has been inserted) or null + */ + ItemStack inject(ItemStack what); + } + + @FunctionalInterface + public interface TInventoryExtractor<T> { + + /** + * Allows to extract an item from the dynamic inventory + * + * @param where Index from where we want to take an item out + * @return Item that we took out or null + */ + T extract(int where); + } + + @FunctionalInterface + public interface TInventoryReplacerOrMerger { + + /** + * Allows to replace an item in Dynamic Inventory + * + * @param where which index we want to replace + * @param stack what stack we want to replace it with + * @return Stack that we are left with or null + */ + ItemStack replaceOrMerge(int where, ItemStack stack); + } + +} diff --git a/src/main/java/kubatech/api/LoaderReference.java b/src/main/java/kubatech/api/LoaderReference.java new file mode 100644 index 0000000000..57a7077d26 --- /dev/null +++ b/src/main/java/kubatech/api/LoaderReference.java @@ -0,0 +1,23 @@ +package kubatech.api; + +import cpw.mods.fml.common.Loader; + +public class LoaderReference { + + public static final boolean BloodMagic = Loader.isModLoaded("AWWayofTime"); + public static final boolean EnderIO = Loader.isModLoaded("EnderIO"); + public static final boolean ExtraUtilities = Loader.isModLoaded("ExtraUtilities"); + public static final boolean InfernalMobs = Loader.isModLoaded("InfernalMobs"); + public static final boolean Thaumcraft = Loader.isModLoaded("Thaumcraft"); + public static final boolean MineTweaker = Loader.isModLoaded("MineTweaker3"); + public static final boolean Bartworks = Loader.isModLoaded("bartworks"); + public static final boolean GTNHCoreMod = Loader.isModLoaded("dreamcraft"); + public static final boolean GTPlusPlus = Loader.isModLoaded("miscutils"); + public static final boolean HarvestCraft = Loader.isModLoaded("harvestcraft"); + public static final boolean Forestry = Loader.isModLoaded("Forestry"); + public static final boolean DraconicEvolution = Loader.isModLoaded("DraconicEvolution"); + public static final boolean Avaritia = Loader.isModLoaded("Avaritia"); + public static final boolean ProjRedIllumination = Loader.isModLoaded("ProjRed|Illumination"); + public static final boolean RandomThings = Loader.isModLoaded("RandomThings"); + public static final boolean ElectroMagicTools = Loader.isModLoaded("EMT"); +} diff --git a/src/main/java/kubatech/api/Variables.java b/src/main/java/kubatech/api/Variables.java new file mode 100644 index 0000000000..a5821325e2 --- /dev/null +++ b/src/main/java/kubatech/api/Variables.java @@ -0,0 +1,63 @@ +/* + * 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 <https://www.gnu.org/licenses/>. + * spotless:on + */ + +package kubatech.api; + +import java.text.DecimalFormat; +import java.text.NumberFormat; + +import net.minecraft.util.EnumChatFormatting; + +import kubatech.api.utils.StringUtils; + +public class Variables { + + public static final String Author = "Author: " + + StringUtils.applyRainbow("kuba6000", 0, EnumChatFormatting.BOLD.toString()); + + public static String buildAuthorList(String... authors) { + if (authors.length == 0) return "Author: Unknown"; + StringBuilder b = new StringBuilder("Author: ") + .append(StringUtils.applyRainbow(authors[0], 0, EnumChatFormatting.BOLD.toString())); + for (int i = 1; i < authors.length; i++) { + String author = authors[i]; + b.append(EnumChatFormatting.RESET) + .append(" & ") + .append(EnumChatFormatting.GOLD) + .append(author); + } + return b.toString(); + } + + public static final String StructureHologram = "To see the structure, use a " + EnumChatFormatting.BLUE + + "Structure" + + EnumChatFormatting.DARK_BLUE + + "Lib" + + EnumChatFormatting.RESET + + "" + + EnumChatFormatting.GRAY + + " Hologram Projector on the Controller!"; + + public static final double ln4 = Math.log(4d); + public static final double ln2 = Math.log(2d); + + public static final NumberFormat numberFormatScientific = new DecimalFormat("0.00E0"); + public static final NumberFormat numberFormat = NumberFormat.getInstance(); +} diff --git a/src/main/java/kubatech/api/enums/ItemList.java b/src/main/java/kubatech/api/enums/ItemList.java new file mode 100644 index 0000000000..3a26974c0a --- /dev/null +++ b/src/main/java/kubatech/api/enums/ItemList.java @@ -0,0 +1,226 @@ +package kubatech.api.enums; + +import static gregtech.api.enums.GT_Values.NI; +import static gregtech.api.enums.GT_Values.W; + +import java.util.Locale; + +import net.minecraft.block.Block; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; + +import gregtech.api.interfaces.IItemContainer; +import gregtech.api.util.GT_LanguageManager; +import gregtech.api.util.GT_ModHandler; +import gregtech.api.util.GT_OreDictUnificator; +import gregtech.api.util.GT_Utility; + +public enum ItemList implements IItemContainer { + + ExtremeEntityCrusher, + ExtremeIndustrialApiary, + ExtremeIndustrialGreenhouse, + DraconicEvolutionFusionCrafter, + LegendaryBlackTea, + LegendaryButterflyTea, + LegendaryEarlGrayTea, + LegendaryGreenTea, + LegendaryLemonTea, + LegendaryMilkTea, + LegendaryOolongTea, + LegendaryPeppermintTea, + LegendaryPuerhTea, + LegendaryRedTea, + LegendaryWhiteTea, + LegendaryYellowTea, + LegendaryUltimateTea, + BlackTea, + EarlGrayTea, + GreenTea, + LemonTea, + MilkTea, + OolongTea, + PeppermintTea, + PuerhTea, + WhiteTea, + YellowTea, + BlackTeaLeaf, + GreenTeaLeaf, + OolongTeaLeaf, + PuerhTeaLeaf, + WhiteTeaLeaf, + YellowTeaLeaf, + TeaLeafDehydrated, + SteamedTeaLeaf, + RolledTeaLeaf, + OxidizedTeaLeaf, + FermentedTeaLeaf, + BruisedTeaLeaf, + PartiallyOxidizedTeaLeaf, + TeaAcceptorResearchNote, + TeaAcceptor, + TeaStorage, + Beeeeee, + DEFCCasingBase, + DEFCCasingT1, + DEFCCasingT2, + DEFCCasingT3, + DEFCCasingT4, + DEFCCasingT5, + DEFCDraconicSchematic, + DEFCWyvernSchematic, + DEFCAwakenedSchematic, + DEFCChaoticSchematic, + + ; + + private ItemStack mStack; + private boolean mHasNotBeenSet = true; + + @Override + public IItemContainer set(Item aItem) { + mHasNotBeenSet = false; + if (aItem == null) return this; + ItemStack aStack = new ItemStack(aItem, 1, 0); + mStack = GT_Utility.copyAmount(1, aStack); + return this; + } + + @Override + public IItemContainer set(ItemStack aStack) { + mHasNotBeenSet = false; + mStack = GT_Utility.copyAmount(1, aStack); + return this; + } + + @Override + public Item getItem() { + if (mHasNotBeenSet) + throw new IllegalAccessError("The Enum '" + name() + "' has not been set to an Item at this time!"); + if (GT_Utility.isStackInvalid(mStack)) return null; + return mStack.getItem(); + } + + @Override + public Block getBlock() { + if (mHasNotBeenSet) + throw new IllegalAccessError("The Enum '" + name() + "' has not been set to an Item at this time!"); + return GT_Utility.getBlockFromItem(getItem()); + } + + @Override + public final boolean hasBeenSet() { + return !mHasNotBeenSet; + } + + @Override + public boolean isStackEqual(Object aStack) { + return isStackEqual(aStack, false, false); + } + + @Override + public boolean isStackEqual(Object aStack, boolean aWildcard, boolean aIgnoreNBT) { + if (GT_Utility.isStackInvalid(aStack)) return false; + return GT_Utility.areUnificationsEqual((ItemStack) aStack, aWildcard ? getWildcard(1) : get(1), aIgnoreNBT); + } + + @Override + public ItemStack get(long aAmount, Object... aReplacements) { + if (mHasNotBeenSet) + throw new IllegalAccessError("The Enum '" + name() + "' has not been set to an Item at this time!"); + if (GT_Utility.isStackInvalid(mStack)) return GT_Utility.copyAmount(aAmount, aReplacements); + return GT_Utility.copyAmount(aAmount, GT_OreDictUnificator.get(mStack)); + } + + @Override + public ItemStack getWildcard(long aAmount, Object... aReplacements) { + if (mHasNotBeenSet) + throw new IllegalAccessError("The Enum '" + name() + "' has not been set to an Item at this time!"); + if (GT_Utility.isStackInvalid(mStack)) return GT_Utility.copyAmount(aAmount, aReplacements); + return GT_Utility.copyAmountAndMetaData(aAmount, W, GT_OreDictUnificator.get(mStack)); + } + + @Override + public ItemStack getUndamaged(long aAmount, Object... aReplacements) { + if (mHasNotBeenSet) + throw new IllegalAccessError("The Enum '" + name() + "' has not been set to an Item at this time!"); + if (GT_Utility.isStackInvalid(mStack)) return GT_Utility.copyAmount(aAmount, aReplacements); + return GT_Utility.copyAmountAndMetaData(aAmount, 0, GT_OreDictUnificator.get(mStack)); + } + + @Override + public ItemStack getAlmostBroken(long aAmount, Object... aReplacements) { + if (mHasNotBeenSet) + throw new IllegalAccessError("The Enum '" + name() + "' has not been set to an Item at this time!"); + if (GT_Utility.isStackInvalid(mStack)) return GT_Utility.copyAmount(aAmount, aReplacements); + return GT_Utility.copyAmountAndMetaData(aAmount, mStack.getMaxDamage() - 1, GT_OreDictUnificator.get(mStack)); + } + + @Override + public ItemStack getWithName(long aAmount, String aDisplayName, Object... aReplacements) { + ItemStack rStack = get(1, aReplacements); + if (GT_Utility.isStackInvalid(rStack)) return NI; + + // CamelCase alphanumeric words from aDisplayName + StringBuilder tCamelCasedDisplayNameBuilder = new StringBuilder(); + final String[] tDisplayNameWords = aDisplayName.split("\\W"); + for (String tWord : tDisplayNameWords) { + if (tWord.length() > 0) tCamelCasedDisplayNameBuilder.append( + tWord.substring(0, 1) + .toUpperCase(Locale.US)); + if (tWord.length() > 1) tCamelCasedDisplayNameBuilder.append( + tWord.substring(1) + .toLowerCase(Locale.US)); + } + if (tCamelCasedDisplayNameBuilder.length() == 0) { + // CamelCased DisplayName is empty, so use hash of aDisplayName + tCamelCasedDisplayNameBuilder.append(((Long) (long) aDisplayName.hashCode())); + } + + // Construct a translation key from UnlocalizedName and CamelCased DisplayName + final String tKey = rStack.getUnlocalizedName() + ".with." + tCamelCasedDisplayNameBuilder + ".name"; + + rStack.setStackDisplayName(GT_LanguageManager.addStringLocalization(tKey, aDisplayName)); + return GT_Utility.copyAmount(aAmount, rStack); + } + + @Override + public ItemStack getWithCharge(long aAmount, int aEnergy, Object... aReplacements) { + ItemStack rStack = get(1, aReplacements); + if (GT_Utility.isStackInvalid(rStack)) return null; + GT_ModHandler.chargeElectricItem(rStack, aEnergy, Integer.MAX_VALUE, true, false); + return GT_Utility.copyAmount(aAmount, rStack); + } + + @Override + public ItemStack getWithDamage(long aAmount, long aMetaValue, Object... aReplacements) { + if (mHasNotBeenSet) + throw new IllegalAccessError("The Enum '" + name() + "' has not been set to an Item at this time!"); + if (GT_Utility.isStackInvalid(mStack)) return GT_Utility.copyAmount(aAmount, aReplacements); + return GT_Utility.copyAmountAndMetaData(aAmount, aMetaValue, GT_OreDictUnificator.get(mStack)); + } + + @Override + public IItemContainer registerOre(Object... aOreNames) { + if (mHasNotBeenSet) + throw new IllegalAccessError("The Enum '" + name() + "' has not been set to an Item at this time!"); + for (Object tOreName : aOreNames) GT_OreDictUnificator.registerOre(tOreName, get(1)); + return this; + } + + @Override + public IItemContainer registerWildcardAsOre(Object... aOreNames) { + if (mHasNotBeenSet) + throw new IllegalAccessError("The Enum '" + name() + "' has not been set to an Item at this time!"); + for (Object tOreName : aOreNames) GT_OreDictUnificator.registerOre(tOreName, getWildcard(1)); + return this; + } + + /** + * Returns the internal stack. This method is unsafe. It's here only for quick operations. DON'T CHANGE THE RETURNED + * VALUE! + */ + public ItemStack getInternalStack_unsafe() { + return mStack; + } +} diff --git a/src/main/java/kubatech/api/helpers/GTHelper.java b/src/main/java/kubatech/api/helpers/GTHelper.java new file mode 100644 index 0000000000..72bbe8cf77 --- /dev/null +++ b/src/main/java/kubatech/api/helpers/GTHelper.java @@ -0,0 +1,99 @@ +/* + * 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 <https://www.gnu.org/licenses/>. + * spotless:on + */ + +package kubatech.api.helpers; + +import static kubatech.api.Variables.ln4; + +import java.io.IOException; +import java.util.ArrayList; + +import net.minecraft.item.ItemStack; +import net.minecraft.network.PacketBuffer; + +import com.kuba6000.mobsinfo.api.utils.ItemID; + +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Energy; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_MultiBlockBase; +import kubatech.api.implementations.KubaTechGTMultiBlockBase; + +public class GTHelper { + + public static long getMaxInputEU(GT_MetaTileEntity_MultiBlockBase mte) { + if (mte instanceof KubaTechGTMultiBlockBase) return ((KubaTechGTMultiBlockBase<?>) mte).getMaxInputEu(); + long rEU = 0; + for (GT_MetaTileEntity_Hatch_Energy tHatch : mte.mEnergyHatches) + if (tHatch.isValid()) rEU += tHatch.maxEUInput() * tHatch.maxAmperesIn(); + return rEU; + } + + public static double getVoltageTierD(long voltage) { + return Math.log((double) voltage / 8L) / ln4; + } + + public static double getVoltageTierD(GT_MetaTileEntity_MultiBlockBase mte) { + return Math.log((double) getMaxInputEU(mte) / 8L) / ln4; + } + + public static int getVoltageTier(long voltage) { + return (int) getVoltageTierD(voltage); + } + + public static int getVoltageTier(GT_MetaTileEntity_MultiBlockBase mte) { + return (int) getVoltageTierD(mte); + } + + public static class StackableItemSlot { + + public StackableItemSlot(int count, ItemStack stack, ArrayList<Integer> realSlots) { + this.count = count; + this.stack = stack; + this.realSlots = realSlots; + } + + public final int count; + public final ItemStack stack; + public final ArrayList<Integer> realSlots; + + public void write(PacketBuffer buffer) throws IOException { + buffer.writeVarIntToBuffer(count); + buffer.writeItemStackToBuffer(stack); + } + + public static StackableItemSlot read(PacketBuffer buffer) throws IOException { + return new StackableItemSlot( + buffer.readVarIntFromBuffer(), + buffer.readItemStackFromBuffer(), + new ArrayList<>()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (!(obj instanceof StackableItemSlot)) return false; + StackableItemSlot other = (StackableItemSlot) obj; + return count == other.count && ItemID.createNoCopy(stack, false) + .hashCode() + == ItemID.createNoCopy(other.stack, false) + .hashCode() + && realSlots.equals(other.realSlots); + } + } +} diff --git a/src/main/java/kubatech/api/helpers/ReflectionHelper.java b/src/main/java/kubatech/api/helpers/ReflectionHelper.java new file mode 100644 index 0000000000..5c5bb1070e --- /dev/null +++ b/src/main/java/kubatech/api/helpers/ReflectionHelper.java @@ -0,0 +1,205 @@ +/* + * 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 <https://www.gnu.org/licenses/>. + * spotless:on + */ + +package kubatech.api.helpers; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.net.JarURLConnection; +import java.net.URL; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Objects; +import java.util.jar.JarFile; +import java.util.stream.Collectors; + +import net.minecraft.launchwrapper.Launch; + +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.tree.ClassNode; + +public class ReflectionHelper { + + private static class _FieldsMethods { + + final HashMap<String, Field> fields = new HashMap<>(); + final HashMap<String, Method> methods = new HashMap<>(); + } + + private static final HashMap<String, _FieldsMethods> classes = new HashMap<>(); + + @SuppressWarnings("unchecked") + public static <T> T getField(Object obj, String fieldName, T defaultvalue) { + Class<?> cl = obj.getClass(); + String clName = cl.getName(); + HashMap<String, Field> classmap = classes.computeIfAbsent(clName, s -> new _FieldsMethods()).fields; + try { + if (classmap.containsKey(fieldName)) { + Field f = classmap.get(fieldName); + if (f == null) return defaultvalue; + return (T) f.get(obj); + } + boolean exceptionDetected; + Field f = null; + do { + exceptionDetected = false; + try { + f = cl.getDeclaredField(fieldName); + f.setAccessible(true); + } catch (Exception ex) { + exceptionDetected = true; + cl = cl.getSuperclass(); + } + } while (exceptionDetected && !cl.equals(Object.class)); + classmap.put(fieldName, f); + if (f == null) return defaultvalue; + return (T) f.get(obj); + } catch (Exception ex) { + return defaultvalue; + } + } + + public static <T> boolean setField(Object obj, String fieldName, T value) { + Class<?> cl = obj.getClass(); + String clName = cl.getName(); + HashMap<String, Field> classmap = classes.computeIfAbsent(clName, s -> new _FieldsMethods()).fields; + try { + if (classmap.containsKey(fieldName)) { + Field f = classmap.get(fieldName); + if (f == null) return false; + f.set(obj, value); + return true; + } + boolean exceptionDetected; + Field f = null; + do { + exceptionDetected = false; + try { + f = cl.getDeclaredField(fieldName); + f.setAccessible(true); + } catch (Exception ex) { + exceptionDetected = true; + cl = cl.getSuperclass(); + } + } while (exceptionDetected && !cl.equals(Object.class)); + classmap.put(fieldName, f); + if (f == null) return false; + f.set(obj, value); + return true; + } catch (Exception ex) { + return false; + } + } + + public static <T> T getField(Object obj, String fieldName) { + return getField(obj, fieldName, null); + } + + @SuppressWarnings("unchecked") + public static <T> T callMethod(Object obj, String methodName, T defaultValue, Object... args) { + Class<?> cl = obj.getClass(); + String clName = cl.getName(); + HashMap<String, Method> classmap = classes.computeIfAbsent(clName, s -> new _FieldsMethods()).methods; + StringBuilder builder = new StringBuilder(methodName); + Class<?>[] argsTypes = new Class<?>[args.length]; + for (int i = 0; i < args.length; i++) { + Class<?> arg = args[i].getClass(); + builder.append(";") + .append(arg.getSimpleName()); + argsTypes[i] = arg; + } + String methodNameUnique = builder.toString(); + try { + if (classmap.containsKey(methodNameUnique)) { + Method m = classmap.get(methodNameUnique); + if (m == null) return defaultValue; + return (T) m.invoke(obj, args); + } + boolean exceptionDetected; + Method m = null; + do { + exceptionDetected = false; + try { + m = cl.getDeclaredMethod(methodName, argsTypes); + m.setAccessible(true); + } catch (Exception ex) { + exceptionDetected = true; + cl = cl.getSuperclass(); + } + } while (exceptionDetected && !cl.equals(Object.class)); + classmap.put(methodNameUnique, m); + if (m == null) return defaultValue; + return (T) m.invoke(obj, args); + } catch (Exception ex) { + return defaultValue; + } + } + + /** + * Gets all classes in a specific package path, works only for jar files. + * + * @param packageName The package name + * @return The class nodes + */ + public static Collection<ClassNode> getClasses(String packageName) throws IOException { + ClassLoader classLoader = Thread.currentThread() + .getContextClassLoader(); + assert classLoader != null; + String packagePath = packageName.replace('.', '/'); + URL resource = classLoader.getResource(packagePath); + if (resource == null) throw new FileNotFoundException(); + if (!resource.getProtocol() + .equals("jar")) return Collections.emptySet(); + try (JarFile jar = ((JarURLConnection) resource.openConnection()).getJarFile()) { + return jar.stream() + .filter( + j -> !j.isDirectory() && j.getName() + .startsWith(packagePath) + && j.getName() + .endsWith(".class")) + .map(j -> { + try { + String name = j.getName(); + URL jarResource = Launch.classLoader.getResource(name); + if (jarResource == null) return null; + byte[] bytes; + try (InputStream is = jarResource.openStream()) { + bytes = new byte[(int) j.getSize()]; + if (is.read(bytes) != bytes.length) return null; + if (is.available() > 0) return null; + } + + ClassNode cn = new ClassNode(); + ClassReader cr = new ClassReader(bytes); + cr.accept(cn, 0); + + return cn; + } catch (IOException ignored) {} + return null; + }) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + } + } +} diff --git a/src/main/java/kubatech/api/helpers/UUIDFinder.java b/src/main/java/kubatech/api/helpers/UUIDFinder.java new file mode 100644 index 0000000000..922904705b --- /dev/null +++ b/src/main/java/kubatech/api/helpers/UUIDFinder.java @@ -0,0 +1,43 @@ +/* + * 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 <https://www.gnu.org/licenses/>. + * spotless:on + */ + +package kubatech.api.helpers; + +import java.util.HashMap; +import java.util.UUID; + +public class UUIDFinder { + + private static final HashMap<UUID, String> UUIDToUsernameMap = new HashMap<>(); + private static final HashMap<String, UUID> UsernameToUUIDMap = new HashMap<>(); + + public static UUID getUUID(String username) { + return UsernameToUUIDMap.get(username); + } + + public static String getUsername(UUID player) { + return UUIDToUsernameMap.get(player); + } + + public static void updateMapping(String username, UUID player) { + UUIDToUsernameMap.put(player, username); + UsernameToUUIDMap.put(username, player); + } +} diff --git a/src/main/java/kubatech/api/implementations/KubaTechGTMultiBlockBase.java b/src/main/java/kubatech/api/implementations/KubaTechGTMultiBlockBase.java new file mode 100644 index 0000000000..bf74df9154 --- /dev/null +++ b/src/main/java/kubatech/api/implementations/KubaTechGTMultiBlockBase.java @@ -0,0 +1,341 @@ +/* + * 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 <https://www.gnu.org/licenses/>. + * 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<T extends GT_MetaTileEntity_ExtendedPowerMultiBlockBase<T>> + extends GT_MetaTileEntity_ExtendedPowerMultiBlockBase<T> { + + @Deprecated + public final int mEUt = 0; + + @SuppressWarnings("unchecked") + protected static <K extends KubaTechGTMultiBlockBase<?>> UIInfo<?, ?> createKTMetaTileEntityUI( + KTContainerConstructor<K> 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<T extends KubaTechGTMultiBlockBase<?>> { + + 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<ItemStack> list) { + return tryOutputAll(list, l -> Collections.singletonList((ItemStack) l)); + } + + protected boolean tryOutputAll(List<?> list, Function<Object, List<ItemStack>> 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<ItemStack> toOutputNow = mappingFunction.apply(list.get(0)); + 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 boolean useModularUI() { + return true; + } + + @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<SlotWidget> 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<Widget, Boolean> isFixed = widget -> getIdealStatus() == getRepairStatus() && mMachine; + protected static final Function<Integer, IDrawable> toggleButtonTextureGetter = val -> val == 0 + ? GT_UITextures.OVERLAY_BUTTON_CROSS + : GT_UITextures.OVERLAY_BUTTON_CHECKMARK; + protected static final Function<Integer, IDrawable[]> toggleButtonBackgroundGetter = val -> new IDrawable[] { + val == 0 ? GT_UITextures.BUTTON_STANDARD : GT_UITextures.BUTTON_STANDARD_PRESSED }; +} diff --git a/src/main/java/kubatech/api/tea/TeaNetwork.java b/src/main/java/kubatech/api/tea/TeaNetwork.java new file mode 100644 index 0000000000..68c8275bfd --- /dev/null +++ b/src/main/java/kubatech/api/tea/TeaNetwork.java @@ -0,0 +1,93 @@ +package kubatech.api.tea; + +import java.math.BigInteger; +import java.util.HashSet; +import java.util.UUID; + +import net.minecraft.nbt.NBTTagCompound; + +import kubatech.savedata.PlayerData; +import kubatech.savedata.PlayerDataManager; +import kubatech.tileentity.TeaStorageTile; + +public class TeaNetwork { + + // TODO: Optimize later :P + public BigInteger teaAmount = BigInteger.ZERO; + public BigInteger teaLimit = BigInteger.valueOf(Long.MAX_VALUE); + PlayerData owner; + private HashSet<TeaStorageTile> teaStorageExtenders = new HashSet<>(); + + public static TeaNetwork getNetwork(UUID player) { + PlayerData p = PlayerDataManager.getPlayer(player); + if (p == null) return null; + TeaNetwork n = p.teaNetwork; + if (n == null) { + p.teaNetwork = new TeaNetwork(); + p.teaNetwork.owner = p; + return p.teaNetwork; + } + n.owner = p; + return n; + } + + public boolean canAfford(long price, boolean take) { + return canAfford(BigInteger.valueOf(price), take); + } + + public boolean canAfford(BigInteger price, boolean take) { + if (teaAmount.compareTo(price) >= 0) { + if (take) { + teaAmount = teaAmount.subtract(price); + markDirty(); + } + return true; + } + return false; + } + + public boolean addTea(long toAdd) { + return addTea(BigInteger.valueOf(toAdd)); + } + + public boolean addTea(BigInteger toAdd) { + BigInteger newValue = teaAmount.add(toAdd); + if (newValue.compareTo(teaLimit) > 0) return false; + teaAmount = teaAmount.add(toAdd); + markDirty(); + return true; + } + + public boolean canAdd(long toAdd) { + return canAdd(BigInteger.valueOf(toAdd)); + } + + public boolean canAdd(BigInteger toAdd) { + return teaAmount.add(toAdd) + .compareTo(teaLimit) <= 0; + } + + public void registerTeaStorageExtender(TeaStorageTile storageTile) { + if (teaStorageExtenders.add(storageTile)) teaLimit = teaLimit.add(storageTile.teaExtendAmount()); + } + + public void unregisterTeaStorageExtender(TeaStorageTile storageTile) { + if (teaStorageExtenders.remove(storageTile)) teaLimit = teaLimit.subtract(storageTile.teaExtendAmount()); + } + + public void markDirty() { + owner.markDirty(); + } + + public NBTTagCompound toNBT() { + NBTTagCompound nbt = new NBTTagCompound(); + nbt.setByteArray("teaAmount", teaAmount.toByteArray()); + return nbt; + } + + public static TeaNetwork fromNBT(NBTTagCompound nbt) { + TeaNetwork teaNetwork = new TeaNetwork(); + teaNetwork.teaAmount = new BigInteger(nbt.getByteArray("teaAmount")); + return teaNetwork; + } +} diff --git a/src/main/java/kubatech/api/tileentity/CustomTileEntityPacketHandler.java b/src/main/java/kubatech/api/tileentity/CustomTileEntityPacketHandler.java new file mode 100644 index 0000000000..4fa014cfc0 --- /dev/null +++ b/src/main/java/kubatech/api/tileentity/CustomTileEntityPacketHandler.java @@ -0,0 +1,28 @@ +/* + * 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 <https://www.gnu.org/licenses/>. + * spotless:on + */ + +package kubatech.api.tileentity; + +import kubatech.network.CustomTileEntityPacket; + +public interface CustomTileEntityPacketHandler { + + void HandleCustomPacket(CustomTileEntityPacket customdata); +} diff --git a/src/main/java/kubatech/api/utils/ItemUtils.java b/src/main/java/kubatech/api/utils/ItemUtils.java new file mode 100644 index 0000000000..2fc34057c3 --- /dev/null +++ b/src/main/java/kubatech/api/utils/ItemUtils.java @@ -0,0 +1,26 @@ +package kubatech.api.utils; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +public class ItemUtils { + + public static NBTTagCompound writeItemStackToNBT(ItemStack stack) { + NBTTagCompound compound = new NBTTagCompound(); + + stack.writeToNBT(compound); + compound.setInteger("IntCount", stack.stackSize); + + return compound; + } + + public static ItemStack readItemStackFromNBT(NBTTagCompound compound) { + ItemStack stack = ItemStack.loadItemStackFromNBT(compound); + + if (stack == null) return null; + + if (compound.hasKey("IntCount")) stack.stackSize = compound.getInteger("IntCount"); + + return stack; + } +} diff --git a/src/main/java/kubatech/api/utils/ModUtils.java b/src/main/java/kubatech/api/utils/ModUtils.java new file mode 100644 index 0000000000..a055965cff --- /dev/null +++ b/src/main/java/kubatech/api/utils/ModUtils.java @@ -0,0 +1,38 @@ +/* + * 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 <https://www.gnu.org/licenses/>. + * spotless:on + */ + +package kubatech.api.utils; + +import net.minecraft.launchwrapper.Launch; + +import cpw.mods.fml.common.FMLCommonHandler; + +public class ModUtils { + + public static final boolean isDeobfuscatedEnvironment = (boolean) Launch.blackboard + .get("fml.deobfuscatedEnvironment"); + public static boolean isClientSided = false; + + public static boolean isClientThreaded() { + return FMLCommonHandler.instance() + .getEffectiveSide() + .isClient(); + } +} diff --git a/src/main/java/kubatech/api/utils/StringUtils.java b/src/main/java/kubatech/api/utils/StringUtils.java new file mode 100644 index 0000000000..c60da71b14 --- /dev/null +++ b/src/main/java/kubatech/api/utils/StringUtils.java @@ -0,0 +1,52 @@ +/* + * 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 <https://www.gnu.org/licenses/>. + * spotless:on + */ + +package kubatech.api.utils; + +import net.minecraft.util.EnumChatFormatting; + +public class StringUtils { + + private static final String[] rainbow = new String[] { EnumChatFormatting.DARK_RED.toString(), + EnumChatFormatting.RED.toString(), EnumChatFormatting.GOLD.toString(), EnumChatFormatting.YELLOW.toString(), + EnumChatFormatting.DARK_GREEN.toString(), EnumChatFormatting.GREEN.toString(), + EnumChatFormatting.AQUA.toString(), EnumChatFormatting.DARK_AQUA.toString(), + EnumChatFormatting.DARK_BLUE.toString(), EnumChatFormatting.BLUE.toString(), + EnumChatFormatting.LIGHT_PURPLE.toString(), EnumChatFormatting.DARK_PURPLE.toString(), + EnumChatFormatting.WHITE.toString(), EnumChatFormatting.GRAY.toString(), + EnumChatFormatting.DARK_GRAY.toString(), EnumChatFormatting.BLACK.toString(), }; + + public static String applyRainbow(String str, int offset, String additional) { + StringBuilder final_string = new StringBuilder(); + int i = offset; + for (char c : str.toCharArray()) final_string.append(rainbow[i++ % rainbow.length]) + .append(additional) + .append(c); + return final_string.toString(); + } + + public static String applyRainbow(String str, int offset) { + return applyRainbow(str, offset, ""); + } + + public static String applyRainbow(String str) { + return applyRainbow(str, 0, ""); + } +} |