Compare commits

...

32 Commits

Author SHA1 Message Date
James Seibel 095fff96ff Up version 2.1.1-dev -> 2.1.2 2024-06-24 20:53:45 -05:00
James Seibel a23211d061 Fix NeoForge not running 2024-06-24 20:52:14 -05:00
James Seibel b57ea41686 neoforge build script cleanup 2024-06-23 08:52:55 -05:00
James Seibel 62fb5ffb73 Add DB file lock checking 2024-06-23 08:36:48 -05:00
James Seibel 99c713967b Temporary spongepowered.vanillagradle fix/workaround 2024-06-22 16:21:19 -05:00
James Seibel 9f3de07bd8 Increase default world gen timeout to 3 minutes (from 60 sec) 2024-06-18 07:12:01 -05:00
James Seibel cd74117de3 Fix file handler tooltip 2024-06-17 07:42:35 -05:00
James Seibel e7d7033548 Improve F3 menu logic and visuals 2024-06-15 19:20:25 -05:00
James Seibel 34db7c9dac Lower the default CPU presets 2024-06-15 11:26:05 -05:00
James Seibel 272841aae9 Add a startup low memory warning 2024-06-15 11:05:10 -05:00
James Seibel 389b09a5cd Prevent creating LODs for already processed chunks 2024-06-15 09:42:49 -05:00
James Seibel 84bd876c71 Refactor ChunkWrapper 2024-06-15 08:11:26 -05:00
James Seibel 7e45051ffd Fix more MC version compiles 2024-06-14 22:21:52 -05:00
James Seibel 5570f3a313 Fix some compiling issues 2024-06-14 19:31:21 -05:00
James Seibel f4e71f7012 Add NeoForge 1.21 2024-06-14 19:05:45 -05:00
James Seibel 601d4e6e3a Fix CI not picking up 1.21 2024-06-14 07:40:29 -05:00
James Seibel a12092c1a1 Add fabric 1.21 support 2024-06-14 07:36:25 -05:00
James Seibel 94ad118c5d Minor memory optimization thanks to littlewolf 2024-06-13 07:30:42 -05:00
James Seibel 48e2978438 Fixes #713 (Forge/Neo level unload events not being called) 2024-06-13 07:15:11 -05:00
James Seibel 96b4c1a9e8 Use existing lighting for pre-generated chunks 2024-06-11 20:22:13 -05:00
James Seibel cc4a69c10c Move shared ChunkWrapper code form Main to Core 2024-06-11 18:35:02 -05:00
James Seibel 7293677ddb Batch Generation Environment refactoring 2024-06-10 21:32:14 -05:00
James Seibel 0f2ff20375 Re-arange ChunkLoader 2024-06-10 21:17:57 -05:00
James Seibel 7706240acb Remove OpenGL multithreading 2024-06-08 12:49:17 -05:00
James Seibel 4cf48fd997 Try changing LZMA preset from 4 -> 3 (faster, less compressed)
won't require any lod regeneration since the decompressor is the same
2024-06-08 11:06:42 -05:00
James Seibel 2708c1ee11 Improve config comment spacing 2024-06-08 08:33:41 -05:00
James Seibel ebb0f6ebad Up the manifold version 2023.1.17 -> 2024.1.15 2024-06-08 08:12:03 -05:00
James Seibel 2c263a2549 Up the API version 2.0.0 -> 2.1.0 2024-06-08 08:11:48 -05:00
James Seibel 955524c632 Remove blendium from the list of suggested fabric mods 2024-06-08 08:11:34 -05:00
James Seibel 564e0d3263 Add update branch config "auto" 2024-06-08 08:11:26 -05:00
James Seibel c533b2e8ea Fix config screen blur on 1.20.6 2024-06-08 07:19:50 -05:00
James Seibel 6073d8122a Up the version number 2.1.0-a -> 2.1.1-a-dev 2024-06-07 17:42:46 -05:00
40 changed files with 1021 additions and 831 deletions
+1 -1
View File
@@ -30,7 +30,7 @@ build:
stage: build stage: build
parallel: parallel:
matrix: matrix:
- MC_VER: ["1.16.5", "1.17.1", "1.18.2", "1.19.2", "1.19.4", "1.20.1", "1.20.2", "1.20.4", "1.20.6"] - MC_VER: ["1.16.5", "1.17.1", "1.18.2", "1.19.2", "1.19.4", "1.20.1", "1.20.2", "1.20.4", "1.20.6", "1.21"]
script: script:
# this both runs the unit tests and assembles the code # this both runs the unit tests and assembles the code
- ./gradlew clean -PmcVer="${MC_VER}" -PinfoGitCommit="${CI_COMMIT_SHA}" -PinfoGitBranch="${CI_COMMIT_BRANCH}" -PinfoBuildSource="GitLab CI (${CI_PIPELINE_ID})" --gradle-user-home cache/; - ./gradlew clean -PmcVer="${MC_VER}" -PinfoGitCommit="${CI_COMMIT_SHA}" -PinfoGitBranch="${CI_COMMIT_BRANCH}" -PinfoBuildSource="GitLab CI (${CI_PIPELINE_ID})" --gradle-user-home cache/;
+19 -14
View File
@@ -54,7 +54,7 @@ def writeBuildGradlePredefine(List<String> mcVers, int mcIndex)
// Transfers the values set in settings.gradle to the rest of the project // Transfers the values set in settings.gradle to the rest of the project
project.gradle.ext.getProperties().each { prop -> project.gradle.ext.getProperties().each { prop ->
rootProject.ext.set(prop.key, prop.value) rootProject.ext.set(prop.key, prop.value)
// println "Added prop [key:" + prop.key + ", value:" + prop.value + "]" //println "Added prop [key:" + prop.key + ", value:" + prop.value + "]"
} }
// Sets up manifold stuff // Sets up manifold stuff
writeBuildGradlePredefine(rootProject.mcVers, rootProject.mcIndex) writeBuildGradlePredefine(rootProject.mcVers, rootProject.mcIndex)
@@ -106,11 +106,12 @@ subprojects { p ->
apply plugin: "systems.manifold.manifold-gradle-plugin" apply plugin: "systems.manifold.manifold-gradle-plugin"
// Apply forge's loom // Apply forge's loom
if ( if ((findProject(":forge") && p == project(":forge")) ||
(findProject(":forge") && p == project(":forge")) || (findProject(":neoforge") && p == project(":neoforge"))
(findProject(":neoforge") && p == project(":neoforge")) )
) {
apply plugin: "dev.architectury.loom" apply plugin: "dev.architectury.loom"
}
// Set the manifold version (may not be required tough) // Set the manifold version (may not be required tough)
@@ -430,9 +431,11 @@ subprojects { p ->
jar { jar {
from "LICENSE.txt" from "LICENSE.txt"
manifest { manifest {
attributes 'Implementation-Title': rootProject.mod_name, attributes(
'Implementation-Version': rootProject.mod_version, 'Implementation-Title': rootProject.mod_name,
'Main-Class': 'com.seibel.distanthorizons.core.jar.JarMain' // When changing the main of the jar change this line 'Implementation-Version': rootProject.mod_version,
'Main-Class': 'com.seibel.distanthorizons.core.jar.JarMain' // When changing the main of the jar change this line
)
} }
} }
@@ -521,14 +524,16 @@ allprojects { p ->
} }
} }
// Required for ModMenu // VanillaGradle and Mixins in common
maven { url "https://maven.terraformersmc.com/" }
// Required for Mixins & VanillaGradle
maven { url "https://repo.spongepowered.org/maven/" } maven { url "https://repo.spongepowered.org/maven/" }
// Required for Canvas (mod) // Canvas mod
maven { url "https://maven.vram.io/" } maven { url "https://maven.vram.io/" }
// ModMenu mod
maven { url "https://maven.terraformersmc.com/" }
// neoforge
maven { url "https://maven.neoforged.net/releases/" }
// These 3 are for importing mods that arnt on CursedForge, Modrinth, GitHub, GitLab or anywhere opensource // These 3 are for importing mods that arnt on CursedForge, Modrinth, GitHub, GitLab or anywhere opensource
flatDir { flatDir {
+9
View File
@@ -1,4 +1,13 @@
// temporary fix for broken spongepowered version
buildscript {
configurations.configureEach {
resolutionStrategy {
force 'org.spongepowered:vanillagradle:0.2.1-20240507.024226-82'
}
}
}
plugins { plugins {
id "org.spongepowered.gradle.vanilla" version "0.2.1-SNAPSHOT" id "org.spongepowered.gradle.vanilla" version "0.2.1-SNAPSHOT"
} }
@@ -130,7 +130,7 @@ public class WrapperFactory implements IWrapperFactory
} }
} }
#if MC_VER <= MC_1_20_6 #if MC_VER <= MC_1_21
else if (objectArray.length == 2) else if (objectArray.length == 2)
{ {
// correct number of parameters from the API // correct number of parameters from the API
@@ -195,7 +195,7 @@ public class WrapperFactory implements IWrapperFactory
{ {
String[] expectedClassNames; String[] expectedClassNames;
#if MC_VER <= MC_1_20_6 #if MC_VER <= MC_1_21
expectedClassNames = new String[] expectedClassNames = new String[]
{ {
ChunkAccess.class.getName(), ChunkAccess.class.getName(),
@@ -243,7 +243,7 @@ public class WrapperFactory implements IWrapperFactory
Biome biome = (Biome) objectArray[0]; Biome biome = (Biome) objectArray[0];
return BiomeWrapper.getBiomeWrapper(biome, coreLevelWrapper); return BiomeWrapper.getBiomeWrapper(biome, coreLevelWrapper);
#elif MC_VER <= MC_1_20_6 #elif MC_VER <= MC_1_21
if (!(objectArray[0] instanceof Holder) || !(((Holder<?>) objectArray[0]).value() instanceof Biome)) if (!(objectArray[0] instanceof Holder) || !(((Holder<?>) objectArray[0]).value() instanceof Biome))
{ {
throw new ClassCastException(createBiomeWrapperErrorMessage(objectArray)); throw new ClassCastException(createBiomeWrapperErrorMessage(objectArray));
@@ -266,7 +266,7 @@ public class WrapperFactory implements IWrapperFactory
#if MC_VER < MC_1_18_2 #if MC_VER < MC_1_18_2
expectedClassNames = new String[] { Biome.class.getName() }; expectedClassNames = new String[] { Biome.class.getName() };
#elif MC_VER <= MC_1_20_6 #elif MC_VER <= MC_1_21
expectedClassNames = new String[] { Holder.class.getName()+"<"+Biome.class.getName()+">" }; expectedClassNames = new String[] { Holder.class.getName()+"<"+Biome.class.getName()+">" };
#else #else
// See preprocessor comment in createChunkWrapper() for full documentation // See preprocessor comment in createChunkWrapper() for full documentation
@@ -287,7 +287,7 @@ public class WrapperFactory implements IWrapperFactory
#if MC_VER <= MC_1_20_6 #if MC_VER <= MC_1_21
if (objectArray.length != 1) if (objectArray.length != 1)
{ {
throw new ClassCastException(createBlockStateWrapperErrorMessage(objectArray)); throw new ClassCastException(createBlockStateWrapperErrorMessage(objectArray));
@@ -314,7 +314,7 @@ public class WrapperFactory implements IWrapperFactory
#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
expectedClassNames = new String[] { Biome.class.getName() }; expectedClassNames = new String[] { Biome.class.getName() };
#elif MC_VER <= MC_1_20_6 #elif MC_VER <= MC_1_21
expectedClassNames = new String[] { Holder.class.getName()+"<"+Biome.class.getName()+">" }; expectedClassNames = new String[] { Holder.class.getName()+"<"+Biome.class.getName()+">" };
#else #else
// See preprocessor comment in createChunkWrapper() for full documentation // See preprocessor comment in createChunkWrapper() for full documentation
@@ -293,7 +293,11 @@ public class BiomeWrapper implements IBiomeWrapper
ResourceLocation resourceLocation; ResourceLocation resourceLocation;
try try
{ {
#if MC_VER < MC_1_21
resourceLocation = new ResourceLocation(resourceLocationString.substring(0, separatorIndex), resourceLocationString.substring(separatorIndex + 1)); resourceLocation = new ResourceLocation(resourceLocationString.substring(0, separatorIndex), resourceLocationString.substring(separatorIndex + 1));
#else
resourceLocation = ResourceLocation.fromNamespaceAndPath(resourceLocationString.substring(0, separatorIndex), resourceLocationString.substring(separatorIndex + 1));
#endif
} }
catch (Exception e) catch (Exception e)
{ {
@@ -380,7 +380,11 @@ public class BlockStateWrapper implements IBlockStateWrapper
ResourceLocation resourceLocation; ResourceLocation resourceLocation;
try try
{ {
#if MC_VER < MC_1_21
resourceLocation = new ResourceLocation(resourceStateString.substring(0, separatorIndex), resourceStateString.substring(separatorIndex + 1)); resourceLocation = new ResourceLocation(resourceStateString.substring(0, separatorIndex), resourceStateString.substring(separatorIndex + 1));
#else
resourceLocation = ResourceLocation.fromNamespaceAndPath(resourceStateString.substring(0, separatorIndex), resourceStateString.substring(separatorIndex + 1));
#endif
} }
catch (Exception e) catch (Exception e)
{ {
@@ -1,239 +0,0 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2023 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.chunk;
import com.seibel.distanthorizons.coreapi.util.BitShiftUtil;
import java.util.ArrayList;
import java.util.Arrays;
/**
* Compact, efficient storage for light levels.
* all blocks only take up 4 bits in total,
* and if a 16x16x16 area is detected to have the same light level in all positions,
* then we store a single byte for that light level, instead of 2 kilobytes.
*
* @author Builderb0y
*/
public class ChunkLightStorage
{
/** the minimum Y level in the chunk which this storage is storing light levels for (inclusive). */
public int minY;
/** the maximum Y level in the chunk which this storage is storing light levels for (exclusive). */
public int maxY;
/** the data stored in this storage, split up into 16x16x16 areas. */
public LightSection[] lightSections;
/**
* If the get method is called on a Y position above what's stored
* this value will be returned. <br><br>
*
* This needs to be manually defined since sky and block lights behave differently
* for values both above and below what's defined.
*/
public int aboveMaxYValue;
/** @see ChunkLightStorage#aboveMaxYValue */
public int belowMinYValue;
//=============//
// constructor //
//=============//
public ChunkLightStorage(int minY, int maxY, int aboveMaxYValue, int belowMinYValue)
{
this.minY = minY;
this.maxY = maxY;
this.aboveMaxYValue = aboveMaxYValue;
this.belowMinYValue = belowMinYValue;
}
//=====================//
// getters and setters //
//=====================//
public int get(int x, int y, int z)
{
if (y < this.minY)
{
return this.belowMinYValue;
}
else if (y >= this.maxY)
{
return this.aboveMaxYValue;
}
if (this.lightSections != null)
{
LightSection lightSection = this.lightSections[BitShiftUtil.divideByPowerOfTwo(y - this.minY, 4)];
if (lightSection != null)
{
return lightSection.get(x, y, z);
}
}
return 0;
}
public void set(int x, int y, int z, int lightLevel)
{
if (y < this.minY || y >= this.maxY)
{
return;
}
//populate array if it doesn't exist.
if (this.lightSections == null)
{
this.lightSections = new LightSection[BitShiftUtil.divideByPowerOfTwo(this.maxY - this.minY, 4)];
}
int index = (y - this.minY) >> 4;
LightSection lightSection = this.lightSections[index];
//populate lightSection in array if it doesn't exist.
if (lightSection == null)
{
lightSection = new LightSection(0);
this.lightSections[index] = lightSection;
}
lightSection.set(x, y, z, lightLevel);
}
//================//
// helper classes //
//================//
public static class LightSection
{
public byte constantValue;
public long[] data;
public short[] counts;
public LightSection(int initialValue)
{
this.constantValue = (byte) (initialValue);
this.counts = new short[16];
this.counts[initialValue] = 16 * 16 * 16;
}
public int get(int x, int y, int z)
{
if (this.constantValue >= 0)
{
return this.constantValue;
}
x &= 15;
y &= 15;
z &= 15;
long bits = this.data[(z << 4) | x];
return ((int) (bits >>> (y << 2))) & 15;
}
public void set(int x, int y, int z, int lightLevel)
{
int oldLightLevel = -1;
if (this.constantValue >= 0)
{
oldLightLevel = this.constantValue;
//if the light level didn't change, then there's nothing to do.
if (oldLightLevel == lightLevel) return;
//if we are a constant value and need to change something,
//then that means we need to convert to a non-constant value.
this.data = DataRecycler.get();
//repeat oldLightLevel 16 times as a bit pattern.
long payload = oldLightLevel;
payload |= payload << 4;
payload |= payload << 8;
payload |= payload << 16;
payload |= payload << 32;
//fill our data with our constant value.
Arrays.fill(this.data, payload);
//we are no longer a constant value.
this.constantValue = -1;
}
x &= 15;
y &= 15;
z &= 15;
int index = (z << 4) | x;
long bits = this.data[index];
//if we weren't a constant value before, now's the time to initialize oldLightLevel.
if (oldLightLevel < 0)
{
oldLightLevel = ((int) (bits >>> (y << 2))) & 15;
}
//clear the 4 bits that correspond to the light level at x, y, z...
bits &= ~(15L << (y << 2));
//...and then re-populate those bits with the new light level.
bits |= ((long) (lightLevel)) << (y << 2);
//store the updated bits in our data.
this.data[index] = bits;
//we have one less of the old light level...
this.counts[oldLightLevel]--;
//...and one more of the new level.
//if the number associated with the new level is now 4096 (AKA 16 ^ 3),
//then this implies every position in this section has the same light level,
//and therefore we can convert back to a constant value.
if (++this.counts[lightLevel] == 4096)
{
this.constantValue = (byte) (lightLevel);
DataRecycler.reclaim(this.data);
this.data = null;
}
}
}
static class DataRecycler
{
private static final ArrayList<long[]> recycled = new ArrayList<>(256);
static synchronized long[] get()
{
if (recycled.isEmpty())
{
return new long[256];
}
else
{
return recycled.remove(recycled.size() - 1);
}
}
static synchronized void reclaim(long[] data) { if (recycled.size() < 256) recycled.add(data); }
}
}
@@ -25,13 +25,12 @@ import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.Dh
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.pos.DhBlockPos; import com.seibel.distanthorizons.core.pos.DhBlockPos;
import com.seibel.distanthorizons.core.pos.DhChunkPos; import com.seibel.distanthorizons.core.pos.DhChunkPos;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.ChunkLightStorage;
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.coreapi.ModInfo;
import net.minecraft.client.multiplayer.ClientChunkCache; import net.minecraft.client.multiplayer.ClientChunkCache;
import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
@@ -83,9 +82,6 @@ public class ChunkWrapper implements IChunkWrapper
{ {
private static final Logger LOGGER = DhLoggerBuilder.getLogger(); private static final Logger LOGGER = DhLoggerBuilder.getLogger();
/** useful for debugging, but can slow down chunk operations quite a bit due to being called every time. */
private static final boolean RUN_RELATIVE_POS_INDEX_VALIDATION = ModInfo.IS_DEV_BUILD;
/** can be used for interactions with the underlying chunk where creating new BlockPos objects could cause issues for the garbage collector. */ /** can be used for interactions with the underlying chunk where creating new BlockPos objects could cause issues for the garbage collector. */
private static final ThreadLocal<BlockPos.MutableBlockPos> MUTABLE_BLOCK_POS_REF = ThreadLocal.withInitial(() -> new BlockPos.MutableBlockPos()); private static final ThreadLocal<BlockPos.MutableBlockPos> MUTABLE_BLOCK_POS_REF = ThreadLocal.withInitial(() -> new BlockPos.MutableBlockPos());
@@ -109,6 +105,8 @@ public class ChunkWrapper implements IChunkWrapper
private int minNonEmptyHeight = Integer.MIN_VALUE; private int minNonEmptyHeight = Integer.MIN_VALUE;
private int maxNonEmptyHeight = Integer.MAX_VALUE; private int maxNonEmptyHeight = Integer.MAX_VALUE;
private int blockBiomeHashCode = 0;
/** /**
* Due to vanilla `isClientLightReady()` not being designed for use by a non-render thread, it may return 'true' * Due to vanilla `isClientLightReady()` not being designed for use by a non-render thread, it may return 'true'
* before the light engine has ticked, (right after all light changes is marked by the engine to be processed). * before the light engine has ticked, (right after all light changes is marked by the engine to be processed).
@@ -148,30 +146,34 @@ public class ChunkWrapper implements IChunkWrapper
//=========// //=========//
// methods // // getters //
//=========// //=========//
@Override @Override
public int getHeight() public int getHeight() { return getHeight(this.chunk); }
public static int getHeight(ChunkAccess chunk)
{ {
#if MC_VER < MC_1_17_1 #if MC_VER < MC_1_17_1
return 255; return 255;
#else #else
return this.chunk.getHeight(); return chunk.getHeight();
#endif #endif
} }
@Override @Override
public int getMinBuildHeight() public int getMinBuildHeight() { return getMinBuildHeight(this.chunk); }
public static int getMinBuildHeight(ChunkAccess chunk)
{ {
#if MC_VER < MC_1_17_1 #if MC_VER < MC_1_17_1
return 0; return 0;
#else #else
return this.chunk.getMinBuildHeight(); return chunk.getMinBuildHeight();
#endif #endif
} }
@Override @Override
public int getMaxBuildHeight() { return this.chunk.getMaxBuildHeight(); } public int getMaxBuildHeight() { return getMaxBuildHeight(this.chunk); }
public static int getMaxBuildHeight(ChunkAccess chunk) { return chunk.getMaxBuildHeight(); }
@Override @Override
public int getMinNonEmptyHeight() public int getMinNonEmptyHeight()
@@ -263,7 +265,6 @@ public class ChunkWrapper implements IChunkWrapper
public int getLightBlockingHeightMapValue(int xRel, int zRel) { return this.chunk.getOrCreateHeightmapUnprimed(Heightmap.Types.MOTION_BLOCKING).getFirstAvailable(xRel, zRel); } public int getLightBlockingHeightMapValue(int xRel, int zRel) { return this.chunk.getOrCreateHeightmapUnprimed(Heightmap.Types.MOTION_BLOCKING).getFirstAvailable(xRel, zRel); }
@Override @Override
public IBiomeWrapper getBiome(int relX, int relY, int relZ) public IBiomeWrapper getBiome(int relX, int relY, int relZ)
{ {
@@ -287,11 +288,35 @@ public class ChunkWrapper implements IChunkWrapper
#endif #endif
} }
@Override
public IBlockStateWrapper getBlockState(int relX, int relY, int relZ)
{
this.throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, relY, relZ);
BlockPos.MutableBlockPos blockPos = MUTABLE_BLOCK_POS_REF.get();
blockPos.setX(relX);
blockPos.setY(relY);
blockPos.setZ(relZ);
return BlockStateWrapper.fromBlockState(this.chunk.getBlockState(blockPos), this.wrappedLevel);
}
@Override @Override
public DhChunkPos getChunkPos() { return this.chunkPos; } public DhChunkPos getChunkPos() { return this.chunkPos; }
public ChunkAccess getChunk() { return this.chunk; } public ChunkAccess getChunk() { return this.chunk; }
public ChunkStatus getStatus() { return getStatus(this.getChunk()); }
public static ChunkStatus getStatus(ChunkAccess chunk)
{
#if MC_VER < MC_1_21
return chunk.getStatus();
#else
return chunk.getPersistedStatus();
#endif
}
@Override @Override
public int getMaxBlockX() { return this.chunk.getPos().getMaxBlockX(); } public int getMaxBlockX() { return this.chunk.getPos().getMaxBlockX(); }
@Override @Override
@@ -301,8 +326,11 @@ public class ChunkWrapper implements IChunkWrapper
@Override @Override
public int getMinBlockZ() { return this.chunk.getPos().getMinBlockZ(); } public int getMinBlockZ() { return this.chunk.getPos().getMinBlockZ(); }
@Override
public long getLongChunkPos() { return this.chunk.getPos().toLong(); }
//==========//
// lighting //
//==========//
@Override @Override
public void setIsDhLightCorrect(boolean isDhLightCorrect) { this.isDhLightCorrect = isDhLightCorrect; } public void setIsDhLightCorrect(boolean isDhLightCorrect) { this.isDhLightCorrect = isDhLightCorrect; }
@@ -310,8 +338,6 @@ public class ChunkWrapper implements IChunkWrapper
@Override @Override
public void setUseDhLighting(boolean useDhLighting) { this.useDhLighting = useDhLighting; } public void setUseDhLighting(boolean useDhLighting) { this.useDhLighting = useDhLighting; }
@Override @Override
public boolean isLightCorrect() public boolean isLightCorrect()
{ {
@@ -364,13 +390,11 @@ public class ChunkWrapper implements IChunkWrapper
{ {
if (this.blockLightStorage == null) if (this.blockLightStorage == null)
{ {
this.blockLightStorage = new ChunkLightStorage( this.blockLightStorage = ChunkLightStorage.createBlockLightStorage(this);
this.getMinBuildHeight(), this.getMaxBuildHeight(),
// positions above and below the handled area should be unlit
LodUtil.MIN_MC_LIGHT, LodUtil.MIN_MC_LIGHT);
} }
return this.blockLightStorage; return this.blockLightStorage;
} }
public void setBlockLightStorage(ChunkLightStorage lightStorage) { this.blockLightStorage = lightStorage; }
@Override @Override
@@ -390,13 +414,11 @@ public class ChunkWrapper implements IChunkWrapper
{ {
if (this.skyLightStorage == null) if (this.skyLightStorage == null)
{ {
this.skyLightStorage = new ChunkLightStorage( this.skyLightStorage = ChunkLightStorage.createSkyLightStorage(this);
this.getMinBuildHeight(), this.getMaxBuildHeight(),
// positions above should be lit but positions below should be unlit
LodUtil.MAX_MC_LIGHT, LodUtil.MIN_MC_LIGHT);
} }
return this.skyLightStorage; return this.skyLightStorage;
} }
public void setSkyLightStorage(ChunkLightStorage lightStorage) { this.skyLightStorage = lightStorage; }
@Override @Override
@@ -466,55 +488,6 @@ public class ChunkWrapper implements IChunkWrapper
return this.blockLightPosList; return this.blockLightPosList;
} }
@Override
public boolean doNearbyChunksExist()
{
if (this.lightSource instanceof DhLitWorldGenRegion)
{
return true;
}
for (int dx = -1; dx <= 1; dx++)
{
for (int dz = -1; dz <= 1; dz++)
{
if (dx == 0 && dz == 0)
{
continue;
}
else if (this.lightSource.getChunk(dx + this.chunk.getPos().x, dz + this.chunk.getPos().z, ChunkStatus.BIOMES, false) == null)
{
return false;
}
}
}
return true;
}
public LevelReader getColorResolver() { return this.lightSource; }
@Override
public String toString() { return this.chunk.getClass().getSimpleName() + this.chunk.getPos(); }
@Override
public IBlockStateWrapper getBlockState(int relX, int relY, int relZ)
{
this.throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, relY, relZ);
BlockPos.MutableBlockPos blockPos = MUTABLE_BLOCK_POS_REF.get();
blockPos.setX(relX);
blockPos.setY(relY);
blockPos.setZ(relZ);
return BlockStateWrapper.fromBlockState(this.chunk.getBlockState(blockPos), this.wrappedLevel);
}
@Override
public boolean isStillValid() { return this.wrappedLevel.tryGetChunk(this.chunkPos) == this; }
public static void syncedUpdateClientLightStatus() public static void syncedUpdateClientLightStatus()
{ {
#if MC_VER < MC_1_18_2 #if MC_VER < MC_1_18_2
@@ -574,64 +547,57 @@ public class ChunkWrapper implements IChunkWrapper
//================// //===============//
// helper methods // // other methods //
//================// //===============//
/** used to prevent accidentally attempting to get/set values outside this chunk's boundaries */ @Override
private void throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(int x, int y, int z) throws IndexOutOfBoundsException public boolean doNearbyChunksExist()
{ {
if (!RUN_RELATIVE_POS_INDEX_VALIDATION) if (this.lightSource instanceof DhLitWorldGenRegion)
{ {
return; return true;
} }
for (int dx = -1; dx <= 1; dx++)
// FIXME +1 is to handle the fact that LodDataBuilder adds +1 to all block lighting calculations, also done in the constructor
int minHeight = this.getMinBuildHeight();
int maxHeight = this.getMaxBuildHeight() + 1;
if (x < 0 || x >= LodUtil.CHUNK_WIDTH
|| z < 0 || z >= LodUtil.CHUNK_WIDTH
|| y < minHeight || y > maxHeight)
{ {
String errorMessage = "Relative position [" + x + "," + y + "," + z + "] out of bounds. \n" + for (int dz = -1; dz <= 1; dz++)
"X/Z must be between 0 and 15 (inclusive) \n" + {
"Y must be between [" + minHeight + "] and [" + maxHeight + "] (inclusive)."; if (dx == 0 && dz == 0)
throw new IndexOutOfBoundsException(errorMessage); {
continue;
}
else if (this.lightSource.getChunk(dx + this.chunk.getPos().x, dz + this.chunk.getPos().z, ChunkStatus.BIOMES, false) == null)
{
return false;
}
}
} }
return true;
} }
@Override
public boolean isStillValid() { return this.wrappedLevel.tryGetChunk(this.chunkPos) == this; }
/**
* Converts a 3D position into a 1D array index. <br><br>
*
* Source: <br>
* <a href="https://stackoverflow.com/questions/7367770/how-to-flatten-or-index-3d-array-in-1d-array">stackoverflow</a>
*/
public int relativeBlockPosToIndex(int xRel, int y, int zRel)
{
int yRel = y - this.getMinBuildHeight();
return (zRel * LodUtil.CHUNK_WIDTH * this.getHeight()) + (yRel * LodUtil.CHUNK_WIDTH) + xRel;
}
/**
* Converts a 3D position into a 1D array index. <br><br>
*
* Source: <br>
* <a href="https://stackoverflow.com/questions/7367770/how-to-flatten-or-index-3d-array-in-1d-array">stackoverflow</a>
*/
public DhBlockPos indexToRelativeBlockPos(int index)
{
final int zRel = index / (LodUtil.CHUNK_WIDTH * this.getHeight());
index -= (zRel * LodUtil.CHUNK_WIDTH * this.getHeight());
final int y = index / LodUtil.CHUNK_WIDTH; //================//
final int yRel = y + this.getMinBuildHeight(); // base overrides //
//================//
final int xRel = index % LodUtil.CHUNK_WIDTH; @Override
return new DhBlockPos(xRel, yRel, zRel); public String toString() { return this.chunk.getClass().getSimpleName() + this.chunk.getPos(); }
}
//@Override
//public int hashCode()
//{
// if (this.blockBiomeHashCode == 0)
// {
// this.blockBiomeHashCode = this.getBlockBiomeHashCode();
// }
//
// return this.blockBiomeHashCode;
//}
} }
@@ -245,7 +245,7 @@ public class ClassicConfigGUI
} }
// Changelog button // Changelog button
if (Config.Client.Advanced.AutoUpdater.enableAutoUpdater.get() && Config.Client.Advanced.AutoUpdater.updateBranch.get() == EDhApiUpdateBranch.STABLE) if (Config.Client.Advanced.AutoUpdater.enableAutoUpdater.get() && !ModInfo.IS_DEV_BUILD) // we only have changelogs for stable builds
{ {
this.addBtn(new TexturedButtonWidget( this.addBtn(new TexturedButtonWidget(
// Where the button is on the screen // Where the button is on the screen
@@ -255,7 +255,13 @@ public class ClassicConfigGUI
// texture UV Offset // texture UV Offset
0, 0, 0, 0,
// Some textuary stuff // Some textuary stuff
0, new ResourceLocation(ModInfo.ID, "textures/gui/changelog.png"), 20, 20, 0,
#if MC_VER < MC_1_21
new ResourceLocation(ModInfo.ID, "textures/gui/changelog.png"),
#else
ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "textures/gui/changelog.png"),
#endif
20, 20,
// Create the button and tell it where to go // Create the button and tell it where to go
(buttonWidget) -> { (buttonWidget) -> {
ChangelogScreen changelogScreen = new ChangelogScreen(this); ChangelogScreen changelogScreen = new ChangelogScreen(this);
@@ -168,10 +168,9 @@ public class ChangelogScreen extends DhScreen
#endif #endif
this.changelogArea.render(matrices, mouseX, mouseY, delta); // Render the changelog // render order matters, otherwise on 1.20.6+ the blurred background will render on top of the text
super.render(matrices, mouseX, mouseY, delta); // Render the buttons super.render(matrices, mouseX, mouseY, delta); // Render the buttons
this.changelogArea.render(matrices, mouseX, mouseY, delta); // Render the changelog
DhDrawCenteredString(matrices, font, title, width / 2, 15, 0xFFFFFF); // Render title DhDrawCenteredString(matrices, font, title, width / 2, 15, 0xFFFFFF); // Render title
} }
@@ -42,15 +42,17 @@ public class UpdateModScreen extends DhScreen
this.parent = parent; this.parent = parent;
this.newVersionID = newVersionID; this.newVersionID = newVersionID;
switch (Config.Client.Advanced.AutoUpdater.updateBranch.get()) {
case STABLE: EDhApiUpdateBranch updateBranch = EDhApiUpdateBranch.convertAutoToStableOrNightly(Config.Client.Advanced.AutoUpdater.updateBranch.get());
currentVer = ModInfo.VERSION; if (updateBranch == EDhApiUpdateBranch.STABLE)
nextVer = ModrinthGetter.releaseNames.get(this.newVersionID); {
break; this.currentVer = ModInfo.VERSION;
case NIGHTLY: this.nextVer = ModrinthGetter.releaseNames.get(this.newVersionID);
currentVer = ModJarInfo.Git_Commit.substring(0,7); }
nextVer = this.newVersionID.substring(0,7); else
break; {
this.currentVer = ModJarInfo.Git_Commit.substring(0,7);
this.nextVer = this.newVersionID.substring(0,7);
} }
} }
@@ -73,7 +75,13 @@ public class UpdateModScreen extends DhScreen
// Offset // Offset
0, 0, 0, 0,
// Some textuary stuff // Some textuary stuff
0, new ResourceLocation(ModInfo.ID, "logo.png"), 130, 65, 0,
#if MC_VER < MC_1_21
new ResourceLocation(ModInfo.ID, "logo.png"),
#else
ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "logo.png"),
#endif
130, 65,
// Create the button and tell it where to go // Create the button and tell it where to go
// For now it goes to the client option by default // For now it goes to the client option by default
(buttonWidget) -> System.out.println("Nice, you found an easter egg :)"), // TODO: Add a proper easter egg to pressing the logo (maybe with confetti) (buttonWidget) -> System.out.println("Nice, you found an easter egg :)"), // TODO: Add a proper easter egg to pressing the logo (maybe with confetti)
@@ -88,7 +96,7 @@ public class UpdateModScreen extends DhScreen
e.printStackTrace(); e.printStackTrace();
} }
if (Config.Client.Advanced.AutoUpdater.updateBranch.get() == EDhApiUpdateBranch.STABLE) if (!ModInfo.IS_DEV_BUILD)
{ {
this.addBtn(new TexturedButtonWidget( this.addBtn(new TexturedButtonWidget(
// Where the button is on the screen // Where the button is on the screen
@@ -98,7 +106,13 @@ public class UpdateModScreen extends DhScreen
// Offset // Offset
0, 0, 0, 0,
// Some textuary stuff // Some textuary stuff
0, new ResourceLocation(ModInfo.ID, "textures/gui/changelog.png"), 20, 20, 0,
#if MC_VER < MC_1_21
new ResourceLocation(ModInfo.ID, "textures/gui/changelog.png"),
#else
ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "textures/gui/changelog.png"),
#endif
20, 20,
// Create the button and tell it where to go // Create the button and tell it where to go
(buttonWidget) -> Objects.requireNonNull(minecraft).setScreen(new ChangelogScreen(this, this.newVersionID)), // TODO: Add a proper easter egg to pressing the logo (maybe with confetti) (buttonWidget) -> Objects.requireNonNull(minecraft).setScreen(new ChangelogScreen(this, this.newVersionID)), // TODO: Add a proper easter egg to pressing the logo (maybe with confetti)
// Add a title to the button // Add a title to the button
@@ -12,16 +12,20 @@ public class MinecraftDedicatedServerWrapper implements IMinecraftSharedWrapper
private MinecraftDedicatedServerWrapper() { } private MinecraftDedicatedServerWrapper() { }
public DedicatedServer dedicatedServer = null; public DedicatedServer dedicatedServer = null;
@Override @Override
public boolean isDedicatedServer() public boolean isDedicatedServer() { return true; }
{
return true;
}
@Override @Override
public File getInstallationDirectory() public File getInstallationDirectory()
{ {
if (dedicatedServer == null) if (this.dedicatedServer == null)
{
throw new IllegalStateException("Trying to get Installation Direction before Dedicated server complete initialization!"); throw new IllegalStateException("Trying to get Installation Direction before Dedicated server complete initialization!");
return dedicatedServer.getServerDirectory(); }
#if MC_VER < MC_1_21
return this.dedicatedServer.getServerDirectory();
#else
return this.dedicatedServer.getServerDirectory().toFile();
#endif
} }
} }
@@ -212,15 +212,24 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
{ {
if (MC.level.dimensionType().hasSkyLight()) if (MC.level.dimensionType().hasSkyLight())
{ {
#if MC_VER < MC_1_17_1 float frameTime;
Vec3 colorValues = MC.level.getSkyColor(MC.gameRenderer.getMainCamera().getBlockPosition(), MC.getFrameTime()); #if MC_VER < MC_1_21
frameTime = MC.getFrameTime();
#else #else
Vec3 colorValues = MC.level.getSkyColor(MC.gameRenderer.getMainCamera().getPosition(), MC.getFrameTime()); frameTime = MC.getTimer().getRealtimeDeltaTicks();
#endif
#if MC_VER < MC_1_17_1
Vec3 colorValues = MC.level.getSkyColor(MC.gameRenderer.getMainCamera().getBlockPosition(), frameTime);
#else
Vec3 colorValues = MC.level.getSkyColor(MC.gameRenderer.getMainCamera().getPosition(), frameTime);
#endif #endif
return new Color((float) colorValues.x, (float) colorValues.y, (float) colorValues.z); return new Color((float) colorValues.x, (float) colorValues.y, (float) colorValues.z);
} }
else else
{
return new Color(0, 0, 0); return new Color(0, 0, 0);
}
} }
@Override @Override
@@ -35,6 +35,7 @@ import com.seibel.distanthorizons.core.pos.DhChunkPos;
import com.seibel.distanthorizons.core.util.objects.EventTimer; import com.seibel.distanthorizons.core.util.objects.EventTimer;
import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.util.gridList.ArrayGridList; import com.seibel.distanthorizons.core.util.gridList.ArrayGridList;
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.ChunkLightStorage;
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.worldGeneration.AbstractBatchGenerationEnvironmentWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.worldGeneration.AbstractBatchGenerationEnvironmentWrapper;
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
@@ -109,8 +110,6 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
new ConfigBasedLogger(LogManager.getLogger("LodWorldGen"), new ConfigBasedLogger(LogManager.getLogger("LodWorldGen"),
() -> Config.Client.Advanced.Logging.logWorldGenLoadEvent.get()); () -> Config.Client.Advanced.Logging.logWorldGenLoadEvent.get());
//TODO: Make actual proper support for StarLight
public static class PerfCalculator public static class PerfCalculator
{ {
private static final String[] TIME_NAMES = { private static final String[] TIME_NAMES = {
@@ -294,6 +293,9 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
//=================//
// synchronization //
//=================//
public <T> T joinSync(CompletableFuture<T> future) public <T> T joinSync(CompletableFuture<T> future)
{ {
@@ -344,7 +346,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
} }
else if (event.hasTimeout(Config.Client.Advanced.WorldGenerator.worldGenerationTimeoutLengthInSeconds.get(), TimeUnit.SECONDS)) else if (event.hasTimeout(Config.Client.Advanced.WorldGenerator.worldGenerationTimeoutLengthInSeconds.get(), TimeUnit.SECONDS))
{ {
EVENT_LOGGER.error("Batching World Generator: " + event + " timed out and terminated!"); EVENT_LOGGER.error("Batching World Generator: " + event + " timed out and terminated! Please lower your CPU load.");
EVENT_LOGGER.info("Dump PrefEvent: " + event.timer); EVENT_LOGGER.info("Dump PrefEvent: " + event.timer);
try try
{ {
@@ -368,31 +370,197 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
} }
} }
private static ProtoChunk EmptyChunk(ServerLevel level, ChunkPos chunkPos)
//==================//
// world generation //
//==================//
public void generateLodFromList(GenerationEvent genEvent) throws InterruptedException
{ {
return new ProtoChunk(chunkPos, UpgradeData.EMPTY EVENT_LOGGER.debug("Lod Generate Event: " + genEvent.minPos);
#if MC_VER >= MC_1_17_1 , level #endif
#if MC_VER >= MC_1_18_2 , level.registryAccess().registryOrThrow(
#if MC_VER < MC_1_19_4
Registry.BIOME_REGISTRY
#else
Registries.BIOME
#endif
), null #endif
);
ArrayGridList<ChunkWrapper> chunkWrapperList;
DhLitWorldGenRegion region;
DummyLightEngine dummyLightEngine;
LightGetterAdaptor adaptor;
int borderSize = MaxBorderNeeded;
int refSize = genEvent.size + borderSize * 2;
int refPosX = genEvent.minPos.x - borderSize;
int refPosZ = genEvent.minPos.z - borderSize;
try
{
ArrayGridList<ChunkAccess> totalChunks;
adaptor = new LightGetterAdaptor(this.params.level);
dummyLightEngine = new DummyLightEngine(adaptor);
//=============================//
// try getting existing chunks //
//=============================//
HashMap<DhChunkPos, ChunkLightStorage> chunkSkyLightingByDhPos = new HashMap<>();
HashMap<DhChunkPos, ChunkLightStorage> chunkBlockLightingByDhPos = new HashMap<>();
IEmptyChunkGeneratorFunc emptyChunkGeneratorFunc = (int x, int z) ->
{
ChunkPos chunkPos = new ChunkPos(x, z);
DhChunkPos dhChunkPos = new DhChunkPos(x, z);
ChunkAccess newChunk = null;
try
{
// get the chunk
CompoundTag chunkData = this.getChunkNbtData(chunkPos);
newChunk = this.loadOrMakeChunk(chunkPos, chunkData);
// get chunk lighting
ChunkLoader.CombinedChunkLightStorage combinedLights = ChunkLoader.readLight(newChunk, chunkData);
if (combinedLights != null)
{
chunkSkyLightingByDhPos.put(dhChunkPos, combinedLights.skyLightStorage);
chunkBlockLightingByDhPos.put(dhChunkPos, combinedLights.blockLightStorage);
}
}
catch (RuntimeException loadChunkError)
{
// Continue...
}
if (newChunk == null)
{
newChunk = new ProtoChunk(chunkPos, UpgradeData.EMPTY
#if MC_VER >= MC_1_17_1 , this.params.level #endif
#if MC_VER >= MC_1_18_2 , this.params.biomes, null #endif
);
}
return newChunk;
};
totalChunks = new ArrayGridList<>(refSize, (x, z) -> emptyChunkGeneratorFunc.generate(x + refPosX, z + refPosZ));
int radius = refSize / 2;
int centerX = refPosX + radius;
int centerZ = refPosZ + radius;
ChunkAccess centerChunk = totalChunks.stream().filter(chunk -> chunk.getPos().x == centerX && chunk.getPos().z == centerZ).findFirst().get();
genEvent.refreshTimeout();
region = new DhLitWorldGenRegion(
centerX, centerZ,
centerChunk,
this.params.level, dummyLightEngine, totalChunks,
ChunkStatus.STRUCTURE_STARTS, radius, emptyChunkGeneratorFunc);
adaptor.setRegion(region);
genEvent.threadedParam.makeStructFeat(region, this.params);
//=======================//
// create chunk wrappers //
//=======================//
chunkWrapperList = new ArrayGridList<>(totalChunks.gridSize);
totalChunks.forEachPos((x, z) ->
{
ChunkAccess chunk = totalChunks.get(x, z);
if (chunk != null)
{
// wrap the chunk
ChunkWrapper chunkWrapper = new ChunkWrapper(chunk, region, this.serverlevel.getLevelWrapper());
chunkWrapperList.set(x, z, chunkWrapper);
// try getting the chunk lighting
if (chunkBlockLightingByDhPos.containsKey(chunkWrapper.getChunkPos()))
{
chunkWrapper.setBlockLightStorage(chunkBlockLightingByDhPos.get(chunkWrapper.getChunkPos()));
chunkWrapper.setSkyLightStorage(chunkSkyLightingByDhPos.get(chunkWrapper.getChunkPos()));
chunkWrapper.setUseDhLighting(true);
chunkWrapper.setIsDhLightCorrect(true);
}
else
{
int k = 0;
}
}
});
//=================//
// generate chunks //
//=================//
this.generateDirect(genEvent, chunkWrapperList, borderSize, genEvent.targetGenerationStep, region);
genEvent.timer.nextEvent("cleanup");
}
catch (StepStructureStart.StructStartCorruptedException f)
{
genEvent.threadedParam.markAsInvalid();
throw (RuntimeException) f.getCause();
}
ArrayGridList<ChunkWrapper> finalGenChunks = GetCutoutFrom(chunkWrapperList, borderSize);
for (int offsetY = 0; offsetY < finalGenChunks.gridSize; offsetY++)
{
for (int offsetX = 0; offsetX < finalGenChunks.gridSize; offsetX++)
{
ChunkWrapper wrappedChunk = finalGenChunks.get(offsetX, offsetY);
ChunkAccess target = wrappedChunk.getChunk();
if (target instanceof LevelChunk)
{
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
((LevelChunk) target).setLoaded(true);
#else
((LevelChunk) target).loaded = true;
#endif
}
if (!wrappedChunk.isLightCorrect())
{
throw new RuntimeException("The generated chunk somehow has isLightCorrect() returning false");
}
boolean isFull = ChunkWrapper.getStatus(target) == ChunkStatus.FULL || target instanceof LevelChunk;
#if MC_VER >= MC_1_18_2
boolean isPartial = target.isOldNoiseGeneration();
#endif
if (isFull)
{
LOAD_LOGGER.info("Detected full existing chunk at {}", target.getPos());
genEvent.resultConsumer.accept(wrappedChunk);
}
#if MC_VER >= MC_1_18_2
else if (isPartial)
{
LOAD_LOGGER.info("Detected old existing chunk at {}", target.getPos());
genEvent.resultConsumer.accept(wrappedChunk);
}
#endif
else if (ChunkWrapper.getStatus(target) == ChunkStatus.EMPTY)
{
genEvent.resultConsumer.accept(wrappedChunk);
}
else
{
genEvent.resultConsumer.accept(wrappedChunk);
}
}
}
genEvent.timer.complete();
genEvent.refreshTimeout();
if (PREF_LOGGER.canMaybeLog())
{
genEvent.threadedParam.perf.recordEvent(genEvent.timer);
PREF_LOGGER.infoInc("{}", genEvent.timer);
}
} }
private CompoundTag getChunkNbtData(ChunkPos chunkPos)
public ChunkAccess loadOrMakeChunk(ChunkPos chunkPos)
{ {
ServerLevel level = this.params.level; ServerLevel level = this.params.level;
//====================//
// get the chunk data //
//====================//
CompoundTag chunkData = null; CompoundTag chunkData = null;
try try
{ {
@@ -425,15 +593,15 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
LOAD_LOGGER.error("DistantHorizons: Couldn't load or make chunk " + chunkPos + ". Error: " + e.getMessage(), e); LOAD_LOGGER.error("DistantHorizons: Couldn't load or make chunk " + chunkPos + ". Error: " + e.getMessage(), e);
} }
return chunkData;
}
//========================// private ChunkAccess loadOrMakeChunk(ChunkPos chunkPos, CompoundTag chunkData)
// convert the chunk data // {
//========================// ServerLevel level = this.params.level;
if (chunkData == null) if (chunkData == null)
{ {
return EmptyChunk(level, chunkPos); return CreateEmptyChunk(level, chunkPos);
} }
else else
{ {
@@ -445,154 +613,28 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
catch (Exception e) catch (Exception e)
{ {
LOAD_LOGGER.error( LOAD_LOGGER.error(
"DistantHorizons: couldn't load or make chunk at ["+chunkPos+"]." + "DistantHorizons: couldn't load or make chunk at ["+chunkPos+"]." +
"Please try optimizing your world to fix this issue. \n" + "Please try optimizing your world to fix this issue. \n" +
"World optimization can be done from the singleplayer world selection screen.\n" + "World optimization can be done from the singleplayer world selection screen.\n" +
"Error: ["+e.getMessage()+"]." "Error: ["+e.getMessage()+"]."
, e); , e);
return EmptyChunk(level, chunkPos); return CreateEmptyChunk(level, chunkPos);
} }
} }
} }
private static ProtoChunk CreateEmptyChunk(ServerLevel level, ChunkPos chunkPos)
private static <T> ArrayGridList<T> GetCutoutFrom(ArrayGridList<T> total, int border)
{ {
return new ArrayGridList<>(total, border, total.gridSize - border); return new ProtoChunk(chunkPos, UpgradeData.EMPTY
} #if MC_VER >= MC_1_17_1 , level #endif
#if MC_VER >= MC_1_18_2 , level.registryAccess().registryOrThrow(
private static <T> ArrayGridList<T> GetCutoutFrom(ArrayGridList<T> total, EDhApiWorldGenerationStep step) #if MC_VER < MC_1_19_4
{ Registry.BIOME_REGISTRY
return GetCutoutFrom(total, MaxBorderNeeded - BorderNeeded.get(step)); #else
} Registries.BIOME
#endif
public void generateLodFromList(GenerationEvent genEvent) throws InterruptedException ), null #endif
{ );
EVENT_LOGGER.debug("Lod Generate Event: " + genEvent.minPos);
ArrayGridList<ChunkWrapper> chunkWrapperList;
DhLitWorldGenRegion region;
DummyLightEngine lightEngine;
LightGetterAdaptor adaptor;
int borderSize = MaxBorderNeeded;
int refSize = genEvent.size + borderSize * 2;
int refPosX = genEvent.minPos.x - borderSize;
int refPosZ = genEvent.minPos.z - borderSize;
try
{
ArrayGridList<ChunkAccess> totalChunks;
adaptor = new LightGetterAdaptor(this.params.level);
lightEngine = new DummyLightEngine(adaptor);
EmptyChunkGenerator generator = (int x, int z) ->
{
ChunkPos chunkPos = new ChunkPos(x, z);
ChunkAccess target = null;
try
{
target = this.loadOrMakeChunk(chunkPos);
}
catch (RuntimeException e2)
{
// Continue...
}
if (target == null)
{
target = new ProtoChunk(chunkPos, UpgradeData.EMPTY
#if MC_VER >= MC_1_17_1 , params.level #endif
#if MC_VER >= MC_1_18_2 , params.biomes, null #endif
);
}
return target;
};
totalChunks = new ArrayGridList<>(refSize, (x, z) -> generator.generate(x + refPosX, z + refPosZ));
genEvent.refreshTimeout();
region = new DhLitWorldGenRegion(params.level, lightEngine, totalChunks,
ChunkStatus.STRUCTURE_STARTS, refSize / 2, generator);
adaptor.setRegion(region);
genEvent.threadedParam.makeStructFeat(region, params);
chunkWrapperList = new ArrayGridList<>(totalChunks.gridSize);
totalChunks.forEachPos((x, z) ->
{
ChunkAccess chunk = totalChunks.get(x, z);
if (chunk != null)
{
chunkWrapperList.set(x, z, new ChunkWrapper(chunk, region, serverlevel.getLevelWrapper()));
}
});
this.generateDirect(genEvent, chunkWrapperList, borderSize, genEvent.targetGenerationStep, region);
genEvent.timer.nextEvent("cleanup");
}
catch (StepStructureStart.StructStartCorruptedException f)
{
genEvent.threadedParam.markAsInvalid();
throw (RuntimeException) f.getCause();
}
ArrayGridList<ChunkWrapper> finalGenChunks = GetCutoutFrom(chunkWrapperList, borderSize);
for (int offsetY = 0; offsetY < finalGenChunks.gridSize; offsetY++)
{
for (int offsetX = 0; offsetX < finalGenChunks.gridSize; offsetX++)
{
ChunkWrapper wrappedChunk = finalGenChunks.get(offsetX, offsetY);
ChunkAccess target = wrappedChunk.getChunk();
if (target instanceof LevelChunk)
{
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
((LevelChunk) target).setLoaded(true);
#else
((LevelChunk) target).loaded = true;
#endif
}
if (!wrappedChunk.isLightCorrect())
{
throw new RuntimeException("The generated chunk somehow has isLightCorrect() returning false");
}
boolean isFull = target.getStatus() == ChunkStatus.FULL || target instanceof LevelChunk;
#if MC_VER >= MC_1_18_2
boolean isPartial = target.isOldNoiseGeneration();
#endif
if (isFull)
{
LOAD_LOGGER.info("Detected full existing chunk at {}", target.getPos());
genEvent.resultConsumer.accept(wrappedChunk);
}
#if MC_VER >= MC_1_18_2
else if (isPartial)
{
LOAD_LOGGER.info("Detected old existing chunk at {}", target.getPos());
genEvent.resultConsumer.accept(wrappedChunk);
}
#endif
else if (target.getStatus() == ChunkStatus.EMPTY)
{
genEvent.resultConsumer.accept(wrappedChunk);
}
else
{
genEvent.resultConsumer.accept(wrappedChunk);
}
}
}
genEvent.timer.complete();
genEvent.refreshTimeout();
if (PREF_LOGGER.canMaybeLog())
{
genEvent.threadedParam.perf.recordEvent(genEvent.timer);
PREF_LOGGER.infoInc("{}", genEvent.timer);
}
} }
public void generateDirect( public void generateDirect(
@@ -694,7 +736,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
for (int i = 0; i < chunksToGenerate.size(); i++) // regular for loop since enhanced for loops increase GC pressure slightly for (int i = 0; i < chunksToGenerate.size(); i++) // regular for loop since enhanced for loops increase GC pressure slightly
{ {
ChunkWrapper chunkWrapper = chunksToGenerate.get(i); ChunkWrapper chunkWrapper = chunksToGenerate.get(i);
if (chunkWrapper.getChunk().getStatus() != ChunkStatus.EMPTY) if (chunkWrapper.getStatus() != ChunkStatus.EMPTY)
{ {
iChunkWrapperList.add(chunkWrapper); iChunkWrapperList.add(chunkWrapper);
} }
@@ -715,19 +757,19 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
// if this isn't done everything else afterward may fail // if this isn't done everything else afterward may fail
Heightmap.primeHeightmaps(((ChunkWrapper)centerChunk).getChunk(), ChunkStatus.FEATURES.heightmapsAfter()); Heightmap.primeHeightmaps(((ChunkWrapper)centerChunk).getChunk(), ChunkStatus.FEATURES.heightmapsAfter());
// populate the lighting // pre-generated chunks should have lighting but new ones won't
DhLightingEngine.INSTANCE.lightChunk(centerChunk, iChunkWrapperList, maxSkyLight); if (!centerChunk.isLightCorrect())
{
DhLightingEngine.INSTANCE.lightChunk(centerChunk, iChunkWrapperList, maxSkyLight);
}
} }
genEvent.refreshTimeout(); genEvent.refreshTimeout();
} }
} }
private static <T> ArrayGridList<T> GetCutoutFrom(ArrayGridList<T> total, int border) { return new ArrayGridList<>(total, border, total.gridSize - border); }
private static <T> ArrayGridList<T> GetCutoutFrom(ArrayGridList<T> total, EDhApiWorldGenerationStep step) { return GetCutoutFrom(total, MaxBorderNeeded - BorderNeeded.get(step)); }
public interface EmptyChunkGenerator
{
ChunkAccess generate(int x, int z);
}
@Override @Override
public int getEventCount() { return this.generationEventList.size(); } public int getEventCount() { return this.generationEventList.size(); }
@@ -776,6 +818,12 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
return genEvent.future; return genEvent.future;
} }
//================//
// helper methods //
//================//
/** /**
* Called before code that may run for an extended period of time. <br> * Called before code that may run for an extended period of time. <br>
* This is necessary to allow canceling world gen since waiting * This is necessary to allow canceling world gen since waiting
@@ -789,4 +837,16 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
} }
} }
//================//
// helper classes //
//================//
@FunctionalInterface
public interface IEmptyChunkGeneratorFunc
{
ChunkAccess generate(int x, int z);
}
} }
@@ -22,9 +22,14 @@ package com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
import com.mojang.serialization.Dynamic; 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.common.wrappers.worldGeneration.BatchGenerationEnvironment;
import com.seibel.distanthorizons.core.logging.ConfigBasedLogger; import com.seibel.distanthorizons.core.logging.ConfigBasedLogger;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.ChunkLightStorage;
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
import it.unimi.dsi.fastutil.longs.LongSet; import it.unimi.dsi.fastutil.longs.LongSet;
@@ -44,6 +49,7 @@ import net.minecraft.core.registries.Registries;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag; import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.NbtOps;
import net.minecraft.nbt.Tag;
import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.*; import net.minecraft.world.level.*;
@@ -79,6 +85,9 @@ import net.minecraft.world.level.material.Fluids;
#if MC_VER == MC_1_20_6 #if MC_VER == MC_1_20_6
import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.chunk.status.ChunkStatus;
import net.minecraft.world.level.chunk.status.ChunkType; import net.minecraft.world.level.chunk.status.ChunkType;
#elif MC_VER == MC_1_21
import net.minecraft.world.level.chunk.status.ChunkStatus;
import net.minecraft.world.level.chunk.status.ChunkType;
#endif #endif
import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.Fluid;
@@ -100,138 +109,13 @@ public class ChunkLoader
private static final String FLUID_TICKS_TAG_PRE18 = "LiquidTicks"; private static final String FLUID_TICKS_TAG_PRE18 = "LiquidTicks";
private static final ConfigBasedLogger LOGGER = BatchGenerationEnvironment.LOAD_LOGGER; private static final ConfigBasedLogger LOGGER = BatchGenerationEnvironment.LOAD_LOGGER;
#if MC_VER >= MC_1_18_2 private static boolean lightingSectionErrorLogged = false;
private static BlendingData readBlendingData(CompoundTag chunkData)
{
BlendingData blendingData = null;
if (chunkData.contains("blending_data", 10))
{
@SuppressWarnings({"unchecked", "rawtypes"})
Dynamic<CompoundTag> blendingDataTag = new Dynamic(NbtOps.INSTANCE, chunkData.getCompound("blending_data"));
blendingData = BlendingData.CODEC.parse(blendingDataTag).resultOrPartial(LOGGER::error).orElse(null);
}
return blendingData;
}
#endif
private static LevelChunkSection[] readSections(LevelAccessor level, ChunkPos chunkPos, CompoundTag chunkData)
{
#if MC_VER >= MC_1_18_2
#if MC_VER < MC_1_19_4
Registry<Biome> biomes = level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY);
#else
Registry<Biome> biomes = level.registryAccess().registryOrThrow(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));
#else
Codec<PalettedContainer<Holder<Biome>>> biomeCodec = PalettedContainer.codecRW(
biomes.asHolderIdMap(), biomes.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getHolderOrThrow(Biomes.PLAINS));
#endif
#endif
int i = #if MC_VER < MC_1_17_1 16; #else level.getSectionsCount(); #endif
LevelChunkSection[] chunkSections = new LevelChunkSection[i];
boolean isLightOn = chunkData.getBoolean("isLightOn");
boolean hasSkyLight = level.dimensionType().hasSkyLight();
ListTag tagSections = chunkData.getList("Sections", 10);
if (tagSections.isEmpty()) tagSections = chunkData.getList("sections", 10);
for (int j = 0; j < tagSections.size(); ++j) //============//
{ // read chunk //
CompoundTag tagSection = tagSections.getCompound(j); //============//
int sectionYPos = tagSection.getByte("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
blockStateContainer = tagSection.contains("block_states", 10)
? BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, tagSection.getCompound("block_states")).promotePartial(string -> logErrors(chunkPos, sectionYPos, string))
#if MC_VER < MC_1_20_6 .getOrThrow(false, LOGGER::error) #else .getOrThrow((message) -> (RuntimeException) LOGGER.errorAndThrow(message, null)) #endif
: new PalettedContainer<BlockState>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);
#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, LOGGER::error)
: new PalettedContainer<Biome>(biomes, biomes.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
#else
biomeContainer = tagSection.contains("biomes", 10)
? biomeCodec.parse(NbtOps.INSTANCE, tagSection.getCompound("biomes")).promotePartial(string -> logErrors(chunkPos, i, (String) string))
#if MC_VER < MC_1_20_6 .getOrThrow(false, LOGGER::error) #else .getOrThrow((message) -> (RuntimeException) LOGGER.errorAndThrow(message, null)) #endif
: new PalettedContainer<Holder<Biome>>(biomes.asHolderIdMap(), biomes.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
#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 void readHeightmaps(LevelChunk chunk, CompoundTag chunkData)
{
CompoundTag tagHeightmaps = chunkData.getCompound("Heightmaps");
for (Heightmap.Types type : ChunkStatus.FULL.heightmapsAfter())
{
String heightmap = type.getSerializationKey();
if (tagHeightmaps.contains(heightmap, 12))
chunk.setHeightmap(type, tagHeightmaps.getLongArray(heightmap));
}
Heightmap.primeHeightmaps(chunk, ChunkStatus.FULL.heightmapsAfter());
}
private static void readPostPocessings(LevelChunk chunk, CompoundTag chunkData)
{
ListTag tagPostProcessings = chunkData.getList("PostProcessing", 9);
for (int n = 0; n < tagPostProcessings.size(); ++n)
{
ListTag listTag3 = tagPostProcessings.getList(n);
for (int o = 0; o < listTag3.size(); ++o)
{
chunk.addPackedPostProcess(listTag3.getShort(o), n);
}
}
}
public static #if MC_VER < MC_1_20_6 ChunkStatus.ChunkType #else ChunkType #endif readChunkType(CompoundTag tagLevel)
{
ChunkStatus chunkStatus = ChunkStatus.byName(tagLevel.getString("Status"));
if (chunkStatus != null)
{
return chunkStatus.getChunkType();
}
return #if MC_VER < MC_1_20_6 ChunkStatus.ChunkType.PROTOCHUNK; #else ChunkType.PROTOCHUNK; #endif
}
public static LevelChunk read(WorldGenLevel level, ChunkPos chunkPos, CompoundTag chunkData) public static LevelChunk read(WorldGenLevel level, ChunkPos chunkPos, CompoundTag chunkData)
{ {
@@ -349,11 +233,290 @@ public class ChunkLoader
readPostPocessings(chunk, chunkData); readPostPocessings(chunk, chunkData);
return chunk; return chunk;
} }
private static LevelChunkSection[] readSections(LevelAccessor level, ChunkPos chunkPos, CompoundTag chunkData)
{
#if MC_VER >= MC_1_18_2
#if MC_VER < MC_1_19_4
Registry<Biome> biomes = level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY);
#else
Registry<Biome> biomes = level.registryAccess().registryOrThrow(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));
#else
Codec<PalettedContainer<Holder<Biome>>> biomeCodec = PalettedContainer.codecRW(
biomes.asHolderIdMap(), biomes.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getHolderOrThrow(Biomes.PLAINS));
#endif
#endif
int i = #if MC_VER < MC_1_17_1 16; #else level.getSectionsCount(); #endif
LevelChunkSection[] chunkSections = new LevelChunkSection[i];
boolean isLightOn = chunkData.getBoolean("isLightOn");
boolean hasSkyLight = level.dimensionType().hasSkyLight();
ListTag tagSections = chunkData.getList("Sections", 10);
if (tagSections.isEmpty()) tagSections = chunkData.getList("sections", 10);
for (int j = 0; j < tagSections.size(); ++j)
{
CompoundTag tagSection = tagSections.getCompound(j);
int sectionYPos = tagSection.getByte("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
blockStateContainer = tagSection.contains("block_states", 10)
? BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, tagSection.getCompound("block_states")).promotePartial(string -> logErrors(chunkPos, sectionYPos, string))
#if MC_VER < MC_1_20_6
.getOrThrow(false, LOGGER::error)
#else
.getOrThrow((message) -> (RuntimeException) LOGGER.errorAndThrow(message, null))
#endif
: new PalettedContainer<BlockState>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);
#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, LOGGER::error)
: new PalettedContainer<Biome>(biomes, biomes.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
#else
biomeContainer = tagSection.contains("biomes", 10)
? biomeCodec.parse(NbtOps.INSTANCE, tagSection.getCompound("biomes")).promotePartial(string -> logErrors(chunkPos, i, (String) string))
#if MC_VER < MC_1_20_6
.getOrThrow(false, LOGGER::error)
#else
.getOrThrow((message) -> (RuntimeException) LOGGER.errorAndThrow(message, null))
#endif
: new PalettedContainer<Holder<Biome>>(biomes.asHolderIdMap(), biomes.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
#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 ChunkType
#else ChunkType #endif
readChunkType(CompoundTag tagLevel)
{
ChunkStatus chunkStatus = ChunkStatus.byName(tagLevel.getString("Status"));
if (chunkStatus != null)
{
return chunkStatus.getChunkType();
}
return
#if MC_VER <= MC_1_20_4 ChunkStatus.ChunkType.PROTOCHUNK;
#else ChunkType.PROTOCHUNK; #endif
}
private static void readHeightmaps(LevelChunk chunk, CompoundTag chunkData)
{
CompoundTag tagHeightmaps = chunkData.getCompound("Heightmaps");
for (Heightmap.Types type : ChunkStatus.FULL.heightmapsAfter())
{
String heightmap = type.getSerializationKey();
if (tagHeightmaps.contains(heightmap, 12))
chunk.setHeightmap(type, tagHeightmaps.getLongArray(heightmap));
}
Heightmap.primeHeightmaps(chunk, ChunkStatus.FULL.heightmapsAfter());
}
private static void readPostPocessings(LevelChunk chunk, CompoundTag chunkData)
{
ListTag tagPostProcessings = chunkData.getList("PostProcessing", 9);
for (int n = 0; n < tagPostProcessings.size(); ++n)
{
ListTag listTag3 = tagPostProcessings.getList(n);
for (int o = 0; o < listTag3.size(); ++o)
{
chunk.addPackedPostProcess(listTag3.getShort(o), n);
}
}
}
#if MC_VER >= MC_1_18_2
private static BlendingData readBlendingData(CompoundTag chunkData)
{
BlendingData blendingData = null;
if (chunkData.contains("blending_data", 10))
{
@SuppressWarnings({"unchecked", "rawtypes"})
Dynamic<CompoundTag> blendingDataTag = new Dynamic(NbtOps.INSTANCE, chunkData.getCompound("blending_data"));
blendingData = BlendingData.CODEC.parse(blendingDataTag).resultOrPartial(LOGGER::error).orElse(null);
}
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.getMinBuildHeight(chunk), ChunkWrapper.getMaxBuildHeight(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 = chunkSectionCompoundTag.getByteArray("BlockLight");
byte[] skyLightNibbleArray = chunkSectionCompoundTag.getByteArray("SkyLight");
// 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.getMinBuildHeight(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);
}
}
private static void logErrors(ChunkPos chunkPos, int i, String string) private static void logErrors(ChunkPos chunkPos, int i, String string)
{ {
LOGGER.error("Distant Horizons: Recoverable errors when loading section [" + chunkPos.x + ", " + i + ", " + chunkPos.z + "]: " + string); LOGGER.error("Distant Horizons: Recoverable errors when loading section [" + chunkPos.x + ", " + i + ", " + chunkPos.z + "]: " + string);
} }
//================//
// 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);
}
}
} }
@@ -0,0 +1,23 @@
package com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject;
#if MC_VER >= MC_1_21
import net.minecraft.server.level.GenerationChunkHolder;
import net.minecraft.world.level.ChunkPos;
public class DhGenerationChunkHolder extends GenerationChunkHolder
{
public DhGenerationChunkHolder(ChunkPos pos)
{
super(pos);
}
@Override
public int getTicketLevel() { return 0; }
@Override
public int getQueueLevel() { return 0; }
}
#endif
@@ -20,9 +20,10 @@
package com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject; package com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.util.EnumSet;
import java.util.List; 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.worldGeneration.BatchGenerationEnvironment; import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.util.LodUtil;
@@ -59,7 +60,13 @@ import net.minecraft.world.level.lighting.LevelLightEngine;
#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;
#else #else
import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.chunk.status.*;
#endif
#if MC_VER == MC_1_21
import net.minecraft.util.StaticCache2D;
import com.google.common.collect.ImmutableList;
import net.minecraft.server.level.GenerationChunkHolder;
#endif #endif
@@ -71,7 +78,7 @@ public class DhLitWorldGenRegion extends WorldGenRegion
public final DummyLightEngine lightEngine; public final DummyLightEngine lightEngine;
public final BatchGenerationEnvironment.EmptyChunkGenerator generator; public final BatchGenerationEnvironment.IEmptyChunkGeneratorFunc generator;
public final int writeRadius; public final int writeRadius;
public final int size; public final int size;
@@ -112,11 +119,29 @@ public class DhLitWorldGenRegion extends WorldGenRegion
public DhLitWorldGenRegion( public DhLitWorldGenRegion(
int centerChunkX, int centerChunkZ,
ChunkAccess centerChunk,
ServerLevel serverLevel, DummyLightEngine lightEngine, ServerLevel serverLevel, DummyLightEngine lightEngine,
List<ChunkAccess> chunkList, ChunkStatus chunkStatus, int writeRadius, List<ChunkAccess> chunkList, ChunkStatus chunkStatus, int writeRadius,
BatchGenerationEnvironment.EmptyChunkGenerator generator) BatchGenerationEnvironment.IEmptyChunkGeneratorFunc generator)
{ {
super(serverLevel, chunkList #if MC_VER >= MC_1_17_1 , chunkStatus, writeRadius #endif ); #if MC_VER == MC_1_16_5
super(serverLevel, chunkList);
#elif MC_VER < MC_1_21
super(serverLevel, chunkList, chunkStatus, writeRadius);
#else
super(serverLevel,
StaticCache2D.create(
centerChunkX, centerChunkZ,
writeRadius * 2, (x,z) -> new DhGenerationChunkHolder(new ChunkPos(x, z))),
new ChunkStep(chunkStatus,
// reverse is needed because MC uses the index of the chunkStatus to determine how many items are in the list instead of the actual list count
new ChunkDependencies(ImmutableList.copyOf(ChunkStatus.getStatusList()).reverse()),
new ChunkDependencies(ImmutableList.copyOf(ChunkStatus.getStatusList()).reverse()),
writeRadius, (WorldGenContext var1, ChunkStep var2, StaticCache2D<GenerationChunkHolder> var3, ChunkAccess var4) -> null),
centerChunk);
#endif
this.firstPos = chunkList.get(0).getPos(); this.firstPos = chunkList.get(0).getPos();
this.generator = generator; this.generator = generator;
this.lightEngine = lightEngine; this.lightEngine = lightEngine;
@@ -280,7 +305,7 @@ public class DhLitWorldGenRegion extends WorldGenRegion
private ChunkAccess getChunkAccess(int chunkX, int chunkZ, ChunkStatus chunkStatus, boolean returnNonNull) private ChunkAccess getChunkAccess(int chunkX, int chunkZ, ChunkStatus chunkStatus, boolean returnNonNull)
{ {
ChunkAccess chunk = this.superHasChunk(chunkX, chunkZ) ? this.superGetChunk(chunkX, chunkZ) : null; ChunkAccess chunk = this.superHasChunk(chunkX, chunkZ) ? this.superGetChunk(chunkX, chunkZ) : null;
if (chunk != null && chunk.getStatus().isOrAfter(chunkStatus)) if (chunk != null && ChunkWrapper.getStatus(chunk).isOrAfter(chunkStatus))
{ {
return chunk; return chunk;
} }
@@ -56,29 +56,39 @@ public final class StepBiomes
List<ChunkWrapper> chunkWrappers) List<ChunkWrapper> chunkWrappers)
{ {
ArrayList<ChunkAccess> chunksToDo = new ArrayList<ChunkAccess>(); ArrayList<ChunkAccess> chunksToDo = new ArrayList<>();
for (ChunkWrapper chunkWrapper : chunkWrappers) for (ChunkWrapper chunkWrapper : chunkWrappers)
{ {
ChunkAccess chunk = chunkWrapper.getChunk(); ChunkAccess chunk = chunkWrapper.getChunk();
if (chunk.getStatus().isOrAfter(STATUS)) continue; if (!chunkWrapper.getStatus().isOrAfter(STATUS))
((ProtoChunk) chunk).setStatus(STATUS); {
chunksToDo.add(chunk); #if MC_VER < MC_1_21
((ProtoChunk) chunk).setStatus(STATUS);
#else
((ProtoChunk) chunk).setPersistedStatus(STATUS);
#endif
chunksToDo.add(chunk);
}
} }
for (ChunkAccess chunk : chunksToDo) for (ChunkAccess chunk : chunksToDo)
{ {
// System.out.println("StepBiomes: "+chunk.getPos()); // System.out.println("StepBiomes: "+chunk.getPos());
#if MC_VER < MC_1_18_2 #if MC_VER < MC_1_18_2
environment.params.generator.createBiomes(environment.params.biomes, chunk); this.environment.params.generator.createBiomes(this.environment.params.biomes, chunk);
#elif MC_VER < MC_1_19_2 #elif MC_VER < MC_1_19_2
chunk = environment.joinSync(environment.params.generator.createBiomes(environment.params.biomes, Runnable::run, Blender.of(worldGenRegion), chunk = this.environment.joinSync(this.environment.params.generator.createBiomes(this.environment.params.biomes, Runnable::run, Blender.of(worldGenRegion),
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk)); tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
#elif MC_VER < MC_1_19_4 #elif MC_VER < MC_1_19_4
chunk = environment.joinSync(environment.params.generator.createBiomes(environment.params.biomes, Runnable::run, environment.params.randomState, Blender.of(worldGenRegion), chunk = this.environment.joinSync(this.environment.params.generator.createBiomes(this.environment.params.biomes, Runnable::run, this.environment.params.randomState, Blender.of(worldGenRegion),
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
#elif MC_VER < MC_1_21
chunk = this.environment.joinSync(this.environment.params.generator.createBiomes(Runnable::run, this.environment.params.randomState, Blender.of(worldGenRegion),
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk)); tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
#else #else
chunk = environment.joinSync(environment.params.generator.createBiomes(Runnable::run, environment.params.randomState, Blender.of(worldGenRegion), chunk = this.environment.joinSync(this.environment.params.generator.createBiomes(this.environment.params.randomState, Blender.of(worldGenRegion),
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk)); tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
#endif #endif
} }
@@ -59,14 +59,14 @@ public final class StepFeatures
for (ChunkWrapper chunkWrapper : chunkWrappers) for (ChunkWrapper chunkWrapper : chunkWrappers)
{ {
ChunkAccess chunk = chunkWrapper.getChunk(); ChunkAccess chunk = chunkWrapper.getChunk();
if (chunk.getStatus().isOrAfter(STATUS)) if (!chunkWrapper.getStatus().isOrAfter(STATUS)
{ && chunk instanceof ProtoChunk)
continue;
}
if (chunk instanceof ProtoChunk)
{ {
#if MC_VER < MC_1_21
((ProtoChunk) chunk).setStatus(STATUS); ((ProtoChunk) chunk).setStatus(STATUS);
#else
((ProtoChunk) chunk).setPersistedStatus(STATUS);
#endif
} }
@@ -58,13 +58,21 @@ public final class StepNoise
List<ChunkWrapper> chunkWrappers) List<ChunkWrapper> chunkWrappers)
{ {
ArrayList<ChunkAccess> chunksToDo = new ArrayList<ChunkAccess>(); ArrayList<ChunkAccess> chunksToDo = new ArrayList<>();
for (ChunkWrapper chunkWrapper : chunkWrappers) for (ChunkWrapper chunkWrapper : chunkWrappers)
{ {
ChunkAccess chunk = chunkWrapper.getChunk(); ChunkAccess chunk = chunkWrapper.getChunk();
if (chunk.getStatus().isOrAfter(STATUS)) continue; if (chunkWrapper.getStatus().isOrAfter(STATUS))
{
continue;
}
#if MC_VER < MC_1_21
((ProtoChunk) chunk).setStatus(STATUS); ((ProtoChunk) chunk).setStatus(STATUS);
#else
((ProtoChunk) chunk).setPersistedStatus(STATUS);
#endif
chunksToDo.add(chunk); chunksToDo.add(chunk);
} }
@@ -72,15 +80,18 @@ public final class StepNoise
{ {
// System.out.println("StepNoise: "+chunk.getPos()); // System.out.println("StepNoise: "+chunk.getPos());
#if MC_VER < MC_1_17_1 #if MC_VER < MC_1_17_1
environment.params.generator.fillFromNoise(worldGenRegion, tParams.structFeat, chunk); this.environment.params.generator.fillFromNoise(worldGenRegion, tParams.structFeat, chunk);
#elif MC_VER < MC_1_18_2 #elif MC_VER < MC_1_18_2
chunk = environment.joinSync(environment.params.generator.fillFromNoise(Runnable::run, chunk = this.environment.joinSync(this.environment.params.generator.fillFromNoise(Runnable::run,
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk)); tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
#elif MC_VER < MC_1_19_2 #elif MC_VER < MC_1_19_2
chunk = environment.joinSync(environment.params.generator.fillFromNoise(Runnable::run, Blender.of(worldGenRegion), chunk = this.environment.joinSync(this.environment.params.generator.fillFromNoise(Runnable::run, Blender.of(worldGenRegion),
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
#elif MC_VER < MC_1_21
chunk = this.environment.joinSync(this.environment.params.generator.fillFromNoise(Runnable::run, Blender.of(worldGenRegion), this.environment.params.randomState,
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk)); tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
#else #else
chunk = environment.joinSync(environment.params.generator.fillFromNoise(Runnable::run, Blender.of(worldGenRegion), environment.params.randomState, chunk = this.environment.joinSync(this.environment.params.generator.fillFromNoise(Blender.of(worldGenRegion), this.environment.params.randomState,
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk)); tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
#endif #endif
UncheckedInterruptedException.throwIfInterrupted(); UncheckedInterruptedException.throwIfInterrupted();
@@ -59,9 +59,15 @@ public final class StepStructureReference
for (ChunkWrapper chunkWrapper : chunkWrappers) for (ChunkWrapper chunkWrapper : chunkWrappers)
{ {
ChunkAccess chunk = chunkWrapper.getChunk(); ChunkAccess chunk = chunkWrapper.getChunk();
if (chunk.getStatus().isOrAfter(STATUS)) continue; if (!chunkWrapper.getStatus().isOrAfter(STATUS))
((ProtoChunk) chunk).setStatus(STATUS); {
chunksToDo.add(chunk); #if MC_VER < MC_1_21
((ProtoChunk) chunk).setStatus(STATUS);
#else
((ProtoChunk) chunk).setPersistedStatus(STATUS);
#endif
chunksToDo.add(chunk);
}
} }
for (ChunkAccess chunk : chunksToDo) for (ChunkAccess chunk : chunksToDo)
@@ -76,9 +76,13 @@ public final class StepStructureStart
for (ChunkWrapper chunkWrapper : chunkWrappers) for (ChunkWrapper chunkWrapper : chunkWrappers)
{ {
ChunkAccess chunk = chunkWrapper.getChunk(); ChunkAccess chunk = chunkWrapper.getChunk();
if (!chunk.getStatus().isOrAfter(STATUS)) if (!chunkWrapper.getStatus().isOrAfter(STATUS))
{ {
#if MC_VER < MC_1_21
((ProtoChunk) chunk).setStatus(STATUS); ((ProtoChunk) chunk).setStatus(STATUS);
#else
((ProtoChunk) chunk).setPersistedStatus(STATUS);
#endif
chunksToDo.add(chunk); chunksToDo.add(chunk);
} }
} }
@@ -58,9 +58,16 @@ public final class StepSurface
for (ChunkWrapper chunkWrapper : chunkWrappers) for (ChunkWrapper chunkWrapper : chunkWrappers)
{ {
ChunkAccess chunk = chunkWrapper.getChunk(); ChunkAccess chunk = chunkWrapper.getChunk();
if (chunk.getStatus().isOrAfter(STATUS)) continue; if (!chunkWrapper.getStatus().isOrAfter(STATUS))
((ProtoChunk) chunk).setStatus(STATUS); {
chunksToDo.add(chunk); #if MC_VER < MC_1_21
((ProtoChunk) chunk).setStatus(STATUS);
#else
((ProtoChunk) chunk).setPersistedStatus(STATUS);
#endif
chunksToDo.add(chunk);
}
} }
for (ChunkAccess chunk : chunksToDo) for (ChunkAccess chunk : chunksToDo)
@@ -208,7 +208,12 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
this.clientApi.renderLods(ClientLevelWrapper.getWrapper(renderContext.world()), this.clientApi.renderLods(ClientLevelWrapper.getWrapper(renderContext.world()),
modelViewMatrix, modelViewMatrix,
projectionMatrix, projectionMatrix,
renderContext.tickDelta()); #if MC_VER < MC_1_21
renderContext.tickDelta()
#else
renderContext.tickCounter().getGameTimeDeltaTicks()
#endif
);
}); });
// Debug keyboard event // Debug keyboard event
@@ -120,7 +120,12 @@ public class MixinLevelRenderer
ClientApi.INSTANCE.renderDeferredLods(ClientLevelWrapper.getWrapper(this.level), ClientApi.INSTANCE.renderDeferredLods(ClientLevelWrapper.getWrapper(this.level),
mcModelViewMatrix, mcModelViewMatrix,
mcProjectionMatrix, mcProjectionMatrix,
Minecraft.getInstance().getFrameTime()); #if MC_VER < MC_1_21
Minecraft.getInstance().getFrameTime()
#else
Minecraft.getInstance().getTimer().getRealtimeDeltaTicks()
#endif
);
} }
// FIXME completely disables rendering when sodium is installed // FIXME completely disables rendering when sodium is installed
@@ -8,6 +8,7 @@ import com.seibel.distanthorizons.core.jar.installer.GitlabGetter;
import com.seibel.distanthorizons.core.jar.installer.ModrinthGetter; import com.seibel.distanthorizons.core.jar.installer.ModrinthGetter;
import com.seibel.distanthorizons.core.jar.updater.SelfUpdater; import com.seibel.distanthorizons.core.jar.updater.SelfUpdater;
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants; import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
import com.seibel.distanthorizons.coreapi.ModInfo;
import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.TitleScreen; import net.minecraft.client.gui.screens.TitleScreen;
@@ -87,13 +88,23 @@ public class MixinMinecraft
) )
) )
{ {
runnable = () -> { runnable = () ->
{
String versionId;
EDhApiUpdateBranch updateBranch = EDhApiUpdateBranch.convertAutoToStableOrNightly(Config.Client.Advanced.AutoUpdater.updateBranch.get());
if (updateBranch == EDhApiUpdateBranch.STABLE)
{
versionId = ModrinthGetter.getLatestIDForVersion(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion());
}
else
{
versionId = GitlabGetter.INSTANCE.projectPipelines.get(0).get("sha");
}
Minecraft.getInstance().setScreen(new UpdateModScreen( Minecraft.getInstance().setScreen(new UpdateModScreen(
// TODO: Change to runnable, instead of tittle screen // TODO: Change to runnable, instead of tittle screen
new TitleScreen(false), // We don't want to use the vanilla title screen as it would fade the buttons new TitleScreen(false), // We don't want to use the vanilla title screen as it would fade the buttons
(Config.Client.Advanced.AutoUpdater.updateBranch.get() == EDhApiUpdateBranch.STABLE versionId
? ModrinthGetter.getLatestIDForVersion(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion())
: GitlabGetter.INSTANCE.projectPipelines.get(0).get("sha"))
)); ));
}; };
} }
@@ -23,16 +23,13 @@ import com.seibel.distanthorizons.common.wrappers.gui.GetConfigScreen;
import com.seibel.distanthorizons.common.wrappers.gui.TexturedButtonWidget; import com.seibel.distanthorizons.common.wrappers.gui.TexturedButtonWidget;
import com.seibel.distanthorizons.coreapi.ModInfo; import com.seibel.distanthorizons.coreapi.ModInfo;
import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.config.Config;
import net.minecraft.client.gui.screens.OptionsScreen;
import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
#if MC_VER < MC_1_19_2 #if MC_VER < MC_1_19_2
import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.network.chat.TranslatableComponent;
#endif #endif
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique; 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;
@@ -41,11 +38,20 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
#if MC_VER == MC_1_20_6 #if MC_VER >= MC_1_20_6
import net.minecraft.client.gui.layouts.LinearLayout; import net.minecraft.client.gui.layouts.LinearLayout;
import net.minecraft.client.gui.layouts.HeaderAndFooterLayout; import net.minecraft.client.gui.layouts.HeaderAndFooterLayout;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Shadow;
#endif #endif
#if MC_VER < MC_1_21
import net.minecraft.client.gui.screens.OptionsScreen;
#else
import net.minecraft.client.gui.screens.options.OptionsScreen;
#endif
/** /**
* Adds a button to the menu to goto the config * Adds a button to the menu to goto the config
* *
@@ -57,13 +63,18 @@ public class MixinOptionsScreen extends Screen
{ {
/** Texture used for the config opening button */ /** Texture used for the config opening button */
@Unique @Unique
private static final ResourceLocation ICON_TEXTURE = new ResourceLocation(ModInfo.ID, "textures/gui/button.png"); private static final ResourceLocation ICON_TEXTURE =
#if MC_VER < MC_1_21
new ResourceLocation(ModInfo.ID, "textures/gui/button.png");
#else
ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "textures/gui/button.png");
#endif
@Unique @Unique
private TexturedButtonWidget optionsButton = null; private TexturedButtonWidget optionsButton = null;
#if MC_VER == MC_1_20_6 #if MC_VER >= MC_1_20_6
@Shadow @Shadow
@Final @Final
protected HeaderAndFooterLayout layout; protected HeaderAndFooterLayout layout;
@@ -5,7 +5,7 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IBCLibAcces
#elif MC_VER == MC_1_18_2 #elif MC_VER == MC_1_18_2
import ru.bclib.config.ClientConfig; import ru.bclib.config.ClientConfig;
import ru.bclib.config.Configs; import ru.bclib.config.Configs;
#else #elif MC_VER < MC_1_21
import org.betterx.bclib.config.ClientConfig; import org.betterx.bclib.config.ClientConfig;
import org.betterx.bclib.config.Configs; import org.betterx.bclib.config.Configs;
#endif #endif
@@ -17,7 +17,8 @@ public class BCLibAccessor implements IBCLibAccessor
public void setRenderCustomFog(boolean newValue) public void setRenderCustomFog(boolean newValue)
{ {
#if !(MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1 || MC_VER == MC_1_20_4 || MC_VER == MC_1_20_6) // These versions either don't have BCLib, or the implementation is different // only some MC versions have BCLib and require this fix
#if (MC_VER > MC_1_17_1 && MC_VER < MC_1_20_4)
// Change the value of CUSTOM_FOG_RENDERING in the bclib client config // Change the value of CUSTOM_FOG_RENDERING in the bclib client config
// This disabled fog from rendering within bclib // This disabled fog from rendering within bclib
@@ -56,7 +56,6 @@
}, },
"suggests": { "suggests": {
"blendium": "*"
}, },
"breaks": $fabric_incompatibility_list, "breaks": $fabric_incompatibility_list,
@@ -144,7 +144,7 @@ public class ForgeClientProxy implements AbstractModInitializer.IEventProxy
#if MC_VER < MC_1_19_2 #if MC_VER < MC_1_19_2
public void clientLevelUnloadEvent(WorldEvent.Unload event) public void clientLevelUnloadEvent(WorldEvent.Unload event)
#else #else
public void clientLevelUnloadEvent(LevelEvent.Load event) public void clientLevelUnloadEvent(LevelEvent.Unload event)
#endif #endif
{ {
LOGGER.info("level unload"); LOGGER.info("level unload");
@@ -73,11 +73,23 @@ public class MixinMinecraft
&& SelfUpdater.onStart() && SelfUpdater.onStart()
) )
{ {
runnable = () -> { runnable = () ->
{
String versionId;
EDhApiUpdateBranch updateBranch = EDhApiUpdateBranch.convertAutoToStableOrNightly(Config.Client.Advanced.AutoUpdater.updateBranch.get());
if (updateBranch == EDhApiUpdateBranch.STABLE)
{
versionId = ModrinthGetter.getLatestIDForVersion(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion());
}
else
{
versionId = GitlabGetter.INSTANCE.projectPipelines.get(0).get("sha");
}
Minecraft.getInstance().setScreen(new UpdateModScreen( Minecraft.getInstance().setScreen(new UpdateModScreen(
// TODO: Change to runnable, instead of tittle screen // TODO: Change to runnable, instead of tittle screen
new TitleScreen(false), // We don't want to use the vanilla title screen as it would fade the buttons new TitleScreen(false), // We don't want to use the vanilla title screen as it would fade the buttons
(Config.Client.Advanced.AutoUpdater.updateBranch.get() == EDhApiUpdateBranch.STABLE ? ModrinthGetter.getLatestIDForVersion(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion()) : GitlabGetter.INSTANCE.projectPipelines.get(0).get("sha")) versionId
)); ));
}; };
} }
+3 -3
View File
@@ -5,8 +5,8 @@ org.gradle.caching=true
# Mod Info # Mod Info
mod_name=DistantHorizons mod_name=DistantHorizons
mod_version=2.1.0-a mod_version=2.1.2-a
api_version=2.0.0 api_version=2.1.0
maven_group=com.seibel.distanthorizons maven_group=com.seibel.distanthorizons
mod_readable_name=Distant Horizons mod_readable_name=Distant Horizons
mod_description=This mod generates and renders simplified terrain beyond the normal view distance at a low performance cost. Allowing you to see much farther without turning your game into a slideshow. mod_description=This mod generates and renders simplified terrain beyond the normal view distance at a low performance cost. Allowing you to see much farther without turning your game into a slideshow.
@@ -49,7 +49,7 @@ versionStr=
# This defines what MC version Intellij will use for the preprocessor # This defines what MC version Intellij will use for the preprocessor
# and what version is used automatically by build and run commands # and what version is used automatically by build and run commands
mcVer=1.20.6 mcVer=1.21
# Defines the maximum amount of memory Minecraft is allowed when run in a development environment # Defines the maximum amount of memory Minecraft is allowed when run in a development environment
#minecraftMemoryJavaArg="-Xmx4G" #minecraftMemoryJavaArg="-Xmx4G"
+16 -42
View File
@@ -11,41 +11,17 @@ architectury {
neoForge() neoForge()
} }
// TODO this is already defined in the main settings.gradle file, why doesn't it work unless also defined here? (If compiling does work without this block feel free to remove)
repositories {
maven {
name "Neoforge"
url "https://maven.neoforged.net/releases/"
}
}
//loom {
// forge {
// convertAccessWideners.set(true)
// extraAccessWideners.add("lod.accesswidener")
// mixinConfigs("DistantHorizons.mixins.json")
// }
//}
loom { loom {
silentMojangMappingsLicense() // Shut the licencing warning silentMojangMappingsLicense() // Shut the licencing warning
accessWidenerPath = project(":common").file("src/main/resources/${accessWidenerVersion}.distanthorizons.accesswidener") accessWidenerPath = project(":common").file("src/main/resources/${accessWidenerVersion}.distanthorizons.accesswidener")
neoForge { neoForge {
// Access wideners are now defined in the `remapJar.atAccessWideners` // Access wideners are defined in the `remapJar.atAccessWideners`
// convertAccessWideners = true
// extraAccessWideners.add loom.accessWidenerPath.get().asFile.name
// Mixins are now defined in the `mods.toml` // Mixins are defined in the `mods.toml`
// mixinConfigs = [
// "DistantHorizons.mixins.json"
// ]
} }
mixin { mixin {
// Mixins are now defined in the `mods.toml` // Mixins are defined in the `mods.toml`
// mixinConfigs = [
// "DistantHorizons.mixins.json"
// ]
} }
// "runs" isn't required, but when we do need it then it can be useful // "runs" isn't required, but when we do need it then it can be useful
@@ -55,7 +31,7 @@ loom {
setConfigName("NeoForge Client") setConfigName("NeoForge Client")
ideConfigGenerated(true) ideConfigGenerated(true)
runDir("../run") runDir("../run")
// vmArgs("-XX:-OmitStackTraceInFastThrow", minecraftMemoryJavaArg) //vmArgs("-XX:-OmitStackTraceInFastThrow", minecraftMemoryJavaArg)
} }
server { server {
server() server()
@@ -66,13 +42,7 @@ loom {
} }
} }
remapJar {
inputFile = shadowJar.archiveFile
dependsOn shadowJar
// classifier null
atAccessWideners.add("distanthorizons.accesswidener")
}
def addMod(path, enabled) { def addMod(path, enabled) {
if (enabled == "2") if (enabled == "2")
@@ -80,21 +50,24 @@ def addMod(path, enabled) {
else if (enabled == "1") else if (enabled == "1")
dependencies { modCompileOnly(path) } dependencies { modCompileOnly(path) }
} }
dependencies { dependencies {
minecraft "com.mojang:minecraft:${rootProject.minecraft_version}" minecraft "com.mojang:minecraft:${rootProject.minecraft_version}"
mappings loom.layered() { mappings loom.layered()
{
// Mojmap mappings // Mojmap mappings
officialMojangMappings() officialMojangMappings()
// Parchment mappings (it adds parameter mappings & javadoc) // Parchment mappings (it adds parameter mappings & javadoc)
parchment("org.parchmentmc.data:parchment-${rootProject.parchment_version}@zip") parchment("org.parchmentmc.data:parchment-${rootProject.parchment_version}@zip")
} }
// 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) addMod("curse.maven:TerraFirmaCraft-302973:4616004", rootProject.enable_terrafirmacraft)
} }
task deleteResources(type: Delete) { task deleteResources(type: Delete) {
delete file("build/resources/main") delete file("build/resources/main")
} }
@@ -113,14 +86,15 @@ tasks.named('runClient') {
finalizedBy(deleteResources) finalizedBy(deleteResources)
} }
remapJar {
inputFile = shadowJar.archiveFile
dependsOn shadowJar
atAccessWideners.add("distanthorizons.accesswidener")
}
sourcesJar { sourcesJar {
def commonSources = project(":common").sourcesJar def commonSources = project(":common").sourcesJar
dependsOn commonSources dependsOn commonSources
from commonSources.archiveFile.map { zipTree(it) } from commonSources.archiveFile.map { zipTree(it) }
} }
//components.java {
// withVariantsFromConfiguration(project.configurations.shadowRuntimeElements) {
// skip()
// }
//}
@@ -140,7 +140,7 @@ public class NeoforgeClientProxy implements AbstractModInitializer.IEventProxy
ClientApi.INSTANCE.clientLevelLoadEvent(clientLevelWrapper); ClientApi.INSTANCE.clientLevelLoadEvent(clientLevelWrapper);
} }
@SubscribeEvent @SubscribeEvent
public void clientLevelUnloadEvent(LevelEvent.Load event) public void clientLevelUnloadEvent(LevelEvent.Unload event)
{ {
LOGGER.info("level unload"); LOGGER.info("level unload");
@@ -98,7 +98,6 @@ public class MixinLevelRenderer
private void renderChunkLayer(RenderType renderType, double x, double y, double z, Matrix4f projectionMatrix, Matrix4f frustumMatrix, CallbackInfo callback) private void renderChunkLayer(RenderType renderType, double x, double y, double z, Matrix4f projectionMatrix, Matrix4f frustumMatrix, CallbackInfo callback)
#endif #endif
{ {
// get MC's model view and projection matrices
#if MC_VER == MC_1_16_5 #if MC_VER == MC_1_16_5
// get the matrices from the OpenGL fixed pipeline // get the matrices from the OpenGL fixed pipeline
float[] mcProjMatrixRaw = new float[16]; float[] mcProjMatrixRaw = new float[16];
@@ -120,15 +119,21 @@ public class MixinLevelRenderer
#endif #endif
float frameTime;
#if MC_VER < MC_1_21
frameTime = Minecraft.getInstance().getFrameTime();
#else
frameTime = Minecraft.getInstance().getTimer().getRealtimeDeltaTicks();
#endif
// only render before solid blocks // only render before solid blocks
if (renderType.equals(RenderType.solid())) if (renderType.equals(RenderType.solid()))
{ {
ClientApi.INSTANCE.renderLods(ClientLevelWrapper.getWrapper(this.level), mcModelViewMatrix, mcProjectionMatrix, Minecraft.getInstance().getFrameTime()); ClientApi.INSTANCE.renderLods(ClientLevelWrapper.getWrapper(this.level), mcModelViewMatrix, mcProjectionMatrix, frameTime);
} }
else if (renderType.equals(RenderType.translucent())) else if (renderType.equals(RenderType.translucent()))
{ {
ClientApi.INSTANCE.renderDeferredLods(ClientLevelWrapper.getWrapper(this.level), mcModelViewMatrix, mcProjectionMatrix, Minecraft.getInstance().getFrameTime()); ClientApi.INSTANCE.renderDeferredLods(ClientLevelWrapper.getWrapper(this.level), mcModelViewMatrix, mcProjectionMatrix, frameTime);
} }
if (Config.Client.Advanced.Debugging.lodOnlyMode.get()) if (Config.Client.Advanced.Debugging.lodOnlyMode.get())
@@ -154,4 +159,5 @@ public class MixinLevelRenderer
ChunkWrapper.syncedUpdateClientLightStatus(); ChunkWrapper.syncedUpdateClientLightStatus();
} }
} }
@@ -8,6 +8,7 @@ import com.seibel.distanthorizons.core.jar.installer.GitlabGetter;
import com.seibel.distanthorizons.core.jar.installer.ModrinthGetter; import com.seibel.distanthorizons.core.jar.installer.ModrinthGetter;
import com.seibel.distanthorizons.core.jar.updater.SelfUpdater; import com.seibel.distanthorizons.core.jar.updater.SelfUpdater;
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants; import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
import com.seibel.distanthorizons.coreapi.ModInfo;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.TitleScreen; import net.minecraft.client.gui.screens.TitleScreen;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
@@ -75,11 +76,23 @@ public class MixinMinecraft
&& SelfUpdater.onStart() && SelfUpdater.onStart()
) )
{ {
runnable = () -> { runnable = () ->
{
String versionId;
EDhApiUpdateBranch updateBranch = EDhApiUpdateBranch.convertAutoToStableOrNightly(Config.Client.Advanced.AutoUpdater.updateBranch.get());
if (updateBranch == EDhApiUpdateBranch.STABLE)
{
versionId = ModrinthGetter.getLatestIDForVersion(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion());
}
else
{
versionId = GitlabGetter.INSTANCE.projectPipelines.get(0).get("sha");
}
Minecraft.getInstance().setScreen(new UpdateModScreen( Minecraft.getInstance().setScreen(new UpdateModScreen(
// TODO: Change to runnable, instead of tittle screen // TODO: Change to runnable, instead of tittle screen
new TitleScreen(false), // We don't want to use the vanilla title screen as it would fade the buttons new TitleScreen(false), // We don't want to use the vanilla title screen as it would fade the buttons
(Config.Client.Advanced.AutoUpdater.updateBranch.get() == EDhApiUpdateBranch.STABLE ? ModrinthGetter.getLatestIDForVersion(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion()) : GitlabGetter.INSTANCE.projectPipelines.get(0).get("sha")) versionId
)); ));
}; };
} }
@@ -23,16 +23,13 @@ import com.seibel.distanthorizons.common.wrappers.gui.GetConfigScreen;
import com.seibel.distanthorizons.common.wrappers.gui.TexturedButtonWidget; import com.seibel.distanthorizons.common.wrappers.gui.TexturedButtonWidget;
import com.seibel.distanthorizons.coreapi.ModInfo; import com.seibel.distanthorizons.coreapi.ModInfo;
import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.config.Config;
import net.minecraft.client.gui.screens.OptionsScreen;
import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
#if MC_VER < MC_1_19_2 #if MC_VER < MC_1_19_2
import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.network.chat.TranslatableComponent;
#endif #endif
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique; 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;
@@ -41,11 +38,20 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
#if MC_VER == MC_1_20_6 #if MC_VER >= MC_1_20_6
import net.minecraft.client.gui.layouts.LinearLayout; import net.minecraft.client.gui.layouts.LinearLayout;
import net.minecraft.client.gui.layouts.HeaderAndFooterLayout; import net.minecraft.client.gui.layouts.HeaderAndFooterLayout;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Shadow;
#endif #endif
#if MC_VER < MC_1_21
import net.minecraft.client.gui.screens.OptionsScreen;
#else
import net.minecraft.client.gui.screens.options.OptionsScreen;
#endif
/** /**
* Adds a button to the menu to goto the config * Adds a button to the menu to goto the config
* *
@@ -57,13 +63,18 @@ public class MixinOptionsScreen extends Screen
{ {
/** Texture used for the config opening button */ /** Texture used for the config opening button */
@Unique @Unique
private static final ResourceLocation ICON_TEXTURE = new ResourceLocation(ModInfo.ID, "textures/gui/button.png"); private static final ResourceLocation ICON_TEXTURE =
#if MC_VER < MC_1_21
new ResourceLocation(ModInfo.ID, "textures/gui/button.png");
#else
ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "textures/gui/button.png");
#endif
@Unique @Unique
private TexturedButtonWidget optionsButton = null; private TexturedButtonWidget optionsButton = null;
#if MC_VER == MC_1_20_6 #if MC_VER >= MC_1_20_6
@Shadow @Shadow
@Final @Final
protected HeaderAndFooterLayout layout; protected HeaderAndFooterLayout layout;
@@ -93,7 +104,6 @@ public class MixinOptionsScreen extends Screen
// add the button to the correct location in the UI // add the button to the correct location in the UI
// TODO is there a better way to do this instead of using access transformers to inject into the exact UI elements? // TODO is there a better way to do this instead of using access transformers to inject into the exact UI elements?
// TODO is there a way we can put the button on the left side of the FOV bar like before?
LinearLayout layout = (LinearLayout) this.layout.headerFrame.children.get(0).child; LinearLayout layout = (LinearLayout) this.layout.headerFrame.children.get(0).child;
// determine how wide the other option buttons are so we can put our botton to the left of them all // determine how wide the other option buttons are so we can put our botton to the left of them all
+53
View File
@@ -0,0 +1,53 @@
# 1.21 version
java_version=21
minecraft_version=1.21
parchment_version=1.20.6:2024.05.01
compatible_minecraft_versions=["1.21.0"]
accessWidenerVersion=1_20_6
builds_for=fabric,neoforge
# forge is broken due to gradle/build script issues
# Fabric loader
fabric_loader_version=0.15.11
fabric_api_version=0.100.1+1.21
# Fabric mod versions
modmenu_version=11.0.0-beta.1
starlight_version_fabric=
phosphor_version_fabric=
lithium_version=
sodium_version=mc1.21-0.5.9
iris_version=1.7.1+1.21
bclib_version=
immersive_portals_version=
canvas_version=
fabric_incompatibility_list={ "iris": "<=1.6.20" }
fabric_recommend_list={}
# Fabric mod run
# 0 = Don't enable and don't run
# 1 = Can be referenced in code but doesn't run
# 2 = Can be referenced in code and runs in client
enable_starlight=0
enable_phosphor=0
enable_sodium=1
enable_lithium=0
enable_iris=1
enable_bclib=0
enable_immersive_portals=0
enable_canvas=0
# (Neo)Forge loader
forge_version=50.0.19
neoforge_version=21.0.4-beta
# (Neo)Forge mod versions
starlight_version_forge=
terraforged_version=
# (Neo)Forge mod run
# 0 = Don't enable and don't run
# 1 = Can be referenced in code but doesn't run
# 2 = Can be referenced in code and runs in client
enable_starlight_forge=0
enable_terraforged=0
enable_terrafirmacraft=0