This commit is contained in:
s809
2023-08-08 12:48:37 +05:00
48 changed files with 822 additions and 326 deletions
+18 -2
View File
@@ -5,7 +5,9 @@ image: gradle:eclipse-temurin
# all stages need to be defined here
stages:
# TODO: Make stages depending on what is in versionProperties
# TODO: Make stages depend on what is in versionProperties
- build_1_16_5
- build_1_17_1
- build_1_18_2
- build_1_19_2
- build_1_19_4
@@ -54,6 +56,20 @@ variables:
extends: .build_java
# 1.16.5 build
build_1_16_5:
stage: build_1_16_5
variables:
MC_VER: "1.16.5"
extends: .build_mc
# 1.17.1 build
build_1_17_1:
stage: build_1_17_1
variables:
MC_VER: "1.17.1"
extends: .build_mc
# 1.18.2 build
build_1_18_2:
stage: build_1_18_2
@@ -130,7 +146,7 @@ pages:
# ============================== Previos CI for future reference ============================== #
# ============================== Previous CI for future reference ============================== #
## all stages need to be defined here
# # Don't build the standalone jar yet because it isn't done yet
# # - build_standalone
+16 -14
View File
@@ -20,31 +20,31 @@ If you want to see a quick demo, check out a video covering the mod here:
### This branch supports the following versions of Minecraft:
#### 1.19.4 (BROKE)
#### 1.20.1, 1.20
Fabric: 0.14.21\
Fabric API: 0.85.0+1.20.1\
Forge: 45.1.0\
Parchment: 1.19.3:2023.03.25\
Modmenu: 7.0.1
#### 1.19.4
Fabric: 0.14.21\
Fabric API: 0.83.0+1.19.4\
Forge: 45.1.0\
Parchment: 1.19.3:2023.03.12\
Parchment: 1.19.3:2023.06.25\
Modmenu: 6.2.3
#### 1.19.2 (BROKE)
#### 1.19.2
Fabric: 0.14.21\
Fabric API: 0.76.0+1.19.2\
Forge: 43.2.14\
Parchment: 1.19.2:2022.11.27\
Modmenu: 4.2.0-beta.2
#### 1.19 (BROKE)
Fabric: 0.14.21\
Fabric API: 0.58.0+1.19\
Forge: 41.1.0\
Parchment: 1.19.2:2022.11.27\
Modmenu: 4.0.4
#### 1.18.2
#### 1.18.2 (Default)
Fabric: 0.14.21\
Fabric API: 0.76.0+1.18.2\
Forge: 40.2.9\
Forge: 40.2.10\
Parchment: 1.18.2:2022.11.06\
Modmenu: 3.2.5
@@ -64,6 +64,8 @@ Modmenu: 1.16.22
### Versions no longer supported
- 1.18.1, 1.18
- 1.19.1, 1.19
- 1.19.3
<br><br>
### Plugin and Library versions
@@ -119,7 +121,7 @@ From the File Explorer:
1. Download and extract the project zip
2. Download the core from https://gitlab.com/jeseibel/distant-horizons-core and extract into a folder called `coreSubProjects`
3. Open a terminal emulator in the project folder (On Windows you can type `cmd` in the title bar)
4. Run the commands: `./gradlew assemble`
4. Run the commands: `./gradlew assemble` (You may need to use a `.\` on Windows)
5. Merge the jars wih `./gradlew mergeJars`
6. The compiled jar file will be in the folder `Merged`
@@ -178,7 +180,7 @@ https://github.com/PacifistMC/Forgix
LZ4 for Java (data compression)\
https://github.com/lz4/lz4-java
Json & Toml for Java (config handling)\
NightConfig for Json & Toml (config handling)\
https://github.com/TheElectronWill/night-config
SVG Salamander for SVG support\
+29 -7
View File
@@ -31,6 +31,7 @@ def writeBuildGradlePredefine(List<String> mcVers, int mcIndex) {
if (mcIndex < i) {
// exclusive before
// FIXME doesn't function correctly for 1.16.5 (IE the first item in the list)
redefineList.add("PRE_MC_" + mcStr)
}
if (mcIndex <= i) {
@@ -230,6 +231,7 @@ subprojects { p ->
forgeShadowMe("com.formdev:flatlaf-extras:${rootProject.flatlaf_version}")
// Netty
// Breaks 1.16.5
forgeShadowMe("io.netty:netty-all:${rootProject.netty_version}")
// Remember, for lwjgl dependencies that arent included in Minecraft, you need to also need to add it to the ShadowJar thing
@@ -324,13 +326,17 @@ subprojects { p ->
// Put stuff from gradle.properties into the mod info
processResources {
def resourceTargets = [ // Location of where to inject the properties
// Properties for each of the loaders
"fabric.mod.json",
"quilt.mod.json",
"META-INF/mods.toml",
// Holds info like git commit
// TODO: For some reason this script doesnt work with the core project
"build_info.json",
// The mixins for each of the loaders
"DistantHorizons."+ p.name +".fabricLike.mixins.json"
// Properties for each of the loaders
"fabric.mod.json",
"quilt.mod.json",
"META-INF/mods.toml",
// The mixins for each of the loaders
"DistantHorizons."+ p.name +".fabricLike.mixins.json"
]
def intoTargets = ["$buildDir/resources/main/"] // Location of the built resources folder
@@ -353,6 +359,18 @@ subprojects { p ->
// TODOI: Find something we can use so we can basically re-map only when the jar is shadowed and relocated
// println p.tasks.findByName('shadowJar')
// Gets git info for the project
def git_main_commit = "Git_not_found"
def git_core_commit = "Git_not_found"
def git_main_branch = "Git_not_found"
try {
"git rev-parse --is-inside-work-tree".execute() // If git doesnt exist, or this isnt cloned from git, then this wont work
git_main_commit = 'git rev-parse --verify HEAD'.execute().text.trim()
git_core_commit = 'git ls-tree --object-only HEAD coreSubProjects'.execute().text.trim()
git_main_branch = 'git symbolic-ref --short HEAD'.execute().text.trim()
} catch (Exception e) {
println "Git or Git project not found"
}
def replaceProperties = [
version : mod_version,
@@ -368,7 +386,11 @@ subprojects { p ->
compatible_minecraft_versions: compatible_minecraft_versions,
compatible_forgemc_versions : compatible_forgemc_versions,
java_version : java_version,
quilt_contributors : "{"+quilt_contributors.join(", ")+"}"
quilt_contributors : "{"+quilt_contributors.join(", ")+"}",
git_main_commit : git_main_commit,
git_core_commit : git_core_commit,
git_main_branch : git_main_branch
]
// The left side is what gets replaced in the mod info and the right side is where to get it from in the gradle.properties
@@ -7,6 +7,8 @@ import org.joml.Matrix4f;
#endif
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.util.RenderUtil;
import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
import org.lwjgl.opengl.GL15;
import java.nio.FloatBuffer;
@@ -30,15 +32,44 @@ public class SeamlessOverdraw
minecraftProjectionMatrix.get(matrixFloatArray);
#endif
return overwriteMinecraftNearFarClipPlanes(matrixFloatArray, previousPartialTicks);
}
public static float[] overwriteMinecraftNearFarClipPlanes(Mat4f minecraftProjectionMatrix, float previousPartialTicks)
{
return overwriteMinecraftNearFarClipPlanes(minecraftProjectionMatrix.getValuesAsArray(), previousPartialTicks);
}
private static float[] overwriteMinecraftNearFarClipPlanes(float[] projectionMatrixFloatArray, float previousPartialTicks)
{
float dhFarClipPlane = RenderUtil.getNearClipPlaneDistanceInBlocks(previousPartialTicks);
// works for fabric, bad not for forge for some reason :/
float farClip = dhFarClipPlane * 5.1f; // magic number found via trial and error, James has no idea what it represents, except that it makes the seam between DH and vanilla rendering pretty close
float nearClip = 0.5f; // this causes issues with some vanilla rendering, specifically the wireframe around selected blocks is slightly off. Unfortunately the ratio between the near and far clip plane can't be easily modified without completely screwing up the rendering.
// these may be the wrong index locations in any version of MC other than 1.18.2
matrixFloatArray[10] = -((farClip + nearClip) / (farClip - nearClip)); // near clip plane
matrixFloatArray[11] = -((2 * farClip * nearClip) / (farClip - nearClip)); // far clip plane
projectionMatrixFloatArray[10] = -((farClip + nearClip) / (farClip - nearClip)); // near clip plane
projectionMatrixFloatArray[11] = -((2 * farClip * nearClip) / (farClip - nearClip)); // far clip plane
return matrixFloatArray;
return projectionMatrixFloatArray;
}
//================//
// helper methods //
//================//
public static void applyLegacyProjectionMatrix(float[] projectionMatrixFloatArray)
{
int glMatrixMode = GL15.glGetInteger(GL15.GL_MATRIX_MODE);
GL15.glMatrixMode(GL15.GL_PROJECTION);
GL15.glLoadMatrixf(projectionMatrixFloatArray);
GL15.glMatrixMode(glMatrixMode);
}
}
@@ -95,23 +95,25 @@ public class WrapperFactory implements IWrapperFactory
}
}
// MC 1.18, 1.19, 1.20
#if POST_MC_1_17_1
// MC 1.16, 1.18, 1.19, 1.20
#if POST_MC_1_17_1 || MC_1_16_5
else if (objectArray.length == 2)
{
// correct number of parameters from the API
// chunk
if (!(objectArray[0] instanceof ChunkAccess chunk))
if (!(objectArray[0] instanceof ChunkAccess))
{
throw new ClassCastException(createChunkWrapperErrorMessage(objectArray));
}
ChunkAccess chunk = (ChunkAccess)objectArray[0];
// light source
if (!(objectArray[1] instanceof LevelReader lightSource))
if (!(objectArray[1] instanceof LevelReader))
{
throw new ClassCastException(createChunkWrapperErrorMessage(objectArray));
}
LevelReader lightSource = (LevelReader)objectArray[1];
return new ChunkWrapper(chunk, lightSource, /*A DH wrapped level isn't necessary*/null);
@@ -142,8 +144,8 @@ public class WrapperFactory implements IWrapperFactory
"Chunk wrapper creation failed. \n" +
"Expected parameters: \n");
// MC 1.18, 1.19, 1.20
#if POST_MC_1_17_1
// MC 1.16, 1.18, 1.19, 1.20
#if POST_MC_1_17_1 || MC_1_16_5
message.append("["+ChunkAccess.class.getName()+"], \n");
message.append("["+LevelReader.class.getName()+"]. \n");
#else
@@ -26,7 +26,6 @@ import java.util.concurrent.ConcurrentMap;
import com.google.gson.JsonParser;
import com.mojang.serialization.JsonOps;
import com.seibel.distanthorizons.core.level.IDhLevel;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
@@ -36,7 +35,9 @@ import net.minecraft.core.Holder;
import net.minecraft.data.worldgen.biome.EndBiomes;
import net.minecraft.data.worldgen.biome.NetherBiomes;
#endif
import net.minecraft.core.Registry;
import net.minecraft.resources.RegistryOps;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.Biomes;
@@ -72,14 +73,7 @@ public class BiomeWrapper implements IBiomeWrapper
return biome.unwrapKey().orElse(Biomes.THE_VOID).registry().toString();
#endif
}
@Override
public String serialize(ILevelWrapper levelWrapper) {
String data = Biome.CODEC.encodeStart(RegistryOps.create(JsonOps.INSTANCE, ((Level)levelWrapper.getWrappedMcObject()).registryAccess()),
biome).get().orThrow().toString();
return data;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -93,19 +87,70 @@ public class BiomeWrapper implements IBiomeWrapper
return Objects.hash(biome);
}
public static IBiomeWrapper deserialize(String str, ILevelWrapper levelWrapper) throws IOException
@Override
public String serialize(ILevelWrapper levelWrapper) // FIXME pass in level to prevent null pointers (or maybe just RegistryAccess?)
{
net.minecraft.core.RegistryAccess registryAccess = ((Level)levelWrapper.getWrappedMcObject()).registryAccess();
ResourceLocation resourceLocation;
#if MC_1_16_5 || MC_1_17_1
resourceLocation = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).getKey(this.biome);
#elif MC_1_18_2 || MC_1_19_2
resourceLocation = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).getKey(this.biome.value());
#else
resourceLocation = registryAccess.registryOrThrow(Registries.BIOME).getKey(this.biome.value());
#endif
if (resourceLocation == null)
{
// shouldn't normally happen, but just in case
return "";
}
else
{
String resourceLocationString = resourceLocation.getNamespace()+":"+resourceLocation.getPath();
return resourceLocationString;
}
}
public static IBiomeWrapper deserialize(String resourceLocationString, ILevelWrapper levelWrapper) throws IOException // FIXME pass in level to prevent null pointers (or maybe just RegistryAccess?)
{
if (resourceLocationString.trim().isEmpty() || resourceLocationString.equals(""))
{
// shouldn't normally happen, but just in case
new ResourceLocation("minecraft", "the_void"); // just "void" in MC 1.12 through 1.9 (inclusive)
}
// parse the resource location
int separatorIndex = resourceLocationString.indexOf(":");
if (separatorIndex == -1)
{
throw new IOException("Unable to parse resource location string: ["+resourceLocationString+"].");
}
ResourceLocation resourceLocation = new ResourceLocation(resourceLocationString.substring(0, separatorIndex), resourceLocationString.substring(separatorIndex+1));
try
{
#if PRE_MC_1_18_2 Biome #else
Holder<Biome> #endif
biome = Biome.CODEC.decode(RegistryOps.create(JsonOps.INSTANCE, ((Level)levelWrapper.getWrappedMcObject()).registryAccess()),
JsonParser.parseString(str)).get().orThrow().getFirst();
net.minecraft.core.RegistryAccess registryAccess = ((Level)levelWrapper.getWrappedMcObject()).registryAccess();
#if MC_1_16_5 || MC_1_17_1
Biome biome = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).get(resourceLocation);
#elif MC_1_18_2 || MC_1_19_2
Biome unwrappedBiome = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).get(resourceLocation);
Holder<Biome> biome = new Holder.Direct<>(unwrappedBiome);
#else
Biome unwrappedBiome = registryAccess.registryOrThrow(Registries.BIOME).get(resourceLocation);
Holder<Biome> biome = new Holder.Direct<>(unwrappedBiome);
#endif
return getBiomeWrapper(biome);
}
catch (Exception e)
{
throw new IOException("Failed to deserialize the string ["+str+"] into a BiomeWrapper: "+e.getMessage(), e);
throw new IOException("Failed to deserialize the string ["+resourceLocationString+"] into a BiomeWrapper: "+e.getMessage(), e);
}
}
@@ -1,29 +1,50 @@
package com.seibel.distanthorizons.common.wrappers.block;
import com.google.gson.JsonParser;
import com.mojang.serialization.JsonOps;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.util.ColorUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
import net.minecraft.client.resources.model.Material;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.EmptyBlockGetter;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
#if MC_1_16_5 || MC_1_17_1
import net.minecraft.core.Registry;
#elif MC_1_18_2 || MC_1_19_2
import net.minecraft.client.Minecraft;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Registry;
#else
import net.minecraft.client.Minecraft;
import net.minecraft.core.BlockPos;
import net.minecraft.core.registries.Registries;
import net.minecraft.world.level.EmptyBlockGetter;
#endif
public class BlockStateWrapper implements IBlockStateWrapper
{
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
public static final BlockStateWrapper AIR = new BlockStateWrapper(null);
/** example "minecraft:plains" */
public static final String RESOURCE_LOCATION_SEPARATOR = ":";
/** example "minecraft:water_state_{level:0}" */
public static final String STATE_STRING_SEPARATOR = "_STATE_";
// must be defined before AIR, otherwise a null pointer will be thrown
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
public static final BlockStateWrapper AIR = new BlockStateWrapper(null);
public static ConcurrentHashMap<BlockState, BlockStateWrapper> cache = new ConcurrentHashMap<>();
//==============//
// constructors //
//==============//
@@ -72,34 +93,130 @@ public class BlockStateWrapper implements IBlockStateWrapper
@Override
public String serialize()
public String serialize() // FIXME pass in level to prevent null pointers (or maybe just RegistryAccess?)
{
if (this.blockState == null)
{
return "AIR";
}
return BlockState.CODEC.encodeStart(JsonOps.INSTANCE, this.blockState).get().orThrow().toString();
ResourceLocation resourceLocation;
#if MC_1_16_5 || MC_1_17_1
resourceLocation = Registry.BLOCK.getKey(this.blockState.getBlock());
#elif MC_1_18_2 || MC_1_19_2
net.minecraft.core.RegistryAccess registryAccess = Minecraft.getInstance().level.registryAccess();
resourceLocation = registryAccess.registryOrThrow(Registry.BLOCK_REGISTRY).getKey(this.blockState.getBlock());
#else
net.minecraft.core.RegistryAccess registryAccess = Minecraft.getInstance().level.registryAccess();
resourceLocation = registryAccess.registryOrThrow(Registries.BLOCK).getKey(this.blockState.getBlock());
#endif
String resourceStateString = resourceLocation.getNamespace() + RESOURCE_LOCATION_SEPARATOR + resourceLocation.getPath()
+ STATE_STRING_SEPARATOR + serializeBlockStateProperties(this.blockState);
return resourceStateString;
}
public static BlockStateWrapper deserialize(String str) throws IOException
public static BlockStateWrapper deserialize(String resourceStateString) throws IOException // FIXME pass in level to prevent null pointers (or maybe just RegistryAccess?)
{
if (str.equals("AIR"))
if (resourceStateString.equals("AIR") || resourceStateString.equals("")) // the empty string shouldn't normally happen, but just in case
{
return AIR;
}
// parse the BlockState
int stateSeparatorIndex = resourceStateString.indexOf(STATE_STRING_SEPARATOR);
if (stateSeparatorIndex == -1)
{
throw new IOException("Unable to parse BlockState out of string: ["+resourceStateString+"].");
}
String blockStatePropertiesString = resourceStateString.substring(stateSeparatorIndex+STATE_STRING_SEPARATOR.length());
resourceStateString = resourceStateString.substring(0, stateSeparatorIndex);
// parse the resource location
int resourceSeparatorIndex = resourceStateString.indexOf(RESOURCE_LOCATION_SEPARATOR);
if (resourceSeparatorIndex == -1)
{
throw new IOException("Unable to parse Resource Location out of string: ["+resourceStateString+"].");
}
ResourceLocation resourceLocation = new ResourceLocation(resourceStateString.substring(0, resourceSeparatorIndex), resourceStateString.substring(resourceSeparatorIndex+1));
// attempt to get the BlockState from all possible BlockStates
try
{
return new BlockStateWrapper(
BlockState.CODEC.decode(JsonOps.INSTANCE, JsonParser.parseString(str)).get().orThrow().getFirst()
);
Block block;
#if MC_1_16_5 || MC_1_17_1
block = Registry.BLOCK.get(resourceLocation);
#elif MC_1_18_2 || MC_1_19_2
net.minecraft.core.RegistryAccess registryAccess = Minecraft.getInstance().level.registryAccess();
block = registryAccess.registryOrThrow(Registry.BLOCK_REGISTRY).get(resourceLocation);
#else
net.minecraft.core.RegistryAccess registryAccess = Minecraft.getInstance().level.registryAccess();
block = registryAccess.registryOrThrow(Registries.BLOCK).get(resourceLocation);
#endif
BlockState foundState = null;
List<BlockState> possibleStateList = block.getStateDefinition().getPossibleStates();
for (BlockState possibleState : possibleStateList)
{
String possibleStatePropertiesString = serializeBlockStateProperties(possibleState);
if (possibleStatePropertiesString.equals(blockStatePropertiesString))
{
foundState = possibleState;
break;
}
}
// use the default if no state was found
if (foundState == null)
{
LOGGER.debug("Unable to find BlockState for Block ["+resourceLocation+"] with properties: ["+blockStatePropertiesString+"].");
foundState = block.defaultBlockState();
}
return new BlockStateWrapper(foundState);
}
catch (Exception e)
{
throw new IOException("Failed to deserialize the string ["+str+"] into a BlockStateWrapper: "+e.getMessage(), e);
throw new IOException("Failed to deserialize the string ["+resourceStateString+"] into a BlockStateWrapper: "+e.getMessage(), e);
}
}
/** used to compare and save BlockStates based on their properties */
private static String serializeBlockStateProperties(BlockState blockState)
{
// get the property list for this block (doesn't contain this block state's values, just the names and possible values)
java.util.Collection<net.minecraft.world.level.block.state.properties.Property<?>> blockPropertyCollection = blockState.getProperties();
// alphabetically sort the list so they are always in the same order
List<net.minecraft.world.level.block.state.properties.Property<?>> sortedBlockPropteryList = new ArrayList<>(blockPropertyCollection);
sortedBlockPropteryList.sort((a,b) -> a.getName().compareTo(b.getName()));
StringBuilder stringBuilder = new StringBuilder();
for (net.minecraft.world.level.block.state.properties.Property<?> property : sortedBlockPropteryList)
{
String propertyName = property.getName();
String value = "NULL";
if (blockState.hasProperty(property))
{
value = blockState.getValue(property).toString();
}
stringBuilder.append("{");
stringBuilder.append(propertyName).append(RESOURCE_LOCATION_SEPARATOR).append(value);
stringBuilder.append("}");
}
return stringBuilder.toString();
}
@Override
public boolean equals(Object obj)
{
@@ -21,7 +21,6 @@ package com.seibel.distanthorizons.common.wrappers.block;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Holder;
import net.minecraft.world.level.*;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.entity.BlockEntity;
@@ -30,6 +29,10 @@ import net.minecraft.world.level.lighting.LevelLightEngine;
import net.minecraft.world.level.material.FluidState;
import org.jetbrains.annotations.Nullable;
#if POST_MC_1_18_2
import net.minecraft.core.Holder;
#endif
public class TintWithoutLevelOverrider implements BlockAndTintGetter {
final BiomeWrapper biome;
@@ -70,6 +73,9 @@ public class TintWithoutLevelOverrider implements BlockAndTintGetter {
public FluidState getFluidState(BlockPos pos) {
throw new UnsupportedOperationException("ERROR: getFluidState() called on TintWithoutLevelOverrider. Object is for tinting only.");
}
#if MC_1_17_1 || POST_MC_1_18_2
@Override
public int getHeight() {
throw new UnsupportedOperationException("ERROR: getHeight() called on TintWithoutLevelOverrider. Object is for tinting only.");
@@ -78,4 +84,6 @@ public class TintWithoutLevelOverrider implements BlockAndTintGetter {
public int getMinBuildHeight() {
throw new UnsupportedOperationException("ERROR: getMinBuildHeight() called on TintWithoutLevelOverrider. Object is for tinting only.");
}
#endif
}
@@ -21,7 +21,6 @@ package com.seibel.distanthorizons.common.wrappers.block;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Holder;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.ColorResolver;
import net.minecraft.world.level.biome.Biome;
@@ -31,6 +30,10 @@ import net.minecraft.world.level.lighting.LevelLightEngine;
import net.minecraft.world.level.material.FluidState;
import org.jetbrains.annotations.Nullable;
#if POST_MC_1_18_2
import net.minecraft.core.Holder;
#endif
public class TintWithoutLevelSmoothOverrider implements BlockAndTintGetter {
final BiomeWrapper biome;
public int smoothingRange;
@@ -102,6 +105,9 @@ public class TintWithoutLevelSmoothOverrider implements BlockAndTintGetter {
public FluidState getFluidState(BlockPos pos) {
throw new UnsupportedOperationException("ERROR: getFluidState() called on TintWithoutLevelOverrider. Object is for tinting only.");
}
#if MC_1_17_1 || POST_MC_1_18_2
@Override
public int getHeight() {
throw new UnsupportedOperationException("ERROR: getHeight() called on TintWithoutLevelOverrider. Object is for tinting only.");
@@ -110,4 +116,6 @@ public class TintWithoutLevelSmoothOverrider implements BlockAndTintGetter {
public int getMinBuildHeight() {
throw new UnsupportedOperationException("ERROR: getMinBuildHeight() called on TintWithoutLevelOverrider. Object is for tinting only.");
}
#endif
}
@@ -74,18 +74,20 @@ public class ChunkWrapper implements IChunkWrapper
private LinkedList<DhBlockPos> blockLightPosList = null;
private final boolean useDhLightingEngine;
private boolean useDhLighting;
// Due to vanilla `isClientLightReady()` not designed to be used by non-render thread, that value may return 'true'
// just before the light engine is ticked, (right after all light changes is marked to the engine to be processed).
// To fix this, on client-only mode, we mixin-redirect the `isClientLightReady()` so that after the call, it will
// trigger a synchronous update of this flag here on all chunks that are wrapped.
//
// Note: Using a static weak hash map to store the chunks that need to be updated, as instance of chunk wrapper
// can be duplicated, with same chunk instance. And the data stored here are all temporary, and thus will not be
// visible when a chunk is re-wrapped later.
// (Also, thread safety done via a reader writer lock)
private final static WeakHashMap<ChunkAccess, Boolean> chunksToUpdateClientLightReady = new WeakHashMap<>();
/**
* Due to vanilla `isClientLightReady()` not designed to be used by non-render thread, that value may return 'true'
* just before the light engine is ticked, (right after all light changes is marked to the engine to be processed).
* To fix this, on client-only mode, we mixin-redirect the `isClientLightReady()` so that after the call, it will
* trigger a synchronous update of this flag here on all chunks that are wrapped. <br><br>
*
* Note: Using a static weak hash map to store the chunks that need to be updated, as instance of chunk wrapper
* can be duplicated, with same chunk instance. And the data stored here are all temporary, and thus will not be
* visible when a chunk is re-wrapped later. <br>
* (Also, thread safety done via a reader writer lock)
*/
private final static WeakHashMap<ChunkAccess, Boolean> chunksToUpdateClientLightReady = new WeakHashMap<>(); // TODO this is never cleared
private final static ReentrantReadWriteLock weakMapLock = new ReentrantReadWriteLock();
@@ -103,7 +105,7 @@ public class ChunkWrapper implements IChunkWrapper
// TODO is this the best way to differentiate between when we are generating chunks and when MC gave us a chunk?
boolean isDhGeneratedChunk = (this.lightSource.getClass() == DhLitWorldGenRegion.class);
this.useDhLightingEngine = isDhGeneratedChunk && (Config.Client.Advanced.WorldGenerator.worldGenLightingEngine.get() == ELightGenerationMode.DISTANT_HORIZONS);
this.useDhLighting = isDhGeneratedChunk && (Config.Client.Advanced.WorldGenerator.worldGenLightingEngine.get() == ELightGenerationMode.DISTANT_HORIZONS);
weakMapLock.writeLock().lock();
chunksToUpdateClientLightReady.put(chunk, false);
@@ -153,16 +155,16 @@ public class ChunkWrapper implements IChunkWrapper
//if (wrappedLevel != null) return wrappedLevel.getBiome(new DhBlockPos(x + getMinX(), y, z + getMinZ()));
#if PRE_MC_1_17_1
return BiomeWrapper.getBiomeWrapper(chunk.getBiomes().getNoiseBiome(
x >> 2, y >> 2, z >> 2));
return BiomeWrapper.getBiomeWrapper(this.chunk.getBiomes().getNoiseBiome(
relX >> 2, relY >> 2, relZ >> 2));
#elif PRE_MC_1_18_2
return BiomeWrapper.getBiomeWrapper(chunk.getBiomes().getNoiseBiome(
QuartPos.fromBlock(x), QuartPos.fromBlock(y), QuartPos.fromBlock(z)));
return BiomeWrapper.getBiomeWrapper(this.chunk.getBiomes().getNoiseBiome(
QuartPos.fromBlock(relX), QuartPos.fromBlock(relY), QuartPos.fromBlock(relZ)));
#elif PRE_MC_1_18_2
return BiomeWrapper.getBiomeWrapper(chunk.getNoiseBiome(
QuartPos.fromBlock(x), QuartPos.fromBlock(y), QuartPos.fromBlock(z)));
return BiomeWrapper.getBiomeWrapper(this.chunk.getNoiseBiome(
QuartPos.fromBlock(relX), QuartPos.fromBlock(relY), QuartPos.fromBlock(relZ)));
#else //Now returns a Holder<Biome> instead of Biome
return BiomeWrapper.getBiomeWrapper(chunk.getNoiseBiome(
return BiomeWrapper.getBiomeWrapper(this.chunk.getNoiseBiome(
QuartPos.fromBlock(relX), QuartPos.fromBlock(relY), QuartPos.fromBlock(relZ)));
#endif
}
@@ -187,10 +189,15 @@ public class ChunkWrapper implements IChunkWrapper
@Override
public void setIsDhLightCorrect(boolean isDhLightCorrect) { this.isDhLightCorrect = isDhLightCorrect; }
@Override
public void setUseDhLighting(boolean useDhLighting) { this.useDhLighting = useDhLighting; }
@Override
public boolean isLightCorrect()
{
if (this.useDhLightingEngine)
if (this.useDhLighting)
{
return this.isDhLightCorrect;
}
@@ -255,7 +262,7 @@ public class ChunkWrapper implements IChunkWrapper
throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, relY, relZ);
// use the full lighting engine when the chunks are within render distance or the config requests it
if (this.useDhLightingEngine)
if (this.useDhLighting)
{
// DH lighting method
return this.blockLightAtRelBlockPos.getOrDefault(new DhBlockPos(relX, relY, relZ), 0);
@@ -275,7 +282,7 @@ public class ChunkWrapper implements IChunkWrapper
throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, relY, relZ);
// use the full lighting engine when the chunks are within render distance or the config requests it
if (this.useDhLightingEngine)
if (this.useDhLighting)
{
// DH lighting method
return this.skyLightAtRelBlockPos.getOrDefault(new DhBlockPos(relX, relY, relZ), 0);
@@ -370,15 +377,20 @@ public class ChunkWrapper implements IChunkWrapper
#endif
// Should be called after client light updates are triggered.
private static boolean updateClientLightReady(ChunkAccess chunk, boolean oldValue) {
private static boolean updateClientLightReady(ChunkAccess chunk, boolean oldValue)
{
if (chunk instanceof LevelChunk && ((LevelChunk)chunk).getLevel() instanceof ClientLevel)
{
LevelChunk levelChunk = (LevelChunk)chunk;
ClientChunkCache clientChunkCache = ((ClientLevel)levelChunk.getLevel()).getChunkSource();
return clientChunkCache.getChunkForLighting(chunk.getPos().x, chunk.getPos().z) != null &&
#if PRE_MC_1_20_1 levelChunk.isClientLightReady()
#else checkLightSectionsOnChunk(levelChunk, levelChunk.getLevel().getLightEngine())
#endif;
#if MC_1_16_5 || MC_1_17_1
levelChunk.isLightCorrect();
#elif PRE_MC_1_20_1
levelChunk.isClientLightReady();
#else
checkLightSectionsOnChunk(levelChunk, levelChunk.getLevel().getLightEngine());
#endif
}
else
{
@@ -396,7 +408,8 @@ public class ChunkWrapper implements IChunkWrapper
{
chunksToUpdateClientLightReady.replaceAll(ChunkWrapper::updateClientLightReady);
}
finally {
finally
{
weakMapLock.writeLock().unlock();
}
#endif
@@ -285,6 +285,7 @@ public class ClassicConfigGUI
widget.setValue(value -> Translatable(translationPrefix + "enum." + info.getType().getSimpleName() + "." + info.get().toString()));
}
this.list.addButton(MakeBtn(widget.getValue().apply(info.get()), this.width - 150 - ConfigScreenConfigs.SpaceFromRightScreen, 0, 150, 20, widget.getKey()), resetButton, null, name);
return;
} else if (((EntryInfo) info.guiValue).widget != null) {
EditBox widget = new EditBox(font, this.width - 150 - ConfigScreenConfigs.SpaceFromRightScreen + 2, 0, 150 - 4, 20, null);
widget.setMaxLength(150);
@@ -292,18 +293,34 @@ public class ClassicConfigGUI
Predicate<String> processor = ((BiFunction<EditBox, Button, Predicate<String>>) ((EntryInfo) info.guiValue).widget).apply(widget, doneButton);
widget.setFilter(processor);
this.list.addButton(widget, resetButton, null, name);
return;
}
} else if (ConfigCategory.class.isAssignableFrom(info.getClass())) {
}
if (ConfigCategory.class.isAssignableFrom(info.getClass())) {
Button widget = MakeBtn(name, this.width / 2 - 100, this.height - 28, 100 * 2, 20, (button -> {
ConfigBase.INSTANCE.configFileINSTANCE.saveToFile();
Objects.requireNonNull(minecraft).setScreen(ClassicConfigGUI.getScreen(this.configBase, this, ((ConfigCategory) info).getDestination()));
}));
this.list.addButton(widget, null, null, null);
} else if (ConfigUIComment.class.isAssignableFrom(info.getClass())) {
this.list.addButton(null, null, null, name);
} else if (ConfigLinkedEntry.class.isAssignableFrom(info.getClass())) {
this.addMenuItem(((ConfigLinkedEntry) info).get());
return;
}
if (ConfigUIButton.class.isAssignableFrom(info.getClass())) {
Button widget = MakeBtn(name, this.width / 2 - 100, this.height - 28, 100 * 2, 20, (button -> {
((ConfigUIButton) info).runAction();
}));
this.list.addButton(widget, null, null, null);
return;
}
if (ConfigUIComment.class.isAssignableFrom(info.getClass())) {
this.list.addButton(null, null, null, name);
return;
}
if (ConfigLinkedEntry.class.isAssignableFrom(info.getClass())) {
this.addMenuItem(((ConfigLinkedEntry) info).get());
return;
}
LOGGER.warn("Config ["+ info.getNameWCategory() +"] failed to show. Please try something like changing its type.");
}
@Override
@@ -25,13 +25,17 @@ public class GetConfigScreen
// This shouldn't be here, but I need a way to test it after Minecraft inits its assets
//System.out.println(ConfigBase.INSTANCE.generateLang(false, true));
return switch (useScreen)
switch (useScreen)
{
case Classic -> ClassicConfigGUI.getScreen(ConfigBase.INSTANCE, parent, "client");
case OpenGL -> MinecraftScreen.getScreen(parent, new OpenGLConfigScreen(), ModInfo.ID + ".title");
case Classic:
return ClassicConfigGUI.getScreen(ConfigBase.INSTANCE, parent, "client");
case OpenGL: MinecraftScreen.getScreen(parent, new OpenGLConfigScreen(), ModInfo.ID + ".title");
return null;
// case JavaFX -> MinecraftScreen.getScreen(parent, new JavaScreenHandlerScreen(new JavaScreenHandlerScreen.ExampleScreen()), ModInfo.ID + ".title");
case JavaFX -> MinecraftScreen.getScreen(parent, new JavaScreenHandlerScreen(new ConfigScreen()), ModInfo.ID + ".title");
default -> null;
};
case JavaFX:
return MinecraftScreen.getScreen(parent, new JavaScreenHandlerScreen(new ConfigScreen()), ModInfo.ID + ".title");
default:
return null;
}
}
}
@@ -22,10 +22,16 @@ package com.seibel.distanthorizons.common.wrappers.gui;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.gui.components.ImageButton;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
#if PRE_MC_1_17_1
import net.minecraft.client.Minecraft;
#else
import net.minecraft.client.renderer.GameRenderer;
#endif
/**
* Creates a button with a texture on it
*/
@@ -9,19 +9,22 @@ import com.seibel.distanthorizons.core.jar.installer.MarkdownFormatter;
import com.seibel.distanthorizons.core.jar.installer.ModrinthGetter;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.components.ContainerObjectSelectionList;
import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
#if POST_MC_1_17_1
import net.minecraft.client.gui.narration.NarratableEntry;
#endif
#if PRE_MC_1_20_1
import net.minecraft.client.gui.GuiComponent;
#else
import net.minecraft.client.gui.GuiGraphics;
#endif
import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.components.ContainerObjectSelectionList;
import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.gui.narration.NarratableEntry;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
#if PRE_MC_1_19_2
#endif
import static com.seibel.distanthorizons.common.wrappers.gui.GuiHelper.*;
@@ -69,10 +72,10 @@ public class ChangelogScreen extends DhScreen {
this.changelog.add("");
// Get the release changelog and split it by the new lines
List<String> unwrappedChangelog =
List.of(new MarkdownFormatter.MinecraftFormat().convertTo( // This formats markdown to minecraft's "§" characters
String[] unwrappedChangelog = // Arrays.asList could be used if a list object is desired here vs List.of which is only available for Java 9+
new MarkdownFormatter.MinecraftFormat().convertTo( // This formats markdown to minecraft's "§" characters
ModrinthGetter.changeLogs.get(versionID)
).split("\\n"));
).split("\\n");
// Makes the words wrap around to not go off the screen
for (String str: unwrappedChangelog) {
this.changelog.addAll(
@@ -116,7 +119,13 @@ public class ChangelogScreen extends DhScreen {
// Set the scroll position to the mouse height relative to the screen
// This is a bit of a hack as we cannot scroll on this area
this.changelogArea.scrollAmount = ((double) mouseY)/((double) this.height) * 1.1 * this.changelogArea.getMaxScroll();
double scrollAmount = ((double) mouseY)/((double) this.height) * 1.1 * this.changelogArea.getMaxScroll();
#if MC_1_16_5 || MC_1_17_1
this.changelogArea.setScrollAmount(scrollAmount);
#else
this.changelogArea.scrollAmount = scrollAmount;
#endif
this.changelogArea.render(matrices, mouseX, mouseY, delta); // Render the changelog
@@ -149,7 +158,8 @@ public class ChangelogScreen extends DhScreen {
}
}
public static class ButtonEntry extends ContainerObjectSelectionList.Entry<ButtonEntry> {
public static class ButtonEntry extends ContainerObjectSelectionList.Entry<ButtonEntry>
{
private static final Font textRenderer = Minecraft.getInstance().font;
private final Component text;
private final List<AbstractWidget> children = new ArrayList<>();
@@ -326,11 +326,6 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
#endif
}
@Override
public boolean tryDisableVanillaFog() {
return true; // Handled via MixinFogRenderer in both forge and fabric
}
public void updateLightmap(NativeImage lightPixels) {
if (lightmap== null) {
lightmap = new LightMapWrapper();
@@ -374,16 +374,17 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
public ChunkAccess loadOrMakeChunk(ChunkPos chunkPos, WorldGenLevelLightEngine lightEngine)
{
ServerLevel level = params.level;
ServerLevel level = this.params.level;
CompoundTag chunkData = null;
try
{
// Warning: if multiple threads attempt to access this method at the same time,
// it can throw EOFExceptions that are caught and logged by Minecraft
//chunkData = level.getChunkSource().chunkMap.readChunk(chunkPos);
RegionFileStorage storage = params.level.getChunkSource().chunkMap.worker.storage;
RegionFileStorageExternalCache cache = getOrCreateRegionFileCache(storage);
RegionFileStorage storage = this.params.level.getChunkSource().chunkMap.worker.storage;
RegionFileStorageExternalCache cache = this.getOrCreateRegionFileCache(storage);
chunkData = cache.read(chunkPos);
}
catch (Exception e)
@@ -499,7 +500,11 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
ChunkAccess target = wrappedChunk.getChunk();
if (target instanceof LevelChunk)
{
#if MC_1_16_5 || MC_1_17_1
((LevelChunk) target).setLoaded(true);
#else
((LevelChunk) target).loaded = true;
#endif
}
if (!wrappedChunk.isLightCorrect())
@@ -692,7 +697,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
}
// clear the chunk cache
var regionStorage = this.regionFileStorageCacheRef.get();
RegionFileStorageExternalCache regionStorage = this.regionFileStorageCacheRef.get();
if (regionStorage != null)
{
try
@@ -88,7 +88,7 @@ public final class ThreadedParameters
}
#if PRE_MC_1_19_2
#if POST_MC_1_18_2 && PRE_MC_1_19_2
public void recreateStructureCheck()
{
if (previousGlobalParameters != null)
@@ -14,23 +14,28 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.ConcurrentLinkedQueue;
public class RegionFileStorageExternalCache implements AutoCloseable {
public class RegionFileStorageExternalCache implements AutoCloseable
{
public final RegionFileStorage storage;
public static final int MAX_CACHE_SIZE = 16;
@Override
public void close() throws IOException {
public void close() throws IOException
{
RegionFileCache cache;
while ((cache = regionFileCache.poll()) != null) {
while ((cache = this.regionFileCache.poll()) != null)
{
cache.file.close();
}
}
static class RegionFileCache {
static class RegionFileCache
{
public final long pos;
public final RegionFile file;
public RegionFileCache(long pos, RegionFile file) {
public RegionFileCache(long pos, RegionFile file)
{
this.pos = pos;
this.file = file;
}
@@ -38,9 +43,7 @@ public class RegionFileStorageExternalCache implements AutoCloseable {
public ConcurrentLinkedQueue<RegionFileCache> regionFileCache = new ConcurrentLinkedQueue<>();
public RegionFileStorageExternalCache(RegionFileStorage storage) {
this.storage = storage;
}
public RegionFileStorageExternalCache(RegionFileStorage storage) { this.storage = storage; }
@Nullable
public RegionFile getRegionFile(ChunkPos pos) throws IOException
@@ -53,7 +56,12 @@ public class RegionFileStorageExternalCache implements AutoCloseable {
{
try
{
rFile = this.storage.regionCache.getOrDefault(posLong, null);
#if MC_1_16_5 || MC_1_17_1
rFile = this.storage.getRegionFile(pos);
#else
rFile = this.storage.regionCache.getOrDefault(posLong, null);
#endif
break;
}
catch (ArrayIndexOutOfBoundsException e)
@@ -77,18 +85,29 @@ public class RegionFileStorageExternalCache implements AutoCloseable {
}
// Otherwise, check if file exist, and if so, add it to the cache
Path p = storage.folder;
if (!Files.exists(p))
Path storageFolderPath;
#if MC_1_16_5 || MC_1_17_1
storageFolderPath = this.storage.folder.toPath();
#else
storageFolderPath = this.storage.folder;
#endif
if (!Files.exists(storageFolderPath))
{
return null;
}
Path rFilePath = p.resolve("r." + pos.getRegionX() + "." + pos.getRegionZ() + ".mca");
rFile = new RegionFile(rFilePath, p, false);
regionFileCache.add(new RegionFileCache(ChunkPos.asLong(pos.getRegionX(), pos.getRegionZ()), rFile));
while (regionFileCache.size() > MAX_CACHE_SIZE)
Path regionFilePath = storageFolderPath.resolve("r." + pos.getRegionX() + "." + pos.getRegionZ() + ".mca");
#if MC_1_16_5 || MC_1_17_1
rFile = new RegionFile(regionFilePath.toFile(), storageFolderPath.toFile(), false);
#else
rFile = new RegionFile(regionFilePath, storageFolderPath, false);
#endif
this.regionFileCache.add(new RegionFileCache(ChunkPos.asLong(pos.getRegionX(), pos.getRegionZ()), rFile));
while (this.regionFileCache.size() > MAX_CACHE_SIZE)
{
regionFileCache.poll().file.close();
this.regionFileCache.poll().file.close();
}
return rFile;
@@ -50,13 +50,17 @@ import net.minecraft.world.level.StructureManager;
#if POST_MC_1_18_2
import net.minecraft.world.level.levelgen.structure.StructureCheck;
#endif
import net.minecraft.world.level.levelgen.structure.StructureStart;
#if PRE_MC_1_19_2
public class WorldGenStructFeatManager extends StructureFeatureManager {
#else
public class WorldGenStructFeatManager extends StructureManager {
#endif
#if PRE_MC_1_18_2
import net.minecraft.world.level.levelgen.feature.StructureFeature;
#endif
public class WorldGenStructFeatManager extends #if PRE_MC_1_19_2 StructureFeatureManager #else StructureManager #endif
{
final WorldGenLevel genLevel;
#if PRE_MC_1_19_4
@@ -29,7 +29,11 @@ import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.ProtoChunk;
#if PRE_MC_1_17_1
import net.minecraft.world.level.lighting.LevelLightEngine;
#else
import net.minecraft.world.level.lighting.LightEventListener;
#endif
public final class StepLight {
/**
@@ -35,6 +35,10 @@ accessible method net/minecraft/world/level/lighting/LayerLightEngine queueSecti
# lod generation from save file
accessible field net/minecraft/server/level/ChunkMap mainThreadExecutor Lnet/minecraft/util/thread/BlockableEventLoop;
accessible method net/minecraft/server/level/ChunkMap readChunk (Lnet/minecraft/world/level/ChunkPos;)Lnet/minecraft/nbt/CompoundTag;
accessible method net/minecraft/world/level/chunk/storage/RegionFileStorage getRegionFile (Lnet/minecraft/world/level/ChunkPos;)Lnet/minecraft/world/level/chunk/storage/RegionFile;
accessible field net/minecraft/world/level/chunk/storage/RegionFileStorage folder Ljava/io/File;
accessible field net/minecraft/world/level/chunk/storage/ChunkStorage worker Lnet/minecraft/world/level/chunk/storage/IOWorker;
accessible field net/minecraft/world/level/chunk/storage/IOWorker storage Lnet/minecraft/world/level/chunk/storage/RegionFileStorage;
# grabbing textures
accessible field net/minecraft/client/renderer/block/model/BakedQuad sprite Lnet/minecraft/client/renderer/texture/TextureAtlasSprite;
@@ -35,7 +35,10 @@ accessible method net/minecraft/world/level/lighting/LayerLightEngine queueSecti
# lod generation from save file
accessible field net/minecraft/server/level/ChunkMap mainThreadExecutor Lnet/minecraft/util/thread/BlockableEventLoop;
accessible method net/minecraft/server/level/ChunkMap readChunk (Lnet/minecraft/world/level/ChunkPos;)Lnet/minecraft/nbt/CompoundTag;
accessible method net/minecraft/world/level/chunk/storage/RegionFileStorage getRegionFile (Lnet/minecraft/world/level/ChunkPos;)Lnet/minecraft/world/level/chunk/storage/RegionFile;
accessible field net/minecraft/world/level/chunk/storage/RegionFileStorage folder Ljava/io/File;
accessible field net/minecraft/world/level/chunk/storage/ChunkStorage worker Lnet/minecraft/world/level/chunk/storage/IOWorker;
accessible field net/minecraft/world/level/chunk/storage/IOWorker storage Lnet/minecraft/world/level/chunk/storage/RegionFileStorage;
# grabbing textures
accessible field net/minecraft/client/renderer/texture/TextureAtlasSprite animatedTexture Lnet/minecraft/client/renderer/texture/TextureAtlasSprite$AnimatedTexture;
@@ -0,0 +1,5 @@
{
"git_main_commit": "${git_main_commit}",
"git_core_commit": "${git_core_commit}",
"git_main_branch": "${git_main_branch}"
}
+5 -5
View File
@@ -76,11 +76,11 @@ dependencies {
// Sodium
addMod("maven.modrinth:sodium:${rootProject.sodium_version}", rootProject.enable_sodium)
// if (rootProject.enable_sodium != "0") {
// implementation "org.joml:joml:1.10.2"
// modImplementation(fabricApi.module("fabric-rendering-data-attachment-v1", rootProject.fabric_api_version))
// modImplementation(fabricApi.module("fabric-rendering-fluids-v1", rootProject.fabric_api_version))
// }
if (rootProject.enable_sodium == "2") {
implementation "org.joml:joml:1.10.2"
modImplementation(fabricApi.module("fabric-rendering-data-attachment-v1", rootProject.fabric_api_version))
modImplementation(fabricApi.module("fabric-rendering-fluids-v1", rootProject.fabric_api_version))
}
// Lithium
addMod("maven.modrinth:lithium:${rootProject.lithium_version}", rootProject.enable_lithium)
@@ -62,6 +62,7 @@ import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.phys.HitResult;
import org.apache.logging.log4j.Logger;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.opengl.GL15;
/**
* This handles all events sent to the client,
@@ -211,7 +212,9 @@ public class FabricClientProxy
{
float[] matrixFloatArray = SeamlessOverdraw.overwriteMinecraftNearFarClipPlanes(renderContext.projectionMatrix(), renderContext.tickDelta());
#if PRE_MC_1_19_4
#if MC_1_16_5
SeamlessOverdraw.applyLegacyProjectionMatrix(matrixFloatArray);
#elif PRE_MC_1_19_4
renderContext.projectionMatrix().load(FloatBuffer.wrap(matrixFloatArray));
#else
renderContext.projectionMatrix().set(matrixFloatArray);
@@ -22,6 +22,7 @@ package com.seibel.distanthorizons.fabric;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiAfterDhInitEvent;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeDhInitEvent;
import com.seibel.distanthorizons.core.config.ConfigBase;
import com.seibel.distanthorizons.core.jar.ModGitInfo;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.*;
import com.seibel.distanthorizons.common.LodCommonMain;
import com.seibel.distanthorizons.coreapi.ModInfo;
@@ -72,6 +73,11 @@ public class FabricMain
FabricDependencySetup.createInitialBindings();
LOGGER.info(ModInfo.READABLE_NAME + ", Version: " + ModInfo.VERSION);
// Print git info (Useful for dev builds)
LOGGER.info("DH Branch: "+ ModGitInfo.Git_Main_Branch);
LOGGER.info("DH Commit: "+ ModGitInfo.Git_Main_Commit);
LOGGER.info("DH-Core Commit: "+ ModGitInfo.Git_Core_Commit);
if (SingletonInjector.INSTANCE.get(IModChecker.class).isModLoaded("sodium")) {
ModAccessorInjector.INSTANCE.bind(ISodiumAccessor.class, new SodiumAccessor());
}
@@ -17,16 +17,6 @@ public class MixinGameRenderer
#if POST_MC_1_17_1
@Inject(method = "shutdownShaders", at = @At("HEAD"))
public void onShutdownShaders(CallbackInfo ci) {
LOGGER.info("Shutting down renderer (fabric)");
if (!DependencySetupDoneCheck.isDone) {
LOGGER.warn("Dependency setup is not done yet, skipping renderer this shutdown event!");
return;
}
ClientApi.INSTANCE.rendererShutdownEvent();
}
// FIXME: This I think will dup multiple renderStartupEvent calls...
@Inject(method = {"reloadShaders", "preloadUiShader"}, at = @At("TAIL"))
public void onStartupShaders(CallbackInfo ci) {
@@ -37,20 +27,28 @@ public class MixinGameRenderer
}
ClientApi.INSTANCE.rendererStartupEvent();
}
#else
// FIXME: on 1.16 we dont have stuff for reloading/shutting down shaders
@Inject(method = "shutdownShaders", at = @At("HEAD"))
@Inject(method = "shutdownShaders", at = @At("HEAD"))
public void onShutdownShaders(CallbackInfo ci) {
LOGGER.info("Shutting down renderer");
LOGGER.info("Shutting down renderer (fabric)");
if (!DependencySetupDoneCheck.isDone) {
LOGGER.warn("Dependency setup is not done yet, skipping renderer this shutdown event!");
return;
}
ClientApi.INSTANCE.rendererShutdownEvent();
}
// FIXME: This I think will dup multiple renderStartupEvent calls...
@Inject(method = {"reloadShaders", "preloadUiShader", "preloadShader"}, at = @At("TAIL"))
public void onStartupShaders(CallbackInfo ci) {
LOGGER.info("Starting up renderer");
ClientApi.INSTANCE.rendererStartupEvent();
}
#else
// FIXME: on 1.16 we dont have stuff for reloading/shutting down shaders
// FIXME: This I think will dup multiple renderStartupEvent calls...
@Inject(method = {"loadEffect"}, at = @At("TAIL"))
public void onStartupShaders(CallbackInfo ci) {
ClientApi.INSTANCE.rendererStartupEvent();
}
@Inject(method = "shutdownEffect", at = @At("HEAD"))
public void onShutdownShaders(CallbackInfo ci) {
ClientApi.INSTANCE.rendererShutdownEvent();
}
#endif
}
@@ -96,10 +96,11 @@ public class MixinLevelRenderer
private void renderChunkLayer(RenderType renderType, PoseStack modelViewMatrixStack, double cameraXBlockPos, double cameraYBlockPos, double cameraZBlockPos, Matrix4f projectionMatrix, CallbackInfo callback)
#endif
{
if (Config.Client.Advanced.Debugging.lodOnlyMode.get())
// FIXME completely disables rendering when sodium is installed
if (Config.Client.Advanced.Debugging.lodOnlyMode.get())
{
callback.cancel();
}
callback.cancel();
}
}
@Redirect(method =
@@ -1,37 +0,0 @@
package com.seibel.distanthorizons.fabric.mixins.mods.sodium;
import com.seibel.distanthorizons.core.api.internal.ClientApi;
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.ISodiumAccessor;
import com.seibel.distanthorizons.fabric.wrappers.modAccessor.SodiumAccessor;
import me.jellysquid.mods.sodium.client.gl.device.CommandList;
import me.jellysquid.mods.sodium.client.render.chunk.ChunkCameraContext;
import me.jellysquid.mods.sodium.client.render.chunk.ChunkRenderList;
import me.jellysquid.mods.sodium.client.render.chunk.ChunkRenderMatrices;
import me.jellysquid.mods.sodium.client.render.chunk.RegionChunkRenderer;
import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(RegionChunkRenderer.class)
public class MixinSodiumChunkRenderer {
@Unique SodiumAccessor accessor = null;
@Inject(remap = false, method = "render", at = @At(value = "INVOKE", target = "Lme/jellysquid/mods/sodium/client/render/chunk/ShaderChunkRenderer;begin(Lme/jellysquid/mods/sodium/client/render/chunk/passes/BlockRenderPass;)V", shift = At.Shift.AFTER))
private void injectDHLoDRendering(ChunkRenderMatrices matrices, CommandList commandList, ChunkRenderList list, BlockRenderPass pass, ChunkCameraContext camera, CallbackInfo ci) {
if (accessor == null) {
accessor = (SodiumAccessor)ModAccessorInjector.INSTANCE.get(ISodiumAccessor.class);
}
if (pass.equals(BlockRenderPass.SOLID)) {
//TODO: use matrices.modelView() and matrices.projection() instead of
// SodiumAccessor.mcModelViewMatrix,
// SodiumAccessor.mcProjectionMatrix,
ClientApi.INSTANCE.renderLods(accessor.levelWrapper,
accessor.mcModelViewMatrix,
accessor.mcProjectionMatrix,
accessor.partialTicks);
}
}
}
@@ -0,0 +1,136 @@
package com.seibel.distanthorizons.fabric.mixins.mods.sodium;
#if POST_MC_1_20_1
// Sodium 0.5
import com.seibel.distanthorizons.core.api.internal.ClientApi;
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.ISodiumAccessor;
import com.seibel.distanthorizons.fabric.wrappers.modAccessor.SodiumAccessor;
import me.jellysquid.mods.sodium.client.gl.device.CommandList;
import me.jellysquid.mods.sodium.client.render.chunk.ChunkCameraContext;
import me.jellysquid.mods.sodium.client.render.chunk.ChunkRenderMatrices;
import me.jellysquid.mods.sodium.client.render.chunk.RegionChunkRenderer;
import me.jellysquid.mods.sodium.client.render.chunk.lists.SortedRenderLists;
import me.jellysquid.mods.sodium.client.render.chunk.region.RenderRegionManager;
import me.jellysquid.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses;
import me.jellysquid.mods.sodium.client.render.chunk.terrain.TerrainRenderPass;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(RegionChunkRenderer.class)
public class MixinSodiumRenderer
{
@Unique SodiumAccessor accessor = null;
@Inject(remap = false, method = "render", at = @At(value = "INVOKE", target = "Lme/jellysquid/mods/sodium/client/render/chunk/ShaderChunkRenderer;begin(Lme/jellysquid/mods/sodium/client/render/chunk/terrain/TerrainRenderPass;)V", shift = At.Shift.AFTER))
private void injectDHLoDRendering(ChunkRenderMatrices matrices, CommandList commandList, RenderRegionManager regions, SortedRenderLists renderLists, TerrainRenderPass renderPass, ChunkCameraContext camera, CallbackInfo ci)
{
if (accessor == null)
{
accessor = (SodiumAccessor)ModAccessorInjector.INSTANCE.get(ISodiumAccessor.class);
}
if (renderPass.equals(DefaultTerrainRenderPasses.SOLID))
{
//TODO: use matrices.modelView() and matrices.projection() instead of
// SodiumAccessor.mcModelViewMatrix,
// SodiumAccessor.mcProjectionMatrix,
ClientApi.INSTANCE.renderLods(accessor.levelWrapper,
accessor.mcModelViewMatrix,
accessor.mcProjectionMatrix,
accessor.partialTicks);
}
}
}
#elif POST_MC_1_17_1
// Sodium 0.3 to 0.4
import com.seibel.distanthorizons.core.api.internal.ClientApi;
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.ISodiumAccessor;
import com.seibel.distanthorizons.fabric.wrappers.modAccessor.SodiumAccessor;
import me.jellysquid.mods.sodium.client.gl.device.CommandList;
import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer;
import me.jellysquid.mods.sodium.client.render.chunk.ChunkCameraContext;
import me.jellysquid.mods.sodium.client.render.chunk.ChunkRenderList;
import me.jellysquid.mods.sodium.client.render.chunk.ChunkRenderMatrices;
import me.jellysquid.mods.sodium.client.render.chunk.RegionChunkRenderer;
import me.jellysquid.mods.sodium.client.render.chunk.passes.BlockRenderPass;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(RegionChunkRenderer.class)
public class MixinSodiumRenderer
{
@Unique SodiumAccessor accessor = null;
@Inject(remap = false, method = "render", at = @At(value = "INVOKE", target = "Lme/jellysquid/mods/sodium/client/render/chunk/ShaderChunkRenderer;begin(Lme/jellysquid/mods/sodium/client/render/chunk/passes/BlockRenderPass;)V", shift = At.Shift.AFTER))
private void injectDHLoDRendering(ChunkRenderMatrices matrices, CommandList commandList, ChunkRenderList list, BlockRenderPass pass, ChunkCameraContext camera, CallbackInfo ci)
{
if (accessor == null)
{
accessor = (SodiumAccessor)ModAccessorInjector.INSTANCE.get(ISodiumAccessor.class);
}
if (pass.equals(BlockRenderPass.SOLID))
{
//TODO: use matrices.modelView() and matrices.projection() instead of
// SodiumAccessor.mcModelViewMatrix,
// SodiumAccessor.mcProjectionMatrix,
ClientApi.INSTANCE.renderLods(accessor.levelWrapper,
accessor.mcModelViewMatrix,
accessor.mcProjectionMatrix,
accessor.partialTicks);
}
}
}
#else
// Sodium 0.2 and under
import com.mojang.blaze3d.vertex.PoseStack;
import com.seibel.distanthorizons.core.api.internal.ClientApi;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.ISodiumAccessor;
import com.seibel.distanthorizons.fabric.wrappers.modAccessor.SodiumAccessor;
import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer;
import net.minecraft.client.renderer.RenderType;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(SodiumWorldRenderer.class)
public class MixinSodiumRenderer
{
@Unique SodiumAccessor accessor = null;
@Inject(method="drawChunkLayer", remap = false, at = @At("HEAD"))
private void drawChunkLayer(RenderType renderLayer, PoseStack matrixStack, double x, double y, double z, CallbackInfo callback)
{
if (this.accessor == null)
{
this.accessor = (SodiumAccessor) ModAccessorInjector.INSTANCE.get(ISodiumAccessor.class);
}
if (renderLayer == RenderType.solid())
{
ClientApi.INSTANCE.renderLods(this.accessor.levelWrapper,
this.accessor.mcModelViewMatrix,
this.accessor.mcProjectionMatrix,
this.accessor.partialTicks);
}
}
}
#endif
@@ -28,7 +28,17 @@ public class MixinChunkMap {
ServerLevel level;
@Inject(method = "save", at = @At(value = "INVOKE", target = CHUNK_SERIALIZER_WRITE))
private void onChunkSave(ChunkAccess chunk, CallbackInfoReturnable<Boolean> ci) {
private void onChunkSave(ChunkAccess chunk, CallbackInfoReturnable<Boolean> ci)
{
#if MC_1_16_5
if (chunk.getBiomes() == null)
{
// in 1.16.5 some chunks may be missing their biomes, which cause issues when attempting to save them
return;
}
#endif
ServerApi.INSTANCE.serverChunkSaveEvent(
new ChunkWrapper(chunk, level, ServerLevelWrapper.getWrapper(level)),
ServerLevelWrapper.getWrapper(level)
@@ -35,6 +35,7 @@ import java.util.concurrent.Semaphore;
/**
* Why does this exist? But okay! (Will be probably removed when the experimental generator is done)
* FIXME: Recheck this
*/
@Mixin(ThreadingDetector.class)
public class MixinThreadingDetector {
@@ -48,6 +49,9 @@ public class MixinThreadingDetector {
}
}
#else
import net.minecraft.server.level.ServerLevel;
@Mixin(ServerLevel.class)
public class MixinThreadingDectector {} //FIXME: Is there some way to make this file just not be added?
public class MixinThreadingDetector { } //FIXME: Is there some way to make this file just not be added?
#endif
@@ -1,7 +1,8 @@
package com.seibel.distanthorizons.fabric.wrappers.modAccessor;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IBCLibAccessor;
#if PRE_MC_1_19_2
#if MC_1_16_5
#elif PRE_MC_1_19_2
import ru.bclib.config.ClientConfig;
import ru.bclib.config.Configs;
#else
@@ -9,15 +10,18 @@ import org.betterx.bclib.config.ClientConfig;
import org.betterx.bclib.config.Configs;
#endif
public class BCLibAccessor implements IBCLibAccessor {
public class BCLibAccessor implements IBCLibAccessor
{
@Override
public String getModName() {
return "BCLib";
}
public String getModName() { return "BCLib"; }
public void setRenderCustomFog(boolean newValue) {
// Change the value of CUSTOM_FOG_RENDERING in the bclib client config
public void setRenderCustomFog(boolean newValue)
{
#if MC_1_16_5 || MC_1_17_1
#elif PRE_MC_1_19_2
// Change the value of CUSTOM_FOG_RENDERING in the bclib client config
// This disabled fog from rendering within bclib
Configs.CLIENT_CONFIG.set(ClientConfig.CUSTOM_FOG_RENDERING, newValue);
#endif
}
}
@@ -64,7 +64,14 @@ public class SodiumAccessor implements ISodiumAccessor {
SodiumWorldRenderer renderer = SodiumWorldRenderer.instance();
LevelHeightAccessor height = Minecraft.getInstance().level;
#if POST_MC_1_18_2
#if POST_MC_1_20_1
// TODO: This is just a tmp solution, use a proper solution later
return MC_RENDER.getMaximumRenderedChunks().stream().filter((DhChunkPos chunk) -> {
return (renderer.isBoxVisible(
chunk.getMinBlockX()+1, height.getMinBuildHeight()+1, chunk.getMinBlockZ()+1,
chunk.getMinBlockX()+15, height.getMaxBuildHeight()-1, chunk.getMinBlockZ()+15));
}).collect(Collectors.toCollection(HashSet::new));
#elif POST_MC_1_18_2
// 0b11 = Lighted chunk & loaded chunk
return renderer.getChunkTracker().getChunks(0b00).filter(
(long l) -> {
@@ -72,7 +79,7 @@ public class SodiumAccessor implements ISodiumAccessor {
}).mapToObj(DhChunkPos::new).collect(Collectors.toCollection(HashSet::new));
#else
// TODO: Maybe use a mixin to make this more efficient, and maybe ignore changes behind the camera
return MC_RENDER.getMaximumRenderedChunks().stream().filter((DHChunkPos chunk) -> {
return MC_RENDER.getMaximumRenderedChunks().stream().filter((DhChunkPos chunk) -> {
return (renderer.isBoxVisible(
chunk.getMinBlockX()+1, height.getMinBuildHeight()+1, chunk.getMinBlockZ()+1,
chunk.getMinBlockX()+15, height.getMaxBuildHeight()-1, chunk.getMinBlockZ()+15));
@@ -81,11 +88,11 @@ public class SodiumAccessor implements ISodiumAccessor {
}
#else
@Override
public HashSet<DHChunkPos> getNormalRenderedChunks() {
public HashSet<DhChunkPos> getNormalRenderedChunks() {
SodiumWorldRenderer renderer = SodiumWorldRenderer.getInstance();
LevelAccessor height = Minecraft.getInstance().level;
// TODO: Maybe use a mixin to make this more efficient
return MC_RENDER.getMaximumRenderedChunks().stream().filter((DHChunkPos chunk) -> {
return MC_RENDER.getMaximumRenderedChunks().stream().filter((DhChunkPos chunk) -> {
FakeChunkEntity AABB = new FakeChunkEntity(chunk.getX(), chunk.getZ(), height.getMaxBuildHeight());
return (renderer.isEntityVisible(AABB));
}).collect(Collectors.toCollection(HashSet::new));
@@ -20,7 +20,7 @@
"client.MixinMinecraft",
"client.MixinTextureUtil",
"mods.sodium.MixinSodiumChunkRenderer"
"mods.sodium.MixinSodiumRenderer"
],
"server": [],
"injectors": {
@@ -26,6 +26,7 @@ import com.seibel.distanthorizons.common.forge.LodForgeMethodCaller;
import com.seibel.distanthorizons.common.wrappers.DependencySetup;
import com.seibel.distanthorizons.common.wrappers.gui.GetConfigScreen;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftClientWrapper;
import com.seibel.distanthorizons.core.jar.ModGitInfo;
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
import com.seibel.distanthorizons.coreapi.ModInfo;
import com.seibel.distanthorizons.core.ReflectionHandler;
@@ -112,6 +113,11 @@ public class ForgeMain implements LodForgeMethodCaller
ForgeDependencySetup.createInitialBindings();
LOGGER.info(ModInfo.READABLE_NAME + ", Version: " + ModInfo.VERSION);
// Print git info (Useful for dev builds)
LOGGER.info("DH Branch: "+ ModGitInfo.Git_Main_Branch);
LOGGER.info("DH Commit: "+ ModGitInfo.Git_Main_Commit);
LOGGER.info("DH-Core Commit: "+ ModGitInfo.Git_Core_Commit);
client_proxy = new ForgeClientProxy();
MinecraftForge.EVENT_BUS.register(client_proxy);
server_proxy = new ForgeServerProxy(false);
@@ -124,7 +130,7 @@ public class ForgeMain implements LodForgeMethodCaller
#if PRE_MC_1_17_1
ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.CONFIGGUIFACTORY,
() -> (client, parent) -> GetConfigScreen.getScreen(parent));
#elif POST_MC_1_18_2 && PRE_MC_1_19_2
#elif MC_1_17_1 || MC_1_18_2 || PRE_MC_1_19_2
ModLoadingContext.get().registerExtensionPoint(ConfigGuiHandler.ConfigGuiFactory.class,
() -> new ConfigGuiHandler.ConfigGuiFactory((client, parent) -> GetConfigScreen.getScreen(parent)));
#else
@@ -8,14 +8,9 @@ import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.TitleScreen;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.level.LevelAccessor;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.event.server.ServerAboutToStartEvent;
import net.minecraftforge.event.server.ServerStoppingEvent;
#if PRE_MC_1_19_2
import net.minecraftforge.event.world.ChunkEvent;
import net.minecraftforge.event.world.WorldEvent;
@@ -24,6 +19,19 @@ import net.minecraftforge.event.level.ChunkEvent;
import net.minecraftforge.event.level.LevelEvent;
#endif
import net.minecraftforge.eventbus.api.SubscribeEvent;
#if MC_1_16_5
import net.minecraftforge.fml.event.server.FMLServerAboutToStartEvent;
import net.minecraftforge.fml.event.server.FMLServerStoppingEvent;
#elif MC_1_17_1
import net.minecraftforge.fmlserverevents.FMLServerAboutToStartEvent;
import net.minecraftforge.fmlserverevents.FMLServerStoppingEvent;
#else
import net.minecraftforge.event.server.ServerAboutToStartEvent;
import net.minecraftforge.event.server.ServerStoppingEvent;
#endif
import org.apache.logging.log4j.Logger;
import java.util.function.Supplier;
@@ -74,7 +82,7 @@ public class ForgeServerProxy
// ServerWorldLoadEvent
@SubscribeEvent
public void dedicatedWorldLoadEvent(ServerAboutToStartEvent event)
public void dedicatedWorldLoadEvent(#if MC_1_16_5 || MC_1_17_1 FMLServerAboutToStartEvent #else ServerAboutToStartEvent #endif event)
{
if (this.isValidTime())
{
@@ -84,7 +92,7 @@ public class ForgeServerProxy
// ServerWorldUnloadEvent
@SubscribeEvent
public void serverWorldUnloadEvent(ServerStoppingEvent event)
public void serverWorldUnloadEvent(#if MC_1_16_5 || MC_1_17_1 FMLServerStoppingEvent #else ServerStoppingEvent #endif event)
{
if (this.isValidTime())
{
@@ -125,22 +133,26 @@ public class ForgeServerProxy
@SubscribeEvent
public void serverChunkLoadEvent(ChunkEvent.Load event)
{
if (isValidTime()) {
if (GetLevel(event) instanceof ServerLevel) {
ServerLevelWrapper wrappedLevel = ServerLevelWrapper.getWrapper((ServerLevel) GetLevel(event));
IChunkWrapper chunk = new ChunkWrapper(event.getChunk(), GetLevel(event), wrappedLevel);
serverApi.serverChunkLoadEvent(chunk, getLevelWrapper((ServerLevel) GetLevel(event)));
}
if (this.isValidTime())
{
if (GetLevel(event) instanceof ServerLevel)
{
ServerLevelWrapper wrappedLevel = ServerLevelWrapper.getWrapper((ServerLevel) GetLevel(event));
IChunkWrapper chunk = new ChunkWrapper(event.getChunk(), GetLevel(event), wrappedLevel);
this.serverApi.serverChunkLoadEvent(chunk, this.getLevelWrapper((ServerLevel) GetLevel(event)));
}
}
}
@SubscribeEvent
public void serverChunkSaveEvent(ChunkEvent.Unload event)
{
if (isValidTime()) {
if (GetLevel(event) instanceof ServerLevel) {
if (this.isValidTime())
{
if (GetLevel(event) instanceof ServerLevel)
{
ServerLevelWrapper wrappedLevel = ServerLevelWrapper.getWrapper((ServerLevel) GetLevel(event));
IChunkWrapper chunk = new ChunkWrapper(event.getChunk(), GetLevel(event), wrappedLevel);
serverApi.serverChunkSaveEvent(chunk, getLevelWrapper((ServerLevel) GetLevel(event)));
this.serverApi.serverChunkSaveEvent(chunk, this.getLevelWrapper((ServerLevel) GetLevel(event)));
}
}
}
@@ -50,7 +50,7 @@ public class MixinFogRenderer {
@Inject(at = @At("RETURN"),
method = "setupFog(Lnet/minecraft/client/Camera;Lnet/minecraft/client/renderer/FogRenderer$FogMode;FZF)V",
remap = #if MC_1_16_5 || POST_AND_MC_1_19_2 true #else false #endif) // Remap messiness due to this being added by forge.
remap = #if MC_1_18_2 false #else true #endif) // Remap messiness due to this being weird in forge
private static void disableSetupFog(Camera camera, FogMode fogMode, float f, boolean bl, float partTick, CallbackInfo callback)
{
#if PRE_MC_1_17_1
@@ -60,7 +60,8 @@ public class MixinFogRenderer {
FogType fogTypes = camera.getFluidInCamera();
boolean cameraNotInFluid = fogTypes == FogType.NONE;
#endif
Entity entity = camera.getEntity();
boolean isSpecialFog = (entity instanceof LivingEntity) && ((LivingEntity) entity).hasEffect(MobEffects.BLINDNESS);
if (!isSpecialFog && cameraNotInFluid && fogMode == FogMode.FOG_TERRAIN
@@ -17,16 +17,6 @@ public class MixinGameRenderer
private static final Logger LOGGER = LogManager.getLogger(MixinGameRenderer.class.getSimpleName());
#if POST_MC_1_17_1
@Inject(method = "shutdownShaders", at = @At("HEAD"))
public void onShutdownShaders(CallbackInfo ci) {
LOGGER.info("Shutting down renderer (forge)");
if (!DependencySetupDoneCheck.isDone) {
LOGGER.warn("Dependency setup is not done yet, skipping renderer this shutdown event!");
return;
}
ClientApi.INSTANCE.rendererShutdownEvent();
}
// FIXME: This I think will dup multiple renderStartupEvent calls...
@Inject(method = {"reloadShaders", "preloadUiShader"}, at = @At("TAIL"))
public void onStartupShaders(CallbackInfo ci) {
@@ -37,21 +27,28 @@ public class MixinGameRenderer
}
ClientApi.INSTANCE.rendererStartupEvent();
}
#else
// FIXME: on 1.16 we dont have stuff for reloading/shutting down shaders
@Inject(method = "shutdownShaders", at = @At("HEAD"))
@Inject(method = "shutdownShaders", at = @At("HEAD"))
public void onShutdownShaders(CallbackInfo ci) {
LOGGER.info("Shutting down renderer");
LOGGER.info("Shutting down renderer (forge)");
if (!DependencySetupDoneCheck.isDone) {
LOGGER.warn("Dependency setup is not done yet, skipping renderer this shutdown event!");
return;
}
ClientApi.INSTANCE.rendererShutdownEvent();
}
// FIXME: This I think will dup multiple renderStartupEvent calls...
@Inject(method = {"reloadShaders", "preloadUiShader", "preloadShader"}, at = @At("TAIL"))
#else
@Inject(method = {"loadEffect"}, at = @At("TAIL"))
public void onStartupShaders(CallbackInfo ci) {
LOGGER.info("Starting up renderer");
ClientApi.INSTANCE.rendererStartupEvent();
}
@Inject(method = "shutdownEffect", at = @At("HEAD"))
public void onShutdownShaders(CallbackInfo ci) {
ClientApi.INSTANCE.rendererShutdownEvent();
}
#endif
}
@@ -46,6 +46,11 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.nio.FloatBuffer;
#if PRE_MC_1_17_1
import org.lwjgl.opengl.GL15;
#endif
/**
* This class is used to mix in my rendering code
* before Minecraft starts rendering blocks.
@@ -75,43 +80,18 @@ public class MixinLevelRenderer
#if PRE_MC_1_17_1
@Inject(at = @At("RETURN"), method = "renderSky(Lcom/mojang/blaze3d/vertex/PoseStack;F)V")
private void renderSky(PoseStack matrixStackIn, float partialTicks, CallbackInfo callback)
#else
@Inject(method = "renderClouds", at = @At("HEAD"), cancellable = true)
public void renderClouds(PoseStack poseStack, Matrix4f projectionMatrix, float partialTicks, double cameraX, double cameraY, double cameraZ, CallbackInfo ci)
#endif
{
// get the partial ticks since renderBlockLayer doesn't
// have access to them
previousPartialTicks = partialTicks;
}
@Inject(at = @At("HEAD"),
method = "renderChunkLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDD)V",
cancellable = true)
private void renderChunkLayer(RenderType renderType, PoseStack matrixStackIn, double xIn, double yIn, double zIn, CallbackInfo callback)
{
// only render before solid blocks
if (renderType.equals(RenderType.solid()))
{
// get MC's current projection matrix
float[] mcProjMatrixRaw = new float[16];
GL15.glGetFloatv(GL15.GL_PROJECTION_MATRIX, mcProjMatrixRaw);
Mat4f mcProjectionMatrix = new Mat4f(mcProjMatrixRaw);
mcProjectionMatrix.transpose();
Mat4f mcModelViewMatrix = McObjectConverter.Convert(matrixStackIn.last().pose());
ClientApi.INSTANCE.renderLods(LevelWrapper.getWorldWrapper(level), mcModelViewMatrix, mcProjectionMatrix, previousPartialTicks);
}
if (Config.Client.Advanced.lodOnlyMode.get()) {
callback.cancel();
}
}
#else
@Inject(method = "renderClouds", at = @At("HEAD"), cancellable = true)
public void renderClouds(PoseStack poseStack, Matrix4f projectionMatrix, float tickDelta, double cameraX, double cameraY, double cameraZ, CallbackInfo ci) {
// get the partial ticks since renderChunkLayer doesn't
// have access to them
previousPartialTicks = tickDelta;
}
#endif
// TODO: Can we move this o forge's client proxy simmilar to how fabric does it
// TODO: Can we move this to forge's client proxy similarly to how fabric does it
#if PRE_MC_1_17_1
@Inject(at = @At("HEAD"),
method = "renderChunkLayer(Lnet/minecraft/client/renderer/RenderType;Lcom/mojang/blaze3d/vertex/PoseStack;DDD)V",
@@ -129,20 +109,37 @@ public class MixinLevelRenderer
private void renderChunkLayer(RenderType renderType, PoseStack modelViewMatrixStack, double cameraXBlockPos, double cameraYBlockPos, double cameraZBlockPos, Matrix4f projectionMatrix, CallbackInfo callback)
#endif
{
// get MC's model view and projection matrices
#if MC_1_16_5
// get the matrices from the OpenGL fixed pipeline
float[] mcProjMatrixRaw = new float[16];
GL15.glGetFloatv(GL15.GL_PROJECTION_MATRIX, mcProjMatrixRaw);
Mat4f mcProjectionMatrix = new Mat4f(mcProjMatrixRaw);
mcProjectionMatrix.transpose();
Mat4f mcModelViewMatrix = McObjectConverter.Convert(matrixStackIn.last().pose());
#else
// get the matrices directly from MC
Mat4f mcModelViewMatrix = McObjectConverter.Convert(modelViewMatrixStack.last().pose());
Mat4f mcProjectionMatrix = McObjectConverter.Convert(projectionMatrix);
#endif
// only render before solid blocks
if (renderType.equals(RenderType.solid()))
{
Mat4f mcModelViewMatrix = McObjectConverter.Convert(modelViewMatrixStack.last().pose());
Mat4f mcProjectionMatrix = McObjectConverter.Convert(projectionMatrix);
ClientApi.INSTANCE.renderLods(ClientLevelWrapper.getWrapper(level), mcModelViewMatrix, mcProjectionMatrix, previousPartialTicks);
// experimental proof-of-concept option
if (Config.Client.Advanced.Graphics.AdvancedGraphics.seamlessOverdraw.get())
{
float[] matrixFloatArray = SeamlessOverdraw.overwriteMinecraftNearFarClipPlanes(projectionMatrix, previousPartialTicks);
float[] matrixFloatArray = SeamlessOverdraw.overwriteMinecraftNearFarClipPlanes(mcProjectionMatrix, previousPartialTicks);
#if PRE_MC_1_19_4
#if MC_1_16_5
SeamlessOverdraw.applyLegacyProjectionMatrix(matrixFloatArray);
#elif PRE_MC_1_19_4
projectionMatrix.load(FloatBuffer.wrap(matrixFloatArray));
#else
projectionMatrix.set(matrixFloatArray);
@@ -13,13 +13,15 @@ import org.spongepowered.asm.mixin.injection.Redirect;
* @author coolGi
*/
@Mixin(TextureUtil.class)
public class MixinTextureUtil {
@Redirect(method = "Lcom/mojang/blaze3d/platform/TextureUtil;prepareImage(Lcom/mojang/blaze3d/platform/NativeImage$InternalGlFormat;IIII)V",
public class MixinTextureUtil
{
@Redirect(method = "prepareImage(Lcom/mojang/blaze3d/platform/NativeImage$InternalGlFormat;IIII)V",
at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/platform/GlStateManager;_texParameter(IIF)V"), remap=false)
private static void setLodBias(int target, int pname, float param)
{
float biasValue = Config.Client.Advanced.Graphics.AdvancedGraphics.lodBias.get().floatValue();
if (biasValue != 0) {
if (biasValue != 0)
{
// The target is GL11.GL_TEXTURE_2D
// And the pname is GL14.GL_TEXTURE_LOD_BIAS
GlStateManager._texParameter(target, pname, biasValue);
@@ -3,7 +3,13 @@ package com.seibel.distanthorizons.forge.mixins.server;
import net.minecraft.world.level.chunk.ChunkGenerator;
import org.spongepowered.asm.mixin.Mixin;
#if PRE_MC_1_17_1
#if MC_1_16_5
@Mixin(ChunkGenerator.class)
class MixinTFChunkGenerator
{
// not currently implemented, attempting to run with the mod enabled in the IDE causes the game to lock up
}
#elif PRE_MC_1_17_1
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@@ -14,11 +20,11 @@ import java.util.Random;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
@Mixin(FeatureGenerator.class)
public class MixinTFChunkGenerator {
public class MixinTFChunkGenerator
{
@Redirect(method = "decorate("
+ "Lnet/minecraft/world/level/StructureFeatureManager;"
@@ -51,6 +57,5 @@ public class MixinTFChunkGenerator {
#else
@Mixin(ChunkGenerator.class)
class MixinTFChunkGenerator {
}
class MixinTFChunkGenerator { }
#endif
@@ -32,7 +32,7 @@ import java.util.concurrent.Semaphore;
/**
* Why does this exist? But okay! (Will be probably removed when the experimental generator is done)
* FIXME: Recheck this
* FIXME: Recheck this // STILL check this
*/
@Mixin(ThreadingDetector.class)
public class MixinThreadingDetector {
@@ -47,6 +47,9 @@ public class MixinThreadingDetector {
}
#else
import net.minecraft.world.level.chunk.ChunkGenerator;
@Mixin(ChunkGenerator.class)
public class MixinThreadingDectector {}
public class MixinThreadingDetector { }
#endif
+1 -1
View File
@@ -18,7 +18,7 @@ mod_issues=https://gitlab.com/jeseibel/minecraft-lod-mod/-/issues
mod_discord=https://discord.gg/xAB8G4cENx
# Global Plugin Versions
manifold_version=2023.1.10
manifold_version=2023.1.11
toml_version=3.6.4
lz4_version=1.8.0
nightconfig_version=3.6.6
+1 -1
View File
@@ -80,7 +80,7 @@ project(":api").projectDir = file('coreSubProjects/api')
include("common")
// Enables or disables the subprojects depending on whats in the versionProperties/mcVer.properties
for (loader in ((String) gradle.builds_for).split(",")) {
include(loader)
include(loader.strip()) // Strip it in case a space is added before or after the comma
}
//if (gradle.builds_for.contains("fabric") || gradle.builds_for.contains("quilt"))
// include("fabricLike")
+4 -3
View File
@@ -16,7 +16,7 @@ fabric_api_version=0.42.0+1.16
lithium_version=mc1.16.5-0.6.6
sodium_version=mc1.16.5-0.2.0
iris_version=1.16.x-v1.2.5
bclib_version=0.1.41
bclib_version=
immersive_portals_version=
canvas_version=
@@ -29,6 +29,7 @@ fabric_api_version=0.42.0+1.16
enable_lithium=0
enable_sodium=1
enable_iris=0
# not available via github, use curse.maven if necessary
enable_bclib=0
enable_immersive_portals=0
enable_canvas=0
@@ -37,12 +38,12 @@ fabric_api_version=0.42.0+1.16
forge_version=36.2.39
# Forge mod versions
starlight_version_forge=
terraforged_version=3285909
terraforged_version=4044290
# 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=2
enable_terraforged=1
enable_terrafirmacraft=0
+1 -1
View File
@@ -14,7 +14,7 @@ fabric_api_version=0.85.0+1.20.1
starlight_version_fabric=
phosphor_version_fabric=
lithium_version=
sodium_version=mc1.20-0.4.10
sodium_version=mc1.20.1-0.5.0
iris_version=1.6.4+1.20.1
bclib_version=3.0.12
immersive_portals_version=