Refactored crafting patterns (#4458)
* Deduplicate crafting patterns internals This should save a bit memory for duplicate patterns as well as speed up loading new patterns on reloading chunks. * Encode recipe id in pattern * Use the recipe id directly for looking it up * Slightly refactored how patterns encode whether they are crafting patterns or not. * Renamed PatternHelper. * Added APIs to encode patterns. (#4463) * Removed ICraftingPatternItem. * Renamed isCrafting to isCraftable Co-authored-by: shartte <shartte@users.noreply.github.com>
This commit is contained in:
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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.
|
||||
* <p>
|
||||
* 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);
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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}.
|
||||
* <p>
|
||||
* 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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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<CraftingInventory> 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<ItemStack> 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
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
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<IAEItemStack> ingredients = patternItem.getIngredients(itemStack);
|
||||
List<IAEItemStack> 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -101,7 +101,7 @@ public class CraftRequestPacket extends BasePacket {
|
||||
if (futureJob != null) {
|
||||
futureJob.cancel(true);
|
||||
}
|
||||
AELog.debug(e);
|
||||
AELog.info(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+44
-49
@@ -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<PatternHelper> {
|
||||
public class CraftingPatternDetails implements ICraftingPatternDetails, Comparable<CraftingPatternDetails> {
|
||||
|
||||
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<Patter
|
||||
private final IAEItemStack[] condensedOutputs;
|
||||
private final IAEItemStack[] inputs;
|
||||
private final IAEItemStack[] outputs;
|
||||
private final boolean isCrafting;
|
||||
private final boolean isCraftable;
|
||||
private final boolean canSubstitute;
|
||||
private final Set<TestLookup> failCache = new HashSet<>();
|
||||
private final Set<TestLookup> 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<IAEItemStack> ingredients = templateItem.getIngredients(itemStack);
|
||||
final List<IAEItemStack> 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<IAEItemStack> in = new ArrayList<>();
|
||||
final List<IAEItemStack> 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<IAEItemStack, IAEItemStack> tmpOutputs = new HashMap<>();
|
||||
|
||||
@@ -190,12 +185,12 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable<Patter
|
||||
|
||||
@Override
|
||||
public ItemStack getPattern() {
|
||||
return this.patternItem;
|
||||
return this.pattern.createItemStack();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isValidItemForSlot(final int slotIndex, final ItemStack i, final World w) {
|
||||
if (!this.isCrafting) {
|
||||
if (!this.isCraftable) {
|
||||
throw new IllegalStateException("Only crafting recipes supported.");
|
||||
}
|
||||
|
||||
@@ -241,7 +236,7 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable<Patter
|
||||
|
||||
@Override
|
||||
public boolean isCraftable() {
|
||||
return this.isCrafting;
|
||||
return this.isCraftable;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -271,7 +266,7 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable<Patter
|
||||
|
||||
@Override
|
||||
public ItemStack getOutput(final CraftingInventory craftingInv, final World w) {
|
||||
if (!this.isCrafting) {
|
||||
if (!this.isCraftable) {
|
||||
throw new IllegalStateException("Only crafting recipes supported.");
|
||||
}
|
||||
|
||||
@@ -323,7 +318,7 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable<Patter
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(final PatternHelper o) {
|
||||
public int compareTo(final CraftingPatternDetails o) {
|
||||
return Integer.compare(o.priority, this.priority);
|
||||
}
|
||||
|
||||
@@ -341,7 +336,7 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable<Patter
|
||||
return false;
|
||||
}
|
||||
|
||||
final PatternHelper other = (PatternHelper) obj;
|
||||
final CraftingPatternDetails other = (CraftingPatternDetails) obj;
|
||||
|
||||
if (this.pattern != null && other.pattern != null) {
|
||||
return this.pattern.equals(other.pattern);
|
||||
@@ -57,7 +57,6 @@ import appeng.api.config.Actionable;
|
||||
import appeng.api.config.Settings;
|
||||
import appeng.api.config.Upgrades;
|
||||
import appeng.api.config.YesNo;
|
||||
import appeng.api.implementations.ICraftingPatternItem;
|
||||
import appeng.api.implementations.IUpgradeableHost;
|
||||
import appeng.api.implementations.tiles.ICraftingMachine;
|
||||
import appeng.api.networking.GridFlags;
|
||||
@@ -407,21 +406,15 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
|
||||
}
|
||||
|
||||
private void addToCraftingList(final ItemStack is) {
|
||||
if (is.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
final ICraftingPatternDetails details = Api.instance().crafting().decodePattern(is,
|
||||
this.iHost.getTileEntity().getWorld());
|
||||
|
||||
if (is.getItem() instanceof ICraftingPatternItem) {
|
||||
final ICraftingPatternItem cpi = (ICraftingPatternItem) is.getItem();
|
||||
final ICraftingPatternDetails details = cpi.getPatternForItem(is, this.iHost.getTileEntity().getWorld());
|
||||
|
||||
if (details != null) {
|
||||
if (this.craftingList == null) {
|
||||
this.craftingList = new ArrayList<>();
|
||||
}
|
||||
|
||||
this.craftingList.add(details);
|
||||
if (details != null) {
|
||||
if (this.craftingList == null) {
|
||||
this.craftingList = new ArrayList<>();
|
||||
}
|
||||
|
||||
this.craftingList.add(details);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<ItemStack, ItemStack> 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<ITextComponent> 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<IAEItemStack> 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<IAEItemStack> 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<IAEItemStack> 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<IAEItemStack> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<ICraftingMedium> details = this.craftingMethods.get(api);
|
||||
if (details == null) {
|
||||
details = new ArrayList<>();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user