Mirror von
https://github.com/IntellectualSites/FastAsyncWorldEdit.git
synchronisiert 2024-12-27 19:30:07 +01:00
Initial experimental work on Folia support
Dieser Commit ist enthalten in:
Ursprung
fbb8a9b944
Commit
0faaaa55ee
@ -2,6 +2,7 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1;
|
|||||||
|
|
||||||
import com.fastasyncworldedit.bukkit.adapter.FaweAdapter;
|
import com.fastasyncworldedit.bukkit.adapter.FaweAdapter;
|
||||||
import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory;
|
import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory;
|
||||||
|
import com.fastasyncworldedit.core.Fawe;
|
||||||
import com.fastasyncworldedit.core.FaweCache;
|
import com.fastasyncworldedit.core.FaweCache;
|
||||||
import com.fastasyncworldedit.core.entity.LazyBaseEntity;
|
import com.fastasyncworldedit.core.entity.LazyBaseEntity;
|
||||||
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
|
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
|
||||||
@ -240,7 +241,12 @@ public final class PaperweightFaweAdapter extends FaweAdapter<net.minecraft.nbt.
|
|||||||
int y = location.getBlockY();
|
int y = location.getBlockY();
|
||||||
int z = location.getBlockZ();
|
int z = location.getBlockZ();
|
||||||
final ServerLevel handle = getServerLevel(location.getWorld());
|
final ServerLevel handle = getServerLevel(location.getWorld());
|
||||||
LevelChunk chunk = handle.getChunk(x >> 4, z >> 4);
|
LevelChunk chunk;
|
||||||
|
if (Fawe.isTickThread()) {
|
||||||
|
chunk = handle.getChunk(x >> 4, z >> 4);
|
||||||
|
} else {
|
||||||
|
chunk = TaskManager.taskManager().syncAt(() -> handle.getChunk(x >> 4, z >> 4), BukkitAdapter.adapt(location));
|
||||||
|
}
|
||||||
final BlockPos blockPos = new BlockPos(x, y, z);
|
final BlockPos blockPos = new BlockPos(x, y, z);
|
||||||
final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos);
|
final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos);
|
||||||
BlockState state = adapt(blockData);
|
BlockState state = adapt(blockData);
|
||||||
|
@ -59,7 +59,8 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
|
|||||||
this.level = level;
|
this.level = level;
|
||||||
// Use the actual tick as minecraft-defined so we don't try to force blocks into the world when the server's already lagging.
|
// Use the actual tick as minecraft-defined so we don't try to force blocks into the world when the server's already lagging.
|
||||||
// - With the caveat that we don't want to have too many cached changed (1024) so we'd flush those at 1024 anyway.
|
// - With the caveat that we don't want to have too many cached changed (1024) so we'd flush those at 1024 anyway.
|
||||||
this.lastTick = new AtomicInteger(MinecraftServer.currentTick);
|
// TODO
|
||||||
|
this.lastTick = new AtomicInteger(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Level getLevel() {
|
private Level getLevel() {
|
||||||
|
@ -11,10 +11,14 @@ import com.fastasyncworldedit.core.util.MathMan;
|
|||||||
import com.fastasyncworldedit.core.util.ReflectionUtils;
|
import com.fastasyncworldedit.core.util.ReflectionUtils;
|
||||||
import com.fastasyncworldedit.core.util.TaskManager;
|
import com.fastasyncworldedit.core.util.TaskManager;
|
||||||
import com.mojang.datafixers.util.Either;
|
import com.mojang.datafixers.util.Either;
|
||||||
|
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||||
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 com.sk89q.worldedit.bukkit.adapter.Refraction;
|
import com.sk89q.worldedit.bukkit.adapter.Refraction;
|
||||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||||
|
import com.sk89q.worldedit.math.Vector3;
|
||||||
|
import com.sk89q.worldedit.util.Location;
|
||||||
|
import com.sk89q.worldedit.world.World;
|
||||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||||
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
||||||
import com.sk89q.worldedit.world.block.BlockState;
|
import com.sk89q.worldedit.world.block.BlockState;
|
||||||
@ -383,13 +387,19 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet));
|
nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet));
|
||||||
});
|
}, toLocation(nmsWorld, coordIntPair));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<ServerPlayer> nearbyPlayers(ServerLevel serverLevel, ChunkPos coordIntPair) {
|
private static List<ServerPlayer> nearbyPlayers(ServerLevel serverLevel, ChunkPos coordIntPair) {
|
||||||
return serverLevel.getChunkSource().chunkMap.getPlayers(coordIntPair, false);
|
return serverLevel.getChunkSource().chunkMap.getPlayers(coordIntPair, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Location toLocation(ServerLevel serverLevel, ChunkPos chunkPos) {
|
||||||
|
final World adapt = BukkitAdapter.adapt(serverLevel.getWorld());
|
||||||
|
final Vector3 pos = Vector3.at(chunkPos.getMinBlockX(), 0, chunkPos.getMinBlockZ());
|
||||||
|
return new Location(adapt, pos);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
NMS conversion
|
NMS conversion
|
||||||
*/
|
*/
|
||||||
|
@ -11,6 +11,8 @@ import com.fastasyncworldedit.bukkit.regions.ResidenceFeature;
|
|||||||
import com.fastasyncworldedit.bukkit.regions.TownyFeature;
|
import com.fastasyncworldedit.bukkit.regions.TownyFeature;
|
||||||
import com.fastasyncworldedit.bukkit.regions.WorldGuardFeature;
|
import com.fastasyncworldedit.bukkit.regions.WorldGuardFeature;
|
||||||
import com.fastasyncworldedit.bukkit.util.BukkitTaskManager;
|
import com.fastasyncworldedit.bukkit.util.BukkitTaskManager;
|
||||||
|
import com.fastasyncworldedit.bukkit.util.FoliaTaskManager;
|
||||||
|
import com.fastasyncworldedit.core.util.FoliaSupport;
|
||||||
import com.fastasyncworldedit.bukkit.util.ItemUtil;
|
import com.fastasyncworldedit.bukkit.util.ItemUtil;
|
||||||
import com.fastasyncworldedit.bukkit.util.MinecraftVersion;
|
import com.fastasyncworldedit.bukkit.util.MinecraftVersion;
|
||||||
import com.fastasyncworldedit.bukkit.util.image.BukkitImageViewer;
|
import com.fastasyncworldedit.bukkit.util.image.BukkitImageViewer;
|
||||||
@ -63,6 +65,7 @@ public class FaweBukkit implements IFawe, Listener {
|
|||||||
private ItemUtil itemUtil;
|
private ItemUtil itemUtil;
|
||||||
private Preloader preloader;
|
private Preloader preloader;
|
||||||
private volatile boolean keepUnloaded;
|
private volatile boolean keepUnloaded;
|
||||||
|
private static final Thread startingThread = Thread.currentThread();
|
||||||
|
|
||||||
public FaweBukkit(Plugin plugin) {
|
public FaweBukkit(Plugin plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
@ -74,7 +77,7 @@ public class FaweBukkit implements IFawe, Listener {
|
|||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
LOGGER.error("Brush Listener Failed", e);
|
LOGGER.error("Brush Listener Failed", e);
|
||||||
}
|
}
|
||||||
if (PaperLib.isPaper() && Settings.settings().EXPERIMENTAL.DYNAMIC_CHUNK_RENDERING > 1) {
|
if (!FoliaSupport.isFolia() && PaperLib.isPaper() && Settings.settings().EXPERIMENTAL.DYNAMIC_CHUNK_RENDERING > 1) {
|
||||||
new RenderListener(plugin);
|
new RenderListener(plugin);
|
||||||
}
|
}
|
||||||
} catch (final Throwable e) {
|
} catch (final Throwable e) {
|
||||||
@ -89,20 +92,22 @@ public class FaweBukkit implements IFawe, Listener {
|
|||||||
platformAdapter = new NMSAdapter();
|
platformAdapter = new NMSAdapter();
|
||||||
|
|
||||||
//PlotSquared support is limited to Spigot/Paper as of 02/20/2020
|
//PlotSquared support is limited to Spigot/Paper as of 02/20/2020
|
||||||
TaskManager.taskManager().later(this::setupPlotSquared, 0);
|
// TODO plotsquared support
|
||||||
|
// TaskManager.taskManager().later(this::setupPlotSquared, 0);
|
||||||
|
|
||||||
|
// TODO moved out of task below??
|
||||||
|
Bukkit.getPluginManager().registerEvents(FaweBukkit.this, FaweBukkit.this.plugin);
|
||||||
// Registered delayed Event Listeners
|
// Registered delayed Event Listeners
|
||||||
TaskManager.taskManager().task(() -> {
|
/*TaskManager.taskManager().task(() -> {
|
||||||
// Fix for ProtocolSupport
|
// Fix for ProtocolSupport
|
||||||
Settings.settings().PROTOCOL_SUPPORT_FIX =
|
Settings.settings().PROTOCOL_SUPPORT_FIX =
|
||||||
Bukkit.getPluginManager().isPluginEnabled("ProtocolSupport");
|
Bukkit.getPluginManager().isPluginEnabled("ProtocolSupport");
|
||||||
|
|
||||||
// This class
|
// This class
|
||||||
Bukkit.getPluginManager().registerEvents(FaweBukkit.this, FaweBukkit.this.plugin);
|
|
||||||
|
|
||||||
// The tick limiter
|
// The tick limiter
|
||||||
new ChunkListener9();
|
new ChunkListener9();
|
||||||
});
|
});*/
|
||||||
|
|
||||||
// Warn if small-edits are enabled with extended world heights
|
// Warn if small-edits are enabled with extended world heights
|
||||||
if (version.isEqualOrHigherThan(MinecraftVersion.CAVES_18) && Settings.settings().HISTORY.SMALL_EDITS) {
|
if (version.isEqualOrHigherThan(MinecraftVersion.CAVES_18) && Settings.settings().HISTORY.SMALL_EDITS) {
|
||||||
@ -192,6 +197,9 @@ public class FaweBukkit implements IFawe, Listener {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public TaskManager getTaskManager() {
|
public TaskManager getTaskManager() {
|
||||||
|
if (FoliaSupport.isFolia()) {
|
||||||
|
return new FoliaTaskManager();
|
||||||
|
}
|
||||||
return new BukkitTaskManager(plugin);
|
return new BukkitTaskManager(plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -312,6 +320,14 @@ public class FaweBukkit implements IFawe, Listener {
|
|||||||
return platformAdapter;
|
return platformAdapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTickThread() {
|
||||||
|
if (FoliaSupport.isFolia()) {
|
||||||
|
return FoliaSupport.isTickThread();
|
||||||
|
}
|
||||||
|
return Thread.currentThread() == startingThread;
|
||||||
|
}
|
||||||
|
|
||||||
private void setupPlotSquared() {
|
private void setupPlotSquared() {
|
||||||
Plugin plotSquared = this.plugin.getServer().getPluginManager().getPlugin("PlotSquared");
|
Plugin plotSquared = this.plugin.getServer().getPluginManager().getPlugin("PlotSquared");
|
||||||
if (plotSquared == null) {
|
if (plotSquared == null) {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.fastasyncworldedit.bukkit.listener;
|
package com.fastasyncworldedit.bukkit.listener;
|
||||||
|
|
||||||
import com.fastasyncworldedit.bukkit.FaweBukkit;
|
import com.fastasyncworldedit.bukkit.FaweBukkit;
|
||||||
|
import com.fastasyncworldedit.core.util.FoliaSupport;
|
||||||
import com.fastasyncworldedit.core.Fawe;
|
import com.fastasyncworldedit.core.Fawe;
|
||||||
import com.fastasyncworldedit.core.configuration.Settings;
|
import com.fastasyncworldedit.core.configuration.Settings;
|
||||||
import com.fastasyncworldedit.core.util.FaweTimer;
|
import com.fastasyncworldedit.core.util.FaweTimer;
|
||||||
@ -59,6 +60,9 @@ public abstract class ChunkListener implements Listener {
|
|||||||
Settings.settings().TICK_LIMITER.FALLING, Settings.settings().TICK_LIMITER.ITEMS};
|
Settings.settings().TICK_LIMITER.FALLING, Settings.settings().TICK_LIMITER.ITEMS};
|
||||||
|
|
||||||
public ChunkListener() {
|
public ChunkListener() {
|
||||||
|
if (FoliaSupport.isFolia()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (Settings.settings().TICK_LIMITER.ENABLED) {
|
if (Settings.settings().TICK_LIMITER.ENABLED) {
|
||||||
PluginManager plm = Bukkit.getPluginManager();
|
PluginManager plm = Bukkit.getPluginManager();
|
||||||
Plugin plugin = Fawe.<FaweBukkit>platform().getPlugin();
|
Plugin plugin = Fawe.<FaweBukkit>platform().getPlugin();
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
package com.fastasyncworldedit.bukkit.util;
|
package com.fastasyncworldedit.bukkit.util;
|
||||||
|
|
||||||
import com.fastasyncworldedit.core.util.TaskManager;
|
import com.fastasyncworldedit.core.util.TaskManager;
|
||||||
|
import com.sk89q.worldedit.entity.Player;
|
||||||
|
import com.sk89q.worldedit.util.Location;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class BukkitTaskManager extends TaskManager {
|
public class BukkitTaskManager extends TaskManager {
|
||||||
|
|
||||||
@ -34,11 +38,21 @@ public class BukkitTaskManager extends TaskManager {
|
|||||||
this.plugin.getServer().getScheduler().runTask(this.plugin, runnable).getTaskId();
|
this.plugin.getServer().getScheduler().runTask(this.plugin, runnable).getTaskId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void task(@NotNull final Runnable runnable, @NotNull final Location context) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void later(@Nonnull final Runnable runnable, final int delay) {
|
public void later(@Nonnull final Runnable runnable, final int delay) {
|
||||||
this.plugin.getServer().getScheduler().runTaskLater(this.plugin, runnable, delay).getTaskId();
|
this.plugin.getServer().getScheduler().runTaskLater(this.plugin, runnable, delay).getTaskId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void later(@NotNull final Runnable runnable, final Location location, final int delay) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void laterAsync(@Nonnull final Runnable runnable, final int delay) {
|
public void laterAsync(@Nonnull final Runnable runnable, final int delay) {
|
||||||
this.plugin.getServer().getScheduler().runTaskLaterAsynchronously(this.plugin, runnable, delay);
|
this.plugin.getServer().getScheduler().runTaskLaterAsynchronously(this.plugin, runnable, delay);
|
||||||
@ -51,4 +65,16 @@ public class BukkitTaskManager extends TaskManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T syncAt(final Supplier<T> supplier, final Location context) {
|
||||||
|
return sync(supplier);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T syncWith(final Supplier<T> supplier, final Player context) {
|
||||||
|
return sync(supplier);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,206 @@
|
|||||||
|
package com.fastasyncworldedit.bukkit.util;
|
||||||
|
|
||||||
|
import com.fastasyncworldedit.core.util.TaskManager;
|
||||||
|
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||||
|
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||||
|
import com.sk89q.worldedit.entity.Entity;
|
||||||
|
import com.sk89q.worldedit.entity.Player;
|
||||||
|
import com.sk89q.worldedit.util.Location;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.lang.invoke.MethodHandle;
|
||||||
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.lang.invoke.MethodType;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.FutureTask;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import static java.lang.invoke.MethodHandles.dropReturn;
|
||||||
|
import static java.lang.invoke.MethodHandles.explicitCastArguments;
|
||||||
|
import static java.lang.invoke.MethodHandles.filterArguments;
|
||||||
|
import static java.lang.invoke.MethodHandles.insertArguments;
|
||||||
|
import static java.lang.invoke.MethodType.methodType;
|
||||||
|
|
||||||
|
public class FoliaTaskManager extends TaskManager {
|
||||||
|
|
||||||
|
private final ScheduledExecutorService backgroundExecutor = Executors.newSingleThreadScheduledExecutor();
|
||||||
|
private final AtomicInteger idCounter = new AtomicInteger();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int repeat(@NotNull final Runnable runnable, final int interval) {
|
||||||
|
return fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int repeatAsync(@NotNull final Runnable runnable, final int interval) {
|
||||||
|
backgroundExecutor.scheduleAtFixedRate(runnable, 0, ticksToMs(interval), TimeUnit.MILLISECONDS);
|
||||||
|
return idCounter.getAndIncrement();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void async(@NotNull final Runnable runnable) {
|
||||||
|
backgroundExecutor.submit(runnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void task(@NotNull final Runnable runnable) {
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void task(@NotNull final Runnable runnable, @NotNull final Location context) {
|
||||||
|
SchedulerAdapter.executeForLocation(context, runnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void later(@NotNull final Runnable runnable, final int delay) {
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void later(@NotNull final Runnable runnable, final Location location, final int delay) {
|
||||||
|
fail("Not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void laterAsync(@NotNull final Runnable runnable, final int delay) {
|
||||||
|
backgroundExecutor.schedule(runnable, ticksToMs(delay), TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cancel(final int task) {
|
||||||
|
fail("Not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T syncAt(final Supplier<T> supplier, final Location context) {
|
||||||
|
FutureTask<T> task = new FutureTask<>(supplier::get);
|
||||||
|
SchedulerAdapter.executeForLocation(context, task);
|
||||||
|
try {
|
||||||
|
return task.get();
|
||||||
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T syncWith(final Supplier<T> supplier, final Player context) {
|
||||||
|
FutureTask<T> task = new FutureTask<>(supplier::get);
|
||||||
|
SchedulerAdapter.executeForEntity(context, task);
|
||||||
|
try {
|
||||||
|
return task.get();
|
||||||
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int ticksToMs(int ticks) {
|
||||||
|
// 1 tick = 50ms
|
||||||
|
return ticks * 50;
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T> T fail() {
|
||||||
|
return fail("No main thread present");
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T> T fail(String message) {
|
||||||
|
throw new UnsupportedOperationException(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class SchedulerAdapter {
|
||||||
|
|
||||||
|
private static final MethodHandle EXECUTE_FOR_LOCATION;
|
||||||
|
private static final MethodHandle EXECUTE_FOR_PLAYER;
|
||||||
|
|
||||||
|
private static final MethodType LOCATION_EXECUTE_TYPE = methodType(
|
||||||
|
void.class,
|
||||||
|
Plugin.class,
|
||||||
|
org.bukkit.Location.class,
|
||||||
|
Runnable.class
|
||||||
|
);
|
||||||
|
|
||||||
|
private static final MethodType ENTITY_EXECUTE_TYPE = methodType(
|
||||||
|
boolean.class,
|
||||||
|
Plugin.class,
|
||||||
|
Runnable.class,
|
||||||
|
Runnable.class,
|
||||||
|
long.class
|
||||||
|
);
|
||||||
|
|
||||||
|
static {
|
||||||
|
final Plugin pluginInstance = WorldEditPlugin.getInstance();
|
||||||
|
final MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||||
|
|
||||||
|
MethodHandle executeForLocation;
|
||||||
|
|
||||||
|
MethodHandle executeForPlayer;
|
||||||
|
try {
|
||||||
|
Class<?> regionisedSchedulerClass = Class.forName("io.papermc.paper.threadedregions.scheduler.RegionisedScheduler");
|
||||||
|
final Method method = Bukkit.class.getDeclaredMethod("getRegionScheduler");
|
||||||
|
executeForLocation = lookup.findVirtual(
|
||||||
|
regionisedSchedulerClass,
|
||||||
|
"execute",
|
||||||
|
LOCATION_EXECUTE_TYPE
|
||||||
|
);
|
||||||
|
executeForLocation = executeForLocation.bindTo(method.invoke(null));
|
||||||
|
executeForLocation = executeForLocation.bindTo(pluginInstance);
|
||||||
|
|
||||||
|
Class<?> entitySchedulerClass = Class.forName("io.papermc.paper.threadedregions.scheduler.EntityScheduler");
|
||||||
|
executeForPlayer = lookup.findVirtual(
|
||||||
|
entitySchedulerClass,
|
||||||
|
"execute",
|
||||||
|
ENTITY_EXECUTE_TYPE
|
||||||
|
);
|
||||||
|
// (ES, P, R, R, L)Z (ES, R, R, L)Z
|
||||||
|
executeForPlayer = insertArguments(executeForPlayer, 1, pluginInstance);
|
||||||
|
// (ES, R1, R2, L)Z -> (ES, R1)Z
|
||||||
|
executeForPlayer = insertArguments(executeForPlayer, 2, null, 0);
|
||||||
|
// (ES, R1)Z -> (ES, R1)V
|
||||||
|
executeForPlayer = dropReturn(executeForPlayer);
|
||||||
|
MethodHandle getScheduler = lookup.findVirtual(
|
||||||
|
org.bukkit.entity.Entity.class,
|
||||||
|
"getScheduler",
|
||||||
|
methodType(entitySchedulerClass)
|
||||||
|
);
|
||||||
|
// (ES, R1)V -> (E, R1)V
|
||||||
|
executeForPlayer = filterArguments(executeForPlayer, 0, getScheduler);
|
||||||
|
MethodType finalType = methodType(void.class, org.bukkit.entity.Player.class, Runnable.class);
|
||||||
|
// (ES, R1)V -> (P, R1)V
|
||||||
|
executeForPlayer = explicitCastArguments(executeForPlayer, finalType);
|
||||||
|
} catch (Throwable throwable) {
|
||||||
|
throw new AssertionError(throwable);
|
||||||
|
}
|
||||||
|
EXECUTE_FOR_LOCATION = executeForLocation;
|
||||||
|
EXECUTE_FOR_PLAYER = executeForPlayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void executeForLocation(Location location, Runnable task) {
|
||||||
|
try {
|
||||||
|
EXECUTE_FOR_LOCATION.invokeExact(BukkitAdapter.adapt(location), task);
|
||||||
|
} catch (Error | RuntimeException e) {
|
||||||
|
throw e;
|
||||||
|
} catch (Throwable other) {
|
||||||
|
throw new RuntimeException(other);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void executeForEntity(Player player, Runnable task) {
|
||||||
|
// TODO task might not be run if player retires
|
||||||
|
try {
|
||||||
|
EXECUTE_FOR_PLAYER.invokeExact(BukkitAdapter.adapt(player), task);
|
||||||
|
} catch (Error | RuntimeException e) {
|
||||||
|
throw e;
|
||||||
|
} catch (Throwable other) {
|
||||||
|
throw new RuntimeException(other);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -161,7 +161,7 @@ public class BukkitPlayer extends AbstractPlayerActor {
|
|||||||
public void giveItem(BaseItemStack itemStack) {
|
public void giveItem(BaseItemStack itemStack) {
|
||||||
final PlayerInventory inv = player.getInventory();
|
final PlayerInventory inv = player.getInventory();
|
||||||
ItemStack newItem = BukkitAdapter.adapt(itemStack);
|
ItemStack newItem = BukkitAdapter.adapt(itemStack);
|
||||||
TaskManager.taskManager().sync(() -> {
|
TaskManager.taskManager().syncWith(() -> {
|
||||||
if (itemStack.getType().getId().equalsIgnoreCase(WorldEdit.getInstance().getConfiguration().wandItem)) {
|
if (itemStack.getType().getId().equalsIgnoreCase(WorldEdit.getInstance().getConfiguration().wandItem)) {
|
||||||
inv.remove(newItem);
|
inv.remove(newItem);
|
||||||
}
|
}
|
||||||
@ -183,7 +183,7 @@ public class BukkitPlayer extends AbstractPlayerActor {
|
|||||||
}
|
}
|
||||||
player.updateInventory();
|
player.updateInventory();
|
||||||
return null;
|
return null;
|
||||||
});
|
}, this);
|
||||||
}
|
}
|
||||||
//FAWE end
|
//FAWE end
|
||||||
|
|
||||||
@ -240,14 +240,15 @@ public class BukkitPlayer extends AbstractPlayerActor {
|
|||||||
}
|
}
|
||||||
org.bukkit.World finalWorld = world;
|
org.bukkit.World finalWorld = world;
|
||||||
//FAWE end
|
//FAWE end
|
||||||
return TaskManager.taskManager().sync(() -> player.teleport(new Location(
|
// TODO async teleport?
|
||||||
|
return TaskManager.taskManager().syncWith(() -> player.teleport(new Location(
|
||||||
finalWorld,
|
finalWorld,
|
||||||
pos.getX(),
|
pos.getX(),
|
||||||
pos.getY(),
|
pos.getY(),
|
||||||
pos.getZ(),
|
pos.getZ(),
|
||||||
yaw,
|
yaw,
|
||||||
pitch
|
pitch
|
||||||
)));
|
)), this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -6,6 +6,7 @@ import com.fastasyncworldedit.core.queue.implementation.QueueHandler;
|
|||||||
import com.fastasyncworldedit.core.util.CachedTextureUtil;
|
import com.fastasyncworldedit.core.util.CachedTextureUtil;
|
||||||
import com.fastasyncworldedit.core.util.CleanTextureUtil;
|
import com.fastasyncworldedit.core.util.CleanTextureUtil;
|
||||||
import com.fastasyncworldedit.core.util.FaweTimer;
|
import com.fastasyncworldedit.core.util.FaweTimer;
|
||||||
|
import com.fastasyncworldedit.core.util.FoliaSupport;
|
||||||
import com.fastasyncworldedit.core.util.MainUtil;
|
import com.fastasyncworldedit.core.util.MainUtil;
|
||||||
import com.fastasyncworldedit.core.util.MemUtil;
|
import com.fastasyncworldedit.core.util.MemUtil;
|
||||||
import com.fastasyncworldedit.core.util.RandomTextureUtil;
|
import com.fastasyncworldedit.core.util.RandomTextureUtil;
|
||||||
@ -129,14 +130,17 @@ public class Fawe {
|
|||||||
this.timer = new FaweTimer();
|
this.timer = new FaweTimer();
|
||||||
|
|
||||||
// Delayed worldedit setup
|
// Delayed worldedit setup
|
||||||
TaskManager.taskManager().later(() -> {
|
// TODO support again
|
||||||
|
/*TaskManager.taskManager().later(() -> {
|
||||||
try {
|
try {
|
||||||
WEManager.weManager().addManagers(Fawe.this.implementation.getMaskManagers());
|
WEManager.weManager().addManagers(Fawe.this.implementation.getMaskManagers());
|
||||||
} catch (Throwable ignored) {
|
} catch (Throwable ignored) {
|
||||||
}
|
}
|
||||||
}, 0);
|
}, 0);*/
|
||||||
|
|
||||||
TaskManager.taskManager().repeat(timer, 1);
|
if (!FoliaSupport.isFolia()) {
|
||||||
|
TaskManager.taskManager().repeat(timer, 1);
|
||||||
|
}
|
||||||
|
|
||||||
clipboardExecutor = new KeyQueuedExecutorService<>(new ThreadPoolExecutor(
|
clipboardExecutor = new KeyQueuedExecutorService<>(new ThreadPoolExecutor(
|
||||||
1,
|
1,
|
||||||
@ -206,10 +210,15 @@ public class Fawe {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public static boolean isMainThread() {
|
public static boolean isMainThread() {
|
||||||
return instance == null || instance.thread == Thread.currentThread();
|
return instance == null || instance.thread == Thread.currentThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isTickThread() {
|
||||||
|
return instance == null || instance.implementation.isTickThread();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Non-api. Handles an input FAWE exception if not already handled, given the input boolean array.
|
* Non-api. Handles an input FAWE exception if not already handled, given the input boolean array.
|
||||||
* Looks at the {@link FaweException.Type} and decides what to do (rethrows if we want to attempt to show the error to the
|
* Looks at the {@link FaweException.Type} and decides what to do (rethrows if we want to attempt to show the error to the
|
||||||
|
@ -49,4 +49,6 @@ public interface IFawe {
|
|||||||
|
|
||||||
FAWEPlatformAdapterImpl getPlatformAdapter();
|
FAWEPlatformAdapterImpl getPlatformAdapter();
|
||||||
|
|
||||||
|
boolean isTickThread();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ import com.fastasyncworldedit.core.util.collection.CleanableThreadLocal;
|
|||||||
import com.fastasyncworldedit.core.util.task.FaweForkJoinWorkerThreadFactory;
|
import com.fastasyncworldedit.core.util.task.FaweForkJoinWorkerThreadFactory;
|
||||||
import com.fastasyncworldedit.core.wrappers.WorldWrapper;
|
import com.fastasyncworldedit.core.wrappers.WorldWrapper;
|
||||||
import com.google.common.util.concurrent.Futures;
|
import com.google.common.util.concurrent.Futures;
|
||||||
|
import com.sk89q.worldedit.util.Location;
|
||||||
import com.sk89q.worldedit.world.World;
|
import com.sk89q.worldedit.world.World;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
@ -90,13 +91,14 @@ public abstract class QueueHandler implements Trimable, Runnable {
|
|||||||
private long allocate = 50;
|
private long allocate = 50;
|
||||||
|
|
||||||
protected QueueHandler() {
|
protected QueueHandler() {
|
||||||
TaskManager.taskManager().repeat(this, 1);
|
// TODO make main thread independent
|
||||||
|
// TaskManager.taskManager().repeat(this, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (!Fawe.isMainThread()) {
|
if (!Fawe.isTickThread()) {
|
||||||
throw new IllegalStateException("Not main thread");
|
throw new IllegalStateException("Not ticking thread");
|
||||||
}
|
}
|
||||||
if (!syncTasks.isEmpty()) {
|
if (!syncTasks.isEmpty()) {
|
||||||
long currentAllocate = getAllocate();
|
long currentAllocate = getAllocate();
|
||||||
|
@ -0,0 +1,38 @@
|
|||||||
|
package com.fastasyncworldedit.core.util;
|
||||||
|
|
||||||
|
public final class FoliaSupport {
|
||||||
|
private FoliaSupport() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final boolean IS_FOLIA;
|
||||||
|
private static final Class<?> TICK_THREAD_CLASS;
|
||||||
|
static {
|
||||||
|
boolean isFolia = false;
|
||||||
|
try {
|
||||||
|
// Assume API is present
|
||||||
|
Class.forName("io.papermc.paper.threadedregions.scheduler.EntityScheduler");
|
||||||
|
isFolia = true;
|
||||||
|
} catch (Exception unused) {
|
||||||
|
|
||||||
|
}
|
||||||
|
IS_FOLIA = isFolia;
|
||||||
|
Class<?> tickThreadClass = String.class; // thread will never be instance of String
|
||||||
|
if (IS_FOLIA) {
|
||||||
|
try {
|
||||||
|
tickThreadClass = Class.forName("io.papermc.paper.util.TickThread");
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TICK_THREAD_CLASS = tickThreadClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isFolia() {
|
||||||
|
return IS_FOLIA;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isTickThread() {
|
||||||
|
return TICK_THREAD_CLASS.isInstance(Thread.currentThread());
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,10 @@ import com.fastasyncworldedit.core.Fawe;
|
|||||||
import com.fastasyncworldedit.core.configuration.Settings;
|
import com.fastasyncworldedit.core.configuration.Settings;
|
||||||
import com.fastasyncworldedit.core.queue.implementation.QueueHandler;
|
import com.fastasyncworldedit.core.queue.implementation.QueueHandler;
|
||||||
import com.fastasyncworldedit.core.util.task.RunnableVal;
|
import com.fastasyncworldedit.core.util.task.RunnableVal;
|
||||||
|
import com.sk89q.worldedit.entity.Entity;
|
||||||
|
import com.sk89q.worldedit.entity.Player;
|
||||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||||
|
import com.sk89q.worldedit.util.Location;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
@ -52,6 +55,7 @@ public abstract class TaskManager {
|
|||||||
* @param runnable the task to run
|
* @param runnable the task to run
|
||||||
* @param interval in ticks
|
* @param interval in ticks
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public abstract int repeat(@Nonnull final Runnable runnable, final int interval);
|
public abstract int repeat(@Nonnull final Runnable runnable, final int interval);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -75,7 +79,14 @@ public abstract class TaskManager {
|
|||||||
*
|
*
|
||||||
* @param runnable the task to run
|
* @param runnable the task to run
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public abstract void task(@Nonnull final Runnable runnable);
|
public abstract void task(@Nonnull final Runnable runnable);
|
||||||
|
/**
|
||||||
|
* Run a task on the main thread.
|
||||||
|
*
|
||||||
|
* @param runnable the task to run
|
||||||
|
*/
|
||||||
|
public abstract void task(@Nonnull final Runnable runnable, @Nonnull Location contextLocation);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the public ForkJoinPool.
|
* Get the public ForkJoinPool.
|
||||||
@ -159,6 +170,7 @@ public abstract class TaskManager {
|
|||||||
/**
|
/**
|
||||||
* Disable async catching for a specific task.
|
* Disable async catching for a specific task.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public void runUnsafe(Runnable run) {
|
public void runUnsafe(Runnable run) {
|
||||||
QueueHandler queue = Fawe.instance().getQueueHandler();
|
QueueHandler queue = Fawe.instance().getQueueHandler();
|
||||||
queue.startUnsafe(Fawe.isMainThread());
|
queue.startUnsafe(Fawe.isMainThread());
|
||||||
@ -191,6 +203,7 @@ public abstract class TaskManager {
|
|||||||
*
|
*
|
||||||
* @param runnable the task to run
|
* @param runnable the task to run
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public void taskNowMain(@Nonnull final Runnable runnable) {
|
public void taskNowMain(@Nonnull final Runnable runnable) {
|
||||||
if (Fawe.isMainThread()) {
|
if (Fawe.isMainThread()) {
|
||||||
runnable.run();
|
runnable.run();
|
||||||
@ -215,6 +228,7 @@ public abstract class TaskManager {
|
|||||||
* @param runnable the task to run.
|
* @param runnable the task to run.
|
||||||
* @param async whether the task should run on the main thread
|
* @param async whether the task should run on the main thread
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public void taskSoonMain(@Nonnull final Runnable runnable, boolean async) {
|
public void taskSoonMain(@Nonnull final Runnable runnable, boolean async) {
|
||||||
if (async) {
|
if (async) {
|
||||||
async(runnable);
|
async(runnable);
|
||||||
@ -230,7 +244,9 @@ public abstract class TaskManager {
|
|||||||
* @param runnable the task to run
|
* @param runnable the task to run
|
||||||
* @param delay in ticks
|
* @param delay in ticks
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public abstract void later(@Nonnull final Runnable runnable, final int delay);
|
public abstract void later(@Nonnull final Runnable runnable, final int delay);
|
||||||
|
public abstract void later(@Nonnull final Runnable runnable, Location location, final int delay);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run a task later asynchronously.
|
* Run a task later asynchronously.
|
||||||
@ -255,6 +271,7 @@ public abstract class TaskManager {
|
|||||||
* @param task the task to run on each object
|
* @param task the task to run on each object
|
||||||
* @param whenDone when the object task completes
|
* @param whenDone when the object task completes
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public <T> void objectTask(Collection<T> objects, final RunnableVal<T> task, final Runnable whenDone) {
|
public <T> void objectTask(Collection<T> objects, final RunnableVal<T> task, final Runnable whenDone) {
|
||||||
final Iterator<T> iterator = objects.iterator();
|
final Iterator<T> iterator = objects.iterator();
|
||||||
task(new Runnable() {
|
task(new Runnable() {
|
||||||
@ -307,6 +324,7 @@ public abstract class TaskManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public void taskWhenFree(@Nonnull Runnable run) {
|
public void taskWhenFree(@Nonnull Runnable run) {
|
||||||
if (Fawe.isMainThread()) {
|
if (Fawe.isMainThread()) {
|
||||||
run.run();
|
run.run();
|
||||||
@ -320,6 +338,7 @@ public abstract class TaskManager {
|
|||||||
* - Useful if you need to access something from the Bukkit API from another thread<br>
|
* - Useful if you need to access something from the Bukkit API from another thread<br>
|
||||||
* - Usually wait time is around 25ms<br>
|
* - Usually wait time is around 25ms<br>
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public <T> T syncWhenFree(@Nonnull final RunnableVal<T> function) {
|
public <T> T syncWhenFree(@Nonnull final RunnableVal<T> function) {
|
||||||
if (Fawe.isMainThread()) {
|
if (Fawe.isMainThread()) {
|
||||||
function.run();
|
function.run();
|
||||||
@ -337,6 +356,7 @@ public abstract class TaskManager {
|
|||||||
* - Useful if you need to access something from the Bukkit API from another thread<br>
|
* - Useful if you need to access something from the Bukkit API from another thread<br>
|
||||||
* - Usually wait time is around 25ms<br>
|
* - Usually wait time is around 25ms<br>
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public <T> T syncWhenFree(@Nonnull final Supplier<T> supplier) {
|
public <T> T syncWhenFree(@Nonnull final Supplier<T> supplier) {
|
||||||
if (Fawe.isMainThread()) {
|
if (Fawe.isMainThread()) {
|
||||||
return supplier.get();
|
return supplier.get();
|
||||||
@ -353,6 +373,7 @@ public abstract class TaskManager {
|
|||||||
* - Useful if you need to access something from the Bukkit API from another thread<br>
|
* - Useful if you need to access something from the Bukkit API from another thread<br>
|
||||||
* - Usually wait time is around 25ms
|
* - Usually wait time is around 25ms
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public <T> T sync(@Nonnull final RunnableVal<T> function) {
|
public <T> T sync(@Nonnull final RunnableVal<T> function) {
|
||||||
return sync((Supplier<T>) function);
|
return sync((Supplier<T>) function);
|
||||||
}
|
}
|
||||||
@ -362,6 +383,7 @@ public abstract class TaskManager {
|
|||||||
* - Useful if you need to access something from the Bukkit API from another thread<br>
|
* - Useful if you need to access something from the Bukkit API from another thread<br>
|
||||||
* - Usually wait time is around 25ms<br>
|
* - Usually wait time is around 25ms<br>
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public <T> T sync(final Supplier<T> function) {
|
public <T> T sync(final Supplier<T> function) {
|
||||||
if (Fawe.isMainThread()) {
|
if (Fawe.isMainThread()) {
|
||||||
return function.get();
|
return function.get();
|
||||||
@ -373,4 +395,8 @@ public abstract class TaskManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract <T> T syncAt(Supplier<T> supplier, Location context);
|
||||||
|
|
||||||
|
public abstract <T> T syncWith(Supplier<T> supplier, Player context);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -58,12 +58,12 @@ public class AsyncPlayer extends PlayerProxy {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void findFreePosition() {
|
public void findFreePosition() {
|
||||||
TaskManager.taskManager().sync(new RunnableVal<Boolean>() {
|
TaskManager.taskManager().syncWith(new RunnableVal<Boolean>() {
|
||||||
@Override
|
@Override
|
||||||
public void run(Boolean value) {
|
public void run(Boolean value) {
|
||||||
getBasePlayer().findFreePosition();
|
getBasePlayer().findFreePosition();
|
||||||
}
|
}
|
||||||
});
|
}, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren