Applied-Energistics-2-tiler.../src/main/java/appeng/me/storage/MEMonitorIInventory.java

338 lines
7.8 KiB
Java
Raw Normal View History

2014-11-14 12:02:52 +01:00
/*
* 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>.
*/
2014-09-24 02:26:27 +02:00
package appeng.me.storage;
2014-09-24 02:26:27 +02:00
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map.Entry;
import java.util.NavigableMap;
import java.util.concurrent.ConcurrentSkipListMap;
2014-09-24 02:26:27 +02:00
import net.minecraft.item.ItemStack;
2014-09-24 02:26:27 +02:00
import appeng.api.AEApi;
import appeng.api.config.AccessRestriction;
import appeng.api.config.Actionable;
import appeng.api.config.StorageFilter;
import appeng.api.networking.security.BaseActionSource;
import appeng.api.networking.ticking.TickRateModulation;
import appeng.api.storage.IMEMonitor;
import appeng.api.storage.IMEMonitorHandlerReceiver;
import appeng.api.storage.StorageChannel;
import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IItemList;
import appeng.util.InventoryAdaptor;
import appeng.util.Platform;
import appeng.util.inv.ItemSlot;
2014-10-04 08:08:28 +02:00
public class MEMonitorIInventory implements IMEMonitor<IAEItemStack>
2014-09-24 02:26:27 +02:00
{
final InventoryAdaptor adaptor;
final IItemList<IAEItemStack> list = AEApi.instance().storage().createItemList();
2014-09-28 22:20:14 +02:00
final HashMap<IMEMonitorHandlerReceiver<IAEItemStack>, Object> listeners = new HashMap<IMEMonitorHandlerReceiver<IAEItemStack>, Object>();
private final NavigableMap<Integer, CachedItemStack> memory;
2014-09-24 02:26:27 +02:00
public BaseActionSource mySource;
public StorageFilter mode = StorageFilter.EXTRACTABLE_ONLY;
public MEMonitorIInventory( InventoryAdaptor adaptor )
2014-09-24 02:26:27 +02:00
{
this.adaptor = adaptor;
this.memory = new ConcurrentSkipListMap<Integer, CachedItemStack>();
2014-09-24 02:26:27 +02:00
}
@Override
public void addListener( IMEMonitorHandlerReceiver<IAEItemStack> l, Object verificationToken )
2014-09-24 02:26:27 +02:00
{
this.listeners.put( l, verificationToken );
2014-09-24 02:26:27 +02:00
}
@Override
public void removeListener( IMEMonitorHandlerReceiver<IAEItemStack> l )
2014-09-24 02:26:27 +02:00
{
this.listeners.remove( l );
2014-09-24 02:26:27 +02:00
}
@Override
public IAEItemStack injectItems( IAEItemStack input, Actionable type, BaseActionSource src )
2014-09-24 02:26:27 +02:00
{
ItemStack out = null;
if( type == Actionable.SIMULATE )
2015-04-29 02:30:53 +02:00
{
2014-12-29 15:13:47 +01:00
out = this.adaptor.simulateAdd( input.getItemStack() );
2015-04-29 02:30:53 +02:00
}
2014-09-24 02:26:27 +02:00
else
2015-04-29 02:30:53 +02:00
{
2014-12-29 15:13:47 +01:00
out = this.adaptor.addItems( input.getItemStack() );
2015-04-29 02:30:53 +02:00
}
2014-09-24 02:26:27 +02:00
if( type == Actionable.MODULATE )
{
this.onTick();
}
2014-09-24 02:26:27 +02:00
if( out == null )
2015-04-29 02:30:53 +02:00
{
2014-09-24 02:26:27 +02:00
return null;
2015-04-29 02:30:53 +02:00
}
2014-09-24 02:26:27 +02:00
// better then doing construction from scratch :3
IAEItemStack o = input.copy();
o.setStackSize( out.stackSize );
return o;
}
@Override
public IAEItemStack extractItems( IAEItemStack request, Actionable type, BaseActionSource src )
2014-09-24 02:26:27 +02:00
{
ItemStack out = null;
if( type == Actionable.SIMULATE )
2015-04-29 02:30:53 +02:00
{
2014-12-29 15:13:47 +01:00
out = this.adaptor.simulateRemove( (int) request.getStackSize(), request.getItemStack(), null );
2015-04-29 02:30:53 +02:00
}
2014-09-24 02:26:27 +02:00
else
2015-04-29 02:30:53 +02:00
{
2014-12-29 15:13:47 +01:00
out = this.adaptor.removeItems( (int) request.getStackSize(), request.getItemStack(), null );
2015-04-29 02:30:53 +02:00
}
2014-09-24 02:26:27 +02:00
if( out == null )
2015-04-29 02:30:53 +02:00
{
2014-09-24 02:26:27 +02:00
return null;
2015-04-29 02:30:53 +02:00
}
2014-09-24 02:26:27 +02:00
// better then doing construction from scratch :3
IAEItemStack o = request.copy();
o.setStackSize( out.stackSize );
if( type == Actionable.MODULATE )
{
this.onTick();
}
2014-09-24 02:26:27 +02:00
return o;
}
@Override
public StorageChannel getChannel()
{
return StorageChannel.ITEMS;
}
2014-09-24 02:26:27 +02:00
public TickRateModulation onTick()
{
boolean changed = false;
LinkedList<IAEItemStack> changes = new LinkedList<IAEItemStack>();
int high = 0;
2014-12-29 15:13:47 +01:00
this.list.resetStatus();
for( ItemSlot is : this.adaptor )
2014-09-24 02:26:27 +02:00
{
2014-12-29 15:13:47 +01:00
CachedItemStack old = this.memory.get( is.slot );
2014-09-24 02:26:27 +02:00
high = Math.max( high, is.slot );
2014-12-29 15:13:47 +01:00
ItemStack newIS = !is.isExtractable && this.mode == StorageFilter.EXTRACTABLE_ONLY ? null : is.getItemStack();
2014-09-24 02:26:27 +02:00
ItemStack oldIS = old == null ? null : old.itemStack;
if( this.isDifferent( newIS, oldIS ) )
2014-09-24 02:26:27 +02:00
{
CachedItemStack cis = new CachedItemStack( is.getItemStack() );
2014-12-29 15:13:47 +01:00
this.memory.put( is.slot, cis );
2014-09-24 02:26:27 +02:00
if( old != null && old.aeStack != null )
2014-09-24 02:26:27 +02:00
{
old.aeStack.setStackSize( -old.aeStack.getStackSize() );
changes.add( old.aeStack );
}
if( cis.aeStack != null )
2014-09-24 02:26:27 +02:00
{
changes.add( cis.aeStack );
2014-12-29 15:13:47 +01:00
this.list.add( cis.aeStack );
2014-09-24 02:26:27 +02:00
}
changed = true;
}
2014-09-28 19:41:51 +02:00
else
2014-09-24 02:26:27 +02:00
{
int newSize = ( newIS == null ? 0 : newIS.stackSize );
int diff = newSize - ( oldIS == null ? 0 : oldIS.stackSize );
2014-09-24 02:26:27 +02:00
IAEItemStack stack = ( old == null || old.aeStack == null ? AEApi.instance().storage().createItemStack( newIS ) : old.aeStack.copy() );
if( stack != null )
2014-09-24 02:26:27 +02:00
{
stack.setStackSize( newSize );
2014-12-29 15:13:47 +01:00
this.list.add( stack );
2014-09-24 02:26:27 +02:00
}
if( diff != 0 && stack != null )
2014-09-24 02:26:27 +02:00
{
CachedItemStack cis = new CachedItemStack( is.getItemStack() );
2014-12-29 15:13:47 +01:00
this.memory.put( is.slot, cis );
2014-09-24 02:26:27 +02:00
IAEItemStack a = stack.copy();
a.setStackSize( diff );
changes.add( a );
changed = true;
}
}
}
// detect dropped items; should fix non IISided Inventory Changes.
2014-12-29 15:13:47 +01:00
NavigableMap<Integer, CachedItemStack> end = this.memory.tailMap( high, false );
if( !end.isEmpty() )
2014-09-24 02:26:27 +02:00
{
for( CachedItemStack cis : end.values() )
2014-09-24 02:26:27 +02:00
{
if( cis != null && cis.aeStack != null )
2014-09-24 02:26:27 +02:00
{
IAEItemStack a = cis.aeStack.copy();
a.setStackSize( -a.getStackSize() );
changes.add( a );
changed = true;
}
}
end.clear();
}
if( !changes.isEmpty() )
2015-04-29 02:30:53 +02:00
{
2014-12-29 15:13:47 +01:00
this.postDifference( changes );
2015-04-29 02:30:53 +02:00
}
2014-09-24 02:26:27 +02:00
return changed ? TickRateModulation.URGENT : TickRateModulation.SLOWER;
}
private boolean isDifferent( ItemStack a, ItemStack b )
2014-09-24 02:26:27 +02:00
{
if( a == b && b == null )
2015-04-29 02:30:53 +02:00
{
2014-09-24 02:26:27 +02:00
return false;
2015-04-29 02:30:53 +02:00
}
2014-09-24 02:26:27 +02:00
if( ( a == null && b != null ) || ( a != null && b == null ) )
2015-04-29 02:30:53 +02:00
{
2014-09-24 02:26:27 +02:00
return true;
2015-04-29 02:30:53 +02:00
}
2014-09-24 02:26:27 +02:00
return !Platform.isSameItemPrecise( a, b );
}
private void postDifference( Iterable<IAEItemStack> a )
2014-09-24 02:26:27 +02:00
{
// AELog.info( a.getItemStack().getUnlocalizedName() + " @ " + a.getStackSize() );
if( a != null )
2014-09-24 02:26:27 +02:00
{
2014-12-29 15:13:47 +01:00
Iterator<Entry<IMEMonitorHandlerReceiver<IAEItemStack>, Object>> i = this.listeners.entrySet().iterator();
while( i.hasNext() )
2014-09-24 02:26:27 +02:00
{
Entry<IMEMonitorHandlerReceiver<IAEItemStack>, Object> l = i.next();
IMEMonitorHandlerReceiver<IAEItemStack> key = l.getKey();
if( key.isValid( l.getValue() ) )
2015-04-29 02:30:53 +02:00
{
2014-12-29 15:13:47 +01:00
key.postChange( this, a, this.mySource );
2015-04-29 02:30:53 +02:00
}
2014-09-24 02:26:27 +02:00
else
2015-04-29 02:30:53 +02:00
{
2014-09-24 02:26:27 +02:00
i.remove();
2015-04-29 02:30:53 +02:00
}
2014-09-24 02:26:27 +02:00
}
}
}
@Override
public AccessRestriction getAccess()
2014-09-24 02:26:27 +02:00
{
return AccessRestriction.READ_WRITE;
2014-09-24 02:26:27 +02:00
}
@Override
public boolean isPrioritized( IAEItemStack input )
{
return false;
}
@Override
public boolean canAccept( IAEItemStack input )
2014-09-24 02:26:27 +02:00
{
return true;
}
@Override
public int getPriority()
{
return 0;
}
@Override
public int getSlot()
{
return 0;
}
@Override
public boolean validForPass( int i )
{
return true;
}
@Override
public IItemList<IAEItemStack> getAvailableItems( IItemList out )
{
for( CachedItemStack is : this.memory.values() )
2015-04-29 02:30:53 +02:00
{
out.addStorage( is.aeStack );
2015-04-29 02:30:53 +02:00
}
return out;
}
@Override
public IItemList<IAEItemStack> getStorageList()
{
return this.list;
}
static class CachedItemStack
{
final ItemStack itemStack;
final IAEItemStack aeStack;
public CachedItemStack( ItemStack is )
{
if( is == null )
{
this.itemStack = null;
this.aeStack = null;
}
else
{
this.itemStack = is.copy();
this.aeStack = AEApi.instance().storage().createItemStack( is );
}
}
}
2014-09-24 02:26:27 +02:00
}