diff --git a/src/main/java/gregtech/api/capability/impl/GhostCircuitItemStackHandler.java b/src/main/java/gregtech/api/capability/impl/GhostCircuitItemStackHandler.java index 81a2b901f8a..1dfd56e7396 100644 --- a/src/main/java/gregtech/api/capability/impl/GhostCircuitItemStackHandler.java +++ b/src/main/java/gregtech/api/capability/impl/GhostCircuitItemStackHandler.java @@ -12,6 +12,7 @@ import net.minecraftforge.items.IItemHandlerModifiable; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; @@ -29,8 +30,15 @@ public class GhostCircuitItemStackHandler extends GTItemStackHandler private int circuitValue = NO_CONFIG; private ItemStack circuitStack = ItemStack.EMPTY; - public GhostCircuitItemStackHandler(MetaTileEntity metaTileEntity) { + public GhostCircuitItemStackHandler(@NotNull MetaTileEntity metaTileEntity) { + this(metaTileEntity, metaTileEntity); + } + + public GhostCircuitItemStackHandler(@NotNull MetaTileEntity metaTileEntity, @Nullable MetaTileEntity mteToNotify) { super(metaTileEntity); + if (mteToNotify != null) { + notifiableEntities.add(mteToNotify); + } } /** diff --git a/src/main/java/gregtech/api/capability/impl/ItemHandlerList.java b/src/main/java/gregtech/api/capability/impl/ItemHandlerList.java index 4f45f7b6d45..8cf116b5af5 100644 --- a/src/main/java/gregtech/api/capability/impl/ItemHandlerList.java +++ b/src/main/java/gregtech/api/capability/impl/ItemHandlerList.java @@ -20,9 +20,11 @@ public class ItemHandlerList implements IItemHandlerModifiable { private final Int2ObjectMap handlerBySlotIndex = new Int2ObjectOpenHashMap<>(); private final Object2IntMap baseIndexOffset = new Object2IntArrayMap<>(); - public ItemHandlerList(List itemHandlerList) { + public ItemHandlerList(@NotNull List itemHandlerList) { int currentSlotIndex = 0; for (IItemHandler itemHandler : itemHandlerList) { + Objects.requireNonNull(itemHandler, "Handler passed to ItemHandlerList was null."); + if (baseIndexOffset.containsKey(itemHandler)) { throw new IllegalArgumentException("Attempted to add item handler " + itemHandler + " twice"); } diff --git a/src/main/java/gregtech/api/gui/widgets/TankWidget.java b/src/main/java/gregtech/api/gui/widgets/TankWidget.java index 7a550ff478e..fa5398efd2c 100644 --- a/src/main/java/gregtech/api/gui/widgets/TankWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/TankWidget.java @@ -511,7 +511,7 @@ public static void addIngotMolFluidTooltip(FluidStack fluidStack, List t if (extra != 0) { fluidAmount += String.format(" + %d L", extra); } - tooltip.add(TextFormatting.GRAY + LocalizationUtils.format("gregtech.gui.amount_raw") + fluidAmount); + tooltip.add(TextFormatting.GRAY + LocalizationUtils.format("gregtech.gui.amount_raw", fluidAmount)); } } } diff --git a/src/main/java/gregtech/api/items/metaitem/MetaItem.java b/src/main/java/gregtech/api/items/metaitem/MetaItem.java index 235e97214e9..64255de08c7 100644 --- a/src/main/java/gregtech/api/items/metaitem/MetaItem.java +++ b/src/main/java/gregtech/api/items/metaitem/MetaItem.java @@ -1007,7 +1007,7 @@ public ItemStack getStackForm(int amount) { return new ItemStack(MetaItem.this, amount, metaItemOffset + metaValue); } - public boolean isItemEqual(ItemStack itemStack) { + public boolean isItemEqual(@NotNull ItemStack itemStack) { return itemStack.getItem() == MetaItem.this && itemStack.getItemDamage() == (metaItemOffset + metaValue); } diff --git a/src/main/java/gregtech/api/metatileentity/IAEStatusProvider.java b/src/main/java/gregtech/api/metatileentity/IAEStatusProvider.java new file mode 100644 index 00000000000..82a725d27d5 --- /dev/null +++ b/src/main/java/gregtech/api/metatileentity/IAEStatusProvider.java @@ -0,0 +1,8 @@ +package gregtech.api.metatileentity; + +public interface IAEStatusProvider { + + boolean isOnline(); + + boolean allowsExtraConnections(); +} diff --git a/src/main/java/gregtech/api/metatileentity/SimpleMachineMetaTileEntity.java b/src/main/java/gregtech/api/metatileentity/SimpleMachineMetaTileEntity.java index 5ecd01baa1a..18d34751e39 100644 --- a/src/main/java/gregtech/api/metatileentity/SimpleMachineMetaTileEntity.java +++ b/src/main/java/gregtech/api/metatileentity/SimpleMachineMetaTileEntity.java @@ -127,7 +127,6 @@ protected void initializeInventory() { this.outputFluidInventory = new FluidHandlerProxy(new FluidTankList(false), exportFluids); if (this.hasGhostCircuitInventory()) { this.circuitInventory = new GhostCircuitItemStackHandler(this); - this.circuitInventory.addNotifiableMetaTileEntity(this); } this.actualImportItems = null; diff --git a/src/main/java/gregtech/api/mui/GTByteBufAdapters.java b/src/main/java/gregtech/api/mui/GTByteBufAdapters.java index 8f286097c98..770b4a3178b 100644 --- a/src/main/java/gregtech/api/mui/GTByteBufAdapters.java +++ b/src/main/java/gregtech/api/mui/GTByteBufAdapters.java @@ -3,10 +3,14 @@ import gregtech.api.recipes.chance.output.impl.ChancedFluidOutput; import gregtech.api.recipes.chance.output.impl.ChancedItemOutput; import gregtech.api.util.NetworkUtil; +import gregtech.common.metatileentities.multi.multiblockpart.appeng.stack.WrappedFluidStack; +import gregtech.common.metatileentities.multi.multiblockpart.appeng.stack.WrappedItemStack; import net.minecraft.network.PacketBuffer; import net.minecraftforge.fluids.Fluid; +import appeng.api.storage.data.IAEFluidStack; +import appeng.api.storage.data.IAEItemStack; import com.cleanroommc.modularui.utils.serialization.*; import org.jetbrains.annotations.NotNull; @@ -23,6 +27,12 @@ public class GTByteBufAdapters { public static final IByteBufAdapter FLUID = makeAdapter(NetworkUtil::readFluid, NetworkUtil::writeFluid); + public static final IByteBufAdapter WRAPPED_ITEM_STACK = makeAdapter(WrappedItemStack::fromPacket, + (buffer, value) -> value.writeToPacket(buffer)); + + public static final IByteBufAdapter WRAPPED_FLUID_STACK = makeAdapter( + WrappedFluidStack::fromPacket, (buffer, value) -> value.writeToPacket(buffer)); + public static IByteBufAdapter makeAdapter(@NotNull IByteBufDeserializer deserializer, @NotNull IByteBufSerializer serializer) { return makeAdapter(deserializer, serializer, IEquals.defaultTester()); diff --git a/src/main/java/gregtech/api/mui/GTGuiTextures.java b/src/main/java/gregtech/api/mui/GTGuiTextures.java index 998ad9c1d03..8743c140536 100644 --- a/src/main/java/gregtech/api/mui/GTGuiTextures.java +++ b/src/main/java/gregtech/api/mui/GTGuiTextures.java @@ -32,6 +32,7 @@ public static class IDs { public static final String PRIMITIVE_BACKGROUND = id("primitive_bg"); public static final String STANDARD_SLOT = id("standard_slot"); + public static final String DARK_SLOT = id("dark_slot"); public static final String BRONZE_SLOT = id("bronze_slot"); public static final String STEEL_SLOT = id("steel_slot"); public static final String PRIMITIVE_SLOT = id("primitive_slot"); @@ -159,6 +160,14 @@ private static String id(String path) { .canApplyTheme() .build(); + public static final UITexture SLOT_DARK = new UITexture.Builder() + .location(GTValues.MODID, "textures/gui/base/slot_dark.png") + .imageSize(18, 18) + .adaptable(1) + .name(IDs.DARK_SLOT) + .canApplyTheme() + .build(); + public static final UITexture SLOT_BRONZE = new UITexture.Builder() .location(GTValues.MODID, "textures/gui/base/slot_bronze.png") .imageSize(18, 18) @@ -709,6 +718,17 @@ private static String id(String path) { // MISC + // ME hatch/bus + public static final UITexture NUMBER_BACKGROUND = fullImage("textures/gui/widget/number_background.png"); + public static final UITexture CONFIG_ARROW = fullImage("textures/gui/widget/config_arrow.png"); + public static final UITexture CONFIG_ARROW_DARK = fullImage("textures/gui/widget/config_arrow_dark.png"); + public static final UITexture SELECT_BOX = fullImage("textures/gui/widget/select_box.png"); + public static final UITexture BUTTON_AUTO_PULL = fullImage("textures/gui/widget/button_me_auto_pull.png"); + public static final UITexture ARROW_DOUBLE = fullImage("textures/gui/widget/arrow_double.png"); + public static final UITexture ARROW_OPPOSITE = fullImage("textures/gui/widget/opposite_arrows.png"); + public static final UITexture[] AUTO_PULL = slice("textures/gui/widget/button_me_auto_pull.png", + 16, 32, 16, 16, ColorType.DEFAULT); + public static void init() {/**/} private static UITexture fullImage(String path) { diff --git a/src/main/java/gregtech/api/mui/GTGuis.java b/src/main/java/gregtech/api/mui/GTGuis.java index a8301981eaa..0f4f23b5517 100644 --- a/src/main/java/gregtech/api/mui/GTGuis.java +++ b/src/main/java/gregtech/api/mui/GTGuis.java @@ -16,10 +16,11 @@ import com.cleanroommc.modularui.widgets.ButtonWidget; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public class GTGuis { - public static final int DEFAULT_WIDTH = 176, DEFAULT_HIEGHT = 166; + public static final int DEFAULT_WIDTH = 176, DEFAULT_HEIGHT = 166; @ApiStatus.Internal public static void registerFactories() { @@ -53,7 +54,7 @@ public static ModularPanel createPanel(ItemStack stack, int width, int height) { } public static ModularPanel createPanel(String name) { - return ModularPanel.defaultPanel(name, DEFAULT_WIDTH, DEFAULT_HIEGHT); + return ModularPanel.defaultPanel(name, DEFAULT_WIDTH, DEFAULT_HEIGHT); } public static ModularPanel defaultPanel(MetaTileEntity mte) { @@ -65,7 +66,7 @@ public static ModularPanel defaultPanel(Cover cover) { } public static ModularPanel defaultPanel(ItemStack stack) { - return createPanel(stack, DEFAULT_WIDTH, DEFAULT_HIEGHT); + return createPanel(stack, DEFAULT_WIDTH, DEFAULT_HEIGHT); } public static ModularPanel defaultPanel(MetaItem.MetaValueItem valueItem) { @@ -83,8 +84,17 @@ public static PopupPanel createPopupPanel(String name, int width, int height, bo } public static PopupPanel defaultPopupPanel(String name) { - return new PopupPanel(name) - .size(DEFAULT_WIDTH, DEFAULT_HIEGHT); + return new PopupPanel(name, true) + .size(DEFAULT_WIDTH, DEFAULT_HEIGHT); + } + + public static PopupPanel blankPopupPanel(String name, int width, int height) { + return new PopupPanel(name, false) + .size(width, height); + } + + public static PopupPanel blankPopupPanel(String name) { + return blankPopupPanel(name, DEFAULT_WIDTH, DEFAULT_HEIGHT); } public static PopupPanel defaultPopupPanel(String name, boolean disableBelow, @@ -100,17 +110,21 @@ public static class PopupPanel extends ModularPanel { private boolean disableBelow; private boolean closeOnOutsideClick; private boolean deleteCachedPanel; + @Nullable + private Runnable closeListener; - private PopupPanel(@NotNull String name) { + private PopupPanel(@NotNull String name, boolean addCloseButton) { super(name); align(Alignment.Center); background(GTGuiTextures.BACKGROUND_POPUP); - child(ButtonWidget.panelCloseButton().top(5).right(5) + childIf(addCloseButton, () -> ButtonWidget.panelCloseButton() + .top(5).right(5) .onMousePressed(mouseButton -> { if (mouseButton == 0 || mouseButton == 1) { - this.closeIfOpen(); + closeIfOpen(); return true; } + return false; })); } @@ -121,6 +135,10 @@ public void onClose() { if (deleteCachedPanel && isSynced() && getSyncHandler() instanceof IPanelHandler handler) { handler.deleteCachedPanel(); } + + if (closeListener != null) { + closeListener.run(); + } } public PopupPanel disablePanelsBelow(boolean disableBelow) { @@ -159,5 +177,10 @@ public boolean disablePanelsBelow() { public boolean closeOnOutOfBoundsClick() { return closeOnOutsideClick; } + + public PopupPanel closeListener(@Nullable Runnable closeListener) { + this.closeListener = closeListener; + return this; + } } } diff --git a/src/main/java/gregtech/api/mui/GregTechGuiScreen.java b/src/main/java/gregtech/api/mui/GregTechGuiScreen.java index ad5c48449c5..d7a42853e3e 100644 --- a/src/main/java/gregtech/api/mui/GregTechGuiScreen.java +++ b/src/main/java/gregtech/api/mui/GregTechGuiScreen.java @@ -1,15 +1,24 @@ package gregtech.api.mui; import gregtech.api.GTValues; +import gregtech.integration.jei.JustEnoughItemsModule; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; +import com.cleanroommc.modularui.integration.recipeviewer.RecipeViewerRecipeTransferHandler; import com.cleanroommc.modularui.screen.ModularPanel; import com.cleanroommc.modularui.screen.ModularScreen; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import mezz.jei.api.gui.IRecipeLayout; +import mezz.jei.api.recipe.transfer.IRecipeTransferError; +@SuppressWarnings("UnstableApiUsage") @SideOnly(Side.CLIENT) -public class GregTechGuiScreen extends ModularScreen { +public class GregTechGuiScreen extends ModularScreen implements RecipeViewerRecipeTransferHandler { + + private static final Object2ObjectMap knownRecipeReceivers = new Object2ObjectOpenHashMap<>(); public GregTechGuiScreen(ModularPanel mainPanel) { this(mainPanel, GTGuiTheme.STANDARD); @@ -27,4 +36,21 @@ public GregTechGuiScreen(String owner, ModularPanel mainPanel, String themeId) { super(owner, mainPanel); useTheme(themeId); } + + @Override + public IRecipeTransferError transferRecipe(IRecipeLayout recipeLayout, boolean maxTransfer, boolean simulate) { + for (IJEIRecipeReceiver handler : knownRecipeReceivers.values()) { + IRecipeTransferError error = handler.receiveRecipe(recipeLayout, maxTransfer, simulate); + if (error == null) return null; + } + return JustEnoughItemsModule.transferHelper.createInternalError(); + } + + public static void registerRecipeReceiver(String key, IJEIRecipeReceiver receiver) { + knownRecipeReceivers.put(key, receiver); + } + + public static void removeRecipeReceiver(String key) { + knownRecipeReceivers.remove(key); + } } diff --git a/src/main/java/gregtech/api/mui/GregTechGuiTransferHandler.java b/src/main/java/gregtech/api/mui/GregTechGuiTransferHandler.java deleted file mode 100644 index 9332b8a9a70..00000000000 --- a/src/main/java/gregtech/api/mui/GregTechGuiTransferHandler.java +++ /dev/null @@ -1,69 +0,0 @@ -package gregtech.api.mui; - -import gregtech.api.mui.sync.PagedWidgetSyncHandler; -import gregtech.common.metatileentities.storage.CraftingRecipeLogic; - -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.ItemStack; - -import com.cleanroommc.modularui.screen.ModularContainer; -import com.cleanroommc.modularui.value.sync.PanelSyncManager; -import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import mezz.jei.api.gui.IGuiItemStackGroup; -import mezz.jei.api.gui.IRecipeLayout; -import mezz.jei.api.recipe.transfer.IRecipeTransferError; -import mezz.jei.api.recipe.transfer.IRecipeTransferHandler; -import mezz.jei.api.recipe.transfer.IRecipeTransferHandlerHelper; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class GregTechGuiTransferHandler implements IRecipeTransferHandler { - - private final IRecipeTransferHandlerHelper handlerHelper; - - public GregTechGuiTransferHandler(IRecipeTransferHandlerHelper handlerHelper) { - this.handlerHelper = handlerHelper; - } - - @Override - public @NotNull Class getContainerClass() { - return ModularContainer.class; - } - - @Override - public @Nullable IRecipeTransferError transferRecipe(ModularContainer container, - @NotNull IRecipeLayout recipeLayout, - @NotNull EntityPlayer player, boolean maxTransfer, - boolean doTransfer) { - if (!container.getSyncManager().isOpen("workbench")) { - return null; - } - PanelSyncManager syncManager = container.getSyncManager().getPanelSyncManager("workbench"); - var recipeLogic = (CraftingRecipeLogic) syncManager.getSyncHandler("recipe_logic:0"); - var pageController = (PagedWidgetSyncHandler) syncManager.getSyncHandler("page_controller:0"); - - if (!doTransfer) { - // todo highlighting in JEI? - return null; - } - - var matrix = extractMatrix(recipeLayout.getItemStacks()); - recipeLogic.fillCraftingGrid(matrix); - pageController.setPage(0); - return null; - } - - private Int2ObjectMap extractMatrix(IGuiItemStackGroup stackGroup) { - var ingredients = stackGroup.getGuiIngredients(); - Int2ObjectMap matrix = new Int2ObjectArrayMap<>(9); - for (var slot : ingredients.keySet()) { - if (slot != 0) { - var ing = ingredients.get(slot).getDisplayedIngredient(); - if (ing == null) continue; - matrix.put(slot - 1, ingredients.get(slot).getDisplayedIngredient()); - } - } - return matrix; - } -} diff --git a/src/main/java/gregtech/api/mui/IJEIRecipeReceiver.java b/src/main/java/gregtech/api/mui/IJEIRecipeReceiver.java new file mode 100644 index 00000000000..db0b1004813 --- /dev/null +++ b/src/main/java/gregtech/api/mui/IJEIRecipeReceiver.java @@ -0,0 +1,33 @@ +package gregtech.api.mui; + +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +import mezz.jei.api.gui.IRecipeLayout; +import mezz.jei.api.recipe.transfer.IRecipeTransferError; +import org.jetbrains.annotations.NotNull; + +/** + * For receiving a JEI recipe transfer (the + button in a recipe).
+ * Implement this on a {@link com.cleanroommc.modularui.value.sync.SyncHandler} and ensure it's registered to the + * {@link com.cleanroommc.modularui.value.sync.PanelSyncManager}.
+ * If there are multiple sync handlers implementing this, the handler that will be used to receive the recipe is + * indeterminate. + */ +public interface IJEIRecipeReceiver { + + /** + * Returning an {@link IRecipeTransferError} with a type of {@link IRecipeTransferError.Type#INTERNAL} will hide the + * + button.
+ * JEI has a static instance available at {@link mezz.jei.transfer.RecipeTransferErrorInternal#INSTANCE} for this + * purpose. + * + * @param recipeLayout the recipe layout that contains the recipe category, and the item and fluid stacks + * @param maxTransfer if the receiver should try to move as many ingredients as possible to the crafting slots, ie + * a crafting table + * @param simulate if this recipe should only be simulated being transferred + * @return a {@link IRecipeTransferError} if something isn't right, or null if it's okay to transfer this recipe + */ + @SideOnly(Side.CLIENT) + IRecipeTransferError receiveRecipe(@NotNull IRecipeLayout recipeLayout, boolean maxTransfer, boolean simulate); +} diff --git a/src/main/java/gregtech/api/mui/sync/RecipeSyncHandler.java b/src/main/java/gregtech/api/mui/sync/RecipeSyncHandler.java new file mode 100644 index 00000000000..e08a77bc5d7 --- /dev/null +++ b/src/main/java/gregtech/api/mui/sync/RecipeSyncHandler.java @@ -0,0 +1,22 @@ +package gregtech.api.mui.sync; + +import gregtech.api.mui.GregTechGuiScreen; +import gregtech.api.mui.IJEIRecipeReceiver; + +import com.cleanroommc.modularui.value.sync.PanelSyncManager; +import com.cleanroommc.modularui.value.sync.SyncHandler; + +public abstract class RecipeSyncHandler extends SyncHandler implements IJEIRecipeReceiver { + + @Override + public void init(String key, PanelSyncManager syncManager) { + super.init(key, syncManager); + GregTechGuiScreen.registerRecipeReceiver(getKey(), this); + } + + @Override + public void dispose() { + GregTechGuiScreen.removeRecipeReceiver(getKey()); + super.dispose(); + } +} diff --git a/src/main/java/gregtech/api/mui/sync/appeng/AEFluidSyncHandler.java b/src/main/java/gregtech/api/mui/sync/appeng/AEFluidSyncHandler.java new file mode 100644 index 00000000000..4c709dcad85 --- /dev/null +++ b/src/main/java/gregtech/api/mui/sync/appeng/AEFluidSyncHandler.java @@ -0,0 +1,97 @@ +package gregtech.api.mui.sync.appeng; + +import gregtech.api.capability.impl.GhostCircuitItemStackHandler; +import gregtech.api.mui.GTByteBufAdapters; +import gregtech.api.recipes.ingredients.IntCircuitIngredient; +import gregtech.api.util.GTUtility; +import gregtech.api.util.JEIUtil; +import gregtech.common.metatileentities.multi.multiblockpart.appeng.slot.ExportOnlyAEFluidList; +import gregtech.common.metatileentities.multi.multiblockpart.appeng.slot.ExportOnlyAEFluidSlot; +import gregtech.common.metatileentities.multi.multiblockpart.appeng.slot.IConfigurableSlot; +import gregtech.common.metatileentities.multi.multiblockpart.appeng.stack.WrappedFluidStack; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +import appeng.api.storage.data.IAEFluidStack; +import com.cleanroommc.modularui.utils.serialization.IByteBufAdapter; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import mezz.jei.api.gui.IRecipeLayout; +import mezz.jei.api.recipe.transfer.IRecipeTransferError; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.IntConsumer; + +public class AEFluidSyncHandler extends AESyncHandler { + + protected final ExportOnlyAEFluidList fluidList; + + public AEFluidSyncHandler(ExportOnlyAEFluidList fluidList, @Nullable Runnable dirtyNotifier, + @NotNull IntConsumer circuitChangeConsumer) { + super(fluidList.getInventory(), fluidList.isStocking(), dirtyNotifier, circuitChangeConsumer); + this.fluidList = fluidList; + } + + @Override + protected @NotNull IConfigurableSlot @NotNull [] initializeCache() { + // noinspection unchecked + IConfigurableSlot[] cache = new IConfigurableSlot[slots.length]; + for (int index = 0; index < slots.length; index++) { + cache[index] = new ExportOnlyAEFluidSlot(); + } + return cache; + } + + @Override + protected @NotNull IByteBufAdapter initializeByteBufAdapter() { + return GTByteBufAdapters.WRAPPED_FLUID_STACK; + } + + @Override + public boolean isStackValidForSlot(int index, @Nullable IAEFluidStack stack) { + if (stack == null) return true; + if (!isStocking) return true; + return !fluidList.hasStackInConfig(((WrappedFluidStack) stack).getDefinition(), true); + } + + @Override + public IRecipeTransferError receiveRecipe(@NotNull IRecipeLayout recipeLayout, boolean maxTransfer, + boolean simulate) { + if (simulate) return null; + + Int2ObjectMap originalFluidInputs = JEIUtil + .getDisplayedInputFluidStacks(recipeLayout.getFluidStacks(), false, true); + List fluidInputs = new ArrayList<>(originalFluidInputs.values()); + GTUtility.collapseFluidList(fluidInputs); + + int lastSlotIndex; + for (lastSlotIndex = 0; lastSlotIndex < fluidInputs.size(); lastSlotIndex++) { + FluidStack newConfig = fluidInputs.get(lastSlotIndex); + setConfig(lastSlotIndex, newConfig); + } + clearConfigFrom(lastSlotIndex); + + Int2ObjectMap itemInputs = JEIUtil.getDisplayedInputItemStacks(recipeLayout.getItemStacks(), false, + false); + int circuitValue = GhostCircuitItemStackHandler.NO_CONFIG; + for (ItemStack inputStack : itemInputs.values()) { + if (IntCircuitIngredient.isIntegratedCircuit(inputStack)) { + circuitValue = IntCircuitIngredient.getCircuitConfiguration(inputStack); + break; + } + } + ghostCircuitConfig.accept(circuitValue); + + return null; + } + + @SideOnly(Side.CLIENT) + public void setConfig(int index, @Nullable FluidStack stack) { + setConfig(index, WrappedFluidStack.fromFluidStack(stack)); + } +} diff --git a/src/main/java/gregtech/api/mui/sync/appeng/AEItemSyncHandler.java b/src/main/java/gregtech/api/mui/sync/appeng/AEItemSyncHandler.java new file mode 100644 index 00000000000..0c47dd99745 --- /dev/null +++ b/src/main/java/gregtech/api/mui/sync/appeng/AEItemSyncHandler.java @@ -0,0 +1,99 @@ +package gregtech.api.mui.sync.appeng; + +import gregtech.api.capability.impl.GhostCircuitItemStackHandler; +import gregtech.api.mui.GTByteBufAdapters; +import gregtech.api.recipes.ingredients.IntCircuitIngredient; +import gregtech.api.util.GTUtility; +import gregtech.api.util.JEIUtil; +import gregtech.common.metatileentities.multi.multiblockpart.appeng.slot.ExportOnlyAEItemList; +import gregtech.common.metatileentities.multi.multiblockpart.appeng.slot.ExportOnlyAEItemSlot; +import gregtech.common.metatileentities.multi.multiblockpart.appeng.slot.IConfigurableSlot; +import gregtech.common.metatileentities.multi.multiblockpart.appeng.stack.WrappedItemStack; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +import appeng.api.storage.data.IAEItemStack; +import com.cleanroommc.modularui.utils.serialization.IByteBufAdapter; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import mezz.jei.api.gui.IRecipeLayout; +import mezz.jei.api.recipe.transfer.IRecipeTransferError; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.function.IntConsumer; + +public class AEItemSyncHandler extends AESyncHandler { + + protected final ExportOnlyAEItemList itemList; + + public AEItemSyncHandler(ExportOnlyAEItemList itemList, @Nullable Runnable dirtyNotifier, + @NotNull IntConsumer circuitChangeConsumer) { + super(itemList.getInventory(), itemList.isStocking(), dirtyNotifier, circuitChangeConsumer); + this.itemList = itemList; + } + + @Override + protected @NotNull IConfigurableSlot @NotNull [] initializeCache() { + // noinspection unchecked + IConfigurableSlot[] cache = new IConfigurableSlot[slots.length]; + for (int index = 0; index < slots.length; index++) { + cache[index] = new ExportOnlyAEItemSlot(); + } + return cache; + } + + @Override + protected @NotNull IByteBufAdapter initializeByteBufAdapter() { + return GTByteBufAdapters.WRAPPED_ITEM_STACK; + } + + @Override + public boolean isStackValidForSlot(int index, @Nullable IAEItemStack stack) { + if (stack == null || stack.getDefinition().isEmpty()) return true; + if (!isStocking) return true; + return !itemList.hasStackInConfig(stack.getDefinition(), true); + } + + @Override + public IRecipeTransferError receiveRecipe(@NotNull IRecipeLayout recipeLayout, boolean maxTransfer, + boolean simulate) { + if (simulate) return null; + + Int2ObjectMap originalItemInputs = JEIUtil.getDisplayedInputItemStacks(recipeLayout.getItemStacks(), + false, true); + List itemInputs = new ArrayList<>(originalItemInputs.values()); + GTUtility.collapseItemList(itemInputs); + + int circuitValue = GhostCircuitItemStackHandler.NO_CONFIG; + Iterator inputsIterator = itemInputs.iterator(); + while (inputsIterator.hasNext()) { + ItemStack stack = inputsIterator.next(); + if (stack == null) continue; + if (IntCircuitIngredient.isIntegratedCircuit(stack)) { + circuitValue = IntCircuitIngredient.getCircuitConfiguration(stack); + inputsIterator.remove(); + break; + } + } + ghostCircuitConfig.accept(circuitValue); + + int lastSlotIndex; + for (lastSlotIndex = 0; lastSlotIndex < itemInputs.size(); lastSlotIndex++) { + ItemStack newConfig = itemInputs.get(lastSlotIndex); + setConfig(lastSlotIndex, newConfig); + } + clearConfigFrom(lastSlotIndex); + + return null; + } + + @SideOnly(Side.CLIENT) + public void setConfig(int index, @Nullable ItemStack stack) { + setConfig(index, WrappedItemStack.fromItemStack(stack)); + } +} diff --git a/src/main/java/gregtech/api/mui/sync/appeng/AESyncHandler.java b/src/main/java/gregtech/api/mui/sync/appeng/AESyncHandler.java new file mode 100644 index 00000000000..b78cadba8f8 --- /dev/null +++ b/src/main/java/gregtech/api/mui/sync/appeng/AESyncHandler.java @@ -0,0 +1,262 @@ +package gregtech.api.mui.sync.appeng; + +import gregtech.api.mui.IJEIRecipeReceiver; +import gregtech.common.metatileentities.multi.multiblockpart.appeng.slot.IConfigurableSlot; + +import net.minecraft.network.PacketBuffer; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +import appeng.api.storage.data.IAEStack; +import com.cleanroommc.modularui.utils.serialization.IByteBufAdapter; +import com.cleanroommc.modularui.value.sync.SyncHandler; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.util.function.IntConsumer; +import java.util.function.LongBinaryOperator; + +public abstract class AESyncHandler> extends SyncHandler + implements IJEIRecipeReceiver { + + public static final int slotSyncID = 0; + public static final int setConfigID = 1; + public static final int clearConfigID = 2; + public static final int bulkClearConfigID = 3; + public static final int changeConfigAmountID = 4; + public static final int bulkConfigAmountChangeID = 5; + + protected final boolean isStocking; + protected final IntConsumer ghostCircuitConfig; + protected final @NotNull IConfigurableSlot[] slots; + private final @NotNull IConfigurableSlot[] cached; + private final Int2ObjectMap<@NotNull IConfigurableSlot> changeMap = new Int2ObjectOpenHashMap<>(); + + private final IByteBufAdapter byteBufAdapter; + + @Nullable + private final Runnable dirtyNotifier; + + public AESyncHandler(IConfigurableSlot[] slots, boolean isStocking, @Nullable Runnable dirtyNotifier, + @NotNull IntConsumer ghostCircuitConfig) { + this.slots = slots; + this.isStocking = isStocking; + this.ghostCircuitConfig = ghostCircuitConfig; + this.dirtyNotifier = dirtyNotifier; + this.cached = initializeCache(); + this.byteBufAdapter = initializeByteBufAdapter(); + } + + protected abstract @NotNull IConfigurableSlot @NotNull [] initializeCache(); + + protected abstract @NotNull IByteBufAdapter initializeByteBufAdapter(); + + public abstract boolean isStackValidForSlot(int index, @Nullable AEStackType stack); + + @SuppressWarnings("DuplicatedCode") + @Override + public void detectAndSendChanges(boolean init) { + for (int index = 0; index < slots.length; index++) { + IConfigurableSlot slot = slots[index]; + IConfigurableSlot cache = cached[index]; + + AEStackType newConfig = slot.getConfig(); + AEStackType cachedConfig = cache.getConfig(); + AEStackType newStock = slot.getStock(); + AEStackType cachedStock = cache.getStock(); + + if (init || !areAEStackCountEquals(newConfig, cachedConfig) || + !areAEStackCountEquals(newStock, cachedStock)) { + IConfigurableSlot newCache = slot.copy(); + cached[index] = newCache; + changeMap.put(index, newCache); + } + } + + if (!changeMap.isEmpty()) { + syncToClient(slotSyncID, buf -> { + buf.writeVarInt(changeMap.size()); + for (int index : changeMap.keySet()) { + buf.writeVarInt(index); + + AEStackType syncConfig = changeMap.get(index).getConfig(); + if (syncConfig == null) { + buf.writeBoolean(false); + } else { + buf.writeBoolean(true); + syncConfig.writeToPacket(buf); + } + + AEStackType syncStock = changeMap.get(index).getStock(); + if (syncStock == null) { + buf.writeBoolean(false); + } else { + buf.writeBoolean(true); + syncStock.writeToPacket(buf); + } + } + }); + + if (dirtyNotifier != null) { + dirtyNotifier.run(); + } + + changeMap.clear(); + } + } + + @Override + public void readOnServer(int id, PacketBuffer buf) throws IOException { + switch (id) { + case clearConfigID -> slots[buf.readVarInt()].setConfig(null); + case changeConfigAmountID -> { + AEStackType config = getConfig(buf.readVarInt()); + if (config != null) { + config.setStackSize(buf.readLong()); + } + } + case setConfigID -> { + int index = buf.readVarInt(); + AEStackType newConfig = buf.readBoolean() ? byteBufAdapter.deserialize(buf) : null; + if (isStackValidForSlot(index, newConfig)) { + IConfigurableSlot slot = slots[index]; + slot.setConfig(newConfig); + } + } + case bulkClearConfigID -> { + int indexFrom = buf.readVarInt(); + for (int index = indexFrom; index < slots.length; index++) { + IConfigurableSlot slot = slots[index]; + slot.setConfig(null); + } + } + case bulkConfigAmountChangeID -> { + long[] changes = buf.readLongArray(new long[slots.length]); + for (int index = 0; index < slots.length; index++) { + AEStackType config = slots[index].getConfig(); + if (config != null) { + config.setStackSize(changes[index]); + } + } + } + } + } + + @Override + public void readOnClient(int id, PacketBuffer buf) throws IOException { + if (id == slotSyncID) { + int size = buf.readVarInt(); + for (int i = 0; i < size; i++) { + int index = buf.readVarInt(); + IConfigurableSlot slot = slots[index]; + + if (buf.readBoolean()) { + slot.setConfig(byteBufAdapter.deserialize(buf)); + } else { + slot.setConfig(null); + } + + if (buf.readBoolean()) { + slot.setStock(byteBufAdapter.deserialize(buf)); + } else { + slot.setStock(null); + } + } + } + } + + @SideOnly(Side.CLIENT) + public void clearConfig(int index) { + syncToServer(clearConfigID, buf -> buf.writeVarInt(index)); + } + + @SideOnly(Side.CLIENT) + public void clearConfigFrom(int startingIndex) { + syncToServer(bulkClearConfigID, buf -> buf.writeVarInt(startingIndex)); + } + + @SideOnly(Side.CLIENT) + public void setConfig(int index, @Nullable AEStackType newConfig) { + syncToServer(setConfigID, buf -> { + buf.writeVarInt(index); + if (newConfig == null) { + buf.writeBoolean(false); + } else { + buf.writeBoolean(true); + byteBufAdapter.serialize(buf, newConfig); + } + }); + } + + @Nullable + public AEStackType getConfig(int index) { + return slots[index].getConfig(); + } + + public boolean hasConfig(int index) { + return getConfig(index) != null; + } + + public long getConfigAmount(int index) { + AEStackType config = getConfig(index); + return config == null ? 0 : config.getStackSize(); + } + + @SideOnly(Side.CLIENT) + public void setConfigAmount(int index, long newAmount) { + syncToServer(changeConfigAmountID, buf -> { + buf.writeVarInt(index); + buf.writeLong(newAmount); + }); + } + + @Nullable + public AEStackType getStock(int index) { + return slots[index].getStock(); + } + + /** + * Operate over the amounts of all slots, skipping empty slots. + * + * @param function a function that takes the slot index and the original stack size, and returns a new stack size + */ + @SideOnly(Side.CLIENT) + public boolean modifyConfigAmounts(@NotNull LongBinaryOperator function) { + long[] newAmounts = new long[slots.length]; + + boolean anyChanged = false; + for (int index = 0; index < slots.length; index++) { + AEStackType config = slots[index].getConfig(); + if (config != null) { + long originalSize = config.getStackSize(); + long newSize = function.applyAsLong(index, originalSize); + if (newSize != originalSize) { + anyChanged = true; + newAmounts[index] = newSize; + } + } + } + + if (anyChanged) { + syncToServer(bulkConfigAmountChangeID, buf -> buf.writeLongArray(newAmounts)); + } + + return anyChanged; + } + + @SuppressWarnings("BooleanMethodIsAlwaysInverted") + public final boolean areAEStackCountEquals(AEStackType stack1, AEStackType stack2) { + if (stack2 == stack1) { + return true; + } + + if (stack1 != null && stack2 != null) { + return stack1.getStackSize() == stack2.getStackSize() && stack1.equals(stack2); + } + + return false; + } +} diff --git a/src/main/java/gregtech/api/mui/widget/appeng/AEConfigSlot.java b/src/main/java/gregtech/api/mui/widget/appeng/AEConfigSlot.java new file mode 100644 index 00000000000..9737b7d437f --- /dev/null +++ b/src/main/java/gregtech/api/mui/widget/appeng/AEConfigSlot.java @@ -0,0 +1,177 @@ +package gregtech.api.mui.widget.appeng; + +import gregtech.api.mui.GTGuiTextures; +import gregtech.api.mui.GTGuis; +import gregtech.api.mui.sync.appeng.AESyncHandler; + +import appeng.api.storage.data.IAEStack; +import com.cleanroommc.modularui.api.IPanelHandler; +import com.cleanroommc.modularui.api.UpOrDown; +import com.cleanroommc.modularui.api.drawable.IDrawable; +import com.cleanroommc.modularui.api.drawable.IKey; +import com.cleanroommc.modularui.api.widget.Interactable; +import com.cleanroommc.modularui.integration.recipeviewer.RecipeViewerIngredientProvider; +import com.cleanroommc.modularui.screen.RichTooltip; +import com.cleanroommc.modularui.screen.viewport.ModularGuiContext; +import com.cleanroommc.modularui.theme.WidgetThemeEntry; +import com.cleanroommc.modularui.value.LongValue; +import com.cleanroommc.modularui.value.sync.SyncHandler; +import com.cleanroommc.modularui.widget.Widget; +import com.cleanroommc.modularui.widgets.textfield.TextFieldWidget; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.BooleanSupplier; + +public abstract class AEConfigSlot> extends Widget> + implements RecipeViewerIngredientProvider, Interactable { + + protected final boolean isStocking; + protected final int index; + protected final BooleanSupplier isAutoPull; + + private static final IDrawable normalBackground = IDrawable.of(GTGuiTextures.SLOT, GTGuiTextures.CONFIG_ARROW_DARK); + private static final IDrawable autoPullBackground = IDrawable.of(GTGuiTextures.SLOT_DARK, + GTGuiTextures.CONFIG_ARROW); + + @Nullable + private IPanelHandler amountPanel; + protected boolean selected = false; + + @Nullable + protected Runnable onSelect; + + public AEConfigSlot(boolean isStocking, int index, @NotNull BooleanSupplier isAutoPull) { + this.isStocking = isStocking; + this.index = index; + this.isAutoPull = isAutoPull; + size(18); + tooltipBuilder(this::buildTooltip); + } + + protected void buildTooltip(@NotNull RichTooltip tooltip) { + if (isAutoPull.getAsBoolean()) { + tooltip.addLine(IKey.lang("gregtech.gui.config_slot.auto_pull_managed")); + } else { + if (isStocking) { + tooltip.addLine(IKey.lang("gregtech.gui.config_slot.set_only")); + } else { + tooltip.addLine(IKey.lang("gregtech.gui.config_slot.set")); + tooltip.addLine(IKey.lang("gregtech.gui.config_slot.scroll")); + } + tooltip.addLine(IKey.lang("gregtech.gui.config_slot.remove")); + } + } + + @SuppressWarnings("unchecked") + @Override + public @NotNull AESyncHandler getSyncHandler() { + return (AESyncHandler) super.getSyncHandler(); + } + + @Override + public boolean isValidSyncHandler(SyncHandler syncHandler) { + return syncHandler instanceof AESyncHandler; + } + + @Override + public void drawOverlay(ModularGuiContext context, WidgetThemeEntry widgetTheme) { + super.drawOverlay(context, widgetTheme); + + if (selected) { + GTGuiTextures.SELECT_BOX.draw(0, 0, 18, 18); + } + } + + @Override + public @NotNull Result onMousePressed(int mouseButton) { + if (mouseButton == 1) { + getSyncHandler().clearConfig(index); + deselect(); + return Result.SUCCESS; + } else if (!isStocking && mouseButton == 0 && !isAmountPanelOpen() && getSyncHandler().hasConfig(index)) { + if (onSelect != null) { + onSelect.run(); + } + + selected = true; + getAmountPanel().openPanel(); + + return Result.SUCCESS; + } + + return Result.IGNORE; + } + + @Override + public boolean onMouseScroll(UpOrDown scrollDirection, int scrollAmount) { + if (!getSyncHandler().hasConfig(index) || isStocking) return false; + + long newStackSize = getSyncHandler().getConfigAmount(index); + + if (Interactable.hasControlDown()) { + switch (scrollDirection) { + case UP -> newStackSize *= 2; + case DOWN -> newStackSize /= 2; + } + } else { + switch (scrollDirection) { + case UP -> newStackSize += 1; + case DOWN -> newStackSize -= 1; + } + } + + if (newStackSize > 0) { + getSyncHandler().setConfigAmount(index, newStackSize); + return true; + } + + return false; + } + + @Override + public @Nullable IDrawable getBackground() { + return isAutoPull.getAsBoolean() ? autoPullBackground : normalBackground; + } + + protected IPanelHandler getAmountPanel() { + if (amountPanel == null) { + amountPanel = IPanelHandler.simple(getPanel(), + (parentPanel, player) -> GTGuis.blankPopupPanel("ae_slot_amount." + index, 150, 18 + 5 * 2) + .closeListener(onSelect) + .child(createPopupDrawable() + .size(18) + .left(5) + .top(5)) + .child(new TextFieldWidget() + .setNumbersLong(test -> test < 1 ? 1 : test) + .setDefaultNumber(1) + .value(new LongValue.Dynamic(() -> getSyncHandler().getConfigAmount(index), + newAmount -> getSyncHandler().setConfigAmount(index, newAmount))) + .size(100, 10) + .left(18 + 5 * 2) + // alignY didn't work :whar: + .top(7)), + true); + } + + return amountPanel; + } + + public boolean isAmountPanelOpen() { + return getAmountPanel().isPanelOpen(); + } + + public void deselect() { + selected = false; + if (isAmountPanelOpen()) { + getAmountPanel().closePanel(); + } + } + + public void onSelect(@Nullable Runnable onSelect) { + this.onSelect = onSelect; + } + + protected abstract @NotNull AEStackPreviewWidget createPopupDrawable(); +} diff --git a/src/main/java/gregtech/api/mui/widget/appeng/AEDisplaySlot.java b/src/main/java/gregtech/api/mui/widget/appeng/AEDisplaySlot.java new file mode 100644 index 00000000000..d8b3f76288b --- /dev/null +++ b/src/main/java/gregtech/api/mui/widget/appeng/AEDisplaySlot.java @@ -0,0 +1,21 @@ +package gregtech.api.mui.widget.appeng; + +import appeng.api.storage.data.IAEStack; +import com.cleanroommc.modularui.integration.recipeviewer.RecipeViewerIngredientProvider; +import com.cleanroommc.modularui.screen.RichTooltip; +import com.cleanroommc.modularui.widget.Widget; +import org.jetbrains.annotations.NotNull; + +public abstract class AEDisplaySlot> extends Widget> + implements RecipeViewerIngredientProvider { + + protected final int index; + + public AEDisplaySlot(int index) { + this.index = index; + size(18); + tooltipBuilder(this::buildTooltip); + } + + protected abstract void buildTooltip(@NotNull RichTooltip tooltip); +} diff --git a/src/main/java/gregtech/api/mui/widget/appeng/AEStackPreviewWidget.java b/src/main/java/gregtech/api/mui/widget/appeng/AEStackPreviewWidget.java new file mode 100644 index 00000000000..cc0f9c3252f --- /dev/null +++ b/src/main/java/gregtech/api/mui/widget/appeng/AEStackPreviewWidget.java @@ -0,0 +1,34 @@ +package gregtech.api.mui.widget.appeng; + +import appeng.api.storage.data.IAEStack; +import com.cleanroommc.modularui.integration.recipeviewer.RecipeViewerIngredientProvider; +import com.cleanroommc.modularui.screen.RichTooltip; +import com.cleanroommc.modularui.screen.viewport.ModularGuiContext; +import com.cleanroommc.modularui.theme.WidgetThemeEntry; +import com.cleanroommc.modularui.widget.Widget; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Supplier; + +public abstract class AEStackPreviewWidget> extends Widget> + implements RecipeViewerIngredientProvider { + + @NotNull + protected final Supplier stackToDraw; + + public AEStackPreviewWidget(@NotNull Supplier stackToDraw) { + this.stackToDraw = stackToDraw; + tooltipAutoUpdate(true); + tooltipBuilder(this::buildTooltip); + } + + protected abstract void buildTooltip(@NotNull RichTooltip tooltip); + + @Override + public void draw(ModularGuiContext context, WidgetThemeEntry widgetTheme) { + draw(stackToDraw.get(), 1, 1, getArea().w() - 2, getArea().h() - 2); + } + + public abstract void draw(@Nullable T stackToDraw, int x, int y, int width, int height); +} diff --git a/src/main/java/gregtech/api/mui/widget/appeng/fluid/AEFluidConfigSlot.java b/src/main/java/gregtech/api/mui/widget/appeng/fluid/AEFluidConfigSlot.java new file mode 100644 index 00000000000..4bea3e7e5f1 --- /dev/null +++ b/src/main/java/gregtech/api/mui/widget/appeng/fluid/AEFluidConfigSlot.java @@ -0,0 +1,127 @@ +package gregtech.api.mui.widget.appeng.fluid; + +import gregtech.api.mui.GTGuiTextures; +import gregtech.api.mui.sync.appeng.AEFluidSyncHandler; +import gregtech.api.mui.widget.appeng.AEConfigSlot; +import gregtech.api.mui.widget.appeng.AEStackPreviewWidget; +import gregtech.api.util.FluidTooltipUtil; +import gregtech.api.util.KeyUtil; +import gregtech.api.util.TextFormattingUtil; +import gregtech.client.utils.RenderUtil; +import gregtech.common.metatileentities.multi.multiblockpart.appeng.stack.WrappedFluidStack; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.FluidUtil; + +import appeng.api.storage.data.IAEFluidStack; +import com.cleanroommc.modularui.api.widget.Interactable; +import com.cleanroommc.modularui.drawable.GuiDraw; +import com.cleanroommc.modularui.drawable.text.TextRenderer; +import com.cleanroommc.modularui.integration.recipeviewer.RecipeViewerGhostIngredientSlot; +import com.cleanroommc.modularui.screen.RichTooltip; +import com.cleanroommc.modularui.screen.viewport.ModularGuiContext; +import com.cleanroommc.modularui.theme.WidgetThemeEntry; +import com.cleanroommc.modularui.utils.Color; +import com.cleanroommc.modularui.value.sync.SyncHandler; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.BooleanSupplier; + +public class AEFluidConfigSlot extends AEConfigSlot + implements Interactable, RecipeViewerGhostIngredientSlot { + + public AEFluidConfigSlot(boolean isStocking, int index, @NotNull BooleanSupplier isAutoPull) { + super(isStocking, index, isAutoPull); + tooltipAutoUpdate(true); + } + + @Override + public void onInit() { + super.onInit(); + getContext().getRecipeViewerSettings().addGhostIngredientSlot(this); + } + + @Override + protected void buildTooltip(@NotNull RichTooltip tooltip) { + WrappedFluidStack config = (WrappedFluidStack) getSyncHandler().getConfig(index); + if (config != null) { + FluidStack stack = config.getDefinition(); + tooltip.addLine(KeyUtil.fluid(stack)); + FluidTooltipUtil.fluidInfo(stack, tooltip, false, true, true); + tooltip.addLine(FluidTooltipUtil.getFluidModNameKey(stack)); + tooltip.addLine((context, x, y, width, height, widgetTheme) -> { + final int color = Color.GREY.darker(2); + // TODO: do I need to access the text renderer like this? + codechicken.lib.gui.GuiDraw.drawRect(x, y + 3, (int) TextRenderer.SHARED.getLastActualWidth(), 2, + color); + }); + } + + super.buildTooltip(tooltip); + } + + @Override + public @NotNull AEFluidSyncHandler getSyncHandler() { + return (AEFluidSyncHandler) super.getSyncHandler(); + } + + @Override + public boolean isValidSyncHandler(SyncHandler syncHandler) { + return syncHandler instanceof AEFluidSyncHandler; + } + + @Override + public void draw(ModularGuiContext context, WidgetThemeEntry widgetTheme) { + WrappedFluidStack config = (WrappedFluidStack) getSyncHandler().getConfig(index); + if (config != null) { + GuiDraw.drawFluidTexture(config.getDefinition(), 1, 1, getArea().w() - 2, getArea().h() - 2, 0); + if (!isStocking) { + RenderUtil.renderTextFixedCorner(TextFormattingUtil.formatLongToCompactString(config.getStackSize(), 4), + 17d, 18d, 0xFFFFFF, true, 0.5f); + } + } + + RenderUtil.handleJEIGhostSlotOverlay(this, widgetTheme); + } + + @Override + public @NotNull Result onMousePressed(int mouseButton) { + if (isAutoPull.getAsBoolean()) return Result.IGNORE; + + if (mouseButton == 0) { + ItemStack heldItem = getSyncHandler().getSyncManager().getCursorItem(); + FluidStack heldFluid = FluidUtil.getFluidContained(heldItem); + + if (heldFluid != null) { + getSyncHandler().setConfig(index, heldFluid); + return Result.SUCCESS; + } + } + + return super.onMousePressed(mouseButton); + } + + @Override + public void setGhostIngredient(@NotNull FluidStack ingredient) { + getSyncHandler().setConfig(index, ingredient); + } + + @Override + public @Nullable FluidStack castGhostIngredientIfValid(@NotNull Object ingredient) { + return !isAutoPull.getAsBoolean() && ingredient instanceof FluidStack stack ? stack : null; + } + + @Override + public @Nullable Object getIngredient() { + IAEFluidStack config = getSyncHandler().getConfig(index); + return config == null ? null : config.getFluidStack(); + } + + @Override + protected @NotNull AEStackPreviewWidget createPopupDrawable() { + return new AEFluidStackPreviewWidget(() -> getSyncHandler().getConfig(index)) + .background(GTGuiTextures.FLUID_SLOT); + } +} diff --git a/src/main/java/gregtech/api/mui/widget/appeng/fluid/AEFluidDisplaySlot.java b/src/main/java/gregtech/api/mui/widget/appeng/fluid/AEFluidDisplaySlot.java new file mode 100644 index 00000000000..bcad0fd4b1a --- /dev/null +++ b/src/main/java/gregtech/api/mui/widget/appeng/fluid/AEFluidDisplaySlot.java @@ -0,0 +1,67 @@ +package gregtech.api.mui.widget.appeng.fluid; + +import gregtech.api.mui.sync.appeng.AEFluidSyncHandler; +import gregtech.api.mui.widget.appeng.AEDisplaySlot; +import gregtech.api.util.FluidTooltipUtil; +import gregtech.api.util.KeyUtil; +import gregtech.api.util.TextFormattingUtil; +import gregtech.client.utils.RenderUtil; +import gregtech.common.metatileentities.multi.multiblockpart.appeng.stack.WrappedFluidStack; + +import net.minecraftforge.fluids.FluidStack; + +import appeng.api.storage.data.IAEFluidStack; +import com.cleanroommc.modularui.drawable.GuiDraw; +import com.cleanroommc.modularui.screen.RichTooltip; +import com.cleanroommc.modularui.screen.viewport.ModularGuiContext; +import com.cleanroommc.modularui.theme.WidgetThemeEntry; +import com.cleanroommc.modularui.value.sync.SyncHandler; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class AEFluidDisplaySlot extends AEDisplaySlot { + + public AEFluidDisplaySlot(int index) { + super(index); + tooltipAutoUpdate(true); + } + + @Override + protected void buildTooltip(@NotNull RichTooltip tooltip) { + WrappedFluidStack stock = (WrappedFluidStack) getSyncHandler().getStock(index); + if (stock != null) { + FluidStack stack = stock.getDefinition(); + tooltip.addLine(KeyUtil.fluid(stack)); + FluidTooltipUtil.fluidInfo(stack, tooltip, false, true, true); + tooltip.addLine(FluidTooltipUtil.getFluidModNameKey(stack)); + } + } + + @Override + public @NotNull AEFluidSyncHandler getSyncHandler() { + return (AEFluidSyncHandler) super.getSyncHandler(); + } + + @Override + public boolean isValidSyncHandler(SyncHandler syncHandler) { + return syncHandler instanceof AEFluidSyncHandler; + } + + @Override + public void draw(ModularGuiContext context, WidgetThemeEntry widgetTheme) { + WrappedFluidStack stock = (WrappedFluidStack) getSyncHandler().getStock(index); + if (stock != null) { + GuiDraw.drawFluidTexture(stock.getDefinition(), 1, 1, getArea().w() - 2, getArea().h() - 2, 0); + RenderUtil.renderTextFixedCorner(TextFormattingUtil.formatLongToCompactString(stock.getStackSize(), 4), 17d, + 18d, 0xFFFFFF, true, 0.5f); + } + + RenderUtil.handleSlotOverlay(this, widgetTheme); + } + + @Override + public @Nullable Object getIngredient() { + IAEFluidStack stock = getSyncHandler().getStock(index); + return stock == null ? null : stock.getFluidStack(); + } +} diff --git a/src/main/java/gregtech/api/mui/widget/appeng/fluid/AEFluidStackPreviewWidget.java b/src/main/java/gregtech/api/mui/widget/appeng/fluid/AEFluidStackPreviewWidget.java new file mode 100644 index 00000000000..61b6d0b3fe7 --- /dev/null +++ b/src/main/java/gregtech/api/mui/widget/appeng/fluid/AEFluidStackPreviewWidget.java @@ -0,0 +1,46 @@ +package gregtech.api.mui.widget.appeng.fluid; + +import gregtech.api.mui.widget.appeng.AEStackPreviewWidget; +import gregtech.api.util.FluidTooltipUtil; +import gregtech.api.util.KeyUtil; +import gregtech.common.metatileentities.multi.multiblockpart.appeng.stack.WrappedFluidStack; + +import net.minecraftforge.fluids.FluidStack; + +import appeng.api.storage.data.IAEFluidStack; +import com.cleanroommc.modularui.drawable.GuiDraw; +import com.cleanroommc.modularui.screen.RichTooltip; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Supplier; + +class AEFluidStackPreviewWidget extends AEStackPreviewWidget { + + public AEFluidStackPreviewWidget(@NotNull Supplier stackToDraw) { + super(stackToDraw); + } + + @Override + protected void buildTooltip(@NotNull RichTooltip tooltip) { + if (stackToDraw.get() instanceof WrappedFluidStack wrappedFluidStack) { + FluidStack stack = wrappedFluidStack.getDefinition(); + tooltip.addLine(KeyUtil.fluid(stack)); + FluidTooltipUtil.fluidInfo(stack, tooltip, false, true, false); + tooltip.addLine(FluidTooltipUtil.getFluidModNameKey(stack)); + } + } + + @Override + public void draw(@Nullable IAEFluidStack stackToDraw, int x, int y, int width, int height) { + if (stackToDraw instanceof WrappedFluidStack wrappedFluidStack) { + GuiDraw.drawFluidTexture(wrappedFluidStack.getDefinition(), x, y, width, height, 0.0f); + } + } + + @Override + public @Nullable Object getIngredient() { + IAEFluidStack stack = stackToDraw.get(); + return stack == null ? null : stack.getFluidStack(); + } +} diff --git a/src/main/java/gregtech/api/mui/widget/appeng/item/AEItemConfigSlot.java b/src/main/java/gregtech/api/mui/widget/appeng/item/AEItemConfigSlot.java new file mode 100644 index 00000000000..de31ad2e6f9 --- /dev/null +++ b/src/main/java/gregtech/api/mui/widget/appeng/item/AEItemConfigSlot.java @@ -0,0 +1,116 @@ +package gregtech.api.mui.widget.appeng.item; + +import gregtech.api.mui.GTGuiTextures; +import gregtech.api.mui.sync.appeng.AEItemSyncHandler; +import gregtech.api.mui.widget.appeng.AEConfigSlot; +import gregtech.api.mui.widget.appeng.AEStackPreviewWidget; +import gregtech.api.util.TextFormattingUtil; +import gregtech.client.utils.RenderUtil; +import gregtech.common.metatileentities.multi.multiblockpart.appeng.stack.WrappedItemStack; + +import net.minecraft.item.ItemStack; + +import appeng.api.storage.data.IAEItemStack; +import codechicken.lib.gui.GuiDraw; +import com.cleanroommc.modularui.drawable.text.TextRenderer; +import com.cleanroommc.modularui.integration.recipeviewer.RecipeViewerGhostIngredientSlot; +import com.cleanroommc.modularui.screen.RichTooltip; +import com.cleanroommc.modularui.screen.viewport.ModularGuiContext; +import com.cleanroommc.modularui.theme.WidgetThemeEntry; +import com.cleanroommc.modularui.utils.Color; +import com.cleanroommc.modularui.value.sync.SyncHandler; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.BooleanSupplier; + +public class AEItemConfigSlot extends AEConfigSlot implements RecipeViewerGhostIngredientSlot { + + public AEItemConfigSlot(boolean isStocking, int index, @NotNull BooleanSupplier isAutoPull) { + super(isStocking, index, isAutoPull); + tooltipAutoUpdate(true); + } + + @Override + public void onInit() { + super.onInit(); + getContext().getRecipeViewerSettings().addGhostIngredientSlot(this); + } + + @Override + protected void buildTooltip(@NotNull RichTooltip tooltip) { + WrappedItemStack config = (WrappedItemStack) getSyncHandler().getConfig(index); + if (config != null) { + tooltip.addFromItem(config.getDefinition()); + tooltip.addLine((context, x, y, width, height, widgetTheme) -> { + final int color = Color.GREY.darker(2); + // TODO: do I need to access the text renderer like this? + GuiDraw.drawRect(x, y + 3, (int) TextRenderer.SHARED.getLastActualWidth(), 2, color); + }); + } + + super.buildTooltip(tooltip); + } + + @Override + public @NotNull AEItemSyncHandler getSyncHandler() { + return (AEItemSyncHandler) super.getSyncHandler(); + } + + @Override + public boolean isValidSyncHandler(SyncHandler syncHandler) { + return syncHandler instanceof AEItemSyncHandler; + } + + @Override + public void draw(ModularGuiContext context, WidgetThemeEntry widgetTheme) { + WrappedItemStack config = (WrappedItemStack) getSyncHandler().getConfig(index); + if (config != null) { + RenderUtil.drawItemStack(config.getDefinition(), 1, 1, false); + if (!isStocking) { + RenderUtil.renderTextFixedCorner(TextFormattingUtil.formatLongToCompactString(config.getStackSize(), 4), + 17d, 18d, 0xFFFFFF, true, 0.5f); + } + } + + RenderUtil.handleJEIGhostSlotOverlay(this, widgetTheme); + } + + @Override + public @NotNull Result onMousePressed(int mouseButton) { + if (isAutoPull.getAsBoolean()) return Result.IGNORE; + + if (mouseButton == 0) { + ItemStack heldItem = getSyncHandler().getSyncManager().getCursorItem(); + + if (!heldItem.isEmpty()) { + getSyncHandler().setConfig(index, heldItem); + return Result.SUCCESS; + } + } + + return super.onMousePressed(mouseButton); + } + + @Override + public void setGhostIngredient(@NotNull ItemStack ingredient) { + getSyncHandler().setConfig(index, ingredient); + } + + @Override + public @Nullable ItemStack castGhostIngredientIfValid(@NotNull Object ingredient) { + return !isAutoPull.getAsBoolean() && ingredient instanceof ItemStack stack ? stack : null; + } + + @Override + public @Nullable Object getIngredient() { + IAEItemStack config = getSyncHandler().getConfig(index); + return config == null ? null : config.createItemStack(); + } + + @Override + protected @NotNull AEStackPreviewWidget createPopupDrawable() { + return new AEItemStackPreviewWidget(() -> getSyncHandler().getConfig(index)) + .background(GTGuiTextures.SLOT); + } +} diff --git a/src/main/java/gregtech/api/mui/widget/appeng/item/AEItemDisplaySlot.java b/src/main/java/gregtech/api/mui/widget/appeng/item/AEItemDisplaySlot.java new file mode 100644 index 00000000000..e3bc2c84322 --- /dev/null +++ b/src/main/java/gregtech/api/mui/widget/appeng/item/AEItemDisplaySlot.java @@ -0,0 +1,62 @@ +package gregtech.api.mui.widget.appeng.item; + +import gregtech.api.mui.sync.appeng.AEItemSyncHandler; +import gregtech.api.mui.widget.appeng.AEDisplaySlot; +import gregtech.api.util.TextFormattingUtil; +import gregtech.client.utils.RenderUtil; +import gregtech.common.metatileentities.multi.multiblockpart.appeng.stack.WrappedItemStack; + +import net.minecraft.item.ItemStack; + +import appeng.api.storage.data.IAEItemStack; +import com.cleanroommc.modularui.screen.RichTooltip; +import com.cleanroommc.modularui.screen.viewport.ModularGuiContext; +import com.cleanroommc.modularui.theme.WidgetThemeEntry; +import com.cleanroommc.modularui.value.sync.SyncHandler; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class AEItemDisplaySlot extends AEDisplaySlot { + + public AEItemDisplaySlot(int index) { + super(index); + tooltipAutoUpdate(true); + } + + @Override + protected void buildTooltip(@NotNull RichTooltip tooltip) { + WrappedItemStack stock = (WrappedItemStack) getSyncHandler().getStock(index); + if (stock != null) { + tooltip.addFromItem(stock.getDefinition()); + } + } + + @Override + public @NotNull AEItemSyncHandler getSyncHandler() { + return (AEItemSyncHandler) super.getSyncHandler(); + } + + @Override + public boolean isValidSyncHandler(SyncHandler syncHandler) { + return syncHandler instanceof AEItemSyncHandler; + } + + @Override + public void draw(ModularGuiContext context, WidgetThemeEntry widgetTheme) { + WrappedItemStack stock = (WrappedItemStack) getSyncHandler().getStock(index); + if (stock != null) { + ItemStack stack = stock.createItemStack(); + RenderUtil.drawItemStack(stack, 1, 1, false); + RenderUtil.renderTextFixedCorner(TextFormattingUtil.formatLongToCompactString(stock.getStackSize(), 4), 17d, + 18d, 0xFFFFFF, true, 0.5f); + } + + RenderUtil.handleSlotOverlay(this, widgetTheme); + } + + @Override + public @Nullable Object getIngredient() { + IAEItemStack stock = getSyncHandler().getStock(index); + return stock == null ? null : stock.createItemStack(); + } +} diff --git a/src/main/java/gregtech/api/mui/widget/appeng/item/AEItemStackPreviewWidget.java b/src/main/java/gregtech/api/mui/widget/appeng/item/AEItemStackPreviewWidget.java new file mode 100644 index 00000000000..92a30c18dcd --- /dev/null +++ b/src/main/java/gregtech/api/mui/widget/appeng/item/AEItemStackPreviewWidget.java @@ -0,0 +1,39 @@ +package gregtech.api.mui.widget.appeng.item; + +import gregtech.api.mui.widget.appeng.AEStackPreviewWidget; +import gregtech.client.utils.RenderUtil; +import gregtech.common.metatileentities.multi.multiblockpart.appeng.stack.WrappedItemStack; + +import appeng.api.storage.data.IAEItemStack; +import com.cleanroommc.modularui.screen.RichTooltip; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Supplier; + +class AEItemStackPreviewWidget extends AEStackPreviewWidget { + + public AEItemStackPreviewWidget(@NotNull Supplier stackToDraw) { + super(stackToDraw); + } + + @Override + protected void buildTooltip(@NotNull RichTooltip tooltip) { + if (stackToDraw.get() instanceof WrappedItemStack wrappedItemStack) { + tooltip.addFromItem(wrappedItemStack.getDefinition()); + } + } + + @Override + public void draw(@Nullable IAEItemStack stackToDraw, int x, int y, int width, int height) { + if (stackToDraw instanceof WrappedItemStack wrappedItemStack) { + RenderUtil.drawItemStack(wrappedItemStack.getDefinition(), x, y, false); + } + } + + @Override + public @Nullable Object getIngredient() { + IAEItemStack stack = stackToDraw.get(); + return stack == null ? null : stack.createItemStack(); + } +} diff --git a/src/main/java/gregtech/api/recipes/ingredients/IntCircuitIngredient.java b/src/main/java/gregtech/api/recipes/ingredients/IntCircuitIngredient.java index ee259cf24f1..911304019ff 100644 --- a/src/main/java/gregtech/api/recipes/ingredients/IntCircuitIngredient.java +++ b/src/main/java/gregtech/api/recipes/ingredients/IntCircuitIngredient.java @@ -3,12 +3,14 @@ import gregtech.api.items.gui.PlayerInventoryHolder; import gregtech.api.recipes.ingredients.nbtmatch.NBTCondition; import gregtech.api.recipes.ingredients.nbtmatch.NBTMatcher; +import gregtech.api.util.GTUtility; import gregtech.common.items.MetaItems; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.math.MathHelper; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Objects; @@ -93,16 +95,14 @@ protected int computeHash() { @Override public boolean equals(Object obj) { if (this == obj) return true; - if (!(obj instanceof IntCircuitIngredient)) return false; - IntCircuitIngredient other = (IntCircuitIngredient) obj; + if (!(obj instanceof IntCircuitIngredient other)) return false; return this.isConsumable == other.isConsumable && this.matchingConfigurations == other.matchingConfigurations; } @Override public boolean equalIgnoreAmount(GTRecipeInput input) { if (this == input) return true; - if (!(input instanceof IntCircuitIngredient)) return false; - IntCircuitIngredient other = (IntCircuitIngredient) input; + if (!(input instanceof IntCircuitIngredient other)) return false; return this.matchingConfigurations == other.matchingConfigurations; } @@ -116,26 +116,22 @@ public String toString() { return "1xcircuit(" + matchingConfigurations + ")"; } - public static ItemStack getIntegratedCircuit(int configuration) { + public static @NotNull ItemStack getIntegratedCircuit(int configuration) { ItemStack stack = MetaItems.INTEGRATED_CIRCUIT.getStackForm(); setCircuitConfiguration(stack, configuration); return stack; } - public static void setCircuitConfiguration(ItemStack itemStack, int configuration) { + public static void setCircuitConfiguration(@NotNull ItemStack itemStack, int configuration) { if (!MetaItems.INTEGRATED_CIRCUIT.isItemEqual(itemStack)) throw new IllegalArgumentException("Given item stack is not an integrated circuit!"); if (configuration < 0 || configuration > CIRCUIT_MAX) throw new IllegalArgumentException("Given configuration number is out of range!"); - NBTTagCompound tagCompound = itemStack.getTagCompound(); - if (tagCompound == null) { - tagCompound = new NBTTagCompound(); - itemStack.setTagCompound(tagCompound); - } + NBTTagCompound tagCompound = GTUtility.getOrCreateNbtCompound(itemStack); tagCompound.setInteger("Configuration", configuration); } - public static int getCircuitConfiguration(ItemStack itemStack) { + public static int getCircuitConfiguration(@NotNull ItemStack itemStack) { if (!isIntegratedCircuit(itemStack)) return 0; NBTTagCompound tagCompound = itemStack.getTagCompound(); if (tagCompound != null) { @@ -144,7 +140,7 @@ public static int getCircuitConfiguration(ItemStack itemStack) { return 0; } - public static boolean isIntegratedCircuit(ItemStack itemStack) { + public static boolean isIntegratedCircuit(@NotNull ItemStack itemStack) { boolean isCircuit = MetaItems.INTEGRATED_CIRCUIT.isItemEqual(itemStack); if (isCircuit && !itemStack.hasTagCompound()) { NBTTagCompound compound = new NBTTagCompound(); diff --git a/src/main/java/gregtech/api/util/FluidTooltipUtil.java b/src/main/java/gregtech/api/util/FluidTooltipUtil.java index 37607a28bf5..c713442f3d5 100644 --- a/src/main/java/gregtech/api/util/FluidTooltipUtil.java +++ b/src/main/java/gregtech/api/util/FluidTooltipUtil.java @@ -11,6 +11,8 @@ import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.FluidRegistry; import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fml.common.Loader; +import net.minecraftforge.fml.common.ModContainer; import com.cleanroommc.modularui.api.drawable.IKey; import com.cleanroommc.modularui.screen.RichTooltip; @@ -133,6 +135,27 @@ public static Supplier> createFluidTooltip(@Nullable Material mater }; } + public static void fluidInfo(@Nullable FluidStack stack, @NotNull RichTooltip tooltip, boolean showAmount, + boolean showTooltip, boolean showMolAmount) { + if (stack == null) return; + + if (showAmount) { + tooltip.addLine(IKey.str("%,d L", stack.amount)); + } + + if (showTooltip) { + handleFluidTooltip(tooltip, stack); + } + + if (showMolAmount) { + addIngotMolFluidTooltip(tooltip, stack); + } + } + + public static void fluidInfo(@Nullable FluidStack stack, @NotNull RichTooltip tooltip) { + fluidInfo(stack, tooltip, true, true, true); + } + public static void addIngotMolFluidTooltip(@NotNull RichTooltip tooltip, @NotNull FluidStack fluidStack) { // Add tooltip showing how many "ingot moles" (increments of 144) this fluid is if shift is held if (TooltipHelper.isShiftDown() && fluidStack.amount > GTValues.L) { @@ -142,7 +165,27 @@ public static void addIngotMolFluidTooltip(@NotNull RichTooltip tooltip, @NotNul if (extra != 0) { fluidAmount += String.format(" + %d L", extra); } - tooltip.addLine(TextFormatting.GRAY + LocalizationUtils.format("gregtech.gui.amount_raw") + fluidAmount); + tooltip.addLine(KeyUtil.lang(TextFormatting.GRAY, "gregtech.gui.amount_raw", fluidAmount)); } } + + public static @NotNull IKey getFluidModNameKey(@NotNull FluidStack fluidStack) { + return IKey.str(getFluidModName(fluidStack.getFluid())); + } + + public static @NotNull String getFluidModName(@NotNull FluidStack fluidStack) { + return getFluidModName(fluidStack.getFluid()); + } + + public static @NotNull String getFluidModName(@NotNull Fluid fluid) { + ModContainer modContainer = Loader.instance().getIndexedModList().get(getFluidModID(fluid)); + if (modContainer == null) throw new IllegalStateException( + "Tried to get the mod name of a fluid that isn't registered to the Forge FluidRegistry"); + return "§9§o" + modContainer.getName() + "§r"; + } + + public static @NotNull String getFluidModID(@NotNull Fluid fluid) { + String fluidModName = FluidRegistry.getDefaultFluidName(fluid); + return fluidModName.substring(0, fluidModName.indexOf(":")); + } } diff --git a/src/main/java/gregtech/api/util/GTUtility.java b/src/main/java/gregtech/api/util/GTUtility.java index 597f8ef6095..d7f880cc566 100644 --- a/src/main/java/gregtech/api/util/GTUtility.java +++ b/src/main/java/gregtech/api/util/GTUtility.java @@ -56,6 +56,7 @@ import net.minecraftforge.items.IItemHandlerModifiable; import com.google.common.util.concurrent.AtomicDouble; +import it.unimi.dsi.fastutil.Hash; import it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.tuple.Pair; @@ -954,13 +955,38 @@ public double getAsDouble() { } /** - * Safely cast a Long to an Int without overflow. + * Safely multiply two Integers without overflow or underflow, returning {@link Integer#MAX_VALUE} or + * {@link Integer#MIN_VALUE} if it would have. * - * @param v The Long value to cast to an Int. - * @return v, cast to Int, or Integer.MAX_VALUE if it would overflow. + * @param num The Long value to cast to an Int. */ - public static int safeCastLongToInt(long v) { - return v > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) v; + public static int safeCastLongToInt(long num) { + if (num > Integer.MAX_VALUE) { + return Integer.MAX_VALUE; + } else if (num < Integer.MIN_VALUE) { + return Integer.MIN_VALUE; + } else { + return (int) num; + } + } + + /** + * Safely multiply two Ints without overflow or underflow. + */ + public static int multiplySaturated(int a, int b) { + return safeCastLongToInt((long) a * b); + } + + /** + * Safely multiply two Longs without overflow or underflow, returning {@link Long#MAX_VALUE} or + * {@link Long#MIN_VALUE} if it would have. + */ + public static long multiplySaturated(long a, long b) { + if (a > 0 && b > 0 && a > Long.MAX_VALUE / b) return Long.MAX_VALUE; + if (a < 0 && b < 0 && a < Long.MAX_VALUE / b) return Long.MAX_VALUE; + if (a > 0 && b < 0 && b < Long.MIN_VALUE / a) return Long.MIN_VALUE; + if (a < 0 && b > 0 && a < Long.MIN_VALUE / b) return Long.MIN_VALUE; + return a * b; } /** @@ -1024,6 +1050,105 @@ public static int combineRGB(@Range(from = 0, to = 255) int r, @Range(from = 0, return map.get(key.toWildcard()); } + /** + * Attempts to collapse a {@link List} of {@link ItemStack}s by combining similar stacks downwards (towards index + * 0).
+ * WARNING: Mutates original item stacks and list, you might want to make a new list with copies! + * + * @param stacks the list to collapse + * @param maxStackSize the max stack size of the to-be combined stack + * @param removeEmpty if true, will remove entries from the list if they're empty after collapsing + */ + public static void collapseItemList(@NotNull List stacks, + @Range(from = 1, to = Integer.MAX_VALUE) int maxStackSize, + boolean removeEmpty) { + stacks.removeIf(Objects::isNull); + Hash.Strategy stackStrategy = ItemStackHashStrategy.comparingAllButCount(); + + for (int checkingSlot = 0; checkingSlot < stacks.size(); checkingSlot++) { + ItemStack stackToCheck = stacks.get(checkingSlot); + if (stackToCheck.getCount() >= maxStackSize) continue; + + for (int collapsingSlot = stacks.size() - 1; collapsingSlot > checkingSlot; collapsingSlot--) { + ItemStack collapsingStack = stacks.get(collapsingSlot); + if (collapsingStack.isEmpty()) continue; + + if (stackStrategy.equals(stackToCheck, collapsingStack)) { + final int checkingSize = stackToCheck.getCount(); + final int collapsingSize = collapsingStack.getCount(); + + final int maxFinalSize = Math.min(maxStackSize, checkingSize + collapsingSize); + final int toTransfer = maxFinalSize - checkingSize; + + stackToCheck.grow(toTransfer); + collapsingStack.shrink(toTransfer); + } + } + } + + if (removeEmpty) { + stacks.removeIf(ItemStack::isEmpty); + } + } + + /** + * The same as {@link #collapseItemList(List, int, boolean)} but has a stack size limit of {@link Integer#MAX_VALUE} + * and removes empty stacks.
+ * WARNING: Mutates original item stacks, you might want to make a new list with copies! + */ + public static void collapseItemList(List stacks) { + collapseItemList(stacks, Integer.MAX_VALUE, true); + } + + /** + * Attempts to collapse a {@link List} of {@link FluidStack}s by combining similar stacks downwards (towards index + * 0).
+ * WARNING: Mutates original fluid stacks and list, you might want to make a new list with copies! + * + * @param stacks the list to collapse + * @param maxStackSize the max stack size of the to-be combined stack + * @param removeEmpty if true, will remove entries from the list if they're empty after collapsing + */ + public static void collapseFluidList(@NotNull List stacks, + @Range(from = 1, to = Integer.MAX_VALUE) int maxStackSize, + boolean removeEmpty) { + stacks.removeIf(Objects::isNull); + + for (int checkingSlot = 0; checkingSlot < stacks.size(); checkingSlot++) { + FluidStack stackToCheck = stacks.get(checkingSlot); + if (stackToCheck.amount >= maxStackSize) continue; + + for (int collapsingSlot = stacks.size() - 1; collapsingSlot > checkingSlot; collapsingSlot--) { + FluidStack collapsingStack = stacks.get(collapsingSlot); + if (collapsingStack.amount < 1) continue; + + if (FluidStackHashStrategy.comparingAllButAmount().equals(stackToCheck, collapsingStack)) { + final int checkingSize = stackToCheck.amount; + final int collapsingSize = collapsingStack.amount; + + final int maxFinalSize = Math.min(maxStackSize, checkingSize + collapsingSize); + final int toTransfer = maxFinalSize - checkingSize; + + stackToCheck.amount += toTransfer; + collapsingStack.amount -= toTransfer; + } + } + } + + if (removeEmpty) { + stacks.removeIf(stack -> stack.amount < 1); + } + } + + /** + * The same as {@link #collapseFluidList(List, int, boolean)} but has a stack size limit of + * {@link Integer#MAX_VALUE} and removes empty stacks.
+ * WARNING: Mutates original fluid stacks, you might want to make a new list with copies! + */ + public static void collapseFluidList(List stacks) { + collapseFluidList(stacks, Integer.MAX_VALUE, true); + } + public static boolean areFluidStacksEqual(@Nullable FluidStack a, @Nullable FluidStack b) { if (a == b) return true; if (a == null) return false; diff --git a/src/main/java/gregtech/api/util/JEIUtil.java b/src/main/java/gregtech/api/util/JEIUtil.java index 64729686dbf..45721bdd692 100644 --- a/src/main/java/gregtech/api/util/JEIUtil.java +++ b/src/main/java/gregtech/api/util/JEIUtil.java @@ -1,14 +1,147 @@ package gregtech.api.util; import gregtech.integration.jei.JustEnoughItemsModule; +import gregtech.mixins.jei.GuiIngredientGroupAccessor; import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; import com.cleanroommc.modularui.integration.jei.ModularUIJeiPlugin; import com.cleanroommc.modularui.integration.recipeviewer.RecipeViewerGhostIngredientSlot; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import mezz.jei.api.gui.IGuiFluidStackGroup; +import mezz.jei.api.gui.IGuiIngredientGroup; +import mezz.jei.api.gui.IGuiItemStackGroup; +import org.jetbrains.annotations.NotNull; + +import java.util.Set; public class JEIUtil { + /** + * Collects all the item stacks from the input slots of a {@link IGuiItemStackGroup}. + * + * @param stackGroup the group to collect {@link ItemStack}s from + * @param getEmptySlots if true, empty slots will be entered into the map as {@link ItemStack#EMPTY} + * @return a map of collected item stacks to their slot index + */ + public static @NotNull Int2ObjectMap getDisplayedInputItemStacks(@NotNull IGuiItemStackGroup stackGroup, + boolean getEmptySlots, + boolean copyStacks) { + var originalMap = stackGroup.getGuiIngredients(); + Set inputIndexes = getInputIndexes(stackGroup); + if (inputIndexes.isEmpty()) return Int2ObjectMaps.emptyMap(); + + Int2ObjectMap stackMap = new Int2ObjectOpenHashMap<>(inputIndexes.size()); + for (var index : originalMap.keySet()) { + if (inputIndexes.contains(index)) { + ItemStack displayStack = originalMap.get(index).getDisplayedIngredient(); + if (displayStack == null && getEmptySlots) { + stackMap.put(index, ItemStack.EMPTY); + } else if (displayStack != null && !displayStack.isEmpty()) { + stackMap.put(index, copyStacks ? displayStack.copy() : displayStack); + } + } + } + + return stackMap; + } + + /** + * Collects all the item stacks from the input slots of a {@link IGuiItemStackGroup}. + * + * @param stackGroup the group to collect {@link ItemStack}s from + * @param getEmptySlots if true, empty slots will be entered into the map as {@link ItemStack#EMPTY} + * @return a map of collected item stacks to their slot index + */ + public static @NotNull Int2ObjectMap getDisplayedOutputItemStacks(@NotNull IGuiItemStackGroup stackGroup, + boolean getEmptySlots, + boolean copyStacks) { + var originalMap = stackGroup.getGuiIngredients(); + Set inputIndexes = getInputIndexes(stackGroup); + int outputCount = originalMap.size() - inputIndexes.size(); + if (outputCount < 1) return Int2ObjectMaps.emptyMap(); + + Int2ObjectMap stackMap = new Int2ObjectOpenHashMap<>(outputCount); + for (var index : originalMap.keySet()) { + if (!inputIndexes.contains(index)) { + ItemStack displayStack = originalMap.get(index).getDisplayedIngredient(); + if (displayStack == null && getEmptySlots) { + stackMap.put(index, ItemStack.EMPTY); + } else if (displayStack != null && !displayStack.isEmpty()) { + stackMap.put(index, copyStacks ? displayStack.copy() : displayStack); + } + } + } + + return stackMap; + } + + /** + * Collects all the fluid stacks from the input slots of a {@link IGuiFluidStackGroup}. + * + * @param stackGroup the group to collect {@link FluidStack}s from + * @param getEmptySlots if true, empty slots will be entered into the map as null + * @return a map of collected fluid stacks + */ + public static @NotNull Int2ObjectMap getDisplayedInputFluidStacks(@NotNull IGuiFluidStackGroup stackGroup, + boolean getEmptySlots, + boolean copyStacks) { + var originalMap = stackGroup.getGuiIngredients(); + Set inputIndexes = getInputIndexes(stackGroup); + if (inputIndexes.isEmpty()) return Int2ObjectMaps.emptyMap(); + + Int2ObjectMap stackMap = new Int2ObjectOpenHashMap<>(inputIndexes.size()); + for (var index : originalMap.keySet()) { + if (inputIndexes.contains(index)) { + FluidStack displayStack = originalMap.get(index).getDisplayedIngredient(); + if (displayStack == null && getEmptySlots) { + stackMap.put(index, null); + } else if (displayStack != null) { + stackMap.put(index, copyStacks ? displayStack.copy() : displayStack); + } + } + } + + return stackMap; + } + + /** + * Collects all the fluid stacks from the output slots of a {@link IGuiFluidStackGroup}. + * + * @param stackGroup the group to collect {@link FluidStack}s from + * @param getEmptySlots if true, empty slots will be entered into the map as null + * @return a map of collected fluid stacks + */ + public static @NotNull Int2ObjectMap getDisplayedOutputFluidStacks(@NotNull IGuiFluidStackGroup stackGroup, + boolean getEmptySlots, + boolean copyStacks) { + var originalMap = stackGroup.getGuiIngredients(); + Set inputIndexes = getInputIndexes(stackGroup); + int outputCount = originalMap.size() - inputIndexes.size(); + if (outputCount < 1) return Int2ObjectMaps.emptyMap(); + + Int2ObjectMap stackMap = new Int2ObjectOpenHashMap<>(outputCount); + for (var index : originalMap.keySet()) { + if (!inputIndexes.contains(index)) { + FluidStack displayStack = originalMap.get(index).getDisplayedIngredient(); + if (displayStack == null && getEmptySlots) { + stackMap.put(index, null); + } else if (displayStack != null) { + stackMap.put(index, copyStacks ? displayStack.copy() : displayStack); + } + } + } + + return stackMap; + } + + private static Set getInputIndexes(IGuiIngredientGroup ingredientGroup) { + return ((GuiIngredientGroupAccessor) ingredientGroup).getInputSlotIndexes(); + } + /** * Check if the player is currently hovering over a valid ingredient for this slot.
* Will always return false is JEI is not installed. diff --git a/src/main/java/gregtech/api/util/Mods.java b/src/main/java/gregtech/api/util/Mods.java index 4c73cbdb699..424213ae5ba 100644 --- a/src/main/java/gregtech/api/util/Mods.java +++ b/src/main/java/gregtech/api/util/Mods.java @@ -80,6 +80,7 @@ public enum Mods { XaerosMinimap(Names.XAEROS_MINIMAP), Vintagium(Names.VINTAGIUM), Alfheim(Names.ALFHEIM), + ModNameTooltip(Names.MOD_NAME_TOOLTIP), OptiFine(null) { @@ -156,6 +157,7 @@ public static class Names { public static final String XAEROS_MINIMAP = "xaerominimap"; public static final String VINTAGIUM = "vintagium"; public static final String ALFHEIM = "alfheim"; + public static final String MOD_NAME_TOOLTIP = "modnametooltip"; } private final String ID; diff --git a/src/main/java/gregtech/client/IsGuiActuallyClosing.java b/src/main/java/gregtech/client/IsGuiActuallyClosing.java new file mode 100644 index 00000000000..3e7c765d3a0 --- /dev/null +++ b/src/main/java/gregtech/client/IsGuiActuallyClosing.java @@ -0,0 +1,6 @@ +package gregtech.client; + +public class IsGuiActuallyClosing { + + public static boolean isGuiActuallyClosing; +} diff --git a/src/main/java/gregtech/client/utils/RenderUtil.java b/src/main/java/gregtech/client/utils/RenderUtil.java index 7ad7228b23a..d3020d24ba7 100644 --- a/src/main/java/gregtech/client/utils/RenderUtil.java +++ b/src/main/java/gregtech/client/utils/RenderUtil.java @@ -382,6 +382,25 @@ public static void renderText(float x, float y, float z, float scale, int color, GlStateManager.popMatrix(); } + public static void renderTextSized(String text, double x, double y, int color, boolean dropShadow, float scale, + boolean center) { + GlStateManager.pushMatrix(); + FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer; + double scaledTextWidth = center ? fontRenderer.getStringWidth(text) * scale : 0.0; + GlStateManager.translate(x - scaledTextWidth / 2.0, y, 0.0f); + GlStateManager.scale(scale, scale, scale); + fontRenderer.drawString(text, 0, 0, color, dropShadow); + GlStateManager.popMatrix(); + } + + public static void renderTextFixedCorner(String text, double x, double y, int color, boolean dropShadow, + float scale) { + FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer; + double scaledWidth = fontRenderer.getStringWidth(text) * scale; + double scaledHeight = fontRenderer.FONT_HEIGHT * scale; + renderTextSized(text, x - scaledWidth, y - scaledHeight, color, dropShadow, scale, false); + } + public static void renderItemOverLay(float x, float y, float z, float scale, ItemStack itemStack) { RenderHelper.enableStandardItemLighting(); GlStateManager.pushMatrix(); diff --git a/src/main/java/gregtech/common/ConfigHolder.java b/src/main/java/gregtech/common/ConfigHolder.java index 93cbb1dbdcf..618d967a531 100644 --- a/src/main/java/gregtech/common/ConfigHolder.java +++ b/src/main/java/gregtech/common/ConfigHolder.java @@ -335,13 +335,13 @@ public static class EnergyCompatOptions { public static class AE2CompatOptions { - @Config.Comment({ "The interval between ME Hatch/Bus interact ME network.", - "It may cause lag if the interval is too small.", "Default: 2 sec" }) - @Config.RangeInt(min = 1, max = 80) + @Config.Comment({ "The default refresh rate of ME I/O hatches", + "Setting this low may cause lag.", "Default: 40 ticks" }) + @Config.RangeInt(min = 1) public int updateIntervals = 40; @Config.Comment({ "The energy consumption of ME Hatch/Bus.", "Default: 1.0AE/t" }) - @Config.RangeDouble(min = 0.0, max = 10.0) + @Config.RangeDouble(min = 0) public double meHatchEnergyUsage = 1.0; } } diff --git a/src/main/java/gregtech/common/gui/widget/appeng/AEConfigWidget.java b/src/main/java/gregtech/common/gui/widget/appeng/AEConfigWidget.java deleted file mode 100644 index 1195fa8f34f..00000000000 --- a/src/main/java/gregtech/common/gui/widget/appeng/AEConfigWidget.java +++ /dev/null @@ -1,147 +0,0 @@ -package gregtech.common.gui.widget.appeng; - -import gregtech.api.gui.Widget; -import gregtech.api.gui.widgets.AbstractWidgetGroup; -import gregtech.api.util.Position; -import gregtech.api.util.Size; -import gregtech.common.gui.widget.appeng.slot.AEConfigSlot; -import gregtech.common.gui.widget.appeng.slot.AmountSetSlot; -import gregtech.common.metatileentities.multi.multiblockpart.appeng.slot.IConfigurableSlot; - -import appeng.api.storage.data.IAEStack; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; - -import java.io.IOException; - -/** - * @Author GlodBlock - * @Description Display the config like ME Interface - * @Date 2023/4/21-0:27 - */ -public abstract class AEConfigWidget> extends AbstractWidgetGroup { - - protected final IConfigurableSlot[] config; - protected IConfigurableSlot[] cached; - protected Int2ObjectMap> changeMap = new Int2ObjectOpenHashMap<>(); - protected IConfigurableSlot[] displayList; - protected AmountSetSlot amountSetWidget; - protected final boolean isStocking; - protected final static int UPDATE_ID = 1000; - - public AEConfigWidget(int x, int y, IConfigurableSlot[] config, boolean isStocking) { - super(new Position(x, y), new Size(config.length * 18, 18 * 2)); - this.isStocking = isStocking; - this.config = config; - this.init(); - if (!isStocking()) { - this.amountSetWidget = new AmountSetSlot<>(80, -40, this); - this.addWidget(this.amountSetWidget); - this.addWidget(this.amountSetWidget.getText()); - this.amountSetWidget.setVisible(false); - this.amountSetWidget.getText().setVisible(false); - } - } - - public void enableAmount(int slotIndex) { - // Only allow the amount set widget if not stocking, as amount is useless for stocking - if (isStocking()) return; - this.amountSetWidget.setSlotIndex(slotIndex); - this.amountSetWidget.setVisible(true); - this.amountSetWidget.getText().setVisible(true); - } - - public void disableAmount() { - // Only allow the amount set widget if not stocking, as amount is useless for stocking - if (isStocking()) return; - this.amountSetWidget.setSlotIndex(-1); - this.amountSetWidget.setVisible(false); - this.amountSetWidget.getText().setVisible(false); - } - - @Override - public boolean mouseClicked(int mouseX, int mouseY, int button) { - // Only allow the amount set widget if not stocking, as amount is useless for stocking - if (!isStocking()) { - if (this.amountSetWidget.isVisible()) { - if (this.amountSetWidget.getText().mouseClicked(mouseX, mouseY, button)) { - return true; - } - } - for (Widget w : this.widgets) { - if (w instanceof AEConfigSlot) { - ((AEConfigSlot) w).setSelect(false); - } - } - this.disableAmount(); - } - return super.mouseClicked(mouseX, mouseY, button); - } - - abstract void init(); - - public boolean isStocking() { - return isStocking; - } - - @Override - public void detectAndSendChanges() { - super.detectAndSendChanges(); - this.changeMap.clear(); - for (int index = 0; index < this.config.length; index++) { - IConfigurableSlot newSlot = this.config[index]; - IConfigurableSlot oldSlot = this.cached[index]; - T nConfig = newSlot.getConfig(); - T nStock = newSlot.getStock(); - T oConfig = oldSlot.getConfig(); - T oStock = oldSlot.getStock(); - if (!areAEStackCountEquals(nConfig, oConfig) || !areAEStackCountEquals(nStock, oStock)) { - this.changeMap.put(index, newSlot.copy()); - this.cached[index] = this.config[index].copy(); - this.gui.holder.markAsDirty(); - } - } - if (!this.changeMap.isEmpty()) { - this.writeUpdateInfo(UPDATE_ID, buf -> { - try { - buf.writeVarInt(this.changeMap.size()); - for (int index : this.changeMap.keySet()) { - T sConfig = this.changeMap.get(index).getConfig(); - T sStock = this.changeMap.get(index).getStock(); - buf.writeVarInt(index); - if (sConfig != null) { - buf.writeBoolean(true); - sConfig.writeToPacket(buf); - } else { - buf.writeBoolean(false); - } - if (sStock != null) { - buf.writeBoolean(true); - sStock.writeToPacket(buf); - } else { - buf.writeBoolean(false); - } - } - } catch (IOException ignored) {} - }); - } - } - - public final IConfigurableSlot getConfig(int index) { - return this.config[index]; - } - - public final IConfigurableSlot getDisplay(int index) { - return this.displayList[index]; - } - - protected final boolean areAEStackCountEquals(T s1, T s2) { - if (s2 == s1) { - return true; - } - if (s1 != null && s2 != null) { - return s1.getStackSize() == s2.getStackSize() && s1.equals(s2); - } - return false; - } -} diff --git a/src/main/java/gregtech/common/gui/widget/appeng/AEFluidConfigWidget.java b/src/main/java/gregtech/common/gui/widget/appeng/AEFluidConfigWidget.java deleted file mode 100644 index b5f709b0b86..00000000000 --- a/src/main/java/gregtech/common/gui/widget/appeng/AEFluidConfigWidget.java +++ /dev/null @@ -1,68 +0,0 @@ -package gregtech.common.gui.widget.appeng; - -import gregtech.common.gui.widget.appeng.slot.AEFluidConfigSlot; -import gregtech.common.metatileentities.multi.multiblockpart.appeng.slot.ExportOnlyAEFluidList; -import gregtech.common.metatileentities.multi.multiblockpart.appeng.slot.ExportOnlyAEFluidSlot; -import gregtech.common.metatileentities.multi.multiblockpart.appeng.slot.IConfigurableSlot; -import gregtech.common.metatileentities.multi.multiblockpart.appeng.stack.WrappedFluidStack; - -import net.minecraft.network.PacketBuffer; -import net.minecraftforge.fluids.FluidStack; - -import appeng.api.storage.data.IAEFluidStack; - -public class AEFluidConfigWidget extends AEConfigWidget { - - final ExportOnlyAEFluidList fluidList; - - public AEFluidConfigWidget(int x, int y, ExportOnlyAEFluidList fluidList) { - super(x, y, fluidList.getInventory(), fluidList.isStocking()); - this.fluidList = fluidList; - } - - @Override - @SuppressWarnings("unchecked") - void init() { - final int size = (int) Math.sqrt(this.config.length); - this.displayList = new IConfigurableSlot[this.config.length]; - this.cached = new IConfigurableSlot[this.config.length]; - for (int h = 0; h < size; h++) { - for (int w = 0; w < size; w++) { - final int index = h * size + w; - this.displayList[index] = new ExportOnlyAEFluidSlot(); - this.cached[index] = new ExportOnlyAEFluidSlot(); - this.addWidget(new AEFluidConfigSlot(w * 18, h * 18, this, index)); - } - } - } - - public boolean hasStackInConfig(FluidStack stack) { - return fluidList.hasStackInConfig(stack, true); - } - - public boolean isAutoPull() { - return fluidList.isAutoPull(); - } - - @Override - public void readUpdateInfo(int id, PacketBuffer buffer) { - super.readUpdateInfo(id, buffer); - if (id == UPDATE_ID) { - int size = buffer.readVarInt(); - for (int i = 0; i < size; i++) { - int index = buffer.readVarInt(); - IConfigurableSlot slot = this.displayList[index]; - if (buffer.readBoolean()) { - slot.setConfig(WrappedFluidStack.fromPacket(buffer)); - } else { - slot.setConfig(null); - } - if (buffer.readBoolean()) { - slot.setStock(WrappedFluidStack.fromPacket(buffer)); - } else { - slot.setStock(null); - } - } - } - } -} diff --git a/src/main/java/gregtech/common/gui/widget/appeng/AEFluidGridWidget.java b/src/main/java/gregtech/common/gui/widget/appeng/AEFluidGridWidget.java deleted file mode 100644 index 3f7d1358e99..00000000000 --- a/src/main/java/gregtech/common/gui/widget/appeng/AEFluidGridWidget.java +++ /dev/null @@ -1,96 +0,0 @@ -package gregtech.common.gui.widget.appeng; - -import gregtech.api.gui.Widget; -import gregtech.common.gui.widget.appeng.slot.AEFluidDisplayWidget; - -import net.minecraft.network.PacketBuffer; -import net.minecraftforge.fluids.FluidRegistry; -import net.minecraftforge.fluids.FluidStack; - -import appeng.api.storage.data.IAEFluidStack; -import appeng.api.storage.data.IItemList; -import appeng.fluids.util.AEFluidStack; -import appeng.fluids.util.FluidList; -import it.unimi.dsi.fastutil.objects.Object2LongMap; -import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap; - -/** - * @Author GlodBlock - * @Description Display fluid list - * @Date 2023/4/19-0:28 - */ -public class AEFluidGridWidget extends AEListGridWidget { - - private final Object2LongMap changeMap = new Object2LongOpenHashMap<>(); - protected final IItemList cached = new FluidList(); - protected final IItemList displayList = new FluidList(); - - public AEFluidGridWidget(int x, int y, int slotsY, IItemList internalList) { - super(x, y, slotsY, internalList); - } - - @Override - public IAEFluidStack getAt(int index) { - int cnt = 0; - for (IAEFluidStack fluid : this.displayList) { - if (cnt == index) { - return fluid; - } - cnt++; - } - return null; - } - - @Override - protected void addSlotRows(int amount) { - for (int i = 0; i < amount; i++) { - int widgetAmount = this.widgets.size(); - Widget widget = new AEFluidDisplayWidget(0, 0, this, widgetAmount); - this.addWidget(widget); - } - } - - @Override - protected void writeListChange() { - this.changeMap.clear(); - // Remove fluid - for (IAEFluidStack fluid : this.cached) { - if (this.list.findPrecise(fluid) == null || this.list.findPrecise(fluid).getStackSize() == 0) { - this.changeMap.put(fluid.copy(), -fluid.getStackSize()); - fluid.reset(); - } - } - // Change/Add fluid - for (IAEFluidStack fluid : this.list) { - IAEFluidStack cachedFluid = this.cached.findPrecise(fluid); - if (cachedFluid == null || cachedFluid.getStackSize() == 0) { - this.changeMap.put(fluid.copy(), fluid.getStackSize()); - this.cached.add(fluid.copy()); - } else { - if (cachedFluid.getStackSize() != fluid.getStackSize()) { - this.changeMap.put(fluid.copy(), fluid.getStackSize() - cachedFluid.getStackSize()); - this.cached.add(fluid.copy().setStackSize(fluid.getStackSize() - cachedFluid.getStackSize())); - } - } - } - this.writeUpdateInfo(CONTENT_CHANGE_ID, buf -> { - buf.writeVarInt(this.changeMap.size()); - for (IAEFluidStack fluid : this.changeMap.keySet()) { - buf.writeString(fluid.getFluid().getName()); - buf.writeVarLong(this.changeMap.get(fluid)); - } - }); - } - - @Override - protected void readListChange(PacketBuffer buffer) { - int size = buffer.readVarInt(); - for (int i = 0; i < size; i++) { - FluidStack fluid = FluidRegistry.getFluidStack(buffer.readString(Integer.MAX_VALUE / 16), 1); - long delta = buffer.readVarLong(); - if (fluid != null) { - this.displayList.add(AEFluidStack.fromFluidStack(fluid).setStackSize(delta)); - } - } - } -} diff --git a/src/main/java/gregtech/common/gui/widget/appeng/AEItemConfigWidget.java b/src/main/java/gregtech/common/gui/widget/appeng/AEItemConfigWidget.java deleted file mode 100644 index 0f2afe98235..00000000000 --- a/src/main/java/gregtech/common/gui/widget/appeng/AEItemConfigWidget.java +++ /dev/null @@ -1,68 +0,0 @@ -package gregtech.common.gui.widget.appeng; - -import gregtech.common.gui.widget.appeng.slot.AEItemConfigSlot; -import gregtech.common.metatileentities.multi.multiblockpart.appeng.slot.ExportOnlyAEItemList; -import gregtech.common.metatileentities.multi.multiblockpart.appeng.slot.ExportOnlyAEItemSlot; -import gregtech.common.metatileentities.multi.multiblockpart.appeng.slot.IConfigurableSlot; -import gregtech.common.metatileentities.multi.multiblockpart.appeng.stack.WrappedItemStack; - -import net.minecraft.item.ItemStack; -import net.minecraft.network.PacketBuffer; - -import appeng.api.storage.data.IAEItemStack; - -public class AEItemConfigWidget extends AEConfigWidget { - - final ExportOnlyAEItemList itemList; - - public AEItemConfigWidget(int x, int y, ExportOnlyAEItemList itemList) { - super(x, y, itemList.getInventory(), itemList.isStocking()); - this.itemList = itemList; - } - - @Override - @SuppressWarnings("unchecked") - void init() { - final int size = (int) Math.sqrt(this.config.length); - this.displayList = new IConfigurableSlot[this.config.length]; - this.cached = new IConfigurableSlot[this.config.length]; - for (int h = 0; h < size; h++) { - for (int w = 0; w < size; w++) { - final int index = h * size + w; - this.displayList[index] = new ExportOnlyAEItemSlot(); - this.cached[index] = new ExportOnlyAEItemSlot(); - this.addWidget(new AEItemConfigSlot(w * 18, h * 18, this, index)); - } - } - } - - public boolean hasStackInConfig(ItemStack stack) { - return itemList.hasStackInConfig(stack, true); - } - - public boolean isAutoPull() { - return itemList.isAutoPull(); - } - - @Override - public void readUpdateInfo(int id, PacketBuffer buffer) { - super.readUpdateInfo(id, buffer); - if (id == UPDATE_ID) { - int size = buffer.readVarInt(); - for (int i = 0; i < size; i++) { - int index = buffer.readVarInt(); - IConfigurableSlot slot = this.displayList[index]; - if (buffer.readBoolean()) { - slot.setConfig(WrappedItemStack.fromPacket(buffer)); - } else { - slot.setConfig(null); - } - if (buffer.readBoolean()) { - slot.setStock(WrappedItemStack.fromPacket(buffer)); - } else { - slot.setStock(null); - } - } - } - } -} diff --git a/src/main/java/gregtech/common/gui/widget/appeng/AEItemGridWidget.java b/src/main/java/gregtech/common/gui/widget/appeng/AEItemGridWidget.java deleted file mode 100644 index 7b036eee6af..00000000000 --- a/src/main/java/gregtech/common/gui/widget/appeng/AEItemGridWidget.java +++ /dev/null @@ -1,100 +0,0 @@ -package gregtech.common.gui.widget.appeng; - -import gregtech.api.gui.Widget; -import gregtech.common.gui.widget.appeng.slot.AEItemDisplayWidget; - -import net.minecraft.item.ItemStack; -import net.minecraft.network.PacketBuffer; - -import appeng.api.storage.data.IAEItemStack; -import appeng.api.storage.data.IItemList; -import appeng.util.item.AEItemStack; -import appeng.util.item.ItemList; -import it.unimi.dsi.fastutil.objects.Object2LongMap; -import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap; - -import java.io.IOException; - -/** - * @Author GlodBlock - * @Description Display item list - * @Date 2023/4/19-21:33 - */ -public class AEItemGridWidget extends AEListGridWidget { - - private final Object2LongMap changeMap = new Object2LongOpenHashMap<>(); - protected final IItemList cached = new ItemList(); - protected final IItemList displayList = new ItemList(); - - public AEItemGridWidget(int x, int y, int slotsY, IItemList internalList) { - super(x, y, slotsY, internalList); - } - - @Override - public IAEItemStack getAt(int index) { - int cnt = 0; - for (IAEItemStack item : this.displayList) { - if (cnt == index) { - return item; - } - cnt++; - } - return null; - } - - @Override - protected void addSlotRows(int amount) { - for (int i = 0; i < amount; i++) { - int widgetAmount = this.widgets.size(); - Widget widget = new AEItemDisplayWidget(0, 0, this, widgetAmount); - this.addWidget(widget); - } - } - - @Override - protected void writeListChange() { - this.changeMap.clear(); - // Remove item - for (IAEItemStack item : this.cached) { - if (this.list.findPrecise(item) == null || this.list.findPrecise(item).getStackSize() == 0) { - this.changeMap.put(item.copy(), -item.getStackSize()); - item.reset(); - } - } - // Change/Add item - for (IAEItemStack item : this.list) { - IAEItemStack cachedItem = this.cached.findPrecise(item); - if (cachedItem == null || cachedItem.getStackSize() == 0) { - this.changeMap.put(item.copy(), item.getStackSize()); - this.cached.add(item.copy()); - } else { - if (cachedItem.getStackSize() != item.getStackSize()) { - this.changeMap.put(item.copy(), item.getStackSize() - cachedItem.getStackSize()); - this.cached.add(item.copy().setStackSize(item.getStackSize() - cachedItem.getStackSize())); - } - } - } - this.writeUpdateInfo(CONTENT_CHANGE_ID, buf -> { - buf.writeVarInt(this.changeMap.size()); - for (IAEItemStack item : this.changeMap.keySet()) { - buf.writeItemStack(item.createItemStack()); - buf.writeVarLong(this.changeMap.get(item)); - } - }); - } - - @Override - protected void readListChange(PacketBuffer buffer) { - int size = buffer.readVarInt(); - try { - for (int i = 0; i < size; i++) { - ItemStack item = buffer.readItemStack(); - item.setCount(1); - long delta = buffer.readVarLong(); - if (!item.isEmpty()) { - this.displayList.add(AEItemStack.fromItemStack(item).setStackSize(delta)); - } - } - } catch (IOException ignore) {} - } -} diff --git a/src/main/java/gregtech/common/gui/widget/appeng/AEListGridWidget.java b/src/main/java/gregtech/common/gui/widget/appeng/AEListGridWidget.java deleted file mode 100644 index 1cdcdf4804b..00000000000 --- a/src/main/java/gregtech/common/gui/widget/appeng/AEListGridWidget.java +++ /dev/null @@ -1,79 +0,0 @@ -package gregtech.common.gui.widget.appeng; - -import gregtech.api.gui.Widget; -import gregtech.api.gui.widgets.ScrollableListWidget; - -import net.minecraft.network.PacketBuffer; - -import appeng.api.storage.data.IAEStack; -import appeng.api.storage.data.IItemList; - -/** - * @Author GlodBlock - * @Description A display only widget for {@link IItemList} - * @Date 2023/4/19-0:18 - */ -public abstract class AEListGridWidget> extends ScrollableListWidget { - - protected final IItemList list; - private final int slotAmountY; - private int slotRowsAmount = 0; - protected final static int ROW_CHANGE_ID = 2; - protected final static int CONTENT_CHANGE_ID = 3; - - public AEListGridWidget(int x, int y, int slotsY, IItemList internalList) { - super(x, y, 18 + 140, slotsY * 18); - this.list = internalList; - this.slotAmountY = slotsY; - } - - public abstract T getAt(int index); - - protected abstract void addSlotRows(int amount); - - private void removeSlotRows(int amount) { - for (int i = 0; i < amount; i++) { - Widget slotWidget = this.widgets.remove(this.widgets.size() - 1); - removeWidget(slotWidget); - } - } - - private void modifySlotRows(int delta) { - if (delta > 0) { - addSlotRows(delta); - } else { - removeSlotRows(delta); - } - } - - @Override - public void detectAndSendChanges() { - super.detectAndSendChanges(); - if (this.list == null) return; - int amountOfTypes = this.list.size(); - int slotRowsRequired = Math.max(this.slotAmountY, amountOfTypes); - if (this.slotRowsAmount != slotRowsRequired) { - int slotsToAdd = slotRowsRequired - this.slotRowsAmount; - this.slotRowsAmount = slotRowsRequired; - this.writeUpdateInfo(ROW_CHANGE_ID, buf -> buf.writeVarInt(slotsToAdd)); - this.modifySlotRows(slotsToAdd); - } - this.writeListChange(); - } - - protected abstract void writeListChange(); - - @Override - public void readUpdateInfo(int id, PacketBuffer buffer) { - super.readUpdateInfo(id, buffer); - if (id == ROW_CHANGE_ID) { - int slotsToAdd = buffer.readVarInt(); - this.modifySlotRows(slotsToAdd); - } - if (id == CONTENT_CHANGE_ID) { - this.readListChange(buffer); - } - } - - protected abstract void readListChange(PacketBuffer buffer); -} diff --git a/src/main/java/gregtech/common/gui/widget/appeng/slot/AEConfigSlot.java b/src/main/java/gregtech/common/gui/widget/appeng/slot/AEConfigSlot.java deleted file mode 100644 index d663340a451..00000000000 --- a/src/main/java/gregtech/common/gui/widget/appeng/slot/AEConfigSlot.java +++ /dev/null @@ -1,82 +0,0 @@ -package gregtech.common.gui.widget.appeng.slot; - -import gregtech.api.gui.Widget; -import gregtech.api.gui.ingredient.IGhostIngredientTarget; -import gregtech.api.util.Position; -import gregtech.api.util.Size; -import gregtech.common.gui.widget.appeng.AEConfigWidget; -import gregtech.common.metatileentities.multi.multiblockpart.appeng.slot.IConfigurableSlot; - -import net.minecraft.client.resources.I18n; -import net.minecraft.item.ItemStack; - -import appeng.api.storage.data.IAEStack; -import mezz.jei.api.gui.IGhostIngredientHandler; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -public class AEConfigSlot> extends Widget implements IGhostIngredientTarget { - - protected static final int DISPLAY_X_OFFSET = 18 * 5; - protected AEConfigWidget parentWidget; - protected int index; - protected final static int REMOVE_ID = 1000; - protected final static int UPDATE_ID = 1001; - protected final static int AMOUNT_CHANGE_ID = 1002; - protected boolean select = false; - - public AEConfigSlot(Position pos, Size size, AEConfigWidget widget, int index) { - super(pos, size); - this.parentWidget = widget; - this.index = index; - } - - @Override - public void drawInForeground(int mouseX, int mouseY) { - super.drawInForeground(mouseX, mouseY); - IConfigurableSlot slot = this.parentWidget.getDisplay(this.index); - if (slot.getConfig() == null && mouseOverConfig(mouseX, mouseY)) { - List hoverStringList = new ArrayList<>(); - addHoverText(hoverStringList); - if (!hoverStringList.isEmpty()) { - drawHoveringText(ItemStack.EMPTY, hoverStringList, -1, mouseX, mouseY); - } - } - } - - protected void addHoverText(List hoverText) { - hoverText.add(I18n.format("gregtech.gui.config_slot")); - if (!parentWidget.isStocking()) { - hoverText.add(I18n.format("gregtech.gui.config_slot.set")); - hoverText.add(I18n.format("gregtech.gui.config_slot.scroll")); - } else { - hoverText.add(I18n.format("gregtech.gui.config_slot.set_only")); - } - hoverText.add(I18n.format("gregtech.gui.config_slot.remove")); - } - - public void setSelect(boolean val) { - this.select = val; - } - - protected boolean mouseOverConfig(int mouseX, int mouseY) { - Position position = getPosition(); - return isMouseOver(position.x, position.y, 18, 18, mouseX, mouseY); - } - - protected boolean mouseOverStock(int mouseX, int mouseY) { - Position position = getPosition(); - return isMouseOver(position.x + DISPLAY_X_OFFSET, position.y, 18, 18, mouseX, mouseY); - } - - @Override - public List> getPhantomTargets(Object ingredient) { - return Collections.emptyList(); - } - - public AEConfigWidget getParentWidget() { - return parentWidget; - } -} diff --git a/src/main/java/gregtech/common/gui/widget/appeng/slot/AEFluidConfigSlot.java b/src/main/java/gregtech/common/gui/widget/appeng/slot/AEFluidConfigSlot.java deleted file mode 100644 index 2b852fdeb14..00000000000 --- a/src/main/java/gregtech/common/gui/widget/appeng/slot/AEFluidConfigSlot.java +++ /dev/null @@ -1,294 +0,0 @@ -package gregtech.common.gui.widget.appeng.slot; - -import gregtech.api.gui.GuiTextures; -import gregtech.api.gui.IRenderContext; -import gregtech.api.util.FluidTooltipUtil; -import gregtech.api.util.Position; -import gregtech.api.util.Size; -import gregtech.api.util.TextFormattingUtil; -import gregtech.client.utils.RenderUtil; -import gregtech.common.gui.widget.appeng.AEFluidConfigWidget; -import gregtech.common.metatileentities.multi.multiblockpart.appeng.slot.IConfigurableSlot; -import gregtech.common.metatileentities.multi.multiblockpart.appeng.stack.WrappedFluidStack; - -import net.minecraft.client.resources.I18n; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.network.PacketBuffer; -import net.minecraftforge.fluids.FluidRegistry; -import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.fluids.FluidUtil; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; - -import appeng.api.storage.data.IAEFluidStack; -import com.google.common.collect.Lists; -import mezz.jei.api.gui.IGhostIngredientHandler; -import org.jetbrains.annotations.NotNull; - -import java.awt.*; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import static gregtech.api.capability.GregtechDataCodes.LOAD_PHANTOM_FLUID_STACK_FROM_NBT; -import static gregtech.api.util.GTUtility.getFluidFromContainer; - -public class AEFluidConfigSlot extends AEConfigSlot { - - public AEFluidConfigSlot(int x, int y, AEFluidConfigWidget widget, int index) { - super(new Position(x, y), new Size(18 * 6, 18), widget, index); - } - - @Override - public AEFluidConfigWidget getParentWidget() { - return (AEFluidConfigWidget) super.getParentWidget(); - } - - @Override - public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { - super.drawInBackground(mouseX, mouseY, partialTicks, context); - AEFluidConfigWidget pw = getParentWidget(); - Position position = getPosition(); - IConfigurableSlot slot = pw.getDisplay(this.index); - IAEFluidStack config = slot.getConfig(); - IAEFluidStack stock = slot.getStock(); - drawSlots(pw.isAutoPull(), position.x, position.y); - if (this.select) { - GuiTextures.SELECT_BOX.draw(position.x, position.y, 18, 18); - } - int stackX = position.x + 1; - int stackY = position.y + 1; - if (config != null) { - RenderUtil.drawFluidForGui(config.getFluidStack(), config.getFluidStack().amount, stackX, stackY, 17, 17); - - if (!pw.isStocking()) { - String amountStr = TextFormattingUtil.formatLongToCompactString(config.getStackSize(), 4) + "L"; - drawStringFixedCorner(amountStr, stackX + 17, stackY + 17, 16777215, true, 0.5f); - } - } - if (stock != null) { - RenderUtil.drawFluidForGui(stock.getFluidStack(), stock.getFluidStack().amount, stackX + DISPLAY_X_OFFSET, - stackY, 17, 17); - String amountStr = TextFormattingUtil.formatLongToCompactString(stock.getStackSize(), 4) + "L"; - drawStringFixedCorner(amountStr, stackX + DISPLAY_X_OFFSET + 17, stackY + 17, 16777215, true, 0.5f); - } - if (mouseOverConfig(mouseX, mouseY)) { - drawSelectionOverlay(stackX, stackY, 16, 16); - } else if (mouseOverStock(mouseX, mouseY)) { - drawSelectionOverlay(stackX + DISPLAY_X_OFFSET, stackY, 16, 16); - } - } - - private void drawSlots(boolean autoPull, int x, int y) { - if (autoPull) { - GuiTextures.SLOT_DARK.draw(x, y, 18, 18); - } else { - GuiTextures.FLUID_SLOT.draw(x, y, 18, 18); - } - GuiTextures.SLOT_DARK.draw(x + DISPLAY_X_OFFSET, y, 18, 18); - GuiTextures.CONFIG_ARROW.draw(x, y, 18, 18); - } - - @Override - public void drawInForeground(int mouseX, int mouseY) { - super.drawInForeground(mouseX, mouseY); - IAEFluidStack fluid = null; - boolean displayAmt = false; - IConfigurableSlot slot = this.parentWidget.getDisplay(this.index); - if (mouseOverConfig(mouseX, mouseY)) { - fluid = slot.getConfig(); - } else if (mouseOverStock(mouseX, mouseY)) { - fluid = slot.getStock(); - displayAmt = true; - } - if (fluid != null) { - List hoverStringList = new ArrayList<>(); - hoverStringList.add(fluid.getFluidStack().getLocalizedName()); - if (displayAmt) { - hoverStringList.add(String.format("%,d L", fluid.getStackSize())); - } - List formula = FluidTooltipUtil.getFluidTooltip(fluid.getFluidStack()); - if (formula != null) { - for (String s : formula) { - if (s.isEmpty()) continue; - hoverStringList.add(s); - } - } - drawHoveringText(ItemStack.EMPTY, hoverStringList, -1, mouseX, mouseY); - } - } - - @Override - protected void addHoverText(List hoverText) { - if (getParentWidget().isAutoPull()) { - hoverText.add(I18n.format("gregtech.gui.config_slot")); - hoverText.add(I18n.format("gregtech.gui.config_slot.auto_pull_managed")); - } else { - super.addHoverText(hoverText); - } - } - - @Override - public boolean mouseClicked(int mouseX, int mouseY, int button) { - AEFluidConfigWidget pw = getParentWidget(); - if (pw.isAutoPull()) { - return false; - } - - if (mouseOverConfig(mouseX, mouseY)) { - if (button == 1) { - // Right click to clear - writeClientAction(REMOVE_ID, buf -> {}); - - if (!pw.isStocking()) { - this.parentWidget.disableAmount(); - } - } else if (button == 0) { - // Left click to set/select - ItemStack hold = this.gui.entityPlayer.inventory.getItemStack(); - FluidStack fluid = FluidUtil.getFluidContained(hold); - - if (fluid != null) { - writeClientAction(UPDATE_ID, buf -> { - buf.writeString(fluid.getFluid().getName()); - buf.writeVarInt(fluid.amount); - }); - } - - if (!pw.isStocking()) { - this.parentWidget.enableAmount(this.index); - this.select = true; - } - } - return true; - } - return false; - } - - @Override - public void handleClientAction(int id, PacketBuffer buffer) { - super.handleClientAction(id, buffer); - IConfigurableSlot slot = this.parentWidget.getConfig(this.index); - if (id == REMOVE_ID) { - slot.setConfig(null); - this.parentWidget.disableAmount(); - writeUpdateInfo(REMOVE_ID, buf -> {}); - } - if (id == UPDATE_ID) { - FluidStack fluid = FluidRegistry.getFluidStack(buffer.readString(Integer.MAX_VALUE / 16), - buffer.readVarInt()); - if (!isFluidValidForSlot(fluid)) return; - slot.setConfig(WrappedFluidStack.fromFluidStack(fluid)); - this.parentWidget.enableAmount(this.index); - if (fluid != null) { - writeUpdateInfo(UPDATE_ID, buf -> { - buf.writeString(fluid.getFluid().getName()); - buf.writeVarInt(fluid.amount); - }); - } - } - if (id == AMOUNT_CHANGE_ID) { - if (slot.getConfig() != null) { - int amt = buffer.readInt(); - slot.getConfig().setStackSize(amt); - writeUpdateInfo(AMOUNT_CHANGE_ID, buf -> buf.writeInt(amt)); - } - } - if (id == LOAD_PHANTOM_FLUID_STACK_FROM_NBT) { - try { - FluidStack fluid = FluidStack.loadFluidStackFromNBT(buffer.readCompoundTag()); - slot.setConfig(WrappedFluidStack.fromFluidStack(fluid)); - this.parentWidget.enableAmount(this.index); - if (fluid != null) { - writeUpdateInfo(UPDATE_ID, buf -> { - buf.writeString(fluid.getFluid().getName()); - buf.writeVarInt(fluid.amount); - }); - } - } catch (IOException e) { - throw new RuntimeException(e); - } - } - } - - @Override - public void readUpdateInfo(int id, PacketBuffer buffer) { - super.readUpdateInfo(id, buffer); - IConfigurableSlot slot = this.parentWidget.getDisplay(this.index); - if (id == REMOVE_ID) { - slot.setConfig(null); - } - if (id == UPDATE_ID) { - FluidStack fluid = FluidRegistry.getFluidStack(buffer.readString(Integer.MAX_VALUE / 16), - buffer.readVarInt()); - slot.setConfig(WrappedFluidStack.fromFluidStack(fluid)); - } - if (id == AMOUNT_CHANGE_ID) { - if (slot.getConfig() != null) { - int amt = buffer.readInt(); - slot.getConfig().setStackSize(amt); - } - } - } - - private boolean isFluidValidForSlot(FluidStack stack) { - if (stack == null) return true; - AEFluidConfigWidget pw = getParentWidget(); - if (!pw.isStocking()) return true; - return !pw.hasStackInConfig(stack); - } - - @Override - public List> getPhantomTargets(Object ingredient) { - if (getFluidFromContainer(ingredient) == null) { - return Collections.emptyList(); - } - Rectangle rectangle = toRectangleBox(); - rectangle.width /= 6; - return Lists.newArrayList(new IGhostIngredientHandler.Target<>() { - - @NotNull - @Override - public Rectangle getArea() { - return rectangle; - } - - @Override - public void accept(@NotNull Object ingredient) { - FluidStack stack = getFluidFromContainer(ingredient); - - if (stack != null) { - NBTTagCompound compound = stack.writeToNBT(new NBTTagCompound()); - writeClientAction(LOAD_PHANTOM_FLUID_STACK_FROM_NBT, buf -> buf.writeCompoundTag(compound)); - } - } - }); - } - - @SideOnly(Side.CLIENT) - public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { - if (parentWidget.isStocking()) return false; - IConfigurableSlot slot = this.parentWidget.getDisplay(this.index); - Rectangle rectangle = toRectangleBox(); - rectangle.width /= 6; - if (slot.getConfig() == null || wheelDelta == 0 || !rectangle.contains(mouseX, mouseY)) { - return false; - } - FluidStack fluid = slot.getConfig().getFluidStack(); - long amt; - if (isCtrlDown()) { - amt = wheelDelta > 0 ? fluid.amount * 2L : fluid.amount / 2L; - } else { - amt = wheelDelta > 0 ? fluid.amount + 1L : fluid.amount - 1L; - } - - if (amt > 0 && amt < Integer.MAX_VALUE + 1L) { - int finalAmt = (int) amt; - writeClientAction(AMOUNT_CHANGE_ID, buf -> buf.writeInt(finalAmt)); - return true; - } - return false; - } -} diff --git a/src/main/java/gregtech/common/gui/widget/appeng/slot/AEFluidDisplayWidget.java b/src/main/java/gregtech/common/gui/widget/appeng/slot/AEFluidDisplayWidget.java deleted file mode 100644 index 6aa47927c36..00000000000 --- a/src/main/java/gregtech/common/gui/widget/appeng/slot/AEFluidDisplayWidget.java +++ /dev/null @@ -1,73 +0,0 @@ -package gregtech.common.gui.widget.appeng.slot; - -import gregtech.api.gui.GuiTextures; -import gregtech.api.gui.IRenderContext; -import gregtech.api.gui.Widget; -import gregtech.api.util.FluidTooltipUtil; -import gregtech.api.util.Position; -import gregtech.api.util.Size; -import gregtech.client.utils.RenderUtil; -import gregtech.common.gui.widget.appeng.AEListGridWidget; - -import net.minecraft.item.ItemStack; - -import appeng.api.storage.data.IAEFluidStack; - -import java.util.ArrayList; -import java.util.List; - -/** - * @Author GlodBlock - * @Description Display a certain {@link IAEFluidStack} element. - * @Date 2023/4/19-0:30 - */ -public class AEFluidDisplayWidget extends Widget { - - private final AEListGridWidget gridWidget; - private final int index; - - public AEFluidDisplayWidget(int x, int y, AEListGridWidget gridWidget, int index) { - super(new Position(x, y), new Size(18, 18)); - this.gridWidget = gridWidget; - this.index = index; - } - - @Override - public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { - super.drawInBackground(mouseX, mouseY, partialTicks, context); - Position position = getPosition(); - IAEFluidStack fluid = this.gridWidget.getAt(this.index); - GuiTextures.FLUID_SLOT.draw(position.x, position.y, 18, 18); - GuiTextures.NUMBER_BACKGROUND.draw(position.x + 18, position.y, 140, 18); - int stackX = position.x + 1; - int stackY = position.y + 1; - if (fluid != null) { - RenderUtil.drawFluidForGui(fluid.getFluidStack(), fluid.getFluidStack().amount, stackX, stackY, 17, 17); - String amountStr = String.format("x%,d", fluid.getStackSize()); - drawText(amountStr, stackX + 20, stackY + 5, 1, 0xFFFFFFFF); - } - if (isMouseOverElement(mouseX, mouseY)) { - drawSelectionOverlay(stackX, stackY, 16, 16); - } - } - - @Override - public void drawInForeground(int mouseX, int mouseY) { - if (isMouseOverElement(mouseX, mouseY)) { - IAEFluidStack fluid = this.gridWidget.getAt(this.index); - if (fluid != null) { - List hoverStringList = new ArrayList<>(); - hoverStringList.add(fluid.getFluidStack().getLocalizedName()); - hoverStringList.add(String.format("%,d L", fluid.getStackSize())); - List formula = FluidTooltipUtil.getFluidTooltip(fluid.getFluidStack()); - if (formula != null) { - for (String s : formula) { - if (s.isEmpty()) continue; - hoverStringList.add(s); - } - } - drawHoveringText(ItemStack.EMPTY, hoverStringList, -1, mouseX, mouseY); - } - } - } -} diff --git a/src/main/java/gregtech/common/gui/widget/appeng/slot/AEItemConfigSlot.java b/src/main/java/gregtech/common/gui/widget/appeng/slot/AEItemConfigSlot.java deleted file mode 100644 index aa66bdf9412..00000000000 --- a/src/main/java/gregtech/common/gui/widget/appeng/slot/AEItemConfigSlot.java +++ /dev/null @@ -1,256 +0,0 @@ -package gregtech.common.gui.widget.appeng.slot; - -import gregtech.api.gui.GuiTextures; -import gregtech.api.gui.IRenderContext; -import gregtech.api.util.Position; -import gregtech.api.util.Size; -import gregtech.api.util.TextFormattingUtil; -import gregtech.client.utils.RenderUtil; -import gregtech.common.gui.widget.appeng.AEItemConfigWidget; -import gregtech.common.metatileentities.multi.multiblockpart.appeng.slot.IConfigurableSlot; -import gregtech.common.metatileentities.multi.multiblockpart.appeng.stack.WrappedItemStack; - -import net.minecraft.client.resources.I18n; -import net.minecraft.item.ItemStack; -import net.minecraft.network.PacketBuffer; -import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; - -import appeng.api.storage.data.IAEItemStack; -import com.google.common.collect.Lists; -import mezz.jei.api.gui.IGhostIngredientHandler; -import org.jetbrains.annotations.NotNull; - -import java.awt.*; -import java.io.IOException; -import java.util.Collections; -import java.util.List; - -public class AEItemConfigSlot extends AEConfigSlot { - - public AEItemConfigSlot(int x, int y, AEItemConfigWidget widget, int index) { - super(new Position(x, y), new Size(18 * 6, 18), widget, index); - } - - @Override - public AEItemConfigWidget getParentWidget() { - return (AEItemConfigWidget) super.getParentWidget(); - } - - @Override - public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { - super.drawInBackground(mouseX, mouseY, partialTicks, context); - AEItemConfigWidget pw = getParentWidget(); - Position position = getPosition(); - IConfigurableSlot slot = pw.getDisplay(this.index); - IAEItemStack config = slot.getConfig(); - IAEItemStack stock = slot.getStock(); - drawSlots(pw.isAutoPull(), position.x, position.y); - if (this.select) { - GuiTextures.SELECT_BOX.draw(position.x, position.y, 18, 18); - } - int stackX = position.x + 1; - int stackY = position.y + 1; - if (config != null) { - ItemStack stack = config.createItemStack(); - stack.setCount(1); - RenderUtil.drawItemStack(stack, stackX, stackY); - - // Only draw the config amount if not stocking, as its meaningless when stocking - if (!pw.isStocking()) { - String amountStr = TextFormattingUtil.formatLongToCompactString(config.getStackSize(), 4); - drawStringFixedCorner(amountStr, stackX + 17, stackY + 17, 16777215, true, 0.5f); - } - } - if (stock != null) { - ItemStack stack = stock.createItemStack(); - stack.setCount(1); - RenderUtil.drawItemStack(stack, stackX + DISPLAY_X_OFFSET, stackY); - String amountStr = TextFormattingUtil.formatLongToCompactString(stock.getStackSize(), 4); - drawStringFixedCorner(amountStr, stackX + DISPLAY_X_OFFSET + 17, stackY + 17, 16777215, true, 0.5f); - } - if (mouseOverConfig(mouseX, mouseY)) { - drawSelectionOverlay(stackX, stackY, 16, 16); - } else if (mouseOverStock(mouseX, mouseY)) { - drawSelectionOverlay(stackX + DISPLAY_X_OFFSET, stackY, 16, 16); - } - } - - private void drawSlots(boolean autoPull, int x, int y) { - if (autoPull) { - GuiTextures.SLOT_DARK.draw(x, y, 18, 18); - GuiTextures.CONFIG_ARROW.draw(x, y, 18, 18); - } else { - GuiTextures.SLOT.draw(x, y, 18, 18); - GuiTextures.CONFIG_ARROW_DARK.draw(x, y, 18, 18); - } - GuiTextures.SLOT_DARK.draw(x + DISPLAY_X_OFFSET, y, 18, 18); - } - - @Override - public void drawInForeground(int mouseX, int mouseY) { - super.drawInForeground(mouseX, mouseY); - IAEItemStack item = null; - IConfigurableSlot slot = this.getParentWidget().getDisplay(this.index); - if (mouseOverConfig(mouseX, mouseY)) { - item = slot.getConfig(); - } else if (mouseOverStock(mouseX, mouseY)) { - item = slot.getStock(); - } - if (item != null) { - drawHoveringText(item.createItemStack(), getItemToolTip(item.createItemStack()), -1, mouseX, mouseY); - } - } - - @Override - protected void addHoverText(List hoverText) { - if (getParentWidget().isAutoPull()) { - hoverText.add(I18n.format("gregtech.gui.config_slot")); - hoverText.add(I18n.format("gregtech.gui.config_slot.auto_pull_managed")); - } else { - super.addHoverText(hoverText); - } - } - - @Override - public boolean mouseClicked(int mouseX, int mouseY, int button) { - AEItemConfigWidget pw = getParentWidget(); - // don't allow manual interaction with config slots when auto pull is enabled - if (pw.isAutoPull()) { - return false; - } - - if (mouseOverConfig(mouseX, mouseY)) { - if (button == 1) { - // Right click to clear - writeClientAction(REMOVE_ID, buf -> {}); - - if (!pw.isStocking()) { - pw.disableAmount(); - } - } else if (button == 0) { - // Left click to set/select - ItemStack item = this.gui.entityPlayer.inventory.getItemStack(); - - if (!item.isEmpty()) { - writeClientAction(UPDATE_ID, buf -> buf.writeItemStack(item)); - return true; - } - - if (!pw.isStocking()) { - pw.enableAmount(this.index); - this.select = true; - } - } - return true; - } - return false; - } - - @Override - public void handleClientAction(int id, PacketBuffer buffer) { - super.handleClientAction(id, buffer); - IConfigurableSlot slot = this.parentWidget.getConfig(this.index); - if (id == REMOVE_ID) { - slot.setConfig(null); - this.parentWidget.disableAmount(); - writeUpdateInfo(REMOVE_ID, buf -> {}); - } - if (id == UPDATE_ID) { - try { - ItemStack item = buffer.readItemStack(); - if (!isItemValidForSlot(item)) return; - slot.setConfig(WrappedItemStack.fromItemStack(item)); - this.parentWidget.enableAmount(this.index); - if (!item.isEmpty()) { - writeUpdateInfo(UPDATE_ID, buf -> buf.writeItemStack(item)); - } - } catch (IOException ignored) {} - } - if (id == AMOUNT_CHANGE_ID) { - if (slot.getConfig() != null) { - int amt = buffer.readInt(); - slot.getConfig().setStackSize(amt); - writeUpdateInfo(AMOUNT_CHANGE_ID, buf -> buf.writeInt(amt)); - } - } - } - - @Override - public void readUpdateInfo(int id, PacketBuffer buffer) { - super.readUpdateInfo(id, buffer); - IConfigurableSlot slot = this.parentWidget.getDisplay(this.index); - if (id == REMOVE_ID) { - slot.setConfig(null); - } - if (id == UPDATE_ID) { - try { - ItemStack item = buffer.readItemStack(); - slot.setConfig(WrappedItemStack.fromItemStack(item)); - } catch (IOException ignored) {} - } - if (id == AMOUNT_CHANGE_ID) { - if (slot.getConfig() != null) { - int amt = buffer.readInt(); - slot.getConfig().setStackSize(amt); - } - } - } - - // Method for server-side validation of an attempted new configured item - private boolean isItemValidForSlot(ItemStack stack) { - if (stack == null || stack.isEmpty()) return true; - AEItemConfigWidget pw = getParentWidget(); - if (!pw.isStocking()) return true; - return !pw.hasStackInConfig(stack); - } - - @Override - public List> getPhantomTargets(Object ingredient) { - if (!(ingredient instanceof ItemStack)) { - return Collections.emptyList(); - } - Rectangle rectangle = toRectangleBox(); - rectangle.width /= 6; - return Lists.newArrayList(new IGhostIngredientHandler.Target<>() { - - @NotNull - @Override - public Rectangle getArea() { - return rectangle; - } - - @Override - public void accept(@NotNull Object ingredient) { - if (ingredient instanceof ItemStack) { - writeClientAction(UPDATE_ID, buf -> buf.writeItemStack((ItemStack) ingredient)); - } - } - }); - } - - @SideOnly(Side.CLIENT) - public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { - // Only allow the amount scrolling if not stocking, as amount is useless for stocking - if (parentWidget.isStocking()) return false; - IConfigurableSlot slot = this.parentWidget.getDisplay(this.index); - Rectangle rectangle = toRectangleBox(); - rectangle.width /= 6; - if (slot.getConfig() == null || wheelDelta == 0 || !rectangle.contains(mouseX, mouseY)) { - return false; - } - ItemStack stack = slot.getConfig().createItemStack(); - long amt; - if (isCtrlDown()) { - amt = wheelDelta > 0 ? stack.getCount() * 2L : stack.getCount() / 2L; - } else { - amt = wheelDelta > 0 ? stack.getCount() + 1L : stack.getCount() - 1L; - } - if (amt > 0 && amt < Integer.MAX_VALUE + 1L) { - int finalAmt = (int) amt; - writeClientAction(AMOUNT_CHANGE_ID, buf -> buf.writeInt(finalAmt)); - return true; - } - return false; - } -} diff --git a/src/main/java/gregtech/common/gui/widget/appeng/slot/AEItemDisplayWidget.java b/src/main/java/gregtech/common/gui/widget/appeng/slot/AEItemDisplayWidget.java index 8ccc48590a4..8b137891791 100644 --- a/src/main/java/gregtech/common/gui/widget/appeng/slot/AEItemDisplayWidget.java +++ b/src/main/java/gregtech/common/gui/widget/appeng/slot/AEItemDisplayWidget.java @@ -1,61 +1 @@ -package gregtech.common.gui.widget.appeng.slot; -import gregtech.api.gui.GuiTextures; -import gregtech.api.gui.IRenderContext; -import gregtech.api.gui.Widget; -import gregtech.api.util.Position; -import gregtech.api.util.Size; -import gregtech.client.utils.RenderUtil; -import gregtech.common.gui.widget.appeng.AEListGridWidget; - -import net.minecraft.item.ItemStack; - -import appeng.api.storage.data.IAEItemStack; - -/** - * @Author GlodBlock - * @Description Display a certain {@link IAEItemStack} element. - * @Date 2023/4/19-21:23 - */ -public class AEItemDisplayWidget extends Widget { - - private final AEListGridWidget gridWidget; - private final int index; - - public AEItemDisplayWidget(int x, int y, AEListGridWidget gridWidget, int index) { - super(new Position(x, y), new Size(18, 18)); - this.gridWidget = gridWidget; - this.index = index; - } - - @Override - public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { - super.drawInBackground(mouseX, mouseY, partialTicks, context); - Position position = getPosition(); - IAEItemStack item = this.gridWidget.getAt(this.index); - GuiTextures.SLOT.draw(position.x, position.y, 18, 18); - GuiTextures.NUMBER_BACKGROUND.draw(position.x + 18, position.y, 140, 18); - int stackX = position.x + 1; - int stackY = position.y + 1; - if (item != null) { - ItemStack realStack = item.createItemStack(); - realStack.setCount(1); - RenderUtil.drawItemStack(realStack, stackX, stackY); - String amountStr = String.format("x%,d", item.getStackSize()); - drawText(amountStr, stackX + 20, stackY + 5, 1, 0xFFFFFFFF); - } - if (isMouseOverElement(mouseX, mouseY)) { - drawSelectionOverlay(stackX, stackY, 16, 16); - } - } - - @Override - public void drawInForeground(int mouseX, int mouseY) { - if (isMouseOverElement(mouseX, mouseY)) { - IAEItemStack item = this.gridWidget.getAt(this.index); - if (item != null) { - drawHoveringText(item.createItemStack(), getItemToolTip(item.createItemStack()), -1, mouseX, mouseY); - } - } - } -} diff --git a/src/main/java/gregtech/common/gui/widget/appeng/slot/AmountSetSlot.java b/src/main/java/gregtech/common/gui/widget/appeng/slot/AmountSetSlot.java deleted file mode 100644 index 35063d5638b..00000000000 --- a/src/main/java/gregtech/common/gui/widget/appeng/slot/AmountSetSlot.java +++ /dev/null @@ -1,86 +0,0 @@ -package gregtech.common.gui.widget.appeng.slot; - -import gregtech.api.gui.GuiTextures; -import gregtech.api.gui.IRenderContext; -import gregtech.api.gui.Widget; -import gregtech.api.gui.widgets.TextFieldWidget2; -import gregtech.api.util.Position; -import gregtech.common.gui.widget.appeng.AEConfigWidget; -import gregtech.common.metatileentities.multi.multiblockpart.appeng.slot.IConfigurableSlot; - -import net.minecraft.network.PacketBuffer; - -import appeng.api.storage.data.IAEStack; - -/** - * @Author GlodBlock - * @Description The amount set widget for config slot - * @Date 2023/4/21-21:20 - */ -public class AmountSetSlot> extends Widget { - - private int index = -1; - private final TextFieldWidget2 amountText; - private final AEConfigWidget parentWidget; - - public AmountSetSlot(int x, int y, AEConfigWidget widget) { - super(x, y, 80, 30); - this.parentWidget = widget; - this.amountText = new TextFieldWidget2(x + 3, y + 14, 60, 15, this::getAmountStr, this::setNewAmount) - .setNumbersOnly(0, Integer.MAX_VALUE) - .setMaxLength(10); - } - - public void setSlotIndex(int slotIndex) { - this.index = slotIndex; - writeClientAction(0, buf -> buf.writeVarInt(this.index)); - } - - public TextFieldWidget2 getText() { - return this.amountText; - } - - public String getAmountStr() { - if (this.index < 0) { - return "0"; - } - IConfigurableSlot slot = this.parentWidget.getConfig(this.index); - if (slot.getConfig() != null) { - return String.valueOf(slot.getConfig().getStackSize()); - } - return "0"; - } - - public void setNewAmount(String amount) { - try { - long newAmount = Long.parseLong(amount); - writeClientAction(1, buf -> buf.writeVarLong(newAmount)); - } catch (NumberFormatException ignore) {} - } - - @Override - public void handleClientAction(int id, PacketBuffer buffer) { - super.handleClientAction(id, buffer); - if (id == 0) { - this.index = buffer.readVarInt(); - } else if (id == 1) { - if (this.index < 0) { - return; - } - IConfigurableSlot slot = this.parentWidget.getConfig(this.index); - long newAmt = buffer.readVarLong(); - if (newAmt > 0 && slot.getConfig() != null) { - slot.getConfig().setStackSize(newAmt); - } - } - } - - @Override - public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { - super.drawInBackground(mouseX, mouseY, partialTicks, context); - Position position = getPosition(); - GuiTextures.BACKGROUND.draw(position.x, position.y, 80, 30); - drawStringSized("Amount", position.x + 3, position.y + 3, 0x404040, false, 1f, false); - GuiTextures.DISPLAY.draw(position.x + 3, position.y + 11, 65, 14); - } -} diff --git a/src/main/java/gregtech/common/inventory/appeng/SerializableFluidList.java b/src/main/java/gregtech/common/inventory/appeng/SerializableFluidList.java deleted file mode 100644 index 2e6ac5ca429..00000000000 --- a/src/main/java/gregtech/common/inventory/appeng/SerializableFluidList.java +++ /dev/null @@ -1,146 +0,0 @@ -package gregtech.common.inventory.appeng; - -import net.minecraft.nbt.NBTBase; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.nbt.NBTTagList; -import net.minecraftforge.common.util.INBTSerializable; -import net.minecraftforge.fluids.Fluid; -import net.minecraftforge.fluids.FluidStack; - -import appeng.api.config.FuzzyMode; -import appeng.api.storage.data.IAEFluidStack; -import appeng.api.storage.data.IItemList; -import appeng.fluids.util.AEFluidStack; -import appeng.fluids.util.MeaningfulFluidIterator; -import it.unimi.dsi.fastutil.objects.Reference2ObjectMap; -import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap; -import org.jetbrains.annotations.NotNull; - -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; - -/** - * @Author GlodBlock - * @Description A serializable {@link IItemList} from AE2, specially improved for fluid. - * @Date 2023/4/18-23:52 - */ -public class SerializableFluidList implements IItemList, INBTSerializable { - - private final Reference2ObjectMap records = new Reference2ObjectOpenHashMap<>(); - - public SerializableFluidList() {} - - @Override - public void add(IAEFluidStack fluid) { - if (fluid != null) { - this.getOrCreateRecord(fluid).add(fluid); - } - } - - @Override - public IAEFluidStack findPrecise(IAEFluidStack fluid) { - if (fluid == null) { - return null; - } else { - return this.records.get(fluid.getFluid()); - } - } - - @Override - public Collection findFuzzy(IAEFluidStack filter, FuzzyMode fuzzy) { - IAEFluidStack stack = findPrecise(filter); - return stack != null ? Collections.singleton(stack) : Collections.emptyList(); - } - - @Override - public boolean isEmpty() { - return !this.iterator().hasNext(); - } - - private IAEFluidStack getOrCreateRecord(@NotNull IAEFluidStack fluid) { - return this.records.computeIfAbsent(fluid.getFluid(), - key -> AEFluidStack.fromFluidStack(new FluidStack(key, 0))); - } - - private IAEFluidStack getRecord(@NotNull IAEFluidStack fluid) { - return this.records.get(fluid.getFluid()); - } - - @Override - public void addStorage(IAEFluidStack fluid) { - if (fluid != null) { - this.getOrCreateRecord(fluid).incStackSize(fluid.getStackSize()); - } - } - - @Override - public void addCrafting(IAEFluidStack fluid) { - if (fluid != null) { - IAEFluidStack record = this.getRecord(fluid); - if (record != null) { - record.setCraftable(true); - } - } - } - - @Override - public void addRequestable(IAEFluidStack fluid) { - if (fluid != null) { - IAEFluidStack record = this.getRecord(fluid); - if (record != null) { - record.setCountRequestable(record.getCountRequestable() + fluid.getCountRequestable()); - } - } - } - - @Override - public IAEFluidStack getFirstItem() { - for (final IAEFluidStack fluid : this) { - return fluid; - } - return null; - } - - @Override - public int size() { - return this.records.size(); - } - - @Override - public Iterator iterator() { - return new MeaningfulFluidIterator<>(this.records.values().iterator()); - } - - @Override - public void resetStatus() { - for (final IAEFluidStack i : this) { - i.reset(); - } - } - - @Override - public NBTTagList serializeNBT() { - NBTTagList list = new NBTTagList(); - for (IAEFluidStack fluid : this) { - if (fluid != null) { - NBTTagCompound tag = new NBTTagCompound(); - fluid.writeToNBT(tag); - list.appendTag(tag); - } - } - return list; - } - - @Override - public void deserializeNBT(NBTTagList list) { - for (NBTBase tag : list) { - if (tag instanceof NBTTagCompound) { - IAEFluidStack fluid = AEFluidStack.fromNBT((NBTTagCompound) tag); - if (fluid != null) { - this.records.put(fluid.getFluid(), fluid); - } - } - } - } -} diff --git a/src/main/java/gregtech/common/inventory/appeng/SerializableItemList.java b/src/main/java/gregtech/common/inventory/appeng/SerializableItemList.java deleted file mode 100644 index ad09fa2e5b6..00000000000 --- a/src/main/java/gregtech/common/inventory/appeng/SerializableItemList.java +++ /dev/null @@ -1,107 +0,0 @@ -package gregtech.common.inventory.appeng; - -import net.minecraft.nbt.NBTBase; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.nbt.NBTTagList; -import net.minecraftforge.common.util.INBTSerializable; - -import appeng.api.config.FuzzyMode; -import appeng.api.storage.data.IAEItemStack; -import appeng.api.storage.data.IItemList; -import appeng.util.item.AEItemStack; -import appeng.util.item.ItemList; - -import java.util.Collection; -import java.util.Iterator; - -/** - * @Author GlodBlock - * @Description A serializable {@link IItemList} from AE2 - * @Date 2023/4/18-23:52 - */ -public class SerializableItemList implements IItemList, INBTSerializable { - - private final ItemList parent = new ItemList(); - - public SerializableItemList() {} - - @Override - public void addStorage(IAEItemStack stack) { - this.parent.addStorage(stack); - } - - @Override - public void addCrafting(IAEItemStack stack) { - this.parent.addStorage(stack); - } - - @Override - public void addRequestable(IAEItemStack stack) { - this.parent.addRequestable(stack); - } - - @Override - public IAEItemStack getFirstItem() { - return this.parent.getFirstItem(); - } - - @Override - public int size() { - return this.parent.size(); - } - - @Override - public Iterator iterator() { - return this.parent.iterator(); - } - - @Override - public void resetStatus() { - this.parent.resetStatus(); - } - - @Override - public void add(IAEItemStack stack) { - this.parent.add(stack); - } - - @Override - public IAEItemStack findPrecise(IAEItemStack stack) { - return this.parent.findPrecise(stack); - } - - @Override - public Collection findFuzzy(IAEItemStack stack, FuzzyMode fuzzyMode) { - return this.parent.findFuzzy(stack, fuzzyMode); - } - - @Override - public boolean isEmpty() { - return this.parent.isEmpty(); - } - - @Override - public NBTTagList serializeNBT() { - NBTTagList list = new NBTTagList(); - for (IAEItemStack item : this) { - if (item != null) { - NBTTagCompound tag = new NBTTagCompound(); - item.writeToNBT(tag); - list.appendTag(tag); - } - } - return list; - } - - @Override - public void deserializeNBT(NBTTagList list) { - for (NBTBase tag : list) { - if (tag instanceof NBTTagCompound) { - IAEItemStack item = AEItemStack.fromNBT((NBTTagCompound) tag); - if (item != null) { - this.parent.add(item); - } - } - } - } -} diff --git a/src/main/java/gregtech/common/metatileentities/MetaTileEntities.java b/src/main/java/gregtech/common/metatileentities/MetaTileEntities.java index 2da6fd0d304..4e5d7e330e2 100644 --- a/src/main/java/gregtech/common/metatileentities/MetaTileEntities.java +++ b/src/main/java/gregtech/common/metatileentities/MetaTileEntities.java @@ -111,7 +111,7 @@ import gregtech.common.metatileentities.storage.MetaTileEntityQuantumProxy; import gregtech.common.metatileentities.storage.MetaTileEntityQuantumStorageController; import gregtech.common.metatileentities.storage.MetaTileEntityQuantumTank; -import gregtech.common.metatileentities.storage.MetaTileEntityWorkbench; +import gregtech.common.metatileentities.workbench.MetaTileEntityWorkbench; import gregtech.common.pipelike.fluidpipe.longdistance.MetaTileEntityLDFluidEndpoint; import gregtech.common.pipelike.itempipe.longdistance.MetaTileEntityLDItemEndpoint; import gregtech.integration.jei.multiblock.MultiblockInfoCategory; diff --git a/src/main/java/gregtech/common/metatileentities/MetaTileEntityRegistration.java b/src/main/java/gregtech/common/metatileentities/MetaTileEntityRegistration.java index 55cd52e5cd4..1fe3b082d3d 100644 --- a/src/main/java/gregtech/common/metatileentities/MetaTileEntityRegistration.java +++ b/src/main/java/gregtech/common/metatileentities/MetaTileEntityRegistration.java @@ -120,7 +120,7 @@ import gregtech.common.metatileentities.storage.MetaTileEntityQuantumProxy; import gregtech.common.metatileentities.storage.MetaTileEntityQuantumStorageController; import gregtech.common.metatileentities.storage.MetaTileEntityQuantumTank; -import gregtech.common.metatileentities.storage.MetaTileEntityWorkbench; +import gregtech.common.metatileentities.workbench.MetaTileEntityWorkbench; import gregtech.common.pipelike.fluidpipe.longdistance.MetaTileEntityLDFluidEndpoint; import gregtech.common.pipelike.itempipe.longdistance.MetaTileEntityLDItemEndpoint; @@ -1056,13 +1056,13 @@ private static void multiblockParts() { // ME Hatches, IDs 11525-11539 if (Mods.AppliedEnergistics2.isModLoaded()) { MetaTileEntities.ITEM_IMPORT_BUS_ME = MetaTileEntities.registerMetaTileEntity(11525, - new MetaTileEntityMEInputBus(gregtechId("me_import_item_bus"))); + new MetaTileEntityMEInputBus(gregtechId("me_import_item_bus"), GTValues.EV)); MetaTileEntities.FLUID_IMPORT_HATCH_ME = MetaTileEntities.registerMetaTileEntity(11526, - new MetaTileEntityMEInputHatch(gregtechId("me_import_fluid_hatch"))); + new MetaTileEntityMEInputHatch(gregtechId("me_import_fluid_hatch"), GTValues.EV)); MetaTileEntities.STOCKING_BUS_ME = MetaTileEntities.registerMetaTileEntity(11527, - new MetaTileEntityMEStockingBus(gregtechId("me_stocking_item_bus"))); + new MetaTileEntityMEStockingBus(gregtechId("me_stocking_item_bus"), GTValues.IV)); MetaTileEntities.STOCKING_HATCH_ME = MetaTileEntities.registerMetaTileEntity(11528, - new MetaTileEntityMEStockingHatch(gregtechId("me_stocking_fluid_hatch"))); + new MetaTileEntityMEStockingHatch(gregtechId("me_stocking_fluid_hatch"), GTValues.IV)); // slots left for CRIB and CRIBuffer in the future for nicer sorting order MetaTileEntities.ITEM_EXPORT_BUS_ME = MetaTileEntities.registerMetaTileEntity(11532, new MetaTileEntityMEOutputBus(gregtechId("me_export_item_bus"))); diff --git a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/MetaTileEntityFluidHatch.java b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/MetaTileEntityFluidHatch.java index a1e6ab43a3c..62339874ce7 100644 --- a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/MetaTileEntityFluidHatch.java +++ b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/MetaTileEntityFluidHatch.java @@ -91,7 +91,6 @@ protected void initializeInventory() { super.initializeInventory(); if (this.hasGhostCircuitInventory()) { this.circuitInventory = new GhostCircuitItemStackHandler(this); - this.circuitInventory.addNotifiableMetaTileEntity(this); } } diff --git a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/MetaTileEntityItemBus.java b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/MetaTileEntityItemBus.java index 127977cb343..39d4840cab9 100644 --- a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/MetaTileEntityItemBus.java +++ b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/MetaTileEntityItemBus.java @@ -85,7 +85,6 @@ protected void initializeInventory() { super.initializeInventory(); if (this.hasGhostCircuitInventory()) { this.circuitInventory = new GhostCircuitItemStackHandler(this); - this.circuitInventory.addNotifiableMetaTileEntity(this); this.actualImportItems = new ItemHandlerList(Arrays.asList(super.getImportItems(), this.circuitInventory)); } else { this.actualImportItems = null; diff --git a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/MetaTileEntityMultiblockNotifiablePart.java b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/MetaTileEntityMultiblockNotifiablePart.java index 7efd88c5471..7f7b3831724 100644 --- a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/MetaTileEntityMultiblockNotifiablePart.java +++ b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/MetaTileEntityMultiblockNotifiablePart.java @@ -9,6 +9,9 @@ import net.minecraft.util.ResourceLocation; import net.minecraftforge.fluids.IFluidTank; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + import java.util.ArrayList; import java.util.List; @@ -21,7 +24,7 @@ public MetaTileEntityMultiblockNotifiablePart(ResourceLocation metaTileEntityId, this.isExportHatch = isExportHatch; } - private List getItemHandlers() { + private @NotNull List getItemHandlers() { List notifiables = new ArrayList<>(); var mteHandler = isExportHatch ? getExportItems() : getImportItems(); if (mteHandler instanceof INotifiableHandler notifiable) { @@ -38,14 +41,14 @@ private List getItemHandlers() { return notifiables; } - private FluidTankList getFluidHandlers() { - FluidTankList handler = null; - if (isExportHatch && getExportFluids().getFluidTanks().size() > 0) { - handler = getExportFluids(); - } else if (!isExportHatch && getImportFluids().getFluidTanks().size() > 0) { - handler = getImportFluids(); + private @Nullable FluidTankList getFluidHandlers() { + if (isExportHatch) { + FluidTankList exports = getExportFluids(); + return exports.getFluidTanks().isEmpty() ? null : exports; + } else { + FluidTankList imports = getImportFluids(); + return imports.getFluidTanks().isEmpty() ? null : imports; } - return handler; } private List getPartHandlers() { @@ -57,19 +60,18 @@ private List getPartHandlers() { } } - if (this.fluidInventory.getTankProperties().length > 0) { - FluidTankList fluidTankList = getFluidHandlers(); - if (fluidTankList != null) { - for (IFluidTank fluidTank : fluidTankList) { - if (fluidTank instanceof IMultipleTankHandler.ITankEntry entry) { - fluidTank = entry.getDelegate(); - } - if (fluidTank instanceof INotifiableHandler) { - handlerList.add((INotifiableHandler) fluidTank); - } + FluidTankList fluidTankList = getFluidHandlers(); + if (fluidTankList != null) { + for (IFluidTank fluidTank : fluidTankList) { + if (fluidTank instanceof IMultipleTankHandler.ITankEntry entry) { + fluidTank = entry.getDelegate(); + } + if (fluidTank instanceof INotifiableHandler iNotifiableHandler) { + handlerList.add(iNotifiableHandler); } } } + return handlerList; } diff --git a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/MetaTileEntityReservoirHatch.java b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/MetaTileEntityReservoirHatch.java index 00241591cf8..95d1d0dea8b 100644 --- a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/MetaTileEntityReservoirHatch.java +++ b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/MetaTileEntityReservoirHatch.java @@ -79,7 +79,6 @@ public MetaTileEntity createMetaTileEntity(IGregTechTileEntity tileEntity) { protected void initializeInventory() { super.initializeInventory(); this.circuitInventory = new GhostCircuitItemStackHandler(this); - this.circuitInventory.addNotifiableMetaTileEntity(this); } @Override diff --git a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityAEHostableChannelPart.java b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityAEHostableChannelPart.java new file mode 100644 index 00000000000..912c4b9765a --- /dev/null +++ b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityAEHostableChannelPart.java @@ -0,0 +1,92 @@ +package gregtech.common.metatileentities.multi.multiblockpart.appeng; + +import gregtech.common.ConfigHolder; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.ResourceLocation; + +import appeng.api.AEApi; +import appeng.api.storage.IMEMonitor; +import appeng.api.storage.IStorageChannel; +import appeng.api.storage.data.IAEStack; +import appeng.me.GridAccessException; +import appeng.me.helpers.AENetworkProxy; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public abstract class MetaTileEntityAEHostableChannelPart> extends MetaTileEntityAEHostablePart { + + public static final String REFRESH_RATE_TAG = "RefreshRate"; + + private final Class> storageChannel; + protected int refreshRate; + + public MetaTileEntityAEHostableChannelPart(ResourceLocation metaTileEntityId, int tier, boolean isExportHatch, + Class> storageChannel) { + super(metaTileEntityId, tier, isExportHatch); + this.storageChannel = storageChannel; + this.refreshRate = ConfigHolder.compat.ae2.updateIntervals; + } + + /** + * ME hatch will try to put its buffer back to me system when removal. + * So there is no need to drop them. + */ + @Override + public void clearMachineInventory(@NotNull List<@NotNull ItemStack> itemBuffer) {} + + protected boolean shouldOperateOnME() { + return getMEUpdateTick() % refreshRate == 0; + } + + @NotNull + protected IStorageChannel getStorageChannel() { + return AEApi.instance().storage().getStorageChannel(storageChannel); + } + + @Nullable + protected IMEMonitor getMonitor() { + AENetworkProxy proxy = getProxy(); + if (proxy == null) return null; + + IStorageChannel channel = getStorageChannel(); + + try { + return proxy.getStorage().getInventory(channel); + } catch (GridAccessException ignored) { + return null; + } + } + + public int getRefreshRate() { + return this.refreshRate; + } + + protected void setRefreshRate(int newRefreshRate) { + this.refreshRate = newRefreshRate; + if (!getWorld().isRemote) { + markDirty(); + } + } + + @Override + public NBTTagCompound writeToNBT(NBTTagCompound data) { + super.writeToNBT(data); + + data.setInteger(REFRESH_RATE_TAG, this.refreshRate); + + return data; + } + + @Override + public void readFromNBT(NBTTagCompound data) { + super.readFromNBT(data); + + if (data.hasKey(REFRESH_RATE_TAG)) { + this.refreshRate = data.getInteger(REFRESH_RATE_TAG); + } + } +} diff --git a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityAEHostablePart.java b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityAEHostablePart.java index 5fec49de898..a20e0cb8903 100644 --- a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityAEHostablePart.java +++ b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityAEHostablePart.java @@ -1,11 +1,10 @@ package gregtech.common.metatileentities.multi.multiblockpart.appeng; -import gregtech.api.capability.IControllable; +import gregtech.api.metatileentity.IAEStatusProvider; import gregtech.common.ConfigHolder; import gregtech.common.metatileentities.multi.multiblockpart.MetaTileEntityMultiblockNotifiablePart; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.PacketBuffer; import net.minecraft.util.EnumFacing; @@ -13,16 +12,11 @@ import net.minecraft.util.ResourceLocation; import net.minecraft.util.text.TextComponentTranslation; -import appeng.api.AEApi; import appeng.api.networking.GridFlags; import appeng.api.networking.security.IActionHost; import appeng.api.networking.security.IActionSource; -import appeng.api.storage.IMEMonitor; -import appeng.api.storage.IStorageChannel; -import appeng.api.storage.data.IAEStack; import appeng.api.util.AECableType; import appeng.api.util.AEPartLocation; -import appeng.me.GridAccessException; import appeng.me.helpers.AENetworkProxy; import appeng.me.helpers.BaseActionSource; import appeng.me.helpers.IGridProxyable; @@ -33,26 +27,20 @@ import java.io.IOException; import java.util.EnumSet; -import java.util.List; import static gregtech.api.capability.GregtechDataCodes.UPDATE_ONLINE_STATUS; -public abstract class MetaTileEntityAEHostablePart> extends MetaTileEntityMultiblockNotifiablePart - implements IControllable { +public abstract class MetaTileEntityAEHostablePart extends MetaTileEntityMultiblockNotifiablePart implements + IAEStatusProvider { - private final Class> storageChannel; private AENetworkProxy aeProxy; - private int meUpdateTick; + private int meUpdateTick = 0; protected boolean isOnline; - private boolean allowExtraConnections; + protected boolean allowsExtraConnections = false; protected boolean meStatusChanged = false; - public MetaTileEntityAEHostablePart(ResourceLocation metaTileEntityId, int tier, boolean isExportHatch, - Class> storageChannel) { + public MetaTileEntityAEHostablePart(ResourceLocation metaTileEntityId, int tier, boolean isExportHatch) { super(metaTileEntityId, tier, isExportHatch); - this.meUpdateTick = 0; - this.storageChannel = storageChannel; - this.allowExtraConnections = false; } @Override @@ -63,32 +51,41 @@ public void update() { } } - /** - * ME hatch will try to put its buffer back to me system when removal. - * So there is no need to drop them. - */ + public boolean isOnline() { + return isOnline; + } + + public int getMEUpdateTick() { + return meUpdateTick; + } + @Override - public void clearMachineInventory(@NotNull List<@NotNull ItemStack> itemBuffer) {} + public boolean allowsExtraConnections() { + return allowsExtraConnections; + } @Override public void writeInitialSyncData(PacketBuffer buf) { super.writeInitialSyncData(buf); - if (this.aeProxy != null) { + + if (aeProxy != null) { buf.writeBoolean(true); NBTTagCompound proxy = new NBTTagCompound(); - this.aeProxy.writeToNBT(proxy); + aeProxy.writeToNBT(proxy); buf.writeCompoundTag(proxy); } else { buf.writeBoolean(false); } - buf.writeInt(this.meUpdateTick); - buf.writeBoolean(this.isOnline); - buf.writeBoolean(this.allowExtraConnections); + + buf.writeInt(meUpdateTick); + buf.writeBoolean(isOnline); + buf.writeBoolean(allowsExtraConnections); } @Override public void receiveInitialSyncData(PacketBuffer buf) { super.receiveInitialSyncData(buf); + if (buf.readBoolean()) { NBTTagCompound nbtTagCompound; try { @@ -97,13 +94,14 @@ public void receiveInitialSyncData(PacketBuffer buf) { nbtTagCompound = null; } - if (this.aeProxy != null && nbtTagCompound != null) { - this.aeProxy.readFromNBT(nbtTagCompound); + if (aeProxy != null && nbtTagCompound != null) { + aeProxy.readFromNBT(nbtTagCompound); } } - this.meUpdateTick = buf.readInt(); - this.isOnline = buf.readBoolean(); - this.allowExtraConnections = buf.readBoolean(); + + meUpdateTick = buf.readInt(); + isOnline = buf.readBoolean(); + allowsExtraConnections = buf.readBoolean(); } @Override @@ -121,67 +119,47 @@ public void receiveCustomData(int dataId, PacketBuffer buf) { @NotNull @Override public AECableType getCableConnectionType(@NotNull AEPartLocation part) { - if (part.getFacing() != this.frontFacing && !this.allowExtraConnections) { + if (part.getFacing() != frontFacing && !allowsExtraConnections) { return AECableType.NONE; } return AECableType.SMART; } - @Nullable - @Override - public AENetworkProxy getProxy() { - if (this.aeProxy == null) { - return this.aeProxy = this.createProxy(); - } - if (!this.aeProxy.isReady() && this.getWorld() != null) { - this.aeProxy.onReady(); - } - return this.aeProxy; + public EnumSet getConnectableSides() { + return allowsExtraConnections ? EnumSet.allOf(EnumFacing.class) : EnumSet.of(getFrontFacing()); } - @Override - public void setFrontFacing(EnumFacing frontFacing) { - super.setFrontFacing(frontFacing); - updateConnectableSides(); + public void updateConnectableSides() { + if (aeProxy != null) { + aeProxy.setValidSides(getConnectableSides()); + } } @Override - public void gridChanged() {} + public boolean onWireCutterClick(EntityPlayer playerIn, EnumHand hand, EnumFacing facing, + CuboidRayTraceResult hitResult) { + allowsExtraConnections = !allowsExtraConnections; + updateConnectableSides(); - /** - * Get the me network connection status, updating it if on serverside. - * - * @return the updated status. - */ - public boolean updateMEStatus() { if (!getWorld().isRemote) { - boolean isOnline = this.aeProxy != null && this.aeProxy.isActive() && this.aeProxy.isPowered(); - if (this.isOnline != isOnline) { - writeCustomData(UPDATE_ONLINE_STATUS, buf -> buf.writeBoolean(isOnline)); - this.isOnline = isOnline; - this.meStatusChanged = true; - } else { - this.meStatusChanged = false; - } + playerIn.sendStatusMessage(new TextComponentTranslation(allowsExtraConnections ? + "gregtech.machine.me.extra_connections.enabled" : "gregtech.machine.me.extra_connections.disabled"), + true); } - return this.isOnline; - } - protected boolean shouldSyncME() { - return this.meUpdateTick % ConfigHolder.compat.ae2.updateIntervals == 0; + return true; } - protected IActionSource getActionSource() { - if (this.getHolder() instanceof IActionHost holder) { - return new MachineSource(holder); - } - return new BaseActionSource(); + @Override + public void setFrontFacing(EnumFacing frontFacing) { + super.setFrontFacing(frontFacing); + updateConnectableSides(); } @Nullable private AENetworkProxy createProxy() { - if (this.getHolder() instanceof IGridProxyable holder) { - AENetworkProxy proxy = new AENetworkProxy(holder, "mte_proxy", this.getStackForm(), true); + if (getHolder() instanceof IGridProxyable holder) { + AENetworkProxy proxy = new AENetworkProxy(holder, "mte_proxy", getStackForm(), true); proxy.setFlags(GridFlags.REQUIRE_CHANNEL); proxy.setIdlePowerUsage(ConfigHolder.compat.ae2.meHatchEnergyUsage); proxy.setValidSides(getConnectableSides()); @@ -190,64 +168,61 @@ private AENetworkProxy createProxy() { return null; } - @NotNull - protected IStorageChannel getStorageChannel() { - return AEApi.instance().storage().getStorageChannel(storageChannel); - } - @Nullable - protected IMEMonitor getMonitor() { - AENetworkProxy proxy = getProxy(); - if (proxy == null) return null; - - IStorageChannel channel = getStorageChannel(); + @Override + public AENetworkProxy getProxy() { + if (aeProxy == null) { + return aeProxy = createProxy(); + } - try { - return proxy.getStorage().getInventory(channel); - } catch (GridAccessException ignored) { - return null; + if (!aeProxy.isReady() && getWorld() != null) { + aeProxy.onReady(); } - } - public EnumSet getConnectableSides() { - return this.allowExtraConnections ? EnumSet.allOf(EnumFacing.class) : EnumSet.of(getFrontFacing()); + return aeProxy; } - public void updateConnectableSides() { - if (this.aeProxy != null) { - this.aeProxy.setValidSides(getConnectableSides()); + protected IActionSource getActionSource() { + if (this.getHolder() instanceof IActionHost holder) { + return new MachineSource(holder); } + + return new BaseActionSource(); } @Override - public boolean onWireCutterClick(EntityPlayer playerIn, EnumHand hand, EnumFacing facing, - CuboidRayTraceResult hitResult) { - this.allowExtraConnections = !this.allowExtraConnections; - updateConnectableSides(); + public void gridChanged() {} + /** + * Get the me network connection status, updating it if on serverside. + * + * @return the updated status. + */ + public boolean updateMEStatus() { if (!getWorld().isRemote) { - playerIn.sendStatusMessage(new TextComponentTranslation(this.allowExtraConnections ? - "gregtech.machine.me.extra_connections.enabled" : "gregtech.machine.me.extra_connections.disabled"), - true); + boolean isOnline = this.aeProxy != null && this.aeProxy.isActive() && this.aeProxy.isPowered(); + if (this.isOnline != isOnline) { + writeCustomData(UPDATE_ONLINE_STATUS, buf -> buf.writeBoolean(isOnline)); + this.isOnline = isOnline; + meStatusChanged = true; + } else { + meStatusChanged = false; + } } - return true; - } - - public boolean isOnline() { return isOnline; } @Override public NBTTagCompound writeToNBT(NBTTagCompound data) { super.writeToNBT(data); - data.setBoolean("AllowExtraConnections", this.allowExtraConnections); + data.setBoolean("AllowExtraConnections", allowsExtraConnections); return data; } @Override public void readFromNBT(NBTTagCompound data) { super.readFromNBT(data); - this.allowExtraConnections = data.getBoolean("AllowExtraConnections"); + allowsExtraConnections = data.getBoolean("AllowExtraConnections"); } } diff --git a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEInputBase.java b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEInputBase.java new file mode 100644 index 00000000000..e7c9ec63d75 --- /dev/null +++ b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEInputBase.java @@ -0,0 +1,377 @@ +package gregtech.common.metatileentities.multi.multiblockpart.appeng; + +import gregtech.api.capability.GregtechDataCodes; +import gregtech.api.capability.GregtechTileCapabilities; +import gregtech.api.capability.IControllable; +import gregtech.api.capability.IGhostSlotConfigurable; +import gregtech.api.capability.impl.GhostCircuitItemStackHandler; +import gregtech.api.mui.GTGuiTextures; +import gregtech.api.mui.GTGuis; +import gregtech.api.mui.sync.appeng.AESyncHandler; +import gregtech.api.mui.widget.GhostCircuitSlotWidget; +import gregtech.api.util.GTUtility; +import gregtech.common.ConfigHolder; +import gregtech.common.metatileentities.multi.multiblockpart.appeng.slot.ExportOnlyAESlot; +import gregtech.common.metatileentities.multi.multiblockpart.appeng.slot.IExportOnlyAEStackList; +import gregtech.common.metatileentities.multi.multiblockpart.appeng.stack.IWrappedStack; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.World; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.Constants; + +import appeng.api.config.Actionable; +import appeng.api.storage.IMEMonitor; +import appeng.api.storage.IStorageChannel; +import appeng.api.storage.data.IAEStack; +import com.cleanroommc.modularui.api.IPanelHandler; +import com.cleanroommc.modularui.api.drawable.IKey; +import com.cleanroommc.modularui.drawable.ItemDrawable; +import com.cleanroommc.modularui.factory.PosGuiData; +import com.cleanroommc.modularui.screen.ModularPanel; +import com.cleanroommc.modularui.screen.UISettings; +import com.cleanroommc.modularui.value.IntValue; +import com.cleanroommc.modularui.value.sync.IntSyncValue; +import com.cleanroommc.modularui.value.sync.PanelSyncHandler; +import com.cleanroommc.modularui.value.sync.PanelSyncManager; +import com.cleanroommc.modularui.widget.Widget; +import com.cleanroommc.modularui.widgets.ButtonWidget; +import com.cleanroommc.modularui.widgets.SlotGroupWidget; +import com.cleanroommc.modularui.widgets.layout.Flow; +import com.cleanroommc.modularui.widgets.textfield.TextFieldWidget; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Range; + +public abstract class MetaTileEntityMEInputBase> + extends MetaTileEntityAEHostableChannelPart + implements IControllable, IGhostSlotConfigurable { + + public final static int CONFIG_SIZE = 16; + public static final String WORKING_TAG = "WorkingEnabled"; + public static final String SYNC_HANDLER_NAME = "aeSync"; + + protected IExportOnlyAEStackList aeHandler; + protected GhostCircuitItemStackHandler circuitInventory; + protected boolean workingEnabled = true; + + public MetaTileEntityMEInputBase(ResourceLocation metaTileEntityId, int tier, boolean isExportHatch, + Class> storageChannel) { + super(metaTileEntityId, tier, isExportHatch, storageChannel); + } + + @Override + protected void initializeInventory() { + super.initializeInventory(); + this.aeHandler = initializeAEHandler(); + this.circuitInventory = new GhostCircuitItemStackHandler(this); + this.importItems = circuitInventory; + } + + protected abstract @NotNull IExportOnlyAEStackList initializeAEHandler(); + + protected abstract @NotNull IExportOnlyAEStackList getAEHandler(); + + @Override + public void update() { + super.update(); + if (!getWorld().isRemote && this.workingEnabled && updateMEStatus() && shouldOperateOnME()) { + operateOnME(); + } + } + + public boolean isAutoPull() { + return getAEHandler().isAutoPull(); + } + + public boolean isStocking() { + return getAEHandler().isStocking(); + } + + protected void operateOnME() { + syncME(); + } + + protected void syncME() { + IMEMonitor monitor = getMonitor(); + if (monitor == null) return; + + for (ExportOnlyAESlot slot : getAEHandler().getInventory()) { + AEStackType exceedStack = slot.exceedStack(); + if (exceedStack != null) { + long total = exceedStack.getStackSize(); + AEStackType notInserted = monitor.injectItems(exceedStack, Actionable.MODULATE, getActionSource()); + if (notInserted != null && notInserted.getStackSize() > 0L) { + slot.decrementStock(total - notInserted.getStackSize()); + continue; + } else { + slot.decrementStock(total); + } + } + + AEStackType requestStack = slot.requestStack(); + if (requestStack == null) continue; + AEStackType extracted = monitor.extractItems(requestStack, Actionable.MODULATE, getActionSource()); + if (extracted == null) continue; + slot.addStack(extracted); + } + } + + @Override + public void onRemoval() { + flushInventory(); + super.onRemoval(); + } + + protected void flushInventory() { + IMEMonitor monitor = getMonitor(); + if (monitor == null) return; + + for (ExportOnlyAESlot slot : getAEHandler().getInventory()) { + AEStackType stock = slot.getStock(); + if (stock instanceof IWrappedStackwrappedStack) { + // noinspection unchecked + stock = (AEStackType) wrappedStack.copyAsAEStack(); + } + + if (stock == null) continue; + monitor.injectItems(stock, Actionable.MODULATE, getActionSource()); + } + } + + @Override + public boolean usesMui2() { + return true; + } + + protected abstract @NotNull AESyncHandler createAESyncHandler(); + + @Override + public ModularPanel buildUI(PosGuiData guiData, PanelSyncManager panelSyncManager, UISettings settings) { + ModularPanel mainPanel = GTGuis.createPanel(this, 176, 18 + 18 * 4 + 94); + final boolean isStocking = getAEHandler().isStocking(); + + panelSyncManager.syncValue(SYNC_HANDLER_NAME, 0, createAESyncHandler()); + + return mainPanel.child(IKey.lang(getMetaFullName()) + .asWidget() + .pos(5, 5)) + .child(SlotGroupWidget.playerInventory(false) + .left(7) + .bottom(7)) + .child(IKey.lang(() -> isOnline() ? "gregtech.gui.me_network.online" : + "gregtech.gui.me_network.offline") + .asWidget() + .marginLeft(5) + .widthRel(1.0f) + .top(15)) + .child(createConfigGrid(guiData, panelSyncManager)) + .child(Flow.column() + .pos(7 + 18 * 4, 25) + .size(18, 18 * 4) + .child(createMainColumnWidget(0, guiData, panelSyncManager)) + .child(createMainColumnWidget(1, guiData, panelSyncManager)) + .child(createMainColumnWidget(2, guiData, panelSyncManager)) + .child(createMainColumnWidget(3, guiData, panelSyncManager))) + .child(createDisplayGrid(guiData, panelSyncManager)) + .child(Flow.row() + .width(isStocking ? 18 : 18 * 2) + .height(18) + .top(5) + .right(7) + .childIf(!isStocking, getMultiplierWidget(guiData, panelSyncManager)) + .child(getSettingWidget(guiData, panelSyncManager))); + } + + protected abstract @NotNull Widget createConfigGrid(@NotNull PosGuiData guiData, + @NotNull PanelSyncManager panelSyncManager); + + protected abstract @NotNull Widget createDisplayGrid(@NotNull PosGuiData guiData, + @NotNull PanelSyncManager panelSyncManager); + + protected @NotNull Widget createMainColumnWidget(@Range(from = 0, to = 3) int index, @NotNull PosGuiData guiData, + @NotNull PanelSyncManager panelSyncManager) { + return switch (index) { + case 1 -> GTGuiTextures.ARROW_DOUBLE.asWidget(); + case 2 -> createGhostCircuitWidget(); + default -> new Widget<>() + .size(18); + }; + } + + protected @NotNull GhostCircuitSlotWidget createGhostCircuitWidget() { + return new GhostCircuitSlotWidget() + .slot(circuitInventory, 0) + .background(GTGuiTextures.SLOT, GTGuiTextures.INT_CIRCUIT_OVERLAY); + } + + protected Widget getSettingWidget(@NotNull PosGuiData guiData, @NotNull PanelSyncManager guiSyncManager) { + IPanelHandler settingPopup = guiSyncManager.panel("settings_panel", this::buildSettingsPopup, true); + + return new ButtonWidget<>() + .onMousePressed(mouse -> { + if (settingPopup.isPanelOpen()) { + settingPopup.closePanel(); + } else { + settingPopup.openPanel(); + } + + return true; + }) + .addTooltipLine(IKey.lang("gregtech.machine.me.settings.button")) + .overlay(GTGuiTextures.FILTER_SETTINGS_OVERLAY); + } + + protected ModularPanel buildSettingsPopup(PanelSyncManager syncManager, IPanelHandler syncHandler) { + IntSyncValue refreshRateSync = new IntSyncValue(this::getRefreshRate, this::setRefreshRate); + ItemDrawable meControllerDrawable = new ItemDrawable(getStackForm()); + + final int width = 110; + return GTGuis.createPopupPanel("settings", width, getSettingsPopupHeight()) + .child(Flow.row() + .pos(4, 4) + .height(16) + .child(meControllerDrawable.asWidget() + .size(16) + .marginRight(4)) + .child(IKey.lang("gregtech.machine.me.settings.button") + .asWidget() + .heightRel(1.0f))) + .child(IKey.lang("gregtech.machine.me.settings.refresh_rate") + .asWidget() + .left(5) + .top(5 + 18)) + .child(new TextFieldWidget() + .left(5) + .top(15 + 18) + .size(width - 10, 10) + .setNumbers(1, Integer.MAX_VALUE) + .setDefaultNumber(ConfigHolder.compat.ae2.updateIntervals) + .value(refreshRateSync)); + } + + protected int getSettingsPopupHeight() { + return 33 + 14 + 5; + } + + protected Widget getMultiplierWidget(@NotNull PosGuiData guiData, @NotNull PanelSyncManager syncManager) { + IPanelHandler multiplierPopup = syncManager.panel("multiplier_panel", this::buildMultiplierPopup, true); + + return new ButtonWidget<>() + .onMousePressed(mouse -> { + if (multiplierPopup.isPanelOpen()) { + multiplierPopup.closePanel(); + } else { + multiplierPopup.openPanel(); + } + + return true; + }) + .addTooltipLine(IKey.lang("gregtech.machine.me.multiplier.button")) + .overlay(GTGuiTextures.ARROW_OPPOSITE); + } + + protected ModularPanel buildMultiplierPopup(PanelSyncManager syncManager, IPanelHandler syncHandler) { + AESyncHandler aeSyncHandler = ((PanelSyncHandler) syncHandler).getSyncManager() + .findSyncHandler(SYNC_HANDLER_NAME, 0, AESyncHandler.class); + IntValue multiplier = new IntValue(2); + + return GTGuis.createPopupPanel("multiplier", 100, 35) + .child(new ButtonWidget<>() + .onMousePressed(mouse -> aeSyncHandler + .modifyConfigAmounts((index, amount) -> Math.max(1, amount / multiplier.getIntValue()))) + .left(5) + .top(7) + .overlay(IKey.str("/"))) + .child(new TextFieldWidget() + .alignX(0.5f) + .top(5) + .widthRel(0.5f) + .height(20) + .setNumbers(2, Integer.MAX_VALUE) + .setDefaultNumber(2) + .value(multiplier)) + .child(new ButtonWidget<>() + .onMousePressed(mouse -> aeSyncHandler.modifyConfigAmounts( + (index, amount) -> GTUtility.multiplySaturated(amount, multiplier.getIntValue()))) + .right(5) + .top(7) + .overlay(IKey.str("x"))); + } + + @Override + public boolean isWorkingEnabled() { + return this.workingEnabled; + } + + @Override + public void setWorkingEnabled(boolean workingEnabled) { + this.workingEnabled = workingEnabled; + World world = this.getWorld(); + if (world != null && !world.isRemote) { + writeCustomData(GregtechDataCodes.WORKING_ENABLED, buf -> buf.writeBoolean(workingEnabled)); + } + } + + @Override + public boolean hasGhostCircuitInventory() { + return true; + } + + @Override + public void setGhostCircuitConfig(int config) { + if (this.circuitInventory.getCircuitValue() == config) { + return; + } + + this.circuitInventory.setCircuitValue(config); + if (!getWorld().isRemote) { + markDirty(); + } + } + + @Override + public T getCapability(Capability capability, EnumFacing side) { + if (capability == GregtechTileCapabilities.CAPABILITY_CONTROLLABLE) { + return GregtechTileCapabilities.CAPABILITY_CONTROLLABLE.cast(this); + } + + return super.getCapability(capability, side); + } + + @Override + public void writeInitialSyncData(PacketBuffer buf) { + super.writeInitialSyncData(buf); + buf.writeBoolean(this.workingEnabled); + } + + @Override + public void receiveInitialSyncData(PacketBuffer buf) { + super.receiveInitialSyncData(buf); + this.workingEnabled = buf.readBoolean(); + } + + @Override + protected boolean shouldSerializeInventories() { + return false; + } + + @Override + public NBTTagCompound writeToNBT(NBTTagCompound data) { + super.writeToNBT(data); + data.setBoolean(WORKING_TAG, this.workingEnabled); + this.circuitInventory.write(data); + return data; + } + + @Override + public void readFromNBT(NBTTagCompound data) { + super.readFromNBT(data); + if (data.hasKey(WORKING_TAG, Constants.NBT.TAG_BYTE)) { + this.workingEnabled = data.getBoolean(WORKING_TAG); + } + this.circuitInventory.read(data); + } +} diff --git a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEInputBus.java b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEInputBus.java index 23f1ab2899b..e338ea523ae 100644 --- a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEInputBus.java +++ b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEInputBus.java @@ -1,27 +1,22 @@ package gregtech.common.metatileentities.multi.multiblockpart.appeng; -import gregtech.api.GTValues; -import gregtech.api.capability.GregtechDataCodes; -import gregtech.api.capability.GregtechTileCapabilities; import gregtech.api.capability.IDataStickIntractable; -import gregtech.api.capability.IGhostSlotConfigurable; import gregtech.api.capability.INotifiableHandler; -import gregtech.api.capability.impl.GhostCircuitItemStackHandler; import gregtech.api.capability.impl.ItemHandlerList; import gregtech.api.capability.impl.NotifiableItemStackHandler; -import gregtech.api.gui.GuiTextures; -import gregtech.api.gui.ModularUI; -import gregtech.api.gui.widgets.GhostCircuitSlotWidget; -import gregtech.api.gui.widgets.SlotWidget; import gregtech.api.metatileentity.MetaTileEntity; import gregtech.api.metatileentity.interfaces.IGregTechTileEntity; import gregtech.api.metatileentity.multiblock.AbilityInstances; import gregtech.api.metatileentity.multiblock.IMultiblockAbilityPart; import gregtech.api.metatileentity.multiblock.MultiblockAbility; import gregtech.api.metatileentity.multiblock.MultiblockControllerBase; +import gregtech.api.mui.GTGuiTextures; +import gregtech.api.mui.sync.appeng.AEItemSyncHandler; +import gregtech.api.mui.sync.appeng.AESyncHandler; +import gregtech.api.mui.widget.appeng.item.AEItemConfigSlot; +import gregtech.api.mui.widget.appeng.item.AEItemDisplaySlot; import gregtech.api.util.GTUtility; import gregtech.client.renderer.texture.Textures; -import gregtech.common.gui.widget.appeng.AEItemConfigWidget; import gregtech.common.metatileentities.multi.multiblockpart.appeng.slot.ExportOnlyAEItemList; import gregtech.common.metatileentities.multi.multiblockpart.appeng.slot.ExportOnlyAEItemSlot; import gregtech.common.metatileentities.multi.multiblockpart.appeng.stack.WrappedItemStack; @@ -32,139 +27,79 @@ import net.minecraft.nbt.NBTBase; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; -import net.minecraft.network.PacketBuffer; -import net.minecraft.util.EnumFacing; import net.minecraft.util.ResourceLocation; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; -import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandlerModifiable; -import appeng.api.config.Actionable; -import appeng.api.storage.IMEMonitor; import appeng.api.storage.channels.IItemStorageChannel; import appeng.api.storage.data.IAEItemStack; import codechicken.lib.render.CCRenderState; import codechicken.lib.render.pipeline.IVertexOperation; import codechicken.lib.vec.Matrix4; +import com.cleanroommc.modularui.api.drawable.IKey; +import com.cleanroommc.modularui.api.widget.IWidget; +import com.cleanroommc.modularui.factory.PosGuiData; +import com.cleanroommc.modularui.value.sync.PanelSyncManager; +import com.cleanroommc.modularui.value.sync.SyncHandlers; +import com.cleanroommc.modularui.widget.Widget; +import com.cleanroommc.modularui.widgets.layout.Grid; +import com.cleanroommc.modularui.widgets.slot.ItemSlot; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.Range; import java.util.Arrays; import java.util.List; -public class MetaTileEntityMEInputBus extends MetaTileEntityAEHostablePart - implements IMultiblockAbilityPart, - IGhostSlotConfigurable, IDataStickIntractable { +public class MetaTileEntityMEInputBus extends MetaTileEntityMEInputBase + implements IMultiblockAbilityPart, IDataStickIntractable { - public final static String ITEM_BUFFER_TAG = "ItemSlots"; - public final static String WORKING_TAG = "WorkingEnabled"; - private final static int CONFIG_SIZE = 16; - private boolean workingEnabled = true; - protected ExportOnlyAEItemList aeItemHandler; - protected GhostCircuitItemStackHandler circuitInventory; - protected NotifiableItemStackHandler extraSlotInventory; - private ItemHandlerList actualImportItems; + public static final String ITEM_BUFFER_TAG = "ItemSlots"; - public MetaTileEntityMEInputBus(ResourceLocation metaTileEntityId) { - this(metaTileEntityId, GTValues.EV); - } + protected NotifiableItemStackHandler extraSlotInventory; - protected MetaTileEntityMEInputBus(ResourceLocation metaTileEntityId, int tier) { + public MetaTileEntityMEInputBus(ResourceLocation metaTileEntityId, int tier) { super(metaTileEntityId, tier, false, IItemStorageChannel.class); } - protected ExportOnlyAEItemList getAEItemHandler() { - if (aeItemHandler == null) { - aeItemHandler = new ExportOnlyAEItemList(this, CONFIG_SIZE, this.getController()); - } - return aeItemHandler; + @Override + public MetaTileEntity createMetaTileEntity(IGregTechTileEntity iGregTechTileEntity) { + return new MetaTileEntityMEInputBus(metaTileEntityId, getTier()); } @Override protected void initializeInventory() { super.initializeInventory(); - this.aeItemHandler = getAEItemHandler(); - this.circuitInventory = new GhostCircuitItemStackHandler(this); - this.circuitInventory.addNotifiableMetaTileEntity(this); this.extraSlotInventory = new NotifiableItemStackHandler(this, 1, this, false); this.extraSlotInventory.addNotifiableMetaTileEntity(this); - this.actualImportItems = new ItemHandlerList( - Arrays.asList(this.aeItemHandler, this.circuitInventory, this.extraSlotInventory)); - this.importItems = this.actualImportItems; - } - - public IItemHandlerModifiable getImportItems() { - return this.actualImportItems; + this.importItems = new ItemHandlerList( + Arrays.asList(getAEHandler(), this.circuitInventory, this.extraSlotInventory)); } @Override - public void update() { - super.update(); - if (!getWorld().isRemote && this.workingEnabled && updateMEStatus() && shouldSyncME()) { - syncME(); - } + protected @NotNull ExportOnlyAEItemList initializeAEHandler() { + return new ExportOnlyAEItemList(this, CONFIG_SIZE, this.getController()); } - protected void syncME() { - IMEMonitor monitor = getMonitor(); - if (monitor == null) return; - - for (ExportOnlyAEItemSlot aeSlot : this.getAEItemHandler().getInventory()) { - // Try to clear the wrong item - IAEItemStack exceedItem = aeSlot.exceedStack(); - if (exceedItem != null) { - long total = exceedItem.getStackSize(); - IAEItemStack notInserted = monitor.injectItems(exceedItem, Actionable.MODULATE, this.getActionSource()); - if (notInserted != null && notInserted.getStackSize() > 0) { - aeSlot.extractItem(0, (int) (total - notInserted.getStackSize()), false); - continue; - } else { - aeSlot.extractItem(0, (int) total, false); - } - } - // Fill it - IAEItemStack reqItem = aeSlot.requestStack(); - if (reqItem != null) { - IAEItemStack extracted = monitor.extractItems(reqItem, Actionable.MODULATE, this.getActionSource()); - if (extracted != null) { - aeSlot.addStack(extracted); - } - } - } + @NotNull + protected ExportOnlyAEItemList getAEHandler() { + return (ExportOnlyAEItemList) aeHandler; } @Override - public void onRemoval() { - flushInventory(); - super.onRemoval(); - } - - protected void flushInventory() { - IMEMonitor monitor = getMonitor(); - if (monitor == null) return; - - for (ExportOnlyAEItemSlot aeSlot : this.getAEItemHandler().getInventory()) { - IAEItemStack stock = aeSlot.getStock(); - if (stock instanceof WrappedItemStack) { - stock = ((WrappedItemStack) stock).getAEStack(); - } - if (stock != null) { - monitor.injectItems(stock, Actionable.MODULATE, this.getActionSource()); - } + public void clearMachineInventory(@NotNull List<@NotNull ItemStack> itemBuffer) { + ItemStack extraSlotStack = extraSlotInventory.getStackInSlot(0); + if (!extraSlotStack.isEmpty()) { + itemBuffer.add(extraSlotStack); } } - @Override - public MetaTileEntity createMetaTileEntity(IGregTechTileEntity iGregTechTileEntity) { - return new MetaTileEntityMEInputBus(metaTileEntityId); - } - @Override public void addToMultiBlock(MultiblockControllerBase controllerBase) { super.addToMultiBlock(controllerBase); - for (IItemHandler handler : this.actualImportItems.getBackingHandlers()) { + for (IItemHandler handler : ((ItemHandlerList) this.importItems).getBackingHandlers()) { if (handler instanceof INotifiableHandler notifiable) { notifiable.addNotifiableMetaTileEntity(controllerBase); notifiable.addToNotifiedList(this, handler, false); @@ -175,7 +110,7 @@ public void addToMultiBlock(MultiblockControllerBase controllerBase) { @Override public void removeFromMultiBlock(MultiblockControllerBase controllerBase) { super.removeFromMultiBlock(controllerBase); - for (IItemHandler handler : this.actualImportItems.getBackingHandlers()) { + for (IItemHandler handler : ((ItemHandlerList) this.importItems).getBackingHandlers()) { if (handler instanceof INotifiableHandler notifiable) { notifiable.removeNotifiableMetaTileEntity(controllerBase); } @@ -183,120 +118,97 @@ public void removeFromMultiBlock(MultiblockControllerBase controllerBase) { } @Override - protected final ModularUI createUI(EntityPlayer player) { - ModularUI.Builder builder = createUITemplate(player); - return builder.build(this.getHolder(), player); - } - - protected ModularUI.Builder createUITemplate(EntityPlayer player) { - ModularUI.Builder builder = ModularUI - .builder(GuiTextures.BACKGROUND, 176, 18 + 18 * 4 + 94) - .label(10, 5, getMetaFullName()); - // ME Network status - builder.dynamicLabel(10, 15, () -> this.isOnline ? - I18n.format("gregtech.gui.me_network.online") : - I18n.format("gregtech.gui.me_network.offline"), - 0x404040); - - // Config slots - builder.widget(new AEItemConfigWidget(7, 25, this.getAEItemHandler())); - - // Ghost circuit slot - SlotWidget circuitSlot = new GhostCircuitSlotWidget(circuitInventory, 0, 7 + 18 * 4, 25 + 18 * 3) - .setBackgroundTexture(GuiTextures.SLOT, GuiTextures.INT_CIRCUIT_OVERLAY); - builder.widget(circuitSlot.setConsumer(w -> { - String configString; - if (circuitInventory == null || - circuitInventory.getCircuitValue() == GhostCircuitItemStackHandler.NO_CONFIG) { - configString = new TextComponentTranslation("gregtech.gui.configurator_slot.no_value") - .getFormattedText(); - } else { - configString = String.valueOf(circuitInventory.getCircuitValue()); - } - - w.setTooltipText("gregtech.gui.configurator_slot.tooltip", configString); - })); - - // Extra slot - builder.widget(new SlotWidget(extraSlotInventory, 0, 7 + 18 * 4, 25 + 18 * 2) - .setBackgroundTexture(GuiTextures.SLOT) - .setTooltipText("gregtech.gui.me_bus.extra_slot")); - - // Arrow image - builder.image(7 + 18 * 4, 25 + 18, 18, 18, GuiTextures.ARROW_DOUBLE); - - builder.bindPlayerInventory(player.inventory, GuiTextures.SLOT, 7, 18 + 18 * 4 + 12); - return builder; - } - - @Override - public boolean isWorkingEnabled() { - return this.workingEnabled; + protected @NotNull AESyncHandler createAESyncHandler() { + return new AEItemSyncHandler(getAEHandler(), this::markDirty, circuitInventory::setCircuitValue); } @Override - public void setWorkingEnabled(boolean workingEnabled) { - this.workingEnabled = workingEnabled; - World world = this.getWorld(); - if (world != null && !world.isRemote) { - writeCustomData(GregtechDataCodes.WORKING_ENABLED, buf -> buf.writeBoolean(workingEnabled)); + protected @NotNull Widget createMainColumnWidget(@Range(from = 0, to = 3) int index, @NotNull PosGuiData guiData, + @NotNull PanelSyncManager panelSyncManager) { + if (index == 3) { + panelSyncManager.registerSlotGroup("extra_slot", 1); + return new ItemSlot() + .slot(SyncHandlers.itemSlot(extraSlotInventory, 0) + .slotGroup("extra_slot")) + .addTooltipLine(IKey.lang("gregtech.gui.me_bus.extra_slot")); } + + return super.createMainColumnWidget(index, guiData, panelSyncManager); } @Override - public T getCapability(Capability capability, EnumFacing side) { - if (capability == GregtechTileCapabilities.CAPABILITY_CONTROLLABLE) { - return GregtechTileCapabilities.CAPABILITY_CONTROLLABLE.cast(this); + protected @NotNull Widget createConfigGrid(@NotNull PosGuiData guiData, + @NotNull PanelSyncManager panelSyncManager) { + Grid grid = new Grid() + .pos(7, 25) + .size(18 * 4) + .minElementMargin(0, 0) + .minColWidth(18) + .minRowHeight(18) + .matrix(Grid.mapToMatrix((int) Math.sqrt(CONFIG_SIZE), CONFIG_SIZE, + index -> new AEItemConfigSlot(isStocking(), index, this::isAutoPull) + .syncHandler(SYNC_HANDLER_NAME, 0) + .name("Index " + index))); + + for (IWidget slotUpper : grid.getChildren()) { + ((AEItemConfigSlot) slotUpper).onSelect(() -> { + for (IWidget slotLower : grid.getChildren()) { + ((AEItemConfigSlot) slotLower).deselect(); + } + }); } - return super.getCapability(capability, side); - } - @Override - public void writeInitialSyncData(PacketBuffer buf) { - super.writeInitialSyncData(buf); - buf.writeBoolean(workingEnabled); + return grid; } @Override - public void receiveInitialSyncData(PacketBuffer buf) { - super.receiveInitialSyncData(buf); - this.workingEnabled = buf.readBoolean(); + protected @NotNull Widget createDisplayGrid(@NotNull PosGuiData guiData, + @NotNull PanelSyncManager panelSyncManager) { + return new Grid() + .pos(7 + 18 * 5, 25) + .size(18 * 4) + .minElementMargin(0, 0) + .minColWidth(18) + .minRowHeight(18) + .matrix(Grid.mapToMatrix((int) Math.sqrt(CONFIG_SIZE), CONFIG_SIZE, + index -> new AEItemDisplaySlot(index) + .background(GTGuiTextures.SLOT_DARK) + .syncHandler(SYNC_HANDLER_NAME, 0) + .name("Index " + index))); } @Override public NBTTagCompound writeToNBT(NBTTagCompound data) { super.writeToNBT(data); - data.setBoolean(WORKING_TAG, this.workingEnabled); + NBTTagList slots = new NBTTagList(); for (int i = 0; i < CONFIG_SIZE; i++) { - ExportOnlyAEItemSlot slot = this.getAEItemHandler().getInventory()[i]; + ExportOnlyAEItemSlot slot = this.getAEHandler().getInventory()[i]; NBTTagCompound slotTag = new NBTTagCompound(); slotTag.setInteger("slot", i); slotTag.setTag("stack", slot.serializeNBT()); slots.appendTag(slotTag); } data.setTag(ITEM_BUFFER_TAG, slots); - this.circuitInventory.write(data); - // Extra slot inventory + GTUtility.writeItems(this.extraSlotInventory, "ExtraInventory", data); + return data; } @Override public void readFromNBT(NBTTagCompound data) { super.readFromNBT(data); - if (data.hasKey(WORKING_TAG)) { - this.workingEnabled = data.getBoolean(WORKING_TAG); - } + if (data.hasKey(ITEM_BUFFER_TAG, 9)) { NBTTagList slots = (NBTTagList) data.getTag(ITEM_BUFFER_TAG); for (NBTBase nbtBase : slots) { NBTTagCompound slotTag = (NBTTagCompound) nbtBase; - ExportOnlyAEItemSlot slot = this.getAEItemHandler().getInventory()[slotTag.getInteger("slot")]; + ExportOnlyAEItemSlot slot = this.getAEHandler().getInventory()[slotTag.getInteger("slot")]; slot.deserializeNBT(slotTag.getCompoundTag("stack")); } } - this.circuitInventory.read(data); + GTUtility.readItems(this.extraSlotInventory, "ExtraInventory", data); this.importItems = createImportItemHandler(); } @@ -305,7 +217,7 @@ public void readFromNBT(NBTTagCompound data) { public void renderMetaTileEntity(CCRenderState renderState, Matrix4 translation, IVertexOperation[] pipeline) { super.renderMetaTileEntity(renderState, translation, pipeline); if (this.shouldRenderOverlay()) { - if (isOnline) { + if (isOnline()) { Textures.ME_INPUT_BUS_ACTIVE.renderSided(getFrontFacing(), renderState, translation, pipeline); } else { Textures.ME_INPUT_BUS.renderSided(getFrontFacing(), renderState, translation, pipeline); @@ -332,23 +244,7 @@ public MultiblockAbility getAbility() { @Override public void registerAbilities(@NotNull AbilityInstances abilityInstances) { - abilityInstances.add(this.actualImportItems); - } - - @Override - public boolean hasGhostCircuitInventory() { - return true; - } - - @Override - public void setGhostCircuitConfig(int config) { - if (this.circuitInventory.getCircuitValue() == config) { - return; - } - this.circuitInventory.setCircuitValue(config); - if (!getWorld().isRemote) { - markDirty(); - } + abilityInstances.add(this.importItems); } @Override @@ -365,7 +261,7 @@ protected NBTTagCompound writeConfigToTag() { NBTTagCompound configStacks = new NBTTagCompound(); tag.setTag("ConfigStacks", configStacks); for (int i = 0; i < CONFIG_SIZE; i++) { - var slot = this.aeItemHandler.getInventory()[i]; + var slot = this.aeHandler.getInventory()[i]; IAEItemStack config = slot.getConfig(); if (config == null) { continue; @@ -374,7 +270,11 @@ protected NBTTagCompound writeConfigToTag() { config.getDefinition().writeToNBT(stackNbt); configStacks.setTag(Integer.toString(i), stackNbt); } + tag.setByte("GhostCircuit", (byte) this.circuitInventory.getCircuitValue()); + + tag.setInteger(REFRESH_RATE_TAG, this.refreshRate); + return tag; } @@ -397,14 +297,19 @@ protected void readConfigFromTag(NBTTagCompound tag) { String key = Integer.toString(i); if (configStacks.hasKey(key)) { NBTTagCompound configTag = configStacks.getCompoundTag(key); - this.aeItemHandler.getInventory()[i].setConfig(WrappedItemStack.fromNBT(configTag)); + this.aeHandler.getInventory()[i].setConfig(WrappedItemStack.fromNBT(configTag)); } else { - this.aeItemHandler.getInventory()[i].setConfig(null); + this.aeHandler.getInventory()[i].setConfig(null); } } } + if (tag.hasKey("GhostCircuit")) { this.setGhostCircuitConfig(tag.getByte("GhostCircuit")); } + + if (tag.hasKey(REFRESH_RATE_TAG)) { + this.refreshRate = tag.getInteger(REFRESH_RATE_TAG); + } } } diff --git a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEInputHatch.java b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEInputHatch.java index 120b25e8827..9bfe4af7fe1 100644 --- a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEInputHatch.java +++ b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEInputHatch.java @@ -1,20 +1,18 @@ package gregtech.common.metatileentities.multi.multiblockpart.appeng; -import gregtech.api.GTValues; -import gregtech.api.capability.GregtechDataCodes; -import gregtech.api.capability.GregtechTileCapabilities; import gregtech.api.capability.IDataStickIntractable; import gregtech.api.capability.impl.FluidTankList; -import gregtech.api.gui.GuiTextures; -import gregtech.api.gui.ModularUI; -import gregtech.api.gui.widgets.ImageWidget; import gregtech.api.metatileentity.MetaTileEntity; import gregtech.api.metatileentity.interfaces.IGregTechTileEntity; import gregtech.api.metatileentity.multiblock.AbilityInstances; import gregtech.api.metatileentity.multiblock.IMultiblockAbilityPart; import gregtech.api.metatileentity.multiblock.MultiblockAbility; +import gregtech.api.mui.GTGuiTextures; +import gregtech.api.mui.sync.appeng.AEFluidSyncHandler; +import gregtech.api.mui.sync.appeng.AESyncHandler; +import gregtech.api.mui.widget.appeng.fluid.AEFluidConfigSlot; +import gregtech.api.mui.widget.appeng.fluid.AEFluidDisplaySlot; import gregtech.client.renderer.texture.Textures; -import gregtech.common.gui.widget.appeng.AEFluidConfigWidget; import gregtech.common.metatileentities.multi.multiblockpart.appeng.slot.ExportOnlyAEFluidList; import gregtech.common.metatileentities.multi.multiblockpart.appeng.slot.ExportOnlyAEFluidSlot; import gregtech.common.metatileentities.multi.multiblockpart.appeng.stack.WrappedFluidStack; @@ -25,217 +23,142 @@ import net.minecraft.nbt.NBTBase; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; -import net.minecraft.network.PacketBuffer; -import net.minecraft.util.EnumFacing; import net.minecraft.util.ResourceLocation; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; -import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.fluids.IFluidTank; -import appeng.api.config.Actionable; -import appeng.api.storage.IMEMonitor; import appeng.api.storage.channels.IFluidStorageChannel; import appeng.api.storage.data.IAEFluidStack; import codechicken.lib.render.CCRenderState; import codechicken.lib.render.pipeline.IVertexOperation; import codechicken.lib.vec.Matrix4; +import com.cleanroommc.modularui.api.widget.IWidget; +import com.cleanroommc.modularui.factory.PosGuiData; +import com.cleanroommc.modularui.value.sync.PanelSyncManager; +import com.cleanroommc.modularui.widget.Widget; +import com.cleanroommc.modularui.widgets.layout.Grid; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.Range; import java.util.Arrays; import java.util.List; -public class MetaTileEntityMEInputHatch extends MetaTileEntityAEHostablePart +public class MetaTileEntityMEInputHatch extends MetaTileEntityMEInputBase implements IMultiblockAbilityPart, IDataStickIntractable { - public final static String FLUID_BUFFER_TAG = "FluidTanks"; - public final static String WORKING_TAG = "WorkingEnabled"; - private final static int CONFIG_SIZE = 16; - private boolean workingEnabled = true; - protected ExportOnlyAEFluidList aeFluidHandler; + public static final String FLUID_BUFFER_TAG = "FluidTanks"; - public MetaTileEntityMEInputHatch(ResourceLocation metaTileEntityId) { - this(metaTileEntityId, GTValues.EV); - } - - protected MetaTileEntityMEInputHatch(ResourceLocation metaTileEntityId, int tier) { + public MetaTileEntityMEInputHatch(ResourceLocation metaTileEntityId, int tier) { super(metaTileEntityId, tier, false, IFluidStorageChannel.class); } - protected ExportOnlyAEFluidList getAEFluidHandler() { - if (aeFluidHandler == null) { - aeFluidHandler = new ExportOnlyAEFluidList(this, CONFIG_SIZE, this.getController()); - } - return aeFluidHandler; + @Override + public MetaTileEntity createMetaTileEntity(IGregTechTileEntity iGregTechTileEntity) { + return new MetaTileEntityMEInputHatch(this.metaTileEntityId, getTier()); } @Override protected void initializeInventory() { - getAEFluidHandler(); // initialize it super.initializeInventory(); + this.importFluids = new FluidTankList(false, getAEHandler().getInventory()); } @Override - protected FluidTankList createImportFluidHandler() { - return new FluidTankList(false, getAEFluidHandler().getInventory()); + protected @NotNull ExportOnlyAEFluidList initializeAEHandler() { + return new ExportOnlyAEFluidList(this, CONFIG_SIZE, this.getController()); } @Override - public void update() { - super.update(); - if (!getWorld().isRemote && this.workingEnabled && this.shouldSyncME() && updateMEStatus()) { - syncME(); - } - } - - protected void syncME() { - IMEMonitor monitor = getMonitor(); - if (monitor == null) return; - - for (ExportOnlyAEFluidSlot aeTank : this.getAEFluidHandler().getInventory()) { - // Try to clear the wrong fluid - IAEFluidStack exceedFluid = aeTank.exceedStack(); - if (exceedFluid != null) { - long total = exceedFluid.getStackSize(); - IAEFluidStack notInserted = monitor.injectItems(exceedFluid, Actionable.MODULATE, - this.getActionSource()); - if (notInserted != null && notInserted.getStackSize() > 0) { - aeTank.drain((int) (total - notInserted.getStackSize()), true); - continue; - } else { - aeTank.drain((int) total, true); - } - } - // Fill it - IAEFluidStack reqFluid = aeTank.requestStack(); - if (reqFluid != null) { - IAEFluidStack extracted = monitor.extractItems(reqFluid, Actionable.MODULATE, this.getActionSource()); - if (extracted != null) { - aeTank.addStack(extracted); - } - } - } + @NotNull + protected ExportOnlyAEFluidList getAEHandler() { + return (ExportOnlyAEFluidList) aeHandler; } @Override - public void onRemoval() { - flushInventory(); - super.onRemoval(); - } - - protected void flushInventory() { - IMEMonitor monitor = getMonitor(); - if (monitor == null) return; - - for (ExportOnlyAEFluidSlot aeTank : this.getAEFluidHandler().getInventory()) { - IAEFluidStack stock = aeTank.getStock(); - if (stock instanceof WrappedFluidStack) { - stock = ((WrappedFluidStack) stock).getAEStack(); - } - if (stock != null) { - monitor.injectItems(stock, Actionable.MODULATE, this.getActionSource()); - } - } + protected @NotNull AESyncHandler createAESyncHandler() { + return new AEFluidSyncHandler(getAEHandler(), this::markDirty, circuitInventory::setCircuitValue); } @Override - public MetaTileEntity createMetaTileEntity(IGregTechTileEntity iGregTechTileEntity) { - return new MetaTileEntityMEInputHatch(this.metaTileEntityId); + protected @NotNull Widget createMainColumnWidget(@Range(from = 0, to = 3) int index, @NotNull PosGuiData guiData, + @NotNull PanelSyncManager panelSyncManager) { + return switch (index) { + case 2 -> new Widget<>() + .size(18); + case 3 -> createGhostCircuitWidget(); + default -> super.createMainColumnWidget(index, guiData, panelSyncManager); + }; } @Override - protected final ModularUI createUI(EntityPlayer player) { - ModularUI.Builder builder = createUITemplate(player); - return builder.build(this.getHolder(), player); - } - - protected ModularUI.Builder createUITemplate(EntityPlayer player) { - ModularUI.Builder builder = ModularUI - .builder(GuiTextures.BACKGROUND, 176, 18 + 18 * 4 + 94) - .label(10, 5, getMetaFullName()); - // ME Network status - builder.dynamicLabel(10, 15, () -> this.isOnline ? - I18n.format("gregtech.gui.me_network.online") : - I18n.format("gregtech.gui.me_network.offline"), - 0x404040); - - // Config slots - builder.widget(new AEFluidConfigWidget(7, 25, this.getAEFluidHandler())); - - // Arrow image - builder.image(7 + 18 * 4, 25 + 18, 18, 18, GuiTextures.ARROW_DOUBLE); - - // GT Logo, cause there's some free real estate - builder.widget(new ImageWidget(7 + 18 * 4, 25 + 18 * 3, 17, 17, - GTValues.XMAS.get() ? GuiTextures.GREGTECH_LOGO_XMAS : GuiTextures.GREGTECH_LOGO) - .setIgnoreColor(true)); - - builder.bindPlayerInventory(player.inventory, GuiTextures.SLOT, 7, 18 + 18 * 4 + 12); - return builder; - } - - @Override - public boolean isWorkingEnabled() { - return this.workingEnabled; - } - - @Override - public void setWorkingEnabled(boolean workingEnabled) { - this.workingEnabled = workingEnabled; - World world = this.getWorld(); - if (world != null && !world.isRemote) { - writeCustomData(GregtechDataCodes.WORKING_ENABLED, buf -> buf.writeBoolean(workingEnabled)); - } - } - - @Override - public T getCapability(Capability capability, EnumFacing side) { - if (capability == GregtechTileCapabilities.CAPABILITY_CONTROLLABLE) { - return GregtechTileCapabilities.CAPABILITY_CONTROLLABLE.cast(this); + protected @NotNull Widget createConfigGrid(@NotNull PosGuiData guiData, + @NotNull PanelSyncManager panelSyncManager) { + Grid grid = new Grid() + .pos(7, 25) + .size(18 * 4) + .minElementMargin(0, 0) + .minColWidth(18) + .minRowHeight(18) + .matrix(Grid.mapToMatrix((int) Math.sqrt(CONFIG_SIZE), CONFIG_SIZE, + index -> new AEFluidConfigSlot(isStocking(), index, this::isAutoPull) + .syncHandler(SYNC_HANDLER_NAME, 0) + .name("Index " + index))); + + for (IWidget slotUpper : grid.getChildren()) { + ((AEFluidConfigSlot) slotUpper).onSelect(() -> { + for (IWidget slotLower : grid.getChildren()) { + ((AEFluidConfigSlot) slotLower).deselect(); + } + }); } - return super.getCapability(capability, side); - } - @Override - public void writeInitialSyncData(PacketBuffer buf) { - super.writeInitialSyncData(buf); - buf.writeBoolean(workingEnabled); + return grid; } @Override - public void receiveInitialSyncData(PacketBuffer buf) { - super.receiveInitialSyncData(buf); - this.workingEnabled = buf.readBoolean(); + protected @NotNull Widget createDisplayGrid(@NotNull PosGuiData guiData, + @NotNull PanelSyncManager panelSyncManager) { + return new Grid() + .pos(7 + 18 * 5, 25) + .size(18 * 4) + .minElementMargin(0, 0) + .minColWidth(18) + .minRowHeight(18) + .matrix(Grid.mapToMatrix((int) Math.sqrt(CONFIG_SIZE), CONFIG_SIZE, + index -> new AEFluidDisplaySlot(index) + .background(GTGuiTextures.SLOT_DARK) + .syncHandler(SYNC_HANDLER_NAME, 0) + .name("Index " + index))); } @Override public NBTTagCompound writeToNBT(NBTTagCompound data) { super.writeToNBT(data); - data.setBoolean(WORKING_TAG, this.workingEnabled); + NBTTagList tanks = new NBTTagList(); for (int i = 0; i < CONFIG_SIZE; i++) { - ExportOnlyAEFluidSlot tank = this.getAEFluidHandler().getInventory()[i]; + ExportOnlyAEFluidSlot tank = this.getAEHandler().getInventory()[i]; NBTTagCompound tankTag = new NBTTagCompound(); tankTag.setInteger("slot", i); tankTag.setTag("tank", tank.serializeNBT()); tanks.appendTag(tankTag); } data.setTag(FLUID_BUFFER_TAG, tanks); + return data; } @Override public void readFromNBT(NBTTagCompound data) { super.readFromNBT(data); - if (data.hasKey(WORKING_TAG)) { - this.workingEnabled = data.getBoolean(WORKING_TAG); - } + if (data.hasKey(FLUID_BUFFER_TAG, 9)) { NBTTagList tanks = (NBTTagList) data.getTag(FLUID_BUFFER_TAG); for (NBTBase nbtBase : tanks) { NBTTagCompound tankTag = (NBTTagCompound) nbtBase; - ExportOnlyAEFluidSlot tank = this.getAEFluidHandler().getInventory()[tankTag.getInteger("slot")]; + ExportOnlyAEFluidSlot tank = this.getAEHandler().getInventory()[tankTag.getInteger("slot")]; tank.deserializeNBT(tankTag.getCompoundTag("tank")); } } @@ -245,7 +168,7 @@ public void readFromNBT(NBTTagCompound data) { public void renderMetaTileEntity(CCRenderState renderState, Matrix4 translation, IVertexOperation[] pipeline) { super.renderMetaTileEntity(renderState, translation, pipeline); if (this.shouldRenderOverlay()) { - if (isOnline) { + if (isOnline()) { Textures.ME_INPUT_HATCH_ACTIVE.renderSided(getFrontFacing(), renderState, translation, pipeline); } else { Textures.ME_INPUT_HATCH.renderSided(getFrontFacing(), renderState, translation, pipeline); @@ -266,13 +189,17 @@ public void addInformation(ItemStack stack, @Nullable World player, @NotNull Lis } @Override - public MultiblockAbility getAbility() { - return MultiblockAbility.IMPORT_FLUIDS; + public @NotNull List> getAbilities() { + return Arrays.asList(MultiblockAbility.IMPORT_FLUIDS, MultiblockAbility.IMPORT_ITEMS); } @Override public void registerAbilities(@NotNull AbilityInstances abilityInstances) { - abilityInstances.addAll(Arrays.asList(this.getAEFluidHandler().getInventory())); + if (abilityInstances.isKey(MultiblockAbility.IMPORT_FLUIDS)) { + abilityInstances.add(Arrays.asList(getAEHandler().getInventory())); + } else if (abilityInstances.isKey(MultiblockAbility.IMPORT_ITEMS)) { + abilityInstances.add(circuitInventory); + } } @Override @@ -289,7 +216,7 @@ protected NBTTagCompound writeConfigToTag() { NBTTagCompound configStacks = new NBTTagCompound(); tag.setTag("ConfigStacks", configStacks); for (int i = 0; i < CONFIG_SIZE; i++) { - var slot = this.aeFluidHandler.getInventory()[i]; + var slot = this.aeHandler.getInventory()[i]; IAEFluidStack config = slot.getConfig(); if (config == null) { continue; @@ -298,6 +225,9 @@ protected NBTTagCompound writeConfigToTag() { config.writeToNBT(stackNbt); configStacks.setTag(Integer.toString(i), stackNbt); } + + tag.setInteger(REFRESH_RATE_TAG, this.refreshRate); + return tag; } @@ -320,11 +250,15 @@ protected void readConfigFromTag(NBTTagCompound tag) { String key = Integer.toString(i); if (configStacks.hasKey(key)) { NBTTagCompound configTag = configStacks.getCompoundTag(key); - this.aeFluidHandler.getInventory()[i].setConfig(WrappedFluidStack.fromNBT(configTag)); + this.aeHandler.getInventory()[i].setConfig(WrappedFluidStack.fromNBT(configTag)); } else { - this.aeFluidHandler.getInventory()[i].setConfig(null); + this.aeHandler.getInventory()[i].setConfig(null); } } } + + if (tag.hasKey(REFRESH_RATE_TAG)) { + this.refreshRate = tag.getInteger(REFRESH_RATE_TAG); + } } } diff --git a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEOutputBase.java b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEOutputBase.java new file mode 100644 index 00000000000..158c040d444 --- /dev/null +++ b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEOutputBase.java @@ -0,0 +1,352 @@ +package gregtech.common.metatileentities.multi.multiblockpart.appeng; + +import gregtech.api.capability.GregtechDataCodes; +import gregtech.api.capability.GregtechTileCapabilities; +import gregtech.api.capability.IControllable; +import gregtech.api.capability.INotifiableHandler; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.mui.GTGuiTextures; +import gregtech.api.mui.GTGuis; +import gregtech.common.metatileentities.multi.multiblockpart.appeng.stack.IWrappedStack; +import gregtech.common.mui.widget.ScrollableTextWidget; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.World; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +import appeng.api.config.Actionable; +import appeng.api.storage.IMEMonitor; +import appeng.api.storage.IStorageChannel; +import appeng.api.storage.data.IAEStack; +import com.cleanroommc.modularui.api.drawable.IKey; +import com.cleanroommc.modularui.api.drawable.IRichTextBuilder; +import com.cleanroommc.modularui.factory.PosGuiData; +import com.cleanroommc.modularui.screen.ModularPanel; +import com.cleanroommc.modularui.screen.UISettings; +import com.cleanroommc.modularui.utils.Alignment; +import com.cleanroommc.modularui.utils.serialization.IByteBufDeserializer; +import com.cleanroommc.modularui.value.sync.BooleanSyncValue; +import com.cleanroommc.modularui.value.sync.PanelSyncManager; +import com.cleanroommc.modularui.value.sync.SyncHandler; +import com.cleanroommc.modularui.widgets.SlotGroupWidget; +import it.unimi.dsi.fastutil.Hash; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.function.Consumer; + +public abstract class MetaTileEntityMEOutputBase, RealStackType> + extends MetaTileEntityAEHostableChannelPart + implements IControllable { + + public final static String WORKING_TAG = "WorkingEnabled"; + + protected boolean workingEnabled = true; + protected List<@NotNull IWrappedStack> internalBuffer; + + public MetaTileEntityMEOutputBase(ResourceLocation metaTileEntityId, int tier, + Class> storageChannel) { + super(metaTileEntityId, tier, true, storageChannel); + } + + @Override + protected void initializeInventory() { + super.initializeInventory(); + this.internalBuffer = new ObjectArrayList<>(); + } + + @Override + public void update() { + super.update(); + if (!getWorld().isRemote && this.workingEnabled && this.shouldOperateOnME() && updateMEStatus()) { + if (this.internalBuffer.isEmpty()) return; + + IMEMonitor monitor = getMonitor(); + if (monitor == null) return; + + Iterator> internalBufferIterator = internalBuffer.iterator(); + while (internalBufferIterator.hasNext()) { + IWrappedStack stackInBuffer = internalBufferIterator.next(); + // We have to create an AEItem/FluidStack here, or it'll cause a CCE in ItemVariantList#L35 + AEStackType notPushedToNetwork = monitor.injectItems(stackInBuffer.copyAsAEStack(), Actionable.MODULATE, + getActionSource()); + if (notPushedToNetwork != null && notPushedToNetwork.getStackSize() > 0L) { + stackInBuffer.setStackSize(notPushedToNetwork.getStackSize()); + } else { + internalBufferIterator.remove(); + } + } + } + } + + protected abstract @NotNull IByteBufDeserializer> getDeserializer(); + + @SideOnly(Side.CLIENT) + protected abstract void addStackLine(@NotNull IRichTextBuilder text, + @NotNull IWrappedStack wrappedStack); + + @Override + public boolean usesMui2() { + return true; + } + + @Override + public ModularPanel buildUI(PosGuiData guiData, PanelSyncManager panelSyncManager, UISettings settings) { + BooleanSyncValue onlineSync = new BooleanSyncValue(this::isOnline); + panelSyncManager.syncValue("online", 0, onlineSync); + + WrappedStackSyncHandler bufferSync = new WrappedStackSyncHandler<>(internalBuffer, + getDeserializer()); + panelSyncManager.syncValue("buffer", 0, bufferSync); + + ScrollableTextWidget textList = new ScrollableTextWidget(); + bufferSync.setChangeListener(textList::markDirty); + + return GTGuis.createPanel(this, 176, 18 + 18 * 4 + 94) + .child(IKey.lang(getMetaFullName()) + .asWidget() + .pos(5, 5)) + .child(IKey.lang(() -> onlineSync.getBoolValue() ? + "gregtech.gui.me_network.online" : "gregtech.gui.me_network.offline") + .asWidget() + .marginLeft(5) + .widthRel(1.0f) + .top(15)) + .child(textList.pos(9, 25 + 4) + .size(158, 18 * 4 - 6) + .textBuilder(text -> bufferSync.cacheForEach(stack -> addStackLine(text, stack))) + .alignment(Alignment.TopLeft) + .background(GTGuiTextures.DISPLAY.asIcon() + .margin(-2, -2))) + .child(SlotGroupWidget.playerInventory(false) + .left(7) + .bottom(7)); + } + + @Override + public void onRemoval() { + IMEMonitor monitor = getMonitor(); + if (monitor != null) { + for (IWrappedStack stack : this.internalBuffer) { + monitor.injectItems(stack.copy(), Actionable.MODULATE, this.getActionSource()); + } + } + + super.onRemoval(); + } + + @Override + public boolean isWorkingEnabled() { + return this.workingEnabled; + } + + @Override + public void setWorkingEnabled(boolean workingEnabled) { + this.workingEnabled = workingEnabled; + + World world = this.getWorld(); + if (world != null && !world.isRemote) { + writeCustomData(GregtechDataCodes.WORKING_ENABLED, buf -> buf.writeBoolean(workingEnabled)); + } + } + + @Override + public T getCapability(Capability capability, EnumFacing side) { + if (capability == GregtechTileCapabilities.CAPABILITY_CONTROLLABLE) { + return GregtechTileCapabilities.CAPABILITY_CONTROLLABLE.cast(this); + } + + return super.getCapability(capability, side); + } + + @Override + public void writeInitialSyncData(PacketBuffer buf) { + super.writeInitialSyncData(buf); + buf.writeBoolean(workingEnabled); + } + + @Override + public void receiveInitialSyncData(PacketBuffer buf) { + super.receiveInitialSyncData(buf); + this.workingEnabled = buf.readBoolean(); + } + + @Override + protected boolean shouldSerializeInventories() { + return false; + } + + @Override + public NBTTagCompound writeToNBT(NBTTagCompound data) { + super.writeToNBT(data); + data.setBoolean(WORKING_TAG, this.workingEnabled); + return data; + } + + @Override + public void readFromNBT(NBTTagCompound data) { + super.readFromNBT(data); + if (data.hasKey(WORKING_TAG)) { + this.workingEnabled = data.getBoolean(WORKING_TAG); + } + } + + protected static abstract class InaccessibleInfiniteHandler, + RealStackType> implements INotifiableHandler { + + protected final List> internalBuffer; + protected final List notifiableEntities = new ArrayList<>(); + protected final MetaTileEntity holder; + protected final Hash.Strategy strategy; + + public InaccessibleInfiniteHandler(@NotNull MetaTileEntity holder, + @NotNull List> internalBuffer, + @NotNull MetaTileEntity mte, + @NotNull Hash.Strategy strategy) { + this.holder = holder; + this.internalBuffer = internalBuffer; + this.notifiableEntities.add(mte); + this.strategy = strategy; + } + + protected void add(@NotNull RealStackType stackToAdd, long amount) { + for (IWrappedStack bufferedAEStack : internalBuffer) { + long bufferedAEStackSize = bufferedAEStack.getStackSize(); + RealStackType bufferStack = bufferedAEStack.getDefinition(); + if (strategy.equals(bufferStack, stackToAdd) && bufferedAEStackSize < Long.MAX_VALUE) { + int amountToMerge = (int) Math.min(amount, Long.MAX_VALUE - bufferedAEStackSize); + bufferedAEStack.incStackSize(amountToMerge); + amount -= amountToMerge; + + if (amount == 0) break; + } + } + + if (amount > 0) { + internalBuffer.add(wrapStack(stackToAdd, amount)); + } + } + + protected abstract @NotNull IWrappedStack wrapStack(@NotNull RealStackType stack, + long amount); + + @Override + public void addNotifiableMetaTileEntity(MetaTileEntity metaTileEntity) { + this.notifiableEntities.add(metaTileEntity); + } + + @Override + public void removeNotifiableMetaTileEntity(MetaTileEntity metaTileEntity) { + this.notifiableEntities.remove(metaTileEntity); + } + + protected void trigger() { + this.holder.markDirty(); + for (MetaTileEntity metaTileEntity : this.notifiableEntities) { + if (metaTileEntity != null && metaTileEntity.isValid()) { + this.addToNotifiedList(metaTileEntity, this, true); + } + } + } + } + + private static class WrappedStackSyncHandler, + RealStackType> extends SyncHandler { + + private final List<@NotNull IWrappedStack> source; + private final ObjectArrayList<@NotNull IWrappedStack> cache = new ObjectArrayList<>(); + private final IByteBufDeserializer<@NotNull IWrappedStack> deserializer; + private final IntSet changedIndexes = new IntOpenHashSet(); + @Nullable + private Runnable changeListener; + + public WrappedStackSyncHandler(@NotNull List> source, + @NotNull IByteBufDeserializer> deserializer) { + this.source = source; + this.deserializer = deserializer; + } + + @Override + public void detectAndSendChanges(boolean init) { + int sourceSize = source.size(); + boolean cacheSizeChange = cache.size() != sourceSize; + if (cacheSizeChange) { + cache.size(sourceSize); + } + + for (int index = 0; index < source.size(); index++) { + IWrappedStack newStack = source.get(index); + IWrappedStack cachedStack = cache.get(index); + + if (init || !newStack.delegateAndSizeEqual(cachedStack)) { + IWrappedStack copy = newStack.copyWrapped(); + changedIndexes.add(index); + cache.set(index, copy); + } + } + + if (!changedIndexes.isEmpty() || cacheSizeChange) { + syncToClient(0, buf -> { + buf.writeVarInt(cache.size()); + buf.writeVarInt(changedIndexes.size()); + + for (int index : changedIndexes) { + buf.writeVarInt(index); + cache.get(index).writeToPacketBuffer(buf); + } + }); + + onChange(); + changedIndexes.clear(); + } + } + + @Override + public void readOnClient(int id, PacketBuffer buf) throws IOException { + if (id != 0) return; + + cache.size(buf.readVarInt()); + int changed = buf.readVarInt(); + for (int ignore = 0; ignore < changed; ignore++) { + int index = buf.readVarInt(); + IWrappedStack newStack = deserializer.deserialize(buf); + cache.set(index, newStack); + } + + onChange(); + } + + @Override + public void readOnServer(int id, PacketBuffer buf) { + // This sync handler is Server -> Client only. + } + + public void setChangeListener(@NotNull Runnable listener) { + this.changeListener = listener; + } + + private void onChange() { + if (changeListener != null) { + changeListener.run(); + } + } + + public void cacheForEach(@NotNull Consumer<@NotNull IWrappedStack> consumer) { + for (IWrappedStack stack : cache) { + consumer.accept(stack); + } + } + } +} diff --git a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEOutputBus.java b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEOutputBus.java index de44e64b339..fb153560732 100644 --- a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEOutputBus.java +++ b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEOutputBus.java @@ -1,92 +1,49 @@ package gregtech.common.metatileentities.multi.multiblockpart.appeng; import gregtech.api.GTValues; -import gregtech.api.capability.GregtechDataCodes; -import gregtech.api.capability.GregtechTileCapabilities; -import gregtech.api.capability.INotifiableHandler; -import gregtech.api.gui.GuiTextures; -import gregtech.api.gui.ModularUI; import gregtech.api.metatileentity.MetaTileEntity; import gregtech.api.metatileentity.interfaces.IGregTechTileEntity; import gregtech.api.metatileentity.multiblock.*; +import gregtech.api.mui.drawable.GTObjectDrawable; +import gregtech.api.util.GTLog; +import gregtech.api.util.ItemStackHashStrategy; +import gregtech.api.util.KeyUtil; import gregtech.client.renderer.texture.Textures; -import gregtech.common.gui.widget.appeng.AEItemGridWidget; -import gregtech.common.inventory.appeng.SerializableItemList; +import gregtech.common.metatileentities.multi.multiblockpart.appeng.stack.IWrappedStack; +import gregtech.common.metatileentities.multi.multiblockpart.appeng.stack.WrappedItemStack; import net.minecraft.client.resources.I18n; -import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTBase; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; -import net.minecraft.network.PacketBuffer; -import net.minecraft.util.EnumFacing; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.TextFormatting; import net.minecraft.world.World; -import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.Constants; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; import net.minecraftforge.items.IItemHandlerModifiable; -import appeng.api.config.Actionable; -import appeng.api.storage.IMEMonitor; import appeng.api.storage.channels.IItemStorageChannel; import appeng.api.storage.data.IAEItemStack; -import appeng.api.storage.data.IItemList; -import appeng.util.item.AEItemStack; import codechicken.lib.render.CCRenderState; import codechicken.lib.render.pipeline.IVertexOperation; import codechicken.lib.vec.Matrix4; +import com.cleanroommc.modularui.api.drawable.IRichTextBuilder; +import com.cleanroommc.modularui.utils.serialization.IByteBufDeserializer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; import java.util.List; -public class MetaTileEntityMEOutputBus extends MetaTileEntityAEHostablePart +public class MetaTileEntityMEOutputBus extends MetaTileEntityMEOutputBase implements IMultiblockAbilityPart { public final static String ITEM_BUFFER_TAG = "ItemBuffer"; - public final static String WORKING_TAG = "WorkingEnabled"; - private boolean workingEnabled = true; - private SerializableItemList internalBuffer; public MetaTileEntityMEOutputBus(ResourceLocation metaTileEntityId) { - super(metaTileEntityId, GTValues.EV, true, IItemStorageChannel.class); - } - - @Override - protected void initializeInventory() { - this.internalBuffer = new SerializableItemList(); - super.initializeInventory(); - } - - @Override - public void update() { - super.update(); - if (!getWorld().isRemote && this.workingEnabled && this.shouldSyncME() && this.updateMEStatus()) { - if (this.internalBuffer.isEmpty()) return; - - IMEMonitor monitor = getMonitor(); - if (monitor == null) return; - - for (IAEItemStack item : this.internalBuffer) { - IAEItemStack notInserted = monitor.injectItems(item.copy(), Actionable.MODULATE, getActionSource()); - if (notInserted != null && notInserted.getStackSize() > 0) { - item.setStackSize(notInserted.getStackSize()); - } else { - item.reset(); - } - } - } - } - - @Override - public void onRemoval() { - IMEMonitor monitor = getMonitor(); - if (monitor != null) { - for (IAEItemStack item : this.internalBuffer) { - monitor.injectItems(item.copy(), Actionable.MODULATE, this.getActionSource()); - } - } - super.onRemoval(); + super(metaTileEntityId, GTValues.EV, IItemStorageChannel.class); } @Override @@ -95,72 +52,59 @@ public MetaTileEntity createMetaTileEntity(IGregTechTileEntity iGregTechTileEnti } @Override - protected ModularUI createUI(EntityPlayer entityPlayer) { - ModularUI.Builder builder = ModularUI - .builder(GuiTextures.BACKGROUND, 176, 18 + 18 * 4 + 94) - .label(10, 5, getMetaFullName()); - // ME Network status - builder.dynamicLabel(10, 15, () -> this.isOnline ? - I18n.format("gregtech.gui.me_network.online") : - I18n.format("gregtech.gui.me_network.offline"), - 0x404040); - builder.label(10, 25, "gregtech.gui.waiting_list", 0xFFFFFFFF); - builder.widget(new AEItemGridWidget(10, 35, 3, this.internalBuffer)); - - builder.bindPlayerInventory(entityPlayer.inventory, GuiTextures.SLOT, 7, 18 + 18 * 4 + 12); - return builder.build(this.getHolder(), entityPlayer); + protected @NotNull IByteBufDeserializer> getDeserializer() { + return WrappedItemStack::fromPacket; } + @SideOnly(Side.CLIENT) @Override - public boolean isWorkingEnabled() { - return this.workingEnabled; + protected void addStackLine(@NotNull IRichTextBuilder text, + @NotNull IWrappedStack wrappedStack) { + ItemStack stack = wrappedStack.getDefinition(); + text.add(new GTObjectDrawable(stack, 0) + .asIcon() + .asHoverable() + // Auto update has to be true for "Press CTRL for Advanced Info" to work + .tooltipAutoUpdate(true) + .tooltipBuilder(tooltip -> tooltip.addFromItem(stack))); + text.space(); + text.addLine(KeyUtil.number(TextFormatting.WHITE, wrappedStack.getStackSize(), "x")); } @Override - public void setWorkingEnabled(boolean workingEnabled) { - this.workingEnabled = workingEnabled; - World world = this.getWorld(); - if (world != null && !world.isRemote) { - writeCustomData(GregtechDataCodes.WORKING_ENABLED, buf -> buf.writeBoolean(workingEnabled)); - } - } + public NBTTagCompound writeToNBT(NBTTagCompound data) { + super.writeToNBT(data); - @Override - public T getCapability(Capability capability, EnumFacing side) { - if (capability == GregtechTileCapabilities.CAPABILITY_CONTROLLABLE) { - return GregtechTileCapabilities.CAPABILITY_CONTROLLABLE.cast(this); + NBTTagList nbtList = new NBTTagList(); + for (IWrappedStack stack : internalBuffer) { + NBTTagCompound stackTag = new NBTTagCompound(); + stack.writeToNBT(stackTag); + nbtList.appendTag(stackTag); } - return super.getCapability(capability, side); - } + data.setTag(ITEM_BUFFER_TAG, nbtList); - @Override - public void writeInitialSyncData(PacketBuffer buf) { - super.writeInitialSyncData(buf); - buf.writeBoolean(workingEnabled); - } - - @Override - public void receiveInitialSyncData(PacketBuffer buf) { - super.receiveInitialSyncData(buf); - this.workingEnabled = buf.readBoolean(); - } - - @Override - public NBTTagCompound writeToNBT(NBTTagCompound data) { - super.writeToNBT(data); - data.setBoolean(WORKING_TAG, this.workingEnabled); - data.setTag(ITEM_BUFFER_TAG, this.internalBuffer.serializeNBT()); return data; } @Override public void readFromNBT(NBTTagCompound data) { super.readFromNBT(data); - if (data.hasKey(WORKING_TAG)) { - this.workingEnabled = data.getBoolean(WORKING_TAG); - } - if (data.hasKey(ITEM_BUFFER_TAG, 9)) { - this.internalBuffer.deserializeNBT((NBTTagList) data.getTag(ITEM_BUFFER_TAG)); + for (NBTBase tag : data.getTagList(ITEM_BUFFER_TAG, Constants.NBT.TAG_COMPOUND)) { + NBTTagCompound tagCompound = (NBTTagCompound) tag; + + WrappedItemStack stack; + // Migrate from AEItemStacks to WrappedItemStacks + if (tagCompound.getBoolean("wrapped")) { + stack = WrappedItemStack.fromNBT(tagCompound); + } else { + stack = WrappedItemStack.fromItemStack(new ItemStack(tagCompound), tagCompound.getLong("Cnt")); + } + + if (stack == null) { + GTLog.logger.error("Error reading ME Output Hatch buffer tag list"); + } else { + internalBuffer.add(stack); + } } } @@ -168,7 +112,7 @@ public void readFromNBT(NBTTagCompound data) { public void renderMetaTileEntity(CCRenderState renderState, Matrix4 translation, IVertexOperation[] pipeline) { super.renderMetaTileEntity(renderState, translation, pipeline); if (this.shouldRenderOverlay()) { - if (isOnline) { + if (isOnline()) { Textures.ME_OUTPUT_BUS_ACTIVE.renderSided(getFrontFacing(), renderState, translation, pipeline); } else { Textures.ME_OUTPUT_BUS.renderSided(getFrontFacing(), renderState, translation, pipeline); @@ -200,28 +144,23 @@ public void registerAbilities(@NotNull AbilityInstances abilityInstances) { @Override public void addToMultiBlock(MultiblockControllerBase controllerBase) { super.addToMultiBlock(controllerBase); - if (controllerBase instanceof MultiblockWithDisplayBase) { - ((MultiblockWithDisplayBase) controllerBase).enableItemInfSink(); + if (controllerBase instanceof MultiblockWithDisplayBase multiblockWithDisplayBase) { + multiblockWithDisplayBase.enableItemInfSink(); } } - private static class InaccessibleInfiniteSlot implements IItemHandlerModifiable, INotifiableHandler { - - private final IItemList internalBuffer; - private final List notifiableEntities = new ArrayList<>(); - private final MetaTileEntity holder; + private static class InaccessibleInfiniteSlot extends InaccessibleInfiniteHandler + implements IItemHandlerModifiable { - public InaccessibleInfiniteSlot(MetaTileEntity holder, IItemList internalBuffer, - MetaTileEntity mte) { - this.holder = holder; - this.internalBuffer = internalBuffer; - this.notifiableEntities.add(mte); + public InaccessibleInfiniteSlot(@NotNull MetaTileEntity holder, + @NotNull List> internalBuffer, + @NotNull MetaTileEntity mte) { + super(holder, internalBuffer, mte, ItemStackHashStrategy.comparingAllButCount()); } @Override public void setStackInSlot(int slot, @NotNull ItemStack stack) { - this.internalBuffer.add(AEItemStack.fromItemStack(stack)); - this.holder.markDirty(); + insertItem(slot, stack, false); this.trigger(); } @@ -238,15 +177,16 @@ public ItemStack getStackInSlot(int slot) { @NotNull @Override - public ItemStack insertItem(int slot, @NotNull ItemStack stack, boolean simulate) { - if (stack.isEmpty()) { + public ItemStack insertItem(int slot, @NotNull ItemStack stackToInsert, boolean simulate) { + if (stackToInsert.isEmpty()) { return ItemStack.EMPTY; } + if (!simulate) { - this.internalBuffer.add(AEItemStack.fromItemStack(stack)); - this.holder.markDirty(); + add(stackToInsert, stackToInsert.getCount()); + this.trigger(); } - this.trigger(); + return ItemStack.EMPTY; } @@ -262,21 +202,8 @@ public int getSlotLimit(int slot) { } @Override - public void addNotifiableMetaTileEntity(MetaTileEntity metaTileEntity) { - this.notifiableEntities.add(metaTileEntity); - } - - @Override - public void removeNotifiableMetaTileEntity(MetaTileEntity metaTileEntity) { - this.notifiableEntities.remove(metaTileEntity); - } - - private void trigger() { - for (MetaTileEntity metaTileEntity : this.notifiableEntities) { - if (metaTileEntity != null && metaTileEntity.isValid()) { - this.addToNotifiedList(metaTileEntity, this, true); - } - } + protected @NotNull WrappedItemStack wrapStack(@NotNull ItemStack stack, long amount) { + return WrappedItemStack.fromItemStack(stack, amount); } } } diff --git a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEOutputHatch.java b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEOutputHatch.java index 77ba57bf656..476ea46e2c0 100644 --- a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEOutputHatch.java +++ b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEOutputHatch.java @@ -1,94 +1,52 @@ package gregtech.common.metatileentities.multi.multiblockpart.appeng; import gregtech.api.GTValues; -import gregtech.api.capability.GregtechDataCodes; -import gregtech.api.capability.GregtechTileCapabilities; -import gregtech.api.capability.INotifiableHandler; -import gregtech.api.gui.GuiTextures; -import gregtech.api.gui.ModularUI; import gregtech.api.metatileentity.MetaTileEntity; import gregtech.api.metatileentity.interfaces.IGregTechTileEntity; import gregtech.api.metatileentity.multiblock.*; +import gregtech.api.mui.drawable.GTObjectDrawable; +import gregtech.api.util.FluidStackHashStrategy; +import gregtech.api.util.FluidTooltipUtil; +import gregtech.api.util.GTLog; +import gregtech.api.util.KeyUtil; import gregtech.client.renderer.texture.Textures; -import gregtech.common.gui.widget.appeng.AEFluidGridWidget; -import gregtech.common.inventory.appeng.SerializableFluidList; +import gregtech.common.metatileentities.multi.multiblockpart.appeng.stack.IWrappedStack; +import gregtech.common.metatileentities.multi.multiblockpart.appeng.stack.WrappedFluidStack; import net.minecraft.client.resources.I18n; -import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTBase; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; -import net.minecraft.network.PacketBuffer; -import net.minecraft.util.EnumFacing; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.TextFormatting; import net.minecraft.world.World; -import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.Constants; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidTankInfo; import net.minecraftforge.fluids.IFluidTank; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; -import appeng.api.config.Actionable; -import appeng.api.storage.IMEMonitor; import appeng.api.storage.channels.IFluidStorageChannel; import appeng.api.storage.data.IAEFluidStack; -import appeng.api.storage.data.IItemList; -import appeng.fluids.util.AEFluidStack; import codechicken.lib.render.CCRenderState; import codechicken.lib.render.pipeline.IVertexOperation; import codechicken.lib.vec.Matrix4; +import com.cleanroommc.modularui.api.drawable.IRichTextBuilder; +import com.cleanroommc.modularui.utils.serialization.IByteBufDeserializer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; import java.util.List; -public class MetaTileEntityMEOutputHatch extends MetaTileEntityAEHostablePart +public class MetaTileEntityMEOutputHatch extends MetaTileEntityMEOutputBase implements IMultiblockAbilityPart { public final static String FLUID_BUFFER_TAG = "FluidBuffer"; - public final static String WORKING_TAG = "WorkingEnabled"; - private boolean workingEnabled = true; - private SerializableFluidList internalBuffer; public MetaTileEntityMEOutputHatch(ResourceLocation metaTileEntityId) { - super(metaTileEntityId, GTValues.EV, true, IFluidStorageChannel.class); - } - - @Override - protected void initializeInventory() { - this.internalBuffer = new SerializableFluidList(); - super.initializeInventory(); - } - - @Override - public void update() { - super.update(); - if (!getWorld().isRemote && this.workingEnabled && this.shouldSyncME() && updateMEStatus()) { - if (this.internalBuffer.isEmpty()) return; - - IMEMonitor monitor = getMonitor(); - if (monitor == null) return; - - for (IAEFluidStack fluid : this.internalBuffer) { - IAEFluidStack notInserted = monitor.injectItems(fluid.copy(), Actionable.MODULATE, getActionSource()); - if (notInserted != null && notInserted.getStackSize() > 0) { - fluid.setStackSize(notInserted.getStackSize()); - } else { - fluid.reset(); - } - } - } - } - - @Override - public void onRemoval() { - IMEMonitor monitor = getMonitor(); - if (monitor == null) return; - - for (IAEFluidStack fluid : this.internalBuffer) { - monitor.injectItems(fluid.copy(), Actionable.MODULATE, this.getActionSource()); - } - super.onRemoval(); + super(metaTileEntityId, GTValues.EV, IFluidStorageChannel.class); } @Override @@ -97,72 +55,61 @@ public MetaTileEntity createMetaTileEntity(IGregTechTileEntity iGregTechTileEnti } @Override - protected ModularUI createUI(EntityPlayer entityPlayer) { - ModularUI.Builder builder = ModularUI - .builder(GuiTextures.BACKGROUND, 176, 18 + 18 * 4 + 94) - .label(10, 5, getMetaFullName()); - // ME Network status - builder.dynamicLabel(10, 15, () -> this.isOnline ? - I18n.format("gregtech.gui.me_network.online") : - I18n.format("gregtech.gui.me_network.offline"), - 0x404040); - builder.label(10, 25, "gregtech.gui.waiting_list", 0xFFFFFFFF); - builder.widget(new AEFluidGridWidget(10, 35, 3, this.internalBuffer)); - - builder.bindPlayerInventory(entityPlayer.inventory, GuiTextures.SLOT, 7, 18 + 18 * 4 + 12); - return builder.build(this.getHolder(), entityPlayer); + protected @NotNull IByteBufDeserializer> getDeserializer() { + return WrappedFluidStack::fromPacket; } + @SideOnly(Side.CLIENT) @Override - public boolean isWorkingEnabled() { - return this.workingEnabled; + protected void addStackLine(@NotNull IRichTextBuilder text, + @NotNull IWrappedStack wrappedStack) { + FluidStack stack = wrappedStack.getDefinition(); + text.add(new GTObjectDrawable(stack, 0) + .asIcon() + .asHoverable() + .tooltip(tooltip -> { + tooltip.addLine(KeyUtil.fluid(stack)); + FluidTooltipUtil.handleFluidTooltip(tooltip, stack); + })); + text.space(); + text.addLine(KeyUtil.number(TextFormatting.WHITE, wrappedStack.getStackSize(), "L")); } @Override - public void setWorkingEnabled(boolean workingEnabled) { - this.workingEnabled = workingEnabled; - World world = this.getWorld(); - if (world != null && !world.isRemote) { - writeCustomData(GregtechDataCodes.WORKING_ENABLED, buf -> buf.writeBoolean(workingEnabled)); - } - } + public NBTTagCompound writeToNBT(NBTTagCompound data) { + super.writeToNBT(data); - @Override - public T getCapability(Capability capability, EnumFacing side) { - if (capability == GregtechTileCapabilities.CAPABILITY_CONTROLLABLE) { - return GregtechTileCapabilities.CAPABILITY_CONTROLLABLE.cast(this); + NBTTagList nbtList = new NBTTagList(); + for (IWrappedStack stack : internalBuffer) { + NBTTagCompound stackTag = new NBTTagCompound(); + stack.writeToNBT(stackTag); + nbtList.appendTag(stackTag); } - return super.getCapability(capability, side); - } - - @Override - public void writeInitialSyncData(PacketBuffer buf) { - super.writeInitialSyncData(buf); - buf.writeBoolean(workingEnabled); - } + data.setTag(FLUID_BUFFER_TAG, nbtList); - @Override - public void receiveInitialSyncData(PacketBuffer buf) { - super.receiveInitialSyncData(buf); - this.workingEnabled = buf.readBoolean(); - } - - @Override - public NBTTagCompound writeToNBT(NBTTagCompound data) { - super.writeToNBT(data); - data.setBoolean(WORKING_TAG, this.workingEnabled); - data.setTag(FLUID_BUFFER_TAG, this.internalBuffer.serializeNBT()); return data; } @Override public void readFromNBT(NBTTagCompound data) { super.readFromNBT(data); - if (data.hasKey(WORKING_TAG)) { - this.workingEnabled = data.getBoolean(WORKING_TAG); - } - if (data.hasKey(FLUID_BUFFER_TAG, 9)) { - this.internalBuffer.deserializeNBT((NBTTagList) data.getTag(FLUID_BUFFER_TAG)); + for (NBTBase tag : data.getTagList(FLUID_BUFFER_TAG, Constants.NBT.TAG_COMPOUND)) { + NBTTagCompound tagCompound = (NBTTagCompound) tag; + + WrappedFluidStack stack; + // Migrate from AEFluidStacks to WrappedFluidStacks + if (tagCompound.getBoolean("wrapped")) { + stack = WrappedFluidStack.fromNBT(tagCompound); + } else { + stack = WrappedFluidStack.fromFluidStack(FluidStack.loadFluidStackFromNBT(tagCompound), + data.getLong("Cnt")); + } + + if (stack == null) { + GTLog.logger.error("Error reading ME Output Hatch buffer tag list"); + } else { + internalBuffer.add(stack); + } } } @@ -170,7 +117,7 @@ public void readFromNBT(NBTTagCompound data) { public void renderMetaTileEntity(CCRenderState renderState, Matrix4 translation, IVertexOperation[] pipeline) { super.renderMetaTileEntity(renderState, translation, pipeline); if (this.shouldRenderOverlay()) { - if (isOnline) { + if (isOnline()) { Textures.ME_OUTPUT_HATCH_ACTIVE.renderSided(getFrontFacing(), renderState, translation, pipeline); } else { Textures.ME_OUTPUT_HATCH.renderSided(getFrontFacing(), renderState, translation, pipeline); @@ -202,22 +149,18 @@ public void registerAbilities(@NotNull AbilityInstances abilityInstances) { @Override public void addToMultiBlock(MultiblockControllerBase controllerBase) { super.addToMultiBlock(controllerBase); - if (controllerBase instanceof MultiblockWithDisplayBase) { - ((MultiblockWithDisplayBase) controllerBase).enableFluidInfSink(); + if (controllerBase instanceof MultiblockWithDisplayBase multiblockWithDisplayBase) { + multiblockWithDisplayBase.enableFluidInfSink(); } } - private static class InaccessibleInfiniteTank implements IFluidTank, INotifiableHandler { - - private final IItemList internalBuffer; - private final List notifiableEntities = new ArrayList<>(); - private final MetaTileEntity holder; + private static class InaccessibleInfiniteTank extends InaccessibleInfiniteHandler + implements IFluidTank { - public InaccessibleInfiniteTank(MetaTileEntity holder, IItemList internalBuffer, - MetaTileEntity mte) { - this.holder = holder; - this.internalBuffer = internalBuffer; - this.notifiableEntities.add(mte); + public InaccessibleInfiniteTank(@NotNull MetaTileEntity holder, + @NotNull List> internalBuffer, + @NotNull MetaTileEntity mte) { + super(holder, internalBuffer, mte, FluidStackHashStrategy.comparingAllButAmount()); } @Nullable @@ -242,16 +185,17 @@ public FluidTankInfo getInfo() { } @Override - public int fill(FluidStack resource, boolean doFill) { - if (resource == null) { + public int fill(@Nullable FluidStack stackToInsert, boolean doFill) { + if (stackToInsert == null || stackToInsert.amount < 1) { return 0; } + if (doFill) { - this.internalBuffer.add(AEFluidStack.fromFluidStack(resource)); - holder.markDirty(); + add(stackToInsert, stackToInsert.amount); + this.trigger(); } - this.trigger(); - return resource.amount; + + return stackToInsert.amount; } @Nullable @@ -261,21 +205,8 @@ public FluidStack drain(int maxDrain, boolean doDrain) { } @Override - public void addNotifiableMetaTileEntity(MetaTileEntity metaTileEntity) { - this.notifiableEntities.add(metaTileEntity); - } - - @Override - public void removeNotifiableMetaTileEntity(MetaTileEntity metaTileEntity) { - this.notifiableEntities.remove(metaTileEntity); - } - - private void trigger() { - for (MetaTileEntity metaTileEntity : this.notifiableEntities) { - if (metaTileEntity != null && metaTileEntity.isValid()) { - this.addToNotifiedList(metaTileEntity, this, true); - } - } + protected @NotNull IWrappedStack wrapStack(@NotNull FluidStack stack, long amount) { + return WrappedFluidStack.fromFluidStack(stack, amount); } } } diff --git a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEStockingBus.java b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEStockingBus.java index 5233602bdca..796462099bb 100644 --- a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEStockingBus.java +++ b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEStockingBus.java @@ -1,16 +1,15 @@ package gregtech.common.metatileentities.multi.multiblockpart.appeng; -import gregtech.api.GTValues; -import gregtech.api.gui.GuiTextures; -import gregtech.api.gui.ModularUI; -import gregtech.api.gui.widgets.ImageCycleButtonWidget; +import gregtech.api.capability.impl.ItemHandlerList; import gregtech.api.metatileentity.MetaTileEntity; import gregtech.api.metatileentity.interfaces.IGregTechTileEntity; import gregtech.api.metatileentity.multiblock.MultiblockAbility; import gregtech.api.metatileentity.multiblock.MultiblockControllerBase; import gregtech.api.metatileentity.multiblock.RecipeMapMultiblockController; +import gregtech.api.mui.GTGuiTextures; import gregtech.common.metatileentities.multi.multiblockpart.appeng.slot.ExportOnlyAEItemList; import gregtech.common.metatileentities.multi.multiblockpart.appeng.slot.ExportOnlyAEItemSlot; +import gregtech.common.metatileentities.multi.multiblockpart.appeng.slot.IConfigurableSlot; import gregtech.common.metatileentities.multi.multiblockpart.appeng.stack.WrappedItemStack; import net.minecraft.client.resources.I18n; @@ -23,14 +22,26 @@ import net.minecraft.util.ResourceLocation; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.world.World; +import net.minecraftforge.items.IItemHandler; import appeng.api.config.Actionable; import appeng.api.storage.IMEMonitor; import appeng.api.storage.data.IAEItemStack; import appeng.api.storage.data.IItemList; import codechicken.lib.raytracer.CuboidRayTraceResult; +import com.cleanroommc.modularui.api.IPanelHandler; +import com.cleanroommc.modularui.api.drawable.IKey; +import com.cleanroommc.modularui.factory.PosGuiData; +import com.cleanroommc.modularui.screen.ModularPanel; +import com.cleanroommc.modularui.value.sync.BooleanSyncValue; +import com.cleanroommc.modularui.value.sync.IntSyncValue; +import com.cleanroommc.modularui.value.sync.PanelSyncManager; +import com.cleanroommc.modularui.widget.Widget; +import com.cleanroommc.modularui.widgets.ToggleButton; +import com.cleanroommc.modularui.widgets.textfield.TextFieldWidget; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.Range; import java.util.List; import java.util.function.Predicate; @@ -39,50 +50,60 @@ public class MetaTileEntityMEStockingBus extends MetaTileEntityMEInputBus { + private static final String MINIMUM_STOCK_TAG = "MinimumStackSize"; + private static final int CONFIG_SIZE = 16; private boolean autoPull; private Predicate autoPullTest; + private int minimumStackSize = 0; - public MetaTileEntityMEStockingBus(ResourceLocation metaTileEntityId) { - super(metaTileEntityId, GTValues.IV); + public MetaTileEntityMEStockingBus(ResourceLocation metaTileEntityId, int tier) { + super(metaTileEntityId, tier); this.autoPullTest = $ -> false; } @Override public MetaTileEntity createMetaTileEntity(IGregTechTileEntity iGregTechTileEntity) { - return new MetaTileEntityMEStockingBus(metaTileEntityId); + return new MetaTileEntityMEStockingBus(metaTileEntityId, getTier()); } @Override - protected ExportOnlyAEStockingItemList getAEItemHandler() { - if (this.aeItemHandler == null) { - this.aeItemHandler = new ExportOnlyAEStockingItemList(this, CONFIG_SIZE, getController()); - } - return (ExportOnlyAEStockingItemList) this.aeItemHandler; + protected @NotNull ExportOnlyAEStockingItemList initializeAEHandler() { + return new ExportOnlyAEStockingItemList(this, CONFIG_SIZE, getController()); + } + + @Override + @NotNull + protected ExportOnlyAEStockingItemList getAEHandler() { + return (ExportOnlyAEStockingItemList) aeHandler; } @Override public void update() { super.update(); if (!getWorld().isRemote) { - if (isWorkingEnabled() && autoPull && getOffsetTimer() % 100 == 0) { - refreshList(); - syncME(); - } - // Immediately clear cached items if the status changed, to prevent running recipes while offline - if (this.meStatusChanged && !this.isOnline) { + if (this.meStatusChanged && !isOnline()) { if (autoPull) { clearInventory(0); } else { for (int i = 0; i < CONFIG_SIZE; i++) { - getAEItemHandler().getInventory()[i].setStack(null); + getAEHandler().getInventory()[i].setStack(null); } } } } } + @Override + protected void operateOnME() { + if (autoPull) { + refreshList(); + } + + syncME(); + } + // Update the visual display for the fake items. This also is important for the item handler's // getStackInSlot() method, as it uses the cached items set here. @Override @@ -90,7 +111,7 @@ protected void syncME() { IMEMonitor monitor = super.getMonitor(); if (monitor == null) return; - for (ExportOnlyAEStockingItemSlot slot : this.getAEItemHandler().getInventory()) { + for (ExportOnlyAEStockingItemSlot slot : this.getAEHandler().getInventory()) { if (slot.getConfig() == null) { slot.setStack(null); } else { @@ -101,7 +122,7 @@ protected void syncME() { } else { request = slot.getConfig().copy(); } - request.setStackSize(Integer.MAX_VALUE); + request.setStackSize(Long.MAX_VALUE); IAEItemStack result = monitor.extractItems(request, Actionable.SIMULATE, getActionSource()); slot.setStack(result); } @@ -129,7 +150,7 @@ public void removeFromMultiBlock(MultiblockControllerBase controllerBase) { this.autoPullTest = $ -> false; if (this.autoPull) { // may as well clear if we are auto-pull, no reason to preserve the config - this.getAEItemHandler().clearConfig(); + this.getAEHandler().clearConfig(); } super.removeFromMultiBlock(controllerBase); } @@ -149,7 +170,7 @@ public void onDistinctChange(boolean newValue) { * we are attached to. Prevents dupes in certain situations. */ private void validateConfig() { - for (var slot : this.getAEItemHandler().getInventory()) { + for (var slot : this.getAEHandler().getInventory()) { if (slot.getConfig() != null) { ItemStack configuredStack = slot.getConfig().createItemStack(); if (testConfiguredInOtherBus(configuredStack)) { @@ -163,7 +184,7 @@ private void validateConfig() { /** * @return True if the passed stack is found as a configuration in any other stocking buses on the multiblock. */ - private boolean testConfiguredInOtherBus(ItemStack stack) { + private boolean testConfiguredInOtherBus(@Nullable ItemStack stack) { if (stack == null || stack.isEmpty()) return false; MultiblockControllerBase controller = getController(); if (controller == null) return false; @@ -174,15 +195,27 @@ private boolean testConfiguredInOtherBus(ItemStack stack) { // in any stocking bus in the multi (besides ourselves). var abilityList = controller.getAbilities(MultiblockAbility.IMPORT_ITEMS); for (var ability : abilityList) { - if (ability instanceof ExportOnlyAEStockingItemList aeList) { - // We don't need to check for ourselves, as this case is handled elsewhere. - if (aeList == this.aeItemHandler) continue; - if (aeList.hasStackInConfig(stack, false)) { - return true; + if (ability instanceof ItemHandlerList itemHandlerList) { + for (var handler : itemHandlerList.getBackingHandlers()) { + if (checkHandler(handler, stack)) { + return true; + } } + } else if (checkHandler(ability, stack)) { + return true; } } } + + return false; + } + + private boolean checkHandler(@NotNull IItemHandler itemHandler, @NotNull ItemStack stack) { + if (itemHandler instanceof ExportOnlyAEStockingItemList itemList) { + if (itemList == this.aeHandler) return false; + return itemList.hasStackInConfig(stack, false); + } + return false; } @@ -191,9 +224,9 @@ private void setAutoPull(boolean autoPull) { markDirty(); if (!getWorld().isRemote) { if (!this.autoPull) { - this.getAEItemHandler().clearConfig(); + this.getAEHandler().clearConfig(); } else if (updateMEStatus()) { - this.refreshList(); + refreshList(); syncME(); } writeCustomData(UPDATE_AUTO_PULL, buf -> buf.writeBoolean(this.autoPull)); @@ -220,7 +253,7 @@ private void refreshList() { int index = 0; for (IAEItemStack stack : storageList) { if (index >= CONFIG_SIZE) break; - if (stack.getStackSize() == 0) continue; + if (stack.getStackSize() == 0 || stack.getStackSize() < minimumStackSize) continue; stack = monitor.extractItems(stack, Actionable.SIMULATE, getActionSource()); if (stack == null || stack.getStackSize() == 0) continue; @@ -231,7 +264,7 @@ private void refreshList() { IAEItemStack selectedStack = WrappedItemStack.fromItemStack(itemStack); if (selectedStack == null) continue; IAEItemStack configStack = selectedStack.copy().setStackSize(1); - var slot = this.getAEItemHandler().getInventory()[index]; + var slot = this.getAEHandler().getInventory()[index]; slot.setConfig(configStack); slot.setStack(selectedStack); index++; @@ -242,7 +275,7 @@ private void refreshList() { private void clearInventory(int startIndex) { for (int i = startIndex; i < CONFIG_SIZE; i++) { - var slot = this.getAEItemHandler().getInventory()[i]; + var slot = this.getAEHandler().getInventory()[i]; slot.setConfig(null); slot.setStack(null); } @@ -257,11 +290,55 @@ public void receiveCustomData(int dataId, PacketBuffer buf) { } @Override - protected ModularUI.Builder createUITemplate(EntityPlayer player) { - ModularUI.Builder builder = super.createUITemplate(player); - builder.widget(new ImageCycleButtonWidget(7 + 18 * 4 + 1, 26, 16, 16, GuiTextures.BUTTON_AUTO_PULL, - () -> autoPull, this::setAutoPull).setTooltipHoverString("gregtech.gui.me_bus.auto_pull_button")); - return builder; + protected ModularPanel buildSettingsPopup(PanelSyncManager syncManager, IPanelHandler syncHandler) { + return super.buildSettingsPopup(syncManager, syncHandler) + .child(IKey.lang("gregtech.machine.me.settings.minimum") + .asWidget() + .left(5) + .top(5 + 18 + 18 + 8)) + .child(new TextFieldWidget() + .left(5) + .top(15 + 18 + 18 + 8) + .size(100, 10) + .setNumbers(0, Integer.MAX_VALUE) + .setDefaultNumber(0) + .value(new IntSyncValue(this::getMinimumStackSize, this::setMinimumStackSize))); + } + + @Override + protected int getSettingsPopupHeight() { + return super.getSettingsPopupHeight() + 20 + 7; + } + + @Override + protected @NotNull Widget createMainColumnWidget(@Range(from = 0, to = 3) int index, @NotNull PosGuiData guiData, + @NotNull PanelSyncManager panelSyncManager) { + if (index == 0) { + return new ToggleButton() + .size(16) + .margin(1) + .value(new BooleanSyncValue(this::isAutoPull, this::setAutoPull)) + .disableHoverBackground() + .overlay(false, GTGuiTextures.AUTO_PULL[0]) + .overlay(true, GTGuiTextures.AUTO_PULL[1]) + .addTooltip(false, IKey.lang("gregtech.machine.me.stocking_auto_pull_disabled")) + .addTooltip(true, IKey.lang("gregtech.machine.me.stocking_auto_pull_enabled")); + } + + return super.createMainColumnWidget(index, guiData, panelSyncManager); + } + + public void setMinimumStackSize(int minimumStackSize) { + this.minimumStackSize = minimumStackSize; + if (!getWorld().isRemote) { + markDirty(); + refreshList(); + syncME(); + } + } + + public int getMinimumStackSize() { + return minimumStackSize; } @Override @@ -283,7 +360,8 @@ public boolean onScrewdriverClick(EntityPlayer playerIn, EnumHand hand, EnumFaci @Override public NBTTagCompound writeToNBT(NBTTagCompound data) { super.writeToNBT(data); - data.setBoolean("AutoPull", autoPull); + data.setBoolean("AutoPull", this.autoPull); + data.setInteger(MINIMUM_STOCK_TAG, this.minimumStackSize); return data; } @@ -291,12 +369,16 @@ public NBTTagCompound writeToNBT(NBTTagCompound data) { public void readFromNBT(NBTTagCompound data) { super.readFromNBT(data); this.autoPull = data.getBoolean("AutoPull"); + + if (data.hasKey(MINIMUM_STOCK_TAG)) { + this.minimumStackSize = data.getInteger(MINIMUM_STOCK_TAG); + } } @Override public void writeInitialSyncData(PacketBuffer buf) { super.writeInitialSyncData(buf); - buf.writeBoolean(autoPull); + buf.writeBoolean(this.autoPull); } @Override @@ -305,7 +387,7 @@ public void receiveInitialSyncData(PacketBuffer buf) { this.autoPull = buf.readBoolean(); } - private static class ExportOnlyAEStockingItemSlot extends ExportOnlyAEItemSlot { + public static class ExportOnlyAEStockingItemSlot extends ExportOnlyAEItemSlot { private final MetaTileEntityMEStockingBus holder; @@ -321,7 +403,7 @@ public ExportOnlyAEStockingItemSlot(MetaTileEntityMEStockingBus holder) { } @Override - public ExportOnlyAEStockingItemSlot copy() { + public @NotNull IConfigurableSlot copy() { return new ExportOnlyAEStockingItemSlot( this.config == null ? null : this.config.copy(), this.stock == null ? null : this.stock.copy(), @@ -330,37 +412,38 @@ public ExportOnlyAEStockingItemSlot copy() { @Override public @NotNull ItemStack extractItem(int slot, int amount, boolean simulate) { - if (slot == 0 && this.stock != null) { - if (this.config != null) { - // Extract the items from the real net to either validate (simulate) - // or extract (modulate) when this is called - IMEMonitor monitor = holder.getMonitor(); - if (monitor == null) return ItemStack.EMPTY; - - Actionable action = simulate ? Actionable.SIMULATE : Actionable.MODULATE; - IAEItemStack request; - if (this.config instanceof WrappedItemStack wis) { - request = wis.getAEStack(); - } else { - request = this.config.copy(); + if (slot != 0 || this.stock == null || this.stock.getStackSize() <= 0) return ItemStack.EMPTY; + + if (this.config != null) { + // Extract the items from the real net to either validate (simulate) + // or extract (modulate) when this is called + IMEMonitor monitor = holder.getMonitor(); + if (monitor == null) return ItemStack.EMPTY; + + Actionable action = simulate ? Actionable.SIMULATE : Actionable.MODULATE; + IAEItemStack request; + if (this.config instanceof WrappedItemStack wis) { + request = wis.getAEStack(); + } else { + request = this.config.copy(); + } + request.setStackSize(amount); + + IAEItemStack result = monitor.extractItems(request, action, holder.getActionSource()); + if (result != null) { + int extracted = (int) Math.min(result.getStackSize(), amount); + this.stock.decStackSize(extracted); // may as well update the display here + if (this.trigger != null) { + this.trigger.accept(0); } - request.setStackSize(amount); - - IAEItemStack result = monitor.extractItems(request, action, holder.getActionSource()); - if (result != null) { - int extracted = (int) Math.min(result.getStackSize(), amount); - this.stock.decStackSize(extracted); // may as well update the display here - if (this.trigger != null) { - this.trigger.accept(0); - } - if (extracted != 0) { - ItemStack resultStack = this.config.createItemStack(); - resultStack.setCount(extracted); - return resultStack; - } + if (extracted != 0) { + ItemStack resultStack = this.config.createItemStack(); + resultStack.setCount(extracted); + return resultStack; } } } + return ItemStack.EMPTY; } } @@ -388,6 +471,9 @@ protected NBTTagCompound writeConfigToTag() { NBTTagCompound tag = new NBTTagCompound(); tag.setBoolean("AutoPull", true); tag.setByte("GhostCircuit", (byte) this.circuitInventory.getCircuitValue()); + + tag.setInteger(MINIMUM_STOCK_TAG, this.minimumStackSize); + return tag; } @@ -401,10 +487,15 @@ protected void readConfigFromTag(NBTTagCompound tag) { } // set auto pull first to avoid issues with clearing the config after reading from the data stick this.setAutoPull(false); + + if (tag.hasKey(MINIMUM_STOCK_TAG)) { + this.minimumStackSize = tag.getInteger(MINIMUM_STOCK_TAG); + } + super.readConfigFromTag(tag); } - private static class ExportOnlyAEStockingItemList extends ExportOnlyAEItemList { + public static class ExportOnlyAEStockingItemList extends ExportOnlyAEItemList { private final MetaTileEntityMEStockingBus holder; @@ -429,7 +520,7 @@ protected void createInventory(MetaTileEntity holder) { } @Override - public ExportOnlyAEStockingItemSlot[] getInventory() { + public @NotNull ExportOnlyAEStockingItemSlot @NotNull [] getInventory() { return (ExportOnlyAEStockingItemSlot[]) super.getInventory(); } diff --git a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEStockingHatch.java b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEStockingHatch.java index eb67268d326..0a2e35d57a8 100644 --- a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEStockingHatch.java +++ b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/MetaTileEntityMEStockingHatch.java @@ -1,15 +1,13 @@ package gregtech.common.metatileentities.multi.multiblockpart.appeng; -import gregtech.api.GTValues; -import gregtech.api.gui.GuiTextures; -import gregtech.api.gui.ModularUI; -import gregtech.api.gui.widgets.ImageCycleButtonWidget; import gregtech.api.metatileentity.MetaTileEntity; import gregtech.api.metatileentity.interfaces.IGregTechTileEntity; import gregtech.api.metatileentity.multiblock.MultiblockAbility; import gregtech.api.metatileentity.multiblock.MultiblockControllerBase; +import gregtech.api.mui.GTGuiTextures; import gregtech.common.metatileentities.multi.multiblockpart.appeng.slot.ExportOnlyAEFluidList; import gregtech.common.metatileentities.multi.multiblockpart.appeng.slot.ExportOnlyAEFluidSlot; +import gregtech.common.metatileentities.multi.multiblockpart.appeng.slot.IConfigurableSlot; import gregtech.common.metatileentities.multi.multiblockpart.appeng.stack.WrappedFluidStack; import net.minecraft.client.resources.I18n; @@ -29,8 +27,19 @@ import appeng.api.storage.data.IAEFluidStack; import appeng.api.storage.data.IItemList; import codechicken.lib.raytracer.CuboidRayTraceResult; +import com.cleanroommc.modularui.api.IPanelHandler; +import com.cleanroommc.modularui.api.drawable.IKey; +import com.cleanroommc.modularui.factory.PosGuiData; +import com.cleanroommc.modularui.screen.ModularPanel; +import com.cleanroommc.modularui.value.sync.BooleanSyncValue; +import com.cleanroommc.modularui.value.sync.IntSyncValue; +import com.cleanroommc.modularui.value.sync.PanelSyncManager; +import com.cleanroommc.modularui.widget.Widget; +import com.cleanroommc.modularui.widgets.ToggleButton; +import com.cleanroommc.modularui.widgets.textfield.TextFieldWidget; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.Range; import java.util.List; import java.util.function.Predicate; @@ -39,56 +48,66 @@ public class MetaTileEntityMEStockingHatch extends MetaTileEntityMEInputHatch { + private static final String MINIMUM_STOCK_TAG = "MinimumStackSize"; + private static final int CONFIG_SIZE = 16; private boolean autoPull; private Predicate autoPullTest; + private int minimumStackSize = 0; - public MetaTileEntityMEStockingHatch(ResourceLocation metaTileEntityId) { - super(metaTileEntityId, GTValues.IV); + public MetaTileEntityMEStockingHatch(ResourceLocation metaTileEntityId, int tier) { + super(metaTileEntityId, tier); this.autoPullTest = $ -> false; } @Override public MetaTileEntity createMetaTileEntity(IGregTechTileEntity iGregTechTileEntity) { - return new MetaTileEntityMEStockingHatch(metaTileEntityId); + return new MetaTileEntityMEStockingHatch(metaTileEntityId, getTier()); } @Override - protected ExportOnlyAEStockingFluidList getAEFluidHandler() { - if (this.aeFluidHandler == null) { - this.aeFluidHandler = new ExportOnlyAEStockingFluidList(this, CONFIG_SIZE, getController()); - } - return (ExportOnlyAEStockingFluidList) this.aeFluidHandler; + protected @NotNull ExportOnlyAEStockingFluidList initializeAEHandler() { + return new ExportOnlyAEStockingFluidList(this, CONFIG_SIZE, getController()); + } + + @Override + @NotNull + protected ExportOnlyAEStockingFluidList getAEHandler() { + return (ExportOnlyAEStockingFluidList) this.aeHandler; } @Override public void update() { super.update(); if (!getWorld().isRemote) { - if (isWorkingEnabled() && autoPull && getOffsetTimer() % 100 == 0) { - refreshList(); - syncME(); - } - // Immediately clear cached fluids if the status changed, to prevent running recipes while offline - if (this.meStatusChanged && !this.isOnline) { + if (this.meStatusChanged && !isOnline()) { if (autoPull) { - this.getAEFluidHandler().clearConfig(); + this.getAEHandler().clearConfig(); } else { for (int i = 0; i < CONFIG_SIZE; i++) { - getAEFluidHandler().getInventory()[i].setStack(null); + getAEHandler().getInventory()[i].setStack(null); } } } } } + @Override + protected void operateOnME() { + if (autoPull) { + refreshList(); + } + + syncME(); + } + @Override protected void syncME() { IMEMonitor monitor = super.getMonitor(); if (monitor == null) return; - for (ExportOnlyAEStockingFluidSlot slot : this.getAEFluidHandler().getInventory()) { + for (ExportOnlyAEStockingFluidSlot slot : this.getAEHandler().getInventory()) { if (slot.getConfig() == null) { slot.setStack(null); } else { @@ -99,7 +118,7 @@ protected void syncME() { } else { request = slot.getConfig().copy(); } - request.setStackSize(Integer.MAX_VALUE); + request.setStackSize(Long.MAX_VALUE); IAEFluidStack result = monitor.extractItems(request, Actionable.SIMULATE, getActionSource()); slot.setStack(result); } @@ -122,13 +141,13 @@ public void addToMultiBlock(MultiblockControllerBase controllerBase) { public void removeFromMultiBlock(MultiblockControllerBase controllerBase) { this.autoPullTest = $ -> false; if (this.autoPull) { - this.getAEFluidHandler().clearConfig(); + this.getAEHandler().clearConfig(); } super.removeFromMultiBlock(controllerBase); } private void validateConfig() { - for (var slot : this.getAEFluidHandler().getInventory()) { + for (var slot : this.getAEHandler().getInventory()) { if (slot.getConfig() != null) { FluidStack configuredStack = slot.getConfig().getFluidStack(); if (testConfiguredInOtherHatch(configuredStack)) { @@ -148,12 +167,13 @@ private boolean testConfiguredInOtherHatch(FluidStack stack) { for (var ability : abilityList) { if (ability instanceof ExportOnlyAEStockingFluidSlot aeSlot) { if (aeSlot.getConfig() == null) continue; - if (getAEFluidHandler().ownsSlot(aeSlot)) continue; + if (getAEHandler().ownsSlot(aeSlot)) continue; if (aeSlot.getConfig().getFluid().equals(stack.getFluid())) { return true; } } } + return false; } @@ -162,9 +182,9 @@ private void setAutoPull(boolean autoPull) { markDirty(); if (!getWorld().isRemote) { if (!this.autoPull) { - this.getAEFluidHandler().clearConfig(); + this.getAEHandler().clearConfig(); } else if (updateMEStatus()) { - this.refreshList(); + refreshList(); syncME(); } writeCustomData(UPDATE_AUTO_PULL, buf -> buf.writeBoolean(this.autoPull)); @@ -187,7 +207,7 @@ private void refreshList() { int index = 0; for (IAEFluidStack stack : storageList) { if (index >= CONFIG_SIZE) break; - if (stack.getStackSize() == 0) continue; + if (stack.getStackSize() == 0 || stack.getStackSize() < minimumStackSize) continue; stack = monitor.extractItems(stack, Actionable.SIMULATE, getActionSource()); if (stack == null || stack.getStackSize() == 0) continue; @@ -196,7 +216,7 @@ private void refreshList() { if (autoPullTest != null && !autoPullTest.test(fluidStack)) continue; IAEFluidStack selectedStack = WrappedFluidStack.fromFluidStack(fluidStack); IAEFluidStack configStack = selectedStack.copy().setStackSize(1); - var slot = this.getAEFluidHandler().getInventory()[index]; + var slot = this.getAEHandler().getInventory()[index]; slot.setConfig(configStack); slot.setStack(selectedStack); index++; @@ -207,7 +227,7 @@ private void refreshList() { private void clearInventory(int startIndex) { for (int i = startIndex; i < CONFIG_SIZE; i++) { - var slot = this.getAEFluidHandler().getInventory()[i]; + var slot = this.getAEHandler().getInventory()[i]; slot.setConfig(null); slot.setStack(null); } @@ -222,11 +242,57 @@ public void receiveCustomData(int dataId, PacketBuffer buf) { } @Override - protected ModularUI.Builder createUITemplate(EntityPlayer player) { - ModularUI.Builder builder = super.createUITemplate(player); - builder.widget(new ImageCycleButtonWidget(7 + 18 * 4 + 1, 26, 16, 16, GuiTextures.BUTTON_AUTO_PULL, - () -> autoPull, this::setAutoPull).setTooltipHoverString("gregtech.gui.me_bus.auto_pull_button")); - return builder; + protected ModularPanel buildSettingsPopup(PanelSyncManager syncManager, IPanelHandler syncHandler) { + IntSyncValue minimumStockSync = new IntSyncValue(this::getMinimumStackSize, this::setMinimumStackSize); + + return super.buildSettingsPopup(syncManager, syncHandler) + .child(IKey.lang("gregtech.machine.me.settings.minimum") + .asWidget() + .left(5) + .top(5 + 18 + 18 + 8)) + .child(new TextFieldWidget() + .left(5) + .top(15 + 18 + 18 + 8) + .size(100, 10) + .setNumbers(0, Integer.MAX_VALUE) + .setDefaultNumber(0) + .value(minimumStockSync)); + } + + @Override + protected int getSettingsPopupHeight() { + return super.getSettingsPopupHeight() + 20 + 7; + } + + @Override + protected @NotNull Widget createMainColumnWidget(@Range(from = 0, to = 3) int index, @NotNull PosGuiData guiData, + @NotNull PanelSyncManager panelSyncManager) { + if (index == 0) { + return new ToggleButton() + .size(16) + .margin(1) + .value(new BooleanSyncValue(this::isAutoPull, this::setAutoPull)) + .disableHoverBackground() + .overlay(false, GTGuiTextures.AUTO_PULL[0]) + .overlay(true, GTGuiTextures.AUTO_PULL[1]) + .addTooltip(false, IKey.lang("gregtech.machine.me.stocking_auto_pull_disabled")) + .addTooltip(true, IKey.lang("gregtech.machine.me.stocking_auto_pull_enabled")); + } + + return super.createMainColumnWidget(index, guiData, panelSyncManager); + } + + public void setMinimumStackSize(int minimumStackSize) { + this.minimumStackSize = minimumStackSize; + if (!getWorld().isRemote) { + markDirty(); + refreshList(); + syncME(); + } + } + + public int getMinimumStackSize() { + return minimumStackSize; } @Override @@ -248,7 +314,8 @@ public boolean onScrewdriverClick(EntityPlayer playerIn, EnumHand hand, EnumFaci @Override public NBTTagCompound writeToNBT(NBTTagCompound data) { super.writeToNBT(data); - data.setBoolean("AutoPull", autoPull); + data.setBoolean("AutoPull", this.autoPull); + data.setInteger(MINIMUM_STOCK_TAG, this.minimumStackSize); return data; } @@ -256,18 +323,24 @@ public NBTTagCompound writeToNBT(NBTTagCompound data) { public void readFromNBT(NBTTagCompound data) { super.readFromNBT(data); this.autoPull = data.getBoolean("AutoPull"); + + if (data.hasKey(MINIMUM_STOCK_TAG)) { + this.minimumStackSize = data.getInteger(MINIMUM_STOCK_TAG); + } } @Override public void writeInitialSyncData(PacketBuffer buf) { super.writeInitialSyncData(buf); - buf.writeBoolean(autoPull); + buf.writeBoolean(this.autoPull); + buf.writeVarInt(this.minimumStackSize); } @Override public void receiveInitialSyncData(PacketBuffer buf) { super.receiveInitialSyncData(buf); this.autoPull = buf.readBoolean(); + this.minimumStackSize = buf.readVarInt(); } @Override @@ -289,9 +362,12 @@ protected NBTTagCompound writeConfigToTag() { tag.setBoolean("AutoPull", false); return tag; } - // if in auto-pull, no need to write actual configured slots, but still need to write the ghost circuit + // if in auto-pull, no need to write actual configured slots NBTTagCompound tag = new NBTTagCompound(); tag.setBoolean("AutoPull", true); + + tag.setInteger(MINIMUM_STOCK_TAG, this.minimumStackSize); + return tag; } @@ -304,10 +380,15 @@ protected void readConfigFromTag(NBTTagCompound tag) { } // set auto pull first to avoid issues with clearing the config after reading from the data stick this.setAutoPull(false); + + if (tag.hasKey(MINIMUM_STOCK_TAG)) { + this.minimumStackSize = tag.getInteger(MINIMUM_STOCK_TAG); + } + super.readConfigFromTag(tag); } - private static class ExportOnlyAEStockingFluidSlot extends ExportOnlyAEFluidSlot { + public static class ExportOnlyAEStockingFluidSlot extends ExportOnlyAEFluidSlot { public ExportOnlyAEStockingFluidSlot(MetaTileEntityMEStockingHatch holder, IAEFluidStack config, IAEFluidStack stock, MetaTileEntity entityToNotify) { @@ -324,7 +405,7 @@ protected MetaTileEntityMEStockingHatch getHolder() { } @Override - public ExportOnlyAEFluidSlot copy() { + public @NotNull IConfigurableSlot copy() { return new ExportOnlyAEStockingFluidSlot( this.getHolder(), this.config == null ? null : this.config.copy(), @@ -334,9 +415,10 @@ public ExportOnlyAEFluidSlot copy() { @Override public @Nullable FluidStack drain(int maxDrain, boolean doDrain) { - if (this.stock == null) { + if (this.stock == null || this.stock.getStackSize() <= 0) { return null; } + if (this.config != null) { IMEMonitor monitor = getHolder().getMonitor(); if (monitor == null) return null; @@ -366,7 +448,7 @@ public ExportOnlyAEFluidSlot copy() { } } - private static class ExportOnlyAEStockingFluidList extends ExportOnlyAEFluidList { + public static class ExportOnlyAEStockingFluidList extends ExportOnlyAEFluidList { private final MetaTileEntityMEStockingHatch holder; @@ -388,7 +470,7 @@ protected void createInventory(MetaTileEntity holder, MetaTileEntity entityToNot } @Override - public ExportOnlyAEStockingFluidSlot[] getInventory() { + public @NotNull ExportOnlyAEStockingFluidSlot @NotNull [] getInventory() { return (ExportOnlyAEStockingFluidSlot[]) super.getInventory(); } diff --git a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/slot/ExportOnlyAEFluidList.java b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/slot/ExportOnlyAEFluidList.java index fd4b40ea7e5..600e9372d6b 100644 --- a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/slot/ExportOnlyAEFluidList.java +++ b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/slot/ExportOnlyAEFluidList.java @@ -5,8 +5,9 @@ import net.minecraftforge.fluids.FluidStack; import appeng.api.storage.data.IAEFluidStack; +import org.jetbrains.annotations.NotNull; -public class ExportOnlyAEFluidList { +public class ExportOnlyAEFluidList implements IExportOnlyAEStackList { protected final int size; protected ExportOnlyAEFluidSlot[] inventory; @@ -23,7 +24,7 @@ protected void createInventory(MetaTileEntity holder, MetaTileEntity entityToNot } } - public ExportOnlyAEFluidSlot[] getInventory() { + public @NotNull ExportOnlyAEFluidSlot @NotNull [] getInventory() { return inventory; } diff --git a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/slot/ExportOnlyAEFluidSlot.java b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/slot/ExportOnlyAEFluidSlot.java index 73ad45f9ac4..397afc0f883 100644 --- a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/slot/ExportOnlyAEFluidSlot.java +++ b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/slot/ExportOnlyAEFluidSlot.java @@ -13,6 +13,7 @@ import net.minecraftforge.fluids.capability.IFluidTankProperties; import appeng.api.storage.data.IAEFluidStack; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; @@ -38,6 +39,12 @@ public ExportOnlyAEFluidSlot() { super(); } + @Override + public void decrementStock(long amount) { + if (stock == null) return; + stock.decStackSize(amount); + } + @Override public IAEFluidStack requestStack() { IAEFluidStack result = super.requestStack(); @@ -95,9 +102,10 @@ public void deserializeNBT(NBTTagCompound nbt) { @Nullable @Override public FluidStack getFluid() { - if (this.stock != null && this.stock instanceof WrappedFluidStack) { - return ((WrappedFluidStack) this.stock).getDelegate(); + if (this.stock instanceof WrappedFluidStack wrappedFluidStack) { + return wrappedFluidStack.getDefinition(); } + return null; } @@ -178,7 +186,7 @@ protected void trigger() { } @Override - public ExportOnlyAEFluidSlot copy() { + public @NotNull IConfigurableSlot copy() { return new ExportOnlyAEFluidSlot( this.holder, this.config == null ? null : this.config.copy(), diff --git a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/slot/ExportOnlyAEItemList.java b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/slot/ExportOnlyAEItemList.java index 995670eff15..31b5631d619 100644 --- a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/slot/ExportOnlyAEItemList.java +++ b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/slot/ExportOnlyAEItemList.java @@ -9,7 +9,7 @@ import appeng.api.storage.data.IAEItemStack; import org.jetbrains.annotations.NotNull; -public class ExportOnlyAEItemList extends NotifiableItemStackHandler { +public class ExportOnlyAEItemList extends NotifiableItemStackHandler implements IExportOnlyAEStackList { protected final int size; protected ExportOnlyAEItemSlot[] inventory; @@ -30,7 +30,7 @@ protected void createInventory(MetaTileEntity holder) { } } - public ExportOnlyAEItemSlot[] getInventory() { + public @NotNull ExportOnlyAEItemSlot @NotNull [] getInventory() { return inventory; } diff --git a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/slot/ExportOnlyAEItemSlot.java b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/slot/ExportOnlyAEItemSlot.java index 1408d77ad49..fc7fe955755 100644 --- a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/slot/ExportOnlyAEItemSlot.java +++ b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/slot/ExportOnlyAEItemSlot.java @@ -38,12 +38,18 @@ public void deserializeNBT(NBTTagCompound nbt) { } @Override - public ExportOnlyAEItemSlot copy() { + public @NotNull IConfigurableSlot copy() { return new ExportOnlyAEItemSlot( this.config == null ? null : this.config.copy(), this.stock == null ? null : this.stock.copy()); } + @Override + public void decrementStock(long amount) { + if (stock == null) return; + stock.decStackSize(amount); + } + @Override public void setStackInSlot(int slot, @NotNull ItemStack stack) {} @@ -91,8 +97,8 @@ public ItemStack extractItem(int slot, int amount, boolean simulate) { @Override public IAEItemStack requestStack() { IAEItemStack result = super.requestStack(); - if (result instanceof WrappedItemStack) { - return ((WrappedItemStack) result).getAEStack(); + if (result instanceof WrappedItemStack wrappedItemStack) { + return wrappedItemStack.getAEStack(); } else { return result; } @@ -101,8 +107,8 @@ public IAEItemStack requestStack() { @Override public IAEItemStack exceedStack() { IAEItemStack result = super.exceedStack(); - if (result instanceof WrappedItemStack) { - return ((WrappedItemStack) result).getAEStack(); + if (result instanceof WrappedItemStack wrappedItemStack) { + return wrappedItemStack.getAEStack(); } else { return result; } diff --git a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/slot/ExportOnlyAESlot.java b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/slot/ExportOnlyAESlot.java index 316a76e422b..1fa89d534e0 100644 --- a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/slot/ExportOnlyAESlot.java +++ b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/slot/ExportOnlyAESlot.java @@ -11,10 +11,12 @@ public abstract class ExportOnlyAESlot> protected final static String CONFIG_TAG = "config"; protected final static String STOCK_TAG = "stock"; + @Nullable protected T config; + @Nullable protected T stock; - public ExportOnlyAESlot(T config, T stock) { + public ExportOnlyAESlot(@Nullable T config, @Nullable T stock) { this.config = config; this.stock = stock; } @@ -45,9 +47,11 @@ public T exceedStack() { if (this.stock != null && !this.stock.isMeaningful()) { this.stock = null; } + if (this.config == null && this.stock != null) { return this.stock.copy(); } + if (this.config != null && this.stock != null) { if (this.config.equals(this.stock) && this.config.getStackSize() < this.stock.getStackSize()) { return this.stock.copy().setStackSize(this.stock.getStackSize() - this.config.getStackSize()); @@ -56,6 +60,7 @@ public T exceedStack() { return this.stock.copy(); } } + return null; } @@ -63,6 +68,8 @@ public T exceedStack() { public abstract void setStack(T stack); + public abstract void decrementStock(long amount); + @Override public NBTTagCompound serializeNBT() { NBTTagCompound tag = new NBTTagCompound(); @@ -80,22 +87,22 @@ public NBTTagCompound serializeNBT() { } @Override - public T getConfig() { + public @Nullable T getConfig() { return this.config; } @Override - public T getStock() { + public @Nullable T getStock() { return this.stock; } @Override - public void setConfig(T val) { + public void setConfig(@Nullable T val) { this.config = val; } @Override - public void setStock(T val) { + public void setStock(@Nullable T val) { this.stock = val; } } diff --git a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/slot/IConfigurableSlot.java b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/slot/IConfigurableSlot.java index 9e4532c8f19..648ea0f0d34 100644 --- a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/slot/IConfigurableSlot.java +++ b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/slot/IConfigurableSlot.java @@ -1,14 +1,21 @@ package gregtech.common.metatileentities.multi.multiblockpart.appeng.slot; -public interface IConfigurableSlot { +import appeng.api.storage.data.IAEStack; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +public interface IConfigurableSlot> { + + @Nullable T getConfig(); + @Nullable T getStock(); - void setConfig(T val); + void setConfig(@Nullable T val); - void setStock(T val); + void setStock(@Nullable T val); + @NotNull IConfigurableSlot copy(); } diff --git a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/slot/IExportOnlyAEStackList.java b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/slot/IExportOnlyAEStackList.java new file mode 100644 index 00000000000..e226f62af2f --- /dev/null +++ b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/slot/IExportOnlyAEStackList.java @@ -0,0 +1,14 @@ +package gregtech.common.metatileentities.multi.multiblockpart.appeng.slot; + +import appeng.api.storage.data.IAEStack; +import org.jetbrains.annotations.NotNull; + +public interface IExportOnlyAEStackList> { + + @NotNull + ExportOnlyAESlot @NotNull [] getInventory(); + + boolean isAutoPull(); + + boolean isStocking(); +} diff --git a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/stack/IWrappedStack.java b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/stack/IWrappedStack.java new file mode 100644 index 00000000000..e3eb7a5a6c4 --- /dev/null +++ b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/stack/IWrappedStack.java @@ -0,0 +1,23 @@ +package gregtech.common.metatileentities.multi.multiblockpart.appeng.stack; + +import net.minecraft.network.PacketBuffer; + +import appeng.api.storage.data.IAEStack; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public interface IWrappedStack, RealStackType> extends IAEStack { + + @NotNull + RealStackType getDefinition(); + + void writeToPacketBuffer(@NotNull PacketBuffer packetBuffer); + + boolean delegateAndSizeEqual(@Nullable IWrappedStack wrappedStack); + + @NotNull + IWrappedStack copyWrapped(); + + @NotNull + AEStackType copyAsAEStack(); +} diff --git a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/stack/WrappedFluidStack.java b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/stack/WrappedFluidStack.java index be685df3fd3..75f629249ca 100644 --- a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/stack/WrappedFluidStack.java +++ b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/stack/WrappedFluidStack.java @@ -1,9 +1,12 @@ package gregtech.common.metatileentities.multi.multiblockpart.appeng.stack; +import gregtech.api.util.GTUtility; +import gregtech.api.util.NetworkUtil; + import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.PacketBuffer; import net.minecraftforge.fluids.Fluid; -import net.minecraftforge.fluids.FluidRegistry; import net.minecraftforge.fluids.FluidStack; import appeng.api.AEApi; @@ -14,67 +17,73 @@ import appeng.fluids.util.AEFluidStack; import io.netty.buffer.ByteBuf; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import java.nio.charset.StandardCharsets; +import java.util.Objects; -/** - * @Author GlodBlock - * @Date 2023/4/22-19:25 - */ -public class WrappedFluidStack implements IAEFluidStack { +public class WrappedFluidStack implements IAEFluidStack, IWrappedStack { @NotNull - FluidStack delegate; + private final FluidStack delegate; + private long stackSize; - private WrappedFluidStack(@NotNull FluidStack stack) { + private WrappedFluidStack(@NotNull FluidStack stack, long stackSize) { this.delegate = stack; + this.stackSize = stackSize; } - public static WrappedFluidStack fromFluidStack(FluidStack fluidStack) { - return fluidStack == null ? null : new WrappedFluidStack(fluidStack); + public static WrappedFluidStack fromFluidStack(@Nullable FluidStack fluidStack) { + return fluidStack == null ? null : new WrappedFluidStack(fluidStack, fluidStack.amount); } - public static WrappedFluidStack fromNBT(NBTTagCompound data) { - FluidStack fluidStack = FluidStack.loadFluidStackFromNBT(data); - return fromFluidStack(fluidStack); + public static WrappedFluidStack fromFluidStack(@Nullable FluidStack fluidStack, long amount) { + return fluidStack == null ? null : new WrappedFluidStack(fluidStack, amount); } - public static WrappedFluidStack fromPacket(ByteBuf buffer) { - byte len = buffer.readByte(); - byte[] name = new byte[len]; - buffer.readBytes(name, 0, len); - int amt = buffer.readInt(); - FluidStack fluidStack = FluidRegistry.getFluidStack(new String(name, StandardCharsets.UTF_8), amt); - return fromFluidStack(fluidStack); + public static WrappedFluidStack fromNBT(@NotNull NBTTagCompound data) { + // Migrate old NBT entries from the old format + if (data.getBoolean("wrapped")) { + FluidStack stack = FluidStack.loadFluidStackFromNBT(data.getCompoundTag("stack")); + if (stack == null) return null; + return new WrappedFluidStack(stack, data.getLong("stackSize")); + } else { + return fromFluidStack(FluidStack.loadFluidStackFromNBT(data)); + } } - public AEFluidStack getAEStack() { - return AEFluidStack.fromFluidStack(this.delegate); + public static WrappedFluidStack fromPacket(@NotNull PacketBuffer buffer) { + return new WrappedFluidStack(Objects.requireNonNull(NetworkUtil.readFluidStack(buffer)), buffer.readLong()); } @NotNull - public FluidStack getDelegate() { - return this.delegate; + public AEFluidStack getAEStack() { + AEFluidStack aeFluidStack = AEFluidStack.fromFluidStack(this.delegate); + aeFluidStack.setStackSize(stackSize); + return aeFluidStack; } @Override public FluidStack getFluidStack() { - return this.delegate.copy(); + FluidStack newStack = this.delegate.copy(); + newStack.amount = GTUtility.safeCastLongToInt(stackSize); + return newStack; } @Override public void add(IAEFluidStack iaeFluidStack) { - this.delegate.amount += iaeFluidStack.getStackSize(); + if (equals(iaeFluidStack)) { + incStackSize(iaeFluidStack.getStackSize()); + } } @Override public long getStackSize() { - return this.delegate.amount; + return stackSize; } @Override - public IAEFluidStack setStackSize(long l) { - this.delegate.amount = (int) l; + public IAEFluidStack setStackSize(long newStackSize) { + this.stackSize = newStackSize; return this; } @@ -101,6 +110,7 @@ public IAEFluidStack setCraftable(boolean b) { @Override public IAEFluidStack reset() { this.delegate.amount = 0; + this.stackSize = 0L; return this; } @@ -110,13 +120,15 @@ public boolean isMeaningful() { } @Override - public void incStackSize(long l) { - this.delegate.amount += l; + public void incStackSize(long add) { + if (add < 1) return; + this.stackSize += Math.min(Long.MAX_VALUE - this.stackSize, add); } @Override - public void decStackSize(long l) { - this.delegate.amount -= l; + public void decStackSize(long sub) { + if (sub < 1) return; + this.stackSize -= Math.min(this.stackSize, sub); } @Override @@ -131,7 +143,15 @@ public void decCountRequestable(long l) { @Override public void writeToNBT(NBTTagCompound nbtTagCompound) { - this.delegate.writeToNBT(nbtTagCompound); + nbtTagCompound.setTag("stack", this.delegate.writeToNBT(new NBTTagCompound())); + nbtTagCompound.setLong("stackSize", this.stackSize); + nbtTagCompound.setBoolean("wrapped", true); + } + + public NBTTagCompound serializeToNBT() { + NBTTagCompound tag = new NBTTagCompound(); + writeToNBT(tag); + return tag; } @Override @@ -141,20 +161,34 @@ public boolean fuzzyComparison(IAEFluidStack stack, FuzzyMode fuzzyMode) { @Override public void writeToPacket(ByteBuf buffer) { - byte[] name = this.delegate.getFluid().getName().getBytes(StandardCharsets.UTF_8); - buffer.writeByte((byte) name.length); - buffer.writeBytes(name); - buffer.writeInt(this.delegate.amount); + writeToPacketBuffer(new PacketBuffer(buffer)); + } + + public void writeToPacketBuffer(@NotNull PacketBuffer packetBuffer) { + NetworkUtil.writeFluidStack(packetBuffer, this.delegate); + packetBuffer.writeLong(this.stackSize); } @Override public IAEFluidStack copy() { - return new WrappedFluidStack(this.delegate.copy()); + return new WrappedFluidStack(delegate.copy(), stackSize); + } + + @Override + public @NotNull IAEFluidStack copyAsAEStack() { + IAEFluidStack stack = AEFluidStack.fromFluidStack(delegate.copy()); + stack.setStackSize(stackSize); + return stack; + } + + @Override + public @NotNull IWrappedStack copyWrapped() { + return new WrappedFluidStack(delegate.copy(), stackSize); } @Override public IAEFluidStack empty() { - IAEFluidStack dup = new WrappedFluidStack(this.delegate.copy()); + IAEFluidStack dup = copy(); dup.reset(); return dup; } @@ -184,16 +218,32 @@ public Fluid getFluid() { return this.delegate.getFluid(); } + @Override + public @NotNull FluidStack getDefinition() { + delegate.amount = GTUtility.safeCastLongToInt(stackSize); + return delegate; + } + @Override public boolean equals(Object other) { - if (other instanceof WrappedFluidStack) { - return ((WrappedFluidStack) other).delegate.isFluidEqual(this.delegate); - } else if (other instanceof FluidStack) { - return ((FluidStack) other).isFluidEqual(this.delegate); + if (other instanceof WrappedFluidStack wrappedFluidStack) { + return wrappedFluidStack.delegate.isFluidEqual(this.delegate); + } else if (other instanceof AEFluidStack aeFluidStack) { + // noinspection EqualsBetweenInconvertibleTypes + return aeFluidStack.equals(delegate); + } else if (other instanceof FluidStack fluidStack) { + return fluidStack.isFluidEqual(this.delegate); } + return false; } + @Override + public boolean delegateAndSizeEqual(@Nullable IWrappedStack wrappedStack) { + if (wrappedStack == null) return false; + return delegate.isFluidEqual(wrappedStack.getDefinition()) && stackSize == wrappedStack.getStackSize(); + } + @Override public int hashCode() { int result = 1; @@ -201,4 +251,9 @@ public int hashCode() { result = 31 * result + (this.delegate.tag == null ? 0 : this.delegate.tag.hashCode()); return result; } + + @Override + public String toString() { + return String.format("Wrapped: %s, Stack Size: %d", delegate, stackSize); + } } diff --git a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/stack/WrappedItemStack.java b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/stack/WrappedItemStack.java index 274d4aac26c..128057c42d9 100644 --- a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/stack/WrappedItemStack.java +++ b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/appeng/stack/WrappedItemStack.java @@ -1,9 +1,12 @@ package gregtech.common.metatileentities.multi.multiblockpart.appeng.stack; +import gregtech.api.util.GTUtility; +import gregtech.api.util.NetworkUtil; + import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; -import net.minecraftforge.fml.common.network.ByteBufUtils; +import net.minecraft.network.PacketBuffer; import appeng.api.config.FuzzyMode; import appeng.api.storage.IStorageChannel; @@ -15,44 +18,59 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -/** - * @Author GlodBlock - * @Date 2023/4/22-21:02 - */ -public class WrappedItemStack implements IAEItemStack { +public class WrappedItemStack implements IAEItemStack, IWrappedStack { @NotNull - ItemStack delegate; + private ItemStack delegate; + private long stackSize; - private WrappedItemStack(@NotNull ItemStack itemStack) { + private WrappedItemStack(@NotNull ItemStack itemStack, long stackSize) { this.delegate = itemStack; + this.stackSize = stackSize; + } + + public static WrappedItemStack fromItemStack(@Nullable ItemStack stack) { + if (stack == null) return null; + return stack.isEmpty() ? null : new WrappedItemStack(stack, stack.getCount()); } - @Nullable - public static WrappedItemStack fromItemStack(@NotNull ItemStack stack) { - return stack.isEmpty() ? null : new WrappedItemStack(stack); + public static WrappedItemStack fromItemStack(@Nullable ItemStack stack, long amount) { + if (stack == null) return null; + return stack.isEmpty() ? null : new WrappedItemStack(stack, amount); } - public static WrappedItemStack fromNBT(NBTTagCompound i) { - if (i == null) { + public static WrappedItemStack fromNBT(@Nullable NBTTagCompound tag) { + if (tag == null) { return null; } else { - ItemStack itemstack = new ItemStack(i); - return fromItemStack(itemstack); + // Migrate old NBT entries from the old format + if (tag.getBoolean("wrapped")) { + return new WrappedItemStack(new ItemStack(tag.getCompoundTag("stack")), tag.getLong("stackSize")); + } else { + ItemStack itemStack = new ItemStack(tag); + return fromItemStack(itemStack); + } } } - public static WrappedItemStack fromPacket(ByteBuf data) { - return fromNBT(ByteBufUtils.readTag(data)); + public static WrappedItemStack fromPacket(@NotNull PacketBuffer data) { + WrappedItemStack wrappedItemStack = fromItemStack(NetworkUtil.readItemStack(data)); + wrappedItemStack.setStackSize(data.readLong()); + return wrappedItemStack; } public AEItemStack getAEStack() { - return AEItemStack.fromItemStack(this.delegate); + AEItemStack aeItemStack = AEItemStack.fromItemStack(this.delegate); + assert aeItemStack != null; + aeItemStack.setStackSize(stackSize); + return aeItemStack; } @Override public ItemStack createItemStack() { - return this.delegate.copy(); + ItemStack newStack = this.delegate.copy(); + newStack.setCount(GTUtility.safeCastLongToInt(stackSize)); + return newStack; } @Override @@ -62,17 +80,19 @@ public boolean hasTagCompound() { @Override public void add(IAEItemStack iaeItemStack) { - this.delegate.grow((int) iaeItemStack.getStackSize()); + if (equals(iaeItemStack)) { + incStackSize(iaeItemStack.getStackSize()); + } } @Override public long getStackSize() { - return this.delegate.getCount(); + return stackSize; } @Override - public IAEItemStack setStackSize(long l) { - this.delegate.setCount((int) l); + public IAEItemStack setStackSize(long newStackSize) { + this.stackSize = newStackSize; return this; } @@ -99,6 +119,7 @@ public IAEItemStack setCraftable(boolean b) { @Override public IAEItemStack reset() { this.delegate.setCount(0); + this.stackSize = 0; return this; } @@ -108,13 +129,15 @@ public boolean isMeaningful() { } @Override - public void incStackSize(long l) { - this.delegate.grow((int) l); + public void incStackSize(long add) { + if (add < 1) return; + this.stackSize += Math.min(Long.MAX_VALUE - this.stackSize, add); } @Override - public void decStackSize(long l) { - this.delegate.shrink((int) l); + public void decStackSize(long sub) { + if (sub < 1) return; + this.stackSize -= Math.min(this.stackSize, sub); } @Override @@ -129,7 +152,9 @@ public void decCountRequestable(long l) { @Override public void writeToNBT(NBTTagCompound nbtTagCompound) { - this.delegate.writeToNBT(nbtTagCompound); + nbtTagCompound.setTag("stack", this.delegate.serializeNBT()); + nbtTagCompound.setLong("stackSize", this.stackSize); + nbtTagCompound.setBoolean("wrapped", true); } @Override @@ -139,17 +164,38 @@ public boolean fuzzyComparison(IAEItemStack stack, FuzzyMode fuzzyMode) { @Override public void writeToPacket(ByteBuf byteBuf) { - ByteBufUtils.writeTag(byteBuf, this.delegate.serializeNBT()); + writeToPacketBuffer(new PacketBuffer(byteBuf)); + } + + public void writeToPacketBuffer(@NotNull PacketBuffer packetBuffer) { + NetworkUtil.writeItemStack(packetBuffer, this.delegate); + packetBuffer.writeLong(this.stackSize); } @Override public IAEItemStack copy() { - return new WrappedItemStack(this.delegate.copy()); + return new WrappedItemStack(delegate.copy(), stackSize); + } + + @Override + public @NotNull IAEItemStack copyAsAEStack() { + IAEItemStack stack = AEItemStack.fromItemStack(delegate.copy()); + if (stack == null) { + throw new IllegalStateException("Error creating AEItemStack from delegate"); + } + + stack.setStackSize(stackSize); + return stack; + } + + @Override + public @NotNull IWrappedStack copyWrapped() { + return new WrappedItemStack(delegate.copy(), stackSize); } @Override public IAEItemStack empty() { - IAEItemStack copy = this.copy(); + IAEItemStack copy = copy(); copy.reset(); return copy; } @@ -171,6 +217,7 @@ public IStorageChannel getChannel() { @Override public ItemStack asItemStackRepresentation() { + delegate.setCount(GTUtility.safeCastLongToInt(stackSize)); return this.delegate; } @@ -206,7 +253,8 @@ public boolean isSameType(ItemStack itemStack) { } @Override - public ItemStack getDefinition() { + public @NotNull ItemStack getDefinition() { + delegate.setCount(GTUtility.safeCastLongToInt(stackSize)); return this.delegate; } @@ -217,15 +265,35 @@ public boolean equals(ItemStack itemStack) { @Override public boolean equals(Object other) { - if (other instanceof IAEItemStack) { - return this.delegate.isItemEqual(((IAEItemStack) other).createItemStack()); - } - if (other instanceof ItemStack) { - return this.delegate.isItemEqual((ItemStack) other); + if (other instanceof WrappedItemStack wrappedItemStack) { + ItemStack otherStack = wrappedItemStack.getDefinition(); + NBTTagCompound thisTag = delegate.getTagCompound(); + NBTTagCompound otherTag = otherStack.getTagCompound(); + + boolean nbtMatch; + if (thisTag == null) { + nbtMatch = otherTag == null; + } else { + // noinspection PointlessNullCheck + nbtMatch = otherTag != null && thisTag.equals(otherTag); + } + + return this.delegate.isItemEqual(otherStack) && nbtMatch; + } else if (other instanceof AEItemStack aeItemStack) { + return aeItemStack.equals(delegate); + } else if (other instanceof ItemStack itemStack) { + return this.equals(itemStack); } + return false; } + @Override + public boolean delegateAndSizeEqual(@Nullable IWrappedStack wrappedStack) { + if (wrappedStack == null) return false; + return delegate.isItemEqual(wrappedStack.getDefinition()) && stackSize == wrappedStack.getStackSize(); + } + @Override public int hashCode() { int result = 1; @@ -238,7 +306,7 @@ public int hashCode() { @Override public ItemStack getCachedItemStack(long l) { ItemStack copy = this.delegate.copy(); - copy.setCount((int) l); + copy.setCount(GTUtility.safeCastLongToInt(stackSize)); return copy; } @@ -246,4 +314,9 @@ public ItemStack getCachedItemStack(long l) { public void setCachedItemStack(ItemStack itemStack) { this.delegate = itemStack; } + + @Override + public String toString() { + return String.format("Wrapped: %s, Stack Size: %d", delegate, stackSize); + } } diff --git a/src/main/java/gregtech/common/metatileentities/storage/CachedRecipeData.java b/src/main/java/gregtech/common/metatileentities/workbench/CachedRecipeData.java similarity index 97% rename from src/main/java/gregtech/common/metatileentities/storage/CachedRecipeData.java rename to src/main/java/gregtech/common/metatileentities/workbench/CachedRecipeData.java index be5716f65fb..9e16e20fdf0 100755 --- a/src/main/java/gregtech/common/metatileentities/storage/CachedRecipeData.java +++ b/src/main/java/gregtech/common/metatileentities/workbench/CachedRecipeData.java @@ -1,4 +1,4 @@ -package gregtech.common.metatileentities.storage; +package gregtech.common.metatileentities.workbench; import gregtech.api.util.GTLog; diff --git a/src/main/java/gregtech/common/metatileentities/storage/CraftingRecipeLogic.java b/src/main/java/gregtech/common/metatileentities/workbench/CraftingRecipeLogic.java similarity index 91% rename from src/main/java/gregtech/common/metatileentities/storage/CraftingRecipeLogic.java rename to src/main/java/gregtech/common/metatileentities/workbench/CraftingRecipeLogic.java index eece105d06d..96c4116aa17 100644 --- a/src/main/java/gregtech/common/metatileentities/storage/CraftingRecipeLogic.java +++ b/src/main/java/gregtech/common/metatileentities/workbench/CraftingRecipeLogic.java @@ -1,6 +1,8 @@ -package gregtech.common.metatileentities.storage; +package gregtech.common.metatileentities.workbench; import gregtech.api.items.toolitem.ItemGTToolbelt; +import gregtech.api.mui.sync.PagedWidgetSyncHandler; +import gregtech.api.mui.sync.RecipeSyncHandler; import gregtech.api.util.DummyContainer; import gregtech.api.util.GTTransferUtils; import gregtech.api.util.GTUtility; @@ -23,7 +25,6 @@ import net.minecraftforge.items.IItemHandlerModifiable; import com.cleanroommc.modularui.network.NetworkUtils; -import com.cleanroommc.modularui.value.sync.SyncHandler; import it.unimi.dsi.fastutil.ints.Int2BooleanArrayMap; import it.unimi.dsi.fastutil.ints.Int2BooleanMap; import it.unimi.dsi.fastutil.ints.Int2IntArrayMap; @@ -38,11 +39,16 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenCustomHashMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap; +import mezz.jei.api.gui.IGuiItemStackGroup; +import mezz.jei.api.gui.IRecipeLayout; +import mezz.jei.api.recipe.transfer.IRecipeTransferError; +import mezz.jei.transfer.RecipeTransferErrorInternal; +import org.jetbrains.annotations.NotNull; import java.util.Collections; import java.util.Map; -public class CraftingRecipeLogic extends SyncHandler { +public class CraftingRecipeLogic extends RecipeSyncHandler { // client only public static final int UPDATE_INGREDIENTS = 1; @@ -452,6 +458,38 @@ public void syncMatrix() { syncToServer(UPDATE_MATRIX, this::writeMatrix); } + // TODO: extract my recipe transfer into a dedicated branch and improve it. + @Override + public IRecipeTransferError receiveRecipe(@NotNull IRecipeLayout recipeLayout, boolean maxTransfer, + boolean simulate) { + if (!recipeLayout.getRecipeCategory().getUid().equals("minecraft.crafting")) { + return RecipeTransferErrorInternal.INSTANCE; + } + + if (simulate) { + // todo highlighting in JEI? + return null; + } + + var matrix = extractMatrix(recipeLayout.getItemStacks()); + fillCraftingGrid(matrix); + ((PagedWidgetSyncHandler) getSyncManager().getSyncHandler("page_controller:0")).setPage(0); + return null; + } + + private Int2ObjectMap extractMatrix(IGuiItemStackGroup stackGroup) { + var ingredients = stackGroup.getGuiIngredients(); + Int2ObjectMap matrix = new Int2ObjectArrayMap<>(9); + for (var slot : ingredients.keySet()) { + if (slot != 0) { + var ing = ingredients.get(slot).getDisplayedIngredient(); + if (ing == null) continue; + matrix.put(slot - 1, ingredients.get(slot).getDisplayedIngredient()); + } + } + return matrix; + } + public static InventoryCrafting wrapHandler(IItemHandlerModifiable handler) { return new InventoryCrafting(new DummyContainer(), 3, 3) { diff --git a/src/main/java/gregtech/common/metatileentities/storage/CraftingRecipeMemory.java b/src/main/java/gregtech/common/metatileentities/workbench/CraftingRecipeMemory.java similarity index 99% rename from src/main/java/gregtech/common/metatileentities/storage/CraftingRecipeMemory.java rename to src/main/java/gregtech/common/metatileentities/workbench/CraftingRecipeMemory.java index af7f20b0b0b..c29ebfe5e3b 100644 --- a/src/main/java/gregtech/common/metatileentities/storage/CraftingRecipeMemory.java +++ b/src/main/java/gregtech/common/metatileentities/workbench/CraftingRecipeMemory.java @@ -1,4 +1,4 @@ -package gregtech.common.metatileentities.storage; +package gregtech.common.metatileentities.workbench; import gregtech.api.util.ItemStackHashStrategy; diff --git a/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityWorkbench.java b/src/main/java/gregtech/common/metatileentities/workbench/MetaTileEntityWorkbench.java similarity index 99% rename from src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityWorkbench.java rename to src/main/java/gregtech/common/metatileentities/workbench/MetaTileEntityWorkbench.java index 3483c603223..5a4e326d0c6 100644 --- a/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityWorkbench.java +++ b/src/main/java/gregtech/common/metatileentities/workbench/MetaTileEntityWorkbench.java @@ -1,4 +1,4 @@ -package gregtech.common.metatileentities.storage; +package gregtech.common.metatileentities.workbench; import gregtech.api.capability.GregtechDataCodes; import gregtech.api.capability.impl.ItemHandlerList; diff --git a/src/main/java/gregtech/common/mui/widget/workbench/CraftingInputSlot.java b/src/main/java/gregtech/common/mui/widget/workbench/CraftingInputSlot.java index ef19b86415d..0e5778b206c 100644 --- a/src/main/java/gregtech/common/mui/widget/workbench/CraftingInputSlot.java +++ b/src/main/java/gregtech/common/mui/widget/workbench/CraftingInputSlot.java @@ -3,7 +3,7 @@ import gregtech.api.util.GTUtility; import gregtech.api.util.JEIUtil; import gregtech.client.utils.RenderUtil; -import gregtech.common.metatileentities.storage.CraftingRecipeLogic; +import gregtech.common.metatileentities.workbench.CraftingRecipeLogic; import net.minecraft.item.ItemStack; import net.minecraft.network.PacketBuffer; diff --git a/src/main/java/gregtech/common/mui/widget/workbench/CraftingOutputSlot.java b/src/main/java/gregtech/common/mui/widget/workbench/CraftingOutputSlot.java index 5aa7a6e93bf..7bccd2cf4ad 100644 --- a/src/main/java/gregtech/common/mui/widget/workbench/CraftingOutputSlot.java +++ b/src/main/java/gregtech/common/mui/widget/workbench/CraftingOutputSlot.java @@ -1,9 +1,9 @@ package gregtech.common.mui.widget.workbench; import gregtech.client.utils.RenderUtil; -import gregtech.common.metatileentities.storage.CraftingRecipeLogic; -import gregtech.common.metatileentities.storage.CraftingRecipeMemory; -import gregtech.common.metatileentities.storage.MetaTileEntityWorkbench; +import gregtech.common.metatileentities.workbench.CraftingRecipeLogic; +import gregtech.common.metatileentities.workbench.CraftingRecipeMemory; +import gregtech.common.metatileentities.workbench.MetaTileEntityWorkbench; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.IInventory; diff --git a/src/main/java/gregtech/common/mui/widget/workbench/RecipeMemorySlot.java b/src/main/java/gregtech/common/mui/widget/workbench/RecipeMemorySlot.java index af58a753b96..eb6cf0a7e74 100644 --- a/src/main/java/gregtech/common/mui/widget/workbench/RecipeMemorySlot.java +++ b/src/main/java/gregtech/common/mui/widget/workbench/RecipeMemorySlot.java @@ -2,7 +2,7 @@ import gregtech.api.mui.GTGuiTextures; import gregtech.client.utils.RenderUtil; -import gregtech.common.metatileentities.storage.CraftingRecipeMemory; +import gregtech.common.metatileentities.workbench.CraftingRecipeMemory; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.item.ItemStack; diff --git a/src/main/java/gregtech/integration/hwyla/provider/AEMultiblockHatchProvider.java b/src/main/java/gregtech/integration/hwyla/provider/AEMultiblockHatchProvider.java index 1724980aff5..cca2d8c8068 100644 --- a/src/main/java/gregtech/integration/hwyla/provider/AEMultiblockHatchProvider.java +++ b/src/main/java/gregtech/integration/hwyla/provider/AEMultiblockHatchProvider.java @@ -1,8 +1,8 @@ package gregtech.integration.hwyla.provider; import gregtech.api.GTValues; +import gregtech.api.metatileentity.IAEStatusProvider; import gregtech.api.metatileentity.interfaces.IGregTechTileEntity; -import gregtech.common.metatileentities.multi.multiblockpart.appeng.MetaTileEntityAEHostablePart; import net.minecraft.client.resources.I18n; import net.minecraft.entity.player.EntityPlayerMP; @@ -22,7 +22,8 @@ public class AEMultiblockHatchProvider implements IWailaDataProvider { - private static final String NBT_KEY = "ae_part_online"; + private static final String NBT_ONLINE = "ae_part_online"; + private static final String NBT_EXTRA_CONNECTIONS = "ae_extra_connections"; public static final AEMultiblockHatchProvider INSTANCE = new AEMultiblockHatchProvider(); @@ -36,8 +37,9 @@ public void register(@NotNull IWailaRegistrar registrar) { public @NotNull NBTTagCompound getNBTData(EntityPlayerMP player, TileEntity te, NBTTagCompound tag, World world, BlockPos pos) { if (te instanceof IGregTechTileEntity gtte && - gtte.getMetaTileEntity() instanceof MetaTileEntityAEHostablePartaeHostablePart) { - tag.setBoolean(NBT_KEY, aeHostablePart.isOnline()); + gtte.getMetaTileEntity() instanceof IAEStatusProvider aeStatusProvider) { + tag.setBoolean(NBT_ONLINE, aeStatusProvider.isOnline()); + tag.setBoolean(NBT_EXTRA_CONNECTIONS, aeStatusProvider.allowsExtraConnections()); } return tag; @@ -46,14 +48,20 @@ public void register(@NotNull IWailaRegistrar registrar) { @Override public @NotNull List getWailaBody(ItemStack itemStack, List tooltip, IWailaDataAccessor accessor, IWailaConfigHandler config) { - if (accessor.getNBTData().hasKey(NBT_KEY)) { - if (accessor.getNBTData().getBoolean(NBT_KEY)) { + if (accessor.getNBTData().hasKey(NBT_ONLINE)) { + if (accessor.getNBTData().getBoolean(NBT_ONLINE)) { tooltip.add(I18n.format("gregtech.gui.me_network.online")); } else { tooltip.add(I18n.format("gregtech.gui.me_network.offline")); } } + if (accessor.getNBTData().hasKey(NBT_EXTRA_CONNECTIONS)) { + if (accessor.getNBTData().getBoolean(NBT_EXTRA_CONNECTIONS)) { + tooltip.add(I18n.format("gregtech.machine.me.extra_connections.enabled")); + } + } + return tooltip; } } diff --git a/src/main/java/gregtech/integration/jei/JustEnoughItemsModule.java b/src/main/java/gregtech/integration/jei/JustEnoughItemsModule.java index 7772e0ada44..c43c317a719 100644 --- a/src/main/java/gregtech/integration/jei/JustEnoughItemsModule.java +++ b/src/main/java/gregtech/integration/jei/JustEnoughItemsModule.java @@ -12,7 +12,6 @@ import gregtech.api.metatileentity.SteamMetaTileEntity; import gregtech.api.metatileentity.registry.MTERegistry; import gregtech.api.modules.GregTechModule; -import gregtech.api.mui.GregTechGuiTransferHandler; import gregtech.api.recipes.Recipe; import gregtech.api.recipes.RecipeMap; import gregtech.api.recipes.category.GTRecipeCategory; @@ -74,6 +73,7 @@ import mezz.jei.api.recipe.IRecipeCategory; import mezz.jei.api.recipe.IRecipeCategoryRegistration; import mezz.jei.api.recipe.VanillaRecipeCategoryUid; +import mezz.jei.api.recipe.transfer.IRecipeTransferHandlerHelper; import mezz.jei.config.Constants; import mezz.jei.input.IShowsRecipeFocuses; import mezz.jei.input.InputHandler; @@ -105,6 +105,7 @@ public class JustEnoughItemsModule extends IntegrationSubmodule implements IModP public static IIngredientRegistry ingredientRegistry; public static IJeiRuntime jeiRuntime; public static IGuiHelper guiHelper; + public static IRecipeTransferHandlerHelper transferHelper; @Override public void loadComplete(FMLLoadCompleteEvent event) { @@ -159,6 +160,7 @@ public void register(IModRegistry registry) { // register transfer handler for all categories, but not for the crafting station ModularUIGuiHandler modularUIGuiHandler = new ModularUIGuiHandler(jeiHelpers.recipeTransferHandlerHelper()); + transferHelper = jeiHelpers.recipeTransferHandlerHelper(); modularUIGuiHandler.blacklistCategory( IntCircuitCategory.UID, MaterialTreeCategory.UID, @@ -167,10 +169,6 @@ public void register(IModRegistry registry) { registry.getRecipeTransferRegistry().addRecipeTransferHandler(modularUIGuiHandler, Constants.UNIVERSAL_RECIPE_TRANSFER_UID); - // register transfer handler for crafting recipes - registry.getRecipeTransferRegistry().addRecipeTransferHandler(new GregTechGuiTransferHandler( - jeiHelpers.recipeTransferHandlerHelper()), VanillaRecipeCategoryUid.CRAFTING); - registry.addAdvancedGuiHandlers(modularUIGuiHandler); registry.addGhostIngredientHandler(modularUIGuiHandler.getGuiContainerClass(), modularUIGuiHandler); diff --git a/src/main/java/gregtech/integration/theoneprobe/provider/AEMultiblockHatchProvider.java b/src/main/java/gregtech/integration/theoneprobe/provider/AEMultiblockHatchProvider.java index de734d109f2..a48ae706595 100644 --- a/src/main/java/gregtech/integration/theoneprobe/provider/AEMultiblockHatchProvider.java +++ b/src/main/java/gregtech/integration/theoneprobe/provider/AEMultiblockHatchProvider.java @@ -1,7 +1,7 @@ package gregtech.integration.theoneprobe.provider; +import gregtech.api.metatileentity.IAEStatusProvider; import gregtech.api.metatileentity.interfaces.IGregTechTileEntity; -import gregtech.common.metatileentities.multi.multiblockpart.appeng.MetaTileEntityAEHostablePart; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.player.EntityPlayer; @@ -24,12 +24,16 @@ public void addProbeInfo(ProbeMode probeMode, IProbeInfo probeInfo, EntityPlayer IBlockState blockState, IProbeHitData probeHitData) { if (blockState.getBlock().hasTileEntity(blockState) && world.getTileEntity(probeHitData.getPos()) instanceof IGregTechTileEntity gtte && - gtte.getMetaTileEntity() instanceof MetaTileEntityAEHostablePartaeHostablePart) { - if (aeHostablePart.isOnline()) { + gtte.getMetaTileEntity() instanceof IAEStatusProvider aeStatusProvider) { + if (aeStatusProvider.isOnline()) { probeInfo.text("{*gregtech.gui.me_network.online*}"); } else { probeInfo.text("{*gregtech.gui.me_network.offline*}"); } + + if (aeStatusProvider.allowsExtraConnections()) { + probeInfo.text("{*gregtech.machine.me.extra_connections.enabled*}"); + } } } } diff --git a/src/main/java/gregtech/mixins/jei/GuiIngredientGroupAccessor.java b/src/main/java/gregtech/mixins/jei/GuiIngredientGroupAccessor.java new file mode 100644 index 00000000000..503c9a5564b --- /dev/null +++ b/src/main/java/gregtech/mixins/jei/GuiIngredientGroupAccessor.java @@ -0,0 +1,14 @@ +package gregtech.mixins.jei; + +import mezz.jei.gui.ingredients.GuiIngredientGroup; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.Set; + +@Mixin(value = GuiIngredientGroup.class, remap = false) +public interface GuiIngredientGroupAccessor { + + @Accessor(value = "inputSlots") + Set getInputSlotIndexes(); +} diff --git a/src/main/java/gregtech/mixins/minecraft/MinecraftMixin.java b/src/main/java/gregtech/mixins/minecraft/MinecraftMixin.java index 0bba8ad4f03..810be316d44 100644 --- a/src/main/java/gregtech/mixins/minecraft/MinecraftMixin.java +++ b/src/main/java/gregtech/mixins/minecraft/MinecraftMixin.java @@ -1,19 +1,23 @@ package gregtech.mixins.minecraft; import gregtech.api.items.toolitem.ItemGTToolbelt; +import gregtech.client.IsGuiActuallyClosing; import gregtech.common.ConfigHolder; import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiScreen; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.item.ItemStack; import net.minecraft.util.text.TextComponentTranslation; +import org.jetbrains.annotations.Nullable; import org.lwjgl.input.Keyboard; import org.objectweb.asm.Opcodes; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(Minecraft.class) @@ -42,4 +46,9 @@ public void interceptHotbarKeybindsForToolbelt(InventoryPlayer inventoryPlayer, } inventoryPlayer.currentItem = i; } + + @Inject(method = "displayGuiScreen", at = @At(value = "HEAD")) + public void captureNewGUI(@Nullable GuiScreen guiScreenIn, CallbackInfo ci) { + IsGuiActuallyClosing.isGuiActuallyClosing = guiScreenIn == null; + } } diff --git a/src/main/java/gregtech/mixins/mui2/MCHelperMixin.java b/src/main/java/gregtech/mixins/mui2/MCHelperMixin.java new file mode 100644 index 00000000000..eaebbfc006a --- /dev/null +++ b/src/main/java/gregtech/mixins/mui2/MCHelperMixin.java @@ -0,0 +1,30 @@ +package gregtech.mixins.mui2; + +import gregtech.api.util.Mods; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.fml.common.Loader; +import net.minecraftforge.fml.common.ModContainer; + +import com.cleanroommc.modularui.api.MCHelper; +import com.llamalad7.mixinextras.injector.ModifyReturnValue; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +import java.util.List; + +@Mixin(value = MCHelper.class, remap = false) +public class MCHelperMixin { + + @ModifyReturnValue(method = "getItemToolTip", at = @At(value = "RETURN")) + private static List addModName(List original, ItemStack stack) { + if (original.isEmpty() || Mods.ModNameTooltip.isModLoaded()) return original; + + ModContainer modContainer = Loader.instance().getIndexedModList().get(stack.getItem().getCreatorModId(stack)); + if (modContainer != null) { + original.add("§9§o" + modContainer.getName() + "§r"); + } + + return original; + } +} diff --git a/src/main/java/gregtech/mixins/mui2/ModularSyncManagerMixin.java b/src/main/java/gregtech/mixins/mui2/ModularSyncManagerMixin.java new file mode 100644 index 00000000000..9346f9b614e --- /dev/null +++ b/src/main/java/gregtech/mixins/mui2/ModularSyncManagerMixin.java @@ -0,0 +1,20 @@ +package gregtech.mixins.mui2; + +import gregtech.client.IsGuiActuallyClosing; + +import com.cleanroommc.modularui.value.sync.ModularSyncManager; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(value = ModularSyncManager.class, remap = false) +public class ModularSyncManagerMixin { + + @Inject(method = "onClose", at = @At(value = "HEAD"), cancellable = true) + private void cancelIfGUIAboutToOpenIsJEI(CallbackInfo ci) { + if (!IsGuiActuallyClosing.isGuiActuallyClosing) { + ci.cancel(); + } + } +} diff --git a/src/main/resources/assets/gregtech/lang/en_us.lang b/src/main/resources/assets/gregtech/lang/en_us.lang index bdf8e329563..27202504b32 100644 --- a/src/main/resources/assets/gregtech/lang/en_us.lang +++ b/src/main/resources/assets/gregtech/lang/en_us.lang @@ -5536,6 +5536,11 @@ gregtech.machine.me.fluid_import.data_stick.name=§oME Input Hatch Configuration gregtech.machine.me.extra_connections.enabled=Allow connections from all sides gregtech.machine.me.extra_connections.disabled=Allow connection only on front face gregtech.machine.me.extra_connections.tooltip=Right-click with wire cutters to allow connecting to AE2 on all sides +gregtech.machine.me.settings.button=ME Settings +gregtech.machine.me.settings.refresh_rate=Refresh rate: +gregtech.machine.me.settings.minimum=Minimum stack size: +gregtech.machine.me.settings.minimum.tooltip=Set to 0 to disable the minimum stack size filtering +gregtech.machine.me.multiplier.button=Config multiplier # Universal tooltips gregtech.universal.tooltip.voltage_in=§aVoltage IN: §f%,d EU/t (%s§f) @@ -5644,7 +5649,7 @@ gregtech.fluid.state_plasma=§aState: Plasma gregtech.fluid.type_acid.tooltip=§6Acidic! Handle with care! gregtech.gui.fuel_amount=Fuel Amount: gregtech.gui.fluid_amount=Fluid Amount: -gregtech.gui.amount_raw=Amount: +gregtech.gui.amount_raw=Amount: %s gregtech.gui.toggle_view.disabled=Toggle View (Fluids) gregtech.gui.toggle_view.enabled=Toggle View (Items) gregtech.gui.overclock.enabled=Overclocking Enabled./nClick to Disable @@ -5680,8 +5685,6 @@ gregtech.gui.multiblock_voiding_not_supported=This Multiblock does not support V gregtech.gui.multiblock.recipe_producing=Producing: gregtech.gui.me_network.online=Network: §aOnline§r gregtech.gui.me_network.offline=Network: §4Offline§r -gregtech.gui.waiting_list=Sending Queue: -gregtech.gui.config_slot=§fConfig Slot§r gregtech.gui.config_slot.set=§7Click to §bset/select§7 config slot.§r gregtech.gui.config_slot.set_only=§7Click to §bset§7 config slot.§r gregtech.gui.config_slot.scroll=§7Scroll wheel to §achange§7 config amount.§r diff --git a/src/main/resources/assets/gregtech/lang/ja_jp.lang b/src/main/resources/assets/gregtech/lang/ja_jp.lang index 846a51bd8f6..135fc75e5f9 100644 --- a/src/main/resources/assets/gregtech/lang/ja_jp.lang +++ b/src/main/resources/assets/gregtech/lang/ja_jp.lang @@ -5578,7 +5578,7 @@ gregtech.fluid.state_plasma=§a状態: プラズマ gregtech.fluid.type_acid.tooltip=§6酸性! 取扱注意! gregtech.gui.fuel_amount=燃料量: gregtech.gui.fluid_amount=液体量: -gregtech.gui.amount_raw=液体量 (詳細): +gregtech.gui.amount_raw=液体量 (詳細): %s gregtech.gui.toggle_view.disabled=液体スロット切り替え gregtech.gui.toggle_view.enabled=アイテムスロット切り替え gregtech.gui.overclock.enabled=オーバークロックが有効。/nクリックで無効化 diff --git a/src/main/resources/assets/gregtech/lang/ru_ru.lang b/src/main/resources/assets/gregtech/lang/ru_ru.lang index b6cc61eb30b..eb797af7395 100644 --- a/src/main/resources/assets/gregtech/lang/ru_ru.lang +++ b/src/main/resources/assets/gregtech/lang/ru_ru.lang @@ -4815,7 +4815,7 @@ gregtech.fluid.state_plasma=§7Состояние: Плазма gregtech.fluid.type_acid.tooltip=§6Кислота! Соблюдайте осторожность! gregtech.gui.fuel_amount=Кол. топлива: gregtech.gui.fluid_amount=Кол. жидкости: -gregtech.gui.amount_raw=Кол-во: +gregtech.gui.amount_raw=Кол-во: %s gregtech.gui.toggle_view.disabled=Переключить вид (Жидкости) gregtech.gui.toggle_view.enabled=Переключить вид (Предметы) gregtech.gui.overclock.enabled=Ускорение включено./nНажмите, чтобы отключить diff --git a/src/main/resources/assets/gregtech/lang/zh_cn.lang b/src/main/resources/assets/gregtech/lang/zh_cn.lang index 23183d57830..58e7fefd474 100644 --- a/src/main/resources/assets/gregtech/lang/zh_cn.lang +++ b/src/main/resources/assets/gregtech/lang/zh_cn.lang @@ -5634,7 +5634,7 @@ gregtech.fluid.state_plasma=§a状态:等离子态 gregtech.fluid.type_acid.tooltip=§6酸性物质!轻拿轻放! gregtech.gui.fuel_amount=燃料总量: gregtech.gui.fluid_amount=流体总量: -gregtech.gui.amount_raw=数量: +gregtech.gui.amount_raw=数量:%s gregtech.gui.toggle_view.disabled=切换视图(流体) gregtech.gui.toggle_view.enabled=切换视图(物品) gregtech.gui.overclock.enabled=已启用超频/n点击以禁用 diff --git a/src/main/resources/assets/gregtech/textures/gui/widget/opposite_arrows.png b/src/main/resources/assets/gregtech/textures/gui/widget/opposite_arrows.png new file mode 100644 index 00000000000..4d79e31215a Binary files /dev/null and b/src/main/resources/assets/gregtech/textures/gui/widget/opposite_arrows.png differ diff --git a/src/main/resources/mixins.gregtech.jei.json b/src/main/resources/mixins.gregtech.jei.json index 75728d0aeb9..3a536b98e55 100644 --- a/src/main/resources/mixins.gregtech.jei.json +++ b/src/main/resources/mixins.gregtech.jei.json @@ -8,6 +8,7 @@ "BasicRecipeTransferHandlerServerMixin", "DragManagerAccessor", "GhostDragAccessor", + "GuiIngredientGroupAccessor", "IngredientGridMixin", "JEITooltipMixin", "ModRegistryMixin", diff --git a/src/main/resources/mixins.gregtech.mui2.json b/src/main/resources/mixins.gregtech.mui2.json index 5299e07453a..a1fa54c6e06 100644 --- a/src/main/resources/mixins.gregtech.mui2.json +++ b/src/main/resources/mixins.gregtech.mui2.json @@ -12,7 +12,9 @@ "TextWidgetMixin" ], "client": [ - "LangKeyMixin" + "LangKeyMixin", + "ModularSyncManagerMixin", + "MCHelperMixin" ], "server": [] }