mirror of
https://github.com/PaperMC/Folia.git
synced 2025-01-02 18:37:47 +01:00
Adjust shutdown logic to close player inventories
We need to drop items in special containers on shutdown to prevent them from being lost. Fixes https://github.com/PaperMC/Folia/issues/148
This commit is contained in:
parent
815dd7bae8
commit
eb5ec0b932
@ -1195,17 +1195,21 @@ index c03608fec96b51e1867f43d8f42e5aefb1520e46..127d96280cad2d4e5db574a089d67ad6
|
||||
* on all currently scheduled tasks.
|
||||
diff --git a/src/main/java/io/papermc/paper/threadedregions/RegionShutdownThread.java b/src/main/java/io/papermc/paper/threadedregions/RegionShutdownThread.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..e8550cd33ca171aeffb1f40854f80c7ad6c81edf
|
||||
index 0000000000000000000000000000000000000000..261b3019878c31a9e44e56b6611899de6c00ebee
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/threadedregions/RegionShutdownThread.java
|
||||
@@ -0,0 +1,174 @@
|
||||
@@ -0,0 +1,226 @@
|
||||
+package io.papermc.paper.threadedregions;
|
||||
+
|
||||
+import ca.spottedleaf.moonrise.common.util.WorldUtil;
|
||||
+import com.mojang.logging.LogUtils;
|
||||
+import net.minecraft.server.MinecraftServer;
|
||||
+import net.minecraft.server.level.ServerLevel;
|
||||
+import net.minecraft.server.level.ServerPlayer;
|
||||
+import net.minecraft.world.entity.Entity;
|
||||
+import net.minecraft.world.item.ItemStack;
|
||||
+import net.minecraft.world.level.ChunkPos;
|
||||
+import org.bukkit.event.inventory.InventoryCloseEvent;
|
||||
+import org.slf4j.Logger;
|
||||
+import java.util.ArrayList;
|
||||
+import java.util.List;
|
||||
@ -1314,18 +1318,42 @@ index 0000000000000000000000000000000000000000..e8550cd33ca171aeffb1f40854f80c7a
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private void haltWorldNoRegions(final ServerLevel world) {
|
||||
+ private void closePlayerInventories(final ThreadedRegionizer.ThreadedRegion<TickRegions.TickRegionData, TickRegions.TickRegionSectionData> region) {
|
||||
+ ChunkPos center = null;
|
||||
+ try {
|
||||
+ world.moonrise$getChunkTaskScheduler().chunkHolderManager.close(true, true, true, true, false);
|
||||
+ this.shuttingDown = region;
|
||||
+ center = region.getCenterChunk();
|
||||
+
|
||||
+ final RegionizedWorldData worldData = region.regioniser.world.worldRegionData.get();
|
||||
+
|
||||
+ for (final ServerPlayer player : worldData.getLocalPlayers()) {
|
||||
+ try {
|
||||
+ // close inventory
|
||||
+ if (player.containerMenu != player.inventoryMenu) {
|
||||
+ player.closeContainer(InventoryCloseEvent.Reason.DISCONNECT);
|
||||
+ }
|
||||
+
|
||||
+ // drop carried item
|
||||
+ if (!player.containerMenu.getCarried().isEmpty()) {
|
||||
+ ItemStack carried = player.containerMenu.getCarried();
|
||||
+ player.containerMenu.setCarried(ItemStack.EMPTY);
|
||||
+ player.drop(carried, false);
|
||||
+ }
|
||||
+ } catch (final Throwable thr) {
|
||||
+ LOGGER.error("Failed to close world '" + world.getWorld().getName() + "' with no regions", thr);
|
||||
+ LOGGER.error("Failed to close player inventory for player: " + player, thr);
|
||||
+ }
|
||||
+ }
|
||||
+ } catch (final Throwable thr) {
|
||||
+ LOGGER.error("Failed to close player inventories for region around chunk " + center + " in world '" + region.regioniser.world.getWorld().getName() + "'", thr);
|
||||
+ } finally {
|
||||
+ this.shuttingDown = null;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public final void run() {
|
||||
+ // await scheduler termination
|
||||
+ LOGGER.info("Awaiting scheduler termination for 60s");
|
||||
+ LOGGER.info("Awaiting scheduler termination for 60s...");
|
||||
+ if (TickRegions.getScheduler().halt(true, TimeUnit.SECONDS.toNanos(60L))) {
|
||||
+ LOGGER.info("Scheduler halted");
|
||||
+ } else {
|
||||
@ -1335,7 +1363,7 @@ index 0000000000000000000000000000000000000000..e8550cd33ca171aeffb1f40854f80c7a
|
||||
+
|
||||
+ MinecraftServer.getServer().stopServer(); // stop part 1: most logic, kicking players, plugins, etc
|
||||
+ // halt all chunk systems first so that any in-progress chunk generation stops
|
||||
+ LOGGER.info("Halting chunk systems");
|
||||
+ LOGGER.info("Halting chunk systems...");
|
||||
+ for (final ServerLevel world : MinecraftServer.getServer().getAllLevels()) {
|
||||
+ try {
|
||||
+ world.moonrise$getChunkTaskScheduler().halt(false, 0L);
|
||||
@ -1347,27 +1375,51 @@ index 0000000000000000000000000000000000000000..e8550cd33ca171aeffb1f40854f80c7a
|
||||
+ this.haltChunkSystem(world);
|
||||
+ }
|
||||
+ LOGGER.info("Halted chunk systems");
|
||||
+
|
||||
+ LOGGER.info("Finishing pending teleports...");
|
||||
+ for (final ServerLevel world : MinecraftServer.getServer().getAllLevels()) {
|
||||
+ final List<ThreadedRegionizer.ThreadedRegion<TickRegions.TickRegionData, TickRegions.TickRegionSectionData>>
|
||||
+ regions = new ArrayList<>();
|
||||
+ world.regioniser.computeForAllRegionsUnsynchronised(regions::add);
|
||||
+
|
||||
+ for (int i = 0, len = regions.size(); i < len; ++i) {
|
||||
+ final ThreadedRegionizer.ThreadedRegion<TickRegions.TickRegionData, TickRegions.TickRegionSectionData> region = regions.get(i);
|
||||
+ this.finishTeleportations(region, world);
|
||||
+ this.finishTeleportations(regions.get(i), world);
|
||||
+ }
|
||||
+ }
|
||||
+ LOGGER.info("Finished pending teleports");
|
||||
+
|
||||
+ LOGGER.info("Saving all worlds");
|
||||
+ for (final ServerLevel world : MinecraftServer.getServer().getAllLevels()) {
|
||||
+ LOGGER.info("Saving world data for world '" + WorldUtil.getWorldName(world) + "'");
|
||||
+
|
||||
+ final List<ThreadedRegionizer.ThreadedRegion<TickRegions.TickRegionData, TickRegions.TickRegionSectionData>>
|
||||
+ regions = new ArrayList<>();
|
||||
+ world.regioniser.computeForAllRegionsUnsynchronised(regions::add);
|
||||
+
|
||||
+ LOGGER.info("Closing player inventories...");
|
||||
+ for (int i = 0, len = regions.size(); i < len; ++i) {
|
||||
+ final ThreadedRegionizer.ThreadedRegion<TickRegions.TickRegionData, TickRegions.TickRegionSectionData> region = regions.get(i);
|
||||
+ this.saveRegionChunks(region, (i + 1) == len);
|
||||
+ this.closePlayerInventories(regions.get(i));
|
||||
+ }
|
||||
+ LOGGER.info("Closed player inventories");
|
||||
+
|
||||
+ this.saveLevelData(world);
|
||||
+ LOGGER.info("Saving chunks...");
|
||||
+ for (int i = 0, len = regions.size(); i < len; ++i) {
|
||||
+ this.saveRegionChunks(regions.get(i), (i + 1) == len);
|
||||
+ }
|
||||
+ // moved from stop part 1
|
||||
+ // we need this to be after saving level data, as that will complete any teleportations the player is in
|
||||
+ LOGGER.info("Saving players");
|
||||
+ LOGGER.info("Saved chunks");
|
||||
+
|
||||
+ LOGGER.info("Saving level data...");
|
||||
+ this.saveLevelData(world);
|
||||
+ LOGGER.info("Saved level data");
|
||||
+
|
||||
+ LOGGER.info("Saved world data for world '" + WorldUtil.getWorldName(world) + "'");
|
||||
+ }
|
||||
+ LOGGER.info("Saved all worlds");
|
||||
+
|
||||
+ // Note: only save after world data and pending teleportations
|
||||
+ LOGGER.info("Saving all player data...");
|
||||
+ MinecraftServer.getServer().getPlayerList().saveAll();
|
||||
+ LOGGER.info("Saved all player data");
|
||||
+
|
||||
+ MinecraftServer.getServer().stopPart2(); // stop part 2: close other resources (io thread, etc)
|
||||
+ // done, part 2 should call exit()
|
||||
|
Loading…
Reference in New Issue
Block a user