diff --git a/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/ExperimentalGenerator.java b/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/ExperimentalGenerator.java index 2cd4d5a6a..b56b42e0a 100644 --- a/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/ExperimentalGenerator.java +++ b/common/src/main/java/com/seibel/lod/common/wrappers/worldGeneration/ExperimentalGenerator.java @@ -1,7 +1,29 @@ +/* + * This file is part of the Distant Horizon mod (formerly the LOD Mod), + * licensed under the GNU GPL v3 License. + * + * Copyright (C) 2021 Tom Lee (TomTheFurry) & James Seibel (Original code) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package com.seibel.lod.common.wrappers.worldGeneration; +import java.util.concurrent.TimeUnit; + import com.seibel.lod.common.wrappers.world.WorldWrapper; import com.seibel.lod.common.wrappers.worldGeneration.WorldGenerationStep.Steps; +import com.seibel.lod.core.api.ClientApi; import com.seibel.lod.core.builders.lodBuilding.LodBuilder; import com.seibel.lod.core.enums.config.DistanceGenerationMode; import com.seibel.lod.core.objects.PosToGenerateContainer; @@ -27,9 +49,12 @@ public class ExperimentalGenerator extends AbstractExperimentalWorldGeneratorWra public ExperimentalGenerator(LodBuilder newLodBuilder, LodDimension newLodDimension, IWorldWrapper worldWrapper) { super(newLodBuilder, newLodDimension, worldWrapper); - System.out.println("================ExperimentalGenerator INIT============="); + MC.sendChatMessage("WARNING: You are currently using Distant Horizon's Experimental Chunk Pre-Generator!"); + MC.sendChatMessage("The generation mode: Feature mode is not recommended for < 8GB RAM"); + MC.sendChatMessage("Stuff may broke at any time!"); generationGroup = new WorldGenerationStep(((WorldWrapper) worldWrapper).getServerWorld(), newLodBuilder, newLodDimension); + ClientApi.LOGGER.info("1.18 Experimental Chunk Generator initialized"); } @Override @@ -64,7 +89,29 @@ public class ExperimentalGenerator extends AbstractExperimentalWorldGeneratorWra int nearCount = posToGenerate.getNumberOfNearPos(); int farCount = posToGenerate.getNumberOfFarPos(); int maxIteration = Math.max(nearCount, farCount); - + Steps targetStep; + switch (mode) { + case NONE: + return; + case BIOME_ONLY: + targetStep = Steps.Biomes; //NOTE: No block. Require fake height in LodBuilder + break; + case BIOME_ONLY_SIMULATE_HEIGHT: + targetStep = Steps.Noise; //NOTE: Stone only. Require fake surface + break; + case SURFACE: + targetStep = Steps.Surface; //Carvers or Surface??? + break; + case FEATURES: + targetStep = Steps.Features; + break; + case FULL: + targetStep = Steps.Features; // TODO! + break; + default: + assert false; + return; + } for (int i = 0; i < maxIteration; i++) { // We have nearPos to go though @@ -75,7 +122,7 @@ public class ExperimentalGenerator extends AbstractExperimentalWorldGeneratorWra byte detailLevel = (byte) (posToGenerate.getNthDetail(i, true) - 1); int chunkX = LevelPosUtil.getChunkPos(detailLevel, posToGenerate.getNthPosX(i, true)); int chunkZ = LevelPosUtil.getChunkPos(detailLevel, posToGenerate.getNthPosZ(i, true)); - if (generationGroup.tryAddPoint(chunkX, chunkZ, generationGroupSize, Steps.Features)) { + if (generationGroup.tryAddPoint(chunkX, chunkZ, generationGroupSize, targetStep)) { toGenerate--; } } @@ -90,7 +137,7 @@ public class ExperimentalGenerator extends AbstractExperimentalWorldGeneratorWra byte detailLevel = (byte) (posToGenerate.getNthDetail(i, false) - 1); int chunkX = LevelPosUtil.getChunkPos(detailLevel, posToGenerate.getNthPosX(i, false)); int chunkZ = LevelPosUtil.getChunkPos(detailLevel, posToGenerate.getNthPosZ(i, false)); - if (generationGroup.tryAddPoint(chunkX, chunkZ, generationGroupSize, Steps.Surface)) { + if (generationGroup.tryAddPoint(chunkX, chunkZ, generationGroupSize, targetStep)) { toGenerate--; } } @@ -98,6 +145,7 @@ public class ExperimentalGenerator extends AbstractExperimentalWorldGeneratorWra break; } + /* //Enable this for logging if (targetToGenerate != toGenerate) { if (toGenerate <= 0) { System.out.println( @@ -108,7 +156,7 @@ public class ExperimentalGenerator extends AbstractExperimentalWorldGeneratorWra + estimatedSampleNeeded + " points, started " + (targetToGenerate - toGenerate) + " out of targeted " + targetToGenerate + " generations."); } - } + }*/ if (toGenerate > 0 && estimatedSampleNeeded <= posToGenerate.getNumberOfPos()) { // We failed to generate enough points from the samples. @@ -117,7 +165,7 @@ public class ExperimentalGenerator extends AbstractExperimentalWorldGeneratorWra // Ensure wee don't go to basically infinity if (estimatedSampleNeeded > 32768) estimatedSampleNeeded = 32768; - System.out.println("WorldGenerator: Increasing estimatedSampleNeeeded to " + estimatedSampleNeeded); + //System.out.println("WorldGenerator: Increasing estimatedSampleNeeeded to " + estimatedSampleNeeded); } else if (toGenerate <= 0 && positionGoneThough * 1.5 < posToGenerate.getNumberOfPos()) { // We haven't gone though half of them and it's already enough. @@ -126,15 +174,20 @@ public class ExperimentalGenerator extends AbstractExperimentalWorldGeneratorWra // Ensure we don't go to near zero. if (estimatedSampleNeeded < 4) estimatedSampleNeeded = 4; - System.out.println("WorldGenerator: Decreasing estimatedSampleNeeeded to " + estimatedSampleNeeded); + //System.out.println("WorldGenerator: Decreasing estimatedSampleNeeeded to " + estimatedSampleNeeded); } } @Override public void stop() { - System.out.println("================ExperimentalGenerator SHUTDOWN============="); + ClientApi.LOGGER.info("1.18 Experimental Chunk Generator shutting down..."); generationGroup.executors.shutdownNow(); + try { + if (!generationGroup.executors.awaitTermination(3, TimeUnit.SECONDS)) { + ClientApi.LOGGER.info("1.18 Experimental Chunk Generator shutdown failed! Ignoring child threads..."); + } + } catch (InterruptedException e) {} } } 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 dcdf465f5..f15ce7851 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 @@ -1,3 +1,22 @@ +/* + * This file is part of the Distant Horizon mod (formerly the LOD Mod), + * licensed under the GNU GPL v3 License. + * + * Copyright (C) 2021 Tom Lee (TomTheFurry) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package com.seibel.lod.common.wrappers.worldGeneration; import com.seibel.lod.core.builders.lodBuilding.LodBuilder; @@ -11,7 +30,6 @@ import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; @@ -48,7 +66,7 @@ import net.minecraft.world.level.levelgen.structure.StructureCheck; import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager; import net.minecraft.world.level.storage.WorldData; -public class WorldGenerationStep { +public final class WorldGenerationStep { enum Steps { Empty, StructureStart, StructureReference, Biomes, Noise, Surface, Carvers, LiquidCarvers, Features, Light, @@ -120,7 +138,7 @@ public class WorldGenerationStep { } } - public static class GlobalParameters { + public static final class GlobalParameters { final ChunkGenerator generator; final StructureManager structures; final BiomeManager biomeManager; @@ -158,7 +176,7 @@ public class WorldGenerationStep { } } - public static class ThreadedParameters { + public static final class ThreadedParameters { final StructureFeatureManager structFeat; final StructureCheck structCheck; public ThreadedParameters(GlobalParameters param) { @@ -168,7 +186,7 @@ public class WorldGenerationStep { } } - public static class GenerationEvent { + public static final class GenerationEvent { private static int generationFutureDebugIDs = 0; final ThreadedParameters tParam; final ChunkPos pos; @@ -189,29 +207,29 @@ public class WorldGenerationStep { generationGroup.generateLodFromList(this); }); } - public boolean isCompleted() { + public final boolean isCompleted() { return future.isDone(); } - public boolean hasTimeout(int duration, TimeUnit unit) { + public final boolean hasTimeout(int duration, TimeUnit unit) { long currentTime = System.nanoTime(); long delta = currentTime - nanotime; return (delta > TimeUnit.NANOSECONDS.convert(duration, unit)); } - public void terminate() { + public final void terminate() { future.cancel(true); } - public void join() { + public final void join() { try { future.get(); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } - public boolean tooClose(int cx, int cz, int cr) { + public final boolean tooClose(int cx, int cz, int cr) { int dist = Math.min(Math.abs(cx - pos.x), Math.abs(cz - pos.z)); return dist T joinAsync(CompletableFuture f) { + private final static T joinAsync(CompletableFuture f) { //while (!f.isDone()) Thread.yield(); return f.join(); } @@ -241,9 +259,9 @@ public class WorldGenerationStep { public final ExecutorService executors = Executors.newCachedThreadPool(new ThreadFactoryBuilder().setNameFormat("Gen-Worker-Thread-%d").build()); //public ExecutorService executors = Executors.newFixedThreadPool(8, new ThreadFactoryBuilder().setNameFormat("Gen-Worker-Thread-%d").build()); - public boolean tryAddPoint(int x, int z, int range, Steps target) { - x = (int)(x / range) * range; - z = (int)(z / range) * range; + public final boolean tryAddPoint(int x, int z, int range, Steps target) { + x = Math.floorDiv(x, range) * range; + z = Math.floorDiv(z, range) * range; for (GenerationEvent event : events) { if (event.tooClose(x, z, range)) return false; @@ -252,18 +270,26 @@ public class WorldGenerationStep { return true; } - public void updateAllFutures() { + public final void updateAllFutures() { // Update all current out standing jobs Iterator iter = events.iterator(); while (iter.hasNext()) { GenerationEvent event = iter.next(); if (event.isCompleted()) { - event.join(); - iter.remove(); - } else if (event.hasTimeout(10, TimeUnit.SECONDS)) { + try { + event.join(); + } catch (RuntimeException e) { + // Ignore. + } finally { + iter.remove(); + } + } else if (event.hasTimeout(5, TimeUnit.SECONDS)) { System.err.println(event.id+": Timed out and terminated!"); - event.terminate(); - iter.remove(); + try { + event.terminate(); + } finally { + iter.remove(); + } } } } @@ -273,10 +299,10 @@ public class WorldGenerationStep { params = new GlobalParameters(level, lodBuilder, lodDim); } - ConcurrentHashMap chunks = new ConcurrentHashMap(); + //ConcurrentHashMap chunks = new ConcurrentHashMap(); // No longer using Long2ObjectLinkedOpenHashMap as I doubt it is multithread // safe. - +/* private final ChunkAccess getCachedChunk(ChunkPos pos) { ChunkAccess chunk = chunks.get(pos.toLong()); if (chunk != null) @@ -286,11 +312,11 @@ public class WorldGenerationStep { if (oldVal != null) return oldVal; return chunk; - } + }*/ - public void generateLodFromList(GenerationEvent event) { + public final void generateLodFromList(GenerationEvent event) { try { - System.out.println("Started event: "+event); + //System.out.println("Started event: "+event); GridList referencedChunks; DistanceGenerationMode generationMode; switch (event.target) { @@ -341,25 +367,25 @@ public class WorldGenerationStep { } } event.refreshTimeout(); - for (ChunkAccess sync : referencedChunks) { - chunks.remove(sync.getPos().toLong()); - } - System.out.println("Ended event: "+event); + //for (ChunkAccess sync : referencedChunks) { + // chunks.remove(sync.getPos().toLong()); + //} + //System.out.println("Ended event: "+event); } catch (RuntimeException e) { e.printStackTrace(); throw e; } } - public GridList generateEmpty(GenerationEvent e, int range) { + public final GridList generateEmpty(GenerationEvent e, int range) { int cx = e.pos.x; int cy = e.pos.z; GridList chunks = new GridList(range); for (int oy = -range; oy <= range; oy++) { for (int ox = -range; ox <= range; ox++) { - ChunkAccess target = getCachedChunk(new ChunkPos(cx+ox, cy+oy)); - //ChunkAccess target = new ChunkAccess(new ChunkPos(cx+ox, cy+oy), level, biomes); + //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); chunks.add(target); } } @@ -367,7 +393,7 @@ public class WorldGenerationStep { return chunks; } - public GridList generateStructureStart(GenerationEvent e, int range) { + public final GridList generateStructureStart(GenerationEvent e, int range) { int prestepRange = range+8; GridList chunks = generateEmpty(e, prestepRange); WorldGenRegion region = new WorldGenRegion(params.level, chunks, ChunkStatus.STRUCTURE_STARTS, range); @@ -379,7 +405,7 @@ public class WorldGenerationStep { return chunks; } - public GridList generateStructureReference(GenerationEvent e, int range) { + public final GridList generateStructureReference(GenerationEvent e, int range) { int prestepRange = range; GridList chunks = generateStructureStart(e, prestepRange); WorldGenRegion region = new WorldGenRegion(params.level, chunks, ChunkStatus.STRUCTURE_REFERENCES, range); @@ -391,7 +417,7 @@ public class WorldGenerationStep { return chunks; } - public GridList generateBiomes(GenerationEvent e, int range) { + public final GridList generateBiomes(GenerationEvent e, int range) { int prestepRange = range; GridList chunks = generateStructureReference(e, prestepRange); WorldGenRegion region = new WorldGenRegion(params.level, chunks, ChunkStatus.BIOMES, range); @@ -403,7 +429,7 @@ public class WorldGenerationStep { return chunks; } - public GridList generateNoise(GenerationEvent e, int range) { + public final GridList generateNoise(GenerationEvent e, int range) { int prestepRange = range; GridList chunks = generateBiomes(e, prestepRange); WorldGenRegion region = new WorldGenRegion(params.level, chunks, ChunkStatus.NOISE, range); @@ -415,7 +441,7 @@ public class WorldGenerationStep { return chunks; } - public GridList generateSurface(GenerationEvent e, int range) { + public final GridList generateSurface(GenerationEvent e, int range) { int prestepRange = range; GridList chunks = generateNoise(e, prestepRange); WorldGenRegion region = new WorldGenRegion(params.level, chunks, ChunkStatus.SURFACE, range); @@ -428,7 +454,7 @@ public class WorldGenerationStep { } - public GridList generateCarvers(GenerationEvent e, int range) { + public final GridList generateCarvers(GenerationEvent e, int range) { int prestepRange = range; GridList chunks = generateSurface(e, prestepRange); WorldGenRegion region = new WorldGenRegion(params.level, chunks, ChunkStatus.CARVERS, range); @@ -441,7 +467,7 @@ public class WorldGenerationStep { } - public GridList generateFeatures(GenerationEvent e, int range) { + public final GridList generateFeatures(GenerationEvent e, int range) { int prestepRange = range; GridList chunks = generateCarvers(e, prestepRange); WorldGenRegion region = new WorldGenRegion(params.level, chunks, ChunkStatus.FEATURES, range + 1); @@ -453,10 +479,7 @@ public class WorldGenerationStep { return chunks; } - - - - public class StepStructureStart { + public final class StepStructureStart { public final ChunkStatus STATUS = ChunkStatus.STRUCTURE_STARTS; public final int RANGE = STATUS.getRange(); public final EnumSet HEIGHTMAP_TYPES = STATUS.heightmapsAfter(); @@ -481,7 +504,7 @@ public class WorldGenerationStep { }*/ } - public class StepStructureReference { + public final class StepStructureReference { public final ChunkStatus STATUS = ChunkStatus.STRUCTURE_REFERENCES; public final int RANGE = STATUS.getRange(); public final EnumSet HEIGHTMAP_TYPES = STATUS.heightmapsAfter(); @@ -501,7 +524,7 @@ public class WorldGenerationStep { }*/ } - public class StepBiomes { + public final class StepBiomes { public final ChunkStatus STATUS = ChunkStatus.BIOMES; public final int RANGE = STATUS.getRange(); public final EnumSet HEIGHTMAP_TYPES = STATUS.heightmapsAfter(); @@ -521,7 +544,7 @@ public class WorldGenerationStep { }*/ } - public class StepNoise { + public final class StepNoise { public final ChunkStatus STATUS = ChunkStatus.NOISE; public final int RANGE = STATUS.getRange(); public final EnumSet HEIGHTMAP_TYPES = STATUS.heightmapsAfter(); @@ -541,7 +564,7 @@ public class WorldGenerationStep { }*/ } - public class StepSurface { + public final class StepSurface { public final ChunkStatus STATUS = ChunkStatus.SURFACE; public final int RANGE = STATUS.getRange(); public final EnumSet HEIGHTMAP_TYPES = STATUS.heightmapsAfter(); @@ -561,7 +584,7 @@ public class WorldGenerationStep { }*/ } - public class StepCarvers { + public final class StepCarvers { public final ChunkStatus STATUS = ChunkStatus.CARVERS; public final int RANGE = STATUS.getRange(); public final EnumSet HEIGHTMAP_TYPES = STATUS.heightmapsAfter(); @@ -582,7 +605,7 @@ public class WorldGenerationStep { }*/ } - public class StepLiquidCarvers { + public final class StepLiquidCarvers { public final ChunkStatus STATUS = ChunkStatus.LIQUID_CARVERS; public final int RANGE = STATUS.getRange(); public final EnumSet HEIGHTMAP_TYPES = STATUS.heightmapsAfter(); @@ -602,28 +625,28 @@ public class WorldGenerationStep { }*/ } - public class StepFeatures { + public final class StepFeatures { public final ChunkStatus STATUS = ChunkStatus.FEATURES; public final int RANGE = STATUS.getRange(); public final EnumSet HEIGHTMAP_TYPES = STATUS.heightmapsAfter(); public final void generateGroup(ThreadedParameters tParams, WorldGenRegion worldGenRegion, GridList chunks) { for (int i=0; i