Mirror von
https://github.com/IntellectualSites/FastAsyncWorldEdit.git
synchronisiert 2024-12-27 03:12:37 +01:00
rebase fixes
Dieser Commit ist enthalten in:
Ursprung
d64b0d9edf
Commit
fbe69bdc81
@ -85,7 +85,7 @@ allprojects {
|
|||||||
|
|
||||||
applyCommonConfiguration()
|
applyCommonConfiguration()
|
||||||
val supportedVersions = listOf("1.18.2", "1.19.4", "1.20", "1.20.4")
|
val supportedVersions = listOf("1.18.2", "1.19.4", "1.20", "1.20.4")
|
||||||
val foliaSupportedVersions = listOf("1.20.1")
|
val foliaSupportedVersions = listOf("1.20.2")
|
||||||
|
|
||||||
tasks {
|
tasks {
|
||||||
fun registerVersion(version: String, software: String, task: RunServer.() -> Unit = {}) {
|
fun registerVersion(version: String, software: String, task: RunServer.() -> Unit = {}) {
|
||||||
|
@ -10,6 +10,7 @@ import com.fastasyncworldedit.core.queue.IBatchProcessor;
|
|||||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||||
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
|
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
|
||||||
import com.fastasyncworldedit.core.util.NbtUtils;
|
import com.fastasyncworldedit.core.util.NbtUtils;
|
||||||
|
import com.fastasyncworldedit.core.util.TaskManager;
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
@ -35,82 +35,21 @@ public class PaperweightStarlightRelighter extends StarlightRelighter<ServerLeve
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void fixLightingSafe(boolean sky) {
|
protected CompletableFuture<?> chunkLoadFuture(final ChunkPos chunkPos) {
|
||||||
this.areaLock.lock();
|
return serverLevel.getWorld().getChunkAtAsync(chunkPos.x, chunkPos.z)
|
||||||
try {
|
.thenAccept(c -> serverLevel.getChunkSource().addTicketAtLevel(
|
||||||
if (regions.isEmpty()) {
|
FAWE_TICKET,
|
||||||
return;
|
chunkPos,
|
||||||
}
|
LIGHT_LEVEL,
|
||||||
LongSet first = regions.removeFirst();
|
Unit.INSTANCE
|
||||||
fixLighting(first, () -> fixLightingSafe(true));
|
));
|
||||||
} finally {
|
|
||||||
this.areaLock.unlock();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
@Override
|
||||||
* Processes a set of chunks and runs an action afterwards.
|
protected void invokeRelight(
|
||||||
* The action is run async, the chunks are partly processed on the main thread
|
final Set<ChunkPos> coords,
|
||||||
* (as required by the server).
|
final Consumer<ChunkPos> chunkCallback,
|
||||||
*/
|
final IntConsumer processCallback
|
||||||
private void fixLighting(LongSet chunks, Runnable andThen) {
|
|
||||||
// convert from long keys to ChunkPos
|
|
||||||
Set<ChunkPos> coords = new HashSet<>();
|
|
||||||
LongIterator iterator = chunks.iterator();
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
coords.add(new ChunkPos(iterator.nextLong()));
|
|
||||||
}
|
|
||||||
if (FoliaSupport.isFolia()) {
|
|
||||||
relightRegion(andThen, coords);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
TaskManager.taskManager().task(() -> {
|
|
||||||
// trigger chunk load and apply ticket on main thread
|
|
||||||
relightRegion(andThen, coords);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void relightRegion(Runnable andThen, Set<ChunkPos> coords) {
|
|
||||||
List<CompletableFuture<?>> futures = new ArrayList<>();
|
|
||||||
for (ChunkPos pos : coords) {
|
|
||||||
futures.add(serverLevel.getWorld().getChunkAtAsync(pos.x, pos.z)
|
|
||||||
.thenAccept(c -> serverLevel.getChunkSource().addTicketAtLevel(
|
|
||||||
FAWE_TICKET,
|
|
||||||
pos,
|
|
||||||
LIGHT_LEVEL,
|
|
||||||
Unit.INSTANCE
|
|
||||||
))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Location location = toLocation(coords.iterator().next());
|
|
||||||
// collect futures and trigger relight once all chunks are loaded
|
|
||||||
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).thenAcceptAsync(v ->
|
|
||||||
invokeRelight(
|
|
||||||
coords,
|
|
||||||
c -> {
|
|
||||||
}, // no callback for single chunks required
|
|
||||||
i -> {
|
|
||||||
if (i != coords.size()) {
|
|
||||||
LOGGER.warn("Processed {} chunks instead of {}", i, coords.size());
|
|
||||||
}
|
|
||||||
// post process chunks on main thread
|
|
||||||
TaskManager.taskManager().task(() -> postProcessChunks(coords), location);
|
|
||||||
// call callback on our own threads
|
|
||||||
TaskManager.taskManager().async(andThen);
|
|
||||||
}
|
|
||||||
),
|
|
||||||
task -> TaskManager.taskManager().task(task, location)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Location toLocation(ChunkPos chunkPos) {
|
|
||||||
return PaperweightPlatformAdapter.toLocation(this.serverLevel, chunkPos);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void invokeRelight(
|
|
||||||
Set<ChunkPos> coords,
|
|
||||||
Consumer<ChunkPos> chunkCallback,
|
|
||||||
IntConsumer processCallback
|
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
serverLevel.getChunkSource().getLightEngine().relight(coords, chunkCallback, processCallback);
|
serverLevel.getChunkSource().getLightEngine().relight(coords, chunkCallback, processCallback);
|
||||||
|
@ -2,6 +2,7 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2;
|
|||||||
|
|
||||||
import com.fastasyncworldedit.core.Fawe;
|
import com.fastasyncworldedit.core.Fawe;
|
||||||
import com.fastasyncworldedit.core.math.IntPair;
|
import com.fastasyncworldedit.core.math.IntPair;
|
||||||
|
import com.fastasyncworldedit.core.util.FoliaSupport;
|
||||||
import com.fastasyncworldedit.core.util.TaskManager;
|
import com.fastasyncworldedit.core.util.TaskManager;
|
||||||
import com.fastasyncworldedit.core.util.task.RunnableVal;
|
import com.fastasyncworldedit.core.util.task.RunnableVal;
|
||||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||||
@ -21,6 +22,7 @@ import net.minecraft.world.level.Level;
|
|||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
import net.minecraft.world.level.chunk.LevelChunk;
|
import net.minecraft.world.level.chunk.LevelChunk;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.craftbukkit.v1_20_R2.CraftWorld;
|
import org.bukkit.craftbukkit.v1_20_R2.CraftWorld;
|
||||||
import org.bukkit.craftbukkit.v1_20_R2.block.data.CraftBlockData;
|
import org.bukkit.craftbukkit.v1_20_R2.block.data.CraftBlockData;
|
||||||
import org.bukkit.event.block.BlockPhysicsEvent;
|
import org.bukkit.event.block.BlockPhysicsEvent;
|
||||||
@ -58,7 +60,10 @@ 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);
|
this.lastTick = new AtomicInteger();
|
||||||
|
if (!FoliaSupport.isFolia()) {
|
||||||
|
this.lastTick.set(Bukkit.getCurrentTick());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Level getLevel() {
|
private Level getLevel() {
|
||||||
|
@ -319,9 +319,11 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
|
|
||||||
private static void addTicket(ServerLevel serverLevel, int chunkX, int chunkZ) {
|
private static void addTicket(ServerLevel serverLevel, int chunkX, int chunkZ) {
|
||||||
// Ensure chunk is definitely loaded before applying a ticket
|
// Ensure chunk is definitely loaded before applying a ticket
|
||||||
io.papermc.paper.util.MCUtil.MAIN_EXECUTOR.execute(() -> serverLevel
|
PaperweightPlatformAdapter.task(() -> serverLevel
|
||||||
.getChunkSource()
|
.getChunkSource()
|
||||||
.addRegionTicket(TicketType.UNLOAD_COOLDOWN, new ChunkPos(chunkX, chunkZ), 0, Unit.INSTANCE));
|
.addRegionTicket(TicketType.UNLOAD_COOLDOWN, new ChunkPos(chunkX, chunkZ), 0, Unit.INSTANCE),
|
||||||
|
serverLevel, chunkX, chunkZ
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ChunkHolder getPlayerChunk(ServerLevel nmsWorld, final int chunkX, final int chunkZ) {
|
public static ChunkHolder getPlayerChunk(ServerLevel nmsWorld, final int chunkX, final int chunkZ) {
|
||||||
|
@ -2,7 +2,7 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3;
|
|||||||
|
|
||||||
import com.fastasyncworldedit.core.Fawe;
|
import com.fastasyncworldedit.core.Fawe;
|
||||||
import com.fastasyncworldedit.core.math.IntPair;
|
import com.fastasyncworldedit.core.math.IntPair;
|
||||||
import com.fastasyncworldedit.core.util.TaskManager;
|
import com.fastasyncworldedit.core.util.FoliaSupport;
|
||||||
import com.fastasyncworldedit.core.util.task.RunnableVal;
|
import com.fastasyncworldedit.core.util.task.RunnableVal;
|
||||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||||
import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
|
import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
|
||||||
@ -15,12 +15,13 @@ import net.minecraft.core.BlockPos;
|
|||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.level.ServerChunkCache;
|
|
||||||
import net.minecraft.server.level.FullChunkStatus;
|
import net.minecraft.server.level.FullChunkStatus;
|
||||||
|
import net.minecraft.server.level.ServerChunkCache;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
import net.minecraft.world.level.chunk.LevelChunk;
|
import net.minecraft.world.level.chunk.LevelChunk;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
|
import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
|
||||||
import org.bukkit.craftbukkit.v1_20_R3.block.data.CraftBlockData;
|
import org.bukkit.craftbukkit.v1_20_R3.block.data.CraftBlockData;
|
||||||
import org.bukkit.event.block.BlockPhysicsEvent;
|
import org.bukkit.event.block.BlockPhysicsEvent;
|
||||||
@ -58,7 +59,10 @@ 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);
|
this.lastTick = new AtomicInteger();
|
||||||
|
if (!FoliaSupport.isFolia()) {
|
||||||
|
this.lastTick.set(Bukkit.getCurrentTick());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Level getLevel() {
|
private Level getLevel() {
|
||||||
@ -250,7 +254,8 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
TaskManager.taskManager().async(() -> TaskManager.taskManager().sync(runnableVal));
|
// TODO
|
||||||
|
// TaskManager.taskManager().async(() -> TaskManager.taskManager().sync(runnableVal));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -269,7 +274,8 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
|
|||||||
if (Fawe.isMainThread()) {
|
if (Fawe.isMainThread()) {
|
||||||
runnableVal.run();
|
runnableVal.run();
|
||||||
} else {
|
} else {
|
||||||
TaskManager.taskManager().sync(runnableVal);
|
// TODO
|
||||||
|
// TaskManager.taskManager().sync(runnableVal);
|
||||||
}
|
}
|
||||||
cachedChanges.clear();
|
cachedChanges.clear();
|
||||||
cachedChunksToSend.clear();
|
cachedChunksToSend.clear();
|
||||||
|
@ -11,6 +11,7 @@ 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;
|
||||||
@ -58,7 +59,6 @@ import net.minecraft.world.level.entity.PersistentEntitySectionManager;
|
|||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.craftbukkit.v1_20_R3.CraftChunk;
|
import org.bukkit.craftbukkit.v1_20_R3.CraftChunk;
|
||||||
import sun.misc.Unsafe;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@ -298,7 +298,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
} catch (TimeoutException e) {
|
} catch (TimeoutException e) {
|
||||||
String world = serverLevel.getWorld().getName();
|
String world = serverLevel.getWorld().getName();
|
||||||
// We've already taken 10 seconds we can afford to wait a little here.
|
// We've already taken 10 seconds we can afford to wait a little here.
|
||||||
boolean loaded = TaskManager.taskManager().sync(() -> Bukkit.getWorld(world) != null);
|
boolean loaded = TaskManager.taskManager().syncGlobal(() -> Bukkit.getWorld(world) != null);
|
||||||
if (loaded) {
|
if (loaded) {
|
||||||
LOGGER.warn("Chunk {},{} failed to load in 10 seconds in world {}. Retrying...", chunkX, chunkZ, world);
|
LOGGER.warn("Chunk {},{} failed to load in 10 seconds in world {}. Retrying...", chunkX, chunkZ, world);
|
||||||
// Retry chunk load
|
// Retry chunk load
|
||||||
@ -313,7 +313,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return TaskManager.taskManager().sync(() -> serverLevel.getChunk(chunkX, chunkZ));
|
return TaskManager.taskManager().syncGlobal(() -> serverLevel.getChunk(chunkX, chunkZ));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void addTicket(ServerLevel serverLevel, int chunkX, int chunkZ) {
|
private static void addTicket(ServerLevel serverLevel, int chunkX, int chunkZ) {
|
||||||
@ -374,7 +374,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet));
|
nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet));
|
||||||
});
|
}, BukkitAdapter.adapt(nmsWorld.getWorld()), chunkX, chunkZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<ServerPlayer> nearbyPlayers(ServerLevel serverLevel, ChunkPos coordIntPair) {
|
private static List<ServerPlayer> nearbyPlayers(ServerLevel serverLevel, ChunkPos coordIntPair) {
|
||||||
@ -674,6 +674,10 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
return List.of();
|
return List.of();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void task(Runnable task, ServerLevel level, int chunkX, int chunkZ) {
|
||||||
|
TaskManager.taskManager().task(task, BukkitAdapter.adapt(level.getWorld()), chunkX, chunkZ);
|
||||||
|
}
|
||||||
|
|
||||||
record FakeIdMapBlock(int size) implements IdMap<net.minecraft.world.level.block.state.BlockState> {
|
record FakeIdMapBlock(int size) implements IdMap<net.minecraft.world.level.block.state.BlockState> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -4,13 +4,13 @@ import com.fastasyncworldedit.bukkit.adapter.Regenerator;
|
|||||||
import com.fastasyncworldedit.core.Fawe;
|
import com.fastasyncworldedit.core.Fawe;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkCache;
|
import com.fastasyncworldedit.core.queue.IChunkCache;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||||
import com.fastasyncworldedit.core.util.TaskManager;
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.mojang.datafixers.util.Either;
|
import com.mojang.datafixers.util.Either;
|
||||||
import com.mojang.serialization.Lifecycle;
|
import com.mojang.serialization.Lifecycle;
|
||||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.Refraction;
|
import com.sk89q.worldedit.bukkit.adapter.Refraction;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3.PaperweightGetBlocks;
|
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3.PaperweightGetBlocks;
|
||||||
|
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3.PaperweightPlatformAdapter;
|
||||||
import com.sk89q.worldedit.extent.Extent;
|
import com.sk89q.worldedit.extent.Extent;
|
||||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||||
import com.sk89q.worldedit.regions.Region;
|
import com.sk89q.worldedit.regions.Region;
|
||||||
@ -438,11 +438,11 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
|||||||
@Override
|
@Override
|
||||||
protected void populate(LevelChunk levelChunk, Random random, BlockPopulator blockPopulator) {
|
protected void populate(LevelChunk levelChunk, Random random, BlockPopulator blockPopulator) {
|
||||||
// BlockPopulator#populate has to be called synchronously for TileEntity access
|
// BlockPopulator#populate has to be called synchronously for TileEntity access
|
||||||
TaskManager.taskManager().task(() -> {
|
PaperweightPlatformAdapter.task(() -> {
|
||||||
final CraftWorld world = freshWorld.getWorld();
|
final CraftWorld world = freshWorld.getWorld();
|
||||||
final Chunk chunk = world.getChunkAt(levelChunk.locX, levelChunk.locZ);
|
final Chunk chunk = world.getChunkAt(levelChunk.locX, levelChunk.locZ);
|
||||||
blockPopulator.populate(world, random, chunk);
|
blockPopulator.populate(world, random, chunk);
|
||||||
});
|
}, freshWorld, levelChunk.getPos().x, levelChunk.getPos().z);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.fastasyncworldedit.bukkit.adapter;
|
package com.fastasyncworldedit.bukkit.adapter;
|
||||||
|
|
||||||
|
import com.fastasyncworldedit.core.util.FoliaSupport;
|
||||||
import com.fastasyncworldedit.core.util.TaskManager;
|
import com.fastasyncworldedit.core.util.TaskManager;
|
||||||
import com.sk89q.worldedit.EditSession;
|
import com.sk89q.worldedit.EditSession;
|
||||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||||
@ -11,7 +12,16 @@ import org.bukkit.TreeType;
|
|||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.block.BlockState;
|
import org.bukkit.block.BlockState;
|
||||||
|
|
||||||
|
import java.lang.invoke.MethodHandle;
|
||||||
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.lang.invoke.VarHandle;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static com.fastasyncworldedit.core.util.FoliaSupport.getRethrowing;
|
||||||
|
import static com.fastasyncworldedit.core.util.FoliaSupport.runRethrowing;
|
||||||
|
import static java.lang.invoke.MethodType.methodType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A base class for version-specific implementations of the BukkitImplAdapter
|
* A base class for version-specific implementations of the BukkitImplAdapter
|
||||||
@ -21,6 +31,39 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public abstract class FaweAdapter<TAG, SERVER_LEVEL> extends CachedBukkitAdapter implements IDelegateBukkitImplAdapter<TAG> {
|
public abstract class FaweAdapter<TAG, SERVER_LEVEL> extends CachedBukkitAdapter implements IDelegateBukkitImplAdapter<TAG> {
|
||||||
|
|
||||||
|
private static final VarHandle CAPTURE_TREE_GENERATION;
|
||||||
|
private static final VarHandle CAPTURE_BLOCK_STATES;
|
||||||
|
private static final MethodHandle CAPTURED_BLOCK_STATES;
|
||||||
|
private static final MethodHandle GET_CURRENT_WORLD_DATA;
|
||||||
|
|
||||||
|
static {
|
||||||
|
VarHandle captureTreeGeneration = null;
|
||||||
|
VarHandle captureBlockStates = null;
|
||||||
|
MethodHandle capturedBlockStates = null;
|
||||||
|
MethodHandle getCurrentWorldData = null;
|
||||||
|
if (FoliaSupport.isFolia()) {
|
||||||
|
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||||
|
try {
|
||||||
|
Class<?> regionizedWorldDataClass = Class.forName("io.papermc.paper.threadedregions.RegionizedWorldData");
|
||||||
|
Class<?> serverLevelClass = regionizedWorldDataClass.getDeclaredField("world").getType();
|
||||||
|
captureTreeGeneration = lookup.findVarHandle(regionizedWorldDataClass, "captureTreeGeneration", boolean.class);
|
||||||
|
captureBlockStates = lookup.findVarHandle(regionizedWorldDataClass, "captureBlockStates", boolean.class);
|
||||||
|
capturedBlockStates = lookup.findGetter(regionizedWorldDataClass, "capturedBlockStates", Map.class);
|
||||||
|
getCurrentWorldData = lookup.findVirtual(
|
||||||
|
serverLevelClass,
|
||||||
|
"getCurrentWorldData",
|
||||||
|
methodType(regionizedWorldDataClass)
|
||||||
|
);
|
||||||
|
} catch (ClassNotFoundException | NoSuchFieldException | NoSuchMethodException | IllegalAccessException e) {
|
||||||
|
throw new AssertionError("Incompatible Folia version", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CAPTURE_TREE_GENERATION = captureTreeGeneration;
|
||||||
|
CAPTURE_BLOCK_STATES = captureBlockStates;
|
||||||
|
CAPTURED_BLOCK_STATES = capturedBlockStates;
|
||||||
|
GET_CURRENT_WORLD_DATA = getCurrentWorldData;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean generateTree(
|
public boolean generateTree(
|
||||||
final TreeGenerator.TreeType treeType,
|
final TreeGenerator.TreeType treeType,
|
||||||
@ -35,17 +78,17 @@ public abstract class FaweAdapter<TAG, SERVER_LEVEL> extends CachedBukkitAdapter
|
|||||||
}
|
}
|
||||||
BlockVector3 target = blockVector3;
|
BlockVector3 target = blockVector3;
|
||||||
SERVER_LEVEL serverLevel = getServerLevel(world);
|
SERVER_LEVEL serverLevel = getServerLevel(world);
|
||||||
List<BlockState> placed = TaskManager.taskManager().sync(() -> {
|
List<BlockState> placed = TaskManager.taskManager().syncAt(() -> {
|
||||||
preCaptureStates(serverLevel);
|
preCaptureStatesCommon(serverLevel);
|
||||||
try {
|
try {
|
||||||
if (!world.generateTree(BukkitAdapter.adapt(world, target), bukkitType)) {
|
if (!world.generateTree(BukkitAdapter.adapt(world, target), bukkitType)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return getCapturedBlockStatesCopy(serverLevel);
|
return getCapturedBlockStatesCopyCommon(serverLevel);
|
||||||
} finally {
|
} finally {
|
||||||
postCaptureBlockStates(serverLevel);
|
postCaptureBlockStatesCommon(serverLevel);
|
||||||
}
|
}
|
||||||
});
|
}, BukkitAdapter.adapt(world), blockVector3.getBlockX() >> 4, blockVector3.getBlockZ() >> 4);
|
||||||
|
|
||||||
if (placed == null || placed.isEmpty()) {
|
if (placed == null || placed.isEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
@ -61,6 +104,57 @@ public abstract class FaweAdapter<TAG, SERVER_LEVEL> extends CachedBukkitAdapter
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void preCaptureStatesCommon(SERVER_LEVEL serverLevel) {
|
||||||
|
if (FoliaSupport.isFolia()) {
|
||||||
|
preCaptureStatesFolia(serverLevel);
|
||||||
|
} else {
|
||||||
|
preCaptureStates(serverLevel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<BlockState> getCapturedBlockStatesCopyCommon(SERVER_LEVEL serverLevel) {
|
||||||
|
if (FoliaSupport.isFolia()) {
|
||||||
|
return getCapturedBlockStatesCopyFolia(serverLevel);
|
||||||
|
} else {
|
||||||
|
return getCapturedBlockStatesCopy(serverLevel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void postCaptureBlockStatesCommon(SERVER_LEVEL serverLevel) {
|
||||||
|
if (FoliaSupport.isFolia()) {
|
||||||
|
postCaptureBlockStatesFolia(serverLevel);
|
||||||
|
} else {
|
||||||
|
postCaptureBlockStates(serverLevel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void preCaptureStatesFolia(SERVER_LEVEL serverLevel) {
|
||||||
|
runRethrowing(() -> {
|
||||||
|
Object currentWorldData = GET_CURRENT_WORLD_DATA.invoke(serverLevel);
|
||||||
|
CAPTURE_TREE_GENERATION.set(currentWorldData, true);
|
||||||
|
CAPTURE_BLOCK_STATES.set(currentWorldData, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<BlockState> getCapturedBlockStatesCopyFolia(SERVER_LEVEL serverLevel) {
|
||||||
|
return getRethrowing(() -> {
|
||||||
|
Object currentWorldData = GET_CURRENT_WORLD_DATA.invoke(serverLevel);
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
var capturedBlockStates = (Map<?, BlockState>) CAPTURED_BLOCK_STATES.invoke(currentWorldData);
|
||||||
|
return new ArrayList<>(capturedBlockStates.values());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void postCaptureBlockStatesFolia(SERVER_LEVEL serverLevel) {
|
||||||
|
runRethrowing(() -> {
|
||||||
|
Object currentWorldData = GET_CURRENT_WORLD_DATA.invoke(serverLevel);
|
||||||
|
CAPTURE_TREE_GENERATION.set(currentWorldData, false);
|
||||||
|
CAPTURE_BLOCK_STATES.set(currentWorldData, false);
|
||||||
|
var capturedBlockStates = (Map<?, ?>) CAPTURED_BLOCK_STATES.invoke(currentWorldData);
|
||||||
|
capturedBlockStates.clear();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract void preCaptureStates(SERVER_LEVEL serverLevel);
|
protected abstract void preCaptureStates(SERVER_LEVEL serverLevel);
|
||||||
|
|
||||||
protected abstract List<BlockState> getCapturedBlockStatesCopy(SERVER_LEVEL serverLevel);
|
protected abstract List<BlockState> getCapturedBlockStatesCopy(SERVER_LEVEL serverLevel);
|
||||||
|
@ -78,7 +78,8 @@ public abstract class StarlightRelighter<SERVER_LEVEL, CHUNK_POS> implements Rel
|
|||||||
LOGGER.warn("Processed {} chunks instead of {}", i, coords.size());
|
LOGGER.warn("Processed {} chunks instead of {}", i, coords.size());
|
||||||
}
|
}
|
||||||
// post process chunks on main thread
|
// post process chunks on main thread
|
||||||
TaskManager.taskManager().task(() -> postProcessChunks(coords));
|
// safe to run globally on Folia as ticket modification is behind a lock
|
||||||
|
TaskManager.taskManager().taskGlobal(() -> postProcessChunks(coords));
|
||||||
// call callback on our own threads
|
// call callback on our own threads
|
||||||
TaskManager.taskManager().async(andThen);
|
TaskManager.taskManager().async(andThen);
|
||||||
};
|
};
|
||||||
@ -99,7 +100,7 @@ public abstract class StarlightRelighter<SERVER_LEVEL, CHUNK_POS> implements Rel
|
|||||||
*/
|
*/
|
||||||
protected void fixLighting(LongSet chunks, Runnable andThen) {
|
protected void fixLighting(LongSet chunks, Runnable andThen) {
|
||||||
Set<CHUNK_POS> coords = convertChunkKeysToChunkPos(chunks);
|
Set<CHUNK_POS> coords = convertChunkKeysToChunkPos(chunks);
|
||||||
TaskManager.taskManager().task(() -> {
|
TaskManager.taskManager().taskGlobal(() -> {
|
||||||
// trigger chunk load and apply ticket on main thread
|
// trigger chunk load and apply ticket on main thread
|
||||||
List<CompletableFuture<?>> futures = chunkLoadFutures(coords);
|
List<CompletableFuture<?>> futures = chunkLoadFutures(coords);
|
||||||
// collect futures and trigger relight once all chunks are loaded
|
// collect futures and trigger relight once all chunks are loaded
|
||||||
|
@ -33,17 +33,22 @@ public class BukkitTaskManager extends TaskManager {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void task(@NotNull final Runnable runnable, @NotNull final Location location) {
|
public void task(@NotNull final Runnable runnable, @NotNull final Location location) {
|
||||||
|
this.plugin.getServer().getScheduler().runTask(this.plugin, runnable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void task(@NotNull final Runnable runnable, @NotNull final World world, final int chunkX, final int chunkZ) {
|
public void task(@NotNull final Runnable runnable, @NotNull final World world, final int chunkX, final int chunkZ) {
|
||||||
|
this.plugin.getServer().getScheduler().runTask(this.plugin, runnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void taskGlobal(final Runnable runnable) {
|
||||||
|
this.plugin.getServer().getGlobalRegionScheduler().run(this.plugin, task -> runnable.run());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void later(@NotNull final Runnable runnable, final Location location, final int delay) {
|
public void later(@NotNull final Runnable runnable, final Location location, final int delay) {
|
||||||
|
this.plugin.getServer().getScheduler().runTaskLater(this.plugin, runnable, delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.fastasyncworldedit.bukkit.util;
|
package com.fastasyncworldedit.bukkit.util;
|
||||||
|
|
||||||
|
import com.fastasyncworldedit.core.util.FoliaSupport;
|
||||||
import com.fastasyncworldedit.core.util.TaskManager;
|
import com.fastasyncworldedit.core.util.TaskManager;
|
||||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||||
@ -9,6 +10,7 @@ import com.sk89q.worldedit.world.World;
|
|||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.lang.invoke.MethodHandle;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.FutureTask;
|
import java.util.concurrent.FutureTask;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@ -16,8 +18,21 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import static java.lang.invoke.MethodHandles.lookup;
|
||||||
|
import static java.lang.invoke.MethodType.methodType;
|
||||||
|
|
||||||
public class FoliaTaskManager extends TaskManager {
|
public class FoliaTaskManager extends TaskManager {
|
||||||
|
|
||||||
|
private final static MethodHandle IS_GLOBAL_TICK_THREAD;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
IS_GLOBAL_TICK_THREAD = lookup().findStatic(Bukkit.class, "isGlobalTickThread", methodType(boolean.class));
|
||||||
|
} catch (NoSuchMethodException | IllegalAccessException e) {
|
||||||
|
throw new AssertionError("Incompatile Folia version", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private final AtomicInteger idCounter = new AtomicInteger();
|
private final AtomicInteger idCounter = new AtomicInteger();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -49,6 +64,11 @@ public class FoliaTaskManager extends TaskManager {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void taskGlobal(final Runnable runnable) {
|
||||||
|
Bukkit.getGlobalRegionScheduler().run(WorldEditPlugin.getInstance(), asConsumer(runnable));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void later(@NotNull final Runnable runnable, final Location location, final int delay) {
|
public void later(@NotNull final Runnable runnable, final Location location, final int delay) {
|
||||||
Bukkit.getRegionScheduler().runDelayed(
|
Bukkit.getRegionScheduler().runDelayed(
|
||||||
@ -80,6 +100,7 @@ public class FoliaTaskManager extends TaskManager {
|
|||||||
if (Bukkit.isOwnedByCurrentRegion(adapt, chunkX, chunkZ)) {
|
if (Bukkit.isOwnedByCurrentRegion(adapt, chunkX, chunkZ)) {
|
||||||
return supplier.get();
|
return supplier.get();
|
||||||
}
|
}
|
||||||
|
ensureOffTickThread();
|
||||||
FutureTask<T> task = new FutureTask<>(supplier::get);
|
FutureTask<T> task = new FutureTask<>(supplier::get);
|
||||||
Bukkit.getRegionScheduler().run(
|
Bukkit.getRegionScheduler().run(
|
||||||
WorldEditPlugin.getInstance(),
|
WorldEditPlugin.getInstance(),
|
||||||
@ -105,6 +126,7 @@ public class FoliaTaskManager extends TaskManager {
|
|||||||
if (Bukkit.isOwnedByCurrentRegion(adapt)) {
|
if (Bukkit.isOwnedByCurrentRegion(adapt)) {
|
||||||
return supplier.get();
|
return supplier.get();
|
||||||
}
|
}
|
||||||
|
ensureOffTickThread();
|
||||||
FutureTask<T> task = new FutureTask<>(supplier::get);
|
FutureTask<T> task = new FutureTask<>(supplier::get);
|
||||||
adapt.getScheduler().execute(WorldEditPlugin.getInstance(), task, null, 0);
|
adapt.getScheduler().execute(WorldEditPlugin.getInstance(), task, null, 0);
|
||||||
try {
|
try {
|
||||||
@ -117,6 +139,9 @@ public class FoliaTaskManager extends TaskManager {
|
|||||||
@Override
|
@Override
|
||||||
public <T> T syncGlobal(final Supplier<T> supplier) {
|
public <T> T syncGlobal(final Supplier<T> supplier) {
|
||||||
// TODO avoid deadlocks (Bukkit.isGlobalTickThread not available at time of writing)
|
// TODO avoid deadlocks (Bukkit.isGlobalTickThread not available at time of writing)
|
||||||
|
if (isGlobalTickThread()) {
|
||||||
|
return supplier.get();
|
||||||
|
}
|
||||||
FutureTask<T> task = new FutureTask<>(supplier::get);
|
FutureTask<T> task = new FutureTask<>(supplier::get);
|
||||||
Bukkit.getGlobalRegionScheduler().run(WorldEditPlugin.getInstance(), asConsumer(task));
|
Bukkit.getGlobalRegionScheduler().run(WorldEditPlugin.getInstance(), asConsumer(task));
|
||||||
try {
|
try {
|
||||||
@ -126,12 +151,21 @@ public class FoliaTaskManager extends TaskManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isGlobalTickThread() {
|
||||||
|
return FoliaSupport.getRethrowing(() -> (boolean) IS_GLOBAL_TICK_THREAD.invokeExact());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureOffTickThread() {
|
||||||
|
if (FoliaSupport.isTickThread()) {
|
||||||
|
throw new IllegalStateException("Expected to be off tick thread");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private int ticksToMs(int ticks) {
|
private int ticksToMs(int ticks) {
|
||||||
// 1 tick = 50ms
|
// 1 tick = 50ms
|
||||||
return ticks * 50;
|
return ticks * 50;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private <T> T fail(String message) {
|
private <T> T fail(String message) {
|
||||||
throw new UnsupportedOperationException(message);
|
throw new UnsupportedOperationException(message);
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ package com.sk89q.worldedit.bukkit;
|
|||||||
|
|
||||||
import com.fastasyncworldedit.core.configuration.Caption;
|
import com.fastasyncworldedit.core.configuration.Caption;
|
||||||
import com.fastasyncworldedit.core.configuration.Settings;
|
import com.fastasyncworldedit.core.configuration.Settings;
|
||||||
|
import com.fastasyncworldedit.core.util.FoliaSupport;
|
||||||
import com.fastasyncworldedit.core.util.TaskManager;
|
import com.fastasyncworldedit.core.util.TaskManager;
|
||||||
import com.sk89q.util.StringUtil;
|
import com.sk89q.util.StringUtil;
|
||||||
import com.sk89q.wepif.VaultResolver;
|
import com.sk89q.wepif.VaultResolver;
|
||||||
@ -52,6 +53,7 @@ import com.sk89q.worldedit.world.block.BlockStateHolder;
|
|||||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||||
import com.sk89q.worldedit.world.gamemode.GameMode;
|
import com.sk89q.worldedit.world.gamemode.GameMode;
|
||||||
import com.sk89q.worldedit.world.gamemode.GameModes;
|
import com.sk89q.worldedit.world.gamemode.GameModes;
|
||||||
|
import io.papermc.lib.PaperLib;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
@ -69,7 +71,9 @@ import java.util.HashMap;
|
|||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class BukkitPlayer extends AbstractPlayerActor {
|
public class BukkitPlayer extends AbstractPlayerActor {
|
||||||
|
|
||||||
@ -239,16 +243,21 @@ public class BukkitPlayer extends AbstractPlayerActor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
org.bukkit.World finalWorld = world;
|
org.bukkit.World finalWorld = world;
|
||||||
|
final Location target = new Location(finalWorld, pos.getX(), pos.getY(), pos.getZ(), yaw, pitch);
|
||||||
|
Supplier<CompletableFuture<Boolean>> teleport = () -> PaperLib.teleportAsync(player, target);
|
||||||
|
if (FoliaSupport.isTickThread()) {
|
||||||
|
teleport.get().whenComplete((b, thr) -> {
|
||||||
|
if (thr != null) {
|
||||||
|
thr.printStackTrace();
|
||||||
|
}
|
||||||
|
if (!b) {
|
||||||
|
player.sendMessage("Teleportation failed");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return true; // TODO this might not be correct
|
||||||
|
}
|
||||||
|
return TaskManager.taskManager().syncWith(() -> teleport.get().join(), this);
|
||||||
//FAWE end
|
//FAWE end
|
||||||
// TODO async teleport?
|
|
||||||
return TaskManager.taskManager().syncWith(() -> player.teleport(new Location(
|
|
||||||
finalWorld,
|
|
||||||
pos.getX(),
|
|
||||||
pos.getY(),
|
|
||||||
pos.getZ(),
|
|
||||||
yaw,
|
|
||||||
pitch
|
|
||||||
)), this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -35,4 +35,35 @@ public final class FoliaSupport {
|
|||||||
public static boolean isTickThread() {
|
public static boolean isTickThread() {
|
||||||
return TICK_THREAD_CLASS.isInstance(Thread.currentThread());
|
return TICK_THREAD_CLASS.isInstance(Thread.currentThread());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface ThrowingSupplier<T> {
|
||||||
|
|
||||||
|
T get() throws Throwable;
|
||||||
|
|
||||||
|
}
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface ThrowingRunnable {
|
||||||
|
|
||||||
|
void run() throws Throwable;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void runRethrowing(ThrowingRunnable runnable) {
|
||||||
|
getRethrowing(() -> {
|
||||||
|
runnable.run();
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T getRethrowing(ThrowingSupplier<T> supplier) {
|
||||||
|
try {
|
||||||
|
return supplier.get();
|
||||||
|
} catch (RuntimeException | Error e) {
|
||||||
|
throw e;
|
||||||
|
} catch (Throwable e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,6 +73,8 @@ public abstract class TaskManager {
|
|||||||
|
|
||||||
public abstract void task(@Nonnull final Runnable runnable, @Nonnull World world, int chunkX, int chunkZ);
|
public abstract void task(@Nonnull final Runnable runnable, @Nonnull World world, int chunkX, int chunkZ);
|
||||||
|
|
||||||
|
public abstract void taskGlobal(Runnable runnable);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the public ForkJoinPool.
|
* Get the public ForkJoinPool.
|
||||||
* - ONLY SUBMIT SHORT LIVED TASKS<br>
|
* - ONLY SUBMIT SHORT LIVED TASKS<br>
|
||||||
|
@ -40,7 +40,7 @@ public class AsyncPlayer extends PlayerProxy {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void findFreePosition(Location searchPos) {
|
public void findFreePosition(Location searchPos) {
|
||||||
TaskManager.taskManager().syncAt(new RunnableVal<Boolean>() {
|
TaskManager.taskManager().task(new RunnableVal<Boolean>() {
|
||||||
@Override
|
@Override
|
||||||
public void run(Boolean value) {
|
public void run(Boolean value) {
|
||||||
getBasePlayer().findFreePosition(searchPos);
|
getBasePlayer().findFreePosition(searchPos);
|
||||||
@ -50,7 +50,7 @@ public class AsyncPlayer extends PlayerProxy {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setOnGround(Location searchPos) {
|
public void setOnGround(Location searchPos) {
|
||||||
TaskManager.taskManager().syncAt(new RunnableVal<Boolean>() {
|
TaskManager.taskManager().task(new RunnableVal<Boolean>() {
|
||||||
@Override
|
@Override
|
||||||
public void run(Boolean value) {
|
public void run(Boolean value) {
|
||||||
getBasePlayer().setOnGround(searchPos);
|
getBasePlayer().setOnGround(searchPos);
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren