mirror of
https://github.com/GTNewHorizons/Applied-Energistics-2-Unofficial.git
synced 2026-10-25 20:22:23 +00:00
Crafting CPU only drops items when broken (#1713)
Co-authored-by: Martin Robertz <dream-master@gmx.net>
This commit is contained in:
1 parent
2444966e6f
commit
db9e4f579b
5 files changed
+194
-75
No files matched your search
@@ -2,6 +2,7 @@ package appeng.test.me.crafting;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertAll;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@@ -202,6 +203,24 @@ public class CraftingCPUClusterFunctionalTest {
|
||||
assertTrue(cpu.completed());
|
||||
}
|
||||
|
||||
@Test
|
||||
void breakingClusterWithInvalidatedCoreKeepsJob() {
|
||||
cpu.prepare(pattern, 64, 128);
|
||||
cpu.core.updateStatus(cpu);
|
||||
cpu.core.invalidate();
|
||||
|
||||
cpu.breakCluster();
|
||||
|
||||
assertAll(
|
||||
() -> assertTrue(cpu.isDestroyed()),
|
||||
() -> assertFalse(cpu.completed(), "The job must not be cancelled"),
|
||||
() -> assertEquals(512, cpu.storedInputs(), "The inventory must not be spilled"),
|
||||
() -> assertEquals(
|
||||
cpu.getInventory().writeInventory(),
|
||||
cpu.core.getPreviousState().getTag("inventory"),
|
||||
"The core must keep the job"));
|
||||
}
|
||||
|
||||
private void tick() {
|
||||
cpu.updateCraftingLogic(grid, energy, cache);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package appeng.test.tile.crafting;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import appeng.tile.crafting.TileCraftingTile;
|
||||
|
||||
public class TileCraftingTileFunctionalTest {
|
||||
|
||||
@Test
|
||||
void unformedCoreKeepsPendingJobAcrossSaves() {
|
||||
final NBTTagList inventory = new NBTTagList();
|
||||
inventory.appendTag(new ItemStack(Blocks.cobblestone, 64).writeToNBT(new NBTTagCompound()));
|
||||
final NBTTagCompound saved = new NBTTagCompound();
|
||||
saved.setBoolean("core", true);
|
||||
saved.setTag("inventory", inventory);
|
||||
|
||||
final TileCraftingTile unformed = new TileCraftingTile();
|
||||
unformed.readFromNBT(saved);
|
||||
final NBTTagCompound resaved = new NBTTagCompound();
|
||||
unformed.writeToNBT(resaved);
|
||||
final TileCraftingTile reloaded = new TileCraftingTile();
|
||||
reloaded.readFromNBT(resaved);
|
||||
|
||||
assertNotNull(reloaded.getPreviousState());
|
||||
assertEquals(inventory, reloaded.getPreviousState().getTag("inventory"));
|
||||
}
|
||||
}
|
||||
@@ -102,6 +102,7 @@ public class BlockCraftingUnit extends AEBaseTileBlock {
|
||||
final TileCraftingTile cp = this.getTileEntity(w, x, y, z);
|
||||
if (cp != null) {
|
||||
cp.breakCluster();
|
||||
cp.spillPreviousState();
|
||||
}
|
||||
|
||||
super.breakBlock(w, x, y, z, a, b);
|
||||
|
||||
@@ -341,7 +341,7 @@ public class CraftingCPUCluster implements IAECluster, ICraftingCPU {
|
||||
}
|
||||
|
||||
protected void addTile(final TileCraftingTile te) {
|
||||
if (this.machineSrc == null || te.isCoreBlock()) {
|
||||
if (this.machineSrc == null || te.isCoreBlock() && this.getCore().getPreviousState() == null) {
|
||||
this.machineSrc = new MachineSource(te);
|
||||
}
|
||||
|
||||
@@ -621,6 +621,18 @@ public class CraftingCPUCluster implements IAECluster, ICraftingCPU {
|
||||
return (TileCraftingTile) this.machineSrc.via;
|
||||
}
|
||||
|
||||
/// Whether the core tile, which persists this CPU's job, has been unloaded or replaced.
|
||||
public boolean isCoreInvalid() {
|
||||
return this.getCore().isInvalid();
|
||||
}
|
||||
|
||||
/// Saves this CPU's job to its core, to be resumed once the core forms a cluster again.
|
||||
public void storeJobInCore() {
|
||||
final NBTTagCompound job = new NBTTagCompound();
|
||||
this.writeToNBT(job);
|
||||
this.getCore().setPreviousState(job);
|
||||
}
|
||||
|
||||
public IGrid getGrid() {
|
||||
IGrid node;
|
||||
for (final TileCraftingTile r : this.tiles) {
|
||||
@@ -1649,6 +1661,10 @@ public class CraftingCPUCluster implements IAECluster, ICraftingCPU {
|
||||
core.setPreviousState(null);
|
||||
}
|
||||
|
||||
for (final TileCraftingTile te : this.tiles) {
|
||||
te.spillPreviousState();
|
||||
}
|
||||
|
||||
this.updateCPU();
|
||||
this.updateName();
|
||||
|
||||
|
||||
@@ -17,10 +17,12 @@ import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Set;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraftforge.common.util.ForgeDirection;
|
||||
|
||||
@@ -184,8 +186,16 @@ public class TileCraftingTile extends AENetworkTile implements IAEMultiBlock, IP
|
||||
@TileEvent(TileEventType.WORLD_NBT_WRITE)
|
||||
public void writeToNBT_TileCraftingTile(final NBTTagCompound data) {
|
||||
data.setBoolean("core", this.isCoreBlock());
|
||||
if (this.isCoreBlock() && this.cluster != null) {
|
||||
this.cluster.writeToNBT(data);
|
||||
if (this.isCoreBlock()) {
|
||||
if (this.cluster != null) {
|
||||
this.cluster.writeToNBT(data);
|
||||
} else if (this.previousState != null) {
|
||||
for (final String key : (Set<String>) this.previousState.func_150296_c()) {
|
||||
if (!data.hasKey(key)) {
|
||||
data.setTag(key, this.previousState.getTag(key).copy());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,80 +259,118 @@ public class TileCraftingTile extends AENetworkTile implements IAEMultiBlock, IP
|
||||
}
|
||||
|
||||
public void breakCluster() {
|
||||
if (this.cluster != null) {
|
||||
this.cluster.cancel();
|
||||
final MECraftingInventory inv = this.cluster.getInventory();
|
||||
|
||||
final LinkedList<WorldCoord> places = new LinkedList<>();
|
||||
|
||||
final Iterator<IGridHost> i = this.cluster.getTiles();
|
||||
while (i.hasNext()) {
|
||||
final IGridHost h = i.next();
|
||||
if (h == this) {
|
||||
places.add(new WorldCoord(this));
|
||||
} else {
|
||||
final TileEntity te = (TileEntity) h;
|
||||
|
||||
for (final ForgeDirection d : ForgeDirection.VALID_DIRECTIONS) {
|
||||
final WorldCoord wc = new WorldCoord(te);
|
||||
wc.add(d, 1);
|
||||
if (this.worldObj.isAirBlock(wc.x, wc.y, wc.z)) {
|
||||
places.add(wc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Collections.shuffle(places);
|
||||
|
||||
if (places.isEmpty()) {
|
||||
throw new IllegalStateException(
|
||||
this.cluster + " does not contain any kind of blocks, which were destroyed.");
|
||||
}
|
||||
|
||||
for (IAEItemStack ais : (IItemList<IAEItemStack>) inv
|
||||
.getAvailableItems(AEApi.instance().storage().createItemList())) {
|
||||
ais = ais.copy();
|
||||
ais.setStackSize(ais.getItemStack().getMaxStackSize());
|
||||
while (!places.isEmpty()) {
|
||||
final IAEItemStack g = inv.extractItems(ais.copy(), Actionable.MODULATE);
|
||||
if (g == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
final WorldCoord wc = places.removeFirst();
|
||||
if (!AEConfig.instance.limitCraftingCPUSpill) {
|
||||
places.add(wc);
|
||||
}
|
||||
|
||||
Platform.spawnDrops(this.worldObj, wc.x, wc.y, wc.z, Collections.singletonList(g.getItemStack()));
|
||||
}
|
||||
if (places.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (IAEFluidStack ifs : (IItemList<IAEFluidStack>) inv
|
||||
.getAvailableItems(AEApi.instance().storage().createFluidList())) {
|
||||
while (!places.isEmpty()) {
|
||||
final IAEItemStack g = stackConvertPacket(inv.extractItems(ifs, Actionable.MODULATE));
|
||||
if (g == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
final WorldCoord wc = places.removeFirst();
|
||||
if (!AEConfig.instance.limitCraftingCPUSpill) {
|
||||
places.add(wc);
|
||||
}
|
||||
|
||||
Platform.spawnDrops(this.worldObj, wc.x, wc.y, wc.z, Collections.singletonList(g.getItemStack()));
|
||||
}
|
||||
if (places.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (this.cluster == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* An invalidated core was unloaded or replaced (e.g. by a block mover) rather than broken, so the NBT it was
|
||||
* saved to still holds the job and restores it once the core forms a cluster again. Cancelling and spilling the
|
||||
* job here as well would duplicate it. The job is also kept on the core itself, for when the same tile is
|
||||
* revalidated instead of being loaded from NBT.
|
||||
*/
|
||||
if (this.cluster.isCoreInvalid()) {
|
||||
this.cluster.storeJobInCore();
|
||||
this.cluster.destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
this.cluster.cancel();
|
||||
|
||||
final LinkedList<WorldCoord> places = new LinkedList<>();
|
||||
|
||||
final Iterator<IGridHost> i = this.cluster.getTiles();
|
||||
while (i.hasNext()) {
|
||||
final IGridHost h = i.next();
|
||||
if (h == this) {
|
||||
places.add(new WorldCoord(this));
|
||||
} else {
|
||||
places.addAll(this.getAdjacentAir((TileEntity) h));
|
||||
}
|
||||
}
|
||||
|
||||
if (places.isEmpty()) {
|
||||
throw new IllegalStateException(
|
||||
this.cluster + " does not contain any kind of blocks, which were destroyed.");
|
||||
}
|
||||
|
||||
this.spillInventory(this.cluster.getInventory(), places);
|
||||
this.cluster.destroy();
|
||||
}
|
||||
|
||||
/// Drops the items of the job loaded from NBT, for when no cluster resumes it.
|
||||
public void spillPreviousState() {
|
||||
if (this.previousState == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final MECraftingInventory inv = new MECraftingInventory();
|
||||
inv.readInventory((NBTTagList) this.previousState.getTag("inventory"));
|
||||
this.previousState = null;
|
||||
|
||||
final LinkedList<WorldCoord> places = this.getAdjacentAir(this);
|
||||
if (places.isEmpty()) {
|
||||
places.add(new WorldCoord(this));
|
||||
}
|
||||
|
||||
this.spillInventory(inv, places);
|
||||
}
|
||||
|
||||
private LinkedList<WorldCoord> getAdjacentAir(final TileEntity te) {
|
||||
final LinkedList<WorldCoord> places = new LinkedList<>();
|
||||
for (final ForgeDirection d : ForgeDirection.VALID_DIRECTIONS) {
|
||||
final WorldCoord wc = new WorldCoord(te);
|
||||
wc.add(d, 1);
|
||||
if (this.worldObj.isAirBlock(wc.x, wc.y, wc.z)) {
|
||||
places.add(wc);
|
||||
}
|
||||
}
|
||||
return places;
|
||||
}
|
||||
|
||||
private void spillInventory(final MECraftingInventory inv, final LinkedList<WorldCoord> places) {
|
||||
Collections.shuffle(places);
|
||||
|
||||
for (IAEItemStack ais : (IItemList<IAEItemStack>) inv
|
||||
.getAvailableItems(AEApi.instance().storage().createItemList())) {
|
||||
ais = ais.copy();
|
||||
ais.setStackSize(ais.getItemStack().getMaxStackSize());
|
||||
while (!places.isEmpty()) {
|
||||
final IAEItemStack g = inv.extractItems(ais.copy(), Actionable.MODULATE);
|
||||
if (g == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
final WorldCoord wc = places.removeFirst();
|
||||
if (!AEConfig.instance.limitCraftingCPUSpill) {
|
||||
places.add(wc);
|
||||
}
|
||||
|
||||
Platform.spawnDrops(this.worldObj, wc.x, wc.y, wc.z, Collections.singletonList(g.getItemStack()));
|
||||
}
|
||||
if (places.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (IAEFluidStack ifs : (IItemList<IAEFluidStack>) inv
|
||||
.getAvailableItems(AEApi.instance().storage().createFluidList())) {
|
||||
while (!places.isEmpty()) {
|
||||
final IAEItemStack g = stackConvertPacket(inv.extractItems(ifs, Actionable.MODULATE));
|
||||
if (g == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
final WorldCoord wc = places.removeFirst();
|
||||
if (!AEConfig.instance.limitCraftingCPUSpill) {
|
||||
places.add(wc);
|
||||
}
|
||||
|
||||
Platform.spawnDrops(this.worldObj, wc.x, wc.y, wc.z, Collections.singletonList(g.getItemStack()));
|
||||
}
|
||||
if (places.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user