2020-05-07 23:44:33 +00:00
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
2020-05-20 09:11:57 +00:00
index 182b440ba4802d199b8e44f7779b3401ace495d5..10b72083322b7f8e3e14525b3e834f5374ec369d 100644
2020-05-07 23:44:33 +00:00
--- a/src/main/java/com/destroystokyo/paper/PaperCommand.java
+++ b/src/main/java/com/destroystokyo/paper/PaperCommand.java
2020-05-20 09:11:57 +00:00
@@ -20,6 +20,7 @@ import org.bukkit.command.Command;
2020-05-07 23:44:33 +00:00
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;
2020-05-20 09:11:57 +00:00
@@ -36,14 +37,14 @@ public class PaperCommand extends Command {
2020-05-07 23:44:33 +00:00
public PaperCommand(String name) {
super(name);
this.description = "Paper related commands";
2020-05-20 09:11:57 +00:00
- this.usageMessage = "/paper [heap | entity | reload | version | debug | dumpwaiting | chunkinfo | syncloadinfo]";
+ this.usageMessage = "/paper [heap | entity | reload | version | debug | dumpwaiting | chunkinfo | syncloadinfo | fixlight]";
2020-05-07 23:44:33 +00:00
this.setPermission("bukkit.command.paper");
}
@Override
public List<String> tabComplete(CommandSender sender, String alias, String[] args, Location location) throws IllegalArgumentException {
if (args.length <= 1)
2020-05-20 09:11:57 +00:00
- return getListMatchingLast(args, "heap", "entity", "reload", "version", "debug", "dumpwaiting", "chunkinfo", "syncloadinfo");
+ return getListMatchingLast(args, "heap", "entity", "reload", "version", "debug", "dumpwaiting", "chunkinfo", "syncloadinfo", "fixlight");
2020-05-07 23:44:33 +00:00
switch (args[0].toLowerCase(Locale.ENGLISH))
{
2020-05-20 09:11:57 +00:00
@@ -144,6 +145,9 @@ public class PaperCommand extends Command {
2020-05-07 23:44:33 +00:00
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");
2020-05-20 09:11:57 +00:00
@@ -160,6 +164,75 @@ public class PaperCommand extends Command {
2020-05-07 23:44:33 +00:00
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;
+ }
2020-05-10 02:30:28 +00:00
+ 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;
+ }
2020-05-07 23:44:33 +00:00
+ 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);
2020-05-10 02:30:28 +00:00
+ }, MinecraftServer.getServer());
2020-05-07 23:44:33 +00:00
+ }
+
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
2020-05-20 09:11:57 +00:00
index 03fb688fe4bdc19b4bc36b1f1d5b40c61e7bef9b..aeca6b2b9d5d73aeb6dc639b5cad2f2533a2de44 100644
2020-05-07 23:44:33 +00:00
--- a/src/main/java/net/minecraft/server/PlayerChunk.java
+++ b/src/main/java/net/minecraft/server/PlayerChunk.java
2020-05-20 09:11:57 +00:00
@@ -327,6 +327,7 @@ public class PlayerChunk {
2020-05-07 23:44:33 +00:00
}
+ 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
2020-05-21 02:22:47 +00:00
index 3b72b2c88575d19ec51f46226ddcc8a15c169721..a280f4af4f997f29e81a877455a2765d6751e842 100644
2020-05-07 23:44:33 +00:00
--- a/src/main/java/net/minecraft/server/PlayerChunkMap.java
+++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java
2020-05-21 02:22:47 +00:00
@@ -95,6 +95,12 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
2020-05-07 23:44:33 +00:00
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;
2020-05-21 02:22:47 +00:00
@@ -282,11 +288,12 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
2020-05-07 23:44:33 +00:00
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;