Files
Applied-Energistics-2/src/main/java/appeng/me/cluster/implementations/CraftingCPUCluster.java
T
yueh 662dbca3e1 Fixes #4508: Correctly construct the sparse lists. (#4511)
* Fixes #4508: Correctly construct the sparse lists.

Also renamed all uncondensed getters to sparse and all condensed to the simple ones.

* Apply suggestions from code review

Co-authored-by: shartte <shartte@users.noreply.github.com>

* Streamlined collapsing the sparse lists

* Extracted helper to condense stacks

* Sort lists desc by stack size

Co-authored-by: shartte <shartte@users.noreply.github.com>
2020-07-27 11:21:06 +02:00

1178 lines
41 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.me.cluster.implementations;
import java.util.*;
import java.util.Map.Entry;
import com.google.common.collect.ImmutableList;
import net.minecraft.inventory.CraftingInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.ListNBT;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.world.World;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.fml.hooks.BasicEventHooks;
import appeng.api.config.Actionable;
import appeng.api.config.FuzzyMode;
import appeng.api.config.PowerMultiplier;
import appeng.api.crafting.ICraftingHelper;
import appeng.api.networking.IGrid;
import appeng.api.networking.IGridHost;
import appeng.api.networking.IGridNode;
import appeng.api.networking.crafting.*;
import appeng.api.networking.energy.IEnergyGrid;
import appeng.api.networking.events.MENetworkCraftingCpuChange;
import appeng.api.networking.security.IActionSource;
import appeng.api.networking.storage.IStorageGrid;
import appeng.api.storage.IMEInventory;
import appeng.api.storage.IMEMonitorHandlerReceiver;
import appeng.api.storage.channels.IItemStorageChannel;
import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IItemList;
import appeng.container.ContainerNull;
import appeng.core.AELog;
import appeng.core.Api;
import appeng.crafting.*;
import appeng.me.cache.CraftingGridCache;
import appeng.me.cluster.IAECluster;
import appeng.me.cluster.MBCalculator;
import appeng.me.helpers.MachineSource;
import appeng.tile.crafting.CraftingMonitorTileEntity;
import appeng.tile.crafting.CraftingTileEntity;
import appeng.util.Platform;
import appeng.util.item.AEItemStack;
public final class CraftingCPUCluster implements IAECluster, ICraftingCPU {
private static final String LOG_MARK_AS_COMPLETE = "Completed job for %s.";
private final BlockPos boundsMin;
private final BlockPos boundsMax;
private final int[] usedOps = new int[3];
private final Map<ICraftingPatternDetails, TaskProgress> tasks = new HashMap<>();
// INSTANCE sate
private final List<CraftingTileEntity> tiles = new ArrayList<>();
private final List<CraftingTileEntity> storage = new ArrayList<>();
private final List<CraftingMonitorTileEntity> status = new ArrayList<>();
private final HashMap<IMEMonitorHandlerReceiver<IAEItemStack>, Object> listeners = new HashMap<>();
private ICraftingLink myLastLink;
private ITextComponent myName = null;
private boolean isDestroyed = false;
/**
* crafting job info
*/
private MECraftingInventory inventory = new MECraftingInventory();
private IAEItemStack finalOutput;
private boolean waiting = false;
private IItemList<IAEItemStack> waitingFor = Api.instance().storage().getStorageChannel(IItemStorageChannel.class)
.createList();
private long availableStorage = 0;
private MachineSource machineSrc = null;
private int accelerator = 0;
private boolean isComplete = true;
private int remainingOperations;
private boolean somethingChanged;
private long lastTime;
private long elapsedTime;
private long startItemCount;
private long remainingItemCount;
public CraftingCPUCluster(final BlockPos boundsMin, final BlockPos boundsMax) {
this.boundsMin = boundsMin.toImmutable();
this.boundsMax = boundsMax.toImmutable();
}
@Override
public boolean isDestroyed() {
return this.isDestroyed;
}
public ICraftingLink getLastCraftingLink() {
return this.myLastLink;
}
@Override
public BlockPos getBoundsMin() {
return boundsMin;
}
@Override
public BlockPos getBoundsMax() {
return boundsMax;
}
/**
* add a new Listener to the monitor, be sure to properly remove yourself when
* your done.
*/
@Override
public void addListener(final IMEMonitorHandlerReceiver<IAEItemStack> l, final Object verificationToken) {
this.listeners.put(l, verificationToken);
}
/**
* remove a Listener to the monitor.
*/
@Override
public void removeListener(final IMEMonitorHandlerReceiver<IAEItemStack> l) {
this.listeners.remove(l);
}
public IMEInventory<IAEItemStack> getInventory() {
return this.inventory;
}
@Override
public void updateStatus(final boolean updateGrid) {
for (final CraftingTileEntity r : this.tiles) {
r.updateMeta(true);
}
}
@Override
public void destroy() {
if (this.isDestroyed) {
return;
}
this.isDestroyed = true;
boolean ownsModification = !MBCalculator.isModificationInProgress();
if (ownsModification) {
MBCalculator.setModificationInProgress(this);
}
try {
boolean posted = false;
for (final CraftingTileEntity r : this.tiles) {
final IGridNode n = r.getActionableNode();
if (n != null && !posted) {
final IGrid g = n.getGrid();
if (g != null) {
g.postEvent(new MENetworkCraftingCpuChange(n));
posted = true;
}
}
r.updateStatus(null);
}
} finally {
if (ownsModification) {
MBCalculator.setModificationInProgress(null);
}
}
}
@Override
public Iterator<CraftingTileEntity> getTiles() {
return this.tiles.iterator();
}
void addTile(final CraftingTileEntity te) {
if (this.machineSrc == null || te.isCoreBlock()) {
this.machineSrc = new MachineSource(te);
}
te.setCoreBlock(false);
te.saveChanges();
this.tiles.add(0, te);
if (te.isStorage()) {
this.availableStorage += te.getStorageBytes();
this.storage.add(te);
} else if (te.isStatus()) {
this.status.add((CraftingMonitorTileEntity) te);
} else if (te.isAccelerator()) {
this.accelerator++;
}
}
public boolean canAccept(final IAEItemStack input) {
if (input instanceof IAEItemStack) {
final IAEItemStack is = this.waitingFor.findPrecise(input);
if (is != null && is.getStackSize() > 0) {
return true;
}
}
return false;
}
public IAEItemStack injectItems(final IAEItemStack input, final Actionable type, final IActionSource src) {
if (!(input instanceof IAEItemStack)) {
return input;
}
final IAEItemStack what = input.copy();
final IAEItemStack is = this.waitingFor.findPrecise(what);
if (type == Actionable.SIMULATE)// causes crafting to lock up?
{
if (is != null && is.getStackSize() > 0) {
if (is.getStackSize() >= what.getStackSize()) {
if (this.finalOutput.equals(what)) {
if (this.myLastLink != null) {
return ((CraftingLink) this.myLastLink).injectItems(what.copy(), type);
}
return what; // ignore it.
}
return null;
}
final IAEItemStack leftOver = what.copy();
leftOver.decStackSize(is.getStackSize());
final IAEItemStack used = what.copy();
used.setStackSize(is.getStackSize());
if (this.finalOutput.equals(what)) {
if (this.myLastLink != null) {
leftOver.add(((CraftingLink) this.myLastLink).injectItems(used.copy(), type));
return leftOver;
}
return what; // ignore it.
}
return leftOver;
}
} else if (type == Actionable.MODULATE) {
if (is != null && is.getStackSize() > 0) {
this.waiting = false;
this.postChange(what, src);
if (is.getStackSize() >= what.getStackSize()) {
is.decStackSize(what.getStackSize());
this.updateElapsedTime(what);
this.markDirty();
this.postCraftingStatusChange(what.copy().setStackSize(-what.getStackSize()));
if (this.finalOutput.equals(what)) {
IAEItemStack leftover = what;
this.finalOutput.decStackSize(what.getStackSize());
if (this.myLastLink != null) {
leftover = ((CraftingLink) this.myLastLink).injectItems(what, type);
}
if (this.finalOutput.getStackSize() <= 0) {
this.completeJob();
}
this.updateCPU();
return leftover; // ignore it.
}
// 2000
return this.inventory.injectItems(what, type, src);
}
final IAEItemStack insert = what.copy();
insert.setStackSize(is.getStackSize());
what.decStackSize(is.getStackSize());
is.setStackSize(0);
this.postCraftingStatusChange(insert.copy().setStackSize(-insert.getStackSize()));
if (this.finalOutput.equals(insert)) {
IAEItemStack leftover = input;
this.finalOutput.decStackSize(insert.getStackSize());
if (this.myLastLink != null) {
what.add(((CraftingLink) this.myLastLink).injectItems(insert.copy(), type));
leftover = what;
}
if (this.finalOutput.getStackSize() <= 0) {
this.completeJob();
}
this.updateCPU();
this.markDirty();
return leftover; // ignore it.
}
this.inventory.injectItems(insert, type, src);
this.markDirty();
return what;
}
}
return input;
}
private void postChange(final IAEItemStack diff, final IActionSource src) {
final Iterator<Entry<IMEMonitorHandlerReceiver<IAEItemStack>, Object>> i = this.getListeners();
// protect integrity
if (i.hasNext()) {
final ImmutableList<IAEItemStack> single = ImmutableList.of(diff.copy());
while (i.hasNext()) {
final Entry<IMEMonitorHandlerReceiver<IAEItemStack>, Object> o = i.next();
final IMEMonitorHandlerReceiver<IAEItemStack> receiver = o.getKey();
if (receiver.isValid(o.getValue())) {
receiver.postChange(null, single, src);
} else {
i.remove();
}
}
}
}
private void markDirty() {
this.getCore().saveChanges();
}
private void postCraftingStatusChange(final IAEItemStack diff) {
if (this.getGrid() == null) {
return;
}
final CraftingGridCache sg = this.getGrid().getCache(ICraftingGrid.class);
if (sg.getInterestManager().containsKey(diff)) {
final Collection<CraftingWatcher> list = sg.getInterestManager().get(diff);
if (!list.isEmpty()) {
for (final CraftingWatcher iw : list)
{
iw.getHost().onRequestChange(sg, diff);
}
}
}
}
private void completeJob() {
if (this.myLastLink != null) {
((CraftingLink) this.myLastLink).markDone();
}
if (AELog.isCraftingLogEnabled()) {
final IAEItemStack logStack = this.finalOutput.copy();
logStack.setStackSize(this.startItemCount);
AELog.crafting(LOG_MARK_AS_COMPLETE, logStack);
}
this.remainingItemCount = 0;
this.startItemCount = 0;
this.lastTime = 0;
this.elapsedTime = 0;
this.isComplete = true;
}
private void updateCPU() {
IAEItemStack send = this.finalOutput;
if (this.finalOutput != null && this.finalOutput.getStackSize() <= 0) {
send = null;
}
for (final CraftingMonitorTileEntity t : this.status) {
t.setJob(send);
}
}
private Iterator<Entry<IMEMonitorHandlerReceiver<IAEItemStack>, Object>> getListeners() {
return this.listeners.entrySet().iterator();
}
private CraftingTileEntity getCore() {
if (this.machineSrc == null) {
return null;
}
return (CraftingTileEntity) this.machineSrc.machine().get();
}
private IGrid getGrid() {
for (final CraftingTileEntity r : this.tiles) {
final IGridNode gn = r.getActionableNode();
if (gn != null) {
final IGrid g = gn.getGrid();
if (g != null) {
return r.getActionableNode().getGrid();
}
}
}
return null;
}
private boolean canCraft(final ICraftingPatternDetails details, final Collection<IAEItemStack> condensedInputs) {
for (IAEItemStack g : condensedInputs) {
if (details.isCraftable()) {
boolean found = false;
for (IAEItemStack fuzz : this.inventory.getItemList().findFuzzy(g, FuzzyMode.IGNORE_ALL)) {
fuzz = fuzz.copy();
fuzz.setStackSize(g.getStackSize());
final IAEItemStack ais = this.inventory.extractItems(fuzz, Actionable.SIMULATE, this.machineSrc);
final ItemStack is = ais == null ? ItemStack.EMPTY : ais.createItemStack();
if (!is.isEmpty() && is.getCount() == g.getStackSize()) {
found = true;
break;
} else if (!is.isEmpty()) {
g = g.copy();
g.decStackSize(is.getCount());
}
}
if (!found) {
return false;
}
} else {
final IAEItemStack ais = this.inventory.extractItems(g.copy(), Actionable.SIMULATE, this.machineSrc);
final ItemStack is = ais == null ? ItemStack.EMPTY : ais.createItemStack();
if (is.isEmpty() || is.getCount() < g.getStackSize()) {
return false;
}
}
}
return true;
}
public void cancel() {
if (this.myLastLink != null) {
this.myLastLink.cancel();
}
final IItemList<IAEItemStack> list;
this.getListOfItem(list = Api.instance().storage().getStorageChannel(IItemStorageChannel.class).createList(),
CraftingItemList.ALL);
for (final IAEItemStack is : list) {
this.postChange(is, this.machineSrc);
}
this.isComplete = true;
this.myLastLink = null;
this.tasks.clear();
// final ImmutableSet<IAEItemStack> items = ImmutableSet.copyOf( this.waitingFor
// );
final List<IAEItemStack> items = new ArrayList<>(this.waitingFor.size());
this.waitingFor.forEach(stack -> items.add(stack.copy().setStackSize(-stack.getStackSize())));
this.waitingFor.resetStatus();
for (final IAEItemStack is : items) {
this.postCraftingStatusChange(is);
}
this.finalOutput = null;
this.updateCPU();
this.storeItems(); // marks dirty
}
public void updateCraftingLogic(final IGrid grid, final IEnergyGrid eg, final CraftingGridCache cc) {
if (!this.getCore().isActive()) {
return;
}
if (this.myLastLink != null) {
if (this.myLastLink.isCanceled()) {
this.myLastLink = null;
this.cancel();
}
}
if (this.isComplete) {
if (this.inventory.getItemList().isEmpty()) {
return;
}
this.storeItems();
return;
}
this.waiting = false;
if (this.waiting || this.tasks.isEmpty()) // nothing to do here...
{
return;
}
this.remainingOperations = this.accelerator + 1 - (this.usedOps[0] + this.usedOps[1] + this.usedOps[2]);
final int started = this.remainingOperations;
if (this.remainingOperations > 0) {
do {
this.somethingChanged = false;
this.executeCrafting(eg, cc);
} while (this.somethingChanged && this.remainingOperations > 0);
}
this.usedOps[2] = this.usedOps[1];
this.usedOps[1] = this.usedOps[0];
this.usedOps[0] = started - this.remainingOperations;
if (this.remainingOperations > 0 && !this.somethingChanged) {
this.waiting = true;
}
}
private void executeCrafting(final IEnergyGrid eg, final CraftingGridCache cc) {
final Iterator<Entry<ICraftingPatternDetails, TaskProgress>> i = this.tasks.entrySet().iterator();
while (i.hasNext()) {
final Entry<ICraftingPatternDetails, TaskProgress> e = i.next();
if (e.getValue().value <= 0) {
i.remove();
continue;
}
final ICraftingPatternDetails details = e.getKey();
if (this.canCraft(details, details.getInputs())) {
CraftingInventory ic = null;
for (final ICraftingMedium m : cc.getMediums(e.getKey())) {
if (e.getValue().value <= 0) {
continue;
}
if (!m.isBusy()) {
if (ic == null) {
final IAEItemStack[] input = details.getSparseInputs();
double sum = 0;
for (final IAEItemStack anInput : input) {
if (anInput != null) {
sum += anInput.getStackSize();
}
}
// power...
if (eg.extractAEPower(sum, Actionable.MODULATE, PowerMultiplier.CONFIG) < sum - 0.01) {
continue;
}
ic = new CraftingInventory(new ContainerNull(), 3, 3);
boolean found = false;
for (int x = 0; x < input.length; x++) {
if (input[x] != null) {
found = false;
if (details.isCraftable()) {
final Collection<IAEItemStack> itemList;
if (details.canSubstitute()) {
itemList = this.inventory.getItemList().findFuzzy(input[x],
FuzzyMode.IGNORE_ALL);
} else {
itemList = new ArrayList<>(1);
final IAEItemStack item = this.inventory.getItemList()
.findPrecise(input[x]);
if (item != null) {
itemList.add(item);
}
}
for (IAEItemStack fuzz : itemList) {
fuzz = fuzz.copy();
fuzz.setStackSize(input[x].getStackSize());
if (details.isValidItemForSlot(x, fuzz.createItemStack(),
this.getWorld())) {
final IAEItemStack ais = this.inventory.extractItems(fuzz,
Actionable.MODULATE, this.machineSrc);
final ItemStack is = ais == null ? ItemStack.EMPTY
: ais.createItemStack();
if (!is.isEmpty()) {
this.postChange(AEItemStack.fromItemStack(is), this.machineSrc);
ic.setInventorySlotContents(x, is);
found = true;
break;
}
}
}
} else {
final IAEItemStack ais = this.inventory.extractItems(input[x].copy(),
Actionable.MODULATE, this.machineSrc);
final ItemStack is = ais == null ? ItemStack.EMPTY : ais.createItemStack();
if (!is.isEmpty()) {
this.postChange(input[x], this.machineSrc);
ic.setInventorySlotContents(x, is);
if (is.getCount() == input[x].getStackSize()) {
found = true;
continue;
}
}
}
if (!found) {
break;
}
}
}
if (!found) {
// put stuff back..
for (int x = 0; x < ic.getSizeInventory(); x++) {
final ItemStack is = ic.getStackInSlot(x);
if (!is.isEmpty()) {
this.inventory.injectItems(AEItemStack.fromItemStack(is), Actionable.MODULATE,
this.machineSrc);
}
}
ic = null;
break;
}
}
if (m.pushPattern(details, ic)) {
this.somethingChanged = true;
this.remainingOperations--;
for (final IAEItemStack out : details.getOutputs()) {
this.postChange(out, this.machineSrc);
this.waitingFor.add(out.copy());
this.postCraftingStatusChange(out.copy());
}
if (details.isCraftable()) {
BasicEventHooks.firePlayerCraftingEvent(Platform.getPlayer((ServerWorld) getWorld()),
details.getOutput(ic, this.getWorld()), ic);
for (int x = 0; x < ic.getSizeInventory(); x++) {
final ItemStack output = Platform.getContainerItem(ic.getStackInSlot(x));
if (!output.isEmpty()) {
final IAEItemStack cItem = AEItemStack.fromItemStack(output);
this.postChange(cItem, this.machineSrc);
this.waitingFor.add(cItem);
this.postCraftingStatusChange(cItem);
}
}
}
ic = null; // hand off complete!
this.markDirty();
e.getValue().value--;
if (e.getValue().value <= 0) {
continue;
}
if (this.remainingOperations == 0) {
return;
}
}
}
}
if (ic != null) {
// put stuff back..
for (int x = 0; x < ic.getSizeInventory(); x++) {
final ItemStack is = ic.getStackInSlot(x);
if (!is.isEmpty()) {
this.inventory.injectItems(AEItemStack.fromItemStack(is), Actionable.MODULATE,
this.machineSrc);
}
}
}
}
}
}
private void storeItems() {
final IGrid g = this.getGrid();
if (g == null) {
return;
}
final IStorageGrid sg = g.getCache(IStorageGrid.class);
final IMEInventory<IAEItemStack> ii = sg
.getInventory(Api.instance().storage().getStorageChannel(IItemStorageChannel.class));
for (IAEItemStack is : this.inventory.getItemList()) {
is = this.inventory.extractItems(is.copy(), Actionable.MODULATE, this.machineSrc);
if (is != null) {
this.postChange(is, this.machineSrc);
is = ii.injectItems(is, Actionable.MODULATE, this.machineSrc);
}
if (is != null) {
this.inventory.injectItems(is, Actionable.MODULATE, this.machineSrc);
}
}
if (this.inventory.getItemList().isEmpty()) {
this.inventory = new MECraftingInventory();
}
this.markDirty();
}
public ICraftingLink submitJob(final IGrid g, final ICraftingJob job, final IActionSource src,
final ICraftingRequester requestingMachine) {
if (!this.tasks.isEmpty() || !this.waitingFor.isEmpty()) {
return null;
}
if (!(job instanceof CraftingJob)) {
return null;
}
if (this.isBusy() || !this.isActive() || this.availableStorage < job.getByteTotal()) {
return null;
}
final IStorageGrid sg = g.getCache(IStorageGrid.class);
final IMEInventory<IAEItemStack> storage = sg
.getInventory(Api.instance().storage().getStorageChannel(IItemStorageChannel.class));
final MECraftingInventory ci = new MECraftingInventory(storage, true, false, false);
try {
this.waitingFor.resetStatus();
((CraftingJob) job).getTree().setJob(ci, this, src);
if (ci.commit(src)) {
this.finalOutput = job.getOutput();
this.waiting = false;
this.isComplete = false;
this.markDirty();
this.updateCPU();
final String craftID = this.generateCraftingID();
this.myLastLink = new CraftingLink(this.generateLinkData(craftID, requestingMachine == null, false),
this);
this.prepareElapsedTime();
if (requestingMachine == null) {
return this.myLastLink;
}
final ICraftingLink whatLink = new CraftingLink(this.generateLinkData(craftID, false, true),
requestingMachine);
this.submitLink(this.myLastLink);
this.submitLink(whatLink);
final IItemList<IAEItemStack> list = Api.instance().storage()
.getStorageChannel(IItemStorageChannel.class).createList();
this.getListOfItem(list, CraftingItemList.ALL);
for (final IAEItemStack ge : list) {
this.postChange(ge, this.machineSrc);
}
return whatLink;
} else {
this.tasks.clear();
this.inventory.getItemList().resetStatus();
}
} catch (final CraftBranchFailure e) {
this.tasks.clear();
this.inventory.getItemList().resetStatus();
// AELog.error( e );
}
return null;
}
@Override
public boolean isBusy() {
final Iterator<Entry<ICraftingPatternDetails, TaskProgress>> i = this.tasks.entrySet().iterator();
while (i.hasNext()) {
if (i.next().getValue().value <= 0) {
i.remove();
}
}
return !this.tasks.isEmpty() || !this.waitingFor.isEmpty();
}
@Override
public IActionSource getActionSource() {
return this.machineSrc;
}
@Override
public long getAvailableStorage() {
return this.availableStorage;
}
@Override
public int getCoProcessors() {
return this.accelerator;
}
@Override
public ITextComponent getName() {
return this.myName;
}
public boolean isActive() {
final CraftingTileEntity core = this.getCore();
if (core == null) {
return false;
}
final IGridNode node = core.getActionableNode();
if (node == null) {
return false;
}
return node.isActive();
}
private String generateCraftingID() {
final long now = System.currentTimeMillis();
final int hash = System.identityHashCode(this);
final int hmm = this.finalOutput == null ? 0 : this.finalOutput.hashCode();
return Long.toString(now, Character.MAX_RADIX) + '-' + Integer.toString(hash, Character.MAX_RADIX) + '-'
+ Integer.toString(hmm, Character.MAX_RADIX);
}
private CompoundNBT generateLinkData(final String craftingID, final boolean standalone, final boolean req) {
final CompoundNBT tag = new CompoundNBT();
tag.putString("CraftID", craftingID);
tag.putBoolean("canceled", false);
tag.putBoolean("done", false);
tag.putBoolean("standalone", standalone);
tag.putBoolean("req", req);
return tag;
}
private void submitLink(final ICraftingLink myLastLink2) {
if (this.getGrid() != null) {
final CraftingGridCache cc = this.getGrid().getCache(ICraftingGrid.class);
cc.addLink((CraftingLink) myLastLink2);
}
}
public void getListOfItem(final IItemList<IAEItemStack> list, final CraftingItemList whichList) {
switch (whichList) {
case ACTIVE:
for (final IAEItemStack ais : this.waitingFor) {
list.add(ais);
}
break;
case PENDING:
for (final Entry<ICraftingPatternDetails, TaskProgress> t : this.tasks.entrySet()) {
for (IAEItemStack ais : t.getKey().getOutputs()) {
ais = ais.copy();
ais.setStackSize(ais.getStackSize() * t.getValue().value);
list.add(ais);
}
}
break;
case STORAGE:
this.inventory.getAvailableItems(list);
break;
default:
case ALL:
this.inventory.getAvailableItems(list);
for (final IAEItemStack ais : this.waitingFor) {
list.add(ais);
}
for (final Entry<ICraftingPatternDetails, TaskProgress> t : this.tasks.entrySet()) {
for (IAEItemStack ais : t.getKey().getOutputs()) {
ais = ais.copy();
ais.setStackSize(ais.getStackSize() * t.getValue().value);
list.add(ais);
}
}
break;
}
}
public void addStorage(final IAEItemStack extractItems) {
this.inventory.injectItems(extractItems, Actionable.MODULATE, null);
}
public void addEmitable(final IAEItemStack i) {
this.waitingFor.add(i);
this.postCraftingStatusChange(i);
}
public void addCrafting(final ICraftingPatternDetails details, final long crafts) {
TaskProgress i = this.tasks.get(details);
if (i == null) {
this.tasks.put(details, i = new TaskProgress());
}
i.value += crafts;
}
public IAEItemStack getItemStack(final IAEItemStack what, final CraftingItemList storage2) {
IAEItemStack is;
switch (storage2) {
case STORAGE:
is = this.inventory.getItemList().findPrecise(what);
break;
case ACTIVE:
is = this.waitingFor.findPrecise(what);
break;
case PENDING:
is = what.copy();
is.setStackSize(0);
for (final Entry<ICraftingPatternDetails, TaskProgress> t : this.tasks.entrySet()) {
for (final IAEItemStack ais : t.getKey().getOutputs()) {
if (ais.equals(is)) {
is.setStackSize(is.getStackSize() + ais.getStackSize() * t.getValue().value);
}
}
}
break;
default:
case ALL:
throw new IllegalStateException("Invalid Operation");
}
if (is != null) {
return is.copy();
}
is = what.copy();
is.setStackSize(0);
return is;
}
public void writeToNBT(final CompoundNBT data) {
data.put("finalOutput", this.writeItem(this.finalOutput));
data.put("inventory", this.writeList(this.inventory.getItemList()));
data.putBoolean("waiting", this.waiting);
data.putBoolean("isComplete", this.isComplete);
if (this.myLastLink != null) {
final CompoundNBT link = new CompoundNBT();
this.myLastLink.writeToNBT(link);
data.put("link", link);
}
final ListNBT list = new ListNBT();
for (final Entry<ICraftingPatternDetails, TaskProgress> e : this.tasks.entrySet()) {
final CompoundNBT item = this.writeItem(AEItemStack.fromItemStack(e.getKey().getPattern()));
item.putLong("craftingProgress", e.getValue().value);
list.add(item);
}
data.put("tasks", list);
data.put("waitingFor", this.writeList(this.waitingFor));
data.putLong("elapsedTime", this.getElapsedTime());
data.putLong("startItemCount", this.getStartItemCount());
data.putLong("remainingItemCount", this.getRemainingItemCount());
}
private CompoundNBT writeItem(final IAEItemStack finalOutput2) {
final CompoundNBT out = new CompoundNBT();
if (finalOutput2 != null) {
finalOutput2.writeToNBT(out);
}
return out;
}
private ListNBT writeList(final IItemList<IAEItemStack> myList) {
final ListNBT out = new ListNBT();
for (final IAEItemStack ais : myList) {
out.add(this.writeItem(ais));
}
return out;
}
void done() {
final CraftingTileEntity core = this.getCore();
core.setCoreBlock(true);
if (core.getPreviousState() != null) {
this.readFromNBT(core.getPreviousState());
core.setPreviousState(null);
}
this.updateCPU();
this.updateName();
}
public void readFromNBT(final CompoundNBT data) {
this.finalOutput = AEItemStack.fromNBT(data.getCompound("finalOutput"));
for (final IAEItemStack ais : this.readList(data.getList("inventory", 10))) {
this.inventory.injectItems(ais, Actionable.MODULATE, this.machineSrc);
}
this.waiting = data.getBoolean("waiting");
this.isComplete = data.getBoolean("isComplete");
if (data.contains("link")) {
final CompoundNBT link = data.getCompound("link");
this.myLastLink = new CraftingLink(link, this);
this.submitLink(this.myLastLink);
}
final ListNBT list = data.getList("tasks", 10);
for (int x = 0; x < list.size(); x++) {
final CompoundNBT item = list.getCompound(x);
final IAEItemStack pattern = AEItemStack.fromNBT(item);
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();
tp.value = item.getLong("craftingProgress");
this.tasks.put(details, tp);
}
}
}
this.waitingFor = this.readList(data.getList("waitingFor", 10));
for (final IAEItemStack is : this.waitingFor) {
this.postCraftingStatusChange(is.copy());
}
this.lastTime = System.nanoTime();
this.elapsedTime = data.getLong("elapsedTime");
this.startItemCount = data.getLong("startItemCount");
this.remainingItemCount = data.getLong("remainingItemCount");
}
public void updateName() {
this.myName = null;
for (final CraftingTileEntity te : this.tiles) {
if (te.hasCustomInventoryName()) {
if (this.myName != null) {
this.myName.appendText(" ").appendSibling(te.getCustomInventoryName());
} else {
this.myName = te.getCustomInventoryName().deepCopy();
}
}
}
}
private IItemList<IAEItemStack> readList(final ListNBT tag) {
final IItemList<IAEItemStack> out = Api.instance().storage().getStorageChannel(IItemStorageChannel.class)
.createList();
if (tag == null) {
return out;
}
for (int x = 0; x < tag.size(); x++) {
final IAEItemStack ais = AEItemStack.fromNBT(tag.getCompound(x));
if (ais != null) {
out.add(ais);
}
}
return out;
}
private World getWorld() {
return this.getCore().getWorld();
}
public IAEItemStack making(final IAEItemStack what) {
return this.waitingFor.findPrecise(what);
}
public void breakCluster() {
final CraftingTileEntity t = this.getCore();
if (t != null) {
t.breakCluster();
}
}
private void prepareElapsedTime() {
this.lastTime = System.nanoTime();
this.elapsedTime = 0;
final IItemList<IAEItemStack> list = Api.instance().storage().getStorageChannel(IItemStorageChannel.class)
.createList();
this.getListOfItem(list, CraftingItemList.ACTIVE);
this.getListOfItem(list, CraftingItemList.PENDING);
int itemCount = 0;
for (final IAEItemStack ge : list) {
itemCount += ge.getStackSize();
}
this.startItemCount = itemCount;
this.remainingItemCount = itemCount;
}
private void updateElapsedTime(final IAEItemStack is) {
final long nextStartTime = System.nanoTime();
this.elapsedTime = this.getElapsedTime() + nextStartTime - this.lastTime;
this.lastTime = nextStartTime;
this.remainingItemCount = this.getRemainingItemCount() - is.getStackSize();
}
public long getElapsedTime() {
return this.elapsedTime;
}
public long getRemainingItemCount() {
return this.remainingItemCount;
}
public long getStartItemCount() {
return this.startItemCount;
}
private static class TaskProgress {
private long value;
}
}