Skip to content

Commit

Permalink
Protect against chunk read server freezing
Browse files Browse the repository at this point in the history
Fixes all tag timing block load issues from the past as well!
  • Loading branch information
mcmonkey4eva committed Apr 26, 2019
1 parent 8db18e1 commit 952089b
Show file tree
Hide file tree
Showing 14 changed files with 162 additions and 77 deletions.
Expand Up @@ -18,7 +18,9 @@ public ModernBlockData(Material material) {
}

public ModernBlockData(Block block) {
NMSHandler.getInstance().getChunkHelper().changeChunkServerThread(block.getWorld());
this.data = block.getBlockData();
NMSHandler.getInstance().getChunkHelper().restoreServerThread(block.getWorld());
}

public ModernBlockData(BlockState block) {
Expand Down
@@ -1,10 +1,19 @@
package net.aufdemrand.denizen.nms.interfaces;

import org.bukkit.Chunk;
import org.bukkit.World;

public interface ChunkHelper {

void refreshChunkSections(Chunk chunk);

int[] getHeightMap(Chunk chunk);

default void changeChunkServerThread(World world) {
// Do nothing by default.
}

default void restoreServerThread(World world) {
// Do nothing by default.
}
}
Expand Up @@ -69,7 +69,7 @@ public boolean matches(ScriptPath path) {

String mat = path.eventArgLowerAt(2);
if (!mat.equals("sign")
&& (!(event.getBlock().getState() instanceof Sign)
&& (!(dLocation.getBlockStateFor(event.getBlock()) instanceof Sign)
&& (!mat.equals(material.identifyNoIdentifier()) && !mat.equals(material.identifyFullNoIdentifier())))) {
return false;
}
Expand Down Expand Up @@ -131,7 +131,7 @@ public void onPlayerChangesSign(SignChangeEvent event) {
if (dEntity.isNPC(event.getPlayer())) {
return;
}
BlockState state = event.getBlock().getState();
BlockState state = dLocation.getBlockStateFor(event.getBlock());
if (!(state instanceof Sign)) {
return;
}
Expand Down
Expand Up @@ -462,7 +462,7 @@ private boolean matchesMaterialList(Location loc, List<dMaterial> materials) {
if (materials == null) {
return true;
}
dMaterial mat = OldMaterialsHelper.getMaterialFrom(loc.getBlock().getType(), loc.getBlock().getData());
dMaterial mat = new dMaterial(loc.getBlock());
for (dMaterial material : materials) {
if (mat.equals(material) || (mat.getMaterial() == material.getMaterial()
&& (material.getData() == null || material.getData() == 0))) { // TODO: only if null?
Expand Down Expand Up @@ -504,8 +504,7 @@ public List<dLocation> getBlocks_internal(List<dMaterial> materials) {
if (!filter.isEmpty()) { // TODO: Should 'filter' exist?
// Check filter
for (dObject material : filter) {
if (((dMaterial) material).matchesMaterialData(
new MaterialData(loc.getBlock().getType(), loc.getBlock().getData()))) {
if (((dMaterial) material).matchesBlock(loc.getBlock())) {
if (matchesMaterialList(loc, materials)) {
list.add(loc);
}
Expand Down
97 changes: 54 additions & 43 deletions plugin/src/main/java/net/aufdemrand/denizen/objects/dLocation.java

Large diffs are not rendered by default.

Expand Up @@ -250,21 +250,23 @@ public dMaterial(BlockState state) {
}

public dMaterial(BlockData block) {
this.material = block.getMaterial();
if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_13_R2)) {
this.modernData = block.modern();
this.material = modernData.getMaterial();
}
else {
this.material = block.getMaterial();
this.data = block.getData();
}
}

public dMaterial(Block block) {
this.material = block.getType();
if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_13_R2)) {
this.modernData = new ModernBlockData(block);
this.material = modernData.getMaterial();
}
else {
this.material = block.getType();
this.data = block.getData();
}
}
Expand Down
Expand Up @@ -91,14 +91,14 @@ else if (copy_cuboid != null) {
for (Location loc : locations) {

Block source = loc.getBlock();
BlockState sourceState = source.getState();
BlockState sourceState = dLocation.getBlockStateFor(source);
Block update = destination.getBlock();

// TODO: 1.13 - confirm this works
BlockData blockData = NMSHandler.getInstance().getBlockHelper().getBlockData(source);
blockData.setBlock(update, false);

BlockState updateState = update.getState();
BlockState updateState = dLocation.getBlockStateFor(update);

// Note: only a BlockState, not a Block, is actually an instance
// of InventoryHolder
Expand Down
Expand Up @@ -111,7 +111,7 @@ public void execute(final ScriptEntry scriptEntry) {
// TODO: 1.14 - allow new sign types?
sign.setType(MaterialCompat.SIGN, false);
if (direction != null) {
Utilities.setSignRotation(sign.getState(), direction);
Utilities.setSignRotation(dLocation.getBlockStateFor(sign), direction);
}
}
}
Expand All @@ -125,7 +125,7 @@ else if (MaterialCompat.isAnySign(sign.getType())) {
setWallSign(sign, bf);
}
}
BlockState signState = sign.getState();
BlockState signState = dLocation.getBlockStateFor(sign);

Utilities.setSignLines((Sign) signState, text.toArray(4));
}
Expand Down
@@ -1,5 +1,6 @@
package net.aufdemrand.denizen.utilities.blocks;

import net.aufdemrand.denizen.nms.abstracts.ModernBlockData;
import net.aufdemrand.denizen.utilities.Utilities;
import net.aufdemrand.denizen.utilities.debugging.dB;
import org.bukkit.block.Block;
Expand All @@ -12,18 +13,20 @@
public class DirectionalBlocksHelper {

public static boolean isBedTopHalf(Block b) {
if (b.getBlockData() instanceof Bed) {
return ((Bed) b.getBlockData()).getPart() == Bed.Part.HEAD;
ModernBlockData mbd = new ModernBlockData(b);
if (mbd.data instanceof Bed) {
return ((Bed) mbd.data).getPart() == Bed.Part.HEAD;
}
return false;
}

public static BlockFace getFace(Block b) {
if (b.getBlockData() instanceof Directional) {
return ((Directional) b.getBlockData()).getFacing();
ModernBlockData mbd = new ModernBlockData(b);
if (mbd.data instanceof Directional) {
return ((Directional) mbd.data).getFacing();
}
else if (b.getBlockData() instanceof Rotatable) {
return ((Rotatable) b.getBlockData()).getRotation();
else if (mbd.data instanceof Rotatable) {
return ((Rotatable) mbd.data).getRotation();
}
return null;
}
Expand All @@ -37,13 +40,14 @@ public static Vector getFacing(Block b) {
}

public static void setFace(Block b, BlockFace face) {
if (b.getBlockData() instanceof Directional) {
Directional dir = (Directional) b.getBlockData();
ModernBlockData mbd = new ModernBlockData(b);
if (mbd.data instanceof Directional) {
Directional dir = (Directional) mbd.data;
dir.setFacing(face);
b.setBlockData(dir);
}
else if (b.getBlockData() instanceof Rotatable) {
Rotatable dir = (Rotatable) b.getBlockData();
else if (mbd.data instanceof Rotatable) {
Rotatable dir = (Rotatable) mbd.data;
dir.setRotation(face);
b.setBlockData(dir);
}
Expand Down
Expand Up @@ -91,7 +91,7 @@ private void cancelBlock() {
}
cancelTime = -1;
material = null;
location.getBlock().getState().update();
location.getBlockState().update();
blocks.get(player.getOfflinePlayer().getUniqueId()).remove(location);
}

Expand Down
Expand Up @@ -277,29 +277,36 @@ public BiomeNMS getBiomeNMS(Biome biome) {

@Override
public Boolean getSwitchState(Block b) {
if (b.getBlockData() instanceof Openable) {
return ((Openable) b.getBlockData()).isOpen();
ModernBlockData mbd = new ModernBlockData(b);
if (mbd.data instanceof Openable) {
return ((Openable) mbd.data).isOpen();
}
else if (b.getBlockData() instanceof Powerable) {
return ((Powerable) b.getBlockData()).isPowered();
else if (mbd.data instanceof Powerable) {
return ((Powerable) mbd.data).isPowered();
}
return null;
}

@Override
public boolean setSwitchState(Location interactLocation, boolean state) {
if (interactLocation.getBlock().getBlockData() instanceof Openable) {
Openable newState = ((Openable) interactLocation.getBlock().getBlockData());
Block block = interactLocation.getBlock();
ModernBlockData mbd = new ModernBlockData(block);
if (mbd.data instanceof Openable) {
Openable newState = ((Openable) mbd.data);
newState.setOpen(state);
NMSHandler.getInstance().getChunkHelper().changeChunkServerThread(block.getWorld());
interactLocation.getBlock().setBlockData(newState, true);
interactLocation.getBlock().getState().update(true, true);
NMSHandler.getInstance().getChunkHelper().restoreServerThread(block.getWorld());
return true;
}
else if (interactLocation.getBlock().getBlockData() instanceof Powerable) {
Powerable newState = ((Powerable) interactLocation.getBlock().getBlockData());
else if (mbd.data instanceof Powerable) {
Powerable newState = ((Powerable) mbd.data);
newState.setPowered(state);
NMSHandler.getInstance().getChunkHelper().changeChunkServerThread(block.getWorld());
interactLocation.getBlock().setBlockData(newState, true);
interactLocation.getBlock().getState().update(true, true);
NMSHandler.getInstance().getChunkHelper().restoreServerThread(block.getWorld());
return true;
}
return false;
Expand Down
Expand Up @@ -3,6 +3,7 @@
import com.google.common.collect.Iterables;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.Property;
import net.aufdemrand.denizen.nms.NMSHandler;
import net.aufdemrand.denizen.nms.abstracts.ModernBlockData;
import net.aufdemrand.denizen.nms.impl.blocks.BlockData_v1_14_R1;
import net.aufdemrand.denizen.nms.impl.jnbt.CompoundTag_v1_14_R1;
Expand Down Expand Up @@ -82,12 +83,15 @@ public void setPlayerProfile(Skull skull, PlayerProfile playerProfile) {
}
TileEntitySkull tileEntity = getTE((CraftSkull) skull);
tileEntity.setGameProfile(gameProfile);
skull.getBlock().getState().update();
skull.update();
}

@Override
public CompoundTag getNbtData(Block block) {
TileEntity tileEntity = getTE((CraftBlockEntityState) block.getState());
NMSHandler.getInstance().getChunkHelper().changeChunkServerThread(block.getWorld());
org.bukkit.block.BlockState state = block.getState();
NMSHandler.getInstance().getChunkHelper().restoreServerThread(block.getWorld());
TileEntity tileEntity = getTE((CraftBlockEntityState) state);
if (tileEntity == null) {
return null;
}
Expand All @@ -96,7 +100,10 @@ public CompoundTag getNbtData(Block block) {

@Override
public void setNbtData(Block block, CompoundTag compoundTag) {
TileEntity tileEntity = getTE((CraftBlockEntityState) block.getState());
NMSHandler.getInstance().getChunkHelper().changeChunkServerThread(block.getWorld());
org.bukkit.block.BlockState state = block.getState();
NMSHandler.getInstance().getChunkHelper().restoreServerThread(block.getWorld());
TileEntity tileEntity = getTE((CraftBlockEntityState) state);
if (tileEntity == null) {
return;
}
Expand Down
@@ -1,13 +1,56 @@
package net.aufdemrand.denizen.nms.helpers;

import net.aufdemrand.denizen.nms.interfaces.ChunkHelper;
import net.aufdemrand.denizen.nms.util.ReflectionHelper;
import net.aufdemrand.denizencore.utilities.debugging.dB;
import net.minecraft.server.v1_14_R1.*;
import org.bukkit.World;
import org.bukkit.Chunk;
import org.bukkit.craftbukkit.v1_14_R1.CraftChunk;
import org.bukkit.craftbukkit.v1_14_R1.CraftWorld;

import java.lang.reflect.Field;

public class ChunkHelper_v1_14_R1 implements ChunkHelper {

public final static Field chunkProviderServerThreadField;

static {
chunkProviderServerThreadField = ReflectionHelper.getFields(ChunkProviderServer.class).get("serverThread");
}

Thread resetServerThread;

@Override
public void changeChunkServerThread(World world) {
if (resetServerThread != null) {
return;
}
ChunkProviderServer provider = ((CraftWorld) world).getHandle().getChunkProvider();
try {
resetServerThread = (Thread) chunkProviderServerThreadField.get(provider);
chunkProviderServerThreadField.set(provider, Thread.currentThread());
}
catch (IllegalAccessException ex) {
dB.echoError(ex);
}
}

@Override
public void restoreServerThread(World world) {
if (resetServerThread == null) {
return;
}
ChunkProviderServer provider = ((CraftWorld) world).getHandle().getChunkProvider();
try {
chunkProviderServerThreadField.set(provider, resetServerThread);
resetServerThread = null;
}
catch (IllegalAccessException ex) {
dB.echoError(ex);
}
}

@Override
public void refreshChunkSections(Chunk chunk) {
PacketPlayOutMapChunk lowPacket = new PacketPlayOutMapChunk(((CraftChunk) chunk).getHandle(), 255); // 00000000 11111111
Expand Down
Expand Up @@ -37,7 +37,8 @@ public BlockData_v1_14_R1(org.bukkit.block.data.BlockData data) {
}

public BlockData_v1_14_R1(Block block) {
blockData = block.getBlockData();
ModernBlockData mbd = new ModernBlockData(block);
blockData = mbd.data;
TileEntity te = ((CraftWorld) block.getWorld()).getHandle().getTileEntity(
new BlockPosition(block.getX(), block.getY(), block.getZ()));
if (te != null) {
Expand Down

0 comments on commit 952089b

Please sign in to comment.