diff --git a/src/main/java/cr0s/warpdrive/config/Filler.java b/src/main/java/cr0s/warpdrive/config/Filler.java index 52b17a1e..a9c1cb15 100644 --- a/src/main/java/cr0s/warpdrive/config/Filler.java +++ b/src/main/java/cr0s/warpdrive/config/Filler.java @@ -98,7 +98,7 @@ public class Filler implements IXmlRepresentableUnit { final IBlockState blockState; try { blockState = block.getStateFromMeta(metadata); - JumpBlock.setBlockNoLight(world, blockPos, blockState, 2); + JumpBlock.setBlockStateNoLight(world, blockPos, blockState, 2); } catch (final Throwable throwable) { WarpDrive.logger.error(String.format("Throwable detected in Filler.setBlock(%s), check your configuration for that block!", getName())); diff --git a/src/main/java/cr0s/warpdrive/config/WarpDriveConfig.java b/src/main/java/cr0s/warpdrive/config/WarpDriveConfig.java index 688135ff..bf4ee2f7 100644 --- a/src/main/java/cr0s/warpdrive/config/WarpDriveConfig.java +++ b/src/main/java/cr0s/warpdrive/config/WarpDriveConfig.java @@ -168,6 +168,7 @@ public class WarpDriveConfig { public static int G_LUA_SCRIPTS = LUA_SCRIPTS_ALL; public static String G_SCHEMATICS_LOCATION = "warpDrive_schematics"; public static int G_BLOCKS_PER_TICK = 3500; + public static boolean G_ENABLE_FAST_SET_BLOCKSTATE = true; public static boolean G_ENABLE_PROTECTION_CHECKS = true; public static float G_BLAST_RESISTANCE_CAP = 60.0F; @@ -727,7 +728,10 @@ public class WarpDriveConfig { G_BLOCKS_PER_TICK = Commons.clamp(100, 100000, config.get("general", "blocks_per_tick", G_BLOCKS_PER_TICK, "Number of blocks to move per ticks, too high will cause lag spikes on ship jumping or deployment, too low may break the ship wirings").getInt()); - G_ENABLE_PROTECTION_CHECKS = config.get("general", "enable_protection_checks", G_ENABLE_PROTECTION_CHECKS, "Enable area protection checks from other mods or plugins, disable if you use the event system exclusively").getBoolean(G_ENABLE_PROTECTION_CHECKS); + G_ENABLE_FAST_SET_BLOCKSTATE = config.get("general", "enable_fast_set_blockstate", G_ENABLE_FAST_SET_BLOCKSTATE, + "Enable fast blockstate placement, skipping light computation. Disable if you have world implementations conflicts").getBoolean(G_ENABLE_FAST_SET_BLOCKSTATE); + G_ENABLE_PROTECTION_CHECKS = config.get("general", "enable_protection_checks", G_ENABLE_PROTECTION_CHECKS, + "Enable area protection checks from other mods or plugins, disable if you use the event system exclusively").getBoolean(G_ENABLE_PROTECTION_CHECKS); G_BLAST_RESISTANCE_CAP = Commons.clamp(10.0F, 6000.0F, (float) config.get("general", "blast_resistance_cap", G_BLAST_RESISTANCE_CAP, "Maximum allowed blast resistance for non-hull, breakable blocks from other mods. Required to fix non-sense scaling in modded fluids, etc. Default is basic hull resistance (60).").getDouble(G_BLAST_RESISTANCE_CAP)); diff --git a/src/main/java/cr0s/warpdrive/data/JumpBlock.java b/src/main/java/cr0s/warpdrive/data/JumpBlock.java index c4bc312d..74f32bae 100644 --- a/src/main/java/cr0s/warpdrive/data/JumpBlock.java +++ b/src/main/java/cr0s/warpdrive/data/JumpBlock.java @@ -13,6 +13,7 @@ import cr0s.warpdrive.config.Filler; import java.lang.ref.WeakReference; import java.lang.reflect.Method; +import java.util.ConcurrentModificationException; import java.util.HashMap; import java.util.List; import java.util.Map.Entry; @@ -56,7 +57,10 @@ import net.minecraft.nbt.NBTTagList; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +import net.minecraft.world.WorldType; +import net.minecraft.world.chunk.Chunk; +import net.minecraftforge.common.util.BlockSnapshot; import net.minecraftforge.common.util.Constants; import net.minecraftforge.common.util.Constants.NBT; @@ -300,7 +304,7 @@ public class JumpBlock { block, newBlockMeta, nbtToDeploy)); } final IBlockState blockState = block.getStateFromMeta(newBlockMeta); - setBlockNoLight(worldTarget, target, blockState, 2); + setBlockStateNoLight(worldTarget, target, blockState, 2); if (nbtToDeploy != null) { nbtToDeploy.setInteger("x", target.getX()); @@ -407,7 +411,8 @@ public class JumpBlock { } // not needed: if ic2.core.block.machine.tileentity.TileEntityMatter then updated "state" } - } else if ( !superClassName.startsWith("mekanism.") + } else if ( !superClassName.contains("$") + && !superClassName.startsWith("mekanism.") && !superClassName.startsWith("micdoodle8.") ) {// IC2 extensions without network optimization (transferring all fields) try { final Method getNetworkedFields = teClass.getMethod("getNetworkedFields"); @@ -668,170 +673,57 @@ public class JumpBlock { } // This code is a straight copy from Vanilla net.minecraft.world.World.setBlock to remove lighting computations - public static boolean setBlockNoLight(final World w, final BlockPos blockPos, final IBlockState blockState, final int flags) { - return w.setBlockState(blockPos, blockState, flags); - /* - // x, y, z -> blockPos - // par6 -> flags - if (x >= -30000000 && z >= -30000000 && x < 30000000 && z < 30000000) { - if (y < 0) { - return false; - } else if (y >= 256) { - return false; - } else { - final Chunk chunk = w.getChunk(x >> 4, z >> 4); - Block block1 = null; - // net.minecraftforge.common.util.BlockSnapshot blockSnapshot = null; - - if ((par6 & 1) != 0) { - block1 = chunk.getBlock(x & 15, y, z & 15); - } - - // Disable rollback on item use - // if (w.captureBlockSnapshots && !w.isRemote) { - // blockSnapshot = net.minecraftforge.common.util.BlockSnapshot.getBlockSnapshot(w, x, y, z, par6); - // w.capturedBlockSnapshots.add(blockSnapshot); - // } - - final boolean flag = myChunkSBIDWMT(chunk, x & 15, y, z & 15, block, blockMeta); - - // Disable rollback on item use - // if (!flag && blockSnapshot != null) { - // w.capturedBlockSnapshots.remove(blockSnapshot); - // blockSnapshot = null; - // } - - // Remove light computations - // w.theProfiler.startSection("checkLight"); - // w.func_147451_t(x, y, z); - // w.theProfiler.endSection(); - - // Disable rollback on item use - // if (flag && blockSnapshot == null) {// Don't notify clients or update physics while capturing blockstates - // Modularize client and physic updates - // w.markAndNotifyBlock(x, y, z, chunk, block1, block, par6); - // } - if (flag) { - w.markAndNotifyBlock(x, y, z, chunk, block1, block, par6); - } - return flag; - } - } else { - return false; - } - /**/ - } - /* - // This code is a straight copy from Vanilla net.minecraft.world.Chunk.func_150807_a to remove lighting computations - private static boolean myChunkSBIDWMT(final Chunk c, final int x, final int y, final int z, final Block block, final int blockMeta) { - final int i1 = z << 4 | x; - - if (y >= c.precipitationHeightMap[i1] - 1) { - c.precipitationHeightMap[i1] = -999; + public static boolean setBlockStateNoLight(final World world, final BlockPos blockPosPassed, final IBlockState blockStateNew, final int flags) { + assert !world.captureBlockSnapshots; + if (!Commons.isSafeThread()) { + throw new ConcurrentModificationException(String.format("setBlockstate %s to %s 0x%x", + Commons.format(world, blockPosPassed), blockStateNew, flags)); } - // Removed light recalculations - // int j1 = c.heightMap[i1]; - final Block block1 = c.getBlock(x, y, z); - final int k1 = c.getBlockMetadata(x, y, z); + if (!WarpDriveConfig.G_ENABLE_FAST_SET_BLOCKSTATE) { + return world.setBlockState(blockPosPassed, blockStateNew, flags); + } - if (block1 == block && k1 == blockMeta) { + if (world.isOutsideBuildHeight(blockPosPassed)) { + return false; + } else if (!world.isRemote && world.getWorldInfo().getTerrainType() == WorldType.DEBUG_ALL_BLOCK_STATES) { return false; } else { - final ExtendedBlockStorage[] storageArrays = c.getBlockStorageArray(); - ExtendedBlockStorage extendedblockstorage = storageArrays[y >> 4]; - // Removed light recalculations - // boolean flag = false; + final Chunk chunk = world.getChunk(blockPosPassed); - if (extendedblockstorage == null) { - if (block == Blocks.air) { - return false; - } - - extendedblockstorage = storageArrays[y >> 4] = new ExtendedBlockStorage(y >> 4 << 4, !c.world.provider.hasNoSky); - // Removed light recalculations - // flag = y >= j1; + final BlockPos blockPos = blockPosPassed.toImmutable(); // Forge - prevent mutable BlockPos leaks + BlockSnapshot blockSnapshot = null; + if (world.captureBlockSnapshots && !world.isRemote) { + blockSnapshot = BlockSnapshot.getBlockSnapshot(world, blockPos, flags); + world.capturedBlockSnapshots.add(blockSnapshot); } + /* + final IBlockState blockStateOld = world.getBlockState(blockPos); + final int lightOld = blockStateOld.getLightValue(world, blockPos); + final int opacityOld = blockStateOld.getLightOpacity(world, blockPos); + /**/ - final int l1 = c.xPosition * 16 + x; - final int i2 = c.zPosition * 16 + z; + final IBlockState blockStateEffective = chunk.setBlockState(blockPos, blockStateNew); - // Removed light recalculations - // int k2 = block1.getLightOpacity(c.world, l1, y, i2); - - // Removed preDestroy event - // if (!c.world.isRemote) { - // block1.onBlockPreDestroy(c.world, l1, y, i2, k1); - // } - - extendedblockstorage.func_150818_a(x, y & 15, z, block); - extendedblockstorage.setExtBlockMetadata(x, y & 15, z, blockMeta); // This line duplicates the one below, so breakBlock fires with valid worldstate - - // Skip air at destination - if (block1 != Blocks.air) { - if (!c.world.isRemote) { - block1.breakBlock(c.world, l1, y, i2, block1, k1); - // After breakBlock a phantom TE might have been created with incorrect meta. This attempts to kill that phantom TE so the normal one can be created properly later - final TileEntity te = c.getTileEntityUnsafe(x & 0x0F, y, z & 0x0F); - if (te != null && te.shouldRefresh(block1, c.getBlock(x & 0x0F, y, z & 0x0F), k1, c.getBlockMetadata(x & 0x0F, y, z & 0x0F), c.world, l1, y, i2)) { - c.removeTileEntity(x & 0x0F, y, z & 0x0F); - } - } else if (block1.hasTileEntity(k1)) { - final TileEntity te = c.getTileEntityUnsafe(x & 0x0F, y, z & 0x0F); - if (te != null && te.shouldRefresh(block1, block, k1, blockMeta, c.world, l1, y, i2)) { - c.world.removeTileEntity(l1, y, i2); - } + if (blockStateEffective == null) { + if (blockSnapshot != null) { + world.capturedBlockSnapshots.remove(blockSnapshot); } - } - - if (extendedblockstorage.getBlockByExtId(x, y & 15, z) != block) { return false; } else { - extendedblockstorage.setExtBlockMetadata(x, y & 15, z, blockMeta); - // Removed light recalculations /* - if (flag) { - c.generateSkylightMap(); - } else { - int j2 = block.getLightOpacity(c.world, l1, y, i2); - - if (j2 > 0) { - if (y >= j1) { - c.relightBlock(x, y + 1, z); - } - } else if (y == j1 - 1) { - c.relightBlock(x, y, z); - } - - if (j2 != k2 && (j2 < k2 || c.getSavedLightValue(EnumSkyBlock.Sky, x, y, z) > 0 || c.getSavedLightValue(EnumSkyBlock.Block, x, y, z) > 0)) { - c.propagateSkylightOcclusion(x, z); - } + if ( blockStateNew.getLightOpacity(world, blockPos) != opacityOld + || blockStateNew.getLightValue(world, blockPos) != lightOld ) { + world.profiler.startSection("checkLight"); + world.checkLight(blockPos); + world.profiler.endSection(); } /**/ - /* - final TileEntity tileentity; - - // Removed onBlockAdded event - // if (!c.world.isRemote) { - // block.onBlockAdded(c.world, l1, y, i2); - // } - - // Skip air at destination - if (block1 != Blocks.air) { - if (block.hasTileEntity(blockMeta)) { - tileentity = c.func_150806_e(x, y, z); - - if (tileentity != null) { - tileentity.updateContainingBlockInfo(); - tileentity.blockMetadata = blockMeta; - } - } + if (blockSnapshot == null) {// Don't notify clients or update physics while capturing blockstates + world.markAndNotifyBlock(blockPos, chunk, blockStateEffective, blockStateNew, flags); } - - c.isModified = true; return true; } } } - /**/ } diff --git a/src/main/java/cr0s/warpdrive/event/JumpSequencer.java b/src/main/java/cr0s/warpdrive/event/JumpSequencer.java index 6392801a..fa66e940 100644 --- a/src/main/java/cr0s/warpdrive/event/JumpSequencer.java +++ b/src/main/java/cr0s/warpdrive/event/JumpSequencer.java @@ -1248,11 +1248,11 @@ public class JumpSequencer extends AbstractSequencer { } try { final BlockPos blockPos = new BlockPos(jumpBlock.x, jumpBlock.y, jumpBlock.z); - boolean isRemoved = JumpBlock.setBlockNoLight(sourceWorld, blockPos, Blocks.AIR.getDefaultState(), 2); + boolean isRemoved = JumpBlock.setBlockStateNoLight(sourceWorld, blockPos, Blocks.AIR.getDefaultState(), 2); if (!isRemoved) { WarpDrive.logger.info(String.format("Failed to remove %s@%d at (%d %d %d), retrying...", jumpBlock.block, jumpBlock.blockMeta, jumpBlock.x, jumpBlock.y, jumpBlock.z)); - isRemoved = JumpBlock.setBlockNoLight(sourceWorld, blockPos, Blocks.AIR.getDefaultState(), 2); + isRemoved = JumpBlock.setBlockStateNoLight(sourceWorld, blockPos, Blocks.AIR.getDefaultState(), 2); if (!isRemoved) { WarpDrive.logger.error(String.format("Failed to remove %s@%d at (%d %d %d), still failing?", jumpBlock.block, jumpBlock.blockMeta, jumpBlock.x, jumpBlock.y, jumpBlock.z)); diff --git a/src/main/java/cr0s/warpdrive/world/EntitySphereGen.java b/src/main/java/cr0s/warpdrive/world/EntitySphereGen.java index 4ba99037..e055b4bb 100644 --- a/src/main/java/cr0s/warpdrive/world/EntitySphereGen.java +++ b/src/main/java/cr0s/warpdrive/world/EntitySphereGen.java @@ -167,7 +167,7 @@ public final class EntitySphereGen extends Entity { if (isSurfaces.get(currentIndex)) { world.setBlockState(mutableBlockPos, jumpBlock.block.getStateFromMeta(jumpBlock.blockMeta), 2); } else { - JumpBlock.setBlockNoLight(world, mutableBlockPos, jumpBlock.block.getStateFromMeta(jumpBlock.blockMeta), 2); + JumpBlock.setBlockStateNoLight(world, mutableBlockPos, jumpBlock.block.getStateFromMeta(jumpBlock.blockMeta), 2); } currentIndex++; }