Improve pre-existing chunk handling
This commit is contained in:
+56
-51
@@ -18,10 +18,10 @@
|
||||
*/
|
||||
package com.seibel.distanthorizons.common.wrappers.chunk;
|
||||
|
||||
import com.google.gson.internal.NonNullElementWrapperList;
|
||||
import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.misc.MutableBlockPosWrapper;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos;
|
||||
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
||||
@@ -98,9 +98,9 @@ public class ChunkWrapper implements IChunkWrapper
|
||||
private int maxNonEmptyHeight = Integer.MAX_VALUE;
|
||||
|
||||
/** will be null if we are using MC heightmaps */
|
||||
private final int[][] solidHeightMap;
|
||||
private int[][] solidHeightMap = null;
|
||||
/** will be null if we are using MC heightmaps */
|
||||
private final int[][] lightBlockingHeightMap;
|
||||
private int[][] lightBlockingHeightMap = null;
|
||||
|
||||
|
||||
|
||||
@@ -109,23 +109,18 @@ public class ChunkWrapper implements IChunkWrapper
|
||||
//=============//
|
||||
|
||||
public ChunkWrapper(ChunkAccess chunk, ILevelWrapper wrappedLevel)
|
||||
{
|
||||
this(chunk, wrappedLevel, true);
|
||||
}
|
||||
public ChunkWrapper(ChunkAccess chunk, ILevelWrapper wrappedLevel, boolean recreateHeightmaps)
|
||||
{
|
||||
this.chunk = chunk;
|
||||
this.wrappedLevel = wrappedLevel;
|
||||
this.chunkPos = new DhChunkPos(chunk.getPos().x, chunk.getPos().z);
|
||||
|
||||
// use DH heightmaps if requested
|
||||
if (Config.Common.LodBuilding.recalculateChunkHeightmaps.get())
|
||||
if (recreateHeightmaps)
|
||||
{
|
||||
this.solidHeightMap = new int[LodUtil.CHUNK_WIDTH][LodUtil.CHUNK_WIDTH];
|
||||
this.lightBlockingHeightMap = new int[LodUtil.CHUNK_WIDTH][LodUtil.CHUNK_WIDTH];
|
||||
|
||||
this.recalculateDhHeightMapsIfNeeded();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.solidHeightMap = null;
|
||||
this.lightBlockingHeightMap = null;
|
||||
this.createDhHeightMaps();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,56 +243,66 @@ public class ChunkWrapper implements IChunkWrapper
|
||||
}
|
||||
private int getChunkSectionMinHeight(int index) { return (index * 16) + this.getInclusiveMinBuildHeight(); }
|
||||
|
||||
/** Will only run if the config says the MC heightmaps shouldn't be trusted. */
|
||||
public void recalculateDhHeightMapsIfNeeded()
|
||||
public void createDhHeightMaps()
|
||||
{
|
||||
// only continue if we haven't already generated the DH heightmaps
|
||||
if (this.solidHeightMap != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// re-calculate the min/max heights for consistency (during world gen these may be wrong)
|
||||
this.minNonEmptyHeight = Integer.MIN_VALUE;
|
||||
this.maxNonEmptyHeight = Integer.MAX_VALUE;
|
||||
|
||||
|
||||
// recalculate heightmaps if needed
|
||||
if (this.solidHeightMap != null)
|
||||
this.solidHeightMap = new int[LodUtil.CHUNK_WIDTH][LodUtil.CHUNK_WIDTH];
|
||||
this.lightBlockingHeightMap = new int[LodUtil.CHUNK_WIDTH][LodUtil.CHUNK_WIDTH];
|
||||
|
||||
for (int x = 0; x < LodUtil.CHUNK_WIDTH; x++)
|
||||
{
|
||||
for (int x = 0; x < LodUtil.CHUNK_WIDTH; x++)
|
||||
for (int z = 0; z < LodUtil.CHUNK_WIDTH; z++)
|
||||
{
|
||||
for (int z = 0; z < LodUtil.CHUNK_WIDTH; z++)
|
||||
int minInclusiveBuildHeight = this.getMinNonEmptyHeight();
|
||||
// if no blocks are found the height map will be at the bottom of the world
|
||||
int solidHeight = minInclusiveBuildHeight;
|
||||
int lightBlockingHeight = minInclusiveBuildHeight;
|
||||
|
||||
|
||||
int y = this.getMaxNonEmptyHeight(); //this.getExclusiveMaxBuildHeight();
|
||||
IBlockStateWrapper block = this.getBlockState(x, y, z);
|
||||
while (// go down until we reach the minimum build height
|
||||
y > minInclusiveBuildHeight
|
||||
// keep going until we find both height map values
|
||||
&&
|
||||
(
|
||||
solidHeight == minInclusiveBuildHeight
|
||||
|| lightBlockingHeight == minInclusiveBuildHeight
|
||||
)
|
||||
)
|
||||
{
|
||||
int minInclusiveBuildHeight = this.getMinNonEmptyHeight();
|
||||
// if no blocks are found the height map will be at the bottom of the world
|
||||
int solidHeight = minInclusiveBuildHeight;
|
||||
int lightBlockingHeight = minInclusiveBuildHeight;
|
||||
|
||||
|
||||
int y = this.getMaxNonEmptyHeight(); //this.getExclusiveMaxBuildHeight();
|
||||
IBlockStateWrapper block = this.getBlockState(x, y, z);
|
||||
while (// go down until we reach the minimum build height
|
||||
y > minInclusiveBuildHeight
|
||||
// keep going until we find both height map values
|
||||
&& (solidHeight == minInclusiveBuildHeight || lightBlockingHeight == minInclusiveBuildHeight))
|
||||
// is this block solid?
|
||||
if (solidHeight == minInclusiveBuildHeight
|
||||
&& block.isSolid())
|
||||
{
|
||||
// is this block solid?
|
||||
if (solidHeight == minInclusiveBuildHeight
|
||||
&& block.isSolid())
|
||||
{
|
||||
solidHeight = y;
|
||||
}
|
||||
|
||||
// is this block light blocking?
|
||||
if (lightBlockingHeight == minInclusiveBuildHeight
|
||||
&& block.getOpacity() != LodUtil.BLOCK_FULLY_TRANSPARENT)
|
||||
{
|
||||
lightBlockingHeight = y;
|
||||
}
|
||||
|
||||
// get the next block down
|
||||
y--;
|
||||
block = this.getBlockState(x, y, z);
|
||||
solidHeight = y;
|
||||
}
|
||||
|
||||
this.solidHeightMap[x][z] = solidHeight;
|
||||
this.lightBlockingHeightMap[x][z] = lightBlockingHeight;
|
||||
// is this block light blocking?
|
||||
if (lightBlockingHeight == minInclusiveBuildHeight
|
||||
&& block.getOpacity() != LodUtil.BLOCK_FULLY_TRANSPARENT)
|
||||
{
|
||||
lightBlockingHeight = y;
|
||||
}
|
||||
|
||||
// get the next block down
|
||||
y--;
|
||||
block = this.getBlockState(x, y, z);
|
||||
}
|
||||
|
||||
this.solidHeightMap[x][z] = solidHeight;
|
||||
this.lightBlockingHeightMap[x][z] = lightBlockingHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+54
-32
@@ -34,6 +34,7 @@ import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
||||
import com.seibel.distanthorizons.core.sql.dto.BeaconBeamDTO;
|
||||
import com.seibel.distanthorizons.core.util.ExceptionUtil;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import com.seibel.distanthorizons.core.util.gridList.ArrayGridList;
|
||||
@@ -61,7 +62,6 @@ import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.chunk.*;
|
||||
import net.minecraft.world.level.levelgen.DebugLevelSource;
|
||||
import net.minecraft.world.level.levelgen.FlatLevelSource;
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;
|
||||
|
||||
#if MC_VER <= MC_1_17_1
|
||||
@@ -309,13 +309,12 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm
|
||||
int refPosX = genEvent.minPos.getX() - borderSize;
|
||||
int refPosZ = genEvent.minPos.getZ() - borderSize;
|
||||
|
||||
LightGetterAdaptor lightGetterAdaptor = new LightGetterAdaptor(this.globalParams.level);
|
||||
LightGetterAdaptor lightGetterAdaptor = new LightGetterAdaptor(this.globalParams.mcServerLevel);
|
||||
DummyLightEngine dummyLightEngine = new DummyLightEngine(lightGetterAdaptor);
|
||||
|
||||
// reused data between each offset
|
||||
Map<DhChunkPos, ChunkLightStorage> chunkSkyLightingByDhPos = Collections.synchronizedMap(new HashMap<>());
|
||||
Map<DhChunkPos, ChunkLightStorage> chunkBlockLightingByDhPos = Collections.synchronizedMap(new HashMap<>());
|
||||
Map<DhChunkPos, ChunkAccess> generatedChunkByDhPos = Collections.synchronizedMap(new HashMap<>());
|
||||
Map<DhChunkPos, ChunkWrapper> chunkWrappersByDhPos = Collections.synchronizedMap(new HashMap<>());
|
||||
|
||||
|
||||
@@ -324,7 +323,7 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm
|
||||
// read existing chunks from file //
|
||||
//================================//
|
||||
|
||||
HashMap<DhChunkPos, CompletableFuture<ChunkAccess>> readFutureByDhChunkPos = new HashMap<>();
|
||||
HashMap<DhChunkPos, CompletableFuture<ChunkWrapper>> readFutureByDhChunkPos = new HashMap<>();
|
||||
|
||||
Iterator<ChunkPos> existingChunkPosIterator = ChunkPosGenStream.getIterator(
|
||||
genEvent.minPos.getX(), genEvent.minPos.getZ(),
|
||||
@@ -336,18 +335,18 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm
|
||||
ChunkPos chunkPos = existingChunkPosIterator.next();
|
||||
DhChunkPos dhChunkPos = new DhChunkPos(chunkPos.x, chunkPos.z);
|
||||
|
||||
CompletableFuture<ChunkAccess> getExistingChunkFuture
|
||||
CompletableFuture<ChunkWrapper> getExistingChunkFuture
|
||||
// running async allows file IO to run in parallel when C2ME is present
|
||||
= this.chunkFileReader.createEmptyOrPreExistingChunkAsync(
|
||||
= this.chunkFileReader.createEmptyOrPreExistingChunkWrapperAsync(
|
||||
chunkPos.x, chunkPos.z,
|
||||
chunkSkyLightingByDhPos, chunkBlockLightingByDhPos, generatedChunkByDhPos);
|
||||
chunkSkyLightingByDhPos, chunkBlockLightingByDhPos, chunkWrappersByDhPos);
|
||||
|
||||
readFutureByDhChunkPos.put(dhChunkPos, getExistingChunkFuture);
|
||||
}
|
||||
|
||||
// normally DH will handle each of these futures serially
|
||||
// but if C2ME is present these will be completed in parallel
|
||||
for (CompletableFuture<ChunkAccess> readChunkFuture : readFutureByDhChunkPos.values())
|
||||
for (CompletableFuture<ChunkWrapper> readChunkFuture : readFutureByDhChunkPos.values())
|
||||
{
|
||||
readChunkFuture.join();
|
||||
}
|
||||
@@ -371,8 +370,8 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm
|
||||
// create empty chunks outside the generation radius
|
||||
if (!readFutureByDhChunkPos.containsKey(dhChunkPos))
|
||||
{
|
||||
ChunkAccess chunk = ChunkFileReader.CreateEmptyChunk(this.globalParams.level, chunkPos);
|
||||
generatedChunkByDhPos.put(dhChunkPos, chunk);
|
||||
ChunkWrapper chunkWrapper = this.chunkFileReader.CreateProtoChunkWrapper(this.globalParams.mcServerLevel, chunkPos);
|
||||
chunkWrappersByDhPos.put(dhChunkPos, chunkWrapper);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -407,7 +406,7 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm
|
||||
// get/create the list of chunks we're going to generate
|
||||
IEmptyChunkRetrievalFunc fallbackChunkGetterFunc =
|
||||
(chunkPosX, chunkPosZ) -> Objects.requireNonNull(
|
||||
generatedChunkByDhPos.get(new DhChunkPos(chunkPosX, chunkPosZ)),
|
||||
chunkWrappersByDhPos.get(new DhChunkPos(chunkPosX, chunkPosZ)).getChunk(),
|
||||
() -> String.format("Requested chunk [%d, %d] unavailable during world generation", chunkPosX, chunkPosZ));
|
||||
|
||||
ArrayGridList<ChunkAccess> regionChunks = new ArrayGridList<>(
|
||||
@@ -424,7 +423,7 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm
|
||||
DhLitWorldGenRegion region = new DhLitWorldGenRegion(
|
||||
centerX, centerZ,
|
||||
centerChunk,
|
||||
this.globalParams.level, dummyLightEngine, regionChunks,
|
||||
this.globalParams.mcServerLevel, dummyLightEngine, regionChunks,
|
||||
ChunkStatus.STRUCTURE_STARTS, radius,
|
||||
// this method shouldn't be necessary since we're passing in a pre-populated
|
||||
// list of chunks, but just in case
|
||||
@@ -436,8 +435,8 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm
|
||||
|
||||
|
||||
//=============================//
|
||||
// create chunk wrappers //
|
||||
// and process existing chunks //
|
||||
// process existing chunks //
|
||||
//
|
||||
//=============================//
|
||||
|
||||
ArrayGridList<ChunkWrapper> chunkWrapperList = new ArrayGridList<>(regionChunks.gridSize);
|
||||
@@ -454,17 +453,32 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm
|
||||
}
|
||||
else if (chunk != null)
|
||||
{
|
||||
// wrap the chunk
|
||||
//
|
||||
ChunkWrapper chunkWrapper = new ChunkWrapper(chunk, this.dhServerLevel.getLevelWrapper());
|
||||
chunkWrapperList.set(relX, relZ, chunkWrapper);
|
||||
|
||||
// try setting the wrapper's lighting
|
||||
if (chunkBlockLightingByDhPos.containsKey(chunkWrapper.getChunkPos()))
|
||||
{
|
||||
chunkWrapper.setBlockLightStorage(chunkBlockLightingByDhPos.get(chunkWrapper.getChunkPos()));
|
||||
chunkWrapper.setSkyLightStorage(chunkSkyLightingByDhPos.get(chunkWrapper.getChunkPos()));
|
||||
chunkWrapper.setIsDhBlockLightCorrect(true);
|
||||
chunkWrapper.setIsDhSkyLightCorrect(true);
|
||||
// block
|
||||
ChunkLightStorage blockLightStorage = chunkBlockLightingByDhPos.get(chunkWrapper.getChunkPos());
|
||||
// if the light storage is empty then we should try generating the lighting
|
||||
// ourselves, the light data is probably missing
|
||||
if (blockLightStorage != null
|
||||
&& !blockLightStorage.isEmpty())
|
||||
{
|
||||
chunkWrapper.setBlockLightStorage(blockLightStorage);
|
||||
chunkWrapper.setIsDhBlockLightCorrect(true);
|
||||
}
|
||||
|
||||
// sky
|
||||
ChunkLightStorage skyLightStorage = chunkSkyLightingByDhPos.get(chunkWrapper.getChunkPos());
|
||||
if (skyLightStorage != null
|
||||
&& !skyLightStorage.isEmpty())
|
||||
{
|
||||
chunkWrapper.setSkyLightStorage(skyLightStorage);
|
||||
chunkWrapper.setIsDhSkyLightCorrect(true);
|
||||
}
|
||||
}
|
||||
|
||||
chunkWrappersByDhPos.put(chunkPos, chunkWrapper);
|
||||
@@ -553,6 +567,16 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// if we're only working with pre-existing chunks,
|
||||
// biomes need to be initialized but no other steps should be done
|
||||
if (genEvent.generatorMode == EDhApiDistantGeneratorMode.PRE_EXISTING_ONLY)
|
||||
{
|
||||
this.stepBiomes.generateGroup(genEvent.threadedParam, region, GetCutoutFrom(chunkWrappersToGenerate, EDhApiWorldGenerationStep.BIOMES));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
EDhApiWorldGenerationStep step = genEvent.targetGenerationStep;
|
||||
if (step == EDhApiWorldGenerationStep.EMPTY)
|
||||
{
|
||||
@@ -626,27 +650,25 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm
|
||||
// light each chunk in the list
|
||||
for (int i = 0; i < iChunkWrapperList.size(); i++)
|
||||
{
|
||||
ChunkWrapper centerChunk = (ChunkWrapper) iChunkWrapperList.get(i);
|
||||
if (centerChunk == null)
|
||||
ChunkWrapper centerChunkWrapper = (ChunkWrapper) iChunkWrapperList.get(i);
|
||||
if (centerChunkWrapper == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
throwIfThreadInterrupted();
|
||||
|
||||
// make sure the height maps are all properly generated
|
||||
// if this isn't done everything else afterward may fail
|
||||
//Heightmap.primeHeightmaps(centerChunk.getChunk(), ChunkStatus.FEATURES.heightmapsAfter());
|
||||
centerChunk.recalculateDhHeightMapsIfNeeded();
|
||||
|
||||
// pre-generated chunks should have lighting but new ones won't
|
||||
//if (!centerChunk.isDhBlockLightingCorrect())
|
||||
//{
|
||||
// DhLightingEngine.INSTANCE.bakeChunkBlockLighting(centerChunk, iChunkWrapperList, maxSkyLight);
|
||||
//}
|
||||
centerChunk.setIsDhBlockLightCorrect(true);
|
||||
if (!centerChunkWrapper.isDhBlockLightingCorrect())
|
||||
{
|
||||
DhLightingEngine.INSTANCE.bakeChunkBlockLighting(centerChunkWrapper, iChunkWrapperList, maxSkyLight);
|
||||
}
|
||||
|
||||
//this.dhServerLevel.updateBeaconBeamsForChunk(centerChunk, iChunkWrapperList);
|
||||
List<BeaconBeamDTO> activeBeamList = centerChunkWrapper.getAllActiveBeacons(iChunkWrapperList);
|
||||
if (!activeBeamList.isEmpty())
|
||||
{
|
||||
this.dhServerLevel.updateBeaconBeamsForChunkPos(centerChunkWrapper.getChunkPos(), activeBeamList);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+10
-10
@@ -67,8 +67,8 @@ import net.minecraft.world.level.levelgen.RandomState;
|
||||
public final class GlobalWorldGenParams
|
||||
{
|
||||
public final ChunkGenerator generator;
|
||||
public final IDhServerLevel lodLevel;
|
||||
public final ServerLevel level;
|
||||
public final IDhServerLevel dhServerLevel;
|
||||
public final ServerLevel mcServerLevel;
|
||||
public final Registry<Biome> biomes;
|
||||
public final RegistryAccess registry;
|
||||
public final long worldSeed;
|
||||
@@ -98,12 +98,12 @@ public final class GlobalWorldGenParams
|
||||
// constructor //
|
||||
//=============//
|
||||
|
||||
public GlobalWorldGenParams(IDhServerLevel lodLevel)
|
||||
public GlobalWorldGenParams(IDhServerLevel dhServerLevel)
|
||||
{
|
||||
this.lodLevel = lodLevel;
|
||||
this.dhServerLevel = dhServerLevel;
|
||||
|
||||
this.level = ((ServerLevelWrapper) lodLevel.getServerLevelWrapper()).getWrappedMcObject();
|
||||
MinecraftServer server = this.level.getServer();
|
||||
this.mcServerLevel = ((ServerLevelWrapper) dhServerLevel.getServerLevelWrapper()).getWrappedMcObject();
|
||||
MinecraftServer server = this.mcServerLevel.getServer();
|
||||
WorldData worldData = server.getWorldData();
|
||||
this.registry = server.registryAccess();
|
||||
|
||||
@@ -122,16 +122,16 @@ public final class GlobalWorldGenParams
|
||||
#endif
|
||||
|
||||
#if MC_VER >= MC_1_18_2
|
||||
this.biomeManager = new BiomeManager(this.level, BiomeManager.obfuscateSeed(this.worldSeed));
|
||||
this.chunkScanner = this.level.getChunkSource().chunkScanner();
|
||||
this.biomeManager = new BiomeManager(this.mcServerLevel, BiomeManager.obfuscateSeed(this.worldSeed));
|
||||
this.chunkScanner = this.mcServerLevel.getChunkSource().chunkScanner();
|
||||
#endif
|
||||
|
||||
this.structures = server.getStructureManager();
|
||||
this.generator = this.level.getChunkSource().getGenerator();
|
||||
this.generator = this.mcServerLevel.getChunkSource().getGenerator();
|
||||
this.dataFixer = server.getFixerUpper();
|
||||
|
||||
#if MC_VER >= MC_1_19_2
|
||||
this.randomState = this.level.getChunkSource().randomState();
|
||||
this.randomState = this.mcServerLevel.getChunkSource().randomState();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -56,7 +56,7 @@ public final class ThreadWorldGenParams
|
||||
ThreadWorldGenParams threadParam = LOCAL_PARAM_REF.get();
|
||||
if (threadParam != null
|
||||
&& threadParam.isValid
|
||||
&& threadParam.level == globalParams.level)
|
||||
&& threadParam.level == globalParams.mcServerLevel)
|
||||
{
|
||||
return threadParam;
|
||||
}
|
||||
@@ -70,7 +70,7 @@ public final class ThreadWorldGenParams
|
||||
{
|
||||
previousGlobalWorldGenParams = param;
|
||||
|
||||
this.level = param.level;
|
||||
this.level = param.mcServerLevel;
|
||||
|
||||
#if MC_VER < MC_1_18_2
|
||||
this.structFeatManager = new WorldGenStructFeatManager(param.worldGenSettings, this.level);
|
||||
@@ -78,7 +78,7 @@ public final class ThreadWorldGenParams
|
||||
this.structCheck = this.createStructureCheck(param);
|
||||
#else
|
||||
this.structCheck = new StructureCheck(param.chunkScanner, param.registry, param.structures,
|
||||
param.level.dimension(), param.generator, param.randomState, this.level, param.generator.getBiomeSource(), param.worldSeed,
|
||||
param.mcServerLevel.dimension(), param.generator, param.randomState, this.level, param.generator.getBiomeSource(), param.worldSeed,
|
||||
param.dataFixer);
|
||||
#endif
|
||||
}
|
||||
|
||||
+33
-83
@@ -20,11 +20,10 @@
|
||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration.chunkFileHandling;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.DataResult;
|
||||
import com.mojang.serialization.Dynamic;
|
||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.level.IDhServerLevel;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
@@ -36,6 +35,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
|
||||
import net.minecraft.core.Registry;
|
||||
#if MC_VER >= MC_1_19_4
|
||||
import net.minecraft.core.registries.Registries;
|
||||
@@ -64,7 +64,6 @@ import net.minecraft.world.level.block.Blocks;
|
||||
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
#if MC_VER >= MC_1_18_2
|
||||
import net.minecraft.world.level.levelgen.blending.BlendingData;
|
||||
#if MC_VER < MC_1_19_2
|
||||
import net.minecraft.world.level.levelgen.feature.StructureFeature;
|
||||
#endif
|
||||
@@ -86,7 +85,6 @@ import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||
import net.minecraft.world.level.chunk.status.ChunkType;
|
||||
#elif MC_VER >= MC_1_21_1
|
||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||
import net.minecraft.world.level.chunk.status.ChunkType;
|
||||
#endif
|
||||
|
||||
import net.minecraft.world.level.material.Fluid;
|
||||
@@ -111,7 +109,9 @@ public class ChunkCompoundTagParser
|
||||
// read chunk //
|
||||
//============//
|
||||
|
||||
public static LevelChunk createFromTag(WorldGenLevel level, ChunkPos chunkPos, CompoundTag chunkData)
|
||||
public static ChunkWrapper createFromTag(
|
||||
WorldGenLevel mcWorldGenLevel, IDhServerLevel dhServerLevel,
|
||||
ChunkPos chunkPos, CompoundTag chunkData)
|
||||
{
|
||||
#if MC_VER < MC_1_18_2
|
||||
CompoundTag tagLevel = chunkData.getCompound("Level");
|
||||
@@ -158,57 +158,27 @@ public class ChunkCompoundTagParser
|
||||
|
||||
|
||||
|
||||
//==========================//
|
||||
// ignore incomplete chunks //
|
||||
//==========================//
|
||||
|
||||
#if MC_VER < MC_1_20_6
|
||||
ChunkStatus.ChunkType chunkType;
|
||||
#else
|
||||
ChunkType chunkType;
|
||||
#endif
|
||||
chunkType = readChunkType(tagLevel);
|
||||
|
||||
#if MC_VER < MC_1_18_2
|
||||
if (chunkType != ChunkStatus.ChunkType.LEVELCHUNK)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
#elif MC_VER < MC_1_20_6
|
||||
if (chunkType == ChunkStatus.ChunkType.PROTOCHUNK)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
#else
|
||||
if (chunkType == ChunkType.PROTOCHUNK)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//===========//
|
||||
// get ticks //
|
||||
//===========//
|
||||
|
||||
#if MC_VER < MC_1_18_2
|
||||
ChunkBiomeContainer chunkBiomeContainer = new ChunkBiomeContainer(
|
||||
level.getLevel().registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), #if MC_VER >= MC_1_17_1 level, #endif
|
||||
chunkPos, level.getLevel().getChunkSource().getGenerator().getBiomeSource(),
|
||||
mcWorldGenLevel.getLevel().registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), #if MC_VER >= MC_1_17_1 mcWorldGenLevel, #endif
|
||||
chunkPos, mcWorldGenLevel.getLevel().getChunkSource().getGenerator().getBiomeSource(),
|
||||
tagLevel.contains("Biomes", 11) ? tagLevel.getIntArray("Biomes") : null);
|
||||
|
||||
String BLOCK_TICKS_TAG_PRE18 = "TileTicks";
|
||||
TickList<Block> blockTicks = tagLevel.contains(BLOCK_TICKS_TAG_PRE18, 9)
|
||||
? ChunkTickList.create(tagLevel.getList(BLOCK_TICKS_TAG_PRE18, 10), Registry.BLOCK::getKey, Registry.BLOCK::get)
|
||||
: new ProtoTickList<Block>(block -> (block == null || block.defaultBlockState().isAir()), chunkPos,
|
||||
tagLevel.getList("ToBeTicked", 9) #if MC_VER >= MC_1_17_1 , level #endif );
|
||||
tagLevel.getList("ToBeTicked", 9) #if MC_VER >= MC_1_17_1 , mcWorldGenLevel #endif );
|
||||
|
||||
String FLUID_TICKS_TAG_PRE18 = "LiquidTicks";
|
||||
TickList<Fluid> fluidTicks = tagLevel.contains(FLUID_TICKS_TAG_PRE18, 9)
|
||||
? ChunkTickList.create(tagLevel.getList(FLUID_TICKS_TAG_PRE18, 10), Registry.FLUID::getKey, Registry.FLUID::get)
|
||||
: new ProtoTickList<Fluid>(fluid -> (fluid == null || fluid == Fluids.EMPTY), chunkPos,
|
||||
tagLevel.getList("LiquidsToBeTicked", 9) #if MC_VER >= MC_1_17_1 , level #endif );
|
||||
tagLevel.getList("LiquidsToBeTicked", 9) #if MC_VER >= MC_1_17_1 , mcWorldGenLevel #endif );
|
||||
#else
|
||||
// ticks shouldn't be needed so ignore them for MC versions after 1.18.2
|
||||
LevelChunkTicks<Block> blockTicks = new LevelChunkTicks<>();
|
||||
@@ -221,7 +191,10 @@ public class ChunkCompoundTagParser
|
||||
// get misc properties //
|
||||
//=====================//
|
||||
|
||||
LevelChunkSection[] levelChunkSections = readSections(level, chunkPos, tagLevel);
|
||||
int sectionYCount = #if MC_VER < MC_1_17_1 16; #else mcWorldGenLevel.getSectionsCount(); #endif
|
||||
LevelChunkSection[] chunkSections = new LevelChunkSection[sectionYCount];
|
||||
boolean hasBlocks = readAndPopulateSections(mcWorldGenLevel, chunkPos, tagLevel, chunkSections);
|
||||
|
||||
long inhabitedTime = CompoundTagUtil.getLong(tagLevel, "InhabitedTime");
|
||||
boolean isLightOn = CompoundTagUtil.getBoolean(tagLevel, "isLightOn");
|
||||
|
||||
@@ -232,48 +205,20 @@ public class ChunkCompoundTagParser
|
||||
//============//
|
||||
|
||||
#if MC_VER < MC_1_18_2
|
||||
LevelChunk chunk = new LevelChunk((Level) level.getLevel(), chunkPos, chunkBiomeContainer, UpgradeData.EMPTY, blockTicks,
|
||||
fluidTicks, inhabitedTime, levelChunkSections, null);
|
||||
LevelChunk chunk = new LevelChunk((Level) mcWorldGenLevel.getLevel(), chunkPos, chunkBiomeContainer, UpgradeData.EMPTY, blockTicks,
|
||||
fluidTicks, inhabitedTime, chunkSections, null);
|
||||
#else
|
||||
LevelChunk chunk = new LevelChunk((Level) level, chunkPos, UpgradeData.EMPTY, blockTicks,
|
||||
fluidTicks, inhabitedTime, levelChunkSections, null, null);
|
||||
LevelChunk chunk = new LevelChunk((Level) mcWorldGenLevel, chunkPos, UpgradeData.EMPTY, blockTicks,
|
||||
fluidTicks, inhabitedTime, chunkSections, null, null);
|
||||
#endif
|
||||
|
||||
// Set some states after object creation
|
||||
chunk.setLightCorrect(isLightOn);
|
||||
readHeightmaps(chunk, chunkData);
|
||||
boolean hasHeightmapData = readHeightmaps(chunk, chunkData);
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==========================//
|
||||
// chunk type //
|
||||
// (incomplete chunk check) //
|
||||
//==========================//
|
||||
|
||||
private static
|
||||
#if MC_VER < MC_1_20_6 ChunkStatus.ChunkType
|
||||
#elif MC_VER < MC_1_21_1 ChunkType
|
||||
#else ChunkType #endif
|
||||
readChunkType(CompoundTag tagLevel)
|
||||
{
|
||||
String statusString = CompoundTagUtil.getString(tagLevel,"Status");
|
||||
if (statusString != null)
|
||||
{
|
||||
ChunkStatus chunkStatus = ChunkStatus.byName(statusString);
|
||||
if (chunkStatus != null)
|
||||
{
|
||||
return chunkStatus.getChunkType();
|
||||
}
|
||||
}
|
||||
|
||||
#if MC_VER <= MC_1_20_4
|
||||
return ChunkStatus.ChunkType.PROTOCHUNK;
|
||||
#else
|
||||
return ChunkType.PROTOCHUNK;
|
||||
#endif
|
||||
// chunk wrapper so we can pass along extra data more easily
|
||||
ChunkWrapper chunkWrapper = new ChunkWrapper(chunk, dhServerLevel.getServerLevelWrapper(), !hasHeightmapData);
|
||||
return chunkWrapper;
|
||||
}
|
||||
|
||||
|
||||
@@ -284,10 +229,11 @@ public class ChunkCompoundTagParser
|
||||
//=================//
|
||||
|
||||
/** handles both blocks and biomes */
|
||||
private static LevelChunkSection[] readSections(LevelAccessor level, ChunkPos chunkPos, CompoundTag chunkData)
|
||||
private static boolean readAndPopulateSections(
|
||||
LevelAccessor level, ChunkPos chunkPos, CompoundTag chunkData,
|
||||
LevelChunkSection[] chunkSections)
|
||||
{
|
||||
int sectionYIndex = #if MC_VER < MC_1_17_1 16; #else level.getSectionsCount(); #endif
|
||||
LevelChunkSection[] chunkSections = new LevelChunkSection[sectionYIndex];
|
||||
int sectionYCount = #if MC_VER < MC_1_17_1 16; #else level.getSectionsCount(); #endif
|
||||
|
||||
ListTag tagSections = CompoundTagUtil.getListTag(chunkData, "Sections", 10);
|
||||
// try lower-case "sections" if capital "Sections" is missing
|
||||
@@ -298,6 +244,7 @@ public class ChunkCompoundTagParser
|
||||
}
|
||||
|
||||
|
||||
boolean blocksFound = false;
|
||||
if (tagSections != null)
|
||||
{
|
||||
for (int j = 0; j < tagSections.size(); ++j)
|
||||
@@ -364,6 +311,8 @@ public class ChunkCompoundTagParser
|
||||
.promotePartial(string -> logBlockDeserializationWarning(chunkPos, sectionYPos, string))
|
||||
.getOrThrow((message) -> logErrorAndReturnException(message));
|
||||
#endif
|
||||
|
||||
blocksFound = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -416,7 +365,7 @@ public class ChunkCompoundTagParser
|
||||
biomeRegistry.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
|
||||
#else
|
||||
biomeContainer = biomeCodec.parse(NbtOps.INSTANCE, biomeTag)
|
||||
.promotePartial(string -> logBiomeDeserializationWarning(chunkPos, sectionYIndex, (String) string))
|
||||
.promotePartial(string -> logBiomeDeserializationWarning(chunkPos, sectionYCount, (String) string))
|
||||
.getOrThrow((message) -> logErrorAndReturnException(message));
|
||||
#endif
|
||||
}
|
||||
@@ -450,7 +399,7 @@ public class ChunkCompoundTagParser
|
||||
}
|
||||
}
|
||||
|
||||
return chunkSections;
|
||||
return blocksFound;
|
||||
}
|
||||
|
||||
private static Codec<PalettedContainer<BlockState>> getBlockStateCodec(LevelAccessor level)
|
||||
@@ -511,12 +460,12 @@ public class ChunkCompoundTagParser
|
||||
// heightmaps //
|
||||
//============//
|
||||
|
||||
private static void readHeightmaps(LevelChunk chunk, CompoundTag chunkData)
|
||||
private static boolean readHeightmaps(LevelChunk chunk, CompoundTag chunkData)
|
||||
{
|
||||
CompoundTag tagHeightmaps = CompoundTagUtil.getCompoundTag(chunkData, "Heightmaps");
|
||||
if (tagHeightmaps == null)
|
||||
{
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -542,6 +491,7 @@ public class ChunkCompoundTagParser
|
||||
}
|
||||
|
||||
Heightmap.primeHeightmaps(chunk, ChunkStatus.FULL.heightmapsAfter());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+35
-49
@@ -15,7 +15,6 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
||||
import net.minecraft.world.level.chunk.UpgradeData;
|
||||
import net.minecraft.world.level.chunk.storage.IOWorker;
|
||||
@@ -117,64 +116,57 @@ public class ChunkFileReader implements AutoCloseable
|
||||
* If the given chunk pos already exists in the world, that chunk will be returned,
|
||||
* otherwise this will return an empty chunk.
|
||||
*/
|
||||
public CompletableFuture<ChunkAccess> createEmptyOrPreExistingChunkAsync(
|
||||
public CompletableFuture<ChunkWrapper> createEmptyOrPreExistingChunkWrapperAsync(
|
||||
int chunkX, int chunkZ,
|
||||
Map<DhChunkPos, ChunkLightStorage> chunkSkyLightingByDhPos,
|
||||
Map<DhChunkPos, ChunkLightStorage> chunkBlockLightingByDhPos,
|
||||
Map<DhChunkPos, ChunkAccess> generatedChunkByDhPos)
|
||||
Map<DhChunkPos, ChunkWrapper> generatedChunkWrapperByDhPos)
|
||||
{
|
||||
ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ);
|
||||
DhChunkPos dhChunkPos = new DhChunkPos(chunkX, chunkZ);
|
||||
|
||||
if (generatedChunkByDhPos.containsKey(dhChunkPos))
|
||||
if (generatedChunkWrapperByDhPos.containsKey(dhChunkPos))
|
||||
{
|
||||
return CompletableFuture.completedFuture(generatedChunkByDhPos.get(dhChunkPos));
|
||||
return CompletableFuture.completedFuture(generatedChunkWrapperByDhPos.get(dhChunkPos));
|
||||
}
|
||||
|
||||
return this.getChunkNbtDataAsync(chunkPos)
|
||||
.thenApply((CompoundTag chunkData) ->
|
||||
{
|
||||
ChunkAccess newChunk = this.loadOrMakeChunk(chunkPos, chunkData);
|
||||
ChunkWrapper newChunkWrapper = this.loadOrMakeChunkWrapper(chunkPos, chunkData);
|
||||
|
||||
if (Config.Common.LodBuilding.pullLightingForPregeneratedChunks.get())
|
||||
// attempt to get chunk lighting
|
||||
ChunkCompoundTagParser.CombinedChunkLightStorage combinedLights = ChunkCompoundTagParser.readLight(newChunkWrapper.getChunk(), chunkData);
|
||||
if (combinedLights != null)
|
||||
{
|
||||
// attempt to get chunk lighting
|
||||
ChunkCompoundTagParser.CombinedChunkLightStorage combinedLights = ChunkCompoundTagParser.readLight(newChunk, chunkData);
|
||||
if (combinedLights != null)
|
||||
{
|
||||
chunkSkyLightingByDhPos.put(dhChunkPos, combinedLights.skyLightStorage);
|
||||
chunkBlockLightingByDhPos.put(dhChunkPos, combinedLights.blockLightStorage);
|
||||
}
|
||||
// may be empty, empty checks are handled later
|
||||
chunkSkyLightingByDhPos.put(dhChunkPos, combinedLights.skyLightStorage);
|
||||
chunkBlockLightingByDhPos.put(dhChunkPos, combinedLights.blockLightStorage);
|
||||
}
|
||||
|
||||
return newChunk;
|
||||
return newChunkWrapper;
|
||||
})
|
||||
// separate handle so we can cleanly handle missing chunks and/or thrown errors
|
||||
.handle((newChunk, throwable) ->
|
||||
.handle((ChunkWrapper newChunkWrapper, Throwable throwable) ->
|
||||
{
|
||||
if (newChunk != null)
|
||||
if (newChunkWrapper != null)
|
||||
{
|
||||
return newChunk;
|
||||
return newChunkWrapper;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CreateEmptyChunk(this.params.level, chunkPos);
|
||||
return this.CreateProtoChunkWrapper(this.params.mcServerLevel, chunkPos);
|
||||
}
|
||||
})
|
||||
.thenApply((newChunk) ->
|
||||
.thenApply((ChunkWrapper newChunkWrapper) ->
|
||||
{
|
||||
generatedChunkByDhPos.put(dhChunkPos, newChunk);
|
||||
return newChunk;
|
||||
generatedChunkWrapperByDhPos.put(dhChunkPos, newChunkWrapper);
|
||||
return newChunkWrapper;
|
||||
});
|
||||
}
|
||||
private CompletableFuture<CompoundTag> getChunkNbtDataAsync(ChunkPos chunkPos)
|
||||
{
|
||||
ServerLevel level = this.params.level;
|
||||
|
||||
//if (true)
|
||||
// return CompletableFuture.completedFuture(null);
|
||||
|
||||
// TODO disabling drastically reduces GC overhead (2Gb/s -> 1GB/s)
|
||||
ServerLevel level = this.params.mcServerLevel;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -190,7 +182,7 @@ public class ChunkFileReader implements AutoCloseable
|
||||
{
|
||||
try
|
||||
{
|
||||
RegionFileStorage storage = this.params.level.getChunkSource().chunkMap.worker.storage;
|
||||
RegionFileStorage storage = this.params.mcServerLevel.getChunkSource().chunkMap.worker.storage;
|
||||
RegionFileStorageExternalCache cache = this.getOrCreateRegionFileCache(storage);
|
||||
return CompletableFuture.completedFuture(cache.read(chunkPos));
|
||||
}
|
||||
@@ -264,35 +256,24 @@ public class ChunkFileReader implements AutoCloseable
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
}
|
||||
private ChunkAccess loadOrMakeChunk(ChunkPos chunkPos, CompoundTag chunkTagData)
|
||||
private ChunkWrapper loadOrMakeChunkWrapper(ChunkPos chunkPos, CompoundTag chunkTagData)
|
||||
{
|
||||
ServerLevel level = this.params.level;
|
||||
ServerLevel mcServerLevel = this.params.mcServerLevel;
|
||||
|
||||
if (chunkTagData == null)
|
||||
{
|
||||
return CreateEmptyChunk(level, chunkPos);
|
||||
return this.CreateProtoChunkWrapper(mcServerLevel, chunkPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
@Nullable
|
||||
ChunkAccess chunk = ChunkCompoundTagParser.createFromTag(level, chunkPos, chunkTagData);
|
||||
if (chunk != null)
|
||||
ChunkWrapper chunkWrapper = ChunkCompoundTagParser.createFromTag(mcServerLevel, this.params.dhServerLevel, chunkPos, chunkTagData);
|
||||
if (chunkWrapper == null)
|
||||
{
|
||||
if (Config.Common.LodBuilding.assumePreExistingChunksAreFinished.get())
|
||||
{
|
||||
// Sometimes the chunk status is wrong
|
||||
// (this might be an issue with some versions of chunky)
|
||||
// which can cause issues with some world gen steps re-running and locking up
|
||||
ChunkWrapper.trySetStatus(chunk, ChunkStatus.FULL);
|
||||
}
|
||||
chunkWrapper = this.CreateProtoChunkWrapper(mcServerLevel, chunkPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
chunk = CreateEmptyChunk(level, chunkPos);
|
||||
}
|
||||
return chunk;
|
||||
return chunkWrapper;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -303,12 +284,17 @@ public class ChunkFileReader implements AutoCloseable
|
||||
"Error: [" + e.getMessage() + "]."
|
||||
, e);
|
||||
|
||||
return CreateEmptyChunk(level, chunkPos);
|
||||
return this.CreateProtoChunkWrapper(mcServerLevel, chunkPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static ProtoChunk CreateEmptyChunk(ServerLevel level, ChunkPos chunkPos)
|
||||
public ChunkWrapper CreateProtoChunkWrapper(ServerLevel level, ChunkPos chunkPos)
|
||||
{
|
||||
ProtoChunk chunk = CreateProtoChunk(level, chunkPos);
|
||||
return new ChunkWrapper(chunk, this.params.dhServerLevel.getLevelWrapper());
|
||||
}
|
||||
public static ProtoChunk CreateProtoChunk(ServerLevel level, ChunkPos chunkPos)
|
||||
{
|
||||
#if MC_VER <= MC_1_16_5
|
||||
return new ProtoChunk(chunkPos, UpgradeData.EMPTY);
|
||||
|
||||
+3
-4
@@ -172,7 +172,6 @@ public class InternalServerGenerator
|
||||
for (int i = 0; i < chunkWrappers.size(); i++)
|
||||
{
|
||||
ChunkWrapper chunkWrapper = (ChunkWrapper)chunkWrappers.get(i);
|
||||
chunkWrapper.recalculateDhHeightMapsIfNeeded();
|
||||
|
||||
// pre-generated chunks should have lighting but new ones won't
|
||||
if (!chunkWrapper.isDhBlockLightingCorrect())
|
||||
@@ -191,7 +190,7 @@ public class InternalServerGenerator
|
||||
while (chunkPosIterator.hasNext())
|
||||
{
|
||||
ChunkPos chunkPos = chunkPosIterator.next();
|
||||
this.releaseChunkFromServer(this.params.level, chunkPos);
|
||||
this.releaseChunkFromServer(this.params.mcServerLevel, chunkPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -233,7 +232,7 @@ public class InternalServerGenerator
|
||||
{
|
||||
return CompletableFuture.supplyAsync(() ->
|
||||
{
|
||||
ServerLevel level = this.params.level;
|
||||
ServerLevel level = this.params.mcServerLevel;
|
||||
|
||||
// ignore chunk update events for this position
|
||||
SharedApi.CHUNK_UPDATE_QUEUE_MANAGER.addPosToIgnore(new DhChunkPos(chunkPos.x, chunkPos.z));
|
||||
@@ -265,7 +264,7 @@ public class InternalServerGenerator
|
||||
.thenApply(result -> result.orElseThrow(() -> new RuntimeException(result.getError()))); // can throw if the server is shutting down
|
||||
#endif
|
||||
|
||||
}, this.params.level.getChunkSource().chunkMap.mainThreadExecutor)
|
||||
}, this.params.mcServerLevel.getChunkSource().chunkMap.mainThreadExecutor)
|
||||
.thenCompose(Function.identity());
|
||||
}
|
||||
/**
|
||||
|
||||
+2
-2
@@ -106,9 +106,9 @@ public final class StepStructureStart extends AbstractWorldGenStep
|
||||
tParams.structFeatManager, chunk, this.environment.globalParams.structures);
|
||||
#else
|
||||
this.environment.globalParams.generator.createStructures(this.environment.globalParams.registry,
|
||||
this.environment.globalParams.level.getChunkSource().getGeneratorState(),
|
||||
this.environment.globalParams.mcServerLevel.getChunkSource().getGeneratorState(),
|
||||
tParams.structFeatManager, chunk, this.environment.globalParams.structures,
|
||||
this.environment.globalParams.level.dimension());
|
||||
this.environment.globalParams.mcServerLevel.dimension());
|
||||
#endif
|
||||
|
||||
#if MC_VER >= MC_1_18_2
|
||||
|
||||
+1
-1
Submodule coreSubProjects updated: 4e9559f230...385bd326cf
Reference in New Issue
Block a user