Fix bot connection region crash (#149)
* Fix: bot connection causing region crash, fix readme * Fix NPE on Region Shutdown with bots * simple fix up * Revert "Fix NPE on Region Shutdown with bots" This reverts commitb55c982cb9. * Revert "fix: fix a bug in server shutdown with fakeplayer" This reverts commita721c27e96. * fix: improve bot shutdown handling to prevent region crashes --------- Co-authored-by: Helvetica Volubi <suisuroru@blue-millennium.fun>
This commit is contained in:
@@ -33,7 +33,7 @@ index efbbc1a40d203a2818eeda2a4e938b9a6117f1c3..6b85a5ad9af0c57a0d4d5b55f62b82c5
|
||||
private boolean encrypted;
|
||||
private final java.util.concurrent.atomic.AtomicBoolean disconnectionHandled = new java.util.concurrent.atomic.AtomicBoolean(false); // Folia - region threading - may be called concurrently during configuration stage
|
||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index 9e290fa626caffac148920c54479a75ad0919e70..54eaf4f7f8cf728d5d02d88de8d57d88504bc46d 100644
|
||||
index 9e290fa626caffac148920c54479a75ad0919e70..75d93d7d8bc6077dd80e499cd43327a4afe58f51 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -297,6 +297,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -45,15 +45,24 @@ index 9e290fa626caffac148920c54479a75ad0919e70..54eaf4f7f8cf728d5d02d88de8d57d88
|
||||
public static <S extends MinecraftServer> S spin(final Function<Thread, S> factory) {
|
||||
ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.init(); // Paper - rewrite data converter system
|
||||
AtomicReference<S> serverReference = new AtomicReference<>();
|
||||
@@ -1120,6 +1122,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
LOGGER.info("Stopping server");
|
||||
Commands.COMMAND_SENDING_POOL.shutdownNow(); // Paper - Perf: Async command map building; Shutdown and don't bother finishing
|
||||
+ this.getBotList().removeAll(); // Leaves - save or remove bot
|
||||
// CraftBukkit start
|
||||
if (this.server != null) {
|
||||
if (false) this.server.spark.disable(); // Paper - spark // Luminol - Force disable builtin spark
|
||||
@@ -1695,7 +1698,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -1226,6 +1228,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
this.safeShutdown(wait, false);
|
||||
}
|
||||
public void safeShutdown(final boolean wait, final boolean isRestarting) {
|
||||
+ // Lophine start - Folia changes
|
||||
+ safeShutdown(wait, isRestarting, false);
|
||||
+ }
|
||||
+
|
||||
+ public void safeShutdown(final boolean wait, final boolean isRestarting, boolean force) {
|
||||
+ if (!force && !this.getBotList().forceShutdown && !this.getBotList().removeAll()) { // Leaves - save or remove bot
|
||||
+ this.getPlayerList().broadcastSystemMessage(Component.literal("Bot Still need to save, please wait! If you want to shuntdown without bot data saving, please use /stop force"), false);
|
||||
+ return;
|
||||
+ }
|
||||
+ // Lophine end - Folia changes
|
||||
this.isRestarting = isRestarting;
|
||||
this.hasLoggedStop = true; // Paper - Debugging
|
||||
if (this.isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Server stopped"); // Paper - Debugging
|
||||
@@ -1695,7 +1707,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
int emptyTickThreshold = this.pauseWhenEmptySeconds() * 20;
|
||||
this.removeDisabledPluginsBlockingSleep(); // Paper - API to allow/disallow tick sleeping
|
||||
if (false && emptyTickThreshold > 0) { // Folia - region threading - this is complicated to implement, and even if done correctly is messy
|
||||
@@ -62,7 +71,7 @@ index 9e290fa626caffac148920c54479a75ad0919e70..54eaf4f7f8cf728d5d02d88de8d57d88
|
||||
this.emptyTicks++;
|
||||
} else {
|
||||
this.emptyTicks = 0;
|
||||
@@ -1827,6 +1830,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -1827,6 +1839,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
this.isSaving = true;
|
||||
if (playerSaveInterval > 0) {
|
||||
this.playerList.saveAll(playerSaveInterval);
|
||||
@@ -70,7 +79,7 @@ index 9e290fa626caffac148920c54479a75ad0919e70..54eaf4f7f8cf728d5d02d88de8d57d88
|
||||
}
|
||||
if (region == null && fullSave) { // Folia - region threading - don't auto save level data
|
||||
this.saveGlobalData(false);
|
||||
@@ -2065,6 +2069,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -2065,6 +2078,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
protected void tickConnection() {
|
||||
this.getConnection().tick();
|
||||
@@ -78,7 +87,7 @@ index 9e290fa626caffac148920c54479a75ad0919e70..54eaf4f7f8cf728d5d02d88de8d57d88
|
||||
}
|
||||
|
||||
public void forceGameTimeSynchronization() {
|
||||
@@ -3270,6 +3275,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -3270,6 +3284,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
return this.debugSubscribers;
|
||||
}
|
||||
|
||||
@@ -213,6 +222,22 @@ index 636f56bfc0e9075b257e2eb14e858975bdedd801..20cbc0e65fea3fc2d0033259c2f35e15
|
||||
if (!list.isOp(player)) {
|
||||
list.op(player);
|
||||
count++;
|
||||
diff --git a/net/minecraft/server/commands/StopCommand.java b/net/minecraft/server/commands/StopCommand.java
|
||||
index e9c9a468f046832e8eaa999bb57da261b4633604..2efe24c0378a80dd2750b10a54c1887816236c1a 100644
|
||||
--- a/net/minecraft/server/commands/StopCommand.java
|
||||
+++ b/net/minecraft/server/commands/StopCommand.java
|
||||
@@ -11,6 +11,10 @@ public class StopCommand {
|
||||
c.getSource().sendSuccess(() -> Component.translatable("commands.stop.stopping"), true);
|
||||
c.getSource().getServer().halt(false);
|
||||
return 1;
|
||||
- }));
|
||||
+ }).then(Commands.literal("force").requires(Commands.hasPermission(Commands.LEVEL_OWNERS)).executes(c -> {
|
||||
+ c.getSource().sendSuccess(() -> Component.translatable("commands.stop.stopping"), true);
|
||||
+ c.getSource().getServer().safeShutdown(false, false, true);
|
||||
+ return 1;
|
||||
+ })));
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
index 1bc1e9a77dca7acfe5f989f6439f185d0d2e20a6..1790e8c141a8d3f7ccf4b11f9a28b3582325e317 100644
|
||||
--- a/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
|
||||
@@ -84,10 +84,10 @@ index 7e3912b8b29e40eb3347f1451b0fd3ebee2af4f1..0834e402e6af7028e08851378e15390e
|
||||
result.add(player);
|
||||
if (result.size() >= limit) {
|
||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index 54eaf4f7f8cf728d5d02d88de8d57d88504bc46d..269b884ff30d908f772d1c0cf05076e359bcdd7e 100644
|
||||
index 75d93d7d8bc6077dd80e499cd43327a4afe58f51..3b9a4f4b5794faa4955018858c94fd5c2d6ada3d 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -1921,7 +1921,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -1930,7 +1930,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
}
|
||||
|
||||
private ServerStatus.Players buildPlayerStatus() {
|
||||
@@ -96,7 +96,7 @@ index 54eaf4f7f8cf728d5d02d88de8d57d88504bc46d..269b884ff30d908f772d1c0cf05076e3
|
||||
int maxPlayers = this.getMaxPlayers();
|
||||
if (this.hidesOnlinePlayers()) {
|
||||
return new ServerStatus.Players(maxPlayers, players.size(), List.of());
|
||||
@@ -2142,7 +2142,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -2151,7 +2151,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
@Override
|
||||
public int getPlayerCount() {
|
||||
@@ -105,7 +105,7 @@ index 54eaf4f7f8cf728d5d02d88de8d57d88504bc46d..269b884ff30d908f772d1c0cf05076e3
|
||||
}
|
||||
|
||||
public String[] getPlayerNames() {
|
||||
@@ -2354,7 +2354,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -2363,7 +2363,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
} else {
|
||||
int count = 0;
|
||||
|
||||
@@ -114,7 +114,7 @@ index 54eaf4f7f8cf728d5d02d88de8d57d88504bc46d..269b884ff30d908f772d1c0cf05076e3
|
||||
player.getBukkitEntity().taskScheduler.schedule((ServerPlayer updatedPlayer) -> { // Folia - region threading
|
||||
// Paper start - Expand PlayerGameModeChangeEvent
|
||||
org.bukkit.event.player.PlayerGameModeChangeEvent event = updatedPlayer.setGameMode(gameType, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.DEFAULT_GAMEMODE, null); // Folia - region threading
|
||||
@@ -2541,7 +2541,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -2550,7 +2550,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
if (Thread.currentThread() != this.serverThread) return; // Paper
|
||||
// Paper start - we don't need to save everything, just advancements
|
||||
// this.getPlayerList().saveAll();
|
||||
@@ -123,7 +123,7 @@ index 54eaf4f7f8cf728d5d02d88de8d57d88504bc46d..269b884ff30d908f772d1c0cf05076e3
|
||||
player.getAdvancements().save();
|
||||
}
|
||||
// Paper end - we don't need to save everything, just advancements
|
||||
@@ -2677,7 +2677,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -2686,7 +2686,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
PlayerList playerList = this.getPlayerList();
|
||||
UserWhiteList whiteList = playerList.getWhiteList();
|
||||
|
||||
|
||||
+2
-2
@@ -32,10 +32,10 @@ index 24f5b890b0126fc817863f99b676da1a548f7608..78bea975c15130c91c90f48c868ac32e
|
||||
throw PacketUtils.makeReportedException(var3, this.packet, this.listener);
|
||||
}
|
||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index 269b884ff30d908f772d1c0cf05076e359bcdd7e..fe5f6eb98aaa29b2745f4db51b9daad2666ec8f1 100644
|
||||
index 3b9a4f4b5794faa4955018858c94fd5c2d6ada3d..19bef18e606d873308d08987d90e298703efb574 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -2010,11 +2010,26 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -2019,11 +2019,26 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
try {
|
||||
foliaProfiler.startTimer(level.tickTimerId); try { // Folia - profiler
|
||||
level.tick(haveTime, region); // Folia - region threading
|
||||
|
||||
@@ -50,10 +50,12 @@ import org.bukkit.Location;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.craftbukkit.CraftWorld;
|
||||
import org.bukkit.event.entity.EntityRemoveEvent;
|
||||
import org.bukkit.metadata.FixedMetadataValue;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.leavesmc.leaves.event.bot.*;
|
||||
import org.leavesmc.leaves.plugin.MinecraftInternalPlugin;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.util.*;
|
||||
@@ -190,7 +192,11 @@ public class BotList {
|
||||
bot.isRealPlayer = true;
|
||||
bot.loginTime = System.currentTimeMillis();
|
||||
bot.connection = new ServerBotPacketListenerImpl(this.server, bot);
|
||||
if (bot.connection.connection.getPlayer() != bot) {
|
||||
throw new IllegalStateException("Bot connection is not bound to its bot player");
|
||||
}
|
||||
bot.connection.markClientLoaded();
|
||||
bot.getBukkitEntity().setMetadata("NPC", new FixedMetadataValue(MinecraftInternalPlugin.INSTANCE, true));
|
||||
bot.setServerLevel(world);
|
||||
|
||||
BotSpawnLocationEvent event = new BotSpawnLocationEvent(bot.getBukkitEntity(), location);
|
||||
@@ -315,7 +321,7 @@ public class BotList {
|
||||
}
|
||||
}
|
||||
|
||||
if (!TickThread.isShutdownThread()) bot.level().getCurrentWorldData().connections.remove(bot.connection.connection);
|
||||
bot.level().getCurrentWorldData().connections.remove(bot.connection.connection);
|
||||
bot.level().removePlayerImmediately(bot, Entity.RemovalReason.UNLOADED_WITH_PLAYER);
|
||||
bot.retireScheduler();
|
||||
|
||||
|
||||
+10
-3
@@ -31,7 +31,12 @@ import org.jetbrains.annotations.Nullable;
|
||||
public class ServerBotPacketListenerImpl extends ServerGamePacketListenerImpl {
|
||||
|
||||
public ServerBotPacketListenerImpl(MinecraftServer server, ServerBot bot) {
|
||||
super(server, BotConnection.INSTANCE, bot, CommonListenerCookie.createInitial(bot.gameProfile, false));
|
||||
this(server, bot, new BotConnection());
|
||||
}
|
||||
|
||||
private ServerBotPacketListenerImpl(MinecraftServer server, ServerBot bot, BotConnection connection) {
|
||||
super(server, connection, bot, CommonListenerCookie.createInitial(bot.gameProfile, false));
|
||||
connection.bind(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -53,12 +58,14 @@ public class ServerBotPacketListenerImpl extends ServerGamePacketListenerImpl {
|
||||
|
||||
public static class BotConnection extends Connection {
|
||||
|
||||
private static final BotConnection INSTANCE = new BotConnection();
|
||||
|
||||
public BotConnection() {
|
||||
super(PacketFlow.SERVERBOUND);
|
||||
}
|
||||
|
||||
private void bind(ServerBotPacketListenerImpl listener) {
|
||||
this.packetListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user