123 lines
4.4 KiB
Java
123 lines
4.4 KiB
Java
package tc.oc.pgm.listeners;
|
|
|
|
import java.util.HashSet;
|
|
import java.util.Set;
|
|
import javax.annotation.Nullable;
|
|
import javax.inject.Inject;
|
|
|
|
import org.bukkit.Bukkit;
|
|
import org.bukkit.ChatColor;
|
|
import org.bukkit.Chunk;
|
|
import org.bukkit.Location;
|
|
import org.bukkit.Material;
|
|
import org.bukkit.World;
|
|
import org.bukkit.block.Block;
|
|
import org.bukkit.block.BlockFace;
|
|
import org.bukkit.block.BlockState;
|
|
import org.bukkit.block.Skull;
|
|
import org.bukkit.event.EventHandler;
|
|
import org.bukkit.event.EventPriority;
|
|
import org.bukkit.event.Listener;
|
|
import org.bukkit.event.world.ChunkLoadEvent;
|
|
import tc.oc.api.util.Permissions;
|
|
import tc.oc.commons.bukkit.util.BlockVectorSet;
|
|
import tc.oc.commons.bukkit.util.ChunkPosition;
|
|
import tc.oc.commons.bukkit.util.NMSHacks;
|
|
import tc.oc.pgm.events.ListenerScope;
|
|
import tc.oc.pgm.match.Match;
|
|
import tc.oc.pgm.match.MatchModule;
|
|
import tc.oc.pgm.match.MatchScope;
|
|
import tc.oc.pgm.terrain.TerrainOptions;
|
|
|
|
@ListenerScope(MatchScope.LOADED)
|
|
public class WorldProblemMatchModule extends MatchModule implements Listener {
|
|
|
|
private static final int RANDOM_TICK_SPEED_LIMIT = 30;
|
|
|
|
private final Set<ChunkPosition> repairedChunks = new HashSet<>();
|
|
private final BlockVectorSet block36Locations = new BlockVectorSet();
|
|
|
|
@Inject private TerrainOptions options;
|
|
@Inject private World world;
|
|
|
|
@Inject WorldProblemMatchModule(Match match) {
|
|
super(match);
|
|
}
|
|
|
|
void broadcastDeveloperWarning(String message) {
|
|
logger.warning(message);
|
|
Bukkit.broadcast(ChatColor.RED + message, Permissions.MAPERRORS);
|
|
}
|
|
|
|
@Override
|
|
public void load() {
|
|
super.load();
|
|
|
|
final String str = world.getGameRuleValue("randomTickSpeed");
|
|
if(str != null) {
|
|
try {
|
|
int value = Integer.parseInt(str);
|
|
if(value > RANDOM_TICK_SPEED_LIMIT) {
|
|
broadcastDeveloperWarning("Gamerule 'randomTickSpeed' is set to " + value + " for this world (normal value is 3). This may overload the server.");
|
|
}
|
|
} catch(NumberFormatException ignored) {}
|
|
}
|
|
|
|
for(Chunk chunk : world.getLoadedChunks()) {
|
|
checkChunk(chunk);
|
|
}
|
|
if (!options.remove36())
|
|
broadcastDeveloperWarning("Block 36 will NOT be removed! This can cause lag.");
|
|
}
|
|
|
|
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
|
public void onChunkLoad(ChunkLoadEvent event) {
|
|
if(world.equals(event.getWorld())) {
|
|
checkChunk(event.getChunk());
|
|
}
|
|
}
|
|
|
|
private void checkChunk(Chunk chunk) {
|
|
checkChunk(ChunkPosition.of(chunk), chunk);
|
|
}
|
|
|
|
private void checkChunk(ChunkPosition pos, @Nullable Chunk chunk) {
|
|
if(repairedChunks.add(pos)) {
|
|
if(chunk == null) {
|
|
chunk = pos.getChunk(match.getWorld());
|
|
}
|
|
|
|
for(BlockState state : chunk.getTileEntities()) {
|
|
if(state instanceof Skull) {
|
|
if(!NMSHacks.isSkullCached((Skull) state)) {
|
|
Location loc = state.getLocation();
|
|
broadcastDeveloperWarning("Uncached skull \"" + ((Skull) state).getOwner() + "\" at " + loc.getBlockX() + ", " + loc.getBlockY() + ", " + loc.getBlockZ());
|
|
}
|
|
}
|
|
}
|
|
|
|
// Replace formerly invisible half-iron-door blocks with barriers
|
|
for(Block ironDoor : chunk.getBlocks(Material.IRON_DOOR_BLOCK)) {
|
|
BlockFace half = (ironDoor.getData() & 8) == 0 ? BlockFace.DOWN : BlockFace.UP;
|
|
if(ironDoor.getRelative(half.getOppositeFace()).getType() != Material.IRON_DOOR_BLOCK) {
|
|
ironDoor.setType(Material.BARRIER, false);
|
|
}
|
|
}
|
|
if (options.remove36()) {
|
|
// Remove all block 36 and remember the ones at y=0 so VoidFilter can check them
|
|
for(Block block36 : chunk.getBlocks(Material.PISTON_MOVING_PIECE)) {
|
|
if(block36.getY() == 0) {
|
|
block36Locations.add(block36.getX(), block36.getY(), block36.getZ());
|
|
}
|
|
block36.setType(Material.AIR, false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public boolean wasBlock36(int x, int y, int z) {
|
|
checkChunk(ChunkPosition.ofBlock(x, y, z), null);
|
|
return block36Locations.contains(x, y, z);
|
|
}
|
|
}
|