Applied-Energistics-2-tiler.../src/main/java/appeng/spatial/CachedPlane.java

438 lines
12 KiB
Java
Raw Normal View History

2014-11-14 12:02:52 +01:00
/*
* This file is part of Applied Energistics 2.
2015-05-18 00:02:28 +02:00
* Copyright (c) 2013 - 2015, AlgorithmX2, All rights reserved.
2014-11-14 12:02:52 +01:00
*
* Applied Energistics 2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Applied Energistics 2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.spatial;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;
import net.minecraft.block.Block;
2015-06-16 02:44:59 +02:00
import net.minecraft.block.state.IBlockState;
import net.minecraft.tileentity.TileEntity;
2015-06-16 02:44:59 +02:00
import net.minecraft.util.BlockPos;
import net.minecraft.world.NextTickListEntry;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
import appeng.api.AEApi;
import appeng.api.definitions.IBlockDefinition;
import appeng.api.movable.IMovableHandler;
import appeng.api.movable.IMovableRegistry;
2015-06-16 02:44:59 +02:00
import appeng.api.util.AEPartLocation;
import appeng.api.util.WorldCoord;
import appeng.core.AELog;
import appeng.core.WorldSettings;
2014-02-09 02:34:52 +01:00
import appeng.util.Platform;
public class CachedPlane
{
final int x_size;
final int z_size;
final int cx_size;
final int cz_size;
final int x_offset;
final int y_offset;
final int z_offset;
final int y_size;
final Chunk[][] myChunks;
final Column[][] myColumns;
final LinkedList<TileEntity> tiles = new LinkedList<TileEntity>();
final LinkedList<NextTickListEntry> ticks = new LinkedList<NextTickListEntry>();
final World world;
final IMovableRegistry reg = AEApi.instance().registries().movable();
final LinkedList<WorldCoord> updates = new LinkedList<WorldCoord>();
private final IBlockDefinition matrixFrame = AEApi.instance().definitions().blocks().matrixFrame();
int verticalBits;
public CachedPlane( World w, int minX, int minY, int minZ, int maxX, int maxY, int maxZ )
{
2014-12-29 15:13:47 +01:00
this.world = w;
2014-12-29 15:13:47 +01:00
this.x_size = maxX - minX + 1;
this.y_size = maxY - minY + 1;
this.z_size = maxZ - minZ + 1;
2014-12-29 15:13:47 +01:00
this.x_offset = minX;
this.y_offset = minY;
this.z_offset = minZ;
int minCX = minX >> 4;
int minCY = minY >> 4;
int minCZ = minZ >> 4;
int maxCX = maxX >> 4;
int maxCY = maxY >> 4;
int maxCZ = maxZ >> 4;
2014-12-29 15:13:47 +01:00
this.cx_size = maxCX - minCX + 1;
int cy_size = maxCY - minCY + 1;
2014-12-29 15:13:47 +01:00
this.cz_size = maxCZ - minCZ + 1;
2014-12-29 15:13:47 +01:00
this.myChunks = new Chunk[this.cx_size][this.cz_size];
this.myColumns = new Column[this.x_size][this.z_size];
2014-12-29 15:13:47 +01:00
this.verticalBits = 0;
for( int cy = 0; cy < cy_size; cy++ )
{
this.verticalBits |= 1 << ( minCY + cy );
}
for( int x = 0; x < this.x_size; x++ )
2015-04-29 02:30:53 +02:00
{
for( int z = 0; z < this.z_size; z++ )
{
this.myColumns[x][z] = new Column( w.getChunkFromChunkCoords( ( minX + x ) >> 4, ( minZ + z ) >> 4 ), ( minX + x ) & 0xF, ( minZ + z ) & 0xF, minCY, cy_size );
}
2015-04-29 02:30:53 +02:00
}
2014-09-20 22:37:58 +02:00
IMovableRegistry mr = AEApi.instance().registries().movable();
for( int cx = 0; cx < this.cx_size; cx++ )
2015-04-29 02:30:53 +02:00
{
for( int cz = 0; cz < this.cz_size; cz++ )
{
2015-06-16 02:44:59 +02:00
LinkedList<Entry<BlockPos, TileEntity>> rawTiles = new LinkedList<Entry<BlockPos, TileEntity>>();
LinkedList<BlockPos> deadTiles = new LinkedList<BlockPos>();
Chunk c = w.getChunkFromChunkCoords( minCX + cx, minCZ + cz );
2014-12-29 15:13:47 +01:00
this.myChunks[cx][cz] = c;
2015-06-16 02:44:59 +02:00
rawTiles.addAll( ( (HashMap<BlockPos, TileEntity>) c.getTileEntityMap() ).entrySet() );
for( Entry<BlockPos, TileEntity> tx : rawTiles )
{
2015-06-16 02:44:59 +02:00
BlockPos cp = tx.getKey();
TileEntity te = tx.getValue();
2015-06-16 02:44:59 +02:00
BlockPos tePOS = te.getPos();
if( tePOS.getX() >= minX && tePOS.getX() <= maxX && tePOS.getY() >= minY && tePOS.getY() <= maxY && tePOS.getZ() >= minZ && tePOS.getZ() <= maxZ )
{
if( mr.askToMove( te ) )
{
2014-12-29 15:13:47 +01:00
this.tiles.add( te );
deadTiles.add( cp );
}
else
{
2015-06-16 02:44:59 +02:00
Object[] details = this.myColumns[tePOS.getX() - minX][tePOS.getZ() - minZ].getDetails( tePOS.getY() );
2014-02-09 02:34:52 +01:00
Block blk = (Block) details[0];
// don't skip air, just let the code replace it...
2015-06-16 02:44:59 +02:00
if( blk != null && blk.isAir( c.getWorld(), tePOS ) && blk.isReplaceable( c.getWorld(), tePOS ) )
{
2015-06-16 02:44:59 +02:00
c.getWorld().setBlockToAir( tePOS );
}
else
2015-04-29 02:30:53 +02:00
{
2015-06-16 02:44:59 +02:00
this.myColumns[tePOS.getX() - minX][tePOS.getZ() - minZ].setSkip( tePOS.getY() );
2015-04-29 02:30:53 +02:00
}
}
}
}
2015-06-16 02:44:59 +02:00
for( BlockPos cp : deadTiles )
{
2015-06-16 02:44:59 +02:00
c.getTileEntityMap().remove( cp );
}
2014-12-29 15:13:47 +01:00
long k = this.world.getTotalWorldTime();
List list = this.world.getPendingBlockUpdates( c, false );
if( list != null )
{
for( Object o : list )
{
NextTickListEntry entry = (NextTickListEntry) o;
2015-06-16 02:44:59 +02:00
BlockPos tePOS = entry.position;
if( tePOS.getX() >= minX && tePOS.getX() <= maxX && tePOS.getY() >= minY && tePOS.getY() <= maxY && tePOS.getZ() >= minZ && tePOS.getZ() <= maxZ )
{
2015-06-16 02:44:59 +02:00
NextTickListEntry newEntry = new NextTickListEntry( tePOS, entry.getBlock() );
newEntry.scheduledTime = entry.scheduledTime - k;
2014-12-29 15:13:47 +01:00
this.ticks.add( newEntry );
}
}
}
}
2015-04-29 02:30:53 +02:00
}
for( TileEntity te : this.tiles )
{
try
{
2014-12-29 15:13:47 +01:00
this.world.loadedTileEntityList.remove( te );
}
catch( Exception e )
{
AELog.error( e );
}
}
}
private IMovableHandler getHandler( TileEntity te )
{
2014-09-20 22:37:58 +02:00
IMovableRegistry mr = AEApi.instance().registries().movable();
return mr.getHandler( te );
}
2015-05-18 00:02:28 +02:00
void swap( CachedPlane dst )
{
2014-09-20 22:37:58 +02:00
IMovableRegistry mr = AEApi.instance().registries().movable();
if( dst.x_size == this.x_size && dst.y_size == this.y_size && dst.z_size == this.z_size )
{
2014-12-29 15:13:47 +01:00
AELog.info( "Block Copy Scale: " + this.x_size + ", " + this.y_size + ", " + this.z_size );
long startTime = System.nanoTime();
for( int x = 0; x < this.x_size; x++ )
{
for( int z = 0; z < this.z_size; z++ )
{
2014-12-29 15:13:47 +01:00
Column a = this.myColumns[x][z];
Column b = dst.myColumns[x][z];
for( int y = 0; y < this.y_size; y++ )
{
2014-12-29 15:13:47 +01:00
int src_y = y + this.y_offset;
int dst_y = y + dst.y_offset;
if( a.doNotSkip( src_y ) && b.doNotSkip( dst_y ) )
{
2014-02-09 02:34:52 +01:00
Object[] aD = a.getDetails( src_y );
Object[] bD = b.getDetails( dst_y );
a.setBlockIDWithMetadata( src_y, bD );
b.setBlockIDWithMetadata( dst_y, aD );
}
else
{
2014-12-29 15:13:47 +01:00
this.markForUpdate( x + this.x_offset, src_y, z + this.z_offset );
dst.markForUpdate( x + dst.x_offset, dst_y, z + dst.z_offset );
}
}
}
}
long endTime = System.nanoTime();
long duration = endTime - startTime;
AELog.info( "Block Copy Time: " + duration );
for( TileEntity te : this.tiles )
{
2015-06-16 02:44:59 +02:00
BlockPos tePOS = te.getPos();
dst.addTile( tePOS.getX() - this.x_offset, tePOS.getY() - this.y_offset, tePOS.getZ() - this.z_offset, te, this, mr );
}
for( TileEntity te : dst.tiles )
{
2015-06-16 02:44:59 +02:00
BlockPos tePOS = te.getPos();
this.addTile( tePOS.getX() - dst.x_offset, tePOS.getY() - dst.y_offset, tePOS.getZ() - dst.z_offset, te, dst, mr );
}
for( NextTickListEntry entry : this.ticks )
{
2015-06-16 02:44:59 +02:00
BlockPos tePOS = entry.position;
dst.addTick( tePOS.getX() - this.x_offset, tePOS.getY() - this.y_offset, tePOS.getZ() - this.z_offset, entry );
}
for( NextTickListEntry entry : dst.ticks )
{
2015-06-16 02:44:59 +02:00
BlockPos tePOS = entry.position;
this.addTick( tePOS.getX() - dst.x_offset, tePOS.getY() - dst.y_offset, tePOS.getZ() - dst.z_offset, entry );
}
startTime = System.nanoTime();
2014-12-29 15:13:47 +01:00
this.updateChunks();
dst.updateChunks();
endTime = System.nanoTime();
duration = endTime - startTime;
AELog.info( "Update Time: " + duration );
}
}
private void markForUpdate( int x, int y, int z )
{
this.updates.add( new WorldCoord( x, y, z ) );
2015-06-16 02:44:59 +02:00
for( AEPartLocation d : AEPartLocation.SIDE_LOCATIONS )
2015-04-29 02:30:53 +02:00
{
2015-06-16 02:44:59 +02:00
this.updates.add( new WorldCoord( x + d.xOffset, y + d.yOffset, z + d.zOffset ) );
2015-04-29 02:30:53 +02:00
}
}
private void addTick( int x, int y, int z, NextTickListEntry entry )
{
2015-06-16 02:44:59 +02:00
this.world.scheduleUpdate( new BlockPos( x + this.x_offset, y + this.y_offset, z + this.z_offset ), entry.getBlock(), (int) entry.scheduledTime );
}
private void addTile( int x, int y, int z, TileEntity te, CachedPlane alternateDestination, IMovableRegistry mr )
{
try
{
2014-12-29 15:13:47 +01:00
Column c = this.myColumns[x][z];
if( c.doNotSkip( y + this.y_offset ) || alternateDestination == null )
{
2014-12-29 15:13:47 +01:00
IMovableHandler handler = this.getHandler( te );
try
{
2015-06-16 02:44:59 +02:00
handler.moveTile( te, this.world, new BlockPos( x + this.x_offset, y + this.y_offset, z + this.z_offset ) );
}
catch( Throwable e )
{
AELog.error( e );
2015-06-16 02:44:59 +02:00
BlockPos pos = new BlockPos( x,y,z);
// attempt recovery...
2014-12-29 15:13:47 +01:00
te.setWorldObj( this.world );
2015-06-16 02:44:59 +02:00
te.setPos( pos );
c.c.addTileEntity( new BlockPos( c.x, y + y, c.z ), te );
2014-02-09 02:34:52 +01:00
// c.c.setChunkTileEntity( c.x, y + y, c.z, te );
2015-06-16 02:44:59 +02:00
if( c.c.isLoaded() )
{
2014-12-29 15:13:47 +01:00
this.world.addTileEntity( te );
2015-06-16 02:44:59 +02:00
this.world.markBlockForUpdate( pos );
}
}
mr.doneMoving( te );
}
else
{
2014-11-04 12:32:33 +01:00
alternateDestination.addTile( x, y, z, te, null, mr );
}
}
catch( Throwable e )
{
AELog.error( e );
}
}
private void updateChunks()
{
// update shit..
for( int x = 0; x < this.cx_size; x++ )
2015-04-29 02:30:53 +02:00
{
for( int z = 0; z < this.cz_size; z++ )
{
2014-12-29 15:13:47 +01:00
Chunk c = this.myChunks[x][z];
c.resetRelightChecks();
c.generateSkylightMap();
2015-06-16 02:44:59 +02:00
c.setModified( true );
}
2015-04-29 02:30:53 +02:00
}
// send shit...
for( int x = 0; x < this.cx_size; x++ )
2015-04-29 02:30:53 +02:00
{
for( int z = 0; z < this.cz_size; z++ )
{
2014-12-29 15:13:47 +01:00
Chunk c = this.myChunks[x][z];
for( int y = 1; y < 255; y += 32 )
2015-04-29 02:30:53 +02:00
{
2014-12-29 15:13:47 +01:00
WorldSettings.getInstance().getCompass().updateArea( this.world, c.xPosition << 4, y, c.zPosition << 4 );
2015-04-29 02:30:53 +02:00
}
2014-12-29 15:13:47 +01:00
Platform.sendChunk( c, this.verticalBits );
}
2015-04-29 02:30:53 +02:00
}
}
class Column
{
private final int x;
private final int z;
private final Chunk c;
2015-06-16 02:44:59 +02:00
private final Object[] ch = { 0, 0 };
private final ExtendedBlockStorage[] storage;
private List<Integer> skipThese = null;
public Column( Chunk chunk, int x, int z, int chunkY, int chunkHeight )
{
this.x = x;
this.z = z;
this.c = chunk;
this.storage = this.c.getBlockStorageArray();
// make sure storage exists before hand...
for( int ay = 0; ay < chunkHeight; ay++ )
{
int by = ( ay + chunkY );
ExtendedBlockStorage extendedblockstorage = this.storage[by];
if( extendedblockstorage == null )
2015-04-29 02:30:53 +02:00
{
2015-06-16 02:44:59 +02:00
extendedblockstorage = this.storage[by] = new ExtendedBlockStorage( by << 4, !this.c.getWorld().provider.getHasNoSky() );
2015-04-29 02:30:53 +02:00
}
}
}
public void setBlockIDWithMetadata( int y, Object[] blk )
{
for( Block matrixFrameBlock : CachedPlane.this.matrixFrame.maybeBlock().asSet() )
{
if( blk[0] == matrixFrameBlock )
{
blk[0] = Platform.AIR_BLOCK;
}
}
ExtendedBlockStorage extendedBlockStorage = this.storage[y >> 4];
2015-06-16 02:44:59 +02:00
extendedBlockStorage.set( this.x, y & 15, this.z, (IBlockState) blk[0] );
// extendedBlockStorage.setExtBlockID( x, y & 15, z, blk[0] );
2015-06-16 02:44:59 +02:00
extendedBlockStorage.setExtBlocklightValue( this.x, y & 15, this.z, (Integer) blk[1] );
}
public Object[] getDetails( int y )
{
ExtendedBlockStorage extendedblockstorage = this.storage[y >> 4];
2015-06-16 02:44:59 +02:00
this.ch[0] = extendedblockstorage.get( this.x, y & 15, this.z );
this.ch[1] = extendedblockstorage.getExtBlocklightValue( this.x, y & 15, this.z );
return this.ch;
}
public boolean doNotSkip( int y )
{
ExtendedBlockStorage extendedblockstorage = this.storage[y >> 4];
if( CachedPlane.this.reg.isBlacklisted( extendedblockstorage.getBlockByExtId( this.x, y & 15, this.z ) ) )
2015-04-29 02:30:53 +02:00
{
return false;
2015-04-29 02:30:53 +02:00
}
return this.skipThese == null || !this.skipThese.contains( y );
}
public void setSkip( int yCoord )
{
if( this.skipThese == null )
2015-04-29 02:30:53 +02:00
{
this.skipThese = new LinkedList<Integer>();
2015-04-29 02:30:53 +02:00
}
this.skipThese.add( yCoord );
}
}
}