Mirror von
https://github.com/IntellectualSites/FastAsyncWorldEdit.git
synchronisiert 2024-11-16 16:10:07 +01:00
Apply to all versions
Dieser Commit ist enthalten in:
Ursprung
c0a9bc6d97
Commit
9ef74ef7f4
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
@ -57,7 +57,6 @@ import net.minecraft.world.level.chunk.PalettedContainer;
|
|||||||
import net.minecraft.world.level.chunk.SingleValuePalette;
|
import net.minecraft.world.level.chunk.SingleValuePalette;
|
||||||
import net.minecraft.world.level.entity.PersistentEntitySectionManager;
|
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.craftbukkit.v1_20_R2.CraftChunk;
|
import org.bukkit.craftbukkit.v1_20_R2.CraftChunk;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
@ -79,9 +78,8 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.concurrent.TimeoutException;
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
import static java.lang.invoke.MethodType.methodType;
|
import static java.lang.invoke.MethodType.methodType;
|
||||||
@ -276,12 +274,49 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
e.printStackTrace();
|
LOGGER.error("Error apply DelegateSemaphore", e);
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LevelChunk ensureLoaded(ServerLevel serverLevel, int chunkX, int chunkZ) {
|
public static CompletableFuture<LevelChunk> ensureLoaded(ServerLevel serverLevel, int chunkX, int chunkZ) {
|
||||||
|
LevelChunk levelChunk = getChunkImmediatelyAsync(serverLevel, chunkX, chunkZ);
|
||||||
|
if (levelChunk != null) {
|
||||||
|
return CompletableFuture.completedFuture(levelChunk);
|
||||||
|
}
|
||||||
|
if (PaperLib.isPaper()) {
|
||||||
|
CompletableFuture<LevelChunk> future = serverLevel
|
||||||
|
.getWorld()
|
||||||
|
.getChunkAtAsync(chunkX, chunkZ, true, true)
|
||||||
|
.thenApply(chunk -> {
|
||||||
|
addTicket(serverLevel, chunkX, chunkZ);
|
||||||
|
try {
|
||||||
|
return (LevelChunk) CRAFT_CHUNK_GET_HANDLE.invoke(chunk);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
LOGGER.error("Could not asynchronously load chunk at {},{}", chunkX, chunkZ, e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
if (!future.isCompletedExceptionally() || (future.isDone() && future.get() != null)) {
|
||||||
|
return future;
|
||||||
|
}
|
||||||
|
Throwable t = future.exceptionNow();
|
||||||
|
LOGGER.error("Asynchronous chunk load at {},{} exceptionally completed immediately", chunkX, chunkZ, t);
|
||||||
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
|
LOGGER.error(
|
||||||
|
"Unexpected error when getting completed future at chunk {},{}. Returning to default.",
|
||||||
|
chunkX,
|
||||||
|
chunkZ,
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return CompletableFuture.supplyAsync(() -> TaskManager.taskManager().sync(() -> serverLevel.getChunk(chunkX, chunkZ)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static @Nullable LevelChunk getChunkImmediatelyAsync(ServerLevel serverLevel, int chunkX, int chunkZ) {
|
||||||
if (!PaperLib.isPaper()) {
|
if (!PaperLib.isPaper()) {
|
||||||
LevelChunk nmsChunk = serverLevel.getChunkSource().getChunk(chunkX, chunkZ, false);
|
LevelChunk nmsChunk = serverLevel.getChunkSource().getChunk(chunkX, chunkZ, false);
|
||||||
if (nmsChunk != null) {
|
if (nmsChunk != null) {
|
||||||
@ -290,6 +325,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
if (Fawe.isMainThread()) {
|
if (Fawe.isMainThread()) {
|
||||||
return serverLevel.getChunk(chunkX, chunkZ);
|
return serverLevel.getChunk(chunkX, chunkZ);
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
} else {
|
} else {
|
||||||
LevelChunk nmsChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately(chunkX, chunkZ);
|
LevelChunk nmsChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately(chunkX, chunkZ);
|
||||||
if (nmsChunk != null) {
|
if (nmsChunk != null) {
|
||||||
@ -305,30 +341,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
if (Fawe.isMainThread()) {
|
if (Fawe.isMainThread()) {
|
||||||
return serverLevel.getChunk(chunkX, chunkZ);
|
return serverLevel.getChunk(chunkX, chunkZ);
|
||||||
}
|
}
|
||||||
CompletableFuture<org.bukkit.Chunk> future = serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true);
|
return null;
|
||||||
try {
|
|
||||||
CraftChunk chunk;
|
|
||||||
try {
|
|
||||||
chunk = (CraftChunk) future.get(10, TimeUnit.SECONDS);
|
|
||||||
} catch (TimeoutException e) {
|
|
||||||
String world = serverLevel.getWorld().getName();
|
|
||||||
// We've already taken 10 seconds we can afford to wait a little here.
|
|
||||||
boolean loaded = TaskManager.taskManager().sync(() -> Bukkit.getWorld(world) != null);
|
|
||||||
if (loaded) {
|
|
||||||
LOGGER.warn("Chunk {},{} failed to load in 10 seconds in world {}. Retrying...", chunkX, chunkZ, world);
|
|
||||||
// Retry chunk load
|
|
||||||
chunk = (CraftChunk) serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true).get();
|
|
||||||
} else {
|
|
||||||
throw new UnsupportedOperationException("Cannot load chunk from unloaded world " + world + "!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
addTicket(serverLevel, chunkX, chunkZ);
|
|
||||||
return (LevelChunk) CRAFT_CHUNK_GET_HANDLE.invoke(chunk);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return TaskManager.taskManager().sync(() -> serverLevel.getChunk(chunkX, chunkZ));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void addTicket(ServerLevel serverLevel, int chunkX, int chunkZ) {
|
private static void addTicket(ServerLevel serverLevel, int chunkX, int chunkZ) {
|
||||||
@ -672,7 +686,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
}
|
}
|
||||||
methodremoveTickingBlockEntity.invoke(levelChunk, beacon.getBlockPos());
|
methodremoveTickingBlockEntity.invoke(levelChunk, beacon.getBlockPos());
|
||||||
} catch (Throwable throwable) {
|
} catch (Throwable throwable) {
|
||||||
throwable.printStackTrace();
|
LOGGER.error("Error removing beacon", throwable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
@ -57,7 +57,6 @@ import net.minecraft.world.level.chunk.PalettedContainer;
|
|||||||
import net.minecraft.world.level.chunk.SingleValuePalette;
|
import net.minecraft.world.level.chunk.SingleValuePalette;
|
||||||
import net.minecraft.world.level.entity.PersistentEntitySectionManager;
|
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.craftbukkit.v1_20_R3.CraftChunk;
|
import org.bukkit.craftbukkit.v1_20_R3.CraftChunk;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
@ -79,9 +78,8 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.concurrent.TimeoutException;
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
import static java.lang.invoke.MethodType.methodType;
|
import static java.lang.invoke.MethodType.methodType;
|
||||||
@ -276,12 +274,48 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
e.printStackTrace();
|
LOGGER.error("Error apply DelegateSemaphore", e);
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LevelChunk ensureLoaded(ServerLevel serverLevel, int chunkX, int chunkZ) {
|
public static CompletableFuture<LevelChunk> ensureLoaded(ServerLevel serverLevel, int chunkX, int chunkZ) {
|
||||||
|
LevelChunk levelChunk = getChunkImmediatelyAsync(serverLevel, chunkX, chunkZ);
|
||||||
|
if (levelChunk != null) {
|
||||||
|
return CompletableFuture.completedFuture(levelChunk);
|
||||||
|
}
|
||||||
|
if (PaperLib.isPaper()) {
|
||||||
|
CompletableFuture<LevelChunk> future = serverLevel
|
||||||
|
.getWorld()
|
||||||
|
.getChunkAtAsync(chunkX, chunkZ, true, true)
|
||||||
|
.thenApply(chunk -> {
|
||||||
|
addTicket(serverLevel, chunkX, chunkZ);
|
||||||
|
try {
|
||||||
|
return (LevelChunk) CRAFT_CHUNK_GET_HANDLE.invoke(chunk);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
LOGGER.error("Could not asynchronously load chunk at {},{}", chunkX, chunkZ, e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
if (!future.isCompletedExceptionally() || (future.isDone() && future.get() != null)) {
|
||||||
|
return future;
|
||||||
|
}
|
||||||
|
Throwable t = future.exceptionNow();
|
||||||
|
LOGGER.error("Asynchronous chunk load at {},{} exceptionally completed immediately", chunkX, chunkZ, t);
|
||||||
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
|
LOGGER.error(
|
||||||
|
"Unexpected error when getting completed future at chunk {},{}. Returning to default.",
|
||||||
|
chunkX,
|
||||||
|
chunkZ,
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return CompletableFuture.supplyAsync(() -> TaskManager.taskManager().sync(() -> serverLevel.getChunk(chunkX, chunkZ)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @Nullable LevelChunk getChunkImmediatelyAsync(ServerLevel serverLevel, int chunkX, int chunkZ) {
|
||||||
if (!PaperLib.isPaper()) {
|
if (!PaperLib.isPaper()) {
|
||||||
LevelChunk nmsChunk = serverLevel.getChunkSource().getChunk(chunkX, chunkZ, false);
|
LevelChunk nmsChunk = serverLevel.getChunkSource().getChunk(chunkX, chunkZ, false);
|
||||||
if (nmsChunk != null) {
|
if (nmsChunk != null) {
|
||||||
@ -290,6 +324,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
if (Fawe.isMainThread()) {
|
if (Fawe.isMainThread()) {
|
||||||
return serverLevel.getChunk(chunkX, chunkZ);
|
return serverLevel.getChunk(chunkX, chunkZ);
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
} else {
|
} else {
|
||||||
LevelChunk nmsChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately(chunkX, chunkZ);
|
LevelChunk nmsChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately(chunkX, chunkZ);
|
||||||
if (nmsChunk != null) {
|
if (nmsChunk != null) {
|
||||||
@ -305,30 +340,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
if (Fawe.isMainThread()) {
|
if (Fawe.isMainThread()) {
|
||||||
return serverLevel.getChunk(chunkX, chunkZ);
|
return serverLevel.getChunk(chunkX, chunkZ);
|
||||||
}
|
}
|
||||||
CompletableFuture<org.bukkit.Chunk> future = serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true);
|
return null;
|
||||||
try {
|
|
||||||
CraftChunk chunk;
|
|
||||||
try {
|
|
||||||
chunk = (CraftChunk) future.get(10, TimeUnit.SECONDS);
|
|
||||||
} catch (TimeoutException e) {
|
|
||||||
String world = serverLevel.getWorld().getName();
|
|
||||||
// We've already taken 10 seconds we can afford to wait a little here.
|
|
||||||
boolean loaded = TaskManager.taskManager().sync(() -> Bukkit.getWorld(world) != null);
|
|
||||||
if (loaded) {
|
|
||||||
LOGGER.warn("Chunk {},{} failed to load in 10 seconds in world {}. Retrying...", chunkX, chunkZ, world);
|
|
||||||
// Retry chunk load
|
|
||||||
chunk = (CraftChunk) serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true).get();
|
|
||||||
} else {
|
|
||||||
throw new UnsupportedOperationException("Cannot load chunk from unloaded world " + world + "!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
addTicket(serverLevel, chunkX, chunkZ);
|
|
||||||
return (LevelChunk) CRAFT_CHUNK_GET_HANDLE.invoke(chunk);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return TaskManager.taskManager().sync(() -> serverLevel.getChunk(chunkX, chunkZ));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void addTicket(ServerLevel serverLevel, int chunkX, int chunkZ) {
|
private static void addTicket(ServerLevel serverLevel, int chunkX, int chunkZ) {
|
||||||
@ -672,7 +685,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
}
|
}
|
||||||
methodremoveTickingBlockEntity.invoke(levelChunk, beacon.getBlockPos());
|
methodremoveTickingBlockEntity.invoke(levelChunk, beacon.getBlockPos());
|
||||||
} catch (Throwable throwable) {
|
} catch (Throwable throwable) {
|
||||||
throwable.printStackTrace();
|
LOGGER.error("Error removing beacon", throwable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
@ -57,7 +57,6 @@ import net.minecraft.world.level.chunk.SingleValuePalette;
|
|||||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||||
import net.minecraft.world.level.entity.PersistentEntitySectionManager;
|
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.craftbukkit.CraftChunk;
|
import org.bukkit.craftbukkit.CraftChunk;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
@ -79,9 +78,8 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.concurrent.TimeoutException;
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
import static java.lang.invoke.MethodType.methodType;
|
import static java.lang.invoke.MethodType.methodType;
|
||||||
@ -276,12 +274,48 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
e.printStackTrace();
|
LOGGER.error("Error apply DelegateSemaphore", e);
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LevelChunk ensureLoaded(ServerLevel serverLevel, int chunkX, int chunkZ) {
|
public static CompletableFuture<LevelChunk> ensureLoaded(ServerLevel serverLevel, int chunkX, int chunkZ) {
|
||||||
|
LevelChunk levelChunk = getChunkImmediatelyAsync(serverLevel, chunkX, chunkZ);
|
||||||
|
if (levelChunk != null) {
|
||||||
|
return CompletableFuture.completedFuture(levelChunk);
|
||||||
|
}
|
||||||
|
if (PaperLib.isPaper()) {
|
||||||
|
CompletableFuture<LevelChunk> future = serverLevel
|
||||||
|
.getWorld()
|
||||||
|
.getChunkAtAsync(chunkX, chunkZ, true, true)
|
||||||
|
.thenApply(chunk -> {
|
||||||
|
addTicket(serverLevel, chunkX, chunkZ);
|
||||||
|
try {
|
||||||
|
return (LevelChunk) CRAFT_CHUNK_GET_HANDLE.invoke(chunk);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
LOGGER.error("Could not asynchronously load chunk at {},{}", chunkX, chunkZ, e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
if (!future.isCompletedExceptionally() || (future.isDone() && future.get() != null)) {
|
||||||
|
return future;
|
||||||
|
}
|
||||||
|
Throwable t = future.exceptionNow();
|
||||||
|
LOGGER.error("Asynchronous chunk load at {},{} exceptionally completed immediately", chunkX, chunkZ, t);
|
||||||
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
|
LOGGER.error(
|
||||||
|
"Unexpected error when getting completed future at chunk {},{}. Returning to default.",
|
||||||
|
chunkX,
|
||||||
|
chunkZ,
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return CompletableFuture.supplyAsync(() -> TaskManager.taskManager().sync(() -> serverLevel.getChunk(chunkX, chunkZ)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @Nullable LevelChunk getChunkImmediatelyAsync(ServerLevel serverLevel, int chunkX, int chunkZ) {
|
||||||
if (!PaperLib.isPaper()) {
|
if (!PaperLib.isPaper()) {
|
||||||
LevelChunk nmsChunk = serverLevel.getChunkSource().getChunk(chunkX, chunkZ, false);
|
LevelChunk nmsChunk = serverLevel.getChunkSource().getChunk(chunkX, chunkZ, false);
|
||||||
if (nmsChunk != null) {
|
if (nmsChunk != null) {
|
||||||
@ -290,6 +324,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
if (Fawe.isMainThread()) {
|
if (Fawe.isMainThread()) {
|
||||||
return serverLevel.getChunk(chunkX, chunkZ);
|
return serverLevel.getChunk(chunkX, chunkZ);
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
} else {
|
} else {
|
||||||
LevelChunk nmsChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately(chunkX, chunkZ);
|
LevelChunk nmsChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately(chunkX, chunkZ);
|
||||||
if (nmsChunk != null) {
|
if (nmsChunk != null) {
|
||||||
@ -305,30 +340,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
if (Fawe.isMainThread()) {
|
if (Fawe.isMainThread()) {
|
||||||
return serverLevel.getChunk(chunkX, chunkZ);
|
return serverLevel.getChunk(chunkX, chunkZ);
|
||||||
}
|
}
|
||||||
CompletableFuture<org.bukkit.Chunk> future = serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true);
|
return null;
|
||||||
try {
|
|
||||||
CraftChunk chunk;
|
|
||||||
try {
|
|
||||||
chunk = (CraftChunk) future.get(10, TimeUnit.SECONDS);
|
|
||||||
} catch (TimeoutException e) {
|
|
||||||
String world = serverLevel.getWorld().getName();
|
|
||||||
// We've already taken 10 seconds we can afford to wait a little here.
|
|
||||||
boolean loaded = TaskManager.taskManager().sync(() -> Bukkit.getWorld(world) != null);
|
|
||||||
if (loaded) {
|
|
||||||
LOGGER.warn("Chunk {},{} failed to load in 10 seconds in world {}. Retrying...", chunkX, chunkZ, world);
|
|
||||||
// Retry chunk load
|
|
||||||
chunk = (CraftChunk) serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true).get();
|
|
||||||
} else {
|
|
||||||
throw new UnsupportedOperationException("Cannot load chunk from unloaded world " + world + "!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
addTicket(serverLevel, chunkX, chunkZ);
|
|
||||||
return (LevelChunk) CRAFT_CHUNK_GET_HANDLE.invoke(chunk);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return TaskManager.taskManager().sync(() -> serverLevel.getChunk(chunkX, chunkZ));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void addTicket(ServerLevel serverLevel, int chunkX, int chunkZ) {
|
private static void addTicket(ServerLevel serverLevel, int chunkX, int chunkZ) {
|
||||||
@ -672,7 +685,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
}
|
}
|
||||||
methodremoveTickingBlockEntity.invoke(levelChunk, beacon.getBlockPos());
|
methodremoveTickingBlockEntity.invoke(levelChunk, beacon.getBlockPos());
|
||||||
} catch (Throwable throwable) {
|
} catch (Throwable throwable) {
|
||||||
throwable.printStackTrace();
|
LOGGER.error("Error removing beacon", throwable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,11 +452,11 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
final int finalCopyKey = copyKey;
|
final int finalCopyKey = copyKey;
|
||||||
// Run immediately if possible
|
// Run immediately if possible
|
||||||
if (chunk != null) {
|
if (chunk != null) {
|
||||||
return internalCall(set, finalizer, finalCopyKey, chunk, nmsWorld);
|
return tryWrappedInternalCall(set, finalizer, finalCopyKey, chunk, nmsWorld);
|
||||||
}
|
}
|
||||||
// Submit via the STQE as that will help handle excessive queuing by waiting for the submission count to fall below the
|
// Submit via the STQE as that will help handle excessive queuing by waiting for the submission count to fall below the
|
||||||
// target size
|
// target size
|
||||||
nmsChunkFuture.thenApply(nmsChunk -> owner.submitTaskUnchecked(() -> (T) internalCall(
|
nmsChunkFuture.thenApply(nmsChunk -> owner.submitTaskUnchecked(() -> (T) tryWrappedInternalCall(
|
||||||
set,
|
set,
|
||||||
finalizer,
|
finalizer,
|
||||||
finalCopyKey,
|
finalCopyKey,
|
||||||
@ -469,7 +469,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
return (T) (Future) CompletableFuture.completedFuture(null);
|
return (T) (Future) CompletableFuture.completedFuture(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T extends Future<T>> T internalCall(
|
private <T extends Future<T>> T tryWrappedInternalCall(
|
||||||
IChunkSet set,
|
IChunkSet set,
|
||||||
Runnable finalizer,
|
Runnable finalizer,
|
||||||
int copyKey,
|
int copyKey,
|
||||||
@ -477,465 +477,477 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
ServerLevel nmsWorld
|
ServerLevel nmsWorld
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
PaperweightGetBlocks_Copy copy = createCopy ? new PaperweightGetBlocks_Copy(nmsChunk) : null;
|
return internalCall(set, finalizer, copyKey, nmsChunk, nmsWorld);
|
||||||
if (createCopy) {
|
|
||||||
if (copies.containsKey(copyKey)) {
|
|
||||||
throw new IllegalStateException("Copy key already used.");
|
|
||||||
}
|
|
||||||
copies.put(copyKey, copy);
|
|
||||||
}
|
|
||||||
// Remove existing tiles. Create a copy so that we can remove blocks
|
|
||||||
Map<BlockPos, BlockEntity> chunkTiles = new HashMap<>(nmsChunk.getBlockEntities());
|
|
||||||
List<BlockEntity> beacons = null;
|
|
||||||
if (!chunkTiles.isEmpty()) {
|
|
||||||
for (Map.Entry<BlockPos, BlockEntity> entry : chunkTiles.entrySet()) {
|
|
||||||
final BlockPos pos = entry.getKey();
|
|
||||||
final int lx = pos.getX() & 15;
|
|
||||||
final int ly = pos.getY();
|
|
||||||
final int lz = pos.getZ() & 15;
|
|
||||||
final int layer = ly >> 4;
|
|
||||||
if (!set.hasSection(layer)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ordinal = set.getBlock(lx, ly, lz).getOrdinal();
|
|
||||||
if (ordinal != BlockTypesCache.ReservedIDs.__RESERVED__) {
|
|
||||||
BlockEntity tile = entry.getValue();
|
|
||||||
if (PaperLib.isPaper() && tile instanceof BeaconBlockEntity) {
|
|
||||||
if (beacons == null) {
|
|
||||||
beacons = new ArrayList<>();
|
|
||||||
}
|
|
||||||
beacons.add(tile);
|
|
||||||
PaperweightPlatformAdapter.removeBeacon(tile, nmsChunk);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
nmsChunk.removeBlockEntity(tile.getBlockPos());
|
|
||||||
if (createCopy) {
|
|
||||||
copy.storeTile(tile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
final BiomeType[][] biomes = set.getBiomes();
|
|
||||||
|
|
||||||
int bitMask = 0;
|
|
||||||
synchronized (nmsChunk) {
|
|
||||||
LevelChunkSection[] levelChunkSections = nmsChunk.getSections();
|
|
||||||
|
|
||||||
for (int layerNo = getMinSectionPosition(); layerNo <= getMaxSectionPosition(); layerNo++) {
|
|
||||||
|
|
||||||
int getSectionIndex = layerNo - getMinSectionPosition();
|
|
||||||
int setSectionIndex = layerNo - set.getMinSectionPosition();
|
|
||||||
|
|
||||||
if (!set.hasSection(layerNo)) {
|
|
||||||
// No blocks, but might be biomes present. Handle this lazily.
|
|
||||||
if (biomes == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (layerNo < set.getMinSectionPosition() || layerNo > set.getMaxSectionPosition()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (biomes[setSectionIndex] != null) {
|
|
||||||
synchronized (super.sectionLocks[getSectionIndex]) {
|
|
||||||
LevelChunkSection existingSection = levelChunkSections[getSectionIndex];
|
|
||||||
if (createCopy && existingSection != null) {
|
|
||||||
copy.storeBiomes(getSectionIndex, existingSection.getBiomes());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (existingSection == null) {
|
|
||||||
PalettedContainer<Holder<Biome>> biomeData = PaperweightPlatformAdapter.getBiomePalettedContainer(
|
|
||||||
biomes[setSectionIndex],
|
|
||||||
biomeHolderIdMap
|
|
||||||
);
|
|
||||||
LevelChunkSection newSection = PaperweightPlatformAdapter.newChunkSection(
|
|
||||||
layerNo,
|
|
||||||
new char[4096],
|
|
||||||
adapter,
|
|
||||||
biomeRegistry,
|
|
||||||
biomeData
|
|
||||||
);
|
|
||||||
if (PaperweightPlatformAdapter.setSectionAtomic(
|
|
||||||
nmsWorld.getWorld().getName(),
|
|
||||||
chunkPos,
|
|
||||||
levelChunkSections,
|
|
||||||
null,
|
|
||||||
newSection,
|
|
||||||
getSectionIndex
|
|
||||||
)) {
|
|
||||||
updateGet(nmsChunk, levelChunkSections, newSection, new char[4096], getSectionIndex);
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
existingSection = levelChunkSections[getSectionIndex];
|
|
||||||
if (existingSection == null) {
|
|
||||||
LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ,
|
|
||||||
getSectionIndex
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
PalettedContainer<Holder<Biome>> paletteBiomes = setBiomesToPalettedContainer(
|
|
||||||
biomes,
|
|
||||||
setSectionIndex,
|
|
||||||
existingSection.getBiomes()
|
|
||||||
);
|
|
||||||
if (paletteBiomes != null) {
|
|
||||||
PaperweightPlatformAdapter.setBiomesToChunkSection(existingSection, paletteBiomes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
bitMask |= 1 << getSectionIndex;
|
|
||||||
|
|
||||||
// setArr is modified by PaperweightPlatformAdapter#newChunkSection. This is in order to write changes to
|
|
||||||
// this chunk GET when #updateGet is called. Future dords, please listen this time.
|
|
||||||
char[] tmp = set.load(layerNo);
|
|
||||||
char[] setArr = new char[tmp.length];
|
|
||||||
System.arraycopy(tmp, 0, setArr, 0, tmp.length);
|
|
||||||
|
|
||||||
// synchronise on internal section to avoid circular locking with a continuing edit if the chunk was
|
|
||||||
// submitted to keep loaded internal chunks to queue target size.
|
|
||||||
synchronized (super.sectionLocks[getSectionIndex]) {
|
|
||||||
|
|
||||||
LevelChunkSection newSection;
|
|
||||||
LevelChunkSection existingSection = levelChunkSections[getSectionIndex];
|
|
||||||
// Don't attempt to tick section whilst we're editing
|
|
||||||
if (existingSection != null) {
|
|
||||||
PaperweightPlatformAdapter.clearCounts(existingSection);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (createCopy) {
|
|
||||||
char[] tmpLoad = loadPrivately(layerNo);
|
|
||||||
char[] copyArr = new char[4096];
|
|
||||||
System.arraycopy(tmpLoad, 0, copyArr, 0, 4096);
|
|
||||||
copy.storeSection(getSectionIndex, copyArr);
|
|
||||||
if (biomes != null && existingSection != null) {
|
|
||||||
copy.storeBiomes(getSectionIndex, existingSection.getBiomes());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (existingSection == null) {
|
|
||||||
PalettedContainer<Holder<Biome>> biomeData = biomes == null ? new PalettedContainer<>(
|
|
||||||
biomeHolderIdMap,
|
|
||||||
biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)),
|
|
||||||
PalettedContainer.Strategy.SECTION_BIOMES
|
|
||||||
) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap);
|
|
||||||
newSection = PaperweightPlatformAdapter.newChunkSection(
|
|
||||||
layerNo,
|
|
||||||
setArr,
|
|
||||||
adapter,
|
|
||||||
biomeRegistry,
|
|
||||||
biomeData
|
|
||||||
);
|
|
||||||
if (PaperweightPlatformAdapter.setSectionAtomic(
|
|
||||||
nmsWorld.getWorld().getName(),
|
|
||||||
chunkPos,
|
|
||||||
levelChunkSections,
|
|
||||||
null,
|
|
||||||
newSection,
|
|
||||||
getSectionIndex
|
|
||||||
)) {
|
|
||||||
updateGet(nmsChunk, levelChunkSections, newSection, setArr, getSectionIndex);
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
existingSection = levelChunkSections[getSectionIndex];
|
|
||||||
if (existingSection == null) {
|
|
||||||
LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ,
|
|
||||||
getSectionIndex
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//ensure that the server doesn't try to tick the chunksection while we're editing it. (Again)
|
|
||||||
PaperweightPlatformAdapter.clearCounts(existingSection);
|
|
||||||
DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(existingSection);
|
|
||||||
|
|
||||||
// Synchronize to prevent further acquisitions
|
|
||||||
synchronized (lock) {
|
|
||||||
lock.acquire(); // Wait until we have the lock
|
|
||||||
lock.release();
|
|
||||||
try {
|
|
||||||
sectionLock.writeLock().lock();
|
|
||||||
if (this.getChunk() != nmsChunk) {
|
|
||||||
this.levelChunk = nmsChunk;
|
|
||||||
this.sections = null;
|
|
||||||
this.reset();
|
|
||||||
} else if (existingSection != getSections(false)[getSectionIndex]) {
|
|
||||||
this.sections[getSectionIndex] = existingSection;
|
|
||||||
this.reset();
|
|
||||||
} else if (!Arrays.equals(
|
|
||||||
update(getSectionIndex, new char[4096], true),
|
|
||||||
loadPrivately(layerNo)
|
|
||||||
)) {
|
|
||||||
this.reset(layerNo);
|
|
||||||
/*} else if (lock.isModified()) {
|
|
||||||
this.reset(layerNo);*/
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
sectionLock.writeLock().unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
PalettedContainer<Holder<Biome>> biomeData = setBiomesToPalettedContainer(
|
|
||||||
biomes,
|
|
||||||
setSectionIndex,
|
|
||||||
existingSection.getBiomes()
|
|
||||||
);
|
|
||||||
|
|
||||||
newSection = PaperweightPlatformAdapter.newChunkSection(
|
|
||||||
layerNo,
|
|
||||||
this::loadPrivately,
|
|
||||||
setArr,
|
|
||||||
adapter,
|
|
||||||
biomeRegistry,
|
|
||||||
biomeData != null ? biomeData : (PalettedContainer<Holder<Biome>>) existingSection.getBiomes()
|
|
||||||
);
|
|
||||||
if (!PaperweightPlatformAdapter.setSectionAtomic(
|
|
||||||
nmsWorld.getWorld().getName(),
|
|
||||||
chunkPos,
|
|
||||||
levelChunkSections,
|
|
||||||
existingSection,
|
|
||||||
newSection,
|
|
||||||
getSectionIndex
|
|
||||||
)) {
|
|
||||||
LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ,
|
|
||||||
getSectionIndex
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
updateGet(nmsChunk, levelChunkSections, newSection, setArr, getSectionIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<HeightMapType, int[]> heightMaps = set.getHeightMaps();
|
|
||||||
for (Map.Entry<HeightMapType, int[]> entry : heightMaps.entrySet()) {
|
|
||||||
PaperweightGetBlocks.this.setHeightmapToGet(entry.getKey(), entry.getValue());
|
|
||||||
}
|
|
||||||
PaperweightGetBlocks.this.setLightingToGet(
|
|
||||||
set.getLight(),
|
|
||||||
set.getMinSectionPosition(),
|
|
||||||
set.getMaxSectionPosition()
|
|
||||||
);
|
|
||||||
PaperweightGetBlocks.this.setSkyLightingToGet(
|
|
||||||
set.getSkyLight(),
|
|
||||||
set.getMinSectionPosition(),
|
|
||||||
set.getMaxSectionPosition()
|
|
||||||
);
|
|
||||||
|
|
||||||
Runnable[] syncTasks = null;
|
|
||||||
|
|
||||||
int bx = chunkX << 4;
|
|
||||||
int bz = chunkZ << 4;
|
|
||||||
|
|
||||||
// Call beacon deactivate events here synchronously
|
|
||||||
// list will be null on spigot, so this is an implicit isPaper check
|
|
||||||
if (beacons != null && !beacons.isEmpty()) {
|
|
||||||
final List<BlockEntity> finalBeacons = beacons;
|
|
||||||
|
|
||||||
syncTasks = new Runnable[4];
|
|
||||||
|
|
||||||
syncTasks[3] = () -> {
|
|
||||||
for (BlockEntity beacon : finalBeacons) {
|
|
||||||
BeaconBlockEntity.playSound(beacon.getLevel(), beacon.getBlockPos(), SoundEvents.BEACON_DEACTIVATE);
|
|
||||||
new BeaconDeactivatedEvent(CraftBlock.at(beacon.getLevel(), beacon.getBlockPos())).callEvent();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
Set<UUID> entityRemoves = set.getEntityRemoves();
|
|
||||||
if (entityRemoves != null && !entityRemoves.isEmpty()) {
|
|
||||||
if (syncTasks == null) {
|
|
||||||
syncTasks = new Runnable[3];
|
|
||||||
}
|
|
||||||
|
|
||||||
syncTasks[2] = () -> {
|
|
||||||
Set<UUID> entitiesRemoved = new HashSet<>();
|
|
||||||
final List<Entity> entities = PaperweightPlatformAdapter.getEntities(nmsChunk);
|
|
||||||
|
|
||||||
for (Entity entity : entities) {
|
|
||||||
UUID uuid = entity.getUUID();
|
|
||||||
if (entityRemoves.contains(uuid)) {
|
|
||||||
if (createCopy) {
|
|
||||||
copy.storeEntity(entity);
|
|
||||||
}
|
|
||||||
removeEntity(entity);
|
|
||||||
entitiesRemoved.add(uuid);
|
|
||||||
entityRemoves.remove(uuid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) {
|
|
||||||
for (UUID uuid : entityRemoves) {
|
|
||||||
Entity entity = nmsWorld.getEntities().get(uuid);
|
|
||||||
if (entity != null) {
|
|
||||||
removeEntity(entity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Only save entities that were actually removed to history
|
|
||||||
set.getEntityRemoves().clear();
|
|
||||||
set.getEntityRemoves().addAll(entitiesRemoved);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
Collection<FaweCompoundTag> entities = set.entities();
|
|
||||||
if (entities != null && !entities.isEmpty()) {
|
|
||||||
if (syncTasks == null) {
|
|
||||||
syncTasks = new Runnable[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
syncTasks[1] = () -> {
|
|
||||||
Iterator<FaweCompoundTag> iterator = entities.iterator();
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
final FaweCompoundTag nativeTag = iterator.next();
|
|
||||||
final LinCompoundTag linTag = nativeTag.linTag();
|
|
||||||
final LinStringTag idTag = linTag.findTag("Id", LinTagType.stringTag());
|
|
||||||
final LinListTag<LinDoubleTag> posTag = linTag.findListTag("Pos", LinTagType.doubleTag());
|
|
||||||
final LinListTag<LinFloatTag> rotTag = linTag.findListTag("Rotation", LinTagType.floatTag());
|
|
||||||
if (idTag == null || posTag == null || rotTag == null) {
|
|
||||||
LOGGER.error("Unknown entity tag: {}", nativeTag);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
final double x = posTag.get(0).valueAsDouble();
|
|
||||||
final double y = posTag.get(1).valueAsDouble();
|
|
||||||
final double z = posTag.get(2).valueAsDouble();
|
|
||||||
final float yaw = rotTag.get(0).valueAsFloat();
|
|
||||||
final float pitch = rotTag.get(1).valueAsFloat();
|
|
||||||
final String id = idTag.value();
|
|
||||||
|
|
||||||
EntityType<?> type = EntityType.byString(id).orElse(null);
|
|
||||||
if (type != null) {
|
|
||||||
Entity entity = type.create(nmsWorld);
|
|
||||||
if (entity != null) {
|
|
||||||
final CompoundTag tag = (CompoundTag) adapter.fromNativeLin(linTag);
|
|
||||||
for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) {
|
|
||||||
tag.remove(name);
|
|
||||||
}
|
|
||||||
entity.load(tag);
|
|
||||||
entity.absMoveTo(x, y, z, yaw, pitch);
|
|
||||||
entity.setUUID(NbtUtils.uuid(nativeTag));
|
|
||||||
if (!nmsWorld.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) {
|
|
||||||
LOGGER.warn(
|
|
||||||
"Error creating entity of type `{}` in world `{}` at location `{},{},{}`",
|
|
||||||
id,
|
|
||||||
nmsWorld.getWorld().getName(),
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
z
|
|
||||||
);
|
|
||||||
// Unsuccessful create should not be saved to history
|
|
||||||
iterator.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// set tiles
|
|
||||||
Map<BlockVector3, FaweCompoundTag> tiles = set.tiles();
|
|
||||||
if (tiles != null && !tiles.isEmpty()) {
|
|
||||||
if (syncTasks == null) {
|
|
||||||
syncTasks = new Runnable[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
syncTasks[0] = () -> {
|
|
||||||
for (final Map.Entry<BlockVector3, FaweCompoundTag> entry : tiles.entrySet()) {
|
|
||||||
final FaweCompoundTag nativeTag = entry.getValue();
|
|
||||||
final BlockVector3 blockHash = entry.getKey();
|
|
||||||
final int x = blockHash.x() + bx;
|
|
||||||
final int y = blockHash.y();
|
|
||||||
final int z = blockHash.z() + bz;
|
|
||||||
final BlockPos pos = new BlockPos(x, y, z);
|
|
||||||
|
|
||||||
synchronized (nmsWorld) {
|
|
||||||
BlockEntity tileEntity = nmsWorld.getBlockEntity(pos);
|
|
||||||
if (tileEntity == null || tileEntity.isRemoved()) {
|
|
||||||
nmsWorld.removeBlockEntity(pos);
|
|
||||||
tileEntity = nmsWorld.getBlockEntity(pos);
|
|
||||||
}
|
|
||||||
if (tileEntity != null) {
|
|
||||||
final CompoundTag tag = (CompoundTag) adapter.fromNativeLin(nativeTag.linTag());
|
|
||||||
tag.put("x", IntTag.valueOf(x));
|
|
||||||
tag.put("y", IntTag.valueOf(y));
|
|
||||||
tag.put("z", IntTag.valueOf(z));
|
|
||||||
tileEntity.loadWithComponents(tag, DedicatedServer.getServer().registryAccess());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
Runnable callback;
|
|
||||||
if (bitMask == 0 && biomes == null && !lightUpdate) {
|
|
||||||
callback = null;
|
|
||||||
} else {
|
|
||||||
int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0;
|
|
||||||
callback = () -> {
|
|
||||||
// Set Modified
|
|
||||||
nmsChunk.setLightCorrect(true); // Set Modified
|
|
||||||
nmsChunk.mustNotSave = false;
|
|
||||||
nmsChunk.setUnsaved(true);
|
|
||||||
// send to player
|
|
||||||
if (Settings.settings().LIGHTING.MODE == 0 || !Settings.settings().LIGHTING.DELAY_PACKET_SENDING || finalMask == 0 && biomes != null) {
|
|
||||||
this.send();
|
|
||||||
}
|
|
||||||
if (finalizer != null) {
|
|
||||||
finalizer.run();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (syncTasks != null) {
|
|
||||||
QueueHandler queueHandler = Fawe.instance().getQueueHandler();
|
|
||||||
Runnable[] finalSyncTasks = syncTasks;
|
|
||||||
|
|
||||||
// Chain the sync tasks and the callback
|
|
||||||
Callable<Future> chain = () -> {
|
|
||||||
try {
|
|
||||||
// Run the sync tasks
|
|
||||||
for (Runnable task : finalSyncTasks) {
|
|
||||||
if (task != null) {
|
|
||||||
task.run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (callback == null) {
|
|
||||||
if (finalizer != null) {
|
|
||||||
queueHandler.async(finalizer, null);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
return queueHandler.async(callback, null);
|
|
||||||
}
|
|
||||||
} catch (Throwable e) {
|
|
||||||
LOGGER.error("Error performing final chunk calling at {},{}", chunkX, chunkZ, e);
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
//noinspection unchecked - required at compile time
|
|
||||||
return (T) (Future) queueHandler.sync(chain);
|
|
||||||
} else {
|
|
||||||
if (callback == null) {
|
|
||||||
if (finalizer != null) {
|
|
||||||
finalizer.run();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
callback.run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
LOGGER.error("Error calling chunk at {},{}", chunkX, chunkZ, e);
|
LOGGER.error("Error performing chunk call at chunk {},{}", chunkX, chunkZ, e);
|
||||||
return null;
|
return null;
|
||||||
} finally {
|
} finally {
|
||||||
forceLoadSections = true;
|
forceLoadSections = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private <T extends Future<T>> T internalCall(
|
||||||
|
IChunkSet set,
|
||||||
|
Runnable finalizer,
|
||||||
|
int copyKey,
|
||||||
|
LevelChunk nmsChunk,
|
||||||
|
ServerLevel nmsWorld
|
||||||
|
) throws Exception {
|
||||||
|
PaperweightGetBlocks_Copy copy = createCopy ? new PaperweightGetBlocks_Copy(nmsChunk) : null;
|
||||||
|
if (createCopy) {
|
||||||
|
if (copies.containsKey(copyKey)) {
|
||||||
|
throw new IllegalStateException("Copy key already used.");
|
||||||
|
}
|
||||||
|
copies.put(copyKey, copy);
|
||||||
|
}
|
||||||
|
// Remove existing tiles. Create a copy so that we can remove blocks
|
||||||
|
Map<BlockPos, BlockEntity> chunkTiles = new HashMap<>(nmsChunk.getBlockEntities());
|
||||||
|
List<BlockEntity> beacons = null;
|
||||||
|
if (!chunkTiles.isEmpty()) {
|
||||||
|
for (Map.Entry<BlockPos, BlockEntity> entry : chunkTiles.entrySet()) {
|
||||||
|
final BlockPos pos = entry.getKey();
|
||||||
|
final int lx = pos.getX() & 15;
|
||||||
|
final int ly = pos.getY();
|
||||||
|
final int lz = pos.getZ() & 15;
|
||||||
|
final int layer = ly >> 4;
|
||||||
|
if (!set.hasSection(layer)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ordinal = set.getBlock(lx, ly, lz).getOrdinal();
|
||||||
|
if (ordinal != BlockTypesCache.ReservedIDs.__RESERVED__) {
|
||||||
|
BlockEntity tile = entry.getValue();
|
||||||
|
if (PaperLib.isPaper() && tile instanceof BeaconBlockEntity) {
|
||||||
|
if (beacons == null) {
|
||||||
|
beacons = new ArrayList<>();
|
||||||
|
}
|
||||||
|
beacons.add(tile);
|
||||||
|
PaperweightPlatformAdapter.removeBeacon(tile, nmsChunk);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
nmsChunk.removeBlockEntity(tile.getBlockPos());
|
||||||
|
if (createCopy) {
|
||||||
|
copy.storeTile(tile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final BiomeType[][] biomes = set.getBiomes();
|
||||||
|
|
||||||
|
int bitMask = 0;
|
||||||
|
synchronized (nmsChunk) {
|
||||||
|
LevelChunkSection[] levelChunkSections = nmsChunk.getSections();
|
||||||
|
|
||||||
|
for (int layerNo = getMinSectionPosition(); layerNo <= getMaxSectionPosition(); layerNo++) {
|
||||||
|
|
||||||
|
int getSectionIndex = layerNo - getMinSectionPosition();
|
||||||
|
int setSectionIndex = layerNo - set.getMinSectionPosition();
|
||||||
|
|
||||||
|
if (!set.hasSection(layerNo)) {
|
||||||
|
// No blocks, but might be biomes present. Handle this lazily.
|
||||||
|
if (biomes == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (layerNo < set.getMinSectionPosition() || layerNo > set.getMaxSectionPosition()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (biomes[setSectionIndex] != null) {
|
||||||
|
synchronized (super.sectionLocks[getSectionIndex]) {
|
||||||
|
LevelChunkSection existingSection = levelChunkSections[getSectionIndex];
|
||||||
|
if (createCopy && existingSection != null) {
|
||||||
|
copy.storeBiomes(getSectionIndex, existingSection.getBiomes());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existingSection == null) {
|
||||||
|
PalettedContainer<Holder<Biome>> biomeData = PaperweightPlatformAdapter.getBiomePalettedContainer(
|
||||||
|
biomes[setSectionIndex],
|
||||||
|
biomeHolderIdMap
|
||||||
|
);
|
||||||
|
LevelChunkSection newSection = PaperweightPlatformAdapter.newChunkSection(
|
||||||
|
layerNo,
|
||||||
|
new char[4096],
|
||||||
|
adapter,
|
||||||
|
biomeRegistry,
|
||||||
|
biomeData
|
||||||
|
);
|
||||||
|
if (PaperweightPlatformAdapter.setSectionAtomic(
|
||||||
|
nmsWorld.getWorld().getName(),
|
||||||
|
chunkPos,
|
||||||
|
levelChunkSections,
|
||||||
|
null,
|
||||||
|
newSection,
|
||||||
|
getSectionIndex
|
||||||
|
)) {
|
||||||
|
updateGet(nmsChunk, levelChunkSections, newSection, new char[4096], getSectionIndex);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
existingSection = levelChunkSections[getSectionIndex];
|
||||||
|
if (existingSection == null) {
|
||||||
|
LOGGER.error(
|
||||||
|
"Skipping invalid null section. chunk: {}, {} layer: {}",
|
||||||
|
chunkX,
|
||||||
|
chunkZ,
|
||||||
|
getSectionIndex
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
PalettedContainer<Holder<Biome>> paletteBiomes = setBiomesToPalettedContainer(
|
||||||
|
biomes,
|
||||||
|
setSectionIndex,
|
||||||
|
existingSection.getBiomes()
|
||||||
|
);
|
||||||
|
if (paletteBiomes != null) {
|
||||||
|
PaperweightPlatformAdapter.setBiomesToChunkSection(existingSection, paletteBiomes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bitMask |= 1 << getSectionIndex;
|
||||||
|
|
||||||
|
// setArr is modified by PaperweightPlatformAdapter#newChunkSection. This is in order to write changes to
|
||||||
|
// this chunk GET when #updateGet is called. Future dords, please listen this time.
|
||||||
|
char[] tmp = set.load(layerNo);
|
||||||
|
char[] setArr = new char[tmp.length];
|
||||||
|
System.arraycopy(tmp, 0, setArr, 0, tmp.length);
|
||||||
|
|
||||||
|
// synchronise on internal section to avoid circular locking with a continuing edit if the chunk was
|
||||||
|
// submitted to keep loaded internal chunks to queue target size.
|
||||||
|
synchronized (super.sectionLocks[getSectionIndex]) {
|
||||||
|
|
||||||
|
LevelChunkSection newSection;
|
||||||
|
LevelChunkSection existingSection = levelChunkSections[getSectionIndex];
|
||||||
|
// Don't attempt to tick section whilst we're editing
|
||||||
|
if (existingSection != null) {
|
||||||
|
PaperweightPlatformAdapter.clearCounts(existingSection);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (createCopy) {
|
||||||
|
char[] tmpLoad = loadPrivately(layerNo);
|
||||||
|
char[] copyArr = new char[4096];
|
||||||
|
System.arraycopy(tmpLoad, 0, copyArr, 0, 4096);
|
||||||
|
copy.storeSection(getSectionIndex, copyArr);
|
||||||
|
if (biomes != null && existingSection != null) {
|
||||||
|
copy.storeBiomes(getSectionIndex, existingSection.getBiomes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existingSection == null) {
|
||||||
|
PalettedContainer<Holder<Biome>> biomeData = biomes == null ? new PalettedContainer<>(
|
||||||
|
biomeHolderIdMap,
|
||||||
|
biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)),
|
||||||
|
PalettedContainer.Strategy.SECTION_BIOMES
|
||||||
|
) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap);
|
||||||
|
newSection = PaperweightPlatformAdapter.newChunkSection(
|
||||||
|
layerNo,
|
||||||
|
setArr,
|
||||||
|
adapter,
|
||||||
|
biomeRegistry,
|
||||||
|
biomeData
|
||||||
|
);
|
||||||
|
if (PaperweightPlatformAdapter.setSectionAtomic(
|
||||||
|
nmsWorld.getWorld().getName(),
|
||||||
|
chunkPos,
|
||||||
|
levelChunkSections,
|
||||||
|
null,
|
||||||
|
newSection,
|
||||||
|
getSectionIndex
|
||||||
|
)) {
|
||||||
|
updateGet(nmsChunk, levelChunkSections, newSection, setArr, getSectionIndex);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
existingSection = levelChunkSections[getSectionIndex];
|
||||||
|
if (existingSection == null) {
|
||||||
|
LOGGER.error(
|
||||||
|
"Skipping invalid null section. chunk: {}, {} layer: {}",
|
||||||
|
chunkX,
|
||||||
|
chunkZ,
|
||||||
|
getSectionIndex
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//ensure that the server doesn't try to tick the chunksection while we're editing it. (Again)
|
||||||
|
PaperweightPlatformAdapter.clearCounts(existingSection);
|
||||||
|
DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(existingSection);
|
||||||
|
|
||||||
|
// Synchronize to prevent further acquisitions
|
||||||
|
synchronized (lock) {
|
||||||
|
lock.acquire(); // Wait until we have the lock
|
||||||
|
lock.release();
|
||||||
|
try {
|
||||||
|
sectionLock.writeLock().lock();
|
||||||
|
if (this.getChunk() != nmsChunk) {
|
||||||
|
this.levelChunk = nmsChunk;
|
||||||
|
this.sections = null;
|
||||||
|
this.reset();
|
||||||
|
} else if (existingSection != getSections(false)[getSectionIndex]) {
|
||||||
|
this.sections[getSectionIndex] = existingSection;
|
||||||
|
this.reset();
|
||||||
|
} else if (!Arrays.equals(update(getSectionIndex, new char[4096], true), loadPrivately(layerNo))) {
|
||||||
|
this.reset(layerNo);
|
||||||
|
/*} else if (lock.isModified()) {
|
||||||
|
this.reset(layerNo);*/
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
sectionLock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
PalettedContainer<Holder<Biome>> biomeData = setBiomesToPalettedContainer(
|
||||||
|
biomes,
|
||||||
|
setSectionIndex,
|
||||||
|
existingSection.getBiomes()
|
||||||
|
);
|
||||||
|
|
||||||
|
newSection = PaperweightPlatformAdapter.newChunkSection(
|
||||||
|
layerNo,
|
||||||
|
this::loadPrivately,
|
||||||
|
setArr,
|
||||||
|
adapter,
|
||||||
|
biomeRegistry,
|
||||||
|
biomeData != null ? biomeData : (PalettedContainer<Holder<Biome>>) existingSection.getBiomes()
|
||||||
|
);
|
||||||
|
if (!PaperweightPlatformAdapter.setSectionAtomic(
|
||||||
|
nmsWorld.getWorld().getName(),
|
||||||
|
chunkPos,
|
||||||
|
levelChunkSections,
|
||||||
|
existingSection,
|
||||||
|
newSection,
|
||||||
|
getSectionIndex
|
||||||
|
)) {
|
||||||
|
LOGGER.error(
|
||||||
|
"Skipping invalid null section. chunk: {}, {} layer: {}",
|
||||||
|
chunkX,
|
||||||
|
chunkZ,
|
||||||
|
getSectionIndex
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
updateGet(nmsChunk, levelChunkSections, newSection, setArr, getSectionIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<HeightMapType, int[]> heightMaps = set.getHeightMaps();
|
||||||
|
for (Map.Entry<HeightMapType, int[]> entry : heightMaps.entrySet()) {
|
||||||
|
PaperweightGetBlocks.this.setHeightmapToGet(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
PaperweightGetBlocks.this.setLightingToGet(set.getLight(), set.getMinSectionPosition(), set.getMaxSectionPosition());
|
||||||
|
PaperweightGetBlocks.this.setSkyLightingToGet(
|
||||||
|
set.getSkyLight(),
|
||||||
|
set.getMinSectionPosition(),
|
||||||
|
set.getMaxSectionPosition()
|
||||||
|
);
|
||||||
|
|
||||||
|
Runnable[] syncTasks = null;
|
||||||
|
|
||||||
|
int bx = chunkX << 4;
|
||||||
|
int bz = chunkZ << 4;
|
||||||
|
|
||||||
|
// Call beacon deactivate events here synchronously
|
||||||
|
// list will be null on spigot, so this is an implicit isPaper check
|
||||||
|
if (beacons != null && !beacons.isEmpty()) {
|
||||||
|
final List<BlockEntity> finalBeacons = beacons;
|
||||||
|
|
||||||
|
syncTasks = new Runnable[4];
|
||||||
|
|
||||||
|
syncTasks[3] = () -> {
|
||||||
|
for (BlockEntity beacon : finalBeacons) {
|
||||||
|
BeaconBlockEntity.playSound(beacon.getLevel(), beacon.getBlockPos(), SoundEvents.BEACON_DEACTIVATE);
|
||||||
|
new BeaconDeactivatedEvent(CraftBlock.at(beacon.getLevel(), beacon.getBlockPos())).callEvent();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<UUID> entityRemoves = set.getEntityRemoves();
|
||||||
|
if (entityRemoves != null && !entityRemoves.isEmpty()) {
|
||||||
|
if (syncTasks == null) {
|
||||||
|
syncTasks = new Runnable[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
syncTasks[2] = () -> {
|
||||||
|
Set<UUID> entitiesRemoved = new HashSet<>();
|
||||||
|
final List<Entity> entities = PaperweightPlatformAdapter.getEntities(nmsChunk);
|
||||||
|
|
||||||
|
for (Entity entity : entities) {
|
||||||
|
UUID uuid = entity.getUUID();
|
||||||
|
if (entityRemoves.contains(uuid)) {
|
||||||
|
if (createCopy) {
|
||||||
|
copy.storeEntity(entity);
|
||||||
|
}
|
||||||
|
removeEntity(entity);
|
||||||
|
entitiesRemoved.add(uuid);
|
||||||
|
entityRemoves.remove(uuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) {
|
||||||
|
for (UUID uuid : entityRemoves) {
|
||||||
|
Entity entity = nmsWorld.getEntities().get(uuid);
|
||||||
|
if (entity != null) {
|
||||||
|
removeEntity(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Only save entities that were actually removed to history
|
||||||
|
set.getEntityRemoves().clear();
|
||||||
|
set.getEntityRemoves().addAll(entitiesRemoved);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Collection<FaweCompoundTag> entities = set.entities();
|
||||||
|
if (entities != null && !entities.isEmpty()) {
|
||||||
|
if (syncTasks == null) {
|
||||||
|
syncTasks = new Runnable[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
syncTasks[1] = () -> {
|
||||||
|
Iterator<FaweCompoundTag> iterator = entities.iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
final FaweCompoundTag nativeTag = iterator.next();
|
||||||
|
final LinCompoundTag linTag = nativeTag.linTag();
|
||||||
|
final LinStringTag idTag = linTag.findTag("Id", LinTagType.stringTag());
|
||||||
|
final LinListTag<LinDoubleTag> posTag = linTag.findListTag("Pos", LinTagType.doubleTag());
|
||||||
|
final LinListTag<LinFloatTag> rotTag = linTag.findListTag("Rotation", LinTagType.floatTag());
|
||||||
|
if (idTag == null || posTag == null || rotTag == null) {
|
||||||
|
LOGGER.error("Unknown entity tag: {}", nativeTag);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final double x = posTag.get(0).valueAsDouble();
|
||||||
|
final double y = posTag.get(1).valueAsDouble();
|
||||||
|
final double z = posTag.get(2).valueAsDouble();
|
||||||
|
final float yaw = rotTag.get(0).valueAsFloat();
|
||||||
|
final float pitch = rotTag.get(1).valueAsFloat();
|
||||||
|
final String id = idTag.value();
|
||||||
|
|
||||||
|
EntityType<?> type = EntityType.byString(id).orElse(null);
|
||||||
|
if (type != null) {
|
||||||
|
Entity entity = type.create(nmsWorld);
|
||||||
|
if (entity != null) {
|
||||||
|
final CompoundTag tag = (CompoundTag) adapter.fromNativeLin(linTag);
|
||||||
|
for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) {
|
||||||
|
tag.remove(name);
|
||||||
|
}
|
||||||
|
entity.load(tag);
|
||||||
|
entity.absMoveTo(x, y, z, yaw, pitch);
|
||||||
|
entity.setUUID(NbtUtils.uuid(nativeTag));
|
||||||
|
if (!nmsWorld.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) {
|
||||||
|
LOGGER.warn(
|
||||||
|
"Error creating entity of type `{}` in world `{}` at location `{},{},{}`",
|
||||||
|
id,
|
||||||
|
nmsWorld.getWorld().getName(),
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
z
|
||||||
|
);
|
||||||
|
// Unsuccessful create should not be saved to history
|
||||||
|
iterator.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// set tiles
|
||||||
|
Map<BlockVector3, FaweCompoundTag> tiles = set.tiles();
|
||||||
|
if (tiles != null && !tiles.isEmpty()) {
|
||||||
|
if (syncTasks == null) {
|
||||||
|
syncTasks = new Runnable[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
syncTasks[0] = () -> {
|
||||||
|
for (final Map.Entry<BlockVector3, FaweCompoundTag> entry : tiles.entrySet()) {
|
||||||
|
final FaweCompoundTag nativeTag = entry.getValue();
|
||||||
|
final BlockVector3 blockHash = entry.getKey();
|
||||||
|
final int x = blockHash.x() + bx;
|
||||||
|
final int y = blockHash.y();
|
||||||
|
final int z = blockHash.z() + bz;
|
||||||
|
final BlockPos pos = new BlockPos(x, y, z);
|
||||||
|
|
||||||
|
synchronized (nmsWorld) {
|
||||||
|
BlockEntity tileEntity = nmsWorld.getBlockEntity(pos);
|
||||||
|
if (tileEntity == null || tileEntity.isRemoved()) {
|
||||||
|
nmsWorld.removeBlockEntity(pos);
|
||||||
|
tileEntity = nmsWorld.getBlockEntity(pos);
|
||||||
|
}
|
||||||
|
if (tileEntity != null) {
|
||||||
|
final CompoundTag tag = (CompoundTag) adapter.fromNativeLin(nativeTag.linTag());
|
||||||
|
tag.put("x", IntTag.valueOf(x));
|
||||||
|
tag.put("y", IntTag.valueOf(y));
|
||||||
|
tag.put("z", IntTag.valueOf(z));
|
||||||
|
tileEntity.loadWithComponents(tag, DedicatedServer.getServer().registryAccess());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Runnable callback;
|
||||||
|
if (bitMask == 0 && biomes == null && !lightUpdate) {
|
||||||
|
callback = null;
|
||||||
|
} else {
|
||||||
|
int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0;
|
||||||
|
callback = () -> {
|
||||||
|
// Set Modified
|
||||||
|
nmsChunk.setLightCorrect(true); // Set Modified
|
||||||
|
nmsChunk.mustNotSave = false;
|
||||||
|
nmsChunk.setUnsaved(true);
|
||||||
|
// send to player
|
||||||
|
if (Settings.settings().LIGHTING.MODE == 0 || !Settings.settings().LIGHTING.DELAY_PACKET_SENDING || finalMask == 0 && biomes != null) {
|
||||||
|
this.send();
|
||||||
|
}
|
||||||
|
if (finalizer != null) {
|
||||||
|
finalizer.run();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (syncTasks != null) {
|
||||||
|
QueueHandler queueHandler = Fawe.instance().getQueueHandler();
|
||||||
|
Runnable[] finalSyncTasks = syncTasks;
|
||||||
|
|
||||||
|
// Chain the sync tasks and the callback
|
||||||
|
Callable<Future> chain = () -> {
|
||||||
|
try {
|
||||||
|
// Run the sync tasks
|
||||||
|
for (Runnable task : finalSyncTasks) {
|
||||||
|
if (task != null) {
|
||||||
|
task.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (callback == null) {
|
||||||
|
if (finalizer != null) {
|
||||||
|
queueHandler.async(finalizer, null);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return queueHandler.async(callback, null);
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
LOGGER.error("Error performing final chunk calling at {},{}", chunkX, chunkZ, e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//noinspection unchecked - required at compile time
|
||||||
|
return (T) (Future) queueHandler.sync(chain);
|
||||||
|
} else {
|
||||||
|
if (callback == null) {
|
||||||
|
if (finalizer != null) {
|
||||||
|
finalizer.run();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
callback.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private void updateGet(
|
private void updateGet(
|
||||||
LevelChunk nmsChunk,
|
LevelChunk nmsChunk,
|
||||||
LevelChunkSection[] chunkSections,
|
LevelChunkSection[] chunkSections,
|
||||||
|
@ -56,7 +56,6 @@ import net.minecraft.world.level.chunk.SingleValuePalette;
|
|||||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||||
import net.minecraft.world.level.entity.PersistentEntitySectionManager;
|
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.craftbukkit.CraftChunk;
|
import org.bukkit.craftbukkit.CraftChunk;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
@ -79,10 +78,7 @@ import java.util.Map;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.Future;
|
|
||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.concurrent.TimeoutException;
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
import static java.lang.invoke.MethodType.methodType;
|
import static java.lang.invoke.MethodType.methodType;
|
||||||
@ -262,7 +258,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
e.printStackTrace();
|
LOGGER.error("Error apply DelegateSemaphore", e);
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -673,7 +669,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
}
|
}
|
||||||
methodremoveTickingBlockEntity.invoke(levelChunk, beacon.getBlockPos());
|
methodremoveTickingBlockEntity.invoke(levelChunk, beacon.getBlockPos());
|
||||||
} catch (Throwable throwable) {
|
} catch (Throwable throwable) {
|
||||||
throwable.printStackTrace();
|
LOGGER.error("Error removing beacon", throwable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren