mirror of
https://github.com/PaperMC/Paper.git
synced 2024-11-22 15:17:17 +01:00
Remove ThreadedWorldUpgrader patch
The patch does not implement Vanilla forceUpgrade behavior. Specifically, poi/entity conversion and regionfile recreation. The Vanilla force upgrader is also no longer broken by CB, so the bug fixes from this patch are not relevant anymore.
This commit is contained in:
parent
9bf4855524
commit
66cb880754
22 changed files with 10 additions and 425 deletions
|
@ -21,7 +21,7 @@ index ee58c67cb2bd78159cce19ec75f13dc6168a0e7a..149cfb0587299f72fcfddf395fb71b70
|
|||
|
||||
// TODO rebase into util patch
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
index 6f8999df04e6ad4d4d52e87b05a187f586d60c74..a9aa3dca65aca86cf535d6616f5d5db3e1e8fc8b 100644
|
||||
index 2d373be107a610522db9b3ce8ae446b848d92580..84ed5dc8c82e28aa93fa0440d90ddb44dc5f3d40 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -3446,6 +3446,35 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
|
@ -1,395 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Thu, 20 May 2021 07:02:22 -0700
|
||||
Subject: [PATCH] Fix and optimise world force upgrading
|
||||
|
||||
The WorldUpgrader class was incorrectly modified by
|
||||
CB. It will store an IChunkLoader instance for all
|
||||
dimension types in the world, but obviously with how
|
||||
CB shifts around worlds only one dimension type exists
|
||||
per world. But this would be OK if CB did this
|
||||
change correctly. All IChunkLoader instances
|
||||
will point to the same regionfiles. And all
|
||||
IChunkLoader instances are going to be read from.
|
||||
|
||||
This problem hasn't really been reported because
|
||||
it relies on the persistent legacy data to be converted
|
||||
as well to cause corruption. Why? Because the legacy
|
||||
data is also shared, it will result in different
|
||||
outputs from conversion (as once conversion for legacy
|
||||
persistent data takes place, it is REMOVED - so the next
|
||||
convert will _not_ have the data). Which means different
|
||||
sizes on disk. Which means different regionfile sector
|
||||
allocations. Which means there are 3 different possible
|
||||
regionfile sector allocations in memory, and none of them
|
||||
are going to be correct.
|
||||
|
||||
I've fixed this by writing a world upgrader suited to
|
||||
CB's changes to world folder format. It was brain dead
|
||||
easy to add threading, so I did.
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.util.worldupdate.WorldUpgrader REGEX
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/world/ThreadedWorldUpgrader.java b/src/main/java/io/papermc/paper/world/ThreadedWorldUpgrader.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..e049fbe4038aaea896f45b11ce9ce8f05922c898
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/world/ThreadedWorldUpgrader.java
|
||||
@@ -0,0 +1,222 @@
|
||||
+package io.papermc.paper.world;
|
||||
+
|
||||
+import com.mojang.datafixers.DataFixer;
|
||||
+import com.mojang.serialization.MapCodec;
|
||||
+import net.minecraft.SharedConstants;
|
||||
+import net.minecraft.core.RegistryAccess;
|
||||
+import net.minecraft.core.registries.Registries;
|
||||
+import net.minecraft.nbt.CompoundTag;
|
||||
+import net.minecraft.resources.ResourceKey;
|
||||
+import net.minecraft.util.worldupdate.WorldUpgrader;
|
||||
+import net.minecraft.world.level.ChunkPos;
|
||||
+import net.minecraft.world.level.Level;
|
||||
+import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||
+import net.minecraft.world.level.chunk.storage.ChunkStorage;
|
||||
+import net.minecraft.world.level.chunk.storage.RegionFileStorage;
|
||||
+import net.minecraft.world.level.chunk.storage.RegionStorageInfo;
|
||||
+import net.minecraft.world.level.dimension.LevelStem;
|
||||
+import net.minecraft.world.level.storage.DimensionDataStorage;
|
||||
+import net.minecraft.world.level.storage.LevelStorageSource;
|
||||
+import org.apache.logging.log4j.LogManager;
|
||||
+import org.apache.logging.log4j.Logger;
|
||||
+import java.io.File;
|
||||
+import java.io.IOException;
|
||||
+import java.text.DecimalFormat;
|
||||
+import java.util.Optional;
|
||||
+import java.util.concurrent.ExecutorService;
|
||||
+import java.util.concurrent.Executors;
|
||||
+import java.util.concurrent.ThreadFactory;
|
||||
+import java.util.concurrent.atomic.AtomicInteger;
|
||||
+import java.util.concurrent.atomic.AtomicLong;
|
||||
+import java.util.function.Supplier;
|
||||
+
|
||||
+public class ThreadedWorldUpgrader {
|
||||
+
|
||||
+ private static final Logger LOGGER = LogManager.getLogger();
|
||||
+
|
||||
+ private final ResourceKey<LevelStem> dimensionType;
|
||||
+ private final String worldName;
|
||||
+ private final File worldDir;
|
||||
+ private final ExecutorService threadPool;
|
||||
+ private final DataFixer dataFixer;
|
||||
+ private final RegistryAccess registryLookup;
|
||||
+ private final Optional<ResourceKey<MapCodec<? extends ChunkGenerator>>> generatorKey;
|
||||
+ private final boolean removeCaches;
|
||||
+ private final boolean recreateRegionFiles; // TODO
|
||||
+
|
||||
+ public ThreadedWorldUpgrader(final ResourceKey<LevelStem> dimensionType, final String worldName, final File worldDir, final int threads,
|
||||
+ final DataFixer dataFixer, final RegistryAccess registryLookup, final Optional<ResourceKey<MapCodec<? extends ChunkGenerator>>> generatorKey,
|
||||
+ final boolean removeCaches, final boolean recreateRegionFiles) {
|
||||
+ this.dimensionType = dimensionType;
|
||||
+ this.worldName = worldName;
|
||||
+ this.worldDir = worldDir;
|
||||
+ this.threadPool = Executors.newFixedThreadPool(Math.max(1, threads), new ThreadFactory() {
|
||||
+ private final AtomicInteger threadCounter = new AtomicInteger();
|
||||
+
|
||||
+ @Override
|
||||
+ public Thread newThread(final Runnable run) {
|
||||
+ final Thread ret = new Thread(run);
|
||||
+
|
||||
+ ret.setName("World upgrader thread for world " + ThreadedWorldUpgrader.this.worldName + " #" + this.threadCounter.getAndIncrement());
|
||||
+ ret.setUncaughtExceptionHandler((thread, throwable) -> {
|
||||
+ LOGGER.fatal("Error upgrading world", throwable);
|
||||
+ });
|
||||
+
|
||||
+ return ret;
|
||||
+ }
|
||||
+ });
|
||||
+ this.dataFixer = dataFixer;
|
||||
+ this.registryLookup = registryLookup;
|
||||
+ this.generatorKey = generatorKey;
|
||||
+ this.removeCaches = removeCaches;
|
||||
+ this.recreateRegionFiles = recreateRegionFiles;
|
||||
+ }
|
||||
+
|
||||
+ public void convert() {
|
||||
+ final File worldFolder = LevelStorageSource.getStorageFolder(this.worldDir.toPath(), this.dimensionType).toFile();
|
||||
+ final DimensionDataStorage worldPersistentData = new DimensionDataStorage(new File(worldFolder, "data"), this.dataFixer, this.registryLookup);
|
||||
+
|
||||
+ final File regionFolder = new File(worldFolder, "region");
|
||||
+
|
||||
+ LOGGER.info("Force upgrading {}", this.worldName);
|
||||
+ LOGGER.info("Counting regionfiles for {}", this.worldName);
|
||||
+ final File[] regionFiles = regionFolder.listFiles((final File dir, final String name) -> {
|
||||
+ return WorldUpgrader.REGEX.matcher(name).matches();
|
||||
+ });
|
||||
+ if (regionFiles == null) {
|
||||
+ LOGGER.info("Found no regionfiles to convert for world {}", this.worldName);
|
||||
+ return;
|
||||
+ }
|
||||
+ LOGGER.info("Found {} regionfiles to convert", regionFiles.length);
|
||||
+ LOGGER.info("Starting conversion now for world {}", this.worldName);
|
||||
+
|
||||
+ // Only used for profiling, let's fill it anyways just in case
|
||||
+ final RegionStorageInfo storageInfo = new RegionStorageInfo(
|
||||
+ this.worldName,
|
||||
+ ResourceKey.create(Registries.DIMENSION, this.dimensionType.location()),
|
||||
+ "region"
|
||||
+ );
|
||||
+
|
||||
+ final WorldInfo info = new WorldInfo(() -> worldPersistentData,
|
||||
+ new ChunkStorage(storageInfo, regionFolder.toPath(), this.dataFixer, false), this.removeCaches, this.dimensionType, this.generatorKey);
|
||||
+
|
||||
+ long expectedChunks = (long)regionFiles.length * (32L * 32L);
|
||||
+
|
||||
+ for (final File regionFile : regionFiles) {
|
||||
+ final ChunkPos regionPos = RegionFileStorage.getRegionFileCoordinates(regionFile.toPath());
|
||||
+ if (regionPos == null) {
|
||||
+ expectedChunks -= (32L * 32L);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ this.threadPool.execute(new ConvertTask(info, regionPos.x >> 5, regionPos.z >> 5));
|
||||
+ }
|
||||
+ this.threadPool.shutdown();
|
||||
+
|
||||
+ final DecimalFormat format = new DecimalFormat("#0.00");
|
||||
+
|
||||
+ final long start = System.nanoTime();
|
||||
+
|
||||
+ while (!this.threadPool.isTerminated()) {
|
||||
+ final long current = info.convertedChunks.get();
|
||||
+
|
||||
+ LOGGER.info("{}% completed ({} / {} chunks)...", format.format((double)current / (double)expectedChunks * 100.0), current, expectedChunks);
|
||||
+
|
||||
+ try {
|
||||
+ Thread.sleep(1000L);
|
||||
+ } catch (final InterruptedException ignore) {}
|
||||
+ }
|
||||
+
|
||||
+ final long end = System.nanoTime();
|
||||
+
|
||||
+ try {
|
||||
+ info.loader.close();
|
||||
+ } catch (final IOException ex) {
|
||||
+ LOGGER.fatal("Failed to close chunk loader", ex);
|
||||
+ }
|
||||
+ LOGGER.info("Completed conversion. Took {}s, {} out of {} chunks needed to be converted/modified ({}%)",
|
||||
+ (int)Math.ceil((end - start) * 1.0e-9), info.modifiedChunks.get(), expectedChunks, format.format((double)info.modifiedChunks.get() / (double)expectedChunks * 100.0));
|
||||
+ }
|
||||
+
|
||||
+ private static final class WorldInfo {
|
||||
+
|
||||
+ public final Supplier<DimensionDataStorage> persistentDataSupplier;
|
||||
+ public final ChunkStorage loader;
|
||||
+ public final boolean removeCaches;
|
||||
+ public final ResourceKey<LevelStem> worldKey;
|
||||
+ public final Optional<ResourceKey<MapCodec<? extends ChunkGenerator>>> generatorKey;
|
||||
+ public final AtomicLong convertedChunks = new AtomicLong();
|
||||
+ public final AtomicLong modifiedChunks = new AtomicLong();
|
||||
+
|
||||
+ private WorldInfo(final Supplier<DimensionDataStorage> persistentDataSupplier, final ChunkStorage loader, final boolean removeCaches,
|
||||
+ final ResourceKey<LevelStem> worldKey, Optional<ResourceKey<MapCodec<? extends ChunkGenerator>>> generatorKey) {
|
||||
+ this.persistentDataSupplier = persistentDataSupplier;
|
||||
+ this.loader = loader;
|
||||
+ this.removeCaches = removeCaches;
|
||||
+ this.worldKey = worldKey;
|
||||
+ this.generatorKey = generatorKey;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private static final class ConvertTask implements Runnable {
|
||||
+
|
||||
+ private final WorldInfo worldInfo;
|
||||
+ private final int regionX;
|
||||
+ private final int regionZ;
|
||||
+
|
||||
+ public ConvertTask(final WorldInfo worldInfo, final int regionX, final int regionZ) {
|
||||
+ this.worldInfo = worldInfo;
|
||||
+ this.regionX = regionX;
|
||||
+ this.regionZ = regionZ;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void run() {
|
||||
+ final int regionCX = this.regionX << 5;
|
||||
+ final int regionCZ = this.regionZ << 5;
|
||||
+
|
||||
+ final Supplier<DimensionDataStorage> persistentDataSupplier = this.worldInfo.persistentDataSupplier;
|
||||
+ final ChunkStorage loader = this.worldInfo.loader;
|
||||
+ final boolean removeCaches = this.worldInfo.removeCaches;
|
||||
+ final ResourceKey<LevelStem> worldKey = this.worldInfo.worldKey;
|
||||
+
|
||||
+ for (int cz = regionCZ; cz < (regionCZ + 32); ++cz) {
|
||||
+ for (int cx = regionCX; cx < (regionCX + 32); ++cx) {
|
||||
+ final ChunkPos chunkPos = new ChunkPos(cx, cz);
|
||||
+ try {
|
||||
+ // no need to check the coordinate of the chunk, the regionfilecache does that for us
|
||||
+
|
||||
+ CompoundTag chunkNBT = (loader.read(chunkPos).join()).orElse(null);
|
||||
+
|
||||
+ if (chunkNBT == null) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ final int versionBefore = ChunkStorage.getVersion(chunkNBT);
|
||||
+
|
||||
+ chunkNBT = loader.upgradeChunkTag(worldKey, persistentDataSupplier, chunkNBT, this.worldInfo.generatorKey, chunkPos, null);
|
||||
+
|
||||
+ boolean modified = versionBefore < SharedConstants.getCurrentVersion().getDataVersion().getVersion();
|
||||
+
|
||||
+ if (removeCaches) {
|
||||
+ final CompoundTag level = chunkNBT.getCompound("Level");
|
||||
+ modified |= level.contains("Heightmaps");
|
||||
+ level.remove("Heightmaps");
|
||||
+ modified |= level.contains("isLightOn");
|
||||
+ level.remove("isLightOn");
|
||||
+ }
|
||||
+
|
||||
+ if (modified) {
|
||||
+ this.worldInfo.modifiedChunks.getAndIncrement();
|
||||
+ loader.write(chunkPos, chunkNBT);
|
||||
+ }
|
||||
+ } catch (final Exception ex) {
|
||||
+ LOGGER.error("Error upgrading chunk {}", chunkPos, ex);
|
||||
+ } finally {
|
||||
+ this.worldInfo.convertedChunks.getAndIncrement();
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java
|
||||
index 244a19ecd0234fa1d7a6ecfea20751595688605d..5443013060b62e3bfcc51cddca96d1c0bc59fe72 100644
|
||||
--- a/src/main/java/net/minecraft/server/Main.java
|
||||
+++ b/src/main/java/net/minecraft/server/Main.java
|
||||
@@ -392,6 +392,15 @@ public class Main {
|
||||
return new WorldLoader.InitConfig(worldloader_d, Commands.CommandSelection.DEDICATED, serverPropertiesHandler.functionPermissionLevel);
|
||||
}
|
||||
|
||||
+ // Paper start - fix and optimise world upgrading
|
||||
+ public static void convertWorldButItWorks(net.minecraft.resources.ResourceKey<net.minecraft.world.level.dimension.LevelStem> dimensionType, net.minecraft.world.level.storage.LevelStorageSource.LevelStorageAccess worldSession,
|
||||
+ DataFixer dataFixer, RegistryAccess registryLookup, Optional<net.minecraft.resources.ResourceKey<com.mojang.serialization.MapCodec<? extends net.minecraft.world.level.chunk.ChunkGenerator>>> generatorKey, boolean removeCaches, boolean recreateRegionFiles) {
|
||||
+ int threads = Runtime.getRuntime().availableProcessors() * 3 / 8;
|
||||
+ final io.papermc.paper.world.ThreadedWorldUpgrader worldUpgrader = new io.papermc.paper.world.ThreadedWorldUpgrader(dimensionType, worldSession.getLevelId(), worldSession.levelDirectory.path().toFile(), threads, dataFixer, registryLookup, generatorKey, removeCaches, recreateRegionFiles);
|
||||
+ worldUpgrader.convert();
|
||||
+ }
|
||||
+ // Paper end - fix and optimise world upgrading
|
||||
+
|
||||
public static void forceUpgrade(LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, boolean eraseCache, BooleanSupplier continueCheck, RegistryAccess dynamicRegistryManager, boolean recreateRegionFiles) {
|
||||
Main.LOGGER.info("Forcing world upgrade! {}", session.getLevelId()); // CraftBukkit
|
||||
WorldUpgrader worldupgrader = new WorldUpgrader(session, dataFixer, dynamicRegistryManager, eraseCache, recreateRegionFiles);
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 0408d5d54fef7767ecf70e70686ad520d890ff26..f525a8735e5cf5eb1278e2a3002ac81d9fff7b1a 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -596,11 +596,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
worlddata = new PrimaryLevelData(worldsettings, worldoptions, worlddimensions_b.specialWorldProperty(), lifecycle);
|
||||
}
|
||||
worlddata.checkName(name); // CraftBukkit - Migration did not rewrite the level.dat; This forces 1.8 to take the last loaded world as respawn (in this case the end)
|
||||
- if (this.options.has("forceUpgrade")) {
|
||||
- net.minecraft.server.Main.forceUpgrade(worldSession, DataFixers.getDataFixer(), this.options.has("eraseCache"), () -> {
|
||||
- return true;
|
||||
- }, iregistrycustom_dimension, this.options.has("recreateRegionFiles"));
|
||||
- }
|
||||
+ // Paper - fix and optimise world upgrading; move down
|
||||
|
||||
PrimaryLevelData iworlddataserver = worlddata;
|
||||
boolean flag = worlddata.isDebugWorld();
|
||||
@@ -615,6 +611,13 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
biomeProvider = gen.getDefaultBiomeProvider(worldInfo);
|
||||
}
|
||||
|
||||
+ // Paper start - fix and optimise world upgrading
|
||||
+ if (options.has("forceUpgrade")) {
|
||||
+ net.minecraft.server.Main.convertWorldButItWorks(
|
||||
+ dimensionKey, worldSession, DataFixers.getDataFixer(), iregistrycustom_dimension, worlddimension.generator().getTypeNameForDataFixer(), options.has("eraseCache"), options.has("recreateRegionFiles")
|
||||
+ );
|
||||
+ }
|
||||
+ // Paper end - fix and optimise world upgrading
|
||||
ResourceKey<Level> worldKey = ResourceKey.create(Registries.DIMENSION, dimensionKey.location());
|
||||
|
||||
if (dimensionKey == LevelStem.OVERWORLD) {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index 0a8eeebb2d702ebcefd9f26cc0f41d1eab497902..b4ef3ad2c17168085372f1fe46809f02d9dfe74a 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -178,6 +178,15 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
public final Map<Explosion.CacheKey, Float> explosionDensityCache = new HashMap<>(); // Paper - Optimize explosions
|
||||
public java.util.ArrayDeque<net.minecraft.world.level.block.RedstoneTorchBlock.Toggle> redstoneUpdateInfos; // Paper - Faster redstone torch rapid clock removal; Move from Map in BlockRedstoneTorch to here
|
||||
|
||||
+ // Paper start - fix and optimise world upgrading
|
||||
+ // copied from below
|
||||
+ public static ResourceKey<DimensionType> getDimensionKey(DimensionType manager) {
|
||||
+ return ((org.bukkit.craftbukkit.CraftServer)org.bukkit.Bukkit.getServer()).getHandle().getServer().registryAccess().registryOrThrow(net.minecraft.core.registries.Registries.DIMENSION_TYPE).getResourceKey(manager).orElseThrow(() -> {
|
||||
+ return new IllegalStateException("Unregistered dimension type: " + manager);
|
||||
+ });
|
||||
+ }
|
||||
+ // Paper end - fix and optimise world upgrading
|
||||
+
|
||||
public CraftWorld getWorld() {
|
||||
return this.world;
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
index 249705ec1b8b692ef1d7fec34a04918afe6486bc..f6e3b745fc417354380d4a969f83aee430bad785 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
@@ -69,6 +69,29 @@ public class RegionFileStorage implements AutoCloseable {
|
||||
}
|
||||
|
||||
// Paper start
|
||||
+ @Nullable
|
||||
+ public static ChunkPos getRegionFileCoordinates(Path file) {
|
||||
+ String fileName = file.getFileName().toString();
|
||||
+ if (!fileName.startsWith("r.") || !fileName.endsWith(".mca")) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ String[] split = fileName.split("\\.");
|
||||
+
|
||||
+ if (split.length != 4) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ try {
|
||||
+ int x = Integer.parseInt(split[1]);
|
||||
+ int z = Integer.parseInt(split[2]);
|
||||
+
|
||||
+ return new ChunkPos(x << 5, z << 5);
|
||||
+ } catch (NumberFormatException ex) {
|
||||
+ return null;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
public synchronized RegionFile getRegionFileIfLoaded(ChunkPos chunkcoordintpair) {
|
||||
return this.regionCache.getAndMoveToFirst(ChunkPos.asLong(chunkcoordintpair.getRegionX(), chunkcoordintpair.getRegionZ()));
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 8e0b0e4b177f1bcf23e174dfca6eaa0f7203a95a..b63dc96d2b387bd0a6bd3c703853b40a337bb33f 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -1361,9 +1361,7 @@ public final class CraftServer implements Server {
|
||||
worlddata.checkName(name);
|
||||
worlddata.setModdedInfo(this.console.getServerModName(), this.console.getModdedStatus().shouldReportAsModified());
|
||||
|
||||
- if (this.console.options.has("forceUpgrade")) {
|
||||
- net.minecraft.server.Main.forceUpgrade(worldSession, DataFixers.getDataFixer(), this.console.options.has("eraseCache"), () -> true, iregistrycustom_dimension, this.console.options.has("recreateRegionFiles"));
|
||||
- }
|
||||
+ // Paper - fix and optimise world upgrading; move down
|
||||
|
||||
long j = BiomeManager.obfuscateSeed(worlddata.worldGenOptions().seed()); // Paper - use world seed
|
||||
List<CustomSpawner> list = ImmutableList.of(new PhantomSpawner(), new PatrolSpawner(), new CatSpawner(), new VillageSiege(), new WanderingTraderSpawner(worlddata));
|
||||
@@ -1374,6 +1372,13 @@ public final class CraftServer implements Server {
|
||||
biomeProvider = generator.getDefaultBiomeProvider(worldInfo);
|
||||
}
|
||||
|
||||
+ // Paper start - fix and optimise world upgrading
|
||||
+ if (this.console.options.has("forceUpgrade")) {
|
||||
+ net.minecraft.server.Main.convertWorldButItWorks(
|
||||
+ actualDimension, worldSession, DataFixers.getDataFixer(), iregistrycustom_dimension, worlddimension.generator().getTypeNameForDataFixer(), this.console.options.has("eraseCache"), this.console.options.has("recreateRegionFiles")
|
||||
+ );
|
||||
+ }
|
||||
+ // Paper end - fix and optimise world upgrading
|
||||
ResourceKey<net.minecraft.world.level.Level> worldKey;
|
||||
String levelName = this.getServer().getProperties().levelName;
|
||||
if (name.equals(levelName + "_nether")) {
|
|
@ -8,7 +8,7 @@ it will not disable the shield if the attacker is holding
|
|||
an axe item.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
index ca242ba1312263ec095fa2850dc0f02351e844ab..2338e41fde55559249d5f212697235e789b20b2a 100644
|
||||
index d6a7642697c08bcdc69b4f1d4475f0532e131b80..a1a72712e9acd4023c4b6832e5ec09dcc3676b6e 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -2341,7 +2341,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
|
@ -5,26 +5,6 @@ Subject: [PATCH] Write SavedData IO async
|
|||
|
||||
Co-Authored-By: Shane Freeder <theboyetronic@gmail.com>
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/world/ThreadedWorldUpgrader.java b/src/main/java/io/papermc/paper/world/ThreadedWorldUpgrader.java
|
||||
index e049fbe4038aaea896f45b11ce9ce8f05922c898..7f6d1ccd147e5593412567bb2934ce5662da7ef0 100644
|
||||
--- a/src/main/java/io/papermc/paper/world/ThreadedWorldUpgrader.java
|
||||
+++ b/src/main/java/io/papermc/paper/world/ThreadedWorldUpgrader.java
|
||||
@@ -110,6 +110,15 @@ public class ThreadedWorldUpgrader {
|
||||
}
|
||||
|
||||
this.threadPool.execute(new ConvertTask(info, regionPos.x >> 5, regionPos.z >> 5));
|
||||
+ // Paper start - Write SavedData IO async
|
||||
+ this.threadPool.execute(() -> {
|
||||
+ try {
|
||||
+ worldPersistentData.close();
|
||||
+ } catch (IOException exception) {
|
||||
+ LOGGER.error("Failed to close persistent world data", exception);
|
||||
+ }
|
||||
+ });
|
||||
+ // Paper end - Write SavedData IO async
|
||||
}
|
||||
this.threadPool.shutdown();
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
index 36caf354634d6675a3f1ec6829f4778e1d0623bc..b99f50604bafecbc68835974c9ed0caa91911a40 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
|
@ -81,7 +61,7 @@ index aab652174a8175765cad548f7c61ce353ca74803..ca56a0b596976448da6bb2a0e82b3d5c
|
|||
|
||||
public <T extends Entity> List<? extends T> getEntities(EntityTypeTest<Entity, T> filter, Predicate<? super T> predicate) {
|
||||
diff --git a/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java b/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java
|
||||
index 639f72618a7c22fa94effa9d0406b97fffc64cb5..3e582c49069f2a820ba3baac03917493877d9875 100644
|
||||
index ffbb3bf9ff3fc968ef69d4f889b0baf7e8ab691b..954d468459fe167ede0e7fca5b9f99da565d59e1 100644
|
||||
--- a/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java
|
||||
+++ b/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java
|
||||
@@ -116,7 +116,13 @@ public class WorldUpgrader {
|
|
@ -5,7 +5,7 @@ Subject: [PATCH] Revert to vanilla handling of LivingEntity#actuallyHurt
|
|||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
index 2338e41fde55559249d5f212697235e789b20b2a..517e10c3d8b1549cd30fd0e7cf2bcb35e88eb8ed 100644
|
||||
index a1a72712e9acd4023c4b6832e5ec09dcc3676b6e..ef0f118aecf0893e45cb9423a677d7e42496324b 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -2226,7 +2226,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
|
@ -35,7 +35,7 @@ index 52f537b7bfbdeaad9d17c0e88a1ed1c8925a833f..8aff5129f85ab5729b3da2e465871be6
|
|||
} else {
|
||||
super.channelRead(ctx, msg);
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
index a9aa3dca65aca86cf535d6616f5d5db3e1e8fc8b..561a7a8e96e2d91bbb87fe6230e94b5f38073d27 100644
|
||||
index 84ed5dc8c82e28aa93fa0440d90ddb44dc5f3d40..7e6116963d835d4606ef3d93b69d3e44b61288e1 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -273,6 +273,15 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
|
@ -2154,7 +2154,7 @@ index 982b2bab27e3d55d0ba07060862c0c3183ad91b0..5fa8a3343ffc11e82c20b78a73205fd8
|
|||
Component component = message.resolveComponent(commandSourceStack);
|
||||
CommandSigningContext commandSigningContext = commandSourceStack.getSigningContext();
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index f525a8735e5cf5eb1278e2a3002ac81d9fff7b1a..dbc86b8d4d2af6e5f7e678f2bb77fd39b85c04c5 100644
|
||||
index 0408d5d54fef7767ecf70e70686ad520d890ff26..0ed42fa899721f83b598db05be1b5f321af3614a 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -299,7 +299,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
@ -2174,7 +2174,7 @@ index f525a8735e5cf5eb1278e2a3002ac81d9fff7b1a..dbc86b8d4d2af6e5f7e678f2bb77fd39
|
|||
// Paper start - Handled by TerminalConsoleAppender
|
||||
// Try to see if we're actually running in a terminal, disable jline if not
|
||||
/*
|
||||
@@ -678,6 +677,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -675,6 +674,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
this.server.enablePlugins(org.bukkit.plugin.PluginLoadOrder.POSTWORLD);
|
||||
if (io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper != null) io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper.pluginsEnabled(); // Paper - Remap plugins
|
||||
|
@ -2184,7 +2184,7 @@ index f525a8735e5cf5eb1278e2a3002ac81d9fff7b1a..dbc86b8d4d2af6e5f7e678f2bb77fd39
|
|||
this.server.getPluginManager().callEvent(new ServerLoadEvent(ServerLoadEvent.LoadType.STARTUP));
|
||||
this.connection.acceptConnections();
|
||||
}
|
||||
@@ -2299,9 +2301,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -2296,9 +2298,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
return new MinecraftServer.ReloadableResources(resourcemanager, datapackresources);
|
||||
});
|
||||
}).thenAcceptAsync((minecraftserver_reloadableresources) -> {
|
||||
|
@ -2195,7 +2195,7 @@ index f525a8735e5cf5eb1278e2a3002ac81d9fff7b1a..dbc86b8d4d2af6e5f7e678f2bb77fd39
|
|||
this.packRepository.setSelected(dataPacks);
|
||||
WorldDataConfiguration worlddataconfiguration = new WorldDataConfiguration(MinecraftServer.getSelectedPacks(this.packRepository, true), this.worldData.enabledFeatures());
|
||||
|
||||
@@ -2320,8 +2322,17 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -2317,8 +2319,17 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
this.getPlayerList().reloadResources();
|
||||
this.functionManager.replaceLibrary(this.resources.managers.getFunctionLibrary());
|
||||
this.structureTemplateManager.onResourceManagerReload(this.resources.resourceManager);
|
||||
|
@ -2318,7 +2318,7 @@ index 3faf80fca51d66480265eaf3cc89149e53ceb215..b9b3277c8ed94e0cd30b20b9c00a33ea
|
|||
// CraftBukkit end
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index b63dc96d2b387bd0a6bd3c703853b40a337bb33f..2fa5507aa2153a05208077f9547c165a1099b5bb 100644
|
||||
index ac57c3a63bbf234e83f538e4a06ab794c7a0965a..af015237214cebc4d1c4bb9e9c5f939d433e365c 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -270,11 +270,11 @@ public final class CraftServer implements Server {
|
Loading…
Reference in a new issue