diff --git a/worldedit-core/src/main/java/com/boydti/fawe/FaweCache.java b/worldedit-core/src/main/java/com/boydti/fawe/FaweCache.java index ec9b19d3c..570d88b1c 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/FaweCache.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/FaweCache.java @@ -105,21 +105,25 @@ public enum FaweCache implements Trimable { @Override public synchronized boolean trim(boolean aggressive) { - CHUNK_FLAG.clean(); - BYTE_BUFFER_8192.clean(); - BLOCK_TO_PALETTE.clean(); - PALETTE_TO_BLOCK.clean(); - BLOCK_STATES.clean(); - SECTION_BLOCKS.clean(); - PALETTE_CACHE.clean(); - PALETTE_TO_BLOCK_CHAR.clean(); - INDEX_STORE.clean(); + if (aggressive) { + CleanableThreadLocal.cleanAll(); + } else { + CHUNK_FLAG.clean(); + BYTE_BUFFER_8192.clean(); + BLOCK_TO_PALETTE.clean(); + PALETTE_TO_BLOCK.clean(); + BLOCK_STATES.clean(); + SECTION_BLOCKS.clean(); + PALETTE_CACHE.clean(); + PALETTE_TO_BLOCK_CHAR.clean(); + INDEX_STORE.clean(); - MUTABLE_VECTOR3.clean(); - MUTABLE_BLOCKVECTOR3.clean(); - SECTION_BITS_TO_CHAR.clean(); - for (Map.Entry entry : REGISTERED_SINGLETONS.entrySet()) { - entry.getValue().clean(); + MUTABLE_VECTOR3.clean(); + MUTABLE_BLOCKVECTOR3.clean(); + SECTION_BITS_TO_CHAR.clean(); + for (Map.Entry entry : REGISTERED_SINGLETONS.entrySet()) { + entry.getValue().clean(); + } } for (Map.Entry entry : REGISTERED_POOLS.entrySet()) { Pool pool = entry.getValue(); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/CleanableThreadLocal.java b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/CleanableThreadLocal.java index 094b5ca1f..9a1c6ff34 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/CleanableThreadLocal.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/CleanableThreadLocal.java @@ -5,7 +5,10 @@ import com.boydti.fawe.util.MainUtil; import java.lang.ref.Reference; import java.lang.reflect.Array; import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.atomic.LongAdder; import java.util.function.Consumer; import java.util.function.Function; @@ -51,25 +54,47 @@ public class CleanableThreadLocal extends ThreadLocal { } } - public static void clean(ThreadLocal instance) { + public List getAll() { + List list = new ArrayList<>(); + iterate(this, new Consumer() { + Method methodGetEntry; + Field fieldValue; + @Override + public void accept(Object tlm) { + try { + if (methodGetEntry == null) { + methodGetEntry = tlm.getClass().getDeclaredMethod("getEntry", ThreadLocal.class); + methodGetEntry.setAccessible(true); + } + Object entry = methodGetEntry.invoke(tlm, CleanableThreadLocal.this); + if (entry != null) { + if (fieldValue == null) { + fieldValue = entry.getClass().getDeclaredField("value"); + fieldValue.setAccessible(true); + } + Object value = fieldValue.get(entry); + if (value != null) { + list.add((T) value); + } + } + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | NoSuchFieldException e) { + throw new RuntimeException(e); + } + } + }); + return list; + } + + public static void iterate(ThreadLocal instance, Consumer withMap) { try { Thread[] threads = MainUtil.getThreads(); Field tl = Thread.class.getDeclaredField("threadLocals"); tl.setAccessible(true); - Method methodRemove = null; for (Thread thread : threads) { if (thread != null) { Object tlm = tl.get(thread); if (tlm != null) { - if (methodRemove == null) { - methodRemove = tlm.getClass().getDeclaredMethod("remove", ThreadLocal.class); - methodRemove.setAccessible(true); - } - if (methodRemove != null) { - try { - methodRemove.invoke(tlm, instance); - } catch (Throwable ignore) {} - } + withMap.accept(tlm); } } } @@ -78,6 +103,29 @@ public class CleanableThreadLocal extends ThreadLocal { } } + public static void clean(ThreadLocal instance) { + iterate(instance, new Consumer() { + Method methodRemove; + @Override + public void accept(Object tlm) { + try { + if (methodRemove == null) { + methodRemove = tlm.getClass().getDeclaredMethod("remove", ThreadLocal.class); + methodRemove.setAccessible(true); + } + if (methodRemove != null) { + try { + methodRemove.invoke(tlm, instance); + } catch (Throwable ignore) { + } + } + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + }); + } + public static void cleanAll() { try { // Get a reference to the thread locals table of the current thread diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/NullExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/NullExtent.java index 23158f3ad..d38d079cb 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/extent/NullExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/extent/NullExtent.java @@ -1,6 +1,7 @@ package com.boydti.fawe.object.extent; import com.boydti.fawe.FaweCache; +import com.boydti.fawe.beta.IBatchProcessor; import com.boydti.fawe.beta.IChunk; import com.boydti.fawe.beta.IChunkGet; import com.boydti.fawe.beta.IChunkSet; @@ -34,7 +35,7 @@ import java.util.List; import java.util.Set; import javax.annotation.Nullable; -public class NullExtent extends FaweRegionExtent { +public class NullExtent extends FaweRegionExtent implements IBatchProcessor { private final FaweException reason; @@ -328,11 +329,16 @@ public class NullExtent extends FaweRegionExtent { @Override public IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set) { - return null; + throw reason; } @Override public boolean processGet(int chunkX, int chunkZ) { - return false; + throw reason; + } + + @Override + public Extent construct(Extent child) { + throw reason; } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java index 9cfe6b20d..7d6c4d29c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -332,6 +332,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { if (get instanceof AbstractDelegateExtent && !(get instanceof NullExtent)) { traverser.setNext(nullExtent); } + get.addProcessor(nullExtent); traverser = next; } return super.cancel(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Player.java b/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Player.java index 76a77c163..40ce59e8d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Player.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Player.java @@ -25,6 +25,7 @@ import com.boydti.fawe.object.brush.visualization.VirtualWorld; import com.boydti.fawe.object.clipboard.DiskOptimizedClipboard; import com.boydti.fawe.regions.FaweMaskManager; import com.boydti.fawe.util.MainUtil; +import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EmptyClipboardException; import com.sk89q.worldedit.IncompleteRegionException; import com.sk89q.worldedit.LocalSession; @@ -40,6 +41,7 @@ import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.RegionSelector; import com.sk89q.worldedit.session.ClipboardHolder; +import com.sk89q.worldedit.session.request.Request; import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.util.Location; @@ -50,6 +52,7 @@ import com.sk89q.worldedit.world.gamemode.GameMode; import javax.annotation.Nullable; import java.io.File; +import java.io.IOException; /** * Represents a player @@ -381,32 +384,36 @@ public interface Player extends Entity, Actor { } default int cancel(boolean close) { -// Collection queues = SetQueue.IMP.getAllQueues(); TODO NOT IMPLEMENTED -// int cancelled = 0; -// clearActions(); -// for (IQueueExtent queue : queues) { -// Collection sessions = queue.getEditSessions(); -// for (EditSession session : sessions) { -// FawePlayer currentPlayer = session.getPlayer(); -// if (currentPlayer == this) { -// if (session.cancel()) { -// cancelled++; -// } -// } -// } -// } -// VirtualWorld world = getSession().getVirtualWorld(); -// if (world != null) { -// if (close) { -// try { -// world.close(false); -// } catch (IOException e) { -// e.printStackTrace(); -// } -// } -// else world.clear(); -// } - return 0; + int cancelled = 0; + + for (Request request : Request.getAll()) { + EditSession editSession = request.getEditSession(); + if (editSession != null) { + Player player = editSession.getPlayer(); + if (equals(player)) { + editSession.cancel(); + cancelled++; + } + } + } + VirtualWorld world = getSession().getVirtualWorld(); + if (world != null) { + if (close) { + try { + world.close(false); + } catch (IOException e) { + e.printStackTrace(); + } + } + else { + try { + world.close(false); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + return cancelled; } void sendTitle(String title, String sub); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java index 6391c8c50..1d6d2000f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -630,6 +630,7 @@ public final class PlatformCommandManager { Command cmd = optional.get(); CommandQueuedCondition queued = cmd.getCondition().as(CommandQueuedCondition.class).orElse(null); if (queued != null && !queued.isQueued()) { + System.out.println("Not queued"); handleCommandOnCurrentThread(event); return; } @@ -728,8 +729,7 @@ public final class PlatformCommandManager { } else { System.out.println("Invalid context " + context); } - Optional editSessionOpt = - context.injectedValue(Key.of(EditSession.class)); + Optional editSessionOpt = context.injectedValue(Key.of(EditSession.class)); if (editSessionOpt.isPresent()) { EditSession editSession = editSessionOpt.get(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/session/request/Request.java b/worldedit-core/src/main/java/com/sk89q/worldedit/session/request/Request.java index 8e588bb96..8c8c749c5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/session/request/Request.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/session/request/Request.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.session.request; +import com.boydti.fawe.object.collection.CleanableThreadLocal; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.extension.platform.Actor; @@ -26,13 +27,14 @@ import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.world.World; import javax.annotation.Nullable; +import java.util.List; /** * Describes the current request using a {@link ThreadLocal}. */ public final class Request { - private static final ThreadLocal threadLocal = ThreadLocal.withInitial(Request::new); + private static final CleanableThreadLocal threadLocal = new CleanableThreadLocal<>(Request::new); private @Nullable World world; private @Nullable Actor actor; @@ -44,6 +46,10 @@ public final class Request { private Request() { } + public static List getAll() { + return threadLocal.getAll(); + } + /** * Get the request world. *