Relocate Source to proper directory.
This commit is contained in:
@@ -0,0 +1,236 @@
|
||||
package appeng.me;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.networking.IGrid;
|
||||
import appeng.api.networking.IGridCache;
|
||||
import appeng.api.networking.IGridHost;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.IMachineSet;
|
||||
import appeng.api.networking.events.MENetworkEvent;
|
||||
import appeng.api.networking.events.MENetworkPostCacheConstruction;
|
||||
import appeng.api.util.IReadOnlyCollection;
|
||||
import appeng.core.WorldSettings;
|
||||
import appeng.hooks.TickHandler;
|
||||
import appeng.util.ReadOnlyCollection;
|
||||
|
||||
public class Grid implements IGrid
|
||||
{
|
||||
|
||||
GridStorage myStorage;
|
||||
|
||||
NetworkEventBus bus = new NetworkEventBus();
|
||||
HashMap<Class<? extends IGridHost>, Set> Machines = new HashMap<Class<? extends IGridHost>, Set>();
|
||||
HashMap<Class<? extends IGridCache>, GridCacheWrapper> caches = new HashMap<Class<? extends IGridCache>, GridCacheWrapper>();
|
||||
|
||||
GridNode pivot;
|
||||
int isImportant; // how import is this network?
|
||||
|
||||
public Grid(GridNode center) {
|
||||
this.pivot = center;
|
||||
|
||||
HashMap<Class<? extends IGridCache>, IGridCache> myCaches = AEApi.instance().registries().gridCache().createCacheInstance( this );
|
||||
for (Class<? extends IGridCache> c : myCaches.keySet())
|
||||
{
|
||||
bus.readClass( c, myCaches.get( c ).getClass() );
|
||||
caches.put( c, new GridCacheWrapper( myCaches.get( c ) ) );
|
||||
}
|
||||
|
||||
postEvent( new MENetworkPostCacheConstruction() );
|
||||
|
||||
TickHandler.instance.addNetwork( this );
|
||||
center.setGrid( this );
|
||||
}
|
||||
|
||||
public Set<Class<? extends IGridHost>> getMachineClasses()
|
||||
{
|
||||
return Machines.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGridNode getPivot()
|
||||
{
|
||||
return pivot;
|
||||
}
|
||||
|
||||
public int size()
|
||||
{
|
||||
int out = 0;
|
||||
for (Collection<?> x : Machines.values())
|
||||
out += x.size();
|
||||
return out;
|
||||
}
|
||||
|
||||
public void remove(GridNode gridNode)
|
||||
{
|
||||
for (IGridCache c : caches.values())
|
||||
c.removeNode( gridNode, gridNode.getMachine() );
|
||||
|
||||
Collection<IGridNode> nodes = Machines.get( gridNode.getMachineClass() );
|
||||
if ( nodes != null )
|
||||
nodes.remove( gridNode );
|
||||
|
||||
gridNode.setGridStorage( null );
|
||||
|
||||
if ( pivot == gridNode )
|
||||
{
|
||||
Iterator<IGridNode> n = getNodes().iterator();
|
||||
if ( n.hasNext() )
|
||||
pivot = (GridNode) n.next();
|
||||
else
|
||||
{
|
||||
pivot = null;
|
||||
TickHandler.instance.removeNetwork( this );
|
||||
myStorage.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void add(GridNode gridNode)
|
||||
{
|
||||
Class<? extends IGridHost> mClass = gridNode.getMachineClass();
|
||||
Set<IGridNode> nodes = Machines.get( mClass );
|
||||
if ( nodes == null )
|
||||
{
|
||||
Machines.put( mClass, nodes = new MachineSet( mClass ) );
|
||||
bus.readClass( mClass, mClass );
|
||||
}
|
||||
|
||||
// handle loading grid storages.
|
||||
if ( gridNode.getGridStorage() != null )
|
||||
{
|
||||
GridStorage gs = gridNode.getGridStorage();
|
||||
|
||||
if ( gs.getGrid() == null )
|
||||
{
|
||||
myStorage = gs;
|
||||
myStorage.setGrid( this );
|
||||
|
||||
for (IGridCache gc : caches.values())
|
||||
gc.onJoin( myStorage );
|
||||
}
|
||||
else if ( gs.getGrid() != this )
|
||||
{
|
||||
if ( myStorage == null )
|
||||
{
|
||||
myStorage = WorldSettings.getInstance().getNewGridStorage();
|
||||
myStorage.setGrid( this );
|
||||
}
|
||||
|
||||
GridStorage tmp = new GridStorage();
|
||||
if ( !gs.hasDivided( myStorage ) )
|
||||
{
|
||||
gs.addDivided( myStorage );
|
||||
|
||||
for (IGridCache gc : ((Grid) gs.getGrid()).caches.values())
|
||||
gc.onSplit( tmp );
|
||||
|
||||
for (IGridCache gc : caches.values())
|
||||
gc.onJoin( tmp );
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( myStorage == null )
|
||||
{
|
||||
myStorage = WorldSettings.getInstance().getNewGridStorage();
|
||||
myStorage.setGrid( this );
|
||||
}
|
||||
|
||||
// update grid node...
|
||||
gridNode.setGridStorage( myStorage );
|
||||
|
||||
// track node.
|
||||
nodes.add( gridNode );
|
||||
|
||||
for (IGridCache c : caches.values())
|
||||
c.addNode( gridNode, gridNode.getMachine() );
|
||||
|
||||
gridNode.gridProxy.gridChanged();
|
||||
// postEventTo( gridNode, networkChanged );
|
||||
}
|
||||
|
||||
@Override
|
||||
public IReadOnlyCollection<IGridNode> getNodes()
|
||||
{
|
||||
return new NodeIterable( Machines );
|
||||
}
|
||||
|
||||
@Override
|
||||
public IReadOnlyCollection<Class<? extends IGridHost>> getMachinesClasses()
|
||||
{
|
||||
return new ReadOnlyCollection<Class<? extends IGridHost>>( Machines.keySet() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public IMachineSet getMachines(Class<? extends IGridHost> c)
|
||||
{
|
||||
MachineSet s = (MachineSet) Machines.get( c );
|
||||
if ( s == null )
|
||||
return new MachineSet( c );
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C extends IGridCache> C getCache(Class<? extends IGridCache> iface)
|
||||
{
|
||||
return (C) caches.get( iface ).myCache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MENetworkEvent postEventTo(IGridNode node, MENetworkEvent ev)
|
||||
{
|
||||
return bus.postEventTo( this, (GridNode) node, ev );
|
||||
}
|
||||
|
||||
@Override
|
||||
public MENetworkEvent postEvent(MENetworkEvent ev)
|
||||
{
|
||||
return bus.postEvent( this, ev );
|
||||
}
|
||||
|
||||
public void requestSave()
|
||||
{
|
||||
myStorage.markDirty();
|
||||
WorldSettings.getInstance().save();
|
||||
}
|
||||
|
||||
public void update()
|
||||
{
|
||||
for (IGridCache gc : caches.values())
|
||||
{
|
||||
// are there any nodes left?
|
||||
if ( pivot != null )
|
||||
gc.onUpdateTick();
|
||||
}
|
||||
}
|
||||
|
||||
public Iterable<GridCacheWrapper> getCacheWrappers()
|
||||
{
|
||||
return caches.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty()
|
||||
{
|
||||
return pivot == null;
|
||||
}
|
||||
|
||||
public void saveState()
|
||||
{
|
||||
for (IGridCache c : caches.values())
|
||||
{
|
||||
c.populateGridStorage( myStorage );
|
||||
}
|
||||
}
|
||||
|
||||
public void setImportantFlag(int i, boolean publicHasPower)
|
||||
{
|
||||
int flag = 1 << i;
|
||||
isImportant = (isImportant & ~flag) | (publicHasPower ? flag : 0);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package appeng.me;
|
||||
|
||||
public class GridAccessException extends Exception
|
||||
{
|
||||
|
||||
private static final long serialVersionUID = 3914554394866375300L;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package appeng.me;
|
||||
|
||||
import appeng.api.networking.IGridCache;
|
||||
import appeng.api.networking.IGridHost;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.IGridStorage;
|
||||
|
||||
public class GridCacheWrapper implements IGridCache
|
||||
{
|
||||
|
||||
final IGridCache myCache;
|
||||
final String name;
|
||||
|
||||
public GridCacheWrapper(final IGridCache gc) {
|
||||
myCache = gc;
|
||||
name = myCache.getClass().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdateTick()
|
||||
{
|
||||
myCache.onUpdateTick();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNode(final IGridNode gridNode, final IGridHost machine)
|
||||
{
|
||||
myCache.removeNode( gridNode, machine );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNode(final IGridNode gridNode, final IGridHost machine)
|
||||
{
|
||||
myCache.addNode( gridNode, machine );
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSplit(final IGridStorage storageB)
|
||||
{
|
||||
myCache.onSplit( storageB );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onJoin(final IGridStorage storageB)
|
||||
{
|
||||
myCache.onJoin( storageB );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateGridStorage(final IGridStorage storage)
|
||||
{
|
||||
myCache.populateGridStorage( storage );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,230 @@
|
||||
package appeng.me;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
|
||||
import net.minecraftforge.common.util.ForgeDirection;
|
||||
import appeng.api.exceptions.FailedConnection;
|
||||
import appeng.api.networking.GridFlags;
|
||||
import appeng.api.networking.IGridConnection;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.events.MENetworkChannelsChanged;
|
||||
import appeng.api.networking.pathing.IPathingGrid;
|
||||
import appeng.api.util.IReadOnlyCollection;
|
||||
import appeng.core.AEConfig;
|
||||
import appeng.core.AELog;
|
||||
import appeng.core.features.AEFeature;
|
||||
import appeng.me.pathfinding.IPathItem;
|
||||
import appeng.util.Platform;
|
||||
import appeng.util.ReadOnlyCollection;
|
||||
|
||||
public class GridConnection implements IGridConnection, IPathItem
|
||||
{
|
||||
|
||||
final static private MENetworkChannelsChanged event = new MENetworkChannelsChanged();
|
||||
|
||||
private GridNode sideA;
|
||||
private ForgeDirection fromAtoB;
|
||||
private GridNode sideB;
|
||||
|
||||
Object visitorIterationNumber = null;
|
||||
|
||||
public int channelData = 0;
|
||||
|
||||
public GridConnection(IGridNode aNode, IGridNode bNode, ForgeDirection fromAtoB) throws FailedConnection {
|
||||
|
||||
GridNode a = (GridNode) aNode;
|
||||
GridNode b = (GridNode) bNode;
|
||||
|
||||
if ( Platform.securityCheck( a, b ) )
|
||||
{
|
||||
if ( AEConfig.instance.isFeatureEnabled( AEFeature.LogSecurityAudits ) )
|
||||
{
|
||||
AELog.info( "Audit Failed 1: " + a.getGridBlock().getLocation() );
|
||||
AELog.info( "Audit Failed 2: " + b.getGridBlock().getLocation() );
|
||||
}
|
||||
|
||||
throw new FailedConnection();
|
||||
}
|
||||
|
||||
if ( a == null || b == null )
|
||||
throw new GridException( "Connection Forged Between null entities." );
|
||||
|
||||
if ( a.hasConnection( b ) || b.hasConnection( a ) )
|
||||
throw new GridException( "Connection already exists." );
|
||||
|
||||
sideA = a;
|
||||
this.fromAtoB = fromAtoB;
|
||||
sideB = b;
|
||||
|
||||
if ( b.myGrid == null )
|
||||
{
|
||||
b.setGrid( a.getInternalGrid() );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( a.myGrid == null )
|
||||
{
|
||||
GridPropagator gp = new GridPropagator( b.getInternalGrid() );
|
||||
a.beginVisit( gp );
|
||||
}
|
||||
else if ( b.myGrid == null )
|
||||
{
|
||||
GridPropagator gp = new GridPropagator( a.getInternalGrid() );
|
||||
b.beginVisit( gp );
|
||||
}
|
||||
else if ( isNetworkABetter( a, b ) )
|
||||
{
|
||||
GridPropagator gp = new GridPropagator( a.getInternalGrid() );
|
||||
b.beginVisit( gp );
|
||||
}
|
||||
else
|
||||
{
|
||||
GridPropagator gp = new GridPropagator( b.getInternalGrid() );
|
||||
a.beginVisit( gp );
|
||||
}
|
||||
}
|
||||
|
||||
// a connection was destroyed RE-PATH!!
|
||||
IPathingGrid p = sideA.getInternalGrid().getCache( IPathingGrid.class );
|
||||
p.repath();
|
||||
|
||||
sideA.addConnection( this );
|
||||
sideB.addConnection( this );
|
||||
}
|
||||
|
||||
private boolean isNetworkABetter(GridNode a, GridNode b)
|
||||
{
|
||||
return ((Grid) a.myGrid).isImportant > ((Grid) b.myGrid).isImportant || a.myGrid.size() > b.myGrid.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy()
|
||||
{
|
||||
// a connection was destroyed RE-PATH!!
|
||||
IPathingGrid p = sideA.getInternalGrid().getCache( IPathingGrid.class );
|
||||
p.repath();
|
||||
|
||||
sideA.removeConnection( this );
|
||||
sideB.removeConnection( this );
|
||||
|
||||
sideA.validateGrid();
|
||||
sideB.validateGrid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGridNode a()
|
||||
{
|
||||
return sideA;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ForgeDirection getDirection(IGridNode side)
|
||||
{
|
||||
if ( fromAtoB == ForgeDirection.UNKNOWN )
|
||||
return fromAtoB;
|
||||
|
||||
if ( sideA == side )
|
||||
return fromAtoB;
|
||||
else
|
||||
return fromAtoB.getOpposite();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGridNode b()
|
||||
{
|
||||
return sideB;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGridNode getOtherSide(IGridNode gridNode)
|
||||
{
|
||||
if ( gridNode == sideA )
|
||||
return sideB;
|
||||
if ( gridNode == sideB )
|
||||
return sideA;
|
||||
|
||||
throw new GridException( "Invalid Side of Connection" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDirection()
|
||||
{
|
||||
return fromAtoB != ForgeDirection.UNKNOWN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IReadOnlyCollection<IPathItem> getPossibleOptions()
|
||||
{
|
||||
return new ReadOnlyCollection( Arrays.asList( new IPathItem[] { (IPathItem) a(), (IPathItem) b() } ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incrementChannelCount(int usedChannels)
|
||||
{
|
||||
channelData += usedChannels;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSupportMoreChannels()
|
||||
{
|
||||
return getLastUsedChannels() < 32; // max, PERIOD.
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUsedChannels()
|
||||
{
|
||||
return (channelData >> 8) & 0xff;
|
||||
}
|
||||
|
||||
public int getLastUsedChannels()
|
||||
{
|
||||
return channelData & 0xff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPathItem getControllerRoute()
|
||||
{
|
||||
if ( sideA.getFlags().contains( GridFlags.CANNOT_CARRY ) )
|
||||
return null;
|
||||
return sideA;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setControllerRoute(IPathItem fast, boolean zeroOut)
|
||||
{
|
||||
if ( zeroOut )
|
||||
channelData &= ~0xff;
|
||||
|
||||
if ( sideB == fast )
|
||||
{
|
||||
GridNode tmp = sideA;
|
||||
sideA = sideB;
|
||||
sideB = tmp;
|
||||
fromAtoB = fromAtoB.getOpposite();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finalizeChannels()
|
||||
{
|
||||
if ( getUsedChannels() != getLastUsedChannels() )
|
||||
{
|
||||
channelData = (channelData & 0xff);
|
||||
channelData |= channelData << 8;
|
||||
|
||||
if ( sideA.getInternalGrid() != null )
|
||||
sideA.getInternalGrid().postEventTo( sideA, event );
|
||||
|
||||
if ( sideB.getInternalGrid() != null )
|
||||
sideB.getInternalGrid().postEventTo( sideB, event );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<GridFlags> getFlags()
|
||||
{
|
||||
return EnumSet.noneOf( GridFlags.class );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package appeng.me;
|
||||
|
||||
public class GridException extends RuntimeException
|
||||
{
|
||||
|
||||
private static final long serialVersionUID = -8110077032108243076L;
|
||||
|
||||
public GridException(String s) {
|
||||
|
||||
super( s );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,612 @@
|
||||
package appeng.me;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.EnumSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.util.ForgeDirection;
|
||||
import appeng.api.exceptions.FailedConnection;
|
||||
import appeng.api.networking.GridFlags;
|
||||
import appeng.api.networking.GridNotification;
|
||||
import appeng.api.networking.IGrid;
|
||||
import appeng.api.networking.IGridBlock;
|
||||
import appeng.api.networking.IGridCache;
|
||||
import appeng.api.networking.IGridConnectionVisitor;
|
||||
import appeng.api.networking.IGridConnection;
|
||||
import appeng.api.networking.IGridHost;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.IGridVisitor;
|
||||
import appeng.api.networking.energy.IEnergyGrid;
|
||||
import appeng.api.networking.events.MENetworkChannelsChanged;
|
||||
import appeng.api.networking.pathing.IPathingGrid;
|
||||
import appeng.api.util.AEColor;
|
||||
import appeng.api.util.DimensionalCoord;
|
||||
import appeng.api.util.IReadOnlyCollection;
|
||||
import appeng.core.WorldSettings;
|
||||
import appeng.hooks.TickHandler;
|
||||
import appeng.me.pathfinding.IPathItem;
|
||||
import appeng.util.ReadOnlyCollection;
|
||||
|
||||
public class GridNode implements IGridNode, IPathItem
|
||||
{
|
||||
|
||||
final static private MENetworkChannelsChanged event = new MENetworkChannelsChanged();
|
||||
final static private int channelCount[] = new int[] { 0, 8, 32 };
|
||||
|
||||
final List<IGridConnection> Connections = new LinkedList();
|
||||
GridStorage myStorage = null;
|
||||
|
||||
IGridBlock gridProxy;
|
||||
Grid myGrid;
|
||||
|
||||
Object visitorIterationNumber = null;
|
||||
|
||||
// connection criteria
|
||||
private int compressedData = 0;
|
||||
|
||||
@Override
|
||||
public void updateState()
|
||||
{
|
||||
EnumSet<GridFlags> set = gridProxy.getFlags();
|
||||
|
||||
compressedData = set.contains( GridFlags.CANNOT_CARRY ) ? 0 : (set.contains( GridFlags.DENSE_CAPACITY ) ? 2 : 1);
|
||||
|
||||
compressedData = compressedData | (gridProxy.getGridColor().ordinal() << 3);
|
||||
|
||||
for (ForgeDirection dir : gridProxy.getConnectableSides())
|
||||
compressedData = compressedData | (1 << (dir.ordinal() + 8));
|
||||
|
||||
FindConnections();
|
||||
getInternalGrid();
|
||||
}
|
||||
|
||||
public int getMaxChannels()
|
||||
{
|
||||
return channelCount[compressedData & 0x03];
|
||||
}
|
||||
|
||||
public AEColor getColor()
|
||||
{
|
||||
return AEColor.values()[(compressedData >> 3) & 0x1F];
|
||||
}
|
||||
|
||||
private boolean isValidDirection(ForgeDirection dir)
|
||||
{
|
||||
return (compressedData & (1 << (8 + dir.ordinal()))) > 0;
|
||||
}
|
||||
|
||||
// old power draw, used to diff
|
||||
public double previousDraw = 0.0;
|
||||
|
||||
private int channelData = 0;
|
||||
|
||||
public long lastSecurityKey = -1;
|
||||
public int playerID = -1;
|
||||
|
||||
@Override
|
||||
public void setPlayerID(int playerID)
|
||||
{
|
||||
if ( playerID >= 0 )
|
||||
this.playerID = playerID;
|
||||
}
|
||||
|
||||
public int usedChannels()
|
||||
{
|
||||
return channelData >> 8;
|
||||
}
|
||||
|
||||
public GridNode(IGridBlock what) {
|
||||
gridProxy = what;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadFromNBT(String name, NBTTagCompound nodeData)
|
||||
{
|
||||
if ( myGrid == null )
|
||||
{
|
||||
NBTTagCompound node = nodeData.getCompoundTag( name );
|
||||
playerID = node.getInteger( "p" );
|
||||
lastSecurityKey = node.getLong( "k" );
|
||||
setGridStorage( WorldSettings.getInstance().getGridStorage( node.getLong( "g" ) ) );
|
||||
}
|
||||
else
|
||||
throw new RuntimeException( "Loading data after part of a grid, this is invalid." );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveToNBT(String name, NBTTagCompound nodeData)
|
||||
{
|
||||
if ( myStorage != null )
|
||||
{
|
||||
NBTTagCompound node = new NBTTagCompound();
|
||||
|
||||
node.setInteger( "p", playerID );
|
||||
node.setLong( "k", lastSecurityKey );
|
||||
node.setLong( "g", myStorage.getID() );
|
||||
|
||||
nodeData.setTag( name, node );
|
||||
}
|
||||
else
|
||||
nodeData.removeTag( name );
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGridBlock getGridBlock()
|
||||
{
|
||||
return gridProxy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<ForgeDirection> getConnectedSides()
|
||||
{
|
||||
EnumSet<ForgeDirection> set = EnumSet.noneOf( ForgeDirection.class );
|
||||
for (IGridConnection gc : Connections)
|
||||
set.add( gc.getDirection( this ) );
|
||||
return set;
|
||||
}
|
||||
|
||||
public Class<? extends IGridHost> getMachineClass()
|
||||
{
|
||||
return getMachine().getClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGridHost getMachine()
|
||||
{
|
||||
return gridProxy.getMachine();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginVisit(IGridVisitor g)
|
||||
{
|
||||
Object tracker = new Object();
|
||||
|
||||
LinkedList<GridNode> nextRun = new LinkedList();
|
||||
nextRun.add( this );
|
||||
|
||||
visitorIterationNumber = tracker;
|
||||
|
||||
if ( g instanceof IGridConnectionVisitor )
|
||||
{
|
||||
LinkedList<IGridConnection> nextConn = new LinkedList();
|
||||
IGridConnectionVisitor gcv = (IGridConnectionVisitor) g;
|
||||
|
||||
while (!nextRun.isEmpty())
|
||||
{
|
||||
while (!nextConn.isEmpty())
|
||||
gcv.visitConnection( nextConn.poll() );
|
||||
|
||||
LinkedList<GridNode> thisRun = nextRun;
|
||||
nextRun = new LinkedList();
|
||||
|
||||
for (GridNode n : thisRun)
|
||||
n.visitorConnection( tracker, g, nextRun, nextConn );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (!nextRun.isEmpty())
|
||||
{
|
||||
LinkedList<GridNode> thisRun = nextRun;
|
||||
nextRun = new LinkedList();
|
||||
|
||||
for (GridNode n : thisRun)
|
||||
n.visitorNode( tracker, g, nextRun );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void visitorConnection(Object tracker, IGridVisitor g, LinkedList<GridNode> nextRun, LinkedList<IGridConnection> nextConnections)
|
||||
{
|
||||
if ( g.visitNode( this ) )
|
||||
{
|
||||
for (IGridConnection gc : getConnections())
|
||||
{
|
||||
GridNode gn = (GridNode) gc.getOtherSide( this );
|
||||
GridConnection gcc = (GridConnection) gc;
|
||||
|
||||
if ( gcc.visitorIterationNumber != tracker )
|
||||
{
|
||||
gcc.visitorIterationNumber = tracker;
|
||||
nextConnections.add( gc );
|
||||
}
|
||||
|
||||
if ( tracker == gn.visitorIterationNumber )
|
||||
continue;
|
||||
|
||||
gn.visitorIterationNumber = tracker;
|
||||
|
||||
nextRun.add( gn );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void visitorNode(Object tracker, IGridVisitor g, LinkedList<GridNode> nextRun)
|
||||
{
|
||||
if ( g.visitNode( this ) )
|
||||
{
|
||||
for (IGridConnection gc : getConnections())
|
||||
{
|
||||
GridNode gn = (GridNode) gc.getOtherSide( this );
|
||||
|
||||
if ( tracker == gn.visitorIterationNumber )
|
||||
continue;
|
||||
|
||||
gn.visitorIterationNumber = tracker;
|
||||
|
||||
nextRun.add( gn );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void FindConnections()
|
||||
{
|
||||
if ( !gridProxy.isWorldAccessible() )
|
||||
return;
|
||||
|
||||
EnumSet<ForgeDirection> newSecurityConnections = EnumSet.noneOf( ForgeDirection.class );
|
||||
|
||||
DimensionalCoord dc = gridProxy.getLocation();
|
||||
for (ForgeDirection f : ForgeDirection.VALID_DIRECTIONS)
|
||||
{
|
||||
IGridHost te = findGridHost( dc.getWorld(), dc.x + f.offsetX, dc.y + f.offsetY, dc.z + f.offsetZ );
|
||||
if ( te != null )
|
||||
{
|
||||
GridNode node = (GridNode) te.getGridNode( f.getOpposite() );
|
||||
if ( node == null )
|
||||
continue;
|
||||
|
||||
boolean isValidConnection = this.canConnect( node, f ) && node.canConnect( this, f.getOpposite() );
|
||||
|
||||
IGridConnection con = null; // find the connection for this
|
||||
// direction..
|
||||
for (IGridConnection c : getConnections())
|
||||
{
|
||||
if ( c.getDirection( this ) == f )
|
||||
{
|
||||
con = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( con != null )
|
||||
{
|
||||
IGridNode os = (IGridNode) con.getOtherSide( this );
|
||||
if ( os == node )
|
||||
{
|
||||
// if this connection is no longer valid, destroy it.
|
||||
if ( !isValidConnection )
|
||||
con.destroy();
|
||||
}
|
||||
else
|
||||
{
|
||||
con.destroy();
|
||||
// throw new GridException( "invalid state found, encountered connection to phantom block." );
|
||||
}
|
||||
}
|
||||
else if ( isValidConnection )
|
||||
{
|
||||
if ( node.lastSecurityKey != -1 )
|
||||
newSecurityConnections.add( f );
|
||||
else
|
||||
{
|
||||
// construct a new connection between these two nodes.
|
||||
try
|
||||
{
|
||||
new GridConnection( node, this, f.getOpposite() );
|
||||
}
|
||||
catch (FailedConnection e)
|
||||
{
|
||||
TickHandler.instance.addCallable( node.getWorld(), new Callable() {
|
||||
|
||||
@Override
|
||||
public Object call() throws Exception
|
||||
{
|
||||
getMachine().securityBreak();
|
||||
return null;
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
for (ForgeDirection f : newSecurityConnections)
|
||||
{
|
||||
IGridHost te = findGridHost( dc.getWorld(), dc.x + f.offsetX, dc.y + f.offsetY, dc.z + f.offsetZ );
|
||||
if ( te != null )
|
||||
{
|
||||
GridNode node = (GridNode) te.getGridNode( f.getOpposite() );
|
||||
if ( node == null )
|
||||
continue;
|
||||
|
||||
// construct a new connection between these two nodes.
|
||||
try
|
||||
{
|
||||
new GridConnection( node, this, f.getOpposite() );
|
||||
}
|
||||
catch (FailedConnection e)
|
||||
{
|
||||
TickHandler.instance.addCallable( node.getWorld(), new Callable() {
|
||||
|
||||
@Override
|
||||
public Object call() throws Exception
|
||||
{
|
||||
getMachine().securityBreak();
|
||||
return null;
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IGridHost findGridHost(World world, int x, int y, int z)
|
||||
{
|
||||
if ( world.blockExists( x, y, z ) )
|
||||
{
|
||||
TileEntity te = world.getTileEntity( x, y, z );
|
||||
if ( te instanceof IGridHost )
|
||||
return (IGridHost) te;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void addConnection(IGridConnection gridConnection)
|
||||
{
|
||||
Connections.add( gridConnection );
|
||||
if ( gridConnection.hasDirection() )
|
||||
gridProxy.onGridNotification( GridNotification.ConnectionsChanged );
|
||||
|
||||
final IGridNode gn = this;
|
||||
|
||||
Collections.sort( Connections, new Comparator<IGridConnection>() {
|
||||
|
||||
@Override
|
||||
public int compare(IGridConnection o1, IGridConnection o2)
|
||||
{
|
||||
boolean preferredA = o1.getOtherSide( gn ).hasFlag( GridFlags.PREFERRED );
|
||||
boolean preferredB = o2.getOtherSide( gn ).hasFlag( GridFlags.PREFERRED );
|
||||
|
||||
return preferredA == preferredB ? 0 : (preferredA ? -1 : 1);
|
||||
}
|
||||
|
||||
} );
|
||||
}
|
||||
|
||||
public void removeConnection(IGridConnection gridConnection)
|
||||
{
|
||||
Connections.remove( gridConnection );
|
||||
if ( gridConnection.hasDirection() )
|
||||
gridProxy.onGridNotification( GridNotification.ConnectionsChanged );
|
||||
}
|
||||
|
||||
@Override
|
||||
public IReadOnlyCollection<IGridConnection> getConnections()
|
||||
{
|
||||
return new ReadOnlyCollection<IGridConnection>( Connections );
|
||||
}
|
||||
|
||||
public boolean hasConnection(IGridNode otherside)
|
||||
{
|
||||
for (IGridConnection gc : Connections)
|
||||
{
|
||||
if ( gc.a() == otherside || gc.b() == otherside )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean canConnect(GridNode from, ForgeDirection dir)
|
||||
{
|
||||
if ( !isValidDirection( dir ) )
|
||||
return false;
|
||||
|
||||
if ( !from.getColor().matches( getColor() ) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGrid getGrid()
|
||||
{
|
||||
return myGrid;
|
||||
}
|
||||
|
||||
public Grid getInternalGrid()
|
||||
{
|
||||
if ( myGrid == null )
|
||||
myGrid = new Grid( this );
|
||||
|
||||
return myGrid;
|
||||
}
|
||||
|
||||
public void setGrid(Grid grid)
|
||||
{
|
||||
if ( myGrid == grid )
|
||||
return;
|
||||
|
||||
if ( myGrid != null )
|
||||
{
|
||||
myGrid.remove( this );
|
||||
|
||||
if ( myGrid.isEmpty() )
|
||||
{
|
||||
myGrid.saveState();
|
||||
|
||||
for (IGridCache c : grid.caches.values())
|
||||
c.onJoin( myGrid.myStorage );
|
||||
}
|
||||
}
|
||||
|
||||
myGrid = grid;
|
||||
myGrid.add( this );
|
||||
}
|
||||
|
||||
public void validateGrid()
|
||||
{
|
||||
GridSplitDetector gsd = new GridSplitDetector( getInternalGrid().getPivot() );
|
||||
beginVisit( gsd );
|
||||
if ( !gsd.pivotFound )
|
||||
{
|
||||
GridPropagator gp = new GridPropagator( new Grid( this ) );
|
||||
beginVisit( gp );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy()
|
||||
{
|
||||
while (!Connections.isEmpty())
|
||||
{
|
||||
// not part of this network for real anymore.
|
||||
if ( Connections.size() == 1 )
|
||||
setGridStorage( null );
|
||||
|
||||
IGridConnection c = Connections.listIterator().next();
|
||||
GridNode otherSide = (GridNode) c.getOtherSide( this );
|
||||
otherSide.getInternalGrid().pivot = otherSide;
|
||||
c.destroy();
|
||||
}
|
||||
|
||||
if ( myGrid != null )
|
||||
myGrid.remove( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public World getWorld()
|
||||
{
|
||||
return gridProxy.getLocation().getWorld();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean meetsChannelRequirements()
|
||||
{
|
||||
return (!getGridBlock().getFlags().contains( GridFlags.REQUIRE_CHANNEL ) || getUsedChannels() > 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive()
|
||||
{
|
||||
IGrid g = getGrid();
|
||||
if ( g != null )
|
||||
{
|
||||
IPathingGrid pg = g.getCache( IPathingGrid.class );
|
||||
IEnergyGrid eg = g.getCache( IEnergyGrid.class );
|
||||
return meetsChannelRequirements() && eg.isNetworkPowered() && !pg.isNetworkBooting();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSupportMoreChannels()
|
||||
{
|
||||
return getUsedChannels() < getMaxChannels();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IReadOnlyCollection<IPathItem> getPossibleOptions()
|
||||
{
|
||||
return (ReadOnlyCollection) getConnections();
|
||||
}
|
||||
|
||||
public int getLastUsedChannels()
|
||||
{
|
||||
return (channelData >> 8) & 0xff;
|
||||
}
|
||||
|
||||
public int getUsedChannels()
|
||||
{
|
||||
return channelData & 0xff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incrementChannelCount(int usedChannels)
|
||||
{
|
||||
channelData += usedChannels;
|
||||
}
|
||||
|
||||
public void setGridStorage(GridStorage s)
|
||||
{
|
||||
myStorage = s;
|
||||
channelData = 0;
|
||||
}
|
||||
|
||||
public GridStorage getGridStorage()
|
||||
{
|
||||
return myStorage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<GridFlags> getFlags()
|
||||
{
|
||||
return getGridBlock().getFlags();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finalizeChannels()
|
||||
{
|
||||
if ( getFlags().contains( GridFlags.CANNOT_CARRY ) )
|
||||
return;
|
||||
|
||||
if ( getLastUsedChannels() != getUsedChannels() )
|
||||
{
|
||||
channelData = (channelData & 0xff);
|
||||
channelData |= channelData << 8;
|
||||
|
||||
if ( getInternalGrid() != null )
|
||||
getInternalGrid().postEventTo( this, event );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPathItem getControllerRoute()
|
||||
{
|
||||
if ( Connections.isEmpty() || getFlags().contains( GridFlags.CANNOT_CARRY ) )
|
||||
return null;
|
||||
|
||||
return (IPathItem) Connections.get( 0 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setControllerRoute(IPathItem fast, boolean zeroOut)
|
||||
{
|
||||
if ( zeroOut )
|
||||
channelData &= ~0xff;
|
||||
|
||||
int idx = Connections.indexOf( fast );
|
||||
if ( idx > 0 )
|
||||
{
|
||||
Connections.remove( fast );
|
||||
Connections.add( 0, (IGridConnection) fast );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasFlag(GridFlags flag)
|
||||
{
|
||||
return getGridBlock().getFlags().contains( flag );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPlayerID()
|
||||
{
|
||||
return playerID;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package appeng.me;
|
||||
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.IGridVisitor;
|
||||
|
||||
public class GridPropagator implements IGridVisitor
|
||||
{
|
||||
|
||||
final private Grid g;
|
||||
|
||||
public GridPropagator(Grid g) {
|
||||
this.g = g;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visitNode(IGridNode n)
|
||||
{
|
||||
GridNode gn = (GridNode) n;
|
||||
if ( gn.myGrid != g || g.pivot == n )
|
||||
{
|
||||
gn.setGrid( g );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package appeng.me;
|
||||
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.IGridVisitor;
|
||||
|
||||
class GridSplitDetector implements IGridVisitor
|
||||
{
|
||||
|
||||
final IGridNode pivot;
|
||||
boolean pivotFound;
|
||||
|
||||
public GridSplitDetector(IGridNode pivot) {
|
||||
this.pivot = pivot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visitNode(IGridNode n)
|
||||
{
|
||||
if ( n == pivot )
|
||||
pivotFound = true;
|
||||
|
||||
return !pivotFound;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,140 @@
|
||||
package appeng.me;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import net.minecraft.nbt.CompressedStreamTools;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import appeng.api.networking.IGrid;
|
||||
import appeng.api.networking.IGridStorage;
|
||||
import appeng.core.AELog;
|
||||
import appeng.core.WorldSettings;
|
||||
|
||||
public class GridStorage implements IGridStorage
|
||||
{
|
||||
|
||||
IGrid myGrid = null;
|
||||
|
||||
final long myID;
|
||||
final NBTTagCompound data;
|
||||
|
||||
public boolean isDirty = false;
|
||||
private Set<GridStorage> divlist = new HashSet();
|
||||
final GridStorageSearch mySearchEntry; // keep myself in the list until I'm
|
||||
// lost...
|
||||
|
||||
/**
|
||||
* for use with world settings
|
||||
*
|
||||
* @param id
|
||||
* @param gss
|
||||
*/
|
||||
public GridStorage(long id, GridStorageSearch gss) {
|
||||
myID = id;
|
||||
mySearchEntry = gss;
|
||||
data = new NBTTagCompound();
|
||||
}
|
||||
|
||||
/**
|
||||
* for use with world settings
|
||||
*
|
||||
* @param input
|
||||
* @param id
|
||||
* @param gss
|
||||
*/
|
||||
public GridStorage(String input, long id, GridStorageSearch gss) {
|
||||
myID = id;
|
||||
mySearchEntry = gss;
|
||||
NBTTagCompound myTag = null;
|
||||
|
||||
try
|
||||
{
|
||||
byte[] dbata = javax.xml.bind.DatatypeConverter.parseBase64Binary( input );
|
||||
myTag = CompressedStreamTools.readCompressed( new ByteArrayInputStream( dbata ) );
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
myTag = new NBTTagCompound();
|
||||
}
|
||||
|
||||
data = myTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* fake storage.
|
||||
*/
|
||||
public GridStorage() {
|
||||
myID = 0;
|
||||
mySearchEntry = null;
|
||||
data = new NBTTagCompound();
|
||||
}
|
||||
|
||||
public String getValue()
|
||||
{
|
||||
isDirty = false;
|
||||
|
||||
if ( myGrid != null )
|
||||
{
|
||||
((Grid) myGrid).saveState();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
CompressedStreamTools.writeCompressed( data, out );
|
||||
return javax.xml.bind.DatatypeConverter.printBase64Binary( out.toByteArray() );
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
AELog.error( e );
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTTagCompound dataObject()
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getID()
|
||||
{
|
||||
return myID;
|
||||
}
|
||||
|
||||
public void markDirty()
|
||||
{
|
||||
isDirty = true;
|
||||
}
|
||||
|
||||
public IGrid getGrid()
|
||||
{
|
||||
return myGrid;
|
||||
}
|
||||
|
||||
public void setGrid(Grid grid)
|
||||
{
|
||||
myGrid = grid;
|
||||
}
|
||||
|
||||
public void addDivided(GridStorage gs)
|
||||
{
|
||||
divlist.add( gs );
|
||||
}
|
||||
|
||||
public boolean hasDivided(GridStorage myStorage)
|
||||
{
|
||||
return divlist.contains( myStorage );
|
||||
}
|
||||
|
||||
public void remove()
|
||||
{
|
||||
WorldSettings.getInstance().destroyGridStorage( getID() );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package appeng.me;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
public class GridStorageSearch
|
||||
{
|
||||
|
||||
final long id;
|
||||
public WeakReference<GridStorage> gridStorage;
|
||||
|
||||
/**
|
||||
* for use with the world settings
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
public GridStorageSearch(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if ( obj == null )
|
||||
return false;
|
||||
|
||||
GridStorageSearch b = (GridStorageSearch) obj;
|
||||
|
||||
if ( id == b.id )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return ((Long) id).hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package appeng.me;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
import appeng.api.networking.IGridHost;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.IMachineSet;
|
||||
|
||||
public class MachineSet extends HashSet<IGridNode> implements IMachineSet
|
||||
{
|
||||
|
||||
private static final long serialVersionUID = 3224660708327386933L;
|
||||
|
||||
private final Class<? extends IGridHost> machine;
|
||||
|
||||
MachineSet(Class<? extends IGridHost> m) {
|
||||
machine = m;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends IGridHost> getMachineClass()
|
||||
{
|
||||
return machine;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
package appeng.me;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Set;
|
||||
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.events.MENetworkEvent;
|
||||
import appeng.api.networking.events.MENetworkEventSubscribe;
|
||||
import appeng.core.AELog;
|
||||
|
||||
public class NetworkEventBus
|
||||
{
|
||||
|
||||
class NetworkEventDone extends Throwable
|
||||
{
|
||||
|
||||
private static final long serialVersionUID = -3079021487019171205L;
|
||||
|
||||
};
|
||||
|
||||
class EventMethod
|
||||
{
|
||||
|
||||
public final Class objClass;
|
||||
public final Method objMethod;
|
||||
public final Class objEvent;
|
||||
|
||||
public EventMethod(Class Event, Class ObjClass, Method ObjMethod) {
|
||||
this.objClass = ObjClass;
|
||||
this.objMethod = ObjMethod;
|
||||
this.objEvent = Event;
|
||||
}
|
||||
|
||||
public void invoke(Object obj, MENetworkEvent e) throws NetworkEventDone
|
||||
{
|
||||
try
|
||||
{
|
||||
objMethod.invoke( obj, e );
|
||||
}
|
||||
catch (Throwable e1)
|
||||
{
|
||||
AELog.severe( "[AppEng] Network Event caused exception:" );
|
||||
AELog.severe( "Offending Class: " + obj.getClass().getName() );
|
||||
AELog.severe( "Offending Object: " + obj.toString() );
|
||||
AELog.error( e1 );
|
||||
throw new RuntimeException( e1 );
|
||||
}
|
||||
|
||||
if ( e.isCanceled() )
|
||||
throw new NetworkEventDone();
|
||||
}
|
||||
};
|
||||
|
||||
class MENetworkEventInfo
|
||||
{
|
||||
|
||||
private ArrayList<EventMethod> methods = new ArrayList();
|
||||
|
||||
public void Add(Class Event, Class ObjClass, Method ObjMethod)
|
||||
{
|
||||
methods.add( new EventMethod( Event, ObjClass, ObjMethod ) );
|
||||
}
|
||||
|
||||
public void invoke(Object obj, MENetworkEvent e) throws NetworkEventDone
|
||||
{
|
||||
for (EventMethod em : methods)
|
||||
em.invoke( obj, e );
|
||||
}
|
||||
};
|
||||
|
||||
private static Set<Class> readClasses = new HashSet();
|
||||
private static Hashtable<Class<? extends MENetworkEvent>, Hashtable<Class, MENetworkEventInfo>> events = new Hashtable();
|
||||
|
||||
public void readClass(Class listAs, Class c)
|
||||
{
|
||||
if ( readClasses.contains( c ) )
|
||||
return;
|
||||
readClasses.add( c );
|
||||
|
||||
try
|
||||
{
|
||||
for (Method m : c.getMethods())
|
||||
{
|
||||
MENetworkEventSubscribe s = m.getAnnotation( MENetworkEventSubscribe.class );
|
||||
if ( s != null )
|
||||
{
|
||||
Class types[] = m.getParameterTypes();
|
||||
if ( types.length == 1 )
|
||||
{
|
||||
if ( MENetworkEvent.class.isAssignableFrom( types[0] ) )
|
||||
{
|
||||
|
||||
Hashtable<Class, MENetworkEventInfo> classEvents = events.get( types[0] );
|
||||
if ( classEvents == null )
|
||||
events.put( types[0], classEvents = new Hashtable() );
|
||||
|
||||
MENetworkEventInfo thisEvent = classEvents.get( listAs );
|
||||
if ( thisEvent == null )
|
||||
thisEvent = new MENetworkEventInfo();
|
||||
|
||||
thisEvent.Add( types[0], c, m );
|
||||
|
||||
classEvents.put( listAs, thisEvent );
|
||||
}
|
||||
else
|
||||
throw new RuntimeException( "Invalid ME Network Event Subscriber, " + m.getName() + "s Parameter must extend MENetworkEvent." );
|
||||
}
|
||||
else
|
||||
throw new RuntimeException( "Invalid ME Network Event Subscriber, " + m.getName() + " must have exactly 1 parameter." );
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Throwable t )
|
||||
{
|
||||
throw new RuntimeException( "Error while adding "+c.getName()+" to event bus", t );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public MENetworkEvent postEvent(Grid g, MENetworkEvent e)
|
||||
{
|
||||
Hashtable<Class, MENetworkEventInfo> subscribers = events.get( e.getClass() );
|
||||
int x = 0;
|
||||
|
||||
try
|
||||
{
|
||||
if ( subscribers != null )
|
||||
{
|
||||
for (Class o : subscribers.keySet())
|
||||
{
|
||||
MENetworkEventInfo target = subscribers.get( o );
|
||||
GridCacheWrapper cache = g.caches.get( o );
|
||||
if ( cache != null )
|
||||
{
|
||||
x++;
|
||||
target.invoke( cache.myCache, e );
|
||||
}
|
||||
|
||||
for (IGridNode obj : g.getMachines( o ))
|
||||
{
|
||||
x++;
|
||||
target.invoke( obj.getMachine(), e );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (NetworkEventDone done)
|
||||
{
|
||||
// Early out.
|
||||
}
|
||||
|
||||
e.setVisitedObjects( x );
|
||||
return e;
|
||||
}
|
||||
|
||||
public MENetworkEvent postEventTo(Grid grid, GridNode node, MENetworkEvent e)
|
||||
{
|
||||
Hashtable<Class, MENetworkEventInfo> subscribers = events.get( e.getClass() );
|
||||
int x = 0;
|
||||
|
||||
try
|
||||
{
|
||||
if ( subscribers != null )
|
||||
{
|
||||
MENetworkEventInfo target = subscribers.get( node.getMachineClass() );
|
||||
if ( target != null )
|
||||
{
|
||||
x++;
|
||||
target.invoke( node.getMachine(), e );
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (NetworkEventDone done)
|
||||
{
|
||||
// Early out.
|
||||
}
|
||||
|
||||
e.setVisitedObjects( x );
|
||||
return e;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package appeng.me;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class NetworkList implements Collection<Grid>
|
||||
{
|
||||
|
||||
private List<Grid> networks = new LinkedList();
|
||||
|
||||
@Override
|
||||
public boolean add(Grid e)
|
||||
{
|
||||
copy();
|
||||
return networks.add( e );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends Grid> c)
|
||||
{
|
||||
copy();
|
||||
return networks.addAll( c );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear()
|
||||
{
|
||||
networks = new LinkedList<Grid>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o)
|
||||
{
|
||||
return networks.contains( o );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> c)
|
||||
{
|
||||
return networks.containsAll( c );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty()
|
||||
{
|
||||
return networks.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Grid> iterator()
|
||||
{
|
||||
return networks.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o)
|
||||
{
|
||||
copy();
|
||||
return networks.remove( o );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c)
|
||||
{
|
||||
copy();
|
||||
return networks.removeAll( c );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> c)
|
||||
{
|
||||
copy();
|
||||
return networks.retainAll( c );
|
||||
}
|
||||
|
||||
private void copy()
|
||||
{
|
||||
List<Grid> old = networks;
|
||||
networks = new LinkedList<Grid>();
|
||||
networks.addAll( old );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size()
|
||||
{
|
||||
return networks.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray()
|
||||
{
|
||||
return networks.toArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T[] toArray(T[] a)
|
||||
{
|
||||
return networks.toArray( a );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package appeng.me;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.util.IReadOnlyCollection;
|
||||
|
||||
public class NodeIterable<T> implements IReadOnlyCollection<T>
|
||||
{
|
||||
|
||||
final private HashMap<Class, Set<IGridNode>> Machines;
|
||||
|
||||
public NodeIterable(HashMap<Class, Set<IGridNode>> Machines) {
|
||||
this.Machines = Machines;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterator()
|
||||
{
|
||||
return new NodeIterator( Machines );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size()
|
||||
{
|
||||
int size = 0;
|
||||
|
||||
for (Set<IGridNode> o : Machines.values())
|
||||
size += o.size();
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty()
|
||||
{
|
||||
for (Set<IGridNode> o : Machines.values())
|
||||
if ( !o.isEmpty() )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object node)
|
||||
{
|
||||
Class c = ((IGridNode) node).getMachine().getClass();
|
||||
|
||||
Set<IGridNode> p = Machines.get( c );
|
||||
if ( p != null )
|
||||
return p.contains( node );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package appeng.me;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
public class NodeIterator<IGridNode> implements Iterator<IGridNode>
|
||||
{
|
||||
|
||||
boolean hasMore;
|
||||
Iterator lvl1;
|
||||
Iterator lvl2;
|
||||
|
||||
boolean pull()
|
||||
{
|
||||
hasMore = lvl1.hasNext();
|
||||
if ( hasMore )
|
||||
{
|
||||
lvl2 = ((Collection) lvl1.next()).iterator();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public NodeIterator(HashMap<Class, Set<IGridNode>> machines) {
|
||||
lvl1 = machines.values().iterator();
|
||||
pull();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext()
|
||||
{
|
||||
if ( lvl2.hasNext() )
|
||||
return true;
|
||||
if ( pull() )
|
||||
return hasNext();
|
||||
return hasMore;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGridNode next()
|
||||
{
|
||||
return (IGridNode) lvl2.next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove()
|
||||
{
|
||||
lvl2.remove();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,578 @@
|
||||
package appeng.me.cache;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
|
||||
import net.minecraft.world.World;
|
||||
import appeng.api.config.AccessRestriction;
|
||||
import appeng.api.config.Actionable;
|
||||
import appeng.api.networking.IGrid;
|
||||
import appeng.api.networking.IGridHost;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.IGridStorage;
|
||||
import appeng.api.networking.crafting.ICraftingCPU;
|
||||
import appeng.api.networking.crafting.ICraftingCallback;
|
||||
import appeng.api.networking.crafting.ICraftingGrid;
|
||||
import appeng.api.networking.crafting.ICraftingJob;
|
||||
import appeng.api.networking.crafting.ICraftingLink;
|
||||
import appeng.api.networking.crafting.ICraftingMedium;
|
||||
import appeng.api.networking.crafting.ICraftingPatternDetails;
|
||||
import appeng.api.networking.crafting.ICraftingProvider;
|
||||
import appeng.api.networking.crafting.ICraftingProviderHelper;
|
||||
import appeng.api.networking.crafting.ICraftingRequester;
|
||||
import appeng.api.networking.crafting.ICraftingWatcher;
|
||||
import appeng.api.networking.crafting.ICraftingWatcherHost;
|
||||
import appeng.api.networking.energy.IEnergyGrid;
|
||||
import appeng.api.networking.events.MENetworkCraftingCpuChange;
|
||||
import appeng.api.networking.events.MENetworkCraftingPatternChange;
|
||||
import appeng.api.networking.events.MENetworkEventSubscribe;
|
||||
import appeng.api.networking.events.MENetworkPostCacheConstruction;
|
||||
import appeng.api.networking.security.BaseActionSource;
|
||||
import appeng.api.networking.storage.IStorageGrid;
|
||||
import appeng.api.storage.ICellProvider;
|
||||
import appeng.api.storage.IMEInventoryHandler;
|
||||
import appeng.api.storage.StorageChannel;
|
||||
import appeng.api.storage.data.IAEItemStack;
|
||||
import appeng.api.storage.data.IAEStack;
|
||||
import appeng.api.storage.data.IItemList;
|
||||
import appeng.crafting.CraftingJob;
|
||||
import appeng.crafting.CraftingLink;
|
||||
import appeng.crafting.CraftingLinkNexus;
|
||||
import appeng.crafting.CraftingWatcher;
|
||||
import appeng.me.cluster.implementations.CraftingCPUCluster;
|
||||
import appeng.me.helpers.GenericInterestManager;
|
||||
import appeng.me.storage.ItemWatcher;
|
||||
import appeng.tile.crafting.TileCraftingStorageTile;
|
||||
import appeng.tile.crafting.TileCraftingTile;
|
||||
import appeng.util.ItemSorters;
|
||||
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.ImmutableCollection;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.SetMultimap;
|
||||
|
||||
public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper, ICellProvider, IMEInventoryHandler
|
||||
{
|
||||
|
||||
HashSet<CraftingCPUCluster> cpuClusters = new HashSet();
|
||||
HashSet<ICraftingProvider> providers = new HashSet();
|
||||
|
||||
private HashMap<IGridNode, ICraftingWatcher> watchers = new HashMap<IGridNode, ICraftingWatcher>();
|
||||
|
||||
IGrid grid;
|
||||
IStorageGrid sg;
|
||||
IEnergyGrid eg;
|
||||
|
||||
HashMap<ICraftingPatternDetails, List<ICraftingMedium>> craftingMethods = new HashMap();
|
||||
HashMap<IAEItemStack, ImmutableList<ICraftingPatternDetails>> craftableItems = new HashMap();
|
||||
HashSet<IAEItemStack> emitableItems = new HashSet();
|
||||
HashMap<String, CraftingLinkNexus> links = new HashMap();
|
||||
|
||||
boolean updateList = false;
|
||||
final private SetMultimap<IAEStack, ItemWatcher> interests = HashMultimap.create();
|
||||
final public GenericInterestManager interestManager = new GenericInterestManager( interests );
|
||||
|
||||
class ActiveCpuIterator implements Iterator<ICraftingCPU>
|
||||
{
|
||||
|
||||
final Iterator<CraftingCPUCluster> i;
|
||||
CraftingCPUCluster c = null;
|
||||
|
||||
public ActiveCpuIterator(Collection<CraftingCPUCluster> o)
|
||||
{
|
||||
i = o.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext()
|
||||
{
|
||||
findNext();
|
||||
return c != null;
|
||||
}
|
||||
|
||||
private void findNext()
|
||||
{
|
||||
while (i.hasNext() && c == null)
|
||||
{
|
||||
c = i.next();
|
||||
if ( !c.isActive() || c.isDestroyed )
|
||||
c = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICraftingCPU next()
|
||||
{
|
||||
ICraftingCPU o = c;
|
||||
c = null;
|
||||
return o;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove()
|
||||
{
|
||||
// no..
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@Override
|
||||
public ImmutableSet<ICraftingCPU> getCpus()
|
||||
{
|
||||
return ImmutableSet.copyOf( new ActiveCpuIterator( cpuClusters ) );
|
||||
}
|
||||
|
||||
public CraftingGridCache(IGrid g)
|
||||
{
|
||||
grid = g;
|
||||
}
|
||||
|
||||
@MENetworkEventSubscribe
|
||||
public void afterCacheConstruction(MENetworkPostCacheConstruction cc)
|
||||
{
|
||||
sg = grid.getCache( IStorageGrid.class );
|
||||
eg = grid.getCache( IEnergyGrid.class );
|
||||
|
||||
sg.registerCellProvider( this );
|
||||
}
|
||||
|
||||
public void addLink(CraftingLink l)
|
||||
{
|
||||
if ( l.isStandalone() )
|
||||
return;
|
||||
|
||||
CraftingLinkNexus n = links.get( l.getCraftingID() );
|
||||
if ( n == null )
|
||||
links.put( l.getCraftingID(), n = new CraftingLinkNexus( l.getCraftingID() ) );
|
||||
|
||||
l.setNexus( n );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdateTick()
|
||||
{
|
||||
if ( updateList )
|
||||
{
|
||||
updateList = false;
|
||||
updateCPUClusters();
|
||||
}
|
||||
|
||||
Iterator<CraftingLinkNexus> i = links.values().iterator();
|
||||
while (i.hasNext())
|
||||
{
|
||||
if ( i.next().isDead( grid, this ) )
|
||||
i.remove();
|
||||
}
|
||||
|
||||
for (CraftingCPUCluster cpu : cpuClusters)
|
||||
cpu.updateCraftingLogic( grid, eg, this );
|
||||
}
|
||||
|
||||
@MENetworkEventSubscribe
|
||||
public void updateCPUClusters(MENetworkCraftingCpuChange c)
|
||||
{
|
||||
updateList = true;
|
||||
}
|
||||
|
||||
@MENetworkEventSubscribe
|
||||
public void updateCPUClusters(MENetworkCraftingPatternChange c)
|
||||
{
|
||||
updatePatterns();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNode(IGridNode gridNode, IGridHost machine)
|
||||
{
|
||||
if ( machine instanceof ICraftingWatcherHost )
|
||||
{
|
||||
ICraftingWatcher myWatcher = watchers.get( machine );
|
||||
if ( myWatcher != null )
|
||||
{
|
||||
myWatcher.clear();
|
||||
watchers.remove( machine );
|
||||
}
|
||||
}
|
||||
|
||||
if ( machine instanceof ICraftingRequester )
|
||||
{
|
||||
Iterator<CraftingLinkNexus> nex = links.values().iterator();
|
||||
while (nex.hasNext())
|
||||
{
|
||||
CraftingLinkNexus n = nex.next();
|
||||
if ( n.isMachine( machine ) )
|
||||
n.removeNode();
|
||||
}
|
||||
}
|
||||
|
||||
if ( machine instanceof TileCraftingTile )
|
||||
updateList = true;
|
||||
if ( machine instanceof ICraftingProvider )
|
||||
{
|
||||
providers.remove( machine );
|
||||
updatePatterns();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNode(IGridNode gridNode, IGridHost machine)
|
||||
{
|
||||
if ( machine instanceof ICraftingWatcherHost )
|
||||
{
|
||||
ICraftingWatcherHost swh = (ICraftingWatcherHost) machine;
|
||||
CraftingWatcher iw = new CraftingWatcher( this, (ICraftingWatcherHost) swh );
|
||||
watchers.put( gridNode, iw );
|
||||
swh.updateWatcher( iw );
|
||||
}
|
||||
|
||||
if ( machine instanceof ICraftingRequester )
|
||||
{
|
||||
for (ICraftingLink l : ((ICraftingRequester) machine).getRequestedJobs())
|
||||
{
|
||||
if ( l instanceof CraftingLink )
|
||||
addLink( (CraftingLink) l );
|
||||
}
|
||||
}
|
||||
|
||||
if ( machine instanceof TileCraftingTile )
|
||||
updateList = true;
|
||||
if ( machine instanceof ICraftingProvider )
|
||||
{
|
||||
providers.add( (ICraftingProvider) machine );
|
||||
updatePatterns();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateCPUClusters()
|
||||
{
|
||||
cpuClusters.clear();
|
||||
for (IGridNode cst : grid.getMachines( TileCraftingStorageTile.class ))
|
||||
{
|
||||
TileCraftingStorageTile tile = (TileCraftingStorageTile) cst.getMachine();
|
||||
CraftingCPUCluster clust = (CraftingCPUCluster) tile.getCluster();
|
||||
if ( clust != null )
|
||||
{
|
||||
cpuClusters.add( clust );
|
||||
|
||||
if ( clust.myLastLink != null )
|
||||
addLink( (CraftingLink) clust.myLastLink );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCraftingOption(ICraftingMedium medium, ICraftingPatternDetails api)
|
||||
{
|
||||
List<ICraftingMedium> details = craftingMethods.get( api );
|
||||
if ( details == null )
|
||||
{
|
||||
details = new ArrayList<ICraftingMedium>();
|
||||
details.add( medium );
|
||||
craftingMethods.put( api, details );
|
||||
}
|
||||
else
|
||||
details.add( medium );
|
||||
}
|
||||
|
||||
private void updatePatterns()
|
||||
{
|
||||
HashMap<IAEItemStack, ImmutableList<ICraftingPatternDetails>> oldItems = craftableItems;
|
||||
|
||||
// erase list.
|
||||
craftingMethods.clear();
|
||||
craftableItems = new HashMap();
|
||||
emitableItems.clear();
|
||||
|
||||
// update the stuff that was in the list...
|
||||
sg.postAlterationOfStoredItems( StorageChannel.ITEMS, oldItems.keySet(), new BaseActionSource() );
|
||||
|
||||
// re-create list..
|
||||
for (ICraftingProvider cp : providers)
|
||||
cp.provideCrafting( this );
|
||||
|
||||
HashMap<IAEItemStack, Set<ICraftingPatternDetails>> tmpCraft = new HashMap();
|
||||
|
||||
// new craftables!
|
||||
for (ICraftingPatternDetails details : craftingMethods.keySet())
|
||||
{
|
||||
for (IAEItemStack out : details.getOutputs())
|
||||
{
|
||||
out = out.copy();
|
||||
out.reset();
|
||||
out.setCraftable( true );
|
||||
|
||||
Set<ICraftingPatternDetails> methods = tmpCraft.get( out );
|
||||
|
||||
if ( methods == null )
|
||||
tmpCraft.put( out, methods = new HashSet() );
|
||||
|
||||
methods.add( details );
|
||||
}
|
||||
}
|
||||
|
||||
// make them immutable
|
||||
for (Entry<IAEItemStack, Set<ICraftingPatternDetails>> e : tmpCraft.entrySet())
|
||||
craftableItems.put( e.getKey(), ImmutableList.copyOf( e.getValue() ) );
|
||||
|
||||
sg.postAlterationOfStoredItems( StorageChannel.ITEMS, craftableItems.keySet(), new BaseActionSource() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSplit(IGridStorage destinationStorage)
|
||||
{ // nothing!
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onJoin(IGridStorage sourceStorage)
|
||||
{
|
||||
// nothing!
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateGridStorage(IGridStorage destinationStorage)
|
||||
{
|
||||
// nothing!
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IMEInventoryHandler> getCellArray(StorageChannel channel)
|
||||
{
|
||||
ArrayList<IMEInventoryHandler> list = new ArrayList<IMEInventoryHandler>( 1 );
|
||||
if ( channel == StorageChannel.ITEMS )
|
||||
list.add( this );
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPriority()
|
||||
{
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAEStack extractItems(IAEStack request, Actionable mode, BaseActionSource src)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItemList getAvailableItems(IItemList out)
|
||||
{
|
||||
// add craftable items!
|
||||
for (IAEItemStack st : craftableItems.keySet())
|
||||
out.addCrafting( st );
|
||||
|
||||
for (IAEItemStack st : emitableItems)
|
||||
out.addCrafting( st );
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StorageChannel getChannel()
|
||||
{
|
||||
return StorageChannel.ITEMS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessRestriction getAccess()
|
||||
{
|
||||
return AccessRestriction.WRITE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPrioritized(IAEStack input)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAEStack injectItems(IAEStack input, Actionable type, BaseActionSource src)
|
||||
{
|
||||
for (CraftingCPUCluster cpu : cpuClusters)
|
||||
input = cpu.injectItems( input, type, src );
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAccept(IAEStack input)
|
||||
{
|
||||
for (CraftingCPUCluster cpu : cpuClusters)
|
||||
if ( cpu.canAccept( (IAEItemStack) input ) )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICraftingLink submitJob(ICraftingJob job, ICraftingRequester requestingMachine, ICraftingCPU target, final boolean prioritizePower,
|
||||
BaseActionSource src)
|
||||
{
|
||||
if ( job.isSimulation() )
|
||||
return null;
|
||||
|
||||
CraftingCPUCluster cpuClust = null;
|
||||
|
||||
if ( target instanceof CraftingCPUCluster )
|
||||
cpuClust = (CraftingCPUCluster) target;
|
||||
|
||||
if ( target == null )
|
||||
{
|
||||
List<CraftingCPUCluster> validCpusClusters = new ArrayList<CraftingCPUCluster>();
|
||||
for (CraftingCPUCluster cpu : cpuClusters)
|
||||
{
|
||||
if ( cpu.isActive() && !cpu.isBusy() && cpu.getAvailableStorage() >= job.getByteTotal() )
|
||||
{
|
||||
validCpusClusters.add( cpu );
|
||||
}
|
||||
}
|
||||
|
||||
Collections.sort( validCpusClusters, new Comparator<CraftingCPUCluster>() {
|
||||
|
||||
@Override
|
||||
public int compare(CraftingCPUCluster o1, CraftingCPUCluster o2)
|
||||
{
|
||||
if ( prioritizePower )
|
||||
{
|
||||
int a = ItemSorters.compareLong( o2.getCoProcessors(), o1.getCoProcessors() );
|
||||
if ( a != 0 )
|
||||
return a;
|
||||
return ItemSorters.compareLong( o2.getAvailableStorage(), o1.getAvailableStorage() );
|
||||
}
|
||||
|
||||
int a = ItemSorters.compareLong( o1.getCoProcessors(), o2.getCoProcessors() );
|
||||
if ( a != 0 )
|
||||
return a;
|
||||
return ItemSorters.compareLong( o1.getAvailableStorage(), o2.getAvailableStorage() );
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
if ( !validCpusClusters.isEmpty() )
|
||||
cpuClust = validCpusClusters.get( 0 );
|
||||
}
|
||||
|
||||
if ( cpuClust != null )
|
||||
{
|
||||
return cpuClust.submitJob( grid, job, src, requestingMachine );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSlot()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableCollection<ICraftingPatternDetails> getCraftingFor(IAEItemStack whatToCraft, ICraftingPatternDetails details, int slotIndex, World world)
|
||||
{
|
||||
ImmutableList<ICraftingPatternDetails> res = craftableItems.get( whatToCraft );
|
||||
|
||||
if ( res == null )
|
||||
{
|
||||
if ( details != null && details.isCraftable() )
|
||||
{
|
||||
for (IAEItemStack ais : craftableItems.keySet())
|
||||
{
|
||||
if ( ais.getItem() == whatToCraft.getItem() && (!ais.getItem().getHasSubtypes() || ais.getItemDamage() == whatToCraft.getItemDamage()) )
|
||||
{
|
||||
if ( details.isValidItemForSlot( slotIndex, ais.getItemStack(), world ) )
|
||||
{
|
||||
return craftableItems.get( ais );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ImmutableSet.of();
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public List<ICraftingMedium> getMediums(ICraftingPatternDetails key)
|
||||
{
|
||||
List<ICraftingMedium> o = craftingMethods.get( key );
|
||||
|
||||
if ( o == null )
|
||||
o = ImmutableList.of();
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validForPass(int i)
|
||||
{
|
||||
return i == 1;
|
||||
}
|
||||
|
||||
final public static ExecutorService craftingPool;
|
||||
|
||||
static
|
||||
{
|
||||
ThreadFactory factory = new ThreadFactory() {
|
||||
|
||||
@Override
|
||||
public Thread newThread(Runnable ar)
|
||||
{
|
||||
return new Thread( ar, "AE Crafting Calculator" );
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
craftingPool = Executors.newCachedThreadPool( factory );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<ICraftingJob> beginCraftingJob(World world, IGrid grid, BaseActionSource actionSrc, IAEItemStack slotItem, ICraftingCallback cb)
|
||||
{
|
||||
if ( world == null || grid == null || actionSrc == null || slotItem == null )
|
||||
throw new RuntimeException( "Invalid Crafting Job Request" );
|
||||
|
||||
CraftingJob cj = new CraftingJob( world, grid, actionSrc, slotItem, cb );
|
||||
return craftingPool.submit( cj, (ICraftingJob) cj );
|
||||
}
|
||||
|
||||
public boolean hasCpu(ICraftingCPU cpu)
|
||||
{
|
||||
return cpuClusters.contains( cpu );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRequesting(IAEItemStack what)
|
||||
{
|
||||
for (CraftingCPUCluster c : cpuClusters)
|
||||
if ( c.isMaking( what ) )
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canEmitFor(IAEItemStack what)
|
||||
{
|
||||
return emitableItems.contains( what );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEmitable(IAEItemStack what)
|
||||
{
|
||||
emitableItems.add( what.copy() );
|
||||
}
|
||||
|
||||
}
|
||||
+583
@@ -0,0 +1,583 @@
|
||||
package appeng.me.cache;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import appeng.api.config.AccessRestriction;
|
||||
import appeng.api.config.Actionable;
|
||||
import appeng.api.config.PowerMultiplier;
|
||||
import appeng.api.networking.IGrid;
|
||||
import appeng.api.networking.IGridBlock;
|
||||
import appeng.api.networking.IGridHost;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.IGridStorage;
|
||||
import appeng.api.networking.energy.IAEPowerStorage;
|
||||
import appeng.api.networking.energy.IEnergyGrid;
|
||||
import appeng.api.networking.energy.IEnergyGridProvider;
|
||||
import appeng.api.networking.energy.IEnergyWatcher;
|
||||
import appeng.api.networking.energy.IEnergyWatcherHost;
|
||||
import appeng.api.networking.events.MENetworkEventSubscribe;
|
||||
import appeng.api.networking.events.MENetworkPostCacheConstruction;
|
||||
import appeng.api.networking.events.MENetworkPowerIdleChange;
|
||||
import appeng.api.networking.events.MENetworkPowerStatusChange;
|
||||
import appeng.api.networking.events.MENetworkPowerStorage;
|
||||
import appeng.api.networking.pathing.IPathingGrid;
|
||||
import appeng.api.networking.storage.IStackWatcherHost;
|
||||
import appeng.me.Grid;
|
||||
import appeng.me.GridNode;
|
||||
import appeng.me.energy.EnergyThreshold;
|
||||
import appeng.me.energy.EnergyWatcher;
|
||||
|
||||
import com.google.common.collect.HashMultiset;
|
||||
import com.google.common.collect.Multiset;
|
||||
|
||||
public class EnergyGridCache implements IEnergyGrid
|
||||
{
|
||||
|
||||
/**
|
||||
* estimated power available.
|
||||
*/
|
||||
int availableTicksSinceUpdate = 0;
|
||||
double globalAvailablePower = 0;
|
||||
double globalMaxPower = 0;
|
||||
|
||||
/**
|
||||
* idle draw.
|
||||
*/
|
||||
double drainPerTick = 0;
|
||||
|
||||
final double AvgLength = 40.0;
|
||||
|
||||
double avgDrainPerTick = 0;
|
||||
double avgInjectionPerTick = 0;
|
||||
|
||||
double tickDrainPerTick = 0;
|
||||
double tickInjectionPerTick = 0;
|
||||
|
||||
/**
|
||||
* power status
|
||||
*/
|
||||
boolean publicHasPower = false;
|
||||
boolean hasPower = true;
|
||||
long ticksSinceHasPowerChange = 900;
|
||||
|
||||
/**
|
||||
* excess power in the system.
|
||||
*/
|
||||
double extra = 0;
|
||||
|
||||
IAEPowerStorage lastProvider;
|
||||
final Set<IAEPowerStorage> providers = new LinkedHashSet();
|
||||
|
||||
IAEPowerStorage lastRequestor;
|
||||
final Set<IAEPowerStorage> requesters = new LinkedHashSet();
|
||||
|
||||
final public TreeSet<EnergyThreshold> interests = new TreeSet<EnergyThreshold>();
|
||||
final private HashMap<IGridNode, IEnergyWatcher> watchers = new HashMap<IGridNode, IEnergyWatcher>();
|
||||
|
||||
final private Set<IEnergyGrid> localSeen = new HashSet();
|
||||
|
||||
private double buffer()
|
||||
{
|
||||
return providers.isEmpty() ? 1000.0 : 0.0;
|
||||
}
|
||||
|
||||
private IAEPowerStorage getFirstRequestor()
|
||||
{
|
||||
if ( lastRequestor == null )
|
||||
{
|
||||
Iterator<IAEPowerStorage> i = requesters.iterator();
|
||||
lastRequestor = i.hasNext() ? i.next() : null;
|
||||
}
|
||||
|
||||
return lastRequestor;
|
||||
}
|
||||
|
||||
private IAEPowerStorage getFirstProvider()
|
||||
{
|
||||
if ( lastProvider == null )
|
||||
{
|
||||
Iterator<IAEPowerStorage> i = providers.iterator();
|
||||
lastProvider = i.hasNext() ? i.next() : null;
|
||||
}
|
||||
|
||||
return lastProvider;
|
||||
}
|
||||
|
||||
final Multiset<IEnergyGridProvider> gproviders = HashMultiset.create();
|
||||
|
||||
final IGrid myGrid;
|
||||
PathGridCache pgc;
|
||||
|
||||
public EnergyGridCache(IGrid g) {
|
||||
myGrid = g;
|
||||
}
|
||||
|
||||
@MENetworkEventSubscribe
|
||||
public void postInit(MENetworkPostCacheConstruction pcc)
|
||||
{
|
||||
pgc = myGrid.getCache( IPathingGrid.class );
|
||||
}
|
||||
|
||||
@MENetworkEventSubscribe
|
||||
public void EnergyNodeChanges(MENetworkPowerIdleChange ev)
|
||||
{
|
||||
// update power usage based on event.
|
||||
GridNode node = (GridNode) ev.node;
|
||||
IGridBlock gb = node.getGridBlock();
|
||||
|
||||
double newDraw = gb.getIdlePowerUsage();
|
||||
double diffDraw = newDraw - node.previousDraw;
|
||||
node.previousDraw = newDraw;
|
||||
|
||||
drainPerTick += diffDraw;
|
||||
}
|
||||
|
||||
@MENetworkEventSubscribe
|
||||
public void EnergyNodeChanges(MENetworkPowerStorage ev)
|
||||
{
|
||||
if ( ev.storage.isAEPublicPowerStorage() )
|
||||
{
|
||||
switch (ev.type)
|
||||
{
|
||||
case PROVIDE_POWER:
|
||||
if ( ev.storage.getPowerFlow() != AccessRestriction.WRITE )
|
||||
providers.add( ev.storage );
|
||||
break;
|
||||
case REQUEST_POWER:
|
||||
if ( ev.storage.getPowerFlow() != AccessRestriction.READ )
|
||||
requesters.add( ev.storage );
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
(new RuntimeException( "Attempt to ask the IEnergyGrid to charge a non public energy store." )).printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getEnergyDemand(double maxRequired)
|
||||
{
|
||||
localSeen.clear();
|
||||
return getEnergyDemand( maxRequired, localSeen );
|
||||
}
|
||||
|
||||
public double getEnergyDemand(double maxRequired, Set<IEnergyGrid> seen)
|
||||
{
|
||||
if ( !seen.add( this ) )
|
||||
return 0;
|
||||
|
||||
double required = buffer() - extra;
|
||||
|
||||
Iterator<IAEPowerStorage> it = requesters.iterator();
|
||||
while (required < maxRequired && it.hasNext())
|
||||
{
|
||||
IAEPowerStorage node = it.next();
|
||||
if ( node.getPowerFlow() != AccessRestriction.READ )
|
||||
required += Math.max( 0.0, node.getAEMaxPower() - node.getAECurrentPower() );
|
||||
}
|
||||
|
||||
Iterator<IEnergyGridProvider> ix = gproviders.iterator();
|
||||
while (required < maxRequired && ix.hasNext())
|
||||
{
|
||||
IEnergyGridProvider node = ix.next();
|
||||
required += node.getEnergyDemand( maxRequired - required, seen );
|
||||
}
|
||||
|
||||
return required;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double injectPower(double amt, Actionable mode)
|
||||
{
|
||||
localSeen.clear();
|
||||
return injectAEPower( amt, mode, localSeen );
|
||||
}
|
||||
|
||||
public double injectAEPower(double amt, Actionable mode, Set<IEnergyGrid> seen)
|
||||
{
|
||||
if ( !seen.add( this ) )
|
||||
return 0;
|
||||
|
||||
double ignore = extra;
|
||||
amt += extra;
|
||||
|
||||
if ( mode == Actionable.SIMULATE )
|
||||
{
|
||||
Iterator<IAEPowerStorage> it = requesters.iterator();
|
||||
while (amt > 0 && it.hasNext())
|
||||
{
|
||||
IAEPowerStorage node = it.next();
|
||||
amt = node.injectAEPower( amt, Actionable.SIMULATE );
|
||||
}
|
||||
|
||||
Iterator<IEnergyGridProvider> i = gproviders.iterator();
|
||||
while (amt > 0 && i.hasNext())
|
||||
amt = i.next().injectAEPower( amt, mode, seen );
|
||||
}
|
||||
else
|
||||
{
|
||||
tickInjectionPerTick += amt - ignore;
|
||||
// totalInjectionPastTicks[0] += i;
|
||||
|
||||
while (amt > 0 && !requesters.isEmpty())
|
||||
{
|
||||
IAEPowerStorage node = getFirstRequestor();
|
||||
|
||||
amt = node.injectAEPower( amt, Actionable.MODULATE );
|
||||
if ( amt > 0 )
|
||||
{
|
||||
requesters.remove( node );
|
||||
lastRequestor = null;
|
||||
}
|
||||
}
|
||||
|
||||
Iterator<IEnergyGridProvider> i = gproviders.iterator();
|
||||
while (amt > 0 && i.hasNext())
|
||||
{
|
||||
IEnergyGridProvider what = i.next();
|
||||
Set<IEnergyGrid> listCopy = new HashSet<IEnergyGrid>();
|
||||
listCopy.addAll( seen );
|
||||
|
||||
double cannotHold = what.injectAEPower( amt, Actionable.SIMULATE, listCopy );
|
||||
what.injectAEPower( amt - cannotHold, mode, seen );
|
||||
|
||||
amt = cannotHold;
|
||||
}
|
||||
|
||||
extra = amt;
|
||||
}
|
||||
|
||||
return Math.max( 0.0, amt - buffer() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public double extractAEPower(double amt, Actionable mode, PowerMultiplier pm)
|
||||
{
|
||||
localSeen.clear();
|
||||
return pm.divide( extractAEPower( pm.multiply( amt ), mode, localSeen ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNode(IGridNode node, IGridHost machine)
|
||||
{
|
||||
if ( machine instanceof IEnergyGridProvider )
|
||||
gproviders.add( (IEnergyGridProvider) machine );
|
||||
|
||||
// idle draw...
|
||||
GridNode gnode = (GridNode) node;
|
||||
IGridBlock gb = gnode.getGridBlock();
|
||||
gnode.previousDraw = gb.getIdlePowerUsage();
|
||||
drainPerTick += gnode.previousDraw;
|
||||
|
||||
// power storage
|
||||
if ( machine instanceof IAEPowerStorage )
|
||||
{
|
||||
IAEPowerStorage ps = (IAEPowerStorage) machine;
|
||||
if ( ps.isAEPublicPowerStorage() )
|
||||
{
|
||||
double max = ps.getAEMaxPower();
|
||||
double current = ps.getAECurrentPower();
|
||||
|
||||
if ( ps.getPowerFlow() != AccessRestriction.WRITE )
|
||||
{
|
||||
globalMaxPower += ps.getAEMaxPower();
|
||||
}
|
||||
|
||||
if ( current > 0 && ps.getPowerFlow() != AccessRestriction.WRITE )
|
||||
{
|
||||
globalAvailablePower += current;
|
||||
providers.add( ps );
|
||||
}
|
||||
|
||||
if ( current < max && ps.getPowerFlow() != AccessRestriction.READ )
|
||||
requesters.add( ps );
|
||||
}
|
||||
}
|
||||
|
||||
if ( machine instanceof IEnergyWatcherHost )
|
||||
{
|
||||
IEnergyWatcherHost swh = (IEnergyWatcherHost) machine;
|
||||
EnergyWatcher iw = new EnergyWatcher( this, (IEnergyWatcherHost) swh );
|
||||
watchers.put( node, iw );
|
||||
swh.updateWatcher( iw );
|
||||
}
|
||||
|
||||
myGrid.postEventTo( node, new MENetworkPowerStatusChange() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNode(IGridNode node, IGridHost machine)
|
||||
{
|
||||
if ( machine instanceof IEnergyGridProvider )
|
||||
gproviders.remove( machine );
|
||||
|
||||
// idle draw.
|
||||
GridNode gnode = (GridNode) node;
|
||||
drainPerTick -= gnode.previousDraw;
|
||||
|
||||
// power storage.
|
||||
if ( machine instanceof IAEPowerStorage )
|
||||
{
|
||||
IAEPowerStorage ps = (IAEPowerStorage) machine;
|
||||
if ( ps.isAEPublicPowerStorage() )
|
||||
{
|
||||
if ( ps.getPowerFlow() != AccessRestriction.WRITE )
|
||||
{
|
||||
globalMaxPower -= ps.getAEMaxPower();
|
||||
globalAvailablePower -= ps.getAECurrentPower();
|
||||
}
|
||||
|
||||
if ( lastProvider == machine )
|
||||
lastProvider = null;
|
||||
|
||||
if ( lastRequestor == machine )
|
||||
lastRequestor = null;
|
||||
|
||||
providers.remove( machine );
|
||||
requesters.remove( machine );
|
||||
}
|
||||
}
|
||||
|
||||
if ( machine instanceof IStackWatcherHost )
|
||||
{
|
||||
IEnergyWatcher myWatcher = watchers.get( machine );
|
||||
if ( myWatcher != null )
|
||||
{
|
||||
myWatcher.clear();
|
||||
watchers.remove( machine );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
double lastStoredPower = -1;
|
||||
|
||||
@Override
|
||||
public void onUpdateTick()
|
||||
{
|
||||
if ( !interests.isEmpty() )
|
||||
{
|
||||
double oldPower = lastStoredPower;
|
||||
lastStoredPower = getStoredPower();
|
||||
|
||||
EnergyThreshold low = new EnergyThreshold( Math.min( oldPower, lastStoredPower ), null );
|
||||
EnergyThreshold high = new EnergyThreshold( Math.max( oldPower, lastStoredPower ), null );
|
||||
for (EnergyThreshold th : interests.subSet( low, true, high, true ))
|
||||
{
|
||||
((EnergyWatcher) th.watcher).post( this );
|
||||
}
|
||||
}
|
||||
|
||||
avgDrainPerTick *= (AvgLength - 1) / AvgLength;
|
||||
avgInjectionPerTick *= (AvgLength - 1) / AvgLength;
|
||||
|
||||
avgDrainPerTick += tickDrainPerTick / AvgLength;
|
||||
avgInjectionPerTick += tickInjectionPerTick / AvgLength;
|
||||
|
||||
tickDrainPerTick = 0;
|
||||
tickInjectionPerTick = 0;
|
||||
|
||||
// power information.
|
||||
boolean currentlyHasPower = false;
|
||||
|
||||
if ( drainPerTick > 0.0001 )
|
||||
{
|
||||
double drained = extractAEPower( getIdlePowerUsage(), Actionable.MODULATE, PowerMultiplier.CONFIG );
|
||||
currentlyHasPower = drained >= drainPerTick - 0.001;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentlyHasPower = extractAEPower( 0.1, Actionable.SIMULATE, PowerMultiplier.CONFIG ) > 0;
|
||||
}
|
||||
|
||||
// ticks since change..
|
||||
if ( currentlyHasPower == hasPower )
|
||||
ticksSinceHasPowerChange++;
|
||||
else
|
||||
ticksSinceHasPowerChange = 0;
|
||||
|
||||
// update status..
|
||||
hasPower = currentlyHasPower;
|
||||
|
||||
// update public status, this buffers power ups for 30 ticks.
|
||||
if ( hasPower && ticksSinceHasPowerChange > 30 )
|
||||
publicPowerState( true, myGrid );
|
||||
else if ( !hasPower )
|
||||
publicPowerState( false, myGrid );
|
||||
|
||||
availableTicksSinceUpdate++;
|
||||
}
|
||||
|
||||
private void publicPowerState(boolean newState, IGrid grid)
|
||||
{
|
||||
if ( publicHasPower == newState )
|
||||
return;
|
||||
|
||||
publicHasPower = newState;
|
||||
((Grid) myGrid).setImportantFlag( 0, publicHasPower );
|
||||
grid.postEvent( new MENetworkPowerStatusChange() );
|
||||
}
|
||||
|
||||
/**
|
||||
* refresh current stored power.
|
||||
*/
|
||||
public void refreshPower()
|
||||
{
|
||||
availableTicksSinceUpdate = 0;
|
||||
globalAvailablePower = 0;
|
||||
for (IAEPowerStorage p : providers)
|
||||
globalAvailablePower += p.getAECurrentPower();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getStoredPower()
|
||||
{
|
||||
if ( availableTicksSinceUpdate > 90 )
|
||||
refreshPower();
|
||||
|
||||
return Math.max( 0.0, globalAvailablePower );
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getMaxStoredPower()
|
||||
{
|
||||
return globalMaxPower;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double extractAEPower(double amt, Actionable mode, Set<IEnergyGrid> seen)
|
||||
{
|
||||
if ( !seen.add( this ) )
|
||||
return 0;
|
||||
|
||||
double extractedPower = extra;
|
||||
|
||||
if ( mode == Actionable.SIMULATE )
|
||||
{
|
||||
extractedPower += simulateExtract( extractedPower, amt );
|
||||
|
||||
if ( extractedPower < amt )
|
||||
{
|
||||
Iterator<IEnergyGridProvider> i = gproviders.iterator();
|
||||
while (extractedPower < amt && i.hasNext())
|
||||
extractedPower += i.next().extractAEPower( amt - extractedPower, mode, seen );
|
||||
}
|
||||
|
||||
return extractedPower;
|
||||
}
|
||||
else
|
||||
{
|
||||
extra = 0;
|
||||
extractedPower = doExtract( extractedPower, amt );
|
||||
}
|
||||
|
||||
// got more then we wanted?
|
||||
if ( extractedPower > amt )
|
||||
{
|
||||
extra = extractedPower - amt;
|
||||
globalAvailablePower -= amt;
|
||||
|
||||
tickDrainPerTick += amt;
|
||||
return amt;
|
||||
}
|
||||
|
||||
if ( extractedPower < amt )
|
||||
{
|
||||
Iterator<IEnergyGridProvider> i = gproviders.iterator();
|
||||
while (extractedPower < amt && i.hasNext())
|
||||
extractedPower += i.next().extractAEPower( amt - extractedPower, mode, seen );
|
||||
}
|
||||
|
||||
// go less or the correct amount?
|
||||
globalAvailablePower -= extractedPower;
|
||||
tickDrainPerTick += extractedPower;
|
||||
return extractedPower;
|
||||
}
|
||||
|
||||
private double doExtract(double extractedPower, double amt)
|
||||
{
|
||||
while (extractedPower < amt && !providers.isEmpty())
|
||||
{
|
||||
IAEPowerStorage node = getFirstProvider();
|
||||
|
||||
double req = amt - extractedPower;
|
||||
double newPower = node.extractAEPower( req, Actionable.MODULATE, PowerMultiplier.ONE );
|
||||
extractedPower += newPower;
|
||||
|
||||
if ( newPower < req )
|
||||
{
|
||||
providers.remove( node );
|
||||
lastProvider = null;
|
||||
}
|
||||
}
|
||||
|
||||
// totalDrainPastTicks[0] += extractedPower;
|
||||
return extractedPower;
|
||||
}
|
||||
|
||||
private double simulateExtract(double extractedPower, double amt)
|
||||
{
|
||||
Iterator<IAEPowerStorage> it = providers.iterator();
|
||||
|
||||
while (extractedPower < amt && it.hasNext())
|
||||
{
|
||||
IAEPowerStorage node = it.next();
|
||||
|
||||
double req = amt - extractedPower;
|
||||
double newPower = node.extractAEPower( req, Actionable.SIMULATE, PowerMultiplier.ONE );
|
||||
extractedPower += newPower;
|
||||
}
|
||||
|
||||
return extractedPower;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNetworkPowered()
|
||||
{
|
||||
return publicHasPower;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getIdlePowerUsage()
|
||||
{
|
||||
return drainPerTick + pgc.channelPowerUsage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getAvgPowerUsage()
|
||||
{
|
||||
return avgDrainPerTick;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getAvgPowerInjection()
|
||||
{
|
||||
return avgInjectionPerTick;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSplit(IGridStorage storageB)
|
||||
{
|
||||
extra /= 2;
|
||||
storageB.dataObject().setDouble( "extraEnergy", extra );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onJoin(IGridStorage storageB)
|
||||
{
|
||||
extra += storageB.dataObject().getDouble( "extraEnergy" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateGridStorage(IGridStorage storage)
|
||||
{
|
||||
storage.dataObject().setDouble( "extraEnergy", this.extra );
|
||||
}
|
||||
|
||||
}
|
||||
+351
@@ -0,0 +1,351 @@
|
||||
package appeng.me.cache;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.networking.IGrid;
|
||||
import appeng.api.networking.IGridHost;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.IGridStorage;
|
||||
import appeng.api.networking.events.MENetworkCellArrayUpdate;
|
||||
import appeng.api.networking.events.MENetworkEventSubscribe;
|
||||
import appeng.api.networking.security.BaseActionSource;
|
||||
import appeng.api.networking.security.IActionHost;
|
||||
import appeng.api.networking.security.ISecurityGrid;
|
||||
import appeng.api.networking.security.MachineSource;
|
||||
import appeng.api.networking.storage.IStackWatcher;
|
||||
import appeng.api.networking.storage.IStackWatcherHost;
|
||||
import appeng.api.networking.storage.IStorageGrid;
|
||||
import appeng.api.storage.ICellContainer;
|
||||
import appeng.api.storage.ICellProvider;
|
||||
import appeng.api.storage.IMEInventoryHandler;
|
||||
import appeng.api.storage.IMEMonitor;
|
||||
import appeng.api.storage.StorageChannel;
|
||||
import appeng.api.storage.data.IAEFluidStack;
|
||||
import appeng.api.storage.data.IAEItemStack;
|
||||
import appeng.api.storage.data.IAEStack;
|
||||
import appeng.api.storage.data.IItemList;
|
||||
import appeng.me.helpers.GenericInterestManager;
|
||||
import appeng.me.storage.ItemWatcher;
|
||||
import appeng.me.storage.NetworkInventoryHandler;
|
||||
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.SetMultimap;
|
||||
|
||||
public class GridStorageCache implements IStorageGrid
|
||||
{
|
||||
|
||||
final private SetMultimap<IAEStack, ItemWatcher> interests = HashMultimap.create();
|
||||
final public GenericInterestManager interestManager = new GenericInterestManager( interests );
|
||||
|
||||
final HashSet<ICellProvider> activeCellProviders = new HashSet();
|
||||
final HashSet<ICellProvider> inactiveCellProviders = new HashSet();
|
||||
final public IGrid myGrid;
|
||||
|
||||
private NetworkInventoryHandler<IAEItemStack> myItemNetwork;
|
||||
private NetworkMonitor<IAEItemStack> itemMonitor = new NetworkMonitor<IAEItemStack>( this, StorageChannel.ITEMS );
|
||||
|
||||
private NetworkInventoryHandler<IAEFluidStack> myFluidNetwork;
|
||||
private NetworkMonitor<IAEFluidStack> fluidMonitor = new NetworkMonitor<IAEFluidStack>( this, StorageChannel.FLUIDS );
|
||||
|
||||
private HashMap<IGridNode, IStackWatcher> watchers = new HashMap<IGridNode, IStackWatcher>();
|
||||
|
||||
public GridStorageCache(IGrid g) {
|
||||
myGrid = g;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdateTick()
|
||||
{
|
||||
itemMonitor.onTick();
|
||||
fluidMonitor.onTick();
|
||||
}
|
||||
|
||||
private class CellChangeTrackerRecord
|
||||
{
|
||||
|
||||
final StorageChannel channel;
|
||||
final int up_or_down;
|
||||
final IItemList list;
|
||||
final BaseActionSource src;
|
||||
|
||||
public CellChangeTrackerRecord(StorageChannel channel, int i, IMEInventoryHandler<? extends IAEStack> h, BaseActionSource actionSrc) {
|
||||
this.channel = channel;
|
||||
this.up_or_down = i;
|
||||
this.src = actionSrc;
|
||||
|
||||
if ( channel == StorageChannel.ITEMS )
|
||||
this.list = ((IMEInventoryHandler<IAEItemStack>) h).getAvailableItems( AEApi.instance().storage().createItemList() );
|
||||
else if ( channel == StorageChannel.FLUIDS )
|
||||
this.list = ((IMEInventoryHandler<IAEFluidStack>) h).getAvailableItems( AEApi.instance().storage().createFluidList() );
|
||||
else
|
||||
this.list = null;
|
||||
}
|
||||
|
||||
public void applyChanges()
|
||||
{
|
||||
postChangesToNetwork( channel, up_or_down, list, src );
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private class CellChangeTracker
|
||||
{
|
||||
|
||||
List<CellChangeTrackerRecord> data = new LinkedList();
|
||||
|
||||
public void postChanges(StorageChannel channel, int i, IMEInventoryHandler<? extends IAEStack> h, BaseActionSource actionSrc)
|
||||
{
|
||||
data.add( new CellChangeTrackerRecord( channel, i, h, actionSrc ) );
|
||||
}
|
||||
|
||||
public void applyChanges()
|
||||
{
|
||||
for (CellChangeTrackerRecord rec : data)
|
||||
rec.applyChanges();
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void registerCellProvider(ICellProvider provider)
|
||||
{
|
||||
inactiveCellProviders.add( provider );
|
||||
addCellProvider( provider, new CellChangeTracker() ).applyChanges();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterCellProvider(ICellProvider provider)
|
||||
{
|
||||
removeCellProvider( provider, new CellChangeTracker() ).applyChanges();
|
||||
inactiveCellProviders.remove( provider );
|
||||
}
|
||||
|
||||
public CellChangeTracker addCellProvider(ICellProvider cc, CellChangeTracker tracker)
|
||||
{
|
||||
if ( inactiveCellProviders.contains( cc ) )
|
||||
{
|
||||
inactiveCellProviders.remove( cc );
|
||||
activeCellProviders.add( cc );
|
||||
|
||||
BaseActionSource actionSrc = new BaseActionSource();
|
||||
if ( cc instanceof IActionHost )
|
||||
actionSrc = new MachineSource( (IActionHost) cc );
|
||||
|
||||
for (IMEInventoryHandler<IAEItemStack> h : cc.getCellArray( StorageChannel.ITEMS ))
|
||||
{
|
||||
tracker.postChanges( StorageChannel.ITEMS, 1, h, actionSrc );
|
||||
}
|
||||
|
||||
for (IMEInventoryHandler<IAEFluidStack> h : cc.getCellArray( StorageChannel.FLUIDS ))
|
||||
{
|
||||
tracker.postChanges( StorageChannel.FLUIDS, 1, h, actionSrc );
|
||||
}
|
||||
}
|
||||
|
||||
return tracker;
|
||||
}
|
||||
|
||||
public CellChangeTracker removeCellProvider(ICellProvider cc, CellChangeTracker tracker)
|
||||
{
|
||||
if ( activeCellProviders.contains( cc ) )
|
||||
{
|
||||
inactiveCellProviders.add( cc );
|
||||
activeCellProviders.remove( cc );
|
||||
|
||||
BaseActionSource actionSrc = new BaseActionSource();
|
||||
if ( cc instanceof IActionHost )
|
||||
actionSrc = new MachineSource( (IActionHost) cc );
|
||||
|
||||
for (IMEInventoryHandler<IAEItemStack> h : cc.getCellArray( StorageChannel.ITEMS ))
|
||||
{
|
||||
tracker.postChanges( StorageChannel.ITEMS, -1, h, actionSrc );
|
||||
}
|
||||
|
||||
for (IMEInventoryHandler<IAEFluidStack> h : cc.getCellArray( StorageChannel.FLUIDS ))
|
||||
{
|
||||
tracker.postChanges( StorageChannel.FLUIDS, -1, h, actionSrc );
|
||||
}
|
||||
}
|
||||
|
||||
return tracker;
|
||||
}
|
||||
|
||||
@MENetworkEventSubscribe
|
||||
public void cellUpdate(MENetworkCellArrayUpdate ev)
|
||||
{
|
||||
myItemNetwork = null;
|
||||
myFluidNetwork = null;
|
||||
|
||||
LinkedList<ICellProvider> ll = new LinkedList();
|
||||
ll.addAll( inactiveCellProviders );
|
||||
ll.addAll( activeCellProviders );
|
||||
|
||||
CellChangeTracker tracker = new CellChangeTracker();
|
||||
|
||||
for (ICellProvider cc : ll)
|
||||
{
|
||||
boolean Active = true;
|
||||
|
||||
if ( cc instanceof IActionHost )
|
||||
{
|
||||
IGridNode node = ((IActionHost) cc).getActionableNode();
|
||||
if ( node != null && node.isActive() )
|
||||
Active = true;
|
||||
else
|
||||
Active = false;
|
||||
}
|
||||
|
||||
if ( Active )
|
||||
addCellProvider( cc, tracker );
|
||||
else
|
||||
removeCellProvider( cc, tracker );
|
||||
}
|
||||
|
||||
itemMonitor.forceUpdate();
|
||||
fluidMonitor.forceUpdate();
|
||||
|
||||
tracker.applyChanges();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNode(IGridNode node, IGridHost machine)
|
||||
{
|
||||
if ( machine instanceof ICellContainer )
|
||||
{
|
||||
ICellContainer cc = (ICellContainer) machine;
|
||||
|
||||
myGrid.postEvent( new MENetworkCellArrayUpdate() );
|
||||
removeCellProvider( cc, new CellChangeTracker() ).applyChanges();
|
||||
inactiveCellProviders.remove( cc );
|
||||
}
|
||||
|
||||
if ( machine instanceof IStackWatcherHost )
|
||||
{
|
||||
IStackWatcher myWatcher = watchers.get( machine );
|
||||
if ( myWatcher != null )
|
||||
{
|
||||
myWatcher.clear();
|
||||
watchers.remove( machine );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNode(IGridNode node, IGridHost machine)
|
||||
{
|
||||
if ( machine instanceof ICellContainer )
|
||||
{
|
||||
ICellContainer cc = (ICellContainer) machine;
|
||||
inactiveCellProviders.add( cc );
|
||||
|
||||
myGrid.postEvent( new MENetworkCellArrayUpdate() );
|
||||
if ( node.isActive() )
|
||||
addCellProvider( cc, new CellChangeTracker() ).applyChanges();
|
||||
}
|
||||
|
||||
if ( machine instanceof IStackWatcherHost )
|
||||
{
|
||||
IStackWatcherHost swh = (IStackWatcherHost) machine;
|
||||
ItemWatcher iw = new ItemWatcher( this, (IStackWatcherHost) swh );
|
||||
watchers.put( node, iw );
|
||||
swh.updateWatcher( iw );
|
||||
}
|
||||
}
|
||||
|
||||
private void buildNetworkStorage(StorageChannel chan)
|
||||
{
|
||||
SecurityCache security = myGrid.getCache( ISecurityGrid.class );
|
||||
|
||||
switch (chan)
|
||||
{
|
||||
case FLUIDS:
|
||||
myFluidNetwork = new NetworkInventoryHandler<IAEFluidStack>( StorageChannel.FLUIDS, security );
|
||||
for (ICellProvider cc : activeCellProviders)
|
||||
{
|
||||
for (IMEInventoryHandler<IAEFluidStack> h : cc.getCellArray( chan ))
|
||||
myFluidNetwork.addNewStorage( h );
|
||||
}
|
||||
break;
|
||||
case ITEMS:
|
||||
myItemNetwork = new NetworkInventoryHandler<IAEItemStack>( StorageChannel.ITEMS, security );
|
||||
for (ICellProvider cc : activeCellProviders)
|
||||
{
|
||||
for (IMEInventoryHandler<IAEItemStack> h : cc.getCellArray( chan ))
|
||||
myItemNetwork.addNewStorage( h );
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
private void postChangesToNetwork(StorageChannel chan, int up_or_down, IItemList availableItems, BaseActionSource src)
|
||||
{
|
||||
switch (chan)
|
||||
{
|
||||
case FLUIDS:
|
||||
fluidMonitor.postChange( up_or_down > 0, (IItemList<IAEFluidStack>) availableItems, src );
|
||||
break;
|
||||
case ITEMS:
|
||||
itemMonitor.postChange( up_or_down > 0, (IItemList<IAEItemStack>) availableItems, src );
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
public IMEInventoryHandler<IAEItemStack> getItemInventoryHandler()
|
||||
{
|
||||
if ( myItemNetwork == null )
|
||||
buildNetworkStorage( StorageChannel.ITEMS );
|
||||
return myItemNetwork;
|
||||
}
|
||||
|
||||
public IMEInventoryHandler<IAEFluidStack> getFluidInventoryHandler()
|
||||
{
|
||||
if ( myFluidNetwork == null )
|
||||
buildNetworkStorage( StorageChannel.FLUIDS );
|
||||
return myFluidNetwork;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postAlterationOfStoredItems(StorageChannel chan, Iterable<? extends IAEStack> input, BaseActionSource src)
|
||||
{
|
||||
if ( chan == StorageChannel.ITEMS )
|
||||
itemMonitor.postChange( true, (Iterable<IAEItemStack>) input, src );
|
||||
else if ( chan == StorageChannel.FLUIDS )
|
||||
fluidMonitor.postChange( true, (Iterable<IAEFluidStack>) input, src );
|
||||
}
|
||||
|
||||
@Override
|
||||
public IMEMonitor<IAEFluidStack> getFluidInventory()
|
||||
{
|
||||
return fluidMonitor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IMEMonitor<IAEItemStack> getItemInventory()
|
||||
{
|
||||
return itemMonitor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSplit(IGridStorage storageB)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onJoin(IGridStorage storageB)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateGridStorage(IGridStorage storage)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
package appeng.me.cache;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import appeng.api.networking.events.MENetworkStorageEvent;
|
||||
import appeng.api.networking.security.BaseActionSource;
|
||||
import appeng.api.storage.IMEInventoryHandler;
|
||||
import appeng.api.storage.IMEMonitorHandlerReceiver;
|
||||
import appeng.api.storage.MEMonitorHandler;
|
||||
import appeng.api.storage.StorageChannel;
|
||||
import appeng.api.storage.data.IAEStack;
|
||||
import appeng.api.storage.data.IItemList;
|
||||
import appeng.me.storage.ItemWatcher;
|
||||
|
||||
public class NetworkMonitor<T extends IAEStack<T>> extends MEMonitorHandler<T>
|
||||
{
|
||||
|
||||
final private GridStorageCache myGridCache;
|
||||
final private StorageChannel myChannel;
|
||||
|
||||
boolean sendEvent = false;
|
||||
|
||||
public void forceUpdate()
|
||||
{
|
||||
hasChanged = true;
|
||||
|
||||
Iterator<Entry<IMEMonitorHandlerReceiver<T>, Object>> i = getListeners();
|
||||
while (i.hasNext())
|
||||
{
|
||||
Entry<IMEMonitorHandlerReceiver<T>, Object> o = i.next();
|
||||
IMEMonitorHandlerReceiver<T> recv = o.getKey();
|
||||
|
||||
if ( recv.isValid( o.getValue() ) )
|
||||
recv.onListUpdate();
|
||||
else
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
|
||||
public NetworkMonitor(GridStorageCache cache, StorageChannel chan) {
|
||||
super( null, chan );
|
||||
myGridCache = cache;
|
||||
myChannel = chan;
|
||||
}
|
||||
|
||||
final static public LinkedList depth = new LinkedList();
|
||||
|
||||
@Override
|
||||
protected void postChangesToListeners(Iterable<T> changes, BaseActionSource src)
|
||||
{
|
||||
postChange( true, changes, src );
|
||||
}
|
||||
|
||||
protected void postChange(boolean Add, Iterable<T> changes, BaseActionSource src)
|
||||
{
|
||||
if ( depth.contains( this ) )
|
||||
return;
|
||||
|
||||
depth.push( this );
|
||||
|
||||
sendEvent = true;
|
||||
notifyListenersOfChange( changes, src );
|
||||
|
||||
IItemList<T> myStorageList = getStorageList();
|
||||
|
||||
for (T changedItem : changes)
|
||||
{
|
||||
T difference = changedItem;
|
||||
|
||||
if ( !Add && changedItem != null )
|
||||
(difference = changedItem.copy()).setStackSize( -changedItem.getStackSize() );
|
||||
|
||||
if ( myGridCache.interestManager.containsKey( changedItem ) )
|
||||
{
|
||||
Set<ItemWatcher> list = myGridCache.interestManager.get( changedItem );
|
||||
if ( !list.isEmpty() )
|
||||
{
|
||||
IAEStack fullStack = myStorageList.findPrecise( changedItem );
|
||||
if ( fullStack == null )
|
||||
{
|
||||
fullStack = changedItem.copy();
|
||||
fullStack.setStackSize( 0 );
|
||||
}
|
||||
|
||||
myGridCache.interestManager.enableTransactions();
|
||||
|
||||
for (ItemWatcher iw : list)
|
||||
iw.getHost().onStackChange( myStorageList, fullStack, difference, src, getChannel() );
|
||||
|
||||
myGridCache.interestManager.disableTransactions();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Object last = depth.pop();
|
||||
if ( last != this )
|
||||
throw new RuntimeException( "Invalid Access to Networked Storage API detected." );
|
||||
}
|
||||
|
||||
public void onTick()
|
||||
{
|
||||
if ( sendEvent )
|
||||
{
|
||||
sendEvent = false;
|
||||
myGridCache.myGrid.postEvent( new MENetworkStorageEvent( this, myChannel ) );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IMEInventoryHandler getHandler()
|
||||
{
|
||||
switch (myChannel)
|
||||
{
|
||||
case ITEMS:
|
||||
return myGridCache.getItemInventoryHandler();
|
||||
case FLUIDS:
|
||||
return myGridCache.getFluidInventoryHandler();
|
||||
default:
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
+186
@@ -0,0 +1,186 @@
|
||||
package appeng.me.cache;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import appeng.api.networking.GridFlags;
|
||||
import appeng.api.networking.IGrid;
|
||||
import appeng.api.networking.IGridCache;
|
||||
import appeng.api.networking.IGridHost;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.IGridStorage;
|
||||
import appeng.api.networking.events.MENetworkBootingStatusChange;
|
||||
import appeng.api.networking.events.MENetworkEventSubscribe;
|
||||
import appeng.api.networking.events.MENetworkPowerStatusChange;
|
||||
import appeng.api.networking.ticking.ITickManager;
|
||||
import appeng.me.cache.helpers.TunnelCollection;
|
||||
import appeng.parts.p2p.PartP2PTunnel;
|
||||
import appeng.parts.p2p.PartP2PTunnelME;
|
||||
|
||||
import com.google.common.collect.LinkedHashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
public class P2PCache implements IGridCache
|
||||
{
|
||||
|
||||
final private HashMap<Long, PartP2PTunnel> inputs = new HashMap();
|
||||
final private Multimap<Long, PartP2PTunnel> outputs = LinkedHashMultimap.create();
|
||||
final private TunnelCollection NullColl = new TunnelCollection<PartP2PTunnel>( null, null );
|
||||
|
||||
final IGrid myGrid;
|
||||
|
||||
public P2PCache(IGrid g) {
|
||||
myGrid = g;
|
||||
}
|
||||
|
||||
@MENetworkEventSubscribe
|
||||
public void bootComplete(MENetworkBootingStatusChange bootstat)
|
||||
{
|
||||
ITickManager tm = myGrid.getCache( ITickManager.class );
|
||||
for (PartP2PTunnel me : inputs.values())
|
||||
{
|
||||
if ( me instanceof PartP2PTunnelME )
|
||||
tm.wakeDevice( me.getGridNode() );
|
||||
}
|
||||
}
|
||||
|
||||
@MENetworkEventSubscribe
|
||||
public void bootComplete(MENetworkPowerStatusChange power)
|
||||
{
|
||||
ITickManager tm = myGrid.getCache( ITickManager.class );
|
||||
for (PartP2PTunnel me : inputs.values())
|
||||
{
|
||||
if ( me instanceof PartP2PTunnelME )
|
||||
tm.wakeDevice( me.getGridNode() );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdateTick()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void updateFreq(PartP2PTunnel t, long NewFreq)
|
||||
{
|
||||
if ( outputs.containsValue( t ) )
|
||||
outputs.remove( t.freq, t );
|
||||
|
||||
if ( inputs.containsValue( t ) )
|
||||
inputs.remove( t.freq );
|
||||
|
||||
t.freq = NewFreq;
|
||||
|
||||
if ( t.output )
|
||||
outputs.put( t.freq, t );
|
||||
else
|
||||
inputs.put( t.freq, t );
|
||||
|
||||
// AELog.info( "update-" + (t.output ? "output: " : "input: ") + t.freq
|
||||
// );
|
||||
updateTunnel( t.freq, t.output, true );
|
||||
updateTunnel( t.freq, !t.output, true );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNode(IGridNode node, IGridHost machine)
|
||||
{
|
||||
if ( machine instanceof PartP2PTunnel )
|
||||
{
|
||||
if ( machine instanceof PartP2PTunnelME )
|
||||
{
|
||||
if ( !node.hasFlag( GridFlags.REQUIRE_CHANNEL ) )
|
||||
return;
|
||||
}
|
||||
|
||||
PartP2PTunnel t = (PartP2PTunnel) machine;
|
||||
// AELog.info( "add-" + (t.output ? "output: " : "input: ") + t.freq
|
||||
// );
|
||||
|
||||
if ( t.output )
|
||||
outputs.put( t.freq, t );
|
||||
else
|
||||
inputs.put( t.freq, t );
|
||||
|
||||
updateTunnel( t.freq, !t.output, false );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNode(IGridNode node, IGridHost machine)
|
||||
{
|
||||
if ( machine instanceof PartP2PTunnel )
|
||||
{
|
||||
if ( machine instanceof PartP2PTunnelME )
|
||||
{
|
||||
if ( !node.hasFlag( GridFlags.REQUIRE_CHANNEL ) )
|
||||
return;
|
||||
}
|
||||
|
||||
PartP2PTunnel t = (PartP2PTunnel) machine;
|
||||
// AELog.info( "rmv-" + (t.output ? "output: " : "input: ") + t.freq
|
||||
// );
|
||||
|
||||
if ( t.output )
|
||||
outputs.remove( t.freq, t );
|
||||
else
|
||||
inputs.remove( t.freq );
|
||||
|
||||
updateTunnel( t.freq, !t.output, false );
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTunnel(long freq, boolean updateOutputs, boolean configChange)
|
||||
{
|
||||
for (PartP2PTunnel p : outputs.get( freq ))
|
||||
{
|
||||
if ( configChange )
|
||||
p.onTunnelConfigChange();
|
||||
p.onTunnelNetworkChange();
|
||||
}
|
||||
|
||||
PartP2PTunnel in = inputs.get( freq );
|
||||
if ( in != null )
|
||||
{
|
||||
if ( configChange )
|
||||
in.onTunnelConfigChange();
|
||||
in.onTunnelNetworkChange();
|
||||
}
|
||||
}
|
||||
|
||||
public TunnelCollection<PartP2PTunnel> getOutputs(long freq, Class<? extends PartP2PTunnel> c)
|
||||
{
|
||||
PartP2PTunnel in = inputs.get( freq );
|
||||
if ( in == null )
|
||||
return NullColl;
|
||||
|
||||
TunnelCollection<PartP2PTunnel> out = inputs.get( freq ).getCollection( outputs.get( freq ), c );
|
||||
if ( out == null )
|
||||
return NullColl;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
public PartP2PTunnel getInput(long freq)
|
||||
{
|
||||
return inputs.get( freq );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSplit(IGridStorage storageB)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onJoin(IGridStorage storageB)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateGridStorage(IGridStorage storage)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+379
@@ -0,0 +1,379 @@
|
||||
package appeng.me.cache;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import net.minecraftforge.common.util.ForgeDirection;
|
||||
import appeng.api.networking.GridFlags;
|
||||
import appeng.api.networking.IGrid;
|
||||
import appeng.api.networking.IGridBlock;
|
||||
import appeng.api.networking.IGridConnection;
|
||||
import appeng.api.networking.IGridHost;
|
||||
import appeng.api.networking.IGridMultiblock;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.IGridStorage;
|
||||
import appeng.api.networking.events.MENetworkBootingStatusChange;
|
||||
import appeng.api.networking.events.MENetworkChannelChanged;
|
||||
import appeng.api.networking.events.MENetworkControllerChange;
|
||||
import appeng.api.networking.events.MENetworkEventSubscribe;
|
||||
import appeng.api.networking.pathing.ControllerState;
|
||||
import appeng.api.networking.pathing.IPathingGrid;
|
||||
import appeng.api.util.DimensionalCoord;
|
||||
import appeng.core.AEConfig;
|
||||
import appeng.core.features.AEFeature;
|
||||
import appeng.core.stats.Achievements;
|
||||
import appeng.me.GridConnection;
|
||||
import appeng.me.GridNode;
|
||||
import appeng.me.pathfinding.AdHocChannelUpdater;
|
||||
import appeng.me.pathfinding.ControllerChannelUpdater;
|
||||
import appeng.me.pathfinding.ControllerValidator;
|
||||
import appeng.me.pathfinding.IPathItem;
|
||||
import appeng.me.pathfinding.PathSegment;
|
||||
import appeng.tile.networking.TileController;
|
||||
import appeng.util.Platform;
|
||||
|
||||
public class PathGridCache implements IPathingGrid
|
||||
{
|
||||
|
||||
boolean recalculateControllerNextTick = true;
|
||||
boolean updateNetwork = true;
|
||||
boolean booting = false;
|
||||
|
||||
final LinkedList<PathSegment> active = new LinkedList();
|
||||
|
||||
ControllerState controllerState = ControllerState.NO_CONTROLLER;
|
||||
|
||||
int instance = Integer.MIN_VALUE;
|
||||
|
||||
int ticksUntilReady = 20;
|
||||
public int channelsInUse = 0;
|
||||
int lastChannels = 0;
|
||||
|
||||
final Set<TileController> controllers = new HashSet();
|
||||
final Set<IGridNode> requireChannels = new HashSet();
|
||||
final Set<IGridNode> blockDense = new HashSet();
|
||||
|
||||
final IGrid myGrid;
|
||||
private HashSet<IPathItem> semiOpen = new HashSet();
|
||||
private HashSet<IPathItem> closedList = new HashSet();
|
||||
|
||||
public int channelsByBlocks = 0;
|
||||
public double channelPowerUsage = 0.0;
|
||||
|
||||
public PathGridCache(IGrid g)
|
||||
{
|
||||
myGrid = g;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdateTick()
|
||||
{
|
||||
if ( recalculateControllerNextTick )
|
||||
{
|
||||
recalcController();
|
||||
}
|
||||
|
||||
if ( updateNetwork )
|
||||
{
|
||||
if ( !booting )
|
||||
myGrid.postEvent( new MENetworkBootingStatusChange() );
|
||||
|
||||
booting = true;
|
||||
updateNetwork = false;
|
||||
instance++;
|
||||
channelsInUse = 0;
|
||||
|
||||
if ( !AEConfig.instance.isFeatureEnabled( AEFeature.Channels ) )
|
||||
{
|
||||
int used = calculateRequiredChannels();
|
||||
|
||||
int nodes = myGrid.getNodes().size();
|
||||
ticksUntilReady = 20 + Math.max( 0, nodes / 100 - 20 );
|
||||
channelsByBlocks = nodes * used;
|
||||
channelPowerUsage = (double) channelsByBlocks / 128.0;
|
||||
|
||||
myGrid.getPivot().beginVisit( new AdHocChannelUpdater( used ) );
|
||||
}
|
||||
else if ( controllerState == ControllerState.NO_CONTROLLER )
|
||||
{
|
||||
int requiredChannels = calculateRequiredChannels();
|
||||
int used = requiredChannels;
|
||||
if ( requiredChannels > 8 )
|
||||
used = 0;
|
||||
|
||||
int nodes = myGrid.getNodes().size();
|
||||
channelsInUse = used;
|
||||
|
||||
ticksUntilReady = 20 + Math.max( 0, nodes / 100 - 20 );
|
||||
channelsByBlocks = nodes * used;
|
||||
channelPowerUsage = (double) channelsByBlocks / 128.0;
|
||||
|
||||
myGrid.getPivot().beginVisit( new AdHocChannelUpdater( used ) );
|
||||
}
|
||||
else if ( controllerState == ControllerState.CONTROLLER_CONFLICT )
|
||||
{
|
||||
ticksUntilReady = 20;
|
||||
myGrid.getPivot().beginVisit( new AdHocChannelUpdater( 0 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
int nodes = myGrid.getNodes().size();
|
||||
ticksUntilReady = 20 + Math.max( 0, nodes / 100 - 20 );
|
||||
closedList = new HashSet();
|
||||
semiOpen = new HashSet();
|
||||
|
||||
// myGrid.getPivot().beginVisit( new AdHocChannelUpdater( 0 )
|
||||
// );
|
||||
for (IGridNode node : myGrid.getMachines( TileController.class ))
|
||||
{
|
||||
closedList.add( (IPathItem) node );
|
||||
for (IGridConnection gcc : node.getConnections())
|
||||
{
|
||||
GridConnection gc = (GridConnection) gcc;
|
||||
if ( !(gc.getOtherSide( node ).getMachine() instanceof TileController) )
|
||||
{
|
||||
List open = new LinkedList();
|
||||
closedList.add( gc );
|
||||
open.add( gc );
|
||||
gc.setControllerRoute( (GridNode) node, true );
|
||||
active.add( new PathSegment( this, open, semiOpen, closedList ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( !active.isEmpty() || ticksUntilReady > 0 )
|
||||
{
|
||||
Iterator<PathSegment> i = active.iterator();
|
||||
while (i.hasNext())
|
||||
{
|
||||
PathSegment pat = i.next();
|
||||
if ( pat.step() )
|
||||
{
|
||||
pat.isDead = true;
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
|
||||
ticksUntilReady--;
|
||||
|
||||
if ( active.isEmpty() && ticksUntilReady <= 0 )
|
||||
{
|
||||
if ( controllerState == ControllerState.CONTROLLER_ONLINE )
|
||||
{
|
||||
for (TileController tc : controllers)
|
||||
{
|
||||
tc.getGridNode( ForgeDirection.UNKNOWN ).beginVisit( new ControllerChannelUpdater() );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// check for achievements
|
||||
achievementPost();
|
||||
|
||||
booting = false;
|
||||
channelPowerUsage = (double) channelsByBlocks / 128.0;
|
||||
myGrid.postEvent( new MENetworkBootingStatusChange() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void achievementPost()
|
||||
{
|
||||
if ( lastChannels != channelsInUse && AEConfig.instance.isFeatureEnabled( AEFeature.Channels ) )
|
||||
{
|
||||
Achievements currentBracket = getAchievementBracket( channelsInUse );
|
||||
Achievements lastBracket = getAchievementBracket( lastChannels );
|
||||
if ( currentBracket != lastBracket && currentBracket != null )
|
||||
{
|
||||
Set<Integer> players = new HashSet();
|
||||
for (IGridNode n : requireChannels)
|
||||
players.add( n.getPlayerID() );
|
||||
|
||||
for (int id : players)
|
||||
{
|
||||
Platform.addStat( id, currentBracket.getAchievement() );
|
||||
}
|
||||
}
|
||||
}
|
||||
lastChannels = channelsInUse;
|
||||
}
|
||||
|
||||
private Achievements getAchievementBracket(int ch)
|
||||
{
|
||||
if ( ch < 8 )
|
||||
return null;
|
||||
|
||||
if ( ch < 128 )
|
||||
return Achievements.Networking1;
|
||||
|
||||
if ( ch < 2048 )
|
||||
return Achievements.Networking2;
|
||||
|
||||
return Achievements.Networking3;
|
||||
}
|
||||
|
||||
private int calculateRequiredChannels()
|
||||
{
|
||||
int depth = 0;
|
||||
semiOpen.clear();
|
||||
|
||||
for (IGridNode nodes : requireChannels)
|
||||
{
|
||||
if ( !semiOpen.contains( nodes ) )
|
||||
{
|
||||
IGridBlock gb = nodes.getGridBlock();
|
||||
EnumSet<GridFlags> flags = gb.getFlags();
|
||||
|
||||
if ( flags.contains( GridFlags.COMPRESSED_CHANNEL ) && !blockDense.isEmpty() )
|
||||
return 9;
|
||||
|
||||
depth++;
|
||||
|
||||
if ( flags.contains( GridFlags.MULTIBLOCK ) )
|
||||
{
|
||||
IGridMultiblock gmb = (IGridMultiblock) gb;
|
||||
Iterator<IGridNode> i = gmb.getMultiblockNodes();
|
||||
while (i.hasNext())
|
||||
semiOpen.add( (IPathItem) i.next() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return depth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void repath()
|
||||
{
|
||||
// clean up...
|
||||
active.clear();
|
||||
|
||||
channelsByBlocks = 0;
|
||||
updateNetwork = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNode(IGridNode gridNode, IGridHost machine)
|
||||
{
|
||||
if ( machine instanceof TileController )
|
||||
{
|
||||
controllers.remove( machine );
|
||||
recalculateControllerNextTick = true;
|
||||
}
|
||||
|
||||
EnumSet<GridFlags> flags = gridNode.getGridBlock().getFlags();
|
||||
|
||||
if ( flags.contains( GridFlags.REQUIRE_CHANNEL ) )
|
||||
requireChannels.remove( gridNode );
|
||||
|
||||
if ( flags.contains( GridFlags.CANNOT_CARRY_COMPRESSED ) )
|
||||
blockDense.remove( gridNode );
|
||||
|
||||
repath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNode(IGridNode gridNode, IGridHost machine)
|
||||
{
|
||||
if ( machine instanceof TileController )
|
||||
{
|
||||
controllers.add( (TileController) machine );
|
||||
recalculateControllerNextTick = true;
|
||||
}
|
||||
|
||||
EnumSet<GridFlags> flags = gridNode.getGridBlock().getFlags();
|
||||
|
||||
if ( flags.contains( GridFlags.REQUIRE_CHANNEL ) )
|
||||
requireChannels.add( gridNode );
|
||||
|
||||
if ( flags.contains( GridFlags.CANNOT_CARRY_COMPRESSED ) )
|
||||
blockDense.add( gridNode );
|
||||
|
||||
repath();
|
||||
}
|
||||
|
||||
@MENetworkEventSubscribe
|
||||
void updateNodReq(MENetworkChannelChanged ev)
|
||||
{
|
||||
IGridNode gridNode = ev.node;
|
||||
|
||||
if ( gridNode.getGridBlock().getFlags().contains( GridFlags.REQUIRE_CHANNEL ) )
|
||||
requireChannels.add( gridNode );
|
||||
else
|
||||
requireChannels.remove( gridNode );
|
||||
|
||||
repath();
|
||||
}
|
||||
|
||||
private void recalcController()
|
||||
{
|
||||
recalculateControllerNextTick = false;
|
||||
ControllerState old = controllerState;
|
||||
|
||||
if ( controllers.isEmpty() )
|
||||
{
|
||||
controllerState = ControllerState.NO_CONTROLLER;
|
||||
}
|
||||
else
|
||||
{
|
||||
IGridNode startingNode = controllers.iterator().next().getGridNode( ForgeDirection.UNKNOWN );
|
||||
if ( startingNode == null )
|
||||
{
|
||||
controllerState = ControllerState.CONTROLLER_CONFLICT;
|
||||
return;
|
||||
}
|
||||
|
||||
DimensionalCoord dc = startingNode.getGridBlock().getLocation();
|
||||
ControllerValidator cv = new ControllerValidator( dc.x, dc.y, dc.z );
|
||||
|
||||
startingNode.beginVisit( cv );
|
||||
|
||||
if ( cv.isValid && cv.found == controllers.size() )
|
||||
controllerState = ControllerState.CONTROLLER_ONLINE;
|
||||
else
|
||||
controllerState = ControllerState.CONTROLLER_CONFLICT;
|
||||
}
|
||||
|
||||
if ( old != controllerState )
|
||||
{
|
||||
myGrid.postEvent( new MENetworkControllerChange() );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ControllerState getControllerState()
|
||||
{
|
||||
return controllerState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNetworkBooting()
|
||||
{
|
||||
return !active.isEmpty() && booting == false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSplit(IGridStorage storageB)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onJoin(IGridStorage storageB)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateGridStorage(IGridStorage storage)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
package appeng.me.cache;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import appeng.api.config.SecurityPermissions;
|
||||
import appeng.api.networking.IGrid;
|
||||
import appeng.api.networking.IGridCache;
|
||||
import appeng.api.networking.IGridHost;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.IGridStorage;
|
||||
import appeng.api.networking.events.MENetworkEventSubscribe;
|
||||
import appeng.api.networking.events.MENetworkSecurityChange;
|
||||
import appeng.api.networking.security.ISecurityGrid;
|
||||
import appeng.api.networking.security.ISecurityProvider;
|
||||
import appeng.core.WorldSettings;
|
||||
import appeng.me.GridNode;
|
||||
|
||||
public class SecurityCache implements IGridCache, ISecurityGrid
|
||||
{
|
||||
|
||||
final private List<ISecurityProvider> securityProvider = new ArrayList();
|
||||
final private HashMap<Integer, EnumSet<SecurityPermissions>> playerPerms = new HashMap<Integer, EnumSet<SecurityPermissions>>();
|
||||
|
||||
public SecurityCache(IGrid g) {
|
||||
myGrid = g;
|
||||
}
|
||||
|
||||
private long securityKey = -1;
|
||||
public final IGrid myGrid;
|
||||
|
||||
@MENetworkEventSubscribe
|
||||
public void updatePermissions(MENetworkSecurityChange ev)
|
||||
{
|
||||
playerPerms.clear();
|
||||
if ( securityProvider.isEmpty() )
|
||||
return;
|
||||
|
||||
securityProvider.get( 0 ).readPermissions( playerPerms );
|
||||
}
|
||||
|
||||
public long getSecurityKey()
|
||||
{
|
||||
return securityKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable()
|
||||
{
|
||||
return securityProvider.size() == 1 && securityProvider.get( 0 ).isSecurityEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(EntityPlayer player, SecurityPermissions perm)
|
||||
{
|
||||
return hasPermission( player == null ? -1 : WorldSettings.getInstance().getPlayerID( player.getGameProfile() ), perm );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(int playerID, SecurityPermissions perm)
|
||||
{
|
||||
if ( isAvailable() )
|
||||
{
|
||||
EnumSet<SecurityPermissions> perms = playerPerms.get( playerID );
|
||||
|
||||
if ( perms == null )
|
||||
{
|
||||
if ( playerID == -1 ) // no default?
|
||||
return false;
|
||||
else
|
||||
return hasPermission( -1, perm );
|
||||
}
|
||||
|
||||
return perms.contains( perm );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void updateSecurityKey()
|
||||
{
|
||||
long lastCode = securityKey;
|
||||
|
||||
if ( securityProvider.size() == 1 )
|
||||
securityKey = securityProvider.get( 0 ).getSecurityKey();
|
||||
else
|
||||
securityKey = -1;
|
||||
|
||||
if ( lastCode != securityKey )
|
||||
{
|
||||
myGrid.postEvent( new MENetworkSecurityChange() );
|
||||
for (IGridNode n : myGrid.getNodes())
|
||||
((GridNode) n).lastSecurityKey = securityKey;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNode(IGridNode gridNode, IGridHost machine)
|
||||
{
|
||||
if ( machine instanceof ISecurityProvider )
|
||||
{
|
||||
securityProvider.remove( (ISecurityProvider) machine );
|
||||
updateSecurityKey();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNode(IGridNode gridNode, IGridHost machine)
|
||||
{
|
||||
if ( machine instanceof ISecurityProvider )
|
||||
{
|
||||
securityProvider.add( (ISecurityProvider) machine );
|
||||
updateSecurityKey();
|
||||
}
|
||||
else
|
||||
((GridNode) gridNode).lastSecurityKey = securityKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdateTick()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSplit(IGridStorage destinationStorage)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onJoin(IGridStorage sourceStorage)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateGridStorage(IGridStorage destinationStorage)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOwner()
|
||||
{
|
||||
if ( isAvailable() )
|
||||
return securityProvider.get( 0 ).getOwner();
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
package appeng.me.cache;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import appeng.api.networking.IGrid;
|
||||
import appeng.api.networking.IGridCache;
|
||||
import appeng.api.networking.IGridHost;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.IGridStorage;
|
||||
import appeng.api.networking.events.MENetworkBootingStatusChange;
|
||||
import appeng.api.networking.events.MENetworkEventSubscribe;
|
||||
import appeng.api.networking.spatial.ISpatialCache;
|
||||
import appeng.api.util.DimensionalCoord;
|
||||
import appeng.api.util.IReadOnlyCollection;
|
||||
import appeng.core.AEConfig;
|
||||
import appeng.me.cluster.implementations.SpatialPylonCluster;
|
||||
import appeng.tile.spatial.TileSpatialIOPort;
|
||||
import appeng.tile.spatial.TileSpatialPylon;
|
||||
|
||||
public class SpatialPylonCache implements IGridCache, ISpatialCache
|
||||
{
|
||||
|
||||
long powerRequired = 0;
|
||||
double efficiency = 0.0;
|
||||
|
||||
DimensionalCoord captureMin;
|
||||
DimensionalCoord captureMax;
|
||||
boolean isValid = false;
|
||||
|
||||
List<TileSpatialIOPort> ioPorts = new LinkedList();
|
||||
HashMap<SpatialPylonCluster, SpatialPylonCluster> clusters = new HashMap();
|
||||
|
||||
boolean needsUpdate = false;
|
||||
|
||||
final IGrid myGrid;
|
||||
|
||||
public SpatialPylonCache(IGrid g) {
|
||||
myGrid = g;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long requiredPower()
|
||||
{
|
||||
return powerRequired;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRegion()
|
||||
{
|
||||
return captureMin != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidRegion()
|
||||
{
|
||||
return hasRegion() && isValid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DimensionalCoord getMin()
|
||||
{
|
||||
return captureMin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DimensionalCoord getMax()
|
||||
{
|
||||
return captureMax;
|
||||
}
|
||||
|
||||
public void reset(IGrid grid)
|
||||
{
|
||||
int reqX = 0;
|
||||
int reqY = 0;
|
||||
int reqZ = 0;
|
||||
int requirePylonBlocks = 1;
|
||||
|
||||
double minPower = 0;
|
||||
double maxPower = 0;
|
||||
|
||||
clusters = new HashMap();
|
||||
ioPorts = new LinkedList();
|
||||
|
||||
for (IGridNode gm : grid.getMachines( TileSpatialIOPort.class ))
|
||||
{
|
||||
ioPorts.add( (TileSpatialIOPort) gm.getMachine() );
|
||||
}
|
||||
|
||||
IReadOnlyCollection<IGridNode> set = grid.getMachines( TileSpatialPylon.class );
|
||||
for (IGridNode gm : set)
|
||||
{
|
||||
if ( gm.meetsChannelRequirements() )
|
||||
{
|
||||
SpatialPylonCluster c = ((TileSpatialPylon) gm.getMachine()).getCluster();
|
||||
if ( c != null )
|
||||
clusters.put( c, c );
|
||||
}
|
||||
}
|
||||
|
||||
captureMax = null;
|
||||
captureMin = null;
|
||||
isValid = true;
|
||||
|
||||
int pylonBlocks = 0;
|
||||
for (SpatialPylonCluster cl : clusters.values())
|
||||
{
|
||||
if ( captureMax == null )
|
||||
captureMax = cl.max.copy();
|
||||
if ( captureMin == null )
|
||||
captureMin = cl.min.copy();
|
||||
|
||||
pylonBlocks += cl.tileCount();
|
||||
|
||||
captureMin.x = Math.min( captureMin.x, cl.min.x );
|
||||
captureMin.y = Math.min( captureMin.y, cl.min.y );
|
||||
captureMin.z = Math.min( captureMin.z, cl.min.z );
|
||||
|
||||
captureMax.x = Math.max( captureMax.x, cl.max.x );
|
||||
captureMax.y = Math.max( captureMax.y, cl.max.y );
|
||||
captureMax.z = Math.max( captureMax.z, cl.max.z );
|
||||
}
|
||||
|
||||
if ( hasRegion() )
|
||||
{
|
||||
isValid = captureMax.x - captureMin.x > 1 && captureMax.y - captureMin.y > 1 && captureMax.z - captureMin.z > 1;
|
||||
|
||||
for (SpatialPylonCluster cl : clusters.values())
|
||||
{
|
||||
switch (cl.currentAxis)
|
||||
{
|
||||
case X:
|
||||
|
||||
isValid = isValid && ((captureMax.y == cl.min.y || captureMin.y == cl.max.y) || (captureMax.z == cl.min.z || captureMin.z == cl.max.z))
|
||||
&& ((captureMax.y == cl.max.y || captureMin.y == cl.min.y) || (captureMax.z == cl.max.z || captureMin.z == cl.min.z));
|
||||
|
||||
break;
|
||||
case Y:
|
||||
|
||||
isValid = isValid && ((captureMax.x == cl.min.x || captureMin.x == cl.max.x) || (captureMax.z == cl.min.z || captureMin.z == cl.max.z))
|
||||
&& ((captureMax.x == cl.max.x || captureMin.x == cl.min.x) || (captureMax.z == cl.max.z || captureMin.z == cl.min.z));
|
||||
|
||||
break;
|
||||
case Z:
|
||||
|
||||
isValid = isValid && ((captureMax.y == cl.min.y || captureMin.y == cl.max.y) || (captureMax.x == cl.min.x || captureMin.x == cl.max.x))
|
||||
&& ((captureMax.y == cl.max.y || captureMin.y == cl.min.y) || (captureMax.x == cl.max.x || captureMin.x == cl.min.x));
|
||||
|
||||
break;
|
||||
case UNFORMED:
|
||||
isValid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
reqX = captureMax.x - captureMin.x;
|
||||
reqY = captureMax.y - captureMin.y;
|
||||
reqZ = captureMax.z - captureMin.z;
|
||||
requirePylonBlocks = Math.max( 6, ((reqX * reqZ + reqX * reqY + reqY * reqZ) * 3) / 8 );
|
||||
|
||||
efficiency = (double) pylonBlocks / (double) requirePylonBlocks;
|
||||
|
||||
if ( efficiency > 1.0 )
|
||||
efficiency = 1.0;
|
||||
if ( efficiency < 0.0 )
|
||||
efficiency = 0.0;
|
||||
|
||||
minPower = (double) reqX * (double) reqY * reqZ * AEConfig.instance.spatialPowerMultiplier;
|
||||
maxPower = Math.pow( minPower, AEConfig.instance.spatialPowerScaler );
|
||||
}
|
||||
|
||||
double affective_efficiency = Math.pow( efficiency, 0.25 );
|
||||
powerRequired = (long) (affective_efficiency * minPower + (1.0 - affective_efficiency) * maxPower);
|
||||
|
||||
for (SpatialPylonCluster cl : clusters.values())
|
||||
{
|
||||
boolean myWasValid = cl.isValid;
|
||||
cl.isValid = isValid;
|
||||
if ( myWasValid != isValid )
|
||||
cl.updateStatus( false );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float currentEfficiency()
|
||||
{
|
||||
return (float) efficiency * 100;
|
||||
}
|
||||
|
||||
@MENetworkEventSubscribe
|
||||
public void bootingRender(MENetworkBootingStatusChange c)
|
||||
{
|
||||
reset( myGrid );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdateTick()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNode(IGridNode node, IGridHost machine)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNode(IGridNode node, IGridHost machine)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSplit(IGridStorage storageB)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onJoin(IGridStorage storageB)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateGridStorage(IGridStorage storage)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+225
@@ -0,0 +1,225 @@
|
||||
package appeng.me.cache;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.PriorityQueue;
|
||||
|
||||
import net.minecraft.crash.CrashReport;
|
||||
import net.minecraft.crash.CrashReportCategory;
|
||||
import net.minecraft.util.ReportedException;
|
||||
import appeng.api.networking.IGrid;
|
||||
import appeng.api.networking.IGridHost;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.IGridStorage;
|
||||
import appeng.api.networking.ticking.IGridTickable;
|
||||
import appeng.api.networking.ticking.ITickManager;
|
||||
import appeng.api.networking.ticking.TickRateModulation;
|
||||
import appeng.api.networking.ticking.TickingRequest;
|
||||
import appeng.me.cache.helpers.TickTracker;
|
||||
|
||||
public class TickManagerCache implements ITickManager
|
||||
{
|
||||
|
||||
private long currentTick = 0;
|
||||
|
||||
final IGrid myGrid;
|
||||
|
||||
public TickManagerCache(IGrid g) {
|
||||
myGrid = g;
|
||||
}
|
||||
|
||||
final HashMap<IGridNode, TickTracker> alertable = new HashMap<IGridNode, TickTracker>();
|
||||
|
||||
final HashMap<IGridNode, TickTracker> sleeping = new HashMap<IGridNode, TickTracker>();
|
||||
final HashMap<IGridNode, TickTracker> awake = new HashMap<IGridNode, TickTracker>();
|
||||
|
||||
final PriorityQueue<TickTracker> upcomingTicks = new PriorityQueue<TickTracker>();
|
||||
|
||||
public long getCurrentTick()
|
||||
{
|
||||
return currentTick;
|
||||
}
|
||||
|
||||
public long getAvgNanoTime(IGridNode node)
|
||||
{
|
||||
TickTracker tt = awake.get( node );
|
||||
|
||||
if ( tt == null )
|
||||
tt = sleeping.get( node );
|
||||
|
||||
if ( tt == null )
|
||||
return -1;
|
||||
|
||||
return tt.getAvgNanos();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdateTick()
|
||||
{
|
||||
TickTracker tt = null;
|
||||
try
|
||||
{
|
||||
currentTick++;
|
||||
while (!upcomingTicks.isEmpty())
|
||||
{
|
||||
tt = upcomingTicks.peek();
|
||||
int diff = (int) (currentTick - tt.lastTick);
|
||||
if ( diff >= tt.current_rate )
|
||||
{
|
||||
// remove tt..
|
||||
upcomingTicks.poll();
|
||||
TickRateModulation mod = tt.gt.tickingRequest( tt.node, diff );
|
||||
|
||||
switch (mod)
|
||||
{
|
||||
case FASTER:
|
||||
tt.setRate( tt.current_rate - 2 );
|
||||
break;
|
||||
case IDLE:
|
||||
tt.setRate( tt.request.maxTickRate );
|
||||
break;
|
||||
case SAME:
|
||||
break;
|
||||
case SLEEP:
|
||||
sleepDevice( tt.node );
|
||||
break;
|
||||
case SLOWER:
|
||||
tt.setRate( tt.current_rate + 1 );
|
||||
break;
|
||||
case URGENT:
|
||||
tt.setRate( 0 );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ( awake.containsKey( tt.node ) )
|
||||
addToQueue( tt );
|
||||
}
|
||||
else
|
||||
return; // done!
|
||||
}
|
||||
}
|
||||
catch( Throwable t )
|
||||
{
|
||||
CrashReport crashreport = CrashReport.makeCrashReport(t, "Ticking GridNode");
|
||||
CrashReportCategory crashreportcategory = crashreport.makeCategory( tt.gt.getClass().getSimpleName() + " being ticked." );
|
||||
tt.addEntityCrashInfo(crashreportcategory);
|
||||
throw new ReportedException(crashreport);
|
||||
}
|
||||
}
|
||||
|
||||
private void addToQueue(TickTracker tt)
|
||||
{
|
||||
tt.lastTick = currentTick;
|
||||
upcomingTicks.add( tt );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean alertDevice(IGridNode node)
|
||||
{
|
||||
TickTracker tt = alertable.get( node );
|
||||
if ( tt == null )
|
||||
return false;
|
||||
// throw new RuntimeException(
|
||||
// "Invalid alerted device, this node is not marked as alertable, or part of this grid." );
|
||||
|
||||
// set to awake, this is for sanity.
|
||||
sleeping.remove( node );
|
||||
awake.put( node, tt );
|
||||
|
||||
// configure sort.
|
||||
tt.lastTick = tt.lastTick - tt.request.maxTickRate;
|
||||
tt.current_rate = tt.request.minTickRate;
|
||||
|
||||
// prevent dupes and tick build up.
|
||||
upcomingTicks.remove( tt );
|
||||
upcomingTicks.add( tt );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sleepDevice(IGridNode node)
|
||||
{
|
||||
if ( awake.containsKey( node ) )
|
||||
{
|
||||
TickTracker gt = awake.get( node );
|
||||
awake.remove( node );
|
||||
sleeping.put( node, gt );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean wakeDevice(IGridNode node)
|
||||
{
|
||||
if ( sleeping.containsKey( node ) )
|
||||
{
|
||||
TickTracker gt = sleeping.get( node );
|
||||
sleeping.remove( node );
|
||||
awake.put( node, gt );
|
||||
addToQueue( gt );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNode(IGridNode gridNode, IGridHost machine)
|
||||
{
|
||||
if ( machine instanceof IGridTickable )
|
||||
{
|
||||
alertable.remove( gridNode );
|
||||
sleeping.remove( gridNode );
|
||||
awake.remove( gridNode );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNode(IGridNode gridNode, IGridHost machine)
|
||||
{
|
||||
if ( machine instanceof IGridTickable )
|
||||
{
|
||||
TickingRequest tr = ((IGridTickable) machine).getTickingRequest( gridNode );
|
||||
if ( tr != null )
|
||||
{
|
||||
TickTracker tt = new TickTracker( tr, gridNode, (IGridTickable) machine, currentTick, this );
|
||||
|
||||
if ( tr.canBeAlerted )
|
||||
alertable.put( gridNode, tt );
|
||||
|
||||
if ( tr.isSleeping )
|
||||
sleeping.put( gridNode, tt );
|
||||
else
|
||||
{
|
||||
awake.put( gridNode, tt );
|
||||
addToQueue( tt );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSplit(IGridStorage storageB)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onJoin(IGridStorage storageB)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateGridStorage(IGridStorage storage)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package appeng.me.cache.helpers;
|
||||
|
||||
import appeng.api.networking.IGridConnection;
|
||||
|
||||
public class ConnectionWrapper
|
||||
{
|
||||
|
||||
public IGridConnection connection;
|
||||
|
||||
public ConnectionWrapper(IGridConnection gc) {
|
||||
connection = gc;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package appeng.me.cache.helpers;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.parts.p2p.PartP2PTunnelME;
|
||||
|
||||
public class Connections implements Callable
|
||||
{
|
||||
|
||||
final private PartP2PTunnelME me;
|
||||
final public HashMap<IGridNode, TunnelConnection> connections = new HashMap();
|
||||
|
||||
public boolean create = false;
|
||||
public boolean destroy = false;
|
||||
|
||||
public Connections(PartP2PTunnelME o) {
|
||||
me = o;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object call() throws Exception
|
||||
{
|
||||
me.updateConnections( this );
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void markDestroy()
|
||||
{
|
||||
create = false;
|
||||
destroy = true;
|
||||
}
|
||||
|
||||
public void markCreate()
|
||||
{
|
||||
create = true;
|
||||
destroy = false;
|
||||
}
|
||||
|
||||
};
|
||||
@@ -0,0 +1,76 @@
|
||||
package appeng.me.cache.helpers;
|
||||
|
||||
import net.minecraft.crash.CrashReportCategory;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.ticking.IGridTickable;
|
||||
import appeng.api.networking.ticking.TickingRequest;
|
||||
import appeng.api.util.DimensionalCoord;
|
||||
import appeng.me.cache.TickManagerCache;
|
||||
import appeng.parts.AEBasePart;
|
||||
|
||||
public class TickTracker implements Comparable<TickTracker>
|
||||
{
|
||||
|
||||
public final TickingRequest request;
|
||||
public final IGridTickable gt;
|
||||
public final IGridNode node;
|
||||
public final TickManagerCache host;
|
||||
|
||||
public long LastFiveTicksTime = 0;
|
||||
|
||||
public long lastTick;
|
||||
public int current_rate;
|
||||
|
||||
public TickTracker(TickingRequest req, IGridNode node, IGridTickable gt, long currentTick, TickManagerCache tickManagerCache) {
|
||||
request = req;
|
||||
this.gt = gt;
|
||||
this.node = node;
|
||||
current_rate = (req.minTickRate + req.maxTickRate) / 2;
|
||||
lastTick = currentTick;
|
||||
host = tickManagerCache;
|
||||
}
|
||||
|
||||
public long getAvgNanos()
|
||||
{
|
||||
return (LastFiveTicksTime / 5);
|
||||
}
|
||||
|
||||
public void setRate(int rate)
|
||||
{
|
||||
current_rate = rate;
|
||||
|
||||
if ( current_rate < request.minTickRate )
|
||||
current_rate = request.minTickRate;
|
||||
|
||||
if ( current_rate > request.maxTickRate )
|
||||
current_rate = request.maxTickRate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(TickTracker t)
|
||||
{
|
||||
int nextTick = (int) ((lastTick - host.getCurrentTick()) + current_rate);
|
||||
int ts_nextTick = (int) ((t.lastTick - host.getCurrentTick()) + t.current_rate);
|
||||
return nextTick - ts_nextTick;
|
||||
}
|
||||
|
||||
public void addEntityCrashInfo(CrashReportCategory crashreportcategory)
|
||||
{
|
||||
if ( gt instanceof AEBasePart )
|
||||
{
|
||||
AEBasePart part = (AEBasePart)gt;
|
||||
part.addEntityCrashInfo( crashreportcategory );
|
||||
}
|
||||
|
||||
crashreportcategory.addCrashSection( "CurrentTickRate", current_rate );
|
||||
crashreportcategory.addCrashSection( "MinTickRate", request.minTickRate );
|
||||
crashreportcategory.addCrashSection( "MaxTickRate", request.maxTickRate );
|
||||
crashreportcategory.addCrashSection( "MachineType", gt.getClass().getName() );
|
||||
crashreportcategory.addCrashSection( "GridBlockType", node.getGridBlock().getClass().getName() );
|
||||
crashreportcategory.addCrashSection( "ConnectedSides", node.getConnectedSides() );
|
||||
|
||||
DimensionalCoord dc = node.getGridBlock().getLocation();
|
||||
if ( dc != null )
|
||||
crashreportcategory.addCrashSection( "Location", dc );
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,47 @@
|
||||
package appeng.me.cache.helpers;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
|
||||
import appeng.parts.p2p.PartP2PTunnel;
|
||||
import appeng.util.iterators.NullIterator;
|
||||
|
||||
public class TunnelCollection<T extends PartP2PTunnel> implements Iterable<T>
|
||||
{
|
||||
|
||||
final Class clz;
|
||||
Collection<T> tunnelsource;
|
||||
|
||||
public TunnelCollection(Collection<T> src, Class c) {
|
||||
tunnelsource = src;
|
||||
clz = c;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterator()
|
||||
{
|
||||
if ( tunnelsource == null )
|
||||
return new NullIterator();
|
||||
return new TunnelIterator( tunnelsource, clz );
|
||||
}
|
||||
|
||||
public void setSource(Collection<T> c)
|
||||
{
|
||||
tunnelsource = c;
|
||||
}
|
||||
|
||||
public boolean isEmpty()
|
||||
{
|
||||
return !iterator().hasNext();
|
||||
}
|
||||
|
||||
public boolean matches(Class<? extends PartP2PTunnel> c)
|
||||
{
|
||||
return clz == c;
|
||||
}
|
||||
|
||||
public Class<? extends PartP2PTunnel> getClz()
|
||||
{
|
||||
return clz;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package appeng.me.cache.helpers;
|
||||
|
||||
import appeng.api.networking.IGridConnection;
|
||||
import appeng.parts.p2p.PartP2PTunnelME;
|
||||
|
||||
public class TunnelConnection
|
||||
{
|
||||
|
||||
final public PartP2PTunnelME tunnel;
|
||||
final public IGridConnection c;
|
||||
|
||||
public TunnelConnection(PartP2PTunnelME t, IGridConnection con) {
|
||||
tunnel = t;
|
||||
c = con;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package appeng.me.cache.helpers;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
|
||||
import appeng.parts.p2p.PartP2PTunnel;
|
||||
|
||||
public class TunnelIterator<T extends PartP2PTunnel> implements Iterator<T>
|
||||
{
|
||||
|
||||
Iterator<T> wrapped;
|
||||
Class targetType;
|
||||
T Next;
|
||||
|
||||
private void findNext()
|
||||
{
|
||||
while (Next == null && wrapped.hasNext())
|
||||
{
|
||||
Next = wrapped.next();
|
||||
if ( !targetType.isInstance( Next ) )
|
||||
Next = null;
|
||||
}
|
||||
}
|
||||
|
||||
public TunnelIterator(Collection<T> tunnelsource, Class clz) {
|
||||
wrapped = tunnelsource.iterator();
|
||||
targetType = clz;
|
||||
findNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext()
|
||||
{
|
||||
findNext();
|
||||
return Next != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next()
|
||||
{
|
||||
T tmp = Next;
|
||||
Next = null;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove()
|
||||
{
|
||||
// no.
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package appeng.me.cluster;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import appeng.api.networking.IGridHost;
|
||||
|
||||
public interface IAECluster
|
||||
{
|
||||
|
||||
void updateStatus(boolean updateGrid);
|
||||
|
||||
void destroy();
|
||||
|
||||
Iterator<IGridHost> getTiles();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package appeng.me.cluster;
|
||||
|
||||
public interface IAEMultiBlock
|
||||
{
|
||||
|
||||
void disconnect(boolean b);
|
||||
|
||||
IAECluster getCluster();
|
||||
|
||||
boolean isValid();
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
package appeng.me.cluster;
|
||||
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.util.ForgeDirection;
|
||||
import appeng.api.util.WorldCoord;
|
||||
import appeng.core.AELog;
|
||||
import appeng.util.Platform;
|
||||
|
||||
public abstract class MBCalculator
|
||||
{
|
||||
|
||||
final private IAEMultiBlock target;
|
||||
|
||||
public MBCalculator(IAEMultiBlock t) {
|
||||
target = t;
|
||||
}
|
||||
|
||||
/**
|
||||
* check if the tile entities are correct for the structure.
|
||||
*
|
||||
* @param te
|
||||
* @return
|
||||
*/
|
||||
public abstract boolean isValidTile(TileEntity te);
|
||||
|
||||
/**
|
||||
* construct the correct cluster, usually very simple.
|
||||
*
|
||||
* @param w
|
||||
* @param min
|
||||
* @param max
|
||||
* @return
|
||||
*/
|
||||
public abstract IAECluster createCluster(World w, WorldCoord min, WorldCoord max);
|
||||
|
||||
/**
|
||||
* configure the mutli-block tiles, most of the important stuff is in here.
|
||||
*
|
||||
* @param c
|
||||
* @param w
|
||||
* @param min
|
||||
* @param max
|
||||
*/
|
||||
public abstract void updateTiles(IAECluster c, World w, WorldCoord min, WorldCoord max);
|
||||
|
||||
/**
|
||||
* disassembles the multi-block.
|
||||
*/
|
||||
public abstract void disconnect();
|
||||
|
||||
/**
|
||||
* verify if the structure is the correct dimensions, or size
|
||||
*
|
||||
* @param min
|
||||
* @param max
|
||||
* @return
|
||||
*/
|
||||
public abstract boolean checkMultiblockScale(WorldCoord min, WorldCoord max);
|
||||
|
||||
public boolean isValidTileAt(World w, int x, int y, int z)
|
||||
{
|
||||
return isValidTile( w.getTileEntity( x, y, z ) );
|
||||
}
|
||||
|
||||
public void calculateMultiblock(World worldObj, WorldCoord loc)
|
||||
{
|
||||
if ( Platform.isClient() )
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
WorldCoord min = loc.copy();
|
||||
WorldCoord max = loc.copy();
|
||||
|
||||
World w = worldObj;
|
||||
|
||||
// find size of MB structure...
|
||||
while (isValidTileAt( w, min.x - 1, min.y, min.z ))
|
||||
min.x--;
|
||||
while (isValidTileAt( w, min.x, min.y - 1, min.z ))
|
||||
min.y--;
|
||||
while (isValidTileAt( w, min.x, min.y, min.z - 1 ))
|
||||
min.z--;
|
||||
while (isValidTileAt( w, max.x + 1, max.y, max.z ))
|
||||
max.x++;
|
||||
while (isValidTileAt( w, max.x, max.y + 1, max.z ))
|
||||
max.y++;
|
||||
while (isValidTileAt( w, max.x, max.y, max.z + 1 ))
|
||||
max.z++;
|
||||
|
||||
if ( checkMultiblockScale( min, max ) )
|
||||
{
|
||||
if ( verifyUnownedRegion( w, min, max ) )
|
||||
{
|
||||
IAECluster c = createCluster( w, min, max );
|
||||
|
||||
try
|
||||
{
|
||||
if ( !verifyInternalStructure( worldObj, min, max ) )
|
||||
{
|
||||
disconnect();
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
boolean updateGrid = false;
|
||||
IAECluster clust = target.getCluster();
|
||||
if ( clust == null )
|
||||
{
|
||||
updateTiles( c, w, min, max );
|
||||
|
||||
updateGrid = true;
|
||||
}
|
||||
else
|
||||
c = clust;
|
||||
|
||||
c.updateStatus( updateGrid );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Throwable err)
|
||||
{
|
||||
AELog.error( err );
|
||||
}
|
||||
|
||||
disconnect();
|
||||
}
|
||||
|
||||
public abstract boolean verifyInternalStructure(World worldObj, WorldCoord min, WorldCoord max);
|
||||
|
||||
public boolean verifyUnownedRegionInner(World w, int minx, int miny, int minz, int maxx, int maxy, int maxz, ForgeDirection side)
|
||||
{
|
||||
switch (side)
|
||||
{
|
||||
case WEST:
|
||||
minx -= 1;
|
||||
maxx = minx;
|
||||
break;
|
||||
case EAST:
|
||||
maxx += 1;
|
||||
minx = maxx;
|
||||
break;
|
||||
case DOWN:
|
||||
miny -= 1;
|
||||
maxy = miny;
|
||||
break;
|
||||
case NORTH:
|
||||
maxz += 1;
|
||||
minz = maxz;
|
||||
break;
|
||||
case SOUTH:
|
||||
minz -= 1;
|
||||
maxz = minz;
|
||||
break;
|
||||
case UP:
|
||||
maxy += 1;
|
||||
miny = maxy;
|
||||
break;
|
||||
case UNKNOWN:
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int x = minx; x <= maxx; x++)
|
||||
{
|
||||
for (int y = miny; y <= maxy; y++)
|
||||
{
|
||||
for (int z = minz; z <= maxz; z++)
|
||||
{
|
||||
TileEntity te = w.getTileEntity( x, y, z );
|
||||
if ( isValidTile( te ) )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean verifyUnownedRegion(World w, WorldCoord min, WorldCoord max)
|
||||
{
|
||||
for (ForgeDirection side : ForgeDirection.VALID_DIRECTIONS)
|
||||
if ( verifyUnownedRegionInner( w, min.x, min.y, min.z, max.x, max.y, max.z, side ) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package appeng.me.cluster.implementations;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.util.ForgeDirection;
|
||||
import appeng.api.networking.IGrid;
|
||||
import appeng.api.networking.IGridHost;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.events.MENetworkCraftingCpuChange;
|
||||
import appeng.api.util.WorldCoord;
|
||||
import appeng.me.cluster.IAECluster;
|
||||
import appeng.me.cluster.IAEMultiBlock;
|
||||
import appeng.me.cluster.MBCalculator;
|
||||
import appeng.tile.crafting.TileCraftingTile;
|
||||
|
||||
public class CraftingCPUCalculator extends MBCalculator
|
||||
{
|
||||
|
||||
final TileCraftingTile tqb;
|
||||
|
||||
public CraftingCPUCalculator(IAEMultiBlock t) {
|
||||
super( t );
|
||||
tqb = (TileCraftingTile) t;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidTile(TileEntity te)
|
||||
{
|
||||
return te instanceof TileCraftingTile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkMultiblockScale(WorldCoord min, WorldCoord max)
|
||||
{
|
||||
if ( max.x - min.x > 16 )
|
||||
return false;
|
||||
|
||||
if ( max.y - min.y > 16 )
|
||||
return false;
|
||||
|
||||
if ( max.z - min.z > 16 )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTiles(IAECluster cl, World w, WorldCoord min, WorldCoord max)
|
||||
{
|
||||
CraftingCPUCluster c = (CraftingCPUCluster) cl;
|
||||
|
||||
for (int x = min.x; x <= max.x; x++)
|
||||
{
|
||||
for (int y = min.y; y <= max.y; y++)
|
||||
{
|
||||
for (int z = min.z; z <= max.z; z++)
|
||||
{
|
||||
TileCraftingTile te = (TileCraftingTile) w.getTileEntity( x, y, z );
|
||||
te.updateStatus( c );
|
||||
c.addTile( te );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c.done();
|
||||
|
||||
Iterator<IGridHost> i = c.getTiles();
|
||||
while (i.hasNext())
|
||||
{
|
||||
IGridHost gh = i.next();
|
||||
IGridNode n = gh.getGridNode( ForgeDirection.UNKNOWN );
|
||||
if ( n != null )
|
||||
{
|
||||
IGrid g = n.getGrid();
|
||||
if ( g != null )
|
||||
{
|
||||
g.postEvent( new MENetworkCraftingCpuChange( n ) );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAECluster createCluster(World w, WorldCoord min, WorldCoord max)
|
||||
{
|
||||
return new CraftingCPUCluster( min, max );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect()
|
||||
{
|
||||
tqb.disconnect( true );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verifyInternalStructure(World w, WorldCoord min, WorldCoord max)
|
||||
{
|
||||
boolean storage = false;
|
||||
|
||||
for (int x = min.x; x <= max.x; x++)
|
||||
{
|
||||
for (int y = min.y; y <= max.y; y++)
|
||||
{
|
||||
for (int z = min.z; z <= max.z; z++)
|
||||
{
|
||||
IAEMultiBlock te = (IAEMultiBlock) w.getTileEntity( x, y, z );
|
||||
|
||||
if ( !te.isValid() )
|
||||
return false;
|
||||
|
||||
if ( !storage && te instanceof TileCraftingTile )
|
||||
storage = ((TileCraftingTile) te).getStorageBytes() > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return storage;
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,130 @@
|
||||
package appeng.me.cluster.implementations;
|
||||
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.world.World;
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.util.WorldCoord;
|
||||
import appeng.me.cluster.IAECluster;
|
||||
import appeng.me.cluster.IAEMultiBlock;
|
||||
import appeng.me.cluster.MBCalculator;
|
||||
import appeng.tile.qnb.TileQuantumBridge;
|
||||
import appeng.util.Platform;
|
||||
|
||||
public class QuantumCalculator extends MBCalculator
|
||||
{
|
||||
|
||||
final private TileQuantumBridge tqb;
|
||||
|
||||
public QuantumCalculator(IAEMultiBlock t) {
|
||||
super( t );
|
||||
tqb = (TileQuantumBridge) t;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidTile(TileEntity te)
|
||||
{
|
||||
return te instanceof TileQuantumBridge;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkMultiblockScale(WorldCoord min, WorldCoord max)
|
||||
{
|
||||
|
||||
if ( (max.x - min.x + 1) * (max.y - min.y + 1) * (max.z - min.z + 1) == 9 )
|
||||
{
|
||||
int ones = ((max.x - min.x) == 0 ? 1 : 0) + ((max.y - min.y) == 0 ? 1 : 0) + ((max.z - min.z) == 0 ? 1 : 0);
|
||||
|
||||
int threes = ((max.x - min.x) == 2 ? 1 : 0) + ((max.y - min.y) == 2 ? 1 : 0) + ((max.z - min.z) == 2 ? 1 : 0);
|
||||
|
||||
return ones == 1 && threes == 2;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTiles(IAECluster cl, World w, WorldCoord min, WorldCoord max)
|
||||
{
|
||||
byte num = 0;
|
||||
byte ringNum = 0;
|
||||
QuantumCluster c = (QuantumCluster) cl;
|
||||
|
||||
for (int x = min.x; x <= max.x; x++)
|
||||
{
|
||||
for (int y = min.y; y <= max.y; y++)
|
||||
{
|
||||
for (int z = min.z; z <= max.z; z++)
|
||||
{
|
||||
TileQuantumBridge te = (TileQuantumBridge) w.getTileEntity( x, y, z );
|
||||
|
||||
byte flags = 0;
|
||||
|
||||
num++;
|
||||
if ( num == 5 )
|
||||
{
|
||||
flags = (byte) (num);
|
||||
c.setCenter( te );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( num == 1 || num == 3 || num == 7 || num == 9 )
|
||||
flags = (byte) (tqb.corner | num);
|
||||
else
|
||||
flags = (byte) (num);
|
||||
c.Ring[ringNum++] = te;
|
||||
}
|
||||
|
||||
te.updateStatus( c, flags, true );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAECluster createCluster(World w, WorldCoord min, WorldCoord max)
|
||||
{
|
||||
return new QuantumCluster( min, max );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect()
|
||||
{
|
||||
tqb.disconnect(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verifyInternalStructure(World w, WorldCoord min, WorldCoord max)
|
||||
{
|
||||
|
||||
byte num = 0;
|
||||
|
||||
for (int x = min.x; x <= max.x; x++)
|
||||
{
|
||||
for (int y = min.y; y <= max.y; y++)
|
||||
{
|
||||
for (int z = min.z; z <= max.z; z++)
|
||||
{
|
||||
IAEMultiBlock te = (IAEMultiBlock) w.getTileEntity( x, y, z );
|
||||
|
||||
if ( !te.isValid() )
|
||||
return false;
|
||||
|
||||
num++;
|
||||
if ( num == 5 )
|
||||
{
|
||||
if ( !Platform.blockAtLocationIs( w, x, y, z, AEApi.instance().blocks().blockQuantumLink ) )
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !Platform.blockAtLocationIs( w, x, y, z, AEApi.instance().blocks().blockQuantumRing ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,259 @@
|
||||
package appeng.me.cluster.implementations;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraftforge.common.DimensionManager;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.common.util.ForgeDirection;
|
||||
import net.minecraftforge.event.world.WorldEvent;
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.events.LocatableEventAnnounce;
|
||||
import appeng.api.events.LocatableEventAnnounce.LocatableEvent;
|
||||
import appeng.api.exceptions.FailedConnection;
|
||||
import appeng.api.features.ILocatable;
|
||||
import appeng.api.networking.IGridHost;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.util.WorldCoord;
|
||||
import appeng.me.cache.helpers.ConnectionWrapper;
|
||||
import appeng.me.cluster.IAECluster;
|
||||
import appeng.tile.qnb.TileQuantumBridge;
|
||||
import appeng.util.iterators.ChainedIterator;
|
||||
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
|
||||
|
||||
public class QuantumCluster implements ILocatable, IAECluster
|
||||
{
|
||||
|
||||
final public WorldCoord min;
|
||||
final public WorldCoord max;
|
||||
public boolean isDestroyed = false;
|
||||
public boolean updateStatus = true;
|
||||
|
||||
boolean registered = false;
|
||||
private long thisSide;
|
||||
private long otherSide;
|
||||
|
||||
ConnectionWrapper connection;
|
||||
|
||||
public TileQuantumBridge Ring[];
|
||||
private TileQuantumBridge center;
|
||||
|
||||
@Override
|
||||
public Iterator<IGridHost> getTiles()
|
||||
{
|
||||
return new ChainedIterator<IGridHost>( Ring[0], Ring[1], Ring[2], Ring[3], Ring[4], Ring[5], Ring[6], Ring[7], center );
|
||||
}
|
||||
|
||||
public void setCenter(TileQuantumBridge c)
|
||||
{
|
||||
registered = true;
|
||||
MinecraftForge.EVENT_BUS.register( this );
|
||||
center = c;
|
||||
}
|
||||
|
||||
public QuantumCluster(WorldCoord _min, WorldCoord _max) {
|
||||
min = _min;
|
||||
max = _max;
|
||||
Ring = new TileQuantumBridge[8];
|
||||
}
|
||||
|
||||
public boolean canUseNode(long qe)
|
||||
{
|
||||
QuantumCluster qc = (QuantumCluster) AEApi.instance().registries().locatable().findLocatableBySerial( qe );
|
||||
if ( qc != null && qc.center instanceof TileQuantumBridge )
|
||||
{
|
||||
World theWorld = qc.getCenter().getWorldObj();
|
||||
if ( !qc.isDestroyed )
|
||||
{
|
||||
Chunk c = theWorld.getChunkFromBlockCoords( qc.center.xCoord, qc.center.zCoord );
|
||||
if ( c.isChunkLoaded )
|
||||
{
|
||||
int id = theWorld.provider.dimensionId;
|
||||
World cur = DimensionManager.getWorld( id );
|
||||
|
||||
TileEntity te = theWorld.getTileEntity( qc.center.xCoord, qc.center.yCoord, qc.center.zCoord );
|
||||
return te != qc.center || theWorld != cur;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void onUnload(WorldEvent.Unload e)
|
||||
{
|
||||
if ( center.getWorldObj() == e.world )
|
||||
{
|
||||
updateStatus = false;
|
||||
destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateStatus(boolean updateGrid)
|
||||
{
|
||||
long qe;
|
||||
|
||||
qe = center.getQEDest();
|
||||
|
||||
if ( thisSide != qe && thisSide != -qe )
|
||||
{
|
||||
if ( qe != 0 )
|
||||
{
|
||||
if ( thisSide != 0 )
|
||||
MinecraftForge.EVENT_BUS.post( new LocatableEventAnnounce( this, LocatableEvent.Unregister ) );
|
||||
|
||||
if ( canUseNode( -qe ) )
|
||||
{
|
||||
otherSide = qe;
|
||||
thisSide = -qe;
|
||||
}
|
||||
else if ( canUseNode( qe ) )
|
||||
{
|
||||
thisSide = qe;
|
||||
otherSide = -qe;
|
||||
}
|
||||
|
||||
MinecraftForge.EVENT_BUS.post( new LocatableEventAnnounce( this, LocatableEvent.Register ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
MinecraftForge.EVENT_BUS.post( new LocatableEventAnnounce( this, LocatableEvent.Unregister ) );
|
||||
|
||||
otherSide = 0;
|
||||
thisSide = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Object myOtherSide = otherSide == 0 ? null : AEApi.instance().registries().locatable().findLocatableBySerial( otherSide );
|
||||
|
||||
boolean shutdown = false;
|
||||
|
||||
if ( myOtherSide instanceof QuantumCluster )
|
||||
{
|
||||
QuantumCluster sideA = (QuantumCluster) this;
|
||||
QuantumCluster sideB = (QuantumCluster) myOtherSide;
|
||||
|
||||
if ( sideA.isActive() && sideB.isActive() )
|
||||
{
|
||||
if ( connection != null && connection.connection != null )
|
||||
{
|
||||
IGridNode a = connection.connection.a();
|
||||
IGridNode b = connection.connection.b();
|
||||
IGridNode sa = sideA.getNode();
|
||||
IGridNode sb = sideB.getNode();
|
||||
if ( (a == sa || b == sa) && (a == sb || b == sb) )
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if ( sideA.connection != null )
|
||||
{
|
||||
if ( sideA.connection.connection != null )
|
||||
{
|
||||
sideA.connection.connection.destroy();
|
||||
sideA.connection = new ConnectionWrapper( null );
|
||||
}
|
||||
}
|
||||
|
||||
if ( sideB.connection != null )
|
||||
{
|
||||
if ( sideB.connection.connection != null )
|
||||
{
|
||||
sideB.connection.connection.destroy();
|
||||
sideB.connection = new ConnectionWrapper( null );
|
||||
}
|
||||
}
|
||||
|
||||
sideA.connection = sideB.connection = new ConnectionWrapper( AEApi.instance().createGridConnection( sideA.getNode(), sideB.getNode() ) );
|
||||
}
|
||||
catch (FailedConnection e)
|
||||
{
|
||||
// :(
|
||||
}
|
||||
}
|
||||
else
|
||||
shutdown = true;
|
||||
}
|
||||
else
|
||||
shutdown = true;
|
||||
|
||||
if ( shutdown && connection != null )
|
||||
{
|
||||
if ( connection.connection != null )
|
||||
{
|
||||
connection.connection.destroy();
|
||||
connection.connection = null;
|
||||
connection = new ConnectionWrapper( null );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy()
|
||||
{
|
||||
if ( isDestroyed )
|
||||
return;
|
||||
isDestroyed = true;
|
||||
|
||||
if ( registered )
|
||||
{
|
||||
MinecraftForge.EVENT_BUS.unregister( this );
|
||||
registered = false;
|
||||
}
|
||||
|
||||
if ( getLocatableSerial() != 0 )
|
||||
{
|
||||
updateStatus( true );
|
||||
MinecraftForge.EVENT_BUS.post( new LocatableEventAnnounce( this, LocatableEvent.Unregister ) );
|
||||
}
|
||||
|
||||
center.updateStatus( null, (byte) -1, updateStatus );
|
||||
|
||||
for (TileQuantumBridge r : Ring)
|
||||
{
|
||||
r.updateStatus( null, (byte) -1, updateStatus );
|
||||
}
|
||||
|
||||
center = null;
|
||||
Ring = new TileQuantumBridge[8];
|
||||
}
|
||||
|
||||
public boolean isCorner(TileQuantumBridge tileQuantumBridge)
|
||||
{
|
||||
return Ring[0] == tileQuantumBridge || Ring[2] == tileQuantumBridge || Ring[4] == tileQuantumBridge || Ring[6] == tileQuantumBridge;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLocatableSerial()
|
||||
{
|
||||
return thisSide;
|
||||
}
|
||||
|
||||
public TileQuantumBridge getCenter()
|
||||
{
|
||||
return center;
|
||||
}
|
||||
|
||||
public boolean hasQES()
|
||||
{
|
||||
return getLocatableSerial() != 0;
|
||||
}
|
||||
|
||||
private IGridNode getNode()
|
||||
{
|
||||
return center.getGridNode( ForgeDirection.UNKNOWN );
|
||||
}
|
||||
|
||||
private boolean isActive()
|
||||
{
|
||||
if ( isDestroyed || !registered )
|
||||
return false;
|
||||
|
||||
return center.isPowered() && hasQES();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package appeng.me.cluster.implementations;
|
||||
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.world.World;
|
||||
import appeng.api.util.DimensionalCoord;
|
||||
import appeng.api.util.WorldCoord;
|
||||
import appeng.me.cluster.IAECluster;
|
||||
import appeng.me.cluster.IAEMultiBlock;
|
||||
import appeng.me.cluster.MBCalculator;
|
||||
import appeng.tile.spatial.TileSpatialPylon;
|
||||
|
||||
public class SpatialPylonCalculator extends MBCalculator
|
||||
{
|
||||
|
||||
private final TileSpatialPylon tqb;
|
||||
|
||||
public SpatialPylonCalculator(IAEMultiBlock t) {
|
||||
super( t );
|
||||
tqb = (TileSpatialPylon) t;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidTile(TileEntity te)
|
||||
{
|
||||
return te instanceof TileSpatialPylon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkMultiblockScale(WorldCoord min, WorldCoord max)
|
||||
{
|
||||
return (min.x == max.x && min.y == max.y && min.z != max.z) || (min.x == max.x && min.y != max.y && min.z == max.z) || (min.x != max.x && min.y == max.y && min.z == max.z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTiles(IAECluster cl, World w, WorldCoord min, WorldCoord max)
|
||||
{
|
||||
SpatialPylonCluster c = (SpatialPylonCluster) cl;
|
||||
|
||||
for (int x = min.x; x <= max.x; x++)
|
||||
{
|
||||
for (int y = min.y; y <= max.y; y++)
|
||||
{
|
||||
for (int z = min.z; z <= max.z; z++)
|
||||
{
|
||||
TileSpatialPylon te = (TileSpatialPylon) w.getTileEntity( x, y, z );
|
||||
te.updateStatus( c );
|
||||
c.line.add( (te) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAECluster createCluster(World w, WorldCoord min, WorldCoord max)
|
||||
{
|
||||
return new SpatialPylonCluster( new DimensionalCoord( w, min.x, min.y, min.z ), new DimensionalCoord( w, max.x, max.y, max.z ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect()
|
||||
{
|
||||
tqb.disconnect(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verifyInternalStructure(World w, WorldCoord min, WorldCoord max)
|
||||
{
|
||||
|
||||
for (int x = min.x; x <= max.x; x++)
|
||||
{
|
||||
for (int y = min.y; y <= max.y; y++)
|
||||
{
|
||||
for (int z = min.z; z <= max.z; z++)
|
||||
{
|
||||
IAEMultiBlock te = (IAEMultiBlock) w.getTileEntity( x, y, z );
|
||||
|
||||
if ( !te.isValid() )
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package appeng.me.cluster.implementations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import appeng.api.networking.IGridHost;
|
||||
import appeng.api.util.DimensionalCoord;
|
||||
import appeng.me.cluster.IAECluster;
|
||||
import appeng.tile.spatial.TileSpatialPylon;
|
||||
|
||||
public class SpatialPylonCluster implements IAECluster
|
||||
{
|
||||
|
||||
public enum Axis
|
||||
{
|
||||
X, Y, Z, UNFORMED
|
||||
};
|
||||
|
||||
final public DimensionalCoord min;
|
||||
final public DimensionalCoord max;
|
||||
public boolean isDestroyed = false;
|
||||
|
||||
public Axis currentAxis = Axis.UNFORMED;
|
||||
|
||||
final List<TileSpatialPylon> line = new ArrayList();
|
||||
public boolean isValid;
|
||||
public boolean hasPower;
|
||||
public boolean hasChannel;
|
||||
|
||||
public SpatialPylonCluster(DimensionalCoord _min, DimensionalCoord _max) {
|
||||
min = _min.copy();
|
||||
max = _max.copy();
|
||||
|
||||
if ( min.x != max.x )
|
||||
currentAxis = Axis.X;
|
||||
else if ( min.y != max.y )
|
||||
currentAxis = Axis.Y;
|
||||
else if ( min.z != max.z )
|
||||
currentAxis = Axis.Z;
|
||||
else
|
||||
currentAxis = Axis.UNFORMED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateStatus(boolean updateGrid)
|
||||
{
|
||||
for (TileSpatialPylon r : line)
|
||||
{
|
||||
r.recalculateDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy()
|
||||
{
|
||||
|
||||
if ( isDestroyed )
|
||||
return;
|
||||
isDestroyed = true;
|
||||
|
||||
for (TileSpatialPylon r : line)
|
||||
{
|
||||
r.updateStatus( null );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public int tileCount()
|
||||
{
|
||||
return line.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<IGridHost> getTiles()
|
||||
{
|
||||
return (Iterator) line.iterator();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package appeng.me.energy;
|
||||
|
||||
import appeng.api.networking.energy.IEnergyWatcher;
|
||||
import appeng.util.ItemSorters;
|
||||
|
||||
public class EnergyThreshold implements Comparable<EnergyThreshold>
|
||||
{
|
||||
|
||||
public final double Limit;
|
||||
public final IEnergyWatcher watcher;
|
||||
final int hash;
|
||||
|
||||
public EnergyThreshold(double lim, IEnergyWatcher wat) {
|
||||
Limit = lim;
|
||||
watcher = wat;
|
||||
|
||||
if ( watcher != null )
|
||||
hash = watcher.hashCode() ^ ((Double) lim).hashCode();
|
||||
else
|
||||
hash = ((Double) lim).hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(EnergyThreshold o)
|
||||
{
|
||||
return ItemSorters.compareDouble( Limit, o.Limit );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
package appeng.me.energy;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
|
||||
import appeng.api.networking.energy.IEnergyWatcher;
|
||||
import appeng.api.networking.energy.IEnergyWatcherHost;
|
||||
import appeng.me.cache.EnergyGridCache;
|
||||
|
||||
/**
|
||||
* Maintain my interests, and a global watch list, they should always be fully synchronized.
|
||||
*/
|
||||
public class EnergyWatcher implements IEnergyWatcher
|
||||
{
|
||||
|
||||
class EnergyWatcherIterator implements Iterator<Double>
|
||||
{
|
||||
|
||||
final EnergyWatcher watcher;
|
||||
final Iterator<EnergyThreshold> interestIterator;
|
||||
EnergyThreshold myLast;
|
||||
|
||||
public EnergyWatcherIterator(EnergyWatcher parent, Iterator<EnergyThreshold> i) {
|
||||
watcher = parent;
|
||||
interestIterator = i;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext()
|
||||
{
|
||||
return interestIterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double next()
|
||||
{
|
||||
myLast = interestIterator.next();
|
||||
return myLast.Limit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove()
|
||||
{
|
||||
gsc.interests.remove( myLast );
|
||||
interestIterator.remove();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
EnergyGridCache gsc;
|
||||
IEnergyWatcherHost myObject;
|
||||
HashSet<EnergyThreshold> myInterests = new HashSet();
|
||||
|
||||
public void post(EnergyGridCache energyGridCache)
|
||||
{
|
||||
myObject.onThresholdPass( energyGridCache );
|
||||
}
|
||||
|
||||
public EnergyWatcher(EnergyGridCache cache, IEnergyWatcherHost host) {
|
||||
gsc = cache;
|
||||
myObject = host;
|
||||
}
|
||||
|
||||
public IEnergyWatcherHost getHost()
|
||||
{
|
||||
return myObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(Double e)
|
||||
{
|
||||
if ( myInterests.contains( e ) )
|
||||
return false;
|
||||
|
||||
EnergyThreshold eh = new EnergyThreshold( e, this );
|
||||
return gsc.interests.add( eh ) && myInterests.add( eh );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends Double> c)
|
||||
{
|
||||
boolean didChange = false;
|
||||
|
||||
for (Double o : c)
|
||||
didChange = add( o ) || didChange;
|
||||
|
||||
return didChange;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear()
|
||||
{
|
||||
Iterator<EnergyThreshold> i = myInterests.iterator();
|
||||
while (i.hasNext())
|
||||
{
|
||||
gsc.interests.remove( i.next() );
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o)
|
||||
{
|
||||
return myInterests.contains( o );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> c)
|
||||
{
|
||||
return myInterests.containsAll( c );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty()
|
||||
{
|
||||
return myInterests.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Double> iterator()
|
||||
{
|
||||
return new EnergyWatcherIterator( this, myInterests.iterator() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o)
|
||||
{
|
||||
EnergyThreshold eh = new EnergyThreshold( (Double) o, this );
|
||||
return myInterests.remove( eh ) && gsc.interests.remove( eh );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c)
|
||||
{
|
||||
boolean didSomething = false;
|
||||
for (Object o : c)
|
||||
didSomething = remove( o ) || didSomething;
|
||||
return didSomething;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> c)
|
||||
{
|
||||
boolean changed = false;
|
||||
Iterator<Double> i = iterator();
|
||||
|
||||
while (i.hasNext())
|
||||
{
|
||||
if ( !c.contains( i.next() ) )
|
||||
{
|
||||
i.remove();
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size()
|
||||
{
|
||||
return myInterests.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray()
|
||||
{
|
||||
return myInterests.toArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T[] toArray(T[] a)
|
||||
{
|
||||
return myInterests.toArray( a );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,376 @@
|
||||
package appeng.me.helpers;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraftforge.common.util.ForgeDirection;
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.networking.GridFlags;
|
||||
import appeng.api.networking.GridNotification;
|
||||
import appeng.api.networking.IGrid;
|
||||
import appeng.api.networking.IGridBlock;
|
||||
import appeng.api.networking.IGridHost;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.crafting.ICraftingGrid;
|
||||
import appeng.api.networking.energy.IEnergyGrid;
|
||||
import appeng.api.networking.events.MENetworkPowerIdleChange;
|
||||
import appeng.api.networking.pathing.IPathingGrid;
|
||||
import appeng.api.networking.security.ISecurityGrid;
|
||||
import appeng.api.networking.storage.IStorageGrid;
|
||||
import appeng.api.networking.ticking.ITickManager;
|
||||
import appeng.api.util.AEColor;
|
||||
import appeng.api.util.DimensionalCoord;
|
||||
import appeng.api.util.IOrientable;
|
||||
import appeng.core.WorldSettings;
|
||||
import appeng.hooks.TickHandler;
|
||||
import appeng.me.GridAccessException;
|
||||
import appeng.me.cache.P2PCache;
|
||||
import appeng.parts.networking.PartCable;
|
||||
import appeng.tile.AEBaseTile;
|
||||
import appeng.util.Platform;
|
||||
|
||||
public class AENetworkProxy implements IGridBlock
|
||||
{
|
||||
|
||||
final private IGridProxyable gp;
|
||||
final private boolean worldNode;
|
||||
|
||||
private ItemStack myRepInstance;
|
||||
|
||||
private boolean isReady = false;
|
||||
private IGridNode node = null;
|
||||
|
||||
private EnumSet<ForgeDirection> validSides;
|
||||
public AEColor myColor = AEColor.Transparent;
|
||||
|
||||
private EnumSet<GridFlags> flags = EnumSet.noneOf( GridFlags.class );
|
||||
private double idleDraw = 1.0;
|
||||
|
||||
final private String nbtName; // name
|
||||
NBTTagCompound data = null; // input
|
||||
|
||||
private EntityPlayer owner;
|
||||
|
||||
@Override
|
||||
public ItemStack getMachineRepresentation()
|
||||
{
|
||||
return myRepInstance;
|
||||
}
|
||||
|
||||
public void setVisualRepresentation(ItemStack is)
|
||||
{
|
||||
myRepInstance = is;
|
||||
}
|
||||
|
||||
public AENetworkProxy(IGridProxyable te, String nbtName, ItemStack visual, boolean inWorld) {
|
||||
this.gp = te;
|
||||
this.nbtName = nbtName;
|
||||
worldNode = inWorld;
|
||||
myRepInstance = visual;
|
||||
validSides = EnumSet.allOf( ForgeDirection.class );
|
||||
}
|
||||
|
||||
public void writeToNBT(NBTTagCompound tag)
|
||||
{
|
||||
if ( node != null )
|
||||
node.saveToNBT( nbtName, tag );
|
||||
}
|
||||
|
||||
public void readFromNBT(NBTTagCompound tag)
|
||||
{
|
||||
data = tag;
|
||||
if ( node != null && data != null )
|
||||
{
|
||||
node.loadFromNBT( nbtName, data );
|
||||
data = null;
|
||||
}
|
||||
else if ( node != null && owner != null )
|
||||
{
|
||||
node.setPlayerID( WorldSettings.getInstance().getPlayerID( owner.getGameProfile() ) );
|
||||
owner = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DimensionalCoord getLocation()
|
||||
{
|
||||
return gp.getLocation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AEColor getGridColor()
|
||||
{
|
||||
return myColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGridNotification(GridNotification notification)
|
||||
{
|
||||
if ( gp instanceof PartCable )
|
||||
((PartCable) gp).markForUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNetworkStatus(IGrid grid, int channelsInUse)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<ForgeDirection> getConnectableSides()
|
||||
{
|
||||
return validSides;
|
||||
}
|
||||
|
||||
public void setValidSides(EnumSet<ForgeDirection> validSides)
|
||||
{
|
||||
this.validSides = validSides;
|
||||
if ( node != null )
|
||||
node.updateState();
|
||||
}
|
||||
|
||||
public IGridNode getNode()
|
||||
{
|
||||
if ( node == null && Platform.isServer() && isReady )
|
||||
{
|
||||
node = AEApi.instance().createGridNode( this );
|
||||
readFromNBT( data );
|
||||
node.updateState();
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
public void validate()
|
||||
{
|
||||
if ( gp instanceof AEBaseTile )
|
||||
TickHandler.instance.addInit( (AEBaseTile) gp );
|
||||
}
|
||||
|
||||
public void onChunkUnload()
|
||||
{
|
||||
isReady = false;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void invalidate()
|
||||
{
|
||||
isReady = false;
|
||||
if ( node != null )
|
||||
{
|
||||
node.destroy();
|
||||
node = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void onReady()
|
||||
{
|
||||
isReady = true;
|
||||
|
||||
// send orientation based directionality to the node.
|
||||
if ( gp instanceof IOrientable )
|
||||
{
|
||||
IOrientable ori = (IOrientable) gp;
|
||||
if ( ori.canBeRotated() )
|
||||
ori.setOrientation( ori.getForward(), ori.getUp() );
|
||||
}
|
||||
|
||||
getNode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGridHost getMachine()
|
||||
{
|
||||
return gp;
|
||||
}
|
||||
|
||||
/**
|
||||
* short cut!
|
||||
*
|
||||
* @return
|
||||
* @throws GridAccessException
|
||||
*/
|
||||
public IGrid getGrid() throws GridAccessException
|
||||
{
|
||||
if ( node == null )
|
||||
throw new GridAccessException();
|
||||
IGrid grid = node.getGrid();
|
||||
if ( grid == null )
|
||||
throw new GridAccessException();
|
||||
return grid;
|
||||
}
|
||||
|
||||
public IEnergyGrid getEnergy() throws GridAccessException
|
||||
{
|
||||
IGrid grid = getGrid();
|
||||
if ( grid == null )
|
||||
throw new GridAccessException();
|
||||
IEnergyGrid eg = grid.getCache( IEnergyGrid.class );
|
||||
if ( eg == null )
|
||||
throw new GridAccessException();
|
||||
return eg;
|
||||
}
|
||||
|
||||
public IPathingGrid getPath() throws GridAccessException
|
||||
{
|
||||
IGrid grid = getGrid();
|
||||
if ( grid == null )
|
||||
throw new GridAccessException();
|
||||
IPathingGrid pg = grid.getCache( IPathingGrid.class );
|
||||
if ( pg == null )
|
||||
throw new GridAccessException();
|
||||
return pg;
|
||||
}
|
||||
|
||||
public ITickManager getTick() throws GridAccessException
|
||||
{
|
||||
IGrid grid = getGrid();
|
||||
if ( grid == null )
|
||||
throw new GridAccessException();
|
||||
ITickManager pg = grid.getCache( ITickManager.class );
|
||||
if ( pg == null )
|
||||
throw new GridAccessException();
|
||||
return pg;
|
||||
}
|
||||
|
||||
public IStorageGrid getStorage() throws GridAccessException
|
||||
{
|
||||
IGrid grid = getGrid();
|
||||
if ( grid == null )
|
||||
throw new GridAccessException();
|
||||
|
||||
IStorageGrid pg = grid.getCache( IStorageGrid.class );
|
||||
|
||||
if ( pg == null )
|
||||
throw new GridAccessException();
|
||||
|
||||
return pg;
|
||||
}
|
||||
|
||||
public P2PCache getP2P() throws GridAccessException
|
||||
{
|
||||
IGrid grid = getGrid();
|
||||
if ( grid == null )
|
||||
throw new GridAccessException();
|
||||
|
||||
P2PCache pg = grid.getCache( P2PCache.class );
|
||||
|
||||
if ( pg == null )
|
||||
throw new GridAccessException();
|
||||
|
||||
return pg;
|
||||
}
|
||||
|
||||
public ISecurityGrid getSecurity() throws GridAccessException
|
||||
{
|
||||
IGrid grid = getGrid();
|
||||
if ( grid == null )
|
||||
throw new GridAccessException();
|
||||
|
||||
ISecurityGrid sg = grid.getCache( ISecurityGrid.class );
|
||||
|
||||
if ( sg == null )
|
||||
throw new GridAccessException();
|
||||
|
||||
return sg;
|
||||
}
|
||||
|
||||
public ICraftingGrid getCrafting() throws GridAccessException
|
||||
{
|
||||
IGrid grid = getGrid();
|
||||
if ( grid == null )
|
||||
throw new GridAccessException();
|
||||
|
||||
ICraftingGrid sg = grid.getCache( ICraftingGrid.class );
|
||||
|
||||
if ( sg == null )
|
||||
throw new GridAccessException();
|
||||
|
||||
return sg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWorldAccessible()
|
||||
{
|
||||
return worldNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<GridFlags> getFlags()
|
||||
{
|
||||
return flags;
|
||||
}
|
||||
|
||||
public void setFlags(GridFlags... requireChannel)
|
||||
{
|
||||
EnumSet<GridFlags> flags = EnumSet.noneOf( GridFlags.class );
|
||||
|
||||
for (GridFlags gf : requireChannel)
|
||||
flags.add( gf );
|
||||
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getIdlePowerUsage()
|
||||
{
|
||||
return idleDraw;
|
||||
}
|
||||
|
||||
public void setIdlePowerUsage(double idle)
|
||||
{
|
||||
idleDraw = idle;
|
||||
|
||||
if ( node != null )
|
||||
{
|
||||
try
|
||||
{
|
||||
IGrid g = getGrid();
|
||||
g.postEvent( new MENetworkPowerIdleChange( node ) );
|
||||
}
|
||||
catch (GridAccessException e)
|
||||
{
|
||||
// not ready for this yet..
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isReady()
|
||||
{
|
||||
return isReady;
|
||||
}
|
||||
|
||||
public boolean isActive()
|
||||
{
|
||||
if ( node == null )
|
||||
return false;
|
||||
|
||||
return node.isActive();
|
||||
}
|
||||
|
||||
public boolean isPowered()
|
||||
{
|
||||
try
|
||||
{
|
||||
return getEnergy().isNetworkPowered();
|
||||
}
|
||||
catch (GridAccessException e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void gridChanged()
|
||||
{
|
||||
gp.gridChanged();
|
||||
}
|
||||
|
||||
public void setOwner(EntityPlayer player)
|
||||
{
|
||||
owner = player;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package appeng.me.helpers;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import appeng.api.networking.IGridMultiblock;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.me.cluster.IAECluster;
|
||||
import appeng.me.cluster.IAEMultiBlock;
|
||||
import appeng.util.iterators.ChainedIterator;
|
||||
import appeng.util.iterators.ProxyNodeIterator;
|
||||
|
||||
public class AENetworkProxyMultiblock extends AENetworkProxy implements IGridMultiblock
|
||||
{
|
||||
|
||||
IAECluster getCluster()
|
||||
{
|
||||
return ((IAEMultiBlock) getMachine()).getCluster();
|
||||
}
|
||||
|
||||
public AENetworkProxyMultiblock(IGridProxyable te, String nbtName, ItemStack itemStack, boolean inWorld) {
|
||||
super( te, nbtName, itemStack, inWorld );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<IGridNode> getMultiblockNodes()
|
||||
{
|
||||
if ( getCluster() == null )
|
||||
return new ChainedIterator<IGridNode>();
|
||||
|
||||
return new ProxyNodeIterator( getCluster().getTiles() );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package appeng.me.helpers;
|
||||
|
||||
import appeng.api.config.Actionable;
|
||||
import appeng.api.config.PowerMultiplier;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.energy.IEnergySource;
|
||||
|
||||
public class ChannelPowerSrc implements IEnergySource
|
||||
{
|
||||
|
||||
IGridNode node;
|
||||
IEnergySource realSrc;
|
||||
|
||||
public ChannelPowerSrc(IGridNode networkNode, IEnergySource src) {
|
||||
node = networkNode;
|
||||
realSrc = src;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double extractAEPower(double amt, Actionable mode, PowerMultiplier usePowerMultiplier)
|
||||
{
|
||||
if ( node.isActive() )
|
||||
return realSrc.extractAEPower( amt, mode, usePowerMultiplier );
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package appeng.me.helpers;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.Set;
|
||||
|
||||
import appeng.api.storage.data.IAEStack;
|
||||
|
||||
import com.google.common.collect.SetMultimap;
|
||||
|
||||
public class GenericInterestManager<T>
|
||||
{
|
||||
|
||||
class SavedTransactions
|
||||
{
|
||||
|
||||
public final boolean put;
|
||||
public final IAEStack stack;
|
||||
public final T iw;
|
||||
|
||||
public SavedTransactions(boolean putOperation, IAEStack myStack, T watcher) {
|
||||
put = putOperation;
|
||||
stack = myStack;
|
||||
iw = watcher;
|
||||
}
|
||||
};
|
||||
|
||||
private final SetMultimap<IAEStack, T> container;
|
||||
private LinkedList<SavedTransactions> transactions = null;
|
||||
private int transDepth = 0;
|
||||
|
||||
public GenericInterestManager(SetMultimap<IAEStack, T> interests) {
|
||||
container = interests;
|
||||
}
|
||||
|
||||
public void enableTransactions()
|
||||
{
|
||||
if ( transDepth == 0 )
|
||||
transactions = new LinkedList();
|
||||
|
||||
transDepth++;
|
||||
}
|
||||
|
||||
public void disableTransactions()
|
||||
{
|
||||
transDepth--;
|
||||
|
||||
if ( transDepth == 0 )
|
||||
{
|
||||
LinkedList<SavedTransactions> myActions = transactions;
|
||||
transactions = null;
|
||||
|
||||
for (SavedTransactions t : myActions)
|
||||
{
|
||||
if ( t.put )
|
||||
put( t.stack, t.iw );
|
||||
else
|
||||
remove( t.stack, t.iw );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean containsKey(IAEStack stack)
|
||||
{
|
||||
return container.containsKey( stack );
|
||||
}
|
||||
|
||||
public Set<T> get(IAEStack stack)
|
||||
{
|
||||
return container.get( stack );
|
||||
}
|
||||
|
||||
public boolean put(IAEStack stack, T iw)
|
||||
{
|
||||
if ( transactions != null )
|
||||
{
|
||||
transactions.add( new SavedTransactions( true, stack, iw ) );
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return container.put( stack, iw );
|
||||
}
|
||||
|
||||
public boolean remove(IAEStack stack, T iw)
|
||||
{
|
||||
if ( transactions != null )
|
||||
{
|
||||
transactions.add( new SavedTransactions( true, stack, iw ) );
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return container.remove( stack, iw );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package appeng.me.helpers;
|
||||
|
||||
import appeng.api.networking.IGridHost;
|
||||
import appeng.api.util.DimensionalCoord;
|
||||
|
||||
public interface IGridProxyable extends IGridHost
|
||||
{
|
||||
|
||||
AENetworkProxy getProxy();
|
||||
|
||||
DimensionalCoord getLocation();
|
||||
|
||||
void gridChanged();
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package appeng.me.pathfinding;
|
||||
|
||||
import appeng.api.networking.IGridConnectionVisitor;
|
||||
import appeng.api.networking.IGridConnection;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.me.GridConnection;
|
||||
import appeng.me.GridNode;
|
||||
|
||||
public class AdHocChannelUpdater implements IGridConnectionVisitor
|
||||
{
|
||||
|
||||
final private int usedChannels;
|
||||
|
||||
public AdHocChannelUpdater(int used) {
|
||||
usedChannels = used;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visitNode(IGridNode n)
|
||||
{
|
||||
GridNode gn = (GridNode) n;
|
||||
gn.setControllerRoute( null, true );
|
||||
gn.incrementChannelCount( usedChannels );
|
||||
gn.finalizeChannels();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitConnection(IGridConnection gcc)
|
||||
{
|
||||
GridConnection gc = (GridConnection) gcc;
|
||||
gc.setControllerRoute( null, true );
|
||||
gc.incrementChannelCount( usedChannels );
|
||||
gc.finalizeChannels();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package appeng.me.pathfinding;
|
||||
|
||||
import appeng.api.networking.IGridConnectionVisitor;
|
||||
import appeng.api.networking.IGridConnection;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.me.GridConnection;
|
||||
import appeng.me.GridNode;
|
||||
|
||||
public class ControllerChannelUpdater implements IGridConnectionVisitor
|
||||
{
|
||||
|
||||
@Override
|
||||
public boolean visitNode(IGridNode n)
|
||||
{
|
||||
GridNode gn = (GridNode) n;
|
||||
gn.finalizeChannels();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitConnection(IGridConnection gcc)
|
||||
{
|
||||
GridConnection gc = (GridConnection) gcc;
|
||||
gc.finalizeChannels();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package appeng.me.pathfinding;
|
||||
|
||||
import appeng.api.networking.IGridHost;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.IGridVisitor;
|
||||
import appeng.tile.networking.TileController;
|
||||
|
||||
public class ControllerValidator implements IGridVisitor
|
||||
{
|
||||
|
||||
int minX;
|
||||
int minY;
|
||||
int minZ;
|
||||
|
||||
int maxX;
|
||||
int maxY;
|
||||
int maxZ;
|
||||
|
||||
public boolean isValid = true;
|
||||
public int found = 0;
|
||||
|
||||
public ControllerValidator(int x, int y, int z) {
|
||||
minX = x;
|
||||
minY = y;
|
||||
minZ = z;
|
||||
maxX = x;
|
||||
maxY = y;
|
||||
maxZ = z;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visitNode(IGridNode n)
|
||||
{
|
||||
IGridHost host = n.getMachine();
|
||||
if ( isValid && host instanceof TileController )
|
||||
{
|
||||
TileController c = (TileController) host;
|
||||
|
||||
minX = Math.min( c.xCoord, minX );
|
||||
maxX = Math.max( c.xCoord, maxX );
|
||||
minY = Math.min( c.yCoord, minY );
|
||||
maxY = Math.max( c.yCoord, maxY );
|
||||
minZ = Math.min( c.zCoord, minZ );
|
||||
maxZ = Math.max( c.zCoord, maxZ );
|
||||
|
||||
if ( maxX - minX < 7 && maxY - minY < 7 && maxZ - minZ < 7 )
|
||||
{
|
||||
found++;
|
||||
return true;
|
||||
}
|
||||
|
||||
isValid = false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
return isValid;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package appeng.me.pathfinding;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
import appeng.api.networking.GridFlags;
|
||||
import appeng.api.util.IReadOnlyCollection;
|
||||
|
||||
public interface IPathItem
|
||||
{
|
||||
|
||||
IPathItem getControllerRoute();
|
||||
|
||||
void setControllerRoute(IPathItem fast, boolean zeroOut);
|
||||
|
||||
/**
|
||||
* used to determine if the finder can continue.
|
||||
*/
|
||||
boolean canSupportMoreChannels();
|
||||
|
||||
/**
|
||||
* find possible choices for other pathing.
|
||||
*/
|
||||
IReadOnlyCollection<IPathItem> getPossibleOptions();
|
||||
|
||||
/**
|
||||
* add one to the channel count, this is mostly for cables.
|
||||
*/
|
||||
void incrementChannelCount(int usedChannels);
|
||||
|
||||
/**
|
||||
* get the grid flags for this IPathItem.
|
||||
*
|
||||
* @return the flag set.
|
||||
*/
|
||||
public EnumSet<GridFlags> getFlags();
|
||||
|
||||
/**
|
||||
* channels are done, wrap it up.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
void finalizeChannels();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
package appeng.me.pathfinding;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import appeng.api.networking.GridFlags;
|
||||
import appeng.api.networking.IGridMultiblock;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.me.cache.PathGridCache;
|
||||
|
||||
public class PathSegment
|
||||
{
|
||||
|
||||
public boolean isDead;
|
||||
|
||||
static class RouteComplete extends Exception
|
||||
{
|
||||
|
||||
private static final long serialVersionUID = 810456465120286110L;
|
||||
|
||||
};
|
||||
|
||||
PathGridCache pgc;
|
||||
|
||||
public PathSegment(PathGridCache myPGC, List open, Set semiopen, Set closed)
|
||||
{
|
||||
this.open = open;
|
||||
this.semiopen = semiopen;
|
||||
this.closed = closed;
|
||||
pgc = myPGC;
|
||||
isDead = false;
|
||||
}
|
||||
|
||||
List<IPathItem> open;
|
||||
Set<IPathItem> semiopen;
|
||||
Set<IPathItem> closed;
|
||||
|
||||
public boolean step()
|
||||
{
|
||||
List<IPathItem> oldOpen = open;
|
||||
open = new LinkedList();
|
||||
|
||||
for (IPathItem i : oldOpen)
|
||||
{
|
||||
for (IPathItem pi : i.getPossibleOptions())
|
||||
{
|
||||
EnumSet<GridFlags> flags = pi.getFlags();
|
||||
|
||||
if ( !closed.contains( pi ) )
|
||||
{
|
||||
pi.setControllerRoute( i, true );
|
||||
|
||||
if ( flags.contains( GridFlags.REQUIRE_CHANNEL ) )
|
||||
{
|
||||
// close the semi open.
|
||||
if ( !semiopen.contains( pi ) )
|
||||
{
|
||||
boolean worked = false;
|
||||
|
||||
if ( flags.contains( GridFlags.COMPRESSED_CHANNEL ) )
|
||||
worked = useDenseChannel( pi );
|
||||
else
|
||||
worked = useChannel( pi );
|
||||
|
||||
if ( worked && flags.contains( GridFlags.MULTIBLOCK ) )
|
||||
{
|
||||
Iterator<IGridNode> oni = ((IGridMultiblock) ((IGridNode) pi).getGridBlock()).getMultiblockNodes();
|
||||
while (oni.hasNext())
|
||||
{
|
||||
IGridNode otherNodes = oni.next();
|
||||
if ( otherNodes != pi )
|
||||
semiopen.add( (IPathItem) otherNodes );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pi.incrementChannelCount( 1 ); // give a channel.
|
||||
semiopen.remove( pi );
|
||||
}
|
||||
}
|
||||
|
||||
closed.add( pi );
|
||||
open.add( pi );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return open.isEmpty();
|
||||
}
|
||||
|
||||
private boolean useChannel(IPathItem start)
|
||||
{
|
||||
IPathItem pi = start;
|
||||
while (pi != null)
|
||||
{
|
||||
if ( !pi.canSupportMoreChannels() )
|
||||
return false;
|
||||
|
||||
pi = pi.getControllerRoute();
|
||||
}
|
||||
|
||||
pi = start;
|
||||
while (pi != null)
|
||||
{
|
||||
pgc.channelsByBlocks++;
|
||||
pi.incrementChannelCount( 1 );
|
||||
pi = pi.getControllerRoute();
|
||||
}
|
||||
|
||||
pgc.channelsInUse++;
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean useDenseChannel(IPathItem start)
|
||||
{
|
||||
IPathItem pi = start;
|
||||
while (pi != null)
|
||||
{
|
||||
if ( !pi.canSupportMoreChannels() || pi.getFlags().contains( GridFlags.CANNOT_CARRY_COMPRESSED ) )
|
||||
return false;
|
||||
|
||||
pi = pi.getControllerRoute();
|
||||
}
|
||||
|
||||
pi = start;
|
||||
while (pi != null)
|
||||
{
|
||||
pgc.channelsByBlocks++;
|
||||
pi.incrementChannelCount( 1 );
|
||||
pi = pi.getControllerRoute();
|
||||
}
|
||||
|
||||
pgc.channelsInUse++;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package appeng.me.storage;
|
||||
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraftforge.common.util.ForgeDirection;
|
||||
import appeng.api.implementations.tiles.ITileStorageMonitorable;
|
||||
import appeng.api.networking.security.BaseActionSource;
|
||||
import appeng.api.storage.IExternalStorageHandler;
|
||||
import appeng.api.storage.IMEInventory;
|
||||
import appeng.api.storage.IStorageMonitorable;
|
||||
import appeng.api.storage.StorageChannel;
|
||||
import appeng.api.storage.data.IAEFluidStack;
|
||||
import appeng.api.storage.data.IAEItemStack;
|
||||
import appeng.tile.misc.TileCondenser;
|
||||
|
||||
public class AEExternalHandler implements IExternalStorageHandler
|
||||
{
|
||||
|
||||
@Override
|
||||
public boolean canHandle(TileEntity te, ForgeDirection d, StorageChannel channel, BaseActionSource mySrc)
|
||||
{
|
||||
if ( channel == StorageChannel.ITEMS && te instanceof ITileStorageMonitorable )
|
||||
return ((ITileStorageMonitorable) te).getMonitorable( d, mySrc ) != null;
|
||||
|
||||
return te instanceof TileCondenser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IMEInventory getInventory(TileEntity te, ForgeDirection d, StorageChannel channel, BaseActionSource src)
|
||||
{
|
||||
if ( te instanceof TileCondenser )
|
||||
{
|
||||
if ( channel == StorageChannel.ITEMS )
|
||||
return new VoidItemInventory( (TileCondenser) te );
|
||||
else
|
||||
return new VoidFluidInventory( (TileCondenser) te );
|
||||
}
|
||||
|
||||
if ( te instanceof ITileStorageMonitorable )
|
||||
{
|
||||
ITileStorageMonitorable iface = (ITileStorageMonitorable) te;
|
||||
IStorageMonitorable sm = iface.getMonitorable( d, src );
|
||||
|
||||
if ( channel == StorageChannel.ITEMS && sm != null )
|
||||
{
|
||||
IMEInventory<IAEItemStack> ii = sm.getItemInventory();
|
||||
if ( ii != null )
|
||||
return ii;
|
||||
}
|
||||
|
||||
if ( channel == StorageChannel.FLUIDS && sm != null )
|
||||
{
|
||||
IMEInventory<IAEFluidStack> fi = sm.getFluidInventory();
|
||||
if ( fi != null )
|
||||
return fi;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,540 @@
|
||||
package appeng.me.storage;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraftforge.oredict.OreDictionary;
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.config.Actionable;
|
||||
import appeng.api.config.FuzzyMode;
|
||||
import appeng.api.exceptions.AppEngException;
|
||||
import appeng.api.implementations.items.IStorageCell;
|
||||
import appeng.api.networking.security.BaseActionSource;
|
||||
import appeng.api.storage.ICellInventory;
|
||||
import appeng.api.storage.IMEInventory;
|
||||
import appeng.api.storage.IMEInventoryHandler;
|
||||
import appeng.api.storage.ISaveProvider;
|
||||
import appeng.api.storage.StorageChannel;
|
||||
import appeng.api.storage.data.IAEItemStack;
|
||||
import appeng.api.storage.data.IItemList;
|
||||
import appeng.util.Platform;
|
||||
import appeng.util.item.AEItemStack;
|
||||
|
||||
public class CellInventory implements ICellInventory
|
||||
{
|
||||
|
||||
static final String ITEM_TYPE_TAG = "it";
|
||||
static final String ITEM_COUNT_TAG = "ic";
|
||||
static final String ITEM_SLOT = "#";
|
||||
static final String ITEM_SLOTCOUNT = "@";
|
||||
static final String ITEM_PRE_FORMATTED_COUNT = "PF";
|
||||
static final String ITEM_PRE_FORMATTED_SLOT = "PF#";
|
||||
static final String ITEM_PRE_FORMATTED_NAME = "PN";
|
||||
static final String ITEM_PRE_FORMATTED_FUZZY = "FP";
|
||||
|
||||
static protected String[] ITEM_SLOT_ARR;
|
||||
static protected String[] ITEM_SLOTCOUNT_ARR;
|
||||
|
||||
final protected NBTTagCompound tagCompound;
|
||||
protected int MAX_ITEM_TYPES = 63;
|
||||
protected short storedItems = 0;
|
||||
protected int storedItemCount = 0;
|
||||
protected IItemList<IAEItemStack> cellItems;
|
||||
|
||||
protected ItemStack i;
|
||||
protected IStorageCell CellType;
|
||||
|
||||
final protected ISaveProvider container;
|
||||
|
||||
protected CellInventory(NBTTagCompound data, ISaveProvider container) {
|
||||
tagCompound = data;
|
||||
this.container = container;
|
||||
}
|
||||
|
||||
protected void loadCellItems()
|
||||
{
|
||||
if ( cellItems == null )
|
||||
cellItems = AEApi.instance().storage().createItemList();
|
||||
|
||||
cellItems.resetStatus(); // clears totals and stuff.
|
||||
|
||||
int types = (int) getStoredItemTypes();
|
||||
|
||||
for (int x = 0; x < types; x++)
|
||||
{
|
||||
ItemStack t = ItemStack.loadItemStackFromNBT( tagCompound.getCompoundTag( ITEM_SLOT_ARR[x] ) );
|
||||
if ( t != null )
|
||||
{
|
||||
t.stackSize = tagCompound.getInteger( ITEM_SLOTCOUNT_ARR[x] );
|
||||
|
||||
if ( t.stackSize > 0 )
|
||||
{
|
||||
cellItems.add( AEItemStack.create( t ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// cellItems.clean();
|
||||
}
|
||||
|
||||
void saveChanges()
|
||||
{
|
||||
// cellItems.clean();
|
||||
int itemCount = 0;
|
||||
|
||||
// add new pretty stuff...
|
||||
int x = 0;
|
||||
Iterator<IAEItemStack> i = cellItems.iterator();
|
||||
while (i.hasNext())
|
||||
{
|
||||
IAEItemStack v = i.next();
|
||||
itemCount += v.getStackSize();
|
||||
|
||||
NBTBase c = tagCompound.getTag( ITEM_SLOT_ARR[x] );
|
||||
if ( c instanceof NBTTagCompound )
|
||||
v.writeToNBT( (NBTTagCompound) c );
|
||||
else
|
||||
{
|
||||
NBTTagCompound g = new NBTTagCompound();
|
||||
v.writeToNBT( g );
|
||||
tagCompound.setTag( ITEM_SLOT_ARR[x], g );
|
||||
}
|
||||
|
||||
/*
|
||||
* NBTBase tagSlotCount = tagCompound.getTag( ITEM_SLOTCOUNT_ARR[x] ); if ( tagSlotCount instanceof
|
||||
* NBTTagInt ) ((NBTTagInt) tagSlotCount).data = (int) v.getStackSize(); else
|
||||
*/
|
||||
tagCompound.setInteger( ITEM_SLOTCOUNT_ARR[x], (int) v.getStackSize() );
|
||||
|
||||
x++;
|
||||
}
|
||||
|
||||
// NBTBase tagType = tagCompound.getTag( ITEM_TYPE_TAG );
|
||||
// NBTBase tagCount = tagCompound.getTag( ITEM_COUNT_TAG );
|
||||
short oldStoreditems = storedItems;
|
||||
|
||||
/*
|
||||
* if ( tagType instanceof NBTTagShort ) ((NBTTagShort) tagType).data = storedItems = (short) cellItems.size();
|
||||
* else
|
||||
*/
|
||||
tagCompound.setShort( ITEM_TYPE_TAG, storedItems = (short) cellItems.size() );
|
||||
|
||||
/*
|
||||
* if ( tagCount instanceof NBTTagInt ) ((NBTTagInt) tagCount).data = storedItemCount = itemCount; else
|
||||
*/
|
||||
tagCompound.setInteger( ITEM_COUNT_TAG, storedItemCount = itemCount );
|
||||
|
||||
// clean any old crusty stuff...
|
||||
for (; x < oldStoreditems && x < MAX_ITEM_TYPES; x++)
|
||||
{
|
||||
tagCompound.removeTag( ITEM_SLOT_ARR[x] );
|
||||
tagCompound.removeTag( ITEM_SLOTCOUNT_ARR[x] );
|
||||
}
|
||||
|
||||
if ( container != null )
|
||||
container.saveChanges( this );
|
||||
}
|
||||
|
||||
protected CellInventory(ItemStack o, ISaveProvider container) throws AppEngException {
|
||||
if ( ITEM_SLOT_ARR == null )
|
||||
{
|
||||
ITEM_SLOT_ARR = new String[MAX_ITEM_TYPES];
|
||||
ITEM_SLOTCOUNT_ARR = new String[MAX_ITEM_TYPES];
|
||||
|
||||
for (int x = 0; x < MAX_ITEM_TYPES; x++)
|
||||
{
|
||||
ITEM_SLOT_ARR[x] = ITEM_SLOT + x;
|
||||
ITEM_SLOTCOUNT_ARR[x] = ITEM_SLOTCOUNT + x;
|
||||
}
|
||||
}
|
||||
|
||||
if ( o == null )
|
||||
{
|
||||
throw new AppEngException( "ItemStack was used as a cell, but was not a cell!" );
|
||||
}
|
||||
|
||||
CellType = null;
|
||||
i = o;
|
||||
|
||||
Item type = i.getItem();
|
||||
if ( type instanceof IStorageCell )
|
||||
{
|
||||
CellType = (IStorageCell) i.getItem();
|
||||
MAX_ITEM_TYPES = CellType.getTotalTypes( i );
|
||||
}
|
||||
|
||||
if ( CellType == null )
|
||||
{
|
||||
throw new AppEngException( "ItemStack was used as a cell, but was not a cell!" );
|
||||
}
|
||||
|
||||
if ( !CellType.isStorageCell( i ) )
|
||||
{
|
||||
throw new AppEngException( "ItemStack was used as a cell, but was not a cell!" );
|
||||
}
|
||||
|
||||
if ( MAX_ITEM_TYPES > 63 )
|
||||
MAX_ITEM_TYPES = 63;
|
||||
if ( MAX_ITEM_TYPES < 1 )
|
||||
MAX_ITEM_TYPES = 1;
|
||||
|
||||
this.container = container;
|
||||
tagCompound = Platform.openNbtData( o );
|
||||
storedItems = tagCompound.getShort( ITEM_TYPE_TAG );
|
||||
storedItemCount = tagCompound.getInteger( ITEM_COUNT_TAG );
|
||||
cellItems = null;
|
||||
}
|
||||
|
||||
IItemList<IAEItemStack> getCellItems()
|
||||
{
|
||||
if ( cellItems == null )
|
||||
{
|
||||
cellItems = AEApi.instance().storage().createItemList();
|
||||
loadCellItems();
|
||||
}
|
||||
|
||||
return cellItems;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBytesPerType()
|
||||
{
|
||||
return CellType.BytePerType( i );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canHoldNewItem()
|
||||
{
|
||||
long bytesFree = getFreeBytes();
|
||||
return (bytesFree > getBytesPerType() || (bytesFree == getBytesPerType() && getUnusedItemCount() > 0)) && getRemainingItemTypes() > 0;
|
||||
}
|
||||
|
||||
public static IMEInventoryHandler getCell(ItemStack o, ISaveProvider container2)
|
||||
{
|
||||
try
|
||||
{
|
||||
return new CellInventoryHandler( new CellInventory( o, container2 ) );
|
||||
}
|
||||
catch (AppEngException e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isStorageCell(ItemStack i)
|
||||
{
|
||||
if ( i == null )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Item type = i.getItem();
|
||||
if ( type instanceof IStorageCell )
|
||||
{
|
||||
return !((IStorageCell) type).storableInStorageCell();
|
||||
}
|
||||
}
|
||||
catch (Throwable err)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isCell(ItemStack i)
|
||||
{
|
||||
if ( i == null )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Item type = i.getItem();
|
||||
if ( type instanceof IStorageCell )
|
||||
{
|
||||
return ((IStorageCell) type).isStorageCell( i );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTotalBytes()
|
||||
{
|
||||
return CellType.getBytes( i );
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getFreeBytes()
|
||||
{
|
||||
return getTotalBytes() - getUsedBytes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getUsedBytes()
|
||||
{
|
||||
long bytesForItemCount = (getStoredItemCount() + getUnusedItemCount()) / 8;
|
||||
return getStoredItemTypes() * getBytesPerType() + bytesForItemCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTotalItemTypes()
|
||||
{
|
||||
return MAX_ITEM_TYPES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getStoredItemTypes()
|
||||
{
|
||||
return storedItems;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getStoredItemCount()
|
||||
{
|
||||
return storedItemCount;
|
||||
}
|
||||
|
||||
private void updateItemCount(long delta)
|
||||
{
|
||||
tagCompound.setInteger( ITEM_COUNT_TAG, storedItemCount = (int) (storedItemCount + delta) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getRemainingItemTypes()
|
||||
{
|
||||
long basedOnStorage = getFreeBytes() / getBytesPerType();
|
||||
long baseOnTotal = getTotalItemTypes() - getStoredItemTypes();
|
||||
return basedOnStorage > baseOnTotal ? baseOnTotal : basedOnStorage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getRemainingItemCount()
|
||||
{
|
||||
long remaining = getFreeBytes() * 8 + getUnusedItemCount();
|
||||
return remaining > 0 ? remaining : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUnusedItemCount()
|
||||
{
|
||||
int div = (int) (getStoredItemCount() % 8);
|
||||
|
||||
if ( div == 0 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 8 - div;
|
||||
}
|
||||
|
||||
private static HashSet<Integer> blackList = new HashSet();
|
||||
|
||||
public static void addBasicBlackList(int itemID, int Meta)
|
||||
{
|
||||
blackList.add( (Meta << Platform.DEF_OFFSET) | itemID );
|
||||
}
|
||||
|
||||
public static boolean isBlackListed(IAEItemStack input)
|
||||
{
|
||||
if ( blackList.contains( (OreDictionary.WILDCARD_VALUE << Platform.DEF_OFFSET) | Item.getIdFromItem( input.getItem() ) ) )
|
||||
return true;
|
||||
return blackList.contains( (input.getItemDamage() << Platform.DEF_OFFSET) | Item.getIdFromItem( input.getItem() ) );
|
||||
}
|
||||
|
||||
private boolean isEmpty(IMEInventory meinv)
|
||||
{
|
||||
return meinv.getAvailableItems( AEApi.instance().storage().createItemList() ).isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAEItemStack injectItems(IAEItemStack input, Actionable mode, BaseActionSource src)
|
||||
{
|
||||
if ( input == null )
|
||||
return null;
|
||||
if ( input.getStackSize() == 0 )
|
||||
return null;
|
||||
|
||||
if ( isBlackListed( input ) || CellType.isBlackListed( i, input ) )
|
||||
return input;
|
||||
|
||||
ItemStack sharedItemStack = input.getItemStack();
|
||||
|
||||
if ( CellInventory.isStorageCell( sharedItemStack ) )
|
||||
{
|
||||
IMEInventory meinv = getCell( sharedItemStack, null );
|
||||
if ( meinv != null && !isEmpty( meinv ) )
|
||||
return input;
|
||||
}
|
||||
|
||||
IAEItemStack l = getCellItems().findPrecise( input );
|
||||
if ( l != null )
|
||||
{
|
||||
long remainingItemSlots = getRemainingItemCount();
|
||||
if ( remainingItemSlots < 0 )
|
||||
return input;
|
||||
|
||||
if ( input.getStackSize() > remainingItemSlots )
|
||||
{
|
||||
IAEItemStack r = input.copy();
|
||||
r.setStackSize( r.getStackSize() - remainingItemSlots );
|
||||
if ( mode == Actionable.MODULATE )
|
||||
{
|
||||
l.setStackSize( l.getStackSize() + remainingItemSlots );
|
||||
updateItemCount( remainingItemSlots );
|
||||
saveChanges();
|
||||
}
|
||||
return r;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( mode == Actionable.MODULATE )
|
||||
{
|
||||
l.setStackSize( l.getStackSize() + input.getStackSize() );
|
||||
updateItemCount( input.getStackSize() );
|
||||
saveChanges();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if ( canHoldNewItem() ) // room for new type, and for at least one item!
|
||||
{
|
||||
int remainingItemCount = (int) getRemainingItemCount() - getBytesPerType() * 8;
|
||||
if ( remainingItemCount > 0 )
|
||||
{
|
||||
if ( input.getStackSize() > remainingItemCount )
|
||||
{
|
||||
ItemStack toReturn = Platform.cloneItemStack( sharedItemStack );
|
||||
toReturn.stackSize = sharedItemStack.stackSize - remainingItemCount;
|
||||
if ( mode == Actionable.MODULATE )
|
||||
{
|
||||
ItemStack toWrite = Platform.cloneItemStack( sharedItemStack );
|
||||
toWrite.stackSize = remainingItemCount;
|
||||
|
||||
cellItems.add( AEItemStack.create( toWrite ) );
|
||||
updateItemCount( toWrite.stackSize );
|
||||
|
||||
saveChanges();
|
||||
}
|
||||
return AEItemStack.create( toReturn );
|
||||
}
|
||||
|
||||
if ( mode == Actionable.MODULATE )
|
||||
{
|
||||
updateItemCount( input.getStackSize() );
|
||||
cellItems.add( input );
|
||||
saveChanges();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAEItemStack extractItems(IAEItemStack request, Actionable mode, BaseActionSource src)
|
||||
{
|
||||
if ( request == null )
|
||||
return null;
|
||||
|
||||
ItemStack sharedItem = request.getItemStack();
|
||||
int size = sharedItem.stackSize;
|
||||
|
||||
IAEItemStack Results = null;
|
||||
|
||||
IAEItemStack l = getCellItems().findPrecise( request );
|
||||
if ( l != null )
|
||||
{
|
||||
Results = l.copy();
|
||||
|
||||
if ( l.getStackSize() <= size )
|
||||
{
|
||||
Results.setStackSize( l.getStackSize() );
|
||||
if ( mode == Actionable.MODULATE )
|
||||
{
|
||||
updateItemCount( -l.getStackSize() );
|
||||
l.setStackSize( 0 );
|
||||
saveChanges();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Results.setStackSize( size );
|
||||
if ( mode == Actionable.MODULATE )
|
||||
{
|
||||
l.setStackSize( l.getStackSize() - size );
|
||||
updateItemCount( -size );
|
||||
saveChanges();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Results;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItemList getAvailableItems(IItemList out)
|
||||
{
|
||||
for (IAEItemStack i : getCellItems())
|
||||
out.add( i );
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StorageChannel getChannel()
|
||||
{
|
||||
return StorageChannel.ITEMS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getIdleDrain()
|
||||
{
|
||||
return CellType.getIdleDrain();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FuzzyMode getFuzzyMode()
|
||||
{
|
||||
return CellType.getFuzzyMode( this.i );
|
||||
}
|
||||
|
||||
@Override
|
||||
public IInventory getConfigInventory()
|
||||
{
|
||||
return CellType.getConfigInventory( this.i );
|
||||
}
|
||||
|
||||
@Override
|
||||
public IInventory getUpgradesInventory()
|
||||
{
|
||||
return CellType.getUpgradesInventory( this.i );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStatusForCell()
|
||||
{
|
||||
if ( canHoldNewItem() )
|
||||
return 1;
|
||||
if ( getRemainingItemCount() > 0 )
|
||||
return 2;
|
||||
return 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItemStack()
|
||||
{
|
||||
return i;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package appeng.me.storage;
|
||||
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.config.FuzzyMode;
|
||||
import appeng.api.config.IncludeExclude;
|
||||
import appeng.api.config.Upgrades;
|
||||
import appeng.api.implementations.items.IUpgradeModule;
|
||||
import appeng.api.storage.ICellInventory;
|
||||
import appeng.api.storage.ICellInventoryHandler;
|
||||
import appeng.api.storage.IMEInventory;
|
||||
import appeng.api.storage.StorageChannel;
|
||||
import appeng.api.storage.data.IAEItemStack;
|
||||
import appeng.api.storage.data.IItemList;
|
||||
import appeng.util.Platform;
|
||||
import appeng.util.item.AEItemStack;
|
||||
import appeng.util.prioitylist.FuzzyPriorityList;
|
||||
import appeng.util.prioitylist.PrecisePriorityList;
|
||||
|
||||
public class CellInventoryHandler extends MEInventoryHandler<IAEItemStack> implements ICellInventoryHandler
|
||||
{
|
||||
|
||||
NBTTagCompound openNbtData()
|
||||
{
|
||||
return Platform.openNbtData( getCellInv().getItemStack() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICellInventory getCellInv()
|
||||
{
|
||||
Object o = this.internal;
|
||||
|
||||
if ( o instanceof MEPassthru )
|
||||
o = ((MEPassthru) o).getInternal();
|
||||
|
||||
return (ICellInventory) (o instanceof ICellInventory ? o : null);
|
||||
}
|
||||
|
||||
CellInventoryHandler(IMEInventory c) {
|
||||
super( c, StorageChannel.ITEMS );
|
||||
|
||||
ICellInventory ci = getCellInv();
|
||||
if ( ci != null )
|
||||
{
|
||||
IItemList<IAEItemStack> priorityList = AEApi.instance().storage().createItemList();
|
||||
|
||||
IInventory upgrades = ci.getUpgradesInventory();
|
||||
IInventory config = ci.getConfigInventory();
|
||||
FuzzyMode fzMode = ci.getFuzzyMode();
|
||||
|
||||
boolean hasInverter = false;
|
||||
boolean hasFuzzy = false;
|
||||
|
||||
for (int x = 0; x < upgrades.getSizeInventory(); x++)
|
||||
{
|
||||
ItemStack is = upgrades.getStackInSlot( x );
|
||||
if ( is != null && is.getItem() instanceof IUpgradeModule )
|
||||
{
|
||||
Upgrades u = ((IUpgradeModule) is.getItem()).getType( is );
|
||||
if ( u != null )
|
||||
{
|
||||
switch (u)
|
||||
{
|
||||
case FUZZY:
|
||||
hasFuzzy = true;
|
||||
break;
|
||||
case INVERTER:
|
||||
hasInverter = true;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int x = 0; x < config.getSizeInventory(); x++)
|
||||
{
|
||||
ItemStack is = config.getStackInSlot( x );
|
||||
if ( is != null )
|
||||
priorityList.add( AEItemStack.create( is ) );
|
||||
}
|
||||
|
||||
myWhitelist = hasInverter ? IncludeExclude.BLACKLIST : IncludeExclude.WHITELIST;
|
||||
|
||||
if ( !priorityList.isEmpty() )
|
||||
{
|
||||
if ( hasFuzzy )
|
||||
myPartitionList = new FuzzyPriorityList<IAEItemStack>( priorityList, fzMode );
|
||||
else
|
||||
myPartitionList = new PrecisePriorityList<IAEItemStack>( priorityList );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isPreformatted()
|
||||
{
|
||||
return ! myPartitionList.isEmpty();
|
||||
}
|
||||
|
||||
public boolean isFuzzy()
|
||||
{
|
||||
return myPartitionList instanceof FuzzyPriorityList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IncludeExclude getIncludeExcludeMode()
|
||||
{
|
||||
return myWhitelist;
|
||||
}
|
||||
|
||||
public int getStatusForCell()
|
||||
{
|
||||
int val = getCellInv().getStatusForCell();
|
||||
|
||||
if ( val == 1 && isPreformatted() )
|
||||
val = 2;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
package appeng.me.storage;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.config.AccessRestriction;
|
||||
import appeng.api.config.Actionable;
|
||||
import appeng.api.exceptions.AppEngException;
|
||||
import appeng.api.networking.security.BaseActionSource;
|
||||
import appeng.api.storage.IMEInventoryHandler;
|
||||
import appeng.api.storage.StorageChannel;
|
||||
import appeng.api.storage.data.IAEItemStack;
|
||||
import appeng.api.storage.data.IItemList;
|
||||
import appeng.items.contents.CellConfig;
|
||||
import appeng.util.item.AEItemStack;
|
||||
|
||||
public class CreativeCellInventory implements IMEInventoryHandler<IAEItemStack>
|
||||
{
|
||||
|
||||
IItemList<IAEItemStack> itemListCache = AEApi.instance().storage().createItemList();
|
||||
|
||||
public static IMEInventoryHandler getCell(ItemStack o)
|
||||
{
|
||||
try
|
||||
{
|
||||
return new CellInventoryHandler( new CreativeCellInventory( o ) );
|
||||
}
|
||||
catch (AppEngException e)
|
||||
{
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected CreativeCellInventory(ItemStack o) throws AppEngException {
|
||||
CellConfig cc = new CellConfig( o );
|
||||
for (ItemStack is : cc)
|
||||
if ( is != null )
|
||||
{
|
||||
IAEItemStack i = AEItemStack.create( is );
|
||||
i.setStackSize( Integer.MAX_VALUE );
|
||||
itemListCache.add( i );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAEItemStack injectItems(IAEItemStack input, Actionable mode, BaseActionSource src)
|
||||
{
|
||||
IAEItemStack local = itemListCache.findPrecise( input );
|
||||
if ( local == null )
|
||||
return input;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAEItemStack extractItems(IAEItemStack request, Actionable mode, BaseActionSource src)
|
||||
{
|
||||
IAEItemStack local = itemListCache.findPrecise( request );
|
||||
if ( local == null )
|
||||
return null;
|
||||
|
||||
return request.copy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItemList<IAEItemStack> getAvailableItems(IItemList out)
|
||||
{
|
||||
for (IAEItemStack ais : itemListCache)
|
||||
out.add( ais );
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StorageChannel getChannel()
|
||||
{
|
||||
return StorageChannel.ITEMS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessRestriction getAccess()
|
||||
{
|
||||
return AccessRestriction.READ_WRITE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPrioritized(IAEItemStack input)
|
||||
{
|
||||
return itemListCache.findPrecise( input ) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAccept(IAEItemStack input)
|
||||
{
|
||||
return itemListCache.findPrecise( input ) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPriority()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSlot()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validForPass(int i)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package appeng.me.storage;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import appeng.api.config.Actionable;
|
||||
import appeng.api.implementations.tiles.IChestOrDrive;
|
||||
import appeng.api.networking.security.BaseActionSource;
|
||||
import appeng.api.storage.ICellHandler;
|
||||
import appeng.api.storage.IMEInventory;
|
||||
import appeng.api.storage.data.IAEStack;
|
||||
|
||||
public class DriveWatcher<T extends IAEStack<T>> extends MEInventoryHandler<T>
|
||||
{
|
||||
|
||||
int oldStatus = 0;
|
||||
final ItemStack is;
|
||||
final ICellHandler handler;
|
||||
final IChestOrDrive cord;
|
||||
|
||||
public DriveWatcher(IMEInventory<T> i, ItemStack is, ICellHandler han, IChestOrDrive cod) {
|
||||
super( i, i.getChannel() );
|
||||
this.is = is;
|
||||
handler = han;
|
||||
cord = cod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T injectItems(T input, Actionable type, BaseActionSource src)
|
||||
{
|
||||
long size = input.getStackSize();
|
||||
|
||||
T a = super.injectItems( input, type, src );
|
||||
|
||||
if ( a == null || a.getStackSize() != size )
|
||||
{
|
||||
int newStatus = handler.getStatusForCell( is, getInternal() );
|
||||
|
||||
if ( newStatus != oldStatus )
|
||||
{
|
||||
cord.blinkCell( getSlot() );
|
||||
}
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T extractItems(T request, Actionable type, BaseActionSource src)
|
||||
{
|
||||
T a = super.extractItems( request, type, src );
|
||||
|
||||
if ( a != null )
|
||||
{
|
||||
int newStatus = handler.getStatusForCell( is, getInternal() );
|
||||
|
||||
if ( newStatus != oldStatus )
|
||||
{
|
||||
cord.blinkCell( getSlot() );
|
||||
}
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
package appeng.me.storage;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
|
||||
import appeng.api.networking.storage.IStackWatcher;
|
||||
import appeng.api.networking.storage.IStackWatcherHost;
|
||||
import appeng.api.storage.data.IAEStack;
|
||||
import appeng.me.cache.GridStorageCache;
|
||||
|
||||
/**
|
||||
* Maintain my interests, and a global watch list, they should always be fully synchronized.
|
||||
*/
|
||||
public class ItemWatcher implements IStackWatcher
|
||||
{
|
||||
|
||||
class ItemWatcherIterator implements Iterator<IAEStack>
|
||||
{
|
||||
|
||||
final ItemWatcher watcher;
|
||||
final Iterator<IAEStack> interestIterator;
|
||||
IAEStack myLast;
|
||||
|
||||
public ItemWatcherIterator(ItemWatcher parent, Iterator<IAEStack> i) {
|
||||
watcher = parent;
|
||||
interestIterator = i;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext()
|
||||
{
|
||||
return interestIterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAEStack next()
|
||||
{
|
||||
return myLast = interestIterator.next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove()
|
||||
{
|
||||
gsc.interestManager.remove( myLast, watcher );
|
||||
interestIterator.remove();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
GridStorageCache gsc;
|
||||
IStackWatcherHost myObject;
|
||||
HashSet<IAEStack> myInterests = new HashSet();
|
||||
|
||||
public ItemWatcher(GridStorageCache cache, IStackWatcherHost host) {
|
||||
gsc = cache;
|
||||
myObject = host;
|
||||
}
|
||||
|
||||
public IStackWatcherHost getHost()
|
||||
{
|
||||
return myObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(IAEStack e)
|
||||
{
|
||||
if ( myInterests.contains( e ) )
|
||||
return false;
|
||||
|
||||
return myInterests.add( e.copy() ) && gsc.interestManager.put( e, this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends IAEStack> c)
|
||||
{
|
||||
boolean didChange = false;
|
||||
|
||||
for (IAEStack o : c)
|
||||
didChange = add( o ) || didChange;
|
||||
|
||||
return didChange;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear()
|
||||
{
|
||||
Iterator<IAEStack> i = myInterests.iterator();
|
||||
while (i.hasNext())
|
||||
{
|
||||
gsc.interestManager.remove( i.next(), this );
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o)
|
||||
{
|
||||
return myInterests.contains( o );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> c)
|
||||
{
|
||||
return myInterests.containsAll( c );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty()
|
||||
{
|
||||
return myInterests.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<IAEStack> iterator()
|
||||
{
|
||||
return new ItemWatcherIterator( this, myInterests.iterator() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o)
|
||||
{
|
||||
return myInterests.remove( o ) && gsc.interestManager.remove( (IAEStack)o, this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c)
|
||||
{
|
||||
boolean didSomething = false;
|
||||
for (Object o : c)
|
||||
didSomething = remove( o ) || didSomething;
|
||||
return didSomething;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> c)
|
||||
{
|
||||
boolean changed = false;
|
||||
Iterator<IAEStack> i = iterator();
|
||||
|
||||
while (i.hasNext())
|
||||
{
|
||||
if ( !c.contains( i.next() ) )
|
||||
{
|
||||
i.remove();
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size()
|
||||
{
|
||||
return myInterests.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray()
|
||||
{
|
||||
return myInterests.toArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T[] toArray(T[] a)
|
||||
{
|
||||
return myInterests.toArray( a );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
package appeng.me.storage;
|
||||
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import appeng.api.config.Actionable;
|
||||
import appeng.api.networking.security.BaseActionSource;
|
||||
import appeng.api.storage.IMEInventory;
|
||||
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.item.AEItemStack;
|
||||
|
||||
public class MEIInventoryWrapper implements IMEInventory<IAEItemStack>
|
||||
{
|
||||
|
||||
protected IInventory target;
|
||||
protected InventoryAdaptor adaptor;
|
||||
|
||||
public MEIInventoryWrapper(IInventory m, InventoryAdaptor ia) {
|
||||
target = m;
|
||||
adaptor = ia;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StorageChannel getChannel()
|
||||
{
|
||||
return StorageChannel.ITEMS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAEItemStack injectItems(IAEItemStack iox, Actionable mode, BaseActionSource src)
|
||||
{
|
||||
ItemStack input = iox.getItemStack();
|
||||
|
||||
if ( adaptor != null )
|
||||
{
|
||||
ItemStack is = mode == Actionable.SIMULATE ? adaptor.simulateAdd( input ) : adaptor.addItems( input );
|
||||
if ( is == null )
|
||||
return null;
|
||||
return AEItemStack.create( is );
|
||||
}
|
||||
|
||||
ItemStack out = Platform.cloneItemStack( input );
|
||||
|
||||
if ( mode == Actionable.MODULATE ) // absolutely no need for a first run in simulate mode.
|
||||
{
|
||||
for (int x = 0; x < target.getSizeInventory(); x++)
|
||||
{
|
||||
ItemStack t = target.getStackInSlot( x );
|
||||
|
||||
if ( Platform.isSameItem( t, input ) )
|
||||
{
|
||||
int oriStack = t.stackSize;
|
||||
t.stackSize += out.stackSize;
|
||||
|
||||
target.setInventorySlotContents( x, t );
|
||||
|
||||
if ( t.stackSize > target.getInventoryStackLimit() )
|
||||
{
|
||||
t.stackSize = target.getInventoryStackLimit();
|
||||
}
|
||||
|
||||
if ( t.stackSize > t.getMaxStackSize() )
|
||||
{
|
||||
t.stackSize = t.getMaxStackSize();
|
||||
}
|
||||
|
||||
out.stackSize -= t.stackSize - oriStack;
|
||||
|
||||
if ( out.stackSize <= 0 )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int x = 0; x < target.getSizeInventory(); x++)
|
||||
{
|
||||
ItemStack t = target.getStackInSlot( x );
|
||||
|
||||
if ( t == null )
|
||||
{
|
||||
t = Platform.cloneItemStack( input );
|
||||
t.stackSize = out.stackSize;
|
||||
|
||||
if ( t.stackSize > target.getInventoryStackLimit() )
|
||||
{
|
||||
t.stackSize = target.getInventoryStackLimit();
|
||||
}
|
||||
|
||||
out.stackSize -= t.stackSize;
|
||||
if ( mode == Actionable.MODULATE )
|
||||
target.setInventorySlotContents( x, t );
|
||||
|
||||
if ( out.stackSize <= 0 )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return AEItemStack.create( out );
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAEItemStack extractItems(IAEItemStack request, Actionable mode, BaseActionSource src)
|
||||
{
|
||||
ItemStack Gathered = null;
|
||||
ItemStack Req = request.getItemStack();
|
||||
|
||||
int request_stackSize = Req.stackSize;
|
||||
|
||||
if ( request_stackSize > Req.getMaxStackSize() )
|
||||
{
|
||||
request_stackSize = Req.getMaxStackSize();
|
||||
}
|
||||
|
||||
Req.stackSize = request_stackSize;
|
||||
|
||||
if ( adaptor != null )
|
||||
{
|
||||
Gathered = adaptor.removeItems( Req.stackSize, Req, null );
|
||||
}
|
||||
else
|
||||
{
|
||||
Gathered = request.getItemStack();
|
||||
Gathered.stackSize = 0;
|
||||
|
||||
// try to find matching inventories that already have it...
|
||||
for (int x = 0; x < target.getSizeInventory(); x++)
|
||||
{
|
||||
ItemStack sub = target.getStackInSlot( x );
|
||||
|
||||
if ( Platform.isSameItem( sub, Req ) )
|
||||
{
|
||||
int reqNum = Req.stackSize;
|
||||
|
||||
if ( reqNum > sub.stackSize )
|
||||
{
|
||||
reqNum = Req.stackSize;
|
||||
}
|
||||
|
||||
ItemStack retrieved = null;
|
||||
|
||||
if ( sub.stackSize < Req.stackSize )
|
||||
{
|
||||
retrieved = Platform.cloneItemStack( sub );
|
||||
sub.stackSize = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
retrieved = sub.splitStack( Req.stackSize );
|
||||
}
|
||||
|
||||
if ( sub.stackSize <= 0 )
|
||||
target.setInventorySlotContents( x, null );
|
||||
else
|
||||
target.setInventorySlotContents( x, sub );
|
||||
|
||||
if ( retrieved != null )
|
||||
{
|
||||
Gathered.stackSize += retrieved.stackSize;
|
||||
Req.stackSize -= retrieved.stackSize;
|
||||
}
|
||||
|
||||
if ( request_stackSize == Gathered.stackSize )
|
||||
{
|
||||
return AEItemStack.create( Gathered );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( Gathered.stackSize == 0 )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return AEItemStack.create( Gathered );
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItemList<IAEItemStack> getAvailableItems(IItemList out)
|
||||
{
|
||||
for (int x = 0; x < target.getSizeInventory(); x++)
|
||||
{
|
||||
out.addStorage( AEItemStack.create( target.getStackInSlot( x ) ) );
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
package appeng.me.storage;
|
||||
|
||||
import appeng.api.config.AccessRestriction;
|
||||
import appeng.api.config.Actionable;
|
||||
import appeng.api.config.IncludeExclude;
|
||||
import appeng.api.networking.security.BaseActionSource;
|
||||
import appeng.api.storage.IMEInventory;
|
||||
import appeng.api.storage.IMEInventoryHandler;
|
||||
import appeng.api.storage.IMEMonitor;
|
||||
import appeng.api.storage.StorageChannel;
|
||||
import appeng.api.storage.data.IAEStack;
|
||||
import appeng.api.storage.data.IItemList;
|
||||
import appeng.util.prioitylist.DefaultPriorityList;
|
||||
import appeng.util.prioitylist.IPartitionList;
|
||||
|
||||
public class MEInventoryHandler<T extends IAEStack<T>> implements IMEInventoryHandler<T>
|
||||
{
|
||||
|
||||
final StorageChannel channel;
|
||||
final protected IMEMonitor<T> monitor;
|
||||
final protected IMEInventoryHandler<T> internal;
|
||||
|
||||
public int myPriority = 0;
|
||||
public IncludeExclude myWhitelist = IncludeExclude.WHITELIST;
|
||||
public AccessRestriction myAccess = AccessRestriction.READ_WRITE;
|
||||
public IPartitionList<T> myPartitionList = new DefaultPriorityList<T>();
|
||||
|
||||
public MEInventoryHandler(IMEInventory<T> i, StorageChannel channel) {
|
||||
this.channel = channel;
|
||||
|
||||
if ( i instanceof IMEInventoryHandler )
|
||||
internal = (IMEInventoryHandler<T>) i;
|
||||
else
|
||||
internal = new MEPassthru<T>( i, channel );
|
||||
|
||||
monitor = internal instanceof IMEMonitor ? (IMEMonitor<T>) internal : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T injectItems(T input, Actionable type, BaseActionSource src)
|
||||
{
|
||||
if ( !this.canAccept( input ) )
|
||||
return input;
|
||||
|
||||
return internal.injectItems( input, type, src );
|
||||
}
|
||||
|
||||
@Override
|
||||
public T extractItems(T request, Actionable type, BaseActionSource src)
|
||||
{
|
||||
if ( !getAccess().hasPermission( AccessRestriction.READ ) )
|
||||
return null;
|
||||
|
||||
return internal.extractItems( request, type, src );
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItemList<T> getAvailableItems(IItemList<T> out)
|
||||
{
|
||||
if ( !getAccess().hasPermission( AccessRestriction.READ ) )
|
||||
return out;
|
||||
|
||||
return internal.getAvailableItems( out );
|
||||
}
|
||||
|
||||
@Override
|
||||
public StorageChannel getChannel()
|
||||
{
|
||||
return internal.getChannel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessRestriction getAccess()
|
||||
{
|
||||
return myAccess.restrictPermissions( internal.getAccess() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPrioritized(T input)
|
||||
{
|
||||
if ( myWhitelist == IncludeExclude.WHITELIST )
|
||||
return myPartitionList.isListed( input ) || internal.isPrioritized( input );
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAccept(T input)
|
||||
{
|
||||
if ( !getAccess().hasPermission( AccessRestriction.WRITE ) )
|
||||
return false;
|
||||
|
||||
if ( myWhitelist == IncludeExclude.BLACKLIST && myPartitionList.isListed( input ) )
|
||||
return false;
|
||||
if ( myPartitionList.isEmpty() || myWhitelist == IncludeExclude.BLACKLIST )
|
||||
return internal.canAccept( input );
|
||||
return myPartitionList.isListed( input ) && internal.canAccept( input );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPriority()
|
||||
{
|
||||
return myPriority;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSlot()
|
||||
{
|
||||
return internal.getSlot();
|
||||
}
|
||||
|
||||
public IMEInventory<T> getInternal()
|
||||
{
|
||||
return internal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validForPass(int i)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,290 @@
|
||||
package appeng.me.storage;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.NavigableMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
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.IMEInventory;
|
||||
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;
|
||||
|
||||
public class MEMonitorIInventory implements IMEInventory<IAEItemStack>, IMEMonitor<IAEItemStack>
|
||||
{
|
||||
|
||||
class CachedItemStack
|
||||
{
|
||||
|
||||
public CachedItemStack(ItemStack is)
|
||||
{
|
||||
if ( is == null )
|
||||
{
|
||||
itemStack = null;
|
||||
aeStack = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
itemStack = is.copy();
|
||||
aeStack = AEApi.instance().storage().createItemStack( is );
|
||||
}
|
||||
}
|
||||
|
||||
final ItemStack itemStack;
|
||||
final IAEItemStack aeStack;
|
||||
};
|
||||
|
||||
final InventoryAdaptor adaptor;
|
||||
|
||||
final TreeMap<Integer, CachedItemStack> memory;
|
||||
final IItemList<IAEItemStack> list = AEApi.instance().storage().createItemList();
|
||||
final HashMap<IMEMonitorHandlerReceiver<IAEItemStack>, Object> listeners = new HashMap();
|
||||
|
||||
public BaseActionSource mySource;
|
||||
public StorageFilter mode = StorageFilter.EXTRACTABLE_ONLY;
|
||||
|
||||
@Override
|
||||
public void addListener(IMEMonitorHandlerReceiver<IAEItemStack> l, Object verificationToken)
|
||||
{
|
||||
listeners.put( l, verificationToken );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(IMEMonitorHandlerReceiver<IAEItemStack> l)
|
||||
{
|
||||
listeners.remove( l );
|
||||
}
|
||||
|
||||
public MEMonitorIInventory(InventoryAdaptor adaptor)
|
||||
{
|
||||
this.adaptor = adaptor;
|
||||
memory = new TreeMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAEItemStack injectItems(IAEItemStack input, Actionable type, BaseActionSource src)
|
||||
{
|
||||
ItemStack out = null;
|
||||
|
||||
if ( type == Actionable.SIMULATE )
|
||||
out = adaptor.simulateAdd( input.getItemStack() );
|
||||
else
|
||||
out = adaptor.addItems( input.getItemStack() );
|
||||
|
||||
onTick();
|
||||
|
||||
if ( out == null )
|
||||
return null;
|
||||
|
||||
// better then doing construction from scratch :3
|
||||
IAEItemStack o = input.copy();
|
||||
o.setStackSize( out.stackSize );
|
||||
return o;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessRestriction getAccess()
|
||||
{
|
||||
return AccessRestriction.READ_WRITE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPrioritized(IAEItemStack input)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAccept(IAEItemStack input)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPriority()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSlot()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItemList<IAEItemStack> getStorageList()
|
||||
{
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItemList<IAEItemStack> getAvailableItems(IItemList out)
|
||||
{
|
||||
for (CachedItemStack is : memory.values())
|
||||
out.addStorage( is.aeStack );
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAEItemStack extractItems(IAEItemStack request, Actionable type, BaseActionSource src)
|
||||
{
|
||||
ItemStack out = null;
|
||||
|
||||
if ( type == Actionable.SIMULATE )
|
||||
out = adaptor.simulateRemove( (int) request.getStackSize(), request.getItemStack(), null );
|
||||
else
|
||||
out = adaptor.removeItems( (int) request.getStackSize(), request.getItemStack(), null );
|
||||
|
||||
if ( out == null )
|
||||
return null;
|
||||
|
||||
// better then doing construction from scratch :3
|
||||
IAEItemStack o = request.copy();
|
||||
o.setStackSize( out.stackSize );
|
||||
|
||||
onTick();
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
public TickRateModulation onTick()
|
||||
{
|
||||
boolean changed = false;
|
||||
|
||||
LinkedList<IAEItemStack> changes = new LinkedList<IAEItemStack>();
|
||||
|
||||
int high = 0;
|
||||
list.resetStatus();
|
||||
for (ItemSlot is : adaptor)
|
||||
{
|
||||
CachedItemStack old = memory.get( is.slot );
|
||||
high = Math.max( high, is.slot );
|
||||
|
||||
ItemStack newIS = is == null || is.isExtractable == false && mode == StorageFilter.EXTRACTABLE_ONLY ? null : is.getItemStack();
|
||||
ItemStack oldIS = old == null ? null : old.itemStack;
|
||||
|
||||
if ( isDifferent( newIS, oldIS ) )
|
||||
{
|
||||
CachedItemStack cis = new CachedItemStack( is.getItemStack() );
|
||||
memory.put( is.slot, cis );
|
||||
|
||||
if ( old != null && old.aeStack != null )
|
||||
{
|
||||
old.aeStack.setStackSize( -old.aeStack.getStackSize() );
|
||||
changes.add( old.aeStack );
|
||||
}
|
||||
|
||||
if ( cis != null && cis.aeStack != null )
|
||||
{
|
||||
changes.add( cis.aeStack );
|
||||
list.add( cis.aeStack );
|
||||
}
|
||||
|
||||
changed = true;
|
||||
}
|
||||
else if ( is != null )
|
||||
{
|
||||
int newSize = (newIS == null ? 0 : newIS.stackSize);
|
||||
int diff = newSize - (oldIS == null ? 0 : oldIS.stackSize);
|
||||
|
||||
IAEItemStack stack = (old == null || old.aeStack == null ? AEApi.instance().storage().createItemStack( newIS ) : old.aeStack.copy());
|
||||
if ( stack != null )
|
||||
{
|
||||
stack.setStackSize( newSize );
|
||||
list.add( stack );
|
||||
}
|
||||
|
||||
if ( diff != 0 && stack != null )
|
||||
{
|
||||
CachedItemStack cis = new CachedItemStack( is.getItemStack() );
|
||||
memory.put( is.slot, cis );
|
||||
|
||||
IAEItemStack a = stack.copy();
|
||||
a.setStackSize( diff );
|
||||
changes.add( a );
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// detect dropped items; should fix non IISided Inventory Changes.
|
||||
NavigableMap<Integer, CachedItemStack> end = memory.tailMap( high, false );
|
||||
if ( !end.isEmpty() )
|
||||
{
|
||||
for (CachedItemStack cis : end.values())
|
||||
{
|
||||
if ( cis != null && cis.aeStack != null )
|
||||
{
|
||||
IAEItemStack a = cis.aeStack.copy();
|
||||
a.setStackSize( -a.getStackSize() );
|
||||
changes.add( a );
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
end.clear();
|
||||
}
|
||||
|
||||
if ( !changes.isEmpty() )
|
||||
postDifference( changes );
|
||||
|
||||
return changed ? TickRateModulation.URGENT : TickRateModulation.SLOWER;
|
||||
}
|
||||
|
||||
private boolean isDifferent(ItemStack a, ItemStack b)
|
||||
{
|
||||
if ( a == b && b == null )
|
||||
return false;
|
||||
|
||||
if ( (a == null && b != null) || (a != null && b == null) )
|
||||
return true;
|
||||
|
||||
return !Platform.isSameItemPrecise( a, b );
|
||||
}
|
||||
|
||||
private void postDifference(Iterable<IAEItemStack> a)
|
||||
{
|
||||
// AELog.info( a.getItemStack().getUnlocalizedName() + " @ " + a.getStackSize() );
|
||||
if ( a != null )
|
||||
{
|
||||
Iterator<Entry<IMEMonitorHandlerReceiver<IAEItemStack>, Object>> i = listeners.entrySet().iterator();
|
||||
while (i.hasNext())
|
||||
{
|
||||
Entry<IMEMonitorHandlerReceiver<IAEItemStack>, Object> l = i.next();
|
||||
IMEMonitorHandlerReceiver<IAEItemStack> key = l.getKey();
|
||||
if ( key.isValid( l.getValue() ) )
|
||||
key.postChange( this, a, mySource );
|
||||
else
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public StorageChannel getChannel()
|
||||
{
|
||||
return StorageChannel.ITEMS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validForPass(int i)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package appeng.me.storage;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import appeng.api.networking.security.BaseActionSource;
|
||||
import appeng.api.networking.storage.IBaseMonitor;
|
||||
import appeng.api.storage.IMEInventory;
|
||||
import appeng.api.storage.IMEMonitor;
|
||||
import appeng.api.storage.IMEMonitorHandlerReceiver;
|
||||
import appeng.api.storage.StorageChannel;
|
||||
import appeng.api.storage.data.IAEStack;
|
||||
import appeng.api.storage.data.IItemList;
|
||||
import appeng.util.Platform;
|
||||
import appeng.util.inv.ItemListIgnoreCrafting;
|
||||
|
||||
public class MEMonitorPassthu<T extends IAEStack<T>> extends MEPassthru<T> implements IMEMonitor<T>, IMEMonitorHandlerReceiver<T>
|
||||
{
|
||||
|
||||
HashMap<IMEMonitorHandlerReceiver<T>, Object> listeners = new HashMap();
|
||||
IMEMonitor<T> monitor;
|
||||
|
||||
public BaseActionSource changeSource;
|
||||
|
||||
public MEMonitorPassthu(IMEInventory<T> i, StorageChannel channel) {
|
||||
super( i, channel );
|
||||
if ( i instanceof IMEMonitor )
|
||||
monitor = (IMEMonitor<T>) i;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInternal(IMEInventory<T> i)
|
||||
{
|
||||
if ( monitor != null )
|
||||
monitor.removeListener( this );
|
||||
|
||||
monitor = null;
|
||||
IItemList<T> before = getInternal() == null ? channel.createList() : getInternal()
|
||||
.getAvailableItems( new ItemListIgnoreCrafting( channel.createList() ) );
|
||||
|
||||
super.setInternal( i );
|
||||
if ( i instanceof IMEMonitor )
|
||||
monitor = (IMEMonitor<T>) i;
|
||||
|
||||
IItemList<T> after = getInternal() == null ? channel.createList() : getInternal()
|
||||
.getAvailableItems( new ItemListIgnoreCrafting( channel.createList() ) );
|
||||
|
||||
if ( monitor != null )
|
||||
monitor.addListener( this, monitor );
|
||||
|
||||
Platform.postListChanges( before, after, this, changeSource );
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItemList<T> getAvailableItems(IItemList out)
|
||||
{
|
||||
super.getAvailableItems( new ItemListIgnoreCrafting( out ) );
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(IMEMonitorHandlerReceiver<T> l, Object verificationToken)
|
||||
{
|
||||
listeners.put( l, verificationToken );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(IMEMonitorHandlerReceiver<T> l)
|
||||
{
|
||||
listeners.remove( l );
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItemList<T> getStorageList()
|
||||
{
|
||||
if ( monitor == null )
|
||||
{
|
||||
IItemList<T> out = channel.createList();
|
||||
getInternal().getAvailableItems( new ItemListIgnoreCrafting( out ) );
|
||||
return out;
|
||||
}
|
||||
return monitor.getStorageList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(Object verificationToken)
|
||||
{
|
||||
return verificationToken == monitor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postChange(IBaseMonitor<T> monitor, Iterable<T> change, BaseActionSource source)
|
||||
{
|
||||
Iterator<Entry<IMEMonitorHandlerReceiver<T>, Object>> i = listeners.entrySet().iterator();
|
||||
while (i.hasNext())
|
||||
{
|
||||
Entry<IMEMonitorHandlerReceiver<T>, Object> e = i.next();
|
||||
IMEMonitorHandlerReceiver<T> recv = e.getKey();
|
||||
if ( recv.isValid( e.getValue() ) )
|
||||
recv.postChange( this, change, source );
|
||||
else
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onListUpdate()
|
||||
{
|
||||
Iterator<Entry<IMEMonitorHandlerReceiver<T>, Object>> i = listeners.entrySet().iterator();
|
||||
while (i.hasNext())
|
||||
{
|
||||
Entry<IMEMonitorHandlerReceiver<T>, Object> e = i.next();
|
||||
IMEMonitorHandlerReceiver<T> recv = e.getKey();
|
||||
if ( recv.isValid( e.getValue() ) )
|
||||
recv.onListUpdate();
|
||||
else
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package appeng.me.storage;
|
||||
|
||||
import appeng.api.config.AccessRestriction;
|
||||
import appeng.api.config.Actionable;
|
||||
import appeng.api.networking.security.BaseActionSource;
|
||||
import appeng.api.storage.IMEInventory;
|
||||
import appeng.api.storage.IMEInventoryHandler;
|
||||
import appeng.api.storage.StorageChannel;
|
||||
import appeng.api.storage.data.IAEStack;
|
||||
import appeng.api.storage.data.IItemList;
|
||||
|
||||
public class MEPassthru<T extends IAEStack<T>> implements IMEInventoryHandler<T>
|
||||
{
|
||||
|
||||
private IMEInventory<T> internal;
|
||||
final protected StorageChannel channel;
|
||||
|
||||
protected IMEInventory<T> getInternal()
|
||||
{
|
||||
return internal;
|
||||
}
|
||||
|
||||
public MEPassthru(IMEInventory<T> i, StorageChannel channel) {
|
||||
this.channel = channel;
|
||||
setInternal( i );
|
||||
}
|
||||
|
||||
public void setInternal(IMEInventory<T> i)
|
||||
{
|
||||
internal = i;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T injectItems(T input, Actionable type, BaseActionSource src)
|
||||
{
|
||||
return internal.injectItems( input, type, src );
|
||||
}
|
||||
|
||||
@Override
|
||||
public T extractItems(T request, Actionable type, BaseActionSource src)
|
||||
{
|
||||
return internal.extractItems( request, type, src );
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItemList<T> getAvailableItems(IItemList out)
|
||||
{
|
||||
return internal.getAvailableItems( out );
|
||||
}
|
||||
|
||||
@Override
|
||||
public StorageChannel getChannel()
|
||||
{
|
||||
return internal.getChannel();
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validForPass(int i)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,287 @@
|
||||
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;
|
||||
import appeng.util.ItemSorters;
|
||||
|
||||
public class NetworkInventoryHandler<T extends IAEStack<T>> implements IMEInventoryHandler<T>
|
||||
{
|
||||
|
||||
private final static Comparator prioritySorter = new Comparator<Integer>() {
|
||||
|
||||
@Override
|
||||
public int compare(Integer o1, Integer o2)
|
||||
{
|
||||
return ItemSorters.compareInt( o2, o1 );
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
final StorageChannel myChannel;
|
||||
final SecurityCache security;
|
||||
|
||||
// final TreeMultimap<Integer, IMEInventoryHandler<T>> priorityInventory;
|
||||
final TreeMap<Integer, List<IMEInventoryHandler<T>>> priorityInventory;
|
||||
|
||||
public NetworkInventoryHandler(StorageChannel chan, SecurityCache security) {
|
||||
myChannel = chan;
|
||||
this.security = security;
|
||||
priorityInventory = new TreeMap( prioritySorter ); // TreeMultimap.create( prioritySorter, hashSorter );
|
||||
}
|
||||
|
||||
public void addNewStorage(IMEInventoryHandler<T> h)
|
||||
{
|
||||
int priority = h.getPriority();
|
||||
List<IMEInventoryHandler<T>> list = priorityInventory.get( priority );
|
||||
if ( list == null )
|
||||
priorityInventory.put( priority, list = new ArrayList() );
|
||||
|
||||
list.add( h );
|
||||
}
|
||||
|
||||
static int currentPass = 0;
|
||||
int myPass = 0;
|
||||
static final ThreadLocal<LinkedList> depthMod = new ThreadLocal<LinkedList>();
|
||||
static final ThreadLocal<LinkedList> depthSim = new ThreadLocal<LinkedList>();
|
||||
|
||||
private LinkedList getDepth(Actionable type)
|
||||
{
|
||||
ThreadLocal<LinkedList> depth = type == Actionable.MODULATE ? depthMod : depthSim;
|
||||
|
||||
LinkedList s = depth.get();
|
||||
|
||||
if ( s == null )
|
||||
depth.set( s = new LinkedList() );
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
private boolean diveList(NetworkInventoryHandler<T> networkInventoryHandler, Actionable type)
|
||||
{
|
||||
LinkedList cDepth = getDepth( type );
|
||||
if ( cDepth.contains( networkInventoryHandler ) )
|
||||
return true;
|
||||
|
||||
cDepth.push( this );
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean diveIteration(NetworkInventoryHandler<T> networkInventoryHandler, Actionable type)
|
||||
{
|
||||
LinkedList cDepth = getDepth( type );
|
||||
if ( cDepth.isEmpty() )
|
||||
{
|
||||
currentPass++;
|
||||
myPass = currentPass;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( currentPass == myPass )
|
||||
return true;
|
||||
else
|
||||
myPass = currentPass;
|
||||
}
|
||||
|
||||
cDepth.push( this );
|
||||
return false;
|
||||
}
|
||||
|
||||
private void surface(NetworkInventoryHandler<T> networkInventoryHandler, Actionable type)
|
||||
{
|
||||
if ( getDepth( type ).pop() != 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, type ) )
|
||||
return input;
|
||||
|
||||
if ( testPermission( src, SecurityPermissions.INJECT ) )
|
||||
{
|
||||
surface( this, type );
|
||||
return input;
|
||||
}
|
||||
|
||||
Iterator<List<IMEInventoryHandler<T>>> i = priorityInventory.values().iterator();// asMap().entrySet().iterator();
|
||||
|
||||
while (i.hasNext())
|
||||
{
|
||||
List<IMEInventoryHandler<T>> invList = i.next();
|
||||
|
||||
Iterator<IMEInventoryHandler<T>> ii = invList.iterator();
|
||||
while (ii.hasNext() && input != null)
|
||||
{
|
||||
IMEInventoryHandler<T> inv = ii.next();
|
||||
|
||||
if ( inv.validForPass( 1 ) && inv.canAccept( input )
|
||||
&& (inv.isPrioritized( input ) || inv.extractItems( input, Actionable.SIMULATE, src ) != null) )
|
||||
input = inv.injectItems( input, type, src );
|
||||
}
|
||||
|
||||
ii = invList.iterator();
|
||||
while (ii.hasNext() && input != null)
|
||||
{
|
||||
IMEInventoryHandler<T> inv = ii.next();
|
||||
if ( inv.validForPass( 2 ) && inv.canAccept( input ) )// ignore crafting on the second pass.
|
||||
input = inv.injectItems( input, type, src );
|
||||
}
|
||||
}
|
||||
|
||||
surface( this, type );
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T extractItems(T request, Actionable mode, BaseActionSource src)
|
||||
{
|
||||
if ( diveList( this, mode ) )
|
||||
return null;
|
||||
|
||||
if ( testPermission( src, SecurityPermissions.EXTRACT ) )
|
||||
{
|
||||
surface( this, mode );
|
||||
return null;
|
||||
}
|
||||
|
||||
Iterator<List<IMEInventoryHandler<T>>> i = priorityInventory.descendingMap().values().iterator();// priorityInventory.asMap().descendingMap().entrySet().iterator();
|
||||
|
||||
T output = request.copy();
|
||||
request = request.copy();
|
||||
output.setStackSize( 0 );
|
||||
long req = request.getStackSize();
|
||||
|
||||
while (i.hasNext())
|
||||
{
|
||||
List<IMEInventoryHandler<T>> invList = i.next();
|
||||
|
||||
Iterator<IMEInventoryHandler<T>> ii = invList.iterator();
|
||||
while (ii.hasNext() && output.getStackSize() < req)
|
||||
{
|
||||
IMEInventoryHandler<T> inv = ii.next();
|
||||
|
||||
request.setStackSize( req - output.getStackSize() );
|
||||
output.add( inv.extractItems( request, mode, src ) );
|
||||
}
|
||||
}
|
||||
|
||||
surface( this, mode );
|
||||
|
||||
if ( output.getStackSize() <= 0 )
|
||||
return null;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItemList<T> getAvailableItems(IItemList out)
|
||||
{
|
||||
if ( diveIteration( this, Actionable.SIMULATE ) )
|
||||
return out;
|
||||
|
||||
// for (Entry<Integer, IMEInventoryHandler<T>> h : priorityInventory.entries())
|
||||
for (List<IMEInventoryHandler<T>> i : priorityInventory.values())
|
||||
for (IMEInventoryHandler<T> j : i)
|
||||
out = j.getAvailableItems( out );
|
||||
|
||||
surface( this, Actionable.SIMULATE );
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validForPass(int i)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package appeng.me.storage;
|
||||
|
||||
import appeng.api.config.AccessRestriction;
|
||||
import appeng.api.config.Actionable;
|
||||
import appeng.api.networking.security.BaseActionSource;
|
||||
import appeng.api.storage.IMEInventoryHandler;
|
||||
import appeng.api.storage.StorageChannel;
|
||||
import appeng.api.storage.data.IAEStack;
|
||||
import appeng.api.storage.data.IItemList;
|
||||
|
||||
public class NullInventory<T extends IAEStack<T>> implements IMEInventoryHandler<T>
|
||||
{
|
||||
|
||||
@Override
|
||||
public StorageChannel getChannel()
|
||||
{
|
||||
return StorageChannel.ITEMS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T injectItems(T input, Actionable mode, BaseActionSource src)
|
||||
{
|
||||
return input;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T extractItems(T request, Actionable mode, BaseActionSource src)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItemList<T> getAvailableItems(IItemList out)
|
||||
{
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessRestriction getAccess()
|
||||
{
|
||||
return AccessRestriction.READ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPrioritized(T input)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAccept(T input)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPriority()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSlot()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validForPass(int i)
|
||||
{
|
||||
return i == 2;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
package appeng.me.storage;
|
||||
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.config.AccessRestriction;
|
||||
import appeng.api.config.Actionable;
|
||||
import appeng.api.config.SecurityPermissions;
|
||||
import appeng.api.implementations.items.IBiometricCard;
|
||||
import appeng.api.networking.security.BaseActionSource;
|
||||
import appeng.api.networking.security.PlayerSource;
|
||||
import appeng.api.storage.IMEInventoryHandler;
|
||||
import appeng.api.storage.StorageChannel;
|
||||
import appeng.api.storage.data.IAEItemStack;
|
||||
import appeng.api.storage.data.IItemList;
|
||||
import appeng.me.GridAccessException;
|
||||
import appeng.tile.misc.TileSecurity;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
|
||||
public class SecurityInventory implements IMEInventoryHandler<IAEItemStack>
|
||||
{
|
||||
|
||||
final TileSecurity securityTile;
|
||||
final public IItemList<IAEItemStack> storedItems = AEApi.instance().storage().createItemList();
|
||||
|
||||
public SecurityInventory(TileSecurity ts) {
|
||||
securityTile = ts;
|
||||
}
|
||||
|
||||
private boolean hasPermission(BaseActionSource src)
|
||||
{
|
||||
if ( src.isPlayer() )
|
||||
{
|
||||
try
|
||||
{
|
||||
return securityTile.getProxy().getSecurity().hasPermission( ((PlayerSource) src).player, SecurityPermissions.SECURITY );
|
||||
}
|
||||
catch (GridAccessException e)
|
||||
{
|
||||
// :P
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAEItemStack injectItems(IAEItemStack input, Actionable type, BaseActionSource src)
|
||||
{
|
||||
if ( hasPermission( src ) && AEApi.instance().items().itemBiometricCard.sameAsStack( input.getItemStack() ) )
|
||||
{
|
||||
if ( canAccept( input ) )
|
||||
{
|
||||
if ( type == Actionable.SIMULATE )
|
||||
return null;
|
||||
|
||||
storedItems.add( input );
|
||||
securityTile.inventoryChanged();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAEItemStack extractItems(IAEItemStack request, Actionable mode, BaseActionSource src)
|
||||
{
|
||||
if ( hasPermission( src ) )
|
||||
{
|
||||
IAEItemStack target = storedItems.findPrecise( request );
|
||||
if ( target != null )
|
||||
{
|
||||
IAEItemStack output = target.copy();
|
||||
|
||||
if ( mode == Actionable.SIMULATE )
|
||||
return output;
|
||||
|
||||
target.setStackSize( 0 );
|
||||
securityTile.inventoryChanged();
|
||||
return output;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItemList<IAEItemStack> getAvailableItems(IItemList out)
|
||||
{
|
||||
for (IAEItemStack ais : storedItems)
|
||||
out.add( ais );
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StorageChannel getChannel()
|
||||
{
|
||||
return StorageChannel.ITEMS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessRestriction getAccess()
|
||||
{
|
||||
return AccessRestriction.READ_WRITE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPrioritized(IAEItemStack input)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAccept(IAEItemStack input)
|
||||
{
|
||||
if ( input.getItem() instanceof IBiometricCard )
|
||||
{
|
||||
IBiometricCard tbc = (IBiometricCard) input.getItem();
|
||||
GameProfile newUser = tbc.getProfile( input.getItemStack() );
|
||||
|
||||
int PlayerID = AEApi.instance().registries().players().getID( newUser );
|
||||
if ( securityTile.getOwner() == PlayerID )
|
||||
return false;
|
||||
|
||||
for (IAEItemStack ais : storedItems)
|
||||
{
|
||||
if ( ais.isMeaningful() )
|
||||
{
|
||||
GameProfile thisUser = tbc.getProfile( ais.getItemStack() );
|
||||
if ( thisUser == newUser )
|
||||
return false;
|
||||
|
||||
if ( thisUser != null && thisUser.equals( newUser ) )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPriority()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSlot()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validForPass(int i)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package appeng.me.storage;
|
||||
|
||||
import appeng.api.config.AccessRestriction;
|
||||
import appeng.api.config.Actionable;
|
||||
import appeng.api.networking.security.BaseActionSource;
|
||||
import appeng.api.storage.IMEInventoryHandler;
|
||||
import appeng.api.storage.StorageChannel;
|
||||
import appeng.api.storage.data.IAEFluidStack;
|
||||
import appeng.api.storage.data.IItemList;
|
||||
import appeng.tile.misc.TileCondenser;
|
||||
|
||||
public class VoidFluidInventory implements IMEInventoryHandler<IAEFluidStack>
|
||||
{
|
||||
|
||||
TileCondenser target;
|
||||
|
||||
public VoidFluidInventory(TileCondenser te) {
|
||||
target = te;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAEFluidStack injectItems(IAEFluidStack input, Actionable mode, BaseActionSource src)
|
||||
{
|
||||
if ( input != null )
|
||||
target.addPower( (double) input.getStackSize() / 1000.0 );
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StorageChannel getChannel()
|
||||
{
|
||||
return StorageChannel.FLUIDS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAEFluidStack extractItems(IAEFluidStack request, Actionable mode, BaseActionSource src)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItemList<IAEFluidStack> getAvailableItems(IItemList out)
|
||||
{
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessRestriction getAccess()
|
||||
{
|
||||
return AccessRestriction.WRITE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPrioritized(IAEFluidStack input)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAccept(IAEFluidStack input)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPriority()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSlot()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validForPass(int i)
|
||||
{
|
||||
return i == 2;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package appeng.me.storage;
|
||||
|
||||
import appeng.api.config.AccessRestriction;
|
||||
import appeng.api.config.Actionable;
|
||||
import appeng.api.networking.security.BaseActionSource;
|
||||
import appeng.api.storage.IMEInventoryHandler;
|
||||
import appeng.api.storage.StorageChannel;
|
||||
import appeng.api.storage.data.IAEItemStack;
|
||||
import appeng.api.storage.data.IItemList;
|
||||
import appeng.tile.misc.TileCondenser;
|
||||
|
||||
public class VoidItemInventory implements IMEInventoryHandler<IAEItemStack>
|
||||
{
|
||||
|
||||
TileCondenser target;
|
||||
|
||||
public VoidItemInventory(TileCondenser te) {
|
||||
target = te;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAEItemStack injectItems(IAEItemStack input, Actionable mode, BaseActionSource src)
|
||||
{
|
||||
if ( input != null )
|
||||
target.addPower( input.getStackSize() );
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StorageChannel getChannel()
|
||||
{
|
||||
return StorageChannel.ITEMS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAEItemStack extractItems(IAEItemStack request, Actionable mode, BaseActionSource src)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItemList<IAEItemStack> getAvailableItems(IItemList out)
|
||||
{
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessRestriction getAccess()
|
||||
{
|
||||
return AccessRestriction.WRITE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPrioritized(IAEItemStack input)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAccept(IAEItemStack input)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPriority()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSlot()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validForPass(int i)
|
||||
{
|
||||
return i == 2;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user