From 93e18230f084a26da6f630629527149e5911fa75 Mon Sep 17 00:00:00 2001 From: tom lee Date: Tue, 18 Jan 2022 22:44:32 +0800 Subject: [PATCH] GENERATE LOD FROM FILE IS HERE!!!!!!! Noted issue: 1. Non problematic WARN of `Tried to access a block entity before it was created` 2. The loading is.... a bit slow due to single thread action. Will be improved soon. 3. Possible Chunk Status not correct issue. It... sometimes happen, but it's mostly fine~ Special thanks to the YouTube commentors on the a1.6 Teaser Trailer video. If not for them, I would not notice how many people want this, and actually look into slapping in this feature in a1.6. --- .../worldGeneration/WorldGenerationStep.java | 130 ++++++++++++++---- common/src/main/resources/lod.accesswidener | 3 + core | 2 +- 3 files changed, 110 insertions(+), 25 deletions(-) diff --git a/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/WorldGenerationStep.java b/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/WorldGenerationStep.java index 81a6fa270..6e5bb2854 100644 --- a/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/WorldGenerationStep.java +++ b/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/WorldGenerationStep.java @@ -27,6 +27,8 @@ import com.seibel.lod.core.enums.config.DistanceGenerationMode; import com.seibel.lod.core.objects.lod.LodDimension; import com.seibel.lod.core.wrapperInterfaces.modAccessor.IStarlightAccessor; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; + import java.time.Duration; import java.util.ArrayList; import java.util.Iterator; @@ -39,6 +41,8 @@ import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; +import org.jetbrains.annotations.Nullable; + import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.mojang.datafixers.DataFixer; import com.seibel.lod.common.wrappers.chunk.ChunkWrapper; @@ -92,7 +96,7 @@ Lod Generation: 0.269023348s */ public final class WorldGenerationStep { - public static final boolean ENABLE_PERF_LOGGING = false; + public static final boolean ENABLE_PERF_LOGGING = true; //TODO: Make this LightMode a config public static final LightMode DEFAULT_LIGHTMODE = LightMode.Fancy; @@ -167,7 +171,7 @@ public final class WorldGenerationStep { } public String toString() { - return "Total: " + Duration.ofNanos((long) totalTime.getAverage()) + ", Empty: " + return "Total: " + Duration.ofNanos((long) totalTime.getAverage()) + ", Empty/LoadChunk: " + Duration.ofNanos((long) emptyTime.getAverage()) + ", StructStart: " + Duration.ofNanos((long) structStartTime.getAverage()) + ", StructRef: " + Duration.ofNanos((long) structRefTime.getAverage()) + ", Biome: " @@ -380,7 +384,7 @@ public final class WorldGenerationStep { int distX = Math.abs(cx - pos.x); int distZ = Math.abs(cz - pos.z); int minRange = cr+range+1; //Need one to account for the center - minRange += 3 + 3; // Account for required empty chunks + minRange += 1+1; // Account for required empty chunks return distX < minRange && distZ < minRange; } @@ -458,6 +462,12 @@ public final class WorldGenerationStep { ClientApi.LOGGER.info("================WORLD_GEN_STEP_INITING============="); params = new GlobalParameters(level, lodBuilder, lodDim); } + + public void startLoadingAllRegionsFromFile(LodDimension lodDim) { + ServerLevel level = params.level; + level.getChunkSource(); + + } public void generateLodFromList(GenerationEvent e) { e.pEvent.beginNano = System.nanoTime(); @@ -467,22 +477,35 @@ public final class WorldGenerationStep { try { int cx = e.pos.x; int cy = e.pos.z; - int rangeEmpty = e.range + 3; - if (rangeEmpty < 7) - rangeEmpty = 7; // For some reason the Blender needs at least range 7??? + int rangeEmpty = e.range + 1; GridList chunks = new GridList(rangeEmpty); + + @SuppressWarnings("resource") + EmptyChunkGenerator generator = (int x, int z) -> { + ChunkPos chunkPos = new ChunkPos(x, z); + ChunkAccess target = null; + try { + target = params.level.getChunkSource().chunkMap.scheduleChunkLoad(chunkPos).join().left().orElseGet(null); + } catch (RuntimeException e2) { + // Continue... + e2.printStackTrace(); + } + if (target == null) + target = new ProtoChunk(chunkPos, UpgradeData.EMPTY, params.level, + params.biomes, null); + return target; + }; for (int oy = -rangeEmpty; oy <= rangeEmpty; oy++) { for (int ox = -rangeEmpty; ox <= rangeEmpty; ox++) { // ChunkAccess target = getCachedChunk(new ChunkPos(cx+ox, cy+oy)); - ChunkAccess target = new ProtoChunk(new ChunkPos(cx + ox, cy + oy), UpgradeData.EMPTY, params.level, - params.biomes, null); + ChunkAccess target = generator.generate(cx + ox, cy + oy); chunks.add(target); } } e.pEvent.emptyNano = System.nanoTime(); e.refreshTimeout(); - region = new LightedWorldGenRegion(params.level, chunks, ChunkStatus.STRUCTURE_STARTS, e.range + 1, e.lightMode); + region = new LightedWorldGenRegion(params.level, chunks, ChunkStatus.STRUCTURE_STARTS, e.range + 1, e.lightMode, generator); referencedChunks = chunks.subGrid(e.range); referencedChunks = generateDirect(e, referencedChunks, e.target, region); @@ -611,12 +634,16 @@ public final class WorldGenerationStep { public void generateGroup(ThreadedParameters tParams, WorldGenRegion worldGenRegion, List chunks) { + ArrayList chunksToDo = new ArrayList(); + for (ChunkAccess chunk : chunks) { + if (chunk.getStatus().isOrAfter(STATUS)) continue; ((ProtoChunk) chunk).setStatus(STATUS); + chunksToDo.add(chunk); } if (params.worldGenSettings.generateFeatures()) { - for (ChunkAccess chunk : chunks) { + for (ChunkAccess chunk : chunksToDo) { // System.out.println("StepStructureStart: "+chunk.getPos()); params.generator.createStructures(params.registry, tParams.structFeat, chunk, params.structures, params.worldSeed); @@ -677,11 +704,15 @@ public final class WorldGenerationStep { public void generateGroup(ThreadedParameters tParams, WorldGenRegion worldGenRegion, List chunks) { - for (ChunkAccess chunk : chunks) { - ((ProtoChunk) chunk).setStatus(STATUS); - } + ArrayList chunksToDo = new ArrayList(); for (ChunkAccess chunk : chunks) { + if (chunk.getStatus().isOrAfter(STATUS)) continue; + ((ProtoChunk) chunk).setStatus(STATUS); + chunksToDo.add(chunk); + } + + for (ChunkAccess chunk : chunksToDo) { // System.out.println("StepStructureReference: "+chunk.getPos()); createReferences(worldGenRegion, tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk); } @@ -694,14 +725,19 @@ public final class WorldGenerationStep { public void generateGroup(ThreadedParameters tParams, WorldGenRegion worldGenRegion, List chunks) { - for (ChunkAccess chunk : chunks) { - ((ProtoChunk) chunk).setStatus(STATUS); - } + ArrayList chunksToDo = new ArrayList(); for (ChunkAccess chunk : chunks) { + if (chunk.getStatus().isOrAfter(STATUS)) continue; + ((ProtoChunk) chunk).setStatus(STATUS); + chunksToDo.add(chunk); + } + + for (ChunkAccess chunk : chunksToDo) { // System.out.println("StepBiomes: "+chunk.getPos()); chunk = joinAsync(params.generator.createBiomes(params.biomes, Runnable::run, - Blender.of(worldGenRegion), tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk)); + Blender.of(worldGenRegion), + tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk)); } } } @@ -712,10 +748,15 @@ public final class WorldGenerationStep { public void generateGroup(ThreadedParameters tParams, WorldGenRegion worldGenRegion, List chunks) { + ArrayList chunksToDo = new ArrayList(); + for (ChunkAccess chunk : chunks) { + if (chunk.getStatus().isOrAfter(STATUS)) continue; ((ProtoChunk) chunk).setStatus(STATUS); + chunksToDo.add(chunk); } - for (ChunkAccess chunk : chunks) { + + for (ChunkAccess chunk : chunksToDo) { // System.out.println("StepNoise: "+chunk.getPos()); chunk = joinAsync(params.generator.fillFromNoise(Runnable::run, Blender.of(worldGenRegion), tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk)); @@ -728,10 +769,15 @@ public final class WorldGenerationStep { public void generateGroup(ThreadedParameters tParams, WorldGenRegion worldGenRegion, List chunks) { + ArrayList chunksToDo = new ArrayList(); + for (ChunkAccess chunk : chunks) { + if (chunk.getStatus().isOrAfter(STATUS)) continue; ((ProtoChunk) chunk).setStatus(STATUS); + chunksToDo.add(chunk); } - for (ChunkAccess chunk : chunks) { + + for (ChunkAccess chunk : chunksToDo) { // System.out.println("StepSurface: "+chunk.getPos()); params.generator.buildSurface(worldGenRegion, tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk); @@ -744,7 +790,15 @@ public final class WorldGenerationStep { public void generateGroup(ThreadedParameters tParams, WorldGenRegion worldGenRegion, List chunks) { + ArrayList chunksToDo = new ArrayList(); + for (ChunkAccess chunk : chunks) { + if (chunk.getStatus().isOrAfter(STATUS)) continue; + ((ProtoChunk) chunk).setStatus(STATUS); + chunksToDo.add(chunk); + } + + for (ChunkAccess chunk : chunksToDo) { // DISABLED CURRENTLY! // System.out.println("StepCarvers: "+chunk.getPos()); // Blender.addAroundOldChunksCarvingMaskFilter((WorldGenLevel) worldGenRegion, @@ -763,11 +817,15 @@ public final class WorldGenerationStep { public void generateGroup(ThreadedParameters tParams, WorldGenRegion worldGenRegion, GridList chunks) { - for (ChunkAccess chunk : chunks) { - ((ProtoChunk) chunk).setStatus(STATUS); - } + ArrayList chunksToDo = new ArrayList(); for (ChunkAccess chunk : chunks) { + if (chunk.getStatus().isOrAfter(STATUS)) continue; + ((ProtoChunk) chunk).setStatus(STATUS); + chunksToDo.add(chunk); + } + + for (ChunkAccess chunk : chunksToDo) { try { params.generator.applyBiomeDecoration(worldGenRegion, chunk, tParams.structFeat.forWorldGenRegion(worldGenRegion)); @@ -792,9 +850,13 @@ public final class WorldGenerationStep { public void generateGroup(LevelLightEngine lightEngine, GridList chunks) { + //ArrayList chunksToDo = new ArrayList(); + for (ChunkAccess chunk : chunks) { + if (chunk.getStatus().isOrAfter(STATUS)) continue; ((ProtoChunk) chunk).setStatus(STATUS); } + for (ChunkAccess chunk : chunks) { try { if (lightEngine instanceof WorldGenLightEngine) { @@ -812,13 +874,20 @@ public final class WorldGenerationStep { } } + public interface EmptyChunkGenerator { + ChunkAccess generate(int x, int z); + } + public static class LightedWorldGenRegion extends WorldGenRegion { final LevelLightEngine light; final LightMode lightMode; - - public LightedWorldGenRegion(ServerLevel serverLevel, List list, ChunkStatus chunkStatus, int i, LightMode lightMode) { + final EmptyChunkGenerator generator; + Long2ObjectOpenHashMap chunkMap = new Long2ObjectOpenHashMap(); + public LightedWorldGenRegion(ServerLevel serverLevel, List list, ChunkStatus chunkStatus, int i, + LightMode lightMode, EmptyChunkGenerator generator) { super(serverLevel, list, chunkStatus, i); this.lightMode = lightMode; + this.generator = generator; light = lightMode==LightMode.StarLight ? serverLevel.getLightEngine() : new WorldGenLightEngine(new LightGetterAdaptor(this)); } @@ -848,6 +917,19 @@ public final class WorldGenerationStep { public boolean canSeeSky(BlockPos blockPos) { return (getBrightness(LightLayer.SKY, blockPos) >= getMaxLightLevel()); } + + @Override + @Nullable + public ChunkAccess getChunk(int i, int j, ChunkStatus chunkStatus, boolean bl) { + if (!bl || this.hasChunk(i, j)) return super.getChunk(i, j, chunkStatus, bl); + ChunkAccess chunk = chunkMap.get(ChunkPos.asLong(i, j)); + if (chunk!=null) return chunk; + chunk = generator.generate(i, j); + if (chunk==null) throw new NullPointerException(); + chunkMap.put(ChunkPos.asLong(i, j), chunk); + return chunk; + } + } diff --git a/common/src/main/resources/lod.accesswidener b/common/src/main/resources/lod.accesswidener index a8fc4a282..aee5bbf63 100644 --- a/common/src/main/resources/lod.accesswidener +++ b/common/src/main/resources/lod.accesswidener @@ -23,6 +23,9 @@ accessible field net/minecraft/world/level/lighting/LevelLightEngine skyEngine L accessible method net/minecraft/world/level/levelgen/Heightmap setHeight (III)V accessible field net/minecraft/world/level/biome/Biome generationSettings Lnet/minecraft/world/level/biome/BiomeGenerationSettings; +# lod generation from save file +accessible method net/minecraft/server/level/ChunkMap scheduleChunkLoad (Lnet/minecraft/world/level/ChunkPos;)Ljava/util/concurrent/CompletableFuture; + # grabbing textures accessible field net/minecraft/client/renderer/texture/TextureAtlasSprite animatedTexture Lnet/minecraft/client/renderer/texture/TextureAtlasSprite$AnimatedTexture; accessible field net/minecraft/client/renderer/texture/TextureAtlasSprite width I diff --git a/core b/core index 546d60f1f..6c77164a6 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 546d60f1fc17cb175df10aee3742fa4a2d06a550 +Subproject commit 6c77164a65e41d3112a177a3c8bfcae5d6ce75af