Prevent chunk unload during async relight + delay tasks

This commit is contained in:
Jesse Boyd 2016-06-28 22:09:47 +10:00
parent 478cbbf393
commit a521cb9ac3
4 changed files with 92 additions and 32 deletions

View File

@ -4,19 +4,29 @@ import com.boydti.fawe.Fawe;
import com.boydti.fawe.example.CharFaweChunk; import com.boydti.fawe.example.CharFaweChunk;
import com.boydti.fawe.example.NMSMappedFaweQueue; import com.boydti.fawe.example.NMSMappedFaweQueue;
import com.boydti.fawe.object.FaweChunk; import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.util.MathMan;
import com.boydti.fawe.util.SetQueue;
import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ConcurrentLinkedDeque;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Chunk; import org.bukkit.Chunk;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.world.ChunkUnloadEvent;
import org.bukkit.plugin.Plugin;
public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMappedFaweQueue<World, CHUNK, CHUNKSECTIONS, SECTION> { public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMappedFaweQueue<World, CHUNK, CHUNKSECTIONS, SECTION> implements Listener {
public Object adapter; public Object adapter;
public Method methodToNative; public Method methodToNative;
@ -25,6 +35,10 @@ public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMa
public BukkitQueue_0(final String world) { public BukkitQueue_0(final String world) {
super(world); super(world);
setupAdapter(null); setupAdapter(null);
if (!registered) {
registered = true;
Bukkit.getServer().getPluginManager().registerEvents(this, (Plugin) Fawe.imp());
}
} }
public void checkVersion(String supported) { public void checkVersion(String supported) {
@ -35,34 +49,58 @@ public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMa
} }
} }
public void setupAdapter(BukkitImplAdapter adapter) { private static boolean registered = false;
try {
WorldEditPlugin instance = (WorldEditPlugin) Bukkit.getPluginManager().getPlugin("WorldEdit"); @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
Field fieldAdapter = WorldEditPlugin.class.getDeclaredField("bukkitAdapter"); public static void onChunkUnload(ChunkUnloadEvent event) {
fieldAdapter.setAccessible(true); ConcurrentLinkedDeque<FaweQueue> queues = SetQueue.IMP.activeQueues;
if ((this.adapter = adapter) != null) { if (queues.isEmpty()) {
fieldAdapter.set(instance, adapter); return;
} else { }
this.adapter = fieldAdapter.get(instance); String world = event.getWorld().getName();
} Chunk chunk = event.getChunk();
for (Method method : this.adapter.getClass().getDeclaredMethods()) { long pair = MathMan.pairInt(chunk.getX(), chunk.getZ());
switch (method.getName()) { for (FaweQueue queue : queues) {
case "toNative": if (queue.getWorldName().equals(world)) {
methodToNative = method; HashSet<Long> relighting = ((NMSMappedFaweQueue) queue).relighting;
methodToNative.setAccessible(true); if (!relighting.isEmpty() && relighting.contains(pair)) {
break; event.setCancelled(true);
case "fromNative": return;
methodFromNative = method;
methodFromNative.setAccessible(true);
break;
} }
} }
} catch (Throwable e) { }
Fawe.debug("====== NO NATIVE WORLDEDIT ADAPTER ======"); }
Fawe.debug("Try updating WorldEdit: ");
Fawe.debug(" - http://builds.enginehub.org/job/worldedit?branch=master"); public void setupAdapter(BukkitImplAdapter adapter) {
Fawe.debug("See also: http://wiki.sk89q.com/wiki/WorldEdit/Bukkit_adapters"); if (adapter == null) {
Fawe.debug("========================================="); try {
WorldEditPlugin instance = (WorldEditPlugin) Bukkit.getPluginManager().getPlugin("WorldEdit");
Field fieldAdapter = WorldEditPlugin.class.getDeclaredField("bukkitAdapter");
fieldAdapter.setAccessible(true);
if ((this.adapter = adapter) != null) {
fieldAdapter.set(instance, adapter);
} else {
this.adapter = fieldAdapter.get(instance);
}
for (Method method : this.adapter.getClass().getDeclaredMethods()) {
switch (method.getName()) {
case "toNative":
methodToNative = method;
methodToNative.setAccessible(true);
break;
case "fromNative":
methodFromNative = method;
methodFromNative.setAccessible(true);
break;
}
}
} catch (Throwable e) {
Fawe.debug("====== NO NATIVE WORLDEDIT ADAPTER ======");
Fawe.debug("Try updating WorldEdit: ");
Fawe.debug(" - http://builds.enginehub.org/job/worldedit?branch=master");
Fawe.debug("See also: http://wiki.sk89q.com/wiki/WorldEdit/Bukkit_adapters");
Fawe.debug("=========================================");
}
} }
} }

View File

@ -273,7 +273,6 @@ public class BukkitQueue_1_10 extends BukkitQueue_0<Chunk, ChunkSection[], DataP
continue; continue;
} }
pos.c(X + x, y, Z + z); pos.c(X + x, y, Z + z);
if (async && !chunk.isLoaded()) return false;
w.w(pos); w.w(pos);
} }
continue; continue;
@ -314,7 +313,6 @@ public class BukkitQueue_1_10 extends BukkitQueue_0<Chunk, ChunkSection[], DataP
continue; continue;
} }
pos.c(X + x, y, Z + z); pos.c(X + x, y, Z + z);
if (async && !chunk.isLoaded()) return false;
w.w(pos); w.w(pos);
} }
} }

View File

@ -25,8 +25,8 @@ public abstract class MappedFaweQueue<WORLD, CHUNK, SECTION> extends FaweQueue {
/** /**
* Map of chunks in the queue * Map of chunks in the queue
*/ */
private ConcurrentHashMap<Long, FaweChunk> blocks = new ConcurrentHashMap<>(); public ConcurrentHashMap<Long, FaweChunk> blocks = new ConcurrentHashMap<>();
private ConcurrentLinkedDeque<FaweChunk> chunks = new ConcurrentLinkedDeque<FaweChunk>() { public ConcurrentLinkedDeque<FaweChunk> chunks = new ConcurrentLinkedDeque<FaweChunk>() {
@Override @Override
public boolean add(FaweChunk o) { public boolean add(FaweChunk o) {
if (getProgressTask() != null) { if (getProgressTask() != null) {
@ -35,7 +35,7 @@ public abstract class MappedFaweQueue<WORLD, CHUNK, SECTION> extends FaweQueue {
return super.add(o); return super.add(o);
} }
}; };
private ArrayDeque<Runnable> tasks = new ArrayDeque<>(); public ArrayDeque<Runnable> tasks = new ArrayDeque<>();
@Override @Override
public void optimize() { public void optimize() {

View File

@ -4,9 +4,12 @@ import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.FaweChunk; import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.FaweQueue; import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.object.exception.FaweException; import com.boydti.fawe.object.exception.FaweException;
import com.boydti.fawe.util.MathMan;
import com.boydti.fawe.util.SetQueue;
import com.boydti.fawe.util.TaskManager; import com.boydti.fawe.util.TaskManager;
import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTag;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
@ -16,6 +19,13 @@ public abstract class NMSMappedFaweQueue<WORLD, CHUNK, CHUNKSECTION, SECTION> ex
super(world); super(world);
} }
public boolean isRelighting(int x, int z) {
long pair = MathMan.pairInt(x, z);
return relighting.contains(pair) || blocks.contains(pair);
}
public final HashSet<Long> relighting = new HashSet<>();
@Override @Override
public void sendChunk(final FaweChunk fc, RelightMode mode) { public void sendChunk(final FaweChunk fc, RelightMode mode) {
if (mode == null) { if (mode == null) {
@ -25,6 +35,8 @@ public abstract class NMSMappedFaweQueue<WORLD, CHUNK, CHUNKSECTION, SECTION> ex
TaskManager.IMP.taskSyncSoon(new Runnable() { TaskManager.IMP.taskSyncSoon(new Runnable() {
@Override @Override
public void run() { public void run() {
final long pair = fc.longHash();
relighting.add(pair);
final boolean result = finalMode == RelightMode.NONE || fixLighting(fc, finalMode); final boolean result = finalMode == RelightMode.NONE || fixLighting(fc, finalMode);
TaskManager.IMP.taskSyncNow(new Runnable() { TaskManager.IMP.taskSyncNow(new Runnable() {
@Override @Override
@ -34,6 +46,10 @@ public abstract class NMSMappedFaweQueue<WORLD, CHUNK, CHUNKSECTION, SECTION> ex
} }
CHUNK chunk = (CHUNK) fc.getChunk(); CHUNK chunk = (CHUNK) fc.getChunk();
refreshChunk(getWorld(), chunk); refreshChunk(getWorld(), chunk);
relighting.remove(pair);
if (relighting.isEmpty()) {
runTasks();
}
} }
}, false); }, false);
} }
@ -63,4 +79,12 @@ public abstract class NMSMappedFaweQueue<WORLD, CHUNK, CHUNKSECTION, SECTION> ex
} }
return getTileEntity(lastChunk, x, y, z); return getTileEntity(lastChunk, x, y, z);
} }
@Override
public int size() {
if (chunks.size() == 0 && SetQueue.IMP.getStage(this) != SetQueue.QueueStage.INACTIVE && relighting.isEmpty()) {
runTasks();
}
return chunks.size();
}
} }