Skip to content

Commit

Permalink
Fix paper compatibility
Browse files Browse the repository at this point in the history
  • Loading branch information
SBPrime committed May 27, 2019
1 parent fc0768e commit bc1874d
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 85 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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<Long, Integer> 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<String, Map<Long, Boolean>> m_forceload = new ConcurrentHashMap<>();
private final Map<String, Map<Long, Long>> m_forceload = new HashMap<>();

private final Queue<ForceLoadEntry> m_forceLoadQueue = new ConcurrentLinkedQueue<>();
private final Queue<ForceLoadEntry> 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<ForceLoadEntry> 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<Long> 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<Long, Long> 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<Long, Long> 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
Expand Down Expand Up @@ -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<Long, Boolean> 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
Expand Down Expand Up @@ -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();
}
}
}
2 changes: 1 addition & 1 deletion AsyncWorldEditInjector/dependency-reduced-pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
<dependency>
<groupId>org.primesoft.asyncworldedit</groupId>
<artifactId>AsyncWorldEdit-Utils</artifactId>
<version>3.6.1</version>
<version>3.6.2</version>
<scope>compile</scope>
</dependency>
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<Long, Object>) 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();
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<artifactId>AsyncWorldEdit_AllInOne</artifactId>
<version>${global.awe.version}</version>
<properties>
<global.awe.version>3.6.1</global.awe.version>
<global.awe.version>3.6.2</global.awe.version>
<global.awe-api.version>2.3.0</global.awe-api.version>
</properties>

Expand Down

0 comments on commit bc1874d

Please sign in to comment.