Fixed CME crash in air simulation

This commit is contained in:
LemADEC 2017-11-01 15:48:29 +01:00
parent dd69616a68
commit 8380d9873c
8 changed files with 90 additions and 47 deletions

View file

@ -96,8 +96,9 @@ public class BreathingManager {
vAirBlock = vPosition;
break;
} else if (block != Blocks.air) {
StateAir stateAir = ChunkHandler.getStateAir(entityLivingBase.worldObj, vPosition.x, vPosition.y, vPosition.z);
if (stateAir.concentration > 0) {
final StateAir stateAir = ChunkHandler.getStateAir(entityLivingBase.worldObj, vPosition.x, vPosition.y, vPosition.z);
if ( stateAir == null
|| stateAir.concentration > 0 ) {
vAirBlock = vPosition;
break;
}

View file

@ -46,7 +46,7 @@ public class LocalProfiler {
}
}
private static void printCallStats() {
public static void printCallStats() {
WarpDrive.logger.info("Dumping chunk stats:");
for (Entry<String, Integer> entryStat : stats.entrySet()) {
WarpDrive.logger.info(String.format("%10d x %s",

View file

@ -16,7 +16,8 @@ public class BlockAirFlow extends BlockAbstractAir {
public AxisAlignedBB getCollisionBoundingBoxFromPool(World world, int x, int y, int z) {
if (!world.isRemote) {
final StateAir stateAir = ChunkHandler.getStateAir(world, x, y, z);
if (!stateAir.isAirFlow() || stateAir.concentration == 0) {
if ( stateAir != null
&& (!stateAir.isAirFlow() || stateAir.concentration == 0) ) {
world.setBlockToAir(x, y, z);
}
}

View file

@ -15,8 +15,9 @@ public class BlockAirSource extends BlockAbstractAir {
@Override
public AxisAlignedBB getCollisionBoundingBoxFromPool(World world, int x, int y, int z) {
if (!world.isRemote) {
StateAir stateAir = ChunkHandler.getStateAir(world, x, y, z);
if (!stateAir.isAirSource() || stateAir.concentration == 0) {
final StateAir stateAir = ChunkHandler.getStateAir(world, x, y, z);
if ( stateAir != null
&& (!stateAir.isAirSource() || stateAir.concentration == 0) ) {
world.setBlockToAir(x, y, z);
}
}

View file

@ -95,7 +95,10 @@ public class TileEntityAirGeneratorTiered extends TileEntityAbstractEnergy {
final int y = yCoord + direction.offsetY;
final int z = zCoord + direction.offsetZ;
StateAir stateAir = ChunkHandler.getStateAir(worldObj, x, y, z);
final StateAir stateAir = ChunkHandler.getStateAir(worldObj, x, y, z);
if (stateAir == null) {// chunk isn't loaded
return;
}
stateAir.updateBlockCache(worldObj);
if (stateAir.isAir()) {// can be air
final short range = (short) (WarpDriveConfig.BREATHING_AIR_GENERATION_RANGE_BLOCKS[tier - 1] - 1);

View file

@ -46,11 +46,9 @@ public class CompatWarpDrive implements IBlockTransformer {
public NBTBase saveExternals(final World world, final int x, final int y, final int z,
final Block block, final int blockMeta, final TileEntity tileEntity) {
if (block instanceof BlockAirFlow || block instanceof BlockAirSource) {
final ChunkData chunkData = ChunkHandler.getChunkData(world, x, y, z, false);
final ChunkData chunkData = ChunkHandler.getChunkData(world, x, y, z);
if (chunkData == null) {
WarpDrive.logger.error(String.format("CompatWarpDrive trying to get data from an non-loaded chunk in %s @ (%d %d %d)",
world.provider.getDimensionName(), x, y, z));
assert(false);
// chunk isn't loaded, skip it
return null;
}
final int dataAir = chunkData.getDataAir(x, y, z);
@ -68,11 +66,9 @@ public class CompatWarpDrive implements IBlockTransformer {
public void removeExternals(final World world, final int x, final int y, final int z,
final Block block, final int blockMeta, final TileEntity tileEntity) {
if (block instanceof BlockAirFlow || block instanceof BlockAirSource) {
final ChunkData chunkData = ChunkHandler.getChunkData(world, x, y, z, false);
final ChunkData chunkData = ChunkHandler.getChunkData(world, x, y, z);
if (chunkData == null) {
WarpDrive.logger.error(String.format("CompatWarpDrive trying to get data from an non-loaded chunk in %s @ (%d %d %d)",
world.provider.getDimensionName(), x, y, z));
assert(false);
// chunk isn't loaded, skip it
return;
}
chunkData.setDataAir(x, y, z, StateAir.AIR_DEFAULT);
@ -188,11 +184,9 @@ public class CompatWarpDrive implements IBlockTransformer {
if (((NBTTagCompound) nbtBase).hasKey("dataAir")) {
final byte rotationSteps = transformation.getRotationSteps();
final int dataAir = ((NBTTagCompound) nbtBase).getInteger("dataAir");
final ChunkData chunkData = ChunkHandler.getChunkData(world, x, y, z, false);
final ChunkData chunkData = ChunkHandler.getChunkData(world, x, y, z);
if (chunkData == null) {
WarpDrive.logger.error(String.format("CompatWarpDrive trying to set data from an non-loaded chunk in %s @ (%d %d %d)",
world.provider.getDimensionName(), x, y, z));
assert(false);
// chunk isn't loaded, skip it
return;
}
final int dataAirRotated = StateAir.rotate(dataAir, rotationSteps);

View file

@ -91,10 +91,9 @@ public class StateAir {
private void refresh(final World world) {
// update chunk cache
if (chunkData == null || !chunkData.isInside(x, y, z)) {
chunkData = ChunkHandler.getChunkData(world, x, y, z, false);
chunkData = ChunkHandler.getChunkData(world, x, y, z);
if (chunkData == null) {
WarpDrive.logger.error(String.format("State air trying to get data from an non-loaded chunk in %s @ (%d %d %d)",
world.provider.getDimensionName(), x, y, z));
// chunk isn't loaded, skip it
assert(false);
}
chunk = null;

View file

@ -7,6 +7,7 @@ import cr0s.warpdrive.config.WarpDriveConfig;
import cr0s.warpdrive.data.ChunkData;
import cr0s.warpdrive.data.StateAir;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
@ -230,7 +231,7 @@ public class ChunkHandler {
public static void onBlockUpdated(final World world, final int x, final int y, final int z) {
if (!world.isRemote) {
final ChunkData chunkData = getChunkData(world, x, y, z, false);
final ChunkData chunkData = getChunkData(world, x, y, z);
if (chunkData != null) {
chunkData.onBlockUpdated(x, y, z);
} else {
@ -246,13 +247,28 @@ public class ChunkHandler {
}
/* internal access */
public static ChunkData getChunkData(final World world, final int x, final int y, final int z, final boolean doCreate) {
return getChunkData(world.isRemote, world.provider.dimensionId, x, y, z, doCreate);
/**
* Return null and spam logs if chunk isn't already generated or loaded
*/
public static ChunkData getChunkData(final World world, final int x, final int y, final int z) {
final ChunkData chunkData = getChunkData(world.isRemote, world.provider.dimensionId, x, y, z);
if (chunkData == null) {
WarpDrive.logger.error(String.format("Trying to get data from an non-loaded chunk in %s world %s @ (%d %d %d)",
world.isRemote ? "Client" : "Server",
world.provider.getDimensionName(), x, y, z));
LocalProfiler.printCallStats();
Commons.dumpAllThreads();
assert(false);
}
return chunkData;
}
private static ChunkData getChunkData(final boolean isRemote, final int dimensionId, final int x, final int y, final int z, final boolean doCreate) {
/**
* Return null if chunk isn't already generated or loaded
*/
private static ChunkData getChunkData(final boolean isRemote, final int dimensionId, final int x, final int y, final int z) {
assert (y >= 0 && y <= 255);
return getChunkData(isRemote, dimensionId, x >> 4, z >> 4, doCreate);
return getChunkData(isRemote, dimensionId, x >> 4, z >> 4, false);
}
private static ChunkData getChunkData(final boolean isRemote, final int dimensionId, final int xChunk, final int zChunk, final boolean doCreate) {
@ -287,7 +303,16 @@ public class ChunkHandler {
dimensionId,
chunkData.getChunkCoords()));
}
mapRegistryItems.put(index, chunkData);
if (Commons.isSafeThread()) {
mapRegistryItems.put(index, chunkData);
} else {
WarpDrive.logger.error(String.format("%s world DIM%d chunk %s is being added to the registry outside main thread!",
isRemote ? "Client" : "Server",
dimensionId,
chunkData.getChunkCoords()));
Commons.dumpAllThreads();
mapRegistryItems.put(index, chunkData);
}
}
return chunkData;
}
@ -301,13 +326,18 @@ public class ChunkHandler {
/* commons */
public static boolean isLoaded(final World world, final int x, final int y, final int z) {
final ChunkData chunkData = getChunkData(world, x, y, z, false);
final ChunkData chunkData = getChunkData(world.isRemote, world.provider.dimensionId, x, y, z);
return chunkData != null && chunkData.isLoaded();
}
/* air handling */
public static StateAir getStateAir(final World world, final int x, final int y, final int z) {
return getChunkData(world, x, y, z, true).getStateAir(world, x, y, z);
final ChunkData chunkData = getChunkData(world, x, y, z);
if (chunkData == null) {
// chunk isn't loaded, skip it
return null;
}
return chunkData.getStateAir(world, x, y, z);
}
public static void updateTick(final World world) {
@ -321,26 +351,40 @@ public class ChunkHandler {
int countLoaded = 0;
final long timeForRemoval = System.currentTimeMillis() - CHUNK_HANDLER_UNLOADED_CHUNK_MAX_AGE_MS;
final long timeForThrottle = System.currentTimeMillis() + 200;
for(final Iterator<Entry<Long, ChunkData>> entryIterator = mapRegistryItems.entrySet().iterator(); entryIterator.hasNext(); ) {
final Map.Entry<Long, ChunkData> entryChunkData = entryIterator.next();
final ChunkData chunkData = entryChunkData.getValue();
// update loaded chunks, remove old unloaded chunks
if (chunkData.isLoaded()) {
countLoaded++;
if (System.currentTimeMillis() < timeForThrottle) {
updateTickLoopStep(world, mapRegistryItems, entryChunkData.getValue());
final long sizeBefore = mapRegistryItems.size();
try {
for (final Iterator<Entry<Long, ChunkData>> entryIterator = mapRegistryItems.entrySet().iterator(); entryIterator.hasNext(); ) {
final Map.Entry<Long, ChunkData> entryChunkData = entryIterator.next();
final ChunkData chunkData = entryChunkData.getValue();
// update loaded chunks, remove old unloaded chunks
if (chunkData.isLoaded()) {
countLoaded++;
if (System.currentTimeMillis() < timeForThrottle) {
updateTickLoopStep(world, mapRegistryItems, entryChunkData.getValue());
}
} else if (chunkData.timeUnloaded < timeForRemoval) {
if (WarpDriveConfig.LOGGING_CHUNK_HANDLER) {
WarpDrive.logger.info(String.format("%s world %s chunk %s is being removed from updateTick (size is %d)",
world.isRemote ? "Client" : "Server",
world.provider.getDimensionName(),
chunkData.getChunkCoords(),
mapRegistryItems.size()));
}
entryIterator.remove();
}
} else if (chunkData.timeUnloaded < timeForRemoval) {
if (WarpDriveConfig.LOGGING_CHUNK_HANDLER) {
WarpDrive.logger.info(String.format("%s world %s chunk %s is being removed from updateTick (size is %d)",
world.isRemote ? "Client" : "Server",
world.provider.getDimensionName(),
chunkData.getChunkCoords(),
mapRegistryItems.size()));
}
entryIterator.remove();
}
} catch (ConcurrentModificationException exception) {
WarpDrive.logger.error(String.format("%s world %s had some chunks changed outside main thread? (size %d -> %d)",
world.isRemote ? "Client" : "Server",
world.provider.getDimensionName(),
sizeBefore, mapRegistryItems.size()));
exception.printStackTrace();
LocalProfiler.printCallStats();
}
if (WarpDriveConfig.LOGGING_CHUNK_HANDLER) {
if (world.provider.dimensionId == 0) {
delayLogging = (delayLogging + 1) % 4096;