diff --git a/src/api/java/appeng/api/IAppEngApi.java b/src/api/java/appeng/api/IAppEngApi.java
index 59b06c871..6a3391f8c 100644
--- a/src/api/java/appeng/api/IAppEngApi.java
+++ b/src/api/java/appeng/api/IAppEngApi.java
@@ -24,6 +24,7 @@
package appeng.api;
import appeng.api.client.IClientHelper;
+import appeng.api.crafting.ICraftingHelper;
import appeng.api.definitions.IDefinitions;
import appeng.api.features.IRegistryContainer;
import appeng.api.networking.IGridHelper;
@@ -48,6 +49,11 @@ public interface IAppEngApi {
*/
IStorageHelper storage();
+ /**
+ * @return A helper for working with crafting related tasks.
+ */
+ ICraftingHelper crafting();
+
/**
* @return A helper to create {@link IGridNode} and other grid related objects.
*/
diff --git a/src/api/java/appeng/api/crafting/ICraftingHelper.java b/src/api/java/appeng/api/crafting/ICraftingHelper.java
new file mode 100644
index 000000000..909f26353
--- /dev/null
+++ b/src/api/java/appeng/api/crafting/ICraftingHelper.java
@@ -0,0 +1,108 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 TeamAppliedEnergistics
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package appeng.api.crafting;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.minecraft.item.ItemStack;
+import net.minecraft.item.crafting.ICraftingRecipe;
+import net.minecraft.world.World;
+
+import appeng.api.networking.crafting.ICraftingPatternDetails;
+import appeng.api.storage.data.IAEItemStack;
+
+public interface ICraftingHelper {
+
+ /**
+ * Checks that the given item stack is an encoded pattern.
+ */
+ boolean isEncodedPattern(@Nullable IAEItemStack item);
+
+ /**
+ * Checks that the given item stack is an encoded pattern.
+ */
+ boolean isEncodedPattern(ItemStack item);
+
+ /**
+ * Encodes a processing pattern which represents the ability to convert the
+ * given inputs into the given outputs using some process external to the ME
+ * system.
+ *
+ * @param stack If null, a new item will be created to hold the encoded pattern.
+ * Otherwise the given item must already contains an encoded
+ * pattern that will be overwritten.
+ * @return A new encoded pattern, or the given stack with the pattern encoded in
+ * it.
+ */
+ ItemStack encodeProcessingPattern(@Nullable ItemStack stack, ItemStack[] in, ItemStack[] out);
+
+ /**
+ * Encodes a crafting pattern which represents a Vanilla crafting recipe.
+ *
+ * @param stack If null, a new item will be created to hold the
+ * encoded pattern. Otherwise the given item must
+ * already contains an encoded pattern that will be
+ * overwritten.
+ * @param recipe The Vanilla crafting recipe to be encoded.
+ * @param in The items in the crafting grid, which are used to
+ * determine what items are supplied from the ME system
+ * to craft using this pattern.
+ * @param out What is to be expected as the result of this crafting
+ * operation by the ME system.
+ * @param allowSubstitutes Controls whether the ME system will allow the use of
+ * equivalent items to craft this recipe.
+ */
+ ItemStack encodeCraftingPattern(@Nullable ItemStack stack, ICraftingRecipe recipe, ItemStack[] in, ItemStack out,
+ boolean allowSubstitutes);
+
+ /**
+ * Same as {@link #decodePattern(ItemStack, World, boolean)} with no auto
+ * recovery of changed recipe ids.
+ */
+ @Nullable
+ default ICraftingPatternDetails decodePattern(@Nonnull ItemStack itemStack, @Nonnull World world) {
+ return decodePattern(itemStack, world, false);
+ }
+
+ /**
+ * Decodes an encoded crafting pattern and returns the pattern details.
+ *
+ * The item backing the {@link ItemStack} needs to be an item returned by the
+ * encode methods of this class.
+ *
+ * @param itemStack pattern
+ * @param world world used to access the
+ * {@link net.minecraft.item.crafting.RecipeManager}.
+ * @param autoRecovery If true, the method will try to recover from changed
+ * recipe ids by searching the entire recipe manager for a
+ * recipe matching the inputs. If this is successful, the
+ * given item stack will be changed to reflect the new
+ * recipe id.
+ * @return The pattern details if the pattern could be decoded. Otherwise null.
+ */
+ @Nullable
+ ICraftingPatternDetails decodePattern(@Nonnull ItemStack itemStack, @Nonnull World world, boolean autoRecovery);
+
+}
diff --git a/src/api/java/appeng/api/implementations/ICraftingPatternItem.java b/src/api/java/appeng/api/implementations/ICraftingPatternItem.java
deleted file mode 100644
index 5b93bd7f6..000000000
--- a/src/api/java/appeng/api/implementations/ICraftingPatternItem.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2013 AlgorithmX2
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-package appeng.api.implementations;
-
-import net.minecraft.item.Item;
-import net.minecraft.item.ItemStack;
-import net.minecraft.world.World;
-
-import appeng.api.networking.crafting.ICraftingPatternDetails;
-
-/**
- * Implemented on {@link Item}
- */
-public interface ICraftingPatternItem {
-
- /**
- * Access Details about a pattern
- *
- * @param is pattern
- * @param w crafting world
- *
- * @return details of pattern
- */
- ICraftingPatternDetails getPatternForItem(ItemStack is, World w);
-}
diff --git a/src/api/java/appeng/api/networking/crafting/ICraftingPatternDetails.java b/src/api/java/appeng/api/networking/crafting/ICraftingPatternDetails.java
index 795c5830b..f2ac98821 100644
--- a/src/api/java/appeng/api/networking/crafting/ICraftingPatternDetails.java
+++ b/src/api/java/appeng/api/networking/crafting/ICraftingPatternDetails.java
@@ -27,18 +27,19 @@ import net.minecraft.inventory.CraftingInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
-import appeng.api.implementations.ICraftingPatternItem;
import appeng.api.storage.data.IAEItemStack;
/**
- * do not implement provided by {@link ICraftingPatternItem}
- *
- * caching this INSTANCE will increase performance of validation and checks.
+ * Describes a crafting or processing pattern decoded by
+ * {@link appeng.api.crafting.ICraftingHelper}.
+ *
+ * Do not cache instances of this class unless you handle recipe reloads on the
+ * server and client correctly.
*/
public interface ICraftingPatternDetails {
/**
- * @return source item.
+ * @return encodes this crafting pattern into a new item stack.
*/
ItemStack getPattern();
@@ -52,7 +53,9 @@ public interface ICraftingPatternDetails {
boolean isValidItemForSlot(int slotIndex, ItemStack itemStack, World world);
/**
- * @return if this pattern is a crafting pattern ( work bench )
+ * @return if this pattern is for a Vanilla
+ * {@link net.minecraft.item.crafting.IRecipeType#CRAFTING crafting
+ * recipe}.
*/
boolean isCraftable();
diff --git a/src/api/java/appeng/api/networking/crafting/ICraftingProviderHelper.java b/src/api/java/appeng/api/networking/crafting/ICraftingProviderHelper.java
index 00efcc1ca..1c7e6c4cc 100644
--- a/src/api/java/appeng/api/networking/crafting/ICraftingProviderHelper.java
+++ b/src/api/java/appeng/api/networking/crafting/ICraftingProviderHelper.java
@@ -23,6 +23,7 @@
package appeng.api.networking.crafting;
+import appeng.api.crafting.ICraftingHelper;
import appeng.api.storage.data.IAEItemStack;
/**
@@ -33,6 +34,9 @@ public interface ICraftingProviderHelper {
/**
* Add new Pattern to AE's crafting cache.
+ *
+ * This will only accept instances created by
+ * {@link ICraftingHelper#decodePattern(net.minecraft.item.ItemStack, net.minecraft.world.World)}
*/
void addCraftingOption(ICraftingMedium medium, ICraftingPatternDetails api);
diff --git a/src/main/java/appeng/container/implementations/MolecularAssemblerContainer.java b/src/main/java/appeng/container/implementations/MolecularAssemblerContainer.java
index 341602fbe..542a32cfd 100644
--- a/src/main/java/appeng/container/implementations/MolecularAssemblerContainer.java
+++ b/src/main/java/appeng/container/implementations/MolecularAssemblerContainer.java
@@ -38,6 +38,7 @@ import appeng.container.slot.AppEngSlot;
import appeng.container.slot.MolecularAssemblerPatternSlot;
import appeng.container.slot.OutputSlot;
import appeng.container.slot.RestrictedInputSlot;
+import appeng.core.Api;
import appeng.items.misc.EncodedPatternItem;
import appeng.tile.crafting.MolecularAssemblerTileEntity;
import appeng.util.Platform;
@@ -79,8 +80,7 @@ public class MolecularAssemblerContainer extends UpgradeableContainer implements
if (is.getItem() instanceof EncodedPatternItem) {
final World w = this.getTileEntity().getWorld();
- final EncodedPatternItem iep = (EncodedPatternItem) is.getItem();
- final ICraftingPatternDetails ph = iep.getPatternForItem(is, w);
+ final ICraftingPatternDetails ph = Api.instance().crafting().decodePattern(is, w);
if (ph.isCraftable()) {
return ph.isValidItemForSlot(slotIndex, i, w);
}
diff --git a/src/main/java/appeng/container/implementations/PatternTermContainer.java b/src/main/java/appeng/container/implementations/PatternTermContainer.java
index 7ca82cc5a..22fd63e5b 100644
--- a/src/main/java/appeng/container/implementations/PatternTermContainer.java
+++ b/src/main/java/appeng/container/implementations/PatternTermContainer.java
@@ -20,7 +20,6 @@ package appeng.container.implementations;
import java.util.ArrayList;
import java.util.List;
-import java.util.Optional;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
@@ -32,11 +31,9 @@ import net.minecraft.inventory.container.CraftingResultSlot;
import net.minecraft.inventory.container.IContainerListener;
import net.minecraft.inventory.container.Slot;
import net.minecraft.item.ItemStack;
+import net.minecraft.item.crafting.ICraftingRecipe;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.item.crafting.IRecipeType;
-import net.minecraft.nbt.CompoundNBT;
-import net.minecraft.nbt.INBT;
-import net.minecraft.nbt.ListNBT;
import net.minecraft.network.PacketBuffer;
import net.minecraft.world.World;
import net.minecraftforge.items.IItemHandler;
@@ -44,6 +41,7 @@ import net.minecraftforge.items.wrapper.PlayerInvWrapper;
import appeng.api.config.Actionable;
import appeng.api.config.SecurityPermissions;
+import appeng.api.crafting.ICraftingHelper;
import appeng.api.definitions.IDefinitions;
import appeng.api.storage.IMEMonitor;
import appeng.api.storage.ITerminalHost;
@@ -98,8 +96,9 @@ public class PatternTermContainer extends MEMonitorableContainer
private final PatternTermSlot craftSlot;
private final RestrictedInputSlot patternSlotIN;
private final RestrictedInputSlot patternSlotOUT;
+ private final ICraftingHelper craftingHelper = Api.INSTANCE.crafting();
- private IRecipe currentRecipe;
+ private ICraftingRecipe currentRecipe;
@GuiSync(97)
public boolean craftingMode = true;
@GuiSync(96)
@@ -206,17 +205,17 @@ public class PatternTermContainer extends MEMonitorableContainer
final ItemStack[] out = this.getOutputs();
// if there is no input, this would be silly.
- if (in == null || out == null) {
+ if (in == null || out == null || isCraftingMode() && currentRecipe == null) {
return;
}
// first check the output slots, should either be null, or a pattern
- if (!output.isEmpty() && !this.isPattern(output)) {
+ if (!output.isEmpty() && !craftingHelper.isEncodedPattern(output)) {
return;
} // if nothing is there we should snag a new pattern.
else if (output.isEmpty()) {
output = this.patternSlotIN.getStack();
- if (output.isEmpty() || !this.isPattern(output)) {
+ if (output.isEmpty() || !isPattern(output)) {
return; // no blanks.
}
@@ -226,34 +225,17 @@ public class PatternTermContainer extends MEMonitorableContainer
this.patternSlotIN.putStack(ItemStack.EMPTY);
}
- // add a new encoded pattern.
- Optional maybePattern = Api.instance().definitions().items().encodedPattern().maybeStack(1);
- if (maybePattern.isPresent()) {
- output = maybePattern.get();
- this.patternSlotOUT.putStack(output);
- }
+ // let the crafting helper create a new encoded pattern
+ output = null;
}
- // encode the slot.
- final CompoundNBT encodedValue = new CompoundNBT();
-
- final ListNBT tagIn = new ListNBT();
- final ListNBT tagOut = new ListNBT();
-
- for (final ItemStack i : in) {
- tagIn.add(this.createItemTag(i));
+ if (this.isCraftingMode()) {
+ output = craftingHelper.encodeCraftingPattern(output, this.currentRecipe, in, out[0], isSubstitute());
+ } else {
+ output = craftingHelper.encodeProcessingPattern(output, in, out);
}
+ this.patternSlotOUT.putStack(output);
- for (final ItemStack i : out) {
- tagOut.add(this.createItemTag(i));
- }
-
- encodedValue.put("in", tagIn);
- encodedValue.put("out", tagOut);
- encodedValue.putBoolean("crafting", this.isCraftingMode());
- encodedValue.putBoolean("substitute", this.isSubstitute());
-
- output.setTag(encodedValue);
}
private ItemStack[] getInputs() {
@@ -308,21 +290,7 @@ public class PatternTermContainer extends MEMonitorableContainer
}
final IDefinitions definitions = Api.instance().definitions();
-
- boolean isPattern = definitions.items().encodedPattern().isSameAs(output);
- isPattern |= definitions.materials().blankPattern().isSameAs(output);
-
- return isPattern;
- }
-
- private INBT createItemTag(final ItemStack i) {
- final CompoundNBT c = new CompoundNBT();
-
- if (!i.isEmpty()) {
- i.write(c);
- }
-
- return c;
+ return definitions.materials().blankPattern().isSameAs(output);
}
@Override
diff --git a/src/main/java/appeng/container/slot/RestrictedInputSlot.java b/src/main/java/appeng/container/slot/RestrictedInputSlot.java
index 152c9eb92..d6913fc45 100644
--- a/src/main/java/appeng/container/slot/RestrictedInputSlot.java
+++ b/src/main/java/appeng/container/slot/RestrictedInputSlot.java
@@ -33,11 +33,11 @@ import net.minecraft.world.World;
import net.minecraftforge.common.ForgeHooks;
import net.minecraftforge.items.IItemHandler;
+import appeng.api.crafting.ICraftingHelper;
import appeng.api.definitions.IDefinitions;
import appeng.api.definitions.IItems;
import appeng.api.definitions.IMaterials;
import appeng.api.features.INetworkEncodable;
-import appeng.api.implementations.ICraftingPatternItem;
import appeng.api.implementations.items.IBiometricCard;
import appeng.api.implementations.items.ISpatialStorageCell;
import appeng.api.implementations.items.IStorageComponent;
@@ -88,10 +88,7 @@ public class RestrictedInputSlot extends AppEngSlot {
public boolean isValid(final ItemStack is, final World theWorld) {
if (this.which == PlacableItemType.VALID_ENCODED_PATTERN_W_OUTPUT) {
- final ICraftingPatternDetails ap = is.getItem() instanceof ICraftingPatternItem
- ? ((ICraftingPatternItem) is.getItem()).getPatternForItem(is, theWorld)
- : null;
- return ap != null;
+ return Api.instance().crafting().decodePattern(is, theWorld) != null;
}
return true;
}
@@ -126,39 +123,24 @@ public class RestrictedInputSlot extends AppEngSlot {
final IDefinitions definitions = Api.instance().definitions();
final IMaterials materials = definitions.materials();
final IItems items = definitions.items();
+ final ICraftingHelper crafting = Api.instance().crafting();
switch (this.which) {
case ENCODED_CRAFTING_PATTERN:
- if (i.getItem() instanceof ICraftingPatternItem) {
- final ICraftingPatternItem b = (ICraftingPatternItem) i.getItem();
- final ICraftingPatternDetails de = b.getPatternForItem(i, this.p.player.world);
- if (de != null) {
- return de.isCraftable();
- }
+ final ICraftingPatternDetails de = crafting.decodePattern(i, this.p.player.world);
+ if (de != null) {
+ return de.isCraftable();
}
return false;
case VALID_ENCODED_PATTERN_W_OUTPUT:
case ENCODED_PATTERN_W_OUTPUT:
- case ENCODED_PATTERN: {
- if (i.getItem() instanceof ICraftingPatternItem) {
- return true;
- }
- // ICraftingPatternDetails pattern = i.getItem() instanceof ICraftingPatternItem
- // ?
- // ((ICraftingPatternItem)
- // i.getItem()).getPatternForItem( i ) : null;
- return false;// pattern != null;
- }
+ case ENCODED_PATTERN:
+ return crafting.isEncodedPattern(i);
case BLANK_PATTERN:
return materials.blankPattern().isSameAs(i);
case PATTERN:
-
- if (i.getItem() instanceof ICraftingPatternItem) {
- return true;
- }
-
- return materials.blankPattern().isSameAs(i);
+ return materials.blankPattern().isSameAs(i) || crafting.isEncodedPattern(i);
case INSCRIBER_PLATE:
if (materials.namePress().isSameAs(i)) {
diff --git a/src/main/java/appeng/core/Api.java b/src/main/java/appeng/core/Api.java
index b61134ab0..f052afd07 100644
--- a/src/main/java/appeng/core/Api.java
+++ b/src/main/java/appeng/core/Api.java
@@ -21,10 +21,12 @@ package appeng.core;
import appeng.api.AEAddon;
import appeng.api.IAppEngApi;
import appeng.api.client.IClientHelper;
+import appeng.api.crafting.ICraftingHelper;
import appeng.api.features.IRegistryContainer;
import appeng.api.networking.IGridHelper;
import appeng.api.storage.IStorageHelper;
import appeng.core.api.ApiClientHelper;
+import appeng.core.api.ApiCrafting;
import appeng.core.api.ApiGrid;
import appeng.core.api.ApiPart;
import appeng.core.api.ApiStorage;
@@ -59,6 +61,7 @@ public final class Api implements IAppEngApi {
private final IStorageHelper storageHelper;
private final IGridHelper networkHelper;
private final ApiDefinitions definitions;
+ private final ICraftingHelper craftingHelper;
private final IClientHelper client;
private Api() {
@@ -67,6 +70,7 @@ public final class Api implements IAppEngApi {
this.registryContainer = new RegistryContainer();
this.partHelper = new ApiPart();
this.definitions = new ApiDefinitions((PartModels) this.registryContainer.partModels());
+ this.craftingHelper = new ApiCrafting(this.definitions);
this.client = new ApiClientHelper(this.definitions);
}
@@ -84,6 +88,11 @@ public final class Api implements IAppEngApi {
return this.storageHelper;
}
+ @Override
+ public ICraftingHelper crafting() {
+ return this.craftingHelper;
+ }
+
@Override
public IGridHelper grid() {
return this.networkHelper;
diff --git a/src/main/java/appeng/core/api/ApiCrafting.java b/src/main/java/appeng/core/api/ApiCrafting.java
new file mode 100644
index 000000000..e4f710bc2
--- /dev/null
+++ b/src/main/java/appeng/core/api/ApiCrafting.java
@@ -0,0 +1,167 @@
+/*
+ * This file is part of Applied Energistics 2.
+ * Copyright (c) 2020, TeamAppliedEnergistics, All rights reserved.
+ *
+ * Applied Energistics 2 is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Applied Energistics 2 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Applied Energistics 2. If not, see .
+ */
+
+package appeng.core.api;
+
+import java.util.List;
+
+import javax.annotation.Nullable;
+
+import com.google.common.base.Preconditions;
+
+import net.minecraft.inventory.CraftingInventory;
+import net.minecraft.item.ItemStack;
+import net.minecraft.item.crafting.ICraftingRecipe;
+import net.minecraft.item.crafting.IRecipe;
+import net.minecraft.item.crafting.IRecipeType;
+import net.minecraft.item.crafting.RecipeManager;
+import net.minecraft.util.ResourceLocation;
+import net.minecraft.world.World;
+
+import appeng.api.crafting.ICraftingHelper;
+import appeng.api.definitions.IItemDefinition;
+import appeng.api.networking.crafting.ICraftingPatternDetails;
+import appeng.api.storage.channels.IItemStorageChannel;
+import appeng.api.storage.data.IAEItemStack;
+import appeng.container.ContainerNull;
+import appeng.core.AELog;
+import appeng.core.Api;
+import appeng.core.ApiDefinitions;
+import appeng.helpers.CraftingPatternDetails;
+import appeng.items.misc.EncodedPatternItem;
+
+public class ApiCrafting implements ICraftingHelper {
+
+ private final IItemDefinition encodedPattern;
+
+ public ApiCrafting(ApiDefinitions definitions) {
+ this.encodedPattern = definitions.items().encodedPattern();
+ }
+
+ @Override
+ public boolean isEncodedPattern(@Nullable IAEItemStack item) {
+ return item != null && item.getItem() instanceof EncodedPatternItem;
+ }
+
+ @Override
+ public boolean isEncodedPattern(ItemStack item) {
+ return !item.isEmpty() && item.getItem() instanceof EncodedPatternItem;
+ }
+
+ @Override
+ public ItemStack encodeCraftingPattern(@Nullable ItemStack stack, ICraftingRecipe recipe, ItemStack[] in,
+ ItemStack out, boolean allowSubstitutes) {
+ if (stack == null) {
+ stack = encodedPattern.stack(1);
+ } else {
+ Preconditions.checkArgument(isEncodedPattern(stack));
+ }
+
+ EncodedPatternItem.encodeCraftingPattern(stack, in, new ItemStack[] { out }, recipe.getId(), allowSubstitutes);
+ return stack;
+ }
+
+ @Override
+ public ItemStack encodeProcessingPattern(@Nullable ItemStack stack, ItemStack[] in, ItemStack[] out) {
+ if (stack == null) {
+ stack = encodedPattern.stack(1);
+ } else {
+ Preconditions.checkArgument(isEncodedPattern(stack));
+ }
+
+ EncodedPatternItem.encodeProcessingPattern(stack, in, out);
+ return stack;
+ }
+
+ @Override
+ public ICraftingPatternDetails decodePattern(final ItemStack is, final World world, boolean autoRecovery) {
+ if (is == null || world == null) {
+ return null;
+ }
+
+ EncodedPatternItem patternItem = getPatternItem(is);
+ if (patternItem == null || !patternItem.isEncodedPattern(is)) {
+ return null;
+ }
+
+ // The recipe ids encoded in a pattern can go stale. This code attempts to find
+ // the new id
+ // based on the stored inputs/outputs if that happens.
+ ResourceLocation recipeId = patternItem.getCraftingRecipeId(is);
+ if (recipeId != null) {
+ IRecipe> recipe = world.getRecipeManager().getRecipes(IRecipeType.CRAFTING).get(recipeId);
+ if (!(recipe instanceof ICraftingRecipe)) {
+ if (!autoRecovery || !attemptRecovery(patternItem, is, world)) {
+ return null;
+ }
+ }
+ }
+
+ // We use the shared itemstack for an identity lookup.
+ IAEItemStack ais = Api.instance().storage().getStorageChannel(IItemStorageChannel.class).createStack(is);
+
+ return new CraftingPatternDetails(ais, world);
+ }
+
+ private boolean attemptRecovery(EncodedPatternItem patternItem, ItemStack itemStack, World world) {
+
+ RecipeManager recipeManager = world.getRecipeManager();
+
+ List ingredients = patternItem.getIngredients(itemStack);
+ List products = patternItem.getProducts(itemStack);
+ if (ingredients.size() < 9 || products.size() < 1) {
+ return false;
+ }
+
+ ResourceLocation currentRecipeId = patternItem.getCraftingRecipeId(itemStack);
+
+ // Fill a crafting inventory with the ingredients to find a suitable recipe
+ CraftingInventory testInventory = new CraftingInventory(new ContainerNull(), 3, 3);
+ for (int x = 0; x < 9; x++) {
+ final IAEItemStack ais = ingredients.get(x);
+ final ItemStack gs = ais != null ? ais.createItemStack() : ItemStack.EMPTY;
+ testInventory.setInventorySlotContents(x, gs);
+ }
+
+ ICraftingRecipe potentialRecipe = recipeManager.getRecipe(IRecipeType.CRAFTING, testInventory, world)
+ .orElse(null);
+
+ if (potentialRecipe != null) {
+ // Check that it matches the expected output
+ if (products.get(0).isSameType(potentialRecipe.getCraftingResult(testInventory))) {
+ // Yay we found a match, reencode the pattern
+ AELog.debug("Re-Encoding pattern from %s -> %s", currentRecipeId, potentialRecipe.getId());
+ ItemStack[] in = ingredients.stream().map(ais -> ais != null ? ais.createItemStack() : ItemStack.EMPTY)
+ .toArray(ItemStack[]::new);
+ ItemStack out = products.get(0).createItemStack();
+ encodeCraftingPattern(itemStack, potentialRecipe, in, out, patternItem.allowsSubstitution(itemStack));
+ }
+ }
+
+ AELog.debug("Failed to recover encoded crafting pattern for recipe %s", currentRecipeId);
+ return false;
+ }
+
+ private static EncodedPatternItem getPatternItem(ItemStack itemStack) {
+ if (itemStack.getItem() instanceof EncodedPatternItem) {
+ return (EncodedPatternItem) itemStack.getItem();
+ }
+ return null;
+ }
+
+}
diff --git a/src/main/java/appeng/core/sync/packets/CraftRequestPacket.java b/src/main/java/appeng/core/sync/packets/CraftRequestPacket.java
index 56bf5bce3..713fdadec 100644
--- a/src/main/java/appeng/core/sync/packets/CraftRequestPacket.java
+++ b/src/main/java/appeng/core/sync/packets/CraftRequestPacket.java
@@ -101,7 +101,7 @@ public class CraftRequestPacket extends BasePacket {
if (futureJob != null) {
futureJob.cancel(true);
}
- AELog.debug(e);
+ AELog.info(e);
}
}
}
diff --git a/src/main/java/appeng/helpers/PatternHelper.java b/src/main/java/appeng/helpers/CraftingPatternDetails.java
similarity index 79%
rename from src/main/java/appeng/helpers/PatternHelper.java
rename to src/main/java/appeng/helpers/CraftingPatternDetails.java
index 0664ec83e..b92dcad17 100644
--- a/src/main/java/appeng/helpers/PatternHelper.java
+++ b/src/main/java/appeng/helpers/CraftingPatternDetails.java
@@ -25,13 +25,15 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
+import com.google.common.base.Preconditions;
+
import net.minecraft.inventory.CraftingInventory;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.ICraftingRecipe;
+import net.minecraft.item.crafting.IRecipe;
import net.minecraft.item.crafting.IRecipeType;
-import net.minecraft.nbt.CompoundNBT;
-import net.minecraft.nbt.ListNBT;
+import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import appeng.api.networking.crafting.ICraftingPatternDetails;
@@ -39,12 +41,11 @@ import appeng.api.storage.channels.IItemStorageChannel;
import appeng.api.storage.data.IAEItemStack;
import appeng.container.ContainerNull;
import appeng.core.Api;
+import appeng.items.misc.EncodedPatternItem;
import appeng.util.Platform;
-import appeng.util.item.AEItemStack;
-public class PatternHelper implements ICraftingPatternDetails, Comparable {
+public class CraftingPatternDetails implements ICraftingPatternDetails, Comparable {
- private final ItemStack patternItem;
private final CraftingInventory crafting = new CraftingInventory(new ContainerNull(), 3, 3);
private final CraftingInventory testFrame = new CraftingInventory(new ContainerNull(), 3, 3);
private final ItemStack correctOutput;
@@ -53,79 +54,73 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable failCache = new HashSet<>();
private final Set passCache = new HashSet<>();
private final IAEItemStack pattern;
private int priority = 0;
- public PatternHelper(final ItemStack is, final World w) {
- final CompoundNBT encodedValue = is.getTag();
+ public CraftingPatternDetails(final IAEItemStack is, final World w) {
+ Preconditions.checkArgument(is.getItem() instanceof EncodedPatternItem,
+ "itemStack is not a ICraftingPatternItem");
- if (encodedValue == null) {
- throw new IllegalArgumentException("No pattern here!");
- }
+ final EncodedPatternItem templateItem = (EncodedPatternItem) is.getItem();
+ final ItemStack itemStack = is.createItemStack();
- final ListNBT inTag = encodedValue.getList("in", 10);
- final ListNBT outTag = encodedValue.getList("out", 10);
- this.isCrafting = encodedValue.getBoolean("crafting");
+ final List ingredients = templateItem.getIngredients(itemStack);
+ final List products = templateItem.getProducts(itemStack);
+ final ResourceLocation recipeId = templateItem.getCraftingRecipeId(itemStack);
- this.canSubstitute = this.isCrafting && encodedValue.getBoolean("substitute");
- this.patternItem = is;
- this.pattern = AEItemStack.fromItemStack(is);
+ this.pattern = is.copy();
+ this.isCraftable = recipeId != null;
+ this.canSubstitute = templateItem.allowsSubstitution(itemStack);
final List in = new ArrayList<>();
final List out = new ArrayList<>();
- for (int x = 0; x < inTag.size(); x++) {
- CompoundNBT ingredient = inTag.getCompound(x);
- final ItemStack gs = ItemStack.read(ingredient);
-
- if (!ingredient.isEmpty() && gs.isEmpty()) {
- throw new IllegalArgumentException("No pattern here!");
- }
+ for (int x = 0; x < 9; x++) {
+ final IAEItemStack ais = ingredients.get(x);
+ final ItemStack gs = ais != null ? ais.createItemStack() : ItemStack.EMPTY;
this.crafting.setInventorySlotContents(x, gs);
- if (!gs.isEmpty() && (!this.isCrafting || !gs.hasTag())) {
+ if (!gs.isEmpty() && (!this.isCraftable) || !gs.hasTag()) {
this.markItemAs(x, gs, TestStatus.ACCEPT);
}
- in.add(Api.instance().storage().getStorageChannel(IItemStorageChannel.class).createStack(gs));
+ in.add(ais != null ? ais.copy() : null);
this.testFrame.setInventorySlotContents(x, gs);
}
- if (this.isCrafting) {
- this.standardRecipe = w.getRecipeManager().getRecipe(IRecipeType.CRAFTING, this.crafting, w).orElse(null);
+ if (this.isCraftable) {
+ IRecipe> recipe = w.getRecipeManager().getRecipes(IRecipeType.CRAFTING).get(recipeId);
- if (this.standardRecipe != null) {
- this.correctOutput = this.standardRecipe.getCraftingResult(this.crafting);
- out.add(Api.instance().storage().getStorageChannel(IItemStorageChannel.class)
- .createStack(this.correctOutput));
- } else {
- throw new IllegalStateException("No pattern here!");
+ if (recipe == null || recipe.getType() != IRecipeType.CRAFTING) {
+ throw new IllegalStateException("recipe id is not a crafting recipe");
}
+
+ this.standardRecipe = (ICraftingRecipe) recipe;
+ this.correctOutput = this.standardRecipe.getCraftingResult(this.crafting);
+
+ out.add(Api.instance().storage().getStorageChannel(IItemStorageChannel.class)
+ .createStack(this.correctOutput));
} else {
this.standardRecipe = null;
this.correctOutput = ItemStack.EMPTY;
- for (int x = 0; x < outTag.size(); x++) {
- CompoundNBT resultItemTag = outTag.getCompound(x);
- final ItemStack gs = ItemStack.read(resultItemTag);
-
- if (!resultItemTag.isEmpty() && gs.isEmpty()) {
- throw new IllegalArgumentException("No pattern here!");
- }
+ for (int x = 0; x < 3; x++) {
+ final IAEItemStack ais = products.get(x);
+ final ItemStack gs = ais.createItemStack();
if (!gs.isEmpty()) {
- out.add(Api.instance().storage().getStorageChannel(IItemStorageChannel.class).createStack(gs));
+ out.add(ais.copy());
}
}
}
- this.outputs = out.toArray(new IAEItemStack[0]);
this.inputs = in.toArray(new IAEItemStack[0]);
+ this.outputs = out.toArray(new IAEItemStack[0]);
final Map tmpOutputs = new HashMap<>();
@@ -190,12 +185,12 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable();
- }
-
- this.craftingList.add(details);
+ if (details != null) {
+ if (this.craftingList == null) {
+ this.craftingList = new ArrayList<>();
}
+
+ this.craftingList.add(details);
}
}
diff --git a/src/main/java/appeng/items/misc/EncodedPatternItem.java b/src/main/java/appeng/items/misc/EncodedPatternItem.java
index 41dd4b3df..9009a35ff 100644
--- a/src/main/java/appeng/items/misc/EncodedPatternItem.java
+++ b/src/main/java/appeng/items/misc/EncodedPatternItem.java
@@ -18,37 +18,50 @@
package appeng.items.misc;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
+import com.google.common.base.Preconditions;
+
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemUseContext;
+import net.minecraft.nbt.CompoundNBT;
+import net.minecraft.nbt.INBT;
+import net.minecraft.nbt.ListNBT;
import net.minecraft.util.ActionResult;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Hand;
+import net.minecraft.util.ResourceLocation;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.text.TextFormatting;
import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
+import net.minecraftforge.common.util.Constants;
-import appeng.api.implementations.ICraftingPatternItem;
import appeng.api.networking.crafting.ICraftingPatternDetails;
+import appeng.api.storage.channels.IItemStorageChannel;
import appeng.api.storage.data.IAEItemStack;
import appeng.core.Api;
import appeng.core.AppEng;
import appeng.core.localization.GuiText;
import appeng.helpers.InvalidPatternHelper;
-import appeng.helpers.PatternHelper;
import appeng.items.AEBaseItem;
import appeng.util.Platform;
-public class EncodedPatternItem extends AEBaseItem implements ICraftingPatternItem {
+public class EncodedPatternItem extends AEBaseItem {
+
+ public static final String NBT_INGREDIENTS = "in";
+ public static final String NBT_PRODUCTS = "out";
+ public static final String NBT_SUBSITUTE = "substitute";
+ public static final String NBT_RECIPE_ID = "recipe";
+
// rather simple client side caching.
private static final Map SIMPLE_CACHE = new WeakHashMap<>();
@@ -95,7 +108,7 @@ public class EncodedPatternItem extends AEBaseItem implements ICraftingPatternIt
@OnlyIn(Dist.CLIENT)
public void addInformation(final ItemStack stack, final World world, final List lines,
final ITooltipFlag advancedTooltips) {
- final ICraftingPatternDetails details = this.getPatternForItem(stack, world);
+ final ICraftingPatternDetails details = Api.instance().crafting().decodePattern(stack, world);
if (details == null) {
if (!stack.hasTag()) {
@@ -181,15 +194,6 @@ public class EncodedPatternItem extends AEBaseItem implements ICraftingPatternIt
}
}
- @Override
- public ICraftingPatternDetails getPatternForItem(final ItemStack is, final World w) {
- try {
- return new PatternHelper(is, w);
- } catch (final Throwable t) {
- return null;
- }
- }
-
public ItemStack getOutput(final ItemStack item) {
ItemStack out = SIMPLE_CACHE.get(item);
@@ -202,11 +206,127 @@ public class EncodedPatternItem extends AEBaseItem implements ICraftingPatternIt
return ItemStack.EMPTY;
}
- final ICraftingPatternDetails details = this.getPatternForItem(item, w);
+ final ICraftingPatternDetails details = Api.instance().crafting().decodePattern(item, w);
out = details != null ? details.getOutputs()[0].createItemStack() : ItemStack.EMPTY;
SIMPLE_CACHE.put(item, out);
return out;
}
+
+ public boolean isEncodedPattern(ItemStack itemStack) {
+ return itemStack != null && !itemStack.isEmpty() && itemStack.getItem() == this && itemStack.getTag() != null
+ && itemStack.getTag().contains(NBT_INGREDIENTS, Constants.NBT.TAG_LIST)
+ && itemStack.getTag().contains(NBT_PRODUCTS, Constants.NBT.TAG_LIST);
+ }
+
+ public ResourceLocation getCraftingRecipeId(ItemStack itemStack) {
+ Preconditions.checkArgument(itemStack.getItem() == this, "Given item stack %s is not an encoded pattern.",
+ itemStack);
+ final CompoundNBT tag = itemStack.getTag();
+ Preconditions.checkArgument(tag != null, "itemStack missing a NBT tag");
+
+ return new ResourceLocation(tag.getString(NBT_RECIPE_ID));
+ }
+
+ public List getIngredients(ItemStack itemStack) {
+ Preconditions.checkArgument(itemStack.getItem() == this, "Given item stack %s is not an encoded pattern.",
+ itemStack);
+ final CompoundNBT tag = itemStack.getTag();
+ Preconditions.checkArgument(tag != null, "itemStack missing a NBT tag");
+
+ final ListNBT inTag = tag.getList(NBT_INGREDIENTS, 10);
+ Preconditions.checkArgument(inTag.size() < 10, "Cannot use more than 9 ingredients");
+
+ final List in = new ArrayList<>(inTag.size());
+ for (int x = 0; x < inTag.size(); x++) {
+ CompoundNBT ingredient = inTag.getCompound(x);
+ final ItemStack gs = ItemStack.read(ingredient);
+
+ Preconditions.checkArgument(!(!ingredient.isEmpty() && gs.isEmpty()), "invalid itemStack in slot", x);
+
+ in.add(Api.instance().storage().getStorageChannel(IItemStorageChannel.class).createStack(gs));
+ }
+
+ return in;
+ }
+
+ public List getProducts(ItemStack itemStack) {
+ Preconditions.checkArgument(itemStack.getItem() == this, "Given item stack %s is not an encoded pattern.",
+ itemStack);
+ final CompoundNBT tag = itemStack.getTag();
+ Preconditions.checkArgument(tag != null, "itemStack missing a NBT tag");
+
+ final ListNBT outTag = tag.getList(NBT_PRODUCTS, 10);
+ Preconditions.checkArgument(outTag.size() < 4, "Cannot use more than 3 ingredients");
+
+ final List out = new ArrayList<>(outTag.size());
+ for (int x = 0; x < outTag.size(); x++) {
+ CompoundNBT ingredient = outTag.getCompound(x);
+ final ItemStack gs = ItemStack.read(ingredient);
+
+ Preconditions.checkArgument(!(!ingredient.isEmpty() && gs.isEmpty()), "invalid itemStack in slot", x);
+
+ out.add(Api.instance().storage().getStorageChannel(IItemStorageChannel.class).createStack(gs));
+ }
+
+ return out;
+
+ }
+
+ public boolean allowsSubstitution(ItemStack itemStack) {
+ final CompoundNBT tag = itemStack.getTag();
+
+ Preconditions.checkArgument(tag != null, "itemStack missing a NBT tag");
+
+ return getCraftingRecipeId(itemStack) == null && tag.getBoolean(NBT_SUBSITUTE);
+ }
+
+ /**
+ * Use the public API instead {@link appeng.core.api.ApiCrafting}
+ */
+ public static void encodeCraftingPattern(ItemStack stack, ItemStack[] in, ItemStack[] out,
+ ResourceLocation recipeId, boolean allowSubstitutes) {
+ CompoundNBT encodedValue = encodeInputsAndOutputs(in, out);
+ encodedValue.putString(EncodedPatternItem.NBT_RECIPE_ID, recipeId.toString());
+ encodedValue.putBoolean(EncodedPatternItem.NBT_SUBSITUTE, allowSubstitutes);
+ stack.setTag(encodedValue);
+ }
+
+ /**
+ * Use the public API instead {@link appeng.core.api.ApiCrafting}
+ */
+ public static void encodeProcessingPattern(ItemStack stack, ItemStack[] in, ItemStack[] out) {
+ stack.setTag(encodeInputsAndOutputs(in, out));
+ }
+
+ private static CompoundNBT encodeInputsAndOutputs(ItemStack[] in, ItemStack[] out) {
+ final CompoundNBT encodedValue = new CompoundNBT();
+
+ final ListNBT tagIn = new ListNBT();
+ final ListNBT tagOut = new ListNBT();
+
+ for (final ItemStack i : in) {
+ tagIn.add(createItemTag(i));
+ }
+
+ for (final ItemStack i : out) {
+ tagOut.add(createItemTag(i));
+ }
+
+ encodedValue.put(EncodedPatternItem.NBT_INGREDIENTS, tagIn);
+ encodedValue.put(EncodedPatternItem.NBT_PRODUCTS, tagOut);
+ return encodedValue;
+ }
+
+ private static INBT createItemTag(final ItemStack i) {
+ final CompoundNBT c = new CompoundNBT();
+
+ if (!i.isEmpty()) {
+ i.write(c);
+ }
+
+ return c;
+ }
+
}
diff --git a/src/main/java/appeng/me/cache/CraftingGridCache.java b/src/main/java/appeng/me/cache/CraftingGridCache.java
index 5452970ac..26cac7e84 100644
--- a/src/main/java/appeng/me/cache/CraftingGridCache.java
+++ b/src/main/java/appeng/me/cache/CraftingGridCache.java
@@ -35,6 +35,7 @@ import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
+import com.google.common.base.Preconditions;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
@@ -80,6 +81,7 @@ import appeng.crafting.CraftingJob;
import appeng.crafting.CraftingLink;
import appeng.crafting.CraftingLinkNexus;
import appeng.crafting.CraftingWatcher;
+import appeng.helpers.CraftingPatternDetails;
import appeng.me.cluster.implementations.CraftingCPUCluster;
import appeng.me.helpers.BaseActionSource;
import appeng.me.helpers.GenericInterestManager;
@@ -303,6 +305,8 @@ public class CraftingGridCache
@Override
public void addCraftingOption(final ICraftingMedium medium, final ICraftingPatternDetails api) {
+ Preconditions.checkArgument(api.getClass() == CraftingPatternDetails.class,
+ "Only supports internal ICraftingPatternDetails for now");
List details = this.craftingMethods.get(api);
if (details == null) {
details = new ArrayList<>();
diff --git a/src/main/java/appeng/me/cluster/implementations/CraftingCPUCluster.java b/src/main/java/appeng/me/cluster/implementations/CraftingCPUCluster.java
index 69fa1561c..5fb4428d9 100644
--- a/src/main/java/appeng/me/cluster/implementations/CraftingCPUCluster.java
+++ b/src/main/java/appeng/me/cluster/implementations/CraftingCPUCluster.java
@@ -40,7 +40,7 @@ import net.minecraftforge.fml.hooks.BasicEventHooks;
import appeng.api.config.Actionable;
import appeng.api.config.FuzzyMode;
import appeng.api.config.PowerMultiplier;
-import appeng.api.implementations.ICraftingPatternItem;
+import appeng.api.crafting.ICraftingHelper;
import appeng.api.networking.IGrid;
import appeng.api.networking.IGridHost;
import appeng.api.networking.IGridNode;
@@ -1056,9 +1056,9 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU {
for (int x = 0; x < list.size(); x++) {
final CompoundNBT item = list.getCompound(x);
final IAEItemStack pattern = AEItemStack.fromNBT(item);
- if (pattern != null && pattern.getItem() instanceof ICraftingPatternItem) {
- final ICraftingPatternItem cpi = (ICraftingPatternItem) pattern.getItem();
- final ICraftingPatternDetails details = cpi.getPatternForItem(pattern.createItemStack(),
+ ICraftingHelper craftingHelper = Api.instance().crafting();
+ if (craftingHelper.isEncodedPattern(pattern)) {
+ final ICraftingPatternDetails details = craftingHelper.decodePattern(pattern.createItemStack(),
this.getWorld());
if (details != null) {
final TaskProgress tp = new TaskProgress();
diff --git a/src/main/java/appeng/parts/reporting/PatternTerminalPart.java b/src/main/java/appeng/parts/reporting/PatternTerminalPart.java
index 89ab7a99d..4576b158d 100644
--- a/src/main/java/appeng/parts/reporting/PatternTerminalPart.java
+++ b/src/main/java/appeng/parts/reporting/PatternTerminalPart.java
@@ -28,12 +28,12 @@ import net.minecraft.util.ResourceLocation;
import net.minecraftforge.items.IItemHandler;
import appeng.api.config.SecurityPermissions;
-import appeng.api.implementations.ICraftingPatternItem;
import appeng.api.networking.crafting.ICraftingPatternDetails;
import appeng.api.parts.IPartModel;
import appeng.api.storage.data.IAEItemStack;
import appeng.container.implementations.MEMonitorableContainer;
import appeng.container.implementations.PatternTermContainer;
+import appeng.core.Api;
import appeng.core.AppEng;
import appeng.helpers.Reflected;
import appeng.items.parts.PartModels;
@@ -107,23 +107,20 @@ public class PatternTerminalPart extends AbstractTerminalPart {
final ItemStack removedStack, final ItemStack newStack) {
if (inv == this.pattern && slot == 1) {
final ItemStack is = this.pattern.getStackInSlot(1);
- if (!is.isEmpty() && is.getItem() instanceof ICraftingPatternItem) {
- final ICraftingPatternItem pattern = (ICraftingPatternItem) is.getItem();
- final ICraftingPatternDetails details = pattern.getPatternForItem(is,
- this.getHost().getTile().getWorld());
- if (details != null) {
- this.setCraftingRecipe(details.isCraftable());
- this.setSubstitution(details.canSubstitute());
+ final ICraftingPatternDetails details = Api.instance().crafting().decodePattern(is,
+ this.getHost().getTile().getWorld());
+ if (details != null) {
+ this.setCraftingRecipe(details.isCraftable());
+ this.setSubstitution(details.canSubstitute());
- for (int x = 0; x < this.crafting.getSlots() && x < details.getInputs().length; x++) {
- final IAEItemStack item = details.getInputs()[x];
- this.crafting.setStackInSlot(x, item == null ? ItemStack.EMPTY : item.createItemStack());
- }
+ for (int x = 0; x < this.crafting.getSlots() && x < details.getInputs().length; x++) {
+ final IAEItemStack item = details.getInputs()[x];
+ this.crafting.setStackInSlot(x, item == null ? ItemStack.EMPTY : item.createItemStack());
+ }
- for (int x = 0; x < this.output.getSlots() && x < details.getOutputs().length; x++) {
- final IAEItemStack item = details.getOutputs()[x];
- this.output.setStackInSlot(x, item == null ? ItemStack.EMPTY : item.createItemStack());
- }
+ for (int x = 0; x < this.output.getSlots() && x < details.getOutputs().length; x++) {
+ final IAEItemStack item = details.getOutputs()[x];
+ this.output.setStackInSlot(x, item == null ? ItemStack.EMPTY : item.createItemStack());
}
}
} else if (inv == this.crafting) {
diff --git a/src/main/java/appeng/tile/crafting/MolecularAssemblerTileEntity.java b/src/main/java/appeng/tile/crafting/MolecularAssemblerTileEntity.java
index 96bfd73f8..be9211259 100644
--- a/src/main/java/appeng/tile/crafting/MolecularAssemblerTileEntity.java
+++ b/src/main/java/appeng/tile/crafting/MolecularAssemblerTileEntity.java
@@ -226,8 +226,7 @@ public class MolecularAssemblerTileEntity extends AENetworkInvTileEntity
if (!myPat.isEmpty() && myPat.getItem() instanceof EncodedPatternItem) {
final World w = this.getWorld();
- final EncodedPatternItem iep = (EncodedPatternItem) myPat.getItem();
- final ICraftingPatternDetails ph = iep.getPatternForItem(myPat, w);
+ final ICraftingPatternDetails ph = Api.instance().crafting().decodePattern(myPat, w);
if (ph != null && ph.isCraftable()) {
this.forcePlan = true;
this.myPlan = ph;
@@ -253,8 +252,7 @@ public class MolecularAssemblerTileEntity extends AENetworkInvTileEntity
if (!is.isEmpty() && is.getItem() instanceof EncodedPatternItem) {
if (!ItemStack.areItemsEqual(is, this.myPattern)) {
final World w = this.getWorld();
- final EncodedPatternItem iep = (EncodedPatternItem) is.getItem();
- final ICraftingPatternDetails ph = iep.getPatternForItem(is, w);
+ final ICraftingPatternDetails ph = Api.instance().crafting().decodePattern(is, w);
if (ph != null && ph.isCraftable()) {
this.progress = 0;
diff --git a/src/main/java/team/chisel/ctm/api/IFacade.java b/src/main/java/team/chisel/ctm/api/IFacade.java
index 710a3a250..9d17bd055 100644
--- a/src/main/java/team/chisel/ctm/api/IFacade.java
+++ b/src/main/java/team/chisel/ctm/api/IFacade.java
@@ -10,12 +10,14 @@ import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
/**
- * To be implemented on blocks that "hide" another block inside, so connected textures can still be accomplished.
+ * To be implemented on blocks that "hide" another block inside, so connected
+ * textures can still be accomplished.
*/
public interface IFacade {
/**
- * @deprecated Use {@link #getFacade(IBlockReader, BlockPos, Direction, BlockPos)}
+ * @deprecated Use
+ * {@link #getFacade(IBlockReader, BlockPos, Direction, BlockPos)}
*/
@Nonnull
@Deprecated
@@ -24,20 +26,18 @@ public interface IFacade {
/**
* Gets the blockstate this facade appears as.
*
- * @param world
- * {@link World}
- * @param pos
- * The Blocks position
- * @param side
- * The side being rendered, NOT the side being connected from.
- *
- * This value can be null if no side is specified. Please handle this appropriately.
- * @param connection
- * The position of the block being connected to.
+ * @param world {@link World}
+ * @param pos The Blocks position
+ * @param side The side being rendered, NOT the side being connected from.
+ *
+ * This value can be null if no side is specified. Please
+ * handle this appropriately.
+ * @param connection The position of the block being connected to.
* @return The blockstate which your block appears as.
*/
@Nonnull
- default BlockState getFacade(@Nonnull IBlockReader world, @Nonnull BlockPos pos, @Nullable Direction side, @Nonnull BlockPos connection) {
+ default BlockState getFacade(@Nonnull IBlockReader world, @Nonnull BlockPos pos, @Nullable Direction side,
+ @Nonnull BlockPos connection) {
return getFacade(world, pos, side);
}