Compare commits

...

36 Commits

Author SHA1 Message Date
PrototypeTrousers e09f74cb5f 2 2021-08-14 00:09:32 -03:00
PrototypeTrousers facc1b4ef4 prevent crafting job to be fired if its a pattern failed previously till
the lack of ingredient that caused the failure is satisfied
2021-08-13 22:50:14 -03:00
PrototypeTrousers 618e9390c6 fixes item showing incorrect amounts 2021-08-13 00:17:53 -03:00
PrototypeTrousers 9a71bfb0f0 hash drawers handler by the amount of slots 2021-08-10 09:06:18 -03:00
PrototypeTrousers 9680123906 fix JEI targeting disabled slots as valid 2021-08-06 06:25:12 -03:00
PrototypeTrousers 87730894e9 Update CHANGES.md 2021-08-05 21:36:49 -03:00
PrototypeTrousers 71c944daea fix fluid storagebus NPE crash 2021-08-04 20:49:38 -03:00
PrototypeTrousers e96b4a698a fluid containers can now be drained/filled from fluid interfaces 2021-08-04 19:38:00 -03:00
PrototypeTrousers 1d5465a4b8 partially revert fda8c8 2021-08-04 09:28:47 -03:00
PrototypeTrousers 09cbfe96d6 fix NPE when configuring storage busses 2021-08-01 17:36:23 -03:00
PrototypeTrousers cbdad7c58e hopefully fix storage busses for good
1
2021-07-31 23:05:59 -03:00
PrototypeTrousers 6be96956a9 small optimization to import/export busses 2021-07-30 23:26:42 -03:00
PrototypeTrousers e376e002e9 actually fix #43 ? .... 2021-07-30 07:51:57 -03:00
PrototypeTrousers 0b9df31d4e fix broken recipes resulting in item dupes 2021-07-28 19:46:42 -03:00
PrototypeTrousers cef6dbf0d7 fix copy-paste error in the fluid storage bus constructor 2021-07-27 19:32:59 -03:00
Salomão e4af7b1947 fix adapters insert-only mode still reporting items 2021-07-27 12:51:24 -03:00
Salomão 6eadb8f861 fix IO-Port transfer stopping too soon 2021-07-27 11:10:45 -03:00
PrototypeTrousers b6b6a83563 do the same for fluid storage bus 2021-07-26 20:34:15 -03:00
PrototypeTrousers 32ab4c6af4 Merge remote-tracking branch 'PrototypeTrousers/AE2-Omnifactory' into AE2-Omnifactory 2021-07-26 18:25:24 -03:00
PrototypeTrousers fda8c87410 attempts to fix #42 and #43 2021-07-26 18:25:08 -03:00
PrototypeTrousers 389e060707 Merge pull request #41 from BalaM314/patch-1
Fix #27
2021-07-23 10:40:01 -03:00
BalaM314 0942a90ef4 Fix #27
Not sure exactly what method is causing a crash, but added a catch to just say it is located in another dimension
2021-07-23 15:11:07 +05:30
PrototypeTrousers 8cef06512a restore breaking API change 2021-07-22 21:50:56 -03:00
PrototypeTrousers 8e4658be20 fix power not going to sub-networks
renamed variables
2021-07-18 17:52:01 -03:00
PrototypeTrousers 0bd2bd6b5a dont pause main thread when calculating 2021-07-17 22:15:54 -03:00
PrototypeTrousers db2c4c4325 ensure the local energy cache is iterated last 2021-07-17 22:11:11 -03:00
Salomão ac793ee847 Merge branch 'delta' into AE2-Omnifactory 2021-07-17 14:48:22 -03:00
Salomão 6404f26cca Merge remote-tracking branch 'origin/fluid-terminal-multiple-containers' into AE2-Omnifactory 2021-07-16 14:22:21 -03:00
Salomão ced6ad865c re-introduce time-based calculation quota
player initiated crafting calculation is not affected
2021-07-16 14:22:09 -03:00
Salomão 24750f00b1 reworked how changes are propagated in the network 2021-07-16 14:13:48 -03:00
Salomão df08ce0513 Fluid terminal is now able to fill/empty stacked tanks 2021-07-04 10:28:36 -03:00
Salomão f9c274fb48 Reduce power flickering by increasing energy polling rate
in testing 84 dense cells could sustain MAX Integer on a FE p2p pair
2021-06-27 23:17:26 -03:00
Salomão 3582582e3f fix off-by-one voiding patterns when removing expansion cards 2021-06-26 10:25:47 -03:00
Salomão 6de48f8541 fixes #34
getAllIngredients() can contain nulls
2021-06-26 07:31:16 -03:00
Salomão 5a2c2d06d3 make pattern expansion recipe shapeless 2021-06-24 22:34:21 -03:00
Salomão 98d3cafdfd Merge branch 'oredictfixes' into AE2-Omnifactory 2021-06-23 10:19:02 -03:00
49 changed files with 1586 additions and 909 deletions
+13 -2
View File
@@ -15,6 +15,10 @@ Fixes:
- Exclusive Blocking mode for GTCE ( shapes, molds and configured circuits do not block GTCE machines ) - Exclusive Blocking mode for GTCE ( shapes, molds and configured circuits do not block GTCE machines )
- Blocking modes default to block on any item in the iventory the entity exposes - Blocking modes default to block on any item in the iventory the entity exposes
- Fuzzy includes items that report that they're damageable, but report a maxDamage of 0 ( auto-crafting of basic capacitors -> resonant capacitors is now possible ) <- Broken item implementation. - Fuzzy includes items that report that they're damageable, but report a maxDamage of 0 ( auto-crafting of basic capacitors -> resonant capacitors is now possible ) <- Broken item implementation.
- Fix CME exceptions on the energy grid
- Fix AE going offline even with enough power by extracting from the local buffer always last
- Fix IO-Port copying craftable flag into items
- Fix NBT of old items not clearing on drives that reached 64 types once
Performance: Performance:
@@ -24,6 +28,9 @@ Performance:
- Count items set in interfaces before queuing crafting for them needlessly - Count items set in interfaces before queuing crafting for them needlessly
- Backported b7ca98d ( Avoid copying items on simulated item extraction ) - Backported b7ca98d ( Avoid copying items on simulated item extraction )
- Cache some level emitters functions - Cache some level emitters functions
- Reduced import bus insert simulation to 1 before real insertion (if possible)
- Backported itemlist re-implementation along with pattern changes to avoid CraftingManager fallback issues
- Instead of recalculating all the content of the network on every change, track the changes properly and apply them to the cached list of items
QOL: QOL:
@@ -31,7 +38,7 @@ QOL:
- Added bar on the interface terminal that search by inputs ( The one on the LEFT, also searchs by interface name ) - Added bar on the interface terminal that search by inputs ( The one on the LEFT, also searchs by interface name )
- Shortcut to molecular assemblers with free slots on the terminal interface by @Theisyat - Shortcut to molecular assemblers with free slots on the terminal interface by @Theisyat
- Toggle button on interface terminal to hide full interfaces - Toggle button on interface terminal to hide full interfaces
- JEI "U""R" and "A" (Usages/Recipes/Bookmark) now work on the Crafting Status GUI. ( the one that shows the total items to craft, and whats missing) - JEI "U", "R" and "A" (Usages/Recipes/Bookmark) now work on the Crafting Status GUI. ( the one that shows the total items to craft, and whats missing)
- Patterns can now be made with items currently showing on JEI. ( This is overriden by Just Enough Energistics. ) - Patterns can now be made with items currently showing on JEI. ( This is overriden by Just Enough Energistics. )
- Added multiplier buttons to processing pattern gui - Added multiplier buttons to processing pattern gui
- Switched crafting terminal JEI search to fuzzy mode. If the recipe uses a damageable item, AE will try to grab it ( damaged tools ) - Switched crafting terminal JEI search to fuzzy mode. If the recipe uses a damageable item, AE will try to grab it ( damaged tools )
@@ -39,7 +46,11 @@ QOL:
- Encoded patterns can be draggred on the interface terminal. - Encoded patterns can be draggred on the interface terminal.
- Storage Monitor and Conversion Monitor now also ccepts fluids - Storage Monitor and Conversion Monitor now also ccepts fluids
- Draggable JEI ghost items (also works on bookmarked items. SHIFT + Click will move the hovered item into the first free target slot) - Draggable JEI ghost items (also works on bookmarked items. SHIFT + Click will move the hovered item into the first free target slot)
-JEI auto switches between crafting and processing patterns - JEI auto switches between crafting and processing patterns
- GTCE Blocking mode work through phantom itemfaces
- Shift-clicking blank patterns into the pattern terminal will try to fill the blank pattern slots first
- Mismached simulated/real item count ( most often due to compacting drawers ) will now tell the player wich item cause the failure when trying to start a craft
- Added 'pattern expansion' cards that adds an extra row of patterns to interfaces. up to 3 card on an interface. (each card will increase the interface idle power draw by 4 times)
HOTKEYS: HOTKEYS:
+1 -1
View File
@@ -3,7 +3,7 @@ aechannel=stable
aebuild=7 aebuild=7
aegroup=appeng aegroup=appeng
aebasename=appliedenergistics2 aebasename=appliedenergistics2
trousers=omni-fixes-v44d trousers=omni-fixes-v47
######################################################### #########################################################
# Versions # # Versions #
@@ -44,10 +44,7 @@ public interface IStackWatcherHost
/** /**
* Called when a watched item changes amounts. * Called when a watched item changes amounts.
* *
* @param o changed item list
* @param fullStack old stack
* @param diffStack new stack * @param diffStack new stack
* @param src action source
* @param chan storage channel * @param chan storage channel
*/ */
void onStackChange( IItemList<?> o, IAEStack<?> fullStack, IAEStack<?> diffStack, IActionSource src, IStorageChannel<?> chan ); void onStackChange( IItemList<?> o, IAEStack<?> fullStack, IAEStack<?> diffStack, IActionSource src, IStorageChannel<?> chan );
@@ -51,6 +51,7 @@ public interface IStorageGrid extends IGridCache, IStorageMonitorable
* @param input injected items * @param input injected items
*/ */
void postAlterationOfStoredItems( IStorageChannel<?> chan, Iterable<? extends IAEStack<?>> input, IActionSource src ); void postAlterationOfStoredItems( IStorageChannel<?> chan, Iterable<? extends IAEStack<?>> input, IActionSource src );
void postCraftablesChanges( IStorageChannel<?> chan, Iterable<? extends IAEStack<?>> input, IActionSource src);
/** /**
* Used to add a cell provider to the storage system * Used to add a cell provider to the storage system
@@ -237,7 +237,11 @@ public class GuiInterfaceTerminal extends AEBaseGui
int interfaceDim = dimHashMap.get( guiButtonHashMap.get( this.selectedButton ) ); int interfaceDim = dimHashMap.get( guiButtonHashMap.get( this.selectedButton ) );
if( playerDim != interfaceDim ) if( playerDim != interfaceDim )
{ {
mc.player.sendStatusMessage( new TextComponentString( "Interface located at dimension: " + interfaceDim + " [" + DimensionManager.getWorld( interfaceDim ).provider.getDimensionType().getName() + "] and cant be highlighted" ), false ); try {
mc.player.sendStatusMessage( new TextComponentString( "Interface located at dimension: " + interfaceDim + " [" + DimensionManager.getWorld( interfaceDim ).provider.getDimensionType().getName() + "] and cant be highlighted" ), false );
} catch(Exception e){
mc.player.sendStatusMessage( new TextComponentString( "Interface is located in another dimension and cannot be highlighted" ), false );
}
} }
else else
{ {
@@ -270,12 +270,15 @@ public class GuiUpgradeable extends AEBaseGui implements IJEIGhostIngredients
@Override @Override
public Rectangle getArea() public Rectangle getArea()
{ {
if( slot instanceof SlotFake ) if( slot instanceof SlotFake && ( (SlotFake) slot ).isSlotEnabled() )
{
return new Rectangle( getGuiLeft() + ( (SlotFake) slot ).xPos, getGuiTop() + ( (SlotFake) slot ).yPos, 16, 16 ); return new Rectangle( getGuiLeft() + ( (SlotFake) slot ).xPos, getGuiTop() + ( (SlotFake) slot ).yPos, 16, 16 );
else }
else if( slot instanceof GuiFluidSlot && ( (GuiFluidSlot) slot ).isSlotEnabled() )
{ {
return new Rectangle( getGuiLeft() + ( (GuiFluidSlot) slot ).xPos(), getGuiTop() + ( (GuiFluidSlot) slot ).yPos(), 16, 16 ); return new Rectangle( getGuiLeft() + ( (GuiFluidSlot) slot ).xPos(), getGuiTop() + ( (GuiFluidSlot) slot ).yPos(), 16, 16 );
} }
return new Rectangle();
} }
@Override @Override
@@ -284,7 +287,7 @@ public class GuiUpgradeable extends AEBaseGui implements IJEIGhostIngredients
PacketInventoryAction p = null; PacketInventoryAction p = null;
try try
{ {
if( slot instanceof SlotFake ) if( slot instanceof SlotFake && ( (SlotFake) slot ).isSlotEnabled() )
{ {
if( finalItemStack.isEmpty() && finalFluidStack != null ) if( finalItemStack.isEmpty() && finalFluidStack != null )
{ {
@@ -10,9 +10,9 @@ import net.minecraft.item.ItemStack;
public abstract class GuiCustomSlot extends Gui implements ITooltip public abstract class GuiCustomSlot extends Gui implements ITooltip
{ {
private final int x; protected final int x;
private final int y; protected final int y;
private final int id; protected final int id;
public GuiCustomSlot( final int id, final int x, final int y ) public GuiCustomSlot( final int id, final int x, final int y )
{ {
@@ -245,7 +245,10 @@ public class PacketJEIRecipe extends AppEngPacket
if( out != null ) if( out != null )
{ {
out.setStackSize( recipe[x][y].getCount() ); if (!cct.useRealItems())
{
out.setStackSize( recipe[x][y].getCount() );
}
currentItem = out.createItemStack(); currentItem = out.createItemStack();
} }
} }
@@ -19,6 +19,7 @@
package appeng.core.sync.packets; package appeng.core.sync.packets;
import appeng.fluids.container.ContainerFluidInterface;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
@@ -90,5 +91,9 @@ public class PacketTargetFluidStack extends AppEngPacket
{ {
( (ContainerFluidTerminal) player.openContainer ).setTargetStack( this.stack ); ( (ContainerFluidTerminal) player.openContainer ).setTargetStack( this.stack );
} }
else if( player.openContainer instanceof ContainerFluidInterface )
{
( (ContainerFluidInterface) player.openContainer ).setTargetStack( this.stack );
}
} }
} }
+67 -7
View File
@@ -22,6 +22,7 @@ package appeng.crafting;
import java.util.HashMap; import java.util.HashMap;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import appeng.me.cache.CraftingGridCache;
import com.google.common.base.Stopwatch; import com.google.common.base.Stopwatch;
import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayer;
@@ -59,6 +60,7 @@ public class CraftingJob implements Runnable, ICraftingJob
private final IItemList<IAEItemStack> missing = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList(); private final IItemList<IAEItemStack> missing = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList();
private final HashMap<String, TwoIntegers> opsAndMultiplier = new HashMap<>(); private final HashMap<String, TwoIntegers> opsAndMultiplier = new HashMap<>();
private final Object monitor = new Object(); private final Object monitor = new Object();
private final Stopwatch watch = Stopwatch.createUnstarted();
private CraftingTreeNode tree; private CraftingTreeNode tree;
private final IAEItemStack output; private final IAEItemStack output;
private boolean simulate = false; private boolean simulate = false;
@@ -66,7 +68,12 @@ public class CraftingJob implements Runnable, ICraftingJob
private long bytes = 0; private long bytes = 0;
private final IActionSource actionSrc; private final IActionSource actionSrc;
private final ICraftingCallback callback; private final ICraftingCallback callback;
private boolean running = false;
private boolean done = false; private boolean done = false;
private int time;
private int incTime;
private final ICraftingGrid cc;
private final IStorageGrid sg;
private World wrapWorld( final World w ) private World wrapWorld( final World w )
{ {
@@ -80,10 +87,9 @@ public class CraftingJob implements Runnable, ICraftingJob
this.actionSrc = actionSrc; this.actionSrc = actionSrc;
this.callback = callback; this.callback = callback;
final ICraftingGrid cc = grid.getCache( ICraftingGrid.class ); this.cc = grid.getCache( ICraftingGrid.class );
final IStorageGrid sg = grid.getCache( IStorageGrid.class ); this.sg = grid.getCache( IStorageGrid.class );
this.original = new MECraftingInventory( sg this.original = new MECraftingInventory( sg.getInventory( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ), actionSrc, false, false, false );
.getInventory( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ), actionSrc, false, false, false );
this.setTree( this.getCraftingTree( cc, what ) ); this.setTree( this.getCraftingTree( cc, what ) );
this.availableCheck = null; this.availableCheck = null;
@@ -133,6 +139,7 @@ public class CraftingJob implements Runnable, ICraftingJob
try try
{ {
TickHandler.INSTANCE.registerCraftingSimulation( this.world, this ); TickHandler.INSTANCE.registerCraftingSimulation( this.world, this );
this.handlePausing();
final Stopwatch timer = Stopwatch.createStarted(); final Stopwatch timer = Stopwatch.createStarted();
@@ -214,6 +221,41 @@ public class CraftingJob implements Runnable, ICraftingJob
this.finish(); this.finish();
} }
void handlePausing() throws InterruptedException
{
if( !this.actionSrc.player().isPresent() && this.incTime > 100 )
{
this.incTime = 0;
synchronized ( this.monitor )
{
if( this.watch.elapsed( TimeUnit.MICROSECONDS ) > this.time )
{
this.running = false;
this.watch.stop();
this.monitor.notify();
}
if( !this.running )
{
AELog.craftingDebug( "crafting job will now sleep" );
while ( !this.running )
{
this.monitor.wait();
}
AELog.craftingDebug( "crafting job now active" );
}
}
if( Thread.interrupted() )
{
throw new InterruptedException();
}
}
this.incTime++;
}
private void finish() private void finish()
{ {
if( this.callback != null ) if( this.callback != null )
@@ -225,6 +267,7 @@ public class CraftingJob implements Runnable, ICraftingJob
synchronized( this.monitor ) synchronized( this.monitor )
{ {
this.running = false;
this.done = true; this.done = true;
this.monitor.notify(); this.monitor.notify();
} }
@@ -270,13 +313,25 @@ public class CraftingJob implements Runnable, ICraftingJob
/** /**
* @return true if this needs more simulation * @return true if this needs more simulation
*/ */
public boolean simulateFor() public boolean simulateFor(final int milli)
{ {
synchronized( this.monitor ) { this.time = milli;
if ( this.done ) {
synchronized ( this.monitor )
{
if( this.done )
{
return false; return false;
} }
if( !this.actionSrc.player().isPresent() )
{
this.watch.reset();
this.watch.start();
this.monitor.notify();
}
this.running = true;
} }
return true; return true;
} }
@@ -327,6 +382,11 @@ public class CraftingJob implements Runnable, ICraftingJob
} }
} }
public void addIncompletablePattern( ICraftingPatternDetails details, IAEItemStack stack )
{
( (CraftingGridCache) cc ).getPatternStatusManager().put( details, stack );
}
private static class TwoIntegers private static class TwoIntegers
{ {
private final long perOp = 0; private final long perOp = 0;
@@ -22,7 +22,10 @@ package appeng.crafting;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Optional;
import appeng.util.item.OreHelper;
import appeng.util.item.OreReference;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import net.minecraft.world.World; import net.minecraft.world.World;
@@ -117,9 +120,14 @@ public class CraftingTreeNode
return this.parent.notRecursive( details ); return this.parent.notRecursive( details );
} }
public CraftingTreeProcess getParent()
{
return parent;
}
IAEItemStack request( final MECraftingInventory inv, long l, final IActionSource src ) throws CraftBranchFailure, InterruptedException IAEItemStack request( final MECraftingInventory inv, long l, final IActionSource src ) throws CraftBranchFailure, InterruptedException
{ {
this.job.handlePausing();
final List<IAEItemStack> thingsUsed = new ArrayList<>(); final List<IAEItemStack> thingsUsed = new ArrayList<>();
this.what.setStackSize( l ); this.what.setStackSize( l );
@@ -318,6 +326,7 @@ public class CraftingTreeNode
if( this.missing > 0 ) if( this.missing > 0 )
{ {
job.addMissing( this.getStack( this.missing ) ); job.addMissing( this.getStack( this.missing ) );
addMissingIAEStack();
} }
// missing = 0; // missing = 0;
@@ -329,6 +338,29 @@ public class CraftingTreeNode
} }
} }
void addMissingIAEStack()
{
if( parent != null )
{
parent.addMissingIAEStack();
if( missing > 0 )
{
if( this.parent.details.canSubstitute() && this.getSlot() >= 0 )
{
final List<IAEItemStack> substitutes = this.parent.details.getSubstituteInputs( this.slot );
for( IAEItemStack stack : substitutes )
{
job.addIncompletablePattern( this.getParent().details, stack.copy().setStackSize( this.missing ) );
}
}
else
{
job.addIncompletablePattern( this.getParent().details, this.getStack( this.missing ) );
}
}
}
}
IAEItemStack getStack( final long size ) IAEItemStack getStack( final long size )
{ {
final IAEItemStack is = this.what.copy(); final IAEItemStack is = this.what.copy();
@@ -23,11 +23,10 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import appeng.me.cache.CraftingGridCache;
import net.minecraft.inventory.InventoryCrafting; import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraftforge.fml.common.FMLCommonHandler;
import appeng.api.AEApi; import appeng.api.AEApi;
import appeng.api.config.Actionable; import appeng.api.config.Actionable;
@@ -66,7 +65,7 @@ public class CraftingTreeProcess
this.depth = depth; this.depth = depth;
final World world = job.getWorld(); final World world = job.getWorld();
if( details.isCraftable() ) if( !( (CraftingGridCache) cc ).getPatternStatusManager().containsIncompletablePattern( details ) && details.isCraftable() )
{ {
final IAEItemStack[] list = details.getInputs(); final IAEItemStack[] list = details.getInputs();
@@ -174,6 +173,11 @@ public class CraftingTreeProcess
return this.parent == null || this.parent.notRecursive( details ); return this.parent == null || this.parent.notRecursive( details );
} }
public CraftingTreeNode getParent()
{
return parent;
}
long getTimes( final long remaining, final long stackSize ) long getTimes( final long remaining, final long stackSize )
{ {
if( this.limitQty || this.fullSimulation ) if( this.limitQty || this.fullSimulation )
@@ -185,7 +189,7 @@ public class CraftingTreeProcess
void request( final MECraftingInventory inv, final long i, final IActionSource src ) throws CraftBranchFailure, InterruptedException void request( final MECraftingInventory inv, final long i, final IActionSource src ) throws CraftBranchFailure, InterruptedException
{ {
this.job.handlePausing();
if( this.fullSimulation ) if( this.fullSimulation )
{ {
final InventoryCrafting ic = new InventoryCrafting( new ContainerNull(), 3, 3 ); final InventoryCrafting ic = new InventoryCrafting( new ContainerNull(), 3, 3 );
@@ -317,4 +321,12 @@ public class CraftingTreeProcess
pro.getPlan( plan ); pro.getPlan( plan );
} }
} }
public void addMissingIAEStack()
{
if( parent != null )
{
parent.addMissingIAEStack();
}
}
} }
@@ -21,6 +21,9 @@ package appeng.fluids.client.gui;
import java.io.IOException; import java.io.IOException;
import appeng.api.util.IConfigManager;
import appeng.client.gui.widgets.GuiCustomSlot;
import appeng.util.IConfigManagerHost;
import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiButton;
import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.entity.player.InventoryPlayer;
@@ -38,11 +41,12 @@ import appeng.fluids.helper.IFluidInterfaceHost;
import appeng.fluids.util.IAEFluidTank; import appeng.fluids.util.IAEFluidTank;
public class GuiFluidInterface extends GuiUpgradeable public class GuiFluidInterface extends GuiUpgradeable implements IConfigManagerHost
{ {
public final static int ID_BUTTON_TANK = 222; public final static int ID_BUTTON_TANK = 222;
private final IFluidInterfaceHost host; private final IFluidInterfaceHost host;
private final ContainerFluidInterface container;
private GuiTabButton priority; private GuiTabButton priority;
public GuiFluidInterface( final InventoryPlayer ip, final IFluidInterfaceHost te ) public GuiFluidInterface( final InventoryPlayer ip, final IFluidInterfaceHost te )
@@ -50,6 +54,8 @@ public class GuiFluidInterface extends GuiUpgradeable
super( new ContainerFluidInterface( ip, te ) ); super( new ContainerFluidInterface( ip, te ) );
this.ySize = 231; this.ySize = 231;
this.host = te; this.host = te;
( this.container = (ContainerFluidInterface) this.inventorySlots ).setGui( this );
} }
@Override @Override
@@ -62,9 +68,7 @@ public class GuiFluidInterface extends GuiUpgradeable
for( int i = 0; i < DualityFluidInterface.NUMBER_OF_TANKS; ++i ) for( int i = 0; i < DualityFluidInterface.NUMBER_OF_TANKS; ++i )
{ {
final GuiFluidTank guiTank = new GuiFluidTank( fluidTank, i, DualityFluidInterface.NUMBER_OF_TANKS + i, this.getGuiLeft() + 35 + 18 * i, this this.guiSlots.add( new GuiFluidTank( fluidTank, i, DualityFluidInterface.NUMBER_OF_TANKS + i, 36 + 18 * i, 53, 16, 68 ) );
.getGuiTop() + 53, 16, 68 );
this.buttonList.add( guiTank );
this.guiSlots.add( new GuiFluidSlot( configFluids, i, i, 35 + 18 * i, 35 ) ); this.guiSlots.add( new GuiFluidSlot( configFluids, i, i, 35 + 18 * i, 35 ) );
} }
@@ -104,9 +108,33 @@ public class GuiFluidInterface extends GuiUpgradeable
} }
} }
@Override
protected void mouseClicked( int xCoord, int yCoord, int btn ) throws IOException
{
for( GuiCustomSlot slot : this.guiSlots )
{
if( slot instanceof GuiFluidTank )
{
if( this.isPointInRegion( slot.xPos(), slot.yPos(), slot.getWidth(), slot.getHeight(), xCoord, yCoord ) && slot.canClick( this.mc.player ) )
{
this.container.setTargetStack( ( (GuiFluidTank) slot ).getFluidStack() );
slot.slotClicked( this.mc.player.inventory.getItemStack(), btn );
return;
}
}
}
super.mouseClicked( xCoord, yCoord, btn );
}
@Override @Override
protected boolean drawUpgrades() protected boolean drawUpgrades()
{ {
return false; return false;
} }
@Override
public void updateSetting( IConfigManager manager, Enum settingName, Enum newValue )
{
}
} }
@@ -19,42 +19,50 @@
package appeng.fluids.client.gui.widgets; package appeng.fluids.client.gui.widgets;
import appeng.client.gui.widgets.GuiCustomSlot;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.PacketInventoryAction;
import appeng.helpers.InventoryAction;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.texture.TextureMap; import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly; import net.minecraftforge.fml.relauncher.SideOnly;
import appeng.api.storage.data.IAEFluidStack; import appeng.api.storage.data.IAEFluidStack;
import appeng.api.util.AEColor;
import appeng.client.gui.widgets.ITooltip; import appeng.client.gui.widgets.ITooltip;
import appeng.fluids.util.IAEFluidTank; import appeng.fluids.util.IAEFluidTank;
@SideOnly( Side.CLIENT ) @SideOnly( Side.CLIENT )
public class GuiFluidTank extends GuiButton implements ITooltip public class GuiFluidTank extends GuiCustomSlot implements ITooltip
{ {
private final IAEFluidTank tank; private final IAEFluidTank tank;
private final int slot; private final int slot;
private final int width;
private final int height;
public GuiFluidTank( IAEFluidTank tank, int slot, int id, int x, int y, int w, int h ) public GuiFluidTank( IAEFluidTank tank, int slot, int id, int x, int y, int w, int h )
{ {
super( id, x, y, w, h, "" ); super( id, x, y );
this.tank = tank; this.tank = tank;
this.slot = slot; this.slot = slot;
this.width = w;
this.height = h;
} }
@Override @Override
public void drawButton( final Minecraft mc, final int mouseX, final int mouseY, final float partialTicks ) public void drawContent( Minecraft mc, int mouseX, int mouseY, float partialTicks )
{ {
if( this.visible ) final IAEFluidStack fs = this.getFluidStack();
if( fs != null )
{ {
GlStateManager.disableBlend(); GlStateManager.disableBlend();
GlStateManager.disableLighting(); GlStateManager.disableLighting();
drawRect( this.x, this.y, this.x + this.width, this.y + this.height, AEColor.GRAY.blackVariant | 0xFF000000 ); //drawRect( this.x, this.y, this.x + this.width, this.y + this.height, AEColor.GRAY.blackVariant | 0xFF000000 );
final IAEFluidStack fluid = this.tank.getFluidInSlot( this.slot ); final IAEFluidStack fluid = this.tank.getFluidInSlot( this.slot );
if( fluid != null && fluid.getStackSize() > 0 ) if( fluid != null && fluid.getStackSize() > 0 )
@@ -69,17 +77,16 @@ public class GuiFluidTank extends GuiButton implements ITooltip
TextureAtlasSprite sprite = mc.getTextureMapBlocks().getAtlasSprite( fluid.getFluid().getStill().toString() ); TextureAtlasSprite sprite = mc.getTextureMapBlocks().getAtlasSprite( fluid.getFluid().getStill().toString() );
final int scaledHeight = (int) ( this.height * ( (float) fluid.getStackSize() / this.tank.getTankProperties()[this.slot].getCapacity() ) ); final int scaledHeight = (int) ( this.height * ( (float) fluid.getStackSize() / this.tank.getTankProperties()[this.slot].getCapacity() ) );
int iconHeightRemainder = scaledHeight % 16; int iconHeightRemainder = scaledHeight % this.getHeight();
if( iconHeightRemainder > 0 ) if( iconHeightRemainder > 0 )
{ {
this.drawTexturedModalRect( this.x, this.y + this.height - iconHeightRemainder, sprite, 16, iconHeightRemainder ); this.drawTexturedModalRect( this.xPos(), this.yPos() + this.getHeight() - iconHeightRemainder, sprite, this.getWidth(), iconHeightRemainder );
} }
for( int i = 0; i < scaledHeight / 16; i++ ) for( int i = 0; i < scaledHeight / this.getHeight(); i++ )
{ {
this.drawTexturedModalRect( this.x, this.y + this.height - iconHeightRemainder - ( i + 1 ) * 16, sprite, 16, 16 ); this.drawTexturedModalRect( this.xPos(), this.yPos() + this.getHeight() - iconHeightRemainder - ( i + 1 ) * 16, sprite, this.getWidth(), this.getHeight() );
} }
} }
} }
} }
@@ -100,25 +107,25 @@ public class GuiFluidTank extends GuiButton implements ITooltip
@Override @Override
public int xPos() public int xPos()
{ {
return this.x - 2; return this.x - 1;
} }
@Override @Override
public int yPos() public int yPos()
{ {
return this.y - 2; return this.y - 1;
} }
@Override @Override
public int getWidth() public int getWidth()
{ {
return this.width + 4; return this.width;
} }
@Override @Override
public int getHeight() public int getHeight()
{ {
return this.height + 4; return this.height + 1;
} }
@Override @Override
@@ -127,4 +134,24 @@ public class GuiFluidTank extends GuiButton implements ITooltip
return true; return true;
} }
public IAEFluidStack getFluidStack()
{
return this.tank.getFluidInSlot( this.slot );
}
@Override
public void slotClicked( ItemStack clickStack, final int mouseButton )
{
if( getFluidStack() != null )
{
NetworkHandler.instance().sendToServer( new PacketInventoryAction( InventoryAction.FILL_ITEM, slot, 0 ) );
}
else
{
NetworkHandler.instance().sendToServer( new PacketInventoryAction( InventoryAction.EMPTY_ITEM, slot, 0 ) );
}
}
} }
@@ -19,9 +19,17 @@
package appeng.fluids.container; package appeng.fluids.container;
import javax.annotation.Nonnull;
import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.PacketTargetFluidStack;
import appeng.fluids.util.AEFluidStack;
import appeng.helpers.InventoryAction;
import appeng.util.IConfigManagerHost;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.IContainerListener; import net.minecraft.inventory.IContainerListener;
@@ -33,12 +41,19 @@ import appeng.fluids.helper.FluidSyncHelper;
import appeng.fluids.helper.IFluidInterfaceHost; import appeng.fluids.helper.IFluidInterfaceHost;
import appeng.fluids.util.IAEFluidTank; import appeng.fluids.util.IAEFluidTank;
import appeng.util.Platform; import appeng.util.Platform;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidUtil;
import net.minecraftforge.fluids.capability.IFluidHandlerItem;
public class ContainerFluidInterface extends ContainerFluidConfigurable public class ContainerFluidInterface extends ContainerFluidConfigurable implements IConfigManagerHost
{ {
private final DualityFluidInterface myDuality; private final DualityFluidInterface myDuality;
private final FluidSyncHelper tankSync; private final FluidSyncHelper tankSync;
private IConfigManagerHost gui;
// Holds the fluid the client wishes to extract, or null for insert
private IAEFluidStack clientRequestedTargetFluid = null;
public ContainerFluidInterface( final InventoryPlayer ip, final IFluidInterfaceHost te ) public ContainerFluidInterface( final InventoryPlayer ip, final IFluidInterfaceHost te )
{ {
@@ -60,6 +75,15 @@ public class ContainerFluidInterface extends ContainerFluidConfigurable
return this.myDuality.getConfig(); return this.myDuality.getConfig();
} }
@Override
public void updateSetting( IConfigManager manager, Enum settingName, Enum newValue )
{
if( this.getGui() != null )
{
this.getGui().updateSetting( manager, settingName, newValue );
}
}
@Override @Override
public void detectAndSendChanges() public void detectAndSendChanges()
{ {
@@ -97,6 +121,126 @@ public class ContainerFluidInterface extends ContainerFluidConfigurable
this.tankSync.readPacket( fluids ); this.tankSync.readPacket( fluids );
} }
private IConfigManagerHost getGui()
{
return this.gui;
}
public void setGui( @Nonnull final IConfigManagerHost gui )
{
this.gui = gui;
}
public void doAction( EntityPlayerMP player, InventoryAction action, int slot, long id )
{
if( action != InventoryAction.FILL_ITEM && action != InventoryAction.EMPTY_ITEM )
{
super.doAction( player, action, slot, id );
return;
}
final ItemStack held = player.inventory.getItemStack();
ItemStack heldCopy = held.copy();
heldCopy.setCount( 1 );
IFluidHandlerItem fh = FluidUtil.getFluidHandler( heldCopy );
if( fh == null )
{
// only fluid handlers items
return;
}
if( action == InventoryAction.FILL_ITEM && this.clientRequestedTargetFluid != null )
{
final IAEFluidStack stack = this.clientRequestedTargetFluid.copy();
// Check how much we can store in the item
stack.setStackSize( Integer.MAX_VALUE );
int amountAllowed = fh.fill( stack.getFluidStack(), false );
int heldAmount = held.getCount();
for( int i = 0; i < heldAmount; i++ )
{
ItemStack copiedFluidContainer = held.copy();
copiedFluidContainer.setCount( 1 );
fh = FluidUtil.getFluidHandler( copiedFluidContainer );
FluidStack extractableFluid = this.myDuality.getTanks().drain( stack.setStackSize( amountAllowed ).getFluidStack(), false );
if( extractableFluid == null || extractableFluid.amount == 0 )
{
break;
}
int fillableAmount = fh.fill( extractableFluid, false );
if( fillableAmount > 0 )
{
FluidStack extractedFluid = this.myDuality.getTanks().drain( extractableFluid, true );
fh.fill( extractedFluid, true );
}
if( held.getCount() == 1 )
{
player.inventory.setItemStack( fh.getContainer() );
}
else
{
player.inventory.getItemStack().shrink( 1 );
if( !player.inventory.addItemStackToInventory( fh.getContainer() ) )
{
player.dropItem( fh.getContainer(), false );
}
}
}
}
else if( action == InventoryAction.EMPTY_ITEM )
{
int heldAmount = held.getCount();
for( int i = 0; i < heldAmount; i++ )
{
ItemStack copiedFluidContainer = held.copy();
copiedFluidContainer.setCount( 1 );
fh = FluidUtil.getFluidHandler( copiedFluidContainer );
FluidStack drainable = fh.drain( this.myDuality.getTanks().getTankProperties()[slot].getCapacity(), false );
if( drainable != null )
{
fh.drain( drainable, true );
this.myDuality.getTanks().fill( drainable, true );
}
if( held.getCount() == 1 )
{
player.inventory.setItemStack( fh.getContainer() );
}
else
{
player.inventory.getItemStack().shrink( 1 );
if( !player.inventory.addItemStackToInventory( fh.getContainer() ) )
{
player.dropItem( fh.getContainer(), false );
}
}
}
}
this.updateHeld( player );
}
public void setTargetStack( final IAEFluidStack stack )
{
if( Platform.isClient() )
{
if( stack == null && this.clientRequestedTargetFluid == null )
{
return;
}
if( stack != null && this.clientRequestedTargetFluid != null && stack.getFluidStack().isFluidEqual( this.clientRequestedTargetFluid.getFluidStack() ) )
{
return;
}
NetworkHandler.instance().sendToServer( new PacketTargetFluidStack( (AEFluidStack) stack ) );
}
this.clientRequestedTargetFluid = stack == null ? null : stack.copy();
}
@Override @Override
protected boolean supportCapacity() protected boolean supportCapacity()
{ {
@@ -24,6 +24,9 @@ import java.nio.BufferOverflowException;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import appeng.container.slot.AppEngSlot;
import appeng.container.slot.SlotPlayerHotBar;
import appeng.container.slot.SlotPlayerInv;
import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.entity.player.InventoryPlayer;
@@ -70,6 +73,7 @@ import appeng.me.helpers.ChannelPowerSrc;
import appeng.util.ConfigManager; import appeng.util.ConfigManager;
import appeng.util.IConfigManagerHost; import appeng.util.IConfigManagerHost;
import appeng.util.Platform; import appeng.util.Platform;
import net.minecraftforge.items.IItemHandler;
/** /**
@@ -342,6 +346,89 @@ public class ContainerFluidTerminal extends AEBaseContainer implements IConfigMa
} }
} }
@Override
public ItemStack transferStackInSlot( final EntityPlayer p, final int idx )
{
if( Platform.isClient() )
{
return ItemStack.EMPTY;
}
EntityPlayerMP player = (EntityPlayerMP) p;
if( this.inventorySlots.get( idx ) instanceof SlotPlayerInv || this.inventorySlots.get( idx ) instanceof SlotPlayerHotBar )
{
final AppEngSlot clickSlot = (AppEngSlot) this.inventorySlots.get( idx ); // require AE SLots!
ItemStack itemStack = clickSlot.getStack();
ItemStack copy = itemStack.copy();
copy.setCount( 1 );
IFluidHandlerItem fh = FluidUtil.getFluidHandler( copy );
if( fh == null )
{
// only fluid handlers items
return ItemStack.EMPTY;
}
int heldAmount = itemStack.getCount();
for( int i = 0; i < heldAmount; i++ )
{
copy = itemStack.copy();
copy.setCount( 1 );
fh = FluidUtil.getFluidHandler( copy );
final FluidStack extract = fh.drain( Integer.MAX_VALUE, false );
if( extract == null || extract.amount < 1 )
{
return ItemStack.EMPTY;
}
// Check if we can push into the system
final IAEFluidStack notStorable = Platform.poweredInsert( this.getPowerSource(), this.monitor, AEFluidStack.fromFluidStack( extract ), this.getActionSource(), Actionable.SIMULATE );
if( notStorable != null && notStorable.getStackSize() > 0 )
{
final int toStore = (int) ( extract.amount - notStorable.getStackSize() );
final FluidStack storable = fh.drain( toStore, false );
if( storable == null || storable.amount == 0 )
{
return ItemStack.EMPTY;
}
else
{
extract.amount = storable.amount;
}
}
// Actually drain
final FluidStack drained = fh.drain( extract, true );
extract.amount = drained.amount;
final IAEFluidStack notInserted = Platform.poweredInsert( this.getPowerSource(), this.monitor, AEFluidStack.fromFluidStack( extract ), this.getActionSource() );
if( notInserted != null && notInserted.getStackSize() > 0 )
{
IAEFluidStack spill = this.monitor.injectItems( notInserted, Actionable.MODULATE, this.getActionSource() );
if( spill != null && spill.getStackSize() > 0 )
{
fh.fill( spill.getFluidStack(), true );
}
}
if( notInserted == null )
{
if( !player.inventory.addItemStackToInventory( fh.getContainer() ) )
{
player.dropItem( fh.getContainer(), false );
}
clickSlot.decrStackSize( 1 );
}
}
this.detectAndSendChanges();
return ItemStack.EMPTY;
}
return super.transferStackInSlot( p, idx );
}
@Override @Override
public void doAction( EntityPlayerMP player, InventoryAction action, int slot, long id ) public void doAction( EntityPlayerMP player, InventoryAction action, int slot, long id )
{ {
@@ -352,13 +439,9 @@ public class ContainerFluidTerminal extends AEBaseContainer implements IConfigMa
} }
final ItemStack held = player.inventory.getItemStack(); final ItemStack held = player.inventory.getItemStack();
if( held.getCount() != 1 ) ItemStack heldCopy = held.copy();
{ heldCopy.setCount( 1 );
// only support stacksize 1 for now IFluidHandlerItem fh = FluidUtil.getFluidHandler( heldCopy );
return;
}
final IFluidHandlerItem fh = FluidUtil.getFluidHandler( held );
if( fh == null ) if( fh == null )
{ {
// only fluid handlers items // only fluid handlers items
@@ -372,88 +455,122 @@ public class ContainerFluidTerminal extends AEBaseContainer implements IConfigMa
// Check how much we can store in the item // Check how much we can store in the item
stack.setStackSize( Integer.MAX_VALUE ); stack.setStackSize( Integer.MAX_VALUE );
int amountAllowed = fh.fill( stack.getFluidStack(), false ); int amountAllowed = fh.fill( stack.getFluidStack(), false );
stack.setStackSize( amountAllowed ); int heldAmount = held.getCount();
for( int i = 0; i < heldAmount; i++ )
// Check if we can pull out of the system
final IAEFluidStack canPull = Platform.poweredExtraction( this.getPowerSource(), this.monitor, stack, this.getActionSource(), Actionable.SIMULATE );
if( canPull == null || canPull.getStackSize() < 1 )
{ {
return; ItemStack copiedFluidContainer = held.copy();
} copiedFluidContainer.setCount( 1 );
fh = FluidUtil.getFluidHandler( copiedFluidContainer );
// How much could fit into the container // Check if we can pull out of the system
final int canFill = fh.fill( canPull.getFluidStack(), false ); final IAEFluidStack canPull = Platform.poweredExtraction( this.getPowerSource(), this.monitor, stack.setStackSize( amountAllowed ), this.getActionSource(), Actionable.SIMULATE );
if( canFill == 0 ) if( canPull == null || canPull.getStackSize() < 1 )
{
return;
}
// Now actually pull out of the system
stack.setStackSize( canFill );
final IAEFluidStack pulled = Platform.poweredExtraction( this.getPowerSource(), this.monitor, stack, this.getActionSource() );
if( pulled == null || pulled.getStackSize() < 1 )
{
// Something went wrong
AELog.error( "Unable to pull fluid out of the ME system even though the simulation said yes " );
return;
}
// Actually fill
final int used = fh.fill( pulled.getFluidStack(), true );
if( used != canFill )
{
AELog.error( "Fluid item [%s] reported a different possible amount than it actually accepted.", held.getDisplayName() );
}
player.inventory.setItemStack( fh.getContainer() );
this.updateHeld( player );
}
else if( action == InventoryAction.EMPTY_ITEM )
{
// See how much we can drain from the item
final FluidStack extract = fh.drain( Integer.MAX_VALUE, false );
if( extract == null || extract.amount < 1 )
{
return;
}
// Check if we can push into the system
final IAEFluidStack notStorable = Platform.poweredInsert( this.getPowerSource(), this.monitor, AEFluidStack.fromFluidStack( extract ),
this.getActionSource(), Actionable.SIMULATE );
if( notStorable != null && notStorable.getStackSize() > 0 )
{
final int toStore = (int) ( extract.amount - notStorable.getStackSize() );
final FluidStack storable = fh.drain( toStore, false );
if( storable == null || storable.amount == 0 )
{ {
return; return;
} }
// How much could fit into the container
final int canFill = fh.fill( canPull.getFluidStack(), false );
if( canFill == 0 )
{
return;
}
// Now actually pull out of the system
final IAEFluidStack pulled = Platform.poweredExtraction( this.getPowerSource(), this.monitor, stack.setStackSize( canFill ), this.getActionSource() );
if( pulled == null || pulled.getStackSize() < 1 )
{
// Something went wrong
AELog.error( "Unable to pull fluid out of the ME system even though the simulation said yes " );
return;
}
// Actually fill
final int used = fh.fill( pulled.getFluidStack(), true );
if( used != canFill )
{
AELog.error( "Fluid item [%s] reported a different possible amount than it actually accepted.", held.getDisplayName() );
}
if( held.getCount() == 1 )
{
player.inventory.setItemStack( fh.getContainer() );
}
else else
{ {
extract.amount = storable.amount; player.inventory.getItemStack().shrink( 1 );
if( !player.inventory.addItemStackToInventory( fh.getContainer() ) )
{
player.dropItem( fh.getContainer(), false );
}
} }
} }
this.updateHeld( player );
// Actually drain }
final FluidStack drained = fh.drain( extract, true ); else if( action == InventoryAction.EMPTY_ITEM )
extract.amount = drained.amount; {
int heldAmount = held.getCount();
final IAEFluidStack notInserted = Platform.poweredInsert( this.getPowerSource(), this.monitor, AEFluidStack.fromFluidStack( extract ), for( int i = 0; i < heldAmount; i++ )
this.getActionSource() );
if( notInserted != null && notInserted.getStackSize() > 0 )
{ {
IAEFluidStack spill = this.monitor.injectItems( notInserted, Actionable.MODULATE, this.getActionSource() ); ItemStack copiedFluidContainer = held.copy();
if( spill != null && spill.getStackSize() > 0 ) copiedFluidContainer.setCount( 1 );
fh = FluidUtil.getFluidHandler( copiedFluidContainer );
// See how much we can drain from the item
final FluidStack extract = fh.drain( Integer.MAX_VALUE, false );
if( extract == null || extract.amount < 1 )
{ {
fh.fill( spill.getFluidStack(), true ); return;
}
// Check if we can push into the system
final IAEFluidStack notStorable = Platform.poweredInsert( this.getPowerSource(), this.monitor, AEFluidStack.fromFluidStack( extract ), this.getActionSource(), Actionable.SIMULATE );
if( notStorable != null && notStorable.getStackSize() > 0 )
{
final int toStore = (int) ( extract.amount - notStorable.getStackSize() );
final FluidStack storable = fh.drain( toStore, false );
if( storable == null || storable.amount == 0 )
{
return;
}
else
{
extract.amount = storable.amount;
}
}
// Actually drain
final FluidStack drained = fh.drain( extract, true );
extract.amount = drained.amount;
final IAEFluidStack notInserted = Platform.poweredInsert( this.getPowerSource(), this.monitor, AEFluidStack.fromFluidStack( extract ), this.getActionSource() );
if( notInserted != null && notInserted.getStackSize() > 0 )
{
IAEFluidStack spill = this.monitor.injectItems( notInserted, Actionable.MODULATE, this.getActionSource() );
if( spill != null && spill.getStackSize() > 0 )
{
fh.fill( spill.getFluidStack(), true );
}
}
if( held.getCount() == 1 )
{
player.inventory.setItemStack( fh.getContainer() );
}
else
{
player.inventory.getItemStack().shrink( 1 );
if( !player.inventory.addItemStackToInventory( fh.getContainer() ) )
{
player.dropItem( fh.getContainer(), false );
}
} }
} }
player.inventory.setItemStack( fh.getContainer() );
this.updateHeld( player ); this.updateHeld( player );
} }
} }
@@ -19,16 +19,15 @@
package appeng.fluids.parts; package appeng.fluids.parts;
import java.util.ArrayList; import java.util.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import appeng.api.config.AccessRestriction;
import appeng.api.config.Settings; import appeng.api.config.Settings;
import appeng.api.config.StorageFilter; import appeng.api.config.StorageFilter;
import appeng.parts.misc.PartStorageBus; import appeng.api.storage.data.IAEItemStack;
import appeng.me.GridAccessException;
import appeng.util.inv.ItemSlot;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidHandler; import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.IFluidTankProperties; import net.minecraftforge.fluids.capability.IFluidTankProperties;
@@ -45,7 +44,6 @@ import appeng.api.storage.channels.IFluidStorageChannel;
import appeng.api.storage.data.IAEFluidStack; import appeng.api.storage.data.IAEFluidStack;
import appeng.api.storage.data.IItemList; import appeng.api.storage.data.IItemList;
import appeng.fluids.util.AEFluidStack; import appeng.fluids.util.AEFluidStack;
import appeng.me.GridAccessException;
import appeng.me.helpers.IGridProxyable; import appeng.me.helpers.IGridProxyable;
import appeng.me.storage.ITickingMonitor; import appeng.me.storage.ITickingMonitor;
@@ -65,17 +63,20 @@ public class FluidHandlerAdapter implements IMEInventory<IAEFluidStack>, IBaseMo
private final IGridProxyable proxyable; private final IGridProxyable proxyable;
private final FluidHandlerAdapter.InventoryCache cache; private final FluidHandlerAdapter.InventoryCache cache;
private StorageFilter mode; private StorageFilter mode;
private AccessRestriction access;
FluidHandlerAdapter( IFluidHandler fluidHandler, IGridProxyable proxy ) FluidHandlerAdapter( IFluidHandler fluidHandler, IGridProxyable proxy )
{ {
this.fluidHandler = fluidHandler; this.fluidHandler = fluidHandler;
this.proxyable = proxy; this.proxyable = proxy;
if( this.proxyable instanceof PartStorageBus ) if( this.proxyable instanceof PartFluidStorageBus )
{ {
PartStorageBus partStorageBus = (PartStorageBus) this.proxyable; PartFluidStorageBus partFluidStorageBus = (PartFluidStorageBus) this.proxyable;
this.mode = ( (StorageFilter) partStorageBus.getConfigManager().getSetting( Settings.STORAGE_FILTER ) ); this.mode = ( (StorageFilter) partFluidStorageBus.getConfigManager().getSetting( Settings.STORAGE_FILTER ) );
this.access = ( (AccessRestriction) partFluidStorageBus.getConfigManager().getSetting( Settings.ACCESS ) );
} }
this.cache = new FluidHandlerAdapter.InventoryCache( this.fluidHandler, this.mode); this.cache = new FluidHandlerAdapter.InventoryCache( this.fluidHandler, this.mode );
this.cache.update();
} }
@Override @Override
@@ -94,11 +95,14 @@ public class FluidHandlerAdapter implements IMEInventory<IAEFluidStack>, IBaseMo
if( type == Actionable.MODULATE ) if( type == Actionable.MODULATE )
{ {
IAEFluidStack added = input.copy().setStackSize( input.getStackSize() - remaining );
this.cache.currentlyCached.add( added );
this.postDifference( Collections.singletonList( added ) );
try try
{ {
this.proxyable.getProxy().getTick().alertDevice( this.proxyable.getProxy().getNode() ); this.proxyable.getProxy().getTick().alertDevice( this.proxyable.getProxy().getNode() );
} }
catch( GridAccessException ignore ) catch( GridAccessException ex )
{ {
// meh // meh
} }
@@ -123,25 +127,32 @@ public class FluidHandlerAdapter implements IMEInventory<IAEFluidStack>, IBaseMo
return null; return null;
} }
IAEFluidStack gatheredAEFluidstack = AEFluidStack.fromFluidStack( gathered );
if( mode == Actionable.MODULATE ) if( mode == Actionable.MODULATE )
{ {
IAEFluidStack cachedStack = this.cache.currentlyCached.findPrecise( request );
if( cachedStack != null )
{
cachedStack.decStackSize( gatheredAEFluidstack.getStackSize() );
this.postDifference( Collections.singletonList( gatheredAEFluidstack.copy().setStackSize( -gatheredAEFluidstack.getStackSize() ) ) );
}
try try
{ {
this.proxyable.getProxy().getTick().alertDevice( this.proxyable.getProxy().getNode() ); this.proxyable.getProxy().getTick().alertDevice( this.proxyable.getProxy().getNode() );
} }
catch( GridAccessException ignore ) catch( GridAccessException ex )
{ {
// meh // meh
} }
} }
return AEFluidStack.fromFluidStack( gathered ); return gatheredAEFluidstack;
} }
@Override @Override
public TickRateModulation onTick() public TickRateModulation onTick()
{ {
List<IAEFluidStack> changes = this.cache.update(); List<IAEFluidStack> changes = this.cache.update();
if( !changes.isEmpty() ) if( !changes.isEmpty() && access.hasPermission( AccessRestriction.READ ) )
{ {
this.postDifference( changes ); this.postDifference( changes );
return TickRateModulation.URGENT; return TickRateModulation.URGENT;
@@ -202,9 +213,9 @@ public class FluidHandlerAdapter implements IMEInventory<IAEFluidStack>, IBaseMo
private static class InventoryCache private static class InventoryCache
{ {
private IAEFluidStack[] cachedAeStacks = new IAEFluidStack[0];
private final IFluidHandler fluidHandler; private final IFluidHandler fluidHandler;
private final StorageFilter mode; private final StorageFilter mode;
IItemList<IAEFluidStack> currentlyCached = AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ).createList();
public InventoryCache( IFluidHandler fluidHandler, StorageFilter mode ) public InventoryCache( IFluidHandler fluidHandler, StorageFilter mode )
{ {
@@ -216,19 +227,12 @@ public class FluidHandlerAdapter implements IMEInventory<IAEFluidStack>, IBaseMo
{ {
final List<IAEFluidStack> changes = new ArrayList<>(); final List<IAEFluidStack> changes = new ArrayList<>();
final IFluidTankProperties[] tankProperties = this.fluidHandler.getTankProperties(); final IFluidTankProperties[] tankProperties = this.fluidHandler.getTankProperties();
final int slots = tankProperties.length;
// Make room for new slots IItemList<IAEFluidStack> currentlyOnStorage = AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ).createList();
if( slots > this.cachedAeStacks.length )
{
this.cachedAeStacks = Arrays.copyOf( this.cachedAeStacks, slots );
}
for( int slot = 0; slot < slots; slot++ ) for( IFluidTankProperties tankProperty : tankProperties )
{ {
// Save the old stuff FluidStack newFS = tankProperty.getContents();
final IAEFluidStack oldAEFS = this.cachedAeStacks[slot];
FluidStack newFS = tankProperties[slot].getContents();
if( this.mode == StorageFilter.EXTRACTABLE_ONLY && newFS != null ) if( this.mode == StorageFilter.EXTRACTABLE_ONLY && newFS != null )
{ {
if( this.fluidHandler.drain( 1, false ) == null ) if( this.fluidHandler.drain( 1, false ) == null )
@@ -236,82 +240,40 @@ public class FluidHandlerAdapter implements IMEInventory<IAEFluidStack>, IBaseMo
newFS = null; newFS = null;
} }
} }
this.handlePossibleSlotChanges( slot, oldAEFS, newFS, changes ); if( newFS != null )
}
// Handle cases where the number of slots actually is lower now than before
if( slots < this.cachedAeStacks.length )
{
for( int slot = slots; slot < this.cachedAeStacks.length; slot++ )
{ {
final IAEFluidStack aeStack = this.cachedAeStacks[slot]; currentlyOnStorage.add( AEFluidStack.fromFluidStack( newFS ) );
if( aeStack != null )
{
final IAEFluidStack a = aeStack.copy();
a.setStackSize( -a.getStackSize() );
changes.add( a );
}
} }
this.cachedAeStacks = Arrays.copyOf( this.cachedAeStacks, slots );
} }
for ( final IAEFluidStack is : currentlyCached )
{
is.setStackSize( -is.getStackSize() );
}
for ( final IAEFluidStack is : currentlyOnStorage )
{
currentlyCached.add( is );
}
for ( final IAEFluidStack is : currentlyCached )
{
if( is.getStackSize() != 0 )
{
changes.add( is );
}
}
currentlyCached = currentlyOnStorage;
return changes; return changes;
} }
public IItemList<IAEFluidStack> getAvailableItems( IItemList<IAEFluidStack> out ) public IItemList<IAEFluidStack> getAvailableItems( IItemList<IAEFluidStack> out )
{ {
Arrays.stream( this.cachedAeStacks ).forEach( out::add ); currentlyCached.iterator().forEachRemaining( out::add );
return out; return out;
} }
private void handlePossibleSlotChanges( int slot, IAEFluidStack oldAeFS, FluidStack newFS, List<IAEFluidStack> changes )
{
if( oldAeFS != null && oldAeFS.getFluidStack().isFluidEqual( newFS ) )
{
this.handleStackSizeChanged( slot, oldAeFS, newFS, changes );
}
else
{
this.handleFluidChanged( slot, oldAeFS, newFS, changes );
}
}
private void handleStackSizeChanged( int slot, IAEFluidStack oldAeFS, FluidStack newFS, List<IAEFluidStack> changes )
{
// Still the same fluid, but amount might have changed
final long diff = newFS.amount - oldAeFS.getStackSize();
if( diff != 0 )
{
final IAEFluidStack stack = oldAeFS.copy();
stack.setStackSize( newFS.amount );
this.cachedAeStacks[slot] = stack;
final IAEFluidStack a = stack.copy();
a.setStackSize( diff );
changes.add( a );
}
}
private void handleFluidChanged( int slot, IAEFluidStack oldAeFS, FluidStack newFS, List<IAEFluidStack> changes )
{
// Completely different fluid
this.cachedAeStacks[slot] = AEFluidStack.fromFluidStack( newFS );
// If we had a stack previously in this slot, notify the network about its disappearance
if( oldAeFS != null )
{
oldAeFS.setStackSize( -oldAeFS.getStackSize() );
changes.add( oldAeFS );
}
// Notify the network about the new stack. Note that this is null if newFS was null
if( this.cachedAeStacks[slot] != null )
{
changes.add( this.cachedAeStacks[slot] );
}
}
} }
} }
@@ -204,7 +204,7 @@ public class PartFluidFormationPlane extends PartAbstractFormationPlane<IAEFluid
@Override @Override
public List<IMEInventoryHandler> getCellArray( final IStorageChannel channel ) public List<IMEInventoryHandler> getCellArray( final IStorageChannel channel )
{ {
if( this.getProxy().isActive() && channel == AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ) ) if( channel == AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ) )
{ {
final List<IMEInventoryHandler> handler = new ArrayList<>( 1 ); final List<IMEInventoryHandler> handler = new ArrayList<>( 1 );
handler.add( this.myHandler ); handler.add( this.myHandler );
@@ -4,7 +4,10 @@ package appeng.fluids.parts;
import java.util.Random; import java.util.Random;
import appeng.api.networking.events.MENetworkChannelChanged;
import appeng.api.storage.data.IItemList;
import appeng.fluids.helper.IConfigurableFluidInventory; import appeng.fluids.helper.IConfigurableFluidInventory;
import appeng.me.cache.NetworkMonitor;
import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagCompound;
@@ -34,7 +37,6 @@ import appeng.api.storage.IStorageChannel;
import appeng.api.storage.channels.IFluidStorageChannel; import appeng.api.storage.channels.IFluidStorageChannel;
import appeng.api.storage.data.IAEFluidStack; import appeng.api.storage.data.IAEFluidStack;
import appeng.api.storage.data.IAEStack; import appeng.api.storage.data.IAEStack;
import appeng.api.storage.data.IItemList;
import appeng.api.util.AECableType; import appeng.api.util.AECableType;
import appeng.api.util.AEPartLocation; import appeng.api.util.AEPartLocation;
import appeng.api.util.IConfigManager; import appeng.api.util.IConfigManager;
@@ -114,9 +116,9 @@ public class PartFluidLevelEmitter extends PartUpgradeable implements IStackWatc
@Override @Override
public void onStackChange( IItemList<?> o, IAEStack<?> fullStack, IAEStack<?> diffStack, IActionSource src, IStorageChannel<?> chan ) public void onStackChange( IItemList<?> o, IAEStack<?> fullStack, IAEStack<?> diffStack, IActionSource src, IStorageChannel<?> chan )
{ {
if( chan == AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ) && fullStack.equals( this.config.getFluidInSlot( 0 ) ) ) if( chan == AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ) && diffStack.equals( this.config.getFluidInSlot( 0 ) ) )
{ {
this.lastReportedValue = fullStack.getStackSize(); this.lastReportedValue += diffStack.getStackSize();
this.updateState(); this.updateState();
} }
} }
@@ -128,14 +130,22 @@ public class PartFluidLevelEmitter extends PartUpgradeable implements IStackWatc
} }
@MENetworkEventSubscribe @MENetworkEventSubscribe
public void channelChanged( final MENetworkChannelsChanged c ) public void powerStatusChange( final MENetworkPowerStatusChange powerEvent )
{ {
if (this.getProxy().isActive())
{
onListUpdate();
}
this.updateState(); this.updateState();
} }
@MENetworkEventSubscribe @MENetworkEventSubscribe
public void powerChanged( final MENetworkPowerStatusChange c ) public void channelChanged( final MENetworkChannelsChanged c )
{ {
if (this.getProxy().isActive())
{
onListUpdate();
}
this.updateState(); this.updateState();
} }
@@ -247,10 +257,9 @@ public class PartFluidLevelEmitter extends PartUpgradeable implements IStackWatc
if( myStack == null ) if( myStack == null )
{ {
this.lastReportedValue = 0; if( monitor instanceof NetworkMonitor )
for( final IAEFluidStack st : monitor.getStorageList() )
{ {
this.lastReportedValue += st.getStackSize(); this.lastReportedValue = ( (NetworkMonitor<IAEFluidStack>) monitor ).getGridCurrentCount();
} }
} }
else else
@@ -26,6 +26,7 @@ import java.util.Objects;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import appeng.fluids.helper.IConfigurableFluidInventory; import appeng.fluids.helper.IConfigurableFluidInventory;
import appeng.util.ConfigManager;
import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagCompound;
@@ -167,11 +168,28 @@ public class PartFluidStorageBus extends PartSharedStorageBus implements IMEMoni
final boolean fullReset = this.resetCacheLogic == 2; final boolean fullReset = this.resetCacheLogic == 2;
this.resetCacheLogic = 0; this.resetCacheLogic = 0;
final IMEInventory<IAEFluidStack> in = this.getInternalHandler(); final MEInventoryHandler<IAEFluidStack> in = this.getInternalHandler();
IItemList<IAEFluidStack> before = AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ).createList(); IItemList<IAEFluidStack> before = AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ).createList();
boolean denyRead = false;
if( in != null ) if( in != null )
{ {
before = in.getAvailableItems( before ); if( accessChanged )
{
AccessRestriction currentAccess = (AccessRestriction) ( (ConfigManager) this.getConfigManager() ).getSetting( Settings.ACCESS );
AccessRestriction oldAccess = (AccessRestriction) ( (ConfigManager) this.getConfigManager() ).getOldSetting( Settings.ACCESS );
if( oldAccess.hasPermission( AccessRestriction.READ ) && !currentAccess.hasPermission( AccessRestriction.READ ) )
{
denyRead = true;
}
in.setBaseAccess( oldAccess );
before = in.getAvailableItems( before );
in.setBaseAccess( currentAccess );
accessChanged = false;
}
else
{
before = in.getAvailableItems( before );
}
} }
this.cached = false; this.cached = false;
@@ -180,15 +198,17 @@ public class PartFluidStorageBus extends PartSharedStorageBus implements IMEMoni
this.handlerHash = 0; this.handlerHash = 0;
} }
final IMEInventory<IAEFluidStack> out = this.getInternalHandler(); final MEInventoryHandler<IAEFluidStack> out = this.getInternalHandler();
if( in != out ) if( in != out || denyRead )
{ {
IItemList<IAEFluidStack> after = AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ).createList(); IItemList<IAEFluidStack> after = AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ).createList();
if( out != null )
if( out != null && !denyRead )
{ {
after = out.getAvailableItems( after ); after = out.getAvailableItems( after );
} }
Platform.postListChanges( before, after, this, this.source ); Platform.postListChanges( before, after, this, this.source );
} }
} }
@@ -264,20 +284,25 @@ public class PartFluidStorageBus extends PartSharedStorageBus implements IMEMoni
@Override @Override
public void postChange( final IBaseMonitor<IAEFluidStack> monitor, final Iterable<IAEFluidStack> change, final IActionSource source ) public void postChange( final IBaseMonitor<IAEFluidStack> monitor, final Iterable<IAEFluidStack> change, final IActionSource source )
{ {
if( source == this.source || source.machine().map( machine -> machine == this ).orElse( false ) ) if( this.source.machine().map( machine -> machine == this ).orElse( false ) && monitor != null )
{ {
try AccessRestriction currentAccess = (AccessRestriction) ( (ConfigManager) this.getConfigManager() ).getSetting( Settings.ACCESS );
if( !currentAccess.hasPermission( AccessRestriction.READ ) )
{ {
if( this.getProxy().isActive() ) return;
{
this.getProxy().getStorage().postAlterationOfStoredItems( AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ), change, this.source );
}
} }
catch( final GridAccessException e ) }
try
{
if( this.getProxy().isActive() )
{ {
// :( this.getProxy().getStorage().postAlterationOfStoredItems( AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ), change, this.source );
} }
} }
catch( final GridAccessException e )
{
// :(
}
} }
public MEInventoryHandler<IAEFluidStack> getInternalHandler() public MEInventoryHandler<IAEFluidStack> getInternalHandler()
@@ -415,7 +440,7 @@ public class PartFluidStorageBus extends PartSharedStorageBus implements IMEMoni
{ {
if( channel == this.getStorageChannel() ) if( channel == this.getStorageChannel() )
{ {
final IMEInventoryHandler<IAEFluidStack> out = this.getProxy().isActive() ? this.getInternalHandler() : null; final IMEInventoryHandler<IAEFluidStack> out = this.getInternalHandler();
if( out != null ) if( out != null )
{ {
return Collections.singletonList( out ); return Collections.singletonList( out );
@@ -24,9 +24,12 @@ import java.util.*;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import appeng.api.definitions.IItemDefinition; import appeng.api.definitions.IItemDefinition;
import appeng.api.networking.crafting.*;
import appeng.integration.modules.gregtech.GTCEInventoryAdaptor; import appeng.integration.modules.gregtech.GTCEInventoryAdaptor;
import appeng.me.cache.CraftingGridCache;
import appeng.util.*; import appeng.util.*;
import appeng.util.inv.*; import appeng.util.inv.*;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import de.ellpeck.actuallyadditions.api.tile.IPhantomTile; import de.ellpeck.actuallyadditions.api.tile.IPhantomTile;
@@ -65,10 +68,6 @@ import appeng.api.implementations.tiles.ICraftingMachine;
import appeng.api.networking.GridFlags; import appeng.api.networking.GridFlags;
import appeng.api.networking.IGrid; import appeng.api.networking.IGrid;
import appeng.api.networking.IGridNode; import appeng.api.networking.IGridNode;
import appeng.api.networking.crafting.ICraftingLink;
import appeng.api.networking.crafting.ICraftingPatternDetails;
import appeng.api.networking.crafting.ICraftingProvider;
import appeng.api.networking.crafting.ICraftingProviderHelper;
import appeng.api.networking.energy.IEnergySource; import appeng.api.networking.energy.IEnergySource;
import appeng.api.networking.events.MENetworkCraftingPatternChange; import appeng.api.networking.events.MENetworkCraftingPatternChange;
import appeng.api.networking.security.IActionHost; import appeng.api.networking.security.IActionHost;
@@ -110,7 +109,6 @@ import static gregtech.api.block.machines.BlockMachine.getMetaTileEntity;
public class DualityInterface implements IGridTickable, IStorageMonitorable, IInventoryDestination, IAEAppEngInventory, IConfigManagerHost, ICraftingProvider, IUpgradeableHost public class DualityInterface implements IGridTickable, IStorageMonitorable, IInventoryDestination, IAEAppEngInventory, IConfigManagerHost, ICraftingProvider, IUpgradeableHost
{ {
private int[] failedCraftTriesSlot = {0,0,0,0,0,0,0,0,0};
public static final int NUMBER_OF_STORAGE_SLOTS = 9; public static final int NUMBER_OF_STORAGE_SLOTS = 9;
public static final int NUMBER_OF_CONFIG_SLOTS = 9; public static final int NUMBER_OF_CONFIG_SLOTS = 9;
@@ -608,14 +606,14 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
List<ItemStack> dropList = new ArrayList<>(); List<ItemStack> dropList = new ArrayList<>();
for( int invSlot = 0; invSlot < patterns.getSlots(); invSlot++ ) for( int invSlot = 0; invSlot < patterns.getSlots(); invSlot++ )
{ {
if( invSlot >= 9 + ( this.getInstalledUpgrades( Upgrades.PATTERN_EXPANSION ) ) * 9 ) if( invSlot > 8 + this.getInstalledUpgrades( Upgrades.PATTERN_EXPANSION ) * 9 )
{ {
ItemStack is = patterns.getStackInSlot( invSlot ); ItemStack is = patterns.getStackInSlot( invSlot );
if( is.isEmpty() ) continue; if( is.isEmpty() ) continue;
dropList.add( patterns.extractItem( invSlot, Integer.MAX_VALUE, false ) ); dropList.add( patterns.extractItem( invSlot, Integer.MAX_VALUE, false ) );
} }
} }
if( dropList.size() > 1 ) if( dropList.size() > 0 )
{ {
World world = this.getLocation().getWorld(); World world = this.getLocation().getWorld();
BlockPos blockPos = this.getLocation().getPos(); BlockPos blockPos = this.getLocation().getPos();
@@ -931,17 +929,7 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
{ {
if( this.getInstalledUpgrades( Upgrades.CRAFTING ) > 0 && itemStack != null ) if( this.getInstalledUpgrades( Upgrades.CRAFTING ) > 0 && itemStack != null )
{ {
if (this.failedCraftTriesSlot[x] <= 0) return this.craftingTracker.handleCrafting( x, itemStack.getStackSize(), itemStack, d, this.iHost.getTileEntity().getWorld(), this.gridProxy.getGrid(), this.gridProxy.getCrafting(), this.mySource );
{
boolean crafted = this.craftingTracker.handleCrafting( x, itemStack.getStackSize(), itemStack, d, this.iHost.getTileEntity().getWorld(),
this.gridProxy.getGrid(), this.gridProxy.getCrafting(), this.mySource );
if (crafted) this.failedCraftTriesSlot[x] = 0;
else{
this.failedCraftTriesSlot[x] += 2;
}
}
this.failedCraftTriesSlot[x] -= 1;
} }
} }
catch( final GridAccessException e ) catch( final GridAccessException e )
@@ -22,6 +22,9 @@ package appeng.helpers;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import appeng.api.networking.crafting.*;
import appeng.me.cache.CraftingGridCache;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagCompound;
@@ -29,10 +32,6 @@ import net.minecraft.world.World;
import appeng.api.AEApi; import appeng.api.AEApi;
import appeng.api.networking.IGrid; import appeng.api.networking.IGrid;
import appeng.api.networking.crafting.ICraftingGrid;
import appeng.api.networking.crafting.ICraftingJob;
import appeng.api.networking.crafting.ICraftingLink;
import appeng.api.networking.crafting.ICraftingRequester;
import appeng.api.networking.security.IActionSource; import appeng.api.networking.security.IActionSource;
import appeng.api.storage.data.IAEItemStack; import appeng.api.storage.data.IAEItemStack;
import appeng.util.InventoryAdaptor; import appeng.util.InventoryAdaptor;
@@ -132,6 +131,17 @@ public class MultiCraftingTracker
final IAEItemStack aisC = ais.copy(); final IAEItemStack aisC = ais.copy();
aisC.setStackSize( itemToCraft ); aisC.setStackSize( itemToCraft );
CraftingGridCache cgc = (CraftingGridCache) cg;
ImmutableCollection<ICraftingPatternDetails> cl = cgc.getCraftingFor( aisC, null, x, w );
for( ICraftingPatternDetails craftingPatternDetails : cl )
{
if( cgc.getPatternStatusManager().containsIncompletablePattern( craftingPatternDetails ) )
{
return false;
}
}
this.setJob( x, cg.beginCraftingJob( w, g, mySrc, aisC, null ) ); this.setJob( x, cg.beginCraftingJob( w, g, mySrc, aisC, null ) );
} }
} }
+7 -12
View File
@@ -187,20 +187,15 @@ public class TickHandler
if( ev.type == Type.WORLD && ev.phase == Phase.END ) if( ev.type == Type.WORLD && ev.phase == Phase.END )
{ {
final WorldTickEvent wte = (WorldTickEvent) ev; final WorldTickEvent wte = (WorldTickEvent) ev;
synchronized( this.craftingJobs ) synchronized ( this.craftingJobs )
{ {
final Collection<CraftingJob> jobSet = this.craftingJobs.get( wte.world ); final Collection<CraftingJob> jobSet = this.craftingJobs.get( wte.world );
if( !jobSet.isEmpty() ) if (!jobSet.isEmpty()) {
{ final int jobSize = jobSet.size();
final Iterator<CraftingJob> i = jobSet.iterator(); final int microSecondsPerTick = AEConfig.instance().getCraftingCalculationTimePerTick() * 1000;
while( i.hasNext() ) final int simTime = Math.max(1, microSecondsPerTick / jobSize);
{
final CraftingJob cj = i.next(); jobSet.removeIf( cj -> !cj.simulateFor( simTime ) );
if( !cj.simulateFor() )
{
i.remove();
}
}
} }
} }
} }
@@ -147,8 +147,12 @@ class RecipeTransferHandler<T extends Container> implements IRecipeTransferHandl
} }
// prefer pure crystals. // prefer pure crystals.
for( ItemStack stack : ingredient.getAllIngredients() ) for ( ItemStack stack : ingredient.getAllIngredients() )
{ {
if( stack == null )
{
continue;
}
if( Platform.isRecipePrioritized( stack ) ) if( Platform.isRecipePrioritized( stack ) )
{ {
list.add( 0, stack ); list.add( 0, stack );
@@ -159,7 +163,7 @@ class RecipeTransferHandler<T extends Container> implements IRecipeTransferHandl
} }
} }
for( final ItemStack is : list ) for ( final ItemStack is : list )
{ {
final NBTTagCompound tag = new NBTTagCompound(); final NBTTagCompound tag = new NBTTagCompound();
is.writeToNBT( tag ); is.writeToNBT( tag );
+28 -13
View File
@@ -30,22 +30,19 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadFactory;
import appeng.me.helpers.PatternStatusManager;
import com.google.common.collect.HashMultimap; import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableCollection; import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import it.unimi.dsi.fastutil.objects.*;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectRBTreeSet;
import it.unimi.dsi.fastutil.objects.ObjectSet;
import net.minecraft.world.World; import net.minecraft.world.World;
import appeng.api.AEApi; import appeng.api.AEApi;
@@ -270,20 +267,17 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper
// coalesce change events during a grid traversal to a single rebuild // coalesce change events during a grid traversal to a single rebuild
if (pauseRebuilds != 0) if (pauseRebuilds != 0)
{ {
rebuildNeeded.add(this); rebuildNeeded.add( this );
return; return;
} }
final Object2ObjectMap<IAEItemStack, ImmutableList<ICraftingPatternDetails>> oldItems = this.craftableItems; final Object2ObjectMap<IAEItemStack, ImmutableList<ICraftingPatternDetails>> oldItems = new Object2ObjectOpenHashMap<>( this.craftableItems );
// erase list. // erase list.
this.craftingMethods.clear(); this.craftingMethods.clear();
this.craftableItems.clear(); this.craftableItems.clear();
this.emitableItems.clear(); this.emitableItems.clear();
( (GridStorageCache) this.storageGrid ).clearPatternStatus();
// update the stuff that was in the list...
this.storageGrid.postAlterationOfStoredItems( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ), oldItems.keySet(),
new BaseActionSource() );
// re-create list.. // re-create list..
for( final ICraftingProvider provider : this.craftingProviders ) for( final ICraftingProvider provider : this.craftingProviders )
@@ -319,7 +313,23 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper
this.craftableItems.put( e.getKey(), ImmutableList.copyOf( e.getValue() ) ); this.craftableItems.put( e.getKey(), ImmutableList.copyOf( e.getValue() ) );
} }
this.storageGrid.postAlterationOfStoredItems( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ), this.craftableItems.keySet(), Object2ObjectMap<IAEItemStack, ImmutableList<ICraftingPatternDetails>> craftablesChanged = new Object2ObjectArrayMap<>();
ObjectSet<Entry<IAEItemStack, ImmutableList<ICraftingPatternDetails>>> i = oldItems.entrySet();
for ( Entry<IAEItemStack, ImmutableList<ICraftingPatternDetails>> ais : i) {
if (!this.craftableItems.containsKey( ais.getKey() )) {
craftablesChanged.put( ais.getKey().setCraftable( false ), ais.getValue() );
}
}
ObjectSet<Entry<IAEItemStack, ImmutableList<ICraftingPatternDetails>>> j = this.craftableItems.entrySet();
for ( Entry<IAEItemStack, ImmutableList<ICraftingPatternDetails>> ais : j) {
if (!oldItems.containsKey( ais )){
craftablesChanged.put( ais.getKey().setCraftable( true ), ais.getValue() );
}
}
this.storageGrid.postCraftablesChanges( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ), craftablesChanged.keySet(),
new BaseActionSource() ); new BaseActionSource() );
} }
@@ -639,7 +649,7 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper
public boolean hasCpu( final ICraftingCPU cpu ) public boolean hasCpu( final ICraftingCPU cpu )
{ {
if (cpu instanceof CraftingCPUCluster) if( cpu instanceof CraftingCPUCluster )
{ {
return this.craftingCPUClusters.contains( (CraftingCPUCluster) cpu ); return this.craftingCPUClusters.contains( (CraftingCPUCluster) cpu );
} }
@@ -651,6 +661,11 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper
return this.interestManager; return this.interestManager;
} }
public PatternStatusManager getPatternStatusManager()
{
return ( (GridStorageCache) this.storageGrid ).getPatternStatusManager();
}
private static class ActiveCpuIterator implements Iterator<ICraftingCPU> private static class ActiveCpuIterator implements Iterator<ICraftingCPU>
{ {
+101 -71
View File
@@ -19,21 +19,10 @@
package appeng.me.cache; package appeng.me.cache;
import java.util.Collection; import java.util.*;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.NavigableSet;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Set;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.collect.HashMultiset; import com.google.common.collect.*;
import com.google.common.collect.Multiset;
import com.google.common.collect.Sets;
import appeng.api.config.AccessRestriction; import appeng.api.config.AccessRestriction;
import appeng.api.config.Actionable; import appeng.api.config.Actionable;
@@ -81,7 +70,7 @@ public class EnergyGridCache implements IEnergyGrid
// Should only be modified from the add/remove methods below to guard against // Should only be modified from the add/remove methods below to guard against
// concurrent modifications // concurrent modifications
private final double averageLength = 40.0; private final double averageLength = 40.0;
private final Set<IAEPowerStorage> providers = new LinkedHashSet<>(); private final Multimap<Integer,IAEPowerStorage> providers = HashMultimap.create();
// Used to track whether an extraction is currently in progress, to fail fast // Used to track whether an extraction is currently in progress, to fail fast
// when something externally // when something externally
// modifies the energy grid. // modifies the energy grid.
@@ -89,7 +78,7 @@ public class EnergyGridCache implements IEnergyGrid
// Should only be modified from the add/remove methods below to guard against // Should only be modified from the add/remove methods below to guard against
// concurrent modifications // concurrent modifications
private final Set<IAEPowerStorage> requesters = new LinkedHashSet<>(); private final Multimap<Integer,IAEPowerStorage> requesters = HashMultimap.create();
// Used to track whether an injection is currently in progress, to fail fast // Used to track whether an injection is currently in progress, to fail fast
// when something externally // when something externally
// modifies the energy grid. // modifies the energy grid.
@@ -126,16 +115,16 @@ public class EnergyGridCache implements IEnergyGrid
private double lastStoredPower = -1; private double lastStoredPower = -1;
private final GridPowerStorage localStorage = new GridPowerStorage(); private final GridPowerStorage localStorage = new GridPowerStorage();
private Set<IAEPowerStorage> providerToRemove = new HashSet<>(); private Set<IAEPowerStorage> providersToRemove = new HashSet<>();
private Set<IAEPowerStorage> requesterToRemove = new HashSet<>(); private Set<IAEPowerStorage> requestersToRemove = new HashSet<>();
private Set<IAEPowerStorage> providersToAdd = new HashSet<>(); private Set<IAEPowerStorage> providersToAdd = new HashSet<>();
private Set<IAEPowerStorage> requesterToAdd = new HashSet<>(); private Set<IAEPowerStorage> requestersToAdd = new HashSet<>();
public EnergyGridCache( final IGrid g ) public EnergyGridCache( final IGrid g )
{ {
this.myGrid = g; this.myGrid = g;
this.requesters.add( this.localStorage ); this.requesters.put( 0, this.localStorage );
this.providers.add( this.localStorage ); this.providers.put( 1, this.localStorage );
} }
@MENetworkEventSubscribe @MENetworkEventSubscribe
@@ -187,7 +176,7 @@ public class EnergyGridCache implements IEnergyGrid
} }
else else
{ {
this.requesterToAdd.add( ev.storage ); this.requestersToAdd.add( ev.storage );
} }
} }
break; break;
@@ -202,23 +191,6 @@ public class EnergyGridCache implements IEnergyGrid
@Override @Override
public void onUpdateTick() public void onUpdateTick()
{ {
if (!providerToRemove.isEmpty() && !ongoingExtractOperation) {
this.providers.removeIf( p -> providerToRemove.contains( p ) );
providerToRemove.clear();
}
if (!requesterToRemove.isEmpty() && !ongoingInjectOperation) {
this.requesters.removeIf( r -> providerToRemove.contains( r ) );
requesterToRemove.clear();
}
if (!providersToAdd.isEmpty() && !ongoingExtractOperation) {
this.providers.addAll(providersToAdd);
providersToAdd.clear();
}
if( !requesterToAdd.isEmpty() && !ongoingInjectOperation){
this.requesters.addAll(requesterToAdd);
requesterToAdd.clear();
}
if( !this.interests.isEmpty() ) if( !this.interests.isEmpty() )
{ {
final double oldPower = this.lastStoredPower; final double oldPower = this.lastStoredPower;
@@ -335,7 +307,7 @@ public class EnergyGridCache implements IEnergyGrid
{ {
this.availableTicksSinceUpdate = 0; this.availableTicksSinceUpdate = 0;
this.globalAvailablePower = 0; this.globalAvailablePower = 0;
for( final IAEPowerStorage p : this.providers ) for( final IAEPowerStorage p : this.providers.values() )
{ {
this.globalAvailablePower += p.getAECurrentPower(); this.globalAvailablePower += p.getAECurrentPower();
} }
@@ -352,7 +324,19 @@ public class EnergyGridCache implements IEnergyGrid
{ {
double extractedPower = 0; double extractedPower = 0;
final Iterator<IAEPowerStorage> it = this.providers.iterator(); providersToAdd.forEach( provider -> {
if( provider instanceof GridPowerStorage )
{
providers.put( 1, provider );
}
else
{
providers.put( 0, provider );
}
} );
providersToAdd.clear();
final Iterator<IAEPowerStorage> it = this.providers.values().iterator();
ongoingExtractOperation = true; ongoingExtractOperation = true;
try try
@@ -361,12 +345,6 @@ public class EnergyGridCache implements IEnergyGrid
{ {
final IAEPowerStorage node = it.next(); final IAEPowerStorage node = it.next();
if ( providerToRemove.contains( node )) {
it.remove();
providerToRemove.remove( node );
continue;
}
final double req = amt - extractedPower; final double req = amt - extractedPower;
final double newPower = node.extractAEPower( req, mode, PowerMultiplier.ONE ); final double newPower = node.extractAEPower( req, mode, PowerMultiplier.ONE );
extractedPower += newPower; extractedPower += newPower;
@@ -376,7 +354,19 @@ public class EnergyGridCache implements IEnergyGrid
it.remove(); it.remove();
} }
} }
} finally { } finally
{
providersToRemove.forEach( provider -> {
if( provider instanceof GridPowerStorage )
{
providers.remove( 1, provider );
}
else
{
providers.remove( 0, provider );
}
} );
this.providersToRemove.clear();
ongoingExtractOperation = false; ongoingExtractOperation = false;
} }
@@ -401,7 +391,19 @@ public class EnergyGridCache implements IEnergyGrid
{ {
final double originalAmount = amt; final double originalAmount = amt;
final Iterator<IAEPowerStorage> it = this.requesters.iterator(); requestersToAdd.forEach( requester -> {
if( requester instanceof GridPowerStorage )
{
requesters.put( 0, requester );
}
else
{
requesters.put( 1, requester );
}
} );
requestersToAdd.clear();
final Iterator<IAEPowerStorage> it = this.requesters.values().iterator();
ongoingInjectOperation = true; ongoingInjectOperation = true;
try try
@@ -410,12 +412,6 @@ public class EnergyGridCache implements IEnergyGrid
{ {
final IAEPowerStorage node = it.next(); final IAEPowerStorage node = it.next();
if ( requesterToRemove.contains( node )) {
it.remove();
requesterToRemove.remove( node );
continue;
}
amt = node.injectAEPower( amt, mode ); amt = node.injectAEPower( amt, mode );
if( amt > 0 && mode == Actionable.MODULATE ) if( amt > 0 && mode == Actionable.MODULATE )
@@ -425,6 +421,17 @@ public class EnergyGridCache implements IEnergyGrid
} }
} finally } finally
{ {
requestersToRemove.forEach( requester -> {
if( requester instanceof GridPowerStorage )
{
requesters.remove( 0, requester );
}
else
{
requesters.remove( 1, requester );
}
} );
this.requestersToRemove.clear();
ongoingInjectOperation = false; ongoingInjectOperation = false;
} }
@@ -443,7 +450,7 @@ public class EnergyGridCache implements IEnergyGrid
{ {
double required = 0; double required = 0;
final Iterator<IAEPowerStorage> it = this.requesters.iterator(); final Iterator<IAEPowerStorage> it = this.requesters.values().iterator();
while( required < maxRequired && it.hasNext() ) while( required < maxRequired && it.hasNext() )
{ {
final IAEPowerStorage node = it.next(); final IAEPowerStorage node = it.next();
@@ -505,11 +512,7 @@ public class EnergyGridCache implements IEnergyGrid
@Override @Override
public double getStoredPower() public double getStoredPower()
{ {
if( this.availableTicksSinceUpdate > 2 ) this.refreshPower();
{
this.refreshPower();
}
return Math.max( 0.0, this.globalAvailablePower ); return Math.max( 0.0, this.globalAvailablePower );
} }
@@ -588,7 +591,7 @@ public class EnergyGridCache implements IEnergyGrid
} }
else else
{ {
this.providerToRemove.add( ps ); this.providersToRemove.add( ps );
} }
if( !ongoingInjectOperation ) if( !ongoingInjectOperation )
{ {
@@ -596,7 +599,7 @@ public class EnergyGridCache implements IEnergyGrid
} }
else else
{ {
this.requesterToRemove.add( ps ); this.requestersToRemove.add( ps );
} }
} }
} }
@@ -616,28 +619,55 @@ public class EnergyGridCache implements IEnergyGrid
private void addRequester(IAEPowerStorage requester) { private void addRequester(IAEPowerStorage requester) {
Preconditions.checkState(!ongoingInjectOperation, Preconditions.checkState(!ongoingInjectOperation,
"Cannot modify energy requesters while energy is being injected."); "Cannot modify energy requesters while energy is being injected.");
this.requesters.add(requester); if( requester instanceof GridPowerStorage )
{
requesters.put( 0, requester );
}
else
{
requesters.put( 1, requester );
}
} }
private void removeRequester(IAEPowerStorage requester) { private void removeRequester(IAEPowerStorage requester) {
Preconditions.checkState(!ongoingInjectOperation, Preconditions.checkState(!ongoingInjectOperation,
"Cannot modify energy requesters while energy is being injected."); "Cannot modify energy requesters while energy is being injected.");
this.requesters.remove(requester); if( requester instanceof GridPowerStorage )
{
requesters.remove( 0, requester );
}
else
{
requesters.remove( 1, requester );
}
} }
private void addProvider(IAEPowerStorage provider) { private void addProvider(IAEPowerStorage provider) {
Preconditions.checkState(!ongoingExtractOperation, Preconditions.checkState(!ongoingExtractOperation,
"Cannot modify energy providers while energy is being extracted."); "Cannot modify energy providers while energy is being extracted.");
this.providers.add(provider); if( provider instanceof GridPowerStorage )
{
providers.put( 1, provider );
}
else
{
providers.put( 0, provider );
}
} }
private void removeProvider(IAEPowerStorage provider) { private void removeProvider(IAEPowerStorage provider)
Preconditions.checkState(!ongoingExtractOperation, {
"Cannot modify energy providers while energy is being extracted."); Preconditions.checkState( !ongoingExtractOperation, "Cannot modify energy providers while energy is being extracted." );
this.providers.remove(provider); if( provider instanceof GridPowerStorage )
{
providers.remove( 1, provider );
}
else
{
providers.remove( 0, provider );
}
} }
@Override @Override
public void addNode( final IGridNode node, final IGridHost machine ) public void addNode( final IGridNode node, final IGridHost machine )
{ {
@@ -687,7 +717,7 @@ public class EnergyGridCache implements IEnergyGrid
} }
else else
{ {
this.requesterToAdd.add( ps ); this.requestersToAdd.add( ps );
} }
} }
} }
+25 -2
View File
@@ -26,7 +26,10 @@ import java.util.IdentityHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import appeng.api.networking.crafting.ICraftingPatternDetails;
import appeng.me.helpers.PatternStatusManager;
import com.google.common.collect.HashMultimap; import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.SetMultimap; import com.google.common.collect.SetMultimap;
import appeng.api.AEApi; import appeng.api.AEApi;
@@ -65,6 +68,10 @@ public class GridStorageCache implements IStorageGrid
private final HashSet<ICellProvider> inactiveCellProviders = new HashSet<>(); private final HashSet<ICellProvider> inactiveCellProviders = new HashSet<>();
private final SetMultimap<IAEStack, ItemWatcher> interests = HashMultimap.create(); private final SetMultimap<IAEStack, ItemWatcher> interests = HashMultimap.create();
private final GenericInterestManager<ItemWatcher> interestManager = new GenericInterestManager<>( this.interests ); private final GenericInterestManager<ItemWatcher> interestManager = new GenericInterestManager<>( this.interests );
private final Multimap<ICraftingPatternDetails, IAEStack> patternDetails2IAEStackMultimap = HashMultimap.create();
private final Multimap<IAEStack, ICraftingPatternDetails> iaeStack2PatternDetailsMultimap = HashMultimap.create();
private final PatternStatusManager patternStatusManager = new PatternStatusManager( this.patternDetails2IAEStackMultimap, this.iaeStack2PatternDetailsMultimap );
private final HashMap<IGridNode, IStackWatcher> watchers = new HashMap<>(); private final HashMap<IGridNode, IStackWatcher> watchers = new HashMap<>();
private Map<IStorageChannel<? extends IAEStack>, NetworkInventoryHandler<?>> storageNetworks; private Map<IStorageChannel<? extends IAEStack>, NetworkInventoryHandler<?>> storageNetworks;
private Map<IStorageChannel<? extends IAEStack>, NetworkMonitor<?>> storageMonitors; private Map<IStorageChannel<? extends IAEStack>, NetworkMonitor<?>> storageMonitors;
@@ -248,8 +255,6 @@ public class GridStorageCache implements IStorageGrid
} }
} }
this.storageMonitors.forEach( ( channel, monitor ) -> monitor.forceUpdate() );
tracker.applyChanges(); tracker.applyChanges();
} }
@@ -281,6 +286,12 @@ public class GridStorageCache implements IStorageGrid
this.storageMonitors.get( chan ).postChange( true, (Iterable) input, src ); this.storageMonitors.get( chan ).postChange( true, (Iterable) input, src );
} }
@Override
public void postCraftablesChanges( IStorageChannel<?> chan, Iterable<? extends IAEStack<?>> input, IActionSource src )
{
this.storageMonitors.get( chan ).updateCraftables( (Iterable) input, src );
}
@Override @Override
public void registerCellProvider( final ICellProvider provider ) public void registerCellProvider( final ICellProvider provider )
{ {
@@ -300,6 +311,18 @@ public class GridStorageCache implements IStorageGrid
return this.interestManager; return this.interestManager;
} }
public PatternStatusManager getPatternStatusManager()
{
return this.patternStatusManager;
}
public void clearPatternStatus()
{
System.out.println( "reseting pattern status due to pattern changes" );
this.patternDetails2IAEStackMultimap.clear();
this.iaeStack2PatternDetailsMultimap.clear();
}
IGrid getGrid() IGrid getGrid()
{ {
return this.myGrid; return this.myGrid;
+123 -104
View File
@@ -19,34 +19,35 @@
package appeng.me.cache; package appeng.me.cache;
import java.util.Collection;
import java.util.Deque;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import javax.annotation.Nonnegative; import javax.annotation.Nonnegative;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import appeng.api.AEApi;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Queues;
import appeng.api.config.AccessRestriction; import appeng.api.config.AccessRestriction;
import appeng.api.config.Actionable; import appeng.api.config.Actionable;
import appeng.api.config.FuzzyMode;
import appeng.api.networking.crafting.ICraftingPatternDetails;
import appeng.api.networking.events.MENetworkStorageEvent; import appeng.api.networking.events.MENetworkStorageEvent;
import appeng.api.networking.security.IActionSource; import appeng.api.networking.security.IActionSource;
import appeng.api.storage.IMEInventoryHandler; import appeng.api.storage.IMEInventoryHandler;
import appeng.api.storage.IMEMonitor; import appeng.api.storage.IMEMonitor;
import appeng.api.storage.IMEMonitorHandlerReceiver; import appeng.api.storage.IMEMonitorHandlerReceiver;
import appeng.api.storage.IStorageChannel; import appeng.api.storage.IStorageChannel;
import appeng.api.storage.channels.IFluidStorageChannel;
import appeng.api.storage.channels.IItemStorageChannel;
import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IAEStack; import appeng.api.storage.data.IAEStack;
import appeng.api.storage.data.IItemList; import appeng.api.storage.data.IItemList;
import appeng.me.storage.ItemWatcher; import appeng.me.storage.ItemWatcher;
import com.google.common.collect.Queues;
import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import java.util.Collection;
import java.util.Deque;
import java.util.Iterator;
import java.util.Map.Entry;
public class NetworkMonitor<T extends IAEStack<T>> implements IMEMonitor<T> public class NetworkMonitor<T extends IAEStack<T>> implements IMEMonitor<T>
{ {
@@ -63,9 +64,10 @@ public class NetworkMonitor<T extends IAEStack<T>> implements IMEMonitor<T>
private final Object2ObjectMap<IMEMonitorHandlerReceiver<T>, Object> listeners; private final Object2ObjectMap<IMEMonitorHandlerReceiver<T>, Object> listeners;
private boolean sendEvent = false; private boolean sendEvent = false;
private boolean hasChanged = false;
@Nonnegative @Nonnegative
private int localDepthSemaphore = 0; private int localDepthSemaphore = 0;
private long gridItemCount;
private long gridFluidCount;
public NetworkMonitor( final GridStorageCache cache, final IStorageChannel<T> chan ) public NetworkMonitor( final GridStorageCache cache, final IStorageChannel<T> chan )
{ {
@@ -90,21 +92,7 @@ public class NetworkMonitor<T extends IAEStack<T>> implements IMEMonitor<T>
@Override @Override
public T extractItems( final T request, final Actionable mode, final IActionSource src ) public T extractItems( final T request, final Actionable mode, final IActionSource src )
{ {
if( mode == Actionable.SIMULATE ) return this.getHandler().extractItems( request, mode, src );
{
return this.getHandler().extractItems( request, mode, src );
}
this.localDepthSemaphore++;
final T leftover = this.getHandler().extractItems( request, mode, src );
this.localDepthSemaphore--;
if( this.localDepthSemaphore == 0 )
{
this.monitorDifference( request.copy(), leftover, true, src );
}
return leftover;
} }
@Override @Override
@@ -137,38 +125,43 @@ public class NetworkMonitor<T extends IAEStack<T>> implements IMEMonitor<T>
return this.getHandler().getSlot(); return this.getHandler().getSlot();
} }
public long getGridCurrentCount()
{
if( myChannel == AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) )
{
return gridItemCount;
}
else if( myChannel == AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ) )
{
return gridFluidCount;
}
return 0;
}
public long incGridCurrentCount(long count)
{
if( myChannel == AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) )
{
return gridItemCount += count;
}
else if( myChannel == AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ) )
{
return gridFluidCount += count;
}
return 0;
}
@Nonnull @Nonnull
@Override @Override
public IItemList<T> getStorageList() public IItemList<T> getStorageList()
{ {
if( hasChanged )
{
hasChanged = false;
this.cachedList.resetStatus();
return this.getAvailableItems( this.cachedList );
}
return this.cachedList; return this.cachedList;
} }
@Override @Override
public T injectItems( final T input, final Actionable mode, final IActionSource src ) public T injectItems( final T input, final Actionable mode, final IActionSource src )
{ {
if( mode == Actionable.SIMULATE ) return this.getHandler().injectItems( input, mode, src );
{
return this.getHandler().injectItems( input, mode, src );
}
this.localDepthSemaphore++;
final T leftover = this.getHandler().injectItems( input, mode, src );
this.localDepthSemaphore--;
if( this.localDepthSemaphore == 0 )
{
this.monitorDifference( input.copy(), leftover, false, src );
}
return leftover;
} }
@Override @Override
@@ -200,30 +193,8 @@ public class NetworkMonitor<T extends IAEStack<T>> implements IMEMonitor<T>
return this.listeners.entrySet().iterator(); return this.listeners.entrySet().iterator();
} }
private T monitorDifference( final IAEStack<T> original, final T leftOvers, final boolean extraction, final IActionSource src )
{
final T diff = original.copy();
if( extraction )
{
diff.setStackSize( leftOvers == null ? 0 : -leftOvers.getStackSize() );
}
else if( leftOvers != null )
{
diff.decStackSize( leftOvers.getStackSize() );
}
if( diff.getStackSize() != 0 )
{
this.postChangesToListeners( ImmutableList.of( diff ), src );
}
return leftOvers;
}
private void notifyListenersOfChange( final Iterable<T> diff, final IActionSource src ) private void notifyListenersOfChange( final Iterable<T> diff, final IActionSource src )
{ {
this.hasChanged = true;
final Iterator<Entry<IMEMonitorHandlerReceiver<T>, Object>> i = this.getListeners(); final Iterator<Entry<IMEMonitorHandlerReceiver<T>, Object>> i = this.getListeners();
while( i.hasNext() ) while( i.hasNext() )
@@ -241,35 +212,41 @@ public class NetworkMonitor<T extends IAEStack<T>> implements IMEMonitor<T>
} }
} }
private void postChangesToListeners( final Iterable<T> changes, final IActionSource src ) protected void updateCraftables( Iterable<T> input, IActionSource src )
{ {
this.postChange( true, changes, src ); for( final T changedItem : input )
{
if (changedItem.isCraftable()) {
this.cachedList.add( changedItem.copy().setCraftable( true ) );
}
else
{
this.cachedList.findPrecise( changedItem ).setCraftable( false );
}
}
} }
protected void postChange( final boolean add, final Iterable<T> changes, final IActionSource src ) protected void postChange( final boolean add, final Iterable<T> changes, final IActionSource src )
{ {
if( this.localDepthSemaphore > 0 || GLOBAL_DEPTH.contains( this ) ) if( GLOBAL_DEPTH.contains( this ) )
{ {
return; return;
} }
GLOBAL_DEPTH.push( this ); GLOBAL_DEPTH.push( this );
this.localDepthSemaphore++;
this.sendEvent = true; this.sendEvent = true;
this.notifyListenersOfChange( changes, src );
for( final T changedItem : changes ) for( final T changedItem : changes )
{ {
T difference = changedItem;
if( !add && changedItem != null ) if( !add && changedItem != null )
{ {
difference = changedItem.copy(); changedItem.setStackSize( -changedItem.getStackSize() );
difference.setStackSize( -changedItem.getStackSize() );
} }
incGridCurrentCount( changedItem.getStackSize() );
this.cachedList.add( changedItem );
if( this.myGridCache.getInterestManager().containsKey( changedItem ) ) if( this.myGridCache.getInterestManager().containsKey( changedItem ) )
{ {
final Collection<ItemWatcher> list = this.myGridCache.getInterestManager().get( changedItem ); final Collection<ItemWatcher> list = this.myGridCache.getInterestManager().get( changedItem );
@@ -288,16 +265,78 @@ public class NetworkMonitor<T extends IAEStack<T>> implements IMEMonitor<T>
for( final ItemWatcher iw : list ) for( final ItemWatcher iw : list )
{ {
iw.getHost().onStackChange( this.getStorageList(), fullStack, difference, src, this.getChannel() ); iw.getHost().onStackChange( this.getStorageList(), fullStack, changedItem, src, this.getChannel() );
} }
this.myGridCache.getInterestManager().disableTransactions(); this.myGridCache.getInterestManager().disableTransactions();
} }
} }
if( changedItem instanceof IAEItemStack )
{
if( this.myGridCache.getPatternStatusManager().containsMissingIAEStack( changedItem ) )
{
this.myGridCache.getPatternStatusManager().enableTransactions();
for( ICraftingPatternDetails craftingPatternDetails : this.myGridCache.getPatternStatusManager().getIncompletablePattern( changedItem ) )
{
for( IAEStack stack : this.myGridCache.getPatternStatusManager().getMissingIAEStack( craftingPatternDetails ) )
{
if( craftingPatternDetails.canSubstitute() )
{
if( ( (IAEItemStack) stack ).getItem().isDamageable() )
{
if( ( (IAEStack) changedItem ).fuzzyComparison( stack, FuzzyMode.IGNORE_ALL ) )
{
if( changedItem.getStackSize() > 0 )
{
this.myGridCache.getPatternStatusManager().remove( craftingPatternDetails, stack );
}
}
}
else
{
if( ( (IAEItemStack) stack ).sameOre( (IAEItemStack) changedItem ) )
{
if( changedItem.getStackSize() > 0 )
{
if( changedItem.getStackSize() >= stack.getStackSize() )
{
this.myGridCache.getPatternStatusManager().remove( craftingPatternDetails, stack );
}
else
{
stack.decStackSize( changedItem.getStackSize() );
}
}
}
}
}
else if( stack.equals( changedItem ) )
{
if( changedItem.getStackSize() > 0 )
{
if( changedItem.getStackSize() >= stack.getStackSize() )
{
this.myGridCache.getPatternStatusManager().remove( craftingPatternDetails, stack );
}
else
{
stack.decStackSize( changedItem.getStackSize() );
}
}
}
}
}
this.myGridCache.getPatternStatusManager().disableTransactions();
}
}
} }
this.notifyListenersOfChange( changes, src );
final NetworkMonitor<?> last = GLOBAL_DEPTH.pop(); final NetworkMonitor<?> last = GLOBAL_DEPTH.pop();
this.localDepthSemaphore--;
if( last != this ) if( last != this )
{ {
@@ -305,27 +344,6 @@ public class NetworkMonitor<T extends IAEStack<T>> implements IMEMonitor<T>
} }
} }
void forceUpdate()
{
this.hasChanged = true;
final Iterator<Entry<IMEMonitorHandlerReceiver<T>, Object>> i = this.getListeners();
while( i.hasNext() )
{
final Entry<IMEMonitorHandlerReceiver<T>, Object> o = i.next();
final IMEMonitorHandlerReceiver<T> receiver = o.getKey();
if( receiver.isValid( o.getValue() ) )
{
receiver.onListUpdate();
}
else
{
i.remove();
}
}
}
void onTick() void onTick()
{ {
if( this.sendEvent ) if( this.sendEvent )
@@ -333,5 +351,6 @@ public class NetworkMonitor<T extends IAEStack<T>> implements IMEMonitor<T>
this.sendEvent = false; this.sendEvent = false;
this.myGridCache.getGrid().postEvent( new MENetworkStorageEvent( this, this.myChannel ) ); this.myGridCache.getGrid().postEvent( new MENetworkStorageEvent( this, this.myChannel ) );
} }
} }
} }
-1
View File
@@ -138,7 +138,6 @@ public class TickManagerCache implements ITickManager
tt.addEntityCrashInfo( crashreportcategory ); tt.addEntityCrashInfo( crashreportcategory );
throw new ReportedException( crashreport ); throw new ReportedException( crashreport );
} }
PartLevelEmitter.wipeCache();
} }
private void addToQueue( final TickTracker tt ) private void addToQueue( final TickTracker tt )
@@ -23,9 +23,10 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import com.google.common.collect.Multimap; import appeng.api.config.FuzzyMode;
import appeng.api.storage.data.IAEStack; import appeng.api.storage.data.IAEStack;
import appeng.util.item.AEItemStack;
import com.google.common.collect.Multimap;
public class GenericInterestManager<T> public class GenericInterestManager<T>
@@ -101,12 +102,30 @@ public class GenericInterestManager<T>
public boolean containsKey( final IAEStack stack ) public boolean containsKey( final IAEStack stack )
{ {
if( stack.isItem() && ( ( AEItemStack ) stack ).getItem().isDamageable() )
{
return this.container.keySet().stream().filter( s -> s.isItem() )
.anyMatch( s -> s.fuzzyComparison( stack, FuzzyMode.IGNORE_ALL ) );
}
return this.container.containsKey( stack ); return this.container.containsKey( stack );
} }
public Collection<T> get( final IAEStack stack ) public Collection<T> get( final IAEStack stack )
{ {
return this.container.get( stack ); Collection<T> watchers = new ArrayList<>();
if( stack.isItem() && ( ( AEItemStack ) stack ).getItem().isDamageable() )
{
this.container.keySet().stream().filter( s -> s.isItem() )
.filter( k -> k.fuzzyComparison( stack, FuzzyMode.IGNORE_ALL ) )
.forEach( key ->
watchers.addAll( this.container.get( key ) )
);
}
else
{
return this.container.get( stack );
}
return watchers;
} }
private class SavedTransactions private class SavedTransactions
@@ -0,0 +1,166 @@
/*
* 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.helpers;
import appeng.api.config.FuzzyMode;
import appeng.api.networking.crafting.ICraftingPatternDetails;
import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IAEStack;
import com.google.common.collect.Multimap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class PatternStatusManager
{
private final Multimap<ICraftingPatternDetails, IAEStack> patternDetailsIAEStackMultimap;
private final Multimap<IAEStack, ICraftingPatternDetails> iaeStackPatternDetailsMultimap;
private List<SavedTransactions> transactions = null;
private int transDepth = 0;
public PatternStatusManager( final Multimap<ICraftingPatternDetails, IAEStack> interests, final Multimap<IAEStack, ICraftingPatternDetails> interested )
{
this.patternDetailsIAEStackMultimap = interests;
this.iaeStackPatternDetailsMultimap = interested;
}
public void enableTransactions()
{
if( this.transDepth == 0 )
{
this.transactions = new ArrayList<>();
}
this.transDepth++;
}
public void disableTransactions()
{
this.transDepth--;
if( this.transDepth == 0 )
{
final List<SavedTransactions> myActions = this.transactions;
this.transactions = null;
for( final SavedTransactions t : myActions )
{
if( t.put )
{
this.put( t.patternDetails, t.stack );
}
else
{
this.remove( t.patternDetails, t.stack );
}
}
}
}
public boolean put( final ICraftingPatternDetails craftingPatternDetails, final IAEStack debtStack )
{
if( this.transactions != null )
{
this.transactions.add( new SavedTransactions( true, craftingPatternDetails, debtStack ) );
return true;
}
else
{
this.iaeStackPatternDetailsMultimap.put( debtStack, craftingPatternDetails );
return this.patternDetailsIAEStackMultimap.put( craftingPatternDetails, debtStack );
}
}
public boolean remove( final ICraftingPatternDetails craftingPatternDetails, final IAEStack debtStack )
{
if( this.transactions != null )
{
this.transactions.add( new SavedTransactions( false, craftingPatternDetails, debtStack ) );
return true;
}
else
{
this.iaeStackPatternDetailsMultimap.remove( debtStack, craftingPatternDetails );
return this.patternDetailsIAEStackMultimap.remove( craftingPatternDetails, debtStack );
}
}
public boolean containsIncompletablePattern( final ICraftingPatternDetails craftingPatternDetails )
{
return this.patternDetailsIAEStackMultimap.containsKey( craftingPatternDetails );
}
public boolean containsMissingIAEStack( final IAEStack stack )
{
if( ( (IAEItemStack) stack ).getItem().isDamageable() )
{
for( IAEStack i : iaeStackPatternDetailsMultimap.keySet() )
{
if( i.fuzzyComparison( stack, FuzzyMode.IGNORE_ALL ) )
{
return true;
}
}
return false;
}
return this.iaeStackPatternDetailsMultimap.containsKey( stack );
}
public Collection<IAEStack> getMissingIAEStack( final ICraftingPatternDetails patternDetails )
{
return this.patternDetailsIAEStackMultimap.get( patternDetails );
}
public Collection<ICraftingPatternDetails> getIncompletablePattern( final IAEStack stack )
{
Collection<ICraftingPatternDetails> a = new ArrayList<>();
if( ( (IAEItemStack) stack ).getItem().isDamageable() )
{
for( IAEStack i : iaeStackPatternDetailsMultimap.keySet() )
{
if( i.fuzzyComparison( stack, FuzzyMode.IGNORE_ALL ) )
{
a.addAll( this.iaeStackPatternDetailsMultimap.get( i ) );
}
}
return a;
}
return this.iaeStackPatternDetailsMultimap.get( stack );
}
private class SavedTransactions
{
private final boolean put;
private final ICraftingPatternDetails patternDetails;
private final IAEStack stack;
public SavedTransactions( final boolean putOperation, final ICraftingPatternDetails myPatternDetails, final IAEStack stack )
{
this.put = putOperation;
this.patternDetails = myPatternDetails;
this.stack = stack;
}
}
}
@@ -19,6 +19,10 @@
package appeng.me.storage; package appeng.me.storage;
import appeng.me.GridAccessException;
import appeng.me.helpers.MachineSource;
import appeng.tile.storage.TileDrive;
import com.google.common.collect.ImmutableList;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import appeng.api.config.Actionable; import appeng.api.config.Actionable;
@@ -36,6 +40,7 @@ public class DriveWatcher<T extends IAEStack<T>> extends MEInventoryHandler<T>
private final ItemStack is; private final ItemStack is;
private final ICellHandler handler; private final ICellHandler handler;
private final IChestOrDrive cord; private final IChestOrDrive cord;
private IActionSource source;
public DriveWatcher( final ICellInventoryHandler<T> i, final ItemStack is, final ICellHandler han, final IChestOrDrive cod ) public DriveWatcher( final ICellInventoryHandler<T> i, final ItemStack is, final ICellHandler han, final IChestOrDrive cod )
{ {
@@ -43,6 +48,7 @@ public class DriveWatcher<T extends IAEStack<T>> extends MEInventoryHandler<T>
this.is = is; this.is = is;
this.handler = han; this.handler = han;
this.cord = cod; this.cord = cod;
this.source = new MachineSource( cod );
} }
public int getStatus() public int getStatus()
@@ -66,6 +72,14 @@ public class DriveWatcher<T extends IAEStack<T>> extends MEInventoryHandler<T>
this.cord.blinkCell( this.getSlot() ); this.cord.blinkCell( this.getSlot() );
this.oldStatus = newStatus; this.oldStatus = newStatus;
} }
try
{
( (TileDrive) this.cord ).getProxy().getStorage().postAlterationOfStoredItems( this.getChannel(), ImmutableList.of( input.copy().setStackSize( input.getStackSize() - ( a == null ? 0 : a.getStackSize() ) ) ), this.source );
}
catch( GridAccessException e )
{
e.printStackTrace();
}
} }
return a; return a;
@@ -85,6 +99,15 @@ public class DriveWatcher<T extends IAEStack<T>> extends MEInventoryHandler<T>
this.cord.blinkCell( this.getSlot() ); this.cord.blinkCell( this.getSlot() );
this.oldStatus = newStatus; this.oldStatus = newStatus;
} }
try
{
( (TileDrive) this.cord ).getProxy().getStorage().postAlterationOfStoredItems( this.getChannel(), ImmutableList.of( request.copy().setStackSize( -a.getStackSize() ) ), this.source );
}
catch( GridAccessException e )
{
e.printStackTrace();
}
} }
return a; return a;
@@ -72,7 +72,7 @@ public class MEMonitorPassThrough<T extends IAEStack<T>> extends MEPassThrough<T
final IItemList<T> after = this.getInternal() == null ? this.getWrappedChannel().createList() : this.getInternal() final IItemList<T> after = this.getInternal() == null ? this.getWrappedChannel().createList() : this.getInternal()
.getAvailableItems( new ItemListIgnoreCrafting( this.getWrappedChannel().createList() ) ); .getAvailableItems( new ItemListIgnoreCrafting( this.getWrappedChannel().createList() ) );
if( this.monitor != null ) if( this.monitor != null && this.listeners.size() > 0 )
{ {
this.monitor.addListener( this, this.monitor ); this.monitor.addListener( this, this.monitor );
} }
@@ -90,6 +90,13 @@ public class MEMonitorPassThrough<T extends IAEStack<T>> extends MEPassThrough<T
@Override @Override
public void addListener( final IMEMonitorHandlerReceiver<T> l, final Object verificationToken ) public void addListener( final IMEMonitorHandlerReceiver<T> l, final Object verificationToken )
{ {
if( this.listeners.size() == 0 )
{
if( this.monitor != null )
{
this.monitor.addListener( this, this.monitor );
}
}
this.listeners.put( l, verificationToken ); this.listeners.put( l, verificationToken );
} }
@@ -41,7 +41,7 @@ public class MEPassThrough<T extends IAEStack<T>> implements IMEInventoryHandler
this.setInternal( i ); this.setInternal( i );
} }
protected IMEInventory<T> getInternal() public IMEInventory<T> getInternal()
{ {
return this.internal; return this.internal;
} }
@@ -19,6 +19,9 @@
package appeng.parts.automation; package appeng.parts.automation;
import appeng.api.networking.crafting.ICraftingPatternDetails;
import appeng.me.cache.CraftingGridCache;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
@@ -150,18 +153,14 @@ public class PartExportBus extends PartSharedItemBus implements ICraftingRequest
final IAEItemStack ais = this.getConfig().getAEStackInSlot( slotToExport ); final IAEItemStack ais = this.getConfig().getAEStackInSlot( slotToExport );
if( ais == null || this.itemToSend <= 0 ) continue; if( ais == null || this.itemToSend <= 0 )
{
continue;
}
if ( this.craftOnly() ) { if( this.craftOnly() )
if (this.failedCraftTriesSlot[x] <= 0) { {
this.didSomething = this.craftingTracker.handleCrafting( slotToExport, this.itemToSend, ais, destination, this.getTile().getWorld(), this.getProxy().getGrid(), cg, this.mySrc ) || this.didSomething;
this.didSomething = this.craftingTracker.handleCrafting(slotToExport, this.itemToSend, ais, destination, this.getTile().getWorld(),
this.getProxy().getGrid(), cg, this.mySrc) || this.didSomething;
if (this.didSomething) this.failedCraftTriesSlot[x] = 0;
else this.failedCraftTriesSlot[x] += 2;
}
this.failedCraftTriesSlot[x] -= 1;
continue; continue;
} }
@@ -180,20 +179,15 @@ public class PartExportBus extends PartSharedItemBus implements ICraftingRequest
} }
else else
{ {
this.pushItemIntoTarget( destination, energy, inv, ais ); if( inv.getStorageList().findPrecise( ais ) != null )
{
this.pushItemIntoTarget( destination, energy, inv, ais );
}
} }
if( this.itemToSend == before && this.isCraftingEnabled() ) if( this.itemToSend == before && this.isCraftingEnabled() )
{ {
if (this.failedCraftTriesSlot[x] <= 0) { this.didSomething = this.craftingTracker.handleCrafting( slotToExport, this.itemToSend, ais, destination, this.getTile().getWorld(), this.getProxy().getGrid(), cg, this.mySrc ) || this.didSomething;
this.didSomething = this.craftingTracker.handleCrafting(slotToExport, this.itemToSend, ais, destination, this.getTile().getWorld(),
this.getProxy().getGrid(), cg, this.mySrc) || this.didSomething;
if (this.didSomething) this.failedCraftTriesSlot[x] = 0;
else this.failedCraftTriesSlot[x] += 2;
}
this.failedCraftTriesSlot[x] -= 1;
} }
} }
@@ -206,7 +206,7 @@ public class PartFormationPlane extends PartAbstractFormationPlane<IAEItemStack>
@Override @Override
public List<IMEInventoryHandler> getCellArray( final IStorageChannel channel ) public List<IMEInventoryHandler> getCellArray( final IStorageChannel channel )
{ {
if( this.getProxy().isActive() && channel == AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ) if( channel == AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) )
{ {
final List<IMEInventoryHandler> handler = new ArrayList<>( 1 ); final List<IMEInventoryHandler> handler = new ArrayList<>( 1 );
handler.add( this.myHandler ); handler.add( this.myHandler );
@@ -283,12 +283,12 @@ public class PartImportBus extends PartSharedItemBus implements IInventoryDestin
final ItemStack simResult; final ItemStack simResult;
if( this.getInstalledUpgrades( Upgrades.FUZZY ) > 0 ) if( this.getInstalledUpgrades( Upgrades.FUZZY ) > 0 )
{ {
simResult = myAdaptor.simulateSimilarRemove( toSend, itemStackToImport, fzMode, this ); simResult = myAdaptor.simulateSimilarRemove( toSend, itemStackToImport, fzMode, null );
itemAmountNotStorable = inv.injectItems( AEItemStack.fromItemStack( simResult ), Actionable.SIMULATE, this.source ); itemAmountNotStorable = inv.injectItems( AEItemStack.fromItemStack( simResult ), Actionable.SIMULATE, this.source );
} }
else else
{ {
simResult = myAdaptor.simulateRemove( toSend, itemStackToImport, this ); simResult = myAdaptor.simulateRemove( toSend, itemStackToImport, null );
itemAmountNotStorable = inv.injectItems( AEItemStack.fromItemStack( simResult ), Actionable.SIMULATE, this.source ); itemAmountNotStorable = inv.injectItems( AEItemStack.fromItemStack( simResult ), Actionable.SIMULATE, this.source );
} }
@@ -19,40 +19,9 @@
package appeng.parts.automation; package appeng.parts.automation;
import java.util.Random;
import appeng.me.Grid;
import appeng.me.GridNode;
import appeng.util.item.AEItemStack;
import it.unimi.dsi.fastutil.objects.Object2LongMap;
import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumHand;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraftforge.items.IItemHandler;
import appeng.api.AEApi; import appeng.api.AEApi;
import appeng.api.config.FuzzyMode; import appeng.api.config.*;
import appeng.api.config.LevelType; import appeng.api.networking.crafting.*;
import appeng.api.config.RedstoneMode;
import appeng.api.config.Settings;
import appeng.api.config.Upgrades;
import appeng.api.config.YesNo;
import appeng.api.networking.crafting.ICraftingGrid;
import appeng.api.networking.crafting.ICraftingPatternDetails;
import appeng.api.networking.crafting.ICraftingProvider;
import appeng.api.networking.crafting.ICraftingProviderHelper;
import appeng.api.networking.crafting.ICraftingWatcher;
import appeng.api.networking.crafting.ICraftingWatcherHost;
import appeng.api.networking.energy.IEnergyGrid; import appeng.api.networking.energy.IEnergyGrid;
import appeng.api.networking.energy.IEnergyWatcher; import appeng.api.networking.energy.IEnergyWatcher;
import appeng.api.networking.energy.IEnergyWatcherHost; import appeng.api.networking.energy.IEnergyWatcherHost;
@@ -81,10 +50,28 @@ import appeng.core.sync.GuiBridge;
import appeng.helpers.Reflected; import appeng.helpers.Reflected;
import appeng.items.parts.PartModels; import appeng.items.parts.PartModels;
import appeng.me.GridAccessException; import appeng.me.GridAccessException;
import appeng.me.cache.NetworkMonitor;
import appeng.parts.PartModel; import appeng.parts.PartModel;
import appeng.tile.inventory.AppEngInternalAEInventory; import appeng.tile.inventory.AppEngInternalAEInventory;
import appeng.util.Platform; import appeng.util.Platform;
import appeng.util.inv.InvOperation; import appeng.util.inv.InvOperation;
import appeng.util.item.OreHelper;
import appeng.util.item.OreReference;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumHand;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraftforge.items.IItemHandler;
import java.util.Optional;
import java.util.Random;
public class PartLevelEmitter extends PartUpgradeable implements IEnergyWatcherHost, IStackWatcherHost, ICraftingWatcherHost, IMEMonitorHandlerReceiver<IAEItemStack>, ICraftingProvider public class PartLevelEmitter extends PartUpgradeable implements IEnergyWatcherHost, IStackWatcherHost, ICraftingWatcherHost, IMEMonitorHandlerReceiver<IAEItemStack>, ICraftingProvider
@@ -123,9 +110,6 @@ public class PartLevelEmitter extends PartUpgradeable implements IEnergyWatcherH
private double centerX; private double centerX;
private double centerY; private double centerY;
private double centerZ; private double centerZ;
static Object2LongMap<Grid> gridItemCount = new Object2LongOpenHashMap<>();
static Object2ObjectOpenHashMap<Grid, Object2LongMap<AEItemStack>> fuzzyAEItemStackCount = new Object2ObjectOpenHashMap<>();
static Object2ObjectOpenHashMap<Grid, Object2LongMap<AEItemStack>> preciseAEItemStackCount = new Object2ObjectOpenHashMap<>();
@Reflected @Reflected
public PartLevelEmitter( final ItemStack is ) public PartLevelEmitter( final ItemStack is )
@@ -156,12 +140,6 @@ public class PartLevelEmitter extends PartUpgradeable implements IEnergyWatcherH
} }
} }
@MENetworkEventSubscribe
public void powerChanged( final MENetworkPowerStatusChange c )
{
this.updateState();
}
private void updateState() private void updateState()
{ {
final boolean isOn = this.isLevelEmitterOn(); final boolean isOn = this.isLevelEmitterOn();
@@ -206,9 +184,23 @@ public class PartLevelEmitter extends PartUpgradeable implements IEnergyWatcherH
return flipState ? this.reportingValue >= this.lastReportedValue + 1 : this.reportingValue < this.lastReportedValue + 1; return flipState ? this.reportingValue >= this.lastReportedValue + 1 : this.reportingValue < this.lastReportedValue + 1;
} }
@MENetworkEventSubscribe
public void powerStatusChange( final MENetworkPowerStatusChange powerEvent )
{
if (this.getProxy().isActive())
{
onListUpdate();
}
this.updateState();
}
@MENetworkEventSubscribe @MENetworkEventSubscribe
public void channelChanged( final MENetworkChannelsChanged c ) public void channelChanged( final MENetworkChannelsChanged c )
{ {
if (this.getProxy().isActive())
{
onListUpdate();
}
this.updateState(); this.updateState();
} }
@@ -296,24 +288,37 @@ public class PartLevelEmitter extends PartUpgradeable implements IEnergyWatcherH
try try
{ {
if( this.getInstalledUpgrades( Upgrades.FUZZY ) > 0 || myStack == null )
if( myStack == null )
{ {
this.getProxy() this.getProxy().getStorage().getInventory( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ).addListener( this, this.getProxy().getGrid() );
.getStorage()
.getInventory( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) )
.addListener( this,
this.getProxy().getGrid() );
} }
else else
{ {
this.getProxy().getStorage().getInventory( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ).removeListener( this ); this.getProxy().getStorage().getInventory( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ).removeListener( this );
if( this.myWatcher != null ) if( this.myWatcher != null )
{ {
this.myWatcher.add( myStack ); if( this.getInstalledUpgrades( Upgrades.FUZZY ) > 0 )
{
Optional<OreReference> ores = OreHelper.INSTANCE.getOre( myStack.getDefinition() );
if( ores.isPresent() )
{
for( IAEItemStack iaeItemStack : ores.get().getAEEquivalents() )
{
this.myWatcher.add( iaeItemStack );
}
}
else
{
this.myWatcher.add( myStack );
}
}
else
{
this.myWatcher.add( myStack );
}
} }
} }
this.updateReportingValue( this.getProxy().getStorage().getInventory( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ) ); this.updateReportingValue( this.getProxy().getStorage().getInventory( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ) );
} }
catch( final GridAccessException e ) catch( final GridAccessException e )
@@ -323,90 +328,29 @@ public class PartLevelEmitter extends PartUpgradeable implements IEnergyWatcherH
} }
private void updateReportingValue( final IMEMonitor<IAEItemStack> monitor ) private void updateReportingValue( final IMEMonitor<IAEItemStack> monitor )
{
updateReportingValue( monitor,null );
}
private void updateReportingValue( final IMEMonitor<IAEItemStack> monitor, Iterable<IAEItemStack> change )
{ {
final IAEItemStack myStack = this.config.getAEStackInSlot( 0 ); final IAEItemStack myStack = this.config.getAEStackInSlot( 0 );
GridNode node = (GridNode) (this.getGridNode()); if( myStack == null )
if( node != null )
{ {
if( monitor instanceof NetworkMonitor )
final Grid g = node.getInternalGrid();
if( myStack == null )
{ {
if( change != null ) this.lastReportedValue = ( (NetworkMonitor<IAEItemStack>) monitor ).getGridCurrentCount();
{
if( gridItemCount.containsKey( g ) )
{
change.forEach( iaeItemStack -> lastReportedValue += iaeItemStack.getStackSize() );
}
}
gridItemCount.computeIfAbsent( g, ( aLong ) -> {
this.lastReportedValue = 0;
monitor.getStorageList().forEach( iaeItemStack -> lastReportedValue += iaeItemStack.getStackSize() );
return ( lastReportedValue );
} );
this.lastReportedValue = gridItemCount.get( g );
} }
}
else if( this.getInstalledUpgrades( Upgrades.FUZZY ) > 0 ) else if( this.getInstalledUpgrades( Upgrades.FUZZY ) > 0 )
{ {
final FuzzyMode fzMode = (FuzzyMode) this.getConfigManager().getSetting( Settings.FUZZY_MODE ); final FuzzyMode fzMode = (FuzzyMode) this.getConfigManager().getSetting( Settings.FUZZY_MODE );
if( change != null )
{
if( fuzzyAEItemStackCount.containsKey( g ) )
{
change.forEach( iaeItemStack -> {
if( iaeItemStack.sameOre( myStack ) ) lastReportedValue += iaeItemStack.getStackSize();
} );
}
}
fuzzyAEItemStackCount.computeIfAbsent( g, ( grid -> new Object2LongOpenHashMap<>() ) ); this.lastReportedValue = 0;
fuzzyAEItemStackCount.get( g ).computeIfAbsent( (AEItemStack) myStack, ( aLong -> { monitor.getStorageList().findFuzzy( myStack, fzMode ).forEach( iaeItemStack -> lastReportedValue += iaeItemStack.getStackSize() );
this.lastReportedValue = 0; }
monitor.getStorageList().findFuzzy( myStack, fzMode ).forEach( iaeItemStack -> lastReportedValue += iaeItemStack.getStackSize() ); else
return ( lastReportedValue ); {
} ) ); this.lastReportedValue = 0;
IAEItemStack precise = monitor.getStorageList().findPrecise( myStack );
this.lastReportedValue = fuzzyAEItemStackCount.get( g ).get( myStack ); if( precise != null ) lastReportedValue = precise.getStackSize();
if( this.lastReportedValue == 0 )
{
fuzzyAEItemStackCount.get( g ).remove( myStack );
fuzzyAEItemStackCount.trim();
}
}
else
{
if( change != null )
{
if( preciseAEItemStackCount.containsKey( g ) )
{
change.forEach( iaeItemStack -> {
if( iaeItemStack.isSameType( myStack ) ) lastReportedValue += iaeItemStack.getStackSize();
} );
}
}
preciseAEItemStackCount.computeIfAbsent( g, ( grid -> new Object2LongOpenHashMap<>() ) );
preciseAEItemStackCount.get( g ).computeIfAbsent( (AEItemStack) myStack, ( aLong -> {
this.lastReportedValue = 0;
IAEItemStack precise = monitor.getStorageList().findPrecise( myStack );
if( precise != null ) lastReportedValue = precise.getStackSize();
return ( lastReportedValue );
} ) );
this.lastReportedValue = preciseAEItemStackCount.get( g ).get( myStack );
if( this.lastReportedValue == 0 )
{
preciseAEItemStackCount.get( g ).remove( myStack );
preciseAEItemStackCount.trim();
}
}
} }
this.updateState(); this.updateState();
} }
@@ -419,12 +363,23 @@ public class PartLevelEmitter extends PartUpgradeable implements IEnergyWatcherH
} }
@Override @Override
public void onStackChange( final IItemList o, final IAEStack fullStack, final IAEStack diffStack, final IActionSource src, final IStorageChannel chan ) public void onStackChange( IItemList<?> o, IAEStack<?> fullStack, IAEStack<?> diffStack, IActionSource src, IStorageChannel<?> chan )
{ {
if( chan == AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) && fullStack.equals( this.config.getAEStackInSlot( 0 ) ) && this if( chan == AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) )
.getInstalledUpgrades( Upgrades.FUZZY ) == 0 )
{ {
this.lastReportedValue = fullStack.getStackSize(); IAEItemStack myStack = this.config.getAEStackInSlot( 0 );
if( this.getInstalledUpgrades( Upgrades.FUZZY ) > 0 )
{
final FuzzyMode fzMode = (FuzzyMode) this.getConfigManager().getSetting( Settings.FUZZY_MODE );
if( Platform.itemComparisons().isFuzzyEqualItem( myStack.getDefinition(), ( (IAEItemStack) diffStack ).getDefinition(), fzMode ) )
{
this.lastReportedValue += diffStack.getStackSize();
}
}
else if( diffStack.equals( myStack ) )
{
this.lastReportedValue += diffStack.getStackSize();
}
this.updateState(); this.updateState();
} }
} }
@@ -459,7 +414,7 @@ public class PartLevelEmitter extends PartUpgradeable implements IEnergyWatcherH
@Override @Override
public void postChange( final IBaseMonitor<IAEItemStack> monitor, final Iterable<IAEItemStack> change, final IActionSource actionSource ) public void postChange( final IBaseMonitor<IAEItemStack> monitor, final Iterable<IAEItemStack> change, final IActionSource actionSource )
{ {
this.updateReportingValue( (IMEMonitor<IAEItemStack>) monitor, change ); this.updateReportingValue( (IMEMonitor<IAEItemStack>) monitor );
} }
@Override @Override
@@ -636,9 +591,4 @@ public class PartLevelEmitter extends PartUpgradeable implements IEnergyWatcherH
} }
} }
public static void wipeCache(){
fuzzyAEItemStackCount.clear();
preciseAEItemStackCount.clear();
gridItemCount.clear();
}
} }
@@ -21,6 +21,7 @@ package appeng.parts.misc;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import appeng.api.AEApi; import appeng.api.AEApi;
import appeng.api.config.AccessRestriction;
import appeng.api.config.Actionable; import appeng.api.config.Actionable;
import appeng.api.config.Settings; import appeng.api.config.Settings;
import appeng.api.config.StorageFilter; import appeng.api.config.StorageFilter;
@@ -44,7 +45,6 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemHandlerHelper;
import java.util.*; import java.util.*;
@@ -60,6 +60,7 @@ class ItemHandlerAdapter implements IMEInventory<IAEItemStack>, IBaseMonitor<IAE
private final IGridProxyable proxyable; private final IGridProxyable proxyable;
private final InventoryCache cache; private final InventoryCache cache;
private StorageFilter mode; private StorageFilter mode;
private AccessRestriction access;
private ItemStack stackCache = null; private ItemStack stackCache = null;
@@ -71,8 +72,10 @@ class ItemHandlerAdapter implements IMEInventory<IAEItemStack>, IBaseMonitor<IAE
{ {
PartStorageBus partStorageBus = (PartStorageBus) this.proxyable; PartStorageBus partStorageBus = (PartStorageBus) this.proxyable;
this.mode = ( (StorageFilter) partStorageBus.getConfigManager().getSetting( Settings.STORAGE_FILTER ) ); this.mode = ( (StorageFilter) partStorageBus.getConfigManager().getSetting( Settings.STORAGE_FILTER ) );
this.access = ( (AccessRestriction) partStorageBus.getConfigManager().getSetting( Settings.ACCESS ) );
} }
this.cache = new InventoryCache( this.itemHandler, this.mode ); this.cache = new InventoryCache( this.itemHandler, this.mode );
this.cache.update();
} }
@Override @Override
@@ -83,6 +86,8 @@ class ItemHandlerAdapter implements IMEInventory<IAEItemStack>, IBaseMonitor<IAE
stackCache = null; stackCache = null;
ItemStack orgInput; ItemStack orgInput;
int slotCount = this.itemHandler.getSlots();
if( currentCached != null && iox.isSameType( currentCached ) ) if( currentCached != null && iox.isSameType( currentCached ) )
{ {
// Cache is suitable, just update the count // Cache is suitable, just update the count
@@ -94,10 +99,16 @@ class ItemHandlerAdapter implements IMEInventory<IAEItemStack>, IBaseMonitor<IAE
// We need a new stack :-( // We need a new stack :-(
orgInput = iox.createItemStack(); orgInput = iox.createItemStack();
} }
ItemStack remaining = ItemHandlerHelper.insertItem( this.itemHandler, orgInput, type == Actionable.SIMULATE );
ItemStack remaining = orgInput;
for( int i = 0; i < slotCount && !remaining.isEmpty(); i++ )
{
remaining = this.itemHandler.insertItem( i, remaining, type == Actionable.SIMULATE );
}
// Store the stack in the cache for next time. // Store the stack in the cache for next time.
if (!remaining.isEmpty() && remaining != orgInput) if( !remaining.isEmpty() && remaining != orgInput )
{ {
stackCache = remaining; stackCache = remaining;
} }
@@ -111,6 +122,9 @@ class ItemHandlerAdapter implements IMEInventory<IAEItemStack>, IBaseMonitor<IAE
if( type == Actionable.MODULATE ) if( type == Actionable.MODULATE )
{ {
IAEItemStack added = iox.copy().setStackSize( iox.getStackSize() - remaining.getCount() );
this.cache.currentlyCached.add( added );
this.postDifference( Collections.singletonList( added ) );
try try
{ {
this.proxyable.getProxy().getTick().alertDevice( this.proxyable.getProxy().getNode() ); this.proxyable.getProxy().getTick().alertDevice( this.proxyable.getProxy().getNode() );
@@ -119,7 +133,6 @@ class ItemHandlerAdapter implements IMEInventory<IAEItemStack>, IBaseMonitor<IAE
{ {
// meh // meh
} }
} }
return AEItemStack.fromItemStack( remaining ); return AEItemStack.fromItemStack( remaining );
@@ -128,18 +141,17 @@ class ItemHandlerAdapter implements IMEInventory<IAEItemStack>, IBaseMonitor<IAE
@Override @Override
public IAEItemStack extractItems( IAEItemStack request, Actionable mode, IActionSource src ) public IAEItemStack extractItems( IAEItemStack request, Actionable mode, IActionSource src )
{ {
int remainingSize = Ints.saturatedCast(request.getStackSize()); int remainingSize = Ints.saturatedCast( request.getStackSize() );
// Use this to gather the requested items // Use this to gather the requested items
ItemStack gathered = ItemStack.EMPTY; ItemStack gathered = ItemStack.EMPTY;
final boolean simulate = ( mode == Actionable.SIMULATE ); final boolean simulate = ( mode == Actionable.SIMULATE );
for ( int i = 0; i < this.itemHandler.getSlots(); i++ )
for( int i = 0; i < this.itemHandler.getSlots(); i++ )
{ {
ItemStack stackInInventorySlot = this.itemHandler.getStackInSlot( i ); ItemStack stackInInventorySlot = this.itemHandler.getStackInSlot( i );
if (!request.isSameType(stackInInventorySlot)) if( !request.isSameType( stackInInventorySlot ) )
{ {
continue; continue;
} }
@@ -191,8 +203,15 @@ class ItemHandlerAdapter implements IMEInventory<IAEItemStack>, IBaseMonitor<IAE
if( !gathered.isEmpty() ) if( !gathered.isEmpty() )
{ {
IAEItemStack gatheredAEItemStack = AEItemStack.fromItemStack( gathered );
if( mode == Actionable.MODULATE ) if( mode == Actionable.MODULATE )
{ {
IAEItemStack cachedStack = this.cache.currentlyCached.findPrecise( request );
if( cachedStack != null )
{
cachedStack.decStackSize( gatheredAEItemStack.getStackSize() );
this.postDifference( Collections.singletonList( gatheredAEItemStack.copy().setStackSize( -gatheredAEItemStack.getStackSize() ) ) );
}
try try
{ {
this.proxyable.getProxy().getTick().alertDevice( this.proxyable.getProxy().getNode() ); this.proxyable.getProxy().getTick().alertDevice( this.proxyable.getProxy().getNode() );
@@ -203,7 +222,7 @@ class ItemHandlerAdapter implements IMEInventory<IAEItemStack>, IBaseMonitor<IAE
} }
} }
return AEItemStack.fromItemStack( gathered ); return gatheredAEItemStack;
} }
return null; return null;
@@ -213,7 +232,7 @@ class ItemHandlerAdapter implements IMEInventory<IAEItemStack>, IBaseMonitor<IAE
public TickRateModulation onTick() public TickRateModulation onTick()
{ {
List<IAEItemStack> changes = this.cache.update(); List<IAEItemStack> changes = this.cache.update();
if( !changes.isEmpty() ) if( !changes.isEmpty() && access.hasPermission( AccessRestriction.READ ) )
{ {
this.postDifference( changes ); this.postDifference( changes );
return TickRateModulation.URGENT; return TickRateModulation.URGENT;
@@ -274,9 +293,9 @@ class ItemHandlerAdapter implements IMEInventory<IAEItemStack>, IBaseMonitor<IAE
private static class InventoryCache implements Iterable<ItemSlot> private static class InventoryCache implements Iterable<ItemSlot>
{ {
private IAEItemStack[] cachedAeStacks = new IAEItemStack[0];
private final IItemHandler itemHandler; private final IItemHandler itemHandler;
private final StorageFilter mode; private final StorageFilter mode;
IItemList<IAEItemStack> currentlyCached = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList();
public InventoryCache( IItemHandler itemHandler, StorageFilter mode ) public InventoryCache( IItemHandler itemHandler, StorageFilter mode )
{ {
@@ -286,7 +305,7 @@ class ItemHandlerAdapter implements IMEInventory<IAEItemStack>, IBaseMonitor<IAE
public IItemList<IAEItemStack> getAvailableItems( IItemList<IAEItemStack> out ) public IItemList<IAEItemStack> getAvailableItems( IItemList<IAEItemStack> out )
{ {
Arrays.stream( this.cachedAeStacks ).forEach( out::add ); currentlyCached.iterator().forEachRemaining( out::add );
return out; return out;
} }
@@ -298,93 +317,41 @@ class ItemHandlerAdapter implements IMEInventory<IAEItemStack>, IBaseMonitor<IAE
public List<IAEItemStack> update() public List<IAEItemStack> update()
{ {
final List<IAEItemStack> changes = new ArrayList<>(); final List<IAEItemStack> changes = new ArrayList<>();
final int slots = this.itemHandler.getSlots();
// Make room for new slots IItemList<IAEItemStack> currentlyOnStorage = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList();
if( slots > this.cachedAeStacks.length )
{
this.cachedAeStacks = Arrays.copyOf( this.cachedAeStacks, slots );
}
for( final ItemSlot is : this ) for ( final ItemSlot is : this )
{ {
// Save the old stuff
final IAEItemStack oldAeIS = this.cachedAeStacks[is.getSlot()];
final ItemStack newIS = !is.isExtractable() && this.getMode() == StorageFilter.EXTRACTABLE_ONLY ? ItemStack.EMPTY : is.getItemStack(); final ItemStack newIS = !is.isExtractable() && this.getMode() == StorageFilter.EXTRACTABLE_ONLY ? ItemStack.EMPTY : is.getItemStack();
if( !newIS.isEmpty() )
this.handlePossibleSlotChanges( is.getSlot(), oldAeIS, newIS, changes );
}
// Handle cases where the number of slots actually is lower now than before
if( slots < this.cachedAeStacks.length )
{
for( int slot = slots; slot < this.cachedAeStacks.length; slot++ )
{ {
final IAEItemStack aeStack = this.cachedAeStacks[slot]; currentlyOnStorage.add( is.getAEItemStack() );
if( aeStack != null )
{
final IAEItemStack a = aeStack.copy();
a.setStackSize( -a.getStackSize() );
changes.add( a );
}
} }
// Reduce the cache size
this.cachedAeStacks = Arrays.copyOf( this.cachedAeStacks, slots );
} }
for ( final IAEItemStack is : currentlyCached )
{
is.setStackSize( -is.getStackSize() );
}
for ( final IAEItemStack is : currentlyOnStorage )
{
currentlyCached.add( is );
}
for ( final IAEItemStack is : currentlyCached )
{
if( is.getStackSize() != 0 )
{
changes.add( is );
}
}
currentlyCached = currentlyOnStorage;
return changes; return changes;
} }
private void handlePossibleSlotChanges( int slot, IAEItemStack oldAeIS, ItemStack newIS, List<IAEItemStack> changes )
{
if( oldAeIS != null && oldAeIS.isSameType( newIS ) )
{
this.handleStackSizeChanged( slot, oldAeIS, newIS, changes );
}
else
{
this.handleItemChanged( slot, oldAeIS, newIS, changes );
}
}
private void handleStackSizeChanged( int slot, IAEItemStack oldAeIS, ItemStack newIS, List<IAEItemStack> changes )
{
// Still the same item, but amount might have changed
final long diff = newIS.getCount() - oldAeIS.getStackSize();
if( diff != 0 )
{
final IAEItemStack stack = oldAeIS.copy();
stack.setStackSize( newIS.getCount() );
this.cachedAeStacks[slot] = stack;
final IAEItemStack a = stack.copy();
a.setStackSize( diff );
changes.add( a );
}
}
private void handleItemChanged( int slot, IAEItemStack oldAeIS, ItemStack newIS, List<IAEItemStack> changes )
{
// Completely different item
this.cachedAeStacks[slot] = AEItemStack.fromItemStack( newIS );
// If we had a stack previously in this slot, notify the network about its disappearance
if( oldAeIS != null )
{
oldAeIS.setStackSize( -oldAeIS.getStackSize() );
changes.add( oldAeIS );
}
// Notify the network about the new stack. Note that this is null if newIS was null
if( this.cachedAeStacks[slot] != null )
{
changes.add( this.cachedAeStacks[slot] );
}
}
@Override @Override
public Iterator<ItemSlot> iterator() public Iterator<ItemSlot> iterator()
{ {
@@ -2,7 +2,9 @@ package appeng.parts.misc;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import appeng.api.AEApi; import appeng.api.AEApi;
import appeng.api.config.AccessRestriction;
import appeng.api.config.Actionable; import appeng.api.config.Actionable;
import appeng.api.config.Settings;
import appeng.api.networking.security.IActionSource; import appeng.api.networking.security.IActionSource;
import appeng.api.networking.storage.IBaseMonitor; import appeng.api.networking.storage.IBaseMonitor;
import appeng.api.networking.ticking.TickRateModulation; import appeng.api.networking.ticking.TickRateModulation;
@@ -24,7 +26,6 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
/** /**
@@ -39,6 +40,7 @@ class ItemRepositoryAdapter implements IMEInventory<IAEItemStack>, IBaseMonitor<
private final IItemRepository itemRepository; private final IItemRepository itemRepository;
private final IGridProxyable proxyable; private final IGridProxyable proxyable;
private final InventoryCache cache; private final InventoryCache cache;
private AccessRestriction access;
private ItemStack stackCache; private ItemStack stackCache;
@@ -47,6 +49,12 @@ class ItemRepositoryAdapter implements IMEInventory<IAEItemStack>, IBaseMonitor<
this.itemRepository = itemRepository; this.itemRepository = itemRepository;
this.proxyable = proxy; this.proxyable = proxy;
this.cache = new InventoryCache( this.itemRepository ); this.cache = new InventoryCache( this.itemRepository );
if( this.proxyable instanceof PartStorageBus )
{
PartStorageBus partStorageBus = (PartStorageBus) this.proxyable;
this.access = ( (AccessRestriction) partStorageBus.getConfigManager().getSetting( Settings.ACCESS ) );
}
this.cache.update();
} }
@Override @Override
@@ -71,7 +79,7 @@ class ItemRepositoryAdapter implements IMEInventory<IAEItemStack>, IBaseMonitor<
ItemStack remaining = this.itemRepository.insertItem( orgInput, type == Actionable.SIMULATE ); ItemStack remaining = this.itemRepository.insertItem( orgInput, type == Actionable.SIMULATE );
// Store the stack in the cache for next time. // Store the stack in the cache for next time.
if (!remaining.isEmpty() && remaining != orgInput) if( !remaining.isEmpty() && remaining != orgInput )
{ {
stackCache = remaining; stackCache = remaining;
} }
@@ -85,6 +93,9 @@ class ItemRepositoryAdapter implements IMEInventory<IAEItemStack>, IBaseMonitor<
if( type == Actionable.MODULATE ) if( type == Actionable.MODULATE )
{ {
IAEItemStack added = iox.copy().setStackSize( iox.getStackSize() - remaining.getCount() );
this.cache.currentlyCached.add( added );
this.postDifference( Collections.singletonList( added ) );
try try
{ {
this.proxyable.getProxy().getTick().alertDevice( this.proxyable.getProxy().getNode() ); this.proxyable.getProxy().getTick().alertDevice( this.proxyable.getProxy().getNode() );
@@ -102,7 +113,7 @@ class ItemRepositoryAdapter implements IMEInventory<IAEItemStack>, IBaseMonitor<
@Override @Override
public IAEItemStack extractItems( IAEItemStack request, Actionable mode, IActionSource src ) public IAEItemStack extractItems( IAEItemStack request, Actionable mode, IActionSource src )
{ {
int remainingSize = Ints.saturatedCast(request.getStackSize()); int remainingSize = Ints.saturatedCast( request.getStackSize() );
final boolean simulate = ( mode == Actionable.SIMULATE ); final boolean simulate = ( mode == Actionable.SIMULATE );
@@ -119,8 +130,15 @@ class ItemRepositoryAdapter implements IMEInventory<IAEItemStack>, IBaseMonitor<
if( !extracted.isEmpty() ) if( !extracted.isEmpty() )
{ {
IAEItemStack extractedAEItemStack = AEItemStack.fromItemStack( extracted );
if( mode == Actionable.MODULATE ) if( mode == Actionable.MODULATE )
{ {
IAEItemStack cachedStack = this.cache.currentlyCached.findPrecise( request );
if (cachedStack != null)
{
cachedStack.decStackSize( extractedAEItemStack.getStackSize() );
this.postDifference( Collections.singletonList( extractedAEItemStack.copy().setStackSize( -extractedAEItemStack.getStackSize() ) ) );
}
try try
{ {
this.proxyable.getProxy().getTick().alertDevice( this.proxyable.getProxy().getNode() ); this.proxyable.getProxy().getTick().alertDevice( this.proxyable.getProxy().getNode() );
@@ -130,7 +148,7 @@ class ItemRepositoryAdapter implements IMEInventory<IAEItemStack>, IBaseMonitor<
// meh // meh
} }
} }
return AEItemStack.fromItemStack( extracted ); return extractedAEItemStack;
} }
return null; return null;
} }
@@ -180,17 +198,15 @@ class ItemRepositoryAdapter implements IMEInventory<IAEItemStack>, IBaseMonitor<
@Override @Override
public TickRateModulation onTick() public TickRateModulation onTick()
{ {
List<IAEItemStack> changes = this.cache.update();
if( !changes.isEmpty() && access.hasPermission( AccessRestriction.READ ) )
{ {
List<IAEItemStack> changes = this.cache.update(); this.postDifference( changes );
if( !changes.isEmpty() ) return TickRateModulation.URGENT;
{ }
this.postDifference( changes ); else
return TickRateModulation.URGENT; {
} return TickRateModulation.SLOWER;
else
{
return TickRateModulation.SLOWER;
}
} }
} }
@@ -202,7 +218,7 @@ class ItemRepositoryAdapter implements IMEInventory<IAEItemStack>, IBaseMonitor<
private static class InventoryCache private static class InventoryCache
{ {
private IAEItemStack[] cachedAeStacks = new IAEItemStack[0]; private IItemList<IAEItemStack> currentlyCached = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList();
private final IItemRepository iItemRepository; private final IItemRepository iItemRepository;
public InventoryCache( IItemRepository iItemRepository ) public InventoryCache( IItemRepository iItemRepository )
@@ -212,7 +228,7 @@ class ItemRepositoryAdapter implements IMEInventory<IAEItemStack>, IBaseMonitor<
public IItemList<IAEItemStack> getAvailableItems( IItemList<IAEItemStack> out ) public IItemList<IAEItemStack> getAvailableItems( IItemList<IAEItemStack> out )
{ {
Arrays.stream( this.cachedAeStacks ).forEach( out::add ); currentlyCached.iterator().forEachRemaining( out::add );
return out; return out;
} }
@@ -220,95 +236,31 @@ class ItemRepositoryAdapter implements IMEInventory<IAEItemStack>, IBaseMonitor<
{ {
final List<IAEItemStack> changes = new ArrayList<>(); final List<IAEItemStack> changes = new ArrayList<>();
List<IAEItemStack> out = this.iItemRepository.getAllItems().stream().map( s -> AEItemStack.fromItemStack( s.itemPrototype ).setStackSize( s.count ) ).collect( Collectors.toList() ); IItemList<IAEItemStack> currentlyOnStorage = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList();
this.iItemRepository.getAllItems().stream().map( s -> AEItemStack.fromItemStack( s.itemPrototype ).setStackSize( s.count ) ).forEach( currentlyOnStorage::add );
final int size = out.size(); for ( final IAEItemStack is : currentlyCached )
// Make room for new slots
if( size > this.cachedAeStacks.length )
{ {
this.cachedAeStacks = Arrays.copyOf( this.cachedAeStacks, size ); is.setStackSize( -is.getStackSize() );
} }
for( int x = 0; x < size; x++ ) for ( final IAEItemStack is : currentlyOnStorage )
{ {
// Save the old stuff currentlyCached.add( is );
final IAEItemStack oldAeIS = this.cachedAeStacks[x];
final IAEItemStack newIS = out.get( x );
this.handlePossibleSlotChanges( x, oldAeIS, newIS, changes );
} }
// Handle cases where the number of slots actually is lower now than before for ( final IAEItemStack is : currentlyCached )
if( size < this.cachedAeStacks.length )
{ {
for( int x = 0; x < this.cachedAeStacks.length; x++ ) if( is.getStackSize() != 0 )
{ {
final IAEItemStack aeStack = this.cachedAeStacks[x]; changes.add( is );
if( aeStack != null )
{
final IAEItemStack a = aeStack.copy();
a.setStackSize( -a.getStackSize() );
changes.add( a );
}
} }
// Reduce the cache size
this.cachedAeStacks = Arrays.copyOf( this.cachedAeStacks, size );
} }
currentlyCached = currentlyOnStorage;
return changes; return changes;
} }
private void handlePossibleSlotChanges( int slot, IAEItemStack oldAeIS, IAEItemStack newIS, List<IAEItemStack> changes )
{
if( oldAeIS != null && oldAeIS.isSameType( newIS ) )
{
this.handleStackSizeChanged( slot, oldAeIS, newIS, changes );
}
else
{
this.handleItemChanged( slot, oldAeIS, newIS, changes );
}
}
private void handleStackSizeChanged( int slot, IAEItemStack oldAeIS, IAEItemStack newIS, List<IAEItemStack> changes )
{
// Still the same item, but amount might have changed
final long diff = newIS.getStackSize() - oldAeIS.getStackSize();
if( diff != 0 )
{
final IAEItemStack stack = oldAeIS.copy();
stack.setStackSize( newIS.getStackSize() );
this.cachedAeStacks[slot] = stack;
final IAEItemStack a = stack.copy();
a.setStackSize( diff );
changes.add( a );
}
}
private void handleItemChanged( int slot, IAEItemStack oldAeIS, IAEItemStack newIS, List<IAEItemStack> changes )
{
// Completely different item
this.cachedAeStacks[slot] = newIS ;
// If we had a stack previously in this slot, notify the network about its disappearance
if( oldAeIS != null )
{
oldAeIS.setStackSize( -oldAeIS.getStackSize() );
changes.add( oldAeIS );
}
// Notify the network about the new stack. Note that this is null if newIS was null
if( this.cachedAeStacks[slot] != null )
{
changes.add( this.cachedAeStacks[slot] );
}
}
} }
} }
@@ -22,6 +22,7 @@ package appeng.parts.misc;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import appeng.api.config.AccessRestriction;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
@@ -55,6 +56,7 @@ public abstract class PartSharedStorageBus extends PartUpgradeable implements IG
{ {
private boolean wasActive = false; private boolean wasActive = false;
private int priority = 0; private int priority = 0;
protected boolean accessChanged;
public PartSharedStorageBus( ItemStack is ) public PartSharedStorageBus( ItemStack is )
{ {
@@ -146,6 +148,10 @@ public abstract class PartSharedStorageBus extends PartUpgradeable implements IG
@Override @Override
public void updateSetting( final IConfigManager manager, final Enum settingName, final Enum newValue ) public void updateSetting( final IConfigManager manager, final Enum settingName, final Enum newValue )
{ {
if( settingName instanceof AccessRestriction )
{
this.accessChanged = true;
}
this.resetCache( true ); this.resetCache( true );
this.getHost().markForSave(); this.getHost().markForSave();
} }
@@ -23,6 +23,9 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import appeng.fluids.parts.FluidHandlerAdapter;
import appeng.me.storage.MEPassThrough;
import appeng.util.ConfigManager;
import com.jaquadro.minecraft.storagedrawers.api.capabilities.IItemRepository; import com.jaquadro.minecraft.storagedrawers.api.capabilities.IItemRepository;
import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
@@ -121,6 +124,7 @@ public class PartStorageBus extends PartUpgradeable implements IGridTickable, IC
private int handlerHash = 0; private int handlerHash = 0;
private boolean wasActive = false; private boolean wasActive = false;
private byte resetCacheLogic = 0; private byte resetCacheLogic = 0;
private boolean accessChanged;
@Reflected @Reflected
public PartStorageBus( final ItemStack is ) public PartStorageBus( final ItemStack is )
@@ -172,6 +176,10 @@ public class PartStorageBus extends PartUpgradeable implements IGridTickable, IC
@Override @Override
public void updateSetting( final IConfigManager manager, final Enum settingName, final Enum newValue ) public void updateSetting( final IConfigManager manager, final Enum settingName, final Enum newValue )
{ {
if( settingName instanceof AccessRestriction )
{
this.accessChanged = true;
}
this.resetCache( true ); this.resetCache( true );
this.getHost().markForSave(); this.getHost().markForSave();
} }
@@ -258,20 +266,25 @@ public class PartStorageBus extends PartUpgradeable implements IGridTickable, IC
@Override @Override
public void postChange( final IBaseMonitor<IAEItemStack> monitor, final Iterable<IAEItemStack> change, final IActionSource source ) public void postChange( final IBaseMonitor<IAEItemStack> monitor, final Iterable<IAEItemStack> change, final IActionSource source )
{ {
if( source == this.mySrc || source.machine().map( machine -> machine == this ).orElse( false ) ) if( this.mySrc.machine().map( machine -> machine == this ).orElse( false ) && monitor != null )
{ {
try AccessRestriction currentAccess = (AccessRestriction) ( (ConfigManager) this.getConfigManager() ).getSetting( Settings.ACCESS );
if( !currentAccess.hasPermission( AccessRestriction.READ ) )
{ {
if( this.getProxy().isActive() ) return;
{
this.getProxy().getStorage().postAlterationOfStoredItems( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ), change, this.mySrc );
}
} }
catch( final GridAccessException e ) }
try
{
if( this.getProxy().isActive() )
{ {
// :( this.getProxy().getStorage().postAlterationOfStoredItems( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ), change, this.mySrc );
} }
} }
catch( final GridAccessException e )
{
// :(
}
} }
@Override @Override
@@ -351,11 +364,28 @@ public class PartStorageBus extends PartUpgradeable implements IGridTickable, IC
final boolean fullReset = this.resetCacheLogic == 2; final boolean fullReset = this.resetCacheLogic == 2;
this.resetCacheLogic = 0; this.resetCacheLogic = 0;
final IMEInventory<IAEItemStack> in = this.getInternalHandler(); final MEInventoryHandler<IAEItemStack> in = this.getInternalHandler();
IItemList<IAEItemStack> before = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList(); IItemList<IAEItemStack> before = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList();
boolean denyRead = false;
if( in != null ) if( in != null )
{ {
before = in.getAvailableItems( before ); if( accessChanged )
{
AccessRestriction currentAccess = (AccessRestriction) ( (ConfigManager) this.getConfigManager() ).getSetting( Settings.ACCESS );
AccessRestriction oldAccess = (AccessRestriction) ( (ConfigManager) this.getConfigManager() ).getOldSetting( Settings.ACCESS );
if( oldAccess.hasPermission( AccessRestriction.READ ) && !currentAccess.hasPermission( AccessRestriction.READ ) )
{
denyRead = true;
}
in.setBaseAccess( oldAccess );
before = in.getAvailableItems( before );
in.setBaseAccess( currentAccess );
accessChanged = false;
}
else
{
before = in.getAvailableItems( before );
}
} }
this.cached = false; this.cached = false;
@@ -364,16 +394,19 @@ public class PartStorageBus extends PartUpgradeable implements IGridTickable, IC
this.handlerHash = 0; this.handlerHash = 0;
} }
final IMEInventory<IAEItemStack> out = this.getInternalHandler(); final MEInventoryHandler<IAEItemStack> out = this.getInternalHandler();
if( in != out ) if( in != out || denyRead )
{ {
IItemList<IAEItemStack> after = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList(); IItemList<IAEItemStack> after = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList();
if( out != null )
if( out != null && !denyRead )
{ {
after = out.getAvailableItems( after ); after = out.getAvailableItems( after );
} }
Platform.postListChanges( before, after, this, this.mySrc ); Platform.postListChanges( before, after, this, this.mySrc );
} }
} }
@@ -434,16 +467,6 @@ public class PartStorageBus extends PartUpgradeable implements IGridTickable, IC
return Objects.hash( target, target.getCapability( Capabilities.STORAGE_MONITORABLE_ACCESSOR, targetSide ) ); return Objects.hash( target, target.getCapability( Capabilities.STORAGE_MONITORABLE_ACCESSOR, targetSide ) );
} }
if (ITEM_REPOSITORY_CAPABILITY != null && target.hasCapability( ITEM_REPOSITORY_CAPABILITY, targetSide ))
{
final IItemRepository handlerRepo = target.getCapability( ITEM_REPOSITORY_CAPABILITY, targetSide );
if( handlerRepo != null )
{
return Objects.hash( target, handlerRepo, handlerRepo.getAllItems().size() );
}
}
final IItemHandler itemHandler = target.getCapability( CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, targetSide ); final IItemHandler itemHandler = target.getCapability( CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, targetSide );
if( itemHandler != null ) if( itemHandler != null )
@@ -598,7 +621,7 @@ public class PartStorageBus extends PartUpgradeable implements IGridTickable, IC
{ {
if( channel == AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ) if( channel == AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) )
{ {
final IMEInventoryHandler<IAEItemStack> out = this.getProxy().isActive() ? this.getInternalHandler() : null; final IMEInventoryHandler<IAEItemStack> out = this.getInternalHandler();
if( out != null ) if( out != null )
{ {
return Collections.singletonList( out ); return Collections.singletonList( out );
@@ -21,10 +21,14 @@ package appeng.parts.reporting;
import java.io.IOException; import java.io.IOException;
import appeng.api.networking.events.MENetworkChannelsChanged;
import appeng.api.networking.events.MENetworkEventSubscribe;
import appeng.api.networking.events.MENetworkPowerStatusChange;
import appeng.api.networking.security.IActionSource;
import appeng.api.storage.channels.IFluidStorageChannel; import appeng.api.storage.channels.IFluidStorageChannel;
import appeng.api.storage.data.IAEFluidStack; import appeng.api.storage.data.IAEFluidStack;
import appeng.api.storage.data.IItemList;
import appeng.fluids.util.AEFluidStack; import appeng.fluids.util.AEFluidStack;
import appeng.util.item.AEStack;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.GlStateManager;
@@ -43,7 +47,6 @@ import net.minecraftforge.fml.relauncher.SideOnly;
import appeng.api.AEApi; import appeng.api.AEApi;
import appeng.api.implementations.parts.IPartStorageMonitor; import appeng.api.implementations.parts.IPartStorageMonitor;
import appeng.api.networking.security.IActionSource;
import appeng.api.networking.storage.IStackWatcher; import appeng.api.networking.storage.IStackWatcher;
import appeng.api.networking.storage.IStackWatcherHost; import appeng.api.networking.storage.IStackWatcherHost;
import appeng.api.parts.IPartModel; import appeng.api.parts.IPartModel;
@@ -52,7 +55,6 @@ import appeng.api.storage.IStorageChannel;
import appeng.api.storage.channels.IItemStorageChannel; import appeng.api.storage.channels.IItemStorageChannel;
import appeng.api.storage.data.IAEItemStack; import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IAEStack; import appeng.api.storage.data.IAEStack;
import appeng.api.storage.data.IItemList;
import appeng.client.render.TesrRenderHelper; import appeng.client.render.TesrRenderHelper;
import appeng.core.localization.PlayerMessages; import appeng.core.localization.PlayerMessages;
import appeng.helpers.Reflected; import appeng.helpers.Reflected;
@@ -385,19 +387,87 @@ public abstract class AbstractPartMonitor extends AbstractPartDisplay implements
this.configureWatchers(); this.configureWatchers();
} }
@MENetworkEventSubscribe
public void powerStatusChange( final MENetworkPowerStatusChange ev )
{
if( !this.getProxy().isPowered() )
{
if( this.myWatcher != null )
{
if( this.configuredItem != null )
{
this.configuredItem.setStackSize( 0 );
}
if( this.configuredFluid != null )
{
this.configuredFluid.setStackSize( 0 );
}
}
}
else
{
try
{
if( this.configuredItem != null )
{
this.updateReportingValue( this.getProxy().getStorage().getInventory( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ) );
}
if( this.configuredFluid != null )
{
this.updateReportingValue( this.getProxy().getStorage().getInventory( AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ) ) );
}
}
catch( final GridAccessException e )
{
// ;P
}
}
}
@MENetworkEventSubscribe
public void channelChanged( final MENetworkChannelsChanged c )
{
if( !this.getProxy().isPowered() )
{
if( this.myWatcher != null )
{
if( this.configuredItem != null )
{
this.configuredItem.setStackSize( 0 );
}
if( this.configuredFluid != null )
{
this.configuredFluid.setStackSize( 0 );
}
}
}
else
{
try
{
if( this.configuredItem != null )
{
this.updateReportingValue( this.getProxy().getStorage().getInventory( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ) );
}
if( this.configuredFluid != null )
{
this.updateReportingValue( this.getProxy().getStorage().getInventory( AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ) ) );
}
}
catch( final GridAccessException e )
{
// ;P
}
}
}
@Override @Override
public void onStackChange( final IItemList o, final IAEStack fullStack, final IAEStack diffStack, final IActionSource src, final IStorageChannel chan ) public void onStackChange( IItemList<?> o, IAEStack<?> fullStack, IAEStack<?> diffStack, IActionSource src, IStorageChannel<?> chan )
{ {
if( this.configuredItem != null ) if( this.configuredItem != null )
{ {
if( fullStack == null ) long diff = this.configuredItem.getStackSize() + diffStack.getStackSize();
{ this.configuredItem.setStackSize( diff >= 0 ? this.configuredItem.getStackSize() + diffStack.getStackSize() : 0 );
this.configuredItem.setStackSize( 0 );
}
else
{
this.configuredItem.setStackSize( fullStack.getStackSize() );
}
final long stackSize = this.configuredItem.getStackSize(); final long stackSize = this.configuredItem.getStackSize();
final String humanReadableText = NUMBER_CONVERTER.toWideReadableForm( stackSize ); final String humanReadableText = NUMBER_CONVERTER.toWideReadableForm( stackSize );
@@ -410,14 +480,8 @@ public abstract class AbstractPartMonitor extends AbstractPartDisplay implements
} }
else if( this.configuredFluid != null ) else if( this.configuredFluid != null )
{ {
if( fullStack == null ) long diff = this.configuredFluid.getStackSize() + diffStack.getStackSize();
{ this.configuredFluid.setStackSize( diff >= 0 ? this.configuredFluid.getStackSize() + diffStack.getStackSize() : 0 );
this.configuredFluid.setStackSize( 0 );
}
else
{
this.configuredFluid.setStackSize( fullStack.getStackSize() );
}
final long stackSize = this.configuredFluid.getStackSize() / 1000; final long stackSize = this.configuredFluid.getStackSize() / 1000;
final String humanReadableText = NUMBER_CONVERTER.toWideReadableForm( stackSize ) + "B"; final String humanReadableText = NUMBER_CONVERTER.toWideReadableForm( stackSize ) + "B";
@@ -554,14 +554,10 @@ public class TileChest extends AENetworkPowerTile implements IMEChest, ITerminal
@Override @Override
public List<IMEInventoryHandler> getCellArray( final IStorageChannel channel ) public List<IMEInventoryHandler> getCellArray( final IStorageChannel channel )
{ {
if( this.getProxy().isActive() ) this.updateHandler();
if( this.cellHandler != null && this.cellHandler.getChannel() == channel )
{ {
this.updateHandler(); return Collections.singletonList( this.cellHandler );
if( this.cellHandler != null && this.cellHandler.getChannel() == channel )
{
return Collections.singletonList( this.cellHandler );
}
} }
return Collections.emptyList(); return Collections.emptyList();
} }
@@ -692,21 +688,16 @@ public class TileChest extends AENetworkPowerTile implements IMEChest, ITerminal
@Override @Override
public void postChange( final IBaseMonitor<T> monitor, final Iterable<T> change, final IActionSource source ) public void postChange( final IBaseMonitor<T> monitor, final Iterable<T> change, final IActionSource source )
{ {
if( source == TileChest.this.mySrc || source.machine().map( machine -> machine == TileChest.this ).orElse( false ) ) try
{ {
try if( TileChest.this.getProxy().isActive() )
{ {
if( TileChest.this.getProxy().isActive() ) TileChest.this.getProxy().getStorage().postAlterationOfStoredItems( this.chan, change, TileChest.this.mySrc );
{
TileChest.this.getProxy().getStorage().postAlterationOfStoredItems( this.chan, change, TileChest.this.mySrc );
}
}
catch( final GridAccessException e )
{
// :(
} }
} catch ( final GridAccessException e )
{
// :(
} }
TileChest.this.blinkCell( 0 ); TileChest.this.blinkCell( 0 );
} }
@@ -334,13 +334,8 @@ public class TileDrive extends AENetworkInvTile implements IChestOrDrive, IPrior
@Override @Override
public List<IMEInventoryHandler> getCellArray( final IStorageChannel channel ) public List<IMEInventoryHandler> getCellArray( final IStorageChannel channel )
{ {
if( this.getProxy().isActive() ) this.updateState();
{ return this.inventoryHandlers.get( channel );
this.updateState();
return this.inventoryHandlers.get( channel );
}
return Collections.emptyList();
} }
@Override @Override
@@ -418,10 +418,12 @@ public class TileIOPort extends AENetworkInvTile implements IUpgradeableHost, IC
if( possible > 0 ) if( possible > 0 )
{ {
possible = Math.min( possible, itemsToMove ); IAEStack injectable = s.copy();
s.setStackSize( possible );
final IAEStack extracted = src.extractItems( s, Actionable.MODULATE, this.mySrc ); possible = Math.min( possible, itemsToMove );
injectable.setStackSize( possible );
final IAEStack extracted = src.extractItems( injectable, Actionable.MODULATE, this.mySrc );
if( extracted != null ) if( extracted != null )
{ {
possible = extracted.getStackSize(); possible = extracted.getStackSize();
@@ -500,8 +502,9 @@ public class TileIOPort extends AENetworkInvTile implements IUpgradeableHost, IC
final IAEStack test = myList.getFirstItem(); final IAEStack test = myList.getFirstItem();
if( test != null ) if( test != null )
{ {
test.setStackSize( 1 ); IAEStack testCopy = test.copy();
return src.injectItems( test, Actionable.SIMULATE, this.mySrc ) != null; testCopy.setStackSize( 1 );
return src.injectItems( testCopy, Actionable.SIMULATE, this.mySrc ) != null;
} }
return false; return false;
} }
@@ -36,6 +36,7 @@ public final class ConfigManager implements IConfigManager
{ {
private final Map<Settings, Enum<?>> settings = new EnumMap<>( Settings.class ); private final Map<Settings, Enum<?>> settings = new EnumMap<>( Settings.class );
private final IConfigManagerHost target; private final IConfigManagerHost target;
private Map<Settings, Enum<?>> oldSettings = new EnumMap<>( Settings.class );
public ConfigManager( final IConfigManagerHost tile ) public ConfigManager( final IConfigManagerHost tile )
{ {
@@ -72,10 +73,15 @@ public final class ConfigManager implements IConfigManager
{ {
final Enum<?> oldValue = this.getSetting( settingName ); final Enum<?> oldValue = this.getSetting( settingName );
this.settings.put( settingName, newValue ); this.settings.put( settingName, newValue );
this.oldSettings.put( settingName, oldValue );
this.target.updateSetting( this, settingName, newValue ); this.target.updateSetting( this, settingName, newValue );
return oldValue; return oldValue;
} }
public Enum<?> getOldSetting(final Settings settingName){
return this.oldSettings.get( settingName );
}
/** /**
* save all settings using config manager. * save all settings using config manager.
* *
@@ -43,7 +43,7 @@ public class OreReference
return this.otherOptions; return this.otherOptions;
} }
List<IAEItemStack> getAEEquivalents() public List<IAEItemStack> getAEEquivalents()
{ {
if( this.aeOtherOptions == null ) if( this.aeOtherOptions == null )
{ {
@@ -18,32 +18,20 @@
"type": "appliedenergistics2:part", "type": "appliedenergistics2:part",
"part": "material.card_pattern_expansion" "part": "material.card_pattern_expansion"
}, },
"type": "appliedenergistics2:part_shaped", "type": "appliedenergistics2:part_shapeless",
"pattern": [
"ci"
],
"ingredients": [ "ingredients": [
{ {
"type": "appliedenergistics2:part", "type": "appliedenergistics2:part",
"part": "material.advanced_card" "part": "material.advanced_card"
}, },
{ [
"key": "#" {
} "item": "appliedenergistics2:interface"
], },
"key": { {
"i": [ "type": "appliedenergistics2:part",
{ "part": "part.interface"
"item": "appliedenergistics2:interface" }
}, ]
{ ]
"type": "appliedenergistics2:part",
"part": "part.interface"
}],
"c": {
"type": "appliedenergistics2:part",
"part": "material.advanced_card"
}
}
} }