mirror of
https://github.com/PaperMC/Paper.git
synced 2024-11-26 20:46:59 +01:00
4104545b11
"It was from a different time before books were as jank as they are now. As time has gone on they've only proven to be worse and worse."
167 lines
8.8 KiB
Diff
167 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 71ffa66973d8994e2a480435ac1ada3fe61600a4..7b5afc5d34b78e6404c1a5c6bb823d9589471f13 100644
|
|
--- a/src/main/java/com/destroystokyo/paper/PaperCommand.java
|
|
+++ b/src/main/java/com/destroystokyo/paper/PaperCommand.java
|
|
@@ -10,7 +10,8 @@ import net.minecraft.server.MinecraftServer;
|
|
import net.minecraft.server.level.ChunkHolder;
|
|
import net.minecraft.server.level.ServerChunkCache;
|
|
import net.minecraft.server.level.ServerLevel;
|
|
-import net.minecraft.world.entity.Entity;
|
|
+import net.minecraft.server.level.ServerPlayer;
|
|
+import net.minecraft.server.level.ThreadedLevelLightEngine;
|
|
import net.minecraft.world.entity.EntityType;
|
|
import net.minecraft.world.level.ChunkPos;
|
|
import net.minecraft.resources.ResourceLocation;
|
|
@@ -25,15 +26,18 @@ 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;
|
|
import java.time.LocalDateTime;
|
|
import java.time.format.DateTimeFormatter;
|
|
+import java.util.ArrayDeque;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.Collection;
|
|
import java.util.Collections;
|
|
+import java.util.Deque;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
import java.util.Locale;
|
|
@@ -43,7 +47,7 @@ import java.util.stream.Collectors;
|
|
|
|
public class PaperCommand extends Command {
|
|
private static final String BASE_PERM = "bukkit.command.paper.";
|
|
- private static final ImmutableSet<String> SUBCOMMANDS = ImmutableSet.<String>builder().add("heap", "entity", "reload", "version", "debug", "chunkinfo").build();
|
|
+ private static final ImmutableSet<String> SUBCOMMANDS = ImmutableSet.<String>builder().add("heap", "entity", "reload", "version", "debug", "chunkinfo", "fixlight").build();
|
|
|
|
public PaperCommand(String name) {
|
|
super(name);
|
|
@@ -158,6 +162,9 @@ public class PaperCommand extends Command {
|
|
case "chunkinfo":
|
|
doChunkInfo(sender, args);
|
|
break;
|
|
+ case "fixlight":
|
|
+ this.doFixLight(sender, args);
|
|
+ break;
|
|
case "ver":
|
|
if (!testPermission(sender, "version")) break; // "ver" needs a special check because it's an alias. All other commands are checked up before the switch statement (because they are present in the SUBCOMMANDS set)
|
|
case "version":
|
|
@@ -413,4 +420,74 @@ public class PaperCommand extends Command {
|
|
|
|
Command.broadcastCommandMessage(sender, ChatColor.GREEN + "Paper config reload complete.");
|
|
}
|
|
+ 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;
|
|
+ ServerPlayer handle = player.getHandle();
|
|
+ ServerLevel world = (ServerLevel) handle.level;
|
|
+ ThreadedLevelLightEngine lightengine = world.getChunkSource().getLightEngine();
|
|
+
|
|
+ net.minecraft.core.BlockPos center = MCUtil.toBlockPosition(player.getLocation());
|
|
+ Deque<ChunkPos> queue = new ArrayDeque<>(MCUtil.getSpiralOutChunks(center, radius));
|
|
+ updateLight(sender, world, lightengine, queue);
|
|
+ }
|
|
+
|
|
+ private void updateLight(CommandSender sender, ServerLevel world, ThreadedLevelLightEngine lightengine, Deque<ChunkPos> queue) {
|
|
+ ChunkPos coord = queue.poll();
|
|
+ if (coord == null) {
|
|
+ sender.sendMessage("All Chunks Light updated");
|
|
+ return;
|
|
+ }
|
|
+ world.getChunkSource().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;
|
|
+ }
|
|
+ net.minecraft.world.level.chunk.LevelChunk chunk = (net.minecraft.world.level.chunk.LevelChunk) either.left().orElse(null);
|
|
+ if (chunk == null) {
|
|
+ updateLight(sender, world, lightengine, queue);
|
|
+ return;
|
|
+ }
|
|
+ lightengine.setTaskPerBatch(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++) {
|
|
+ net.minecraft.core.BlockPos pos = new net.minecraft.core.BlockPos(cx + x, y, cz + z);
|
|
+ lightengine.checkBlock(pos);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ lightengine.tryScheduleUpdate();
|
|
+ ChunkHolder visibleChunk = world.getChunkSource().chunkMap.getVisibleChunkIfPresent(chunk.coordinateKey);
|
|
+ if (visibleChunk != null) {
|
|
+ world.getChunkSource().chunkMap.addLightTask(visibleChunk, () -> {
|
|
+ MinecraftServer.getServer().processQueue.add(() -> {
|
|
+ visibleChunk.broadcast(new net.minecraft.network.protocol.game.ClientboundLightUpdatePacket(chunk.getPos(), lightengine, null, null, true), false);
|
|
+ updateLight(sender, world, lightengine, queue);
|
|
+ });
|
|
+ });
|
|
+ } else {
|
|
+ updateLight(sender, world, lightengine, queue);
|
|
+ }
|
|
+ lightengine.setTaskPerBatch(world.paperConfig.lightQueueSize);
|
|
+ }, MinecraftServer.getServer());
|
|
+ }
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
|
index e6c42a52d687a418c92e8f628d589ac31ae90626..513876fc53fe5790e5bc6271a1a9ec345a614b98 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
|
@@ -128,6 +128,12 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
private final ChunkTaskPriorityQueueSorter queueSorter;
|
|
private final ProcessorHandle<ChunkTaskPriorityQueueSorter.Message<Runnable>> worldgenMailbox;
|
|
private final ProcessorHandle<ChunkTaskPriorityQueueSorter.Message<Runnable>> mainThreadMailbox;
|
|
+ // Paper start
|
|
+ final ProcessorHandle<ChunkTaskPriorityQueueSorter.Message<Runnable>> mailboxLight;
|
|
+ public void addLightTask(ChunkHolder playerchunk, Runnable run) {
|
|
+ this.mailboxLight.tell(ChunkTaskPriorityQueueSorter.message(playerchunk, run));
|
|
+ }
|
|
+ // Paper end
|
|
public final ChunkProgressListener progressListener;
|
|
private final ChunkStatusUpdateListener chunkStatusListener;
|
|
public final ChunkMap.ChunkDistanceManager distanceManager;
|
|
@@ -204,11 +210,12 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
|
|
this.progressListener = worldGenerationProgressListener;
|
|
this.chunkStatusListener = chunkStatusChangeListener;
|
|
- ProcessorMailbox<Runnable> threadedmailbox1 = ProcessorMailbox.create(executor, "light");
|
|
+ ProcessorMailbox<Runnable> lightthreaded; ProcessorMailbox<Runnable> threadedmailbox1 = lightthreaded = ProcessorMailbox.create(executor, "light"); // Paper
|
|
|
|
this.queueSorter = new ChunkTaskPriorityQueueSorter(ImmutableList.of(threadedmailbox, mailbox, threadedmailbox1), executor, Integer.MAX_VALUE);
|
|
this.worldgenMailbox = this.queueSorter.getProcessor(threadedmailbox, false);
|
|
this.mainThreadMailbox = this.queueSorter.getProcessor(mailbox, false);
|
|
+ this.mailboxLight = this.queueSorter.getProcessor(lightthreaded, false);// Paper
|
|
this.lightEngine = new ThreadedLevelLightEngine(chunkProvider, this, this.level.dimensionType().hasSkyLight(), threadedmailbox1, this.queueSorter.getProcessor(threadedmailbox1, false));
|
|
this.distanceManager = new ChunkMap.ChunkDistanceManager(executor, mainThreadExecutor);
|
|
this.overworldDataStorage = persistentStateManagerFactory;
|