Merge branch 'IItemRepository' into AE2-Omnifactory
This commit is contained in:
@@ -0,0 +1,329 @@
|
||||
package appeng.parts.misc;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import appeng.api.storage.IStorageChannel;
|
||||
|
||||
import appeng.core.AELog;
|
||||
import com.jaquadro.minecraft.storagedrawers.api.capabilities.IItemRepository;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.NonNullList;
|
||||
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.config.Actionable;
|
||||
import appeng.api.networking.security.IActionSource;
|
||||
import appeng.api.networking.storage.IBaseMonitor;
|
||||
import appeng.api.networking.ticking.TickRateModulation;
|
||||
import appeng.api.storage.IMEInventory;
|
||||
import appeng.api.storage.IMEMonitorHandlerReceiver;
|
||||
import appeng.api.storage.channels.IItemStorageChannel;
|
||||
import appeng.api.storage.data.IAEItemStack;
|
||||
import appeng.api.storage.data.IItemList;
|
||||
import appeng.me.GridAccessException;
|
||||
import appeng.me.helpers.IGridProxyable;
|
||||
import appeng.me.storage.ITickingMonitor;
|
||||
import appeng.util.item.AEItemStack;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Wraps an Item Repository in such a way that it can be used as an IMEInventory for items.
|
||||
* Used by the Storage Bus
|
||||
*/
|
||||
|
||||
class ItemRepositoryAdapter implements IMEInventory<IAEItemStack>, IBaseMonitor<IAEItemStack>, ITickingMonitor, IItemRepository
|
||||
{
|
||||
private final Map<IMEMonitorHandlerReceiver<IAEItemStack>, Object> listeners = new HashMap<>();
|
||||
private IActionSource mySource;
|
||||
private final IItemRepository itemRepository;
|
||||
private final IGridProxyable proxyable;
|
||||
private final InventoryCache cache;
|
||||
|
||||
|
||||
ItemRepositoryAdapter( IItemRepository itemRepository, IGridProxyable proxy )
|
||||
{
|
||||
this.itemRepository = itemRepository;
|
||||
this.proxyable = proxy;
|
||||
this.cache = new InventoryCache( this.itemRepository );
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAEItemStack injectItems( IAEItemStack iox, Actionable type, IActionSource src )
|
||||
{
|
||||
ItemStack orgInput = iox.createItemStack();
|
||||
ItemStack remaining = orgInput;
|
||||
|
||||
boolean simulate = ( type == Actionable.SIMULATE );
|
||||
|
||||
remaining = this.itemRepository.insertItem( remaining, simulate );
|
||||
|
||||
// At this point, we still have some items left...
|
||||
if( remaining == orgInput )
|
||||
{
|
||||
// The stack remained unmodified, target inventory is full
|
||||
return iox;
|
||||
}
|
||||
|
||||
if( type == Actionable.MODULATE )
|
||||
{
|
||||
try
|
||||
{
|
||||
this.proxyable.getProxy().getTick().alertDevice( this.proxyable.getProxy().getNode() );
|
||||
}
|
||||
catch( GridAccessException ex )
|
||||
{
|
||||
// meh
|
||||
}
|
||||
}
|
||||
|
||||
return AEItemStack.fromItemStack( remaining );
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAEItemStack extractItems( IAEItemStack request, Actionable mode, IActionSource src )
|
||||
{
|
||||
ItemStack requestedItemStack = request.createItemStack();
|
||||
int remainingSize = requestedItemStack.getCount();
|
||||
|
||||
final boolean simulate = ( mode == Actionable.SIMULATE );
|
||||
|
||||
ItemStack extracted;
|
||||
extracted = this.itemRepository.extractItem( requestedItemStack, remainingSize, simulate );
|
||||
|
||||
if( extracted.getCount() > remainingSize )
|
||||
{
|
||||
// Something broke. It should never return more than we requested...
|
||||
// We're going to silently eat the remainder
|
||||
AELog.warn( "Mod that provided item handler %s is broken. Returned %s items while only requesting %d.",
|
||||
this.itemRepository.getClass().getName(), extracted.toString(), remainingSize );
|
||||
extracted.setCount( remainingSize );
|
||||
}
|
||||
|
||||
if( !extracted.isEmpty() )
|
||||
{
|
||||
if( mode == Actionable.MODULATE )
|
||||
{
|
||||
try
|
||||
{
|
||||
this.proxyable.getProxy().getTick().alertDevice( this.proxyable.getProxy().getNode() );
|
||||
}
|
||||
catch( GridAccessException ex )
|
||||
{
|
||||
// meh
|
||||
}
|
||||
}
|
||||
|
||||
return AEItemStack.fromItemStack( extracted );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItemList<IAEItemStack> getAvailableItems( IItemList<IAEItemStack> out )
|
||||
{
|
||||
return this.cache.getAvailableItems( out );
|
||||
}
|
||||
|
||||
@Override
|
||||
public IStorageChannel<IAEItemStack> getChannel()
|
||||
{
|
||||
return AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener( IMEMonitorHandlerReceiver<IAEItemStack> l, Object verificationToken )
|
||||
{
|
||||
this.listeners.put( l, verificationToken );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener( IMEMonitorHandlerReceiver<IAEItemStack> l )
|
||||
{
|
||||
this.listeners.remove( l );
|
||||
}
|
||||
|
||||
private void postDifference( Iterable<IAEItemStack> a )
|
||||
{
|
||||
final Iterator<Map.Entry<IMEMonitorHandlerReceiver<IAEItemStack>, Object>> i = this.listeners.entrySet().iterator();
|
||||
while( i.hasNext() )
|
||||
{
|
||||
final Map.Entry<IMEMonitorHandlerReceiver<IAEItemStack>, Object> l = i.next();
|
||||
final IMEMonitorHandlerReceiver<IAEItemStack> key = l.getKey();
|
||||
if( key.isValid( l.getValue() ) )
|
||||
{
|
||||
key.postChange( this, a, this.mySource );
|
||||
}
|
||||
else
|
||||
{
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TickRateModulation onTick()
|
||||
{
|
||||
{
|
||||
List<IAEItemStack> changes = this.cache.update();
|
||||
if( !changes.isEmpty() )
|
||||
{
|
||||
this.postDifference( changes );
|
||||
return TickRateModulation.URGENT;
|
||||
}
|
||||
else
|
||||
{
|
||||
return TickRateModulation.SLOWER;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setActionSource( final IActionSource mySource )
|
||||
{
|
||||
this.mySource = mySource;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public NonNullList<ItemRecord> getAllItems()
|
||||
{
|
||||
//not a provider
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public ItemStack insertItem( @Nonnull ItemStack stack, boolean simulate, Predicate<ItemStack> predicate )
|
||||
{
|
||||
//not a provider
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public ItemStack extractItem( @Nonnull ItemStack stack, int amount, boolean simulate, Predicate<ItemStack> predicate )
|
||||
{
|
||||
//not a provider
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class InventoryCache
|
||||
{
|
||||
private IAEItemStack[] cachedAeStacks = new IAEItemStack[0];
|
||||
private final IItemRepository iItemRepository;
|
||||
|
||||
public InventoryCache( IItemRepository iItemRepository )
|
||||
{
|
||||
this.iItemRepository = iItemRepository;
|
||||
}
|
||||
|
||||
public IItemList<IAEItemStack> getAvailableItems( IItemList<IAEItemStack> out )
|
||||
{
|
||||
Arrays.stream( this.cachedAeStacks ).forEach( out::add );
|
||||
return out;
|
||||
}
|
||||
|
||||
public List<IAEItemStack> update()
|
||||
{
|
||||
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() );
|
||||
|
||||
final int size = out.size();
|
||||
|
||||
// Make room for new slots
|
||||
if( size > this.cachedAeStacks.length )
|
||||
{
|
||||
this.cachedAeStacks = Arrays.copyOf( this.cachedAeStacks, size );
|
||||
}
|
||||
|
||||
for( int x = 0; x < size; x++ )
|
||||
{
|
||||
// Save the old stuff
|
||||
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
|
||||
if( size < this.cachedAeStacks.length )
|
||||
{
|
||||
for( int x = 0; x < this.cachedAeStacks.length; x++ )
|
||||
{
|
||||
final IAEItemStack aeStack = this.cachedAeStacks[x];
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
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] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user