refactor: expose pattern encoding apis (#1431)

This commit is contained in:
hinyb authored and GitHub committed 2026-07-12 11:39:33 +00:00
1 parent 3bf34a60d5
commit 9220db1fbe
6 files changed
+324 -157

No files matched your search

@@ -1,25 +1,40 @@
package appeng.api.parts;
import static appeng.util.item.AEItemStackType.ITEM_STACK_TYPE;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.World;
import net.minecraftforge.common.util.Constants.NBT;
import net.minecraftforge.common.util.ForgeDirection;
import org.jetbrains.annotations.NotNull;
import appeng.api.AEApi;
import appeng.api.implementations.ICraftingPatternItem;
import appeng.api.implementations.tiles.IViewCellStorage;
import appeng.api.networking.IGrid;
import appeng.api.networking.crafting.ICraftingPatternDetails;
import appeng.api.networking.energy.IEnergyGrid;
import appeng.api.networking.energy.IEnergySource;
import appeng.api.networking.security.BaseActionSource;
import appeng.api.networking.security.IActionHost;
import appeng.api.networking.security.MachineSource;
import appeng.api.storage.IMEMonitor;
import appeng.api.storage.ITerminalHost;
import appeng.api.storage.ITerminalPins;
import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IAEStack;
import appeng.helpers.PatternHelper;
import appeng.helpers.UltimatePatternHelper;
import appeng.items.misc.ItemEncodedPattern;
import appeng.me.helpers.ChannelPowerSrc;
import appeng.tile.inventory.IAEAppEngInventory;
import appeng.tile.inventory.IAEStackInventory;
import appeng.tile.inventory.IIAEStackInventory;
import appeng.util.IConfigManagerHost;
import appeng.util.item.AEItemStack;
public interface IPatternTerminal extends IIAEStackInventory, ITerminalHost, IConfigManagerHost, IViewCellStorage,
IAEAppEngInventory, ITerminalPins, IActionHost {
@@ -98,4 +113,41 @@ public interface IPatternTerminal extends IIAEStackInventory, ITerminalHost, ICo
}
}
}
interface PatternEncodeListener {
void onEncoded(IPatternTerminal terminal, ItemStack pattern);
}
Iterable<PatternEncodeListener> getPatternEncodeListeners();
void addPatternEncodeListeners(final PatternEncodeListener listener);
void removePatternEncodeListeners(final PatternEncodeListener listener);
default boolean encode(String auther, World world) {
var networkNode = getGridNode(ForgeDirection.UNKNOWN);
final IGrid g = networkNode.getGrid();
if (g == null) return false;
var powerSource = new ChannelPowerSrc(networkNode, g.getCache(IEnergyGrid.class));
var itemMonitor = (IMEMonitor<IAEItemStack>) getMEMonitor(ITEM_STACK_TYPE);
var actionSource = new MachineSource(this);
return encode(powerSource, itemMonitor, actionSource, auther, world);
}
boolean encode(IEnergySource powerSource, IMEMonitor<IAEItemStack> itemMonitor, BaseActionSource actionSource,
String auther, World world);
@NotNull
static IAEItemStack createBlankPattern() {
return AEItemStack.create(AEApi.instance().definitions().materials().blankPattern().maybeStack(1).get());
}
static boolean isBlankPattern(final ItemStack stack) {
return stack != null && AEApi.instance().definitions().materials().blankPattern().isSameAs(stack);
}
static boolean isEncodedPattern(final ItemStack stack) {
return stack != null && stack.getItem() instanceof ItemEncodedPattern;
}
}
@@ -32,6 +32,7 @@ import appeng.api.config.ActionItems;
import appeng.api.config.ItemSubstitution;
import appeng.api.config.PatternBeSubstitution;
import appeng.api.config.Settings;
import appeng.api.parts.IPatternTerminal;
import appeng.api.storage.ITerminalHost;
import appeng.api.storage.StorageName;
import appeng.api.storage.data.IAEItemStack;
@@ -78,7 +79,7 @@ public class GuiPatternTerm extends GuiMEMonitorable {
protected VirtualMEPatternSlot[] outputSlots;
private boolean craftingMode;
@NotNull
private IAEItemStack blankPatternView = ContainerPatternTerm.createBlankPattern().setStackSize(0);
private IAEItemStack blankPatternView = IPatternTerminal.createBlankPattern().setStackSize(0);
public GuiPatternTerm(final InventoryPlayer inventoryPlayer, final ITerminalHost te,
final ContainerPatternTerm containerPatternTerm) {
@@ -10,14 +10,11 @@
package appeng.container.implementations;
import static appeng.api.parts.IPatternTerminal.createBlankPattern;
import static appeng.parts.reporting.PartPatternTerminal.*;
import static appeng.util.IterationCounter.fetchNewId;
import static appeng.util.Platform.isServer;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.entity.player.InventoryPlayer;
@@ -28,13 +25,9 @@ import net.minecraft.inventory.SlotCrafting;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.CraftingManager;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.common.util.ForgeDirection;
import org.jetbrains.annotations.NotNull;
import appeng.api.AEApi;
import appeng.api.config.Actionable;
import appeng.api.networking.security.MachineSource;
@@ -62,8 +55,6 @@ import appeng.core.sync.GuiBridge;
import appeng.core.sync.packets.PacketPatternSlot;
import appeng.helpers.IContainerCraftingPacket;
import appeng.items.contents.WirelessPatternTerminalGuiObject;
import appeng.items.misc.ItemEncodedPattern;
import appeng.items.misc.ItemTunnelPattern;
import appeng.items.storage.ItemViewCell;
import appeng.tile.inventory.AppEngInternalInventory;
import appeng.tile.inventory.IAEAppEngInventory;
@@ -291,148 +282,17 @@ public class ContainerPatternTerm extends ContainerMEMonitorable
}
}
private void encode() {
ItemStack output = this.patternSlotOUT.getStack();
final IAEStack<?>[] in = this.getInputs();
final IAEStack<?>[] out = this.getOutputs();
// if there is no input, this would be silly.
if (in == null) {
return;
public void encode() {
var player = this.getPlayerInv().player;
if (patternTerminal.encode(
getPowerSource(),
getItemMonitor(),
getActionSource(),
player.getCommandSenderName(),
player.worldObj)) {
this.isFirstUpdate = true;
this.detectAndSendChanges();
}
final boolean inputOnly = !isCraftingMode() && (out == null || out.length == 0);
if (!inputOnly && out == null) {
return;
}
final UUID inputOnlyUuid = inputOnly && ItemTunnelPattern.isTunnelPattern(output)
? ItemTunnelPattern.getTunnelUuid(output)
: null;
// first check the output slots, should either be null, or a pattern
if (output != null) {
if (!this.isEncodedPattern(output)) {
return;
}
} // if nothing is there we should snag a new pattern.
else {
ItemStack blank = this.patternSlotIN.getStack();
if (this.isBlankPattern(blank)) {
blank.stackSize--;
if (blank.stackSize == 0) {
this.patternSlotIN.putStack(null);
}
} else if (blank == null) {
IMEMonitor<IAEItemStack> itemMonitor = this.getItemMonitor();
IAEItemStack extracted = Platform.poweredExtraction(
this.getPowerSource(),
itemMonitor,
createBlankPattern(),
this.getActionSource());
if (extracted == null || extracted.getStackSize() <= 0) {
return;
}
} else {
return;
}
}
// add a new encoded pattern.
if (isCraftingMode()) {
output = AEApi.instance().definitions().items().encodedPattern().maybeStack(1).orNull();
} else if (inputOnly) {
output = AEApi.instance().definitions().items().encodedTunnelPattern().maybeStack(1).orNull();
} else {
output = AEApi.instance().definitions().items().encodedUltimatePattern().maybeStack(1).orNull();
}
if (output == null) {
return;
}
// encode the slot.
final NBTTagCompound encodedValue = new NBTTagCompound();
final NBTTagList tagIn = new NBTTagList();
final NBTTagList tagOut = new NBTTagList();
for (final IAEStack<?> i : in) {
tagIn.appendTag(i != null ? i.toNBTGeneric() : new NBTTagCompound());
}
if (out != null) {
for (final IAEStack<?> o : out) {
tagOut.appendTag(o != null ? o.toNBTGeneric() : new NBTTagCompound());
}
}
encodedValue.setTag("in", tagIn);
encodedValue.setTag("out", tagOut);
if (isCraftingMode()) encodedValue.setBoolean("crafting", this.isCraftingMode());
encodedValue.setBoolean("substitute", this.substituteSync.get());
encodedValue.setBoolean("beSubstitute", this.beSubstituteSync.get());
if (inputOnly) {
final UUID uuid = inputOnlyUuid != null ? inputOnlyUuid : UUID.randomUUID();
ItemTunnelPattern.writeTunnelUuid(encodedValue, uuid);
}
encodedValue.setString("author", this.getPlayerInv().player.getCommandSenderName());
output.setTagCompound(encodedValue);
this.patternSlotOUT.putStack(output);
}
private IAEStack<?>[] getInputs() {
final IAEStack<?>[] input = new IAEStack<?>[this.inputs.getSizeInventory()];
boolean hasValue = false;
for (int i = 0; i < this.inputs.getSizeInventory(); i++) {
input[i] = this.inputs.getAEStackInSlot(i);
if (input[i] != null) {
hasValue = true;
}
}
if (hasValue) {
return input;
}
return null;
}
private IAEStack<?>[] getOutputs() {
if (this.isCraftingMode()) {
final IAEStack<?> out = AEItemStack.create(this.getAndUpdateOutput());
if (out != null && out.getStackSize() > 0) {
return new IAEStack<?>[] { out };
}
} else {
final List<IAEStack<?>> list = new ArrayList<>(3);
boolean hasValue = false;
for (int i = 0; i < this.outputs.getSizeInventory(); i++) {
final IAEStack<?> out = this.outputs.getAEStackInSlot(i);
if (out != null && out.getStackSize() > 0) {
list.add(out);
hasValue = true;
}
}
if (hasValue) {
return list.toArray(new IAEStack<?>[0]);
}
}
return null;
}
private boolean isBlankPattern(final ItemStack stack) {
return stack != null && AEApi.instance().definitions().materials().blankPattern().isSameAs(stack);
}
private boolean isEncodedPattern(final ItemStack stack) {
return stack != null && stack.getItem() instanceof ItemEncodedPattern;
}
@Override
@@ -847,9 +707,4 @@ public class ContainerPatternTerm extends ContainerMEMonitorable
}
}
}
@NotNull
public static IAEItemStack createBlankPattern() {
return AEItemStack.create(AEApi.instance().definitions().materials().blankPattern().maybeStack(1).get());
}
}
@@ -0,0 +1,197 @@
package appeng.helpers;
import static appeng.util.Platform.isServer;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.world.World;
import com.google.common.collect.ImmutableList;
import appeng.api.AEApi;
import appeng.api.networking.energy.IEnergySource;
import appeng.api.networking.security.BaseActionSource;
import appeng.api.parts.IPatternTerminal;
import appeng.api.parts.IPatternTerminal.PatternEncodeListener;
import appeng.api.storage.IMEMonitor;
import appeng.api.storage.StorageName;
import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IAEStack;
import appeng.items.misc.ItemTunnelPattern;
import appeng.tile.inventory.IAEStackInventory;
import appeng.util.Platform;
import appeng.util.item.AEItemStack;
public class PatternEncodingHelper {
static private IAEStack<?>[] getInputs(IPatternTerminal terminal) {
final IAEStackInventory inputs = terminal.getAEInventoryByName(StorageName.CRAFTING_INPUT);
final IAEStack<?>[] input = new IAEStack<?>[inputs.getSizeInventory()];
boolean hasValue = false;
for (int i = 0; i < inputs.getSizeInventory(); i++) {
input[i] = inputs.getAEStackInSlot(i);
if (input[i] != null) {
hasValue = true;
}
}
if (hasValue) {
return input;
}
return null;
}
static private ItemStack getCraftingOutput(IPatternTerminal terminal, World world) {
if (!terminal.isCraftingRecipe() || !isServer()) return null;
final InventoryCrafting ic = new InventoryCrafting(new Container() {
@Override
public boolean canInteractWith(EntityPlayer player) {
return false;
}
}, 3, 3);
final IAEStackInventory inputs = terminal.getAEInventoryByName(StorageName.CRAFTING_INPUT);
for (int x = 0; x < ic.getSizeInventory(); x++) {
if (inputs.getAEStackInSlot(x) instanceof IAEItemStack aes) {
ic.setInventorySlotContents(x, aes.getItemStack());
}
}
return Platform.findMatchingRecipeOutput(ic, world);
}
static private IAEStack<?>[] getOutputs(IPatternTerminal terminal, World world) {
final IAEStackInventory outputs = terminal.getAEInventoryByName(StorageName.CRAFTING_OUTPUT);
if (terminal.isCraftingRecipe()) {
final IAEStack<?> out = AEItemStack.create(getCraftingOutput(terminal, world));
if (out != null && out.getStackSize() > 0) {
return new IAEStack<?>[] { out };
}
} else {
final List<IAEStack<?>> list = new ArrayList<>(3);
boolean hasValue = false;
for (int i = 0; i < outputs.getSizeInventory(); i++) {
final IAEStack<?> out = outputs.getAEStackInSlot(i);
if (out != null && out.getStackSize() > 0) {
list.add(out);
hasValue = true;
}
}
if (hasValue) {
return list.toArray(new IAEStack<?>[0]);
}
}
return null;
}
static public boolean encode(IPatternTerminal terminal, IEnergySource powerSource,
IMEMonitor<IAEItemStack> itemMonitor, BaseActionSource actionSource, String auther, World world) {
IInventory pattern = terminal.getInventoryByName("pattern");
ItemStack output = pattern.getStackInSlot(1);
final IAEStack<?>[] in = getInputs(terminal);
final IAEStack<?>[] out = getOutputs(terminal, world);
// if there is no input, this would be silly.
if (in == null) {
return false;
}
final boolean inputOnly = !terminal.isCraftingRecipe() && (out == null || out.length == 0);
if (!inputOnly && out == null) {
return false;
}
final UUID inputOnlyUuid = inputOnly && ItemTunnelPattern.isTunnelPattern(output)
? ItemTunnelPattern.getTunnelUuid(output)
: null;
// first check the output slots, should either be null, or a pattern
if (output != null) {
if (!IPatternTerminal.isEncodedPattern(output)) {
return false;
}
} // if nothing is there we should snag a new pattern.
else {
ItemStack blank = pattern.getStackInSlot(0);
if (IPatternTerminal.isBlankPattern(blank)) {
blank.stackSize--;
if (blank.stackSize == 0) {
pattern.setInventorySlotContents(0, null);
}
} else if (blank == null) {
IAEItemStack extracted = Platform.poweredExtraction(
powerSource,
itemMonitor,
IPatternTerminal.createBlankPattern(),
actionSource);
if (extracted == null || extracted.getStackSize() <= 0) {
return false;
}
} else {
return false;
}
}
// add a new encoded pattern.
if (terminal.isCraftingRecipe()) {
output = AEApi.instance().definitions().items().encodedPattern().maybeStack(1).orNull();
} else if (inputOnly) {
output = AEApi.instance().definitions().items().encodedTunnelPattern().maybeStack(1).orNull();
} else {
output = AEApi.instance().definitions().items().encodedUltimatePattern().maybeStack(1).orNull();
}
if (output == null) {
return false;
}
// encode the slot.
final NBTTagCompound encodedValue = new NBTTagCompound();
final NBTTagList tagIn = new NBTTagList();
final NBTTagList tagOut = new NBTTagList();
for (final IAEStack<?> i : in) {
tagIn.appendTag(i != null ? i.toNBTGeneric() : new NBTTagCompound());
}
if (out != null) {
for (final IAEStack<?> o : out) {
tagOut.appendTag(o != null ? o.toNBTGeneric() : new NBTTagCompound());
}
}
encodedValue.setTag("in", tagIn);
encodedValue.setTag("out", tagOut);
if (terminal.isCraftingRecipe()) encodedValue.setBoolean("crafting", true);
encodedValue.setBoolean("substitute", terminal.isSubstitution());
encodedValue.setBoolean("beSubstitute", terminal.canBeSubstitution());
if (inputOnly) {
final UUID uuid = inputOnlyUuid != null ? inputOnlyUuid : UUID.randomUUID();
ItemTunnelPattern.writeTunnelUuid(encodedValue, uuid);
}
encodedValue.setString("author", auther);
output.setTagCompound(encodedValue);
pattern.setInventorySlotContents(1, output);
for (final PatternEncodeListener listener : ImmutableList.copyOf(terminal.getPatternEncodeListeners())) {
listener.onEncoded(terminal, output);
}
return true;
}
}
@@ -1,5 +1,9 @@
package appeng.items.contents;
import java.util.Collections;
import java.util.Set;
import java.util.WeakHashMap;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
@@ -7,10 +11,15 @@ import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.World;
import appeng.api.features.IWirelessTermHandler;
import appeng.api.networking.energy.IEnergySource;
import appeng.api.networking.security.BaseActionSource;
import appeng.api.parts.IPatternTerminalEx;
import appeng.api.storage.IMEMonitor;
import appeng.api.storage.StorageName;
import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IAEStack;
import appeng.api.util.IConfigManager;
import appeng.helpers.PatternEncodingHelper;
import appeng.helpers.WirelessTerminalGuiObject;
import appeng.tile.inventory.AppEngInternalInventory;
import appeng.tile.inventory.IAEStackInventory;
@@ -26,6 +35,7 @@ public class WirelessPatternTerminalGuiObject extends WirelessTerminalGuiObject
IAEStackInventory output;
private final AppEngInternalInventory pattern = new AppEngInternalInventory(this, 2);
private final Set<PatternEncodeListener> patternEncodeListeners = Collections.newSetFromMap(new WeakHashMap<>());
private boolean craftingMode;
private boolean substitute = false;
@@ -181,4 +191,25 @@ public class WirelessPatternTerminalGuiObject extends WirelessTerminalGuiObject
@Override
public void updateSetting(IConfigManager manager, Enum settingName, Enum newValue) {}
@Override
public boolean encode(IEnergySource powerSource, IMEMonitor<IAEItemStack> itemMonitor,
BaseActionSource actionSource, String auther, World world) {
return PatternEncodingHelper.encode(this, powerSource, itemMonitor, actionSource, auther, world);
}
@Override
public Iterable<PatternEncodeListener> getPatternEncodeListeners() {
return patternEncodeListeners;
}
@Override
public void addPatternEncodeListeners(final PatternEncodeListener listener) {
patternEncodeListeners.add(listener);
}
@Override
public void removePatternEncodeListeners(final PatternEncodeListener listener) {
patternEncodeListeners.remove(listener);
}
}
@@ -10,19 +10,28 @@
package appeng.parts.reporting;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.WeakHashMap;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.World;
import appeng.api.AEApi;
import appeng.api.networking.energy.IEnergySource;
import appeng.api.networking.security.BaseActionSource;
import appeng.api.parts.IPatternTerminal;
import appeng.api.storage.IMEMonitor;
import appeng.api.storage.StorageName;
import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IAEStack;
import appeng.client.texture.CableBusTextures;
import appeng.core.sync.GuiBridge;
import appeng.helpers.PatternEncodingHelper;
import appeng.helpers.Reflected;
import appeng.tile.inventory.AppEngInternalInventory;
import appeng.tile.inventory.IAEStackInventory;
@@ -52,6 +61,7 @@ public class PartPatternTerminal extends AbstractPartTerminal implements IIAESta
getPatternOutputsWidth() * getPatternOutputsHeigh() * getPatternOutputPages(),
StorageName.CRAFTING_OUTPUT);
private final AppEngInternalInventory pattern = new AppEngInternalInventory(this, 2);
private final Set<PatternEncodeListener> patternEncodeListeners = Collections.newSetFromMap(new WeakHashMap<>());
private boolean craftingMode = true;
private boolean substitute = false;
@@ -224,4 +234,25 @@ public class PartPatternTerminal extends AbstractPartTerminal implements IIAESta
public ItemStack getPrimaryGuiIcon() {
return AEApi.instance().definitions().parts().patternTerminal().maybeStack(1).orNull();
}
@Override
public boolean encode(IEnergySource powerSource, IMEMonitor<IAEItemStack> itemMonitor,
BaseActionSource actionSource, String auther, World world) {
return PatternEncodingHelper.encode(this, powerSource, itemMonitor, actionSource, auther, world);
}
@Override
public Iterable<PatternEncodeListener> getPatternEncodeListeners() {
return patternEncodeListeners;
}
@Override
public void addPatternEncodeListeners(final PatternEncodeListener listener) {
patternEncodeListeners.add(listener);
}
@Override
public void removePatternEncodeListeners(final PatternEncodeListener listener) {
patternEncodeListeners.remove(listener);
}
}