papermc/Spigot-Server-Patches/0507-Fix-Light-Command.patch
Aikar 7e1525ea2d
Many improvements to chunk prioritization and bug fixes
Fixed a few bugs, and made numerous improvements.
Fixed issue where a sync chunk load could have its ticket removed and the
priority ticket could expire...
Still not perfect there but better than before.

Also fixed few other misc issues such as watchdog cpu usage, chunk queue update
had risk of double enqueue due to it no longer being a set.

Added much more information about chunk state to watchdog prints.

I see some more room for improvement even, but this is much better than before.

Fixes #3407
Fixes #3411
Fixes #3395
Fixes #3389
2020-05-20 05:13:01 -04:00

166 lines
8.8 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Thu, 7 May 2020 19:17:36 -0400
Subject: [PATCH] Fix Light Command
This lets you run /paper fixlight <chunkRadius> (max 5) to automatically
fix all light data in the chunks.
diff --git a/src/main/java/com/destroystokyo/paper/PaperCommand.java b/src/main/java/com/destroystokyo/paper/PaperCommand.java
index 182b440ba4802d199b8e44f7779b3401ace495d5..10b72083322b7f8e3e14525b3e834f5374ec369d 100644
--- a/src/main/java/com/destroystokyo/paper/PaperCommand.java
+++ b/src/main/java/com/destroystokyo/paper/PaperCommand.java
@@ -20,6 +20,7 @@ import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.craftbukkit.CraftWorld;
+import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.entity.Player;
import java.io.File;
@@ -36,14 +37,14 @@ public class PaperCommand extends Command {
public PaperCommand(String name) {
super(name);
this.description = "Paper related commands";
- this.usageMessage = "/paper [heap | entity | reload | version | debug | dumpwaiting | chunkinfo | syncloadinfo]";
+ this.usageMessage = "/paper [heap | entity | reload | version | debug | dumpwaiting | chunkinfo | syncloadinfo | fixlight]";
this.setPermission("bukkit.command.paper");
}
@Override
public List<String> tabComplete(CommandSender sender, String alias, String[] args, Location location) throws IllegalArgumentException {
if (args.length <= 1)
- return getListMatchingLast(args, "heap", "entity", "reload", "version", "debug", "dumpwaiting", "chunkinfo", "syncloadinfo");
+ return getListMatchingLast(args, "heap", "entity", "reload", "version", "debug", "dumpwaiting", "chunkinfo", "syncloadinfo", "fixlight");
switch (args[0].toLowerCase(Locale.ENGLISH))
{
@@ -144,6 +145,9 @@ public class PaperCommand extends Command {
case "syncloadinfo":
this.doSyncLoadInfo(sender, args);
break;
+ case "fixlight":
+ this.doFixLight(sender, args);
+ break;
case "ver":
case "version":
Command ver = org.bukkit.Bukkit.getServer().getCommandMap().getCommand("version");
@@ -160,6 +164,75 @@ public class PaperCommand extends Command {
return true;
}
+ private void doFixLight(CommandSender sender, String[] args) {
+ if (!(sender instanceof Player)) {
+ sender.sendMessage("Only players can use this command");
+ return;
+ }
+ int radius = 2;
+ if (args.length > 1) {
+ try {
+ radius = Math.min(5, Integer.parseInt(args[1]));
+ } catch (Exception e) {
+ sender.sendMessage("Not a number");
+ return;
+ }
+
+ }
+
+ CraftPlayer player = (CraftPlayer) sender;
+ EntityPlayer handle = player.getHandle();
+ net.minecraft.server.WorldServer world = (WorldServer) handle.world;
+ LightEngineThreaded lightengine = world.getChunkProvider().getLightEngine();
+
+ BlockPosition center = MCUtil.toBlockPosition(player.getLocation());
+ Deque<ChunkCoordIntPair> queue = new ArrayDeque<>(MCUtil.getSpiralOutChunks(center, radius));
+ updateLight(sender, world, lightengine, queue);
+ }
+
+ private void updateLight(CommandSender sender, WorldServer world, LightEngineThreaded lightengine, Deque<ChunkCoordIntPair> queue) {
+ ChunkCoordIntPair coord = queue.poll();
+ if (coord == null) {
+ sender.sendMessage("All Chunks Light updated");
+ return;
+ }
+ world.getChunkProvider().getChunkAtAsynchronously(coord.x, coord.z, false, false).whenCompleteAsync((either, ex) -> {
+ if (ex != null) {
+ sender.sendMessage("Error loading chunk " + coord);
+ updateLight(sender, world, lightengine, queue);
+ return;
+ }
+ Chunk chunk = (Chunk) either.left().orElse(null);
+ if (chunk == null) {
+ updateLight(sender, world, lightengine, queue);
+ return;
+ }
+ lightengine.a(world.paperConfig.lightQueueSize + 16 * 256); // ensure full chunk can fit into queue
+ sender.sendMessage("Updating Light " + coord);
+ for (int y = 0; y < world.getHeight(); y++) {
+ for (int x = 0; x < 16; x++) {
+ for (int z = 0; z < 16; z++) {
+ BlockPosition pos = new BlockPosition(chunk.getPos().getBlockX() + x, y, chunk.getPos().getBlockZ() + z);
+ lightengine.a(pos);
+ }
+ }
+ }
+ lightengine.queueUpdate();
+ PlayerChunk visibleChunk = world.getChunkProvider().playerChunkMap.getVisibleChunk(chunk.coordinateKey);
+ if (visibleChunk != null) {
+ world.getChunkProvider().playerChunkMap.addLightTask(visibleChunk, () -> {
+ MinecraftServer.getServer().processQueue.add(() -> {
+ visibleChunk.sendPacketToTrackedPlayers(new PacketPlayOutLightUpdate(chunk.getPos(), lightengine), false);
+ updateLight(sender, world, lightengine, queue);
+ });
+ });
+ } else {
+ updateLight(sender, world, lightengine, queue);
+ }
+ lightengine.a(world.paperConfig.lightQueueSize);
+ }, MinecraftServer.getServer());
+ }
+
private void doSyncLoadInfo(CommandSender sender, String[] args) {
if (!SyncLoadFinder.ENABLED) {
sender.sendMessage(ChatColor.RED + "This command requires the server startup flag '-Dpaper.debug-sync-loads=true' to be set.");
diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java
index 03fb688fe4bdc19b4bc36b1f1d5b40c61e7bef9b..aeca6b2b9d5d73aeb6dc639b5cad2f2533a2de44 100644
--- a/src/main/java/net/minecraft/server/PlayerChunk.java
+++ b/src/main/java/net/minecraft/server/PlayerChunk.java
@@ -327,6 +327,7 @@ public class PlayerChunk {
}
+ public void sendPacketToTrackedPlayers(Packet<?> packet, boolean flag) { a(packet, flag); } // Paper - OBFHELPER
private void a(Packet<?> packet, boolean flag) {
// Paper start - per player view distance
// there can be potential desync with player's last mapped section and the view distance map, so use the
diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java
index abfe75750ea564cd56b53d3f09eb247478384e2f..430273c306be19d7b5af171f392236f9f0d835a8 100644
--- a/src/main/java/net/minecraft/server/PlayerChunkMap.java
+++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java
@@ -72,6 +72,12 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
private final ChunkTaskQueueSorter p;
private final Mailbox<ChunkTaskQueueSorter.a<Runnable>> mailboxWorldGen;
final Mailbox<ChunkTaskQueueSorter.a<Runnable>> mailboxMain; // Paper - private -> package private
+ // Paper start
+ final Mailbox<ChunkTaskQueueSorter.a<Runnable>> mailboxLight;
+ public void addLightTask(PlayerChunk playerchunk, Runnable run) {
+ this.mailboxLight.a(ChunkTaskQueueSorter.a(playerchunk, run));
+ }
+ // Paper end
public final WorldLoadListener worldLoadListener;
public final PlayerChunkMap.a chunkDistanceManager; public final PlayerChunkMap.a getChunkMapDistanceManager() { return this.chunkDistanceManager; } // Paper - OBFHELPER
private final AtomicInteger u;
@@ -259,11 +265,12 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
Mailbox<Runnable> mailbox = Mailbox.a("main", iasynctaskhandler::a);
this.worldLoadListener = worldloadlistener;
- ThreadedMailbox<Runnable> threadedmailbox1 = ThreadedMailbox.a(executor, "light");
+ ThreadedMailbox<Runnable> lightthreaded; ThreadedMailbox<Runnable> threadedmailbox1 = lightthreaded = ThreadedMailbox.a(executor, "light"); // Paper
this.p = new ChunkTaskQueueSorter(ImmutableList.of(threadedmailbox, mailbox, threadedmailbox1), executor, Integer.MAX_VALUE);
this.mailboxWorldGen = this.p.a(threadedmailbox, false);
this.mailboxMain = this.p.a(mailbox, false);
+ this.mailboxLight = this.p.a(lightthreaded, false);// Paper
this.lightEngine = new LightEngineThreaded(ilightaccess, this, this.world.getWorldProvider().f(), threadedmailbox1, this.p.a(threadedmailbox1, false));
this.chunkDistanceManager = new PlayerChunkMap.a(executor, iasynctaskhandler); this.chunkDistanceManager.chunkMap = this; // Paper
this.l = supplier;