0fdc46b358
# Conflicts: # gradle.properties # gradle/wrapper/gradle-wrapper.jar # gradle/wrapper/gradle-wrapper.properties # src/api/java/appeng/api/features/IWorldGen.java # src/api/java/appeng/api/implementations/items/ISpatialStorageCell.java # src/api/java/appeng/api/parts/IPart.java # src/api/java/appeng/api/storage/ISpatialDimension.java # src/api/java/appeng/api/util/DimensionalCoord.java # src/datagen/java/appeng/data/providers/IAE2DataProvider.java # src/main/java/appeng/block/AEBaseBlockItemChargeable.java # src/main/java/appeng/block/misc/ChargerBlock.java # src/main/java/appeng/block/misc/QuartzFixtureBlock.java # src/main/java/appeng/block/networking/CableBusBlock.java # src/main/java/appeng/block/networking/CableBusColor.java # src/main/java/appeng/block/networking/ControllerBlock.java # src/main/java/appeng/block/networking/WirelessBlock.java # src/main/java/appeng/block/paint/PaintSplotchesBakedModel.java # src/main/java/appeng/block/paint/PaintSplotchesModel.java # src/main/java/appeng/block/qnb/QnbFormedBakedModel.java # src/main/java/appeng/block/qnb/QnbFormedModel.java # src/main/java/appeng/block/spatial/MatrixFrameBlock.java # src/main/java/appeng/block/storage/ChestBlock.java # src/main/java/appeng/block/storage/DriveSlotState.java # src/main/java/appeng/client/gui/AEBaseMEScreen.java # src/main/java/appeng/client/gui/AEBaseScreen.java # src/main/java/appeng/client/gui/implementations/AESubScreen.java # src/main/java/appeng/client/gui/implementations/CellWorkbenchScreen.java # src/main/java/appeng/client/gui/implementations/ChestScreen.java # src/main/java/appeng/client/gui/implementations/CondenserScreen.java # src/main/java/appeng/client/gui/implementations/CraftAmountScreen.java # src/main/java/appeng/client/gui/implementations/CraftConfirmScreen.java # src/main/java/appeng/client/gui/implementations/CraftingCPUScreen.java # src/main/java/appeng/client/gui/implementations/CraftingStatusScreen.java # src/main/java/appeng/client/gui/implementations/CraftingTermScreen.java # src/main/java/appeng/client/gui/implementations/DriveScreen.java # src/main/java/appeng/client/gui/implementations/FormationPlaneScreen.java # src/main/java/appeng/client/gui/implementations/GrinderScreen.java # src/main/java/appeng/client/gui/implementations/IOPortScreen.java # src/main/java/appeng/client/gui/implementations/InscriberScreen.java # src/main/java/appeng/client/gui/implementations/InterfaceScreen.java # src/main/java/appeng/client/gui/implementations/InterfaceTerminalScreen.java # src/main/java/appeng/client/gui/implementations/LevelEmitterScreen.java # src/main/java/appeng/client/gui/implementations/MEMonitorableScreen.java # src/main/java/appeng/client/gui/implementations/MolecularAssemblerScreen.java # src/main/java/appeng/client/gui/implementations/NetworkStatusScreen.java # src/main/java/appeng/client/gui/implementations/NetworkToolScreen.java # src/main/java/appeng/client/gui/implementations/NumberEntryWidget.java # src/main/java/appeng/client/gui/implementations/PatternTermScreen.java # src/main/java/appeng/client/gui/implementations/PriorityScreen.java # src/main/java/appeng/client/gui/implementations/QNBScreen.java # src/main/java/appeng/client/gui/implementations/QuartzKnifeScreen.java # src/main/java/appeng/client/gui/implementations/SecurityStationScreen.java # src/main/java/appeng/client/gui/implementations/SkyChestScreen.java # src/main/java/appeng/client/gui/implementations/SpatialIOPortScreen.java # src/main/java/appeng/client/gui/implementations/StorageBusScreen.java # src/main/java/appeng/client/gui/implementations/UpgradeableScreen.java # src/main/java/appeng/client/gui/implementations/VibrationChamberScreen.java # src/main/java/appeng/client/gui/implementations/WirelessScreen.java # src/main/java/appeng/client/gui/widgets/AETextField.java # src/main/java/appeng/client/gui/widgets/CustomSlotWidget.java # src/main/java/appeng/client/gui/widgets/ITooltip.java # src/main/java/appeng/client/gui/widgets/IconButton.java # src/main/java/appeng/client/gui/widgets/NumberBox.java # src/main/java/appeng/client/gui/widgets/ProgressBar.java # src/main/java/appeng/client/gui/widgets/TabButton.java # src/main/java/appeng/client/gui/widgets/ToggleButton.java # src/main/java/appeng/client/render/ColorableTileBlockColor.java # src/main/java/appeng/client/render/DummyFluidDispatcherBakedModel.java # src/main/java/appeng/client/render/FacadeItemModel.java # src/main/java/appeng/client/render/FacingToRotation.java # src/main/java/appeng/client/render/SpatialSkyRender.java # src/main/java/appeng/client/render/StackSizeRenderer.java # src/main/java/appeng/client/render/StaticBlockColor.java # src/main/java/appeng/client/render/TesrRenderHelper.java # src/main/java/appeng/client/render/cablebus/CableBuilder.java # src/main/java/appeng/client/render/cablebus/CableBusBreakingParticle.java # src/main/java/appeng/client/render/cablebus/CableBusModel.java # src/main/java/appeng/client/render/cablebus/CableBusRenderState.java # src/main/java/appeng/client/render/cablebus/CableCoreType.java # src/main/java/appeng/client/render/cablebus/CubeBuilder.java # src/main/java/appeng/client/render/cablebus/FacadeBlockAccess.java # src/main/java/appeng/client/render/cablebus/FacadeBuilder.java # src/main/java/appeng/client/render/cablebus/P2PTunnelFrequencyModel.java # src/main/java/appeng/client/render/cablebus/QuadRotator.java # src/main/java/appeng/client/render/cablebus/SmartCableTextures.java # src/main/java/appeng/client/render/crafting/CraftingCubeModel.java # src/main/java/appeng/client/render/crafting/EncodedPatternBakedModel.java # src/main/java/appeng/client/render/crafting/EncodedPatternModel.java # src/main/java/appeng/client/render/effects/CraftingFx.java # src/main/java/appeng/client/render/effects/EnergyFx.java # src/main/java/appeng/client/render/effects/LightningArcParticleData.java # src/main/java/appeng/client/render/effects/LightningFX.java # src/main/java/appeng/client/render/effects/MatterCannonFX.java # src/main/java/appeng/client/render/effects/VibrantFX.java # src/main/java/appeng/client/render/model/AutoRotatingBakedModel.java # src/main/java/appeng/client/render/model/BiometricCardModel.java # src/main/java/appeng/client/render/model/ColorApplicatorModel.java # src/main/java/appeng/client/render/model/DriveBakedModel.java # src/main/java/appeng/client/render/model/DriveModel.java # src/main/java/appeng/client/render/model/GlassBakedModel.java # src/main/java/appeng/client/render/model/GlassModel.java # src/main/java/appeng/client/render/model/MatrixVertexTransformer.java # src/main/java/appeng/client/render/model/MemoryCardModel.java # src/main/java/appeng/client/render/model/RenderHelper.java # src/main/java/appeng/client/render/model/SkyCompassBakedModel.java # src/main/java/appeng/client/render/model/SkyCompassModel.java # src/main/java/appeng/client/render/renderable/ItemRenderable.java # src/main/java/appeng/client/render/spatial/SpatialPylonModel.java # src/main/java/appeng/client/render/tesr/CellLedRenderer.java # src/main/java/appeng/client/render/tesr/CrankTESR.java # src/main/java/appeng/client/render/tesr/DriveLedTileEntityRenderer.java # src/main/java/appeng/client/render/tesr/InscriberTESR.java # src/main/java/appeng/client/render/tesr/SkyChestTESR.java # src/main/java/appeng/container/implementations/PatternTermContainer.java # src/main/java/appeng/core/AEConfig.java # src/main/java/appeng/core/AppEng.java # src/main/java/appeng/core/Registration.java # src/main/java/appeng/core/features/registries/MovableTileRegistry.java # src/main/java/appeng/core/features/registries/WorldGenRegistry.java # src/main/java/appeng/core/localization/GuiText.java # src/main/java/appeng/core/sync/BasePacket.java # src/main/java/appeng/core/sync/network/NetworkHandler.java # src/main/java/appeng/core/sync/network/TargetPoint.java # src/main/java/appeng/core/sync/packets/ClickPacket.java # src/main/java/appeng/core/sync/packets/ConfigValuePacket.java # src/main/java/appeng/core/worlddata/WorldData.java # src/main/java/appeng/crafting/CraftingTreeProcess.java # src/main/java/appeng/datagen/AE2DataGenerators.java # src/main/java/appeng/datagen/providers/IAE2DataProvider.java # src/main/java/appeng/datagen/providers/loot/BlockDropProvider.java # src/main/java/appeng/datagen/providers/recipes/SlabStairRecipes.java # src/main/java/appeng/debug/ChunkLoaderBlockEntity.java # src/main/java/appeng/debug/DebugPartPlacerItem.java # src/main/java/appeng/debug/ReplicatorCardItem.java # src/main/java/appeng/entity/TinyTNTPrimedEntity.java # src/main/java/appeng/entity/TinyTNTPrimedRenderer.java # src/main/java/appeng/fluids/client/gui/FluidFormationPlaneScreen.java # src/main/java/appeng/fluids/client/gui/FluidInterfaceScreen.java # src/main/java/appeng/fluids/client/gui/FluidLevelEmitterScreen.java # src/main/java/appeng/fluids/client/gui/FluidStorageBusScreen.java # src/main/java/appeng/fluids/client/gui/FluidTerminalScreen.java # src/main/java/appeng/fluids/client/gui/widgets/FluidSlotWidget.java # src/main/java/appeng/fluids/client/gui/widgets/FluidTankWidget.java # src/main/java/appeng/fluids/parts/FluidAnnihilationPlanePart.java # src/main/java/appeng/fluids/parts/FluidFormationPlanePart.java # src/main/java/appeng/fluids/parts/FluidInterfacePart.java # src/main/java/appeng/fluids/parts/FluidStorageBusPart.java # src/main/java/appeng/fluids/parts/SharedFluidBusPart.java # src/main/java/appeng/forge/data/providers/IAE2DataProvider.java # src/main/java/appeng/helpers/AEMaterials.java # src/main/java/appeng/helpers/CraftingPatternDetails.java # src/main/java/appeng/helpers/DualityInterface.java # src/main/java/appeng/helpers/Splotch.java # src/main/java/appeng/integration/modules/jei/CondenserCategory.java # src/main/java/appeng/integration/modules/theoneprobe/part/ChannelInfoProvider.java # src/main/java/appeng/integration/modules/theoneprobe/part/P2PStateInfoProvider.java # src/main/java/appeng/integration/modules/theoneprobe/part/PowerStateInfoProvider.java # src/main/java/appeng/integration/modules/theoneprobe/tile/ChargerInfoProvider.java # src/main/java/appeng/integration/modules/theoneprobe/tile/CraftingMonitorInfoProvider.java # src/main/java/appeng/integration/modules/theoneprobe/tile/PowerStorageInfoProvider.java # src/main/java/appeng/integration/modules/waila/part/PartAccessor.java # src/main/java/appeng/integration/modules/waila/part/PartStackWailaDataProvider.java # src/main/java/appeng/integration/modules/waila/part/StorageMonitorWailaDataProvider.java # src/main/java/appeng/integration/modules/waila/tile/PowerStateWailaDataProvider.java # src/main/java/appeng/items/misc/EncodedPatternItem.java # src/main/java/appeng/items/parts/FacadeItem.java # src/main/java/appeng/items/storage/SpatialStorageCellItem.java # src/main/java/appeng/items/tools/BiometricCardItem.java # src/main/java/appeng/items/tools/MemoryCardItem.java # src/main/java/appeng/items/tools/powered/ColorApplicatorItem.java # src/main/java/appeng/items/tools/powered/MatterCannonItem.java # src/main/java/appeng/items/tools/quartz/QuartzCuttingKnifeItem.java # src/main/java/appeng/items/tools/quartz/QuartzHoeItem.java # src/main/java/appeng/me/cluster/MBCalculator.java # src/main/java/appeng/me/cluster/implementations/QuantumCluster.java # src/main/java/appeng/parts/AEBasePart.java # src/main/java/appeng/parts/CableBusContainer.java # src/main/java/appeng/parts/ICableBusContainer.java # src/main/java/appeng/parts/NullCableBusContainer.java # src/main/java/appeng/parts/PartPlacement.java # src/main/java/appeng/parts/automation/AnnihilationPlanePart.java # src/main/java/appeng/parts/automation/ExportBusPart.java # src/main/java/appeng/parts/automation/FormationPlanePart.java # src/main/java/appeng/parts/automation/ImportBusPart.java # src/main/java/appeng/parts/automation/PlaneModel.java # src/main/java/appeng/parts/misc/CableAnchorPart.java # src/main/java/appeng/parts/misc/InterfacePart.java # src/main/java/appeng/parts/misc/StorageBusPart.java # src/main/java/appeng/parts/p2p/P2PTunnelPart.java # src/main/java/appeng/parts/reporting/AbstractMonitorPart.java # src/main/java/appeng/parts/reporting/AbstractReportingPart.java # src/main/java/appeng/parts/reporting/AbstractTerminalPart.java # src/main/java/appeng/parts/reporting/ConversionMonitorPart.java # src/main/java/appeng/parts/reporting/InterfaceTerminalPart.java # src/main/java/appeng/parts/reporting/PatternTerminalPart.java # src/main/java/appeng/recipes/handlers/GrinderRecipeSerializer.java # src/main/java/appeng/recipes/handlers/InscriberRecipeSerializer.java # src/main/java/appeng/server/subcommands/TestMeteoritesCommand.java # src/main/java/appeng/server/subcommands/TestOreGenCommand.java # src/main/java/appeng/services/CompassService.java # src/main/java/appeng/spatial/SpatialDimensionManager.java # src/main/java/appeng/spatial/StorageCellDimension.java # src/main/java/appeng/thirdparty/codechicken/lib/model/Quad.java # src/main/java/appeng/thirdparty/codechicken/lib/model/pipeline/transformers/QuadCornerKicker.java # src/main/java/appeng/thirdparty/codechicken/lib/model/pipeline/transformers/QuadMatrixTransformer.java # src/main/java/appeng/tile/AEBaseBlockEntity.java # src/main/java/appeng/tile/AEBaseInvTileEntity.java # src/main/java/appeng/tile/crafting/CraftingBlockEntity.java # src/main/java/appeng/tile/crafting/CraftingMonitorBlockEntity.java # src/main/java/appeng/tile/crafting/MolecularAssemblerBlockEntity.java # src/main/java/appeng/tile/grid/AENetworkBlockEntity.java # src/main/java/appeng/tile/grid/AENetworkInvBlockEntity.java # src/main/java/appeng/tile/grid/AENetworkPowerBlockEntity.java # src/main/java/appeng/tile/misc/CellWorkbenchBlockEntity.java # src/main/java/appeng/tile/misc/CondenserBlockEntity.java # src/main/java/appeng/tile/misc/InscriberBlockEntity.java # src/main/java/appeng/tile/misc/InterfaceBlockEntity.java # src/main/java/appeng/tile/misc/PaintSplotchesBlockEntity.java # src/main/java/appeng/tile/misc/SecurityStationBlockEntity.java # src/main/java/appeng/tile/misc/VibrationChamberBlockEntity.java # src/main/java/appeng/tile/networking/CableBusBlockEntity.java # src/main/java/appeng/tile/networking/EnergyCellBlockEntity.java # src/main/java/appeng/tile/powersink/AEBasePoweredBlockEntity.java # src/main/java/appeng/tile/spatial/SpatialIOPortBlockEntity.java # src/main/java/appeng/tile/storage/ChestBlockEntity.java # src/main/java/appeng/tile/storage/DriveBlockEntity.java # src/main/java/appeng/tile/storage/IOPortBlockEntity.java # src/main/java/appeng/util/Platform.java # src/main/java/appeng/worldgen/ChargedQuartzOreConfig.java # src/main/java/appeng/worldgen/ChargedQuartzOreFeature.java # src/main/java/appeng/worldgen/meteorite/MeteoriteStructure.java # src/main/java/appeng/worldgen/meteorite/MeteoriteStructureStart.java # src/main/java/appeng/worldgen/meteorite/debug/MeteoriteSpawner.java # src/unported/java/appeng/client/ClientHelper.java # src/unported/java/appeng/client/render/DummyFluidItemModel.java # src/unported/java/appeng/client/render/model/UVLModelLoader.java
372 lines
12 KiB
Java
372 lines
12 KiB
Java
/*
|
|
* This file is part of Applied Energistics 2.
|
|
* Copyright (c) 2013 - 2014, AlgorithmX2, 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.helpers;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.Collection;
|
|
import java.util.Comparator;
|
|
import java.util.HashSet;
|
|
import java.util.List;
|
|
import java.util.Objects;
|
|
import java.util.Set;
|
|
import java.util.function.Function;
|
|
import java.util.stream.Collectors;
|
|
|
|
import com.google.common.base.Preconditions;
|
|
import com.google.common.collect.ImmutableList;
|
|
|
|
import net.minecraft.inventory.CraftingInventory;
|
|
import net.minecraft.item.Item;
|
|
import net.minecraft.item.ItemStack;
|
|
import net.minecraft.recipe.CraftingRecipe;
|
|
import net.minecraft.recipe.Recipe;
|
|
import net.minecraft.recipe.RecipeType;
|
|
import net.minecraft.util.Identifier;
|
|
import net.minecraft.world.World;
|
|
|
|
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.Api;
|
|
import appeng.items.misc.EncodedPatternItem;
|
|
import appeng.util.Platform;
|
|
|
|
public class CraftingPatternDetails implements ICraftingPatternDetails, Comparable<CraftingPatternDetails> {
|
|
|
|
private static final int ALL_INPUT_LIMIT = 9;
|
|
private static final int CRAFTING_OUTPUT_LIMIT = 1;
|
|
private static final int PROCESSING_OUTPUT_LIMIT = 3;
|
|
|
|
private static final Comparator<IAEItemStack> COMPARE_BY_STACKSIZE = (left, right) -> Long
|
|
.compare(right.getStackSize(), left.getStackSize());
|
|
|
|
private final CraftingInventory crafting = new CraftingInventory(new ContainerNull(), 3, 3);
|
|
private final CraftingInventory testFrame = new CraftingInventory(new ContainerNull(), 3, 3);
|
|
private final ItemStack correctOutput;
|
|
private final CraftingRecipe standardRecipe;
|
|
private final List<IAEItemStack> inputs;
|
|
private final List<IAEItemStack> outputs;
|
|
private final IAEItemStack[] sparseInputs;
|
|
private final IAEItemStack[] sparseOutputs;
|
|
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 CraftingPatternDetails(final IAEItemStack is, final World w) {
|
|
Preconditions.checkArgument(is.getItem() instanceof EncodedPatternItem,
|
|
"itemStack is not a ICraftingPatternItem");
|
|
|
|
final EncodedPatternItem templateItem = (EncodedPatternItem) is.getItem();
|
|
final ItemStack itemStack = is.createItemStack();
|
|
|
|
final List<IAEItemStack> ingredients = templateItem.getIngredients(itemStack);
|
|
final List<IAEItemStack> products = templateItem.getProducts(itemStack);
|
|
final Identifier recipeId = templateItem.getCraftingRecipeId(itemStack);
|
|
|
|
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 < ALL_INPUT_LIMIT; x++) {
|
|
final IAEItemStack ais = ingredients.get(x);
|
|
final ItemStack gs = ais != null ? ais.createItemStack() : ItemStack.EMPTY;
|
|
|
|
this.crafting.setStack(x, gs);
|
|
|
|
if (!gs.isEmpty() && (!this.isCraftable) || !gs.hasTag()) {
|
|
this.markItemAs(x, gs, TestStatus.ACCEPT);
|
|
}
|
|
|
|
in.add(ais != null ? ais.copy() : null);
|
|
this.testFrame.setStack(x, gs);
|
|
}
|
|
|
|
if (this.isCraftable) {
|
|
Recipe<?> recipe = w.getRecipeManager().getAllOfType(RecipeType.CRAFTING).get(recipeId);
|
|
|
|
if (recipe == null || recipe.getType() != RecipeType.CRAFTING) {
|
|
throw new IllegalStateException("recipe id is not a crafting recipe");
|
|
}
|
|
|
|
this.standardRecipe = (CraftingRecipe) recipe;
|
|
this.correctOutput = this.standardRecipe.craft(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 < PROCESSING_OUTPUT_LIMIT; x++) {
|
|
final IAEItemStack ais = products.get(x);
|
|
|
|
out.add(ais != null ? ais.copy() : null);
|
|
}
|
|
}
|
|
|
|
final int outputLength = this.isCraftable ? CRAFTING_OUTPUT_LIMIT : PROCESSING_OUTPUT_LIMIT;
|
|
this.sparseInputs = in.toArray(new IAEItemStack[ALL_INPUT_LIMIT]);
|
|
this.sparseOutputs = out.toArray(new IAEItemStack[outputLength]);
|
|
|
|
this.inputs = this.condenseStacks(in);
|
|
this.outputs = this.condenseStacks(out);
|
|
}
|
|
|
|
private void markItemAs(final int slotIndex, final ItemStack i, final TestStatus b) {
|
|
if (b == TestStatus.TEST || i.hasTag()) {
|
|
return;
|
|
}
|
|
|
|
(b == TestStatus.ACCEPT ? this.passCache : this.failCache).add(new TestLookup(slotIndex, i));
|
|
}
|
|
|
|
@Override
|
|
public ItemStack getPattern() {
|
|
return this.pattern.createItemStack();
|
|
}
|
|
|
|
@Override
|
|
public synchronized boolean isValidItemForSlot(final int slotIndex, final ItemStack i, final World w) {
|
|
if (!this.isCraftable) {
|
|
throw new IllegalStateException("Only crafting recipes supported.");
|
|
}
|
|
|
|
final TestStatus result = this.getStatus(slotIndex, i);
|
|
|
|
switch (result) {
|
|
case ACCEPT:
|
|
return true;
|
|
case DECLINE:
|
|
return false;
|
|
case TEST:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
for (int x = 0; x < this.crafting.size(); x++) {
|
|
this.testFrame.setStack(x, this.crafting.getStack(x));
|
|
}
|
|
|
|
this.testFrame.setStack(slotIndex, i);
|
|
|
|
// If we cannot substitute, the items must match exactly
|
|
if (!canSubstitute && slotIndex < sparseInputs.length) {
|
|
if (!sparseInputs[slotIndex].isSameType(i)) {
|
|
this.markItemAs(slotIndex, i, TestStatus.DECLINE);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (this.standardRecipe.matches(this.testFrame, w)) {
|
|
final ItemStack testOutput = this.standardRecipe.craft(this.testFrame);
|
|
|
|
if (Platform.itemComparisons().isSameItem(this.correctOutput, testOutput)) {
|
|
this.testFrame.setStack(slotIndex, this.crafting.getStack(slotIndex));
|
|
this.markItemAs(slotIndex, i, TestStatus.ACCEPT);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
this.markItemAs(slotIndex, i, TestStatus.DECLINE);
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public boolean isCraftable() {
|
|
return this.isCraftable;
|
|
}
|
|
|
|
@Override
|
|
public IAEItemStack[] getSparseInputs() {
|
|
return this.sparseInputs;
|
|
}
|
|
|
|
@Override
|
|
public List<IAEItemStack> getInputs() {
|
|
return this.inputs;
|
|
}
|
|
|
|
@Override
|
|
public List<IAEItemStack> getOutputs() {
|
|
return this.outputs;
|
|
}
|
|
|
|
@Override
|
|
public IAEItemStack[] getSparseOutputs() {
|
|
return this.sparseOutputs;
|
|
}
|
|
|
|
@Override
|
|
public boolean canSubstitute() {
|
|
return this.canSubstitute;
|
|
}
|
|
|
|
@Override
|
|
public ItemStack getOutput(final CraftingInventory craftingInv, final World w) {
|
|
if (!this.isCraftable) {
|
|
throw new IllegalStateException("Only crafting recipes supported.");
|
|
}
|
|
|
|
for (int x = 0; x < craftingInv.size(); x++) {
|
|
if (!this.isValidItemForSlot(x, craftingInv.getStack(x), w)) {
|
|
return ItemStack.EMPTY;
|
|
}
|
|
}
|
|
|
|
if (this.sparseOutputs != null && this.sparseOutputs.length > 0) {
|
|
return this.sparseOutputs[0].createItemStack();
|
|
}
|
|
|
|
return ItemStack.EMPTY;
|
|
}
|
|
|
|
private TestStatus getStatus(final int slotIndex, final ItemStack i) {
|
|
if (this.crafting.getStack(slotIndex).isEmpty()) {
|
|
return i.isEmpty() ? TestStatus.ACCEPT : TestStatus.DECLINE;
|
|
}
|
|
|
|
if (i.isEmpty()) {
|
|
return TestStatus.DECLINE;
|
|
}
|
|
|
|
if (i.hasTag()) {
|
|
return TestStatus.TEST;
|
|
}
|
|
|
|
if (this.passCache.contains(new TestLookup(slotIndex, i))) {
|
|
return TestStatus.ACCEPT;
|
|
}
|
|
|
|
if (this.failCache.contains(new TestLookup(slotIndex, i))) {
|
|
return TestStatus.DECLINE;
|
|
}
|
|
|
|
return TestStatus.TEST;
|
|
}
|
|
|
|
@Override
|
|
public int getPriority() {
|
|
return this.priority;
|
|
}
|
|
|
|
@Override
|
|
public void setPriority(final int priority) {
|
|
this.priority = priority;
|
|
}
|
|
|
|
@Override
|
|
public int compareTo(final CraftingPatternDetails o) {
|
|
return Integer.compare(o.priority, this.priority);
|
|
}
|
|
|
|
@Override
|
|
public int hashCode() {
|
|
return this.pattern.hashCode();
|
|
}
|
|
|
|
@Override
|
|
public boolean equals(final Object obj) {
|
|
if (obj == null) {
|
|
return false;
|
|
}
|
|
if (this.getClass() != obj.getClass()) {
|
|
return false;
|
|
}
|
|
|
|
final CraftingPatternDetails other = (CraftingPatternDetails) obj;
|
|
|
|
if (this.pattern != null && other.pattern != null) {
|
|
return this.pattern.equals(other.pattern);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Merges all equal entries into a single one while adding their total stack
|
|
* sizes.
|
|
*
|
|
* @throws IllegalStateException if the result would be empty.
|
|
*
|
|
* @param collection the collection to condense
|
|
*
|
|
* @return a non empty list of condensed stacks.
|
|
*/
|
|
private List<IAEItemStack> condenseStacks(Collection<IAEItemStack> collection) {
|
|
final List<IAEItemStack> merged = collection.stream().filter(Objects::nonNull)
|
|
.collect(Collectors.toMap(Function.identity(), IAEItemStack::copy,
|
|
(left, right) -> left.setStackSize(left.getStackSize() + right.getStackSize())))
|
|
.values().stream().sorted(COMPARE_BY_STACKSIZE).collect(ImmutableList.toImmutableList());
|
|
|
|
if (merged.isEmpty()) {
|
|
throw new IllegalStateException("No pattern here!");
|
|
}
|
|
|
|
return merged;
|
|
}
|
|
|
|
private enum TestStatus {
|
|
ACCEPT, DECLINE, TEST
|
|
}
|
|
|
|
private static final class TestLookup {
|
|
|
|
private final int slot;
|
|
private final int ref;
|
|
private final int hash;
|
|
|
|
public TestLookup(final int slot, final ItemStack i) {
|
|
this(slot, i.getItem(), i.getDamage());
|
|
}
|
|
|
|
public TestLookup(final int slot, final Item item, final int dmg) {
|
|
this.slot = slot;
|
|
this.ref = (dmg << Platform.DEF_OFFSET) | (Item.getRawId(item) & 0xffff);
|
|
final int offset = 3 * slot;
|
|
this.hash = (this.ref << offset) | (this.ref >> (offset + 32));
|
|
}
|
|
|
|
@Override
|
|
public int hashCode() {
|
|
return this.hash;
|
|
}
|
|
|
|
@Override
|
|
public boolean equals(final Object obj) {
|
|
final boolean equality;
|
|
|
|
if (obj instanceof TestLookup) {
|
|
final TestLookup b = (TestLookup) obj;
|
|
|
|
equality = b.slot == this.slot && b.ref == this.ref;
|
|
} else {
|
|
equality = false;
|
|
}
|
|
|
|
return equality;
|
|
}
|
|
}
|
|
}
|