AE2 First Commit, the dawn of 1.7 hast arrived.

This commit is contained in:
algorithmx2
2013-12-27 16:59:59 -06:00
commit e9acdcbee2
468 changed files with 47440 additions and 0 deletions
+232
View File
@@ -0,0 +1,232 @@
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.util.IReadOnlyCollection;
import appeng.core.WorldSettings;
import appeng.helpers.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>();
long LastFiveRemoveTime = 0;
long LastFiveAddNode = 0;
GridNode pivot;
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 ) ) );
}
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( this, 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( this, gridNode, gridNode.getMachine() );
gridNode.gridProxy.gridChanged();
// postEventTo( gridNode, networkChanged );
}
@Override
public boolean isReady()
{
return true;
}
@Override
public IReadOnlyCollection<IGridNode> getNodes()
{
return new NodeIteratable( 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())
{
gc.onUpdateTick( this );
}
}
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 );
}
}
}
+8
View File
@@ -0,0 +1,8 @@
package appeng.me;
public class GridAccessException extends Exception
{
private static final long serialVersionUID = 3914554394866375300L;
}
+87
View File
@@ -0,0 +1,87 @@
package appeng.me;
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.me.cache.TickManagerCache;
import appeng.util.Platform;
public class GridCacheWrapper implements IGridCache
{
final IGridCache myCache;
final public boolean isTickHandler;
public long LastFiveTicksTime = 0;
public long LastFiveRemoveTime = 0;
public long LastFiveAddNode = 0;
public GridCacheWrapper(IGridCache gc) {
myCache = gc;
isTickHandler = myCache instanceof TickManagerCache;
}
@Override
public void onUpdateTick(IGrid grid)
{
long startTime = Platform.nanoTime();
myCache.onUpdateTick( grid );
long estimatedTime = Platform.nanoTime() - startTime;
if ( isTickHandler ) // remove the ticking of tickables from the
// equation.
estimatedTime -= ((TickManagerCache) myCache).getInnerTime();
LastFiveTicksTime = ((LastFiveTicksTime * 4) / 5) + estimatedTime;
}
@Override
public void removeNode(IGrid grid, IGridNode gridNode, IGridHost machine)
{
long startTime = Platform.nanoTime();
myCache.removeNode( grid, gridNode, machine );
long estimatedTime = Platform.nanoTime() - startTime;
LastFiveRemoveTime = ((LastFiveRemoveTime * 4) / 5) + estimatedTime;
}
@Override
public void addNode(IGrid grid, IGridNode gridNode, IGridHost machine)
{
long startTime = Platform.nanoTime();
myCache.addNode( grid, gridNode, machine );
long estimatedTime = Platform.nanoTime() - startTime;
LastFiveAddNode = ((LastFiveAddNode * 4) / 5) + estimatedTime;
}
public String getName()
{
return myCache.getClass().getName();
}
@Override
public void onSplit(IGridStorage storageB)
{
myCache.onSplit( storageB );
}
@Override
public void onJoin(IGridStorage storageB)
{
myCache.onJoin( storageB );
}
@Override
public void populateGridStorage(IGridStorage storage)
{
myCache.populateGridStorage( storage );
}
}
+209
View File
@@ -0,0 +1,209 @@
package appeng.me;
import java.util.Arrays;
import java.util.EnumSet;
import net.minecraftforge.common.ForgeDirection;
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.me.pathfinding.IPathItem;
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;
byte visitorIterationNumber = Byte.MIN_VALUE;
public int channelData = 0;
public GridConnection(IGridNode aNode, IGridNode bNode, ForgeDirection fromAtoB) {
GridNode a = (GridNode) aNode;
GridNode b = (GridNode) bNode;
if ( a == null || b == null )
throw new GridException( "Connection Forged Between null entnties." );
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.beginVisition( gp );
}
else if ( b.myGrid == null )
{
GridPropagator gp = new GridPropagator( a.getInternalGrid() );
b.beginVisition( gp );
}
else if ( a.myGrid.size() > b.myGrid.size() )
{
GridPropagator gp = new GridPropagator( a.getInternalGrid() );
b.beginVisition( gp );
}
else
{
GridPropagator gp = new GridPropagator( b.getInternalGrid() );
a.beginVisition( gp );
}
}
// a connection was destroyed RE-PATH!!
IPathingGrid p = sideA.getInternalGrid().getCache( IPathingGrid.class );
p.repath();
sideA.addConnection( this );
sideB.addConnection( this );
}
@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 );
}
}
+12
View File
@@ -0,0 +1,12 @@
package appeng.me;
public class GridException extends RuntimeException
{
private static final long serialVersionUID = -8110077032108243076L;
public GridException(String s) {
super( s );
}
}
+488
View File
@@ -0,0 +1,488 @@
package appeng.me;
import java.util.EnumSet;
import java.util.LinkedList;
import java.util.List;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import net.minecraftforge.common.ForgeDirection;
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.IGridConnecitonVisitor;
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.me.pathfinding.IPathItem;
import appeng.util.ReadOnlyCollection;
public class GridNode implements IGridNode, IPathItem
{
final static private MENetworkChannelsChanged event = new MENetworkChannelsChanged();
final List<IGridConnection> Connections = new LinkedList();
GridStorage myStorage = null;
IGridBlock gridProxy;
Grid myGrid;
public static byte currentVisitorIterationNumber = Byte.MIN_VALUE;
public static byte currentChannelsIterationNumber = Byte.MIN_VALUE;
byte visitorIterationNumber = Byte.MIN_VALUE;
// connection criteria
AEColor myColor = AEColor.Transparent;
EnumSet<ForgeDirection> validDirections = EnumSet.noneOf( ForgeDirection.class );
// old power draw, used to diff
public double previousDraw = 0.0;
private int maxChannels = 8;
private int channelData = 0;
public int usedChannels()
{
return channelData >> 8;
}
public AEColor getColor()
{
return myColor;
}
public GridNode(IGridBlock what) {
gridProxy = what;
}
@Override
public void loadFromNBT(String name, NBTTagCompound nodeData)
{
if ( myGrid == null )
setGridStorage( WorldSettings.getInstance().getGridStorage( nodeData.getLong( name ) ) );
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 )
nodeData.setLong( name, myStorage.getID() );
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 updateState()
{
EnumSet<GridFlags> set = gridProxy.getFlags();
maxChannels = set.contains( GridFlags.CANNOT_CARRY ) ? 0 : (set.contains( GridFlags.TIER_2_CAPACITY ) ? 32 : 8);
myColor = gridProxy.getGridColor();
validDirections = gridProxy.getConnectableSides();
FindConnections();
getInternalGrid();
}
@Override
public void beginVisition(IGridVisitor g)
{
currentVisitorIterationNumber++;
LinkedList<GridNode> nextRun = new LinkedList();
nextRun.add( this );
visitorIterationNumber = currentVisitorIterationNumber;
if ( g instanceof IGridConnecitonVisitor )
{
LinkedList<IGridConnection> nextConn = new LinkedList();
IGridConnecitonVisitor gcv = (IGridConnecitonVisitor) g;
while (!nextRun.isEmpty())
{
while (!nextConn.isEmpty())
gcv.visitConnection( nextConn.poll() );
LinkedList<GridNode> thisRun = nextRun;
nextRun = new LinkedList();
for (GridNode n : thisRun)
n.visitorConnection( g, nextRun, nextConn );
}
}
else
{
while (!nextRun.isEmpty())
{
LinkedList<GridNode> thisRun = nextRun;
nextRun = new LinkedList();
for (GridNode n : thisRun)
n.visitorNode( g, nextRun );
}
}
}
private void visitorConnection(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 != currentVisitorIterationNumber )
{
gcc.visitorIterationNumber = currentChannelsIterationNumber;
nextConnections.add( gc );
}
if ( currentVisitorIterationNumber == gn.visitorIterationNumber )
continue;
gn.visitorIterationNumber = currentVisitorIterationNumber;
nextRun.add( gn );
}
}
}
private void visitorNode(IGridVisitor g, LinkedList<GridNode> nextRun)
{
if ( g.visitNode( this ) )
{
for (IGridConnection gc : getConnections())
{
GridNode gn = (GridNode) gc.getOtherSide( this );
if ( currentVisitorIterationNumber == gn.visitorIterationNumber )
continue;
gn.visitorIterationNumber = currentVisitorIterationNumber;
nextRun.add( gn );
}
}
}
public void FindConnections()
{
if ( !gridProxy.isWorldAccessable() )
return;
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
{
throw new GridException( "invalid state found, encountered connection to phantom block." );
}
}
else if ( isValidConnection )
{
// construct a new connection between these two nodes.
new GridConnection( node, this, f.getOpposite() );
}
}
}
}
private IGridHost findGridHost(World world, int x, int y, int z)
{
if ( world.blockExists( x, y, z ) )
{
TileEntity te = world.getBlockTileEntity( 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 );
}
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 ( !validDirections.contains( 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() );
beginVisition( gsd );
if ( !gsd.pivotFound )
{
GridPropagator gp = new GridPropagator( new Grid( this ) );
beginVisition( 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.REQURE_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() < maxChannels;
}
@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 );
}
}
}
+27
View File
@@ -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;
}
}
+24
View File
@@ -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;
}
};
+141
View File
@@ -0,0 +1,141 @@
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 org.bouncycastle.util.encoders.Base64;
import appeng.api.networking.IGrid;
import appeng.api.networking.IGridStorage;
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 = Base64.decode( 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 new String( Base64.encode( out.toByteArray() ), "UTF-8" );
}
catch (IOException e)
{
e.printStackTrace();
}
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() );
}
}
+40
View File
@@ -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();
}
}
+26
View File
@@ -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;
}
}
+153
View File
@@ -0,0 +1,153 @@
package appeng.me;
import java.lang.reflect.Method;
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 cpw.mods.fml.common.FMLLog;
public class NetworkEventBus
{
class NetworkEventDone extends Throwable
{
private static final long serialVersionUID = -3079021487019171205L;
};
class MENetworkEventInfo
{
public final Class objClass;
public final Method objMethod;
public final Class objEvent;
public MENetworkEventInfo(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)
{
FMLLog.severe( "[AppEng] Network Event caused exception:" );
FMLLog.severe( "Offending Class: " + obj.getClass().getName() );
FMLLog.severe( "Offending Object: " + obj.toString() );
e1.printStackTrace();
throw new RuntimeException( e1 );
}
if ( e.isCanceled() )
throw new NetworkEventDone();
}
};
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 );
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() );
classEvents.put( listAs, new MENetworkEventInfo( types[0], c, m ) );
}
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." );
}
}
}
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;
}
}
+57
View File
@@ -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 NodeIteratable<T> implements IReadOnlyCollection<T>
{
final private HashMap<Class, Set<IGridNode>> Machines;
public NodeIteratable(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;
}
}
+53
View File
@@ -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();
}
}
+426
View File
@@ -0,0 +1,426 @@
package appeng.me.cache;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
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.events.MENetworkEventSubscribe;
import appeng.api.networking.events.MENetworkPowerIdleChange;
import appeng.api.networking.events.MENetworkPowerStatusChange;
import appeng.api.networking.events.MENetworkPowerStorage;
import appeng.me.GridNode;
public class EnergyGridCache implements IEnergyGrid
{
/**
* estimated power available.
*/
int availableTicksSinceUpdate = 0;
double globalAvailablePower = 0;
/**
* idle draw.
*/
double drainPerTick = 0;
Double[] totalDrainPastTicks = new Double[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
Double[] totalInjectionPastTicks = new Double[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
/**
* power status
*/
boolean publicHasPower = false;
boolean hasPower = true;
long ticksSinceHasPowerChange = 900;
/**
* excess power in the system.
*/
double prev_extra = 0;
double extra = 0;
Set<IAEPowerStorage> providers = new LinkedHashSet();
Set<IAEPowerStorage> requesters = new LinkedHashSet();
Set<IEnergyGridProvider> gproviders = new LinkedHashSet();
final IGrid myGrid;
public EnergyGridCache(IGrid g) {
myGrid = g;
}
@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)
{
double required = 0;
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() );
}
return required;
}
@Override
public double injectPower(double i, Actionable mode)
{
i += extra;
if ( mode == Actionable.SIMULATE )
{
Iterator<IAEPowerStorage> it = requesters.iterator();
while (i > 0 && it.hasNext())
{
IAEPowerStorage node = it.next();
i = node.injectAEPower( i, Actionable.SIMULATE );
}
}
else
{
while (i > 0 && !requesters.isEmpty())
{
IAEPowerStorage node = requesters.iterator().next();
i = node.injectAEPower( i, Actionable.MODULATE );
if ( i > 0 )
requesters.remove( node );
}
extra = i;
totalInjectionPastTicks[0] += i;
}
return i;
}
@Override
public double extractAEPower(double amt, Actionable mode, PowerMultiplier pm)
{
return pm.divide( extractAEPower( pm.multiply( amt ), mode, new HashSet() ) );
}
@Override
public void addNode(IGrid grid, 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 ( current > 0 && ps.getPowerFlow() != AccessRestriction.WRITE )
{
globalAvailablePower += ((IAEPowerStorage) machine).getAECurrentPower();
providers.add( ps );
}
if ( current < max && ps.getPowerFlow() != AccessRestriction.READ )
requesters.add( ps );
}
}
grid.postEventTo( node, new MENetworkPowerStatusChange() );
}
@Override
public void removeNode(IGrid grid, 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.getPowerFlow() != AccessRestriction.WRITE )
globalAvailablePower -= ps.getAECurrentPower();
providers.remove( machine );
requesters.remove( machine );
}
}
// recalculate the whole thing?
public void reset(IGrid grid)
{
providers = new LinkedHashSet();
requesters = new LinkedHashSet();
// re-calculate power info
for (Class c : grid.getMachinesClasses())
{
if ( IAEPowerStorage.class.isAssignableFrom( c ) )
{
for (Object obj : grid.getMachines( c ))
{
IAEPowerStorage ps = (IAEPowerStorage) obj;
if ( ps.isAEPublicPowerStorage() )
{
double max = ps.getAEMaxPower();
double current = ps.getAECurrentPower();
if ( current > 0 && ps.getPowerFlow() != AccessRestriction.WRITE )
{
providers.add( ps );
globalAvailablePower += ps.getAECurrentPower();
}
if ( current < max && ps.getPowerFlow() != AccessRestriction.READ )
requesters.add( ps );
}
}
}
}
}
@Override
public void onUpdateTick(IGrid grid)
{
// next tick is here...
for (int x = 0; x < totalDrainPastTicks.length - 1; x++)
totalDrainPastTicks[x + 1] = totalDrainPastTicks[x];
totalDrainPastTicks[0] = 0.0;
for (int x = 0; x < totalInjectionPastTicks.length - 1; x++)
totalInjectionPastTicks[x + 1] = totalInjectionPastTicks[x];
totalInjectionPastTicks[0] = 0.0;
// power information.
double drained = extractAEPower( getIdlePowerUsage(), Actionable.MODULATE, PowerMultiplier.CONFIG );
boolean currentlyHasPower = drained >= drainPerTick - 0.1;
// 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, grid );
else if ( !hasPower )
publicPowerState( false, grid );
availableTicksSinceUpdate++;
if ( extra > 32 )
injectPower( 0.0, Actionable.MODULATE );
}
private void publicPowerState(boolean newState, IGrid grid)
{
if ( publicHasPower == newState )
return;
publicHasPower = newState;
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 globalAvailablePower;
}
@Override
public double extractAEPower(double amt, Actionable mode, Set<IEnergyGrid> seen)
{
if ( seen.contains( this ) )
return 0;
seen.add( this );
double extractedPower = extra;
if ( mode == Actionable.SIMULATE )
{
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;
}
}
else
{
extra = 0;
while (extractedPower < amt && !providers.isEmpty())
{
IAEPowerStorage node = providers.iterator().next();
double req = amt - extractedPower;
double newPower = node.extractAEPower( req, Actionable.MODULATE, PowerMultiplier.ONE );
extractedPower += newPower;
if ( newPower < req )
providers.remove( node );
}
// add power used to the current tick.
totalDrainPastTicks[0] += extractedPower;
}
// got more then we wanted?
if ( extractedPower > amt )
{
extra = extractedPower - amt;
globalAvailablePower -= amt;
return amt;
}
if ( extractedPower < amt )
{
for (IEnergyGridProvider egp : gproviders)
extractedPower += egp.extractAEPower( amt - extractedPower, mode, seen );
}
// go less or the correct amount?
globalAvailablePower -= extractedPower;
return extractedPower;
}
@Override
public boolean isNetworkPowered()
{
return publicHasPower;
}
@Override
public double getIdlePowerUsage()
{
return drainPerTick;
}
@Override
public double getAvgPowerUsage()
{
double out = 0;
for (double x : totalDrainPastTicks)
out += x;
return out / totalDrainPastTicks.length;
}
@Override
public double getAvgPowerInjection()
{
double out = 0;
for (double x : totalInjectionPastTicks)
out += x;
return out / totalInjectionPastTicks.length;
}
@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 );
}
}
+208
View File
@@ -0,0 +1,208 @@
package appeng.me.cache;
import java.util.HashSet;
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.storage.IStorageGrid;
import appeng.api.storage.ICellContainer;
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.storage.NetworkInventoryHandler;
import appeng.util.item.ItemList;
public class GridStorageCache implements IStorageGrid
{
final HashSet<ICellContainer> cellContainers = new HashSet();
final IGrid myGrid;
private IItemList<IAEItemStack> previousItemSet;
private NetworkInventoryHandler<IAEItemStack> myItemNetwork;
private NetworkMonitor<IAEItemStack> itemMonitor = new NetworkMonitor<IAEItemStack>( this, StorageChannel.ITEMS );
private IItemList<IAEFluidStack> previousFluidSet;
private NetworkInventoryHandler<IAEFluidStack> myFluidNetwork;
private NetworkMonitor<IAEFluidStack> fluidMonitor = new NetworkMonitor<IAEFluidStack>( this, StorageChannel.FLUIDS );
public GridStorageCache(IGrid g) {
myGrid = g;
}
@Override
public void onUpdateTick(IGrid grid)
{
itemMonitor.onTick();
fluidMonitor.onTick();
}
@Override
public void removeNode(IGrid grid, IGridNode node, IGridHost machine)
{
if ( machine instanceof ICellContainer )
{
ICellContainer cc = (ICellContainer) machine;
cellContainers.remove( cc );
for (IMEInventoryHandler<IAEItemStack> h : cc.getCellArray( StorageChannel.ITEMS ))
{
postChanges( StorageChannel.ITEMS, -1, h.getAvailableItems( new ItemList<IAEItemStack>() ) );
}
for (IMEInventoryHandler<IAEFluidStack> h : cc.getCellArray( StorageChannel.FLUIDS ))
{
postChanges( StorageChannel.ITEMS, -1, h.getAvailableItems( new ItemList<IAEFluidStack>() ) );
}
}
myGrid.postEvent( new MENetworkCellArrayUpdate() );
}
@Override
public void addNode(IGrid grid, IGridNode node, IGridHost machine)
{
if ( machine instanceof ICellContainer )
{
ICellContainer cc = (ICellContainer) machine;
cellContainers.add( cc );
for (IMEInventoryHandler<IAEItemStack> h : cc.getCellArray( StorageChannel.ITEMS ))
{
postChanges( StorageChannel.ITEMS, 1, h.getAvailableItems( new ItemList<IAEItemStack>() ) );
}
for (IMEInventoryHandler<IAEFluidStack> h : cc.getCellArray( StorageChannel.FLUIDS ))
{
postChanges( StorageChannel.ITEMS, 1, h.getAvailableItems( new ItemList<IAEFluidStack>() ) );
}
}
myGrid.postEvent( new MENetworkCellArrayUpdate() );
}
private void buildNetworkStorage(StorageChannel chan)
{
switch (chan)
{
case FLUIDS:
myFluidNetwork = new NetworkInventoryHandler<IAEFluidStack>( StorageChannel.FLUIDS );
for (ICellContainer cc : cellContainers)
{
for (IMEInventoryHandler<IAEFluidStack> h : cc.getCellArray( chan ))
myFluidNetwork.addNewStorage( h );
}
break;
case ITEMS:
myItemNetwork = new NetworkInventoryHandler<IAEItemStack>( StorageChannel.ITEMS );
for (ICellContainer cc : cellContainers)
{
for (IMEInventoryHandler<IAEItemStack> h : cc.getCellArray( chan ))
myItemNetwork.addNewStorage( h );
}
break;
default:
}
}
private void postChanges(StorageChannel chan, int up_or_down, IItemList availableItems)
{
switch (chan)
{
case FLUIDS:
for (IAEFluidStack fs : ((IItemList<IAEFluidStack>) availableItems))
{
if ( up_or_down > 0 )
fluidMonitor.postChange( fs );
else
{
fs.setStackSize( -fs.getStackSize() );
fluidMonitor.postChange( fs );
}
}
break;
case ITEMS:
for (IAEItemStack fs : ((IItemList<IAEItemStack>) availableItems))
{
if ( up_or_down > 0 )
itemMonitor.postChange( fs );
else
{
fs.setStackSize( -fs.getStackSize() );
itemMonitor.postChange( fs );
}
}
break;
default:
}
}
@MENetworkEventSubscribe
public void cellUpdate(MENetworkCellArrayUpdate ev)
{
myItemNetwork = null;
myFluidNetwork = null;
}
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, IAEStack input)
{
if ( chan == StorageChannel.ITEMS )
itemMonitor.postChange( (IAEItemStack) input );
else if ( chan == StorageChannel.FLUIDS )
fluidMonitor.postChange( (IAEFluidStack) input );
}
@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)
{
}
}
+66
View File
@@ -0,0 +1,66 @@
package appeng.me.cache;
import java.util.LinkedList;
import appeng.api.networking.events.MENetworkStorageEvent;
import appeng.api.storage.IMEInventoryHandler;
import appeng.api.storage.MEMontorHandler;
import appeng.api.storage.StorageChannel;
import appeng.api.storage.data.IAEStack;
public class NetworkMonitor<T extends IAEStack<T>> extends MEMontorHandler<T>
{
final private GridStorageCache myGridCache;
final private StorageChannel myChannel;
boolean sendEvent = false;
public NetworkMonitor(GridStorageCache cache, StorageChannel chan) {
super( null );
myGridCache = cache;
myChannel = chan;
}
final static public LinkedList depth = new LinkedList();
@Override
protected void postChange(T diff)
{
if ( depth.contains( this ) )
return;
depth.push( this );
sendEvent = true;
super.postChange( diff );
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( getStorageList(), myChannel ) );
}
}
@Override
protected IMEInventoryHandler getHandler()
{
switch (myChannel)
{
case ITEMS:
return myGridCache.getItemInventoryHandler();
case FLUIDS:
return myGridCache.getFluidInventoryHandler();
default:
}
return null;
}
}
+103
View File
@@ -0,0 +1,103 @@
package appeng.me.cache;
import java.util.Collection;
import java.util.HashMap;
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.parts.misc.PartP2PTunnel;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Multimap;
public class P2PCache implements IGridCache
{
private HashMap<Long, PartP2PTunnel> inputs = new HashMap();
private Multimap<Long, PartP2PTunnel> Tunnels = LinkedHashMultimap.create();
final IGrid myGrid;
public P2PCache(IGrid g) {
myGrid = g;
}
@Override
public void addNode(IGrid grid, IGridNode node, IGridHost machine)
{
if ( machine instanceof PartP2PTunnel )
reset( grid );
}
@Override
public void removeNode(IGrid grid, IGridNode node, IGridHost machine)
{
if ( machine instanceof PartP2PTunnel )
reset( grid );
}
public void reset(IGrid grid)
{
Tunnels.clear();
inputs.clear();
for (IGridNode n : grid.getMachines( PartP2PTunnel.class ))
{
PartP2PTunnel p = (PartP2PTunnel) n.getMachine();
if ( p.freq > 0 )
{
if ( p.output )
Tunnels.put( p.freq, p );
else if ( inputs.containsKey( p.freq ) )
p.output = true;
else
inputs.put( p.freq, p );
}
}
for (PartP2PTunnel p : inputs.values())
p.onChange();
for (PartP2PTunnel p : Tunnels.values())
p.onChange();
}
public Collection<PartP2PTunnel> getOutputs(long freq)
{
return Tunnels.get( freq );
}
public PartP2PTunnel getInput(long freq)
{
return inputs.get( freq );
}
@Override
public void onUpdateTick(IGrid grid)
{
}
@Override
public void onSplit(IGridStorage storageB)
{
}
@Override
public void onJoin(IGridStorage storageB)
{
}
@Override
public void populateGridStorage(IGridStorage storage)
{
}
}
+279
View File
@@ -0,0 +1,279 @@
package appeng.me.cache;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import net.minecraftforge.common.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.MENetworkControllerChange;
import appeng.api.networking.pathing.ControllerState;
import appeng.api.networking.pathing.IPathingGrid;
import appeng.api.util.DimensionalCoord;
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;
public class PathGridCache implements IPathingGrid
{
boolean recalculateControllerNextTick = true;
boolean updateNetwork = true;
boolean booting = false;
LinkedList<PathSegment> active = new LinkedList();
ControllerState controllerState = ControllerState.NO_CONTROLLER;
int instance = Integer.MIN_VALUE;
int ticksUntilReady = 20;
Set<TileController> controllers = new HashSet();
Set<IGridNode> requireChannels = new HashSet();
final IGrid myGrid;
private HashSet<IPathItem> semiOpen = new HashSet();
private HashSet<IPathItem> closedList = new HashSet();
public PathGridCache(IGrid g) {
myGrid = g;
}
@Override
public void onUpdateTick(IGrid grid)
{
if ( recalculateControllerNextTick )
{
recalcController();
}
if ( updateNetwork )
{
if ( !booting )
myGrid.postEvent( new MENetworkBootingStatusChange() );
booting = true;
updateNetwork = false;
instance++;
if ( controllerState == ControllerState.NO_CONTROLLER )
{
int requiredChannels = calculateRequiredChanels();
int used = requiredChannels;
if ( requiredChannels > 8 )
used = 0;
int nodes = myGrid.getNodes().size();
ticksUntilReady = 20 + (nodes / 10);
myGrid.getPivot().beginVisition( new AdHocChannelUpdater( used ) );
}
else if ( controllerState == ControllerState.CONTROLLER_CONFLICT )
{
ticksUntilReady = 20;
myGrid.getPivot().beginVisition( new AdHocChannelUpdater( 0 ) );
}
else
{
int nodes = myGrid.getNodes().size();
ticksUntilReady = 20 + (nodes / 10);
closedList = new HashSet();
semiOpen = new HashSet();
// myGrid.getPivot().beginVisition( new AdHocChannelUpdater( 0 ) );
for (IGridNode node : grid.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( 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 ).beginVisition( new ControllerChannelUpdater() );
break;
}
}
booting = false;
myGrid.postEvent( new MENetworkBootingStatusChange() );
}
}
}
private int calculateRequiredChanels()
{
int depth = 0;
semiOpen.clear();
for (IGridNode nodes : requireChannels)
{
if ( !semiOpen.contains( nodes ) )
{
depth++;
IGridBlock gb = nodes.getGridBlock();
if ( gb.getFlags().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();
updateNetwork = true;
}
@Override
public void removeNode(IGrid grid, IGridNode gridNode, IGridHost machine)
{
if ( machine instanceof TileController )
{
controllers.remove( machine );
recalculateControllerNextTick = true;
}
if ( gridNode.getGridBlock().getFlags().contains( GridFlags.REQURE_CHANNEL ) )
requireChannels.remove( gridNode );
repath();
}
@Override
public void addNode(IGrid grid, IGridNode gridNode, IGridHost machine)
{
if ( machine instanceof TileController )
{
controllers.add( (TileController) machine );
recalculateControllerNextTick = true;
}
if ( gridNode.getGridBlock().getFlags().contains( GridFlags.REQURE_CHANNEL ) )
requireChannels.add( 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.beginVisition( 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();
}
@Override
public void onSplit(IGridStorage storageB)
{
}
@Override
public void onJoin(IGridStorage storageB)
{
}
@Override
public void populateGridStorage(IGridStorage storage)
{
}
}
+219
View File
@@ -0,0 +1,219 @@
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.Configuration;
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;
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 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 requirePylongBlocks = 1;
double effiency = 0.0;
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.isActive() )
{
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;
requirePylongBlocks = ((reqX * reqZ + reqX * reqY + reqY * reqZ) * 3) / 5;
effiency = (double) pylonBlocks / (double) requirePylongBlocks;
if ( effiency > 1.0 )
effiency = 1.0;
if ( effiency < 0.0 )
effiency = 0.0;
minPower = (double) reqX * (double) reqY * reqZ * Configuration.instance.spatialPowerMultiplier;
maxPower = Math.pow( minPower, Configuration.instance.spatialPowerScaler );
}
double affective_effiency = Math.pow( effiency, 0.25 );
powerRequired = (long) (affective_effiency * minPower + (1.0 - affective_effiency) * maxPower);
for (SpatialPylonCluster cl : clusters.values())
{
boolean myWasValid = cl.isValid;
cl.isValid = isValid;
if ( myWasValid != isValid )
cl.updateStatus( false );
}
}
@MENetworkEventSubscribe
public void bootingRender(MENetworkBootingStatusChange c)
{
reset( myGrid );
}
@Override
public void onUpdateTick(IGrid grid)
{
}
@Override
public void addNode(IGrid grid, IGridNode node, IGridHost machine)
{
}
@Override
public void removeNode(IGrid grid, IGridNode node, IGridHost machine)
{
}
@Override
public void onSplit(IGridStorage storageB)
{
}
@Override
public void onJoin(IGridStorage storageB)
{
}
@Override
public void populateGridStorage(IGridStorage storage)
{
}
}
+217
View File
@@ -0,0 +1,217 @@
package appeng.me.cache;
import java.util.HashMap;
import java.util.PriorityQueue;
import net.minecraft.tileentity.TileEntity;
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.core.AELog;
import appeng.me.cache.helpers.TickTracker;
import appeng.util.Platform;
public class TickManagerCache implements ITickManager
{
private long currentTick = 0;
private long lastInnerTime = 0;
final IGrid myGrid;
public TickManagerCache(IGrid g) {
myGrid = g;
}
HashMap<IGridNode, TickTracker> alertable = new HashMap<IGridNode, TickTracker>();
HashMap<IGridNode, TickTracker> sleeping = new HashMap<IGridNode, TickTracker>();
HashMap<IGridNode, TickTracker> awake = new HashMap<IGridNode, TickTracker>();
PriorityQueue<TickTracker> upcomingTicks = new PriorityQueue<TickTracker>();
public long getCurrentTick()
{
return currentTick;
}
public long getInnerTime()
{
return lastInnerTime;
}
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(IGrid grid)
{
currentTick++;
while (!upcomingTicks.isEmpty())
{
TickTracker tt = upcomingTicks.peek();
int diff = (int) (currentTick - tt.lastTick);
if ( diff >= tt.current_rate )
{
// remove tt..
upcomingTicks.poll();
long startTime = Platform.nanoTime();
TickRateModulation mod = tt.gt.tickingRequest( tt.node, diff );
long estimatedTime = Platform.nanoTime() - startTime;
lastInnerTime += estimatedTime;
tt.LastFiveTicksTime = ((tt.LastFiveTicksTime * 4) / 5) + estimatedTime;
switch (mod)
{
case FASTER:
tt.setRate( tt.current_rate - 1 );
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!
}
}
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 )
throw new RuntimeException( "Invalid Alertted device, this node is not marked as alertable, or part of this grid." );
tt.lastTick = -tt.request.maxTickRate;
addToQueue( 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(IGrid grid, IGridNode gridNode, IGridHost machine)
{
if ( machine instanceof IGridTickable )
{
alertable.remove( gridNode );
sleeping.remove( gridNode );
awake.remove( gridNode );
}
}
@Override
public void addNode(IGrid grid, IGridNode gridNode, IGridHost machine)
{
if ( machine instanceof IGridTickable )
{
TickingRequest tr = ((IGridTickable) machine).getTickingRequest( gridNode );
if ( tr != null )
{
if ( machine instanceof TileEntity && ((TileEntity) machine).canUpdate() )
AELog.warning( "Tile: " + machine.getClass().getName() + " - reports to use MC ticking, but also requests Network Based Ticking." );
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)
{
}
}
+51
View File
@@ -0,0 +1,51 @@
package appeng.me.cache.helpers;
import appeng.api.networking.IGridNode;
import appeng.api.networking.ticking.IGridTickable;
import appeng.api.networking.ticking.TickingRequest;
import appeng.me.cache.TickManagerCache;
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)
{
return (int) ((host.getCurrentTick() - lastTick) + current_rate);
}
};
+16
View File
@@ -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();
}
+12
View File
@@ -0,0 +1,12 @@
package appeng.me.cluster;
public interface IAEMultiBlock
{
void disconnect();
IAECluster getCluster();
boolean isValid();
}
+194
View File
@@ -0,0 +1,194 @@
package appeng.me.cluster;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import net.minecraftforge.common.ForgeDirection;
import appeng.api.util.WorldCoord;
import appeng.util.Platform;
public abstract class MBCalculator
{
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 dimentions, 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.getBlockTileEntity( 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)
{
err.printStackTrace();
}
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.getBlockTileEntity( 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,30 @@
package appeng.me.cluster.implementations;
import java.util.Iterator;
import appeng.api.networking.IGridHost;
import appeng.me.cluster.IAECluster;
public class IAssemblerCluster implements IAECluster
{
@Override
public void updateStatus(boolean updateGrid)
{
// TODO Auto-generated method stub
}
@Override
public void destroy()
{
// TODO Auto-generated method stub
}
@Override
public Iterator<IGridHost> getTiles()
{
// TODO Auto-generated method stub
return null;
}
}
@@ -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
{
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.getBlockTileEntity( x, y, z );
byte Fish = 0;
num++;
if ( num == 5 )
{
Fish = (byte) (num);
c.setCenter( te );
}
else
{
if ( num == 1 || num == 3 || num == 7 || num == 9 )
Fish = (byte) (tqb.corner | num);
else
Fish = (byte) (num);
c.Ring[ringNum++] = te;
}
te.updateStatus( c, Fish );
}
}
}
}
@Override
public IAECluster createCluster(World w, WorldCoord min, WorldCoord max)
{
return new QuantumCluster( min, max );
}
@Override
public void disconnect()
{
tqb.disconnect();
}
@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.getBlockTileEntity( 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,224 @@
package appeng.me.cluster.implementations;
import java.util.Iterator;
import net.minecraft.world.chunk.Chunk;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.ForgeSubscribe;
import net.minecraftforge.event.world.WorldEvent;
import appeng.api.AEApi;
import appeng.api.events.LocatableEventAnnounce;
import appeng.api.events.LocatableEventAnnounce.LocatableEvent;
import appeng.api.features.ILocatable;
import appeng.api.networking.IGridHost;
import appeng.api.util.DimensionalCoord;
import appeng.api.util.WorldCoord;
import appeng.me.cluster.IAECluster;
import appeng.tile.qnb.TileQuantumBridge;
import appeng.util.iterators.ChainedIterator;
public class QuantumCluster implements ILocatable, IAECluster
{
public WorldCoord min;
public WorldCoord max;
public boolean isDestroyed = false;
boolean registered = false;
private long thisSide;
private long otherSide;
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().locateable().findLocateableBySerial( qe );
if ( qc.center instanceof TileQuantumBridge )
{
if ( !qc.isDestroyed )
{
Chunk c = qc.center.worldObj.getChunkFromBlockCoords( qc.center.xCoord, qc.center.zCoord );
if ( c.isChunkLoaded )
return false;
}
}
return true;
}
@ForgeSubscribe
public void onUnload(WorldEvent.Unload e)
{
if ( center.worldObj == e.world )
{
destroy();
}
}
@Override
public void updateStatus(boolean updateGrid)
{
long oldOtherSide = otherSide;
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;
}
}
if ( updateGrid )
{
updateGrid( this );
Object myOtherSide = otherSide == 0 ? null : AEApi.instance().registries().locateable().findLocateableBySerial( otherSide );
Object oldMyOtherSide = oldOtherSide == 0 ? null : AEApi.instance().registries().locateable().findLocateableBySerial( oldOtherSide );
if ( myOtherSide instanceof QuantumCluster )
updateGrid( (QuantumCluster) myOtherSide );
if ( oldMyOtherSide instanceof QuantumCluster )
updateGrid( (QuantumCluster) oldMyOtherSide );
}
}
public void updateRender()
{
for (int x = 0; x < Ring.length; x++)
{
}
}
private void updateGrid(QuantumCluster c)
{
}
@Override
public void destroy()
{
if ( isDestroyed )
return;
isDestroyed = true;
if ( registered )
{
MinecraftForge.EVENT_BUS.unregister( this );
registered = false;
}
if ( getLocatableSerial() != 0 )
{
updateGrid( this );
Object myOtherSide = otherSide == 0 ? null : AEApi.instance().registries().locateable().findLocateableBySerial( otherSide );
if ( myOtherSide instanceof QuantumCluster )
updateGrid( (QuantumCluster) myOtherSide );
MinecraftForge.EVENT_BUS.post( new LocatableEventAnnounce( this, LocatableEvent.Unregister ) );
}
// updateStatus( true );
center.updateStatus( null, (byte) -1 );
for (TileQuantumBridge r : Ring)
{
r.updateStatus( null, (byte) -1 );
}
center = null;
Ring = new TileQuantumBridge[8];
}
public boolean isCorner(TileQuantumBridge tileQuantumBridge)
{
return Ring[0] == tileQuantumBridge || Ring[2] == tileQuantumBridge || Ring[4] == tileQuantumBridge || Ring[6] == tileQuantumBridge;
}
public DimensionalCoord[] getOtherSide()
{
Object myOtherSide = AEApi.instance().registries().locateable().findLocateableBySerial( otherSide );
if ( myOtherSide != null )
{
try
{
QuantumCluster qc = (QuantumCluster) myOtherSide;
DimensionalCoord[] out = new DimensionalCoord[4];
out[0] = new DimensionalCoord( qc.Ring[1] );
out[1] = new DimensionalCoord( qc.Ring[3] );
out[2] = new DimensionalCoord( qc.Ring[4] );
out[3] = new DimensionalCoord( qc.Ring[6] );
return out;
}
catch (Throwable t)
{
}
}
return new DimensionalCoord[0];
}
@Override
public long getLocatableSerial()
{
return thisSide;
}
public boolean hasPower()
{
return center.bridgePowered;
}
public TileQuantumBridge getCenter()
{
return center;
}
public boolean hasQES()
{
return getLocatableSerial() != 0;
}
}
@@ -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
{
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.getBlockTileEntity( 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();
}
@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.getBlockTileEntity( 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
};
public DimensionalCoord min;
public DimensionalCoord max;
public boolean isDestroyed = false;
public Axis currentAxis = Axis.UNFORMED;
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();
}
}
+299
View File
@@ -0,0 +1,299 @@
package appeng.me.helpers;
import java.util.EnumSet;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.common.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.energy.IEnergyGrid;
import appeng.api.networking.events.MENetworkPowerIdleChange;
import appeng.api.networking.pathing.IPathingGrid;
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.helpers.TickHandler;
import appeng.me.GridAccessException;
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 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
public AENetworkProxy(IGridProxyable te, String nbtName, boolean inWorld) {
this.gp = te;
this.nbtName = nbtName;
worldNode = inWorld;
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;
}
}
@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;
}
@Override
public boolean isNetworkMachineActive()
{
if ( node == null )
return false;
return node.getGrid().isReady();
}
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;
}
@Override
public boolean isWorldAccessable()
{
return worldNode;
}
@Override
public EnumSet<GridFlags> getFlags()
{
return flags;
}
public void setFlags(GridFlags... requreChannel)
{
EnumSet<GridFlags> flags = EnumSet.noneOf( GridFlags.class );
for (GridFlags gf : requreChannel)
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();
}
@Override
public void gridChanged()
{
gp.gridChanged();
}
}
+32
View File
@@ -0,0 +1,32 @@
package appeng.me.helpers;
import java.util.Iterator;
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, boolean inWorld) {
super( te, nbtName, inWorld );
}
@Override
public Iterator<IGridNode> getMultiblockNodes()
{
if ( getCluster() == null )
return new ChainedIterator<IGridNode>();
return new ProxyNodeIterator( getCluster().getTiles() );
}
}
+12
View File
@@ -0,0 +1,12 @@
package appeng.me.helpers;
import appeng.api.networking.IGridHost;
import appeng.api.util.DimensionalCoord;
public interface IGridProxyable extends IGridHost
{
DimensionalCoord getLocation();
void gridChanged();
}
+36
View File
@@ -0,0 +1,36 @@
package appeng.me.pathfinding;
import appeng.api.networking.IGridConnecitonVisitor;
import appeng.api.networking.IGridConnection;
import appeng.api.networking.IGridNode;
import appeng.me.GridConnection;
import appeng.me.GridNode;
public class AdHocChannelUpdater implements IGridConnecitonVisitor
{
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.IGridConnecitonVisitor;
import appeng.api.networking.IGridConnection;
import appeng.api.networking.IGridNode;
import appeng.me.GridConnection;
import appeng.me.GridNode;
public class ControllerChannelUpdater implements IGridConnecitonVisitor
{
@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();
}
}
+59
View File
@@ -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;
}
}
+44
View File
@@ -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();
}
+132
View File
@@ -0,0 +1,132 @@
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;
public class PathSegment
{
public boolean isDead;
static class RouteComplete extends Exception
{
private static final long serialVersionUID = 810456465120286110L;
};
public PathSegment(List open, Set semiopen, Set closed) {
this.open = open;
this.semiopen = semiopen;
this.closed = closed;
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.REQURE_CHANNEL ) )
{
// close the semi open.
if ( !semiopen.contains( pi ) )
{
boolean worked = false;
if ( flags.contains( GridFlags.DENSE_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)
{
pi.incrementChannelCount( 1 );
pi = pi.getControllerRoute();
}
return true;
}
private boolean useDenseChannel(IPathItem start)
{
IPathItem pi = start;
while (pi != null)
{
if ( !pi.canSupportMoreChannels() || pi.getFlags().contains( GridFlags.CANNOT_CARRY_DENSE ) )
return false;
pi = pi.getControllerRoute();
}
pi = start;
while (pi != null)
{
pi.incrementChannelCount( 1 );
pi = pi.getControllerRoute();
}
return true;
}
}
+66
View File
@@ -0,0 +1,66 @@
package appeng.me.storage;
import net.minecraft.inventory.IInventory;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.common.ForgeDirection;
import appeng.api.implementations.IStorageMonitorable;
import appeng.api.storage.IExternalStorageHandler;
import appeng.api.storage.IMEInventory;
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)
{
if ( channel == StorageChannel.ITEMS && te instanceof IStorageMonitorable )
return true;
if ( channel == StorageChannel.ITEMS && te instanceof IInventory )
return true;
return te instanceof TileCondenser;
}
@Override
public IMEInventory getInventory(TileEntity te, ForgeDirection d, StorageChannel channel)
{
if ( te instanceof TileCondenser )
{
if ( channel == StorageChannel.ITEMS )
return new VoidItemInventory( (TileCondenser) te );
else
return new VoidFluidInventory( (TileCondenser) te );
}
if ( te instanceof IStorageMonitorable )
{
IStorageMonitorable iface = (IStorageMonitorable) te;
if ( channel == StorageChannel.ITEMS )
{
IMEInventory<IAEItemStack> ii = iface.getItemInventory();
if ( ii != null )
return ii;
}
if ( channel == StorageChannel.FLUIDS )
{
IMEInventory<IAEFluidStack> fi = iface.getFluidInventory();
if ( fi != null )
return fi;
}
}
if ( channel == StorageChannel.ITEMS && te instanceof IInventory )
{
return new MEMonitorIInventory( (IInventory) te, d );
}
return null;
}
}
+485
View File
@@ -0,0 +1,485 @@
package appeng.me.storage;
import java.util.HashSet;
import java.util.Iterator;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagInt;
import net.minecraft.nbt.NBTTagShort;
import net.minecraftforge.oredict.OreDictionary;
import appeng.api.config.Actionable;
import appeng.api.exceptions.AppEngException;
import appeng.api.implementations.IStorageCell;
import appeng.api.storage.IMEInventory;
import appeng.api.storage.IMEInventoryHandler;
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.item.ItemList;
public class CellInventory implements IMEInventory<IAEItemStack>
{
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_FORMATED_COUNT = "PF";
static final String ITEM_PRE_FORMATED_SLOT = "PF#";
static final String ITEM_PRE_FORMATED_NAME = "PN";
static final String ITEM_PRE_FORMATED_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 ItemList<IAEItemStack> cellItems;
protected ItemStack i;
protected IStorageCell CellType;
protected CellInventory(NBTTagCompound data) {
tagCompound = data;
}
protected void loadCellItems()
{
if ( cellItems == null )
cellItems = new ItemList();
cellItems.resetStatus(); // clears totals and stuff.
int types = (int) storedItemTypes();
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.setCompoundTag( 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] );
}
}
protected CellInventory(ItemStack o) 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;
tagCompound = Platform.openNbtData( o );
storedItems = tagCompound.getShort( ITEM_TYPE_TAG );
storedItemCount = tagCompound.getInteger( ITEM_COUNT_TAG );
cellItems = null;
}
ItemList<IAEItemStack> getCellItems()
{
if ( cellItems == null )
{
cellItems = new ItemList();
loadCellItems();
}
return cellItems;
}
public int BytesPerType()
{
return CellType.BytePerType( i );
}
public boolean canHoldNewItem()
{
long bytesFree = freeBytes();
return (bytesFree > BytesPerType() || (bytesFree == BytesPerType() && unusedItemCount() > 0)) && remainingItemTypes() > 0;
}
public static IMEInventoryHandler getCell(ItemStack o)
{
try
{
return new CellInventoryHandler( new CellInventory( o ) );
}
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;
}
public long totalBytes()
{
return CellType.getBytes( i );
}
public long freeBytes()
{
return totalBytes() - usedBytes();
}
public long usedBytes()
{
long bytesForItemCount = (storedItemCount() + unusedItemCount()) / 8;
return storedItemTypes() * BytesPerType() + bytesForItemCount;
}
public long getTotalItemTypes()
{
return MAX_ITEM_TYPES;
}
public long storedItemTypes()
{
return storedItems;
}
public long storedItemCount()
{
return storedItemCount;
}
private void updateItemCount(long delta)
{
tagCompound.setInteger( ITEM_COUNT_TAG, storedItemCount = (int) (storedItemCount + delta) );
}
public long remainingItemTypes()
{
long basedOnStorage = freeBytes() / BytesPerType();
long baseOnTotal = getTotalItemTypes() - storedItemTypes();
return basedOnStorage > baseOnTotal ? baseOnTotal : basedOnStorage;
}
public long remainingItemCount()
{
long remaining = freeBytes() * 8 + unusedItemCount();
return remaining > 0 ? remaining : 0;
}
// returns the number of items that can be added without using an additional
// byte!
public int unusedItemCount()
{
int div = (int) (storedItemCount() % 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) | input.getItem().itemID ) )
return true;
return blackList.contains( (input.getItemDamage() << Platform.DEF_OFFSET) | input.getItem().itemID );
}
private boolean isEmpty(IMEInventory meinv)
{
return meinv.getAvailableItems( new ItemList() ).isEmpty();
}
@Override
public IAEItemStack injectItems(IAEItemStack input, Actionable mode)
{
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 );
if ( meinv != null && !isEmpty( meinv ) )
return input;
}
IAEItemStack l = getCellItems().findPrecise( input );
if ( l != null )
{
long remainingItemSlots = remainingItemCount();
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) remainingItemCount() - BytesPerType() * 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)
{
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;
}
public double getIdleDrain()
{
return CellType.getIdleDrain();
}
}
+25
View File
@@ -0,0 +1,25 @@
package appeng.me.storage;
import net.minecraft.nbt.NBTTagCompound;
import appeng.api.storage.IMEInventory;
import appeng.api.storage.data.IAEItemStack;
import appeng.util.Platform;
public class CellInventoryHandler extends MEInventoryHandler<IAEItemStack>
{
NBTTagCompound openNbtData()
{
return Platform.openNbtData( getCellInv().i );
}
public CellInventory getCellInv()
{
return (CellInventory) (this.internal instanceof CellInventory ? this.internal : null);
}
CellInventoryHandler(IMEInventory c) {
super( c );
}
}
+118
View File
@@ -0,0 +1,118 @@
package appeng.me.storage;
import net.minecraft.item.ItemStack;
import appeng.api.config.Actionable;
import appeng.api.exceptions.AppEngException;
import appeng.api.implementations.IStorageCell;
import appeng.api.storage.IMEInventoryHandler;
import appeng.api.storage.data.IAEItemStack;
import appeng.util.Platform;
import appeng.util.item.ItemList;
public class CreativeCellInventory extends CellInventory implements IStorageCell
{
ItemList itemListCache;
public static IMEInventoryHandler getCell(ItemStack o)
{
try
{
return new CellInventoryHandler( new CreativeCellInventory( o ) );
}
catch (AppEngException e)
{
}
return null;
}
protected CreativeCellInventory(ItemStack o) throws AppEngException {
super( Platform.openNbtData( o ) );
if ( MAX_ITEM_TYPES > 63 )
MAX_ITEM_TYPES = 63;
if ( MAX_ITEM_TYPES < 1 )
MAX_ITEM_TYPES = 1;
storedItems = tagCompound.getShort( ITEM_TYPE_TAG );
storedItemCount = tagCompound.getInteger( ITEM_COUNT_TAG );
cellItems = null;
}
@Override
public boolean isStorageCell(ItemStack i)
{
return true;
}
@Override
public int getBytes(ItemStack cellItem)
{
return 0;
}
@Override
public int BytePerType(ItemStack iscellItem)
{
return 8;
}
@Override
public int getTotalTypes(ItemStack cellItem)
{
return 63;
}
@Override
public boolean isBlackListed(ItemStack cellItem, IAEItemStack requsetedAddition)
{
return false;
}
@Override
public boolean storableInStorageCell()
{
return false;
}
@Override
public IAEItemStack injectItems(IAEItemStack input, Actionable mode)
{
IAEItemStack local = getCellItems().findPrecise( input );
if ( local == null )
return input;
return null;
}
@Override
public IAEItemStack extractItems(IAEItemStack request, Actionable mode)
{
IAEItemStack local = getCellItems().findPrecise( request );
if ( local == null )
return null;
return request.copy();
}
@Override
ItemList<IAEItemStack> getCellItems()
{
if ( itemListCache != null )
return itemListCache;
ItemList list = new ItemList();
CellInventoryHandler handler = new CellInventoryHandler( this );
for (IAEItemStack is : handler.myPartitionList.getItems())
{
IAEItemStack b = is.copy();
b.setStackSize( Integer.MAX_VALUE );
list.add( b );
}
return itemListCache = list;
}
}
+196
View File
@@ -0,0 +1,196 @@
package appeng.me.storage;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import appeng.api.config.Actionable;
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)
{
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)
{
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;
}
}
+102
View File
@@ -0,0 +1,102 @@
package appeng.me.storage;
import appeng.api.config.AccessRestriction;
import appeng.api.config.Actionable;
import appeng.api.config.IncludeExclude;
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 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();
public MEInventoryHandler(IMEInventory<T> i) {
if ( i instanceof IMEInventoryHandler )
internal = (IMEInventoryHandler<T>) i;
else
internal = new MEPassthru<T>( i );
monitor = internal instanceof IMEMonitor ? (IMEMonitor<T>) internal : null;
}
@Override
public T injectItems(T input, Actionable type)
{
if ( !this.canAccept( input ) )
return input;
return internal.injectItems( input, type );
}
@Override
public T extractItems(T request, Actionable type)
{
return internal.extractItems( request, type );
}
@Override
public IItemList<T> getAvailableItems(IItemList out)
{/*
* if ( monitor != null ) { for (T is : monitor.getStorageList()) out.add( is );
*
* return out; } else
*/
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 ( 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();
}
}
+257
View File
@@ -0,0 +1,257 @@
package appeng.me.storage;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.TreeMap;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraftforge.common.ForgeDirection;
import appeng.api.AEApi;
import appeng.api.config.AccessRestriction;
import appeng.api.config.Actionable;
import appeng.api.networking.ticking.TickRateModulation;
import appeng.api.storage.IMEInventory;
import appeng.api.storage.IMEMonitor;
import appeng.api.storage.IMEMontorHandlerReciever;
import appeng.api.storage.StorageChannel;
import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IItemList;
import appeng.core.AELog;
import appeng.util.InventoryAdaptor;
import appeng.util.Platform;
import appeng.util.inv.ItemSlot;
import appeng.util.item.AEItemStack;
import appeng.util.item.ItemList;
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 IInventory internal;
final ForgeDirection side;
final InventoryAdaptor adaptor;
final TreeMap<Integer, CachedItemStack> memory;
final IItemList<IAEItemStack> list = new ItemList();
final HashMap<IMEMontorHandlerReciever<IAEItemStack>, Object> listeners = new HashMap();
@Override
public void addListener(IMEMontorHandlerReciever<IAEItemStack> l, Object verificationToken)
{
listeners.put( l, verificationToken );
}
@Override
public void removeListener(IMEMontorHandlerReciever<IAEItemStack> l)
{
listeners.remove( l );
}
public MEMonitorIInventory(IInventory inv, ForgeDirection dir) {
adaptor = InventoryAdaptor.getAdaptor( inv, dir );
memory = new TreeMap();
internal = inv;
side = dir;
}
@Override
public IAEItemStack injectItems(IAEItemStack input, Actionable type)
{
ItemStack out = null;
if ( type == Actionable.SIMULATE )
out = adaptor.simulateAdd( input.getItemStack() );
else
out = adaptor.addItems( input.getItemStack() );
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()
{
for (IAEItemStack is : list)
AELog.info( "sl: " + is.getItemStack().getUnlocalizedName() + " @ " + is.getStackSize() );
return list;
}
@Override
public IItemList<IAEItemStack> getAvailableItems(IItemList out)
{
for (ItemSlot is : adaptor)
out.addStorage( AEItemStack.create( is.itemStack ) );
return out;
}
@Override
public IAEItemStack extractItems(IAEItemStack request, Actionable type)
{
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 );
return o;
}
public TickRateModulation onTick()
{
boolean changed = false;
list.resetStatus();
for (ItemSlot is : adaptor)
{
CachedItemStack old = memory.get( is.slot );
ItemStack newIS = is == null ? null : is.itemStack;
ItemStack oldIS = old == null ? null : old.itemStack;
if ( isDiffrent( newIS, oldIS ) )
{
CachedItemStack cis = new CachedItemStack( is.itemStack );
memory.put( is.slot, cis );
if ( old != null && old.aeStack != null )
{
old.aeStack.setStackSize( -old.aeStack.getStackSize() );
postDiffrence( old.aeStack );
}
if ( cis != null && cis.aeStack != null )
{
postDiffrence( 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.itemStack );
memory.put( is.slot, cis );
IAEItemStack a = stack.copy();
a.setStackSize( diff );
postDiffrence( a );
changed = true;
}
}
}
return changed ? TickRateModulation.URGENT : TickRateModulation.SLOWER;
}
private boolean isDiffrent(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 postDiffrence(IAEItemStack a)
{
AELog.info( a.getItemStack().getUnlocalizedName() + " @ " + a.getStackSize() );
if ( a != null )
{
Iterator<Entry<IMEMontorHandlerReciever<IAEItemStack>, Object>> i = listeners.entrySet().iterator();
while (i.hasNext())
{
Entry<IMEMontorHandlerReciever<IAEItemStack>, Object> l = i.next();
IMEMontorHandlerReciever<IAEItemStack> key = l.getKey();
if ( key.isValid( l.getValue() ) )
key.postChange( a );
else
i.remove();
}
}
}
@Override
public StorageChannel getChannel()
{
return StorageChannel.ITEMS;
}
}
+88
View File
@@ -0,0 +1,88 @@
package appeng.me.storage;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import appeng.api.storage.IMEInventory;
import appeng.api.storage.IMEMonitor;
import appeng.api.storage.IMEMontorHandlerReciever;
import appeng.api.storage.data.IAEStack;
import appeng.api.storage.data.IItemList;
import appeng.util.Platform;
import appeng.util.item.ItemList;
public class MEMonitorPassthu<T extends IAEStack<T>> extends MEPassthru<T> implements IMEMonitor<T>, IMEMontorHandlerReciever<T>
{
HashMap<IMEMontorHandlerReciever<T>, Object> listeners = new HashMap();
IMEMonitor<T> monitor;
public MEMonitorPassthu(IMEInventory<T> i) {
super( i );
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 ? new ItemList() : getInternal().getAvailableItems( new ItemList() );
super.setInternal( i );
if ( i instanceof IMEMonitor )
monitor = (IMEMonitor<T>) i;
IItemList<T> after = getInternal() == null ? new ItemList() : getInternal().getAvailableItems( new ItemList() );
if ( monitor != null )
monitor.addListener( this, monitor );
Platform.postListChanges( before, after, this );
}
@Override
public void addListener(IMEMontorHandlerReciever<T> l, Object verificationToken)
{
listeners.put( l, verificationToken );
}
@Override
public void removeListener(IMEMontorHandlerReciever<T> l)
{
listeners.remove( l );
}
@Override
public IItemList<T> getStorageList()
{
if ( monitor == null )
return getInternal().getAvailableItems( new ItemList<T>() );
return monitor.getStorageList();
}
@Override
public boolean isValid(Object verificationToken)
{
return verificationToken == monitor;
}
@Override
public void postChange(T change)
{
Iterator<Entry<IMEMontorHandlerReciever<T>, Object>> i = listeners.entrySet().iterator();
while (i.hasNext())
{
Entry<IMEMontorHandlerReciever<T>, Object> e = i.next();
IMEMontorHandlerReciever<T> recv = e.getKey();
if ( recv.isValid( e.getValue() ) )
recv.postChange( change );
else
i.remove();
}
}
}
+84
View File
@@ -0,0 +1,84 @@
package appeng.me.storage;
import appeng.api.config.AccessRestriction;
import appeng.api.config.Actionable;
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;
protected IMEInventory<T> getInternal()
{
return internal;
}
public MEPassthru(IMEInventory<T> i) {
setInternal( i );
}
public void setInternal(IMEInventory<T> i)
{
internal = i;
}
@Override
public T injectItems(T input, Actionable type)
{
return internal.injectItems( input, type );
}
@Override
public T extractItems(T request, Actionable type)
{
return internal.extractItems( request, type );
}
@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;
}
}
+213
View File
@@ -0,0 +1,213 @@
package appeng.me.storage;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map.Entry;
import appeng.api.config.AccessRestriction;
import appeng.api.config.Actionable;
import appeng.api.storage.IMEInventoryHandler;
import appeng.api.storage.StorageChannel;
import appeng.api.storage.data.IAEStack;
import appeng.api.storage.data.IItemList;
import com.google.common.collect.TreeMultimap;
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 o1 - o2;
}
};
private final static Comparator hashSorter = new Comparator<IMEInventoryHandler>() {
@Override
public int compare(IMEInventoryHandler o1, IMEInventoryHandler o2)
{
return o1.hashCode() - o2.hashCode();
}
};
final StorageChannel myChannel;
final TreeMultimap<Integer, IMEInventoryHandler<T>> prorityInventory;
public NetworkInventoryHandler(StorageChannel chan) {
myChannel = chan;
prorityInventory = TreeMultimap.create( prioritySorter, hashSorter );
}
public void addNewStorage(IMEInventoryHandler<T> h)
{
prorityInventory.put( h.getPriority(), h );
}
static int currentPass = 0;
int myPass = 0;
final static public LinkedList depth = new LinkedList();
private boolean diveList(NetworkInventoryHandler<T> networkInventoryHandler)
{
if ( depth.contains( networkInventoryHandler ) )
return true;
depth.push( this );
return false;
}
private boolean diveIteration(NetworkInventoryHandler<T> networkInventoryHandler)
{
if ( depth.isEmpty() )
{
currentPass++;
myPass = currentPass;
}
else
{
if ( currentPass == myPass )
return true;
else
myPass = currentPass;
}
depth.push( this );
return false;
}
private void surface(NetworkInventoryHandler<T> networkInventoryHandler)
{
Object last = depth.pop();
if ( last != this )
throw new RuntimeException( "Invalid Access to Networked Storage API detected." );
}
@Override
public T injectItems(T input, Actionable type)
{
if ( diveList( this ) )
return input;
Iterator<Entry<Integer, Collection<IMEInventoryHandler<T>>>> i = prorityInventory.asMap().entrySet().iterator();
while (i.hasNext())
{
Entry<Integer, Collection<IMEInventoryHandler<T>>> invList = i.next();
Iterator<IMEInventoryHandler<T>> ii = invList.getValue().iterator();
while (ii.hasNext() && input != null)
{
IMEInventoryHandler<T> inv = ii.next();
if ( inv.canAccept( input ) && (inv.extractItems( input, Actionable.SIMULATE ) != null || inv.isPrioritized( input )) )
input = inv.injectItems( input, type );
}
ii = invList.getValue().iterator();
while (ii.hasNext() && input != null)
{
IMEInventoryHandler<T> inv = ii.next();
if ( inv.canAccept( input ) )
input = inv.injectItems( input, type );
}
}
surface( this );
return input;
}
@Override
public T extractItems(T request, Actionable mode)
{
if ( diveList( this ) )
return null;
Iterator<Entry<Integer, Collection<IMEInventoryHandler<T>>>> i = prorityInventory.asMap().descendingMap().entrySet().iterator();
T output = request.copy();
request = request.copy();
output.setStackSize( 0 );
long req = request.getStackSize();
while (i.hasNext())
{
Entry<Integer, Collection<IMEInventoryHandler<T>>> invList = i.next();
Iterator<IMEInventoryHandler<T>> ii = invList.getValue().iterator();
while (ii.hasNext() && output.getStackSize() < req)
{
IMEInventoryHandler<T> inv = ii.next();
request.setStackSize( req - output.getStackSize() );
output.add( inv.extractItems( request, mode ) );
}
}
surface( this );
if ( output.getStackSize() <= 0 )
return null;
return output;
}
@Override
public IItemList<T> getAvailableItems(IItemList out)
{
if ( diveIteration( this ) )
return out;
for (Entry<Integer, IMEInventoryHandler<T>> h : prorityInventory.entries())
out = h.getValue().getAvailableItems( out );
surface( this );
return out;
}
@Override
public StorageChannel getChannel()
{
return myChannel;
}
@Override
public AccessRestriction getAccess()
{
return AccessRestriction.READ_WRITE;
}
@Override
public boolean isPrioritized(T input)
{
return false;
}
@Override
public boolean canAccept(T input)
{
return true;
}
@Override
public int getPriority()
{
return 0;
}
@Override
public int getSlot()
{
return 0;
}
}
+67
View File
@@ -0,0 +1,67 @@
package appeng.me.storage;
import appeng.api.config.AccessRestriction;
import appeng.api.config.Actionable;
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)
{
return input;
}
@Override
public T extractItems(T request, Actionable mode)
{
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;
}
}
+76
View File
@@ -0,0 +1,76 @@
package appeng.me.storage;
import appeng.api.config.AccessRestriction;
import appeng.api.config.Actionable;
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)
{
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)
{
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;
}
}
+76
View File
@@ -0,0 +1,76 @@
package appeng.me.storage;
import appeng.api.config.AccessRestriction;
import appeng.api.config.Actionable;
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)
{
if ( input != null )
target.addPower( input.getStackSize() );
return null;
}
@Override
public StorageChannel getChannel()
{
return StorageChannel.ITEMS;
}
@Override
public IAEItemStack extractItems(IAEItemStack request, Actionable mode)
{
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;
}
}