55import com .mojang .serialization .Dynamic ;
66import com .mojang .serialization .Lifecycle ;
77import io .papermc .paper .FeatureHooks ;
8+ import io .papermc .paper .world .PaperWorldLoader ;
89import net .minecraft .core .Registry ;
910import net .minecraft .core .RegistryAccess ;
1011import net .minecraft .core .registries .Registries ;
11- import net .minecraft .nbt .NbtException ;
12- import net .minecraft .nbt .ReportedNbtException ;
1312import net .minecraft .resources .ResourceKey ;
1413import net .minecraft .resources .ResourceLocation ;
1514import net .minecraft .server .Main ;
2221import net .minecraft .world .entity .ai .village .VillageSiege ;
2322import net .minecraft .world .entity .npc .CatSpawner ;
2423import net .minecraft .world .entity .npc .WanderingTraderSpawner ;
25- import net .minecraft .world .level .ChunkPos ;
2624import net .minecraft .world .level .CustomSpawner ;
2725import net .minecraft .world .level .GameRules ;
2826import net .minecraft .world .level .GameType ;
3634import net .minecraft .world .level .levelgen .WorldOptions ;
3735import net .minecraft .world .level .storage .LevelDataAndDimensions ;
3836import net .minecraft .world .level .storage .LevelStorageSource ;
39- import net .minecraft .world .level .storage .LevelSummary ;
4037import net .minecraft .world .level .storage .PrimaryLevelData ;
4138import net .minecraft .world .level .validation .ContentValidationException ;
4239import net .thenextlvl .worlds .WorldsPlugin ;
4744import org .bukkit .World ;
4845import org .bukkit .craftbukkit .CraftServer ;
4946import org .bukkit .craftbukkit .generator .CraftWorldInfo ;
50- import org .bukkit .event .world .WorldLoadEvent ;
5147import org .bukkit .generator .WorldInfo ;
5248import org .jspecify .annotations .NullMarked ;
5349
@@ -72,6 +68,7 @@ public CompletableFuture<World> createAsync() {
7268 }
7369
7470 /**
71+ * @see MinecraftServer#createLevel(LevelStem, PaperWorldLoader.WorldLoadingInfo, LevelStorageSource.LevelStorageAccess, PrimaryLevelData)
7572 * @see CraftServer#createWorld(org.bukkit.WorldCreator)
7673 */
7774 private CompletableFuture <World > createInternal () {
@@ -94,6 +91,7 @@ private CompletableFuture<World> createInternal() {
9491 return CompletableFuture .failedFuture (e );
9592 }
9693
94+ /// Worlds start - find generator and biome provider
9795 var chunkGenerator = Optional .ofNullable (super .chunkGenerator )
9896 .orElseGet (() -> Optional .ofNullable (generator )
9997 .map (generator -> generator .generator (name ))
@@ -102,6 +100,7 @@ private CompletableFuture<World> createInternal() {
102100 .orElseGet (() -> Optional .ofNullable (generator )
103101 .map (generator -> generator .biomeProvider (name ))
104102 .orElseGet (() -> server .getBiomeProvider (name )));
103+ /// Worlds end
105104
106105 var dimensionType = resolveDimensionKey ();
107106
@@ -113,51 +112,16 @@ private CompletableFuture<World> createInternal() {
113112 return CompletableFuture .failedFuture (ex );
114113 }
115114
116- Dynamic <?> dataTag ;
117- if (levelStorageAccess .hasWorldData ()) {
118- LevelSummary summary ;
119- try {
120- dataTag = levelStorageAccess .getDataTag ();
121- summary = levelStorageAccess .getSummary (dataTag );
122- } catch (NbtException | ReportedNbtException | IOException e ) {
123- LevelStorageSource .LevelDirectory levelDirectory = levelStorageAccess .getLevelDirectory ();
124- plugin .getComponentLogger ().warn ("Failed to load world data from {}, attempting to use fallback" , levelDirectory .dataFile (), e );
125-
126- try {
127- dataTag = levelStorageAccess .getDataTagFallback ();
128- summary = levelStorageAccess .getSummary (dataTag );
129- } catch (NbtException | ReportedNbtException | IOException e1 ) {
130- plugin .getComponentLogger ().error ("Failed to load world data from {}" , levelDirectory .oldDataFile (), e1 );
131- plugin .getComponentLogger ().error (
132- "Failed to load world data from {} and {}. World files may be corrupted." ,
133- levelDirectory .dataFile (),
134- levelDirectory .oldDataFile ()
135- );
136- return CompletableFuture .failedFuture (e1 );
137- }
138-
139- levelStorageAccess .restoreLevelDataFromOld ();
140- }
141-
142- if (summary .requiresManualConversion ()) {
143- plugin .getComponentLogger ().warn ("This world must be opened in an older version (like 1.6.4) to be safely converted" );
144- return CompletableFuture .failedFuture (new IllegalStateException ("World requires manual conversion" ));
145- }
146-
147- if (!summary .isCompatible ()) {
148- plugin .getComponentLogger ().warn ("This world was created by an incompatible version." );
149- return CompletableFuture .failedFuture (new IllegalStateException ("World is incompatible" ));
150- }
151- } else {
152- dataTag = null ;
153- }
154-
155- var generatorSettings = Optional .ofNullable (preset ).orElse (Presets .CLASSIC_FLAT ).serialize ();
156-
157115 PrimaryLevelData primaryLevelData ;
158- WorldLoader .DataLoadContext context = console .worldLoader ;
116+ WorldLoader .DataLoadContext context = console .worldLoaderContext ;
159117 RegistryAccess .Frozen registryAccess = context .datapackDimensions ();
160118 Registry <LevelStem > contextLevelStemRegistry = registryAccess .lookupOrThrow (Registries .LEVEL_STEM );
119+ /// Worlds start - fail if dimension could not be read
120+ var levelData = PaperWorldLoader .getLevelData (levelStorageAccess );
121+ if (levelData .fatalError ()) return CompletableFuture .failedFuture (new IOException ("Failed to read level data" ));
122+ /// Worlds end
123+ Dynamic <?> dataTag = levelData .dataTag ();
124+
161125 if (dataTag != null ) {
162126 LevelDataAndDimensions levelDataAndDimensions = LevelStorageSource .getLevelDataAndDimensions (
163127 dataTag , context .dataConfiguration (), contextLevelStemRegistry , context .datapackWorldgen ()
@@ -169,6 +133,7 @@ private CompletableFuture<World> createInternal() {
169133 WorldOptions worldOptions = new WorldOptions (seed , structures , bonusChest );
170134 WorldDimensions worldDimensions ;
171135
136+ var generatorSettings = Optional .ofNullable (preset ).orElse (Presets .CLASSIC_FLAT ).serialize (); /// Worlds - serialize preset
172137 DedicatedServerProperties .WorldDimensionData properties = new DedicatedServerProperties .WorldDimensionData (generatorSettings , generatorType .presetName ().asString ());
173138 levelSettings = new LevelSettings (
174139 name ,
@@ -217,58 +182,64 @@ private CompletableFuture<World> createInternal() {
217182 dimensionKey = ResourceKey .create (Registries .DIMENSION , ResourceLocation .fromNamespaceAndPath (key .namespace (), key .value ()));
218183 }
219184
220- primaryLevelData .getGameRules ().getRule (GameRules .RULE_SPAWN_CHUNK_RADIUS ).set (spawnChunkRadius , null );
221-
222185 ServerLevel serverLevel = new ServerLevel (
223186 console ,
224187 console .executor ,
225188 levelStorageAccess ,
226189 primaryLevelData ,
227190 dimensionKey ,
228191 customStem ,
229- MinecraftServer .getServer ().progressListenerFactory .create (primaryLevelData .getGameRules ().getInt (GameRules .RULE_SPAWN_CHUNK_RADIUS )),
230192 primaryLevelData .isDebugWorld (),
231193 seed ,
232- levelStem == net .thenextlvl .worlds .api .generator .LevelStem .OVERWORLD ? list : ImmutableList .of (),
194+ levelStem == net .thenextlvl .worlds .api .generator .LevelStem .OVERWORLD ? list : ImmutableList .of (), /// Worlds
233195 true ,
234196 console .overworld ().getRandomSequences (),
235197 toBukkit (levelStem .dimensionType ()),
236198 chunkGenerator , biomeProvider
237199 );
238200
201+ /// Worlds start - ensure world is memoized before adding to server
239202 if (server .getWorld (name ) == null ) return CompletableFuture .failedFuture (
240203 new IllegalStateException ("World with name " + name + " was not properly memoized" )
241204 );
205+ /// Worlds end
242206
243207 console .addLevel (serverLevel );
244208
209+ /// Worlds start - initialize world for folia
245210 var future = new CompletableFuture <World >();
246211 if (WorldsPlugin .RUNNING_FOLIA ) {
247- serverLevel .randomSpawnSelection = new ChunkPos (serverLevel .getChunkSource ().randomState ().sampler ().findSpawnPosition ());
212+ // fixme: restore folia support once possible
213+ // serverLevel.randomSpawnSelection = new ChunkPos(serverLevel.getChunkSource().randomState().sampler().findSpawnPosition());
248214
249- var x = serverLevel .randomSpawnSelection .x ;
250- var z = serverLevel .randomSpawnSelection .z ;
215+ // var x = serverLevel.randomSpawnSelection.x;
216+ // var z = serverLevel.randomSpawnSelection.z;
251217
252- plugin .getServer ().getRegionScheduler ().run (plugin , serverLevel .getWorld (), x , z , scheduledTask -> {
253- console .initWorld (serverLevel , primaryLevelData , primaryLevelData , primaryLevelData .worldGenOptions ());
254- future .complete (serverLevel .getWorld ());
255- });
256- } else {
257- console .initWorld (serverLevel , primaryLevelData , primaryLevelData , primaryLevelData .worldGenOptions ());
258- future .complete (serverLevel .getWorld ());
259- }
218+ // plugin.getServer().getRegionScheduler().run(plugin, serverLevel.getWorld(), x, z, scheduledTask -> {
219+ // console.initWorld(serverLevel, primaryLevelData, primaryLevelData.worldGenOptions());
220+ // future.complete(serverLevel.getWorld());
221+ // });
222+ /// Worlds end
223+ } else console .initWorld (serverLevel , primaryLevelData , primaryLevelData .worldGenOptions ());
260224
261225 serverLevel .setSpawnSettings (true );
262226
263- console .prepareLevels (serverLevel .getChunkSource ().chunkMap .progressListener , serverLevel );
264- if (WorldsPlugin .RUNNING_FOLIA )
265- io .papermc .paper .threadedregions .RegionizedServer .getInstance ().addWorld (serverLevel );
266- FeatureHooks .tickEntityManager (serverLevel );
267-
227+ /// Worlds start - persist world extra data
268228 persistWorld (serverLevel .getWorld (), levelStem , enabled .toBooleanOrElse (true ));
269229 if (generator != null ) persistGenerator (serverLevel .getWorld (), generator );
230+ /// Worlds end
231+
232+ /// Worlds start - start entity and region ticking for folia
233+ // fixme: restore folia support once possible
234+ // if (WorldsPlugin.RUNNING_FOLIA)
235+ // io.papermc.paper.threadedregions.RegionizedServer.getInstance().addWorld(serverLevel);
236+ FeatureHooks .tickEntityManager (serverLevel );
237+ /// Worlds end
270238
271- new WorldLoadEvent (serverLevel .getWorld ()).callEvent ();
239+ console .prepareLevel (serverLevel );
240+
241+ /// Worlds - complete future immediately if not folia
242+ if (!WorldsPlugin .RUNNING_FOLIA ) future .complete (serverLevel .getWorld ());
272243 return future ;
273244 }
274245
@@ -293,8 +264,9 @@ private ResourceKey<LevelStem> resolveDimensionKey() {
293264 }
294265
295266 private World .Environment toBukkit (DimensionType type ) {
296- if (type .equals (DimensionType .THE_END )) return World .Environment .THE_END ;
267+ if (type .equals (DimensionType .OVERWORLD )) return World .Environment .NORMAL ;
297268 if (type .equals (DimensionType .THE_NETHER )) return World .Environment .NETHER ;
298- return World .Environment .NORMAL ;
269+ if (type .equals (DimensionType .THE_END )) return World .Environment .THE_END ;
270+ return World .Environment .CUSTOM ;
299271 }
300272}
0 commit comments