@@ -19,55 +19,40 @@
|
||||
package appeng.services;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.IWorld;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.chunk.IChunk;
|
||||
import net.minecraft.world.server.ServerWorld;
|
||||
import net.minecraftforge.event.world.WorldEvent;
|
||||
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.util.DimensionalCoord;
|
||||
import appeng.services.compass.CompassReader;
|
||||
import appeng.services.compass.ICompassCallback;
|
||||
import appeng.util.Platform;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.IWorld;
|
||||
import net.minecraft.world.chunk.IChunk;
|
||||
import net.minecraft.world.dimension.DimensionType;
|
||||
import net.minecraft.world.server.ServerWorld;
|
||||
import net.minecraftforge.event.world.WorldEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
|
||||
public final class CompassService
|
||||
{
|
||||
private static final int CHUNK_SIZE = 16;
|
||||
|
||||
private final Map<IWorld, CompassReader> worldSet = new HashMap<>( 10 );
|
||||
private final MinecraftServer server;
|
||||
private final Map<DimensionType, CompassReader> worldSet = new HashMap<>( 10 );
|
||||
private final ExecutorService executor;
|
||||
|
||||
/**
|
||||
* AE2 Folder for each world
|
||||
*/
|
||||
private final File worldCompassFolder;
|
||||
|
||||
private int jobSize;
|
||||
|
||||
public CompassService( @Nonnull final File worldCompassFolder, @Nonnull final ThreadFactory factory )
|
||||
public CompassService(MinecraftServer server, @Nonnull final ThreadFactory factory)
|
||||
{
|
||||
Preconditions.checkNotNull( worldCompassFolder );
|
||||
|
||||
this.worldCompassFolder = worldCompassFolder;
|
||||
this.server = server;
|
||||
this.executor = Executors.newSingleThreadExecutor( factory );
|
||||
this.jobSize = 0;
|
||||
}
|
||||
@@ -83,13 +68,15 @@ public final class CompassService
|
||||
*
|
||||
* @param event the event containing the unloaded world.
|
||||
*/
|
||||
// FIXME this is never registered
|
||||
@SubscribeEvent
|
||||
public void unloadWorld( final WorldEvent.Unload event )
|
||||
{
|
||||
if( Platform.isServer() && this.worldSet.containsKey( event.getWorld() ) )
|
||||
{
|
||||
final CompassReader compassReader = this.worldSet.remove( event.getWorld() );
|
||||
DimensionType dim = event.getWorld().getDimension().getType();
|
||||
|
||||
if( Platform.isServer() && this.worldSet.containsKey( dim ) )
|
||||
{
|
||||
final CompassReader compassReader = this.worldSet.remove( dim );
|
||||
compassReader.close();
|
||||
}
|
||||
}
|
||||
@@ -107,7 +94,7 @@ public final class CompassService
|
||||
}
|
||||
}
|
||||
|
||||
public void updateArea( final World w, final int chunkX, final int chunkZ )
|
||||
public void updateArea( final IWorld w, final int chunkX, final int chunkZ )
|
||||
{
|
||||
final int x = chunkX << 4;
|
||||
final int z = chunkZ << 4;
|
||||
@@ -137,27 +124,29 @@ public final class CompassService
|
||||
// lower level...
|
||||
final IChunk c = w.getChunk( cx, cz );
|
||||
|
||||
Optional<Block> maybeBlock = AEApi.instance().definitions().blocks().skyStoneBlock().maybeBlock();
|
||||
if( maybeBlock.isPresent() )
|
||||
DimensionType dim = w.getDimension().getType();
|
||||
|
||||
Block skyStoneBlock = AEApi.instance().definitions().blocks().skyStoneBlock().block();
|
||||
BlockPos.Mutable pos = new BlockPos.Mutable();
|
||||
for( int i = 0; i < CHUNK_SIZE; i++ )
|
||||
{
|
||||
Block skyStoneBlock = maybeBlock.get();
|
||||
for( int i = 0; i < CHUNK_SIZE; i++ )
|
||||
pos.setX(i);
|
||||
for( int j = 0; j < CHUNK_SIZE; j++ )
|
||||
{
|
||||
for( int j = 0; j < CHUNK_SIZE; j++ )
|
||||
pos.setZ(j);
|
||||
for( int k = low_y; k < hi_y; k++ )
|
||||
{
|
||||
for( int k = low_y; k < hi_y; k++ )
|
||||
pos.setY(k);
|
||||
final Block blk = c.getBlockState( pos ).getBlock();
|
||||
if( blk == skyStoneBlock )
|
||||
{
|
||||
final Block blk = c.getBlockState( new BlockPos(i, k, j) ).getBlock();
|
||||
if( blk == skyStoneBlock )
|
||||
{
|
||||
return this.executor.submit( new CMUpdatePost( w, cx, cz, cdy, true ) );
|
||||
}
|
||||
return this.executor.submit( new CMUpdatePost( dim, cx, cz, cdy, true ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this.executor.submit( new CMUpdatePost( w, cx, cz, cdy, false ) );
|
||||
return this.executor.submit( new CMUpdatePost( dim, cx, cz, cdy, false ) );
|
||||
}
|
||||
|
||||
public void kill()
|
||||
@@ -182,16 +171,15 @@ public final class CompassService
|
||||
}
|
||||
}
|
||||
|
||||
private CompassReader getReader( final IWorld w )
|
||||
private CompassReader getReader( final DimensionType dim )
|
||||
{
|
||||
CompassReader cr = this.worldSet.get( w );
|
||||
CompassReader cr = this.worldSet.get( dim );
|
||||
|
||||
if( cr == null )
|
||||
{
|
||||
ServerWorld sw = (ServerWorld) w;
|
||||
// FIXME: using the numeric dimension ID here seems to be a bad idea!
|
||||
cr = new CompassReader( sw.dimension.getType().getId(), this.worldCompassFolder );
|
||||
this.worldSet.put( w, cr );
|
||||
ServerWorld sw = server.getWorld(dim);
|
||||
cr = new CompassReader(sw);
|
||||
this.worldSet.put( dim, cr );
|
||||
}
|
||||
|
||||
return cr;
|
||||
@@ -216,16 +204,16 @@ public final class CompassService
|
||||
private class CMUpdatePost implements Runnable
|
||||
{
|
||||
|
||||
public final IWorld world;
|
||||
public final DimensionType dim;
|
||||
|
||||
public final int chunkX;
|
||||
public final int chunkZ;
|
||||
public final int doubleChunkY; // 32 blocks instead of 16.
|
||||
public final boolean value;
|
||||
|
||||
public CMUpdatePost( final IWorld w, final int cx, final int cz, final int dcy, final boolean val )
|
||||
public CMUpdatePost(final DimensionType dim, final int cx, final int cz, final int dcy, final boolean val )
|
||||
{
|
||||
this.world = w;
|
||||
this.dim = dim;
|
||||
this.chunkX = cx;
|
||||
this.doubleChunkY = dcy;
|
||||
this.chunkZ = cz;
|
||||
@@ -237,7 +225,7 @@ public final class CompassService
|
||||
{
|
||||
CompassService.this.jobSize--;
|
||||
|
||||
final CompassReader cr = CompassService.this.getReader( this.world );
|
||||
final CompassReader cr = CompassService.this.getReader( this.dim );
|
||||
cr.setHasBeacon( this.chunkX, this.chunkZ, this.doubleChunkY, this.value );
|
||||
|
||||
if( CompassService.this.jobSize() < 2 )
|
||||
@@ -269,7 +257,7 @@ public final class CompassService
|
||||
final int cx = this.coord.x >> 4;
|
||||
final int cz = this.coord.z >> 4;
|
||||
|
||||
final CompassReader cr = CompassService.this.getReader( this.coord.getWorld() );
|
||||
final CompassReader cr = CompassService.this.getReader( this.coord.getWorld().getDimension().getType() );
|
||||
|
||||
// Am I standing on it?
|
||||
if( cr.hasBeacon( cx, cz ) )
|
||||
|
||||
@@ -19,28 +19,21 @@
|
||||
package appeng.services.compass;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import com.google.common.base.Preconditions;
|
||||
import net.minecraft.world.server.ServerWorld;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
|
||||
public final class CompassReader
|
||||
{
|
||||
private final Map<Long, CompassRegion> regions = new HashMap<>( 100 );
|
||||
private final int dimensionId;
|
||||
private final File worldCompassFolder;
|
||||
private final ServerWorld world;
|
||||
|
||||
public CompassReader( final int dimensionId, @Nonnull final File worldCompassFolder )
|
||||
public CompassReader( ServerWorld world )
|
||||
{
|
||||
Preconditions.checkNotNull( worldCompassFolder );
|
||||
Preconditions.checkArgument( worldCompassFolder.isDirectory() );
|
||||
|
||||
this.dimensionId = dimensionId;
|
||||
this.worldCompassFolder = worldCompassFolder;
|
||||
this.world = Preconditions.checkNotNull( world );
|
||||
}
|
||||
|
||||
public void close()
|
||||
@@ -77,7 +70,7 @@ public final class CompassReader
|
||||
|
||||
if( cr == null )
|
||||
{
|
||||
cr = new CompassRegion( cx, cz, this.dimensionId, this.worldCompassFolder );
|
||||
cr = new CompassRegion( world, cx, cz );
|
||||
this.regions.put( pos, cr );
|
||||
}
|
||||
|
||||
|
||||
@@ -19,38 +19,23 @@
|
||||
package appeng.services.compass;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.world.server.ServerWorld;
|
||||
import net.minecraft.world.storage.WorldSavedData;
|
||||
|
||||
import appeng.core.worlddata.MeteorDataNameEncoder;
|
||||
|
||||
|
||||
public final class CompassRegion
|
||||
final class CompassRegion
|
||||
{
|
||||
private final int lowX;
|
||||
private final int lowZ;
|
||||
private final int world;
|
||||
private final File worldCompassFolder;
|
||||
private final MeteorDataNameEncoder encoder;
|
||||
private final ServerWorld world;
|
||||
private SaveData data;
|
||||
|
||||
private boolean hasFile = false;
|
||||
private RandomAccessFile raf = null;
|
||||
private ByteBuffer buffer;
|
||||
|
||||
public CompassRegion( final int cx, final int cz, final int worldID, @Nonnull final File worldCompassFolder )
|
||||
public CompassRegion(ServerWorld world, final int cx, final int cz )
|
||||
{
|
||||
Preconditions.checkNotNull( worldCompassFolder );
|
||||
Preconditions.checkArgument( worldCompassFolder.isDirectory() );
|
||||
Preconditions.checkNotNull( world );
|
||||
|
||||
this.world = worldID;
|
||||
this.worldCompassFolder = worldCompassFolder;
|
||||
this.encoder = new MeteorDataNameEncoder( 0 );
|
||||
this.world = world;
|
||||
|
||||
final int region_x = cx >> 10;
|
||||
final int region_z = cz >> 10;
|
||||
@@ -58,39 +43,26 @@ public final class CompassRegion
|
||||
this.lowX = region_x << 10;
|
||||
this.lowZ = region_z << 10;
|
||||
|
||||
this.openFile( false );
|
||||
this.openData(false);
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
try
|
||||
if( this.data != null )
|
||||
{
|
||||
if( this.hasFile )
|
||||
{
|
||||
this.buffer = null;
|
||||
this.raf.close();
|
||||
this.raf = null;
|
||||
this.hasFile = false;
|
||||
}
|
||||
}
|
||||
catch( final Throwable t )
|
||||
{
|
||||
throw new CompassException( t );
|
||||
this.data = null;
|
||||
}
|
||||
}
|
||||
|
||||
boolean hasBeacon( int cx, int cz )
|
||||
{
|
||||
if( this.hasFile )
|
||||
if( this.data != null )
|
||||
{
|
||||
cx &= 0x3FF;
|
||||
cz &= 0x3FF;
|
||||
|
||||
final int val = this.read( cx, cz );
|
||||
if( val != 0 )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return val != 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -101,9 +73,9 @@ public final class CompassRegion
|
||||
cx &= 0x3FF;
|
||||
cz &= 0x3FF;
|
||||
|
||||
this.openFile( hasBeacon );
|
||||
this.openData( hasBeacon );
|
||||
|
||||
if( this.hasFile )
|
||||
if( this.data != null )
|
||||
{
|
||||
int val = this.read( cx, cz );
|
||||
final int originalVal = val;
|
||||
@@ -124,88 +96,67 @@ public final class CompassRegion
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable
|
||||
private void openData(final boolean create )
|
||||
{
|
||||
try
|
||||
{
|
||||
if( this.raf != null )
|
||||
{
|
||||
this.raf.close();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void openFile( final boolean create )
|
||||
{
|
||||
if( this.hasFile )
|
||||
if( this.data != null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
final File file = this.getFile();
|
||||
if( create || this.isFileExistent( file ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
this.raf = new RandomAccessFile( file, "rw" );
|
||||
final FileChannel fc = this.raf.getChannel();
|
||||
this.buffer = fc.map( FileChannel.MapMode.READ_WRITE, 0, 0x400 * 0x400 );// fc.size() );
|
||||
this.hasFile = true;
|
||||
}
|
||||
catch( final Throwable t )
|
||||
{
|
||||
throw new CompassException( t );
|
||||
String name = this.lowX + "_" + this.lowZ;
|
||||
|
||||
if (create) {
|
||||
this.data = world.getSavedData().getOrCreate(() -> new SaveData(name), name);
|
||||
if (this.data.bitmap == null) {
|
||||
this.data.bitmap = new byte[SaveData.BITMAP_LENGTH];
|
||||
}
|
||||
} else {
|
||||
this.data = world.getSavedData().get(() -> new SaveData(name), name);
|
||||
}
|
||||
}
|
||||
|
||||
private File getFile()
|
||||
{
|
||||
final String fileName = this.encoder.encode( this.world, this.lowX, this.lowZ );
|
||||
|
||||
return new File( this.worldCompassFolder, fileName );
|
||||
}
|
||||
|
||||
private boolean isFileExistent( final File file )
|
||||
{
|
||||
return file.exists() && file.isFile();
|
||||
}
|
||||
|
||||
private int read( final int cx, final int cz )
|
||||
{
|
||||
try
|
||||
{
|
||||
return this.buffer.get( cx + cz * 0x400 );
|
||||
// raf.seek( cx + cz * 0x400 );
|
||||
// return raf.readByte();
|
||||
return this.data.bitmap[cx + cz * 0x400];
|
||||
}
|
||||
catch( final IndexOutOfBoundsException outOfBounds )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
catch( final Throwable t )
|
||||
{
|
||||
throw new CompassException( t );
|
||||
}
|
||||
}
|
||||
|
||||
private void write( final int cx, final int cz, final int val )
|
||||
{
|
||||
try
|
||||
{
|
||||
this.buffer.put( cx + cz * 0x400, (byte) val );
|
||||
// raf.seek( cx + cz * 0x400 );
|
||||
// raf.writeByte( val );
|
||||
}
|
||||
catch( final Throwable t )
|
||||
{
|
||||
throw new CompassException( t );
|
||||
}
|
||||
this.data.bitmap[cx + cz * 0x400] = (byte) val;
|
||||
this.data.markDirty();
|
||||
}
|
||||
|
||||
private static class SaveData extends WorldSavedData {
|
||||
|
||||
private static final int BITMAP_LENGTH = 0x400 * 0x400;
|
||||
|
||||
private byte[] bitmap;
|
||||
|
||||
public SaveData(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(CompoundNBT nbt) {
|
||||
this.bitmap = nbt.getByteArray("b");
|
||||
if (this.bitmap.length != BITMAP_LENGTH) {
|
||||
throw new IllegalStateException("Invalid bitmap length: " + bitmap.length);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundNBT write(CompoundNBT compound) {
|
||||
compound.putByteArray("b", bitmap);
|
||||
return compound;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user