Compare commits
51 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 759ec3676c | |||
| e5ea86bf8f | |||
| 533c6a7f93 | |||
| ff41e070fd | |||
| b3f607e132 | |||
| 9ecbb9cc9f | |||
| 7888de8200 | |||
| d2327ae836 | |||
| ea92a8f922 | |||
| 47e97630b4 | |||
| c250a7408e | |||
| 30da01f580 | |||
| 2c71c2bf76 | |||
| 13a4505d7d | |||
| 7f0eeb9f15 | |||
| d7eabcf3a6 | |||
| 7047d0afdf | |||
| f318b52280 | |||
| f50613e20c | |||
| af3a993042 | |||
| ace1aab42e | |||
| 350d72b6ec | |||
| 986a6cdc19 | |||
| 2aa8d9f489 | |||
| 5652a9328c | |||
| b7253b6549 | |||
| e026cf104c | |||
| ab4a9cbb55 | |||
| a709ab6071 | |||
| 3c11a2dc33 | |||
| ce2aa6602a | |||
| 738aff8ec6 | |||
| 91da0bf252 | |||
| af8dea9d9f | |||
| 384933d351 | |||
| a5344d50c2 | |||
| 2b4c5b91a4 | |||
| 3090544b85 | |||
| 75e1bbbe17 | |||
| 31b604b5c8 | |||
| 70ba93abec | |||
| f628a7f21e | |||
| 254f51ea5e | |||
| d44152dc46 | |||
| 0ef979ee6c | |||
| cf643372b6 | |||
| dc1a117f6b | |||
| 2545c7e76d | |||
| 8d9b5f66fa | |||
| aec28854a3 | |||
| 63acd94fd4 |
+1
-1
@@ -11,7 +11,7 @@ insert_final_newline = false
|
|||||||
max_line_length = 1000
|
max_line_length = 1000
|
||||||
tab_width = 4
|
tab_width = 4
|
||||||
trim_trailing_whitespace = false
|
trim_trailing_whitespace = false
|
||||||
ij_continuation_indent_size = 8
|
ij_continuation_indent_size = 4
|
||||||
ij_formatter_off_tag = @formatter:off
|
ij_formatter_off_tag = @formatter:off
|
||||||
ij_formatter_on_tag = @formatter:on
|
ij_formatter_on_tag = @formatter:on
|
||||||
ij_formatter_tags_enabled = true
|
ij_formatter_tags_enabled = true
|
||||||
|
|||||||
@@ -115,8 +115,8 @@ public abstract class AbstractModInitializer
|
|||||||
this.initializeModCompat();
|
this.initializeModCompat();
|
||||||
|
|
||||||
LOGGER.info(ModInfo.READABLE_NAME + " server Initialized, adding event subscribers...");
|
LOGGER.info(ModInfo.READABLE_NAME + " server Initialized, adding event subscribers...");
|
||||||
|
this.commandInitializer = new CommandInitializer();
|
||||||
this.subscribeRegisterCommandsEvent(dispatcher -> { this.commandInitializer = new CommandInitializer(dispatcher); });
|
this.subscribeRegisterCommandsEvent(dispatcher -> { commandInitializer.initCommands(dispatcher); });
|
||||||
|
|
||||||
this.subscribeServerStartingEvent(server ->
|
this.subscribeServerStartingEvent(server ->
|
||||||
{
|
{
|
||||||
@@ -124,7 +124,7 @@ public abstract class AbstractModInitializer
|
|||||||
|
|
||||||
this.initConfig();
|
this.initConfig();
|
||||||
this.postInit();
|
this.postInit();
|
||||||
this.commandInitializer.initCommands();
|
this.commandInitializer.onServerReady();
|
||||||
|
|
||||||
this.checkForUpdates();
|
this.checkForUpdates();
|
||||||
|
|
||||||
|
|||||||
+28
-10
@@ -3,6 +3,7 @@ package com.seibel.distanthorizons.common.commands;
|
|||||||
import com.mojang.brigadier.CommandDispatcher;
|
import com.mojang.brigadier.CommandDispatcher;
|
||||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
import net.minecraft.commands.CommandSourceStack;
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import static com.seibel.distanthorizons.core.network.messages.MessageRegistry.DEBUG_CODEC_CRASH_MESSAGE;
|
import static com.seibel.distanthorizons.core.network.messages.MessageRegistry.DEBUG_CODEC_CRASH_MESSAGE;
|
||||||
import static net.minecraft.commands.Commands.literal;
|
import static net.minecraft.commands.Commands.literal;
|
||||||
@@ -12,25 +13,42 @@ import static net.minecraft.commands.Commands.literal;
|
|||||||
*/
|
*/
|
||||||
public class CommandInitializer
|
public class CommandInitializer
|
||||||
{
|
{
|
||||||
private final CommandDispatcher<CommandSourceStack> commandDispatcher;
|
private boolean serverReady = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new instance of this class.
|
* A received command dispatcher, which is held until the server is ready to initialize the commands.
|
||||||
*
|
|
||||||
* @param commandDispatcher The dispatcher to use for registering commands.
|
|
||||||
*/
|
*/
|
||||||
public CommandInitializer(CommandDispatcher<CommandSourceStack> commandDispatcher)
|
@Nullable
|
||||||
|
private CommandDispatcher<CommandSourceStack> commandDispatcher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notify the command initializer that the game is ready to accept commands.
|
||||||
|
* If {@link CommandInitializer#initCommands(CommandDispatcher)} has been fired before it was ready, it will also initialize the commands.
|
||||||
|
*/
|
||||||
|
public void onServerReady()
|
||||||
{
|
{
|
||||||
this.commandDispatcher = commandDispatcher;
|
this.serverReady = true;
|
||||||
|
if (this.commandDispatcher != null)
|
||||||
|
{
|
||||||
|
this.initCommands(this.commandDispatcher);
|
||||||
|
this.commandDispatcher = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes all available commands.
|
* Initializes all available commands.
|
||||||
|
* If the game is not ready yet, it stores the dispatcher to initialize the commands later.
|
||||||
|
*
|
||||||
|
* @param commandDispatcher The command dispatcher to register commands to.
|
||||||
*/
|
*/
|
||||||
public void initCommands()
|
public void initCommands(CommandDispatcher<CommandSourceStack> commandDispatcher)
|
||||||
{
|
{
|
||||||
|
if (!this.serverReady)
|
||||||
|
{
|
||||||
|
this.commandDispatcher = commandDispatcher;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
LiteralArgumentBuilder<CommandSourceStack> builder = literal("dh")
|
LiteralArgumentBuilder<CommandSourceStack> builder = literal("dh")
|
||||||
.requires(source -> source.hasPermission(4));
|
.requires(source -> source.hasPermission(4));
|
||||||
|
|
||||||
@@ -43,7 +61,7 @@ public class CommandInitializer
|
|||||||
builder.then(new CrashCommand().buildCommand());
|
builder.then(new CrashCommand().buildCommand());
|
||||||
}
|
}
|
||||||
|
|
||||||
this.commandDispatcher.register(builder);
|
commandDispatcher.register(builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,6 @@ public class DependencySetup
|
|||||||
SingletonInjector.INSTANCE.bind(IVersionConstants.class, VersionConstants.INSTANCE);
|
SingletonInjector.INSTANCE.bind(IVersionConstants.class, VersionConstants.INSTANCE);
|
||||||
SingletonInjector.INSTANCE.bind(IWrapperFactory.class, WrapperFactory.INSTANCE);
|
SingletonInjector.INSTANCE.bind(IWrapperFactory.class, WrapperFactory.INSTANCE);
|
||||||
SingletonInjector.INSTANCE.bind(IKeyedClientLevelManager.class, KeyedClientLevelManager.INSTANCE);
|
SingletonInjector.INSTANCE.bind(IKeyedClientLevelManager.class, KeyedClientLevelManager.INSTANCE);
|
||||||
DependencySetupDoneCheck.isDone = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void createServerBindings()
|
public static void createServerBindings()
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrappe
|
|||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.worldGeneration.AbstractBatchGenerationEnvironmentWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.worldGeneration.IBatchGeneratorEnvironmentWrapper;
|
||||||
import net.minecraft.client.multiplayer.ClientLevel;
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
#if MC_VER > MC_1_17_1
|
#if MC_VER > MC_1_17_1
|
||||||
import net.minecraft.core.Holder;
|
import net.minecraft.core.Holder;
|
||||||
@@ -67,7 +67,7 @@ public class WrapperFactory implements IWrapperFactory
|
|||||||
//==============//
|
//==============//
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AbstractBatchGenerationEnvironmentWrapper createBatchGenerator(IDhLevel targetLevel)
|
public IBatchGeneratorEnvironmentWrapper createBatchGenerator(IDhLevel targetLevel)
|
||||||
{
|
{
|
||||||
if (targetLevel instanceof IDhServerLevel)
|
if (targetLevel instanceof IDhServerLevel)
|
||||||
{
|
{
|
||||||
|
|||||||
+5
-3
@@ -124,11 +124,12 @@ public abstract class AbstractDhTintGetter implements BlockAndTintGetter
|
|||||||
int rollingBlue = 0;
|
int rollingBlue = 0;
|
||||||
|
|
||||||
int xMin = mutableBlockPos.getX() - this.smoothingRadiusInBlocks;
|
int xMin = mutableBlockPos.getX() - this.smoothingRadiusInBlocks;
|
||||||
int xMax = mutableBlockPos.getX() + this.smoothingRadiusInBlocks;
|
int xMax = mutableBlockPos.getX() + this.smoothingRadiusInBlocks + 1; // +1 to account for the center block
|
||||||
|
|
||||||
int zMin = mutableBlockPos.getZ() - this.smoothingRadiusInBlocks;
|
int zMin = mutableBlockPos.getZ() - this.smoothingRadiusInBlocks;
|
||||||
int zMax = mutableBlockPos.getZ() + this.smoothingRadiusInBlocks;
|
int zMax = mutableBlockPos.getZ() + this.smoothingRadiusInBlocks + 1;
|
||||||
|
|
||||||
|
int levelMinY = this.clientLevelWrapper.getMinHeight();
|
||||||
|
|
||||||
for (int x = xMin; x < xMax; x++)
|
for (int x = xMin; x < xMax; x++)
|
||||||
{
|
{
|
||||||
@@ -140,12 +141,13 @@ public abstract class AbstractDhTintGetter implements BlockAndTintGetter
|
|||||||
// this can return the same position/datapoint for larger LODs duplicating work,
|
// this can return the same position/datapoint for larger LODs duplicating work,
|
||||||
// however for small smoothing ranges that isn't a big deal and for large LODs
|
// however for small smoothing ranges that isn't a big deal and for large LODs
|
||||||
// we ignore smoothing anyway
|
// we ignore smoothing anyway
|
||||||
long dataPoint = this.fullDataSource.getDataPointAtBlockPos(mutableBlockPos);
|
long dataPoint = this.fullDataSource.getDataPointAtBlockPos(mutableBlockPos.getX(), mutableBlockPos.getY(), mutableBlockPos.getZ(), levelMinY);
|
||||||
if (dataPoint == FullDataPointUtil.EMPTY_DATA_POINT)
|
if (dataPoint == FullDataPointUtil.EMPTY_DATA_POINT)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// get the color for this nearby position
|
// get the color for this nearby position
|
||||||
int id = FullDataPointUtil.getId(dataPoint);
|
int id = FullDataPointUtil.getId(dataPoint);
|
||||||
BiomeWrapper biomeWrapper = (BiomeWrapper) this.fullDataSource.mapping.getBiomeWrapper(id);
|
BiomeWrapper biomeWrapper = (BiomeWrapper) this.fullDataSource.mapping.getBiomeWrapper(id);
|
||||||
|
|||||||
+7
-6
@@ -274,7 +274,7 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
|
|
||||||
HashSet<String> baseIgnoredBlock = new HashSet<>();
|
HashSet<String> baseIgnoredBlock = new HashSet<>();
|
||||||
baseIgnoredBlock.add(AIR_STRING);
|
baseIgnoredBlock.add(AIR_STRING);
|
||||||
rendererIgnoredBlocks = getBlockWrappers(Config.Client.Advanced.Graphics.Culling.ignoredRenderBlockCsv, baseIgnoredBlock, levelWrapper);
|
rendererIgnoredBlocks = getAllBlockWrappers(Config.Client.Advanced.Graphics.Culling.ignoredRenderBlockCsv, baseIgnoredBlock, levelWrapper);
|
||||||
return rendererIgnoredBlocks;
|
return rendererIgnoredBlocks;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -291,7 +291,7 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
|
|
||||||
HashSet<String> baseIgnoredBlock = new HashSet<>();
|
HashSet<String> baseIgnoredBlock = new HashSet<>();
|
||||||
baseIgnoredBlock.add(AIR_STRING);
|
baseIgnoredBlock.add(AIR_STRING);
|
||||||
rendererIgnoredCaveBlocks = getBlockWrappers(Config.Client.Advanced.Graphics.Culling.ignoredRenderCaveBlockCsv, baseIgnoredBlock, levelWrapper);
|
rendererIgnoredCaveBlocks = getAllBlockWrappers(Config.Client.Advanced.Graphics.Culling.ignoredRenderCaveBlockCsv, baseIgnoredBlock, levelWrapper);
|
||||||
return rendererIgnoredCaveBlocks;
|
return rendererIgnoredCaveBlocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -302,7 +302,7 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
|
|
||||||
// lod builder helpers //
|
// lod builder helpers //
|
||||||
|
|
||||||
private static HashSet<IBlockStateWrapper> getBlockWrappers(ConfigEntry<String> config, HashSet<String> baseResourceLocations, ILevelWrapper levelWrapper)
|
private static HashSet<IBlockStateWrapper> getAllBlockWrappers(ConfigEntry<String> config, HashSet<String> baseResourceLocations, ILevelWrapper levelWrapper)
|
||||||
{
|
{
|
||||||
// get the base blocks
|
// get the base blocks
|
||||||
HashSet<String> blockStringList = new HashSet<>();
|
HashSet<String> blockStringList = new HashSet<>();
|
||||||
@@ -318,9 +318,9 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
blockStringList.addAll(Arrays.asList(ignoreBlockCsv.split(",")));
|
blockStringList.addAll(Arrays.asList(ignoreBlockCsv.split(",")));
|
||||||
}
|
}
|
||||||
|
|
||||||
return getBlockWrappers(blockStringList, levelWrapper);
|
return getAllBlockWrappers(blockStringList, levelWrapper);
|
||||||
}
|
}
|
||||||
private static HashSet<IBlockStateWrapper> getBlockWrappers(HashSet<String> blockResourceLocationSet, ILevelWrapper levelWrapper)
|
private static HashSet<IBlockStateWrapper> getAllBlockWrappers(HashSet<String> blockResourceLocationSet, ILevelWrapper levelWrapper)
|
||||||
{
|
{
|
||||||
// deserialize each of the given resource locations
|
// deserialize each of the given resource locations
|
||||||
HashSet<IBlockStateWrapper> blockStateWrappers = new HashSet<>();
|
HashSet<IBlockStateWrapper> blockStateWrappers = new HashSet<>();
|
||||||
@@ -587,7 +587,8 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
// we need the final string for the concurrent hash map later
|
// we need the final string for the concurrent hash map later
|
||||||
final String finalResourceStateString = resourceStateString;
|
final String finalResourceStateString = resourceStateString;
|
||||||
|
|
||||||
if (finalResourceStateString.equals(AIR_STRING) || finalResourceStateString.equals("")) // the empty string shouldn't normally happen, but just in case
|
if (finalResourceStateString.equals(AIR_STRING)
|
||||||
|
|| finalResourceStateString.equals("")) // the empty string shouldn't normally happen, but just in case
|
||||||
{
|
{
|
||||||
return AIR;
|
return AIR;
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-21
@@ -21,7 +21,6 @@ package com.seibel.distanthorizons.common.wrappers.chunk;
|
|||||||
import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper;
|
import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper;
|
||||||
import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper;
|
import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper;
|
||||||
import com.seibel.distanthorizons.common.wrappers.misc.MutableBlockPosWrapper;
|
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.logging.DhLoggerBuilder;
|
||||||
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos;
|
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos;
|
||||||
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
||||||
@@ -98,9 +97,9 @@ public class ChunkWrapper implements IChunkWrapper
|
|||||||
private int maxNonEmptyHeight = Integer.MAX_VALUE;
|
private int maxNonEmptyHeight = Integer.MAX_VALUE;
|
||||||
|
|
||||||
/** will be null if we are using MC heightmaps */
|
/** 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 */
|
/** will be null if we are using MC heightmaps */
|
||||||
private final int[][] lightBlockingHeightMap;
|
private int[][] lightBlockingHeightMap = null;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -109,23 +108,18 @@ public class ChunkWrapper implements IChunkWrapper
|
|||||||
//=============//
|
//=============//
|
||||||
|
|
||||||
public ChunkWrapper(ChunkAccess chunk, ILevelWrapper wrappedLevel)
|
public ChunkWrapper(ChunkAccess chunk, ILevelWrapper wrappedLevel)
|
||||||
|
{
|
||||||
|
this(chunk, wrappedLevel, true);
|
||||||
|
}
|
||||||
|
public ChunkWrapper(ChunkAccess chunk, ILevelWrapper wrappedLevel, boolean recreateHeightmaps)
|
||||||
{
|
{
|
||||||
this.chunk = chunk;
|
this.chunk = chunk;
|
||||||
this.wrappedLevel = wrappedLevel;
|
this.wrappedLevel = wrappedLevel;
|
||||||
this.chunkPos = new DhChunkPos(chunk.getPos().x, chunk.getPos().z);
|
this.chunkPos = new DhChunkPos(chunk.getPos().x, chunk.getPos().z);
|
||||||
|
|
||||||
// use DH heightmaps if requested
|
if (recreateHeightmaps)
|
||||||
if (Config.Common.LodBuilding.recalculateChunkHeightmaps.get())
|
|
||||||
{
|
{
|
||||||
this.solidHeightMap = new int[LodUtil.CHUNK_WIDTH][LodUtil.CHUNK_WIDTH];
|
this.createDhHeightMaps();
|
||||||
this.lightBlockingHeightMap = new int[LodUtil.CHUNK_WIDTH][LodUtil.CHUNK_WIDTH];
|
|
||||||
|
|
||||||
this.recalculateDhHeightMapsIfNeeded();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.solidHeightMap = null;
|
|
||||||
this.lightBlockingHeightMap = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,17 +242,16 @@ public class ChunkWrapper implements IChunkWrapper
|
|||||||
}
|
}
|
||||||
private int getChunkSectionMinHeight(int index) { return (index * 16) + this.getInclusiveMinBuildHeight(); }
|
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 createDhHeightMaps()
|
||||||
public void recalculateDhHeightMapsIfNeeded()
|
|
||||||
{
|
{
|
||||||
// re-calculate the min/max heights for consistency (during world gen these may be wrong)
|
// re-calculate the min/max heights for consistency (during world gen these may be wrong)
|
||||||
this.minNonEmptyHeight = Integer.MIN_VALUE;
|
this.minNonEmptyHeight = Integer.MIN_VALUE;
|
||||||
this.maxNonEmptyHeight = Integer.MAX_VALUE;
|
this.maxNonEmptyHeight = Integer.MAX_VALUE;
|
||||||
|
|
||||||
|
|
||||||
// recalculate heightmaps if needed
|
this.solidHeightMap = new int[LodUtil.CHUNK_WIDTH][LodUtil.CHUNK_WIDTH];
|
||||||
if (this.solidHeightMap != null)
|
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++)
|
||||||
@@ -274,7 +267,12 @@ public class ChunkWrapper implements IChunkWrapper
|
|||||||
while (// go down until we reach the minimum build height
|
while (// go down until we reach the minimum build height
|
||||||
y > minInclusiveBuildHeight
|
y > minInclusiveBuildHeight
|
||||||
// keep going until we find both height map values
|
// keep going until we find both height map values
|
||||||
&& (solidHeight == minInclusiveBuildHeight || lightBlockingHeight == minInclusiveBuildHeight))
|
&&
|
||||||
|
(
|
||||||
|
solidHeight == minInclusiveBuildHeight
|
||||||
|
|| lightBlockingHeight == minInclusiveBuildHeight
|
||||||
|
)
|
||||||
|
)
|
||||||
{
|
{
|
||||||
// is this block solid?
|
// is this block solid?
|
||||||
if (solidHeight == minInclusiveBuildHeight
|
if (solidHeight == minInclusiveBuildHeight
|
||||||
@@ -300,7 +298,6 @@ public class ChunkWrapper implements IChunkWrapper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getSolidHeightMapValue(int xRel, int zRel)
|
public int getSolidHeightMapValue(int xRel, int zRel)
|
||||||
|
|||||||
+6
@@ -396,4 +396,10 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPreventAutoPause(boolean preventAutoPause)
|
||||||
|
{
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+7
@@ -11,6 +11,7 @@ public class MinecraftServerWrapper implements IMinecraftSharedWrapper
|
|||||||
public static final MinecraftServerWrapper INSTANCE = new MinecraftServerWrapper();
|
public static final MinecraftServerWrapper INSTANCE = new MinecraftServerWrapper();
|
||||||
|
|
||||||
public DedicatedServer dedicatedServer = null;
|
public DedicatedServer dedicatedServer = null;
|
||||||
|
public boolean preventAutoPause = false;
|
||||||
|
|
||||||
|
|
||||||
//=============//
|
//=============//
|
||||||
@@ -49,4 +50,10 @@ public class MinecraftServerWrapper implements IMinecraftSharedWrapper
|
|||||||
return this.dedicatedServer.getPlayerCount();
|
return this.dedicatedServer.getPlayerCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPreventAutoPause(boolean preventAutoPause)
|
||||||
|
{
|
||||||
|
this.preventAutoPause = preventAutoPause;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+245
-797
File diff suppressed because it is too large
Load Diff
+92
@@ -0,0 +1,92 @@
|
|||||||
|
package com.seibel.distanthorizons.common.wrappers.worldGeneration;
|
||||||
|
|
||||||
|
import net.minecraft.world.level.ChunkPos;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Spliterator;
|
||||||
|
import java.util.Spliterators;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import java.util.stream.StreamSupport;
|
||||||
|
|
||||||
|
public class ChunkPosGenStream
|
||||||
|
{
|
||||||
|
|
||||||
|
public static Iterator<ChunkPos> getIterator(int genMinX, int genMinZ, int width, int extraRadius)
|
||||||
|
{ return getStream(genMinX, genMinZ, width, extraRadius).iterator(); }
|
||||||
|
/** @param extraRadius in both the positive and negative directions */
|
||||||
|
public static Stream<ChunkPos> getStream(int genMinX, int genMinZ, int width, int extraRadius)
|
||||||
|
{ return StreamSupport.stream(new InclusiveChunkPosIterator(genMinX, genMinZ, width, extraRadius), false); }
|
||||||
|
|
||||||
|
private static class InclusiveChunkPosIterator extends Spliterators.AbstractSpliterator<ChunkPos>
|
||||||
|
{
|
||||||
|
private final int minX;
|
||||||
|
private final int minZ;
|
||||||
|
|
||||||
|
private final int maxX;
|
||||||
|
private final int maxZ;
|
||||||
|
|
||||||
|
|
||||||
|
/** current X pos */
|
||||||
|
int x;
|
||||||
|
/** current Z pos */
|
||||||
|
private int z;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
|
||||||
|
protected InclusiveChunkPosIterator(int genMinX, int genMinZ, int width, int extraRadius)
|
||||||
|
{
|
||||||
|
super(getCount(width, extraRadius), Spliterator.SIZED);
|
||||||
|
|
||||||
|
this.minX = genMinX - extraRadius;
|
||||||
|
this.minZ = genMinZ - extraRadius;
|
||||||
|
|
||||||
|
this.maxX = genMinX + (width - 1) + extraRadius;
|
||||||
|
this.maxZ = genMinZ + (width - 1) + extraRadius;
|
||||||
|
|
||||||
|
// X starts at 1 minus the minX so we can immediately re-add 1 in the tryAdvance() loop
|
||||||
|
this.x = this.minX - 1;
|
||||||
|
this.z = this.minZ;
|
||||||
|
}
|
||||||
|
private static int getCount(int width, int extraRadius)
|
||||||
|
{
|
||||||
|
int widthPlusExtra = width + (extraRadius * 2);
|
||||||
|
return widthPlusExtra * widthPlusExtra;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=================//
|
||||||
|
// iterator method //
|
||||||
|
//=================//
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean tryAdvance(Consumer<? super ChunkPos> consumer)
|
||||||
|
{
|
||||||
|
if (this.x == this.maxX && this.z == this.maxZ)
|
||||||
|
{
|
||||||
|
// the last returned position was the final valid position
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.x == this.maxX)
|
||||||
|
{
|
||||||
|
// we reached the max X position, loop back around in the next Z row
|
||||||
|
this.x = this.minX;
|
||||||
|
this.z++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.x++;
|
||||||
|
}
|
||||||
|
|
||||||
|
consumer.accept(new ChunkPos(this.x, this.z));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+62
-79
@@ -19,17 +19,16 @@
|
|||||||
|
|
||||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration;
|
package com.seibel.distanthorizons.common.wrappers.worldGeneration;
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandles;
|
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiDistantGeneratorMode;
|
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiDistantGeneratorMode;
|
||||||
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiWorldGenerationStep;
|
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiWorldGenerationStep;
|
||||||
import com.seibel.distanthorizons.core.util.objects.UncheckedInterruptedException;
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.params.ThreadWorldGenParams;
|
||||||
|
import com.seibel.distanthorizons.core.util.ExceptionUtil;
|
||||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
||||||
import com.seibel.distanthorizons.core.util.objects.EventTimer;
|
|
||||||
import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
|
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||||
|
|
||||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
@@ -37,96 +36,101 @@ import com.seibel.distanthorizons.core.logging.DhLogger;
|
|||||||
public final class GenerationEvent
|
public final class GenerationEvent
|
||||||
{
|
{
|
||||||
private static final DhLogger LOGGER = new DhLoggerBuilder().build();;
|
private static final DhLogger LOGGER = new DhLoggerBuilder().build();;
|
||||||
private static int generationFutureDebugIDs = 0;
|
|
||||||
|
|
||||||
|
private static final AtomicInteger DEBUG_ID_REF = new AtomicInteger(0);
|
||||||
|
|
||||||
|
|
||||||
|
/** can be used for troubleshooting */
|
||||||
public final int id;
|
public final int id;
|
||||||
public final ThreadedParameters threadedParam;
|
|
||||||
|
public final ThreadWorldGenParams threadedParam;
|
||||||
public final DhChunkPos minPos;
|
public final DhChunkPos minPos;
|
||||||
/** the number of chunks wide this event is */
|
public final int widthInChunks;
|
||||||
public final int size;
|
|
||||||
public final EDhApiWorldGenerationStep targetGenerationStep;
|
public final EDhApiWorldGenerationStep targetGenerationStep;
|
||||||
public final EDhApiDistantGeneratorMode generatorMode;
|
public final EDhApiDistantGeneratorMode generatorMode;
|
||||||
public EventTimer timer = null;
|
public final CompletableFuture<Void> future;
|
||||||
public long inQueueTime;
|
|
||||||
public long timeoutTime = -1;
|
|
||||||
public CompletableFuture<Void> future = null;
|
|
||||||
public final Consumer<IChunkWrapper> resultConsumer;
|
public final Consumer<IChunkWrapper> resultConsumer;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public GenerationEvent(
|
//=============//
|
||||||
DhChunkPos minPos, int size, BatchGenerationEnvironment generationGroup,
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
|
||||||
|
private GenerationEvent(
|
||||||
|
DhChunkPos minPos, int widthInChunks, BatchGenerationEnvironment generationGroup,
|
||||||
EDhApiDistantGeneratorMode generatorMode, EDhApiWorldGenerationStep targetGenerationStep, Consumer<IChunkWrapper> resultConsumer)
|
EDhApiDistantGeneratorMode generatorMode, EDhApiWorldGenerationStep targetGenerationStep, Consumer<IChunkWrapper> resultConsumer)
|
||||||
{
|
{
|
||||||
this.inQueueTime = System.nanoTime();
|
this.id = DEBUG_ID_REF.getAndIncrement();
|
||||||
this.id = generationFutureDebugIDs++;
|
|
||||||
this.minPos = minPos;
|
this.minPos = minPos;
|
||||||
this.size = size;
|
this.widthInChunks = widthInChunks;
|
||||||
this.generatorMode = generatorMode;
|
|
||||||
this.targetGenerationStep = targetGenerationStep;
|
this.targetGenerationStep = targetGenerationStep;
|
||||||
this.threadedParam = ThreadedParameters.getOrMake(generationGroup.params);
|
this.generatorMode = generatorMode;
|
||||||
|
this.threadedParam = ThreadWorldGenParams.getOrMake(generationGroup.globalParams);
|
||||||
|
this.future = new CompletableFuture<>();
|
||||||
this.resultConsumer = resultConsumer;
|
this.resultConsumer = resultConsumer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static GenerationEvent startEvent(
|
//=======//
|
||||||
DhChunkPos minPos, int size, BatchGenerationEnvironment genEnvironment,
|
// start //
|
||||||
|
//=======//
|
||||||
|
|
||||||
|
public static GenerationEvent start(
|
||||||
|
DhChunkPos minPos, int widthInChunks, BatchGenerationEnvironment genEnvironment,
|
||||||
EDhApiDistantGeneratorMode generatorMode, EDhApiWorldGenerationStep target, Consumer<IChunkWrapper> resultConsumer,
|
EDhApiDistantGeneratorMode generatorMode, EDhApiWorldGenerationStep target, Consumer<IChunkWrapper> resultConsumer,
|
||||||
ExecutorService worldGeneratorThreadPool)
|
ExecutorService worldGeneratorThreadPool)
|
||||||
{
|
{
|
||||||
GenerationEvent generationEvent = new GenerationEvent(minPos, size, genEnvironment, generatorMode, target, resultConsumer);
|
GenerationEvent genEvent = new GenerationEvent(minPos, widthInChunks, genEnvironment, generatorMode, target, resultConsumer);
|
||||||
generationEvent.future = CompletableFuture.supplyAsync(() ->
|
|
||||||
{
|
|
||||||
long runStartTime = System.nanoTime();
|
|
||||||
generationEvent.timeoutTime = runStartTime;
|
|
||||||
generationEvent.inQueueTime = runStartTime - generationEvent.inQueueTime;
|
|
||||||
generationEvent.timer = new EventTimer("setup");
|
|
||||||
|
|
||||||
BatchGenerationEnvironment.isDistantGeneratorThread.set(true);
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
|
||||||
genEnvironment.generateLodFromListAsync(generationEvent, (runnable) ->
|
|
||||||
{
|
{
|
||||||
worldGeneratorThreadPool.execute(() ->
|
worldGeneratorThreadPool.execute(() ->
|
||||||
{
|
{
|
||||||
boolean alreadyMarked = BatchGenerationEnvironment.isCurrentThreadDistantGeneratorThread();
|
|
||||||
if (!alreadyMarked)
|
|
||||||
{
|
|
||||||
BatchGenerationEnvironment.isDistantGeneratorThread.set(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
runnable.run();
|
BatchGenerationEnvironment.isDhWorldGenThreadRef.set(true);
|
||||||
|
|
||||||
|
|
||||||
|
if (genEvent.generatorMode == EDhApiDistantGeneratorMode.INTERNAL_SERVER)
|
||||||
|
{
|
||||||
|
genEnvironment.internalServerGenerator.generateChunksViaInternalServer(genEvent);
|
||||||
|
genEvent.future.complete(null);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
genEnvironment.generateEvent(genEvent);
|
||||||
}
|
}
|
||||||
catch (Throwable throwable)
|
catch (Throwable throwable)
|
||||||
{
|
{
|
||||||
handleWorldGenThrowable(generationEvent, throwable);
|
handleWorldGenThrowable(genEvent, throwable);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
if (!alreadyMarked)
|
genEvent.future.complete(null);
|
||||||
{
|
|
||||||
BatchGenerationEnvironment.isDistantGeneratorThread.set(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
catch (Throwable initialThrowable)
|
catch (Throwable initialThrowable)
|
||||||
{
|
{
|
||||||
handleWorldGenThrowable(generationEvent, initialThrowable);
|
handleWorldGenThrowable(genEvent, initialThrowable);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
BatchGenerationEnvironment.isDistantGeneratorThread.remove();
|
BatchGenerationEnvironment.isDhWorldGenThreadRef.remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (RejectedExecutionException e)
|
||||||
|
{
|
||||||
|
genEvent.future.completeExceptionally(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return genEvent;
|
||||||
}, worldGeneratorThreadPool);
|
|
||||||
return generationEvent;
|
|
||||||
}
|
}
|
||||||
/** There's probably a better way to handle this, but it'll work for now */
|
/** There's probably a better way to handle this, but it'll work for now */
|
||||||
private static void handleWorldGenThrowable(GenerationEvent generationEvent, Throwable initialThrowable)
|
private static void handleWorldGenThrowable(GenerationEvent generationEvent, Throwable initialThrowable)
|
||||||
@@ -137,9 +141,8 @@ public final class GenerationEvent
|
|||||||
throwable = throwable.getCause();
|
throwable = throwable.getCause();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (throwable instanceof InterruptedException
|
boolean isShutdownException = ExceptionUtil.isShutdownException(throwable);
|
||||||
|| throwable instanceof UncheckedInterruptedException
|
if (isShutdownException)
|
||||||
|| throwable instanceof RejectedExecutionException)
|
|
||||||
{
|
{
|
||||||
// these exceptions can be ignored, generally they just mean
|
// these exceptions can be ignored, generally they just mean
|
||||||
// the thread is busy so it'll need to try again later.
|
// the thread is busy so it'll need to try again later.
|
||||||
@@ -154,35 +157,15 @@ public final class GenerationEvent
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isComplete() { return this.future.isDone(); }
|
|
||||||
|
|
||||||
public boolean hasTimeout(int duration, TimeUnit unit)
|
|
||||||
{
|
|
||||||
if (this.timeoutTime == -1)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
long currentTime = System.nanoTime();
|
//================//
|
||||||
long delta = currentTime - this.timeoutTime;
|
// base overrides //
|
||||||
return (delta > TimeUnit.NANOSECONDS.convert(duration, unit));
|
//================//
|
||||||
}
|
|
||||||
|
|
||||||
public boolean terminate()
|
|
||||||
{
|
|
||||||
LOGGER.info("======================DUMPING ALL THREADS FOR WORLD GEN=======================");
|
|
||||||
ThreadPoolUtil.WORLD_GEN_THREAD_FACTORY.dumpAllThreadStacks();
|
|
||||||
this.future.cancel(true);
|
|
||||||
return this.future.isCancelled();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void refreshTimeout()
|
|
||||||
{
|
|
||||||
this.timeoutTime = System.nanoTime();
|
|
||||||
UncheckedInterruptedException.throwIfInterrupted();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() { return this.id + ":" + this.size + "@" + this.minPos + "(" + this.targetGenerationStep + ")"; }
|
public String toString() { return this.id + ":" + this.widthInChunks + "@" + this.minPos + "(" + this.targetGenerationStep + ")"; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
+310
@@ -0,0 +1,310 @@
|
|||||||
|
package com.seibel.distanthorizons.common.wrappers.worldGeneration;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.api.DhApi;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.params.GlobalWorldGenParams;
|
||||||
|
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||||
|
import com.seibel.distanthorizons.core.api.internal.SharedApi;
|
||||||
|
import com.seibel.distanthorizons.core.config.Config;
|
||||||
|
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
|
||||||
|
import com.seibel.distanthorizons.core.generation.DhLightingEngine;
|
||||||
|
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.pos.DhChunkPos;
|
||||||
|
import com.seibel.distanthorizons.core.util.ExceptionUtil;
|
||||||
|
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||||
|
import com.seibel.distanthorizons.core.util.TimerUtil;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IC2meAccessor;
|
||||||
|
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||||
|
import net.minecraft.server.level.ChunkHolder;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.server.level.TicketType;
|
||||||
|
import net.minecraft.world.level.ChunkPos;
|
||||||
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_20_4
|
||||||
|
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||||
|
#else
|
||||||
|
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.CompletionException;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class InternalServerGenerator
|
||||||
|
{
|
||||||
|
public static final DhLogger LOGGER = new DhLoggerBuilder()
|
||||||
|
.name("LOD World Gen - Internal Server")
|
||||||
|
.fileLevelConfig(Config.Common.Logging.logWorldGenEventToFile)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
public static final DhLogger CHUNK_LOAD_LOGGER = new DhLoggerBuilder()
|
||||||
|
.name("LOD Chunk Loading")
|
||||||
|
.fileLevelConfig(Config.Common.Logging.logWorldGenChunkLoadEventToFile)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
private static final IC2meAccessor C2ME_ACCESSOR = ModAccessorInjector.INSTANCE.get(IC2meAccessor.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to revert the ignore logic in {@link SharedApi} so
|
||||||
|
* that given chunk pos can be handled again.
|
||||||
|
* A timer is used so we don't have to inject into MC's code and it works sell enough
|
||||||
|
* most of the time.
|
||||||
|
* If a chunk does get through due the timeout not being long enough that isn't the end of the world.
|
||||||
|
*/
|
||||||
|
private static final int MS_TO_IGNORE_CHUNK_AFTER_COMPLETION = 5_000;
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_21_5
|
||||||
|
private static final TicketType<ChunkPos> DH_SERVER_GEN_TICKET = TicketType.create("dh_server_gen_ticket", Comparator.comparingLong(ChunkPos::toLong));
|
||||||
|
#elif MC_VER < MC_1_21_9
|
||||||
|
private static final TicketType DH_SERVER_GEN_TICKET = new TicketType(/* timeout, 0 = disabled*/0L, /* persist */ false, TicketType.TicketUse.LOADING);
|
||||||
|
#else
|
||||||
|
private static final TicketType DH_SERVER_GEN_TICKET = new TicketType(/* timeout, 0 = disabled*/0L, /* flags */TicketType.FLAG_LOADING);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private static boolean c2meMissingWarningLogged = false;
|
||||||
|
|
||||||
|
|
||||||
|
private final GlobalWorldGenParams params;
|
||||||
|
private final IDhServerLevel dhServerLevel;
|
||||||
|
private final Timer chunkSaveIgnoreTimer = TimerUtil.CreateTimer("ChunkSaveIgnoreTimer");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
|
||||||
|
public InternalServerGenerator(GlobalWorldGenParams params, IDhServerLevel dhServerLevel)
|
||||||
|
{
|
||||||
|
this.params = params;
|
||||||
|
this.dhServerLevel = dhServerLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//============//
|
||||||
|
// generation //
|
||||||
|
//============//
|
||||||
|
|
||||||
|
public void generateChunksViaInternalServer(GenerationEvent genEvent)
|
||||||
|
{
|
||||||
|
this.runValidation();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//=====================//
|
||||||
|
// create gen requests //
|
||||||
|
//=====================//
|
||||||
|
|
||||||
|
ArrayList<CompletableFuture<ChunkAccess>> getChunkFutureList = new ArrayList<>();
|
||||||
|
{
|
||||||
|
Iterator<ChunkPos> chunkPosIterator = ChunkPosGenStream.getIterator(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.widthInChunks, 0);
|
||||||
|
while (chunkPosIterator.hasNext())
|
||||||
|
{
|
||||||
|
ChunkPos chunkPos = chunkPosIterator.next();
|
||||||
|
|
||||||
|
CompletableFuture<ChunkAccess> requestChunkFuture =
|
||||||
|
this.requestChunkFromServerAsync(chunkPos)
|
||||||
|
// log errors if necessary
|
||||||
|
.whenCompleteAsync(
|
||||||
|
(chunk, throwable) ->
|
||||||
|
{
|
||||||
|
// unwrap the CompletionException if necessary
|
||||||
|
Throwable actualThrowable = throwable;
|
||||||
|
while (actualThrowable instanceof CompletionException)
|
||||||
|
{
|
||||||
|
actualThrowable = actualThrowable.getCause();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actualThrowable != null)
|
||||||
|
{
|
||||||
|
// ignore expected shutdown exceptions
|
||||||
|
boolean isShutdownException =
|
||||||
|
ExceptionUtil.isShutdownException(actualThrowable)
|
||||||
|
|| actualThrowable.getMessage().contains("Unloaded chunk");
|
||||||
|
if (!isShutdownException)
|
||||||
|
{
|
||||||
|
CHUNK_LOAD_LOGGER.warn("DistantHorizons: Couldn't load chunk [" + chunkPos + "] from server, error: [" + actualThrowable.getMessage() + "].", actualThrowable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
getChunkFutureList.add(requestChunkFuture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==============================//
|
||||||
|
// wait for generation requests //
|
||||||
|
//==============================//
|
||||||
|
|
||||||
|
// Join-ing each thread will prevent DH from working on anything else
|
||||||
|
// but will also prevent over-queuing world gen tasks.
|
||||||
|
// If C2ME is present the CPU will still be well utilized.
|
||||||
|
|
||||||
|
ArrayList<IChunkWrapper> chunkWrappers = new ArrayList<>();
|
||||||
|
for (int i = 0; i < getChunkFutureList.size(); i++)
|
||||||
|
{
|
||||||
|
CompletableFuture<ChunkAccess> getChunkFuture = getChunkFutureList.get(i);
|
||||||
|
ChunkAccess chunk = getChunkFuture.join();
|
||||||
|
if (chunk != null)
|
||||||
|
{
|
||||||
|
ChunkWrapper chunkWrapper = new ChunkWrapper(chunk, this.dhServerLevel.getLevelWrapper());
|
||||||
|
chunkWrappers.add(chunkWrapper);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==========================//
|
||||||
|
// process generated chunks //
|
||||||
|
//==========================//
|
||||||
|
|
||||||
|
int maxSkyLight = this.dhServerLevel.getServerLevelWrapper().hasSkyLight() ? LodUtil.MAX_MC_LIGHT : LodUtil.MIN_MC_LIGHT;
|
||||||
|
for (int i = 0; i < chunkWrappers.size(); i++)
|
||||||
|
{
|
||||||
|
ChunkWrapper chunkWrapper = (ChunkWrapper)chunkWrappers.get(i);
|
||||||
|
|
||||||
|
// pre-generated chunks should have lighting but new ones won't
|
||||||
|
if (!chunkWrapper.isDhBlockLightingCorrect())
|
||||||
|
{
|
||||||
|
DhLightingEngine.INSTANCE.bakeChunkBlockLighting(chunkWrapper, chunkWrappers, maxSkyLight);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dhServerLevel.updateBeaconBeamsForChunk(chunkWrapper, chunkWrappers);
|
||||||
|
genEvent.resultConsumer.accept(chunkWrapper);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// release all chunks from the server to prevent out of memory issues
|
||||||
|
Iterator<ChunkPos> chunkPosIterator = ChunkPosGenStream.getIterator(genEvent.minPos.getX(), genEvent.minPos.getZ(), genEvent.widthInChunks, 0);
|
||||||
|
while (chunkPosIterator.hasNext())
|
||||||
|
{
|
||||||
|
ChunkPos chunkPos = chunkPosIterator.next();
|
||||||
|
this.releaseChunkFromServer(this.params.mcServerLevel, chunkPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void runValidation()
|
||||||
|
{
|
||||||
|
// DH thread check
|
||||||
|
if (!DhApi.isDhThread()
|
||||||
|
&& ModInfo.IS_DEV_BUILD)
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("Internal server generation should be called from one of DH's world gen thread. Current thread: ["+Thread.currentThread().getName()+"]");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// C2ME present?
|
||||||
|
if (C2ME_ACCESSOR == null
|
||||||
|
&& !c2meMissingWarningLogged)
|
||||||
|
{
|
||||||
|
c2meMissingWarningLogged = true;
|
||||||
|
|
||||||
|
String c2meWarning = "C2ME missing, \n" +
|
||||||
|
"low CPU usage and slow world gen speeds expected. \n" +
|
||||||
|
"DH is set to use MC's internal server for world gen \n" +
|
||||||
|
"this mode is less efficient unless a mod like C2ME is present."
|
||||||
|
;
|
||||||
|
|
||||||
|
if (Config.Common.Logging.Warning.showSlowWorldGenSettingWarnings.get())
|
||||||
|
{
|
||||||
|
String message =
|
||||||
|
// orange text
|
||||||
|
"\u00A76" + "Distant Horizons: slow world gen." + "\u00A7r\n" +
|
||||||
|
c2meWarning;
|
||||||
|
ClientApi.INSTANCE.showChatMessageNextFrame(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGGER.warn(c2meWarning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private CompletableFuture<ChunkAccess> requestChunkFromServerAsync(ChunkPos chunkPos)
|
||||||
|
{
|
||||||
|
return CompletableFuture.supplyAsync(() ->
|
||||||
|
{
|
||||||
|
ServerLevel level = this.params.mcServerLevel;
|
||||||
|
|
||||||
|
// ignore chunk update events for this position
|
||||||
|
SharedApi.CHUNK_UPDATE_QUEUE_MANAGER.addPosToIgnore(new DhChunkPos(chunkPos.x, chunkPos.z));
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_21_5
|
||||||
|
int chunkLevel = 33; // 33 is equivalent to FULL Chunk
|
||||||
|
level.getChunkSource().distanceManager.addTicket(DH_SERVER_GEN_TICKET, chunkPos, chunkLevel, chunkPos);
|
||||||
|
#else
|
||||||
|
level.getChunkSource().addTicketWithRadius(DH_SERVER_GEN_TICKET, chunkPos, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// probably not the most optimal to run updates here, but fast enough
|
||||||
|
level.getChunkSource().distanceManager.runAllUpdates(level.getChunkSource().chunkMap);
|
||||||
|
|
||||||
|
ChunkHolder chunkHolder = level.getChunkSource().chunkMap.getUpdatingChunkIfPresent(chunkPos.toLong());
|
||||||
|
if (chunkHolder == null)
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("No chunk chunkHolder for pos ["+chunkPos+"] after ticket has been added.");
|
||||||
|
}
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_20_4
|
||||||
|
return chunkHolder.getOrScheduleFuture(ChunkStatus.FEATURES, level.getChunkSource().chunkMap)
|
||||||
|
.thenApply(result -> result.left().orElseThrow(() -> new RuntimeException(result.right().get().toString()))); // can throw if the server is shutting down
|
||||||
|
#elif MC_VER <= MC_1_20_6
|
||||||
|
return chunkHolder.getOrScheduleFuture(ChunkStatus.FEATURES, level.getChunkSource().chunkMap)
|
||||||
|
.thenApply(result -> result.orElseThrow(() -> new RuntimeException(result.toString()))); // can throw if the server is shutting down
|
||||||
|
#else
|
||||||
|
return chunkHolder.scheduleChunkGenerationTask(ChunkStatus.FEATURES, level.getChunkSource().chunkMap)
|
||||||
|
.thenApply(result -> result.orElseThrow(() -> new RuntimeException(result.getError()))); // can throw if the server is shutting down
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}, this.params.mcServerLevel.getChunkSource().chunkMap.mainThreadExecutor)
|
||||||
|
.thenCompose(Function.identity());
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* mitigates out of memory issues in the vanilla chunk system. <br>
|
||||||
|
* See: https://github.com/pop4959/Chunky/pull/383
|
||||||
|
*/
|
||||||
|
private void releaseChunkFromServer(ServerLevel level, ChunkPos chunkPos)
|
||||||
|
{
|
||||||
|
level.getChunkSource().chunkMap.mainThreadExecutor.execute(() ->
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
#if MC_VER < MC_1_21_5
|
||||||
|
int chunkLevel = 33; // 33 is equivalent to FULL Chunk
|
||||||
|
level.getChunkSource().distanceManager.removeTicket(DH_SERVER_GEN_TICKET, chunkPos, chunkLevel, chunkPos);
|
||||||
|
#else
|
||||||
|
level.getChunkSource().removeTicketWithRadius(DH_SERVER_GEN_TICKET, chunkPos, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
level.getChunkSource().chunkMap.tick(() -> false);
|
||||||
|
|
||||||
|
#if MC_VER > MC_1_16_5
|
||||||
|
level.entityManager.tick();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// give MC a few seconds to save the chunk before
|
||||||
|
// we can process update events there again
|
||||||
|
this.chunkSaveIgnoreTimer.schedule(new TimerTask()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void run() { SharedApi.CHUNK_UPDATE_QUEUE_MANAGER.removePosToIgnore(new DhChunkPos(chunkPos.x, chunkPos.z)); }
|
||||||
|
}, MS_TO_IGNORE_CHUNK_AFTER_COMPLETION);
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
LOGGER.warn("Failed to release chunk back to internal server. Error: ["+e.getMessage()+"]", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
-109
@@ -1,109 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of the Distant Horizons mod
|
|
||||||
* licensed under the GNU LGPL v3 License.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2020 James Seibel
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration;
|
|
||||||
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment.PerfCalculator;
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.WorldGenStructFeatManager;
|
|
||||||
|
|
||||||
import net.minecraft.server.level.ServerLevel;
|
|
||||||
import net.minecraft.world.level.WorldGenLevel;
|
|
||||||
#if MC_VER >= MC_1_18_2
|
|
||||||
import net.minecraft.world.level.levelgen.structure.StructureCheck;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
public final class ThreadedParameters
|
|
||||||
{
|
|
||||||
private static final ThreadLocal<ThreadedParameters> LOCAL_PARAM = new ThreadLocal<>();
|
|
||||||
|
|
||||||
final ServerLevel level;
|
|
||||||
public WorldGenStructFeatManager structFeat = null;
|
|
||||||
#if MC_VER >= MC_1_18_2
|
|
||||||
public StructureCheck structCheck;
|
|
||||||
#endif
|
|
||||||
boolean isValid = true;
|
|
||||||
public final PerfCalculator perf = new PerfCalculator();
|
|
||||||
|
|
||||||
private static GlobalParameters previousGlobalParameters = null;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static ThreadedParameters getOrMake(GlobalParameters param)
|
|
||||||
{
|
|
||||||
ThreadedParameters tParam = LOCAL_PARAM.get();
|
|
||||||
if (tParam != null && tParam.isValid && tParam.level == param.level)
|
|
||||||
{
|
|
||||||
return tParam;
|
|
||||||
}
|
|
||||||
|
|
||||||
tParam = new ThreadedParameters(param);
|
|
||||||
LOCAL_PARAM.set(tParam);
|
|
||||||
return tParam;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ThreadedParameters(GlobalParameters param)
|
|
||||||
{
|
|
||||||
previousGlobalParameters = param;
|
|
||||||
|
|
||||||
this.level = param.level;
|
|
||||||
#if MC_VER < MC_1_18_2
|
|
||||||
this.structFeat = new WorldGenStructFeatManager(param.worldGenSettings, level);
|
|
||||||
#elif MC_VER < MC_1_19_2
|
|
||||||
this.structCheck = this.createStructureCheck(param);
|
|
||||||
#else
|
|
||||||
this.structCheck = new StructureCheck(param.chunkScanner, param.registry, param.structures,
|
|
||||||
param.level.dimension(), param.generator, param.randomState, level, param.generator.getBiomeSource(), param.worldSeed,
|
|
||||||
param.fixerUpper);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void markAsInvalid() { isValid = false; }
|
|
||||||
|
|
||||||
public void makeStructFeat(WorldGenLevel genLevel, GlobalParameters param)
|
|
||||||
{
|
|
||||||
#if MC_VER < MC_1_19_4
|
|
||||||
structFeat = new WorldGenStructFeatManager(param.worldGenSettings, genLevel #if MC_VER >= MC_1_18_2 , structCheck #endif );
|
|
||||||
#else
|
|
||||||
structFeat = new WorldGenStructFeatManager(param.worldOptions, genLevel, structCheck);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#if MC_VER >= MC_1_18_2 && MC_VER < MC_1_19_2
|
|
||||||
public void recreateStructureCheck()
|
|
||||||
{
|
|
||||||
if (previousGlobalParameters != null)
|
|
||||||
{
|
|
||||||
this.structCheck = createStructureCheck(previousGlobalParameters);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private StructureCheck createStructureCheck(GlobalParameters param)
|
|
||||||
{
|
|
||||||
return new StructureCheck(param.chunkScanner, param.registry, param.structures,
|
|
||||||
param.level.dimension(), param.generator, this.level, param.generator.getBiomeSource(), param.worldSeed,
|
|
||||||
param.fixerUpper);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
public void recreateStructureCheck() { /* do nothing */ }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
+744
@@ -0,0 +1,744 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU GPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.common.wrappers.worldGeneration.chunkFileHandling;
|
||||||
|
|
||||||
|
import com.mojang.serialization.Codec;
|
||||||
|
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;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.ChunkLightStorage;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
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;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.nbt.ListTag;
|
||||||
|
import net.minecraft.nbt.NbtOps;
|
||||||
|
import net.minecraft.nbt.Tag;
|
||||||
|
import net.minecraft.world.level.*;
|
||||||
|
import net.minecraft.world.level.biome.Biome;
|
||||||
|
import net.minecraft.world.level.biome.Biomes;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.chunk.*;
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_21_3
|
||||||
|
import net.minecraft.world.level.chunk.storage.ChunkSerializer;
|
||||||
|
#else
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_21_9
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
#else
|
||||||
|
#endif
|
||||||
|
|
||||||
|
import net.minecraft.world.level.levelgen.Heightmap;
|
||||||
|
#if MC_VER >= MC_1_18_2
|
||||||
|
#if MC_VER < MC_1_19_2
|
||||||
|
import net.minecraft.world.level.levelgen.feature.StructureFeature;
|
||||||
|
#endif
|
||||||
|
import net.minecraft.world.ticks.LevelChunkTicks;
|
||||||
|
#endif
|
||||||
|
#if MC_VER >= MC_1_18_2
|
||||||
|
import net.minecraft.core.Holder;
|
||||||
|
#if MC_VER < MC_1_19_2
|
||||||
|
import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||||
|
import net.minecraft.world.level.material.Fluids;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MC_VER == MC_1_20_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;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
import net.minecraft.world.level.material.Fluid;
|
||||||
|
|
||||||
|
|
||||||
|
public class ChunkCompoundTagParser
|
||||||
|
{
|
||||||
|
public static final DhLogger LOGGER = new DhLoggerBuilder()
|
||||||
|
.name("LOD Chunk Reader")
|
||||||
|
.fileLevelConfig(Config.Common.Logging.logWorldGenChunkLoadEventToFile)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
private static final AtomicBoolean ZERO_CHUNK_POS_ERROR_LOGGED_REF = new AtomicBoolean(false);
|
||||||
|
private static final ConcurrentHashMap<String, Object> LOGGED_ERROR_MESSAGE_MAP = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
private static boolean lightingSectionErrorLogged = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//============//
|
||||||
|
// read chunk //
|
||||||
|
//============//
|
||||||
|
|
||||||
|
public static ChunkWrapper createFromTag(
|
||||||
|
WorldGenLevel mcWorldGenLevel, IDhServerLevel dhServerLevel,
|
||||||
|
ChunkPos chunkPos, CompoundTag chunkData)
|
||||||
|
{
|
||||||
|
#if MC_VER < MC_1_18_2
|
||||||
|
CompoundTag tagLevel = chunkData.getCompound("Level");
|
||||||
|
#else
|
||||||
|
CompoundTag tagLevel = chunkData;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=======================//
|
||||||
|
// validate the chunkPos //
|
||||||
|
//=======================//
|
||||||
|
|
||||||
|
int chunkX = CompoundTagUtil.getInt(tagLevel,"xPos");
|
||||||
|
int chunkZ = CompoundTagUtil.getInt(tagLevel, "zPos");
|
||||||
|
ChunkPos actualChunkPos = new ChunkPos(chunkX, chunkZ);
|
||||||
|
|
||||||
|
// confirm chunk pos is correct
|
||||||
|
if (!Objects.equals(chunkPos, actualChunkPos))
|
||||||
|
{
|
||||||
|
if (chunkX == 0 && chunkZ == 0)
|
||||||
|
{
|
||||||
|
if (!ZERO_CHUNK_POS_ERROR_LOGGED_REF.getAndSet(true))
|
||||||
|
{
|
||||||
|
// explicit chunkPos toString is necessary otherwise the JDK 17 compiler breaks
|
||||||
|
LOGGER.warn("Chunk file at ["+chunkPos.toString()+"] doesn't have a chunk pos. \n" +
|
||||||
|
"This might happen if the world was created using an external program. \n" +
|
||||||
|
"DH will attempt to parse the chunk anyway and won't log this message again.\n" +
|
||||||
|
"If issues arise please try optimizing your world to fix this issue. \n" +
|
||||||
|
"World optimization can be done from the singleplayer world selection screen." +
|
||||||
|
" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOGGER.error("Chunk file at ["+chunkPos.toString()+"] is in the wrong location. \n" +
|
||||||
|
"Please try optimizing your world to fix this issue. \n" +
|
||||||
|
"World optimization can be done from the singleplayer world selection screen. \n" +
|
||||||
|
"(Expected pos: ["+chunkPos.toString()+"], actual ["+actualChunkPos.toString()+"])" +
|
||||||
|
" ");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//===========//
|
||||||
|
// get ticks //
|
||||||
|
//===========//
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_18_2
|
||||||
|
ChunkBiomeContainer chunkBiomeContainer = new ChunkBiomeContainer(
|
||||||
|
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 , 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 , mcWorldGenLevel #endif );
|
||||||
|
#else
|
||||||
|
// ticks shouldn't be needed so ignore them for MC versions after 1.18.2
|
||||||
|
LevelChunkTicks<Block> blockTicks = new LevelChunkTicks<>();
|
||||||
|
LevelChunkTicks<Fluid> fluidTicks = new LevelChunkTicks<>();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=====================//
|
||||||
|
// get misc properties //
|
||||||
|
//=====================//
|
||||||
|
|
||||||
|
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);
|
||||||
|
if (!hasBlocks)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
long inhabitedTime = CompoundTagUtil.getLong(tagLevel, "InhabitedTime");
|
||||||
|
boolean isLightOn = CompoundTagUtil.getBoolean(tagLevel, "isLightOn");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//============//
|
||||||
|
// make chunk //
|
||||||
|
//============//
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_18_2
|
||||||
|
LevelChunk chunk = new LevelChunk((Level) mcWorldGenLevel.getLevel(), chunkPos, chunkBiomeContainer, UpgradeData.EMPTY, blockTicks,
|
||||||
|
fluidTicks, inhabitedTime, chunkSections, null);
|
||||||
|
#else
|
||||||
|
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);
|
||||||
|
boolean hasHeightmapData = readHeightmaps(chunk, chunkData);
|
||||||
|
|
||||||
|
// chunk wrapper so we can pass along extra data more easily
|
||||||
|
ChunkWrapper chunkWrapper = new ChunkWrapper(chunk, dhServerLevel.getServerLevelWrapper(), !hasHeightmapData);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//===========================//
|
||||||
|
// check if chunk has blocks //
|
||||||
|
//===========================//
|
||||||
|
|
||||||
|
// in some MC versions all the NBT data will be there
|
||||||
|
// but the chunk will be totally empty,
|
||||||
|
// usually this means the chunk was only partially generated.
|
||||||
|
// If that happens we should try to generate the chunk from scratch
|
||||||
|
// otherwise we can end up with large empty holes in the world.
|
||||||
|
|
||||||
|
// walking through the heightmap (recreated by DH if missing)
|
||||||
|
// is a fast way to check if there are any blocks in the chunk
|
||||||
|
boolean chunkHasBlocks = false;
|
||||||
|
int serverMinHeight = dhServerLevel.getServerLevelWrapper().getMinHeight();
|
||||||
|
for (int x = 0; x < 16 && !chunkHasBlocks; x++)
|
||||||
|
{
|
||||||
|
for (int z = 0; z < 16 && !chunkHasBlocks; z++)
|
||||||
|
{
|
||||||
|
int heightMap = Math.max(
|
||||||
|
// max between both heightmaps just in case there's a discrepancy
|
||||||
|
chunkWrapper.getLightBlockingHeightMapValue(x, z),
|
||||||
|
chunkWrapper.getSolidHeightMapValue(x, z)
|
||||||
|
);
|
||||||
|
if (heightMap != serverMinHeight)
|
||||||
|
{
|
||||||
|
chunkHasBlocks = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (chunkHasBlocks)
|
||||||
|
{
|
||||||
|
return chunkWrapper;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// no blocks detected, this chunk should be generated from scratch
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=================//
|
||||||
|
// chunk sections //
|
||||||
|
// (Blocks/biomes) //
|
||||||
|
//=================//
|
||||||
|
|
||||||
|
/** handles both blocks and biomes */
|
||||||
|
private static boolean readAndPopulateSections(
|
||||||
|
LevelAccessor level, ChunkPos chunkPos, CompoundTag chunkData,
|
||||||
|
LevelChunkSection[] chunkSections)
|
||||||
|
{
|
||||||
|
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
|
||||||
|
if (tagSections == null
|
||||||
|
|| tagSections.isEmpty())
|
||||||
|
{
|
||||||
|
tagSections = CompoundTagUtil.getListTag(chunkData, "sections", 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
boolean blocksFound = false;
|
||||||
|
if (tagSections != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < tagSections.size(); ++i)
|
||||||
|
{
|
||||||
|
CompoundTag tagSection = CompoundTagUtil.getCompoundTag(tagSections, i);
|
||||||
|
if (tagSection == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int sectionYPos = CompoundTagUtil.getByte(tagSection, "Y");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//===================//
|
||||||
|
// get blocks/biomes //
|
||||||
|
//===================//
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_18_2
|
||||||
|
if (tagSection.contains("Palette", 9)
|
||||||
|
&& tagSection.contains("BlockStates", 12))
|
||||||
|
{
|
||||||
|
LevelChunkSection levelChunkSection = new LevelChunkSection(sectionYPos << 4);
|
||||||
|
levelChunkSection.getStates().read(tagSection.getList("Palette", 10), tagSection.getLongArray("BlockStates"));
|
||||||
|
levelChunkSection.recalcBlockCounts();
|
||||||
|
if (!levelChunkSection.isEmpty())
|
||||||
|
{
|
||||||
|
int sectionIndex;
|
||||||
|
#if MC_VER < MC_1_17_1
|
||||||
|
sectionIndex = sectionYPos;
|
||||||
|
#else
|
||||||
|
sectionIndex = level.getSectionIndexFromSectionY(sectionYPos);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
chunkSections[sectionIndex] = levelChunkSection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
int sectionId = level.getSectionIndexFromSectionY(sectionYPos);
|
||||||
|
if (sectionId >= 0
|
||||||
|
&& sectionId < chunkSections.length)
|
||||||
|
{
|
||||||
|
//========//
|
||||||
|
// blocks //
|
||||||
|
//========//
|
||||||
|
|
||||||
|
PalettedContainer<BlockState> blockStateContainer;
|
||||||
|
|
||||||
|
boolean containsBlockStates = CompoundTagUtil.contains(tagSection, "block_states", 10);
|
||||||
|
if (containsBlockStates)
|
||||||
|
{
|
||||||
|
Codec<PalettedContainer<BlockState>> blockStateCodec = getBlockStateCodec(level);
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_20_6
|
||||||
|
blockStateContainer = blockStateCodec
|
||||||
|
.parse(NbtOps.INSTANCE, CompoundTagUtil.getCompoundTag(tagSection, "block_states"))
|
||||||
|
.promotePartial(string -> logBlockDeserializationWarning(chunkPos, sectionYPos, string))
|
||||||
|
.getOrThrow(false, (message) -> logParsingWarningOnce(message));
|
||||||
|
#else
|
||||||
|
blockStateContainer = blockStateCodec
|
||||||
|
.parse(NbtOps.INSTANCE, CompoundTagUtil.getCompoundTag(tagSection, "block_states"))
|
||||||
|
.promotePartial(string -> logBlockDeserializationWarning(chunkPos, sectionYPos, string))
|
||||||
|
.getOrThrow((message) -> logErrorAndReturnException(message));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
blocksFound = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#if MC_VER < MC_1_21_9
|
||||||
|
blockStateContainer = new PalettedContainer<BlockState>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);
|
||||||
|
#else
|
||||||
|
blockStateContainer = PalettedContainerFactory.create(level.registryAccess()).createForBlockStates();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//========//
|
||||||
|
// biomes //
|
||||||
|
//========//
|
||||||
|
|
||||||
|
Registry<Biome> biomeRegistry = getBiomeRegistry(level);
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_19_2
|
||||||
|
Codec<PalettedContainer<Biome>> biomeCodec;
|
||||||
|
#else
|
||||||
|
Codec<PalettedContainer<Holder<Biome>>> biomeCodec;
|
||||||
|
#endif
|
||||||
|
biomeCodec = getBiomeCodec(level, biomeRegistry);
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_18_2
|
||||||
|
PalettedContainer<Biome> biomeContainer;
|
||||||
|
#else
|
||||||
|
PalettedContainer<Holder<Biome>> biomeContainer;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_18_2
|
||||||
|
biomeContainer = tagSection.contains("biomeRegistry", 10)
|
||||||
|
? biomeCodec.parse(NbtOps.INSTANCE, tagSection.getCompound("biomeRegistry")).promotePartial(string -> logErrors(chunkPos, sectionYPos, string)).getOrThrow(false, (message) -> logWarningOnce(message))
|
||||||
|
: new PalettedContainer<Biome>(biomeRegistry, biomeRegistry.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
CompoundTag biomeTag = CompoundTagUtil.getCompoundTag(tagSection, "biomeRegistry");
|
||||||
|
if (biomeTag == null)
|
||||||
|
{
|
||||||
|
biomeTag = CompoundTagUtil.getCompoundTag(tagSection, "biomes");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (biomeTag != null
|
||||||
|
&& !biomeTag.isEmpty())
|
||||||
|
{
|
||||||
|
#if MC_VER < MC_1_20_6
|
||||||
|
biomeContainer = new PalettedContainer<Holder<Biome>>(
|
||||||
|
biomeRegistry.asHolderIdMap(),
|
||||||
|
biomeRegistry.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
|
||||||
|
#else
|
||||||
|
biomeContainer = biomeCodec.parse(NbtOps.INSTANCE, biomeTag)
|
||||||
|
.promotePartial(string -> logBiomeDeserializationWarning(chunkPos, sectionYCount, (String) string))
|
||||||
|
.getOrThrow((message) -> logErrorAndReturnException(message));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// no biomes found, use the default (probably plains)
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_21_3
|
||||||
|
biomeContainer = new PalettedContainer<Holder<Biome>>(
|
||||||
|
biomeRegistry.asHolderIdMap(),
|
||||||
|
biomeRegistry.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
|
||||||
|
#elif MC_VER < MC_1_21_9
|
||||||
|
biomeContainer = new PalettedContainer<Holder<Biome>>(biomeRegistry.asHolderIdMap(),
|
||||||
|
biomeRegistry.getOrThrow(Biomes.PLAINS),
|
||||||
|
PalettedContainer.Strategy.SECTION_BIOMES);
|
||||||
|
#else
|
||||||
|
biomeContainer = PalettedContainerFactory.create(level.registryAccess()).createForBiomes();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_20_1
|
||||||
|
chunkSections[sectionId] = new LevelChunkSection(sectionYPos, blockStateContainer, biomeContainer);
|
||||||
|
#else
|
||||||
|
chunkSections[sectionId] = new LevelChunkSection(blockStateContainer, biomeContainer);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return blocksFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Codec<PalettedContainer<BlockState>> getBlockStateCodec(LevelAccessor level)
|
||||||
|
{
|
||||||
|
#if MC_VER < MC_1_18_2
|
||||||
|
return null; // unused for older MC versions
|
||||||
|
#elif MC_VER < MC_1_19_2
|
||||||
|
return PalettedContainer.codec(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState());
|
||||||
|
#elif MC_VER <= MC_1_21_8
|
||||||
|
return PalettedContainer.codecRW(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState());
|
||||||
|
#else
|
||||||
|
return PalettedContainerFactory.create(level.registryAccess()).blockStatesContainerCodec();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Registry<Biome> getBiomeRegistry(LevelAccessor level)
|
||||||
|
{
|
||||||
|
#if MC_VER < MC_1_18_2
|
||||||
|
// not needed
|
||||||
|
return null;
|
||||||
|
#elif MC_VER < MC_1_19_4
|
||||||
|
return level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY);
|
||||||
|
#elif MC_VER < MC_1_21_3
|
||||||
|
return level.registryAccess().registryOrThrow(Registries.BIOME);
|
||||||
|
#else
|
||||||
|
return level.registryAccess().lookupOrThrow(Registries.BIOME);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
private static
|
||||||
|
#if MC_VER < MC_1_19_2 Codec<PalettedContainer<Biome>>
|
||||||
|
#else Codec<PalettedContainer<Holder<Biome>>>
|
||||||
|
#endif
|
||||||
|
getBiomeCodec(LevelAccessor level, Registry<Biome> biomeRegistry)
|
||||||
|
{
|
||||||
|
#if MC_VER < MC_1_18_2
|
||||||
|
return null; // unused for older MC versions
|
||||||
|
#elif MC_VER < MC_1_19_2
|
||||||
|
return PalettedContainer.codec(
|
||||||
|
biomeRegistry, biomeRegistry.byNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomeRegistry.getOrThrow(Biomes.PLAINS));
|
||||||
|
#elif MC_VER < MC_1_19_2
|
||||||
|
return PalettedContainer.codec(
|
||||||
|
biomeRegistry.asHolderIdMap(), biomeRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomeRegistry.getHolderOrThrow(Biomes.PLAINS));
|
||||||
|
#elif MC_VER < MC_1_21_3
|
||||||
|
return PalettedContainer.codecRW(
|
||||||
|
biomeRegistry.asHolderIdMap(), biomeRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomeRegistry.getHolderOrThrow(Biomes.PLAINS));
|
||||||
|
#elif MC_VER < MC_1_21_9
|
||||||
|
return PalettedContainer.codecRW(
|
||||||
|
biomeRegistry.asHolderIdMap(), biomeRegistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomeRegistry.getOrThrow(Biomes.PLAINS));
|
||||||
|
#else
|
||||||
|
return PalettedContainer.codecRW(
|
||||||
|
biomeRegistry.holderByNameCodec(), PalettedContainerFactory.create(level.registryAccess()).biomeStrategy(), biomeRegistry.getOrThrow(Biomes.PLAINS));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//============//
|
||||||
|
// heightmaps //
|
||||||
|
//============//
|
||||||
|
|
||||||
|
private static boolean readHeightmaps(LevelChunk chunk, CompoundTag chunkData)
|
||||||
|
{
|
||||||
|
CompoundTag tagHeightmaps = CompoundTagUtil.getCompoundTag(chunkData, "Heightmaps");
|
||||||
|
if (tagHeightmaps == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (Heightmap.Types type : ChunkStatus.FULL.heightmapsAfter())
|
||||||
|
{
|
||||||
|
String heightmapKey = type.getSerializationKey();
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_21_5
|
||||||
|
if (tagHeightmaps.contains(heightmapKey, 12))
|
||||||
|
{
|
||||||
|
chunk.setHeightmap(type, tagHeightmaps.getLongArray(heightmapKey));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (tagHeightmaps.contains(heightmapKey))
|
||||||
|
{
|
||||||
|
Optional<long[]> optionalHeightmap = tagHeightmaps.getLongArray(heightmapKey);
|
||||||
|
if (optionalHeightmap.isPresent())
|
||||||
|
{
|
||||||
|
chunk.setHeightmap(type, optionalHeightmap.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
Heightmap.primeHeightmaps(chunk, ChunkStatus.FULL.heightmapsAfter());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// chunk lighting //
|
||||||
|
//================//
|
||||||
|
|
||||||
|
/** source: https://minecraft.wiki/w/Chunk_format */
|
||||||
|
public static CombinedChunkLightStorage readLight(ChunkAccess chunk, CompoundTag chunkData)
|
||||||
|
{
|
||||||
|
#if MC_VER <= MC_1_17_1
|
||||||
|
// MC 1.16 and 1.17 doesn't have the necessary NBT info
|
||||||
|
return null;
|
||||||
|
#else
|
||||||
|
|
||||||
|
CombinedChunkLightStorage combinedStorage = new CombinedChunkLightStorage(ChunkWrapper.getInclusiveMinBuildHeight(chunk), ChunkWrapper.getExclusiveMaxBuildHeight(chunk));
|
||||||
|
ChunkLightStorage blockLightStorage = combinedStorage.blockLightStorage;
|
||||||
|
ChunkLightStorage skyLightStorage = combinedStorage.skyLightStorage;
|
||||||
|
|
||||||
|
boolean foundSkyLight = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//===================//
|
||||||
|
// get NBT tags info //
|
||||||
|
//===================//
|
||||||
|
|
||||||
|
Tag chunkSectionTags = chunkData.get("sections");
|
||||||
|
if (chunkSectionTags == null)
|
||||||
|
{
|
||||||
|
if (!lightingSectionErrorLogged)
|
||||||
|
{
|
||||||
|
lightingSectionErrorLogged = true;
|
||||||
|
LOGGER.error("No sections found for chunk at pos ["+chunk.getPos()+"] chunk data may be out of date.");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else if (!(chunkSectionTags instanceof ListTag))
|
||||||
|
{
|
||||||
|
if (!lightingSectionErrorLogged)
|
||||||
|
{
|
||||||
|
lightingSectionErrorLogged = true;
|
||||||
|
LOGGER.error("Chunk section tag list have unexpected type ["+chunkSectionTags.getClass().getName()+"], expected ["+ListTag.class.getName()+"].");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ListTag chunkSectionListTag = (ListTag) chunkSectionTags;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//===================//
|
||||||
|
// get lighting info //
|
||||||
|
//===================//
|
||||||
|
|
||||||
|
for (int sectionIndex = 0; sectionIndex < chunkSectionListTag.size(); sectionIndex++)
|
||||||
|
{
|
||||||
|
Tag chunkSectionTag = chunkSectionListTag.get(sectionIndex);
|
||||||
|
if (!(chunkSectionTag instanceof CompoundTag))
|
||||||
|
{
|
||||||
|
if (!lightingSectionErrorLogged)
|
||||||
|
{
|
||||||
|
lightingSectionErrorLogged = true;
|
||||||
|
LOGGER.error("Chunk section tag has an unexpected type ["+chunkSectionTag.getClass().getName()+"], expected ["+CompoundTag.class.getName()+"].");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
CompoundTag chunkSectionCompoundTag = (CompoundTag) chunkSectionTag;
|
||||||
|
|
||||||
|
|
||||||
|
// if null all lights = 0
|
||||||
|
byte[] blockLightNibbleArray = CompoundTagUtil.getByteArray(chunkSectionCompoundTag, "BlockLight");
|
||||||
|
byte[] skyLightNibbleArray = CompoundTagUtil.getByteArray(chunkSectionCompoundTag, "SkyLight");
|
||||||
|
|
||||||
|
if (blockLightNibbleArray != null
|
||||||
|
&& skyLightNibbleArray != null)
|
||||||
|
{
|
||||||
|
// if any sky light was found then all lights above will be max brightness
|
||||||
|
if (skyLightNibbleArray.length != 0)
|
||||||
|
{
|
||||||
|
foundSkyLight = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int relX = 0; relX < LodUtil.CHUNK_WIDTH; relX++)
|
||||||
|
{
|
||||||
|
for (int relZ = 0; relZ < LodUtil.CHUNK_WIDTH; relZ++)
|
||||||
|
{
|
||||||
|
// chunk sections are also 16 blocks tall
|
||||||
|
for (int relY = 0; relY < LodUtil.CHUNK_WIDTH; relY++)
|
||||||
|
{
|
||||||
|
int blockPosIndex = relY*16*16 + relZ*16 + relX;
|
||||||
|
byte blockLight = (blockLightNibbleArray.length == 0) ? 0 : getNibbleAtIndex(blockLightNibbleArray, blockPosIndex);
|
||||||
|
byte skyLight = (skyLightNibbleArray.length == 0) ? 0 : getNibbleAtIndex(skyLightNibbleArray, blockPosIndex);
|
||||||
|
if (skyLightNibbleArray.length == 0 && foundSkyLight)
|
||||||
|
{
|
||||||
|
skyLight = LodUtil.MAX_MC_LIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
int y = relY + (sectionIndex * LodUtil.CHUNK_WIDTH) + ChunkWrapper.getInclusiveMinBuildHeight(chunk);
|
||||||
|
blockLightStorage.set(relX, y, relZ, blockLight);
|
||||||
|
skyLightStorage.set(relX, y, relZ, skyLight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return combinedStorage;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
/** source: https://minecraft.wiki/w/Chunk_format#Block_Format */
|
||||||
|
private static byte getNibbleAtIndex(byte[] arr, int index)
|
||||||
|
{
|
||||||
|
if (index % 2 == 0)
|
||||||
|
{
|
||||||
|
return (byte)(arr[index/2] & 0x0F);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return (byte)((arr[index/2]>>4) & 0x0F);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=========//
|
||||||
|
// logging //
|
||||||
|
//=========//
|
||||||
|
|
||||||
|
private static void logBlockDeserializationWarning(ChunkPos chunkPos, int sectionYIndex, String message)
|
||||||
|
{
|
||||||
|
LOGGED_ERROR_MESSAGE_MAP.computeIfAbsent(message, (newMessage) ->
|
||||||
|
{
|
||||||
|
LOGGER.warn("Unable to deserialize blocks for chunk section [" + chunkPos.x + ", " + sectionYIndex + ", " + chunkPos.z + "], error: ["+newMessage+"]. " +
|
||||||
|
"This can probably be ignored, although if your world looks wrong, optimizing it via the single player menu then deleting your DH database(s) should fix the problem.");
|
||||||
|
|
||||||
|
return newMessage;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
private static void logBiomeDeserializationWarning(ChunkPos chunkPos, int sectionYIndex, String message)
|
||||||
|
{
|
||||||
|
LOGGED_ERROR_MESSAGE_MAP.computeIfAbsent(message, (newMessage) ->
|
||||||
|
{
|
||||||
|
LOGGER.warn("Unable to deserialize biomes for chunk section [" + chunkPos.x + ", " + sectionYIndex + ", " + chunkPos.z + "], error: ["+newMessage+"]. " +
|
||||||
|
"This can probably be ignored, although if your world looks wrong, optimizing it via the single player menu then deleting your DH database(s) should fix the problem.");
|
||||||
|
|
||||||
|
return newMessage;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void logParsingWarningOnce(String message) { logParsingWarningOnce(message, null); }
|
||||||
|
private static void logParsingWarningOnce(String message, Exception e)
|
||||||
|
{
|
||||||
|
if (message == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGGED_ERROR_MESSAGE_MAP.computeIfAbsent(message, (newMessage) ->
|
||||||
|
{
|
||||||
|
LOGGER.warn("Parsing error: ["+newMessage+"]. " +
|
||||||
|
"This can probably be ignored, although if your world looks wrong, optimizing it via the single player menu then deleting your DH database(s) should fix the problem.",
|
||||||
|
e);
|
||||||
|
|
||||||
|
return newMessage;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static RuntimeException logErrorAndReturnException(String message)
|
||||||
|
{
|
||||||
|
LOGGED_ERROR_MESSAGE_MAP.computeIfAbsent(message, (newMessage) ->
|
||||||
|
{
|
||||||
|
LOGGER.warn("Parsing error: ["+newMessage+"]. " +
|
||||||
|
"This can probably be ignored, although if your world looks wrong, optimizing it via the single player menu then deleting your DH database(s) should fix the problem.");
|
||||||
|
|
||||||
|
return newMessage;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Currently we want to ignore these errors, if returning null is a problem, we can change this later
|
||||||
|
return null; //new RuntimeException(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// helper classes //
|
||||||
|
//================//
|
||||||
|
|
||||||
|
public static class CombinedChunkLightStorage
|
||||||
|
{
|
||||||
|
public ChunkLightStorage blockLightStorage;
|
||||||
|
public ChunkLightStorage skyLightStorage;
|
||||||
|
|
||||||
|
public CombinedChunkLightStorage(int minY, int maxY)
|
||||||
|
{
|
||||||
|
this.blockLightStorage = ChunkLightStorage.createBlockLightStorage(minY, maxY);
|
||||||
|
this.skyLightStorage = ChunkLightStorage.createSkyLightStorage(minY, maxY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+343
@@ -0,0 +1,343 @@
|
|||||||
|
package com.seibel.distanthorizons.common.wrappers.worldGeneration.chunkFileHandling;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.params.GlobalWorldGenParams;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.RegionFileStorageExternalCache;
|
||||||
|
import com.seibel.distanthorizons.core.config.Config;
|
||||||
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
|
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.util.ExceptionUtil;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.ChunkLightStorage;
|
||||||
|
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.ProtoChunk;
|
||||||
|
import net.minecraft.world.level.chunk.UpgradeData;
|
||||||
|
import net.minecraft.world.level.chunk.storage.IOWorker;
|
||||||
|
import net.minecraft.world.level.chunk.storage.RegionFileStorage;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.channels.ClosedByInterruptException;
|
||||||
|
import java.nio.channels.ClosedChannelException;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.CompletionException;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_17_1
|
||||||
|
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||||
|
#elif MC_VER <= MC_1_19_2
|
||||||
|
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||||
|
import net.minecraft.core.Registry;
|
||||||
|
#elif MC_VER <= MC_1_19_4
|
||||||
|
import net.minecraft.core.registries.Registries;
|
||||||
|
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||||
|
#elif MC_VER <= MC_1_20_6
|
||||||
|
import net.minecraft.core.registries.Registries;
|
||||||
|
#elif MC_VER <= MC_1_21_3
|
||||||
|
import net.minecraft.core.registries.Registries;
|
||||||
|
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||||
|
#elif MC_VER <= MC_1_21_8
|
||||||
|
import net.minecraft.core.registries.Registries;
|
||||||
|
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||||
|
#elif MC_VER <= MC_1_21_9
|
||||||
|
import net.minecraft.world.level.chunk.PalettedContainerFactory;
|
||||||
|
#else
|
||||||
|
import net.minecraft.world.level.chunk.PalettedContainerFactory;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public class ChunkFileReader implements AutoCloseable
|
||||||
|
{
|
||||||
|
|
||||||
|
public static final DhLogger LOGGER = new DhLoggerBuilder()
|
||||||
|
.name("LOD World Gen")
|
||||||
|
.fileLevelConfig(Config.Common.Logging.logWorldGenEventToFile)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
public static final DhLogger CHUNK_LOAD_LOGGER = new DhLoggerBuilder()
|
||||||
|
.name("LOD Chunk Loading")
|
||||||
|
.fileLevelConfig(Config.Common.Logging.logWorldGenChunkLoadEventToFile)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
private static final IModChecker MOD_CHECKER = SingletonInjector.INSTANCE.get(IModChecker.class);
|
||||||
|
|
||||||
|
public final GlobalWorldGenParams params;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* will be true if C2ME is installed (since they require us to
|
||||||
|
* pull chunks using their async method), or if there
|
||||||
|
* was an issue with the sync pulling method.
|
||||||
|
*/
|
||||||
|
private boolean pullExistingChunkUsingMcAsyncMethod = false;
|
||||||
|
|
||||||
|
private final AtomicReference<RegionFileStorageExternalCache> regionFileStorageCacheRef = new AtomicReference<>();
|
||||||
|
public RegionFileStorageExternalCache getOrCreateRegionFileCache(RegionFileStorage storage)
|
||||||
|
{
|
||||||
|
RegionFileStorageExternalCache cache = this.regionFileStorageCacheRef.get();
|
||||||
|
if (cache == null)
|
||||||
|
{
|
||||||
|
cache = new RegionFileStorageExternalCache(storage);
|
||||||
|
if (!this.regionFileStorageCacheRef.compareAndSet(null, cache))
|
||||||
|
{
|
||||||
|
cache = this.regionFileStorageCacheRef.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
|
||||||
|
public ChunkFileReader(GlobalWorldGenParams params)
|
||||||
|
{
|
||||||
|
this.params = params;
|
||||||
|
|
||||||
|
if (MOD_CHECKER.isModLoaded("c2me"))
|
||||||
|
{
|
||||||
|
LOGGER.info("C2ME detected: DH's pre-existing chunk accessing will use methods handled by C2ME.");
|
||||||
|
this.pullExistingChunkUsingMcAsyncMethod = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the given chunk pos already exists in the world, that chunk will be returned,
|
||||||
|
* otherwise this will return an empty chunk.
|
||||||
|
*/
|
||||||
|
public CompletableFuture<ChunkWrapper> createEmptyOrPreExistingChunkWrapperAsync(
|
||||||
|
int chunkX, int chunkZ,
|
||||||
|
Map<DhChunkPos, ChunkLightStorage> chunkSkyLightingByDhPos,
|
||||||
|
Map<DhChunkPos, ChunkLightStorage> chunkBlockLightingByDhPos,
|
||||||
|
Map<DhChunkPos, ChunkWrapper> generatedChunkWrapperByDhPos)
|
||||||
|
{
|
||||||
|
ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ);
|
||||||
|
DhChunkPos dhChunkPos = new DhChunkPos(chunkX, chunkZ);
|
||||||
|
|
||||||
|
if (generatedChunkWrapperByDhPos.containsKey(dhChunkPos))
|
||||||
|
{
|
||||||
|
return CompletableFuture.completedFuture(generatedChunkWrapperByDhPos.get(dhChunkPos));
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.getChunkNbtDataAsync(chunkPos)
|
||||||
|
.thenApply((CompoundTag chunkData) ->
|
||||||
|
{
|
||||||
|
ChunkWrapper newChunkWrapper = this.loadOrMakeChunkWrapper(chunkPos, chunkData);
|
||||||
|
|
||||||
|
// attempt to get chunk lighting
|
||||||
|
ChunkCompoundTagParser.CombinedChunkLightStorage combinedLights = ChunkCompoundTagParser.readLight(newChunkWrapper.getChunk(), chunkData);
|
||||||
|
if (combinedLights != null)
|
||||||
|
{
|
||||||
|
// may be empty, empty checks are handled later
|
||||||
|
chunkSkyLightingByDhPos.put(dhChunkPos, combinedLights.skyLightStorage);
|
||||||
|
chunkBlockLightingByDhPos.put(dhChunkPos, combinedLights.blockLightStorage);
|
||||||
|
}
|
||||||
|
|
||||||
|
return newChunkWrapper;
|
||||||
|
})
|
||||||
|
// separate handle so we can cleanly handle missing chunks and/or thrown errors
|
||||||
|
.handle((ChunkWrapper newChunkWrapper, Throwable throwable) ->
|
||||||
|
{
|
||||||
|
if (newChunkWrapper != null)
|
||||||
|
{
|
||||||
|
return newChunkWrapper;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return this.CreateProtoChunkWrapper(this.params.mcServerLevel, chunkPos);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.thenApply((ChunkWrapper newChunkWrapper) ->
|
||||||
|
{
|
||||||
|
generatedChunkWrapperByDhPos.put(dhChunkPos, newChunkWrapper);
|
||||||
|
return newChunkWrapper;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
private CompletableFuture<CompoundTag> getChunkNbtDataAsync(ChunkPos chunkPos)
|
||||||
|
{
|
||||||
|
ServerLevel level = this.params.mcServerLevel;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IOWorker ioWorker = level.getChunkSource().chunkMap.worker;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_18_2
|
||||||
|
return CompletableFuture.completedFuture(ioWorker.load(chunkPos));
|
||||||
|
#else
|
||||||
|
|
||||||
|
// storage will be null if C2ME is installed
|
||||||
|
if (!this.pullExistingChunkUsingMcAsyncMethod
|
||||||
|
&& ioWorker.storage != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
RegionFileStorage storage = this.params.mcServerLevel.getChunkSource().chunkMap.worker.storage;
|
||||||
|
RegionFileStorageExternalCache cache = this.getOrCreateRegionFileCache(storage);
|
||||||
|
return CompletableFuture.completedFuture(cache.read(chunkPos));
|
||||||
|
}
|
||||||
|
catch (NullPointerException e)
|
||||||
|
{
|
||||||
|
// this shouldn't happen, if anything is null it should be
|
||||||
|
// ioWorker.storage
|
||||||
|
// but just in case
|
||||||
|
LOGGER.error("Unexpected issue pulling pre-existing chunk ["+chunkPos+"], falling back to async chunk pulling. This may cause server-tick lag.", e);
|
||||||
|
this.pullExistingChunkUsingMcAsyncMethod = true;
|
||||||
|
|
||||||
|
// try again now using the async method
|
||||||
|
return this.getChunkNbtDataAsync(chunkPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// log if we unexpectedly weren't able to run the sync chunk pulling
|
||||||
|
if (!this.pullExistingChunkUsingMcAsyncMethod)
|
||||||
|
{
|
||||||
|
// this shouldn't happen, but just in case
|
||||||
|
LOGGER.info("Unable to pull pre-existing chunk using synchronous method. Falling back to async method. this may cause server-tick lag.");
|
||||||
|
this.pullExistingChunkUsingMcAsyncMethod = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//GET_CHUNK_COUNT_REF.incrementAndGet();
|
||||||
|
|
||||||
|
// When running in vanilla MC on versions before 1.21.4,
|
||||||
|
// DH would attempt to run loadAsync on this same thread via a threading mixin,
|
||||||
|
// to prevent causing lag on the server thread.
|
||||||
|
// However, if a mod like C2ME is installed this will run on a C2ME thread instead.
|
||||||
|
return ioWorker.loadAsync(chunkPos)
|
||||||
|
.thenApply(optional ->
|
||||||
|
{
|
||||||
|
// Debugging note:
|
||||||
|
// If there are reports of extreme memory use when C2ME is installed, that probably means
|
||||||
|
// this method is queuing a lot of tasks (1,000+), which causes C2ME to explode.
|
||||||
|
|
||||||
|
//GET_CHUNK_COUNT_REF.decrementAndGet();
|
||||||
|
//PREF_LOGGER.info("chunk getter count ["+F3Screen.NUMBER_FORMAT.format(GET_CHUNK_COUNT_REF.get())+"]");
|
||||||
|
return optional.orElse(null);
|
||||||
|
})
|
||||||
|
.exceptionally((throwable) ->
|
||||||
|
{
|
||||||
|
// unwrap the CompletionException if necessary
|
||||||
|
Throwable actualThrowable = throwable;
|
||||||
|
while (actualThrowable instanceof CompletionException completionException)
|
||||||
|
{
|
||||||
|
actualThrowable = completionException.getCause();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isShutdownException = ExceptionUtil.isShutdownException(actualThrowable);
|
||||||
|
if (!isShutdownException)
|
||||||
|
{
|
||||||
|
CHUNK_LOAD_LOGGER.warn("DistantHorizons: Couldn't load or make chunk ["+chunkPos+"], error: ["+actualThrowable.getMessage()+"].", actualThrowable);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
catch (ClosedByInterruptException ignore)
|
||||||
|
{
|
||||||
|
// this just means the world generator is being shut down
|
||||||
|
return CompletableFuture.completedFuture(null);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
CHUNK_LOAD_LOGGER.warn("Couldn't load or make chunk [" + chunkPos + "]. Error: [" + e.getMessage() + "].", e);
|
||||||
|
return CompletableFuture.completedFuture(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private ChunkWrapper loadOrMakeChunkWrapper(ChunkPos chunkPos, CompoundTag chunkTagData)
|
||||||
|
{
|
||||||
|
ServerLevel mcServerLevel = this.params.mcServerLevel;
|
||||||
|
|
||||||
|
if (chunkTagData == null)
|
||||||
|
{
|
||||||
|
return this.CreateProtoChunkWrapper(mcServerLevel, chunkPos);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ChunkWrapper chunkWrapper = ChunkCompoundTagParser.createFromTag(mcServerLevel, this.params.dhServerLevel, chunkPos, chunkTagData);
|
||||||
|
if (chunkWrapper == null)
|
||||||
|
{
|
||||||
|
chunkWrapper = this.CreateProtoChunkWrapper(mcServerLevel, chunkPos);
|
||||||
|
}
|
||||||
|
return chunkWrapper;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
CHUNK_LOAD_LOGGER.error(
|
||||||
|
"DistantHorizons: couldn't load or make chunk at [" + chunkPos + "]." +
|
||||||
|
"Please try optimizing your world to fix this issue. \n" +
|
||||||
|
"World optimization can be done from the singleplayer world selection screen.\n" +
|
||||||
|
"Error: [" + e.getMessage() + "]."
|
||||||
|
, e);
|
||||||
|
|
||||||
|
return this.CreateProtoChunkWrapper(mcServerLevel, chunkPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChunkWrapper CreateProtoChunkWrapper(ServerLevel level, ChunkPos chunkPos)
|
||||||
|
{
|
||||||
|
ProtoChunk chunk = CreateProtoChunk(level, chunkPos);
|
||||||
|
return new ChunkWrapper(chunk, this.params.dhServerLevel.getLevelWrapper(), false);
|
||||||
|
}
|
||||||
|
public static ProtoChunk CreateProtoChunk(ServerLevel level, ChunkPos chunkPos)
|
||||||
|
{
|
||||||
|
#if MC_VER <= MC_1_16_5
|
||||||
|
return new ProtoChunk(chunkPos, UpgradeData.EMPTY);
|
||||||
|
#elif MC_VER <= MC_1_17_1
|
||||||
|
return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level);
|
||||||
|
#elif MC_VER <= MC_1_19_2
|
||||||
|
return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level, level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), null);
|
||||||
|
#elif MC_VER <= MC_1_19_4
|
||||||
|
return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level, level.registryAccess().registryOrThrow(Registries.BIOME), null);
|
||||||
|
#elif MC_VER < MC_1_21_3
|
||||||
|
return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level, level.registryAccess().registryOrThrow(Registries.BIOME), null);
|
||||||
|
#elif MC_VER < MC_1_21_9
|
||||||
|
return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level, level.registryAccess().lookupOrThrow(Registries.BIOME), null);
|
||||||
|
#else
|
||||||
|
return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level, PalettedContainerFactory.create(level.registryAccess()), null);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// base overrides //
|
||||||
|
//================//
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close()
|
||||||
|
{
|
||||||
|
RegionFileStorageExternalCache regionStorage = this.regionFileStorageCacheRef.get();
|
||||||
|
if (regionStorage != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
regionStorage.close();
|
||||||
|
}
|
||||||
|
catch (ClosedChannelException ignore) { /* world generator is being shut down */ }
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
LOGGER.error("Failed to close region file storage cache, error: ["+e.getMessage()+"].", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+148
@@ -0,0 +1,148 @@
|
|||||||
|
package com.seibel.distanthorizons.common.wrappers.worldGeneration.chunkFileHandling;
|
||||||
|
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.nbt.ListTag;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* these tag helpers are usedd to simplify tag accessing between MC versions
|
||||||
|
*/
|
||||||
|
public class CompoundTagUtil
|
||||||
|
{
|
||||||
|
|
||||||
|
/** defaults to "false" if the tag isn't present */
|
||||||
|
public static boolean getBoolean(CompoundTag tag, String key)
|
||||||
|
{
|
||||||
|
#if MC_VER < MC_1_21_5
|
||||||
|
return tag.getBoolean(key);
|
||||||
|
#else
|
||||||
|
return tag.getBoolean(key).orElse(false);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/** defaults to "0" if the tag isn't present */
|
||||||
|
public static byte getByte(CompoundTag tag, String key)
|
||||||
|
{
|
||||||
|
#if MC_VER < MC_1_21_5
|
||||||
|
return tag.getByte(key);
|
||||||
|
#else
|
||||||
|
return tag.getByte(key).orElse((byte)0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/** defaults to "0" if the tag isn't present */
|
||||||
|
public static short getShort(ListTag tag, int index)
|
||||||
|
{
|
||||||
|
#if MC_VER < MC_1_21_5
|
||||||
|
return tag.getShort(index);
|
||||||
|
#else
|
||||||
|
return tag.getShort(index).orElse((short)0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/** defaults to "0" if the tag isn't present */
|
||||||
|
public static int getInt(CompoundTag tag, String key)
|
||||||
|
{
|
||||||
|
#if MC_VER < MC_1_21_5
|
||||||
|
return tag.getInt(key);
|
||||||
|
#else
|
||||||
|
return tag.getInt(key).orElse(0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/** defaults to "0" if the tag isn't present */
|
||||||
|
public static long getLong(CompoundTag tag, String key)
|
||||||
|
{
|
||||||
|
#if MC_VER < MC_1_21_5
|
||||||
|
return tag.getInt(key);
|
||||||
|
#else
|
||||||
|
return tag.getLong(key).orElse(0L);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** defaults to null if the tag isn't present */
|
||||||
|
@Nullable
|
||||||
|
public static String getString(CompoundTag tag, String key)
|
||||||
|
{
|
||||||
|
#if MC_VER < MC_1_21_5
|
||||||
|
return tag.getString(key);
|
||||||
|
#else
|
||||||
|
return tag.getString(key).orElse(null);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/** defaults to null if the tag isn't present */
|
||||||
|
@Nullable
|
||||||
|
public static byte[] getByteArray(CompoundTag tag, String key)
|
||||||
|
{
|
||||||
|
#if MC_VER < MC_1_21_5
|
||||||
|
return tag.getByteArray(key);
|
||||||
|
#else
|
||||||
|
return tag.getByteArray(key).orElse(null);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** defaults to null if the tag isn't present */
|
||||||
|
@Nullable
|
||||||
|
public static CompoundTag getCompoundTag(CompoundTag tag, String key)
|
||||||
|
{
|
||||||
|
#if MC_VER < MC_1_21_5
|
||||||
|
return tag.getCompound(key);
|
||||||
|
#else
|
||||||
|
return tag.getCompound(key).orElse(null);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
/** defaults to null if the tag isn't present */
|
||||||
|
@Nullable
|
||||||
|
public static CompoundTag getCompoundTag(ListTag tag, int index)
|
||||||
|
{
|
||||||
|
#if MC_VER < MC_1_21_5
|
||||||
|
return tag.getCompound(index);
|
||||||
|
#else
|
||||||
|
return tag.getCompound(index).orElse(null);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* defaults to null if the tag isn't present
|
||||||
|
* @param elementType unused after MC 1.21.5
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static ListTag getListTag(CompoundTag tag, String key, int elementType)
|
||||||
|
{
|
||||||
|
#if MC_VER < MC_1_21_5
|
||||||
|
return tag.getList(key, elementType);
|
||||||
|
#else
|
||||||
|
return tag.getList(key).orElse(null);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/** defaults to null if the tag isn't present */
|
||||||
|
@Nullable
|
||||||
|
public static ListTag getListTag(ListTag tag, int index)
|
||||||
|
{
|
||||||
|
#if MC_VER < MC_1_21_5
|
||||||
|
return tag.getList(index);
|
||||||
|
#else
|
||||||
|
return tag.getList(index).orElse(null);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static boolean contains(CompoundTag tag, String key, int index)
|
||||||
|
{
|
||||||
|
#if MC_VER < MC_1_21_5
|
||||||
|
return tag.contains(key, index);
|
||||||
|
#else
|
||||||
|
return tag.contains(key);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
-876
@@ -1,876 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of the Distant Horizons mod
|
|
||||||
* licensed under the GNU GPL v3 License.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2020 James Seibel
|
|
||||||
*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject;
|
|
||||||
|
|
||||||
import com.mojang.serialization.Codec;
|
|
||||||
import com.mojang.serialization.Dynamic;
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
|
||||||
|
|
||||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
|
||||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.ChunkLightStorage;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
|
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.shorts.ShortList;
|
|
||||||
import net.minecraft.core.Registry;
|
|
||||||
#if MC_VER >= MC_1_19_4
|
|
||||||
import net.minecraft.core.registries.BuiltInRegistries;
|
|
||||||
import net.minecraft.core.registries.Registries;
|
|
||||||
#endif
|
|
||||||
import net.minecraft.nbt.CompoundTag;
|
|
||||||
import net.minecraft.nbt.ListTag;
|
|
||||||
import net.minecraft.nbt.NbtOps;
|
|
||||||
import net.minecraft.nbt.Tag;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.world.level.*;
|
|
||||||
import net.minecraft.world.level.biome.Biome;
|
|
||||||
import net.minecraft.world.level.biome.Biomes;
|
|
||||||
import net.minecraft.world.level.block.Block;
|
|
||||||
import net.minecraft.world.level.block.Blocks;
|
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
|
||||||
import net.minecraft.world.level.chunk.*;
|
|
||||||
|
|
||||||
#if MC_VER < MC_1_21_3
|
|
||||||
import net.minecraft.world.level.chunk.storage.ChunkSerializer;
|
|
||||||
#else
|
|
||||||
#endif
|
|
||||||
|
|
||||||
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
|
|
||||||
import net.minecraft.world.ticks.LevelChunkTicks;
|
|
||||||
#endif
|
|
||||||
#if MC_VER >= MC_1_18_2
|
|
||||||
import net.minecraft.core.Holder;
|
|
||||||
#if MC_VER < MC_1_19_2
|
|
||||||
import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature;
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
|
||||||
import net.minecraft.world.level.material.Fluids;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if MC_VER == MC_1_20_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;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
|
|
||||||
public class ChunkFileReader
|
|
||||||
{
|
|
||||||
private static final AtomicBoolean ZERO_CHUNK_POS_ERROR_LOGGED_REF = new AtomicBoolean(false);
|
|
||||||
|
|
||||||
private static final DhLogger LOGGER = BatchGenerationEnvironment.CHUNK_LOAD_LOGGER;
|
|
||||||
|
|
||||||
|
|
||||||
#if MC_VER >= MC_1_21_9
|
|
||||||
// BLOCK_STATE_CODEC can no longer be statically created since
|
|
||||||
// it needs a level reference
|
|
||||||
#elif MC_VER >= MC_1_19_2
|
|
||||||
private static final Codec<PalettedContainer<BlockState>> BLOCK_STATE_CODEC = PalettedContainer.codecRW(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState());
|
|
||||||
#elif MC_VER >= MC_1_18_2
|
|
||||||
private static final Codec<PalettedContainer<BlockState>> BLOCK_STATE_CODEC = PalettedContainer.codec(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private static final String TAG_UPGRADE_DATA = "UpgradeData";
|
|
||||||
private static final String BLOCK_TICKS_TAG_18 = "block_ticks";
|
|
||||||
private static final String FLUID_TICKS_TAG_18 = "fluid_ticks";
|
|
||||||
private static final String BLOCK_TICKS_TAG_PRE18 = "TileTicks";
|
|
||||||
private static final String FLUID_TICKS_TAG_PRE18 = "LiquidTicks";
|
|
||||||
|
|
||||||
private static boolean lightingSectionErrorLogged = false;
|
|
||||||
|
|
||||||
private static final ConcurrentHashMap<String, Object> LOGGED_ERROR_MESSAGE_MAP = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//============//
|
|
||||||
// read chunk //
|
|
||||||
//============//
|
|
||||||
|
|
||||||
public static LevelChunk read(WorldGenLevel level, ChunkPos chunkPos, CompoundTag chunkData)
|
|
||||||
{
|
|
||||||
#if MC_VER < MC_1_18_2
|
|
||||||
CompoundTag tagLevel = chunkData.getCompound("Level");
|
|
||||||
#else
|
|
||||||
CompoundTag tagLevel = chunkData;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int chunkX = tagGetInt(tagLevel,"xPos");
|
|
||||||
int chunkZ = tagGetInt(tagLevel, "zPos");
|
|
||||||
ChunkPos actualPos = new ChunkPos(chunkX, chunkZ);
|
|
||||||
|
|
||||||
if (!Objects.equals(chunkPos, actualPos))
|
|
||||||
{
|
|
||||||
if (chunkX == 0 && chunkZ == 0)
|
|
||||||
{
|
|
||||||
if (!ZERO_CHUNK_POS_ERROR_LOGGED_REF.getAndSet(true))
|
|
||||||
{
|
|
||||||
// explicit chunkPos toString is necessary otherwise the JDK 17 compiler breaks
|
|
||||||
LOGGER.warn("Chunk file at ["+chunkPos.toString()+"] doesn't have a chunk pos. \n" +
|
|
||||||
"This might happen if the world was created using an external program. \n" +
|
|
||||||
"DH will attempt to parse the chunk anyway and won't log this message again.\n" +
|
|
||||||
"If issues arise please try optimizing your world to fix this issue. \n" +
|
|
||||||
"World optimization can be done from the singleplayer world selection screen."+
|
|
||||||
"");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// everything is on one line to fix a JDK 17 compiler issue
|
|
||||||
// if the issue is ever resolved, feel free to make this multi-line for readability
|
|
||||||
LOGGER.error("Chunk file at ["+chunkPos.toString()+"] is in the wrong location. \nPlease try optimizing your world to fix this issue. \nWorld optimization can be done from the singleplayer world selection screen. \n(Expected pos: ["+chunkPos.toString()+"], actual ["+actualPos.toString()+"])");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#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_21_6
|
|
||||||
|
|
||||||
BlendingData blendingData = readBlendingData(tagLevel);
|
|
||||||
#if MC_VER < MC_1_19_2
|
|
||||||
if (chunkType == ChunkStatus.ChunkType.PROTOCHUNK && (blendingData == null || !blendingData.oldNoise()))
|
|
||||||
return null;
|
|
||||||
#else
|
|
||||||
if (chunkType == #if MC_VER < MC_1_20_6 ChunkStatus.ChunkType.PROTOCHUNK #else ChunkType.PROTOCHUNK #endif && blendingData == null)
|
|
||||||
return null;
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
|
|
||||||
// ignore blending data, there appears to be an issue with parsing it in 1.21.6
|
|
||||||
BlendingData blendingData = null;
|
|
||||||
|
|
||||||
if (chunkType == ChunkType.PROTOCHUNK)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
long inhabitedTime = tagGetLong(tagLevel, "InhabitedTime");
|
|
||||||
|
|
||||||
//================== Read params for making the LevelChunk ==================
|
|
||||||
|
|
||||||
UpgradeData upgradeData = UpgradeData.EMPTY;
|
|
||||||
// commented out 2025-06-04 as a test to see if the upgrade data
|
|
||||||
// is actually necessary for DH or if it can be ignored
|
|
||||||
// (if it can't be ignored we'll need to handle null responses from tagGetCompoundTag())
|
|
||||||
//
|
|
||||||
//#if MC_VER < MC_1_17_1
|
|
||||||
//upgradeData = tagLevel.contains(TAG_UPGRADE_DATA, 10)
|
|
||||||
// ? new UpgradeData(tagGetCompoundTag(tagLevel, TAG_UPGRADE_DATA))
|
|
||||||
// : UpgradeData.EMPTY;
|
|
||||||
//#elif MC_VER < MC_1_21_5
|
|
||||||
//upgradeData = tagLevel.contains(TAG_UPGRADE_DATA, 10)
|
|
||||||
// ? new UpgradeData(tagGetCompoundTag(tagLevel, TAG_UPGRADE_DATA), level)
|
|
||||||
// : UpgradeData.EMPTY;
|
|
||||||
//#else
|
|
||||||
//upgradeData = tagLevel.contains(TAG_UPGRADE_DATA)
|
|
||||||
// ? new UpgradeData(tagGetCompoundTag(tagLevel, TAG_UPGRADE_DATA), level)
|
|
||||||
// : UpgradeData.EMPTY;
|
|
||||||
//#endif
|
|
||||||
|
|
||||||
|
|
||||||
boolean isLightOn = tagGetBoolean(tagLevel, "isLightOn");
|
|
||||||
#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(),
|
|
||||||
tagLevel.contains("Biomes", 11) ? tagLevel.getIntArray("Biomes") : null);
|
|
||||||
|
|
||||||
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 );
|
|
||||||
|
|
||||||
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 );
|
|
||||||
#else
|
|
||||||
#if MC_VER < MC_1_19_4
|
|
||||||
LevelChunkTicks<Block> blockTicks = LevelChunkTicks.load(tagLevel.getList(BLOCK_TICKS_TAG_18, 10),
|
|
||||||
string -> Registry.BLOCK.getOptional(ResourceLocation.tryParse(string)), chunkPos);
|
|
||||||
LevelChunkTicks<Fluid> fluidTicks = LevelChunkTicks.load(tagLevel.getList(FLUID_TICKS_TAG_18, 10),
|
|
||||||
string -> Registry.FLUID.getOptional(ResourceLocation.tryParse(string)), chunkPos);
|
|
||||||
#elif MC_VER < MC_1_21_4
|
|
||||||
LevelChunkTicks<Block> blockTicks = LevelChunkTicks.load(tagLevel.getList(BLOCK_TICKS_TAG_18, 10),
|
|
||||||
(string -> BuiltInRegistries.BLOCK.getOptional(ResourceLocation.tryParse(string))), chunkPos);
|
|
||||||
LevelChunkTicks<Fluid> fluidTicks = LevelChunkTicks.load(tagLevel.getList(FLUID_TICKS_TAG_18, 10),
|
|
||||||
string -> BuiltInRegistries.FLUID.getOptional(ResourceLocation.tryParse(string)), chunkPos);
|
|
||||||
#else
|
|
||||||
// do we need the ticks for what we're doing?
|
|
||||||
LevelChunkTicks<Block> blockTicks = new LevelChunkTicks<>();
|
|
||||||
LevelChunkTicks<Fluid> fluidTicks = new LevelChunkTicks<>();
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
LevelChunkSection[] levelChunkSections = readSections(level, chunkPos, tagLevel);
|
|
||||||
|
|
||||||
// ====================== Make the chunk =========================
|
|
||||||
#if MC_VER < MC_1_18_2
|
|
||||||
LevelChunk chunk = new LevelChunk((Level) level.getLevel(), chunkPos, chunkBiomeContainer, upgradeData, blockTicks,
|
|
||||||
fluidTicks, inhabitedTime, levelChunkSections, null);
|
|
||||||
#else
|
|
||||||
LevelChunk chunk = new LevelChunk((Level) level, chunkPos, upgradeData, blockTicks,
|
|
||||||
fluidTicks, inhabitedTime, levelChunkSections, null, blendingData);
|
|
||||||
#endif
|
|
||||||
// Set some states after object creation
|
|
||||||
chunk.setLightCorrect(isLightOn);
|
|
||||||
readHeightmaps(chunk, chunkData);
|
|
||||||
//readPostPocessings(chunk, chunkData);
|
|
||||||
return chunk;
|
|
||||||
}
|
|
||||||
private static LevelChunkSection[] readSections(LevelAccessor level, ChunkPos chunkPos, CompoundTag chunkData)
|
|
||||||
{
|
|
||||||
#if MC_VER < MC_1_21_9
|
|
||||||
// BLOCK_STATE_CODEC is created statically
|
|
||||||
// TODO clean up this code separation
|
|
||||||
#else
|
|
||||||
final Codec<PalettedContainer<BlockState>> BLOCK_STATE_CODEC = PalettedContainerFactory.create(level.registryAccess()).blockStatesContainerCodec();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#if MC_VER >= MC_1_18_2
|
|
||||||
#if MC_VER < MC_1_19_4
|
|
||||||
Registry<Biome> biomes = level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY);
|
|
||||||
#elif MC_VER < MC_1_21_3
|
|
||||||
Registry<Biome> biomes = level.registryAccess().registryOrThrow(Registries.BIOME);
|
|
||||||
#else
|
|
||||||
Registry<Biome> biomes = level.registryAccess().lookupOrThrow(Registries.BIOME);
|
|
||||||
#endif
|
|
||||||
#if MC_VER < MC_1_18_2
|
|
||||||
Codec<PalettedContainer<Biome>> biomeCodec = PalettedContainer.codec(
|
|
||||||
biomes, biomes.byNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getOrThrow(Biomes.PLAINS));
|
|
||||||
#elif MC_VER < MC_1_19_2
|
|
||||||
Codec<PalettedContainer<Holder<Biome>>> biomeCodec = PalettedContainer.codec(
|
|
||||||
biomes.asHolderIdMap(), biomes.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getHolderOrThrow(Biomes.PLAINS));
|
|
||||||
#elif MC_VER < MC_1_21_3
|
|
||||||
Codec<PalettedContainer<Holder<Biome>>> biomeCodec = PalettedContainer.codecRW(
|
|
||||||
biomes.asHolderIdMap(), biomes.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getHolderOrThrow(Biomes.PLAINS));
|
|
||||||
#elif MC_VER < MC_1_21_9
|
|
||||||
Codec<PalettedContainer<Holder<Biome>>> biomeCodec = PalettedContainer.codecRW(
|
|
||||||
biomes.asHolderIdMap(), biomes.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getOrThrow(Biomes.PLAINS));
|
|
||||||
#else
|
|
||||||
Codec<PalettedContainer<Holder<Biome>>> biomeCodec = PalettedContainer.codecRW(
|
|
||||||
biomes.holderByNameCodec(), PalettedContainerFactory.create(level.registryAccess()).biomeStrategy(), biomes.getOrThrow(Biomes.PLAINS));
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int sectionYIndex = #if MC_VER < MC_1_17_1 16; #else level.getSectionsCount(); #endif
|
|
||||||
LevelChunkSection[] chunkSections = new LevelChunkSection[sectionYIndex];
|
|
||||||
|
|
||||||
ListTag tagSections = tagGetListTag(chunkData, "Sections", 10);
|
|
||||||
if (tagSections == null || tagSections.isEmpty())
|
|
||||||
{
|
|
||||||
tagSections = tagGetListTag(chunkData, "sections", 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (tagSections != null)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < tagSections.size(); ++j)
|
|
||||||
{
|
|
||||||
CompoundTag tagSection = tagGetCompoundTag(tagSections, j);
|
|
||||||
if (tagSection == null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int sectionYPos = tagGetByte(tagSection, "Y");
|
|
||||||
|
|
||||||
#if MC_VER < MC_1_18_2
|
|
||||||
if (tagSection.contains("Palette", 9) && tagSection.contains("BlockStates", 12))
|
|
||||||
{
|
|
||||||
LevelChunkSection levelChunkSection = new LevelChunkSection(sectionYPos << 4);
|
|
||||||
levelChunkSection.getStates().read(tagSection.getList("Palette", 10),
|
|
||||||
tagSection.getLongArray("BlockStates"));
|
|
||||||
levelChunkSection.recalcBlockCounts();
|
|
||||||
if (!levelChunkSection.isEmpty())
|
|
||||||
chunkSections[#if MC_VER < MC_1_17_1 sectionYPos #else level.getSectionIndexFromSectionY(sectionYPos) #endif ]
|
|
||||||
= levelChunkSection;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
int sectionId = level.getSectionIndexFromSectionY(sectionYPos);
|
|
||||||
if (sectionId >= 0 && sectionId < chunkSections.length)
|
|
||||||
{
|
|
||||||
PalettedContainer<BlockState> blockStateContainer;
|
|
||||||
#if MC_VER < MC_1_18_2
|
|
||||||
PalettedContainer<Biome> biomeContainer;
|
|
||||||
#else
|
|
||||||
PalettedContainer<Holder<Biome>> biomeContainer;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
boolean containsBlockStates;
|
|
||||||
#if MC_VER < MC_1_21_5
|
|
||||||
containsBlockStates = tagSection.contains("block_states", 10);
|
|
||||||
#else
|
|
||||||
containsBlockStates = tagSection.contains("block_states");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (containsBlockStates)
|
|
||||||
{
|
|
||||||
#if MC_VER < MC_1_20_6
|
|
||||||
blockStateContainer = BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, tagGetCompoundTag(tagSection, "block_states"))
|
|
||||||
.promotePartial(string -> logBlockDeserializationWarning(chunkPos, sectionYPos, string))
|
|
||||||
.getOrThrow(false, (message) -> logParsingWarningOnce(message));
|
|
||||||
#else
|
|
||||||
blockStateContainer = BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, tagGetCompoundTag(tagSection, "block_states"))
|
|
||||||
.promotePartial(string -> logBlockDeserializationWarning(chunkPos, sectionYPos, string))
|
|
||||||
.getOrThrow((message) -> logErrorAndReturnException(message));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#if MC_VER < MC_1_21_9
|
|
||||||
blockStateContainer = new PalettedContainer<BlockState>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);
|
|
||||||
#else
|
|
||||||
blockStateContainer = PalettedContainerFactory.create(level.registryAccess()).createForBlockStates();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#if MC_VER < MC_1_18_2
|
|
||||||
biomeContainer = tagSection.contains("biomes", 10)
|
|
||||||
? biomeCodec.parse(NbtOps.INSTANCE, tagSection.getCompound("biomes")).promotePartial(string -> logErrors(chunkPos, sectionYPos, string)).getOrThrow(false, (message) -> logWarningOnce(message))
|
|
||||||
: new PalettedContainer<Biome>(biomes, biomes.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
|
|
||||||
#else
|
|
||||||
|
|
||||||
|
|
||||||
boolean containsBiomes;
|
|
||||||
#if MC_VER < MC_1_21_5
|
|
||||||
containsBiomes = tagSection.contains("biomes", 10);
|
|
||||||
#else
|
|
||||||
containsBiomes = tagSection.contains("biomes");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (containsBiomes)
|
|
||||||
{
|
|
||||||
#if MC_VER < MC_1_20_6
|
|
||||||
biomeContainer = biomeCodec.parse(NbtOps.INSTANCE, tagGetCompoundTag(tagSection, "biomes"))
|
|
||||||
.promotePartial(string -> logBiomeDeserializationWarning(chunkPos, sectionYIndex, (String) string))
|
|
||||||
.getOrThrow(false, (message) -> logParsingWarningOnce(message));
|
|
||||||
#else
|
|
||||||
biomeContainer = biomeCodec.parse(NbtOps.INSTANCE, tagGetCompoundTag(tagSection, "biomes"))
|
|
||||||
.promotePartial(string -> logBiomeDeserializationWarning(chunkPos, sectionYIndex, (String) string))
|
|
||||||
.getOrThrow((message) -> logErrorAndReturnException(message));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#if MC_VER < MC_1_21_3
|
|
||||||
biomeContainer = new PalettedContainer<Holder<Biome>>(
|
|
||||||
biomes.asHolderIdMap(),
|
|
||||||
biomes.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
|
|
||||||
#elif MC_VER < MC_1_21_9
|
|
||||||
biomeContainer = new PalettedContainer<Holder<Biome>>(biomes.asHolderIdMap(),
|
|
||||||
biomes.getOrThrow(Biomes.PLAINS),
|
|
||||||
PalettedContainer.Strategy.SECTION_BIOMES);
|
|
||||||
#else
|
|
||||||
biomeContainer = PalettedContainerFactory.create(level.registryAccess()).createForBiomes();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if MC_VER < MC_1_20_1
|
|
||||||
chunkSections[sectionId] = new LevelChunkSection(sectionYPos, blockStateContainer, biomeContainer);
|
|
||||||
#else
|
|
||||||
chunkSections[sectionId] = new LevelChunkSection(blockStateContainer, biomeContainer);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return chunkSections;
|
|
||||||
}
|
|
||||||
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 = tagGetString(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
|
|
||||||
}
|
|
||||||
private static void readHeightmaps(LevelChunk chunk, CompoundTag chunkData)
|
|
||||||
{
|
|
||||||
CompoundTag tagHeightmaps = tagGetCompoundTag(chunkData, "Heightmaps");
|
|
||||||
if (tagHeightmaps != null)
|
|
||||||
{
|
|
||||||
for (Heightmap.Types type : ChunkStatus.FULL.heightmapsAfter())
|
|
||||||
{
|
|
||||||
String heightmap = type.getSerializationKey();
|
|
||||||
#if MC_VER < MC_1_21_5
|
|
||||||
if (tagHeightmaps.contains(heightmap, 12))
|
|
||||||
{
|
|
||||||
chunk.setHeightmap(type, tagHeightmaps.getLongArray(heightmap));
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (tagHeightmaps.contains(heightmap))
|
|
||||||
{
|
|
||||||
Optional<long[]> optionalHeightmap = tagHeightmaps.getLongArray(heightmap);
|
|
||||||
if (optionalHeightmap.isPresent())
|
|
||||||
{
|
|
||||||
chunk.setHeightmap(type, optionalHeightmap.get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
Heightmap.primeHeightmaps(chunk, ChunkStatus.FULL.heightmapsAfter());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// commented out as a test as of 2025-06-04 to see if this is actually necessary for DH
|
|
||||||
// DH probably doesn't need any chunk post-processing data
|
|
||||||
//private static void readPostPocessings(LevelChunk chunk, CompoundTag chunkData)
|
|
||||||
//{
|
|
||||||
// ListTag tagPostProcessings = tagGetListTag(chunkData,"PostProcessing", 9);
|
|
||||||
// if (tagPostProcessings != null)
|
|
||||||
// {
|
|
||||||
// for (int i = 0; i < tagPostProcessings.size(); ++i)
|
|
||||||
// {
|
|
||||||
// ListTag listTag3 = tagGetListTag(tagPostProcessings, i);
|
|
||||||
// for (int j = 0; j < listTag3.size(); ++j)
|
|
||||||
// {
|
|
||||||
// #if MC_VER < MC_1_21_3
|
|
||||||
// chunk.addPackedPostProcess(listTag3.getShort(j), i);
|
|
||||||
// #else
|
|
||||||
// chunk.addPackedPostProcess(ShortList.of(tagGetShort(listTag3, j)), i);
|
|
||||||
// #endif
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
#if MC_VER >= MC_1_18_2
|
|
||||||
private static BlendingData readBlendingData(CompoundTag chunkData)
|
|
||||||
{
|
|
||||||
BlendingData blendingData = null;
|
|
||||||
|
|
||||||
|
|
||||||
boolean containsBlendingData;
|
|
||||||
#if MC_VER < MC_1_21_5
|
|
||||||
containsBlendingData = chunkData.contains("blending_data", 10);
|
|
||||||
#else
|
|
||||||
containsBlendingData = chunkData.contains("blending_data");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (containsBlendingData)
|
|
||||||
{
|
|
||||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
|
||||||
Dynamic<CompoundTag> blendingDataTag = new Dynamic(NbtOps.INSTANCE, chunkData.getCompound("blending_data"));
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
#if MC_VER < MC_1_21_3
|
|
||||||
blendingData = BlendingData.CODEC.parse(blendingDataTag).resultOrPartial((message) -> logParsingWarningOnce(message)).orElse(null);
|
|
||||||
#else
|
|
||||||
// blending data appears to have changed as of 1.21.6 causing a class cast exception here due to it being wrapped in a Java.Optional
|
|
||||||
blendingData = BlendingData.unpack(BlendingData.Packed.CODEC.parse(blendingDataTag).resultOrPartial((message) -> logParsingWarningOnce(message)).orElse(null));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
String message = e.getMessage();
|
|
||||||
if (message == null || message.trim().isEmpty())
|
|
||||||
{
|
|
||||||
message = "Failed to parse blending data";
|
|
||||||
}
|
|
||||||
|
|
||||||
logParsingWarningOnce(message, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return blendingData;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//=====================//
|
|
||||||
// read chunk lighting //
|
|
||||||
//=====================//
|
|
||||||
|
|
||||||
/**
|
|
||||||
* https://minecraft.wiki/w/Chunk_format
|
|
||||||
*/
|
|
||||||
public static CombinedChunkLightStorage readLight(ChunkAccess chunk, CompoundTag chunkData)
|
|
||||||
{
|
|
||||||
#if MC_VER <= MC_1_17_1
|
|
||||||
// MC 1.16 and 1.17 doesn't have the necessary NBT info
|
|
||||||
return null;
|
|
||||||
#else
|
|
||||||
|
|
||||||
CombinedChunkLightStorage combinedStorage = new CombinedChunkLightStorage(ChunkWrapper.getInclusiveMinBuildHeight(chunk), ChunkWrapper.getExclusiveMaxBuildHeight(chunk));
|
|
||||||
ChunkLightStorage blockLightStorage = combinedStorage.blockLightStorage;
|
|
||||||
ChunkLightStorage skyLightStorage = combinedStorage.skyLightStorage;
|
|
||||||
|
|
||||||
boolean foundSkyLight = false;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//===================//
|
|
||||||
// get NBT tags info //
|
|
||||||
//===================//
|
|
||||||
|
|
||||||
Tag chunkSectionTags = chunkData.get("sections");
|
|
||||||
if (chunkSectionTags == null)
|
|
||||||
{
|
|
||||||
if (!lightingSectionErrorLogged)
|
|
||||||
{
|
|
||||||
lightingSectionErrorLogged = true;
|
|
||||||
LOGGER.error("No sections found for chunk at pos ["+chunk.getPos()+"] chunk data may be out of date.");
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
else if (!(chunkSectionTags instanceof ListTag))
|
|
||||||
{
|
|
||||||
if (!lightingSectionErrorLogged)
|
|
||||||
{
|
|
||||||
lightingSectionErrorLogged = true;
|
|
||||||
LOGGER.error("Chunk section tag list have unexpected type ["+chunkSectionTags.getClass().getName()+"], expected ["+ListTag.class.getName()+"].");
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
ListTag chunkSectionListTag = (ListTag) chunkSectionTags;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//===================//
|
|
||||||
// get lighting info //
|
|
||||||
//===================//
|
|
||||||
|
|
||||||
for (int sectionIndex = 0; sectionIndex < chunkSectionListTag.size(); sectionIndex++)
|
|
||||||
{
|
|
||||||
Tag chunkSectionTag = chunkSectionListTag.get(sectionIndex);
|
|
||||||
if (!(chunkSectionTag instanceof CompoundTag))
|
|
||||||
{
|
|
||||||
if (!lightingSectionErrorLogged)
|
|
||||||
{
|
|
||||||
lightingSectionErrorLogged = true;
|
|
||||||
LOGGER.error("Chunk section tag has an unexpected type ["+chunkSectionTag.getClass().getName()+"], expected ["+CompoundTag.class.getName()+"].");
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
CompoundTag chunkSectionCompoundTag = (CompoundTag) chunkSectionTag;
|
|
||||||
|
|
||||||
|
|
||||||
// if null all lights = 0
|
|
||||||
byte[] blockLightNibbleArray = tagGetByteArray(chunkSectionCompoundTag, "BlockLight");
|
|
||||||
byte[] skyLightNibbleArray = tagGetByteArray(chunkSectionCompoundTag, "SkyLight");
|
|
||||||
|
|
||||||
if (blockLightNibbleArray != null
|
|
||||||
&& skyLightNibbleArray != null)
|
|
||||||
{
|
|
||||||
// if any sky light was found then all lights above will be max brightness
|
|
||||||
if (skyLightNibbleArray.length != 0)
|
|
||||||
{
|
|
||||||
foundSkyLight = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int relX = 0; relX < LodUtil.CHUNK_WIDTH; relX++)
|
|
||||||
{
|
|
||||||
for (int relZ = 0; relZ < LodUtil.CHUNK_WIDTH; relZ++)
|
|
||||||
{
|
|
||||||
// chunk sections are also 16 blocks tall
|
|
||||||
for (int relY = 0; relY < LodUtil.CHUNK_WIDTH; relY++)
|
|
||||||
{
|
|
||||||
int blockPosIndex = relY*16*16 + relZ*16 + relX;
|
|
||||||
byte blockLight = (blockLightNibbleArray.length == 0) ? 0 : getNibbleAtIndex(blockLightNibbleArray, blockPosIndex);
|
|
||||||
byte skyLight = (skyLightNibbleArray.length == 0) ? 0 : getNibbleAtIndex(skyLightNibbleArray, blockPosIndex);
|
|
||||||
if (skyLightNibbleArray.length == 0 && foundSkyLight)
|
|
||||||
{
|
|
||||||
skyLight = LodUtil.MAX_MC_LIGHT;
|
|
||||||
}
|
|
||||||
|
|
||||||
int y = relY + (sectionIndex * LodUtil.CHUNK_WIDTH) + ChunkWrapper.getInclusiveMinBuildHeight(chunk);
|
|
||||||
blockLightStorage.set(relX, y, relZ, blockLight);
|
|
||||||
skyLightStorage.set(relX, y, relZ, skyLight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return combinedStorage;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
/** source: https://minecraft.wiki/w/Chunk_format#Block_Format */
|
|
||||||
private static byte getNibbleAtIndex(byte[] arr, int index)
|
|
||||||
{
|
|
||||||
if (index % 2 == 0)
|
|
||||||
{
|
|
||||||
return (byte)(arr[index/2] & 0x0F);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return (byte)((arr[index/2]>>4) & 0x0F);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//=========//
|
|
||||||
// logging //
|
|
||||||
//=========//
|
|
||||||
|
|
||||||
private static void logBlockDeserializationWarning(ChunkPos chunkPos, int sectionYIndex, String message)
|
|
||||||
{
|
|
||||||
LOGGED_ERROR_MESSAGE_MAP.computeIfAbsent(message, (newMessage) ->
|
|
||||||
{
|
|
||||||
LOGGER.warn("Unable to deserialize blocks for chunk section [" + chunkPos.x + ", " + sectionYIndex + ", " + chunkPos.z + "], error: ["+newMessage+"]. " +
|
|
||||||
"This can probably be ignored, although if your world looks wrong, optimizing it via the single player menu then deleting your DH database(s) should fix the problem.");
|
|
||||||
|
|
||||||
return newMessage;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
private static void logBiomeDeserializationWarning(ChunkPos chunkPos, int sectionYIndex, String message)
|
|
||||||
{
|
|
||||||
LOGGED_ERROR_MESSAGE_MAP.computeIfAbsent(message, (newMessage) ->
|
|
||||||
{
|
|
||||||
LOGGER.warn("Unable to deserialize biomes for chunk section [" + chunkPos.x + ", " + sectionYIndex + ", " + chunkPos.z + "], error: ["+newMessage+"]. " +
|
|
||||||
"This can probably be ignored, although if your world looks wrong, optimizing it via the single player menu then deleting your DH database(s) should fix the problem.");
|
|
||||||
|
|
||||||
return newMessage;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void logParsingWarningOnce(String message) { logParsingWarningOnce(message, null); }
|
|
||||||
private static void logParsingWarningOnce(String message, Exception e)
|
|
||||||
{
|
|
||||||
if (message == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGGED_ERROR_MESSAGE_MAP.computeIfAbsent(message, (newMessage) ->
|
|
||||||
{
|
|
||||||
LOGGER.warn("Parsing error: ["+newMessage+"]. " +
|
|
||||||
"This can probably be ignored, although if your world looks wrong, optimizing it via the single player menu then deleting your DH database(s) should fix the problem.",
|
|
||||||
e);
|
|
||||||
|
|
||||||
return newMessage;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private static RuntimeException logErrorAndReturnException(String message)
|
|
||||||
{
|
|
||||||
LOGGED_ERROR_MESSAGE_MAP.computeIfAbsent(message, (newMessage) ->
|
|
||||||
{
|
|
||||||
LOGGER.warn("Parsing error: ["+newMessage+"]. " +
|
|
||||||
"This can probably be ignored, although if your world looks wrong, optimizing it via the single player menu then deleting your DH database(s) should fix the problem.");
|
|
||||||
|
|
||||||
return newMessage;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Currently we want to ignore these errors, if returning null is a problem, we can change this later
|
|
||||||
return null; //new RuntimeException(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//====================//
|
|
||||||
// tag helper methods //
|
|
||||||
//====================//
|
|
||||||
|
|
||||||
// TODO move into separate file (this file is getting long)
|
|
||||||
// these tag helpers are to simplify tag accessing between MC versions
|
|
||||||
|
|
||||||
/** defaults to "false" if the tag isn't present */
|
|
||||||
private static boolean tagGetBoolean(CompoundTag tag, String key)
|
|
||||||
{
|
|
||||||
#if MC_VER < MC_1_21_5
|
|
||||||
return tag.getBoolean(key);
|
|
||||||
#else
|
|
||||||
return tag.getBoolean(key).orElse(false);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/** defaults to "0" if the tag isn't present */
|
|
||||||
private static byte tagGetByte(CompoundTag tag, String key)
|
|
||||||
{
|
|
||||||
#if MC_VER < MC_1_21_5
|
|
||||||
return tag.getByte(key);
|
|
||||||
#else
|
|
||||||
return tag.getByte(key).orElse((byte)0);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/** defaults to "0" if the tag isn't present */
|
|
||||||
private static short tagGetShort(ListTag tag, int index)
|
|
||||||
{
|
|
||||||
#if MC_VER < MC_1_21_5
|
|
||||||
return tag.getShort(index);
|
|
||||||
#else
|
|
||||||
return tag.getShort(index).orElse((short)0);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/** defaults to "0" if the tag isn't present */
|
|
||||||
private static int tagGetInt(CompoundTag tag, String key)
|
|
||||||
{
|
|
||||||
#if MC_VER < MC_1_21_5
|
|
||||||
return tag.getInt(key);
|
|
||||||
#else
|
|
||||||
return tag.getInt(key).orElse(0);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/** defaults to "0" if the tag isn't present */
|
|
||||||
private static long tagGetLong(CompoundTag tag, String key)
|
|
||||||
{
|
|
||||||
#if MC_VER < MC_1_21_5
|
|
||||||
return tag.getInt(key);
|
|
||||||
#else
|
|
||||||
return tag.getLong(key).orElse(0L);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** defaults to null if the tag isn't present */
|
|
||||||
@Nullable
|
|
||||||
private static String tagGetString(CompoundTag tag, String key)
|
|
||||||
{
|
|
||||||
#if MC_VER < MC_1_21_5
|
|
||||||
return tag.getString(key);
|
|
||||||
#else
|
|
||||||
return tag.getString(key).orElse(null);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/** defaults to null if the tag isn't present */
|
|
||||||
@Nullable
|
|
||||||
private static byte[] tagGetByteArray(CompoundTag tag, String key)
|
|
||||||
{
|
|
||||||
#if MC_VER < MC_1_21_5
|
|
||||||
return tag.getByteArray(key);
|
|
||||||
#else
|
|
||||||
return tag.getByteArray(key).orElse(null);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** defaults to null if the tag isn't present */
|
|
||||||
@Nullable
|
|
||||||
private static CompoundTag tagGetCompoundTag(CompoundTag tag, String key)
|
|
||||||
{
|
|
||||||
#if MC_VER < MC_1_21_5
|
|
||||||
return tag.getCompound(key);
|
|
||||||
#else
|
|
||||||
return tag.getCompound(key).orElse(null);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
/** defaults to null if the tag isn't present */
|
|
||||||
@Nullable
|
|
||||||
private static CompoundTag tagGetCompoundTag(ListTag tag, int index)
|
|
||||||
{
|
|
||||||
#if MC_VER < MC_1_21_5
|
|
||||||
return tag.getCompound(index);
|
|
||||||
#else
|
|
||||||
return tag.getCompound(index).orElse(null);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* defaults to null if the tag isn't present
|
|
||||||
* @param elementType unused after MC 1.21.5
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
private static ListTag tagGetListTag(CompoundTag tag, String key, int elementType)
|
|
||||||
{
|
|
||||||
#if MC_VER < MC_1_21_5
|
|
||||||
return tag.getList(key, elementType);
|
|
||||||
#else
|
|
||||||
return tag.getList(key).orElse(null);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/** defaults to null if the tag isn't present */
|
|
||||||
@Nullable
|
|
||||||
private static ListTag tagGetListTag(ListTag tag, int index)
|
|
||||||
{
|
|
||||||
#if MC_VER < MC_1_21_5
|
|
||||||
return tag.getList(index);
|
|
||||||
#else
|
|
||||||
return tag.getList(index).orElse(null);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//================//
|
|
||||||
// helper classes //
|
|
||||||
//================//
|
|
||||||
|
|
||||||
public static class CombinedChunkLightStorage
|
|
||||||
{
|
|
||||||
public ChunkLightStorage blockLightStorage;
|
|
||||||
public ChunkLightStorage skyLightStorage;
|
|
||||||
|
|
||||||
public CombinedChunkLightStorage(int minY, int maxY)
|
|
||||||
{
|
|
||||||
this.blockLightStorage = ChunkLightStorage.createBlockLightStorage(minY, maxY);
|
|
||||||
this.skyLightStorage = ChunkLightStorage.createSkyLightStorage(minY, maxY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
+16
-16
@@ -1,6 +1,6 @@
|
|||||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject;
|
package com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject;
|
||||||
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.chunkFileHandling.ChunkFileReader;
|
||||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.nbt.NbtIo;
|
import net.minecraft.nbt.NbtIo;
|
||||||
@@ -55,7 +55,7 @@ public class RegionFileStorageExternalCache implements AutoCloseable
|
|||||||
public RegionFileStorageExternalCache(RegionFileStorage storage) { this.storage = storage; }
|
public RegionFileStorageExternalCache(RegionFileStorage storage) { this.storage = storage; }
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public RegionFile getRegionFile(ChunkPos pos) throws IOException
|
public RegionFile getRegionFile(ChunkPos chunkPos) throws IOException
|
||||||
{
|
{
|
||||||
if (this.storage == null)
|
if (this.storage == null)
|
||||||
{
|
{
|
||||||
@@ -70,8 +70,8 @@ public class RegionFileStorageExternalCache implements AutoCloseable
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
long posLong = ChunkPos.asLong(pos.getRegionX(), pos.getRegionZ());
|
long chunkPosLong = ChunkPos.asLong(chunkPos.getRegionX(), chunkPos.getRegionZ());
|
||||||
RegionFile rFile = null;
|
RegionFile regionFile = null;
|
||||||
|
|
||||||
// Check vanilla cache
|
// Check vanilla cache
|
||||||
int retryCount = 0;
|
int retryCount = 0;
|
||||||
@@ -85,7 +85,7 @@ public class RegionFileStorageExternalCache implements AutoCloseable
|
|||||||
this.getRegionFileLock.lock();
|
this.getRegionFileLock.lock();
|
||||||
|
|
||||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||||
rFile = this.storage.getRegionFile(pos);
|
regionFile = this.storage.getRegionFile(chunkPos);
|
||||||
|
|
||||||
// keeping the region cache size low helps prevent concurrency issues
|
// keeping the region cache size low helps prevent concurrency issues
|
||||||
if (this.storage.regionCache.size() > 150) // max 256
|
if (this.storage.regionCache.size() > 150) // max 256
|
||||||
@@ -97,7 +97,7 @@ public class RegionFileStorageExternalCache implements AutoCloseable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
rFile = this.storage.regionCache.getOrDefault(posLong, null);
|
regionFile = this.storage.regionCache.getOrDefault(chunkPosLong, null);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -139,19 +139,19 @@ public class RegionFileStorageExternalCache implements AutoCloseable
|
|||||||
|
|
||||||
if (retryCount >= maxRetryCount)
|
if (retryCount >= maxRetryCount)
|
||||||
{
|
{
|
||||||
BatchGenerationEnvironment.CHUNK_LOAD_LOGGER.warn("Concurrency issue detected when getting region file for chunk at [" + pos + "].");
|
ChunkFileReader.CHUNK_LOAD_LOGGER.warn("Concurrency issue detected when getting region file for chunk at [" + chunkPos + "].");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (rFile != null)
|
if (regionFile != null)
|
||||||
{
|
{
|
||||||
return rFile;
|
return regionFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then check our custom cache
|
// Then check our custom cache
|
||||||
for (RegionFileCache cache : this.regionFileCache)
|
for (RegionFileCache cache : this.regionFileCache)
|
||||||
{
|
{
|
||||||
if (cache.pos == posLong)
|
if (cache.pos == chunkPosLong)
|
||||||
{
|
{
|
||||||
return cache.file;
|
return cache.file;
|
||||||
}
|
}
|
||||||
@@ -170,22 +170,22 @@ public class RegionFileStorageExternalCache implements AutoCloseable
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Path regionFilePath = storageFolderPath.resolve("r." + pos.getRegionX() + "." + pos.getRegionZ() + ".mca");
|
Path regionFilePath = storageFolderPath.resolve("r." + chunkPos.getRegionX() + "." + chunkPos.getRegionZ() + ".mca");
|
||||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||||
rFile = new RegionFile(regionFilePath.toFile(), storageFolderPath.toFile(), false);
|
regionFile = new RegionFile(regionFilePath.toFile(), storageFolderPath.toFile(), false);
|
||||||
#elif MC_VER <= MC_1_20_4
|
#elif MC_VER <= MC_1_20_4
|
||||||
rFile = new RegionFile(regionFilePath, storageFolderPath, false);
|
regionFile = new RegionFile(regionFilePath, storageFolderPath, false);
|
||||||
#else
|
#else
|
||||||
rFile = new RegionFile(new RegionStorageInfo("level", null, "level type"), regionFilePath, storageFolderPath, false);
|
regionFile = new RegionFile(new RegionStorageInfo("level", null, "level type"), regionFilePath, storageFolderPath, false);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
this.regionFileCache.add(new RegionFileCache(ChunkPos.asLong(pos.getRegionX(), pos.getRegionZ()), rFile));
|
this.regionFileCache.add(new RegionFileCache(ChunkPos.asLong(chunkPos.getRegionX(), chunkPos.getRegionZ()), regionFile));
|
||||||
while (this.regionFileCache.size() > MAX_CACHE_SIZE)
|
while (this.regionFileCache.size() > MAX_CACHE_SIZE)
|
||||||
{
|
{
|
||||||
this.regionFileCache.poll().file.close();
|
this.regionFileCache.poll().file.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
return rFile;
|
return regionFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+48
-23
@@ -17,7 +17,7 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration;
|
package com.seibel.distanthorizons.common.wrappers.worldGeneration.params;
|
||||||
|
|
||||||
import com.mojang.datafixers.DataFixer;
|
import com.mojang.datafixers.DataFixer;
|
||||||
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
|
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
|
||||||
@@ -27,35 +27,50 @@ import net.minecraft.core.Registry;
|
|||||||
import net.minecraft.core.RegistryAccess;
|
import net.minecraft.core.RegistryAccess;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.ThreadedLevelLightEngine;
|
|
||||||
import net.minecraft.world.level.biome.Biome;
|
import net.minecraft.world.level.biome.Biome;
|
||||||
import net.minecraft.world.level.biome.BiomeManager;
|
import net.minecraft.world.level.biome.BiomeManager;
|
||||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||||
#if MC_VER >= MC_1_18_2
|
#if MC_VER >= MC_1_18_2
|
||||||
import net.minecraft.world.level.chunk.storage.ChunkScanAccess;
|
import net.minecraft.world.level.chunk.storage.ChunkScanAccess;
|
||||||
#endif
|
#endif
|
||||||
import net.minecraft.world.level.levelgen.WorldGenSettings;
|
|
||||||
#if MC_VER < MC_1_19_2
|
#if MC_VER < MC_1_19_2
|
||||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager;
|
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager;
|
||||||
|
#elif MC_VER < MC_1_19_2
|
||||||
|
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager;
|
||||||
#else
|
#else
|
||||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
|
||||||
import net.minecraft.world.level.levelgen.RandomState;
|
import net.minecraft.world.level.levelgen.RandomState;
|
||||||
#if MC_VER >= MC_1_19_4
|
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
||||||
import net.minecraft.world.level.levelgen.WorldOptions;
|
|
||||||
import net.minecraft.core.registries.Registries;
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
import net.minecraft.world.level.storage.WorldData;
|
import net.minecraft.world.level.storage.WorldData;
|
||||||
|
|
||||||
public final class GlobalParameters
|
#if MC_VER < MC_1_19_4
|
||||||
|
#elif MC_VER < MC_1_21_3
|
||||||
|
import net.minecraft.core.registries.Registries;
|
||||||
|
#else
|
||||||
|
import net.minecraft.core.registries.Registries;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_19_4
|
||||||
|
import net.minecraft.world.level.levelgen.WorldGenSettings;
|
||||||
|
#else
|
||||||
|
import net.minecraft.world.level.levelgen.WorldOptions;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles parameters that are relevant for the entire MC world.
|
||||||
|
*
|
||||||
|
* @see ThreadWorldGenParams
|
||||||
|
*/
|
||||||
|
public final class GlobalWorldGenParams
|
||||||
{
|
{
|
||||||
public final ChunkGenerator generator;
|
public final ChunkGenerator generator;
|
||||||
public final IDhServerLevel lodLevel;
|
public final IDhServerLevel dhServerLevel;
|
||||||
public final ServerLevel level;
|
public final ServerLevel mcServerLevel;
|
||||||
public final Registry<Biome> biomes;
|
public final Registry<Biome> biomes;
|
||||||
public final RegistryAccess registry;
|
public final RegistryAccess registry;
|
||||||
public final long worldSeed;
|
public final long worldSeed;
|
||||||
public final DataFixer fixerUpper;
|
public final DataFixer dataFixer;
|
||||||
|
|
||||||
#if MC_VER < MC_1_19_2
|
#if MC_VER < MC_1_19_2
|
||||||
public final StructureManager structures;
|
public final StructureManager structures;
|
||||||
@@ -72,15 +87,21 @@ public final class GlobalParameters
|
|||||||
|
|
||||||
#if MC_VER >= MC_1_18_2
|
#if MC_VER >= MC_1_18_2
|
||||||
public final BiomeManager biomeManager;
|
public final BiomeManager biomeManager;
|
||||||
public final ChunkScanAccess chunkScanner; // FIXME: Figure out if this is actually needed
|
public final ChunkScanAccess chunkScanner;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public GlobalParameters(IDhServerLevel lodLevel)
|
|
||||||
{
|
|
||||||
this.lodLevel = lodLevel;
|
|
||||||
|
|
||||||
this.level = ((ServerLevelWrapper) lodLevel.getServerLevelWrapper()).getWrappedMcObject();
|
|
||||||
MinecraftServer server = this.level.getServer();
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
|
||||||
|
public GlobalWorldGenParams(IDhServerLevel dhServerLevel)
|
||||||
|
{
|
||||||
|
this.dhServerLevel = dhServerLevel;
|
||||||
|
|
||||||
|
this.mcServerLevel = ((ServerLevelWrapper) dhServerLevel.getServerLevelWrapper()).getWrappedMcObject();
|
||||||
|
MinecraftServer server = this.mcServerLevel.getServer();
|
||||||
WorldData worldData = server.getWorldData();
|
WorldData worldData = server.getWorldData();
|
||||||
this.registry = server.registryAccess();
|
this.registry = server.registryAccess();
|
||||||
|
|
||||||
@@ -99,15 +120,19 @@ public final class GlobalParameters
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if MC_VER >= MC_1_18_2
|
#if MC_VER >= MC_1_18_2
|
||||||
this.biomeManager = new BiomeManager(this.level, BiomeManager.obfuscateSeed(this.worldSeed));
|
this.biomeManager = new BiomeManager(this.mcServerLevel, BiomeManager.obfuscateSeed(this.worldSeed));
|
||||||
this.chunkScanner = this.level.getChunkSource().chunkScanner();
|
this.chunkScanner = this.mcServerLevel.getChunkSource().chunkScanner();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
this.structures = server.getStructureManager();
|
this.structures = server.getStructureManager();
|
||||||
this.generator = this.level.getChunkSource().getGenerator();
|
this.generator = this.mcServerLevel.getChunkSource().getGenerator();
|
||||||
this.fixerUpper = server.getFixerUpper();
|
this.dataFixer = server.getFixerUpper();
|
||||||
|
|
||||||
#if MC_VER >= MC_1_19_2
|
#if MC_VER >= MC_1_19_2
|
||||||
this.randomState = this.level.getChunkSource().randomState();
|
this.randomState = this.mcServerLevel.getChunkSource().randomState();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
+124
@@ -0,0 +1,124 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.common.wrappers.worldGeneration.params;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.WorldGenStructFeatManager;
|
||||||
|
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.world.level.WorldGenLevel;
|
||||||
|
#if MC_VER >= MC_1_18_2
|
||||||
|
import net.minecraft.world.level.levelgen.structure.StructureCheck;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public final class ThreadWorldGenParams
|
||||||
|
{
|
||||||
|
private static final ThreadLocal<ThreadWorldGenParams> LOCAL_PARAM_REF = new ThreadLocal<>();
|
||||||
|
|
||||||
|
|
||||||
|
final ServerLevel level;
|
||||||
|
public WorldGenStructFeatManager structFeatManager = null;
|
||||||
|
|
||||||
|
#if MC_VER >= MC_1_18_2
|
||||||
|
public StructureCheck structCheck;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
boolean isValid = true;
|
||||||
|
|
||||||
|
// used for some older MC versions
|
||||||
|
private static GlobalWorldGenParams previousGlobalWorldGenParams = null;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
|
||||||
|
public static ThreadWorldGenParams getOrMake(GlobalWorldGenParams globalParams)
|
||||||
|
{
|
||||||
|
ThreadWorldGenParams threadParam = LOCAL_PARAM_REF.get();
|
||||||
|
if (threadParam != null
|
||||||
|
&& threadParam.isValid
|
||||||
|
&& threadParam.level == globalParams.mcServerLevel)
|
||||||
|
{
|
||||||
|
return threadParam;
|
||||||
|
}
|
||||||
|
|
||||||
|
threadParam = new ThreadWorldGenParams(globalParams);
|
||||||
|
LOCAL_PARAM_REF.set(threadParam);
|
||||||
|
return threadParam;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ThreadWorldGenParams(GlobalWorldGenParams param)
|
||||||
|
{
|
||||||
|
previousGlobalWorldGenParams = param;
|
||||||
|
|
||||||
|
this.level = param.mcServerLevel;
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_18_2
|
||||||
|
this.structFeatManager = new WorldGenStructFeatManager(param.worldGenSettings, this.level);
|
||||||
|
#elif MC_VER < MC_1_19_2
|
||||||
|
this.structCheck = this.createStructureCheck(param);
|
||||||
|
#else
|
||||||
|
this.structCheck = new StructureCheck(param.chunkScanner, param.registry, param.structures,
|
||||||
|
param.mcServerLevel.dimension(), param.generator, param.randomState, this.level, param.generator.getBiomeSource(), param.worldSeed,
|
||||||
|
param.dataFixer);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==========//
|
||||||
|
// builders //
|
||||||
|
//==========//
|
||||||
|
|
||||||
|
public void makeStructFeatManager(WorldGenLevel genLevel, GlobalWorldGenParams param)
|
||||||
|
{
|
||||||
|
#if MC_VER < MC_1_18_2
|
||||||
|
this.structFeatManager = new WorldGenStructFeatManager(param.worldGenSettings, genLevel);
|
||||||
|
#elif MC_VER < MC_1_19_4
|
||||||
|
this.structFeatManager = new WorldGenStructFeatManager(param.worldGenSettings, genLevel, this.structCheck);
|
||||||
|
#else
|
||||||
|
this.structFeatManager = new WorldGenStructFeatManager(param.worldOptions, genLevel, this.structCheck);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_18_2
|
||||||
|
#elif MC_VER < MC_1_19_2
|
||||||
|
public void recreateStructureCheck()
|
||||||
|
{
|
||||||
|
if (previousGlobalWorldGenParams != null)
|
||||||
|
{
|
||||||
|
this.structCheck = this.createStructureCheck(previousGlobalWorldGenParams);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private StructureCheck createStructureCheck(GlobalWorldGenParams param)
|
||||||
|
{
|
||||||
|
return new StructureCheck(param.chunkScanner, param.registry, param.structures,
|
||||||
|
param.mcServerLevel.dimension(), param.generator, this.level, param.generator.getBiomeSource(), param.worldSeed,
|
||||||
|
param.dataFixer);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
public void recreateStructureCheck() { /* do nothing */ }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+7
-7
@@ -1,7 +1,7 @@
|
|||||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration.step;
|
package com.seibel.distanthorizons.common.wrappers.worldGeneration.step;
|
||||||
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters;
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.params.ThreadWorldGenParams;
|
||||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion;
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion;
|
||||||
import com.seibel.distanthorizons.core.util.gridList.ArrayGridList;
|
import com.seibel.distanthorizons.core.util.gridList.ArrayGridList;
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
@@ -19,7 +19,7 @@ import net.minecraft.world.level.chunk.status.ChunkStatus;
|
|||||||
public abstract class AbstractWorldGenStep
|
public abstract class AbstractWorldGenStep
|
||||||
{
|
{
|
||||||
public abstract void generateGroup(
|
public abstract void generateGroup(
|
||||||
ThreadedParameters tParams, DhLitWorldGenRegion worldGenRegion,
|
ThreadWorldGenParams tParams, DhLitWorldGenRegion worldGenRegion,
|
||||||
ArrayGridList<ChunkWrapper> chunkWrappers);
|
ArrayGridList<ChunkWrapper> chunkWrappers);
|
||||||
|
|
||||||
public abstract ChunkStatus getChunkStatus();
|
public abstract ChunkStatus getChunkStatus();
|
||||||
@@ -27,26 +27,26 @@ public abstract class AbstractWorldGenStep
|
|||||||
|
|
||||||
|
|
||||||
/** @return the list of chunks that have an earlier status and can be generated */
|
/** @return the list of chunks that have an earlier status and can be generated */
|
||||||
protected ArrayList<ChunkAccess> getChunksToGenerate(List<ChunkWrapper> chunkWrappers)
|
protected ArrayList<ChunkWrapper> getChunkWrappersToGenerate(List<ChunkWrapper> chunkWrappers)
|
||||||
{
|
{
|
||||||
ArrayList<ChunkAccess> chunksToGenerate = new ArrayList<>();
|
ArrayList<ChunkWrapper> chunkWrappersToGenerate = new ArrayList<>(chunkWrappers.size());
|
||||||
|
|
||||||
for (ChunkWrapper chunkWrapper : chunkWrappers)
|
for (ChunkWrapper chunkWrapper : chunkWrappers)
|
||||||
{
|
{
|
||||||
ChunkAccess chunk = chunkWrapper.getChunk();
|
ChunkAccess chunk = chunkWrapper.getChunk();
|
||||||
if (chunkWrapper.getStatus().isOrAfter(this.getChunkStatus()))
|
if (chunkWrapper.getStatus().isOrAfter(this.getChunkStatus()))
|
||||||
{
|
{
|
||||||
// this chunk has already generated this step
|
// this chunk has already been generated up to this step
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (chunk instanceof ProtoChunk)
|
else if (chunk instanceof ProtoChunk)
|
||||||
{
|
{
|
||||||
chunkWrapper.trySetStatus(this.getChunkStatus());
|
chunkWrapper.trySetStatus(this.getChunkStatus());
|
||||||
chunksToGenerate.add(chunk);
|
chunkWrappersToGenerate.add(chunkWrapper);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return chunksToGenerate;
|
return chunkWrappersToGenerate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+21
-20
@@ -23,13 +23,11 @@ import java.util.ArrayList;
|
|||||||
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters;
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.params.ThreadWorldGenParams;
|
||||||
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion;
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion;
|
||||||
import com.seibel.distanthorizons.core.util.gridList.ArrayGridList;
|
import com.seibel.distanthorizons.core.util.gridList.ArrayGridList;
|
||||||
import net.minecraft.server.level.WorldGenRegion;
|
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
|
||||||
|
|
||||||
#if MC_VER >= MC_1_18_2
|
#if MC_VER >= MC_1_18_2
|
||||||
import net.minecraft.world.level.levelgen.blending.Blender;
|
import net.minecraft.world.level.levelgen.blending.Blender;
|
||||||
@@ -66,47 +64,50 @@ public final class StepBiomes extends AbstractWorldGenStep
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void generateGroup(
|
public void generateGroup(
|
||||||
ThreadedParameters tParams, DhLitWorldGenRegion worldGenRegion,
|
ThreadWorldGenParams tParams, DhLitWorldGenRegion worldGenRegion,
|
||||||
ArrayGridList<ChunkWrapper> chunkWrappers)
|
ArrayGridList<ChunkWrapper> chunkWrappers)
|
||||||
{
|
{
|
||||||
ArrayList<ChunkAccess> chunksToDo = this.getChunksToGenerate(chunkWrappers);
|
ArrayList<ChunkWrapper> chunksToDo = this.getChunkWrappersToGenerate(chunkWrappers);
|
||||||
for (ChunkAccess chunk : chunksToDo)
|
for (ChunkWrapper chunkWrapper : chunksToDo)
|
||||||
{
|
{
|
||||||
|
ChunkAccess chunk = chunkWrapper.getChunk();
|
||||||
|
|
||||||
|
|
||||||
#if MC_VER < MC_1_18_2
|
#if MC_VER < MC_1_18_2
|
||||||
this.environment.params.generator.createBiomes(this.environment.params.biomes, chunk);
|
this.environment.globalParams.generator.createBiomes(this.environment.globalParams.biomes, chunk);
|
||||||
#elif MC_VER < MC_1_19_2
|
#elif MC_VER < MC_1_19_2
|
||||||
chunk = this.environment.confirmFutureWasRunSynchronously(
|
chunk = this.environment.confirmFutureWasRunSynchronously(
|
||||||
this.environment.params.generator.createBiomes(
|
this.environment.globalParams.generator.createBiomes(
|
||||||
this.environment.params.biomes,
|
this.environment.globalParams.biomes,
|
||||||
Runnable::run,
|
Runnable::run,
|
||||||
Blender.of(worldGenRegion),
|
Blender.of(worldGenRegion),
|
||||||
tParams.structFeat.forWorldGenRegion(worldGenRegion),
|
tParams.structFeatManager.forWorldGenRegion(worldGenRegion),
|
||||||
chunk)
|
chunk)
|
||||||
);
|
);
|
||||||
#elif MC_VER < MC_1_19_4
|
#elif MC_VER < MC_1_19_4
|
||||||
chunk = this.environment.confirmFutureWasRunSynchronously(
|
chunk = this.environment.confirmFutureWasRunSynchronously(
|
||||||
this.environment.params.generator.createBiomes(
|
this.environment.globalParams.generator.createBiomes(
|
||||||
this.environment.params.biomes,
|
this.environment.globalParams.biomes,
|
||||||
Runnable::run,
|
Runnable::run,
|
||||||
this.environment.params.randomState, Blender.of(worldGenRegion),
|
this.environment.globalParams.randomState, Blender.of(worldGenRegion),
|
||||||
tParams.structFeat.forWorldGenRegion(worldGenRegion),
|
tParams.structFeatManager.forWorldGenRegion(worldGenRegion),
|
||||||
chunk)
|
chunk)
|
||||||
);
|
);
|
||||||
#elif MC_VER < MC_1_21_1
|
#elif MC_VER < MC_1_21_1
|
||||||
chunk = this.environment.confirmFutureWasRunSynchronously(
|
chunk = this.environment.confirmFutureWasRunSynchronously(
|
||||||
this.environment.params.generator.createBiomes(
|
this.environment.globalParams.generator.createBiomes(
|
||||||
Runnable::run,
|
Runnable::run,
|
||||||
this.environment.params.randomState,
|
this.environment.globalParams.randomState,
|
||||||
Blender.of(worldGenRegion),
|
Blender.of(worldGenRegion),
|
||||||
tParams.structFeat.forWorldGenRegion(worldGenRegion),
|
tParams.structFeatManager.forWorldGenRegion(worldGenRegion),
|
||||||
chunk)
|
chunk)
|
||||||
);
|
);
|
||||||
#else
|
#else
|
||||||
chunk = this.environment.confirmFutureWasRunSynchronously(
|
chunk = this.environment.confirmFutureWasRunSynchronously(
|
||||||
this.environment.params.generator.createBiomes(
|
this.environment.globalParams.generator.createBiomes(
|
||||||
this.environment.params.randomState,
|
this.environment.globalParams.randomState,
|
||||||
Blender.of(worldGenRegion),
|
Blender.of(worldGenRegion),
|
||||||
tParams.structFeat.forWorldGenRegion(worldGenRegion),
|
tParams.structFeatManager.forWorldGenRegion(worldGenRegion),
|
||||||
chunk)
|
chunk)
|
||||||
);
|
);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+7
-15
@@ -21,13 +21,12 @@ package com.seibel.distanthorizons.common.wrappers.worldGeneration.step;
|
|||||||
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters;
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.params.ThreadWorldGenParams;
|
||||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion;
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion;
|
||||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
import com.seibel.distanthorizons.core.util.gridList.ArrayGridList;
|
import com.seibel.distanthorizons.core.util.gridList.ArrayGridList;
|
||||||
|
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
|
||||||
import net.minecraft.world.level.levelgen.Heightmap;
|
import net.minecraft.world.level.levelgen.Heightmap;
|
||||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
|
||||||
@@ -37,6 +36,7 @@ import net.minecraft.world.level.chunk.ChunkStatus;
|
|||||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.ConcurrentModificationException;
|
import java.util.ConcurrentModificationException;
|
||||||
|
|
||||||
|
|
||||||
@@ -67,32 +67,24 @@ public final class StepFeatures extends AbstractWorldGenStep
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void generateGroup(
|
public void generateGroup(
|
||||||
ThreadedParameters tParams, DhLitWorldGenRegion worldGenRegion,
|
ThreadWorldGenParams tParams, DhLitWorldGenRegion worldGenRegion,
|
||||||
ArrayGridList<ChunkWrapper> chunkWrappers)
|
ArrayGridList<ChunkWrapper> chunkWrappers)
|
||||||
{
|
{
|
||||||
for (ChunkWrapper chunkWrapper : chunkWrappers)
|
ArrayList<ChunkWrapper> chunksToDo = this.getChunkWrappersToGenerate(chunkWrappers);
|
||||||
|
for (ChunkWrapper chunkWrapper : chunksToDo)
|
||||||
{
|
{
|
||||||
ChunkAccess chunk = chunkWrapper.getChunk();
|
ChunkAccess chunk = chunkWrapper.getChunk();
|
||||||
if (chunkWrapper.getStatus().isOrAfter(STATUS))
|
|
||||||
{
|
|
||||||
// this chunk has already generated this step
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (chunk instanceof ProtoChunk)
|
|
||||||
{
|
|
||||||
chunkWrapper.trySetStatus(STATUS);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
#if MC_VER < MC_1_18_2
|
#if MC_VER < MC_1_18_2
|
||||||
worldGenRegion.setOverrideCenter(chunk.getPos());
|
worldGenRegion.setOverrideCenter(chunk.getPos());
|
||||||
environment.params.generator.applyBiomeDecoration(worldGenRegion, tParams.structFeat);
|
environment.globalParams.generator.applyBiomeDecoration(worldGenRegion, tParams.structFeatManager);
|
||||||
#else
|
#else
|
||||||
if (worldGenRegion.hasChunk(chunkWrapper.getChunkPos().getX(), chunkWrapper.getChunkPos().getZ()))
|
if (worldGenRegion.hasChunk(chunkWrapper.getChunkPos().getX(), chunkWrapper.getChunkPos().getZ()))
|
||||||
{
|
{
|
||||||
this.environment.params.generator.applyBiomeDecoration(worldGenRegion, chunk, tParams.structFeat.forWorldGenRegion(worldGenRegion));
|
this.environment.globalParams.generator.applyBiomeDecoration(worldGenRegion, chunk, tParams.structFeatManager.forWorldGenRegion(worldGenRegion));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
+15
-30
@@ -20,18 +20,14 @@
|
|||||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration.step;
|
package com.seibel.distanthorizons.common.wrappers.worldGeneration.step;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters;
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.params.ThreadWorldGenParams;
|
||||||
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion;
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion;
|
||||||
import com.seibel.distanthorizons.core.util.gridList.ArrayGridList;
|
import com.seibel.distanthorizons.core.util.gridList.ArrayGridList;
|
||||||
import com.seibel.distanthorizons.core.util.objects.UncheckedInterruptedException;
|
|
||||||
import net.minecraft.server.level.WorldGenRegion;
|
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
|
||||||
|
|
||||||
#if MC_VER >= MC_1_18_2
|
#if MC_VER >= MC_1_18_2
|
||||||
import net.minecraft.world.level.levelgen.blending.Blender;
|
import net.minecraft.world.level.levelgen.blending.Blender;
|
||||||
@@ -68,56 +64,45 @@ public final class StepNoise extends AbstractWorldGenStep
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void generateGroup(
|
public void generateGroup(
|
||||||
ThreadedParameters tParams, DhLitWorldGenRegion worldGenRegion,
|
ThreadWorldGenParams tParams, DhLitWorldGenRegion worldGenRegion,
|
||||||
ArrayGridList<ChunkWrapper> chunkWrappers)
|
ArrayGridList<ChunkWrapper> chunkWrappers)
|
||||||
{
|
{
|
||||||
ArrayList<ChunkAccess> chunksToDo = new ArrayList<>();
|
ArrayList<ChunkWrapper> chunksToDo = this.getChunkWrappersToGenerate(chunkWrappers);
|
||||||
|
for (ChunkWrapper chunkWrapper : chunksToDo)
|
||||||
for (ChunkWrapper chunkWrapper : chunkWrappers)
|
|
||||||
{
|
{
|
||||||
ChunkAccess chunk = chunkWrapper.getChunk();
|
ChunkAccess chunk = chunkWrapper.getChunk();
|
||||||
if (chunkWrapper.getStatus().isOrAfter(STATUS))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
chunkWrapper.trySetStatus(STATUS);
|
|
||||||
chunksToDo.add(chunk);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ChunkAccess chunk : chunksToDo)
|
|
||||||
{
|
|
||||||
#if MC_VER < MC_1_17_1
|
#if MC_VER < MC_1_17_1
|
||||||
this.environment.params.generator.fillFromNoise(worldGenRegion, tParams.structFeat, chunk);
|
this.environment.globalParams.generator.fillFromNoise(worldGenRegion, tParams.structFeatManager, chunk);
|
||||||
#elif MC_VER < MC_1_18_2
|
#elif MC_VER < MC_1_18_2
|
||||||
chunk = this.environment.confirmFutureWasRunSynchronously(
|
chunk = this.environment.confirmFutureWasRunSynchronously(
|
||||||
this.environment.params.generator.fillFromNoise(
|
this.environment.globalParams.generator.fillFromNoise(
|
||||||
Runnable::run,
|
Runnable::run,
|
||||||
tParams.structFeat.forWorldGenRegion(worldGenRegion),
|
tParams.structFeatManager.forWorldGenRegion(worldGenRegion),
|
||||||
chunk));
|
chunk));
|
||||||
#elif MC_VER < MC_1_19_2
|
#elif MC_VER < MC_1_19_2
|
||||||
chunk = this.environment.confirmFutureWasRunSynchronously(
|
chunk = this.environment.confirmFutureWasRunSynchronously(
|
||||||
this.environment.params.generator.fillFromNoise(
|
this.environment.globalParams.generator.fillFromNoise(
|
||||||
Runnable::run,
|
Runnable::run,
|
||||||
Blender.of(worldGenRegion),
|
Blender.of(worldGenRegion),
|
||||||
tParams.structFeat.forWorldGenRegion(worldGenRegion),
|
tParams.structFeatManager.forWorldGenRegion(worldGenRegion),
|
||||||
chunk));
|
chunk));
|
||||||
#elif MC_VER < MC_1_21_1
|
#elif MC_VER < MC_1_21_1
|
||||||
chunk = this.environment.confirmFutureWasRunSynchronously(
|
chunk = this.environment.confirmFutureWasRunSynchronously(
|
||||||
this.environment.params.generator.fillFromNoise(
|
this.environment.globalParams.generator.fillFromNoise(
|
||||||
Runnable::run,
|
Runnable::run,
|
||||||
Blender.of(worldGenRegion),
|
Blender.of(worldGenRegion),
|
||||||
this.environment.params.randomState,
|
this.environment.globalParams.randomState,
|
||||||
tParams.structFeat.forWorldGenRegion(worldGenRegion),
|
tParams.structFeatManager.forWorldGenRegion(worldGenRegion),
|
||||||
chunk));
|
chunk));
|
||||||
#else
|
#else
|
||||||
chunk = this.environment.confirmFutureWasRunSynchronously(
|
chunk = this.environment.confirmFutureWasRunSynchronously(
|
||||||
this.environment.params.generator.fillFromNoise(
|
this.environment.globalParams.generator.fillFromNoise(
|
||||||
Blender.of(worldGenRegion),
|
Blender.of(worldGenRegion),
|
||||||
this.environment.params.randomState,
|
this.environment.globalParams.randomState,
|
||||||
tParams.structFeat.forWorldGenRegion(worldGenRegion),
|
tParams.structFeatManager.forWorldGenRegion(worldGenRegion),
|
||||||
chunk));
|
chunk));
|
||||||
#endif
|
#endif
|
||||||
UncheckedInterruptedException.throwIfInterrupted();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-24
@@ -20,17 +20,14 @@
|
|||||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration.step;
|
package com.seibel.distanthorizons.common.wrappers.worldGeneration.step;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters;
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.params.ThreadWorldGenParams;
|
||||||
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion;
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion;
|
||||||
import com.seibel.distanthorizons.core.util.gridList.ArrayGridList;
|
import com.seibel.distanthorizons.core.util.gridList.ArrayGridList;
|
||||||
import net.minecraft.server.level.WorldGenRegion;
|
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
|
||||||
|
|
||||||
#if MC_VER <= MC_1_20_4
|
#if MC_VER <= MC_1_20_4
|
||||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||||
@@ -64,30 +61,14 @@ public final class StepStructureReference extends AbstractWorldGenStep
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void generateGroup(
|
public void generateGroup(
|
||||||
ThreadedParameters tParams, DhLitWorldGenRegion worldGenRegion,
|
ThreadWorldGenParams tParams, DhLitWorldGenRegion worldGenRegion,
|
||||||
ArrayGridList<ChunkWrapper> chunkWrappers)
|
ArrayGridList<ChunkWrapper> chunkWrappers)
|
||||||
{
|
{
|
||||||
ArrayList<ChunkAccess> chunksToDo = new ArrayList<ChunkAccess>();
|
ArrayList<ChunkWrapper> chunksToDo = this.getChunkWrappersToGenerate(chunkWrappers);
|
||||||
|
for (ChunkWrapper chunkWrapper : chunksToDo)
|
||||||
for (ChunkWrapper chunkWrapper : chunkWrappers)
|
|
||||||
{
|
{
|
||||||
ChunkAccess chunk = chunkWrapper.getChunk();
|
ChunkAccess chunk = chunkWrapper.getChunk();
|
||||||
if (chunkWrapper.getStatus().isOrAfter(STATUS))
|
this.environment.globalParams.generator.createReferences(worldGenRegion, tParams.structFeatManager.forWorldGenRegion(worldGenRegion), chunk);
|
||||||
{
|
|
||||||
// this chunk has already generated this step
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (chunk instanceof ProtoChunk)
|
|
||||||
{
|
|
||||||
chunkWrapper.trySetStatus(STATUS);
|
|
||||||
chunksToDo.add(chunk);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ChunkAccess chunk : chunksToDo)
|
|
||||||
{
|
|
||||||
// System.out.println("StepStructureReference: "+chunk.getPos());
|
|
||||||
this.environment.params.generator.createReferences(worldGenRegion, tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+28
-27
@@ -20,21 +20,16 @@
|
|||||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration.step;
|
package com.seibel.distanthorizons.common.wrappers.worldGeneration.step;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters;
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.params.ThreadWorldGenParams;
|
||||||
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion;
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion;
|
||||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
import com.seibel.distanthorizons.core.util.gridList.ArrayGridList;
|
import com.seibel.distanthorizons.core.util.gridList.ArrayGridList;
|
||||||
import net.minecraft.resources.ResourceKey;
|
|
||||||
import net.minecraft.server.level.WorldGenRegion;
|
|
||||||
import net.minecraft.world.level.Level;
|
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
|
||||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
|
||||||
#if MC_VER <= MC_1_20_4
|
#if MC_VER <= MC_1_20_4
|
||||||
@@ -71,42 +66,49 @@ public final class StepStructureStart extends AbstractWorldGenStep
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void generateGroup(
|
public void generateGroup(
|
||||||
ThreadedParameters tParams, DhLitWorldGenRegion worldGenRegion,
|
ThreadWorldGenParams tParams, DhLitWorldGenRegion worldGenRegion,
|
||||||
ArrayGridList<ChunkWrapper> chunkWrappers)
|
ArrayGridList<ChunkWrapper> chunkWrappers)
|
||||||
{
|
{
|
||||||
ArrayList<ChunkAccess> chunksToDo = this.getChunksToGenerate(chunkWrappers);
|
ArrayList<ChunkWrapper> chunksToDo = this.getChunkWrappersToGenerate(chunkWrappers);
|
||||||
|
|
||||||
|
// TODO should be put in wrapped environment so we can skip some other world gen steps
|
||||||
|
// SURFACE wouldn't need structure generation either
|
||||||
#if MC_VER < MC_1_19_2
|
#if MC_VER < MC_1_19_2
|
||||||
if (this.environment.params.worldGenSettings.generateFeatures())
|
if (!this.environment.globalParams.worldGenSettings.generateFeatures())
|
||||||
{
|
|
||||||
#elif MC_VER < MC_1_19_4
|
#elif MC_VER < MC_1_19_4
|
||||||
if (this.environment.params.worldGenSettings.generateStructures())
|
if (!this.environment.globalParams.worldGenSettings.generateStructures())
|
||||||
{
|
|
||||||
#else
|
#else
|
||||||
if (this.environment.params.worldOptions.generateStructures())
|
if (!this.environment.globalParams.worldOptions.generateStructures())
|
||||||
{
|
|
||||||
#endif
|
#endif
|
||||||
for (ChunkAccess chunk : chunksToDo)
|
|
||||||
{
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for (ChunkWrapper chunkWrapper : chunksToDo)
|
||||||
|
{
|
||||||
|
ChunkAccess chunk = chunkWrapper.getChunk();
|
||||||
|
|
||||||
// hopefully this shouldn't cause any performance issues (this step is generally quite quick so hopefully it should be fine)
|
// hopefully this shouldn't cause any performance issues (this step is generally quite quick so hopefully it should be fine)
|
||||||
// and should prevent some concurrency issues
|
// and should prevent some concurrency issues
|
||||||
STRUCTURE_PLACEMENT_LOCK.lock();
|
STRUCTURE_PLACEMENT_LOCK.lock();
|
||||||
|
|
||||||
#if MC_VER < MC_1_19_2
|
#if MC_VER < MC_1_19_2
|
||||||
this.environment.params.generator.createStructures(this.environment.params.registry, tParams.structFeat, chunk, this.environment.params.structures,
|
this.environment.globalParams.generator.createStructures(this.environment.globalParams.registry, tParams.structFeatManager, chunk, this.environment.globalParams.structures,
|
||||||
this.environment.params.worldSeed);
|
this.environment.globalParams.worldSeed);
|
||||||
#elif MC_VER < MC_1_19_4
|
#elif MC_VER < MC_1_19_4
|
||||||
this.environment.params.generator.createStructures(this.environment.params.registry, this.environment.params.randomState, tParams.structFeat, chunk, this.environment.params.structures,
|
this.environment.globalParams.generator.createStructures(this.environment.globalParams.registry, this.environment.globalParams.randomState, tParams.structFeatManager, chunk, this.environment.globalParams.structures,
|
||||||
this.environment.params.worldSeed);
|
this.environment.globalParams.worldSeed);
|
||||||
#elif MC_VER <= MC_1_21_3
|
#elif MC_VER <= MC_1_21_3
|
||||||
this.environment.params.generator.createStructures(this.environment.params.registry,
|
this.environment.globalParams.generator.createStructures(this.environment.globalParams.registry,
|
||||||
this.environment.params.level.getChunkSource().getGeneratorState(),
|
this.environment.globalParams.mcServerLevel.getChunkSource().getGeneratorState(),
|
||||||
tParams.structFeat, chunk, this.environment.params.structures);
|
tParams.structFeatManager, chunk, this.environment.globalParams.structures);
|
||||||
#else
|
#else
|
||||||
this.environment.params.generator.createStructures(this.environment.params.registry,
|
this.environment.globalParams.generator.createStructures(this.environment.globalParams.registry,
|
||||||
this.environment.params.level.getChunkSource().getGeneratorState(),
|
this.environment.globalParams.mcServerLevel.getChunkSource().getGeneratorState(),
|
||||||
tParams.structFeat, chunk, this.environment.params.structures,
|
tParams.structFeatManager, chunk, this.environment.globalParams.structures,
|
||||||
this.environment.params.level.dimension());
|
this.environment.globalParams.mcServerLevel.dimension());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if MC_VER >= MC_1_18_2
|
#if MC_VER >= MC_1_18_2
|
||||||
@@ -140,6 +142,5 @@ public final class StepStructureStart extends AbstractWorldGenStep
|
|||||||
STRUCTURE_PLACEMENT_LOCK.unlock();
|
STRUCTURE_PLACEMENT_LOCK.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
+9
-25
@@ -20,17 +20,14 @@
|
|||||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration.step;
|
package com.seibel.distanthorizons.common.wrappers.worldGeneration.step;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters;
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.params.ThreadWorldGenParams;
|
||||||
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion;
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion;
|
||||||
import com.seibel.distanthorizons.core.util.gridList.ArrayGridList;
|
import com.seibel.distanthorizons.core.util.gridList.ArrayGridList;
|
||||||
import net.minecraft.server.level.WorldGenRegion;
|
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
|
||||||
|
|
||||||
#if MC_VER <= MC_1_20_4
|
#if MC_VER <= MC_1_20_4
|
||||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||||
@@ -64,37 +61,24 @@ public final class StepSurface extends AbstractWorldGenStep
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void generateGroup(
|
public void generateGroup(
|
||||||
ThreadedParameters tParams, DhLitWorldGenRegion worldGenRegion,
|
ThreadWorldGenParams tParams, DhLitWorldGenRegion worldGenRegion,
|
||||||
ArrayGridList<ChunkWrapper> chunkWrappers)
|
ArrayGridList<ChunkWrapper> chunkWrappers)
|
||||||
{
|
{
|
||||||
ArrayList<ChunkAccess> chunksToDo = new ArrayList<>();
|
ArrayList<ChunkWrapper> chunksToDo = this.getChunkWrappersToGenerate(chunkWrappers);
|
||||||
|
for (ChunkWrapper chunkWrapper : chunksToDo)
|
||||||
for (ChunkWrapper chunkWrapper : chunkWrappers)
|
|
||||||
{
|
{
|
||||||
ChunkAccess chunk = chunkWrapper.getChunk();
|
ChunkAccess chunk = chunkWrapper.getChunk();
|
||||||
if (chunkWrapper.getStatus().isOrAfter(STATUS))
|
|
||||||
{
|
|
||||||
// this chunk has already generated this step
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (chunk instanceof ProtoChunk)
|
|
||||||
{
|
|
||||||
chunkWrapper.trySetStatus(STATUS);
|
|
||||||
chunksToDo.add(chunk);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ChunkAccess chunk : chunksToDo)
|
|
||||||
{
|
|
||||||
// System.out.println("StepSurface: "+chunk.getPos());
|
|
||||||
#if MC_VER < MC_1_18_2
|
#if MC_VER < MC_1_18_2
|
||||||
environment.params.generator.buildSurfaceAndBedrock(worldGenRegion, chunk);
|
this.environment.globalParams.generator.buildSurfaceAndBedrock(worldGenRegion, chunk);
|
||||||
#elif MC_VER < MC_1_19_2
|
#elif MC_VER < MC_1_19_2
|
||||||
environment.params.generator.buildSurface(worldGenRegion, tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk);
|
this.environment.globalParams.generator.buildSurface(worldGenRegion, tParams.structFeatManager.forWorldGenRegion(worldGenRegion), chunk);
|
||||||
#else
|
#else
|
||||||
environment.params.generator.buildSurface(worldGenRegion, tParams.structFeat.forWorldGenRegion(worldGenRegion), environment.params.randomState, chunk);
|
this.environment.globalParams.generator.buildSurface(worldGenRegion, tParams.structFeatManager.forWorldGenRegion(worldGenRegion), this.environment.globalParams.randomState, chunk);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
+1
-1
Submodule coreSubProjects updated: b82a59ecbc...26d4220967
@@ -223,7 +223,7 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
|
|||||||
// render event //
|
// render event //
|
||||||
//==============//
|
//==============//
|
||||||
|
|
||||||
// TODO wait for fabric to re-add their rendering API
|
|
||||||
#if MC_VER < MC_1_21_9
|
#if MC_VER < MC_1_21_9
|
||||||
WorldRenderEvents.AFTER_SETUP.register((renderContext) ->
|
WorldRenderEvents.AFTER_SETUP.register((renderContext) ->
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -47,8 +47,6 @@ import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
|||||||
import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback;
|
import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
import java.awt.*;
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -110,6 +108,7 @@ public class FabricMain extends AbstractModInitializer implements ClientModIniti
|
|||||||
this.tryCreateModCompatAccessor("starlight", IStarlightAccessor.class, StarlightAccessor::new);
|
this.tryCreateModCompatAccessor("starlight", IStarlightAccessor.class, StarlightAccessor::new);
|
||||||
this.tryCreateModCompatAccessor("optifine", IOptifineAccessor.class, OptifineAccessor::new);
|
this.tryCreateModCompatAccessor("optifine", IOptifineAccessor.class, OptifineAccessor::new);
|
||||||
this.tryCreateModCompatAccessor("bclib", IBCLibAccessor.class, BCLibAccessor::new);
|
this.tryCreateModCompatAccessor("bclib", IBCLibAccessor.class, BCLibAccessor::new);
|
||||||
|
this.tryCreateModCompatAccessor("c2me", IC2meAccessor.class, C2meAccessor::new);
|
||||||
#if MC_VER >= MC_1_19_4
|
#if MC_VER >= MC_1_19_4
|
||||||
// 1.19.4 is the lowest version Iris supports DH
|
// 1.19.4 is the lowest version Iris supports DH
|
||||||
this.tryCreateModCompatAccessor("iris", IIrisAccessor.class, IrisAccessor::new);
|
this.tryCreateModCompatAccessor("iris", IIrisAccessor.class, IrisAccessor::new);
|
||||||
|
|||||||
@@ -93,10 +93,6 @@ public class FabricServerProxy implements AbstractModInitializer.IEventProxy
|
|||||||
|
|
||||||
/* Register the mod needed event callbacks */
|
/* Register the mod needed event callbacks */
|
||||||
|
|
||||||
// ServerTickEvent
|
|
||||||
ServerTickEvents.END_SERVER_TICK.register((server) -> SERVER_API.serverTickEvent());
|
|
||||||
|
|
||||||
|
|
||||||
// can be enabled to test overrides/events without having to build a separate API project
|
// can be enabled to test overrides/events without having to build a separate API project
|
||||||
if (false)
|
if (false)
|
||||||
{
|
{
|
||||||
|
|||||||
+2
-9
@@ -13,8 +13,7 @@ public class MixinLevelTicks<T>
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.DependencySetupDoneCheck;
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||||
|
|
||||||
import net.minecraft.world.ticks.LevelTicks;
|
import net.minecraft.world.ticks.LevelTicks;
|
||||||
import net.minecraft.world.ticks.ScheduledTick;
|
import net.minecraft.world.ticks.ScheduledTick;
|
||||||
|
|
||||||
@@ -26,18 +25,12 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||||||
@Mixin(LevelTicks.class) // available in 1.18.2+, but only needed in 1.21.4+
|
@Mixin(LevelTicks.class) // available in 1.18.2+, but only needed in 1.21.4+
|
||||||
public class MixinLevelTicks<T>
|
public class MixinLevelTicks<T>
|
||||||
{
|
{
|
||||||
// TODO put in a common location
|
|
||||||
private static boolean isWorldGenThread()
|
|
||||||
{ return DependencySetupDoneCheck.isDone && DependencySetupDoneCheck.getIsCurrentThreadDistantGeneratorThread.get(); }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Inject(method = "schedule", at = @At(value = "HEAD"), cancellable = true)
|
@Inject(method = "schedule", at = @At(value = "HEAD"), cancellable = true)
|
||||||
private void onChunkSave(ScheduledTick<T> tick, CallbackInfo ci)
|
private void onChunkSave(ScheduledTick<T> tick, CallbackInfo ci)
|
||||||
{
|
{
|
||||||
// In MC 1.21.4 an error check was added to log attempting to schedule ticks for unloaded chunks
|
// In MC 1.21.4 an error check was added to log attempting to schedule ticks for unloaded chunks
|
||||||
// this caused a lot of unnecessary errors when generating sand (FallingBlock.class).
|
// this caused a lot of unnecessary errors when generating sand (FallingBlock.class).
|
||||||
if (isWorldGenThread())
|
if (BatchGenerationEnvironment.isThisDhWorldGenThread())
|
||||||
{
|
{
|
||||||
ci.cancel();
|
ci.cancel();
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-8
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
package com.seibel.distanthorizons.fabric.mixins.server;
|
package com.seibel.distanthorizons.fabric.mixins.server;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
|
||||||
#if MC_VER < MC_1_21_3
|
#if MC_VER < MC_1_21_3
|
||||||
@@ -35,10 +36,8 @@ public class MixinTracingExecutor
|
|||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.DependencySetupDoneCheck;
|
|
||||||
import com.seibel.distanthorizons.core.util.objects.RunOnThisThreadExecutorService;
|
import com.seibel.distanthorizons.core.util.objects.RunOnThisThreadExecutorService;
|
||||||
import net.minecraft.TracingExecutor;
|
import net.minecraft.TracingExecutor;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
@@ -55,16 +54,11 @@ import java.util.concurrent.Executor;
|
|||||||
@Mixin(TracingExecutor.class)
|
@Mixin(TracingExecutor.class)
|
||||||
public class MixinTracingExecutor
|
public class MixinTracingExecutor
|
||||||
{
|
{
|
||||||
// TODO put in a common location
|
|
||||||
private static boolean isWorldGenThread()
|
|
||||||
{ return DependencySetupDoneCheck.isDone && DependencySetupDoneCheck.getIsCurrentThreadDistantGeneratorThread.get(); }
|
|
||||||
|
|
||||||
|
|
||||||
// replaced with TracingExecutor in MC 1.21.3+
|
// replaced with TracingExecutor in MC 1.21.3+
|
||||||
@Inject(method = "forName(Ljava/lang/String;)Ljava/util/concurrent/Executor;", at = @At("HEAD"), cancellable = true)
|
@Inject(method = "forName(Ljava/lang/String;)Ljava/util/concurrent/Executor;", at = @At("HEAD"), cancellable = true)
|
||||||
private void forName(String executorName, CallbackInfoReturnable<Executor> ci)
|
private void forName(String executorName, CallbackInfoReturnable<Executor> ci)
|
||||||
{
|
{
|
||||||
if (isWorldGenThread())
|
if (BatchGenerationEnvironment.isThisDhWorldGenThread())
|
||||||
{
|
{
|
||||||
// run this task on the current DH thread instead of a new MC thread
|
// run this task on the current DH thread instead of a new MC thread
|
||||||
ci.setReturnValue(new RunOnThisThreadExecutorService());
|
ci.setReturnValue(new RunOnThisThreadExecutorService());
|
||||||
|
|||||||
+8
-12
@@ -19,19 +19,19 @@
|
|||||||
|
|
||||||
package com.seibel.distanthorizons.fabric.mixins.server;
|
package com.seibel.distanthorizons.fabric.mixins.server;
|
||||||
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.DependencySetupDoneCheck;
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||||
import com.seibel.distanthorizons.core.util.objects.RunOnThisThreadExecutorService;
|
import com.seibel.distanthorizons.core.util.objects.RunOnThisThreadExecutorService;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
|
||||||
|
import net.minecraft.Util;
|
||||||
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
import net.minecraft.Util;
|
|
||||||
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
|
|
||||||
#if MC_VER < MC_1_16_5
|
#if MC_VER < MC_1_16_5
|
||||||
#elif MC_VER < MC_1_21_3
|
#elif MC_VER < MC_1_21_3
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
#else
|
#else
|
||||||
#endif
|
#endif
|
||||||
@@ -46,15 +46,11 @@ import java.util.function.Supplier;
|
|||||||
@Mixin(Util.class)
|
@Mixin(Util.class)
|
||||||
public class MixinUtilBackgroundThread
|
public class MixinUtilBackgroundThread
|
||||||
{
|
{
|
||||||
private static boolean isWorldGenThread()
|
|
||||||
{ return DependencySetupDoneCheck.isDone && DependencySetupDoneCheck.getIsCurrentThreadDistantGeneratorThread.get(); }
|
|
||||||
|
|
||||||
|
|
||||||
#if MC_VER < MC_1_21_3
|
#if MC_VER < MC_1_21_3
|
||||||
@Inject(method = "backgroundExecutor", at = @At("HEAD"), cancellable = true)
|
@Inject(method = "backgroundExecutor", at = @At("HEAD"), cancellable = true)
|
||||||
private static void overrideUtil$backgroundExecutor(CallbackInfoReturnable<ExecutorService> ci)
|
private static void overrideUtil$backgroundExecutor(CallbackInfoReturnable<ExecutorService> ci)
|
||||||
{
|
{
|
||||||
if (isWorldGenThread())
|
if (BatchGenerationEnvironment.isThisDhWorldGenThread())
|
||||||
{
|
{
|
||||||
// run this task on the current DH thread instead of a new MC thread
|
// run this task on the current DH thread instead of a new MC thread
|
||||||
ci.setReturnValue(new RunOnThisThreadExecutorService());
|
ci.setReturnValue(new RunOnThisThreadExecutorService());
|
||||||
@@ -70,7 +66,7 @@ public class MixinUtilBackgroundThread
|
|||||||
at = @At("HEAD"), cancellable = true)
|
at = @At("HEAD"), cancellable = true)
|
||||||
private static void overrideUtil$wrapThreadWithTaskName(String string, Runnable r, CallbackInfoReturnable<Runnable> ci)
|
private static void overrideUtil$wrapThreadWithTaskName(String string, Runnable r, CallbackInfoReturnable<Runnable> ci)
|
||||||
{
|
{
|
||||||
if (isWorldGenThread())
|
if (BatchGenerationEnvironment.isThisDhWorldGenThread())
|
||||||
{
|
{
|
||||||
//ApiShared.LOGGER.info("util wrapThreadWithTaskName(Runnable) triggered");
|
//ApiShared.LOGGER.info("util wrapThreadWithTaskName(Runnable) triggered");
|
||||||
ci.setReturnValue(r);
|
ci.setReturnValue(r);
|
||||||
@@ -86,7 +82,7 @@ public class MixinUtilBackgroundThread
|
|||||||
at = @At("HEAD"), cancellable = true)
|
at = @At("HEAD"), cancellable = true)
|
||||||
private static void overrideUtil$wrapThreadWithTaskNameForSupplier(String string, Supplier<?> r, CallbackInfoReturnable<Supplier<?>> ci)
|
private static void overrideUtil$wrapThreadWithTaskNameForSupplier(String string, Supplier<?> r, CallbackInfoReturnable<Supplier<?>> ci)
|
||||||
{
|
{
|
||||||
if (isWorldGenThread())
|
if (BatchGenerationEnvironment.isThisDhWorldGenThread())
|
||||||
{
|
{
|
||||||
//ApiShared.LOGGER.info("util wrapThreadWithTaskName(Supplier) triggered");
|
//ApiShared.LOGGER.info("util wrapThreadWithTaskName(Supplier) triggered");
|
||||||
ci.setReturnValue(r);
|
ci.setReturnValue(r);
|
||||||
|
|||||||
+8
-12
@@ -17,20 +17,16 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.seibel.distanthorizons.common.wrappers;
|
package com.seibel.distanthorizons.fabric.wrappers.modAccessor;
|
||||||
|
|
||||||
import java.util.function.Supplier;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IC2meAccessor;
|
||||||
|
|
||||||
public class DependencySetupDoneCheck
|
public class C2meAccessor implements IC2meAccessor
|
||||||
{
|
{
|
||||||
// TODO move to DependencySetup
|
@Override
|
||||||
public static boolean isDone = false;
|
public String getModName()
|
||||||
/**
|
{
|
||||||
* This is used so we can override some MC logic when running
|
return "c2me";
|
||||||
* in DH's world generator.
|
}
|
||||||
* Specifically so we can redirect threads to run on DH threads instead
|
|
||||||
* of MC threads.
|
|
||||||
*/
|
|
||||||
public static Supplier<Boolean> getIsCurrentThreadDistantGeneratorThread = (() -> { return false; });
|
|
||||||
|
|
||||||
}
|
}
|
||||||
+4
-12
@@ -34,22 +34,14 @@ import net.irisshaders.iris.api.v0.IrisApi;
|
|||||||
public class IrisAccessor implements IIrisAccessor
|
public class IrisAccessor implements IIrisAccessor
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public String getModName()
|
public String getModName() { return Iris.MODID; }
|
||||||
{
|
|
||||||
return Iris.MODID;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isShaderPackInUse()
|
public boolean isShaderPackInUse() { return IrisApi.getInstance().isShaderPackInUse(); }
|
||||||
{
|
|
||||||
return IrisApi.getInstance().isShaderPackInUse();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isRenderingShadowPass()
|
public boolean isRenderingShadowPass() { return IrisApi.getInstance().isRenderingShadowPass(); }
|
||||||
{
|
|
||||||
return IrisApi.getInstance().isRenderingShadowPass();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -90,16 +90,6 @@ public class ForgeServerProxy implements AbstractModInitializer.IEventProxy
|
|||||||
// events //
|
// events //
|
||||||
//========//
|
//========//
|
||||||
|
|
||||||
// ServerTickEvent (at end)
|
|
||||||
@SubscribeEvent
|
|
||||||
public void serverTickEvent(TickEvent.ServerTickEvent event)
|
|
||||||
{
|
|
||||||
if (event.phase == TickEvent.Phase.END)
|
|
||||||
{
|
|
||||||
this.serverApi.serverTickEvent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ServerWorldLoadEvent
|
// ServerWorldLoadEvent
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public void dedicatedWorldLoadEvent(#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1 FMLServerAboutToStartEvent #else ServerAboutToStartEvent #endif event)
|
public void dedicatedWorldLoadEvent(#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1 FMLServerAboutToStartEvent #else ServerAboutToStartEvent #endif event)
|
||||||
|
|||||||
+15
-11
@@ -22,12 +22,15 @@ package com.seibel.distanthorizons.forge.mixins.server;
|
|||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.DependencySetupDoneCheck;
|
|
||||||
import com.seibel.distanthorizons.core.util.objects.RunOnThisThreadExecutorService;
|
import com.seibel.distanthorizons.core.util.objects.RunOnThisThreadExecutorService;
|
||||||
|
|
||||||
import net.minecraft.Util;
|
import net.minecraft.Util;
|
||||||
@@ -35,17 +38,17 @@ import net.minecraft.Util;
|
|||||||
@Mixin(Util.class)
|
@Mixin(Util.class)
|
||||||
public class MixinUtilBackgroundThread
|
public class MixinUtilBackgroundThread
|
||||||
{
|
{
|
||||||
private static boolean shouldApplyOverride()
|
@Unique
|
||||||
{
|
private static final DhLogger LOGGER = new DhLoggerBuilder().name("MixinUtilBackgroundThread").build();
|
||||||
return DependencySetupDoneCheck.isDone && DependencySetupDoneCheck.getIsCurrentThreadDistantGeneratorThread.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "backgroundExecutor", at = @At("HEAD"), cancellable = true)
|
@Inject(method = "backgroundExecutor", at = @At("HEAD"), cancellable = true)
|
||||||
private static void overrideUtil$backgroundExecutor(CallbackInfoReturnable<ExecutorService> ci)
|
private static void overrideUtil$backgroundExecutor(CallbackInfoReturnable<ExecutorService> ci)
|
||||||
{
|
{
|
||||||
if (shouldApplyOverride())
|
if (BatchGenerationEnvironment.isThisDhWorldGenThread())
|
||||||
{
|
{
|
||||||
//ApiShared.LOGGER.info("util backgroundExecutor triggered");
|
//LOGGER.info("util backgroundExecutor triggered");
|
||||||
ci.setReturnValue(new RunOnThisThreadExecutorService());
|
ci.setReturnValue(new RunOnThisThreadExecutorService());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -55,21 +58,22 @@ public class MixinUtilBackgroundThread
|
|||||||
at = @At("HEAD"), cancellable = true)
|
at = @At("HEAD"), cancellable = true)
|
||||||
private static void overrideUtil$wrapThreadWithTaskName(String string, Runnable r, CallbackInfoReturnable<Runnable> ci)
|
private static void overrideUtil$wrapThreadWithTaskName(String string, Runnable r, CallbackInfoReturnable<Runnable> ci)
|
||||||
{
|
{
|
||||||
if (shouldApplyOverride())
|
if (BatchGenerationEnvironment.isThisDhWorldGenThread())
|
||||||
{
|
{
|
||||||
//ApiShared.LOGGER.info("util wrapThreadWithTaskName(Runnable) triggered");
|
//LOGGER.info("util wrapThreadWithTaskName(Runnable) triggered");
|
||||||
ci.setReturnValue(r);
|
ci.setReturnValue(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if MC_VER >= MC_1_18_2
|
#if MC_VER >= MC_1_18_2
|
||||||
@Inject(method = "wrapThreadWithTaskName(Ljava/lang/String;Ljava/util/function/Supplier;)Ljava/util/function/Supplier;",
|
@Inject(method = "wrapThreadWithTaskName(Ljava/lang/String;Ljava/util/function/Supplier;)Ljava/util/function/Supplier;",
|
||||||
at = @At("HEAD"), cancellable = true)
|
at = @At("HEAD"), cancellable = true)
|
||||||
private static void overrideUtil$wrapThreadWithTaskNameForSupplier(String string, Supplier<?> r, CallbackInfoReturnable<Supplier<?>> ci)
|
private static void overrideUtil$wrapThreadWithTaskNameForSupplier(String string, Supplier<?> r, CallbackInfoReturnable<Supplier<?>> ci)
|
||||||
{
|
{
|
||||||
if (shouldApplyOverride())
|
if (BatchGenerationEnvironment.isThisDhWorldGenThread())
|
||||||
{
|
{
|
||||||
//ApiShared.LOGGER.info("util wrapThreadWithTaskName(Supplier) triggered");
|
//LOGGER.info("util wrapThreadWithTaskName(Supplier) triggered");
|
||||||
ci.setReturnValue(r);
|
ci.setReturnValue(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,7 +65,10 @@ dependencies {
|
|||||||
|
|
||||||
// Neoforge
|
// Neoforge
|
||||||
neoForge "net.neoforged:neoforge:${rootProject.neoforge_version}"
|
neoForge "net.neoforged:neoforge:${rootProject.neoforge_version}"
|
||||||
addMod("curse.maven:TerraFirmaCraft-302973:4616004", rootProject.enable_terrafirmacraft)
|
|
||||||
|
// Iris
|
||||||
|
addMod("maven.modrinth:iris:${rootProject.neo_iris_version}", rootProject.neo_enable_iris)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -30,9 +30,13 @@ import com.seibel.distanthorizons.core.network.messages.AbstractNetworkMessage;
|
|||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IC2meAccessor;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IIrisAccessor;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IOptifineAccessor;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IOptifineAccessor;
|
||||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||||
|
import com.seibel.distanthorizons.neoforge.wrappers.modAccessor.C2meAccessor;
|
||||||
|
import com.seibel.distanthorizons.neoforge.wrappers.modAccessor.IrisAccessor;
|
||||||
import com.seibel.distanthorizons.neoforge.wrappers.NeoforgeMinecraftRenderWrapper;
|
import com.seibel.distanthorizons.neoforge.wrappers.NeoforgeMinecraftRenderWrapper;
|
||||||
import com.seibel.distanthorizons.neoforge.wrappers.modAccessor.ModChecker;
|
import com.seibel.distanthorizons.neoforge.wrappers.modAccessor.ModChecker;
|
||||||
import com.seibel.distanthorizons.neoforge.wrappers.modAccessor.OptifineAccessor;
|
import com.seibel.distanthorizons.neoforge.wrappers.modAccessor.OptifineAccessor;
|
||||||
@@ -144,6 +148,12 @@ public class NeoforgeMain extends AbstractModInitializer
|
|||||||
protected void initializeModCompat()
|
protected void initializeModCompat()
|
||||||
{
|
{
|
||||||
this.tryCreateModCompatAccessor("optifine", IOptifineAccessor.class, OptifineAccessor::new);
|
this.tryCreateModCompatAccessor("optifine", IOptifineAccessor.class, OptifineAccessor::new);
|
||||||
|
this.tryCreateModCompatAccessor("c2me", IC2meAccessor.class, C2meAccessor::new);
|
||||||
|
|
||||||
|
#if MC_VER >= MC_1_20_6
|
||||||
|
// 1.20.6 is the lowest version Iris supports Neoforge
|
||||||
|
this.tryCreateModCompatAccessor("iris", IIrisAccessor.class, IrisAccessor::new);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if MC_VER < MC_1_20_6
|
#if MC_VER < MC_1_20_6
|
||||||
ModLoadingContext.get().registerExtensionPoint(ConfigScreenHandler.ConfigScreenFactory.class,
|
ModLoadingContext.get().registerExtensionPoint(ConfigScreenHandler.ConfigScreenFactory.class,
|
||||||
|
|||||||
+1
-19
@@ -31,7 +31,6 @@ import java.util.function.Supplier;
|
|||||||
#if MC_VER < MC_1_20_6
|
#if MC_VER < MC_1_20_6
|
||||||
import net.neoforged.neoforge.event.TickEvent;
|
import net.neoforged.neoforge.event.TickEvent;
|
||||||
#else
|
#else
|
||||||
import net.neoforged.neoforge.event.tick.ServerTickEvent;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -52,7 +51,7 @@ public class NeoforgeServerProxy implements AbstractModInitializer.IEventProxy
|
|||||||
public NeoforgeServerProxy(boolean isDedicated)
|
public NeoforgeServerProxy(boolean isDedicated)
|
||||||
{
|
{
|
||||||
this.isDedicated = isDedicated;
|
this.isDedicated = isDedicated;
|
||||||
isGenerationThreadChecker = BatchGenerationEnvironment::isCurrentThreadDistantGeneratorThread;
|
isGenerationThreadChecker = BatchGenerationEnvironment::isThisDhWorldGenThread;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -68,23 +67,6 @@ public class NeoforgeServerProxy implements AbstractModInitializer.IEventProxy
|
|||||||
// events //
|
// events //
|
||||||
//========//
|
//========//
|
||||||
|
|
||||||
#if MC_VER < MC_1_20_6
|
|
||||||
@SubscribeEvent
|
|
||||||
public void serverTickEvent(TickEvent.ServerTickEvent event)
|
|
||||||
{
|
|
||||||
if (event.phase == TickEvent.Phase.END)
|
|
||||||
{
|
|
||||||
this.serverApi.serverTickEvent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
@SubscribeEvent
|
|
||||||
public void serverTickEvent(ServerTickEvent.Post event)
|
|
||||||
{
|
|
||||||
this.serverApi.serverTickEvent();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ServerWorldLoadEvent
|
// ServerWorldLoadEvent
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public void dedicatedWorldLoadEvent(ServerAboutToStartEvent event)
|
public void dedicatedWorldLoadEvent(ServerAboutToStartEvent event)
|
||||||
|
|||||||
+2
-8
@@ -13,7 +13,7 @@ public class MixinLevelTicks<T>
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.DependencySetupDoneCheck;
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||||
import net.minecraft.world.ticks.LevelTicks;
|
import net.minecraft.world.ticks.LevelTicks;
|
||||||
import net.minecraft.world.ticks.ScheduledTick;
|
import net.minecraft.world.ticks.ScheduledTick;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
@@ -24,18 +24,12 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||||||
@Mixin(LevelTicks.class) // available in 1.18.2+, but only needed in 1.21.4+
|
@Mixin(LevelTicks.class) // available in 1.18.2+, but only needed in 1.21.4+
|
||||||
public class MixinLevelTicks<T>
|
public class MixinLevelTicks<T>
|
||||||
{
|
{
|
||||||
// TODO put in a common location
|
|
||||||
private static boolean isWorldGenThread()
|
|
||||||
{ return DependencySetupDoneCheck.isDone && DependencySetupDoneCheck.getIsCurrentThreadDistantGeneratorThread.get(); }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Inject(method = "schedule", at = @At(value = "HEAD"), cancellable = true)
|
@Inject(method = "schedule", at = @At(value = "HEAD"), cancellable = true)
|
||||||
private void onChunkSave(ScheduledTick<T> tick, CallbackInfo ci)
|
private void onChunkSave(ScheduledTick<T> tick, CallbackInfo ci)
|
||||||
{
|
{
|
||||||
// In MC 1.21.4 an error check was added to log attempting to schedule ticks for unloaded chunks
|
// In MC 1.21.4 an error check was added to log attempting to schedule ticks for unloaded chunks
|
||||||
// this caused a lot of unnecessary errors when generating sand (FallingBlock.class).
|
// this caused a lot of unnecessary errors when generating sand (FallingBlock.class).
|
||||||
if (isWorldGenThread())
|
if (BatchGenerationEnvironment.isThisDhWorldGenThread())
|
||||||
{
|
{
|
||||||
ci.cancel();
|
ci.cancel();
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-7
@@ -35,7 +35,7 @@ public class MixinTracingExecutor
|
|||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.DependencySetupDoneCheck;
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||||
import com.seibel.distanthorizons.core.util.objects.RunOnThisThreadExecutorService;
|
import com.seibel.distanthorizons.core.util.objects.RunOnThisThreadExecutorService;
|
||||||
import net.minecraft.TracingExecutor;
|
import net.minecraft.TracingExecutor;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
@@ -55,11 +55,6 @@ import java.util.concurrent.Executor;
|
|||||||
@Mixin(TracingExecutor.class)
|
@Mixin(TracingExecutor.class)
|
||||||
public class MixinTracingExecutor
|
public class MixinTracingExecutor
|
||||||
{
|
{
|
||||||
// TODO put in a common location
|
|
||||||
private static boolean isWorldGenThread()
|
|
||||||
{ return DependencySetupDoneCheck.isDone && DependencySetupDoneCheck.getIsCurrentThreadDistantGeneratorThread.get(); }
|
|
||||||
|
|
||||||
|
|
||||||
// Util.backgroundExecutor().forName("init_biomes")
|
// Util.backgroundExecutor().forName("init_biomes")
|
||||||
// needed for world gen
|
// needed for world gen
|
||||||
|
|
||||||
@@ -67,7 +62,7 @@ public class MixinTracingExecutor
|
|||||||
@Inject(method = "forName(Ljava/lang/String;)Ljava/util/concurrent/Executor;", at = @At("HEAD"), cancellable = true)
|
@Inject(method = "forName(Ljava/lang/String;)Ljava/util/concurrent/Executor;", at = @At("HEAD"), cancellable = true)
|
||||||
private void forName(String executorName, CallbackInfoReturnable<Executor> ci)
|
private void forName(String executorName, CallbackInfoReturnable<Executor> ci)
|
||||||
{
|
{
|
||||||
if (isWorldGenThread())
|
if (BatchGenerationEnvironment.isThisDhWorldGenThread())
|
||||||
{
|
{
|
||||||
// run this task on the current DH thread instead of a new MC thread
|
// run this task on the current DH thread instead of a new MC thread
|
||||||
ci.setReturnValue(new RunOnThisThreadExecutorService());
|
ci.setReturnValue(new RunOnThisThreadExecutorService());
|
||||||
|
|||||||
+11
-12
@@ -19,18 +19,20 @@
|
|||||||
|
|
||||||
package com.seibel.distanthorizons.neoforge.mixins.server;
|
package com.seibel.distanthorizons.neoforge.mixins.server;
|
||||||
|
|
||||||
import java.util.concurrent.ExecutorService;
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
import com.seibel.distanthorizons.core.util.objects.RunOnThisThreadExecutorService;
|
import com.seibel.distanthorizons.core.util.objects.RunOnThisThreadExecutorService;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
|
||||||
|
import net.minecraft.Util;
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_21_3
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.DependencySetupDoneCheck;
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.function.Supplier;
|
||||||
import net.minecraft.Util;
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is needed for DH's world gen so we can run
|
* This is needed for DH's world gen so we can run
|
||||||
@@ -42,16 +44,13 @@ import net.minecraft.Util;
|
|||||||
@Mixin(Util.class)
|
@Mixin(Util.class)
|
||||||
public class MixinUtilBackgroundThread
|
public class MixinUtilBackgroundThread
|
||||||
{
|
{
|
||||||
private static boolean isWorldGenThread()
|
|
||||||
{ return DependencySetupDoneCheck.isDone && DependencySetupDoneCheck.getIsCurrentThreadDistantGeneratorThread.get(); }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if MC_VER < MC_1_21_3
|
#if MC_VER < MC_1_21_3
|
||||||
@Inject(method = "backgroundExecutor", at = @At("HEAD"), cancellable = true)
|
@Inject(method = "backgroundExecutor", at = @At("HEAD"), cancellable = true)
|
||||||
private static void overrideUtil$backgroundExecutor(CallbackInfoReturnable<ExecutorService> ci)
|
private static void overrideUtil$backgroundExecutor(CallbackInfoReturnable<ExecutorService> ci)
|
||||||
{
|
{
|
||||||
if (isWorldGenThread())
|
if (BatchGenerationEnvironment.isThisDhWorldGenThread())
|
||||||
{
|
{
|
||||||
// run this task on the current DH thread instead of a new MC thread
|
// run this task on the current DH thread instead of a new MC thread
|
||||||
ci.setReturnValue(new RunOnThisThreadExecutorService());
|
ci.setReturnValue(new RunOnThisThreadExecutorService());
|
||||||
@@ -67,7 +66,7 @@ public class MixinUtilBackgroundThread
|
|||||||
at = @At("HEAD"), cancellable = true)
|
at = @At("HEAD"), cancellable = true)
|
||||||
private static void overrideUtil$wrapThreadWithTaskName(String string, Runnable r, CallbackInfoReturnable<Runnable> ci)
|
private static void overrideUtil$wrapThreadWithTaskName(String string, Runnable r, CallbackInfoReturnable<Runnable> ci)
|
||||||
{
|
{
|
||||||
if (isWorldGenThread())
|
if (BatchGenerationEnvironment.isThisDhWorldGenThread())
|
||||||
{
|
{
|
||||||
//ApiShared.LOGGER.info("util wrapThreadWithTaskName(Runnable) triggered");
|
//ApiShared.LOGGER.info("util wrapThreadWithTaskName(Runnable) triggered");
|
||||||
ci.setReturnValue(r);
|
ci.setReturnValue(r);
|
||||||
@@ -83,7 +82,7 @@ public class MixinUtilBackgroundThread
|
|||||||
at = @At("HEAD"), cancellable = true)
|
at = @At("HEAD"), cancellable = true)
|
||||||
private static void overrideUtil$wrapThreadWithTaskNameForSupplier(String string, Supplier<?> r, CallbackInfoReturnable<Supplier<?>> ci)
|
private static void overrideUtil$wrapThreadWithTaskNameForSupplier(String string, Supplier<?> r, CallbackInfoReturnable<Supplier<?>> ci)
|
||||||
{
|
{
|
||||||
if (isWorldGenThread())
|
if (BatchGenerationEnvironment.isThisDhWorldGenThread())
|
||||||
{
|
{
|
||||||
//ApiShared.LOGGER.info("util wrapThreadWithTaskName(Supplier) triggered");
|
//ApiShared.LOGGER.info("util wrapThreadWithTaskName(Supplier) triggered");
|
||||||
ci.setReturnValue(r);
|
ci.setReturnValue(r);
|
||||||
|
|||||||
+6
-30
@@ -17,40 +17,16 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.neoforge.wrappers.modAccessor;
|
||||||
|
|
||||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IC2meAccessor;
|
||||||
|
|
||||||
//FIXME: Move this outside the WorldGenerationStep thingy
|
public class C2meAccessor implements IC2meAccessor
|
||||||
public class Rolling
|
|
||||||
{
|
{
|
||||||
|
@Override
|
||||||
private final int size;
|
public String getModName()
|
||||||
private double total = 0d;
|
|
||||||
private int index = 0;
|
|
||||||
private final double[] samples;
|
|
||||||
|
|
||||||
public Rolling(int size)
|
|
||||||
{
|
{
|
||||||
this.size = size;
|
return "c2me";
|
||||||
samples = new double[size];
|
|
||||||
for (int i = 0; i < size; i++)
|
|
||||||
{
|
|
||||||
samples[i] = 0d;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void add(double x)
|
|
||||||
{
|
|
||||||
total -= samples[index];
|
|
||||||
samples[index] = x;
|
|
||||||
total += x;
|
|
||||||
if (++index == size)
|
|
||||||
index = 0; // cheaper than modulus
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getAverage()
|
|
||||||
{
|
|
||||||
return size == 0 ? 0 : total / size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+67
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.neoforge.wrappers.modAccessor;
|
||||||
|
|
||||||
|
// 1.20.6 is the lowest version Iris supports Neoforge
|
||||||
|
#if MC_VER >= MC_1_20_6
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IIrisAccessor;
|
||||||
|
|
||||||
|
#if MC_VER != MC_1_21_9
|
||||||
|
import net.irisshaders.iris.Iris;
|
||||||
|
import net.irisshaders.iris.api.v0.IrisApi;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public class IrisAccessor implements IIrisAccessor
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public String getModName()
|
||||||
|
{
|
||||||
|
#if MC_VER == MC_1_21_9
|
||||||
|
return "iris"; // Iris doesn't support this MC version
|
||||||
|
#else
|
||||||
|
return Iris.MODID;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isShaderPackInUse()
|
||||||
|
{
|
||||||
|
#if MC_VER == MC_1_21_9
|
||||||
|
return true; // Iris doesn't support this MC version
|
||||||
|
#else
|
||||||
|
return IrisApi.getInstance().isShaderPackInUse();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRenderingShadowPass()
|
||||||
|
{
|
||||||
|
#if MC_VER == MC_1_21_9
|
||||||
|
return false; // Iris doesn't support this MC version
|
||||||
|
#else
|
||||||
|
return IrisApi.getInstance().isRenderingShadowPass();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -48,7 +48,6 @@ forge_version=36.2.39
|
|||||||
neoforge_version_range=[*,)
|
neoforge_version_range=[*,)
|
||||||
|
|
||||||
# Forge mod versions
|
# Forge mod versions
|
||||||
starlight_version_forge=
|
|
||||||
terraforged_version=4044290
|
terraforged_version=4044290
|
||||||
|
|
||||||
# Forge mod run
|
# Forge mod run
|
||||||
|
|||||||
@@ -47,7 +47,6 @@ forge_version=37.1.1
|
|||||||
neoforge_version_range=[*,)
|
neoforge_version_range=[*,)
|
||||||
|
|
||||||
# Forge mod versions
|
# Forge mod versions
|
||||||
starlight_version_forge=3457784
|
|
||||||
terraforged_version=
|
terraforged_version=
|
||||||
|
|
||||||
# Forge mod run
|
# Forge mod run
|
||||||
|
|||||||
@@ -56,7 +56,6 @@ forge_version=40.2.10
|
|||||||
neoforge_version_range=[*,)
|
neoforge_version_range=[*,)
|
||||||
|
|
||||||
# Forge mod versions
|
# Forge mod versions
|
||||||
starlight_version_forge=
|
|
||||||
terraforged_version=
|
terraforged_version=
|
||||||
|
|
||||||
# Forge mod run
|
# Forge mod run
|
||||||
|
|||||||
@@ -47,7 +47,6 @@ forge_version=43.3.2
|
|||||||
neoforge_version_range=[*,)
|
neoforge_version_range=[*,)
|
||||||
|
|
||||||
# Forge mod versions
|
# Forge mod versions
|
||||||
starlight_version_forge=
|
|
||||||
terraforged_version=
|
terraforged_version=
|
||||||
|
|
||||||
# Forge mod run
|
# Forge mod run
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ forge_version=45.2.4
|
|||||||
neoforge_version_range=[*,)
|
neoforge_version_range=[*,)
|
||||||
|
|
||||||
# Forge mod versions
|
# Forge mod versions
|
||||||
starlight_version_forge=
|
|
||||||
terraforged_version=
|
terraforged_version=
|
||||||
|
|
||||||
# Forge mod run
|
# Forge mod run
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ forge_version=47.2.1
|
|||||||
neoforge_version_range=[*,)
|
neoforge_version_range=[*,)
|
||||||
|
|
||||||
# Forge mod versions
|
# Forge mod versions
|
||||||
starlight_version_forge=
|
|
||||||
terraforged_version=
|
terraforged_version=
|
||||||
|
|
||||||
# Forge mod run
|
# Forge mod run
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ forge_version=48.0.13
|
|||||||
neoforge_version_range=[*,)
|
neoforge_version_range=[*,)
|
||||||
|
|
||||||
# Forge mod versions
|
# Forge mod versions
|
||||||
starlight_version_forge=
|
|
||||||
terraforged_version=
|
terraforged_version=
|
||||||
|
|
||||||
# Forge mod run
|
# Forge mod run
|
||||||
|
|||||||
@@ -41,16 +41,15 @@ fabric_api_version=0.91.2+1.20.4
|
|||||||
enable_immersive_portals=0
|
enable_immersive_portals=0
|
||||||
enable_canvas=0
|
enable_canvas=0
|
||||||
|
|
||||||
# (Neo)Forge loader
|
# Forge loader
|
||||||
forge_version=49.1.13
|
forge_version=49.1.13
|
||||||
neoforge_version=20.4.246
|
neoforge_version=
|
||||||
neoforge_version_range=[*,)
|
neoforge_version_range=[*,)
|
||||||
|
|
||||||
# (Neo)Forge mod versions
|
# Forge mod versions
|
||||||
starlight_version_forge=
|
|
||||||
terraforged_version=
|
terraforged_version=
|
||||||
|
|
||||||
# (Neo)Forge mod run
|
# Forge mod run
|
||||||
# 0 = Don't enable and don't run
|
# 0 = Don't enable and don't run
|
||||||
# 1 = Can be referenced in code but doesn't run
|
# 1 = Can be referenced in code but doesn't run
|
||||||
# 2 = Can be referenced in code and runs in client
|
# 2 = Can be referenced in code and runs in client
|
||||||
|
|||||||
@@ -41,19 +41,16 @@ fabric_api_version=0.97.8+1.20.6
|
|||||||
enable_immersive_portals=0
|
enable_immersive_portals=0
|
||||||
enable_canvas=0
|
enable_canvas=0
|
||||||
|
|
||||||
# (Neo)Forge loader
|
# NeoForge loader
|
||||||
forge_version=50.0.19
|
forge_version=
|
||||||
neoforge_version=20.6.136
|
neoforge_version=20.6.136
|
||||||
neoforge_version_range=[*,)
|
neoforge_version_range=[*,)
|
||||||
|
|
||||||
# (Neo)Forge mod versions
|
# NeoForge mod versions
|
||||||
starlight_version_forge=
|
neo_iris_version=1.8.12+1.21.1-neoforge
|
||||||
terraforged_version=
|
|
||||||
|
|
||||||
# (Neo)Forge mod run
|
# (Neo)Forge mod run
|
||||||
# 0 = Don't enable and don't run
|
# 0 = Don't enable and don't run
|
||||||
# 1 = Can be referenced in code but doesn't run
|
# 1 = Can be referenced in code but doesn't run
|
||||||
# 2 = Can be referenced in code and runs in client
|
# 2 = Can be referenced in code and runs in client
|
||||||
enable_starlight_forge=0
|
neo_enable_iris=1
|
||||||
enable_terraforged=0
|
|
||||||
enable_terrafirmacraft=0
|
|
||||||
|
|||||||
@@ -41,19 +41,17 @@ fabric_api_version=0.115.0+1.21.1
|
|||||||
enable_immersive_portals=0
|
enable_immersive_portals=0
|
||||||
enable_canvas=0
|
enable_canvas=0
|
||||||
|
|
||||||
# (Neo)Forge loader
|
# NeoForge loader
|
||||||
forge_version=
|
forge_version=
|
||||||
neoforge_version=21.1.192
|
neoforge_version=21.1.216
|
||||||
neoforge_version_range=[*,)
|
neoforge_version_range=[*,)
|
||||||
|
|
||||||
# (Neo)Forge mod versions
|
# NeoForge mod versions
|
||||||
starlight_version_forge=
|
neo_iris_version=1.8.12+1.21.1-neoforge
|
||||||
terraforged_version=
|
|
||||||
|
|
||||||
# (Neo)Forge mod run
|
# (Neo)Forge mod run
|
||||||
# 0 = Don't enable and don't run
|
# 0 = Don't enable and don't run
|
||||||
# 1 = Can be referenced in code but doesn't run
|
# 1 = Can be referenced in code but doesn't run
|
||||||
# 2 = Can be referenced in code and runs in client
|
# 2 = Can be referenced in code and runs in client
|
||||||
enable_starlight_forge=0
|
neo_enable_iris=1
|
||||||
enable_terraforged=0
|
|
||||||
enable_terrafirmacraft=0
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ netty_version=4.1.97.Final
|
|||||||
|
|
||||||
# Fabric loader
|
# Fabric loader
|
||||||
fabric_loader_version=0.17.3
|
fabric_loader_version=0.17.3
|
||||||
fabric_api_version=0.135.0+1.21.10
|
fabric_api_version=0.138.3+1.21.10
|
||||||
modmenu_version=16.0.0-rc.1
|
modmenu_version=16.0.0-rc.1
|
||||||
starlight_version_fabric=
|
starlight_version_fabric=
|
||||||
phosphor_version_fabric=
|
phosphor_version_fabric=
|
||||||
@@ -39,19 +39,16 @@ fabric_api_version=0.135.0+1.21.10
|
|||||||
enable_immersive_portals=0
|
enable_immersive_portals=0
|
||||||
enable_canvas=0
|
enable_canvas=0
|
||||||
|
|
||||||
# (Neo)Forge loader
|
# NeoForge loader
|
||||||
forge_version=
|
forge_version=
|
||||||
neoforge_version=21.10.6-beta
|
neoforge_version=21.10.56-beta
|
||||||
neoforge_version_range=[21.10.6-beta,)
|
neoforge_version_range=[21.10.6-beta,)
|
||||||
|
|
||||||
# (Neo)Forge mod versions
|
# NeoForge mod versions
|
||||||
starlight_version_forge=
|
neo_iris_version=1.9.6+1.21.10-neoforge
|
||||||
terraforged_version=
|
|
||||||
|
|
||||||
# (Neo)Forge mod run
|
# (Neo)Forge mod run
|
||||||
# 0 = Don't enable and don't run
|
# 0 = Don't enable and don't run
|
||||||
# 1 = Can be referenced in code but doesn't run
|
# 1 = Can be referenced in code but doesn't run
|
||||||
# 2 = Can be referenced in code and runs in client
|
# 2 = Can be referenced in code and runs in client
|
||||||
enable_starlight_forge=0
|
neo_enable_iris=1
|
||||||
enable_terraforged=0
|
|
||||||
enable_terrafirmacraft=0
|
|
||||||
|
|||||||
@@ -41,19 +41,16 @@ fabric_api_version=0.110.0+1.21.3
|
|||||||
enable_immersive_portals=0
|
enable_immersive_portals=0
|
||||||
enable_canvas=0
|
enable_canvas=0
|
||||||
|
|
||||||
# (Neo)Forge loader
|
# NeoForge loader
|
||||||
forge_version=
|
forge_version=
|
||||||
neoforge_version=21.3.86
|
neoforge_version=21.3.86
|
||||||
neoforge_version_range=[*,)
|
neoforge_version_range=[*,)
|
||||||
|
|
||||||
# (Neo)Forge mod versions
|
# NeoForge mod versions
|
||||||
starlight_version_forge=
|
neo_iris_version=1.8.1+1.21.3-neoforge
|
||||||
terraforged_version=
|
|
||||||
|
|
||||||
# (Neo)Forge mod run
|
# (Neo)Forge mod run
|
||||||
# 0 = Don't enable and don't run
|
# 0 = Don't enable and don't run
|
||||||
# 1 = Can be referenced in code but doesn't run
|
# 1 = Can be referenced in code but doesn't run
|
||||||
# 2 = Can be referenced in code and runs in client
|
# 2 = Can be referenced in code and runs in client
|
||||||
enable_starlight_forge=0
|
neo_enable_iris=1
|
||||||
enable_terraforged=0
|
|
||||||
enable_terrafirmacraft=0
|
|
||||||
|
|||||||
@@ -40,20 +40,17 @@ fabric_api_version=0.110.5+1.21.4
|
|||||||
enable_immersive_portals=0
|
enable_immersive_portals=0
|
||||||
enable_canvas=0
|
enable_canvas=0
|
||||||
|
|
||||||
# (Neo)Forge loader
|
# NeoForge loader
|
||||||
forge_version=
|
forge_version=
|
||||||
neoforge_version=21.4.147
|
neoforge_version=21.4.147
|
||||||
# version range may not be necessary, but having compiled DH for an older version caused issues with shaders
|
# version range may not be necessary, but having compiled DH for an older version caused issues with shaders
|
||||||
neoforge_version_range=[21.4.147,)
|
neoforge_version_range=[21.4.147,)
|
||||||
|
|
||||||
# (Neo)Forge mod versions
|
# NeoForge mod versions
|
||||||
starlight_version_forge=
|
neo_iris_version=1.8.8+1.21.4-neoforge
|
||||||
terraforged_version=
|
|
||||||
|
|
||||||
# (Neo)Forge mod run
|
# (Neo)Forge mod run
|
||||||
# 0 = Don't enable and don't run
|
# 0 = Don't enable and don't run
|
||||||
# 1 = Can be referenced in code but doesn't run
|
# 1 = Can be referenced in code but doesn't run
|
||||||
# 2 = Can be referenced in code and runs in client
|
# 2 = Can be referenced in code and runs in client
|
||||||
enable_starlight_forge=0
|
neo_enable_iris=1
|
||||||
enable_terraforged=0
|
|
||||||
enable_terrafirmacraft=0
|
|
||||||
@@ -40,19 +40,16 @@ fabric_api_version=0.119.5+1.21.5
|
|||||||
enable_immersive_portals=0
|
enable_immersive_portals=0
|
||||||
enable_canvas=0
|
enable_canvas=0
|
||||||
|
|
||||||
# (Neo)Forge loader
|
# NeoForge loader
|
||||||
forge_version=
|
forge_version=
|
||||||
neoforge_version=21.5.87
|
neoforge_version=21.5.87
|
||||||
neoforge_version_range=[*,)
|
neoforge_version_range=[*,)
|
||||||
|
|
||||||
# (Neo)Forge mod versions
|
# NeoForge mod versions
|
||||||
starlight_version_forge=
|
neo_iris_version=1.8.11+1.21.5-neoforge
|
||||||
terraforged_version=
|
|
||||||
|
|
||||||
# (Neo)Forge mod run
|
# (Neo)Forge mod run
|
||||||
# 0 = Don't enable and don't run
|
# 0 = Don't enable and don't run
|
||||||
# 1 = Can be referenced in code but doesn't run
|
# 1 = Can be referenced in code but doesn't run
|
||||||
# 2 = Can be referenced in code and runs in client
|
# 2 = Can be referenced in code and runs in client
|
||||||
enable_starlight_forge=0
|
neo_enable_iris=1
|
||||||
enable_terraforged=0
|
|
||||||
enable_terrafirmacraft=0
|
|
||||||
@@ -39,20 +39,17 @@ fabric_api_version=0.127.0+1.21.6
|
|||||||
enable_immersive_portals=0
|
enable_immersive_portals=0
|
||||||
enable_canvas=0
|
enable_canvas=0
|
||||||
|
|
||||||
# (Neo)Forge loader
|
# NeoForge loader
|
||||||
forge_version=
|
forge_version=
|
||||||
neoforge_version=21.6.20-beta
|
neoforge_version=21.6.20-beta
|
||||||
# around 6.19 neo changed how their render API works, failing to meet this causes the game to crash
|
# around 6.19 neo changed how their render API works, failing to meet this causes the game to crash
|
||||||
neoforge_version_range=[21.6.19-beta,)
|
neoforge_version_range=[21.6.19-beta,)
|
||||||
|
|
||||||
# (Neo)Forge mod versions
|
# NeoForge mod versions
|
||||||
starlight_version_forge=
|
neo_iris_version=1.9.6+1.21.8-neoforge
|
||||||
terraforged_version=
|
|
||||||
|
|
||||||
# (Neo)Forge mod run
|
# (Neo)Forge mod run
|
||||||
# 0 = Don't enable and don't run
|
# 0 = Don't enable and don't run
|
||||||
# 1 = Can be referenced in code but doesn't run
|
# 1 = Can be referenced in code but doesn't run
|
||||||
# 2 = Can be referenced in code and runs in client
|
# 2 = Can be referenced in code and runs in client
|
||||||
enable_starlight_forge=0
|
neo_enable_iris=1
|
||||||
enable_terraforged=0
|
|
||||||
enable_terrafirmacraft=0
|
|
||||||
|
|||||||
@@ -39,20 +39,18 @@ fabric_api_version=0.133.4+1.21.8
|
|||||||
enable_immersive_portals=0
|
enable_immersive_portals=0
|
||||||
enable_canvas=0
|
enable_canvas=0
|
||||||
|
|
||||||
# (Neo)Forge loader
|
# NeoForge loader
|
||||||
forge_version=
|
forge_version=
|
||||||
neoforge_version=21.8.2-beta
|
neoforge_version=21.8.52
|
||||||
# around 6.19 neo changed how their render API works, failing to meet this causes the game to crash
|
# around 6.19 neo changed how their render API works, failing to meet this causes the game to crash
|
||||||
neoforge_version_range=[*,)
|
neoforge_version_range=[*,)
|
||||||
|
|
||||||
# (Neo)Forge mod versions
|
# NeoForge mod versions
|
||||||
starlight_version_forge=
|
neo_iris_version=1.9.6+1.21.8-neoforge
|
||||||
terraforged_version=
|
|
||||||
|
|
||||||
# (Neo)Forge mod run
|
# (Neo)Forge mod run
|
||||||
# 0 = Don't enable and don't run
|
# 0 = Don't enable and don't run
|
||||||
# 1 = Can be referenced in code but doesn't run
|
# 1 = Can be referenced in code but doesn't run
|
||||||
# 2 = Can be referenced in code and runs in client
|
# 2 = Can be referenced in code and runs in client
|
||||||
enable_starlight_forge=0
|
neo_enable_iris=1
|
||||||
enable_terraforged=0
|
|
||||||
enable_terrafirmacraft=0
|
|
||||||
|
|||||||
@@ -39,21 +39,19 @@ fabric_api_version=0.134.0+1.21.9
|
|||||||
enable_immersive_portals=0
|
enable_immersive_portals=0
|
||||||
enable_canvas=0
|
enable_canvas=0
|
||||||
|
|
||||||
# (Neo)Forge loader
|
# NeoForge loader
|
||||||
forge_version=
|
forge_version=
|
||||||
neoforge_version=21.9.15-beta
|
neoforge_version=21.9.15-beta
|
||||||
# sometime before 21.9.15-beta Neoforge changed how their rendering API events handle levels
|
# sometime before 21.9.15-beta Neoforge changed how their rendering API events handle levels
|
||||||
# so we can't support both versions at once
|
# so we can't support both versions at once
|
||||||
neoforge_version_range=[21.9.15-beta,)
|
neoforge_version_range=[21.9.15-beta,)
|
||||||
|
|
||||||
# (Neo)Forge mod versions
|
# NeoForge mod versions
|
||||||
starlight_version_forge=
|
# Iris doesn't exist for this MC version
|
||||||
terraforged_version=
|
neo_iris_version=
|
||||||
|
|
||||||
# (Neo)Forge mod run
|
# (Neo)Forge mod run
|
||||||
# 0 = Don't enable and don't run
|
# 0 = Don't enable and don't run
|
||||||
# 1 = Can be referenced in code but doesn't run
|
# 1 = Can be referenced in code but doesn't run
|
||||||
# 2 = Can be referenced in code and runs in client
|
# 2 = Can be referenced in code and runs in client
|
||||||
enable_starlight_forge=0
|
neo_enable_iris=0
|
||||||
enable_terraforged=0
|
|
||||||
enable_terrafirmacraft=0
|
|
||||||
|
|||||||
Reference in New Issue
Block a user