aboutsummaryrefslogtreecommitdiffhomepage
path: root/Spigot-Server-Patches/0483-Fix-Light-Command.patch
blob: d7fd8d334cd120c9f15b21cc71da25cf8f5391a7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
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..cc3fc5200f75f80a60b4cbc260e3a0bc4bb3a869 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,77 @@ 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);
+            int cx = chunk.getPos().x << 4;
+            int cz = chunk.getPos().z << 4;
+            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(cx + x, y, cz + 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, true), 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 40347212ad1bcf857d5b8ddb0ee6a698e2568201..e5751adde516544722b95016f64b2a46c16e77ce 100644
--- a/src/main/java/net/minecraft/server/PlayerChunk.java
+++ b/src/main/java/net/minecraft/server/PlayerChunk.java
@@ -314,6 +314,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 e4f81e93bfb305af7b2bfbccac3fbe981dbddf11..e4527f3f899ac194d629f39bfdb650667d2dab80 100644
--- a/src/main/java/net/minecraft/server/PlayerChunkMap.java
+++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java
@@ -96,6 +96,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;
@@ -287,11 +293,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.getDimensionManager().hasSkyLight(), threadedmailbox1, this.p.a(threadedmailbox1, false));
         this.chunkDistanceManager = new PlayerChunkMap.a(executor, iasynctaskhandler); this.chunkDistanceManager.chunkMap = this; // Paper
         this.l = supplier;