Compare commits

...

36 Commits

Author SHA1 Message Date
NotMyWing 8d4e5734e8 automatically add papers for GT multiblocks 2024-06-01 19:12:45 +11:00
NotMyWing 00ac7c3334 rewrite transfer logic 2024-06-01 18:46:11 +11:00
NotMyWing bcc28c0b28 extra tooltip check just in case 2024-05-31 18:23:54 +11:00
NotMyWing a03d6f4803 bypass unnecessary fuzzy checks if we're ignoring durability anyway 2024-05-31 18:10:37 +11:00
NotMyWing e3b8228608 boring stuff (who even reads these) 2024-05-31 00:42:43 +11:00
NotMyWing 68de8fa1a2 Make OreDict Storage Buses upgradeable
Closes #403
2024-05-28 17:51:07 +11:00
NotMyWing 6864f7ae07 Fix ME Interface GuiSync overlap 2024-05-28 17:15:25 +11:00
NotMyWing 7fa7b726f2 Disable extracting invisible items from Storage Buses altogether
Reverts d82cdabc6d, closes #408
Allows Cells to report/extract lingering unpartitioned items
2024-05-27 20:41:15 +11:00
zeng-git c814fe591d Update zh_cn.lang (#443) 2024-05-27 13:31:22 +11:00
NotMyWing cd0a5d631b Temporarily prevent FakePlayers from using wrenches
Closes #432
2024-05-27 13:28:48 +11:00
NotMyWing d82cdabc6d Fix crafting plan reporting invisible extractable items as available
Closes #438
2024-05-25 00:37:46 +11:00
NotMyWing 2e976a609f Make Storage Cell tooltips configurable
Closes #427
2024-05-24 23:54:05 +11:00
Zengyj a13f9955f2 Backport lock crafting function for ME Interface (#423) 2024-05-24 23:39:03 +11:00
Michael Trittin a65b5015e6 Allow View Cells to be shift-clicked into place (#388) 2024-05-24 23:13:15 +11:00
Yang Xizhi 07eb6c1238 Allow third-party addons to register custom GUIs via GuiBridge (#402) 2024-05-24 23:05:29 +11:00
Domi 529ea5e239 Small UI fixes and improvements (#398) 2024-05-24 23:03:12 +11:00
NotMyWing a9b7faa98b Fix OreDict filters not testing items without entries 2024-05-24 22:52:50 +11:00
Serenibyss 78c7235bea Improve ME Interface Terminal UI (#368)
Co-authored-by: NotMyWing <winwyv@gmail.com>
2024-05-24 22:15:15 +11:00
zeng-git 59edb38208 Add ore dictionary support for Inscriber recipes in JEI (#430) 2024-05-24 21:51:37 +11:00
NotMyWing 08a7aff600 Fix ME Export Buses oversending items
As a side effect, fixes them not sending anything at all with too many Acceleration Cards
Closes #441
2024-05-24 20:25:10 +11:00
NotMyWing 9f19e05592 Fix non-deterministic ME Interface behavior
As a side effect, allows ME Interfaces to fully utilize allowed operations instead of doing at most 1 push per cycle
Closes #440
2024-05-24 19:05:06 +11:00
zeng-git 5f20e3346c Add automatic artifact builds on push (#426) 2024-05-17 22:37:54 +11:00
NotMyWing fd188dc96c Fix stopping already stopped Stopwatches in CraftingJob
Resolves #417
Co-authored-by: frankdai320 <frankdai320@gmail.com>
2024-05-17 19:31:31 +11:00
NotMyWing e471293e60 Fix NPE when suffocating in ME Drives
And hopefully all other cases related to missing slot states
Closes #420
2024-05-17 19:08:18 +11:00
NotMyWing f28a3574df Fix rogue off-by-one OreHelper error breaking nested parens 2024-05-17 15:00:36 +11:00
zeng-git b2b21eae41 Add missing Fluid Terminal localization (#428) 2024-05-16 20:07:12 +11:00
Георгий Торопов e8a186df60 Fix missing letters in ru_ru.lang (#397) 2024-05-12 12:41:49 +11:00
Ghzdude 6425ef6ecd Fix NPE when posting changes for storage busses (#405) 2024-02-24 10:25:51 +08:00
Yang Xizhi 7ebb2a0fbb allow custom slot jei check and fix fluid color in cell workbanch (#401) 2024-02-18 23:06:07 -06:00
Neeve 20a1fec6fb Recache OreDict Buses on RegEx changes & adjust visibility logic (#395) 2024-02-05 13:05:31 +11:00
Yang Xizhi 0fffc829ab Fix invalid pattern outputs throwing NPE in crafting grid (#393) 2024-02-01 19:14:33 +11:00
NotMyWing 88635d9a8d Do not check white-/blacklist on extract
Slightly rollbacks #384, since extractables are filtered in getAvailableItems
Allows extracting inaccessible items from cells and overriding SB behavior via reporting non-extractables
2024-02-01 18:33:13 +11:00
Neeve 0fd0ed1b1c Fix Fluid Cells having no upgrades (#392) 2024-01-31 19:37:05 +11:00
Neeve 87f884228e Fix ME Storage Buses reporting contents regardless of settings (#384) 2024-01-30 16:10:52 +11:00
Serenibyss 3495d3dfd4 Use LoadingCache instead of HashMap for CableBusBakedModel (#385) 2024-01-30 14:19:50 +11:00
ZHAY10086 0acb03b83d Add zh_cn.lang entries for Sticky Card (#381) 2024-01-21 13:55:57 +11:00
85 changed files with 2144 additions and 748 deletions
+21
View File
@@ -0,0 +1,21 @@
name: Build
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up OpenJDK 17
uses: actions/setup-java@v2
with:
java-version: '17'
distribution: 'adopt' # You can choose other OpenJDK distributions.
- name: Build with Gradle
run: ./gradlew build # Ensure your gradlew script is executable
- name: Upload Artifact
uses: actions/upload-artifact@v2
with:
name: AE2-UEL
path: build/libs/*.jar # Make sure this path matches the location of your build artifacts
@@ -38,8 +38,11 @@ public enum ActionItems
DIVIDE_BY_THREE,
DECREASE_BY_ONE,
MAX_COUNT,
FREE_MOLECULAR_SLOT_SHORTCUT,
MOLECULAR_ASSEMBLERS_ON,
MOLECULAR_ASSEMBLERS_OFF,
TOGGLE_SHOW_FULL_INTERFACES_ON,
TOGGLE_SHOW_FULL_INTERFACES_OFF,
TOGGLE_SHOW_ONLY_INVALID_PATTERNS_ON,
TOGGLE_SHOW_ONLY_INVALID_PATTERNS_OFF,
HIGHLIGHT_INTERFACE
}
}
@@ -0,0 +1,26 @@
package appeng.api.config;
public enum LockCraftingMode {
/**
* Crafting is never locked.
*/
NONE,
/**
* After pushing a pattern to an adjacent machine, the pattern provider will not accept further crafts until a
* redstone pulse is received.
*/
LOCK_UNTIL_PULSE,
/**
* Crafting is locked while the pattern provider is receiving a redstone signal.
*/
LOCK_WHILE_HIGH,
/**
* Crafting is locked while the pattern provider is not receiving a redstone signal.
*/
LOCK_WHILE_LOW,
/**
* After pushing a pattern to an adjacent machine, the pattern provider will not accept further crafts until the
* primary pattern result is returned to the network through the pattern provider.
*/
LOCK_UNTIL_RESULT
}
@@ -57,6 +57,8 @@ public enum Settings
IO_DIRECTION( EnumSet.of( RelativeDirection.LEFT, RelativeDirection.RIGHT ) ),
UNLOCK(EnumSet.allOf(LockCraftingMode.class)),
BLOCK( EnumSet.of( YesNo.YES, YesNo.NO ) ),
OPERATION_MODE( EnumSet.allOf( OperationMode.class ) ),
@@ -19,12 +19,11 @@
package appeng.api.features;
import java.util.List;
import java.util.Optional;
import net.minecraft.item.ItemStack;
import javax.annotation.Nonnull;
import net.minecraft.item.ItemStack;
import java.util.List;
import java.util.Optional;
/**
@@ -57,21 +56,35 @@ public interface IInscriberRecipe
@Nonnull
ItemStack getOutput();
@Nonnull
List<ItemStack> getTopInputs();
/**
* gets the top optional
*
* @return item which is used top
*/
@Deprecated
@Nonnull
Optional<ItemStack> getTopOptional();
default Optional<ItemStack> getTopOptional(){
return getTopInputs().isEmpty() ? Optional.empty() : Optional.of(getTopInputs().get(0));
}
@Nonnull
List<ItemStack> getBottomInputs();
/**
* gets the bottom optional
*
* @return item which is used bottom
*/
@Deprecated
@Nonnull
Optional<ItemStack> getBottomOptional();
default Optional<ItemStack> getBottomOptional() {
return getBottomInputs().isEmpty() ? Optional.empty() : Optional.of(getBottomInputs().get(0));
}
/**
* type of inscriber process
@@ -19,11 +19,11 @@
package appeng.api.features;
import java.util.Collection;
import net.minecraft.item.ItemStack;
import javax.annotation.Nonnull;
import net.minecraft.item.ItemStack;
import java.util.Collection;
import java.util.Collections;
/**
@@ -66,7 +66,7 @@ public interface IInscriberRecipeBuilder
* @return currently used builder
*/
@Nonnull
IInscriberRecipeBuilder withTopOptional( @Nonnull ItemStack topOptional );
IInscriberRecipeBuilder withTopOptional(@Nonnull Collection<ItemStack> topOptional );
/**
* Creates an inscriber recipe with bot.
@@ -77,7 +77,7 @@ public interface IInscriberRecipeBuilder
* @return currently used builder
*/
@Nonnull
IInscriberRecipeBuilder withBottomOptional( @Nonnull ItemStack bottomOptional );
IInscriberRecipeBuilder withBottomOptional( @Nonnull Collection<ItemStack> bottomOptional );
/**
* Creates an inscriber recipe with type.
@@ -104,4 +104,14 @@ public interface IInscriberRecipeBuilder
*/
@Nonnull
IInscriberRecipe build();
@Deprecated
default IInscriberRecipeBuilder withTopOptional(@Nonnull ItemStack topOptional){
return withTopOptional(Collections.singleton(topOptional));
}
@Deprecated
default IInscriberRecipeBuilder withBottomOptional(@Nonnull ItemStack bottomOptional){
return withBottomOptional(Collections.singleton(bottomOptional));
}
}
@@ -77,6 +77,14 @@ public interface ICraftingPatternDetails
*/
IAEItemStack[] getCondensedOutputs();
/**
* The primary output of this pattern. The pattern will only be used to craft the primary output; the others are
* just byproducts.
*/
default IAEItemStack getPrimaryOutput() {
return getOutputs()[0];
}
/**
* @return a list of the outputs, will include nulls.
*/
@@ -0,0 +1,87 @@
package yalter.mousetweaks.api;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.Slot;
/**
* This is the interface you want to implement in your GuiScreen to make it compatible with Mouse Tweaks.
* If this interface is not enough (for example, you need a custom slot click function, or if you use a custom Container
* which happens to be incompatible), check IMTModGuiContainer2Ex instead.
* If you just need to disable Mouse Tweaks or the wheel tweak, see the MouseTweaksIgnore
* or the MouseTweaksDisableWheelTweak annotations.
*/
public interface IMTModGuiContainer2 {
/**
* If you want to disable Mouse Tweaks in your GuiScreen, return true from this method.
*
* @return True if Mouse Tweaks should be disabled, false otherwise.
*/
boolean MT_isMouseTweaksDisabled();
/**
* If you want to disable the Wheel Tweak in your GuiScreen, return true from this method.
*
* @return True if the Wheel Tweak should be disabled, false otherwise.
*/
boolean MT_isWheelTweakDisabled();
/**
* Returns the Container.
*
* @return Container that is currently in use.
*/
Container MT_getContainer();
/**
* Returns the Slot that is currently selected by the player, or null if no Slot is selected.
*
* @return Slot that is located under the mouse, or null if no Slot it currently under the mouse.
*/
Slot MT_getSlotUnderMouse();
/**
* Return true if the given Slot behaves like the vanilla crafting output slots (inside the crafting table,
* or the furnace output slot, or the anvil output slot, etc.). These slots are handled differently by Mouse Tweaks.
*
* @param slot the slot to check
* @return True if slot is a crafting output slot.
*/
boolean MT_isCraftingOutput(Slot slot);
/**
* Return true if the given Slot should be ignored by Mouse Tweaks. Examples of ignored slots are the item select
* slots and the Destroy Item slot in the vanilla creative inventory.
*
* @param slot the slot to check
* @return Tru if slot should be ignored by Mouse Tweaks.
*/
boolean MT_isIgnored(Slot slot);
/**
* If your container has an RMB dragging functionality (like vanilla containers), disable it inside this method.
* This method is called every frame (render tick), which is after all mouseClicked / mouseClickMove / mouseReleased
* events are handled (although note these events are handled every game tick, which is far less frequent than every
* render tick).<br><br>
* <p>
* If true is returned from this method, Mouse Tweaks (after checking other conditions like isIgnored) will click
* the slot on which the right mouse button was initially pressed (in most cases this is the slot currently under
* mouse). This is needed because the vanilla RMB dragging functionality prevents the initial slot click.<br><br>
* <p>
* For vanilla containers this method looks like this:
* <pre>
* this.ignoreMouseUp = true;
*
* if (this.dragSplitting) {
* if (this.dragSplittingButton == 1) {
* this.dragSplitting = false;
* return true;
* }
* }
*
* return false;
* </pre>
*
* @return True if Mouse Tweaks should click the slot on which the RMB was pressed.
*/
boolean MT_disableRMBDraggingFunctionality();
}
@@ -1,14 +0,0 @@
package yalter.mousetweaks.api;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Put this on your GuiScreen to disable Mouse Tweaks.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MouseTweaksIgnore {
}
@@ -25,12 +25,14 @@ import appeng.block.AEBaseTileBlock;
import appeng.core.sync.GuiBridge;
import appeng.tile.misc.TileInterface;
import appeng.util.Platform;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.block.properties.IProperty;
import net.minecraft.block.properties.PropertyBool;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
@@ -93,4 +95,12 @@ public class BlockInterface extends AEBaseTileBlock {
((TileInterface) rotatable).setSide(axis);
}
}
@Override
public void neighborChanged(IBlockState state, World worldIn, BlockPos pos, Block blockIn, BlockPos fromPos) {
TileEntity tileEntity = this.getTileEntity(worldIn, pos);
if (tileEntity != null) {
((TileInterface) tileEntity).updateRedstoneState();
}
}
}
+113 -6
View File
@@ -72,7 +72,7 @@ import net.minecraftforge.fml.common.Optional;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.GL11;
import yalter.mousetweaks.api.MouseTweaksIgnore;
import yalter.mousetweaks.api.IMTModGuiContainer2;
import java.awt.*;
import java.io.IOException;
@@ -85,9 +85,8 @@ import java.util.concurrent.TimeUnit;
import static appeng.integration.modules.jei.JEIPlugin.aeGuiHandler;
import static appeng.integration.modules.jei.JEIPlugin.runtime;
@MouseTweaksIgnore
public abstract class AEBaseGui extends GuiContainer {
@Optional.Interface(iface = "yalter.mousetweaks.api.IMTModGuiContainer2", modid = "mousetweaks")
public abstract class AEBaseGui extends GuiContainer implements IMTModGuiContainer2 {
private final List<InternalSlotME> meSlots = new ArrayList<>();
// drag y
private final Set<Slot> drag_click = new HashSet<>();
@@ -258,7 +257,7 @@ public abstract class AEBaseGui extends GuiContainer {
}
}
private void drawTooltip(ITooltip tooltip, int mouseX, int mouseY) {
protected void drawTooltip(ITooltip tooltip, int mouseX, int mouseY) {
final int x = tooltip.xPos(); // ((GuiImgButton) c).x;
int y = tooltip.yPos(); // ((GuiImgButton) c).y;
@@ -950,10 +949,42 @@ public abstract class AEBaseGui extends GuiContainer {
this.zLevel = 0.0F;
this.itemRender.zLevel = 0.0F;
boolean wasDragSplitting = this.dragSplitting;
this.dragSplitting = false; // to prevent the vanilla slot renderer from rendering the stack count during drag splitting, we're re-enabling it later
// Annoying but easier than trying to splice into render item
super.drawSlot(s);
this.stackSizeRenderer.renderStackSize(this.fontRenderer, AEItemStack.fromItemStack(appEngSlot.getDisplayStack()), s.xPos, s.yPos);
ItemStack stackInSlot = ((AppEngSlot)s).getDisplayStack();
ItemStack stackUnderCursor = this.mc.player.inventory.getItemStack();
if (wasDragSplitting
&& this.dragSplittingSlots.contains(s)
&& this.dragSplittingSlots.size() > 1
&& !stackUnderCursor.isEmpty()) {
if (Container.canAddItemToSlot(s, stackUnderCursor, true) && this.inventorySlots.canDragIntoSlot(s))
{
drawRect(s.xPos, s.yPos, s.xPos + 16, s.yPos + 16, -2130706433);
stackInSlot = stackUnderCursor.copy();
Container.computeStackSize(this.dragSplittingSlots, this.dragSplittingLimit, stackInSlot, s.getStack().isEmpty() ? 0 : s.getStack().getCount());
int k = Math.min(stackInSlot.getMaxStackSize(), s.getItemStackLimit(stackInSlot));
if (stackInSlot.getCount() > k)
{
stackInSlot.setCount(k);
}
}
else
{
this.dragSplittingSlots.remove(s);
this.updateDragSplitting();
}
}
this.dragSplitting = wasDragSplitting;
this.stackSizeRenderer.renderStackSize(this.fontRenderer, AEItemStack.fromItemStack(stackInSlot), s.xPos, s.yPos);
return;
} else {
super.drawSlot(s);
@@ -988,4 +1019,80 @@ public abstract class AEBaseGui extends GuiContainer {
protected List<InternalSlotME> getMeSlots() {
return this.meSlots;
}
// TODO: remove this when refactoring slot rendering
private void updateDragSplitting()
{
ItemStack itemstack = this.mc.player.inventory.getItemStack();
if (!itemstack.isEmpty() && this.dragSplitting)
{
if (this.dragSplittingLimit == 2)
{
this.dragSplittingRemnant = itemstack.getMaxStackSize();
}
else
{
this.dragSplittingRemnant = itemstack.getCount();
for (Slot slot : this.dragSplittingSlots)
{
ItemStack itemstack1 = itemstack.copy();
ItemStack itemstack2 = slot.getStack();
int i = itemstack2.isEmpty() ? 0 : itemstack2.getCount();
Container.computeStackSize(this.dragSplittingSlots, this.dragSplittingLimit, itemstack1, i);
int j = Math.min(itemstack1.getMaxStackSize(), slot.getItemStackLimit(itemstack1));
if (itemstack1.getCount() > j)
{
itemstack1.setCount(j);
}
this.dragSplittingRemnant -= itemstack1.getCount() - i;
}
}
}
}
@Override
@Optional.Method(modid = "mousetweaks")
public boolean MT_isMouseTweaksDisabled() {
return true;
}
@Override
@Optional.Method(modid = "mousetweaks")
public boolean MT_isWheelTweakDisabled() {
return true;
}
@Override
@Optional.Method(modid = "mousetweaks")
public Container MT_getContainer() {
return this.inventorySlots;
}
@Override
@Optional.Method(modid = "mousetweaks")
public Slot MT_getSlotUnderMouse() {
return getSlotUnderMouse();
}
@Override
@Optional.Method(modid = "mousetweaks")
public boolean MT_isCraftingOutput(Slot slot) {
return slot instanceof SlotOutput || slot instanceof AppEngCraftingSlot;
}
@Override
@Optional.Method(modid = "mousetweaks")
public boolean MT_isIgnored(Slot slot) {
return true;
}
@Override
@Optional.Method(modid = "mousetweaks")
public boolean MT_disableRMBDraggingFunctionality() {
return true;
}
}
@@ -1,10 +1,14 @@
package appeng.client.gui;
import appeng.api.storage.data.IAEItemStack;
import appeng.client.gui.implementations.*;
import appeng.client.gui.implementations.GuiCraftAmount;
import appeng.client.gui.implementations.GuiCraftConfirm;
import appeng.client.gui.implementations.GuiCraftingCPU;
import appeng.client.gui.implementations.GuiExpandedProcessingPatternTerm;
import appeng.client.gui.implementations.GuiPatternTerm;
import appeng.client.gui.implementations.GuiUpgradeable;
import appeng.container.interfaces.IJEIGhostIngredients;
import appeng.container.slot.SlotFake;
import appeng.fluids.client.gui.widgets.GuiFluidSlot;
import appeng.container.slot.IJEITargetSlot;
import mezz.jei.api.gui.IAdvancedGuiHandler;
import mezz.jei.api.gui.IGhostIngredientHandler;
import net.minecraft.client.gui.GuiScreen;
@@ -78,12 +82,12 @@ public class AEGuiHandler implements IAdvancedGuiHandler<AEBaseGui>, IGhostIngre
return (guiSloty * 3) + guiSlotx + (currentScroll * 3);
}
@SuppressWarnings("unchecked")
@Override
@Nonnull
public <I> List<Target<I>> getTargets(@Nonnull AEBaseGui gui, @Nonnull I ingredient, boolean doStart) {
ArrayList<Target<I>> targets = new ArrayList<>();
if (gui instanceof IJEIGhostIngredients) {
IJEIGhostIngredients g = (IJEIGhostIngredients) gui;
if (gui instanceof IJEIGhostIngredients g) {
List<Target<?>> phantomTargets = g.getPhantomTargets(ingredient);
targets.addAll((List<Target<I>>) (Object) phantomTargets);
}
@@ -91,13 +95,8 @@ public class AEGuiHandler implements IAdvancedGuiHandler<AEBaseGui>, IGhostIngre
if (gui instanceof GuiUpgradeable || gui instanceof GuiPatternTerm || gui instanceof GuiExpandedProcessingPatternTerm) {
IJEIGhostIngredients ghostGui = ((IJEIGhostIngredients) gui);
for (Target<I> target : targets) {
if (ghostGui.getFakeSlotTargetMap().get(target) instanceof SlotFake) {
if (((SlotFake) ghostGui.getFakeSlotTargetMap().get(target)).getStack().isEmpty()) {
target.accept(ingredient);
break;
}
} else if (ghostGui.getFakeSlotTargetMap().get(target) instanceof GuiFluidSlot) {
if (((GuiFluidSlot) ghostGui.getFakeSlotTargetMap().get(target)).getFluidStack() == null) {
if (ghostGui.getFakeSlotTargetMap().get(target) instanceof IJEITargetSlot jeiSlot) {
if (jeiSlot.needAccept()) {
target.accept(ingredient);
break;
}
@@ -19,6 +19,7 @@
package appeng.client.gui.implementations;
import appeng.api.config.LockCraftingMode;
import appeng.api.config.Settings;
import appeng.api.config.YesNo;
import appeng.client.gui.widgets.GuiImgButton;
@@ -41,6 +42,7 @@ import java.io.IOException;
public class GuiInterface extends GuiUpgradeable {
private GuiTabButton priority;
private GuiImgButton UnlockMode;
private GuiImgButton BlockMode;
private GuiToggleButton interfaceMode;
@@ -57,7 +59,10 @@ public class GuiInterface extends GuiUpgradeable {
this.BlockMode = new GuiImgButton(this.guiLeft - 18, this.guiTop + 8, Settings.BLOCK, YesNo.NO);
this.buttonList.add(this.BlockMode);
this.interfaceMode = new GuiToggleButton(this.guiLeft - 18, this.guiTop + 26, 84, 85, GuiText.InterfaceTerminal.getLocal(), GuiText.InterfaceTerminalHint.getLocal());
this.UnlockMode = new GuiImgButton(this.guiLeft - 18,this.guiTop + 26 ,Settings.UNLOCK, LockCraftingMode.NONE);
this.buttonList.add(this.UnlockMode);
this.interfaceMode = new GuiToggleButton(this.guiLeft - 18, this.guiTop + 44, 84, 85, GuiText.InterfaceTerminal.getLocal(), GuiText.InterfaceTerminalHint.getLocal());
this.buttonList.add(this.interfaceMode);
}
@@ -67,6 +72,10 @@ public class GuiInterface extends GuiUpgradeable {
this.BlockMode.set(((ContainerInterface) this.cvb).getBlockingMode());
}
if (this.UnlockMode != null) {
this.UnlockMode.set(((ContainerInterface) this.cvb).getUnlockMode());
}
if (this.interfaceMode != null) {
this.interfaceMode.setState(((ContainerInterface) this.cvb).getInterfaceTerminalMode() == YesNo.YES);
}
@@ -106,6 +115,10 @@ public class GuiInterface extends GuiUpgradeable {
if (btn == this.BlockMode) {
NetworkHandler.instance().sendToServer(new PacketConfigButton(this.BlockMode.getSetting(), backwards));
}
if (btn == this.UnlockMode) {
NetworkHandler.instance.sendToServer(new PacketConfigButton(this.UnlockMode.getSetting(), backwards));
}
}
}
@@ -27,14 +27,18 @@ import appeng.api.storage.channels.IItemStorageChannel;
import appeng.client.gui.AEBaseGui;
import appeng.client.gui.widgets.GuiImgButton;
import appeng.client.gui.widgets.GuiScrollbar;
import appeng.client.gui.widgets.MEGuiTextField;
import appeng.client.gui.widgets.MEGuiTooltipTextField;
import appeng.client.me.ClientDCInternalInv;
import appeng.client.me.SlotDisconnected;
import appeng.container.implementations.ContainerInterfaceTerminal;
import appeng.container.slot.AppEngSlot;
import appeng.core.AEConfig;
import appeng.core.AppEng;
import appeng.core.localization.ButtonToolTips;
import appeng.core.localization.GuiText;
import appeng.core.localization.PlayerMessages;
import appeng.helpers.DualityInterface;
import appeng.helpers.PatternHelper;
import appeng.parts.reporting.PartInterfaceTerminal;
import appeng.util.BlockPosUtils;
import appeng.util.Platform;
@@ -42,13 +46,12 @@ import com.google.common.collect.HashMultimap;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.nbt.NBTUtil;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.world.World;
import net.minecraftforge.common.DimensionManager;
import net.minecraftforge.common.util.Constants;
import net.minecraftforge.fml.common.Loader;
@@ -71,15 +74,12 @@ import static appeng.helpers.ItemStackHelper.stackFromNBT;
public class GuiInterfaceTerminal extends AEBaseGui {
private int rows = 6;
private static final int OFFSET_X = 21;
private static final int MAGIC_HEIGHT_NUMBER = 52 + 99;
private static final String MOLECULAR_ASSEMBLER = "molecular assembler";
// TODO: copied from GuiMEMonitorable. It looks not changed, maybe unneeded?
private final int offsetX = 21;
private int maxRows = Integer.MAX_VALUE;
protected int jeiOffset = Loader.isModLoaded("jei") ? 24 : 0;
private int reservedSpace = 0;
private final boolean jeiEnabled;
private final int jeiButtonPadding;
private final HashMap<Long, ClientDCInternalInv> byId = new HashMap<>();
private final HashMultimap<String, ClientDCInternalInv> byName = HashMultimap.create();
@@ -89,99 +89,116 @@ public class GuiInterfaceTerminal extends AEBaseGui {
private final ArrayList<String> names = new ArrayList<>();
private final ArrayList<Object> lines = new ArrayList<>();
private final Set<Object> matchedStacks = new HashSet<>();
private final Set<ClientDCInternalInv> matchedInterfaces = new HashSet<>();
private final Map<String, Set<Object>> cachedSearches = new WeakHashMap<>();
private final Map<ClientDCInternalInv, Integer> dimHashMap = new HashMap<>();
private final MEGuiTooltipTextField searchFieldOutputs;
private final MEGuiTooltipTextField searchFieldInputs;
private final MEGuiTooltipTextField searchFieldNames;
private final GuiImgButton guiButtonHideFull;
private final GuiImgButton guiButtonAssemblersOnly;
private final GuiImgButton guiButtonBrokenRecipes;
private final GuiImgButton terminalStyleBox;
private boolean refreshList = false;
private MEGuiTextField searchFieldOutputs;
private MEGuiTextField searchFieldInputs;
private final PartInterfaceTerminal partInterfaceTerminal;
private GuiButton guiButtonHide;
private GuiButton guiButtonNextAssembler;
private GuiImgButton terminalStyleBox;
private final HashMap<ClientDCInternalInv, Integer> dimHashMap = new HashMap<>();
private int drawnRows = 0;
/* These are worded so that the intended default is false */
private boolean onlyShowWithSpace = false;
private boolean onlyMolecularAssemblers = false;
private boolean onlyBrokenRecipes = false;
private int rows = 6;
public GuiInterfaceTerminal(final InventoryPlayer inventoryPlayer, final PartInterfaceTerminal te) {
super(new ContainerInterfaceTerminal(inventoryPlayer, te));
this.partInterfaceTerminal = te;
final GuiScrollbar scrollbar = new GuiScrollbar();
this.setScrollBar(scrollbar);
this.xSize = 208;
this.ySize = 255;
this.setReservedSpace(82);
this.jeiEnabled = Loader.isModLoaded("jei");
this.jeiButtonPadding = jeiEnabled ? 22 : 0;
searchFieldInputs = createTextField(86, 12, ButtonToolTips.SearchFieldInputs.getLocal());
searchFieldOutputs = createTextField(86, 12, ButtonToolTips.SearchFieldOutputs.getLocal());
searchFieldNames = createTextField(71, 12, ButtonToolTips.SearchFieldNames.getLocal());
searchFieldNames.setFocused(true);
guiButtonAssemblersOnly = new GuiImgButton(0, 0, Settings.ACTIONS, null);
guiButtonHideFull = new GuiImgButton(0, 0, Settings.ACTIONS, null);
guiButtonBrokenRecipes = new GuiImgButton(0, 0, Settings.ACTIONS, null);
terminalStyleBox = new GuiImgButton(0, 0, Settings.TERMINAL_STYLE, null);
}
private MEGuiTooltipTextField createTextField(final int width, final int height, final String tooltip) {
MEGuiTooltipTextField textField = new MEGuiTooltipTextField(width, height, tooltip) {
@Override
public void onTextChange(String oldText) {
refreshList();
}
};
textField.setEnableBackgroundDrawing(false);
textField.setMaxStringLength(25);
textField.setTextColor(0xFFFFFF);
textField.setCursorPositionZero();
return textField;
}
private void setScrollBar() {
this.getScrollBar().setTop(52).setLeft(189).setHeight(this.rows * 18 - 2);
this.getScrollBar().setRange(0, this.lines.size() - 1, 1);
}
private int calculateRowsCount() {
final int maxRows = getMaxRows();
final int jeiPadding = jeiEnabled ? 22 + 18 : 0;
final int extraSpace = this.height - MAGIC_HEIGHT_NUMBER - jeiPadding;
return Math.max(6, Math.min(maxRows, extraSpace / 18));
}
@Override
public void initGui() {
this.maxRows = AEConfig.instance()
.getConfigManager()
.getSetting(
Settings.TERMINAL_STYLE) != TerminalStyle.TALL ? 6 : Integer.MAX_VALUE;
final int magicNumber = 82 + 14;
final int extraSpace = this.height - magicNumber - this.reservedSpace;
this.rows = (int) Math.floor(extraSpace / 18);
if (this.rows > this.maxRows) {
this.rows = this.maxRows;
}
if (this.rows < 6) {
this.rows = 6;
}
this.ySize = magicNumber + this.rows * 18 + this.reservedSpace;
// this.guiTop = top;
final int unusedSpace = this.height - this.ySize;
this.guiTop = (int) Math.floor(unusedSpace / (unusedSpace < 0 ? 3.8f : 2.0f));
this.rows = calculateRowsCount();
super.initGui();
this.getScrollBar().setLeft(189);
this.getScrollBar().setHeight(106);
this.getScrollBar().setTop(51);
this.ySize = MAGIC_HEIGHT_NUMBER + this.rows * 18;
final int unusedSpace = this.height - this.ySize;
this.guiTop = (int) Math.floor(unusedSpace / (unusedSpace < 0 ? 3.8f : 2.0f));
this.searchFieldInputs = new MEGuiTextField(this.fontRenderer, this.guiLeft + Math.max(32, this.offsetX), this.guiTop + 25, 65, 12);
this.searchFieldInputs.setEnableBackgroundDrawing(false);
this.searchFieldInputs.setMaxStringLength(25);
this.searchFieldInputs.setTextColor(0xFFFFFF);
this.searchFieldInputs.setVisible(true);
this.searchFieldInputs.setFocused(false);
searchFieldInputs.x = guiLeft + 32;
searchFieldInputs.y = guiTop + 25;
searchFieldOutputs.x = guiLeft + 32;
searchFieldOutputs.y = guiTop + 38;
searchFieldNames.x = guiLeft + 32 + 99;
searchFieldNames.y = guiTop + 38;
this.searchFieldOutputs = new MEGuiTextField(this.fontRenderer, this.guiLeft + Math.max(32, this.offsetX), this.guiTop + 38, 65, 12);
this.searchFieldOutputs.setEnableBackgroundDrawing(false);
this.searchFieldOutputs.setMaxStringLength(25);
this.searchFieldOutputs.setTextColor(0xFFFFFF);
this.searchFieldOutputs.setVisible(true);
this.searchFieldOutputs.setFocused(true);
this.searchFieldInputs.setText(partInterfaceTerminal.in);
this.searchFieldOutputs.setText(partInterfaceTerminal.out);
this.fontRenderer.drawString(this.getGuiDisplayName(GuiText.InterfaceTerminal.getLocal()), 8, 6, 4210752);
this.fontRenderer.drawString(GuiText.inventory.getLocal(), this.offsetX + 2, this.ySize - 96 + 3, 4210752);
terminalStyleBox.x = guiLeft - 18;
terminalStyleBox.y = guiTop + 8 + jeiButtonPadding;
guiButtonBrokenRecipes.x = guiLeft - 18;
guiButtonBrokenRecipes.y = terminalStyleBox.y + 20;
guiButtonHideFull.x = guiLeft - 18;
guiButtonHideFull.y = guiButtonBrokenRecipes.y + 20;
guiButtonAssemblersOnly.x = guiLeft - 18;
guiButtonAssemblersOnly.y = guiButtonHideFull.y + 20;
this.setScrollBar();
this.repositionSlots();
}
protected void repositionSlot(final AppEngSlot s) {
this.ySize = 82 + 14 + this.drawnRows * 18 + this.reservedSpace;
s.yPos = s.getY() + this.ySize - 112;
s.xPos = s.getX() + 14;
}
@Override
public void onGuiClosed() {
partInterfaceTerminal.saveSearchStrings(this.searchFieldInputs.getText().toLowerCase(), this.searchFieldOutputs.getText().toLowerCase());
super.onGuiClosed();
protected void repositionSlots() {
for (final Object obj : this.inventorySlots.inventorySlots) {
if (obj instanceof AppEngSlot slot) {
slot.yPos = this.ySize + slot.getY() - 78 - 7;
slot.xPos = slot.getX() + 14;
}
}
}
@Override
public List<Rectangle> getJEIExclusionArea() {
Rectangle tallButton = new Rectangle(this.guiLeft - 18, this.guiTop + 24 + jeiOffset, 18, 18);
Rectangle tallButton = new Rectangle(this.guiLeft - 18, this.guiTop + 24 + 24, 18, 18);
List<Rectangle> area = new ArrayList<>();
area.add(tallButton);
return area;
@@ -189,93 +206,98 @@ public class GuiInterfaceTerminal extends AEBaseGui {
@Override
public void drawFG(final int offsetX, final int offsetY, final int mouseX, final int mouseY) {
this.buttonList.clear();
this.fontRenderer.drawString(this.getGuiDisplayName(GuiText.InterfaceTerminal.getLocal()), OFFSET_X + 2, 6, 4210752);
this.fontRenderer.drawString(GuiText.inventory.getLocal(), OFFSET_X + 2, this.ySize - 96, 4210752);
final int currentScroll = this.getScrollBar().getCurrentScroll();
this.guiButtonNextAssembler = new GuiImgButton(guiLeft + 123, guiTop + 25, Settings.ACTIONS, ActionItems.FREE_MOLECULAR_SLOT_SHORTCUT);
this.buttonList.add(guiButtonNextAssembler);
guiButtonHide = new GuiImgButton(guiLeft + 141, guiTop + 25, Settings.ACTIONS, this.partInterfaceTerminal.onlyInterfacesWithFreeSlots ? ActionItems.TOGGLE_SHOW_FULL_INTERFACES_OFF : ActionItems.TOGGLE_SHOW_FULL_INTERFACES_ON);
this.buttonList.add(guiButtonHide);
this.buttonList.add(this.terminalStyleBox = new GuiImgButton(this.guiLeft - 18, guiTop + 24 + jeiOffset, Settings.TERMINAL_STYLE, AEConfig.instance()
.getConfigManager()
.getSetting(Settings.TERMINAL_STYLE)));
this.inventorySlots.inventorySlots.removeIf(slot -> slot instanceof SlotDisconnected);
for (final Slot s : this.inventorySlots.inventorySlots) {
if (s instanceof AppEngSlot) {
if (s.xPos < 197) {
this.repositionSlot((AppEngSlot) s);
}
}
}
int offset = 52;
int offset = 51;
int linesDraw = 0;
for (int x = 0; x < rows && linesDraw < rows && currentScroll + x < this.lines.size(); x++) {
final Object lineObj = this.lines.get(currentScroll + x);
if (lineObj instanceof ClientDCInternalInv) {
final ClientDCInternalInv inv = (ClientDCInternalInv) lineObj;
GuiButton guiButton = new GuiImgButton(guiLeft + 4, guiTop + offset, Settings.ACTIONS, ActionItems.HIGHLIGHT_INTERFACE);
guiButtonHashMap.put(guiButton, inv);
this.buttonList.add(guiButton);
int extraLines = numUpgradesMap.get(inv);
if (lineObj instanceof ClientDCInternalInv inv) {
final int extraLines = numUpgradesMap.get(inv);
for (int row = 0; row < 1 + extraLines && linesDraw < rows; ++row) {
for (int z = 0; z < 9; z++) {
this.inventorySlots.inventorySlots.add(new SlotDisconnected(inv, z + (row * 9), (z * 18 + 22), offset));
if (this.matchedStacks.contains(inv.getInventory().getStackInSlot(z + (row * 9)))) {
drawRect(z * 18 + 22, offset, z * 18 + 22 + 16, offset + 16, 0x8A00FF00);
} else if (!matchedInterfaces.contains(inv)) {
drawRect(z * 18 + 22, offset, z * 18 + 22 + 16, offset + 16, 0x6A000000);
drawRect(z * 18 + 22, 1 + offset, z * 18 + 22 + 16, 1 + offset + 16, 0x2A00FF00);
}
}
linesDraw++;
offset += 18;
}
} else if (lineObj instanceof String) {
String name = (String) lineObj;
} else if (lineObj instanceof String name) {
final int rows = this.byName.get(name).size();
if (rows > 1) {
name = name + " (" + rows + ')';
}
while (name.length() > 2 && this.fontRenderer.getStringWidth(name) > 155) {
while (name.length() > 2 && this.fontRenderer.getStringWidth(name) > 158) {
name = name.substring(0, name.length() - 1);
}
this.fontRenderer.drawString(name, this.offsetX + 2, 5 + offset, 4210752);
this.fontRenderer.drawString(name, OFFSET_X + 3, 6 + offset, 4210752);
linesDraw++;
offset += 18;
}
}
}
@Override
public void drawScreen(int mouseX, int mouseY, float partialTicks) {
buttonList.clear();
guiButtonHashMap.clear();
inventorySlots.inventorySlots.removeIf(slot -> slot instanceof SlotDisconnected);
guiButtonAssemblersOnly.set(onlyMolecularAssemblers ? ActionItems.MOLECULAR_ASSEMBLERS_ON : ActionItems.MOLECULAR_ASSEMBLERS_OFF);
guiButtonHideFull.set(onlyShowWithSpace ? ActionItems.TOGGLE_SHOW_FULL_INTERFACES_OFF : ActionItems.TOGGLE_SHOW_FULL_INTERFACES_ON);
guiButtonBrokenRecipes.set(onlyBrokenRecipes ? ActionItems.TOGGLE_SHOW_ONLY_INVALID_PATTERNS_ON : ActionItems.TOGGLE_SHOW_ONLY_INVALID_PATTERNS_OFF);
terminalStyleBox.set(AEConfig.instance().getConfigManager().getSetting(Settings.TERMINAL_STYLE));
buttonList.add(guiButtonAssemblersOnly);
buttonList.add(guiButtonHideFull);
buttonList.add(guiButtonBrokenRecipes);
buttonList.add(terminalStyleBox);
int offset = 51;
final int currentScroll = this.getScrollBar().getCurrentScroll();
int linesDraw = 0;
for (int x = 0; x < rows && linesDraw < rows && currentScroll + x < this.lines.size(); x++) {
final Object lineObj = this.lines.get(currentScroll + x);
if (lineObj instanceof ClientDCInternalInv inv) {
GuiButton guiButton = new GuiImgButton(guiLeft + 4, guiTop + offset + 1, Settings.ACTIONS, ActionItems.HIGHLIGHT_INTERFACE);
guiButtonHashMap.put(guiButton, inv);
this.buttonList.add(guiButton);
final int extraLines = numUpgradesMap.get(inv);
for (int row = 0; row < 1 + extraLines && linesDraw < rows; ++row) {
for (int z = 0; z < 9; z++) {
this.inventorySlots.inventorySlots.add(new SlotDisconnected(inv, z + (row * 9), z * 18 + 22, 1+ offset));
}
linesDraw++;
offset += 18;
}
} else if (lineObj instanceof String) {
linesDraw++;
offset += 18;
}
}
if (searchFieldInputs.isMouseIn(mouseX, mouseY)) {
drawTooltip(Mouse.getEventX() * this.width / this.mc.displayWidth - offsetX, mouseY - guiTop, "Inputs OR names");
} else if (searchFieldOutputs.isMouseIn(mouseX, mouseY)) {
drawTooltip(Mouse.getEventX() * this.width / this.mc.displayWidth - offsetX, mouseY - guiTop, "Outputs OR names");
}
super.drawScreen(mouseX, mouseY, partialTicks);
drawTooltip(searchFieldInputs, mouseX, mouseY);
drawTooltip(searchFieldOutputs, mouseX, mouseY);
drawTooltip(searchFieldNames, mouseX, mouseY);
}
@Override
protected void mouseClicked(final int xCoord, final int yCoord, final int btn) throws IOException {
this.searchFieldInputs.mouseClicked(xCoord, yCoord, btn);
if (btn == 1 && this.searchFieldInputs.isMouseIn(xCoord, yCoord)) {
this.searchFieldInputs.setText("");
this.refreshList();
}
this.searchFieldOutputs.mouseClicked(xCoord, yCoord, btn);
if (btn == 1 && this.searchFieldOutputs.isMouseIn(xCoord, yCoord)) {
this.searchFieldOutputs.setText("");
this.refreshList();
}
this.searchFieldNames.mouseClicked(xCoord, yCoord, btn);
super.mouseClicked(xCoord, yCoord, btn);
}
@@ -289,54 +311,37 @@ public class GuiInterfaceTerminal extends AEBaseGui {
int interfaceDim = dimHashMap.get(guiButtonHashMap.get(this.selectedButton));
if (playerDim != interfaceDim) {
try {
mc.player.sendStatusMessage(new TextComponentString("Interface located at dimension: " + interfaceDim + " [" + DimensionManager.getWorld(interfaceDim).provider.getDimensionType().getName() + "] and cant be highlighted"), false);
mc.player.sendStatusMessage(PlayerMessages.InterfaceInOtherDimParam.get(interfaceDim, DimensionManager.getWorld(interfaceDim).provider.getDimensionType().getName()), false);
} catch (Exception e) {
mc.player.sendStatusMessage(new TextComponentString("Interface is located in another dimension and cannot be highlighted"), false);
mc.player.sendStatusMessage(PlayerMessages.InterfaceInOtherDim.get(), false);
}
} else {
hilightBlock(blockPos, System.currentTimeMillis() + 500 * BlockPosUtils.getDistance(blockPos, blockPos2), playerDim);
mc.player.sendStatusMessage(new TextComponentString("The interface is now highlighted at " + "X: " + blockPos.getX() + " Y: " + blockPos.getY() + " Z: " + blockPos.getZ()), false);
mc.player.sendStatusMessage(PlayerMessages.InterfaceHighlighted.get(blockPos.getX(), blockPos.getY(), blockPos.getZ()), false);
}
mc.player.closeScreen();
}
if (btn instanceof GuiImgButton) {
final boolean backwards = Mouse.isButtonDown(1);
final GuiImgButton iBtn = (GuiImgButton) btn;
} else if (btn == guiButtonHideFull) {
onlyShowWithSpace = !onlyShowWithSpace;
this.refreshList();
} else if (btn == guiButtonAssemblersOnly) {
onlyMolecularAssemblers = !onlyMolecularAssemblers;
this.refreshList();
} else if (btn == guiButtonBrokenRecipes) {
onlyBrokenRecipes = !onlyBrokenRecipes;
this.refreshList();
} else if (btn instanceof GuiImgButton iBtn) {
if (iBtn.getSetting() != Settings.ACTIONS) {
final Enum cv = iBtn.getCurrentValue();
final Enum next = Platform.rotateEnum(cv, backwards, iBtn.getSetting().getPossibleValues());
final Enum<?> cv = iBtn.getCurrentValue();
final boolean backwards = Mouse.isButtonDown(1);
final Enum<?> next = Platform.rotateEnum(cv, backwards, iBtn.getSetting().getPossibleValues());
if (btn == this.terminalStyleBox) {
AEConfig.instance().getConfigManager().putSetting(iBtn.getSetting(), next);
}
iBtn.set(next);
if (next.getClass() == TerminalStyle.class) {
this.reinitalize();
}
iBtn.set(next);
}
}
if (btn == guiButtonHide) {
partInterfaceTerminal.onlyInterfacesWithFreeSlots = !partInterfaceTerminal.onlyInterfacesWithFreeSlots;
this.refreshList();
}
if (btn == guiButtonNextAssembler) {
// Set Search to "Molecular Assembler" and set "Only Free Interface"
boolean currentOnlyInterfacesWithFreeSlots = this.partInterfaceTerminal.onlyInterfacesWithFreeSlots;
String currentSearchText = this.searchFieldOutputs.getText();
this.partInterfaceTerminal.onlyInterfacesWithFreeSlots = true;
this.searchFieldOutputs.setText("Molecular Assembler");
this.refreshList();
this.partInterfaceTerminal.onlyInterfacesWithFreeSlots = currentOnlyInterfacesWithFreeSlots;
this.searchFieldOutputs.setText(currentSearchText);
}
}
private void reinitalize() {
@@ -347,74 +352,66 @@ public class GuiInterfaceTerminal extends AEBaseGui {
@Override
public void drawBG(final int offsetX, final int offsetY, final int mouseX, final int mouseY) {
this.bindTexture("guis/newinterfaceterminal.png");
//split the texture for the top
this.drawTexturedModalRect(offsetX, offsetY, 0, 0, this.xSize, 166);
// draw the top portion of the background, above the interface list
this.drawTexturedModalRect(offsetX, offsetY, 0, 0, this.xSize, 53);
for (int x = 0; x < this.rows; x++) {
// draw the background of the rows in the interface list
this.drawTexturedModalRect(offsetX, offsetY + 53 + x * 18, 0, 52, this.xSize, 18);
}
int offset = 51;
final int ex = this.getScrollBar().getCurrentScroll();
int linesDraw = 0;
for (int x = 0; x < rows && linesDraw < rows && ex + x < this.lines.size(); x++) {
for (int x = 0; x < this.rows && linesDraw < rows && ex + x < this.lines.size(); x++) {
final Object lineObj = this.lines.get(ex + x);
if (lineObj instanceof ClientDCInternalInv) {
GlStateManager.color(1, 1, 1, 1);
final int width = 9 * 18;
final int extraLines = numUpgradesMap.get(lineObj);
int extraLines = numUpgradesMap.get(lineObj);
// draw the slot backgrounds
for (int row = 0; row < 1 + extraLines && linesDraw < rows; ++row) {
if (linesDraw == 6) {
this.drawTexturedModalRect(offsetX, offsetY + offset + 7, 0, 166, 190, 7);
this.drawTexturedModalRect(offsetX, offsetY + offset + 14, 0, 166, 190, 4);
} else if (linesDraw >= 7) {
this.drawTexturedModalRect(offsetX, offsetY + offset, 0, 173, 190, 18);
}
this.drawTexturedModalRect(offsetX + 20, offsetY + offset, 20, 173, width, 18);
offset += 18;
linesDraw++;
}
} else {
if (linesDraw == 6) {
this.drawTexturedModalRect(offsetX, offsetY + offset + 7, 0, 166, 190, 7);
this.drawTexturedModalRect(offsetX, offsetY + offset + 14, 0, 166, 190, 4);
this.drawTexturedModalRect(offsetX, offsetY + offset, 0, 53, 183, 18);
} else if (linesDraw >= 7) {
this.drawTexturedModalRect(offsetX, offsetY + offset, 0, 53, 183, 18);
this.drawTexturedModalRect(offsetX + 183, offsetY + offset, 183, 166, 7, 18);
}
offset += 18;
linesDraw++;
}
}
offset = 51 + Math.max(6 * 18, linesDraw * 18);
if (linesDraw > 6) {
this.drawTexturedModalRect(offsetX, offsetY + offset, 0, 166, 190, 7);
}
this.drawTexturedModalRect(offsetX, offsetY + offset + 7, 0, 166, this.xSize, 90);
this.drawnRows = Math.max(6, linesDraw);
// draw the background below the interface list
this.drawTexturedModalRect(offsetX, offsetY + 50 + this.rows * 18, 0, 158, this.xSize, 99);
if (this.searchFieldInputs != null) {
this.searchFieldInputs.drawTextBox();
}
if (this.searchFieldOutputs != null) {
this.searchFieldOutputs.drawTextBox();
}
// draw the text boxes
this.searchFieldInputs.drawTextBox();
this.searchFieldOutputs.drawTextBox();
this.searchFieldNames.drawTextBox();
}
@Override
protected void keyTyped(final char character, final int key) throws IOException {
if (!this.checkHotbarKeys(key)) {
if (character == ' ' && this.searchFieldInputs.getText().isEmpty() && this.searchFieldInputs.isFocused()) {
return;
if (character == ' ') {
if ((this.searchFieldInputs.getText().isEmpty() && this.searchFieldInputs.isFocused())
|| (this.searchFieldOutputs.getText().isEmpty() && this.searchFieldOutputs.isFocused())
|| (this.searchFieldNames.getText().isEmpty() && this.searchFieldNames.isFocused())) {
return;
}
} else if (character == '\t') {
if (handleTab()) {
return;
}
}
if (character == ' ' && this.searchFieldOutputs.getText().isEmpty() && this.searchFieldOutputs.isFocused()) {
return;
}
if (this.searchFieldInputs.textboxKeyTyped(character, key) || this.searchFieldOutputs.textboxKeyTyped(character, key)) {
if (this.searchFieldInputs.textboxKeyTyped(character, key)
|| this.searchFieldOutputs.textboxKeyTyped(character, key)
|| this.searchFieldNames.textboxKeyTyped(character, key)) {
this.refreshList();
} else {
super.keyTyped(character, key);
@@ -422,6 +419,27 @@ public class GuiInterfaceTerminal extends AEBaseGui {
}
}
/** Cycle to the next search bar if tab is pressed, going in reverse if shift is held. */
private boolean handleTab() {
if (searchFieldInputs.isFocused()) {
searchFieldInputs.setFocused(false);
if (isShiftKeyDown()) searchFieldNames.setFocused(true);
else searchFieldOutputs.setFocused(true);
return true;
} else if (searchFieldOutputs.isFocused()) {
searchFieldOutputs.setFocused(false);
if (isShiftKeyDown()) searchFieldInputs.setFocused(true);
else searchFieldNames.setFocused(true);
return true;
} else if (searchFieldNames.isFocused()) {
searchFieldNames.setFocused(false);
if (isShiftKeyDown()) searchFieldOutputs.setFocused(true);
else searchFieldInputs.setFocused(true);
return true;
}
return false;
}
public void postUpdate(final NBTTagCompound in) {
if (in.getBoolean("clear")) {
this.byId.clear();
@@ -467,12 +485,13 @@ public class GuiInterfaceTerminal extends AEBaseGui {
this.byName.clear();
this.buttonList.clear();
this.matchedStacks.clear();
this.matchedInterfaces.clear();
final String searchFieldInputs = this.searchFieldInputs.getText().toLowerCase();
final String searchFieldOutputs = this.searchFieldOutputs.getText().toLowerCase();
final String searchFieldNames = this.searchFieldNames.getText().toLowerCase();
final Set<Object> cachedSearch = this.getCacheForSearchTerm("IN:" + searchFieldInputs + " OUT:" + searchFieldOutputs + partInterfaceTerminal.onlyInterfacesWithFreeSlots);
final Set<Object> cachedSearch = this.getCacheForSearchTerm("IN:" + searchFieldInputs + " OUT:" + searchFieldOutputs
+ "NAME:" + searchFieldNames + onlyShowWithSpace + onlyMolecularAssemblers + onlyBrokenRecipes);
final boolean rebuild = cachedSearch.isEmpty();
for (final ClientDCInternalInv entry : this.byId.values()) {
@@ -483,78 +502,100 @@ public class GuiInterfaceTerminal extends AEBaseGui {
// Shortcut to skip any filter if search term is ""/empty
boolean found = (searchFieldInputs.isEmpty() && searchFieldOutputs.isEmpty() && !partInterfaceTerminal.onlyInterfacesWithFreeSlots);
boolean found = searchFieldInputs.isEmpty() && searchFieldOutputs.isEmpty();
boolean interfaceHasFreeSlots = false;
boolean interfaceHasBrokenRecipes = false;
// Search if the current inventory holds a pattern containing the search term.
if (!found) {
if (!found || onlyShowWithSpace || onlyBrokenRecipes) {
int slot = 0;
for (final ItemStack itemStack : entry.getInventory()) {
if (slot > 8 + numUpgradesMap.get(entry) * 9) {
break;
}
if (!searchFieldInputs.isEmpty() && !searchFieldOutputs.isEmpty()) {
if (this.itemStackMatchesSearchTerm(itemStack, searchFieldInputs, 0) || this.itemStackMatchesSearchTerm(itemStack, searchFieldOutputs, 1)) {
found = true;
matchedStacks.add(itemStack);
}
} else if (!searchFieldInputs.isEmpty()) {
if (this.itemStackMatchesSearchTerm(itemStack, searchFieldInputs, 0)) {
found = true;
matchedStacks.add(itemStack);
}
} else if (!searchFieldOutputs.isEmpty()) {
if (this.itemStackMatchesSearchTerm(itemStack, searchFieldOutputs, 1)) {
found = true;
matchedStacks.add(itemStack);
}
}
// If only Interfaces with empty slots should be shown, check that here
if (itemStack.isEmpty()) {
interfaceHasFreeSlots = true;
}
if (onlyBrokenRecipes && recipeIsBroken(itemStack)) {
interfaceHasBrokenRecipes = true;
}
if ((!searchFieldInputs.isEmpty() && itemStackMatchesSearchTerm(itemStack, searchFieldInputs, 0))
|| (!searchFieldOutputs.isEmpty() && itemStackMatchesSearchTerm(itemStack, searchFieldOutputs, 1))) {
found = true;
matchedStacks.add(itemStack);
}
slot++;
}
}
// if found, filter skipped or machine name matching the search term, add it
if ((searchFieldInputs.isEmpty() && searchFieldOutputs.isEmpty()) ||
!searchFieldInputs.isEmpty() && entry.getName().toLowerCase().contains(searchFieldInputs) ||
(!searchFieldOutputs.isEmpty() && entry.getName().toLowerCase().contains(searchFieldOutputs))) {
this.matchedInterfaces.add(entry);
found = true;
}
if (found) {
if (!partInterfaceTerminal.onlyInterfacesWithFreeSlots) {
this.byName.put(entry.getName(), entry);
cachedSearch.add(entry);
} else if (interfaceHasFreeSlots) {
this.byName.put(entry.getName(), entry);
cachedSearch.add(entry);
}
} else {
// Exit if not found
if (!found) {
cachedSearch.remove(entry);
continue;
}
// Exit if the interface does not match the name search
if (!entry.getName().toLowerCase().contains(searchFieldNames)) {
cachedSearch.remove(entry);
continue;
}
// Exit if molecular assembler filter is on and this is not a molecular assembler
if (onlyMolecularAssemblers && !entry.getName().toLowerCase().contains(MOLECULAR_ASSEMBLER)) {
cachedSearch.remove(entry);
continue;
}
// Exit if we are only showing interfaces with free slots and there are none free in this interface
if (onlyShowWithSpace && !interfaceHasFreeSlots) {
cachedSearch.remove(entry);
continue;
}
// Exit if we are only showing interfaces with broken patterns and there are no broken patterns in this interface
if (onlyBrokenRecipes && !interfaceHasBrokenRecipes) {
cachedSearch.remove(entry);
continue;
}
// Successful search
this.byName.put(entry.getName(), entry);
cachedSearch.add(entry);
}
this.names.clear();
this.names.addAll(this.byName.keySet());
Collections.sort(this.names);
this.lines.clear();
this.lines.ensureCapacity(this.getMaxRows());
this.lines.ensureCapacity(this.names.size() + this.byId.size());
for (final String n : this.names) {
this.lines.add(n);
final ArrayList<ClientDCInternalInv> clientInventories = new ArrayList<>();
clientInventories.addAll(this.byName.get(n));
final ArrayList<ClientDCInternalInv> clientInventories = new ArrayList<>(this.byName.get(n));
Collections.sort(clientInventories);
this.lines.addAll(clientInventories);
}
this.getScrollBar().setRange(0, this.lines.size() - 1, 1);
this.setScrollBar();
}
private boolean recipeIsBroken(final ItemStack stack) {
if (stack == null) return false;
if (stack.isEmpty()) return false;
final NBTTagCompound encodedValue = stack.getTagCompound();
if (encodedValue == null) return true;
final World w = AppEng.proxy.getWorld();
if (w == null) return false;
try {
new PatternHelper(stack, w);
return false;
} catch (Throwable ignored) {
return true;
}
}
private boolean itemStackMatchesSearchTerm(final ItemStack itemStack, final String searchTerm, int pass) {
@@ -624,13 +665,8 @@ public class GuiInterfaceTerminal extends AEBaseGui {
return cache;
}
/**
* The max amount of unique names and each inv row. Not affected by the filtering.
*
* @return max amount of unique names and each inv row
*/
private int getMaxRows() {
return this.names.size() + this.byId.size();
return AEConfig.instance().getConfigManager().getSetting(Settings.TERMINAL_STYLE) != TerminalStyle.TALL ? 6 : Integer.MAX_VALUE;
}
private ClientDCInternalInv getById(final long id, final long sortBy, final String string) {
@@ -643,12 +679,4 @@ public class GuiInterfaceTerminal extends AEBaseGui {
return o;
}
int getReservedSpace() {
return this.reservedSpace;
}
void setReservedSpace(final int reservedSpace) {
this.reservedSpace = reservedSpace;
}
}
@@ -467,6 +467,7 @@ public class GuiMEMonitorable extends AEBaseMEGui implements ISortSource, IConfi
}
final boolean mouseInGui = this.isPointInRegion(0, 0, this.xSize, this.ySize, this.currentMouseX, this.currentMouseY);
final boolean wasSearchFieldFocused = this.searchField.isFocused();
if (this.isAutoFocus && !this.searchField.isFocused() && mouseInGui) {
this.searchField.setFocused(true);
@@ -478,6 +479,10 @@ public class GuiMEMonitorable extends AEBaseMEGui implements ISortSource, IConfi
// tell forge the key event is handled and should not be sent out
this.keyHandled = mouseInGui;
} else {
if (!wasSearchFieldFocused) {
// prevent unhandled keys (like shift) from focusing the search field
searchField.setFocused(false);
}
super.keyTyped(character, key);
}
}
@@ -4,7 +4,6 @@ import appeng.api.config.AccessRestriction;
import appeng.api.config.ActionItems;
import appeng.api.config.Settings;
import appeng.api.config.StorageFilter;
import appeng.client.gui.AEBaseGui;
import appeng.client.gui.widgets.GuiImgButton;
import appeng.client.gui.widgets.GuiTabButton;
import appeng.client.gui.widgets.MEGuiTextField;
@@ -27,7 +26,7 @@ import java.io.IOException;
import java.util.regex.Pattern;
public class GuiOreDictStorageBus extends AEBaseGui {
public class GuiOreDictStorageBus extends GuiUpgradeable {
private final ContainerOreDictStorageBus container;
PartOreDicStorageBus part;
private GuiTabButton priority;
@@ -41,13 +40,11 @@ public class GuiOreDictStorageBus extends AEBaseGui {
super(new ContainerOreDictStorageBus(inventoryPlayer, te));
this.container = (ContainerOreDictStorageBus) super.inventorySlots;
part = te;
this.ySize = 84;
this.ySize = 170;
}
@Override
public void initGui() {
super.initGui();
protected void addButtons() {
this.searchFieldInputs = new MEGuiTextField(this.fontRenderer, this.guiLeft + 3, this.guiTop + 22, 170, 12);
this.searchFieldInputs.setEnableBackgroundDrawing(false);
this.searchFieldInputs.setMaxStringLength(512);
@@ -66,7 +63,6 @@ public class GuiOreDictStorageBus extends AEBaseGui {
} catch (IOException e) {
e.printStackTrace();
}
}
public void fillRegex(String regex) {
@@ -143,10 +139,13 @@ public class GuiOreDictStorageBus extends AEBaseGui {
}
@Override
public void drawBG(int offsetX, int offsetY, int mouseX, int mouseY) {
this.bindTexture("guis/oredictstoragebus.png");
this.drawTexturedModalRect(offsetX, offsetY, 0, 0, 175, 85);
protected String getBackground() {
return "guis/oredictstoragebus.png";
}
@Override
public void drawBG(int offsetX, int offsetY, int mouseX, int mouseY) {
super.drawBG(offsetX, offsetY, mouseX, mouseY);
if (this.searchFieldInputs != null) {
this.searchFieldInputs.drawTextBox();
}
@@ -47,6 +47,7 @@ import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidUtil;
import org.lwjgl.input.Mouse;
import javax.annotation.Nonnull;
import java.awt.*;
import java.io.IOException;
import java.util.List;
@@ -54,7 +55,7 @@ import java.util.*;
public class GuiUpgradeable extends AEBaseGui implements IJEIGhostIngredients {
private final Map<Target<?>, Object> mapTargetSlot = new HashMap<>();
protected final Map<Target<?>, Object> mapTargetSlot = new HashMap<>();
protected final ContainerUpgradeable cvb;
protected final IUpgradeableHost bc;
@@ -218,24 +219,25 @@ public class GuiUpgradeable extends AEBaseGui implements IJEIGhostIngredients {
List<Target<?>> targets = new ArrayList<>();
List<IJEITargetSlot> slots = new ArrayList<>();
if (this.inventorySlots.inventorySlots.size() > 0) {
if (!this.inventorySlots.inventorySlots.isEmpty()) {
for (Slot slot : this.inventorySlots.inventorySlots) {
if (slot instanceof SlotFake && (!itemStack.isEmpty() || this instanceof GuiCellWorkbench && fluidStack != null)) {
slots.add((IJEITargetSlot) slot);
}
}
}
if (this.getGuiSlots().size() > 0) {
if (!this.getGuiSlots().isEmpty()) {
for (GuiCustomSlot slot : this.getGuiSlots()) {
if (slot instanceof GuiFluidSlot && fluidStack != null) {
slots.add((IJEITargetSlot) slot);
}
}
}
for (Object slot : slots) {
for (IJEITargetSlot slot : slots) {
ItemStack finalItemStack = itemStack;
FluidStack finalFluidStack = fluidStack;
Target<Object> targetItem = new Target<Object>() {
Target<Object> targetItem = new Target<>() {
@Nonnull
@Override
public Rectangle getArea() {
if (slot instanceof SlotFake && ((SlotFake) slot).isSlotEnabled()) {
@@ -247,20 +249,20 @@ public class GuiUpgradeable extends AEBaseGui implements IJEIGhostIngredients {
}
@Override
public void accept(Object ingredient) {
public void accept(@Nonnull Object ingredient) {
PacketInventoryAction p = null;
try {
if (slot instanceof SlotFake && ((SlotFake) slot).isSlotEnabled()) {
if (finalItemStack.isEmpty() && finalFluidStack != null) {
p = new PacketInventoryAction(InventoryAction.PLACE_JEI_GHOST_ITEM, (IJEITargetSlot) slot, AEItemStack.fromItemStack(FluidUtil.getFilledBucket(finalFluidStack)));
p = new PacketInventoryAction(InventoryAction.PLACE_JEI_GHOST_ITEM, slot, AEItemStack.fromItemStack(FluidUtil.getFilledBucket(finalFluidStack)));
} else if (!finalItemStack.isEmpty()) {
p = new PacketInventoryAction(InventoryAction.PLACE_JEI_GHOST_ITEM, (IJEITargetSlot) slot, AEItemStack.fromItemStack(finalItemStack));
p = new PacketInventoryAction(InventoryAction.PLACE_JEI_GHOST_ITEM, slot, AEItemStack.fromItemStack(finalItemStack));
}
} else {
if (finalFluidStack == null) {
return;
}
p = new PacketInventoryAction(InventoryAction.PLACE_JEI_GHOST_ITEM, (IJEITargetSlot) slot, AEItemStack.fromItemStack(AEFluidStack.fromFluidStack(finalFluidStack).asItemStackRepresentation()));
p = new PacketInventoryAction(InventoryAction.PLACE_JEI_GHOST_ITEM, slot, AEItemStack.fromItemStack(AEFluidStack.fromFluidStack(finalFluidStack).asItemStackRepresentation()));
}
NetworkHandler.instance().sendToServer(p);
@@ -116,10 +116,13 @@ public class GuiImgButton extends GuiButton implements ITooltip {
this.registerApp(11 + 4 * 16, Settings.ACTIONS, ActionItems.DECREASE_BY_ONE, ButtonToolTips.DecreaseByOne, ButtonToolTips.DecreaseByOneDesc);
this.registerApp(12 + 4 * 16, Settings.ACTIONS, ActionItems.MAX_COUNT, ButtonToolTips.MaxCount, ButtonToolTips.MaxCountDesc);
this.registerApp(6 + 5 * 16, Settings.ACTIONS, ActionItems.FREE_MOLECULAR_SLOT_SHORTCUT, ButtonToolTips.FreeMolecularSlotShortcut, ButtonToolTips.FreeMolecularSlotShortcutDesc);
this.registerApp(6 + 5 * 16, Settings.ACTIONS, ActionItems.MOLECULAR_ASSEMBLERS_ON, ButtonToolTips.ToggleMolecularAssemblers, ButtonToolTips.ToggleMolecularAssemblersOnDesc);
this.registerApp(7 + 5 * 16, Settings.ACTIONS, ActionItems.TOGGLE_SHOW_FULL_INTERFACES_ON, ButtonToolTips.ToggleShowFullInterfaces, ButtonToolTips.ToggleShowFullInterfacesOnDesc);
this.registerApp(8 + 5 * 16, Settings.ACTIONS, ActionItems.TOGGLE_SHOW_FULL_INTERFACES_OFF, ButtonToolTips.ToggleShowFullInterfaces, ButtonToolTips.ToggleShowFullInterfacesOffDesc);
this.registerApp(9 + 5 * 16, Settings.ACTIONS, ActionItems.MOLECULAR_ASSEMBLERS_OFF, ButtonToolTips.ToggleMolecularAssemblers, ButtonToolTips.ToggleMolecularAssemblersOffDesc);
this.registerApp(6 + 6 * 16, Settings.ACTIONS, ActionItems.HIGHLIGHT_INTERFACE, ButtonToolTips.HighlightInterface, "");
this.registerApp(4 + 5 * 16, Settings.ACTIONS, ActionItems.TOGGLE_SHOW_ONLY_INVALID_PATTERNS_OFF, ButtonToolTips.ToggleShowOnlyInvalidInterface, ButtonToolTips.ToggleShowOnlyInvalidInterfaceOffDesc);
this.registerApp(5 + 5 * 16, Settings.ACTIONS, ActionItems.TOGGLE_SHOW_ONLY_INVALID_PATTERNS_ON, ButtonToolTips.ToggleShowOnlyInvalidInterface, ButtonToolTips.ToggleShowOnlyInvalidInterfaceOnDesc);
this.registerApp(8, Settings.ACTIONS, ActionItems.ENCODE, ButtonToolTips.Encode, ButtonToolTips.EncodeDescription);
this.registerApp(4 + 3 * 16, Settings.ACTIONS, ItemSubstitution.ENABLED, ButtonToolTips.Substitutions, ButtonToolTips.SubstitutionsDescEnabled);
@@ -157,6 +160,12 @@ public class GuiImgButton extends GuiButton implements ITooltip {
this.registerApp(16 * 15, Settings.SCHEDULING_MODE, SchedulingMode.DEFAULT, ButtonToolTips.SchedulingMode, ButtonToolTips.SchedulingModeDefault);
this.registerApp(16 * 15 + 1, Settings.SCHEDULING_MODE, SchedulingMode.ROUNDROBIN, ButtonToolTips.SchedulingMode, ButtonToolTips.SchedulingModeRoundRobin);
this.registerApp(16 * 15 + 2, Settings.SCHEDULING_MODE, SchedulingMode.RANDOM, ButtonToolTips.SchedulingMode, ButtonToolTips.SchedulingModeRandom);
this.registerApp(10, Settings.UNLOCK,LockCraftingMode.NONE,ButtonToolTips.LockCraftingMode, ButtonToolTips.LockCraftingModeNone);
this.registerApp(7, Settings.UNLOCK,LockCraftingMode.LOCK_UNTIL_RESULT,ButtonToolTips.LockCraftingMode, ButtonToolTips.LockCraftingUntilResultReturned);
this.registerApp(0, Settings.UNLOCK, LockCraftingMode.LOCK_WHILE_LOW, ButtonToolTips.LockCraftingMode, ButtonToolTips.LockCraftingWhileRedstoneLow);
this.registerApp(1, Settings.UNLOCK, LockCraftingMode.LOCK_WHILE_HIGH, ButtonToolTips.LockCraftingMode, ButtonToolTips.LockCraftingWhileRedstoneHigh);
this.registerApp(2, Settings.UNLOCK, LockCraftingMode.LOCK_UNTIL_PULSE, ButtonToolTips.LockCraftingMode, ButtonToolTips.LockCraftingUntilRedstonePulse);
}
}
@@ -0,0 +1,236 @@
package appeng.client.gui.widgets;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.GuiTextField;
import org.lwjgl.input.Keyboard;
/**
* Different implementation of a text field that wraps instead of extends
* MC's {@link GuiTextField}. This is necessary because of deobfuscated name
* collision between {@link ITooltip} and GuiTextField, which would cause
* crashes in an obfuscated environment. Additionally, since we are not extending that
* class, we can construct this object differently and allow its position to be
* mutable like most other widgets.
*/
public class MEGuiTooltipTextField implements ITooltip {
protected GuiTextField field;
private static final int PADDING = 2;
private static boolean previousKeyboardRepeatEnabled;
private static MEGuiTooltipTextField previousKeyboardRepeatEnabledField;
private String tooltip;
private int fontPad;
public int x;
public int y;
public int w;
public int h;
/**
* Uses the values to instantiate a padded version of a text field. Pays attention to the '_' caret.
*
* @param width absolute width
* @param height absolute height
* @param tooltip tooltip message
*/
public MEGuiTooltipTextField(final int width, final int height, final String tooltip) {
final FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer;
field = new GuiTextField(0, fontRenderer, 0, 0, 0, 0);
w = width;
h = height;
setMessage(tooltip);
this.fontPad = fontRenderer.getCharWidth('_');
setDimensionsAndColor();
}
public MEGuiTooltipTextField(final int width, final int height) {
this(width, height, "");
}
public MEGuiTooltipTextField() {
this(0, 0);
}
protected void setDimensionsAndColor() {
field.x = this.x + PADDING;
field.y = this.y + PADDING;
field.width = this.w - PADDING * 2 - this.fontPad;
field.height = this.h - PADDING * 2;
}
public void onTextChange(final String oldText) {}
public void mouseClicked(final int xPos, final int yPos, final int button) {
if (!this.isMouseIn(xPos, yPos)) {
setFocused(false);
return;
}
field.setCanLoseFocus(false);
setFocused(true);
if (button == 1) {
setText("");
} else {
field.mouseClicked(xPos, yPos, button);
}
field.setCanLoseFocus(true);
}
/**
* Checks if the mouse is within the element
*
* @param xCoord current x coord of the mouse
* @param yCoord current y coord of the mouse
* @return true if mouse position is within the getText field area
*/
public boolean isMouseIn(final int xCoord, final int yCoord) {
final boolean withinXRange = this.x <= xCoord && xCoord < this.x + this.w;
final boolean withinYRange = this.y <= yCoord && yCoord < this.y + this.h;
return withinXRange && withinYRange;
}
public boolean textboxKeyTyped(final char keyChar, final int keyID) {
if (!isFocused()) {
return false;
}
final String oldText = getText();
boolean handled = field.textboxKeyTyped(keyChar, keyID);
if (!handled && (keyID == Keyboard.KEY_RETURN || keyID == Keyboard.KEY_NUMPADENTER
|| keyID == Keyboard.KEY_ESCAPE)) {
setFocused(false);
}
if (handled) {
onTextChange(oldText);
}
return handled;
}
public void drawTextBox() {
if (field.getVisible()) {
setDimensionsAndColor();
GuiTextField.drawRect(
this.x + 1,
this.y + 1,
this.x + this.w - 1,
this.y + this.h - 1,
isFocused() ? 0xFF606060 : 0xFFA8A8A8);
field.drawTextBox();
}
}
public void setText(String text, boolean ignoreTrigger) {
final String oldText = getText();
int currentCursorPos = field.getCursorPosition();
field.setText(text);
field.setCursorPosition(currentCursorPos);
if (!ignoreTrigger) {
onTextChange(oldText);
}
}
public void setText(String text) {
setText(text, false);
}
public void setCursorPositionEnd() {
field.setCursorPositionEnd();
}
public void setFocused(boolean focus) {
if (field.isFocused() == focus) {
return;
}
field.setFocused(focus);
if (focus) {
if (previousKeyboardRepeatEnabledField == null) {
previousKeyboardRepeatEnabled = Keyboard.areRepeatEventsEnabled();
}
previousKeyboardRepeatEnabledField = this;
Keyboard.enableRepeatEvents(true);
} else {
if (previousKeyboardRepeatEnabledField == this) {
previousKeyboardRepeatEnabledField = null;
Keyboard.enableRepeatEvents(previousKeyboardRepeatEnabled);
}
}
}
public void setMaxStringLength(final int size) {
field.setMaxStringLength(size);
}
public void setEnableBackgroundDrawing(final boolean b) {
field.setEnableBackgroundDrawing(b);
}
public void setTextColor(final int color) {
field.setTextColor(color);
}
public void setCursorPositionZero() {
field.setCursorPositionZero();
}
public boolean isFocused() {
return field.isFocused();
}
public String getText() {
return field.getText();
}
public void setMessage(String t) {
tooltip = t;
}
@Override
public String getMessage() {
return tooltip;
}
@Override
public boolean isVisible() {
return field.getVisible();
}
@Override
public int xPos() {
return x;
}
@Override
public int yPos() {
return y;
}
@Override
public int getWidth() {
return w;
}
@Override
public int getHeight() {
return h;
}
}
@@ -24,6 +24,10 @@ import appeng.api.parts.IPartModel;
import appeng.api.util.AECableType;
import appeng.api.util.AEColor;
import appeng.block.networking.BlockCableBus;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.cache.Weigher;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.block.model.BakedQuad;
@@ -38,6 +42,7 @@ import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.MinecraftForgeClient;
import net.minecraftforge.common.property.IExtendedBlockState;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
import java.util.Map.Entry;
@@ -45,8 +50,6 @@ import java.util.Map.Entry;
public class CableBusBakedModel implements IBakedModel {
static final Map<CableBusRenderState, List<BakedQuad>> CABLE_MODEL_CACHE = new HashMap<>();
private final CableBuilder cableBuilder;
private final FacadeBuilder facadeBuilder;
@@ -57,11 +60,24 @@ public class CableBusBakedModel implements IBakedModel {
private final TextureMap textureMap = Minecraft.getMinecraft().getTextureMapBlocks();
private final LoadingCache<CableBusRenderState, List<BakedQuad>> cableModelCache;
CableBusBakedModel(CableBuilder cableBuilder, FacadeBuilder facadeBuilder, Map<ResourceLocation, IBakedModel> partModels, TextureAtlasSprite particleTexture) {
this.cableBuilder = cableBuilder;
this.facadeBuilder = facadeBuilder;
this.partModels = partModels;
this.particleTexture = particleTexture;
this.cableModelCache = CacheBuilder.newBuilder()
.maximumWeight(5000)
.weigher((Weigher<CableBusRenderState, List<BakedQuad>>) (k, v) -> v.size())
.build(new CacheLoader<>() {
@Override
public List<BakedQuad> load(@Nonnull CableBusRenderState rs) {
final List<BakedQuad> model = new ArrayList<>();
addCableQuads(rs, model);
return model;
}
});
}
@Override
@@ -82,12 +98,7 @@ public class CableBusBakedModel implements IBakedModel {
if (layer == BlockRenderLayer.CUTOUT) {
// First, handle the cable at the center of the cable bus
final List<BakedQuad> cableModel = CABLE_MODEL_CACHE.computeIfAbsent(renderState, k ->
{
final List<BakedQuad> model = new ArrayList<>();
this.addCableQuads(renderState, model);
return model;
});
final List<BakedQuad> cableModel = cableModelCache.getUnchecked(renderState);
quads.addAll(cableModel);
// Then handle attachments
@@ -27,26 +27,21 @@ import com.google.common.collect.ImmutableMap;
import net.minecraft.client.renderer.block.model.IBakedModel;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.model.IModel;
import net.minecraftforge.client.model.ModelLoaderRegistry;
import net.minecraftforge.client.resource.IResourceType;
import net.minecraftforge.client.resource.ISelectiveResourceReloadListener;
import net.minecraftforge.client.resource.VanillaResourceType;
import net.minecraftforge.common.model.IModelState;
import net.minecraftforge.common.model.TRSRTransformation;
import java.util.Collection;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Predicate;
/**
* The built-in model for the cable bus block.
*/
public class CableBusModel implements IModel, ISelectiveResourceReloadListener {
public class CableBusModel implements IModel {
private final PartModels partModels;
@@ -106,12 +101,4 @@ public class CableBusModel implements IModel, ISelectiveResourceReloadListener {
public IModelState getDefaultState() {
return TRSRTransformation.identity();
}
@Override
public void onResourceManagerReload(IResourceManager resourceManager, Predicate<IResourceType> resourcePredicate) {
if (resourcePredicate.test(VanillaResourceType.MODELS)) {
CableBusBakedModel.CABLE_MODEL_CACHE.clear();
}
}
}
@@ -60,6 +60,9 @@ public class DriveBakedModel implements IBakedModel {
}
DriveSlotsState slotsState = extState.getValue(BlockDrive.SLOTS_STATE);
if (slotsState == null) {
return result;
}
for (int row = 0; row < 5; row++) {
for (int col = 0; col < 2; col++) {
@@ -90,6 +93,7 @@ public class DriveBakedModel implements IBakedModel {
}
}
return result;
}
@@ -31,7 +31,7 @@ import appeng.api.networking.crafting.ICraftingLink;
import appeng.api.networking.security.IActionHost;
import appeng.api.networking.security.IActionSource;
import appeng.api.networking.storage.IStorageGrid;
import appeng.api.storage.IMEInventory;
import appeng.api.storage.IMEMonitor;
import appeng.api.storage.ITerminalHost;
import appeng.api.storage.channels.IItemStorageChannel;
import appeng.api.storage.data.IAEItemStack;
@@ -213,7 +213,7 @@ public class ContainerCraftConfirm extends AEBaseContainer {
p.setStackSize(out.getCountRequestable());
final IStorageGrid sg = grid.getCache(IStorageGrid.class);
final IMEInventory<IAEItemStack> items = sg.getInventory(AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class));
final IMEMonitor<IAEItemStack> items = sg.getInventory(AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class));
IAEItemStack m = null;
if (c != null && this.result.isSimulation()) {
@@ -330,8 +330,7 @@ public class ContainerCraftConfirm extends AEBaseContainer {
if (te != null) {
Platform.openGUI(this.getInventoryPlayer().player, te, this.getOpenContext().getSide(), originalGui);
} else {
if (ah instanceof IInventorySlotAware) {
IInventorySlotAware i = ((IInventorySlotAware) ah);
if (ah instanceof IInventorySlotAware i) {
Platform.openGUI(this.getInventoryPlayer().player, i.getInventorySlot(), originalGui, i.isBaubleSlot());
}
}
@@ -116,15 +116,19 @@ public class ContainerInscriber extends ContainerUpgradeable implements IProgres
boolean matches = false;
for (final IInscriberRecipe recipe : AEApi.instance().registries().inscriber().getRecipes()) {
final boolean matchA = !top
.isEmpty() && (Platform.itemComparisons().isSameItem(top, recipe.getTopOptional().orElse(ItemStack.EMPTY)) || Platform
.itemComparisons()
.isSameItem(top, recipe.getBottomOptional().orElse(ItemStack.EMPTY)));
final boolean matchB = !bot
.isEmpty() && (Platform.itemComparisons().isSameItem(bot, recipe.getTopOptional().orElse(ItemStack.EMPTY)) || Platform
.itemComparisons()
.isSameItem(bot, recipe.getBottomOptional().orElse(ItemStack.EMPTY)));
// Check if plateA matches any item in the list of top components of the recipe
final boolean matchA = top.isEmpty() && recipe.getTopInputs().isEmpty() ||
recipe.getTopInputs().stream().anyMatch(topItem -> Platform.itemComparisons().isSameItem(top, topItem)) &&
(bot.isEmpty() && recipe.getBottomInputs().isEmpty() ||
recipe.getBottomInputs().stream().anyMatch(bottomItem -> Platform.itemComparisons().isSameItem(bot, bottomItem)));
// Check if plateB matches any item in the list of top components of the recipe
final boolean matchB = bot.isEmpty() && recipe.getTopInputs().isEmpty() ||
recipe.getTopInputs().stream().anyMatch(topItem -> Platform.itemComparisons().isSameItem(bot, topItem)) &&
(top.isEmpty() && recipe.getBottomInputs().isEmpty() ||
recipe.getBottomInputs().stream().anyMatch(bottomItem -> Platform.itemComparisons().isSameItem(top, bottomItem)));
// If either matchA or matchB is true, iterate through the recipe's inputs
if (matchA || matchB) {
matches = true;
for (final ItemStack option : recipe.getInputs()) {
@@ -152,10 +156,22 @@ public class ContainerInscriber extends ContainerUpgradeable implements IProgres
// everything else
for (final IInscriberRecipe recipe : AEApi.instance().registries().inscriber().getRecipes()) {
boolean isValid = false;
if (Platform.itemComparisons().isSameItem(otherSlot, recipe.getTopOptional().orElse(ItemStack.EMPTY))) {
isValid = Platform.itemComparisons().isSameItem(is, recipe.getBottomOptional().orElse(ItemStack.EMPTY));
} else if (Platform.itemComparisons().isSameItem(otherSlot, recipe.getBottomOptional().orElse(ItemStack.EMPTY))) {
isValid = Platform.itemComparisons().isSameItem(is, recipe.getTopOptional().orElse(ItemStack.EMPTY));
// Check if otherSlot matches any item in the top component list
boolean matchTop = recipe.getTopInputs().stream()
.anyMatch(topItem -> Platform.itemComparisons().isSameItem(otherSlot, topItem));
// Check if otherSlot matches any item in the bottom component list
boolean matchBottom = recipe.getBottomInputs().stream()
.anyMatch(bottomItem -> Platform.itemComparisons().isSameItem(otherSlot, bottomItem));
if (matchTop) {
// If otherSlot matches a top component, check if 'is' matches any item in the bottom component list
isValid = recipe.getBottomInputs().stream()
.anyMatch(bottomItem -> Platform.itemComparisons().isSameItem(is, bottomItem));
} else if (matchBottom) {
// If otherSlot matches a bottom component, check if 'is' matches any item in the top component list
isValid = recipe.getTopInputs().stream()
.anyMatch(topItem -> Platform.itemComparisons().isSameItem(is, topItem));
}
if (isValid) {
@@ -19,10 +19,7 @@
package appeng.container.implementations;
import appeng.api.config.SecurityPermissions;
import appeng.api.config.Settings;
import appeng.api.config.Upgrades;
import appeng.api.config.YesNo;
import appeng.api.config.*;
import appeng.api.util.IConfigManager;
import appeng.container.guisync.GuiSync;
import appeng.container.slot.*;
@@ -40,11 +37,14 @@ public class ContainerInterface extends ContainerUpgradeable implements IOptiona
public YesNo bMode = YesNo.NO;
@GuiSync(4)
public YesNo iTermMode = YesNo.YES;
public LockCraftingMode lMode = LockCraftingMode.NONE;
@GuiSync(7)
public int patternExpansions = 0;
@GuiSync(8)
public YesNo iTermMode = YesNo.YES;
public ContainerInterface(final InventoryPlayer ip, final IInterfaceHost te) {
super(ip, te.getInterfaceDuality().getHost());
@@ -107,9 +107,14 @@ public class ContainerInterface extends ContainerUpgradeable implements IOptiona
@Override
protected void loadSettingsFromHost(final IConfigManager cm) {
this.setBlockingMode((YesNo) cm.getSetting(Settings.BLOCK));
this.setUnlockMode((LockCraftingMode) cm.getSetting(Settings.UNLOCK));
this.setInterfaceTerminalMode((YesNo) cm.getSetting(Settings.INTERFACE_TERMINAL));
}
public LockCraftingMode getUnlockMode() {return this.lMode;}
public void setUnlockMode(final LockCraftingMode mode) {this.lMode = mode;}
public YesNo getBlockingMode() {
return this.bMode;
}
@@ -46,6 +46,9 @@ import appeng.api.util.IConfigurableObject;
import appeng.client.gui.implementations.GuiMEMonitorable;
import appeng.container.AEBaseContainer;
import appeng.container.guisync.GuiSync;
import appeng.container.slot.AppEngSlot;
import appeng.container.slot.SlotPlayerHotBar;
import appeng.container.slot.SlotPlayerInv;
import appeng.container.slot.SlotRestrictedInput;
import appeng.core.AELog;
import appeng.core.sync.network.NetworkHandler;
@@ -60,9 +63,11 @@ import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.IContainerListener;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.items.IItemHandler;
import javax.annotation.Nonnull;
import java.io.IOException;
@@ -161,6 +166,51 @@ public class ContainerMEMonitorable extends AEBaseContainer implements IConfigMa
}
}
@Override
public ItemStack transferStackInSlot(final EntityPlayer p, final int idx) {
if (Platform.isClient()) {
return ItemStack.EMPTY;
}
// Below logic is all about handling shift click for view cells
if (!(this.host instanceof IViewCellStorage)) {
return super.transferStackInSlot(p, idx);
}
// Is it a view cell?
final Slot clickSlot = this.inventorySlots.get(idx);
ItemStack itemStack = clickSlot.getStack();
if (!AEApi.instance().definitions().items().viewCell().isSameAs(itemStack)) {
return super.transferStackInSlot(p, idx);
}
// Are we clicking from the player's inventory?
final boolean isPlayerInventorySlot = this.inventorySlots.get(idx) instanceof SlotPlayerInv || this.inventorySlots.get(idx) instanceof SlotPlayerHotBar;
if (!isPlayerInventorySlot) {
return super.transferStackInSlot(p, idx);
}
// Attempt to move the item into the view cell storage
final IItemHandler viewCellInv = ((IViewCellStorage) this.host).getViewCellStorage();
for (int slot = 0; slot < viewCellInv.getSlots(); slot++) {
if (viewCellInv.isItemValid(slot, itemStack) && viewCellInv.getStackInSlot(slot).isEmpty()) {
ItemStack remainder = viewCellInv.insertItem(slot, itemStack, true);
if (!remainder.isEmpty()) { // That slot can't take the item
continue;
}
remainder = viewCellInv.insertItem(slot, itemStack, false);
clickSlot.putStack(remainder);
this.detectAndSendChanges();
if (!remainder.isEmpty()) {
// How??
return super.transferStackInSlot(p, idx);
}
return ItemStack.EMPTY;
}
}
return super.transferStackInSlot(p, idx);
}
public IGridNode getNetworkNode() {
return this.networkNode;
}
@@ -1,15 +1,12 @@
package appeng.container.implementations;
import appeng.api.AEApi;
import appeng.api.config.AccessRestriction;
import appeng.api.config.SecurityPermissions;
import appeng.api.config.Settings;
import appeng.api.config.StorageFilter;
import appeng.api.config.*;
import appeng.api.storage.IMEInventory;
import appeng.api.storage.channels.IItemStorageChannel;
import appeng.api.storage.data.IAEItemStack;
import appeng.container.AEBaseContainer;
import appeng.container.guisync.GuiSync;
import appeng.container.slot.SlotRestrictedInput;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.PacketValueConfig;
import appeng.parts.misc.PartOreDicStorageBus;
@@ -18,6 +15,7 @@ import appeng.util.item.AEItemStack;
import appeng.util.item.OreReference;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.oredict.OreDictionary;
import java.io.IOException;
@@ -26,7 +24,7 @@ import java.util.Iterator;
import java.util.Set;
public class ContainerOreDictStorageBus extends AEBaseContainer {
public class ContainerOreDictStorageBus extends ContainerUpgradeable {
private final PartOreDicStorageBus part;
@GuiSync(3)
@@ -35,6 +33,9 @@ public class ContainerOreDictStorageBus extends AEBaseContainer {
@GuiSync(4)
public StorageFilter storageFilter = StorageFilter.EXTRACTABLE_ONLY;
@GuiSync(7)
public YesNo stickyMode = YesNo.NO;
public ContainerOreDictStorageBus(final InventoryPlayer ip, final PartOreDicStorageBus anchor) {
super(ip, anchor);
this.part = anchor;
@@ -47,9 +48,15 @@ public class ContainerOreDictStorageBus extends AEBaseContainer {
if (Platform.isServer()) {
this.setReadWriteMode((AccessRestriction) part.getConfigManager().getSetting(Settings.ACCESS));
this.setStorageFilter((StorageFilter) part.getConfigManager().getSetting(Settings.STORAGE_FILTER));
this.setStickyMode((YesNo) this.getUpgradeable().getConfigManager().getSetting(Settings.STICKY_MODE));
}
super.detectAndSendChanges();
super.standardDetectAndSendChanges();
}
@Override
protected int getHeight() {
return 170;
}
public void partition() {
@@ -116,4 +123,29 @@ public class ContainerOreDictStorageBus extends AEBaseContainer {
private void setStorageFilter(final StorageFilter storageFilter) {
this.storageFilter = storageFilter;
}
@Override
protected void setupConfig() {
final IItemHandler upgrades = this.getUpgradeable().getInventoryByName("upgrades");
this.addSlotToContainer((new SlotRestrictedInput(SlotRestrictedInput.PlacableItemType.UPGRADES, upgrades, 0, 187, 8, this.getInventoryPlayer()))
.setNotDraggable());
}
@Override
public int availableUpgrades() {
return 1;
}
@Override
protected boolean supportCapacity() {
return false;
}
public YesNo getStickyMode() {
return this.stickyMode;
}
private void setStickyMode(final YesNo stickyMode) {
this.stickyMode = stickyMode;
}
}
@@ -1,4 +1,9 @@
package appeng.container.slot;
public interface IJEITargetSlot {
default boolean needAccept() {
return false;
}
}
@@ -50,7 +50,6 @@ public class SlotFake extends AppEngSlot implements IJEITargetSlot {
if (!is.isEmpty()) {
is = is.copy();
}
super.putStack(is);
}
@@ -58,4 +57,10 @@ public class SlotFake extends AppEngSlot implements IJEITargetSlot {
public boolean canTakeStack(final EntityPlayer par1EntityPlayer) {
return false;
}
@Override
public boolean needAccept() {
return this.getStack().isEmpty();
}
}
+6
View File
@@ -84,6 +84,7 @@ public final class AEConfig extends Configuration implements IConfigurableObject
private PowerUnits selectedPowerUnit = PowerUnits.AE;
private boolean showCraftableTooltip = true;
private boolean showPlacementPreview = true;
private boolean showCellContentsPreview = true;
// Spatial IO/Dimension
private int storageProviderID = -1;
@@ -259,6 +260,7 @@ public final class AEConfig extends Configuration implements IConfigurableObject
this.useColoredCraftingStatus = this.get("Client", "useColoredCraftingStatus", true).getBoolean(true);
this.showCraftableTooltip = this.get("Client", "showCraftableTooltip", true, "Whether to add \"Craftable\" to item tooltips when they can be crafted automatically.").getBoolean(true);
this.showPlacementPreview = this.get("Client", "showPlacementPreview", true, "Whether to show a preview of part and facade placement.").getBoolean(true);
this.showCellContentsPreview = this.get("Client", "showCellContentsPreview", true, "Whether to show a preview of cell contents in tooltips.").getBoolean(true);
// load buttons..
for (int btnNum = 0; btnNum < 4; btnNum++) {
@@ -520,6 +522,10 @@ public final class AEConfig extends Configuration implements IConfigurableObject
return this.showPlacementPreview;
}
public boolean showCellContentsPreview() {
return showCellContentsPreview;
}
public boolean isDisableColoredCableRecipesInJEI() {
return this.disableColoredCableRecipesInJEI;
}
+17 -1
View File
@@ -54,8 +54,8 @@ import appeng.core.stats.PartItemPredicate;
import appeng.core.stats.Stats;
import appeng.core.worlddata.SpatialDimensionManager;
import appeng.fluids.registries.BasicFluidCellGuiHandler;
import appeng.hooks.WrenchClickHook;
import appeng.hooks.TickHandler;
import appeng.hooks.WrenchClickHook;
import appeng.items.materials.ItemMaterial;
import appeng.items.parts.ItemFacade;
import appeng.items.parts.ItemPart;
@@ -387,12 +387,28 @@ final class Registration {
Upgrades.FUZZY.registerItem(AEApi.instance().definitions().materials().cardMagnet(), 1);
Upgrades.INVERTER.registerItem(AEApi.instance().definitions().materials().cardMagnet(), 1);
// Fluid Cells
Upgrades.INVERTER.registerItem(items.fluidCell1k(), 1);
Upgrades.STICKY.registerItem(items.fluidCell1k(), 1);
Upgrades.INVERTER.registerItem(items.fluidCell4k(), 1);
Upgrades.STICKY.registerItem(items.fluidCell4k(), 1);
Upgrades.INVERTER.registerItem(items.fluidCell16k(), 1);
Upgrades.STICKY.registerItem(items.fluidCell16k(), 1);
Upgrades.INVERTER.registerItem(items.fluidCell64k(), 1);
Upgrades.STICKY.registerItem(items.fluidCell64k(), 1);
// Storage Bus
Upgrades.FUZZY.registerItem(parts.storageBus(), 1);
Upgrades.INVERTER.registerItem(parts.storageBus(), 1);
Upgrades.CAPACITY.registerItem(parts.storageBus(), 5);
Upgrades.STICKY.registerItem(parts.storageBus(), 1);
// OreDict Storage Bus
Upgrades.STICKY.registerItem(parts.oreDictStorageBus(), 1);
// Storage Bus Fluids
Upgrades.INVERTER.registerItem(parts.fluidStorageBus(), 1);
Upgrades.CAPACITY.registerItem(parts.fluidStorageBus(), 5);
@@ -11,6 +11,7 @@ import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IAEStack;
import appeng.api.storage.data.IItemList;
import appeng.api.util.IClientHelper;
import appeng.core.AEConfig;
import appeng.core.localization.GuiText;
import appeng.fluids.items.FluidDummyItem;
import appeng.fluids.util.AEFluidStack;
@@ -109,7 +110,10 @@ public class ApiClientHelper implements IClientHelper {
}
}
} else {
if (Minecraft.getMinecraft().gameSettings.advancedItemTooltips || Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_RSHIFT)) {
if (!AEConfig.instance().showCellContentsPreview()) return;
if (Minecraft.getMinecraft().gameSettings.advancedItemTooltips
|| Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_RSHIFT)
) {
cellInventory.getAvailableItems((IItemList) itemList);
for (IAEStack<?> s : itemList) {
if (s instanceof IAEItemStack) {
@@ -25,6 +25,7 @@ import net.minecraft.item.ItemStack;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.List;
/**
@@ -35,7 +36,7 @@ import java.util.Collection;
* @since rv2
*/
public class InscriberInscribeRecipe extends InscriberRecipe {
InscriberInscribeRecipe(@Nonnull final Collection<ItemStack> inputs, @Nonnull final ItemStack output, @Nullable final ItemStack top, @Nullable final ItemStack bot) {
InscriberInscribeRecipe(@Nonnull final Collection<ItemStack> inputs, @Nonnull final ItemStack output, @Nullable final List<ItemStack> top, @Nullable final List<ItemStack> bot) {
super(inputs, output, top, bot, InscriberProcessType.INSCRIBE);
}
}
@@ -28,7 +28,6 @@ import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
/**
@@ -46,21 +45,21 @@ public class InscriberRecipe implements IInscriberRecipe {
private final ItemStack output;
@Nonnull
private final Optional<ItemStack> maybeTop;
private final List<ItemStack> maybeTop;
@Nonnull
private final Optional<ItemStack> maybeBot;
private final List<ItemStack> maybeBot;
@Nonnull
private final InscriberProcessType type;
InscriberRecipe(@Nonnull final Collection<ItemStack> inputs, @Nonnull final ItemStack output, @Nullable final ItemStack top, @Nullable final ItemStack bot, @Nonnull final InscriberProcessType type) {
InscriberRecipe(@Nonnull final Collection<ItemStack> inputs, @Nonnull final ItemStack output, @Nullable final List<ItemStack> top, @Nullable final List<ItemStack> bot, @Nonnull final InscriberProcessType type) {
this.inputs = new ArrayList<>(inputs.size());
this.inputs.addAll(inputs);
this.output = output;
this.maybeTop = Optional.ofNullable(top);
this.maybeBot = Optional.ofNullable(bot);
this.maybeTop = top;
this.maybeBot = bot;
this.type = type;
}
@@ -79,13 +78,13 @@ public class InscriberRecipe implements IInscriberRecipe {
@Nonnull
@Override
public final Optional<ItemStack> getTopOptional() {
public final List<ItemStack> getTopInputs() {
return this.maybeTop;
}
@Nonnull
@Override
public final Optional<ItemStack> getBottomOptional() {
public final List<ItemStack> getBottomInputs() {
return this.maybeBot;
}
@@ -112,10 +111,10 @@ public class InscriberRecipe implements IInscriberRecipe {
if (!this.output.equals(that.getOutput())) {
return false;
}
if (!this.maybeTop.equals(that.getTopOptional())) {
if (!this.maybeTop.equals(that.getTopInputs())) {
return false;
}
if (!this.maybeBot.equals(that.getBottomOptional())) {
if (!this.maybeBot.equals(that.getBottomInputs())) {
return false;
}
return this.type == that.getProcessType();
@@ -130,4 +129,6 @@ public class InscriberRecipe implements IInscriberRecipe {
result = 31 * result + this.type.hashCode();
return result;
}
}
@@ -75,9 +75,8 @@ public final class InscriberRegistry implements IInscriberRegistry {
Preconditions.checkNotNull(recipe, "Tried to add (null) as inscriber recipe to the registry.");
if (this.recipes.add(recipe)) {
recipe.getTopOptional().ifPresent(this.optionals::add);
recipe.getBottomOptional().ifPresent(this.optionals::add);
this.optionals.addAll(recipe.getTopInputs());
this.optionals.addAll(recipe.getBottomInputs());
this.inputs.addAll(recipe.getInputs());
return true;
@@ -110,8 +109,8 @@ public final class InscriberRegistry implements IInscriberRegistry {
private static final class Builder implements IInscriberRecipeBuilder {
private List<ItemStack> inputs;
private ItemStack output;
private ItemStack topOptional;
private ItemStack bottomOptional;
private List<ItemStack> topOptional;
private List<ItemStack> bottomOptional;
private InscriberProcessType type;
@Nonnull
@@ -139,22 +138,22 @@ public final class InscriberRegistry implements IInscriberRegistry {
@Nonnull
@Override
public Builder withTopOptional(@Nonnull final ItemStack topOptional) {
public Builder withTopOptional(@Nonnull final Collection<ItemStack> topOptional) {
Preconditions.checkNotNull(topOptional);
Preconditions.checkArgument(!topOptional.isEmpty());
this.topOptional = topOptional;
this.topOptional = new ArrayList<>(topOptional.size());
this.topOptional.addAll(topOptional);
return this;
}
@Nonnull
@Override
public Builder withBottomOptional(@Nonnull final ItemStack bottomOptional) {
public Builder withBottomOptional(@Nonnull final Collection<ItemStack> bottomOptional) {
Preconditions.checkNotNull(bottomOptional);
Preconditions.checkArgument(!bottomOptional.isEmpty());
this.bottomOptional = bottomOptional;
this.bottomOptional = new ArrayList<>(bottomOptional.size());
this.bottomOptional.addAll(bottomOptional);
return this;
}
@@ -98,6 +98,13 @@ public enum ButtonToolTips {
Blocking,
NonBlocking,
LockCraftingMode,
LockCraftingModeNone,
LockCraftingUntilRedstonePulse,
LockCraftingWhileRedstoneHigh,
LockCraftingWhileRedstoneLow,
LockCraftingUntilResultReturned,
LevelType,
LevelType_Energy,
LevelType_Item,
@@ -150,13 +157,20 @@ public enum ButtonToolTips {
DecreaseByOneDesc,
MaxCount,
MaxCountDesc,
FreeMolecularSlotShortcut,
FreeMolecularSlotShortcutDesc,
ToggleMolecularAssemblers,
ToggleMolecularAssemblersOnDesc,
ToggleMolecularAssemblersOffDesc,
ToggleShowFullInterfaces,
ToggleShowFullInterfacesOnDesc,
ToggleShowFullInterfacesOffDesc,
ToggleShowOnlyInvalidInterface,
ToggleShowOnlyInvalidInterfaceOnDesc,
ToggleShowOnlyInvalidInterfaceOffDesc,
HighlightInterface,
HighlightInterfaceDesc,
SearchFieldInputs,
SearchFieldOutputs,
SearchFieldNames,
// Used in the tooltips of the items in the terminal, when moused over
ItemsStored,
@@ -97,6 +97,7 @@ public enum GuiText {
RedstoneTunnel,
EUTunnel,
FluidTunnel,
FluidTerminal,
OCTunnel,
LightTunnel,
FETunnel,
@@ -41,7 +41,15 @@ public enum PlayerMessages {
DeviceNotLinked,
StationCanNotBeLocated,
SettingCleared,
MissingPatternsToEncode;
MissingPatternsToEncode,
InterfaceInOtherDimParam,
InterfaceInOtherDim,
InterfaceHighlighted,
;
public ITextComponent get(Object... params) {
return new TextComponentTranslation(this.getName(), params);
}
public ITextComponent get() {
return new TextComponentTranslation(this.getName());
+22 -3
View File
@@ -43,7 +43,6 @@ import appeng.container.AEBaseContainer;
import appeng.container.ContainerNull;
import appeng.container.ContainerOpenContext;
import appeng.container.implementations.*;
import appeng.container.interfaces.IInventorySlotAware;
import appeng.fluids.container.*;
import appeng.fluids.helper.IFluidInterfaceHost;
import appeng.fluids.parts.PartFluidFormationPlane;
@@ -59,11 +58,20 @@ import appeng.parts.automation.PartFormationPlane;
import appeng.parts.automation.PartLevelEmitter;
import appeng.parts.misc.PartOreDicStorageBus;
import appeng.parts.misc.PartStorageBus;
import appeng.parts.reporting.*;
import appeng.parts.reporting.PartCraftingTerminal;
import appeng.parts.reporting.PartExpandedProcessingPatternTerminal;
import appeng.parts.reporting.PartFluidInterfaceConfigurationTerminal;
import appeng.parts.reporting.PartInterfaceConfigurationTerminal;
import appeng.parts.reporting.PartInterfaceTerminal;
import appeng.parts.reporting.PartPatternTerminal;
import appeng.tile.crafting.TileCraftingTile;
import appeng.tile.crafting.TileMolecularAssembler;
import appeng.tile.grindstone.TileGrinder;
import appeng.tile.misc.*;
import appeng.tile.misc.TileCellWorkbench;
import appeng.tile.misc.TileCondenser;
import appeng.tile.misc.TileInscriber;
import appeng.tile.misc.TileSecurityStation;
import appeng.tile.misc.TileVibrationChamber;
import appeng.tile.networking.TileWireless;
import appeng.tile.qnb.TileQuantumBridge;
import appeng.tile.spatial.TileSpatialIOPort;
@@ -185,6 +193,7 @@ public enum GuiBridge implements IGuiHandler {
private Class guiClass;
private GuiHostType type;
private SecurityPermissions requiredPermission;
private GuiWrapper.IExternalGui externalGui = null;
GuiBridge() {
this.tileClass = null;
@@ -192,6 +201,16 @@ public enum GuiBridge implements IGuiHandler {
this.containerClass = null;
}
GuiBridge(GuiWrapper.IExternalGui obj) {
this.tileClass = null;
this.containerClass = null;
this.externalGui = obj;
}
public GuiWrapper.IExternalGui getExternalGui() {
return this.externalGui;
}
GuiBridge(final Class containerClass, final SecurityPermissions requiredPermission) {
this.requiredPermission = requiredPermission;
this.containerClass = containerClass;
@@ -0,0 +1,90 @@
package appeng.core.sync;
import it.unimi.dsi.fastutil.Hash;
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.common.util.EnumHelper;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* Allow to register custom GuiBridge from third-party
*/
public class GuiWrapper {
public static final GuiWrapper INSTANCE = new GuiWrapper();
private GuiWrapper() {
// NO-OP
}
private final Object2ObjectMap<ResourceLocation, Opener> openers = new Object2ObjectOpenHashMap<>();
private final Object2ObjectMap<IExternalGui, GuiBridge> externalGuis = new Object2ObjectOpenCustomHashMap<>(new Hash.Strategy<IExternalGui>() {
@Override
public int hashCode(IExternalGui o) {
return o.getID().hashCode();
}
@Override
public boolean equals(@Nullable IExternalGui a, @Nullable IExternalGui b) {
return a == b || (a != null && b != null && a.getID().equals(b.getID()));
}
});
public synchronized void registerExternalGuiHandler(@Nonnull ResourceLocation id, @Nonnull Opener opener) {
openers.put(id, opener);
}
@Nullable
public Opener getOpener(ResourceLocation id) {
return openers.get(id);
}
public GuiBridge wrap(IExternalGui obj) {
return externalGuis.computeIfAbsent(obj, this::create);
}
private GuiBridge create(IExternalGui obj) {
return EnumHelper.addEnum(GuiBridge.class, obj.getID().toString(), new Class<?>[] {IExternalGui.class}, obj);
}
@FunctionalInterface
public interface Opener {
<T extends IExternalGui> void open(T obj, GuiContext context);
}
public interface IExternalGui {
ResourceLocation getID();
}
public static class GuiContext {
public final World world;
public final EntityPlayer player;
public final BlockPos pos;
public final EnumFacing facing;
public final NBTTagCompound extra;
public GuiContext(World world, EntityPlayer player, BlockPos pos, EnumFacing face, NBTTagCompound extra) {
this.world = world;
this.player = player;
this.pos = pos;
this.facing = face;
this.extra = extra;
}
}
}
@@ -32,9 +32,7 @@ import appeng.api.networking.storage.IStorageGrid;
import appeng.api.storage.IMEMonitor;
import appeng.api.storage.channels.IItemStorageChannel;
import appeng.api.storage.data.IAEItemStack;
import appeng.container.implementations.ContainerExpandedProcessingPatternTerm;
import appeng.container.implementations.ContainerPatternEncoder;
import appeng.container.implementations.ContainerPatternTerm;
import appeng.core.sync.AppEngPacket;
import appeng.core.sync.network.INetworkInfo;
import appeng.helpers.IContainerCraftingPacket;
@@ -47,6 +45,7 @@ import appeng.util.item.AEItemStack;
import appeng.util.prioritylist.IPartitionList;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import it.unimi.dsi.fastutil.objects.Object2LongLinkedOpenHashMap;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.inventory.Container;
@@ -69,9 +68,10 @@ import static appeng.helpers.ItemStackHelper.stackFromNBT;
public class PacketJEIRecipe extends AppEngPacket {
static ItemStack[] emptyArray = {ItemStack.EMPTY};
private List<ItemStack[]> recipe;
private List<ItemStack> output;
static ItemStack[] emptyArray = {ItemStack.EMPTY};
private boolean shouldCondense;
// automatic.
@@ -80,6 +80,7 @@ public class PacketJEIRecipe extends AppEngPacket {
bytes.skip(stream.readerIndex());
final NBTTagCompound comp = CompressedStreamTools.readCompressed(bytes);
if (comp != null) {
this.shouldCondense = comp.getBoolean("condense");
this.recipe = new ArrayList<>();
for (int x = 0; x < comp.getKeySet().size(); x++) {
@@ -104,7 +105,6 @@ public class PacketJEIRecipe extends AppEngPacket {
}
}
}
}
// api
@@ -124,167 +124,212 @@ public class PacketJEIRecipe extends AppEngPacket {
@Override
public void serverPacketData(final INetworkInfo manager, final AppEngPacket packet, final EntityPlayer player) {
// oops :)
if (this.recipe == null) return;
final EntityPlayerMP pmp = (EntityPlayerMP) player;
final Container con = pmp.openContainer;
if (!(con instanceof IContainerCraftingPacket cct)) return;
if (!(con instanceof IContainerCraftingPacket)) {
return;
}
final IContainerCraftingPacket cct = (IContainerCraftingPacket) con;
final IGridNode node = cct.getNetworkNode();
if (node == null) {
return;
}
if (node == null) return;
final IGrid grid = node.getGrid();
if (grid == null) {
return;
}
if (grid == null) return;
final IStorageGrid inv = grid.getCache(IStorageGrid.class);
if (inv == null) return;
final IEnergyGrid energy = grid.getCache(IEnergyGrid.class);
final ISecurityGrid security = grid.getCache(ISecurityGrid.class);
if (energy == null) return;
final boolean hasExtractPermissions;
final boolean hasInjectPermissions;
if (grid.getCache(ISecurityGrid.class) instanceof ISecurityGrid security) {
hasInjectPermissions = security.hasPermission(player, SecurityPermissions.INJECT);
hasExtractPermissions = security.hasPermission(player, SecurityPermissions.EXTRACT);
} else {
hasInjectPermissions = false;
hasExtractPermissions = false;
}
final ICraftingGrid crafting = grid.getCache(ICraftingGrid.class);
final IItemHandler craftMatrix = cct.getInventoryByName("crafting");
final IItemHandler playerInventory = cct.getInventoryByName("player");
if (inv != null && this.recipe != null && security != null) {
final IMEMonitor<IAEItemStack> storage = inv.getInventory(AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class));
final IPartitionList<IAEItemStack> filter = ItemViewCell.createFilter(cct.getViewCells());
final Object2LongLinkedOpenHashMap<IAEItemStack> condensedBuffer;
if (this.shouldCondense) {
condensedBuffer = new Object2LongLinkedOpenHashMap<>();
} else {
condensedBuffer = null;
}
for (int x = 0; x < craftMatrix.getSlots(); x++) {
ItemStack currentItem = craftMatrix.getStackInSlot(x);
final IMEMonitor<IAEItemStack> storage = inv.getInventory(AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class));
final IPartitionList<IAEItemStack> filter = ItemViewCell.createFilter(cct.getViewCells());
if (x >= this.recipe.size()) {
currentItem = ItemStack.EMPTY;
// First iteration, find what can be used and send everything else into the network.
for (int matrixSlotIndex = 0; matrixSlotIndex < craftMatrix.getSlots(); matrixSlotIndex++) {
var currentItem = craftMatrix.getStackInSlot(matrixSlotIndex);
if (!currentItem.isEmpty()) {
if (this.canUseInSlot(matrixSlotIndex, currentItem)) continue;
if (!cct.useRealItems()) {
currentItem.setCount(0);
} else if (hasInjectPermissions) {
final var out = Platform.poweredInsert(energy, storage,
AEItemStack.fromItemStack(currentItem), cct.getActionSource());
currentItem.setCount(out != null ? (int) out.getStackSize() : 0);
}
}
}
// prepare slots
if (!currentItem.isEmpty()) {
// already the correct item?
ItemStack newItem = this.canUseInSlot(x, currentItem);
// Second iteration, query AE2 & player inventory for items.
for (int recipeSlotIndex = 0; recipeSlotIndex < recipe.size(); recipeSlotIndex++) {
ItemStack currentItem;
if (!cct.useRealItems() && this.recipe.get(x) != null) {
if (this.recipe.get(x).length > 0) {
currentItem.setCount(recipe.get(x)[0].getCount());
}
}
if (recipeSlotIndex < craftMatrix.getSlots()) {
currentItem = craftMatrix.getStackInSlot(recipeSlotIndex);
} else if (this.shouldCondense) {
// If the inputs should be condensed, we can read past the current grid.
currentItem = ItemStack.EMPTY;
} else {
// Otherwise break.
break;
}
// put away old item
if (newItem != currentItem && security.hasPermission(player, SecurityPermissions.INJECT)) {
final IAEItemStack in = AEItemStack.fromItemStack(currentItem);
final IAEItemStack out = cct.useRealItems() ? Platform.poweredInsert(energy, storage, in, cct.getActionSource()) : null;
if (out != null) {
currentItem = out.createItemStack();
} else {
currentItem = ItemStack.EMPTY;
}
}
}
if (currentItem.isEmpty() && recipe.get(recipeSlotIndex) != null) {
// for each variant
for (int y = 0; y < this.recipe.get(recipeSlotIndex).length && currentItem.isEmpty(); y++) {
var recipeStackVariant = this.recipe.get(recipeSlotIndex)[y];
final IAEItemStack request = AEItemStack.fromItemStack(recipeStackVariant);
if (request != null) {
// try ae
if ((filter == null || filter.isListed(request)) && hasExtractPermissions) {
request.setStackSize(1);
IAEItemStack out;
if (currentItem.isEmpty() && recipe.size() > x && recipe.get(x) != null) {
// for each variant
for (int y = 0; y < this.recipe.get(x).length && currentItem.isEmpty(); y++) {
final IAEItemStack request = AEItemStack.fromItemStack(this.recipe.get(x)[y]);
if (request != null) {
// try ae
if ((filter == null || filter.isListed(request)) && security.hasPermission(player, SecurityPermissions.EXTRACT)) {
request.setStackSize(1);
IAEItemStack out;
if (cct.useRealItems()) {
out = Platform.poweredExtraction(energy, storage, request, cct.getActionSource());
if (out == null) {
if (request.getItem().isDamageable() || Platform.isGTDamageableItem(request.getItem())) {
Collection<IAEItemStack> outList = inv.getInventory(AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class)).getStorageList().findFuzzy(request, FuzzyMode.IGNORE_ALL);
for (IAEItemStack is : outList) {
if (is.getStackSize() == 0) {
if (cct.useRealItems()) {
out = Platform.poweredExtraction(energy, storage, request, cct.getActionSource());
if (out == null) {
if (request.getItem().isDamageable() || Platform.isGTDamageableItem(request.getItem())) {
Collection<IAEItemStack> outList = inv.getInventory(AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class)).getStorageList().findFuzzy(request, FuzzyMode.IGNORE_ALL);
for (IAEItemStack is : outList) {
if (is.getStackSize() == 0) {
continue;
}
if (Platform.isGTDamageableItem(request.getItem())) {
if (!(is.getDefinition().getMetadata() == request.getDefinition().getMetadata())) {
continue;
}
if (Platform.isGTDamageableItem(request.getItem())) {
if (!(is.getDefinition().getMetadata() == request.getDefinition().getMetadata())) {
continue;
}
}
out = Platform.poweredExtraction(energy, storage, is.copy().setStackSize(1), cct.getActionSource());
if (out != null) {
break;
}
}
out = Platform.poweredExtraction(energy, storage, is.copy().setStackSize(1), cct.getActionSource());
if (out != null) {
break;
}
}
}
} else {
// Query the crafting grid if there is a pattern providing the item
if (!crafting.getCraftingFor(request, null, 0, null).isEmpty()) {
out = request;
} else {
// Fall back using an existing item
out = storage.extractItems(request, Actionable.SIMULATE, cct.getActionSource());
}
}
if (out != null) {
if (!cct.useRealItems()) {
out.setStackSize(recipe.get(x)[y].getCount());
}
currentItem = out.createItemStack();
} else {
// Query the crafting grid if there is a pattern providing the item
if (!crafting.getCraftingFor(request, null, 0, null).isEmpty()) {
out = request;
} else {
// Fall back using an existing item
out = storage.extractItems(request, Actionable.SIMULATE, cct.getActionSource());
}
}
// try inventory
if (currentItem.isEmpty()) {
AdaptorItemHandler ad = new AdaptorItemHandler(playerInventory);
if (cct.useRealItems()) {
currentItem = ad.removeSimilarItems(1, this.recipe.get(x)[y], FuzzyMode.IGNORE_ALL, null);
} else {
currentItem = ad.simulateSimilarRemove(recipe.get(x)[y].getCount(), this.recipe.get(x)[y], FuzzyMode.IGNORE_ALL, null);
if (out != null) {
if (!cct.useRealItems()) {
out.setStackSize(recipeStackVariant.getCount());
}
currentItem = out.createItemStack();
}
}
}
if (!cct.useRealItems()) {
if (currentItem.isEmpty() && recipe.size() > x && this.recipe.get(x) != null) {
currentItem = this.recipe.get(x)[0].copy();
// try inventory
if (currentItem.isEmpty()) {
AdaptorItemHandler ad = new AdaptorItemHandler(playerInventory);
if (cct.useRealItems()) {
currentItem = ad.removeSimilarItems(1, recipeStackVariant, FuzzyMode.IGNORE_ALL, null);
} else {
currentItem = ad.simulateSimilarRemove(recipeStackVariant.getCount(), recipeStackVariant, FuzzyMode.IGNORE_ALL, null);
}
}
}
}
ItemHandlerUtil.setStackInSlot(craftMatrix, x, currentItem);
if (!cct.useRealItems()) {
if (currentItem.isEmpty() && recipe.size() > recipeSlotIndex && this.recipe.get(recipeSlotIndex) != null) {
currentItem = this.recipe.get(recipeSlotIndex)[0].copy();
}
}
}
con.onCraftMatrixChanged(new WrapperInvItemHandler(craftMatrix));
if (this.output != null && ((con instanceof ContainerPatternEncoder && !((ContainerPatternEncoder) con).isCraftingMode()))) {
IItemHandler outputSlots = cct.getInventoryByName("output");
for (int i = 0; i < outputSlots.getSlots(); ++i) {
ItemHandlerUtil.setStackInSlot(outputSlots, i, ItemStack.EMPTY);
if (condensedBuffer != null) {
var aeItemStack = AEItemStack.fromItemStack(currentItem);
if (aeItemStack != null) {
condensedBuffer.compute(aeItemStack, (k, v) -> (v == null ? 0 : v) + k.getStackSize());
}
for (int i = 0; i < this.output.size() && i < outputSlots.getSlots(); ++i) {
if (this.output.get(i) == null || this.output.get(i) == ItemStack.EMPTY) {
} else {
ItemHandlerUtil.setStackInSlot(craftMatrix, recipeSlotIndex, currentItem);
}
}
if (condensedBuffer != null) {
var slotIndex = 0;
// Fill the craft matrix with items from the condensed buffer.
for (var entry : condensedBuffer.entrySet()) {
if (slotIndex >= craftMatrix.getSlots()) break;
ItemHandlerUtil.setStackInSlot(craftMatrix, slotIndex,
entry.getKey().copy().setStackSize(entry.getValue()).createItemStack());
slotIndex++;
}
// Clear the remaining slots.
for (var i = slotIndex; i < craftMatrix.getSlots(); i++) {
ItemHandlerUtil.setStackInSlot(craftMatrix, i, ItemStack.EMPTY);
}
}
con.onCraftMatrixChanged(new WrapperInvItemHandler(craftMatrix));
if (this.output != null && con instanceof ContainerPatternEncoder encoder && !encoder.isCraftingMode()) {
var outputSlots = cct.getInventoryByName("output");
for (int i = 0; i < outputSlots.getSlots(); ++i) {
if (i < this.output.size()) {
var outputStack = this.output.get(i);
if (outputStack != null && outputStack != ItemStack.EMPTY) {
ItemHandlerUtil.setStackInSlot(outputSlots, i, outputStack);
continue;
}
ItemHandlerUtil.setStackInSlot(outputSlots, i, this.output.get(i));
}
ItemHandlerUtil.setStackInSlot(outputSlots, i, ItemStack.EMPTY);
}
}
}
/**
* @param slot
* @param slot slot index
* @param is itemstack
* @return is if it can be used, else EMPTY
*/
private ItemStack canUseInSlot(int slot, ItemStack is) {
if (this.recipe.get(slot) != null) {
for (ItemStack option : this.recipe.get(slot)) {
private boolean canUseInSlot(int slot, ItemStack is) {
if (slot >= this.recipe.size()) return false;
var variants = this.recipe.get(slot);
if (variants != null) {
for (ItemStack option : variants) {
if (ItemStack.areItemStacksEqual(is, option)) {
return is;
return true;
}
}
}
return ItemStack.EMPTY;
return false;
}
}
+10 -6
View File
@@ -131,7 +131,7 @@ public class CraftingJob implements Runnable, ICraftingJob {
craftingInventory.ignore(this.output);
this.availableCheck = new MECraftingInventory(this.original, false, false, false);
craftingTreeWatch.start();
craftingTreeWatch.reset().start();
this.getTree().request(craftingInventory, this.output.getStackSize(), this.actionSrc);
craftingTreeWatch.stop();
this.getTree().dive(this);
@@ -170,10 +170,8 @@ public class CraftingJob implements Runnable, ICraftingJob {
} else {
this.logCraftingJob("real, failed", craftingTreeWatch);
}
} catch (final CraftBranchFailure e1) {
} catch (final CraftBranchFailure | CraftingCalculationFailure e1) {
AELog.debug(e1);
} catch (final CraftingCalculationFailure f) {
AELog.debug(f);
} catch (final InterruptedException e1) {
AELog.crafting("Crafting calculation canceled.");
this.finish();
@@ -202,8 +200,14 @@ public class CraftingJob implements Runnable, ICraftingJob {
synchronized (this.monitor) {
if (this.tickSpreadingWatch.elapsed(TimeUnit.MICROSECONDS) > this.time) {
this.running = false;
this.craftingTreeWatch.stop();
this.tickSpreadingWatch.stop();
if (this.craftingTreeWatch.isRunning()) {
this.craftingTreeWatch.stop();
}
if (this.tickSpreadingWatch.isRunning()) {
this.tickSpreadingWatch.stop();
}
this.monitor.notify();
}
@@ -127,7 +127,7 @@ public class GuiFluidTerminal extends AEBaseMEGui implements ISortSource, IConfi
@Override
public void drawFG(int offsetX, int offsetY, int mouseX, int mouseY) {
this.fontRenderer.drawString(this.getGuiDisplayName("Fluid Terminal"), 8, 6, 4210752);
this.fontRenderer.drawString(GuiText.FluidTerminal.getLocal(), 8, 6, 4210752);
this.fontRenderer.drawString(GuiText.inventory.getLocal(), 8, this.ySize - 96 + 3, 4210752);
}
@@ -93,4 +93,10 @@ public class GuiFluidSlot extends GuiCustomSlot implements IJEITargetSlot {
this.fluids.setFluidInSlot(this.slot, stack);
NetworkHandler.instance().sendToServer(new PacketFluidSlot(Collections.singletonMap(this.getId(), this.getFluidStack())));
}
@Override
public boolean needAccept() {
return this.getFluidStack() == null;
}
}
@@ -48,6 +48,7 @@ import appeng.api.util.IConfigManager;
import appeng.capabilities.Capabilities;
import appeng.core.settings.TickRates;
import appeng.fluids.util.AEFluidInventory;
import appeng.fluids.util.AEFluidStack;
import appeng.fluids.util.IAEFluidInventory;
import appeng.fluids.util.IAEFluidTank;
import appeng.helpers.ICustomNameObject;
@@ -473,7 +474,12 @@ public class DualityFluidInterface implements IGridTickable, IStorageMonitorable
}
@Override
public void onFluidInventoryChanged(final IAEFluidTank inventory, final int slot) {
public void onFluidInventoryChanged(IAEFluidTank inv, int slot) {
onFluidInventoryChanged(inv, slot, null, null, null);
}
@Override
public void onFluidInventoryChanged(final IAEFluidTank inventory, final int slot, InvOperation operation, FluidStack added, FluidStack removed) {
if (this.isWorking == slot) {
return;
}
@@ -486,6 +492,9 @@ public class DualityFluidInterface implements IGridTickable, IStorageMonitorable
this.notifyNeighbors();
}
} else if (inventory == this.tanks) {
if (added != null) {
iHost.onStackReturnNetwork(AEFluidStack.fromFluidStack(added));
}
this.saveChanges();
final boolean had = this.hasWorkToDo();
@@ -21,9 +21,11 @@ package appeng.fluids.helper;
import appeng.api.implementations.IUpgradeableHost;
import appeng.api.networking.security.IActionHost;
import appeng.api.storage.data.IAEFluidStack;
import appeng.me.helpers.IGridProxyable;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.fluids.FluidStack;
import java.util.EnumSet;
@@ -36,4 +38,7 @@ public interface IFluidInterfaceHost extends IActionHost, IGridProxyable, IUpgra
TileEntity getTileEntity();
void saveChanges();
default void onStackReturnNetwork(IAEFluidStack stack) {
}
}
@@ -22,6 +22,7 @@ package appeng.fluids.items;
import appeng.bootstrap.IItemRendering;
import appeng.bootstrap.ItemRenderingCustomizer;
import appeng.client.render.DummyFluidItemModel;
import net.minecraftforge.fluids.FluidStack;
/**
@@ -33,5 +34,9 @@ public class FluidDummyItemRendering extends ItemRenderingCustomizer {
@Override
public void customize(IItemRendering rendering) {
rendering.builtInModel("models/item/dummy_fluid_item", new DummyFluidItemModel());
rendering.color(((s, i) -> {
FluidStack fluid = ((FluidDummyItem) s.getItem()).getFluidStack(s);
return fluid != null ? fluid.getFluid().getColor() : 0xFFFFFFFF;
}));
}
}
@@ -29,6 +29,7 @@ import appeng.me.storage.MEInventoryHandler;
import appeng.parts.automation.PartAbstractFormationPlane;
import appeng.parts.automation.PlaneModels;
import appeng.util.Platform;
import appeng.util.inv.InvOperation;
import appeng.util.prioritylist.PrecisePriorityList;
import net.minecraft.block.Block;
import net.minecraft.block.BlockLiquid;
@@ -36,6 +36,7 @@ import appeng.parts.PartModel;
import appeng.parts.automation.PartUpgradeable;
import appeng.util.IConfigManagerHost;
import appeng.util.Platform;
import appeng.util.inv.InvOperation;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
@@ -46,6 +47,7 @@ import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidHandler;
import java.util.Random;
@@ -63,6 +63,7 @@ import appeng.parts.automation.PartUpgradeable;
import appeng.tile.networking.TileCableBus;
import appeng.util.ConfigManager;
import appeng.util.Platform;
import appeng.util.inv.InvOperation;
import appeng.util.prioritylist.FuzzyPriorityList;
import appeng.util.prioritylist.PrecisePriorityList;
import net.minecraft.entity.player.EntityPlayer;
@@ -75,11 +76,13 @@ import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.IBlockAccess;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -220,11 +223,13 @@ public class PartFluidStorageBus extends PartUpgradeable implements IGridTickabl
@Override
public void postChange(final IBaseMonitor<IAEFluidStack> monitor, final Iterable<IAEFluidStack> change, final IActionSource source) {
if (this.getProxy().isActive()) {
var filteredChanges = this.filterChanges(change);
AccessRestriction currentAccess = (AccessRestriction) ((ConfigManager) this.getConfigManager()).getSetting(Settings.ACCESS);
if (readOncePass) {
readOncePass = false;
try {
this.getProxy().getStorage().postAlterationOfStoredItems(AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class), change, this.source);
this.getProxy().getStorage().postAlterationOfStoredItems(AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class), filteredChanges, this.source);
} catch (final GridAccessException e) {
// :(
}
@@ -234,7 +239,7 @@ public class PartFluidStorageBus extends PartUpgradeable implements IGridTickabl
return;
}
try {
this.getProxy().getStorage().postAlterationOfStoredItems(AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class), change, source);
this.getProxy().getStorage().postAlterationOfStoredItems(AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class), filteredChanges, source);
} catch (final GridAccessException e) {
// :(
}
@@ -426,6 +431,7 @@ public class PartFluidStorageBus extends PartUpgradeable implements IGridTickabl
this.handler.setBaseAccess((AccessRestriction) this.getConfigManager().getSetting(Settings.ACCESS));
this.handler.setWhitelist(this.getInstalledUpgrades(Upgrades.INVERTER) > 0 ? IncludeExclude.BLACKLIST : IncludeExclude.WHITELIST);
this.handler.setPriority(this.getPriority());
this.handler.setStorageFilter((StorageFilter) this.getConfigManager().getSetting(Settings.STORAGE_FILTER));
final IItemList<IAEFluidStack> priorityList = AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class).createList();
@@ -537,4 +543,27 @@ public class PartFluidStorageBus extends PartUpgradeable implements IGridTickabl
public GuiBridge getGuiBridge() {
return GuiBridge.GUI_STORAGEBUS_FLUID;
}
// TODO: 1/28/2024 Unify both methods.
/**
* Filters the changes to only include items that pass the storage filter.
* Optimally, this should be handled by the underlying monitor.
*
* @see appeng.parts.misc.PartStorageBus#filterChanges
*/
protected Iterable<IAEFluidStack> filterChanges(Iterable<IAEFluidStack> change) {
var storageFilter = this.getConfigManager().getSetting(Settings.STORAGE_FILTER);
if (storageFilter == StorageFilter.EXTRACTABLE_ONLY && handler != null) {
var filteredList = new ArrayList<IAEFluidStack>();
for (final IAEFluidStack stack : change) {
if (this.handler.passesBlackOrWhitelist(stack)) {
filteredList.add(stack);
}
}
return filteredList;
}
return change;
}
}
@@ -4,6 +4,7 @@ package appeng.fluids.util;
import appeng.api.storage.data.IAEFluidStack;
import appeng.core.AELog;
import appeng.util.Platform;
import appeng.util.inv.InvOperation;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidTankProperties;
@@ -37,24 +38,27 @@ public class AEFluidInventory implements IAEFluidTank {
if (Objects.equals(this.fluids[slot], fluid)) {
if (fluid != null && fluid.getStackSize() != this.fluids[slot].getStackSize()) {
this.fluids[slot].setStackSize(fluid.getStackSize());
this.onContentChanged(slot);
this.onContentChanged(slot, InvOperation.SET, fluid.getFluidStack(), null);
}
} else {
if (fluid == null) {
IAEFluidStack removeStack = this.fluids[slot].copy();
this.fluids[slot] = null;
this.onContentChanged(slot, InvOperation.SET, null, removeStack.getFluidStack());
} else {
IAEFluidStack removeStack = this.fluids[slot];
this.fluids[slot] = fluid.copy();
this.fluids[slot].setStackSize(fluid.getStackSize());
this.onContentChanged(slot, InvOperation.SET, fluid.getFluidStack(), removeStack == null ? null : removeStack.getFluidStack());
}
this.onContentChanged(slot);
}
}
}
private void onContentChanged(final int slot) {
private void onContentChanged(final int slot, InvOperation operation, FluidStack added, FluidStack removed) {
if (this.handler != null && Platform.isServer()) {
this.handler.onFluidInventoryChanged(this, slot);
this.handler.onFluidInventoryChanged(this, slot, operation, added, removed);
}
}
@@ -107,7 +111,7 @@ public class AEFluidInventory implements IAEFluidTank {
this.setFluidInSlot(slot, AEFluidStack.fromFluidStack(resource).setStackSize(amountToStore));
} else {
fluid.setStackSize(fluid.getStackSize() + amountToStore);
this.onContentChanged(slot);
this.onContentChanged(slot, InvOperation.INSERT, resource, null);
}
}
@@ -139,7 +143,7 @@ public class AEFluidInventory implements IAEFluidTank {
if (fluid.getStackSize() <= 0) {
this.fluids[slot] = null;
}
this.onContentChanged(slot);
this.onContentChanged(slot, InvOperation.EXTRACT, null, new FluidStack(fluid.getFluid(), drained));
}
return stack;
}
@@ -21,6 +21,7 @@ package appeng.fluids.util;
import appeng.api.storage.data.IAEFluidStack;
import appeng.util.Platform;
import appeng.util.inv.InvOperation;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.fluids.FluidTank;
@@ -19,7 +19,13 @@
package appeng.fluids.util;
import appeng.util.inv.InvOperation;
import net.minecraftforge.fluids.FluidStack;
@FunctionalInterface
public interface IAEFluidInventory {
void onFluidInventoryChanged(final IAEFluidTank inv, final int slot);
default void onFluidInventoryChanged(final IAEFluidTank inv, final int slot, InvOperation operation, FluidStack added, FluidStack removed) {
}
}
@@ -20,10 +20,7 @@ package appeng.helpers;
import appeng.api.AEApi;
import appeng.api.config.Actionable;
import appeng.api.config.Settings;
import appeng.api.config.Upgrades;
import appeng.api.config.YesNo;
import appeng.api.config.*;
import appeng.api.implementations.ICraftingPatternItem;
import appeng.api.implementations.IUpgradeableHost;
import appeng.api.implementations.tiles.ICraftingMachine;
@@ -53,6 +50,7 @@ import appeng.api.util.AEPartLocation;
import appeng.api.util.DimensionalCoord;
import appeng.api.util.IConfigManager;
import appeng.capabilities.Capabilities;
import appeng.core.AELog;
import appeng.core.settings.TickRates;
import appeng.me.GridAccessException;
import appeng.me.helpers.AENetworkProxy;
@@ -67,10 +65,7 @@ import appeng.tile.inventory.AppEngInternalAEInventory;
import appeng.tile.inventory.AppEngInternalInventory;
import appeng.tile.inventory.AppEngInternalOversizedInventory;
import appeng.tile.networking.TileCableBus;
import appeng.util.ConfigManager;
import appeng.util.IConfigManagerHost;
import appeng.util.InventoryAdaptor;
import appeng.util.Platform;
import appeng.util.*;
import appeng.util.inv.*;
import appeng.util.item.AEItemStack;
import com.google.common.collect.ImmutableSet;
@@ -101,6 +96,8 @@ import net.minecraftforge.items.wrapper.RangedWrapper;
import javax.annotation.Nullable;
import java.util.*;
import static appeng.api.config.LockCraftingMode.LOCK_UNTIL_PULSE;
import static appeng.api.config.LockCraftingMode.LOCK_UNTIL_RESULT;
import static appeng.helpers.ItemStackHelper.*;
@@ -135,6 +132,13 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
private boolean resetConfigCache = true;
private IMEMonitor<IAEItemStack> configCachedHandler;
private YesNo redstoneState = YesNo.UNDECIDED;
@Nullable
private UnlockCraftingEvent unlockEvent;
@Nullable
private IAEItemStack unlockStack;
public DualityInterface(final AENetworkProxy networkProxy, final IInterfaceHost ih) {
this.gridProxy = networkProxy;
this.gridProxy.setFlags(GridFlags.REQUIRE_CHANNEL);
@@ -142,6 +146,7 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
this.upgrades = new StackUpgradeInventory(this.gridProxy.getMachineRepresentation(), this, 4);
this.cm.registerSetting(Settings.BLOCK, YesNo.NO);
this.cm.registerSetting(Settings.INTERFACE_TERMINAL, YesNo.YES);
this.cm.registerSetting(Settings.UNLOCK, LockCraftingMode.NONE);
this.iHost = ih;
this.craftingTracker = new MultiCraftingTracker(this.iHost, 9);
@@ -168,6 +173,7 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
if (this.isWorking == slot) {
return;
}
if (inv == this.config && (!removed.isEmpty() || !added.isEmpty())) {
boolean cfg = hasConfig();
this.readConfig();
@@ -178,6 +184,9 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
} else if (inv == this.patterns && (!removed.isEmpty() || !added.isEmpty())) {
this.updateCraftingList();
} else if (inv == this.storage && slot >= 0) {
if (added != ItemStack.EMPTY){
iHost.onStackReturnNetwork(AEItemStack.fromItemStack(added));
}
final boolean had = this.hasWorkToDo();
this.updatePlan(slot);
@@ -207,6 +216,18 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
this.craftingTracker.writeToNBT(data);
data.setInteger("priority", this.priority);
if (unlockEvent == UnlockCraftingEvent.PULSE) {
data.setByte("unlockEvent", (byte) 1);
} else if (unlockEvent == UnlockCraftingEvent.RESULT) {
if (unlockStack != null) {
data.setByte("unlockEvent", (byte) 2);
NBTTagCompound unlockStackTag = new NBTTagCompound();
unlockStack.writeToNBT(unlockStackTag);
data.setTag("unlockStack", unlockStackTag);
} else {
AELog.error("Saving MEInterface {}, locked waiting for stack, but stack is null!", iHost);
}
}
final NBTTagList waitingToSend = new NBTTagList();
if (this.waitingToSend != null) {
for (final ItemStack is : this.waitingToSend) {
@@ -286,6 +307,27 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
this.cm.readFromNBT(data);
this.readConfig();
this.updateCraftingList();
var unlockEventType = data.getByte("unlockEvent");
this.unlockEvent = switch (unlockEventType) {
case 0 -> null;
case 1 -> UnlockCraftingEvent.PULSE;
case 2 -> UnlockCraftingEvent.RESULT;
default -> {
AELog.error("Unknown unlock event type {} in NBT for MEInterface: {}", unlockEventType, data);
yield null;
}
};
if (this.unlockEvent == UnlockCraftingEvent.RESULT) {
this.unlockStack = AEItemStack.fromNBT(data.getCompoundTag("unlockStack"));
if (this.unlockStack == null) {
AELog.error("Could not load unlock stack for MEInterface from NBT: {}", data);
}
} else {
this.unlockStack = null;
}
}
private void addToSendList(final ItemStack is) {
@@ -912,6 +954,11 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
if (this.getInstalledUpgrades(Upgrades.CRAFTING) == 0) {
this.cancelCrafting();
}
if (newValue == LockCraftingMode.NONE) {
resetCraftingLock();
}
this.iHost.saveChanges();
}
@@ -951,6 +998,10 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
final TileEntity tile = this.iHost.getTileEntity();
final World w = tile.getWorld();
if (getCraftingLockedReason() != LockCraftingMode.NONE) {
return false;
}
if (this.visitedFaces.isEmpty()) {
this.visitedFaces = this.iHost.getTargets();
}
@@ -978,6 +1029,8 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
continue;
} else {
IMEMonitor<IAEItemStack> inv = sm.getInventory(AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class));
var allItemsCanBeInserted = true;
for (int x = 0; x < table.getSizeInventory(); x++) {
final ItemStack is = table.getStackInSlot(x);
if (is.isEmpty()) {
@@ -985,16 +1038,25 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
}
IAEItemStack result = inv.injectItems(AEItemStack.fromItemStack(is), Actionable.SIMULATE, this.mySource);
if (result != null) {
return false;
allItemsCanBeInserted = false;
break;
}
}
if (!allItemsCanBeInserted) {
continue;
}
this.visitedFaces.clear();
for (int x = 0; x < table.getSizeInventory(); x++) {
final ItemStack is = table.getStackInSlot(x);
if (!is.isEmpty()) {
addToSendListFacing(is, s);
}
}
onPushPatternSuccess(patternDetails);
pushItemsOut(s);
return true;
}
}
@@ -1011,6 +1073,7 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
if (cm.acceptsPlans()) {
visitedFaces.remove(s);
if (cm.pushPattern(patternDetails, table, s.getOpposite())) {
onPushPatternSuccess(patternDetails);
return true;
}
continue;
@@ -1044,13 +1107,14 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
}
if (this.acceptsItems(ad, table)) {
visitedFaces.remove(s);
this.visitedFaces.clear();
for (int x = 0; x < table.getSizeInventory(); x++) {
final ItemStack is = table.getStackInSlot(x);
if (!is.isEmpty()) {
addToSendListFacing(is, s);
}
}
onPushPatternSuccess(patternDetails);
pushItemsOut(s);
return true;
}
@@ -1060,6 +1124,57 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
return false;
}
public void resetCraftingLock() {
if (unlockEvent != null) {
unlockEvent = null;
unlockStack = null;
saveChanges();
}
}
private void onPushPatternSuccess(ICraftingPatternDetails pattern) {
resetCraftingLock();
LockCraftingMode lockMode = (LockCraftingMode) cm.getSetting(Settings.UNLOCK);
switch (lockMode) {
case LOCK_UNTIL_PULSE -> {
unlockEvent = UnlockCraftingEvent.PULSE;
saveChanges();
}
case LOCK_UNTIL_RESULT -> {
unlockEvent = UnlockCraftingEvent.RESULT;
unlockStack = pattern.getPrimaryOutput();
saveChanges();
}
}
}
/**
* Gets if the crafting lock is in effect and why.
*
* @return null if the lock isn't in effect
*/
public LockCraftingMode getCraftingLockedReason() {
var lockMode = cm.getSetting(Settings.UNLOCK);
if (lockMode == LockCraftingMode.LOCK_WHILE_LOW && !getRedstoneState()) {
// Crafting locked by redstone signal
return LockCraftingMode.LOCK_WHILE_LOW;
} else if (lockMode == LockCraftingMode.LOCK_WHILE_HIGH && getRedstoneState()) {
return LockCraftingMode.LOCK_WHILE_HIGH;
} else if (unlockEvent != null) {
// Crafting locked by waiting for unlock event
switch (unlockEvent) {
case PULSE -> {
return LOCK_UNTIL_PULSE;
}
case RESULT -> {
return LOCK_UNTIL_RESULT;
}
}
}
return LockCraftingMode.NONE;
}
@Override
public boolean isBusy() {
boolean busy = false;
@@ -1374,6 +1489,55 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
return null;
}
public void updateRedstoneState() {
// If we're waitingh for a pulse, update immediately
if (unlockEvent == UnlockCraftingEvent.PULSE && getRedstoneState()) {
unlockEvent = null; // Unlocked!
} else {
// Otherwise, just reset back to undecided
redstoneState = YesNo.UNDECIDED;
}
saveChanges(); // In any case, this needs to be changed since the state is now outdated
}
/**
* @return Null if {@linkplain #getCraftingLockedReason()} is not {@link LockCraftingMode#LOCK_UNTIL_RESULT}.
*/
@org.jetbrains.annotations.Nullable
public IAEItemStack getUnlockStack() {
return unlockStack;
}
public void onStackReturnedToNetwork(IAEItemStack stack) {
if (unlockEvent != UnlockCraftingEvent.RESULT) {
return; // If we're not waiting for the result, we don't care
}
if (unlockStack == null) {
// Actually an error state...
AELog.error("MEInterface was waiting for RESULT, but no result was set");
unlockEvent = null;
} else if (unlockStack.getItem().equals(stack.getItem())) {
var remainingAmount = unlockStack.getStackSize() - stack.getStackSize();
if (remainingAmount <= 0) {
unlockEvent = null;
unlockStack = null;
} else {
unlockStack.setStackSize(remainingAmount);
}
}
}
private boolean getRedstoneState() {
if (redstoneState == YesNo.UNDECIDED) {
var entity = this.iHost.getTileEntity();
redstoneState = entity.getWorld().getRedstonePowerFromNeighbors(entity.getPos()) > 0
? YesNo.YES
: YesNo.NO;
}
return redstoneState == YesNo.YES;
}
private class InterfaceRequestSource extends MachineSource {
private final InterfaceRequestContext context;
@@ -22,6 +22,7 @@ package appeng.helpers;
import appeng.api.implementations.IUpgradeableHost;
import appeng.api.networking.crafting.ICraftingProvider;
import appeng.api.networking.crafting.ICraftingRequester;
import appeng.api.storage.data.IAEItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
@@ -37,4 +38,8 @@ public interface IInterfaceHost extends ICraftingProvider, IUpgradeableHost, ICr
TileEntity getTileEntity();
void saveChanges();
default void onStackReturnNetwork(IAEItemStack stack) {
getInterfaceDuality().onStackReturnedToNetwork(stack);
}
}
@@ -0,0 +1,6 @@
package appeng.helpers;
public enum UnlockCraftingEvent {
PULSE,
RESULT
}
@@ -14,6 +14,7 @@ import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.World;
import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
@@ -32,15 +33,13 @@ public class WrenchClickHook {
if (event instanceof PlayerInteractEvent.RightClickBlock && !event.getEntityPlayer().world.isRemote) {
EntityPlayer player = event.getEntityPlayer();
if (player instanceof FakePlayer) return;
EnumHand hand = event.getHand();
BlockPos pos = event.getPos();
World world = event.getWorld();
ItemStack held = event.getItemStack();
if (!Platform.hasPermissions(new DimensionalCoord(world, pos), player)) {
return;
}
if (player.isSneaking() && Platform.isWrench(player, held, pos)) {
Block block = world.getBlockState(pos).getBlock();
TileEntity tile = world.getTileEntity(pos);
@@ -48,6 +47,10 @@ public class WrenchClickHook {
return;
}
if (!Platform.hasPermissions(new DimensionalCoord(world, pos), player)) {
return;
}
final LookDirection dir = Platform.getPlayerRay(player, player.getEyeHeight());
final RayTraceResult mop = block.collisionRayTrace(world.getBlockState(pos), world, pos, dir.getA(), dir.getB());
if (mop != null) {
@@ -31,9 +31,7 @@ import net.minecraft.item.ItemStack;
import stanhebben.zenscript.annotations.ZenClass;
import stanhebben.zenscript.annotations.ZenMethod;
import java.util.Collection;
import java.util.Collections;
import java.util.Optional;
import java.util.*;
import java.util.stream.Collectors;
@@ -49,25 +47,15 @@ public class InscriberRecipes {
return;
}
Collection<ItemStack> topList = CTModule.toStacks(top).orElse(Collections.singleton(ItemStack.EMPTY));
Collection<ItemStack> bottomList = CTModule.toStacks(bottom).orElse(Collections.singleton(ItemStack.EMPTY));
for (ItemStack topStack : topList) {
for (ItemStack bottomStack : bottomList) {
final IInscriberRecipeBuilder builder = AEApi.instance().registries().inscriber().builder();
builder.withProcessType(inscribe ? InscriberProcessType.INSCRIBE : InscriberProcessType.PRESS)
.withOutput(CTModule.toStack(output))
.withInputs(inStacks.get());
if (!topStack.isEmpty()) {
builder.withTopOptional(topStack);
}
if (!bottomStack.isEmpty()) {
builder.withBottomOptional(bottomStack);
}
CTModule.MODIFICATIONS.add(new Add(builder.build()));
}
}
List<ItemStack> topList = new ArrayList<>(CTModule.toStacks(top).orElse(Collections.singleton(ItemStack.EMPTY)));
List<ItemStack> bottomList = new ArrayList<>(CTModule.toStacks(bottom).orElse(Collections.singleton(ItemStack.EMPTY)));
final IInscriberRecipeBuilder builder = AEApi.instance().registries().inscriber().builder();
builder.withProcessType(inscribe ? InscriberProcessType.INSCRIBE : InscriberProcessType.PRESS).
withTopOptional(topList).
withBottomOptional(bottomList).
withOutput(CTModule.toStack(output))
.withInputs(inStacks.get());
CTModule.MODIFICATIONS.add(new Add(builder.build()));
}
@ZenMethod
@@ -21,11 +21,11 @@ package appeng.integration.modules.jei;
import appeng.api.features.IInscriberRecipe;
import mezz.jei.api.ingredients.IIngredients;
import mezz.jei.api.ingredients.VanillaTypes;
import mezz.jei.api.recipe.IRecipeWrapper;
import net.minecraft.item.ItemStack;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -40,11 +40,10 @@ class InscriberRecipeWrapper implements IRecipeWrapper {
@Override
public void getIngredients(IIngredients ingredients) {
List<List<ItemStack>> inputSlots = new ArrayList<>(3);
inputSlots.add(Collections.singletonList(this.recipe.getTopOptional().orElse(ItemStack.EMPTY)));
inputSlots.add(this.recipe.getTopInputs());
inputSlots.add(this.recipe.getInputs());
inputSlots.add(Collections.singletonList(this.recipe.getBottomOptional().orElse(ItemStack.EMPTY)));
ingredients.setInputLists(ItemStack.class, inputSlots);
ingredients.setOutput(ItemStack.class, this.recipe.getOutput());
inputSlots.add(this.recipe.getBottomInputs());
ingredients.setInputLists(VanillaTypes.ITEM, inputSlots);
ingredients.setOutput(VanillaTypes.ITEM, this.recipe.getOutput());
}
}
@@ -16,9 +16,9 @@ import mezz.jei.gui.TooltipRenderer;
import mezz.jei.gui.recipes.RecipeLayout;
import mezz.jei.gui.recipes.RecipeTransferButton;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.inventory.Container;
import net.minecraft.item.ItemStack;
import net.minecraft.util.text.translation.I18n;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.wrapper.PlayerMainInvWrapper;
@@ -26,12 +26,14 @@ import javax.annotation.Nonnull;
import java.awt.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import static mezz.jei.api.recipe.transfer.IRecipeTransferError.Type.USER_FACING;
import static net.minecraft.client.resources.I18n.format;
public class JEIMissingItem implements IRecipeTransferError {
private final IRecipeLayout recipeLayout;
private boolean errored;
public long lastUpdate;
private final List<Integer> craftableSlots = new ArrayList<>();
@@ -40,8 +42,11 @@ public class JEIMissingItem implements IRecipeTransferError {
IItemList<IAEItemStack> available = AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class).createList();
IItemList<IAEItemStack> used = AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class).createList();
private boolean foundAny;
JEIMissingItem(Container container, @Nonnull IRecipeLayout recipeLayout) {
this.recipeLayout = recipeLayout;
if (container instanceof ContainerMEMonitorable) {
IItemList<IAEItemStack> ir = ((ContainerMEMonitorable) container).items;
@@ -57,8 +62,7 @@ public class JEIMissingItem implements IRecipeTransferError {
if (i.isInput() && !i.getAllIngredients().isEmpty()) {
List<?> allIngredients = i.getAllIngredients();
for (Object allIngredient : allIngredients) {
if (allIngredient instanceof ItemStack) {
ItemStack stack = (ItemStack) allIngredient;
if (allIngredient instanceof ItemStack stack) {
if (!stack.isEmpty()) {
IAEItemStack search = AEItemStack.fromItemStack(stack);
if (stack.getItem().isDamageable() || Platform.isGTDamageableItem(stack.getItem())) {
@@ -93,7 +97,8 @@ public class JEIMissingItem implements IRecipeTransferError {
}
if (!found) {
this.errored = true;
break;
} else{
this.foundAny = true;
}
}
}
@@ -103,6 +108,13 @@ public class JEIMissingItem implements IRecipeTransferError {
@Nonnull
@Override
public Type getType() {
// Workaround. Re-enable the button if not errored.
if (this.errored && this.foundAny && this.recipeLayout instanceof RecipeLayout castedRecipeLayout) {
var recipeTransferButton = castedRecipeLayout.getRecipeTransferButton();
if (recipeTransferButton != null) {
recipeTransferButton.enabled = true;
}
}
return USER_FACING;
}
@@ -111,12 +123,15 @@ public class JEIMissingItem implements IRecipeTransferError {
Container c = minecraft.player.openContainer;
if (c instanceof ContainerMEMonitorable container) {
IItemList<IAEItemStack> ir = ((ContainerMEMonitorable) c).items;
boolean found = false;
boolean foundAny = false;
boolean craftable = false;
boolean foundAnyCraftable = false;
boolean found;
boolean craftable;
int foundMissing = 0;
int foundCraftables = 0;
int currentSlot = 0;
this.errored = false;
this.foundAny = false;
if (System.currentTimeMillis() - lastUpdate > 1000) {
lastUpdate = System.currentTimeMillis();
@@ -144,6 +159,7 @@ public class JEIMissingItem implements IRecipeTransferError {
found = false;
craftable = false;
IItemList<IAEItemStack> valid = AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class).createList();
if (i.isInput()) {
List<?> allIngredients = i.getAllIngredients();
for (Object allIngredient : allIngredients) {
@@ -209,11 +225,12 @@ public class JEIMissingItem implements IRecipeTransferError {
i.drawHighlight(minecraft, new Color(0.0f, 0.0f, 1.0f, 0.4f), recipeX, recipeY);
this.craftableSlots.add(currentSlot);
recipeLayout.getItemStacks().set(currentSlot, validStacks);
foundAnyCraftable = true;
foundCraftables++;
} else {
i.drawHighlight(minecraft, new Color(1.0f, 0.0f, 0.0f, 0.4f), recipeX, recipeY);
}
this.errored = true;
foundMissing++;
} else {
foundAny = true;
this.foundSlots.add(currentSlot);
@@ -226,18 +243,42 @@ public class JEIMissingItem implements IRecipeTransferError {
if (b != null) {
List<String> tooltipLines = new ArrayList<>();
b.init(c, minecraft.player);
if (errored && foundAny) {
tooltipLines.add(I18n.translateToLocal("gui.tooltips.appliedenergistics2.PartialTransfer"));
if (foundAny) {
tooltipLines.add(format("gui.tooltips.appliedenergistics2.PartialTransfer"));
b.enabled = true;
b.visible = true;
tooltipLines.add(format("gui.tooltips.appliedenergistics2.CondenseItems"));
}
if (errored) {
tooltipLines.add(I18n.translateToLocal("gui.tooltips.appliedenergistics2.MissingItem"));
if (foundMissing > 0) {
tooltipLines.add(format("gui.tooltips.appliedenergistics2.MissingItem", String.valueOf(foundMissing)));
}
if (foundAnyCraftable) {
tooltipLines.add(I18n.translateToLocal("gui.tooltips.appliedenergistics2.CraftableItem"));
if (foundCraftables > 0) {
tooltipLines.add(format("gui.tooltips.appliedenergistics2.CraftableItem", foundCraftables));
}
if (tooltipLines.size() > 0) {
var longestStringWidth = minecraft.fontRenderer.getStringWidth(tooltipLines.stream()
.max(Comparator.comparingInt(String::length)).get());
var background = ((RecipeLayout) recipeLayout).getRecipeCategory().getBackground();
var scaledresolution = new ScaledResolution(minecraft);
// Mostly reverse-engineered Minecraft code.
final int offset;
if (mouseX + longestStringWidth + 4 + 12 > scaledresolution.getScaledWidth()) {
// The tooltip will appear to the left of the mouse cursor.
// Need to offset Y so that the tooltip doesn't block the ingredients.
offset = background.getHeight() + recipeY
+ (minecraft.fontRenderer.FONT_HEIGHT * tooltipLines.size()
+ 2 * (tooltipLines.size() - 1)) / 2
+ 4;
} else {
offset = mouseY;
}
TooltipRenderer.drawHoveringText(minecraft, tooltipLines, mouseX, offset);
}
TooltipRenderer.drawHoveringText(minecraft, tooltipLines, mouseX, mouseY);
}
}
}
@@ -0,0 +1,44 @@
package appeng.integration.modules.jei;
import mezz.jei.api.gui.IRecipeLayout;
import mezz.jei.api.recipe.transfer.IRecipeTransferError;
import mezz.jei.gui.TooltipRenderer;
import mezz.jei.gui.recipes.RecipeLayout;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.I18n;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
public class JEITransferInfo implements IRecipeTransferError {
public static final JEITransferInfo INSTANCE = new JEITransferInfo();
private RecipeLayout recipeLayout;
private JEITransferInfo() {}
@Override
public @NotNull Type getType() {
// Workaround. Re-enable the button.
if (recipeLayout != null) {
var recipeTransferButton = recipeLayout.getRecipeTransferButton();
if (recipeTransferButton != null) {
recipeTransferButton.enabled = true;
}
}
return Type.USER_FACING;
}
public void setRecipeLayout(RecipeLayout recipeLayout) {
this.recipeLayout = recipeLayout;
}
@Override
public void showError(@NotNull Minecraft minecraft, int mouseX, int mouseY, @NotNull IRecipeLayout recipeLayout, int recipeX, int recipeY) {
var tooltipLines = new ArrayList<String>();
tooltipLines.add(I18n.format("gui.tooltips.appliedenergistics2.PartialTransfer"));
tooltipLines.add(I18n.format("gui.tooltips.appliedenergistics2.CondenseItems"));
TooltipRenderer.drawHoveringText(minecraft, tooltipLines, mouseX, mouseY);
}
}
@@ -22,25 +22,29 @@ package appeng.integration.modules.jei;
import appeng.container.implementations.ContainerCraftingTerm;
import appeng.container.implementations.ContainerPatternEncoder;
import appeng.container.implementations.ContainerWirelessCraftingTerminal;
import appeng.container.slot.SlotCraftingMatrix;
import appeng.container.slot.SlotFakeCraftingMatrix;
import appeng.core.AELog;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.PacketJEIRecipe;
import appeng.core.sync.packets.PacketValueConfig;
import appeng.util.Platform;
import gregtech.api.capability.IMultiblockController;
import gregtech.api.util.GTUtility;
import gregtech.integration.jei.multiblock.MultiblockInfoCategory;
import mezz.jei.api.gui.IGuiIngredient;
import mezz.jei.api.gui.IRecipeLayout;
import mezz.jei.api.recipe.VanillaRecipeCategoryUid;
import mezz.jei.api.recipe.transfer.IRecipeTransferError;
import mezz.jei.api.recipe.transfer.IRecipeTransferHandler;
import mezz.jei.gui.recipes.RecipeLayout;
import mezz.jei.transfer.RecipeTransferErrorInternal;
import net.minecraft.client.resources.I18n;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Items;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -50,6 +54,7 @@ import java.util.List;
import java.util.Map;
import static appeng.helpers.ItemStackHelper.stackToNBT;
import static appeng.util.Platform.GTLoaded;
class RecipeTransferHandler<T extends Container> implements IRecipeTransferHandler<T> {
@@ -61,7 +66,7 @@ class RecipeTransferHandler<T extends Container> implements IRecipeTransferHandl
}
@Override
public Class<T> getContainerClass() {
public @NotNull Class<T> getContainerClass() {
return this.containerClass;
}
@@ -77,19 +82,24 @@ class RecipeTransferHandler<T extends Container> implements IRecipeTransferHandl
if (!doTransfer) {
if (recipeType.equals(VanillaRecipeCategoryUid.CRAFTING) && (container instanceof ContainerCraftingTerm || container instanceof ContainerWirelessCraftingTerminal)) {
JEIMissingItem error = new JEIMissingItem(container, recipeLayout);
if (error.errored())
return error;
}
return null;
if (container instanceof ContainerPatternEncoder || container instanceof ContainerCraftingTerm) {
JEITransferInfo.INSTANCE.setRecipeLayout((RecipeLayout) recipeLayout);
return JEITransferInfo.INSTANCE;
}
}
if (container instanceof ContainerPatternEncoder) {
try {
if (!((ContainerPatternEncoder) container).isCraftingMode()) {
if (!((ContainerPatternEncoder) container).isCraftingMode() && !maxTransfer) {
if (recipeType.equals(VanillaRecipeCategoryUid.CRAFTING)) {
NetworkHandler.instance().sendToServer(new PacketValueConfig("PatternTerminal.CraftMode", "1"));
}
} else if (!recipeType.equals(VanillaRecipeCategoryUid.CRAFTING)) {
} else if (!recipeType.equals(VanillaRecipeCategoryUid.CRAFTING) || maxTransfer) {
NetworkHandler.instance().sendToServer(new PacketValueConfig("PatternTerminal.CraftMode", "0"));
}
@@ -104,8 +114,7 @@ class RecipeTransferHandler<T extends Container> implements IRecipeTransferHandl
final NBTTagCompound recipe = new NBTTagCompound();
final NBTTagList outputs = new NBTTagList();
int slotIndex = 0;
var slotIndex = 0;
for (Map.Entry<Integer, ? extends IGuiIngredient<ItemStack>> ingredientEntry : ingredients.entrySet()) {
IGuiIngredient<ItemStack> ingredient = ingredientEntry.getValue();
if (!ingredient.isInput()) {
@@ -117,45 +126,63 @@ class RecipeTransferHandler<T extends Container> implements IRecipeTransferHandl
continue;
}
for (final Slot slot : container.inventorySlots) {
if (slot instanceof SlotCraftingMatrix || slot instanceof SlotFakeCraftingMatrix) {
if (slot.getSlotIndex() == slotIndex) {
final NBTTagList tags = new NBTTagList();
final List<ItemStack> list = new ArrayList<>();
final ItemStack displayed = ingredient.getDisplayedIngredient();
final NBTTagList tags = new NBTTagList();
final List<ItemStack> list = new ArrayList<>();
final ItemStack displayed = ingredient.getDisplayedIngredient();
// prefer currently displayed item
if (displayed != null && !displayed.isEmpty()) {
list.add(displayed);
}
// prefer currently displayed item
if (displayed != null && !displayed.isEmpty()) {
list.add(displayed);
}
// prefer pure crystals.
for (ItemStack stack : ingredient.getAllIngredients()) {
if (stack == null) {
continue;
}
if (Platform.isRecipePrioritized(stack)) {
list.add(0, stack);
} else {
list.add(stack);
}
}
for (final ItemStack is : list) {
final NBTTagCompound tag = stackToNBT(is);
tags.appendTag(tag);
}
recipe.setTag("#" + slot.getSlotIndex(), tags);
break;
}
// prefer pure crystals.
for (ItemStack stack : ingredient.getAllIngredients()) {
if (stack == null) {
continue;
}
if (Platform.isRecipePrioritized(stack)) {
list.add(0, stack);
} else {
list.add(stack);
}
}
for (final ItemStack is : list) {
final NBTTagCompound tag = stackToNBT(is);
tags.appendTag(tag);
}
recipe.setTag("#" + slotIndex, tags);
slotIndex++;
}
if (outputs.isEmpty() && GTLoaded && recipeLayout.getRecipeCategory() instanceof MultiblockInfoCategory) {
// JEI doesn't allow getting the recipe wrapper :(
String controllerName = null;
for (var ingredient : ingredients.entrySet()) {
if (!ingredient.getValue().isInput()) continue;
var ingredientStack = ingredient.getValue().getDisplayedIngredient();
if (ingredientStack == null) continue;
var meta = GTUtility.getMetaTileEntity(ingredientStack);
if (meta == null) continue;
if (!(meta instanceof IMultiblockController)) continue;
controllerName = I18n.format(meta.getMetaFullName());
break;
}
if (controllerName != null) {
var paper = Items.PAPER.getDefaultInstance().copy();
paper.setStackDisplayName(controllerName);
outputs.appendTag(stackToNBT(paper));
}
}
recipe.setTag("outputs", outputs);
recipe.setBoolean("condense", maxTransfer);
try {
NetworkHandler.instance().sendToServer(new PacketJEIRecipe(recipe));
+3
View File
@@ -221,6 +221,9 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper
// new craftables!
for (final ICraftingPatternDetails details : this.craftingMethods.keySet()) {
for (IAEItemStack out : details.getOutputs()) {
if (out == null) {
continue;
}
out = out.copy();
out.reset();
out.setCraftable(true);
@@ -134,4 +134,14 @@ public class BasicCellInventoryHandler<T extends IAEStack<T>> extends MEInventor
NBTTagCompound openNbtData() {
return Platform.openNbtData(this.getCellInv().getItemStack());
}
@Override
protected boolean canExtract(T request) {
return this.hasReadAccess();
}
@Override
protected boolean shouldItemBeAvailable(T request) {
return this.hasReadAccess();
}
}
@@ -22,6 +22,7 @@ package appeng.me.storage;
import appeng.api.config.AccessRestriction;
import appeng.api.config.Actionable;
import appeng.api.config.IncludeExclude;
import appeng.api.config.StorageFilter;
import appeng.api.networking.security.IActionSource;
import appeng.api.storage.IMEInventory;
import appeng.api.storage.IMEInventoryHandler;
@@ -38,12 +39,23 @@ public class MEInventoryHandler<T extends IAEStack<T>> implements IMEInventoryHa
private int myPriority;
private IncludeExclude myWhitelist;
private AccessRestriction myAccess;
private StorageFilter storageFilter;
private IPartitionList<T> myPartitionList;
private AccessRestriction cachedAccessRestriction;
protected final boolean hasReadAccess() {
return hasReadAccess;
}
protected final boolean hasWriteAccess() {
return hasWriteAccess;
}
private boolean hasReadAccess;
private boolean hasWriteAccess;
private boolean isSticky;
private boolean gettingAvailableContent;
public MEInventoryHandler(final IMEInventory<T> i, final IStorageChannel<T> channel) {
if (i instanceof IMEInventoryHandler) {
@@ -77,7 +89,7 @@ public class MEInventoryHandler<T extends IAEStack<T>> implements IMEInventoryHa
this.hasWriteAccess = this.cachedAccessRestriction.hasPermission(AccessRestriction.WRITE);
}
IPartitionList<T> getPartitionList() {
public IPartitionList<T> getPartitionList() {
return this.myPartitionList;
}
@@ -96,7 +108,7 @@ public class MEInventoryHandler<T extends IAEStack<T>> implements IMEInventoryHa
@Override
public T extractItems(final T request, final Actionable type, final IActionSource src) {
if (!this.hasReadAccess) {
if (!this.canExtract(request)) {
return null;
}
@@ -105,11 +117,27 @@ public class MEInventoryHandler<T extends IAEStack<T>> implements IMEInventoryHa
@Override
public IItemList<T> getAvailableItems(final IItemList<T> out) {
if (!this.hasReadAccess) {
if (this.gettingAvailableContent || !this.hasReadAccess) {
return out;
}
return this.internal.getAvailableItems(out);
this.gettingAvailableContent = true;
try {
if (this.storageFilter == StorageFilter.EXTRACTABLE_ONLY) {
var stackList = this.internal.getAvailableItems(this.getChannel().createList());
for (final T t : stackList) {
if (this.shouldItemBeAvailable(t)) {
out.add(t);
}
}
} else {
return this.internal.getAvailableItems(out);
}
} finally {
this.gettingAvailableContent = false;
}
return out;
}
@Override
@@ -136,13 +164,11 @@ public class MEInventoryHandler<T extends IAEStack<T>> implements IMEInventoryHa
return false;
}
if (this.myWhitelist == IncludeExclude.BLACKLIST && this.myPartitionList.isListed(input)) {
if (!this.passesBlackOrWhitelist(input)) {
return false;
}
if (this.myPartitionList.isEmpty() || this.myWhitelist == IncludeExclude.BLACKLIST) {
return this.internal.canAccept(input);
}
return this.myPartitionList.isListed(input) && this.internal.canAccept(input);
return this.internal.canAccept(input);
}
@Override
@@ -176,4 +202,31 @@ public class MEInventoryHandler<T extends IAEStack<T>> implements IMEInventoryHa
public void setSticky(boolean isSticky) {
this.isSticky = isSticky;
}
protected boolean canExtract(T request) {
return this.hasReadAccess && this.passesBlackOrWhitelist(request);
}
protected boolean shouldItemBeAvailable(T request) {
return this.hasReadAccess && this.passesBlackOrWhitelist(request);
}
public boolean passesBlackOrWhitelist(T input) {
if (this.myPartitionList.isEmpty()) {
return true;
}
return switch (this.myWhitelist) {
case WHITELIST -> this.myPartitionList.isListed(input);
case BLACKLIST -> !this.myPartitionList.isListed(input);
};
}
public StorageFilter getStorageFilter() {
return storageFilter;
}
public void setStorageFilter(StorageFilter storageFilter) {
this.storageFilter = storageFilter;
}
}
@@ -151,7 +151,7 @@ public class PartExportBus extends PartSharedItemBus implements ICraftingRequest
} else {
final IAEItemStack o = inv.getStorageList().findPrecise(ais);
if (o != null && o.getStackSize() > 0) {
this.pushItemIntoTarget(destination, energy, inv, ais);
this.pushItemIntoTarget(destination, energy, inv, o);
}
}
@@ -281,7 +281,7 @@ public class PartExportBus extends PartSharedItemBus implements ICraftingRequest
}
}
final long canFit = remaining.isEmpty() ? this.itemToSend : this.itemToSend - remaining.getCount();
final long canFit = Math.min(this.itemToSend, org.getStackSize() - remaining.getCount());
if (canFit > 0) {
IAEItemStack ais = org.copy();
@@ -54,6 +54,7 @@ import appeng.items.parts.PartModels;
import appeng.parts.PartBasicState;
import appeng.parts.PartModel;
import appeng.tile.inventory.AppEngInternalInventory;
import appeng.tile.misc.TileInterface;
import appeng.util.Platform;
import appeng.util.SettingsFrom;
import appeng.util.inv.IAEAppEngInventory;
@@ -68,7 +69,9 @@ import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.IBlockAccess;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.wrapper.PlayerMainInvWrapper;
@@ -196,6 +199,11 @@ public class PartInterface extends PartBasicState implements IGridTickable, ISto
this.duality.onChangeInventory(inv, slot, mc, removedStack, newStack);
}
@Override
public void onStackReturnNetwork(IAEItemStack stack) {
this.duality.onStackReturnedToNetwork(stack);
}
@Override
public DualityInterface getInterfaceDuality() {
return this.duality;
@@ -262,6 +270,14 @@ public class PartInterface extends PartBasicState implements IGridTickable, ISto
}
}
@Override
public void onNeighborChanged(IBlockAccess w, BlockPos pos, BlockPos neighbor) {
TileEntity tileEntity = getTileEntity();
if (tileEntity instanceof TileInterface) {
((TileInterface) tileEntity).updateRedstoneState();
}
}
@Override
public boolean hasCapability(Capability<?> capabilityClass) {
return this.duality.hasCapability(capabilityClass, this.getSide().getFacing());
@@ -19,7 +19,7 @@ import appeng.me.storage.MEInventoryHandler;
import appeng.parts.PartModel;
import appeng.util.ConfigManager;
import appeng.util.Platform;
import appeng.util.item.OreHelper;
import appeng.util.item.OreDictFilterMatcher;
import appeng.util.prioritylist.IPartitionList;
import appeng.util.prioritylist.OreDictPriorityList;
import net.minecraft.entity.player.EntityPlayer;
@@ -51,7 +51,9 @@ public class PartOreDicStorageBus extends PartStorageBus {
public void readFromNBT(NBTTagCompound data) {
super.readFromNBT(data);
this.oreExp = data.getString("oreMatch");
this.priorityList = new OreDictPriorityList<>(OreHelper.INSTANCE.getMatchingOre(oreExp), oreExp);
var rulesList = OreDictFilterMatcher.parseExpression(oreExp);
this.priorityList = new OreDictPriorityList<>(rulesList);
}
@Override
@@ -111,8 +113,9 @@ public class PartOreDicStorageBus extends PartStorageBus {
this.handler.setBaseAccess((AccessRestriction) this.getConfigManager().getSetting(Settings.ACCESS));
this.handler.setWhitelist(this.getInstalledUpgrades(Upgrades.INVERTER) > 0 ? IncludeExclude.BLACKLIST : IncludeExclude.WHITELIST);
this.handler.setPriority(this.priority);
this.handler.setPartitionList(this.getPriorityList());
this.handler.setStorageFilter((StorageFilter) this.getConfigManager().getSetting(Settings.STORAGE_FILTER));
this.handler.setSticky(this.getInstalledUpgrades(Upgrades.STICKY) > 0);
if (inv instanceof IBaseMonitor) {
if (((AccessRestriction) ((ConfigManager) this.getConfigManager()).getSetting(Settings.ACCESS)).hasPermission(AccessRestriction.READ)) {
@@ -148,7 +151,8 @@ public class PartOreDicStorageBus extends PartStorageBus {
private IPartitionList<IAEItemStack> getPriorityList() {
if (priorityList == null) {
this.priorityList = new OreDictPriorityList<>(OreHelper.INSTANCE.getMatchingOre(oreExp), oreExp);
var ruleList = OreDictFilterMatcher.parseExpression(oreExp);
priorityList = new OreDictPriorityList<>(ruleList);
}
return priorityList;
}
@@ -164,10 +168,9 @@ public class PartOreDicStorageBus extends PartStorageBus {
if (!this.oreExp.equals(oreMatch)) {
this.oreExp = oreMatch;
this.priorityList = new OreDictPriorityList<>(OreHelper.INSTANCE.getMatchingOre(oreExp), oreExp);
if (this.handler != null) {
handler.setPartitionList(this.priorityList);
}
var ruleList = OreDictFilterMatcher.parseExpression(oreMatch);
this.priorityList = new OreDictPriorityList<>(ruleList);
this.resetCache(true);
this.getHost().markForSave();
}
}
@@ -80,6 +80,7 @@ import net.minecraftforge.common.capabilities.CapabilityInject;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -195,7 +196,7 @@ public class PartStorageBus extends PartUpgradeable implements IGridTickable, IC
return super.getInventoryByName(name);
}
private void resetCache(final boolean fullReset) {
protected void resetCache(final boolean fullReset) {
if (this.getHost() == null || this.getHost().getTile() == null || this.getHost().getTile().getWorld() == null || this.getHost().getTile().getWorld().isRemote) {
return;
}
@@ -221,11 +222,13 @@ public class PartStorageBus extends PartUpgradeable implements IGridTickable, IC
@Override
public void postChange(final IBaseMonitor<IAEItemStack> monitor, final Iterable<IAEItemStack> change, final IActionSource source) {
if (this.getProxy().isActive()) {
var filteredChanges = this.filterChanges(change);
AccessRestriction currentAccess = (AccessRestriction) ((ConfigManager) this.getConfigManager()).getSetting(Settings.ACCESS);
if (readOncePass) {
readOncePass = false;
try {
this.getProxy().getStorage().postAlterationOfStoredItems(AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class), change, mySrc);
this.getProxy().getStorage().postAlterationOfStoredItems(AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class), filteredChanges, mySrc);
} catch (final GridAccessException e) {
// :(
}
@@ -235,7 +238,7 @@ public class PartStorageBus extends PartUpgradeable implements IGridTickable, IC
return;
}
try {
this.getProxy().getStorage().postAlterationOfStoredItems(AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class), change, source);
this.getProxy().getStorage().postAlterationOfStoredItems(AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class), filteredChanges, source);
} catch (final GridAccessException e) {
// :(
}
@@ -316,7 +319,7 @@ public class PartStorageBus extends PartUpgradeable implements IGridTickable, IC
return TickRateModulation.SLEEP;
}
private void resetCache() {
protected void resetCache() {
final boolean fullReset = this.resetCacheLogic == 2;
this.resetCacheLogic = 0;
@@ -457,6 +460,7 @@ public class PartStorageBus extends PartUpgradeable implements IGridTickable, IC
this.handler.setBaseAccess((AccessRestriction) this.getConfigManager().getSetting(Settings.ACCESS));
this.handler.setWhitelist(this.getInstalledUpgrades(Upgrades.INVERTER) > 0 ? IncludeExclude.BLACKLIST : IncludeExclude.WHITELIST);
this.handler.setPriority(this.priority);
this.handler.setStorageFilter((StorageFilter) this.getConfigManager().getSetting(Settings.STORAGE_FILTER));
final IItemList<IAEItemStack> priorityList = AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class).createList();
@@ -571,4 +575,26 @@ public class PartStorageBus extends PartUpgradeable implements IGridTickable, IC
public GuiBridge getGuiBridge() {
return GuiBridge.GUI_STORAGEBUS;
}
// TODO: 1/28/2024 Unify both methods.
/**
* Filters the changes to only include items that pass the storage filter.
* Optimally, this should be handled by the underlying monitor.
*
* @see appeng.fluids.parts.PartFluidStorageBus#filterChanges
*/
protected Iterable<IAEItemStack> filterChanges(Iterable<IAEItemStack> change) {
var storageFilter = this.getConfigManager().getSetting(Settings.STORAGE_FILTER);
if (storageFilter == StorageFilter.EXTRACTABLE_ONLY && handler != null) {
var filteredList = new ArrayList<IAEItemStack>();
for (final IAEItemStack stack : change) {
if (this.handler.passesBlackOrWhitelist(stack)) {
filteredList.add(stack);
}
}
return filteredList;
}
return change;
}
}
@@ -42,9 +42,6 @@ public class PartInterfaceTerminal extends AbstractPartDisplay {
public static final IPartModel MODELS_OFF = new PartModel(MODEL_BASE, MODEL_OFF, MODEL_STATUS_OFF);
public static final IPartModel MODELS_ON = new PartModel(MODEL_BASE, MODEL_ON, MODEL_STATUS_ON);
public static final IPartModel MODELS_HAS_CHANNEL = new PartModel(MODEL_BASE, MODEL_ON, MODEL_STATUS_HAS_CHANNEL);
public String in = "";
public String out = "";
public boolean onlyInterfacesWithFreeSlots = false;
public PartInterfaceTerminal(final ItemStack is) {
super(is);
@@ -64,9 +61,4 @@ public class PartInterfaceTerminal extends AbstractPartDisplay {
public IPartModel getStaticModels() {
return this.selectModel(MODELS_OFF, MODELS_ON, MODELS_HAS_CHANNEL);
}
public void saveSearchStrings(String in, String out) {
this.in = in;
this.out = out;
}
}
@@ -14,6 +14,7 @@ import net.minecraftforge.common.crafting.CraftingHelper;
import net.minecraftforge.common.crafting.JsonContext;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -27,34 +28,25 @@ public class InscriberHandler implements IAERecipeFactory {
JsonObject ingredients = JsonUtils.getJsonObject(json, "ingredients");
List<ItemStack> middle = Arrays.asList(CraftingHelper.getIngredient(ingredients.get("middle"), ctx).getMatchingStacks());
ItemStack[] top = new ItemStack[]{null};
List<ItemStack> top = Collections.emptyList();
if (ingredients.has("top")) {
top = CraftingHelper.getIngredient(JsonUtils.getJsonObject(ingredients, "top"), ctx).getMatchingStacks();
top = Arrays.asList(CraftingHelper.getIngredient(JsonUtils.getJsonObject(ingredients, "top"), ctx).getMatchingStacks());
}
ItemStack[] bottom = new ItemStack[]{null};
List<ItemStack> bottom = Collections.emptyList();
if (ingredients.has("bottom")) {
bottom = CraftingHelper.getIngredient(JsonUtils.getJsonObject(ingredients, "bottom"), ctx).getMatchingStacks();
bottom = Arrays.asList(CraftingHelper.getIngredient(JsonUtils.getJsonObject(ingredients, "bottom"), ctx).getMatchingStacks());
}
final IInscriberRegistry reg = AEApi.instance().registries().inscriber();
for (int i = 0; i < top.length; ++i) {
for (int j = 0; j < bottom.length; ++j) {
final IInscriberRecipeBuilder builder = reg.builder();
builder.withOutput(result);
builder.withProcessType("press".equals(mode) ? InscriberProcessType.PRESS : InscriberProcessType.INSCRIBE);
builder.withInputs(middle);
if (top[i] != null) {
builder.withTopOptional(top[i]);
}
if (bottom[j] != null) {
builder.withBottomOptional(bottom[j]);
}
reg.addRecipe(builder.build());
}
if (!top.isEmpty() || !bottom.isEmpty()) {
final IInscriberRecipeBuilder builder = reg.builder();
builder.withOutput(result);
builder.withProcessType("press".equals(mode) ? InscriberProcessType.PRESS : InscriberProcessType.INSCRIBE);
builder.withTopOptional(top);
builder.withInputs(middle);
builder.withBottomOptional(bottom);
reg.addRecipe(builder.build());
}
}
}
@@ -65,6 +65,7 @@ import net.minecraftforge.items.IItemHandlerModifiable;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.IOException;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
@@ -281,20 +282,19 @@ public class TileInscriber extends AENetworkPowerTile implements IGridTickable,
for (final IInscriberRecipe recipe : AEApi.instance().registries().inscriber().getRecipes()) {
final boolean matchA = (plateA.isEmpty() && !recipe.getTopOptional().isPresent()) || (Platform.itemComparisons()
.isSameItem(plateA,
recipe.getTopOptional().orElse(ItemStack.EMPTY))) && // and...
((plateB.isEmpty() && !recipe.getBottomOptional().isPresent()) || (Platform.itemComparisons()
.isSameItem(plateB,
recipe.getBottomOptional().orElse(ItemStack.EMPTY))));
// Check if plateA matches any item in the list of top components of the recipe
final boolean matchA = plateA.isEmpty() && recipe.getTopInputs().isEmpty() ||
recipe.getTopInputs().stream().anyMatch(topItem -> Platform.itemComparisons().isSameItem(plateA, topItem)) &&
(plateB.isEmpty() && recipe.getBottomInputs().isEmpty() ||
recipe.getBottomInputs().stream().anyMatch(bottomItem -> Platform.itemComparisons().isSameItem(plateB, bottomItem)));
final boolean matchB = (plateB.isEmpty() && !recipe.getTopOptional().isPresent()) || (Platform.itemComparisons()
.isSameItem(plateB,
recipe.getTopOptional().orElse(ItemStack.EMPTY))) && // and...
((plateA.isEmpty() && !recipe.getBottomOptional().isPresent()) || (Platform.itemComparisons()
.isSameItem(plateA,
recipe.getBottomOptional().orElse(ItemStack.EMPTY))));
// Check if plateB matches any item in the list of top components of the recipe
final boolean matchB = plateB.isEmpty() && recipe.getTopInputs().isEmpty() ||
recipe.getTopInputs().stream().anyMatch(topItem -> Platform.itemComparisons().isSameItem(plateB, topItem)) &&
(plateA.isEmpty() && recipe.getBottomInputs().isEmpty() ||
recipe.getBottomInputs().stream().anyMatch(bottomItem -> Platform.itemComparisons().isSameItem(plateA, bottomItem)));
// If either matchA or matchB is true, iterate through the recipe's inputs
if (matchA || matchB) {
for (final ItemStack option : recipe.getInputs()) {
if (Platform.itemComparisons().isSameItem(input, option)) {
@@ -476,11 +476,11 @@ public class TileInscriber extends AENetworkPowerTile implements IGridTickable,
builder.withInputs(inputs).withOutput(renamedItem).withProcessType(type);
if (!plateA.isEmpty()) {
builder.withTopOptional(plateA);
builder.withTopOptional(Collections.singletonList(plateA));
}
if (!plateB.isEmpty()) {
builder.withBottomOptional(plateB);
builder.withBottomOptional(Collections.singletonList(plateB));
}
return builder.build();
@@ -221,6 +221,11 @@ public class TileInterface extends AENetworkInvTile implements IGridTickable, II
this.duality.onChangeInventory(inv, slot, mc, removed, added);
}
@Override
public void onStackReturnNetwork(IAEItemStack stack) {
this.duality.onStackReturnedToNetwork(stack);
}
@Override
public DualityInterface getInterfaceDuality() {
return this.duality;
@@ -274,6 +279,10 @@ public class TileInterface extends AENetworkInvTile implements IGridTickable, II
return this.duality.injectCraftedItems(link, items, mode);
}
public void updateRedstoneState(){
this.duality.updateRedstoneState();
}
@Override
public void jobStateChange(final ICraftingLink link) {
this.duality.jobStateChange(link);
@@ -25,6 +25,7 @@ import appeng.api.config.StorageFilter;
import appeng.api.util.IConfigManager;
import appeng.core.AELog;
import net.minecraft.nbt.NBTTagCompound;
import org.jetbrains.annotations.Nullable;
import java.util.EnumMap;
import java.util.Map;
+29
View File
@@ -53,6 +53,7 @@ import appeng.core.features.AEFeature;
import appeng.core.stats.Stats;
import appeng.core.sync.GuiBridge;
import appeng.core.sync.GuiHostType;
import appeng.core.sync.GuiWrapper;
import appeng.fluids.util.AEFluidStack;
import appeng.hooks.TickHandler;
import appeng.integration.Integrations;
@@ -323,6 +324,20 @@ public class Platform {
return;
}
if (type.getExternalGui() != null) {
GuiWrapper.IExternalGui obj = type.getExternalGui();
GuiWrapper.Opener opener = GuiWrapper.INSTANCE.getOpener(obj.getID());
if (opener == null) {
AELog.warn("External Gui with ID: %s is missing a opener.", obj.getID());
} else {
World world = tile == null ? p.world : tile.getWorld();
BlockPos pos = tile == null ? null : tile.getPos();
EnumFacing face = side == null ? null : side.getFacing();
opener.open(obj, new GuiWrapper.GuiContext(world, p, pos, face, null));
}
return;
}
int x = 0;
int y = 0;
int z = Integer.MIN_VALUE;
@@ -360,6 +375,20 @@ public class Platform {
return;
}
if (type.getExternalGui() != null) {
GuiWrapper.IExternalGui obj = type.getExternalGui();
GuiWrapper.Opener opener = GuiWrapper.INSTANCE.getOpener(obj.getID());
if (opener == null) {
AELog.warn("External Gui with ID: %s is missing a opener.", obj.getID());
} else {
NBTTagCompound extra = new NBTTagCompound();
extra.setInteger("slot", slot);
extra.setBoolean("isBauble", isBauble);
opener.open(obj, new GuiWrapper.GuiContext(p.world, p, null, null, extra));
}
return;
}
if (type.getType().isItem()) {
p.openGui(AppEng.instance(), type.ordinal() << 4, p.getEntityWorld(), slot, isBauble ? 1 : 0, Integer.MIN_VALUE);
}
@@ -38,7 +38,6 @@ import java.util.Map;
* {@link #findFuzzy(IAEItemStack, FuzzyMode)}.
*/
class FuzzyItemVariantList extends ItemVariantList {
static final SharedStackComparator COMPARATOR = new SharedStackComparator();
// NOTE: We only use Object as they key here so we can pass our special DamageBounds to the subMap method.
@@ -47,6 +46,10 @@ class FuzzyItemVariantList extends ItemVariantList {
@Override
public Collection<IAEItemStack> findFuzzy(final IAEItemStack filter, final FuzzyMode fuzzy) {
if (fuzzy == FuzzyMode.IGNORE_ALL) {
return this.records.values();
}
ItemStack itemStack = filter.getDefinition();
ItemDamageBound lowerBound = makeLowerBound(itemStack, fuzzy);
@@ -161,14 +164,8 @@ class FuzzyItemVariantList extends ItemVariantList {
damage = stack.getItemDamage();
}
if (fuzzy == FuzzyMode.IGNORE_ALL) {
if (maxDamage != 0) {
damage = maxDamage;
}
} else {
final int breakpoint = fuzzy.calculateBreakPoint(maxDamage);
damage = damage <= breakpoint ? breakpoint : maxDamage;
}
final int breakpoint = fuzzy.calculateBreakPoint(maxDamage);
damage = damage <= breakpoint ? breakpoint : maxDamage;
return new ItemDamageBound(damage);
}
@@ -181,26 +178,19 @@ class FuzzyItemVariantList extends ItemVariantList {
Preconditions.checkState(stack.getItem().isDamageable() || (Platform.isGTDamageableItem(stack.getItem())), "Item#isDamageable() has to be true");
int damage;
if (fuzzy == FuzzyMode.IGNORE_ALL) {
damage = MIN_DAMAGE_VALUE;
int maxDamage;
if (Platform.isIC2DamageableItem(stack.getItem())) {
maxDamage = ((ICustomDamageItem) stack.getItem()).getMaxCustomDamage(stack);
damage = ((ICustomDamageItem) stack.getItem()).getCustomDamage(stack);
} else if (Platform.isGTDamageableItem(stack.getItem())) {
maxDamage = ToolClass.getGTMaxDamage(stack);
damage = ToolClass.getGTitemDamage(stack);
} else {
int maxDamage;
if (Platform.isIC2DamageableItem(stack.getItem())) {
maxDamage = ((ICustomDamageItem) stack.getItem()).getMaxCustomDamage(stack);
damage = ((ICustomDamageItem) stack.getItem()).getCustomDamage(stack);
} else if (Platform.isGTDamageableItem(stack.getItem())) {
maxDamage = ToolClass.getGTMaxDamage(stack);
damage = ToolClass.getGTitemDamage(stack);
} else {
maxDamage = stack.getMaxDamage();
damage = stack.getItemDamage();
}
final int breakpoint = fuzzy.calculateBreakPoint(maxDamage);
damage = damage <= breakpoint ? MIN_DAMAGE_VALUE : breakpoint;
maxDamage = stack.getMaxDamage();
damage = stack.getItemDamage();
}
return new ItemDamageBound(damage);
final int breakpoint = fuzzy.calculateBreakPoint(maxDamage);
return new ItemDamageBound(damage <= breakpoint ? MIN_DAMAGE_VALUE : breakpoint);
}
}
@@ -40,7 +40,7 @@ public class OreDictFilterMatcher {
}
if (c == '(') {
List<MatchRule> subRules = new ArrayList<>();
i = parseExpression(subRules, expression.substring(i + 1)) + i + 1;
i = parseExpression(subRules, expression.substring(i + 1)) + i;
rules.add(MatchRule.group(subRules, builder.toString()));
builder = new StringBuilder();
} else {
@@ -130,10 +130,9 @@ public class OreHelper {
}).orElse(false);
}
public Set<Integer> getMatchingOre(String oreExp) {
public Set<Integer> getMatchingOre(List<OreDictFilterMatcher.MatchRule> rulesList) {
Set<Integer> matchingIds = new HashSet<>();
List<OreDictFilterMatcher.MatchRule> rulesList = OreDictFilterMatcher.parseExpression(oreExp);
for (String ore : OreDictionary.getOreNames()) {
if (ore == null) {
continue;
@@ -2,29 +2,33 @@ package appeng.util.prioritylist;
import appeng.api.storage.data.IAEStack;
import appeng.util.item.AEItemStack;
import appeng.util.item.OreDictFilterMatcher;
import appeng.util.item.OreDictFilterMatcher.MatchRule;
import appeng.util.item.OreHelper;
import appeng.util.item.OreReference;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class OreDictPriorityList<T extends IAEStack<T>> implements IPartitionList<T> {
private final Set<Integer> oreIDs;
private final String oreMatch;
private final boolean matchesEmptyOreDict;
public OreDictPriorityList(Set<Integer> oreIDs, String oreMatch) {
this.oreIDs = oreIDs;
this.oreMatch = oreMatch;
public OreDictPriorityList(List<MatchRule> oreMatch) {
this.oreIDs = OreHelper.INSTANCE.getMatchingOre(oreMatch);
this.matchesEmptyOreDict = OreDictFilterMatcher.matches(oreMatch, "");
}
@Override
public boolean isListed(final T input) {
OreReference or = ((AEItemStack) input).getOre().orElse(null);
if (or != null) {
for (Integer oreID : or.getOres()) {
if (this.oreIDs.contains(oreID)) {
return true;
}
if (or == null) return matchesEmptyOreDict;
for (Integer oreID : or.getOres()) {
if (this.oreIDs.contains(oreID)) {
return true;
}
}
return false;
@@ -32,7 +36,7 @@ public class OreDictPriorityList<T extends IAEStack<T>> implements IPartitionLis
@Override
public boolean isEmpty() {
return oreMatch.equals("");
return oreIDs.isEmpty();
}
@Override
@@ -90,6 +90,9 @@ chat.appliedenergistics2.ResetSettings=New device configuration created and copi
chat.appliedenergistics2.AmmoDepleted=Ammo Depleted.
chat.appliedenergistics2.isNowLocked=Monitor is now Locked.
chat.appliedenergistics2.isNowUnlocked=Monitor is now Unlocked.
chat.appliedenergistics2.InterfaceInOtherDimParam=Interface located at dimension: %d [ %s ] and cannot be highlighted
chat.appliedenergistics2.InterfaceInOtherDim=Interface is located in another dimension and cannot be highlighted
chat.appliedenergistics2.InterfaceHighlighted=The interface is now highlighted at X: %s Y: %s Z: %s
// Creative Tabs
itemGroup.appliedenergistics2=Applied Energistics 2
@@ -254,6 +257,7 @@ gui.appliedenergistics2.Nothing=Nothing
gui.appliedenergistics2.CraftingToastDone=Crafting Done!
gui.appliedenergistics2.CraftingToastCancelled=Crafting Cancelled!
gui.appliedenergistics2.Sticky=Sticky
gui.appliedenergistics2.FluidTerminal=Fluid Terminal
// GUI Tooltips
gui.tooltips.appliedenergistics2.Stash=Store Items
@@ -323,6 +327,12 @@ gui.tooltips.appliedenergistics2.Disabled=Disabled
gui.tooltips.appliedenergistics2.Enable=Enabled
gui.tooltips.appliedenergistics2.Blocking=Do not push crafting items if inventory contains items.
gui.tooltips.appliedenergistics2.NonBlocking=Ignore the contents of the target inventory.
gui.tooltips.appliedenergistics2.LockCraftingMode=Lock Crafting
gui.tooltips.appliedenergistics2.LockCraftingModeNone=Never
gui.tooltips.appliedenergistics2.LockCraftingUntilRedstonePulse=Until redstone pulse is received
gui.tooltips.appliedenergistics2.LockCraftingWhileRedstoneHigh=With redstone signal
gui.tooltips.appliedenergistics2.LockCraftingWhileRedstoneLow=Without redstone signal
gui.tooltips.appliedenergistics2.LockCraftingUntilResultReturned=Until primary crafting result is returned
gui.tooltips.appliedenergistics2.Craft=Crafting Behavior
gui.tooltips.appliedenergistics2.CraftOnly=Do not use stocked items, only craft items while exporting.
gui.tooltips.appliedenergistics2.CraftEither=Use stocked items, or craft items while exporting.
@@ -373,15 +383,23 @@ gui.tooltips.appliedenergistics2.DecreaseByOne=Decrease one
gui.tooltips.appliedenergistics2.DecreaseByOneDesc=Will try to add decrease the items set in the crafting slots by one DOES NOT MAINTAIN INGREDIENT RATIO
gui.tooltips.appliedenergistics2.MaxCount=Maximize slot count
gui.tooltips.appliedenergistics2.MaxCountDesc=Will maximize the output maintaing the input ratio of the items set in the crafting slots
gui.tooltips.appliedenergistics2.FreeMolecularSlotShortcut=Show Crafting interfaces with free slots
gui.tooltips.appliedenergistics2.FreeMolecularSlotShortcutDesc=Shortcut that toggles interfaces with free slots and searches for molecular assemblers
gui.tooltips.appliedenergistics2.ToggleMolecularAssemblers=Toggles showing crafting interfaces only
gui.tooltips.appliedenergistics2.ToggleMolecularAssemblersOffDesc=Showing all interfaces
gui.tooltips.appliedenergistics2.ToggleMolecularAssemblersOnDesc=Showing only interfaces on molecular assemblers
gui.tooltips.appliedenergistics2.ToggleShowFullInterfaces=Toggles showing interfaces with full slots
gui.tooltips.appliedenergistics2.ToggleShowFullInterfacesOnDesc=Showing all interfaces
gui.tooltips.appliedenergistics2.ToggleShowFullInterfacesOffDesc=Showing only interfaces with free slots
gui.tooltips.appliedenergistics2.HighlightInterface=Highlight interface
gui.tooltips.appliedenergistics2.ToggleShowOnlyInvalidInterface=Toggles showing interfaces with invalid patterns
gui.tooltips.appliedenergistics2.ToggleShowOnlyInvalidInterfaceOffDesc=Showing all interfaces
gui.tooltips.appliedenergistics2.ToggleShowOnlyInvalidInterfaceOnDesc=Showing only interfaces with invalid patterns
gui.tooltips.appliedenergistics2.HighlightInterface=Highlight Interface
gui.tooltips.appliedenergistics2.SearchFieldInputs=Recipe Inputs
gui.tooltips.appliedenergistics2.SearchFieldOutputs=Recipe Outputs
gui.tooltips.appliedenergistics2.SearchFieldNames=Interface Names
gui.tooltips.appliedenergistics2.PartialTransfer=Move stored items into the crafting grid
gui.tooltips.appliedenergistics2.MissingItem=§cMissing item
gui.tooltips.appliedenergistics2.CraftableItem=§9Craftable item
gui.tooltips.appliedenergistics2.MissingItem=§cMissing %s items
gui.tooltips.appliedenergistics2.CraftableItem=§9Found %s craftable items
gui.tooltips.appliedenergistics2.CondenseItems=§5- hold Shift to condense items
// Units
gui.appliedenergistics2.units.appliedenergstics=AE
@@ -542,7 +542,7 @@ item.appliedenergistics2.multi_part.fluid_formation_plane.name=МЭ Жидкос
item.appliedenergistics2.multi_part.import_bus.name=МЭ Шина импорта
item.appliedenergistics2.multi_part.fluid_import_bus.name=МЭ Жидкостная шина импорта
item.appliedenergistics2.multi_part.interface.name=МЭ Интерфейс
item.appliedenergistics2.multi_part.fluid_interface.name=МЭ Жидкостый нтерфейс
item.appliedenergistics2.multi_part.fluid_interface.name=МЭ Жидкостный интерфейс
item.appliedenergistics2.multi_part.level_emitter.name=МЭ Излучатель уровня
item.appliedenergistics2.multi_part.fluid_level_emitter.name=МЭ Излучатель уровня
item.appliedenergistics2.multi_part.p2p_tunnel.name=Туннель точка-точка
@@ -90,6 +90,9 @@ chat.appliedenergistics2.ResetSettings=新的设备配置已被创建并保存
chat.appliedenergistics2.AmmoDepleted=弹药告罄。
chat.appliedenergistics2.isNowLocked=监控器已锁定。
chat.appliedenergistics2.isNowUnlocked=监控器已解锁。
chat.appliedenergistics2.InterfaceInOtherDimParam=接口位于维度: %d [ %s ] 无法被高亮
chat.appliedenergistics2.InterfaceInOtherDim=接口位于另一个维度,无法被高亮
chat.appliedenergistics2.InterfaceHighlighted=接口被高亮于 X: %s Y: %s Z: %s
// Creative Tabs
itemGroup.appliedenergistics2=应用能源2
@@ -253,6 +256,8 @@ gui.appliedenergistics2.Renamer=自定义名称(按下Enter以设定)
gui.appliedenergistics2.Nothing=无
gui.appliedenergistics2.CraftingToastDone=合成已完成!
gui.appliedenergistics2.CraftingToastCancelled=合成已取消!
gui.appliedenergistics2.Sticky=粘滞
gui.appliedenergistics2.FluidTerminal=流体终端
// GUI Tooltips
gui.tooltips.appliedenergistics2.Stash=存储物品
@@ -322,6 +327,12 @@ gui.tooltips.appliedenergistics2.Disabled=禁用
gui.tooltips.appliedenergistics2.Enable=启用
gui.tooltips.appliedenergistics2.Blocking=当容器内有物品时不传送物品。
gui.tooltips.appliedenergistics2.NonBlocking=忽略目标容器的内容。
gui.tooltips.appliedenergistics2.LockCraftingMode=合成锁定
gui.tooltips.appliedenergistics2.LockCraftingModeNone=永不锁定
gui.tooltips.appliedenergistics2.LockCraftingUntilRedstonePulse=接收到脉冲信号时解锁
gui.tooltips.appliedenergistics2.LockCraftingWhileRedstoneHigh=有红石信号时锁定
gui.tooltips.appliedenergistics2.LockCraftingWhileRedstoneLow=无红石信号时锁定
gui.tooltips.appliedenergistics2.LockCraftingUntilResultReturned=接受到编码样板主产物时解锁
gui.tooltips.appliedenergistics2.Craft=输出时若有需要则合成物品。
gui.tooltips.appliedenergistics2.CraftOnly=不使用已存储物品,只使用合成物品。
gui.tooltips.appliedenergistics2.CraftEither=输出时使用已存储物品或合成物品。
@@ -372,8 +383,6 @@ gui.tooltips.appliedenergistics2.DecreaseByOne=物品数量-1
gui.tooltips.appliedenergistics2.DecreaseByOneDesc=将尝试将格内物品数量-1 注:将不会维持比例
gui.tooltips.appliedenergistics2.MaxCount=物品数量最大
gui.tooltips.appliedenergistics2.MaxCountDesc=将把格内物品数量最大化并维持比例
gui.tooltips.appliedenergistics2.FreeMolecularSlotShortcut=显示有样板位的合成接口
gui.tooltips.appliedenergistics2.FreeMolecularSlotShortcutDesc=快捷切换有样板位的分子装配室接口
gui.tooltips.appliedenergistics2.ToggleShowFullInterfaces=显示满样板的接口
gui.tooltips.appliedenergistics2.ToggleShowFullInterfacesOnDesc=显示所有接口
gui.tooltips.appliedenergistics2.ToggleShowFullInterfacesOffDesc=仅显示有样板位的接口
@@ -381,6 +390,16 @@ gui.tooltips.appliedenergistics2.HighlightInterface=高亮接口
gui.tooltips.appliedenergistics2.PartialTransfer=将存储的物品移动至合成格中
gui.tooltips.appliedenergistics2.MissingItem=§c缺少物品
gui.tooltips.appliedenergistics2.CraftableItem=§9可合成物品
gui.tooltips.appliedenergistics2.ToggleMolecularAssemblers=显示位于分子装配室的接口
gui.tooltips.appliedenergistics2.ToggleMolecularAssemblersOffDesc=显示所有接口
gui.tooltips.appliedenergistics2.ToggleMolecularAssemblersOnDesc=仅显示位于分子装配室的接口
gui.tooltips.appliedenergistics2.ToggleShowOnlyInvalidInterface=显示含有无效编码样板的接口
gui.tooltips.appliedenergistics2.ToggleShowOnlyInvalidInterfaceOffDesc=显示所有接口
gui.tooltips.appliedenergistics2.ToggleShowOnlyInvalidInterfaceOnDesc=仅显示含有无效编码样板的接口
gui.tooltips.appliedenergistics2.SearchFieldInputs=配方输入
gui.tooltips.appliedenergistics2.SearchFieldOutputs=配方输出
gui.tooltips.appliedenergistics2.SearchFieldNames=接口名称
// Units
gui.appliedenergistics2.units.appliedenergstics=AE
@@ -524,6 +543,7 @@ item.appliedenergistics2.material.silicon_print.name=硅板
item.appliedenergistics2.material.name_press.name=名称压印模板
item.appliedenergistics2.material.sky_dust.name=陨石粉
item.appliedenergistics2.material.card_crafting.name=合成卡
item.appliedenergistics2.material.card_sticky.name=粘滞卡
item.appliedenergistics2.multi_part.annihilation_plane.name=ME破坏面板
item.appliedenergistics2.multi_part.fluid_annihilation_plane.name=ME流体破坏面板
Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 527 B

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 15 KiB