package appeng.me.storage; import java.util.ArrayList; import java.util.Comparator; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.TreeMap; import appeng.api.config.AccessRestriction; import appeng.api.config.Actionable; import appeng.api.config.SecurityPermissions; import appeng.api.networking.IGrid; import appeng.api.networking.IGridNode; import appeng.api.networking.security.BaseActionSource; import appeng.api.networking.security.ISecurityGrid; import appeng.api.networking.security.MachineSource; import appeng.api.networking.security.PlayerSource; import appeng.api.storage.IMEInventoryHandler; import appeng.api.storage.StorageChannel; import appeng.api.storage.data.IAEStack; import appeng.api.storage.data.IItemList; import appeng.me.cache.SecurityCache; public class NetworkInventoryHandler> implements IMEInventoryHandler { private final static Comparator prioritySorter = new Comparator() { @Override public int compare(Integer o1, Integer o2) { return o2 - o1; } }; final StorageChannel myChannel; final SecurityCache security; // final TreeMultimap> prorityInventory; final TreeMap>> prorityInventory; public NetworkInventoryHandler(StorageChannel chan, SecurityCache security) { myChannel = chan; this.security = security; prorityInventory = new TreeMap( prioritySorter ); // TreeMultimap.create( prioritySorter, hashSorter ); } public void addNewStorage(IMEInventoryHandler h) { int priority = h.getPriority(); List> list = prorityInventory.get( priority ); if ( list == null ) prorityInventory.put( priority, list = new ArrayList() ); list.add( h ); } static int currentPass = 0; int myPass = 0; final static public LinkedList depth = new LinkedList(); private boolean diveList(NetworkInventoryHandler networkInventoryHandler) { if ( depth.contains( networkInventoryHandler ) ) return true; depth.push( this ); return false; } private boolean diveIteration(NetworkInventoryHandler networkInventoryHandler) { if ( depth.isEmpty() ) { currentPass++; myPass = currentPass; } else { if ( currentPass == myPass ) return true; else myPass = currentPass; } depth.push( this ); return false; } private void surface(NetworkInventoryHandler networkInventoryHandler) { Object last = depth.pop(); if ( last != this ) throw new RuntimeException( "Invalid Access to Networked Storage API detected." ); } private boolean testPermission(BaseActionSource src, SecurityPermissions permission) { if ( src.isPlayer() ) { if ( !security.hasPermission( ((PlayerSource) src).player, permission ) ) return true; } else if ( src.isMachine() ) { if ( security.isAvailable() ) { IGridNode n = ((MachineSource) src).via.getActionableNode(); if ( n == null ) return true; IGrid gn = n.getGrid(); if ( gn != security.myGrid ) { int playerID = -1; ISecurityGrid sg = gn.getCache( ISecurityGrid.class ); playerID = sg.getOwner(); if ( !security.hasPermission( playerID, permission ) ) return true; } } } return false; } @Override public T injectItems(T input, Actionable type, BaseActionSource src) { if ( diveList( this ) ) return input; if ( testPermission( src, SecurityPermissions.INJECT ) ) { surface( this ); return input; } Iterator>> i = prorityInventory.values().iterator();// asMap().entrySet().iterator(); while (i.hasNext()) { List> invList = i.next(); Iterator> ii = invList.iterator(); while (ii.hasNext() && input != null) { IMEInventoryHandler inv = ii.next(); if ( inv.canAccept( input ) && (inv.extractItems( input, Actionable.SIMULATE, src ) != null || inv.isPrioritized( input )) ) input = inv.injectItems( input, type, src ); } ii = invList.iterator(); while (ii.hasNext() && input != null) { IMEInventoryHandler inv = ii.next(); if ( inv.canAccept( input ) ) input = inv.injectItems( input, type, src ); } } surface( this ); return input; } @Override public T extractItems(T request, Actionable mode, BaseActionSource src) { if ( diveList( this ) ) return null; if ( testPermission( src, SecurityPermissions.EXTRACT ) ) { surface( this ); return null; } Iterator>> i = prorityInventory.descendingMap().values().iterator();// prorityInventory.asMap().descendingMap().entrySet().iterator(); T output = request.copy(); request = request.copy(); output.setStackSize( 0 ); long req = request.getStackSize(); while (i.hasNext()) { List> invList = i.next(); Iterator> ii = invList.iterator(); while (ii.hasNext() && output.getStackSize() < req) { IMEInventoryHandler inv = ii.next(); request.setStackSize( req - output.getStackSize() ); output.add( inv.extractItems( request, mode, src ) ); } } surface( this ); if ( output.getStackSize() <= 0 ) return null; return output; } @Override public IItemList getAvailableItems(IItemList out) { if ( diveIteration( this ) ) return out; // for (Entry> h : prorityInventory.entries()) for (List> i : prorityInventory.values()) for (IMEInventoryHandler j : i) out = j.getAvailableItems( out ); surface( this ); return out; } @Override public StorageChannel getChannel() { return myChannel; } @Override public AccessRestriction getAccess() { return AccessRestriction.READ_WRITE; } @Override public boolean isPrioritized(T input) { return false; } @Override public boolean canAccept(T input) { return true; } @Override public int getPriority() { return 0; } @Override public int getSlot() { return 0; } }