From bc1874d6704d78c6e612b1916e1cbc42700a2734 Mon Sep 17 00:00:00 2001 From: SBPrime Date: Mon, 27 May 2019 21:50:11 +0200 Subject: [PATCH] Fix paper compatibility --- .../asyncworldedit/core/ChunkWatch.java | 16 ++ .../platform/bukkit/BukkitChunkWatcher.java | 181 ++++++++++++------ .../dependency-reduced-pom.xml | 2 +- .../visitors/ChunkProviderServerVisitor.java | 23 +-- pom.xml | 2 +- 5 files changed, 139 insertions(+), 85 deletions(-) diff --git a/AsyncWorldEdit/src/main/java/org/primesoft/asyncworldedit/core/ChunkWatch.java b/AsyncWorldEdit/src/main/java/org/primesoft/asyncworldedit/core/ChunkWatch.java index e1b989e..c793c40 100644 --- a/AsyncWorldEdit/src/main/java/org/primesoft/asyncworldedit/core/ChunkWatch.java +++ b/AsyncWorldEdit/src/main/java/org/primesoft/asyncworldedit/core/ChunkWatch.java @@ -148,6 +148,22 @@ public void remove(int cx, int cz, String worldName) { } } + protected final int getReferences(String worldName, int cx, int cz) { + synchronized (m_watchedChunks) { + Map worldEntry = m_watchedChunks.get(worldName); + if (worldEntry == null) { + return 0; + } + + long chunk = encode(cx, cz); + Integer value = worldEntry.get(chunk); + if (value == null) { + return 0; + } + return value; + } + } + protected void chunkLoaded(String worldName, int cx, int cz) { synchronized (m_loadedChunks) { m_loadedChunks diff --git a/AsyncWorldEdit/src/main/java/org/primesoft/asyncworldedit/platform/bukkit/BukkitChunkWatcher.java b/AsyncWorldEdit/src/main/java/org/primesoft/asyncworldedit/platform/bukkit/BukkitChunkWatcher.java index 7cc63de..df33f60 100644 --- a/AsyncWorldEdit/src/main/java/org/primesoft/asyncworldedit/platform/bukkit/BukkitChunkWatcher.java +++ b/AsyncWorldEdit/src/main/java/org/primesoft/asyncworldedit/platform/bukkit/BukkitChunkWatcher.java @@ -47,10 +47,16 @@ */ package org.primesoft.asyncworldedit.platform.bukkit; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; import java.util.Map; +import java.util.Queue; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.logging.Level; -import java.util.logging.Logger; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.SynchronousQueue; +import java.util.function.Predicate; import org.bukkit.Chunk; import org.bukkit.Server; import org.bukkit.World; @@ -68,17 +74,111 @@ */ class BukkitChunkWatcher extends ChunkWatch implements Listener { + private final static int HOLD_CHUNK = 5000; + private final Plugin m_plugin; - private final Map> m_forceload = new ConcurrentHashMap<>(); + private final Map> m_forceload = new HashMap<>(); + + private final Queue m_forceLoadQueue = new ConcurrentLinkedQueue<>(); + private final Queue m_forceUnLoadQueue = new ConcurrentLinkedQueue<>(); private final BukkitScheduler m_scheduler; private final Server m_server; + private long m_lastAccess; + public BukkitChunkWatcher(Plugin plugin) { m_plugin = plugin; m_server = plugin.getServer(); m_scheduler = m_server.getScheduler(); + + m_scheduler.runTaskTimer(plugin, this::forceLoadProcessor, 1, 1); + } + + private void forceLoadProcessor() { + long now = System.currentTimeMillis(); + long minTime = now - HOLD_CHUNK; + /*final Predicate test = t -> t.timestamp <= minTime || !t.unloadChunk; + while (!m_forceLoadQueue.isEmpty() && test.test(m_forceLoadQueue.peek())) { + final ForceLoadEntry e = m_forceLoadQueue.poll(); + final World world = m_server.getWorld(e.world); + if (world == null) { + continue; + } + + final Chunk chunk = world.getChunkAt(e.cx, e.cz); + final long coords = encode(e.cx, e.cz); + + if (!e.unloadChunk && !chunk.isForceLoaded() && e.timestamp >= m_lastAccess) { + chunk.setForceLoaded(true); + m_forceload.computeIfAbsent(e.world, i -> new HashSet<>()).add(coords); + } else if (e.unloadChunk) { + final Set entries = m_forceload.get(e.world); + if (!entries.contains(coords) || getReferences(e.world, e.cx, e.cz) > 0) { + continue; + } + + entries.remove(coords); + chunk.setForceLoaded(false); + } + + m_lastAccess = e.timestamp; + }*/ + while (!m_forceLoadQueue.isEmpty()) { + final ForceLoadEntry e = m_forceLoadQueue.poll(); + + final World world = m_server.getWorld(e.world); + if (world == null) { + continue; + } + + final Chunk chunk = world.getChunkAt(e.cx, e.cz); + final long coords = encode(e.cx, e.cz); + + Map chunkEntry = m_forceload.computeIfAbsent(e.world, i -> new HashMap<>()); + if (!chunk.isForceLoaded()) { + chunkEntry.put(coords, now); + chunk.setForceLoaded(true); + } else if (chunkEntry.containsKey(coords)) { + chunkEntry.put(coords, now); + } + } + + while (!m_forceUnLoadQueue.isEmpty()) { + final ForceLoadEntry e = m_forceUnLoadQueue.peek(); + + Map chunkEntry = m_forceload.get(e.world); + if (chunkEntry == null) { + m_forceUnLoadQueue.poll(); + continue; + } + + final long coords = encode(e.cx, e.cz); + Long value = chunkEntry.get(coords); + if (value == null) { + m_forceUnLoadQueue.poll(); + continue; + } + + if (value >= now - HOLD_CHUNK) { + break; + } + + m_forceUnLoadQueue.poll(); + chunkEntry.remove(coords); + + final World world = m_server.getWorld(e.world); + if (world == null) { + continue; + } + + final Chunk chunk = world.getChunkAt(e.cx, e.cz); + if (chunk == null) { + continue; + } + chunk.setForceLoaded(false); + } } @EventHandler @@ -132,68 +232,12 @@ protected final boolean supportUnloadCancel() { @Override protected void forceloadOff(String world, int cx, int cz) { - Boolean oldValue = m_forceload.get(world).remove(encode(cx, cz)); - - if (oldValue != null && oldValue) { - m_scheduler.runTask(m_plugin, () -> { - World w = m_server.getWorld(world); - if (w == null) { - return; - } - - Chunk c = w.getChunkAt(cx, cz); - if (c == null) { - return; - } - - c.setForceLoaded(false); - }); - } + m_forceUnLoadQueue.add(new ForceLoadEntry(world, cx, cz)); } @Override protected void forceloadOn(String world, int cx, int cz) { - final Map worldEntry = m_forceload.computeIfAbsent(world, _i -> new ConcurrentHashMap<>()); - worldEntry.computeIfAbsent(encode(cx, cz), _chunk -> { - final Boolean[] result = new Boolean[]{null, null}; - m_scheduler.runTask(m_plugin, () -> { - World w = m_server.getWorld(world); - Chunk chunk = w != null ? w.getChunkAt(cx, cz) : null; - if (chunk == null) { - synchronized (result) { - result[1] = true; - result.notifyAll(); - } - return; - } - - if (chunk.isForceLoaded()) { - synchronized (result) { - result[0] = false; - result[1] = true; - result.notifyAll(); - } - return; - } - - chunk.setForceLoaded(true); - synchronized (result) { - result[0] = true; - result[1] = true; - result.notifyAll(); - } - }); - - synchronized (result) { - if (result[1] != null && !result[1]) { - try { - result.wait(5000); - } catch (InterruptedException ex) { - } - } - return result[0]; - } - }); + m_forceLoadQueue.add(new ForceLoadEntry(world, cx, cz)); } @Override @@ -222,4 +266,19 @@ public void clear() { */ m_forceload.clear(); } + + private static class ForceLoadEntry { + + public final String world; + public final int cx; + public final int cz; + public final long timestamp; + + ForceLoadEntry(String world, int cx, int cz) { + this.world = world; + this.cx = cx; + this.cz = cz; + this.timestamp = System.currentTimeMillis(); + } + } } diff --git a/AsyncWorldEditInjector/dependency-reduced-pom.xml b/AsyncWorldEditInjector/dependency-reduced-pom.xml index d4008b6..5561c68 100644 --- a/AsyncWorldEditInjector/dependency-reduced-pom.xml +++ b/AsyncWorldEditInjector/dependency-reduced-pom.xml @@ -60,7 +60,7 @@ org.primesoft.asyncworldedit AsyncWorldEdit-Utils - 3.6.1 + 3.6.2 compile diff --git a/AsyncWorldEditInjector/src/main/java/org/primesoft/asyncworldedit/injector/core/spigot/v1_13_Rx/visitors/ChunkProviderServerVisitor.java b/AsyncWorldEditInjector/src/main/java/org/primesoft/asyncworldedit/injector/core/spigot/v1_13_Rx/visitors/ChunkProviderServerVisitor.java index 237d45b..33aa963 100644 --- a/AsyncWorldEditInjector/src/main/java/org/primesoft/asyncworldedit/injector/core/spigot/v1_13_Rx/visitors/ChunkProviderServerVisitor.java +++ b/AsyncWorldEditInjector/src/main/java/org/primesoft/asyncworldedit/injector/core/spigot/v1_13_Rx/visitors/ChunkProviderServerVisitor.java @@ -108,7 +108,7 @@ public MethodVisitor visitMethod(int access, String name, String descriptor, Str super.visitMethod(access, name, descriptor, signature, exceptions)); } - if ("getChunkAt".equals(name)) { + if ("getChunkAt".equals(name) && descriptor.startsWith("(IIZZ)")) { m_vMethodGetChunkAt.set(); m_getChunkAtDescriptor = descriptor; m_getChunkAtSignature = signature; @@ -121,27 +121,6 @@ public MethodVisitor visitMethod(int access, String name, String descriptor, Str return super.visitMethod(access, name, descriptor, signature, exceptions); } - private final Thread m_tmp = Thread.currentThread(); - - private Object m_foo; - - public Object ___tmp(int x, int z, boolean f1, boolean f2) { - return null; - } - - public Object tmp(int x, int z, boolean f1, boolean f2) { - if (Thread.currentThread() == m_tmp) { - return ___tmp(x, z, f1, f2); - } - - Object result = ((Map) m_foo).get((long) x & 4294967295L | ((long) z & 4294967295L) << 32); - if (result == null) { - throw new IllegalStateException("[AWE] Chunk not found for " + x + "," + z + ". Loading from async thread is not supported."); - } - - return result; - } - @Override public void visitEnd() { super.visitField(Opcodes.ACC_PRIVATE, "m_serverThread", Type.getDescriptor(Thread.class), null, null).visitEnd(); diff --git a/pom.xml b/pom.xml index fad2dc8..daf4db4 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ AsyncWorldEdit_AllInOne ${global.awe.version} - 3.6.1 + 3.6.2 2.3.0