2015-05-25 12:37:24 +02:00
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
2021-11-21 23:00:00 +01:00
@@ -160,6 +160,27 @@
2016-05-10 13:47:39 +02:00
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
2021-03-08 22:47:33 +01:00
2016-05-10 13:47:39 +02:00
+// CraftBukkit start
2021-03-08 22:47:33 +01:00
+import com.mojang.serialization.DynamicOps;
+import com.mojang.serialization.Lifecycle;
2016-07-15 12:08:04 +02:00
+import jline.console.ConsoleReader;
2020-06-25 02:00:00 +02:00
+import joptsimple.OptionSet;
2021-03-15 23:00:00 +01:00
+import net.minecraft.nbt.DynamicOpsNBT;
+import net.minecraft.nbt.NBTBase;
+import net.minecraft.resources.RegistryReadOps;
+import net.minecraft.server.dedicated.DedicatedServer;
+import net.minecraft.server.dedicated.DedicatedServerProperties;
+import net.minecraft.util.datafix.DataConverterRegistry;
2021-11-21 23:00:00 +01:00
+import net.minecraft.world.level.biome.WorldChunkManager;
SPIGOT-5880, SPIGOT-5567: New ChunkGenerator API
## **Current API**
The current world generation API is very old and limited when you want to make more complex world generation. Resulting in some hard to fix bugs such as that you cannot modify blocks outside the chunk in the BlockPopulator (which should and was per the docs possible), or strange behavior such as SPIGOT-5880.
## **New API**
With the new API, the generation is more separate in multiple methods and is more in line with Vanilla chunk generation. The new API is designed to as future proof as possible. If for example a new generation step is added it can easily also be added as a step in API by simply creating the method for it. On the other side if a generation step gets removed, the method can easily be called after another, which is the case with surface and bedrock. The new API and changes are also fully backwards compatible with old chunk generators.
### **Changes in the new api**
**Extra generation steps:**
Noise, surface, bedrock and caves are added as steps. With those generation steps three extra methods for Vanilla generation are also added. Those new methods provide the ChunkData instead of returning one. The reason for this is, that the ChunkData is now backed by a ChunkAccess. With this, each step has the information of the step before and the Vanilla information (if chosen by setting a 'should' method to true). The old method is deprecated.
**New class BiomeProvider**
The BiomeProvider acts as Biome source and wrapper for the NMS class WorldChunkManager. With this the underlying Vanilla ChunkGeneration knows which Biome to use for the structure and decoration generation. (Fixes: SPIGOT-5880). Although the List of Biomes which is required in BiomeProvider, is currently not much in use in Vanilla, I decided to add it to future proof the API when it may be required in later versions of Minecraft.
The BiomeProvider is also separated from the ChunkGenerator for plugins which only want to change the biome map, such as single Biome worlds or if some biomes should be more present than others.
**Deprecated isParallelCapable**
Mojang has and is pushing to a more multi threaded chunk generation. This should also be the case for custom chunk generators. This is why the new API only supports multi threaded generation. This does not affect the old API, which is still checking this.
**Base height method added**
This method was added to also bring the Minecraft generator and Bukkit generator more in line. With this it is possible to return the max height of a location (before decorations). This is useful to let most structures know were to place them. This fixes SPIGOT-5567. (This fixes not all structures placement, desert pyramids for example are still way up at y-level 64, This however is more a vanilla bug and should be fixed at Mojangs end).
**WorldInfo Class**
The World object was swapped for a WorldInfo object. This is because many methods of the World object won't work during world generation and would mostly likely result in a deadlock. It contains any information a plugin should need to identify the world.
**BlockPopulator Changes**
Instead of directly manipulating a chunk, changes are now made to a new class LimitedRegion, this class provides methods to populated the chunk and its surrounding area. The wrapping is done so that the population can be moved into the place where Minecraft generates decorations. Where there is no chunk to access yet. By moving it into this place the generation is now async and the surrounding area of the chunk can also be used.
For common methods between the World and LimitedRegion a RegionAccessor was added.
By: DerFrZocker <derrieple@gmail.com>
2021-08-15 00:08:16 +02:00
+import net.minecraft.world.level.levelgen.ChunkGeneratorAbstract;
2021-03-15 23:00:00 +01:00
+import net.minecraft.world.level.storage.WorldDataServer;
2016-02-29 22:32:46 +01:00
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.CraftServer;
2016-07-15 12:08:04 +02:00
+import org.bukkit.craftbukkit.Main;
SPIGOT-5880, SPIGOT-5567: New ChunkGenerator API
## **Current API**
The current world generation API is very old and limited when you want to make more complex world generation. Resulting in some hard to fix bugs such as that you cannot modify blocks outside the chunk in the BlockPopulator (which should and was per the docs possible), or strange behavior such as SPIGOT-5880.
## **New API**
With the new API, the generation is more separate in multiple methods and is more in line with Vanilla chunk generation. The new API is designed to as future proof as possible. If for example a new generation step is added it can easily also be added as a step in API by simply creating the method for it. On the other side if a generation step gets removed, the method can easily be called after another, which is the case with surface and bedrock. The new API and changes are also fully backwards compatible with old chunk generators.
### **Changes in the new api**
**Extra generation steps:**
Noise, surface, bedrock and caves are added as steps. With those generation steps three extra methods for Vanilla generation are also added. Those new methods provide the ChunkData instead of returning one. The reason for this is, that the ChunkData is now backed by a ChunkAccess. With this, each step has the information of the step before and the Vanilla information (if chosen by setting a 'should' method to true). The old method is deprecated.
**New class BiomeProvider**
The BiomeProvider acts as Biome source and wrapper for the NMS class WorldChunkManager. With this the underlying Vanilla ChunkGeneration knows which Biome to use for the structure and decoration generation. (Fixes: SPIGOT-5880). Although the List of Biomes which is required in BiomeProvider, is currently not much in use in Vanilla, I decided to add it to future proof the API when it may be required in later versions of Minecraft.
The BiomeProvider is also separated from the ChunkGenerator for plugins which only want to change the biome map, such as single Biome worlds or if some biomes should be more present than others.
**Deprecated isParallelCapable**
Mojang has and is pushing to a more multi threaded chunk generation. This should also be the case for custom chunk generators. This is why the new API only supports multi threaded generation. This does not affect the old API, which is still checking this.
**Base height method added**
This method was added to also bring the Minecraft generator and Bukkit generator more in line. With this it is possible to return the max height of a location (before decorations). This is useful to let most structures know were to place them. This fixes SPIGOT-5567. (This fixes not all structures placement, desert pyramids for example are still way up at y-level 64, This however is more a vanilla bug and should be fixed at Mojangs end).
**WorldInfo Class**
The World object was swapped for a WorldInfo object. This is because many methods of the World object won't work during world generation and would mostly likely result in a deadlock. It contains any information a plugin should need to identify the world.
**BlockPopulator Changes**
Instead of directly manipulating a chunk, changes are now made to a new class LimitedRegion, this class provides methods to populated the chunk and its surrounding area. The wrapping is done so that the population can be moved into the place where Minecraft generates decorations. Where there is no chunk to access yet. By moving it into this place the generation is now async and the surrounding area of the chunk can also be used.
For common methods between the World and LimitedRegion a RegionAccessor was added.
By: DerFrZocker <derrieple@gmail.com>
2021-08-15 00:08:16 +02:00
+import org.bukkit.craftbukkit.generator.CustomWorldChunkManager;
2018-09-08 05:37:15 +02:00
+import org.bukkit.event.server.ServerLoadEvent;
2016-02-29 22:32:46 +01:00
+// CraftBukkit end
2021-03-08 22:47:33 +01:00
+
2021-11-21 23:00:00 +01:00
public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTask> implements ICommandListener, AutoCloseable {
2015-02-26 23:41:06 +01:00
2021-03-08 22:47:33 +01:00
public static final Logger LOGGER = LogManager.getLogger();
2021-12-02 22:34:38 +01:00
@@ -252,6 +273,21 @@
2021-06-11 07:00:00 +02:00
protected SaveData worldData;
2021-11-21 23:00:00 +01:00
private volatile boolean isSaving;
2014-11-25 22:32:16 +01:00
+ // CraftBukkit start
2021-12-02 22:34:38 +01:00
+ public final DataPackConfiguration datapackconfiguration;
+ public final RegistryReadOps<NBTBase> registryreadops;
2014-11-25 22:32:16 +01:00
+ public org.bukkit.craftbukkit.CraftServer server;
+ public OptionSet options;
+ public org.bukkit.command.ConsoleCommandSender console;
+ public org.bukkit.command.RemoteConsoleCommandSender remoteConsole;
+ public ConsoleReader reader;
+ public static int currentTick = (int) (System.currentTimeMillis() / 50);
+ public java.util.Queue<Runnable> processQueue = new java.util.concurrent.ConcurrentLinkedQueue<Runnable>();
+ public int autosavePeriod;
2018-07-21 03:20:38 +02:00
+ public CommandDispatcher vanillaCommandDispatcher;
2019-04-25 07:33:13 +02:00
+ private boolean forceTicks;
2014-11-25 22:32:16 +01:00
+ // CraftBukkit end
+
2021-11-21 23:00:00 +01:00
public static <S extends MinecraftServer> S spin(Function<Thread, S> function) {
2020-06-25 02:00:00 +02:00
AtomicReference<S> atomicreference = new AtomicReference();
Thread thread = new Thread(() -> {
2021-12-02 22:34:38 +01:00
@@ -265,14 +301,14 @@
2021-11-21 23:00:00 +01:00
thread.setPriority(8);
}
2020-06-25 02:00:00 +02:00
- S s0 = (MinecraftServer) function.apply(thread);
+ S s0 = function.apply(thread); // CraftBukkit - decompile error
atomicreference.set(s0);
thread.start();
return s0;
}
2021-06-11 07:00:00 +02:00
- public MinecraftServer(Thread thread, IRegistryCustom.Dimension iregistrycustom_dimension, Convertable.ConversionSession convertable_conversionsession, SaveData savedata, ResourcePackRepository resourcepackrepository, Proxy proxy, DataFixer datafixer, DataPackResources datapackresources, @Nullable MinecraftSessionService minecraftsessionservice, @Nullable GameProfileRepository gameprofilerepository, @Nullable UserCache usercache, WorldLoadListenerFactory worldloadlistenerfactory) {
+ public MinecraftServer(OptionSet options, DataPackConfiguration datapackconfiguration, Thread thread, IRegistryCustom.Dimension iregistrycustom_dimension, Convertable.ConversionSession convertable_conversionsession, SaveData savedata, ResourcePackRepository resourcepackrepository, Proxy proxy, DataFixer datafixer, DataPackResources datapackresources, @Nullable MinecraftSessionService minecraftsessionservice, @Nullable GameProfileRepository gameprofilerepository, @Nullable UserCache usercache, WorldLoadListenerFactory worldloadlistenerfactory) {
2019-04-23 04:00:00 +02:00
super("Server");
2021-06-11 07:00:00 +02:00
this.metricsRecorder = InactiveMetricsRecorder.INSTANCE;
2021-11-21 23:00:00 +01:00
this.profiler = this.metricsRecorder.getProfiler();
2021-12-02 22:34:38 +01:00
@@ -284,7 +320,7 @@
2021-06-11 07:00:00 +02:00
this.status = new ServerPing();
this.random = new Random();
this.port = -1;
- this.levels = Maps.newLinkedHashMap();
+ this.levels = Maps.newLinkedHashMap(); // CraftBukkit - keep order, k+v already use identity methods
this.running = true;
this.tickTimes = new long[100];
this.resourcePack = "";
2021-12-02 22:34:38 +01:00
@@ -314,13 +350,41 @@
2021-11-21 23:00:00 +01:00
this.structureManager = new DefinedStructureManager(datapackresources.getResourceManager(), convertable_conversionsession, datafixer);
2020-06-25 02:00:00 +02:00
this.serverThread = thread;
2021-11-21 23:00:00 +01:00
this.executor = SystemUtils.backgroundExecutor();
2014-11-25 22:32:16 +01:00
+ // CraftBukkit start
+ this.options = options;
2020-06-25 02:00:00 +02:00
+ this.datapackconfiguration = datapackconfiguration;
2021-12-02 22:34:38 +01:00
+ this.registryreadops = RegistryReadOps.createAndLoad(DynamicOpsNBT.INSTANCE, datapackresources.getResourceManager(), iregistrycustom_dimension);
2021-06-11 07:00:00 +02:00
+ this.vanillaCommandDispatcher = datapackresources.commands; // CraftBukkit
2014-11-25 22:32:16 +01:00
+ // Try to see if we're actually running in a terminal, disable jline if not
2015-06-11 13:59:36 +02:00
+ if (System.console() == null && System.getProperty("jline.terminal") == null) {
2014-11-25 22:32:16 +01:00
+ System.setProperty("jline.terminal", "jline.UnsupportedTerminal");
+ Main.useJline = false;
+ }
+
+ try {
+ reader = new ConsoleReader(System.in, System.out);
+ reader.setExpandEvents(false); // Avoid parsing exceptions for uncommonly used event designators
+ } catch (Throwable e) {
+ try {
+ // Try again with jline disabled for Windows users without C++ 2008 Redistributable
+ System.setProperty("jline.terminal", "jline.UnsupportedTerminal");
+ System.setProperty("user.language", "en");
+ Main.useJline = false;
+ reader = new ConsoleReader(System.in, System.out);
+ reader.setExpandEvents(false);
+ } catch (IOException ex) {
+ LOGGER.warn((String) null, ex);
+ }
+ }
+ Runtime.getRuntime().addShutdownHook(new org.bukkit.craftbukkit.util.ServerShutdownThread(this));
}
+ // CraftBukkit end
2018-07-15 02:00:00 +02:00
2021-11-21 23:00:00 +01:00
private void readScoreboard(WorldPersistentData worldpersistentdata) {
2021-06-11 07:00:00 +02:00
ScoreboardServer scoreboardserver = this.getScoreboard();
Objects.requireNonNull(scoreboardserver);
2021-11-21 23:00:00 +01:00
- Function function = scoreboardserver::createData;
+ Function<net.minecraft.nbt.NBTTagCompound, net.minecraft.world.scores.PersistentScoreboard> function = scoreboardserver::createData; // CraftBukkit - decompile error
2021-06-11 07:00:00 +02:00
ScoreboardServer scoreboardserver1 = this.getScoreboard();
Objects.requireNonNull(scoreboardserver1);
2021-12-02 22:34:38 +01:00
@@ -329,7 +393,7 @@
2018-07-22 04:00:00 +02:00
2021-11-21 23:00:00 +01:00
protected abstract boolean initServer() throws IOException;
- protected void loadLevel() {
+ protected void loadLevel(String s) { // CraftBukkit
if (!JvmProfiler.INSTANCE.isRunning()) {
;
}
2021-12-02 22:34:38 +01:00
@@ -337,13 +401,8 @@
2021-11-21 23:00:00 +01:00
boolean flag = false;
ProfiledDuration profiledduration = JvmProfiler.INSTANCE.onWorldLoadedStarted();
- this.detectBundledResources();
- this.worldData.setModdedInfo(this.getServerModName(), this.getModdedStatus().shouldReportAsModified());
- WorldLoadListener worldloadlistener = this.progressListenerFactory.create(11);
+ loadWorld0(s); // CraftBukkit
2018-07-22 04:00:00 +02:00
2021-11-21 23:00:00 +01:00
- this.createLevels(worldloadlistener);
- this.forceDifficulty();
- this.prepareLevels(worldloadlistener);
if (profiledduration != null) {
profiledduration.finish();
}
2022-01-31 22:13:13 +01:00
@@ -358,36 +417,206 @@
2018-07-22 04:00:00 +02:00
}
2021-11-21 23:00:00 +01:00
- protected void forceDifficulty() {}
+ // CraftBukkit start
+ private void loadWorld0(String s) {
2021-06-11 07:00:00 +02:00
+ Convertable.ConversionSession worldSession = this.storageSource;
+ IRegistryCustom.Dimension iregistrycustom_dimension = this.registryHolder;
2021-11-21 23:00:00 +01:00
+ WorldDataServer overworldData = (WorldDataServer) worldSession.getDataTag(registryreadops, datapackconfiguration);
2021-04-16 02:36:05 +02:00
+ if (overworldData == null) {
+ WorldSettings worldsettings;
+ GeneratorSettings generatorsettings;
+
2021-11-21 23:00:00 +01:00
+ if (this.isDemo()) {
2021-06-11 07:00:00 +02:00
+ worldsettings = MinecraftServer.DEMO_SETTINGS;
2021-11-21 23:00:00 +01:00
+ generatorsettings = GeneratorSettings.demoSettings(iregistrycustom_dimension);
2021-04-16 02:36:05 +02:00
+ } else {
2021-11-21 23:00:00 +01:00
+ DedicatedServerProperties dedicatedserverproperties = ((DedicatedServer) this).getProperties();
- protected void createLevels(WorldLoadListener worldloadlistener) {
- IWorldDataServer iworlddataserver = this.worldData.overworldData();
- GeneratorSettings generatorsettings = this.worldData.worldGenSettings();
- boolean flag = generatorsettings.isDebug();
- long i = generatorsettings.seed();
- long j = BiomeManager.obfuscateSeed(i);
- List<MobSpawner> list = ImmutableList.of(new MobSpawnerPhantom(), new MobSpawnerPatrol(), new MobSpawnerCat(), new VillageSiege(), new MobSpawnerTrader(iworlddataserver));
- RegistryMaterials<WorldDimension> registrymaterials = generatorsettings.dimensions();
- WorldDimension worlddimension = (WorldDimension) registrymaterials.get(WorldDimension.OVERWORLD);
- DimensionManager dimensionmanager;
- Object object;
-
- if (worlddimension == null) {
- dimensionmanager = (DimensionManager) this.registryHolder.registryOrThrow(IRegistry.DIMENSION_TYPE_REGISTRY).getOrThrow(DimensionManager.OVERWORLD_LOCATION);
- object = GeneratorSettings.makeDefaultOverworld(this.registryHolder, (new Random()).nextLong());
- } else {
- dimensionmanager = worlddimension.type();
- object = worlddimension.generator();
2021-04-16 02:36:05 +02:00
+ worldsettings = new WorldSettings(dedicatedserverproperties.levelName, dedicatedserverproperties.gamemode, dedicatedserverproperties.hardcore, dedicatedserverproperties.difficulty, false, new GameRules(), datapackconfiguration);
2021-11-21 23:00:00 +01:00
+ generatorsettings = options.has("bonusChest") ? dedicatedserverproperties.getWorldGenSettings(iregistrycustom_dimension).withBonusChest() : dedicatedserverproperties.getWorldGenSettings(iregistrycustom_dimension);
2021-04-16 02:36:05 +02:00
+ }
+
+ overworldData = new WorldDataServer(worldsettings, generatorsettings, Lifecycle.stable());
+ }
SPIGOT-5880, SPIGOT-5567: New ChunkGenerator API
## **Current API**
The current world generation API is very old and limited when you want to make more complex world generation. Resulting in some hard to fix bugs such as that you cannot modify blocks outside the chunk in the BlockPopulator (which should and was per the docs possible), or strange behavior such as SPIGOT-5880.
## **New API**
With the new API, the generation is more separate in multiple methods and is more in line with Vanilla chunk generation. The new API is designed to as future proof as possible. If for example a new generation step is added it can easily also be added as a step in API by simply creating the method for it. On the other side if a generation step gets removed, the method can easily be called after another, which is the case with surface and bedrock. The new API and changes are also fully backwards compatible with old chunk generators.
### **Changes in the new api**
**Extra generation steps:**
Noise, surface, bedrock and caves are added as steps. With those generation steps three extra methods for Vanilla generation are also added. Those new methods provide the ChunkData instead of returning one. The reason for this is, that the ChunkData is now backed by a ChunkAccess. With this, each step has the information of the step before and the Vanilla information (if chosen by setting a 'should' method to true). The old method is deprecated.
**New class BiomeProvider**
The BiomeProvider acts as Biome source and wrapper for the NMS class WorldChunkManager. With this the underlying Vanilla ChunkGeneration knows which Biome to use for the structure and decoration generation. (Fixes: SPIGOT-5880). Although the List of Biomes which is required in BiomeProvider, is currently not much in use in Vanilla, I decided to add it to future proof the API when it may be required in later versions of Minecraft.
The BiomeProvider is also separated from the ChunkGenerator for plugins which only want to change the biome map, such as single Biome worlds or if some biomes should be more present than others.
**Deprecated isParallelCapable**
Mojang has and is pushing to a more multi threaded chunk generation. This should also be the case for custom chunk generators. This is why the new API only supports multi threaded generation. This does not affect the old API, which is still checking this.
**Base height method added**
This method was added to also bring the Minecraft generator and Bukkit generator more in line. With this it is possible to return the max height of a location (before decorations). This is useful to let most structures know were to place them. This fixes SPIGOT-5567. (This fixes not all structures placement, desert pyramids for example are still way up at y-level 64, This however is more a vanilla bug and should be fixed at Mojangs end).
**WorldInfo Class**
The World object was swapped for a WorldInfo object. This is because many methods of the World object won't work during world generation and would mostly likely result in a deadlock. It contains any information a plugin should need to identify the world.
**BlockPopulator Changes**
Instead of directly manipulating a chunk, changes are now made to a new class LimitedRegion, this class provides methods to populated the chunk and its surrounding area. The wrapping is done so that the population can be moved into the place where Minecraft generates decorations. Where there is no chunk to access yet. By moving it into this place the generation is now async and the surrounding area of the chunk can also be used.
For common methods between the World and LimitedRegion a RegionAccessor was added.
By: DerFrZocker <derrieple@gmail.com>
2021-08-15 00:08:16 +02:00
+
2021-11-21 23:00:00 +01:00
+ GeneratorSettings overworldSettings = overworldData.worldGenSettings();
+ RegistryMaterials<WorldDimension> registrymaterials = overworldSettings.dimensions();
+ for (Entry<ResourceKey<WorldDimension>, WorldDimension> entry : registrymaterials.entrySet()) {
2021-04-16 02:36:05 +02:00
+ ResourceKey<WorldDimension> dimensionKey = entry.getKey();
2020-06-25 02:00:00 +02:00
+
2014-11-25 22:32:16 +01:00
+ WorldServer world;
2021-04-16 02:36:05 +02:00
+ int dimension = 0;
2021-11-21 23:00:00 +01:00
+
2021-06-11 07:00:00 +02:00
+ if (dimensionKey == WorldDimension.NETHER) {
2021-11-21 23:00:00 +01:00
+ if (isNetherEnabled()) {
2014-11-25 22:32:16 +01:00
+ dimension = -1;
+ } else {
+ continue;
+ }
2021-06-11 07:00:00 +02:00
+ } else if (dimensionKey == WorldDimension.END) {
2014-11-25 22:32:16 +01:00
+ if (server.getAllowEnd()) {
+ dimension = 1;
+ } else {
+ continue;
+ }
2021-04-16 02:36:05 +02:00
+ } else if (dimensionKey != WorldDimension.OVERWORLD) {
+ dimension = -999;
2018-08-26 04:00:00 +02:00
+ }
2019-04-25 07:33:13 +02:00
+
2021-11-21 23:00:00 +01:00
+ String worldType = (dimension == -999) ? dimensionKey.location().getNamespace() + "_" + dimensionKey.location().getPath() : org.bukkit.World.Environment.getEnvironment(dimension).toString().toLowerCase();
2021-04-16 02:36:05 +02:00
+ String name = (dimensionKey == WorldDimension.OVERWORLD) ? s : s + "_" + worldType;
+ if (dimension != 0) {
2021-11-21 23:00:00 +01:00
+ File newWorld = Convertable.getStorageFolder(new File(name).toPath(), dimensionKey).toFile();
+ File oldWorld = Convertable.getStorageFolder(new File(s).toPath(), dimensionKey).toFile();
2020-06-26 01:49:40 +02:00
+ File oldLevelDat = new File(new File(s), "level.dat"); // The data folders exist on first run as they are created in the PersistentCollection constructor above, but the level.dat won't
+
+ if (!newWorld.isDirectory() && oldWorld.isDirectory() && oldLevelDat.isFile()) {
+ MinecraftServer.LOGGER.info("---- Migration of old " + worldType + " folder required ----");
+ MinecraftServer.LOGGER.info("Unfortunately due to the way that Minecraft implemented multiworld support in 1.6, Bukkit requires that you move your " + worldType + " folder to a new location in order to operate correctly.");
+ MinecraftServer.LOGGER.info("We will move this folder for you, but it will mean that you need to move it back should you wish to stop using Bukkit in the future.");
+ MinecraftServer.LOGGER.info("Attempting to move " + oldWorld + " to " + newWorld + "...");
+
+ if (newWorld.exists()) {
+ MinecraftServer.LOGGER.warn("A file or folder already exists at " + newWorld + "!");
+ MinecraftServer.LOGGER.info("---- Migration of old " + worldType + " folder failed ----");
+ } else if (newWorld.getParentFile().mkdirs()) {
+ if (oldWorld.renameTo(newWorld)) {
+ MinecraftServer.LOGGER.info("Success! To restore " + worldType + " in the future, simply move " + newWorld + " to " + oldWorld);
+ // Migrate world data too.
+ try {
+ com.google.common.io.Files.copy(oldLevelDat, new File(new File(name), "level.dat"));
+ org.apache.commons.io.FileUtils.copyDirectory(new File(new File(s), "data"), new File(new File(name), "data"));
+ } catch (IOException exception) {
+ MinecraftServer.LOGGER.warn("Unable to migrate world data.");
+ }
+ MinecraftServer.LOGGER.info("---- Migration of old " + worldType + " folder complete ----");
+ } else {
+ MinecraftServer.LOGGER.warn("Could not move folder " + oldWorld + " to " + newWorld + "!");
+ MinecraftServer.LOGGER.info("---- Migration of old " + worldType + " folder failed ----");
+ }
+ } else {
+ MinecraftServer.LOGGER.warn("Could not create path for " + newWorld + "!");
+ MinecraftServer.LOGGER.info("---- Migration of old " + worldType + " folder failed ----");
+ }
+ }
+
2020-06-25 02:00:00 +02:00
+ try {
2021-11-21 23:00:00 +01:00
+ worldSession = Convertable.createDefault(server.getWorldContainer().toPath()).createAccess(name, dimensionKey);
2020-06-25 02:00:00 +02:00
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
2021-04-16 02:36:05 +02:00
+ org.bukkit.generator.ChunkGenerator gen = this.server.getGenerator(name);
SPIGOT-5880, SPIGOT-5567: New ChunkGenerator API
## **Current API**
The current world generation API is very old and limited when you want to make more complex world generation. Resulting in some hard to fix bugs such as that you cannot modify blocks outside the chunk in the BlockPopulator (which should and was per the docs possible), or strange behavior such as SPIGOT-5880.
## **New API**
With the new API, the generation is more separate in multiple methods and is more in line with Vanilla chunk generation. The new API is designed to as future proof as possible. If for example a new generation step is added it can easily also be added as a step in API by simply creating the method for it. On the other side if a generation step gets removed, the method can easily be called after another, which is the case with surface and bedrock. The new API and changes are also fully backwards compatible with old chunk generators.
### **Changes in the new api**
**Extra generation steps:**
Noise, surface, bedrock and caves are added as steps. With those generation steps three extra methods for Vanilla generation are also added. Those new methods provide the ChunkData instead of returning one. The reason for this is, that the ChunkData is now backed by a ChunkAccess. With this, each step has the information of the step before and the Vanilla information (if chosen by setting a 'should' method to true). The old method is deprecated.
**New class BiomeProvider**
The BiomeProvider acts as Biome source and wrapper for the NMS class WorldChunkManager. With this the underlying Vanilla ChunkGeneration knows which Biome to use for the structure and decoration generation. (Fixes: SPIGOT-5880). Although the List of Biomes which is required in BiomeProvider, is currently not much in use in Vanilla, I decided to add it to future proof the API when it may be required in later versions of Minecraft.
The BiomeProvider is also separated from the ChunkGenerator for plugins which only want to change the biome map, such as single Biome worlds or if some biomes should be more present than others.
**Deprecated isParallelCapable**
Mojang has and is pushing to a more multi threaded chunk generation. This should also be the case for custom chunk generators. This is why the new API only supports multi threaded generation. This does not affect the old API, which is still checking this.
**Base height method added**
This method was added to also bring the Minecraft generator and Bukkit generator more in line. With this it is possible to return the max height of a location (before decorations). This is useful to let most structures know were to place them. This fixes SPIGOT-5567. (This fixes not all structures placement, desert pyramids for example are still way up at y-level 64, This however is more a vanilla bug and should be fixed at Mojangs end).
**WorldInfo Class**
The World object was swapped for a WorldInfo object. This is because many methods of the World object won't work during world generation and would mostly likely result in a deadlock. It contains any information a plugin should need to identify the world.
**BlockPopulator Changes**
Instead of directly manipulating a chunk, changes are now made to a new class LimitedRegion, this class provides methods to populated the chunk and its surrounding area. The wrapping is done so that the population can be moved into the place where Minecraft generates decorations. Where there is no chunk to access yet. By moving it into this place the generation is now async and the surrounding area of the chunk can also be used.
For common methods between the World and LimitedRegion a RegionAccessor was added.
By: DerFrZocker <derrieple@gmail.com>
2021-08-15 00:08:16 +02:00
+ org.bukkit.generator.BiomeProvider biomeProvider = this.server.getBiomeProvider(name);
2020-06-25 02:00:00 +02:00
+
2021-11-21 23:00:00 +01:00
+ WorldDataServer worlddata = (WorldDataServer) worldSession.getDataTag((DynamicOps) registryreadops, datapackconfiguration);
2020-06-25 02:00:00 +02:00
+ if (worlddata == null) {
+ WorldSettings worldsettings;
+ GeneratorSettings generatorsettings;
2019-04-23 04:00:00 +02:00
+
2021-11-21 23:00:00 +01:00
+ if (this.isDemo()) {
2021-06-11 07:00:00 +02:00
+ worldsettings = MinecraftServer.DEMO_SETTINGS;
2021-11-21 23:00:00 +01:00
+ generatorsettings = GeneratorSettings.demoSettings(iregistrycustom_dimension);
2020-06-25 02:00:00 +02:00
+ } else {
2021-11-21 23:00:00 +01:00
+ DedicatedServerProperties dedicatedserverproperties = ((DedicatedServer) this).getProperties();
2020-06-25 02:00:00 +02:00
+
+ worldsettings = new WorldSettings(dedicatedserverproperties.levelName, dedicatedserverproperties.gamemode, dedicatedserverproperties.hardcore, dedicatedserverproperties.difficulty, false, new GameRules(), datapackconfiguration);
2021-11-21 23:00:00 +01:00
+ generatorsettings = options.has("bonusChest") ? dedicatedserverproperties.getWorldGenSettings(iregistrycustom_dimension).withBonusChest() : dedicatedserverproperties.getWorldGenSettings(iregistrycustom_dimension);
2018-08-26 04:00:00 +02:00
+ }
2019-04-23 04:00:00 +02:00
+
2020-06-25 02:00:00 +02:00
+ worlddata = new WorldDataServer(worldsettings, generatorsettings, Lifecycle.stable());
+ }
+ 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 (options.has("forceUpgrade")) {
2021-11-21 23:00:00 +01:00
+ net.minecraft.server.Main.forceUpgrade(worldSession, DataConverterRegistry.getDataFixer(), options.has("eraseCache"), () -> {
2020-06-25 02:00:00 +02:00
+ return true;
2021-11-21 23:00:00 +01:00
+ }, worlddata.worldGenSettings());
2020-06-25 02:00:00 +02:00
+ }
+
+ IWorldDataServer iworlddataserver = worlddata;
2021-11-21 23:00:00 +01:00
+ GeneratorSettings generatorsettings = worlddata.worldGenSettings();
+ boolean flag = generatorsettings.isDebug();
+ long i = generatorsettings.seed();
+ long j = BiomeManager.obfuscateSeed(i);
2020-06-25 02:00:00 +02:00
+ List<MobSpawner> list = ImmutableList.of(new MobSpawnerPhantom(), new MobSpawnerPatrol(), new MobSpawnerCat(), new VillageSiege(), new MobSpawnerTrader(iworlddataserver));
2021-11-23 05:03:34 +01:00
+ WorldDimension worlddimension = (WorldDimension) registrymaterials.get(dimensionKey);
2020-06-25 02:00:00 +02:00
+ DimensionManager dimensionmanager;
+ ChunkGenerator chunkgenerator;
+
+ if (worlddimension == null) {
2021-11-21 23:00:00 +01:00
+ dimensionmanager = (DimensionManager) this.registryHolder.registryOrThrow(IRegistry.DIMENSION_TYPE_REGISTRY).getOrThrow(DimensionManager.OVERWORLD_LOCATION);
+ chunkgenerator = GeneratorSettings.makeDefaultOverworld(this.registryHolder, (new Random()).nextLong());
2020-06-25 02:00:00 +02:00
+ } else {
2021-11-21 23:00:00 +01:00
+ dimensionmanager = worlddimension.type();
+ chunkgenerator = worlddimension.generator();
2020-06-25 02:00:00 +02:00
+ }
+
SPIGOT-5880, SPIGOT-5567: New ChunkGenerator API
## **Current API**
The current world generation API is very old and limited when you want to make more complex world generation. Resulting in some hard to fix bugs such as that you cannot modify blocks outside the chunk in the BlockPopulator (which should and was per the docs possible), or strange behavior such as SPIGOT-5880.
## **New API**
With the new API, the generation is more separate in multiple methods and is more in line with Vanilla chunk generation. The new API is designed to as future proof as possible. If for example a new generation step is added it can easily also be added as a step in API by simply creating the method for it. On the other side if a generation step gets removed, the method can easily be called after another, which is the case with surface and bedrock. The new API and changes are also fully backwards compatible with old chunk generators.
### **Changes in the new api**
**Extra generation steps:**
Noise, surface, bedrock and caves are added as steps. With those generation steps three extra methods for Vanilla generation are also added. Those new methods provide the ChunkData instead of returning one. The reason for this is, that the ChunkData is now backed by a ChunkAccess. With this, each step has the information of the step before and the Vanilla information (if chosen by setting a 'should' method to true). The old method is deprecated.
**New class BiomeProvider**
The BiomeProvider acts as Biome source and wrapper for the NMS class WorldChunkManager. With this the underlying Vanilla ChunkGeneration knows which Biome to use for the structure and decoration generation. (Fixes: SPIGOT-5880). Although the List of Biomes which is required in BiomeProvider, is currently not much in use in Vanilla, I decided to add it to future proof the API when it may be required in later versions of Minecraft.
The BiomeProvider is also separated from the ChunkGenerator for plugins which only want to change the biome map, such as single Biome worlds or if some biomes should be more present than others.
**Deprecated isParallelCapable**
Mojang has and is pushing to a more multi threaded chunk generation. This should also be the case for custom chunk generators. This is why the new API only supports multi threaded generation. This does not affect the old API, which is still checking this.
**Base height method added**
This method was added to also bring the Minecraft generator and Bukkit generator more in line. With this it is possible to return the max height of a location (before decorations). This is useful to let most structures know were to place them. This fixes SPIGOT-5567. (This fixes not all structures placement, desert pyramids for example are still way up at y-level 64, This however is more a vanilla bug and should be fixed at Mojangs end).
**WorldInfo Class**
The World object was swapped for a WorldInfo object. This is because many methods of the World object won't work during world generation and would mostly likely result in a deadlock. It contains any information a plugin should need to identify the world.
**BlockPopulator Changes**
Instead of directly manipulating a chunk, changes are now made to a new class LimitedRegion, this class provides methods to populated the chunk and its surrounding area. The wrapping is done so that the population can be moved into the place where Minecraft generates decorations. Where there is no chunk to access yet. By moving it into this place the generation is now async and the surrounding area of the chunk can also be used.
For common methods between the World and LimitedRegion a RegionAccessor was added.
By: DerFrZocker <derrieple@gmail.com>
2021-08-15 00:08:16 +02:00
+ org.bukkit.generator.WorldInfo worldInfo = new org.bukkit.craftbukkit.generator.CraftWorldInfo(iworlddataserver, worldSession, org.bukkit.World.Environment.getEnvironment(dimension), dimensionmanager);
+ if (biomeProvider == null && gen != null) {
+ biomeProvider = gen.getDefaultBiomeProvider(worldInfo);
+ }
+
+ if (biomeProvider != null) {
2021-11-21 23:00:00 +01:00
+ WorldChunkManager worldChunkManager = new CustomWorldChunkManager(worldInfo, biomeProvider, registryHolder.ownedRegistryOrThrow(IRegistry.BIOME_REGISTRY));
SPIGOT-5880, SPIGOT-5567: New ChunkGenerator API
## **Current API**
The current world generation API is very old and limited when you want to make more complex world generation. Resulting in some hard to fix bugs such as that you cannot modify blocks outside the chunk in the BlockPopulator (which should and was per the docs possible), or strange behavior such as SPIGOT-5880.
## **New API**
With the new API, the generation is more separate in multiple methods and is more in line with Vanilla chunk generation. The new API is designed to as future proof as possible. If for example a new generation step is added it can easily also be added as a step in API by simply creating the method for it. On the other side if a generation step gets removed, the method can easily be called after another, which is the case with surface and bedrock. The new API and changes are also fully backwards compatible with old chunk generators.
### **Changes in the new api**
**Extra generation steps:**
Noise, surface, bedrock and caves are added as steps. With those generation steps three extra methods for Vanilla generation are also added. Those new methods provide the ChunkData instead of returning one. The reason for this is, that the ChunkData is now backed by a ChunkAccess. With this, each step has the information of the step before and the Vanilla information (if chosen by setting a 'should' method to true). The old method is deprecated.
**New class BiomeProvider**
The BiomeProvider acts as Biome source and wrapper for the NMS class WorldChunkManager. With this the underlying Vanilla ChunkGeneration knows which Biome to use for the structure and decoration generation. (Fixes: SPIGOT-5880). Although the List of Biomes which is required in BiomeProvider, is currently not much in use in Vanilla, I decided to add it to future proof the API when it may be required in later versions of Minecraft.
The BiomeProvider is also separated from the ChunkGenerator for plugins which only want to change the biome map, such as single Biome worlds or if some biomes should be more present than others.
**Deprecated isParallelCapable**
Mojang has and is pushing to a more multi threaded chunk generation. This should also be the case for custom chunk generators. This is why the new API only supports multi threaded generation. This does not affect the old API, which is still checking this.
**Base height method added**
This method was added to also bring the Minecraft generator and Bukkit generator more in line. With this it is possible to return the max height of a location (before decorations). This is useful to let most structures know were to place them. This fixes SPIGOT-5567. (This fixes not all structures placement, desert pyramids for example are still way up at y-level 64, This however is more a vanilla bug and should be fixed at Mojangs end).
**WorldInfo Class**
The World object was swapped for a WorldInfo object. This is because many methods of the World object won't work during world generation and would mostly likely result in a deadlock. It contains any information a plugin should need to identify the world.
**BlockPopulator Changes**
Instead of directly manipulating a chunk, changes are now made to a new class LimitedRegion, this class provides methods to populated the chunk and its surrounding area. The wrapping is done so that the population can be moved into the place where Minecraft generates decorations. Where there is no chunk to access yet. By moving it into this place the generation is now async and the surrounding area of the chunk can also be used.
For common methods between the World and LimitedRegion a RegionAccessor was added.
By: DerFrZocker <derrieple@gmail.com>
2021-08-15 00:08:16 +02:00
+ if (chunkgenerator instanceof ChunkGeneratorAbstract) {
2021-11-21 23:00:00 +01:00
+ chunkgenerator = new ChunkGeneratorAbstract(((ChunkGeneratorAbstract) chunkgenerator).noises, worldChunkManager, chunkgenerator.strongholdSeed, ((ChunkGeneratorAbstract) chunkgenerator).settings);
SPIGOT-5880, SPIGOT-5567: New ChunkGenerator API
## **Current API**
The current world generation API is very old and limited when you want to make more complex world generation. Resulting in some hard to fix bugs such as that you cannot modify blocks outside the chunk in the BlockPopulator (which should and was per the docs possible), or strange behavior such as SPIGOT-5880.
## **New API**
With the new API, the generation is more separate in multiple methods and is more in line with Vanilla chunk generation. The new API is designed to as future proof as possible. If for example a new generation step is added it can easily also be added as a step in API by simply creating the method for it. On the other side if a generation step gets removed, the method can easily be called after another, which is the case with surface and bedrock. The new API and changes are also fully backwards compatible with old chunk generators.
### **Changes in the new api**
**Extra generation steps:**
Noise, surface, bedrock and caves are added as steps. With those generation steps three extra methods for Vanilla generation are also added. Those new methods provide the ChunkData instead of returning one. The reason for this is, that the ChunkData is now backed by a ChunkAccess. With this, each step has the information of the step before and the Vanilla information (if chosen by setting a 'should' method to true). The old method is deprecated.
**New class BiomeProvider**
The BiomeProvider acts as Biome source and wrapper for the NMS class WorldChunkManager. With this the underlying Vanilla ChunkGeneration knows which Biome to use for the structure and decoration generation. (Fixes: SPIGOT-5880). Although the List of Biomes which is required in BiomeProvider, is currently not much in use in Vanilla, I decided to add it to future proof the API when it may be required in later versions of Minecraft.
The BiomeProvider is also separated from the ChunkGenerator for plugins which only want to change the biome map, such as single Biome worlds or if some biomes should be more present than others.
**Deprecated isParallelCapable**
Mojang has and is pushing to a more multi threaded chunk generation. This should also be the case for custom chunk generators. This is why the new API only supports multi threaded generation. This does not affect the old API, which is still checking this.
**Base height method added**
This method was added to also bring the Minecraft generator and Bukkit generator more in line. With this it is possible to return the max height of a location (before decorations). This is useful to let most structures know were to place them. This fixes SPIGOT-5567. (This fixes not all structures placement, desert pyramids for example are still way up at y-level 64, This however is more a vanilla bug and should be fixed at Mojangs end).
**WorldInfo Class**
The World object was swapped for a WorldInfo object. This is because many methods of the World object won't work during world generation and would mostly likely result in a deadlock. It contains any information a plugin should need to identify the world.
**BlockPopulator Changes**
Instead of directly manipulating a chunk, changes are now made to a new class LimitedRegion, this class provides methods to populated the chunk and its surrounding area. The wrapping is done so that the population can be moved into the place where Minecraft generates decorations. Where there is no chunk to access yet. By moving it into this place the generation is now async and the surrounding area of the chunk can also be used.
For common methods between the World and LimitedRegion a RegionAccessor was added.
By: DerFrZocker <derrieple@gmail.com>
2021-08-15 00:08:16 +02:00
+ }
+ }
+
2021-11-21 23:00:00 +01:00
+ ResourceKey<World> worldKey = ResourceKey.create(IRegistry.DIMENSION_REGISTRY, dimensionKey.location());
2021-03-08 22:47:33 +01:00
+
2021-04-16 02:36:05 +02:00
+ if (dimensionKey == WorldDimension.OVERWORLD) {
2021-06-11 07:00:00 +02:00
+ this.worldData = worlddata;
2021-11-21 23:00:00 +01:00
+ this.worldData.setGameType(((DedicatedServer) this).getProperties().gamemode); // From DedicatedServer.init
2020-06-25 02:00:00 +02:00
+
2021-06-11 07:00:00 +02:00
+ WorldLoadListener worldloadlistener = this.progressListenerFactory.create(11);
2020-06-25 02:00:00 +02:00
+
SPIGOT-5880, SPIGOT-5567: New ChunkGenerator API
## **Current API**
The current world generation API is very old and limited when you want to make more complex world generation. Resulting in some hard to fix bugs such as that you cannot modify blocks outside the chunk in the BlockPopulator (which should and was per the docs possible), or strange behavior such as SPIGOT-5880.
## **New API**
With the new API, the generation is more separate in multiple methods and is more in line with Vanilla chunk generation. The new API is designed to as future proof as possible. If for example a new generation step is added it can easily also be added as a step in API by simply creating the method for it. On the other side if a generation step gets removed, the method can easily be called after another, which is the case with surface and bedrock. The new API and changes are also fully backwards compatible with old chunk generators.
### **Changes in the new api**
**Extra generation steps:**
Noise, surface, bedrock and caves are added as steps. With those generation steps three extra methods for Vanilla generation are also added. Those new methods provide the ChunkData instead of returning one. The reason for this is, that the ChunkData is now backed by a ChunkAccess. With this, each step has the information of the step before and the Vanilla information (if chosen by setting a 'should' method to true). The old method is deprecated.
**New class BiomeProvider**
The BiomeProvider acts as Biome source and wrapper for the NMS class WorldChunkManager. With this the underlying Vanilla ChunkGeneration knows which Biome to use for the structure and decoration generation. (Fixes: SPIGOT-5880). Although the List of Biomes which is required in BiomeProvider, is currently not much in use in Vanilla, I decided to add it to future proof the API when it may be required in later versions of Minecraft.
The BiomeProvider is also separated from the ChunkGenerator for plugins which only want to change the biome map, such as single Biome worlds or if some biomes should be more present than others.
**Deprecated isParallelCapable**
Mojang has and is pushing to a more multi threaded chunk generation. This should also be the case for custom chunk generators. This is why the new API only supports multi threaded generation. This does not affect the old API, which is still checking this.
**Base height method added**
This method was added to also bring the Minecraft generator and Bukkit generator more in line. With this it is possible to return the max height of a location (before decorations). This is useful to let most structures know were to place them. This fixes SPIGOT-5567. (This fixes not all structures placement, desert pyramids for example are still way up at y-level 64, This however is more a vanilla bug and should be fixed at Mojangs end).
**WorldInfo Class**
The World object was swapped for a WorldInfo object. This is because many methods of the World object won't work during world generation and would mostly likely result in a deadlock. It contains any information a plugin should need to identify the world.
**BlockPopulator Changes**
Instead of directly manipulating a chunk, changes are now made to a new class LimitedRegion, this class provides methods to populated the chunk and its surrounding area. The wrapping is done so that the population can be moved into the place where Minecraft generates decorations. Where there is no chunk to access yet. By moving it into this place the generation is now async and the surrounding area of the chunk can also be used.
For common methods between the World and LimitedRegion a RegionAccessor was added.
By: DerFrZocker <derrieple@gmail.com>
2021-08-15 00:08:16 +02:00
+ world = new WorldServer(this, this.executor, worldSession, iworlddataserver, worldKey, dimensionmanager, worldloadlistener, chunkgenerator, flag, j, list, true, org.bukkit.World.Environment.getEnvironment(dimension), gen, biomeProvider);
2021-11-21 23:00:00 +01:00
+ WorldPersistentData worldpersistentdata = world.getDataStorage();
+ this.readScoreboard(worldpersistentdata);
2014-11-25 22:32:16 +01:00
+ this.server.scoreboardManager = new org.bukkit.craftbukkit.scoreboard.CraftScoreboardManager(this, world.getScoreboard());
2021-06-11 07:00:00 +02:00
+ this.commandStorage = new PersistentCommandStorage(worldpersistentdata);
2018-08-26 04:00:00 +02:00
+ } else {
2021-06-11 07:00:00 +02:00
+ WorldLoadListener worldloadlistener = this.progressListenerFactory.create(11);
SPIGOT-5880, SPIGOT-5567: New ChunkGenerator API
## **Current API**
The current world generation API is very old and limited when you want to make more complex world generation. Resulting in some hard to fix bugs such as that you cannot modify blocks outside the chunk in the BlockPopulator (which should and was per the docs possible), or strange behavior such as SPIGOT-5880.
## **New API**
With the new API, the generation is more separate in multiple methods and is more in line with Vanilla chunk generation. The new API is designed to as future proof as possible. If for example a new generation step is added it can easily also be added as a step in API by simply creating the method for it. On the other side if a generation step gets removed, the method can easily be called after another, which is the case with surface and bedrock. The new API and changes are also fully backwards compatible with old chunk generators.
### **Changes in the new api**
**Extra generation steps:**
Noise, surface, bedrock and caves are added as steps. With those generation steps three extra methods for Vanilla generation are also added. Those new methods provide the ChunkData instead of returning one. The reason for this is, that the ChunkData is now backed by a ChunkAccess. With this, each step has the information of the step before and the Vanilla information (if chosen by setting a 'should' method to true). The old method is deprecated.
**New class BiomeProvider**
The BiomeProvider acts as Biome source and wrapper for the NMS class WorldChunkManager. With this the underlying Vanilla ChunkGeneration knows which Biome to use for the structure and decoration generation. (Fixes: SPIGOT-5880). Although the List of Biomes which is required in BiomeProvider, is currently not much in use in Vanilla, I decided to add it to future proof the API when it may be required in later versions of Minecraft.
The BiomeProvider is also separated from the ChunkGenerator for plugins which only want to change the biome map, such as single Biome worlds or if some biomes should be more present than others.
**Deprecated isParallelCapable**
Mojang has and is pushing to a more multi threaded chunk generation. This should also be the case for custom chunk generators. This is why the new API only supports multi threaded generation. This does not affect the old API, which is still checking this.
**Base height method added**
This method was added to also bring the Minecraft generator and Bukkit generator more in line. With this it is possible to return the max height of a location (before decorations). This is useful to let most structures know were to place them. This fixes SPIGOT-5567. (This fixes not all structures placement, desert pyramids for example are still way up at y-level 64, This however is more a vanilla bug and should be fixed at Mojangs end).
**WorldInfo Class**
The World object was swapped for a WorldInfo object. This is because many methods of the World object won't work during world generation and would mostly likely result in a deadlock. It contains any information a plugin should need to identify the world.
**BlockPopulator Changes**
Instead of directly manipulating a chunk, changes are now made to a new class LimitedRegion, this class provides methods to populated the chunk and its surrounding area. The wrapping is done so that the population can be moved into the place where Minecraft generates decorations. Where there is no chunk to access yet. By moving it into this place the generation is now async and the surrounding area of the chunk can also be used.
For common methods between the World and LimitedRegion a RegionAccessor was added.
By: DerFrZocker <derrieple@gmail.com>
2021-08-15 00:08:16 +02:00
+ world = new WorldServer(this, this.executor, worldSession, iworlddataserver, worldKey, dimensionmanager, worldloadlistener, chunkgenerator, flag, j, ImmutableList.of(), true, org.bukkit.World.Environment.getEnvironment(dimension), gen, biomeProvider);
2018-08-26 04:00:00 +02:00
+ }
2019-04-23 04:00:00 +02:00
+
2021-11-21 23:00:00 +01:00
+ worlddata.setModdedInfo(this.getServerModName(), this.getModdedStatus().shouldReportAsModified());
+ this.initWorld(world, worlddata, worldData, worlddata.worldGenSettings());
2019-01-05 07:03:12 +01:00
+
2021-11-21 23:00:00 +01:00
+ this.levels.put(world.dimension(), world);
+ this.getPlayerList().addWorldborderListener(world);
2020-08-11 23:00:00 +02:00
+
2019-04-23 04:00:00 +02:00
+ if (worlddata.getCustomBossEvents() != null) {
2021-11-21 23:00:00 +01:00
+ this.getCustomBossEvents().load(worlddata.getCustomBossEvents());
2018-07-15 02:00:00 +02:00
+ }
2019-05-04 12:54:32 +02:00
+ }
2021-11-21 23:00:00 +01:00
+ this.forceDifficulty();
+ for (WorldServer worldserver : this.getAllLevels()) {
+ this.prepareLevels(worldserver.getChunkSource().chunkMap.progressListener, worldserver);
2021-07-06 16:00:00 +02:00
+ worldserver.entityManager.tick(); // SPIGOT-6526: Load pending entities so they are available to the API
2019-05-02 07:15:53 +02:00
+ this.server.getPluginManager().callEvent(new org.bukkit.event.world.WorldLoadEvent(worldserver.getWorld()));
2021-11-21 23:00:00 +01:00
}
- WorldServer worldserver = new WorldServer(this, this.executor, this.storageSource, iworlddataserver, World.OVERWORLD, dimensionmanager, worldloadlistener, (ChunkGenerator) object, flag, j, list, true);
2019-04-23 04:00:00 +02:00
+ this.server.enablePlugins(org.bukkit.plugin.PluginLoadOrder.POSTWORLD);
+ this.server.getPluginManager().callEvent(new ServerLoadEvent(ServerLoadEvent.LoadType.STARTUP));
2021-06-11 07:00:00 +02:00
+ this.connection.acceptConnections();
2021-11-21 23:00:00 +01:00
+ }
+ // CraftBukkit end
2019-06-21 12:00:00 +02:00
2021-11-21 23:00:00 +01:00
- this.levels.put(World.OVERWORLD, worldserver);
- WorldPersistentData worldpersistentdata = worldserver.getDataStorage();
+ protected void forceDifficulty() {}
2019-12-10 23:00:00 +01:00
2021-11-21 23:00:00 +01:00
- this.readScoreboard(worldpersistentdata);
- this.commandStorage = new PersistentCommandStorage(worldpersistentdata);
2019-06-25 13:02:13 +02:00
+ // CraftBukkit start
2020-06-25 02:00:00 +02:00
+ public void initWorld(WorldServer worldserver, IWorldDataServer iworlddataserver, SaveData saveData, GeneratorSettings generatorsettings) {
2021-11-21 23:00:00 +01:00
+ boolean flag = generatorsettings.isDebug();
2019-04-23 04:00:00 +02:00
+ // CraftBukkit start
2020-06-25 02:00:00 +02:00
+ if (worldserver.generator != null) {
+ worldserver.getWorld().getPopulators().addAll(worldserver.generator.getDefaultPopulators(worldserver.getWorld()));
2021-11-21 23:00:00 +01:00
+ }
2020-06-25 02:00:00 +02:00
WorldBorder worldborder = worldserver.getWorldBorder();
2022-01-31 22:13:13 +01:00
+ worldborder.applySettings(iworlddataserver.getWorldBorder()); // CraftBukkit - move up so that WorldBorder is set during WorldInitEvent
+ this.server.getPluginManager().callEvent(new org.bukkit.event.world.WorldInitEvent(worldserver.getWorld())); // CraftBukkit - SPIGOT-5569: Call WorldInitEvent before any chunks are generated
2018-07-15 02:00:00 +02:00
2021-11-21 23:00:00 +01:00
if (!iworlddataserver.isInitialized()) {
2022-01-31 22:13:13 +01:00
try {
@@ -411,31 +640,8 @@
2021-11-21 23:00:00 +01:00
iworlddataserver.setInitialized(true);
2019-04-23 04:00:00 +02:00
}
2021-11-21 23:00:00 +01:00
- this.getPlayerList().addWorldborderListener(worldserver);
2021-06-11 07:00:00 +02:00
- if (this.worldData.getCustomBossEvents() != null) {
2021-11-21 23:00:00 +01:00
- this.getCustomBossEvents().load(this.worldData.getCustomBossEvents());
2019-04-23 04:00:00 +02:00
- }
-
2021-11-21 23:00:00 +01:00
- Iterator iterator = registrymaterials.entrySet().iterator();
2019-04-23 04:00:00 +02:00
-
- while (iterator.hasNext()) {
2020-06-25 02:00:00 +02:00
- Entry<ResourceKey<WorldDimension>, WorldDimension> entry = (Entry) iterator.next();
2020-08-11 23:00:00 +02:00
- ResourceKey<WorldDimension> resourcekey = (ResourceKey) entry.getKey();
2019-04-23 04:00:00 +02:00
-
2020-08-11 23:00:00 +02:00
- if (resourcekey != WorldDimension.OVERWORLD) {
2021-11-21 23:00:00 +01:00
- ResourceKey<World> resourcekey1 = ResourceKey.create(IRegistry.DIMENSION_REGISTRY, resourcekey.location());
- DimensionManager dimensionmanager1 = ((WorldDimension) entry.getValue()).type();
- ChunkGenerator chunkgenerator = ((WorldDimension) entry.getValue()).generator();
2021-06-11 07:00:00 +02:00
- SecondaryWorldData secondaryworlddata = new SecondaryWorldData(this.worldData, iworlddataserver);
- WorldServer worldserver1 = new WorldServer(this, this.executor, this.storageSource, secondaryworlddata, resourcekey1, dimensionmanager1, worldloadlistener, chunkgenerator, flag, j, ImmutableList.of(), false);
2020-06-25 02:00:00 +02:00
-
2021-11-21 23:00:00 +01:00
- worldborder.addListener(new IWorldBorderListener.a(worldserver1.getWorldBorder()));
2021-06-11 07:00:00 +02:00
- this.levels.put(resourcekey1, worldserver1);
2019-04-23 04:00:00 +02:00
- }
- }
-
2022-01-31 22:13:13 +01:00
- worldborder.applySettings(iworlddataserver.getWorldBorder());
2018-08-26 04:00:00 +02:00
}
2019-04-23 04:00:00 +02:00
+ // CraftBukkit end
2018-08-26 04:00:00 +02:00
2021-11-21 23:00:00 +01:00
private static void setInitialSpawn(WorldServer worldserver, IWorldDataServer iworlddataserver, boolean flag, boolean flag1) {
2021-06-11 07:00:00 +02:00
if (flag1) {
2021-12-02 22:34:38 +01:00
@@ -443,6 +649,21 @@
2021-11-21 23:00:00 +01:00
} else {
ChunkGenerator chunkgenerator = worldserver.getChunkSource().getGenerator();
ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(chunkgenerator.climateSampler().findSpawnPosition());
2020-06-25 02:00:00 +02:00
+ // CraftBukkit start
+ if (worldserver.generator != null) {
+ Random rand = new Random(worldserver.getSeed());
+ org.bukkit.Location spawn = worldserver.generator.getFixedSpawnLocation(worldserver.getWorld(), rand);
+
+ if (spawn != null) {
+ if (spawn.getWorld() != worldserver.getWorld()) {
2021-11-21 23:00:00 +01:00
+ throw new IllegalStateException("Cannot set spawn point for " + iworlddataserver.getLevelName() + " to be in another world (" + spawn.getWorld().getName() + ")");
2020-06-25 02:00:00 +02:00
+ } else {
2020-08-11 23:00:00 +02:00
+ iworlddataserver.setSpawn(new BlockPosition(spawn.getBlockX(), spawn.getBlockY(), spawn.getBlockZ()), spawn.getYaw());
2020-06-25 02:00:00 +02:00
+ return;
+ }
+ }
+ }
+ // CraftBukkit end
2021-11-21 23:00:00 +01:00
int i = chunkgenerator.getSpawnHeight(worldserver);
2020-06-25 02:00:00 +02:00
2021-11-21 23:00:00 +01:00
if (i < worldserver.getMinBuildHeight()) {
2021-12-02 22:34:38 +01:00
@@ -500,8 +721,15 @@
2020-06-25 02:00:00 +02:00
iworlddataserver.setGameType(EnumGamemode.SPECTATOR);
2019-04-23 04:00:00 +02:00
}
2018-08-26 04:00:00 +02:00
2021-11-21 23:00:00 +01:00
- public void prepareLevels(WorldLoadListener worldloadlistener) {
- WorldServer worldserver = this.overworld();
2019-04-23 04:00:00 +02:00
+ // CraftBukkit start
2021-11-21 23:00:00 +01:00
+ public void prepareLevels(WorldLoadListener worldloadlistener, WorldServer worldserver) {
2019-05-02 07:15:53 +02:00
+ if (!worldserver.getWorld().getKeepSpawnInMemory()) {
+ return;
+ }
+
2021-11-21 23:00:00 +01:00
+ // WorldServer worldserver = this.overworld();
2019-04-25 07:33:13 +02:00
+ this.forceTicks = true;
2019-04-23 04:00:00 +02:00
+ // CraftBukkit end
2014-11-25 22:32:16 +01:00
2021-11-21 23:00:00 +01:00
MinecraftServer.LOGGER.info("Preparing start region for dimension {}", worldserver.dimension().location());
BlockPosition blockposition = worldserver.getSharedSpawnPos();
2021-12-02 22:34:38 +01:00
@@ -514,16 +742,20 @@
2021-11-21 23:00:00 +01:00
chunkproviderserver.addRegionTicket(TicketType.START, new ChunkCoordIntPair(blockposition), 11, Unit.INSTANCE);
2019-04-25 07:33:13 +02:00
2021-11-21 23:00:00 +01:00
while (chunkproviderserver.getTickingGenerated() != 441) {
- this.nextTickTime = SystemUtils.getMillis() + 10L;
- this.waitUntilNextTick();
2019-04-25 07:33:13 +02:00
+ // CraftBukkit start
2021-11-21 23:00:00 +01:00
+ // this.nextTickTime = SystemUtils.getMillis() + 10L;
2019-04-25 07:33:13 +02:00
+ this.executeModerately();
+ // CraftBukkit end
}
2014-11-25 22:32:16 +01:00
2021-11-21 23:00:00 +01:00
- this.nextTickTime = SystemUtils.getMillis() + 10L;
- this.waitUntilNextTick();
2021-06-11 07:00:00 +02:00
- Iterator iterator = this.levels.values().iterator();
2019-04-25 07:33:13 +02:00
-
2019-04-23 04:00:00 +02:00
- while (iterator.hasNext()) {
2020-06-25 02:00:00 +02:00
- WorldServer worldserver1 = (WorldServer) iterator.next();
2019-04-25 07:33:13 +02:00
+ // CraftBukkit start
2021-11-21 23:00:00 +01:00
+ // this.nextTickTime = SystemUtils.getMillis() + 10L;
2019-04-25 07:33:13 +02:00
+ this.executeModerately();
2021-11-21 23:00:00 +01:00
+ // Iterator iterator = this.levels.values().iterator();
2019-04-25 07:33:13 +02:00
+
2019-04-23 04:00:00 +02:00
+ if (true) {
2020-06-25 02:00:00 +02:00
+ WorldServer worldserver1 = worldserver;
2019-04-23 04:00:00 +02:00
+ // CraftBukkit end
2021-11-21 23:00:00 +01:00
ForcedChunk forcedchunk = (ForcedChunk) worldserver1.getDataStorage().get(ForcedChunk::load, "chunks");
2019-04-23 04:00:00 +02:00
if (forcedchunk != null) {
2021-12-02 22:34:38 +01:00
@@ -538,11 +770,18 @@
2019-04-25 07:33:13 +02:00
}
}
2021-11-21 23:00:00 +01:00
- this.nextTickTime = SystemUtils.getMillis() + 10L;
- this.waitUntilNextTick();
2019-04-25 07:33:13 +02:00
+ // CraftBukkit start
2021-11-21 23:00:00 +01:00
+ // this.nextTickTime = SystemUtils.getMillis() + 10L;
2019-04-25 07:33:13 +02:00
+ this.executeModerately();
+ // CraftBukkit end
2021-11-21 23:00:00 +01:00
worldloadlistener.stop();
chunkproviderserver.getLightEngine().setTaskPerBatch(5);
- this.updateMobSpawningFlags();
2019-04-25 07:33:13 +02:00
+ // CraftBukkit start
2021-11-21 23:00:00 +01:00
+ // this.updateMobSpawningFlags();
+ worldserver.setSpawnSettings(this.isSpawningMonsters(), this.isSpawningAnimals());
2020-11-06 08:46:21 +01:00
+
2019-04-25 07:33:13 +02:00
+ this.forceTicks = false;
+ // CraftBukkit end
2014-11-25 22:32:16 +01:00
}
2021-11-21 23:00:00 +01:00
protected void detectBundledResources() {
2021-12-02 22:34:38 +01:00
@@ -587,12 +826,16 @@
2021-06-11 07:00:00 +02:00
worldserver.save((IProgressUpdate) null, flag1, worldserver.noSave && !flag2);
2019-06-25 13:02:13 +02:00
}
2019-04-28 03:13:44 +02:00
2019-06-25 13:02:13 +02:00
+ // CraftBukkit start - moved to WorldServer.save
+ /*
2021-11-21 23:00:00 +01:00
WorldServer worldserver1 = this.overworld();
IWorldDataServer iworlddataserver = this.worldData.overworldData();
2019-04-28 03:13:44 +02:00
2021-11-21 23:00:00 +01:00
iworlddataserver.setWorldBorder(worldserver1.getWorldBorder().createSettings());
this.worldData.setCustomBossEvents(this.getCustomBossEvents().save());
this.storageSource.saveDataTag(this.registryHolder, this.worldData, this.getPlayerList().getSingleplayerData());
2019-06-25 13:02:13 +02:00
+ */
+ // CraftBukkit end
2021-07-06 16:00:00 +02:00
if (flag1) {
2021-11-21 23:00:00 +01:00
Iterator iterator1 = this.getAllLevels().iterator();
2019-04-28 03:13:44 +02:00
2021-12-02 22:34:38 +01:00
@@ -627,8 +870,29 @@
2021-11-21 23:00:00 +01:00
this.stopServer();
2014-11-25 22:32:16 +01:00
}
2015-02-07 11:39:00 +01:00
+ // CraftBukkit start
+ private boolean hasStopped = false;
+ private final Object stopLock = new Object();
2019-04-23 04:00:00 +02:00
+ public final boolean hasStopped() {
+ synchronized (stopLock) {
+ return hasStopped;
+ }
+ }
2015-02-07 11:39:00 +01:00
+ // CraftBukkit end
+
2021-11-21 23:00:00 +01:00
public void stopServer() {
2015-02-07 11:39:00 +01:00
+ // CraftBukkit start - prevent double stopping on multiple threads
+ synchronized(stopLock) {
+ if (hasStopped) return;
+ hasStopped = true;
+ }
+ // CraftBukkit end
2016-02-29 22:32:46 +01:00
MinecraftServer.LOGGER.info("Stopping server");
2016-03-01 20:33:41 +01:00
+ // CraftBukkit start
+ if (this.server != null) {
+ this.server.disablePlugins();
+ }
+ // CraftBukkit end
2021-11-21 23:00:00 +01:00
if (this.getConnection() != null) {
this.getConnection().stop();
2016-03-01 20:33:41 +01:00
}
2021-12-02 22:34:38 +01:00
@@ -638,6 +902,7 @@
2016-02-29 22:32:46 +01:00
MinecraftServer.LOGGER.info("Saving players");
2021-11-21 23:00:00 +01:00
this.playerList.saveAll();
this.playerList.removeAll();
2016-02-29 22:32:46 +01:00
+ try { Thread.sleep(100); } catch (InterruptedException ex) {} // CraftBukkit - SPIGOT-625 - give server at least a chance to send packets
}
2015-09-15 11:52:51 +02:00
2018-08-26 04:00:00 +02:00
MinecraftServer.LOGGER.info("Saving worlds");
2021-12-02 22:34:38 +01:00
@@ -712,9 +977,10 @@
2021-06-11 07:00:00 +02:00
while (this.running) {
2021-11-21 23:00:00 +01:00
long i = SystemUtils.getMillis() - this.nextTickTime;
2019-05-19 04:07:37 +02:00
2021-06-11 07:00:00 +02:00
- if (i > 2000L && this.nextTickTime - this.lastOverloadWarning >= 15000L) {
+ if (i > 5000L && this.nextTickTime - this.lastOverloadWarning >= 30000L) { // CraftBukkit
2018-07-15 02:00:00 +02:00
long j = i / 50L;
2014-11-25 22:32:16 +01:00
+ if (server.getWarnOnOverload()) // CraftBukkit
2018-12-06 00:00:00 +01:00
MinecraftServer.LOGGER.warn("Can't keep up! Is the server overloaded? Running {}ms or {} ticks behind", i, j);
2021-06-11 07:00:00 +02:00
this.nextTickTime += j * 50L;
this.lastOverloadWarning = this.nextTickTime;
2021-12-02 22:34:38 +01:00
@@ -725,6 +991,7 @@
2021-11-21 23:00:00 +01:00
this.debugCommandProfiler = new MinecraftServer.a(SystemUtils.getNanos(), this.tickCount);
2018-07-15 02:00:00 +02:00
}
+ MinecraftServer.currentTick = (int) (System.currentTimeMillis() / 50); // CraftBukkit
2021-06-11 07:00:00 +02:00
this.nextTickTime += 50L;
2021-11-21 23:00:00 +01:00
this.startMetricsRecordingTick();
this.profiler.push("tick");
2021-12-02 22:34:38 +01:00
@@ -775,6 +1042,12 @@
2021-11-21 23:00:00 +01:00
this.profileCache.clearExecutor();
}
2014-11-25 22:32:16 +01:00
+ // CraftBukkit start - Restore terminal to original settings
+ try {
+ reader.getTerminal().restore();
+ } catch (Exception ignored) {
+ }
+ // CraftBukkit end
2021-11-21 23:00:00 +01:00
this.onServerExit();
2014-11-25 22:32:16 +01:00
}
2021-12-02 22:34:38 +01:00
@@ -783,8 +1056,15 @@
2019-04-25 07:33:13 +02:00
}
2021-11-21 23:00:00 +01:00
private boolean haveTime() {
- return this.runningTask() || SystemUtils.getMillis() < (this.mayHaveDelayedTasks ? this.delayedTasksMaxNextTickTime : this.nextTickTime);
2019-04-25 07:33:13 +02:00
+ // CraftBukkit start
2021-11-21 23:00:00 +01:00
+ return this.forceTicks || this.runningTask() || SystemUtils.getMillis() < (this.mayHaveDelayedTasks ? this.delayedTasksMaxNextTickTime : this.nextTickTime);
2019-06-21 12:00:00 +02:00
+ }
+
2019-04-25 07:33:13 +02:00
+ private void executeModerately() {
2021-11-21 23:00:00 +01:00
+ this.runAllTasks();
2019-04-25 07:33:13 +02:00
+ java.util.concurrent.locks.LockSupport.parkNanos("executing tasks", 1000L);
2019-06-21 12:00:00 +02:00
}
2019-04-25 07:33:13 +02:00
+ // CraftBukkit end
2019-06-21 12:00:00 +02:00
2021-11-21 23:00:00 +01:00
protected void waitUntilNextTick() {
this.runAllTasks();
2021-12-02 22:34:38 +01:00
@@ -830,7 +1110,7 @@
2021-11-21 23:00:00 +01:00
}
}
- protected void doRunTask(TickTask ticktask) {
+ public void doRunTask(TickTask ticktask) { // CraftBukkit - decompile error
this.getProfiler().incrementCounter("runTask");
super.doRunTask(ticktask);
}
2021-12-02 22:34:38 +01:00
@@ -901,7 +1181,7 @@
2021-11-21 23:00:00 +01:00
}
2014-11-25 22:32:16 +01:00
}
2021-06-11 07:00:00 +02:00
- if (this.tickCount % 6000 == 0) {
+ if (autosavePeriod > 0 && this.tickCount % autosavePeriod == 0) { // CraftBukkit
2019-04-23 04:00:00 +02:00
MinecraftServer.LOGGER.debug("Autosave started");
2021-11-21 23:00:00 +01:00
this.profiler.push("save");
this.saveEverything(true, false, false);
2021-12-02 22:34:38 +01:00
@@ -920,22 +1200,39 @@
2016-06-30 07:20:04 +02:00
}
2021-11-21 23:00:00 +01:00
public void tickChildren(BooleanSupplier booleansupplier) {
2021-06-11 07:00:00 +02:00
+ this.server.getScheduler().mainThreadHeartbeat(this.tickCount); // CraftBukkit
2021-11-21 23:00:00 +01:00
this.profiler.push("commandFunctions");
this.getFunctions().tick();
this.profiler.popPush("levels");
Iterator iterator = this.getAllLevels().iterator();
2014-11-25 22:32:16 +01:00
+ // CraftBukkit start
+ // Run tasks that are waiting on processing
+ while (!processQueue.isEmpty()) {
+ processQueue.remove().run();
+ }
+
+ // Send time updates to everyone, it will get the right time from the world the player is in.
2021-06-11 07:00:00 +02:00
+ if (this.tickCount % 20 == 0) {
2014-11-25 22:32:16 +01:00
+ for (int i = 0; i < this.getPlayerList().players.size(); ++i) {
+ EntityPlayer entityplayer = (EntityPlayer) this.getPlayerList().players.get(i);
2021-11-21 23:00:00 +01:00
+ entityplayer.connection.send(new PacketPlayOutUpdateTime(entityplayer.level.getGameTime(), entityplayer.getPlayerTime(), entityplayer.level.getGameRules().getBoolean(GameRules.RULE_DAYLIGHT))); // Add support for per player time
2014-11-25 22:32:16 +01:00
+ }
+ }
+
2019-06-21 12:00:00 +02:00
while (iterator.hasNext()) {
WorldServer worldserver = (WorldServer) iterator.next();
2021-11-21 23:00:00 +01:00
this.profiler.push(() -> {
return worldserver + " " + worldserver.dimension().location();
2020-06-25 02:00:00 +02:00
});
+ /* Drop global time updates
2021-06-11 07:00:00 +02:00
if (this.tickCount % 20 == 0) {
2021-11-21 23:00:00 +01:00
this.profiler.push("timeSync");
this.playerList.broadcastAll(new PacketPlayOutUpdateTime(worldserver.getGameTime(), worldserver.getDayTime(), worldserver.getGameRules().getBoolean(GameRules.RULE_DAYLIGHT)), worldserver.dimension());
this.profiler.pop();
2020-01-21 22:00:00 +01:00
}
2020-06-25 02:00:00 +02:00
+ // CraftBukkit end */
2020-01-21 22:00:00 +01:00
2021-11-21 23:00:00 +01:00
this.profiler.push("tick");
2014-11-25 22:32:16 +01:00
2021-12-02 22:34:38 +01:00
@@ -1024,7 +1321,7 @@
2014-11-25 22:32:16 +01:00
2021-06-11 07:00:00 +02:00
@DontObfuscate
2014-11-25 22:32:16 +01:00
public String getServerModName() {
- return "vanilla";
+ return server.getName(); // CraftBukkit - cb > vanilla!
}
2021-11-21 23:00:00 +01:00
public SystemReport fillSystemReport(SystemReport systemreport) {
2021-12-02 22:34:38 +01:00
@@ -1354,16 +1651,17 @@
2020-06-25 02:00:00 +02:00
2021-11-21 23:00:00 +01:00
public CompletableFuture<Void> reloadResources(Collection<String> collection) {
2020-06-25 02:00:00 +02:00
CompletableFuture<Void> completablefuture = CompletableFuture.supplyAsync(() -> {
- Stream stream = collection.stream();
+ Stream<String> stream = collection.stream(); // CraftBukkit - decompile error
2021-06-11 07:00:00 +02:00
ResourcePackRepository resourcepackrepository = this.packRepository;
2020-06-25 02:00:00 +02:00
2021-06-11 07:00:00 +02:00
Objects.requireNonNull(this.packRepository);
2021-11-21 23:00:00 +01:00
- return (ImmutableList) stream.map(resourcepackrepository::getPack).filter(Objects::nonNull).map(ResourcePackLoader::open).collect(ImmutableList.toImmutableList());
+ return stream.map(resourcepackrepository::getPack).filter(Objects::nonNull).map(ResourcePackLoader::open).collect(ImmutableList.toImmutableList()); // CraftBukkit - decompile error
2020-06-25 02:00:00 +02:00
}, this).thenCompose((immutablelist) -> {
2021-11-21 23:00:00 +01:00
return DataPackResources.loadResources(immutablelist, this.registryHolder, this.isDedicatedServer() ? CommandDispatcher.ServerType.DEDICATED : CommandDispatcher.ServerType.INTEGRATED, this.getFunctionCompilationLevel(), this.executor, this);
2020-06-25 02:00:00 +02:00
}).thenAcceptAsync((datapackresources) -> {
2021-06-11 07:00:00 +02:00
this.resources.close();
this.resources = datapackresources;
2020-06-30 02:51:26 +02:00
+ this.server.syncCommands(); // SPIGOT-5884: Lost on reload
2021-11-21 23:00:00 +01:00
this.packRepository.setSelected(collection);
this.worldData.setDataPackConfig(getSelectedPacks(this.packRepository));
datapackresources.updateGlobals();
2021-12-02 22:34:38 +01:00
@@ -1717,7 +2015,7 @@
2021-11-21 23:00:00 +01:00
try {
label51:
{
- ArrayList arraylist;
+ ArrayList<NativeModuleLister.a> arraylist; // CraftBukkit - decompile error
try {
arraylist = Lists.newArrayList(NativeModuleLister.listModules());
2021-12-02 22:34:38 +01:00
@@ -1767,6 +2065,22 @@
2014-11-25 22:32:16 +01:00
2014-11-29 01:53:49 +01:00
}
2016-02-29 22:32:46 +01:00
+ // CraftBukkit start
2019-04-23 04:00:00 +02:00
+ @Override
2021-11-21 23:00:00 +01:00
+ public boolean isSameThread() {
+ return super.isSameThread() || this.isStopped(); // CraftBukkit - MC-142590
2019-04-23 04:00:00 +02:00
+ }
+
2020-06-25 02:00:00 +02:00
+ public boolean isDebugging() {
+ return false;
+ }
+
2016-02-29 22:32:46 +01:00
+ @Deprecated
+ public static MinecraftServer getServer() {
2016-03-25 00:20:27 +01:00
+ return (Bukkit.getServer() instanceof CraftServer) ? ((CraftServer) Bukkit.getServer()).getServer() : null;
2016-02-29 22:32:46 +01:00
+ }
+ // CraftBukkit end
2020-06-25 02:00:00 +02:00
+
2021-11-21 23:00:00 +01:00
private void startMetricsRecordingTick() {
2021-06-11 07:00:00 +02:00
if (this.willStartRecordingMetrics) {
2021-11-21 23:00:00 +01:00
this.metricsRecorder = ActiveMetricsRecorder.createStarted(new ServerMetricsSamplersProvider(SystemUtils.timeSource, this.isDedicatedServer()), SystemUtils.timeSource, SystemUtils.ioPool(), new MetricsPersister("server"), this.onMetricsRecordingStopped, (path) -> {