Fix some brush stuff
Fix issue with editing on main thread
FIx error from misusing AsyncBlock
Tweak some messages
Add TaskBuilder API
This commit is contained in:
Jesse Boyd 2016-11-01 23:35:23 +11:00
parent a28e8b4069
commit 60152a5b1f
No known key found for this signature in database
GPG Key ID: 59F1DE6293AF6E1F
21 changed files with 633 additions and 176 deletions

View File

@ -153,7 +153,7 @@ public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMa
@Override
public World getImpWorld() {
return Bukkit.getWorld(getWorldName());
return getWorldName() != null ? Bukkit.getWorld(getWorldName()) : null;
}
@Override
@ -190,23 +190,45 @@ public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMa
}
private volatile boolean timingsEnabled;
private static boolean alertTimingsChange = true;
private static Field fieldTimingsEnabled;
private static Field fieldAsyncCatcherEnabled;
private static Method methodCheck;
static {
try {
fieldAsyncCatcherEnabled = Class.forName("org.spigotmc.AsyncCatcher").getField("enabled");
fieldAsyncCatcherEnabled.setAccessible(true);
} catch (Throwable ignore) {}
try {
fieldTimingsEnabled = Class.forName("co.aikar.timings.Timings").getDeclaredField("timingsEnabled");
fieldTimingsEnabled.setAccessible(true);
methodCheck = Class.forName("co.aikar.timings.TimingsManager").getDeclaredMethod("recheckEnabled");
methodCheck.setAccessible(true);
} catch (Throwable ignore){}
}
@Override
public void startSet(boolean parallel) {
ChunkListener.physicsFreeze = true;
if (parallel) {
try {
Field fieldEnabled = Class.forName("co.aikar.timings.Timings").getDeclaredField("timingsEnabled");
fieldEnabled.setAccessible(true);
timingsEnabled = (boolean) fieldEnabled.get(null);
if (timingsEnabled) {
fieldEnabled.set(null, false);
Method methodCheck = Class.forName("co.aikar.timings.TimingsManager").getDeclaredMethod("recheckEnabled");
methodCheck.setAccessible(true);
methodCheck.invoke(null);
if (fieldAsyncCatcherEnabled != null) {
fieldAsyncCatcherEnabled.set(null, false);
}
} catch (Throwable ignore) {}
try { Class.forName("org.spigotmc.AsyncCatcher").getField("enabled").set(null, false); } catch (Throwable ignore) {}
if (fieldTimingsEnabled != null) {
timingsEnabled = (boolean) fieldTimingsEnabled.get(null);
if (timingsEnabled) {
if (alertTimingsChange) {
alertTimingsChange = false;
Fawe.debug("Having `parallel-threads` > 1 interferes with the timings.");
}
fieldTimingsEnabled.set(null, false);
methodCheck.invoke(null);
}
}
} catch (Throwable e) {
e.printStackTrace();
}
}
}
@ -214,9 +236,16 @@ public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMa
public void endSet(boolean parallel) {
ChunkListener.physicsFreeze = false;
if (parallel) {
try {Field fieldEnabled = Class.forName("co.aikar.timings.Timings").getDeclaredField("timingsEnabled");fieldEnabled.setAccessible(true);fieldEnabled.set(null, timingsEnabled);
} catch (Throwable ignore) {}
try { Class.forName("org.spigotmc.AsyncCatcher").getField("enabled").set(null, true); } catch (Throwable ignore) {}
try {
if (fieldAsyncCatcherEnabled != null) {
fieldAsyncCatcherEnabled.set(null, true);
}
if (fieldTimingsEnabled != null && timingsEnabled) {
fieldTimingsEnabled.set(null, true);
}
} catch (Throwable e) {
e.printStackTrace();
}
}
}
}

View File

@ -28,7 +28,7 @@ public class AsyncBlock implements Block {
this.world = world;
this.queue = queue;
this.x = x;
this.y = y;
this.y = y & 0xFF;
this.z = z;
}

View File

@ -37,16 +37,11 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.atomic.AtomicInteger;
public abstract class FawePlayer<T> {
public abstract class FawePlayer<T> extends Metadatable {
public final T parent;
private LocalSession session;
/**
* The metadata map.
*/
private volatile ConcurrentHashMap<String, Object> meta;
/**
* Wrap some object into a FawePlayer<br>
* - org.bukkit.entity.Player
@ -396,64 +391,6 @@ public abstract class FawePlayer<T> {
return this.hasPermission("fawe.bypass");
}
/**
* Set some session only metadata for the player
* @param key
* @param value
* @return previous value
*/
public void setMeta(String key, Object value) {
if (this.meta == null) {
this.meta = new ConcurrentHashMap<>(8, 0.9f, 1);
}
this.meta.put(key, value);
}
public <T> T getAndSetMeta(String key, T value) {
if (this.meta == null) {
this.meta = new ConcurrentHashMap<>(8, 0.9f, 1);
}
return (T) this.meta.put(key, value);
}
/**
* Get the metadata for a key.
* @param <V>
* @param key
* @return
*/
public <V> V getMeta(String key) {
if (this.meta != null) {
return (V) this.meta.get(key);
}
return null;
}
/**
* Get the metadata for a specific key (or return the default provided)
* @param key
* @param def
* @param <V>
* @return
*/
public <V> V getMeta(String key, V def) {
if (this.meta != null) {
V value = (V) this.meta.get(key);
return value == null ? def : value;
}
return def;
}
/**
* Delete the metadata for a key.
* - metadata is session only
* - deleting other plugin's metadata may cause issues
* @param key
*/
public Object deleteMeta(String key) {
return this.meta == null ? null : this.meta.remove(key);
}
/**
* Unregister this player (delets all metadata etc)
* - Usually called on logout

View File

@ -0,0 +1,60 @@
package com.boydti.fawe.object;
import java.util.concurrent.ConcurrentHashMap;
public class Metadatable {
private final ConcurrentHashMap<String, Object> meta = new ConcurrentHashMap<>();
/**
* Set some session only metadata for the player
* @param key
* @param value
* @return previous value
*/
public void setMeta(String key, Object value) {
this.meta.put(key, value);
}
public <T> T getAndSetMeta(String key, T value) {
return (T) this.meta.put(key, value);
}
/**
* Get the metadata for a key.
* @param <V>
* @param key
* @return
*/
public <V> V getMeta(String key) {
if (this.meta != null) {
return (V) this.meta.get(key);
}
return null;
}
/**
* Get the metadata for a specific key (or return the default provided)
* @param key
* @param def
* @param <V>
* @return
*/
public <V> V getMeta(String key, V def) {
if (this.meta != null) {
V value = (V) this.meta.get(key);
return value == null ? def : value;
}
return def;
}
/**
* Delete the metadata for a key.
* - metadata is session only
* - deleting other plugin's metadata may cause issues
* @param key
*/
public Object deleteMeta(String key) {
return this.meta == null ? null : this.meta.remove(key);
}
}

View File

@ -10,11 +10,11 @@ public abstract class RunnableVal<T> implements Runnable {
}
@Override
public void run() {
public final void run() {
run(this.value);
}
public T runAndGet() {
public final T runAndGet() {
run();
return value;
}

View File

@ -11,12 +11,7 @@ import com.boydti.fawe.util.MainUtil;
import com.sk89q.jnbt.NBTInputStream;
import com.sk89q.jnbt.NBTOutputStream;
import com.sk89q.worldedit.world.World;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

View File

@ -296,7 +296,7 @@ public abstract class FaweChangeSet implements ChangeSet {
}
};
if (mainThread) {
new Thread(run).start();
run.run();
} else {
TaskManager.IMP.async(run);
}

View File

@ -1,47 +0,0 @@
package com.boydti.fawe.util;
public class ByteArrays {
public static final byte[] EMPTY_ARRAY = new byte[0];
public static void ensureOffsetLength(byte[] a, int offset, int length)
{
ensureOffsetLength(a.length, offset, length);
}
public static void ensureOffsetLength(int arrayLength, int offset, int length)
{
if (offset < 0) {
throw new ArrayIndexOutOfBoundsException("Offset (" + offset + ") is negative");
}
if (length < 0) {
throw new IllegalArgumentException("Length (" + length + ") is negative");
}
if (offset + length > arrayLength) {
throw new ArrayIndexOutOfBoundsException("Last index (" + (offset + length) + ") is greater than array length (" + arrayLength + ")");
}
}
public static byte[] grow(byte[] array, int length, int preserve)
{
if (length > array.length)
{
int newLength = (int)Math.max(
Math.min(2L * array.length, 2147483639L), length);
byte[] t = new byte[newLength];
System.arraycopy(array, 0, t, 0, preserve);
return t;
}
return array;
}
public static byte[] trim(byte[] array, int length)
{
if (length >= array.length) {
return array;
}
byte[] t = length == 0 ? EMPTY_ARRAY : new byte[length];
System.arraycopy(array, 0, t, 0, length);
return t;
}
}

View File

@ -74,11 +74,7 @@ public class MainUtil {
}
public static void stacktrace() {
try {
int i = 1/0;
} catch (Exception e) {
e.printStackTrace();
}
new Exception().printStackTrace();
}
public static void traverse(Path path, final RunnableVal2<Path, BasicFileAttributes> onEach) {

View File

@ -275,7 +275,8 @@ public abstract class TaskManager {
while (running.get()) {
running.wait(timout);
if (running.get() && System.currentTimeMillis() - start > Settings.QUEUE.DISCARD_AFTER_MS) {
MainUtil.stacktrace();
new RuntimeException("FAWE is taking a long time to execute a task (might just be a symptom): ").printStackTrace();
Fawe.debug("For full debug information use: /fawe threads");
}
}
}

View File

@ -0,0 +1,5 @@
package com.boydti.fawe.util.task;
public interface DelayedTask<T> {
int getDelay(T previousResult);
}

View File

@ -0,0 +1,5 @@
package com.boydti.fawe.util.task;
public interface ReceiveTask<T> {
void run(T previous);
}

View File

@ -0,0 +1,5 @@
package com.boydti.fawe.util.task;
public interface ReturnTask<T> {
T run();
}

View File

@ -0,0 +1,5 @@
package com.boydti.fawe.util.task;
public interface Task<T, V> {
T run(V previousResult);
}

View File

@ -0,0 +1,491 @@
package com.boydti.fawe.util.task;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.object.Metadatable;
import com.boydti.fawe.object.RunnableVal;
import com.boydti.fawe.util.SetQueue;
import com.boydti.fawe.util.TaskManager;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.TimeUnit;
public class TaskBuilder extends Metadatable {
private final ForkJoinPool pool = new ForkJoinPool();
private final ArrayDeque<RunnableTask> tasks;
private Object result = null;
private Thread.UncaughtExceptionHandler handler;
public TaskBuilder() {
this(null);
}
public TaskBuilder(Thread.UncaughtExceptionHandler handler) {
tasks = new ArrayDeque<>();
this.handler = handler;
}
public TaskBuilder async(Task task) {
tasks.add(RunnableTask.adapt(task, TaskType.ASYNC));
return this;
}
public TaskBuilder async(ReceiveTask task) {
tasks.add(RunnableTask.adapt(task, TaskType.ASYNC));
return this;
}
public TaskBuilder async(ReturnTask task) {
tasks.add(RunnableTask.adapt(task, TaskType.ASYNC));
return this;
}
public TaskBuilder async(Runnable task) {
tasks.add(RunnableTask.adapt(task, TaskType.ASYNC));
return this;
}
public TaskBuilder sync(Task task) {
tasks.add(RunnableTask.adapt(task, TaskType.SYNC));
return this;
}
public TaskBuilder sync(ReceiveTask task) {
tasks.add(RunnableTask.adapt(task, TaskType.SYNC));
return this;
}
public TaskBuilder sync(ReturnTask task) {
tasks.add(RunnableTask.adapt(task, TaskType.SYNC));
return this;
}
public TaskBuilder sync(Runnable task) {
tasks.add(RunnableTask.adapt(task, TaskType.SYNC));
return this;
}
public TaskBuilder delay(int ticks) {
tasks.add(RunnableDelayedTask.adapt(ticks));
return this;
}
public TaskBuilder delay(DelayedTask task) {
tasks.add(RunnableDelayedTask.adapt(task));
return this;
}
/**
* Run some sync tasks in parallel<br>
* - All sync parallel tasks which occur directly after each other will be run at the same time
* @param run
* @return this
*/
public TaskBuilder syncParallel(Runnable run) {
tasks.add(RunnableTask.adapt(run, TaskType.SYNC_PARALLEL));
return this;
}
public TaskBuilder syncParallel(Task run) {
tasks.add(RunnableTask.adapt(run, TaskType.SYNC_PARALLEL));
return this;
}
public TaskBuilder syncParallel(ReceiveTask run) {
tasks.add(RunnableTask.adapt(run, TaskType.SYNC_PARALLEL));
return this;
}
public TaskBuilder syncParallel(ReturnTask run) {
tasks.add(RunnableTask.adapt(run, TaskType.SYNC_PARALLEL));
return this;
}
/**
* Run some async tasks in parallel<br>
* - All async parallel tasks which occur directly after each other will be run at the same time
* @param run
* @return this
*/
public TaskBuilder asyncParallel(Runnable run) {
tasks.add(RunnableTask.adapt(run, TaskType.ASYNC_PARALLEL));
return this;
}
public TaskBuilder asyncParallel(Task run) {
tasks.add(RunnableTask.adapt(run, TaskType.ASYNC_PARALLEL));
return this;
}
public TaskBuilder asyncParallel(ReceiveTask run) {
tasks.add(RunnableTask.adapt(run, TaskType.ASYNC_PARALLEL));
return this;
}
public TaskBuilder asyncParallel(ReturnTask run) {
tasks.add(RunnableTask.adapt(run, TaskType.ASYNC_PARALLEL));
return this;
}
/**
* Run a split task when the server has free time<br>
* - i.e. To maintain high tps
* - Use the split() method within task execution
* - FAWE will be able to pause execution at these points
* @param run
* @return this
*/
public TaskBuilder syncWhenFree(SplitTask run) {
tasks.add(run);
return this;
}
public TaskBuilder syncWhenFree(Task run) {
tasks.add(RunnableTask.adapt(run, TaskType.SYNC_WHEN_FREE));
return this;
}
public TaskBuilder syncWhenFree(ReceiveTask run) {
tasks.add(RunnableTask.adapt(run, TaskType.SYNC_WHEN_FREE));
return this;
}
public TaskBuilder syncWhenFree(ReturnTask run) {
tasks.add(RunnableTask.adapt(run, TaskType.SYNC_WHEN_FREE));
return this;
}
public TaskBuilder abortIfTrue(Task<Boolean, Object> run) {
tasks.add(RunnableTask.adapt(run, TaskType.ABORT));
return this;
}
/**
* Have all async tasks run on a new thread<br>
* - As opposed to trying to using the current thread
*/
public void buildAsync() {
TaskManager.IMP.async(new Runnable() {
@Override
public void run() {
build();
}
});
}
/**
* Begins execution of the tasks<br>
* - The builder will attempt to run on the current thread if possible
*/
public void build() {
RunnableTask peek;
while ((peek = tasks.peek()) != null) {
try {
switch (peek.type) {
case DELAY:
DelayedTask task = (DelayedTask) tasks.poll();
RunnableTask next = tasks.peek();
if (next != null) {
switch (next.type) {
case SYNC:
case ABORT:
case SYNC_PARALLEL:
TaskManager.IMP.later(new Runnable() {
@Override
public void run() {
build();
}
}, task.getDelay(result));
return;
default:
TaskManager.IMP.laterAsync(new Runnable() {
@Override
public void run() {
build();
}
}, task.getDelay(result));
return;
}
}
return;
case SYNC:
case SYNC_PARALLEL:
if (!Fawe.get().isMainThread()) {
TaskManager.IMP.sync(new RunnableVal() {
@Override
public void run(Object value) {
build();
}
});
return;
}
break;
case SYNC_WHEN_FREE:
case ASYNC:
case ASYNC_PARALLEL:
if (Fawe.get().isMainThread()) {
TaskManager.IMP.async(new Runnable() {
@Override
public void run() {
build();
}
});
return;
}
break;
}
RunnableTask task = tasks.poll();
task.value = result;
switch (task.type) {
case ABORT:
if (((Task<Boolean, Object>) task).run(result)) {
return;
}
break;
case SYNC:
result = task.exec(result);
break;
case SYNC_WHEN_FREE:
if (task instanceof SplitTask) {
SplitTask splitTask = (SplitTask) task;
result = splitTask.execSplit(result);
} else {
result = TaskManager.IMP.syncWhenFree(task);
}
break;
case ASYNC:
result = task.exec(result);
continue;
case SYNC_PARALLEL:
case ASYNC_PARALLEL:
final ArrayList<RunnableTask> parallel = new ArrayList<RunnableTask>();
parallel.add(task);
RunnableTask next = tasks.peek();
while (next != null && next.type == task.type) {
parallel.add(next);
tasks.poll();
next = tasks.peek();
}
for (RunnableTask current : parallel) {
pool.submit(current);
}
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
result = null;
for (RunnableTask current : parallel) {
if (current.value != null) {
result = current.value;
}
}
break;
}
if (task.isAborted()) {
return;
}
} catch (Throwable e) {
if (handler != null) {
handler.uncaughtException(Thread.currentThread(), e);
}
return;
}
}
}
private FaweQueue queue;
private long last;
private long start;
private Object asyncWaitLock = new Object();
private Object syncWaitLock = new Object();
private boolean finished;
private static abstract class RunnableTask<T> extends RunnableVal<T> {
public final TaskType type;
private boolean aborted;
public RunnableTask(TaskType type) {
this.type = type;
}
public void abortNextTasks() {
this.aborted = true;
}
public boolean isAborted() {
return aborted;
}
public static RunnableTask adapt(final Task task, TaskType type) {
return new RunnableTask(type) {
@Override
public Object exec(Object previous) {
return task.run(previous);
}
};
}
public static RunnableTask adapt(final ReturnTask task, TaskType type) {
return new RunnableTask(type) {
@Override
public Object exec(Object previous) {
return task.run();
}
};
}
public static RunnableTask adapt(final ReceiveTask task, TaskType type) {
return new RunnableTask(type) {
@Override
public Object exec(Object previous) {
task.run(previous);
return null;
}
};
}
public static RunnableTask adapt(final Runnable run, TaskType type) {
return new RunnableTask(type) {
@Override
public Object exec(Object previous) {
if (run instanceof RunnableVal) {
((RunnableVal) run).value = this.value;
return this.value = ((RunnableVal) run).runAndGet();
}
run.run();
return null;
}
};
}
public abstract T exec(Object previous);
@Override
public final void run(T value) {
this.value = exec(value);
}
}
private static abstract class RunnableDelayedTask extends RunnableTask {
public RunnableDelayedTask(TaskType type) {
super(type);
}
@Override
public Object exec(Object previous) {
return previous;
}
public abstract int delay(Object previous);
public static RunnableDelayedTask adapt(final DelayedTask task) {
return new RunnableDelayedTask(TaskType.DELAY) {
@Override
public int delay(Object previous) {
return task.getDelay(previous);
}
};
}
public static RunnableDelayedTask adapt(final int time) {
return new RunnableDelayedTask(TaskType.DELAY) {
@Override
public int delay(Object previous) {
return time;
}
};
}
}
public static abstract class SplitTask extends RunnableTask {
private final long allocation;
private final FaweQueue queue;
private long last;
private long start;
private Object asyncWaitLock = new Object();
private Object syncWaitLock = new Object();
private boolean finished;
public SplitTask() {
this(20);
}
public SplitTask(long allocation) {
super(TaskType.SYNC_WHEN_FREE);
this.allocation = allocation;
this.queue = SetQueue.IMP.getNewQueue((String) null, true, false);
}
public Object execSplit(final Object previous) {
this.value = previous;
final Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
synchronized (asyncWaitLock) {
asyncWaitLock.wait(Long.MAX_VALUE);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
exec(previous);
finished = true;
synchronized (syncWaitLock) {
syncWaitLock.notifyAll();
}
}
});
thread.start();
while (thread.isAlive()) {
TaskManager.IMP.syncWhenFree(new RunnableVal() {
@Override
public void run(Object ignore) {
queue.startSet(true);
start = System.currentTimeMillis();
synchronized (asyncWaitLock) {
asyncWaitLock.notifyAll();
}
synchronized (syncWaitLock) {
if (!finished) {
try {
syncWaitLock.wait(Long.MAX_VALUE);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
queue.endSet(true);
}
});
}
return this.value;
}
public void split() {
long now = System.currentTimeMillis();
if (now - start > allocation) {
try {
synchronized (syncWaitLock) {
syncWaitLock.notifyAll();
}
synchronized (asyncWaitLock) {
asyncWaitLock.wait(Long.MAX_VALUE);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
private enum TaskType {
SYNC,
ASYNC,
SYNC_PARALLEL,
ASYNC_PARALLEL,
SYNC_WHEN_FREE,
DELAY,
ABORT
}
}

View File

@ -39,43 +39,17 @@ import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.command.BiomeCommands;
import com.sk89q.worldedit.command.BrushCommands;
import com.sk89q.worldedit.command.ChunkCommands;
import com.sk89q.worldedit.command.ClipboardCommands;
import com.sk89q.worldedit.command.GeneralCommands;
import com.sk89q.worldedit.command.GenerationCommands;
import com.sk89q.worldedit.command.HistoryCommands;
import com.sk89q.worldedit.command.NavigationCommands;
import com.sk89q.worldedit.command.RegionCommands;
import com.sk89q.worldedit.command.SchematicCommands;
import com.sk89q.worldedit.command.ScriptingCommands;
import com.sk89q.worldedit.command.SelectionCommands;
import com.sk89q.worldedit.command.SnapshotCommands;
import com.sk89q.worldedit.command.SnapshotUtilCommands;
import com.sk89q.worldedit.command.SuperPickaxeCommands;
import com.sk89q.worldedit.command.ToolCommands;
import com.sk89q.worldedit.command.ToolUtilCommands;
import com.sk89q.worldedit.command.UtilityCommands;
import com.sk89q.worldedit.command.WorldEditCommands;
import com.sk89q.worldedit.command.*;
import com.sk89q.worldedit.command.argument.ReplaceParser;
import com.sk89q.worldedit.command.argument.TreeGeneratorParser;
import com.sk89q.worldedit.command.composition.ApplyCommand;
import com.sk89q.worldedit.command.composition.DeformCommand;
import com.sk89q.worldedit.command.composition.PaintCommand;
import com.sk89q.worldedit.command.composition.SelectionCommand;
import com.sk89q.worldedit.command.composition.ShapedBrushCommand;
import com.sk89q.worldedit.command.composition.*;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.event.platform.CommandEvent;
import com.sk89q.worldedit.event.platform.CommandSuggestionEvent;
import com.sk89q.worldedit.function.factory.Deform;
import com.sk89q.worldedit.function.factory.Deform.Mode;
import com.sk89q.worldedit.history.changeset.ChangeSet;
import com.sk89q.worldedit.internal.command.ActorAuthorizer;
import com.sk89q.worldedit.internal.command.CommandLoggingHandler;
import com.sk89q.worldedit.internal.command.UserCommandCompleter;
import com.sk89q.worldedit.internal.command.WorldEditBinding;
import com.sk89q.worldedit.internal.command.WorldEditExceptionConverter;
import com.sk89q.worldedit.internal.command.*;
import com.sk89q.worldedit.session.request.Request;
import com.sk89q.worldedit.util.command.Dispatcher;
import com.sk89q.worldedit.util.command.InvalidUsageException;

View File

@ -449,7 +449,8 @@ public class PlatformManager {
public void handlePlayerInput(PlayerInputEvent event) {
// Create a proxy actor with a potentially different world for
// making changes to the world
final Player player = PlayerWrapper.wrap(createProxyActor(event.getPlayer()));
Player actor = createProxyActor(event.getPlayer());
final Player player = new LocationMaskedPlayerWrapper(PlayerWrapper.wrap(actor), actor.getLocation());
try {
switch (event.getInputType()) {

View File

@ -414,7 +414,7 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
@Override
public World getImpWorld() {
if (nmsWorld != null) {
if (nmsWorld != null || getWorldName() == null) {
return nmsWorld;
}
String[] split = getWorldName().split(";");

View File

@ -403,7 +403,7 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
@Override
public World getImpWorld() {
if (nmsWorld != null) {
if (nmsWorld != null || getWorldName() == null) {
return nmsWorld;
}
String[] split = getWorldName().split(";");

View File

@ -377,7 +377,7 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
@Override
public World getImpWorld() {
if (nmsWorld != null) {
if (nmsWorld != null || getWorldName() == null) {
return nmsWorld;
}
String[] split = getWorldName().split(";");

View File

@ -412,7 +412,7 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
@Override
public World getImpWorld() {
if (nmsWorld != null) {
if (nmsWorld != null || getWorldName() == null) {
return nmsWorld;
}
String[] split = getWorldName().split(";");