Add the ability to cull lilly pads, seaGrass, etc.

This commit is contained in:
James Seibel
2026-03-15 20:53:21 -05:00
parent 5933ef8245
commit da2454b249
5 changed files with 152 additions and 44 deletions
@@ -745,57 +745,56 @@ public class Config
+ "Disable this if shadows render incorrectly.")
.build();
public static ConfigUISpacer ignoreCsvStartSpacer = new ConfigUISpacer.Builder().build();
public static ConfigEntry<String> ignoredRenderBlockCsv = new ConfigEntry.Builder<String>()
.set("minecraft:barrier,minecraft:structure_void,minecraft:light,minecraft:tripwire,minecraft:brown_mushroom")
.setAppearance(EConfigEntryAppearance.ALL)
.addListener(RenderBlockCacheCsvHandler.INSTANCE)
.comment(""
+ "A comma separated list of block resource locations that won't be rendered by DH. \n"
+ "Air is always included in this list. \n"
+ "Requires a restart to change. \n"
+ "\n"
+ "Note:\n"
+ "If you see gaps, or holes you may have to change\n"
+ "worldCompression to ["+EDhApiWorldCompressionMode.MERGE_SAME_BLOCKS+"] and re-generate the LODs.\n"
+ "Black spots may happen occur to block lighting being zero for covered blocks.\n"
+ "")
.build();
public static ConfigEntry<String> ignoredRenderCaveBlockCsv = new ConfigEntry.Builder<String>()
.set("") // config is empty since most cave blocks will be automatically ignored due to being: transparent, non-solid, or liquids, but new blocks can be added here if needed
.set("")
.setAppearance(EConfigEntryAppearance.ALL)
.addListener(RenderBlockCacheCsvHandler.INSTANCE)
.comment(""
+ "A comma separated list of block resource locations that shouldn't be rendered \n"
+ "if they are in a 0 sky light underground area. \n"
+ "Air is always included in this list. \n"
+ "Requires a restart to change. \n"
+ "\n"
+ "Defaults to an empty list since most cave blocks will be automatically ignored due to being: \n"
+ "transparent, non-solid, or liquids, but new blocks can be added here if needed.\n"
+ "")
.build();
public static ConfigEntry<String> waterSubSurfaceBlockReplacementCsv = new ConfigEntry.Builder<String>()
.set("minecraft:kelp,minecraft:tall_seagrass,minecraft:seagrass")
.setAppearance(EConfigEntryAppearance.ALL)
.addListener(RenderBlockCacheCsvHandler.INSTANCE)
.comment(""
+ "A comma separated list of block resource locations that will be replaced by water \n"
+ "if they're visible on the water's surface. \n"
+ "")
.build();
public static ConfigEntry<String> waterSurfaceBlockReplacementCsv = new ConfigEntry.Builder<String>()
.set("minecraft:lily_pad")
.setAppearance(EConfigEntryAppearance.ALL)
.addListener(RenderBlockCacheCsvHandler.INSTANCE)
.comment(""
+ "A comma separated list of block resource locations that will be removed \n"
+ "when on top of water. \n"
+ "")
.build();
static
{
ignoredRenderBlockCsv.addListener(new ConfigChangeListener<String>(ignoredRenderBlockCsv,
(blockCsv) ->
{
IWrapperFactory wrapperFactory = SingletonInjector.INSTANCE.get(IWrapperFactory.class);
if (wrapperFactory != null)
{
wrapperFactory.resetRendererIgnoredBlocksSet();
DhApi.Delayed.renderProxy.clearRenderDataCache();
}
}));
ignoredRenderCaveBlockCsv.addListener(new ConfigChangeListener<String>(ignoredRenderCaveBlockCsv,
(blockCsv) ->
{
IWrapperFactory wrapperFactory = SingletonInjector.INSTANCE.get(IWrapperFactory.class);
if (wrapperFactory != null)
{
wrapperFactory.resetRendererIgnoredCaveBlocks();
DhApi.Delayed.renderProxy.clearRenderDataCache();
}
}));
}
}
public static class Experimental
@@ -0,0 +1,69 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.core.config.eventHandlers;
import com.seibel.distanthorizons.api.DhApi;
import com.seibel.distanthorizons.api.enums.config.EDhApiMcRenderingFadeMode;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeRenderEvent;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiCancelableEventParam;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.config.listeners.IConfigListener;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory;
import com.seibel.distanthorizons.coreapi.util.StringUtil;
public class RenderBlockCacheCsvHandler implements IConfigListener
{
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
public static RenderBlockCacheCsvHandler INSTANCE = new RenderBlockCacheCsvHandler();
//=============//
// constructor //
//=============//
/** private since we only ever need one handler at a time */
private RenderBlockCacheCsvHandler() { }
//=================//
// config handling //
//=================//
@Override
public void onConfigValueSet()
{
IWrapperFactory wrapperFactory = SingletonInjector.INSTANCE.get(IWrapperFactory.class);
if (wrapperFactory != null)
{
wrapperFactory.resetCachedIgnoredBlocksSets();
DhApi.Delayed.renderProxy.clearRenderDataCache();
}
}
}
@@ -194,8 +194,12 @@ public class FullDataToRenderDataTransformer
boolean ignoreNonCollidingBlocks = (Config.Client.Advanced.Graphics.Quality.blocksToIgnore.get() == EDhApiBlocksToAvoid.NON_COLLIDING);
boolean colorBelowWithAvoidedBlocks = Config.Client.Advanced.Graphics.Quality.tintWithAvoidedBlocks.get();
ObjectOpenHashSet<IBlockStateWrapper> blockStatesToIgnore = WRAPPER_FACTORY.getRendererIgnoredBlocks(levelWrapper);
ObjectOpenHashSet<IBlockStateWrapper> caveBlockStatesToIgnore = WRAPPER_FACTORY.getRendererIgnoredCaveBlocks(levelWrapper);
final ObjectOpenHashSet<IBlockStateWrapper> blockStatesToIgnore = WRAPPER_FACTORY.getRendererIgnoredBlocks(levelWrapper);
final ObjectOpenHashSet<IBlockStateWrapper> caveBlockStatesToIgnore = WRAPPER_FACTORY.getRendererIgnoredCaveBlocks(levelWrapper);
final ObjectOpenHashSet<IBlockStateWrapper> waterSubsurfaceReplacementBlocks = WRAPPER_FACTORY.getWaterSubsurfaceReplacementBlocks(levelWrapper);
final ObjectOpenHashSet<IBlockStateWrapper> waterSurfaceReplacementBlocks = WRAPPER_FACTORY.getWaterSurfaceReplacementBlocks(levelWrapper);
final IBlockStateWrapper water = WRAPPER_FACTORY.getWaterBlockStateWrapper(levelWrapper);
// build snow block cache if needed
if (snowLayerBlockStates == null)
@@ -223,6 +227,7 @@ public class FullDataToRenderDataTransformer
int colorToApplyToNextBlock = -1;
int lastColor = 0;
int lastBottom = -10_000;
IBlockStateWrapper lastBlock = null;
int skylightToApplyToNextBlock = -1;
int blocklightToApplyToNextBlock = -1;
@@ -283,6 +288,12 @@ public class FullDataToRenderDataTransformer
// cave culling check //
//====================//
if (waterSubsurfaceReplacementBlocks.contains(block)
&& (lastBlock == null || lastBlock.isAir()))
{
block = water;
}
boolean ignoreBlock = blockStatesToIgnore.contains(block);
boolean caveBlock = caveBlockStatesToIgnore.contains(block);
if (caveBlock
@@ -328,6 +339,9 @@ public class FullDataToRenderDataTransformer
else if (ignoreBlock)
{
// this is an ignored block, but shouldn't be merged like a cave block
// applying this sky light to the next block should prevent black spots for opaque covering blocks
skylightToApplyToNextBlock = skyLight;
continue;
}
@@ -343,21 +357,37 @@ public class FullDataToRenderDataTransformer
&& !block.isLiquid()
&& block.getOpacity() != LodUtil.BLOCK_FULLY_OPAQUE;
// merge snow into the block below it
if (snowLayerBlockStates.contains(block))
// handle height reduction
boolean isSnowLayer = snowLayerBlockStates.contains(block);
boolean isWaterSurfaceReplacement = waterSurfaceReplacementBlocks.contains(block);
if (isSnowLayer || isWaterSurfaceReplacement)
{
// sometimes a snow datapoint will be multiple blocks tall,
if (isWaterSurfaceReplacement)
{
// replace the block with water
block = WRAPPER_FACTORY.getWaterBlockStateWrapper(levelWrapper);
}
// sometimes a datapoint will be multiple blocks tall,
// in that case we just want to drop the top by 1
blockHeight -= 1;
if (blockHeight == 0)
{
// this snow block was entirely removed, just color the block below it
// this block was entirely removed, just color the block below it
ignoreNonSolidBlock = true;
// snow is a special case where it should always tint the block
// below it, if not done grass will appear as gray
int snowColor = levelWrapper.getBlockColor(mutableBlockPos, biome, fullDataSource, block);
colorToApplyToNextBlock = ColorUtil.setAlpha(snowColor, 255);
if (isSnowLayer)
{
// snow is a special case where it should always tint the block
// below it, if not done grass will appear as gray
int snowColor = levelWrapper.getBlockColor(mutableBlockPos, biome, fullDataSource, block);
colorToApplyToNextBlock = ColorUtil.setAlpha(snowColor, 255);
}
else //if (isWaterSurfaceReplacement)
{
colorToApplyToNextBlock = levelWrapper.getBlockColor(mutableBlockPos, biome, fullDataSource, block);
}
}
}
@@ -449,6 +479,7 @@ public class FullDataToRenderDataTransformer
}
lastBottom = bottomY;
lastColor = color;
lastBlock = block;
}
@@ -65,6 +65,7 @@ public interface IWrapperFactory extends IDhApiWrapperFactory, IBindable
IBlockStateWrapper deserializeBlockStateWrapper(String str, ILevelWrapper levelWrapper) throws IOException;
IBlockStateWrapper getAirBlockStateWrapper();
IBlockStateWrapper getWaterBlockStateWrapper(ILevelWrapper levelWrapper);
default IBlockStateWrapper deserializeBlockStateWrapperOrGetDefault(String str, ILevelWrapper levelWrapper)
{
IBlockStateWrapper blockState;
@@ -92,10 +93,10 @@ public interface IWrapperFactory extends IDhApiWrapperFactory, IBindable
*/
ObjectOpenHashSet<IBlockStateWrapper> getRendererIgnoredCaveBlocks(ILevelWrapper levelWrapper);
ObjectOpenHashSet<IBlockStateWrapper> getWaterSubsurfaceReplacementBlocks(ILevelWrapper levelWrapper);
ObjectOpenHashSet<IBlockStateWrapper> getWaterSurfaceReplacementBlocks(ILevelWrapper levelWrapper);
/** clears the cached values */
void resetRendererIgnoredCaveBlocks();
/** clears the cached values */
void resetRendererIgnoredBlocksSet();
void resetCachedIgnoredBlocksSets();
/**
@@ -391,12 +391,20 @@
"distanthorizons.config.client.advanced.graphics.culling.ignoredRenderBlockCsv":
"Ignored Block CSV",
"distanthorizons.config.client.advanced.graphics.culling.ignoredRenderBlockCsv.@tooltip":
"A comma separated list of block resource locations that won't be rendered by DH. \nNote: air is always included in this list.",
"A comma separated list of block resource locations that won't be rendered by DH. \nAir is always included in this list. \n\nNote: \nIf you see gaps, or holes you may have to change \nworldCompression to [MERGE_SAME_BLOCKS] and re-generate the LODs.",
"distanthorizons.config.client.advanced.graphics.culling.ignoredRenderCaveBlockCsv":
"Ignored Cave Block CSV",
"distanthorizons.config.client.advanced.graphics.culling.ignoredRenderCaveBlockCsv.@tooltip":
"A comma separated list of block resource locations that shouldn't be rendered \nif they are in a 0 sky light underground area. \nNote: air is always included in this list.",
"A comma separated list of block resource locations that shouldn't be rendered \nif they are in a 0 sky light underground area. \nAir is always included in this list. \n\nDefaults to an empty list since most cave blocks will be automatically ignored due to being: \ntransparent, non-solid, or liquids, but new blocks can be added here if needed.",
"distanthorizons.config.client.advanced.graphics.culling.waterSubSurfaceBlockReplacementCsv":
"Water Sub-Surface Replacement",
"distanthorizons.config.client.advanced.graphics.culling.waterSubSurfaceBlockReplacementCsv.@tooltip":
"A comma separated list of block resource locations that will be replaced by water \nif they're visible on the water's surface.",
"distanthorizons.config.client.advanced.graphics.culling.waterSurfaceBlockReplacementCsv":
"Water Surface Replacement",
"distanthorizons.config.client.advanced.graphics.culling.waterSurfaceBlockReplacementCsv.@tooltip":
"A comma separated list of block resource locations that will be removed \nwhen on top of water.",
"distanthorizons.config.client.advanced.graphics.overrideVanillaGraphicsSettings":
"Override Vanilla Settings",
"distanthorizons.config.client.advanced.graphics.overrideVanillaGraphicsSettings.@tooltip":