diff --git a/.gitmodules b/.gitmodules index 17c60bca6..4998a410e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "core"] path = core url = https://gitlab.com/jeseibel/distant-horizons-core.git +[submodule "Core"] + url = https://gitlab.com/jeseibel/distant-horizons-core + branch = main diff --git a/common/src/main/java/com/seibel/lod/common/Config.java b/common/src/main/java/com/seibel/lod/common/Config.java index 4b3593810..25c7f4f0f 100644 --- a/common/src/main/java/com/seibel/lod/common/Config.java +++ b/common/src/main/java/com/seibel/lod/common/Config.java @@ -124,6 +124,11 @@ public class Config public static String _dropoffQuality = IQuality.DROPOFF_QUALITY_DESC; @ConfigAnnotations.Entry public static DropoffQuality dropoffQuality = IQuality.DROPOFF_QUALITY_DEFAULT; + + @ConfigAnnotations.FileComment + public static String _lodBiomeBlending = IQuality.LOD_BIOME_BLENDING_DESC; + @ConfigAnnotations.Entry(minValue = 0, maxValue = 7) + public static int lodBiomeBlending = IQuality.LOD_BIOME_BLENDING_MIN_DEFAULT_MAX.defaultValue; } diff --git a/common/src/main/java/com/seibel/lod/common/wrappers/block/BlockDetailWrapper.java b/common/src/main/java/com/seibel/lod/common/wrappers/block/BlockDetailWrapper.java index 8b4ff8bf2..ec1d004ad 100644 --- a/common/src/main/java/com/seibel/lod/common/wrappers/block/BlockDetailWrapper.java +++ b/common/src/main/java/com/seibel/lod/common/wrappers/block/BlockDetailWrapper.java @@ -2,34 +2,58 @@ package com.seibel.lod.common.wrappers.block; import java.util.Arrays; import java.util.List; +import java.util.Optional; import java.util.Random; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Stream; +import com.seibel.lod.common.Config; import com.seibel.lod.common.wrappers.McObjectConverter; import com.seibel.lod.common.wrappers.chunk.ChunkWrapper; +import com.seibel.lod.core.api.ApiShared; import com.seibel.lod.core.enums.LodDirection; +import com.seibel.lod.core.handlers.dependencyInjection.SingletonHandler; import com.seibel.lod.core.util.ColorUtil; import com.seibel.lod.core.wrapperInterfaces.block.AbstractBlockPosWrapper; import com.seibel.lod.core.wrapperInterfaces.block.IBlockDetailWrapper; import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper; +import com.seibel.lod.core.wrapperInterfaces.config.ILodConfigWrapperSingleton; +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; +import net.minecraft.Util; import net.minecraft.client.Minecraft; +import net.minecraft.client.color.block.BlockTintCache; +import net.minecraft.client.renderer.BiomeColors; import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.core.BlockPos; +import net.minecraft.core.Cursor3D; import net.minecraft.core.Direction; -import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.*; +import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.FlowerBlock; import net.minecraft.world.level.block.LeavesBlock; import net.minecraft.world.level.block.RenderShape; import net.minecraft.world.level.block.RotatedPillarBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.lighting.LevelLightEngine; +import net.minecraft.world.level.material.FluidState; import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.shapes.VoxelShape; +import org.jetbrains.annotations.Nullable; public class BlockDetailWrapper extends IBlockDetailWrapper { + private static final ILodConfigWrapperSingleton CONFIG = SingletonHandler.get(ILodConfigWrapperSingleton.class); + public static final int FLOWER_COLOR_SCALE = 5; public static final Random random = new Random(0); @@ -195,7 +219,7 @@ public class BlockDetailWrapper extends IBlockDetailWrapper double zWidth = (bbox.maxZ - bbox.minZ); noFullFace = xWidth < 1 && zWidth < 1 && yWidth < 1; } - } else { // Liquad Block + } else { // Liquid Block dontOccludeFaces = new boolean[6]; } isShapeResolved = true; @@ -232,7 +256,14 @@ public class BlockDetailWrapper extends IBlockDetailWrapper isColorResolved = true; } - + private BlockAndTintGetter wrapColorResolver(LevelReader level) { + int blendDistance = CONFIG.client().graphics().quality().getLodBiomeBlending(); + if (blendDistance == 0) { + return new TintGetterOverrideFast(level); + } else { + return new TintGetterOverrideSmooth(level, blendDistance); + } + } @Override public int getAndResolveFaceColor(LodDirection dir, IChunkWrapper chunk, AbstractBlockPosWrapper blockPos) @@ -241,7 +272,7 @@ public class BlockDetailWrapper extends IBlockDetailWrapper resolveColors(); if (!needPostTinting) return baseColor; int tintColor = Minecraft.getInstance().getBlockColors() - .getColor(state, ((ChunkWrapper)chunk).getColorResolver(), + .getColor(state, wrapColorResolver(((ChunkWrapper)chunk).getColorResolver()), McObjectConverter.Convert(blockPos), tintIndex); if (tintColor == -1) return baseColor; return ColorUtil.multiplyARGBwithRGB(baseColor, tintColor); diff --git a/common/src/main/java/com/seibel/lod/common/wrappers/block/TintGetterOverrideFast.java b/common/src/main/java/com/seibel/lod/common/wrappers/block/TintGetterOverrideFast.java new file mode 100644 index 000000000..8be87ce91 --- /dev/null +++ b/common/src/main/java/com/seibel/lod/common/wrappers/block/TintGetterOverrideFast.java @@ -0,0 +1,196 @@ +package com.seibel.lod.common.wrappers.block; + +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; +import net.minecraft.Util; +import net.minecraft.client.color.block.BlockTintCache; +import net.minecraft.client.renderer.BiomeColors; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Cursor3D; +import net.minecraft.core.Direction; +import net.minecraft.world.level.*; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.lighting.LevelLightEngine; +import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +import net.minecraft.world.phys.shapes.VoxelShape; +import org.jetbrains.annotations.Nullable; + +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Supplier; +import java.util.stream.Stream; + +public class TintGetterOverrideFast implements BlockAndTintGetter { + LevelReader parent; + private final Object2ObjectArrayMap> tintCaches; + + public TintGetterOverrideFast(LevelReader parent) { + this.parent = parent; + this.tintCaches = Util.make(new Object2ObjectArrayMap(3), object2ObjectArrayMap -> { + object2ObjectArrayMap.put(BiomeColors.GRASS_COLOR_RESOLVER, new ConcurrentHashMap()); + object2ObjectArrayMap.put(BiomeColors.FOLIAGE_COLOR_RESOLVER, new ConcurrentHashMap()); + object2ObjectArrayMap.put(BiomeColors.WATER_COLOR_RESOLVER, new ConcurrentHashMap()); + }); + } + + private Biome _getBiome(BlockPos pos) { + #if MC_VERSION_1_18_2 + return parent.getBiome(pos).value(); + #elif MC_VERSION_1_18_1 + return parent.getBiome(pos); + #endif + } + + @Override + public int getBlockTint(BlockPos blockPos, ColorResolver colorResolver) { + Biome b = _getBiome(blockPos); + return tintCaches.get(colorResolver).computeIfAbsent(b, (key) -> colorResolver.getColor(b, blockPos.getX(), blockPos.getZ())); + } + + @Override + public float getShade(Direction direction, boolean bl) { + return parent.getShade(direction, bl); + } + + @Override + public LevelLightEngine getLightEngine() { + return parent.getLightEngine(); + } + + @Override + public int getBrightness(LightLayer lightLayer, BlockPos blockPos) { + return parent.getBrightness(lightLayer, blockPos); + } + + @Override + public int getRawBrightness(BlockPos blockPos, int i) { + return parent.getRawBrightness(blockPos, i); + } + + @Override + public boolean canSeeSky(BlockPos blockPos) { + return parent.canSeeSky(blockPos); + } + + @Override + @Nullable + public BlockEntity getBlockEntity(BlockPos blockPos) { + return parent.getBlockEntity(blockPos); + } + + @Override + public Optional getBlockEntity(BlockPos blockPos, BlockEntityType blockEntityType) { + return parent.getBlockEntity(blockPos, blockEntityType); + } + + @Override + public BlockState getBlockState(BlockPos blockPos) { + return parent.getBlockState(blockPos); + } + + @Override + public FluidState getFluidState(BlockPos blockPos) { + return parent.getFluidState(blockPos); + } + + @Override + public int getLightEmission(BlockPos blockPos) { + return parent.getLightEmission(blockPos); + } + + @Override + public int getMaxLightLevel() { + return parent.getMaxLightLevel(); + } + + @Override + public Stream getBlockStates(AABB aABB) { + return parent.getBlockStates(aABB); + } + + @Override + public BlockHitResult isBlockInLine(ClipBlockStateContext clipBlockStateContext) { + return parent.isBlockInLine(clipBlockStateContext); + } + + @Override + public BlockHitResult clip(ClipContext clipContext) { + return parent.clip(clipContext); + } + + @Override + @Nullable + public BlockHitResult clipWithInteractionOverride(Vec3 vec3, Vec3 vec32, BlockPos blockPos, VoxelShape voxelShape, BlockState blockState) { + return parent.clipWithInteractionOverride(vec3, vec32, blockPos, voxelShape, blockState); + } + + @Override + public double getBlockFloorHeight(VoxelShape voxelShape, Supplier supplier) { + return parent.getBlockFloorHeight(voxelShape, supplier); + } + + @Override + public double getBlockFloorHeight(BlockPos blockPos) { + return parent.getBlockFloorHeight(blockPos); + } + + @Override + public int getHeight() { + return parent.getHeight(); + } + + @Override + public int getMinBuildHeight() { + return parent.getMinBuildHeight(); + } + + @Override + public int getMaxBuildHeight() { + return parent.getMaxBuildHeight(); + } + + @Override + public int getSectionsCount() { + return parent.getSectionsCount(); + } + + @Override + public int getMinSection() { + return parent.getMinSection(); + } + + @Override + public int getMaxSection() { + return parent.getMaxSection(); + } + + @Override + public boolean isOutsideBuildHeight(BlockPos blockPos) { + return parent.isOutsideBuildHeight(blockPos); + } + + @Override + public boolean isOutsideBuildHeight(int i) { + return parent.isOutsideBuildHeight(i); + } + + @Override + public int getSectionIndex(int i) { + return parent.getSectionIndex(i); + } + + @Override + public int getSectionIndexFromSectionY(int i) { + return parent.getSectionIndexFromSectionY(i); + } + + @Override + public int getSectionYFromSectionIndex(int i) { + return parent.getSectionYFromSectionIndex(i); + } +} diff --git a/common/src/main/java/com/seibel/lod/common/wrappers/block/TintGetterOverrideSmooth.java b/common/src/main/java/com/seibel/lod/common/wrappers/block/TintGetterOverrideSmooth.java new file mode 100644 index 000000000..760f35aad --- /dev/null +++ b/common/src/main/java/com/seibel/lod/common/wrappers/block/TintGetterOverrideSmooth.java @@ -0,0 +1,219 @@ +package com.seibel.lod.common.wrappers.block; + +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; +import net.minecraft.Util; +import net.minecraft.client.color.block.BlockTintCache; +import net.minecraft.client.renderer.BiomeColors; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Cursor3D; +import net.minecraft.core.Direction; +import net.minecraft.world.level.*; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.lighting.LevelLightEngine; +import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +import net.minecraft.world.phys.shapes.VoxelShape; +import org.jetbrains.annotations.Nullable; + +import java.util.Optional; +import java.util.function.Supplier; +import java.util.stream.Stream; + +public class TintGetterOverrideSmooth implements BlockAndTintGetter { + LevelReader parent; + private final Object2ObjectArrayMap tintCaches; + public int smoothingRange; + + public TintGetterOverrideSmooth(LevelReader parent, int smoothingRange) { + this.parent = parent; + this.smoothingRange = smoothingRange; + this.tintCaches = Util.make(new Object2ObjectArrayMap(3), object2ObjectArrayMap -> { + object2ObjectArrayMap.put(BiomeColors.GRASS_COLOR_RESOLVER, new BlockTintCache((pos) -> calculateBlockTint(pos, BiomeColors.GRASS_COLOR_RESOLVER))); + object2ObjectArrayMap.put(BiomeColors.FOLIAGE_COLOR_RESOLVER, new BlockTintCache((pos) -> calculateBlockTint(pos, BiomeColors.FOLIAGE_COLOR_RESOLVER))); + object2ObjectArrayMap.put(BiomeColors.WATER_COLOR_RESOLVER, new BlockTintCache((pos) -> calculateBlockTint(pos, BiomeColors.WATER_COLOR_RESOLVER))); + }); + } + + private Biome _getBiome(BlockPos pos) { + #if MC_VERSION_1_18_2 + return parent.getBiome(pos).value(); + #elif MC_VERSION_1_18_1 + return parent.getBiome(pos); + #endif + } + + public int calculateBlockTint(BlockPos blockPos, ColorResolver colorResolver) + { + int i = smoothingRange; + if (i == 0) + return colorResolver.getColor(_getBiome(blockPos), blockPos.getX(), blockPos.getZ()); + int j = (i * 2 + 1) * (i * 2 + 1); + int k = 0; + int l = 0; + int m = 0; + Cursor3D cursor3D = new Cursor3D(blockPos.getX() - i, blockPos.getY(), blockPos.getZ() - i, blockPos.getX() + i, blockPos.getY(), blockPos.getZ() + i); + BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos(); + while (cursor3D.advance()) + { + mutableBlockPos.set(cursor3D.nextX(), cursor3D.nextY(), cursor3D.nextZ()); + int n = colorResolver.getColor(_getBiome(mutableBlockPos), mutableBlockPos.getX(), mutableBlockPos.getZ()); + k += (n & 0xFF0000) >> 16; + l += (n & 0xFF00) >> 8; + m += n & 0xFF; + } + return (k / j & 0xFF) << 16 | (l / j & 0xFF) << 8 | m / j & 0xFF; + } + + @Override + public int getBlockTint(BlockPos blockPos, ColorResolver colorResolver) { + BlockTintCache blockTintCache = this.tintCaches.get(colorResolver); + return blockTintCache.getColor(blockPos); + } + + @Override + public float getShade(Direction direction, boolean bl) { + return parent.getShade(direction, bl); + } + + @Override + public LevelLightEngine getLightEngine() { + return parent.getLightEngine(); + } + + @Override + public int getBrightness(LightLayer lightLayer, BlockPos blockPos) { + return parent.getBrightness(lightLayer, blockPos); + } + + @Override + public int getRawBrightness(BlockPos blockPos, int i) { + return parent.getRawBrightness(blockPos, i); + } + + @Override + public boolean canSeeSky(BlockPos blockPos) { + return parent.canSeeSky(blockPos); + } + + @Override + @Nullable + public BlockEntity getBlockEntity(BlockPos blockPos) { + return parent.getBlockEntity(blockPos); + } + + @Override + public Optional getBlockEntity(BlockPos blockPos, BlockEntityType blockEntityType) { + return parent.getBlockEntity(blockPos, blockEntityType); + } + + @Override + public BlockState getBlockState(BlockPos blockPos) { + return parent.getBlockState(blockPos); + } + + @Override + public FluidState getFluidState(BlockPos blockPos) { + return parent.getFluidState(blockPos); + } + + @Override + public int getLightEmission(BlockPos blockPos) { + return parent.getLightEmission(blockPos); + } + + @Override + public int getMaxLightLevel() { + return parent.getMaxLightLevel(); + } + + @Override + public Stream getBlockStates(AABB aABB) { + return parent.getBlockStates(aABB); + } + + @Override + public BlockHitResult isBlockInLine(ClipBlockStateContext clipBlockStateContext) { + return parent.isBlockInLine(clipBlockStateContext); + } + + @Override + public BlockHitResult clip(ClipContext clipContext) { + return parent.clip(clipContext); + } + + @Override + @Nullable + public BlockHitResult clipWithInteractionOverride(Vec3 vec3, Vec3 vec32, BlockPos blockPos, VoxelShape voxelShape, BlockState blockState) { + return parent.clipWithInteractionOverride(vec3, vec32, blockPos, voxelShape, blockState); + } + + @Override + public double getBlockFloorHeight(VoxelShape voxelShape, Supplier supplier) { + return parent.getBlockFloorHeight(voxelShape, supplier); + } + + @Override + public double getBlockFloorHeight(BlockPos blockPos) { + return parent.getBlockFloorHeight(blockPos); + } + + @Override + public int getHeight() { + return parent.getHeight(); + } + + @Override + public int getMinBuildHeight() { + return parent.getMinBuildHeight(); + } + + @Override + public int getMaxBuildHeight() { + return parent.getMaxBuildHeight(); + } + + @Override + public int getSectionsCount() { + return parent.getSectionsCount(); + } + + @Override + public int getMinSection() { + return parent.getMinSection(); + } + + @Override + public int getMaxSection() { + return parent.getMaxSection(); + } + + @Override + public boolean isOutsideBuildHeight(BlockPos blockPos) { + return parent.isOutsideBuildHeight(blockPos); + } + + @Override + public boolean isOutsideBuildHeight(int i) { + return parent.isOutsideBuildHeight(i); + } + + @Override + public int getSectionIndex(int i) { + return parent.getSectionIndex(i); + } + + @Override + public int getSectionIndexFromSectionY(int i) { + return parent.getSectionIndexFromSectionY(i); + } + + @Override + public int getSectionYFromSectionIndex(int i) { + return parent.getSectionYFromSectionIndex(i); + } +} diff --git a/common/src/main/java/com/seibel/lod/common/wrappers/config/LodConfigWrapperSingleton.java b/common/src/main/java/com/seibel/lod/common/wrappers/config/LodConfigWrapperSingleton.java index 789c7e686..6bc9ce8f3 100644 --- a/common/src/main/java/com/seibel/lod/common/wrappers/config/LodConfigWrapperSingleton.java +++ b/common/src/main/java/com/seibel/lod/common/wrappers/config/LodConfigWrapperSingleton.java @@ -195,6 +195,17 @@ public class LodConfigWrapperSingleton implements ILodConfigWrapperSingleton ConfigGui.editSingleOption.getEntry("client.graphics.quality.dropoffQuality").value = newDropoffQuality; ConfigGui.editSingleOption.saveOption("client.graphics.quality.dropoffQuality"); } + + @Override + public int getLodBiomeBlending() { + return Config.Client.Graphics.Quality.lodBiomeBlending; + } + + @Override + public void setLodBiomeBlending(int newLodBiomeBlending) { + ConfigGui.editSingleOption.getEntry("client.graphics.quality.lodBiomeBlending").value = newLodBiomeBlending; + ConfigGui.editSingleOption.saveOption("client.graphics.quality.lodBiomeBlending"); + } } diff --git a/core b/core index c9cabd8a3..8a1d3c2d3 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit c9cabd8a321a63cbd971bfae41b54d224feb43c2 +Subproject commit 8a1d3c2d3f3ed1e4fbb1ef2fce655e9aa0a58152