From 2f686057f3f1b12839780218afd451b545897486 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 27 Jul 2024 09:30:51 -0500 Subject: [PATCH 01/11] Fix ice/water vertical LOD lighting --- coreSubProjects | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreSubProjects b/coreSubProjects index d38711ca4..19d8c89bd 160000 --- a/coreSubProjects +++ b/coreSubProjects @@ -1 +1 @@ -Subproject commit d38711ca4bee9ec8bb1f9a6067993a851a66f41f +Subproject commit 19d8c89bd8d5e157d8ce8dfe6e19a99fcec0835c From 31b57fae503f69a8b49f0d716e9ced2a2dc846b7 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 27 Jul 2024 16:24:31 -0500 Subject: [PATCH 02/11] fix 1.16.5 compiling --- .../common/wrappers/block/BlockStateWrapper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/BlockStateWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/BlockStateWrapper.java index a72505ee9..427386891 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/BlockStateWrapper.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/BlockStateWrapper.java @@ -233,7 +233,7 @@ public class BlockStateWrapper implements IBlockStateWrapper String ignoreBlockCsv = config.get(); if (ignoreBlockCsv != null) { - blockStringList.addAll(List.of(ignoreBlockCsv.split(","))); + blockStringList.addAll(Arrays.asList(ignoreBlockCsv.split(","))); } return getBlockWrappers(blockStringList, levelWrapper); From de05a5f674b20ff8909c48dd77fad815c048e1b7 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 27 Jul 2024 16:25:27 -0500 Subject: [PATCH 03/11] Refactor and cleanup ClientBlockStateCache --- .../block/cache/ClientBlockDetailMap.java | 27 +- .../block/cache/ClientBlockStateCache.java | 391 ++++++++++-------- 2 files changed, 241 insertions(+), 177 deletions(-) diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ClientBlockDetailMap.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ClientBlockDetailMap.java index e05b1a966..6fb510855 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ClientBlockDetailMap.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ClientBlockDetailMap.java @@ -29,20 +29,29 @@ import java.util.concurrent.ConcurrentHashMap; public class ClientBlockDetailMap { private final ConcurrentHashMap blockCache = new ConcurrentHashMap<>(); - //private final ConcurrentHashMap<#if MC_VER < MC_1_18_2 Biome #else Holder #endif, Biome> biomeMap = new ConcurrentHashMap<>(); private final ClientLevelWrapper level; + + + + //=============// + // constructor // + //=============// + public ClientBlockDetailMap(ClientLevelWrapper level) { this.level = level; } - public ClientBlockStateCache getBlockStateData(BlockState state, DhBlockPos pos) - { //TODO: Allow a per pos unique setting - return blockCache.computeIfAbsent(state, (s) -> new ClientBlockStateCache(s, level, pos)); - } - public void clear() { blockCache.clear(); } + + //=========// + // methods // + //=========// + + public ClientBlockStateCache getBlockStateData(BlockState blockState) + { return this.blockCache.computeIfAbsent(blockState, (block) -> new ClientBlockStateCache(block, this.level)); } public int getColor(BlockState state, BiomeWrapper biome, DhBlockPos pos) - { - return getBlockStateData(state, pos).getAndResolveFaceColor(biome, pos); - } + { return this.getBlockStateData(state).getAndResolveFaceColor(biome, pos); } + + public void clear() { this.blockCache.clear(); } + } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ClientBlockStateCache.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ClientBlockStateCache.java index 52b81458c..673d975cb 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ClientBlockStateCache.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ClientBlockStateCache.java @@ -50,7 +50,9 @@ import java.util.HashSet; import java.util.List; /** - * @version 2022-9-16 + * This keeps track of the color each block state should be for a given level. + * + * @see ColorUtil */ public class ClientBlockStateCache { @@ -59,62 +61,42 @@ public class ClientBlockStateCache private static final HashSet BLOCK_STATES_THAT_NEED_LEVEL = new HashSet<>(); private static final HashSet BROKEN_BLOCK_STATES = new HashSet<>(); + /** This is the order each direction on a block is processed when attempting to get the texture/color */ + private static final Direction[] COLOR_RESOLUTION_DIRECTION_ORDER = { Direction.UP, Direction.NORTH, Direction.EAST, Direction.WEST, Direction.SOUTH, Direction.DOWN }; + + private static final int FLOWER_COLOR_SCALE = 5; + + + #if MC_VER < MC_1_19_2 - public static final Random random = new Random(0); + private static final Random random = new Random(0); #else - public static final RandomSource random = RandomSource.create(); + private static final RandomSource random = RandomSource.create(); #endif - public final IClientLevelWrapper levelWrapper; - public final BlockState blockState; - public final LevelReader level; - public final BlockPos pos; + private final IClientLevelWrapper levelWrapper; + private final BlockState blockState; + private final LevelReader level; + + private boolean isColorResolved = false; + private int baseColor = 0; + private boolean needShade = true; + private boolean needPostTinting = false; + private int tintIndex = 0; - public ClientBlockStateCache(BlockState blockState, IClientLevelWrapper samplingLevel, DhBlockPos samplingPos) - { - this.blockState = blockState; - this.levelWrapper = samplingLevel; - this.level = (LevelReader) samplingLevel.getWrappedMcObject(); - this.pos = McObjectConverter.Convert(samplingPos); - this.resolveColors(); - //LOGGER.info("ClientBlocKCache created for {}", blockState); - } + //===========// + // constants // + //===========// - boolean isColorResolved = false; - int baseColor = 0; //TODO: Impl per-face color - boolean needShade = true; - boolean needPostTinting = false; - int tintIndex = 0; + private static final int MIN_SRGB_BITS = 0x39000000; // 2^(-13) + private static final int MAX_SRGB_BITS = 0x3f7fffff; // 1.0 - f32::EPSILON + private static final float MIN_SRGB_BOUND = Float.intBitsToFloat(MIN_SRGB_BITS); + private static final float MAX_SRGB_BOUND = Float.intBitsToFloat(MAX_SRGB_BITS); - - public static final int FLOWER_COLOR_SCALE = 5; - - enum ColorMode - { - Default, - Flower, - Leaves, - Chisel, - Glass; - static ColorMode getColorMode(Block b) + private static final int[] linearToSrgbTable = new int[] { - if (b instanceof LeavesBlock) return Leaves; - if (b instanceof FlowerBlock) return Flower; - if (b.toString().contains("glass")) return Glass; - if (b.toString().equals("Block{chiselsandbits:chiseled}")) return Chisel; - return Default; - } - } - - //Way to efficiently do this was suggested by IMS from sodium. This is where those numbers and support code was lifted from. - private static final int MIN_BITS = 0x39000000; // 2^(-13) - private static final int MAX_BITS = 0x3f7fffff; // 1.0 - f32::EPSILON - private static final float MIN_BOUND = Float.intBitsToFloat(MIN_BITS); - private static final float MAX_BOUND = Float.intBitsToFloat(MAX_BITS); - - private static final int[] linearToSrgbTable = new int[] { 0x0073000d, 0x007a000d, 0x0080000d, 0x0087000d, 0x008d000d, 0x0094000d, 0x009a000d, 0x00a1000d, 0x00a7001a, 0x00b4001a, 0x00c1001a, 0x00ce001a, 0x00da001a, 0x00e7001a, 0x00f4001a, 0x0101001a, 0x010e0033, 0x01280033, 0x01410033, 0x015b0033, 0x01750033, 0x018f0033, 0x01a80033, 0x01c20033, @@ -128,81 +110,131 @@ public class ClientBlockStateCache 0x31d105b0, 0x34a80555, 0x37520507, 0x39d504c5, 0x3c37048b, 0x3e7c0458, 0x40a8042a, 0x42bd0401, 0x44c20798, 0x488e071e, 0x4c1c06b6, 0x4f76065d, 0x52a50610, 0x55ac05cc, 0x5892058f, 0x5b590559, 0x5e0c0a23, 0x631c0980, 0x67db08f6, 0x6c55087f, 0x70940818, 0x74a007bd, 0x787d076c, 0x7c330723, - }; + }; - private static final float[] srgbToLinearTable = new float[] { - 0.0f, 0.000303527f, 0.000607054f, 0.00091058103f, 0.001214108f, 0.001517635f, 0.0018211621f, 0.002124689f, - 0.002428216f, 0.002731743f, 0.00303527f, 0.0033465356f, 0.003676507f, 0.004024717f, 0.004391442f, - 0.0047769533f, 0.005181517f, 0.0056053917f, 0.0060488326f, 0.006512091f, 0.00699541f, 0.0074990317f, - 0.008023192f, 0.008568125f, 0.009134057f, 0.009721218f, 0.010329823f, 0.010960094f, 0.011612245f, - 0.012286487f, 0.012983031f, 0.013702081f, 0.014443844f, 0.015208514f, 0.015996292f, 0.016807375f, - 0.017641952f, 0.018500218f, 0.019382361f, 0.020288562f, 0.02121901f, 0.022173883f, 0.023153365f, - 0.02415763f, 0.025186857f, 0.026241222f, 0.027320892f, 0.028426038f, 0.029556843f, 0.03071345f, 0.03189604f, - 0.033104774f, 0.03433981f, 0.035601325f, 0.036889452f, 0.038204376f, 0.039546248f, 0.04091521f, 0.042311423f, - 0.043735042f, 0.045186214f, 0.046665095f, 0.048171833f, 0.049706575f, 0.051269468f, 0.052860655f, 0.05448028f, - 0.056128494f, 0.057805434f, 0.05951124f, 0.06124607f, 0.06301003f, 0.06480328f, 0.06662595f, 0.06847818f, - 0.07036011f, 0.07227186f, 0.07421358f, 0.07618539f, 0.07818743f, 0.08021983f, 0.082282715f, 0.084376216f, - 0.086500466f, 0.088655606f, 0.09084173f, 0.09305898f, 0.095307484f, 0.09758736f, 0.09989874f, 0.10224175f, - 0.10461649f, 0.10702311f, 0.10946172f, 0.111932434f, 0.11443538f, 0.116970696f, 0.11953845f, 0.12213881f, - 0.12477186f, 0.12743773f, 0.13013652f, 0.13286836f, 0.13563336f, 0.13843165f, 0.14126332f, 0.1441285f, - 0.1470273f, 0.14995982f, 0.15292618f, 0.1559265f, 0.15896086f, 0.16202943f, 0.16513224f, 0.16826946f, - 0.17144115f, 0.17464745f, 0.17788847f, 0.1811643f, 0.18447503f, 0.1878208f, 0.19120172f, 0.19461787f, - 0.19806935f, 0.2015563f, 0.20507877f, 0.2086369f, 0.21223079f, 0.21586053f, 0.21952623f, 0.22322798f, - 0.22696589f, 0.23074007f, 0.23455065f, 0.23839766f, 0.2422812f, 0.2462014f, 0.25015837f, 0.25415218f, - 0.2581829f, 0.26225072f, 0.26635566f, 0.27049786f, 0.27467737f, 0.27889434f, 0.2831488f, 0.2874409f, - 0.2917707f, 0.29613832f, 0.30054384f, 0.30498737f, 0.30946895f, 0.31398875f, 0.31854683f, 0.32314324f, - 0.32777813f, 0.33245158f, 0.33716366f, 0.34191445f, 0.3467041f, 0.3515327f, 0.35640025f, 0.36130688f, - 0.3662527f, 0.37123778f, 0.37626222f, 0.3813261f, 0.38642952f, 0.39157256f, 0.3967553f, 0.40197787f, - 0.4072403f, 0.4125427f, 0.41788515f, 0.42326775f, 0.42869055f, 0.4341537f, 0.43965724f, 0.44520125f, - 0.45078585f, 0.45641106f, 0.46207705f, 0.46778384f, 0.47353154f, 0.47932023f, 0.48514998f, 0.4910209f, - 0.49693304f, 0.5028866f, 0.50888145f, 0.5149178f, 0.5209957f, 0.52711535f, 0.5332766f, 0.5394797f, - 0.5457247f, 0.5520116f, 0.5583406f, 0.5647117f, 0.57112503f, 0.57758063f, 0.5840786f, 0.590619f, 0.597202f, - 0.60382754f, 0.61049575f, 0.61720675f, 0.62396055f, 0.63075733f, 0.637597f, 0.6444799f, 0.6514058f, - 0.65837497f, 0.66538745f, 0.67244333f, 0.6795426f, 0.68668544f, 0.69387203f, 0.70110214f, 0.70837605f, - 0.7156938f, 0.72305536f, 0.730461f, 0.7379107f, 0.7454045f, 0.75294244f, 0.76052475f, 0.7681514f, 0.77582246f, - 0.78353804f, 0.79129815f, 0.79910296f, 0.8069525f, 0.8148468f, 0.822786f, 0.8307701f, 0.83879924f, 0.84687346f, - 0.8549928f, 0.8631574f, 0.87136734f, 0.8796226f, 0.8879232f, 0.89626956f, 0.90466136f, 0.913099f, 0.92158204f, - 0.93011117f, 0.9386859f, 0.9473069f, 0.9559735f, 0.9646866f, 0.9734455f, 0.98225087f, 0.9911022f, 1.0f - }; - - private static int linearToSrgb(float c) { - if (!(c > MIN_BOUND)) { - c = MIN_BOUND; - } - - if (c > MAX_BOUND) { - c = MAX_BOUND; - } - int inputBits = Float.floatToRawIntBits(c); - int entry = linearToSrgbTable[((inputBits - MIN_BITS) >> 20)]; - - int bias = (entry >>> 16) << 9; - int scale = entry & 0xffff; - int t = (inputBits >>> 12) & 0xff; - - return (bias + (scale * t)) >>> 16; - } - ////////////// + private static final float[] srgbToLinearTable = new float[] + { + 0.0f, 0.000303527f, 0.000607054f, 0.00091058103f, 0.001214108f, 0.001517635f, 0.0018211621f, 0.002124689f, + 0.002428216f, 0.002731743f, 0.00303527f, 0.0033465356f, 0.003676507f, 0.004024717f, 0.004391442f, + 0.0047769533f, 0.005181517f, 0.0056053917f, 0.0060488326f, 0.006512091f, 0.00699541f, 0.0074990317f, + 0.008023192f, 0.008568125f, 0.009134057f, 0.009721218f, 0.010329823f, 0.010960094f, 0.011612245f, + 0.012286487f, 0.012983031f, 0.013702081f, 0.014443844f, 0.015208514f, 0.015996292f, 0.016807375f, + 0.017641952f, 0.018500218f, 0.019382361f, 0.020288562f, 0.02121901f, 0.022173883f, 0.023153365f, + 0.02415763f, 0.025186857f, 0.026241222f, 0.027320892f, 0.028426038f, 0.029556843f, 0.03071345f, 0.03189604f, + 0.033104774f, 0.03433981f, 0.035601325f, 0.036889452f, 0.038204376f, 0.039546248f, 0.04091521f, 0.042311423f, + 0.043735042f, 0.045186214f, 0.046665095f, 0.048171833f, 0.049706575f, 0.051269468f, 0.052860655f, 0.05448028f, + 0.056128494f, 0.057805434f, 0.05951124f, 0.06124607f, 0.06301003f, 0.06480328f, 0.06662595f, 0.06847818f, + 0.07036011f, 0.07227186f, 0.07421358f, 0.07618539f, 0.07818743f, 0.08021983f, 0.082282715f, 0.084376216f, + 0.086500466f, 0.088655606f, 0.09084173f, 0.09305898f, 0.095307484f, 0.09758736f, 0.09989874f, 0.10224175f, + 0.10461649f, 0.10702311f, 0.10946172f, 0.111932434f, 0.11443538f, 0.116970696f, 0.11953845f, 0.12213881f, + 0.12477186f, 0.12743773f, 0.13013652f, 0.13286836f, 0.13563336f, 0.13843165f, 0.14126332f, 0.1441285f, + 0.1470273f, 0.14995982f, 0.15292618f, 0.1559265f, 0.15896086f, 0.16202943f, 0.16513224f, 0.16826946f, + 0.17144115f, 0.17464745f, 0.17788847f, 0.1811643f, 0.18447503f, 0.1878208f, 0.19120172f, 0.19461787f, + 0.19806935f, 0.2015563f, 0.20507877f, 0.2086369f, 0.21223079f, 0.21586053f, 0.21952623f, 0.22322798f, + 0.22696589f, 0.23074007f, 0.23455065f, 0.23839766f, 0.2422812f, 0.2462014f, 0.25015837f, 0.25415218f, + 0.2581829f, 0.26225072f, 0.26635566f, 0.27049786f, 0.27467737f, 0.27889434f, 0.2831488f, 0.2874409f, + 0.2917707f, 0.29613832f, 0.30054384f, 0.30498737f, 0.30946895f, 0.31398875f, 0.31854683f, 0.32314324f, + 0.32777813f, 0.33245158f, 0.33716366f, 0.34191445f, 0.3467041f, 0.3515327f, 0.35640025f, 0.36130688f, + 0.3662527f, 0.37123778f, 0.37626222f, 0.3813261f, 0.38642952f, 0.39157256f, 0.3967553f, 0.40197787f, + 0.4072403f, 0.4125427f, 0.41788515f, 0.42326775f, 0.42869055f, 0.4341537f, 0.43965724f, 0.44520125f, + 0.45078585f, 0.45641106f, 0.46207705f, 0.46778384f, 0.47353154f, 0.47932023f, 0.48514998f, 0.4910209f, + 0.49693304f, 0.5028866f, 0.50888145f, 0.5149178f, 0.5209957f, 0.52711535f, 0.5332766f, 0.5394797f, + 0.5457247f, 0.5520116f, 0.5583406f, 0.5647117f, 0.57112503f, 0.57758063f, 0.5840786f, 0.590619f, 0.597202f, + 0.60382754f, 0.61049575f, 0.61720675f, 0.62396055f, 0.63075733f, 0.637597f, 0.6444799f, 0.6514058f, + 0.65837497f, 0.66538745f, 0.67244333f, 0.6795426f, 0.68668544f, 0.69387203f, 0.70110214f, 0.70837605f, + 0.7156938f, 0.72305536f, 0.730461f, 0.7379107f, 0.7454045f, 0.75294244f, 0.76052475f, 0.7681514f, 0.77582246f, + 0.78353804f, 0.79129815f, 0.79910296f, 0.8069525f, 0.8148468f, 0.822786f, 0.8307701f, 0.83879924f, 0.84687346f, + 0.8549928f, 0.8631574f, 0.87136734f, 0.8796226f, 0.8879232f, 0.89626956f, 0.90466136f, 0.913099f, 0.92158204f, + 0.93011117f, 0.9386859f, 0.9473069f, 0.9559735f, 0.9646866f, 0.9734455f, 0.98225087f, 0.9911022f, 1.0f + }; - private static int getWidth(TextureAtlasSprite texture) + + + //=============// + // constructor // + //=============// + + public ClientBlockStateCache(BlockState blockState, IClientLevelWrapper samplingLevel) { - #if MC_VER < MC_1_19_4 - return texture.getWidth(); - #else - return texture.contents().width(); - #endif + this.blockState = blockState; + this.levelWrapper = samplingLevel; + this.level = (LevelReader) samplingLevel.getWrappedMcObject(); + this.resolveColors(); } - private static int getHeight(TextureAtlasSprite texture) + + + //===================// + // color calculation // + //===================// + + private void resolveColors() { - #if MC_VER < MC_1_19_4 - return texture.getHeight(); - #else - return texture.contents().height(); - #endif + if (this.isColorResolved) + { + return; + } + + if (this.blockState.getFluidState().isEmpty()) + { + // look for the first non-empty direction + List quads = null; + for (Direction direction : COLOR_RESOLUTION_DIRECTION_ORDER) + { + quads = Minecraft.getInstance().getModelManager().getBlockModelShaper(). + // TODO getQuads sometimes throws a "makeThreadingException", is there anything we can do about that? + // Note: this isn't a critical issue, it just prints an ugly error and the render data will need to be regenerated. + getBlockModel(this.blockState).getQuads(this.blockState, direction, random); + + if (quads != null && !quads.isEmpty() + && !( + this.blockState.getBlock() instanceof RotatedPillarBlock + && direction == Direction.UP + ) + ) + { + break; + } + } + + if (quads == null || quads.isEmpty()) + { + quads = Minecraft.getInstance().getModelManager().getBlockModelShaper(). + getBlockModel(this.blockState).getQuads(this.blockState, null, random); + } + + if (quads != null && !quads.isEmpty()) + { + this.needPostTinting = quads.get(0).isTinted(); + this.needShade = quads.get(0).isShade(); + this.tintIndex = quads.get(0).getTintIndex(); + this.baseColor = calculateColorFromTexture( + #if MC_VER < MC_1_17_1 quads.get(0).sprite, + #else quads.get(0).getSprite(), #endif + ColorMode.getColorMode(this.blockState.getBlock())); + } + else + { + // Backup method. + this.needPostTinting = false; + this.needShade = false; + this.tintIndex = 0; + this.baseColor = calculateColorFromTexture(Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(this.blockState), + ColorMode.getColorMode(this.blockState.getBlock())); + } + } + else + { + // Liquid Block + this.needPostTinting = true; + this.needShade = false; + this.tintIndex = 0; + this.baseColor = calculateColorFromTexture(Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(this.blockState), + ColorMode.getColorMode(this.blockState.getBlock())); + } + + this.isColorResolved = true; } - - //TODO: Perhaps make this not just use the first frame? private static int calculateColorFromTexture(TextureAtlasSprite texture, ColorMode colorMode) { @@ -212,13 +244,15 @@ public class ClientBlockStateCache double green = 0; double blue = 0; int tempColor; - //make Chiseled block not render. Since ColorMode is set per block, you only need to check it once + + // don't render Chiseled blocks. + // Since ColorMode is set per block, you only need to check this once. if (colorMode != ColorMode.Chisel) { // textures normally use u and v instead of x and y - for (int v = 0; v < getHeight(texture); v++) + for (int v = 0; v < getTextureHeight(texture); v++) { - for (int u = 0; u < getWidth(texture); u++) + for (int u = 0; u < getTextureWidth(texture); u++) { //note: Minecraft color format is: 0xAA BB GG RR //________ DH mod color format is: 0xAA RR GG BB @@ -270,8 +304,10 @@ public class ClientBlockStateCache } if (count == 0) + { // this block is entirely transparent tempColor = ColorUtil.rgbToInt(0, 255, 255, 255); + } else { // determine the average color @@ -281,6 +317,7 @@ public class ClientBlockStateCache linearToSrgb((float) (green / (double) alpha)), linearToSrgb((float) (blue / (double) alpha))); } + //check if not missing texture if (tempColor == ColorUtil.rgbToInt(255, 182, 0, 182)) { @@ -289,61 +326,53 @@ public class ClientBlockStateCache } return tempColor; } - private static final Direction[] DIRECTION_ORDER = {Direction.UP, Direction.NORTH, Direction.EAST, Direction.WEST, Direction.SOUTH, Direction.DOWN}; - - private void resolveColors() + private static int getTextureWidth(TextureAtlasSprite texture) { - if (isColorResolved) return; - if (blockState.getFluidState().isEmpty()) - { - List quads = null; - for (Direction direction : DIRECTION_ORDER) - { - quads = Minecraft.getInstance().getModelManager().getBlockModelShaper(). - getBlockModel(blockState).getQuads(blockState, direction, random); // TODO getQuads sometimes throws a "makeThreadingException", is there anything we can do about that? Note: this isn't a critical issue, it just prints an ugly error and the render data will need to be regenered. - if (quads != null && !quads.isEmpty() && - !(blockState.getBlock() instanceof RotatedPillarBlock && direction == Direction.UP)) - break; - } ; - if (quads == null || quads.isEmpty()) - { - quads = Minecraft.getInstance().getModelManager().getBlockModelShaper(). - getBlockModel(blockState).getQuads(blockState, null, random); - } - if (quads != null && !quads.isEmpty()) - { - needPostTinting = quads.get(0).isTinted(); - needShade = quads.get(0).isShade(); - tintIndex = quads.get(0).getTintIndex(); - baseColor = calculateColorFromTexture( - #if MC_VER < MC_1_17_1 quads.get(0).sprite, - #else quads.get(0).getSprite(), #endif - ColorMode.getColorMode(blockState.getBlock())); - } - else - { // Backup method. - needPostTinting = false; - needShade = false; - tintIndex = 0; - baseColor = calculateColorFromTexture(Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(blockState), - ColorMode.getColorMode(blockState.getBlock())); - } - } - else - { // Liquid Block - needPostTinting = true; - needShade = false; - tintIndex = 0; - baseColor = calculateColorFromTexture(Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(blockState), - ColorMode.getColorMode(blockState.getBlock())); - } - isColorResolved = true; + #if MC_VER < MC_1_19_4 + return texture.getWidth(); + #else + return texture.contents().width(); + #endif } + private static int getTextureHeight(TextureAtlasSprite texture) + { + #if MC_VER < MC_1_19_4 + return texture.getHeight(); + #else + return texture.contents().height(); + #endif + } + /** + * This method was suggested by IMS from the Iris/Sodium team. + * That's where the numbers and code are based. + */ + private static int linearToSrgb(float c) + { + if (!(c > MIN_SRGB_BOUND)) { + c = MIN_SRGB_BOUND; + } + + if (c > MAX_SRGB_BOUND) { + c = MAX_SRGB_BOUND; + } + int inputBits = Float.floatToRawIntBits(c); + int entry = linearToSrgbTable[((inputBits - MIN_SRGB_BITS) >> 20)]; + + int bias = (entry >>> 16) << 9; + int scale = entry & 0xffff; + int t = (inputBits >>> 12) & 0xff; + + return (bias + (scale * t)) >>> 16; + } + + + + //===============// + // public getter // + //===============// public int getAndResolveFaceColor(BiomeWrapper biome, DhBlockPos pos) { - // FIXME: impl per-face colors - // only get the tint if the block needs to be tinted if (!this.needPostTinting) { @@ -409,4 +438,30 @@ public class ClientBlockStateCache } } + + + //================// + // helper classes // + //================// + + enum ColorMode + { + Default, + Flower, + Leaves, + Chisel, + Glass; + + static ColorMode getColorMode(Block block) + { + if (block instanceof LeavesBlock) return Leaves; + if (block instanceof FlowerBlock) return Flower; + if (block.toString().contains("glass")) return Glass; + if (block.toString().equals("Block{chiselsandbits:chiseled}")) return Chisel; + return Default; + } + } + + + } From 50e5898692574b81dafd3a63146ac67728ddccaa Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 27 Jul 2024 16:44:47 -0500 Subject: [PATCH 04/11] Rename ClientBlockStateCache -> ClientBlockStateColorCache And do some additional cleanup --- .../block/cache/ClientBlockDetailMap.java | 57 ------------------- ...e.java => ClientBlockStateColorCache.java} | 11 ++-- .../wrappers/world/ClientLevelWrapper.java | 18 +++--- 3 files changed, 17 insertions(+), 69 deletions(-) delete mode 100644 common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ClientBlockDetailMap.java rename common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/{ClientBlockStateCache.java => ClientBlockStateColorCache.java} (98%) diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ClientBlockDetailMap.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ClientBlockDetailMap.java deleted file mode 100644 index 6fb510855..000000000 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ClientBlockDetailMap.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * This file is part of the Distant Horizons mod - * licensed under the GNU LGPL v3 License. - * - * Copyright (C) 2020-2023 James Seibel - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package com.seibel.distanthorizons.common.wrappers.block.cache; - -import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper; -import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper; -import com.seibel.distanthorizons.core.pos.DhBlockPos; -import net.minecraft.world.level.block.state.BlockState; - -import java.util.concurrent.ConcurrentHashMap; - -public class ClientBlockDetailMap -{ - private final ConcurrentHashMap blockCache = new ConcurrentHashMap<>(); - private final ClientLevelWrapper level; - - - - //=============// - // constructor // - //=============// - - public ClientBlockDetailMap(ClientLevelWrapper level) { this.level = level; } - - - - //=========// - // methods // - //=========// - - public ClientBlockStateCache getBlockStateData(BlockState blockState) - { return this.blockCache.computeIfAbsent(blockState, (block) -> new ClientBlockStateCache(block, this.level)); } - - public int getColor(BlockState state, BiomeWrapper biome, DhBlockPos pos) - { return this.getBlockStateData(state).getAndResolveFaceColor(biome, pos); } - - public void clear() { this.blockCache.clear(); } - - -} diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ClientBlockStateCache.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ClientBlockStateColorCache.java similarity index 98% rename from common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ClientBlockStateCache.java rename to common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ClientBlockStateColorCache.java index 673d975cb..99d77e592 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ClientBlockStateCache.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ClientBlockStateColorCache.java @@ -31,7 +31,6 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapp import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.block.Block; @@ -50,11 +49,13 @@ import java.util.HashSet; import java.util.List; /** - * This keeps track of the color each block state should be for a given level. + * This stores and calculates the colors + * the given {@link BlockState} should have based + * on the given {@link IClientLevelWrapper}. * * @see ColorUtil */ -public class ClientBlockStateCache +public class ClientBlockStateColorCache { private static final Logger LOGGER = DhLoggerBuilder.getLogger(); @@ -154,7 +155,7 @@ public class ClientBlockStateCache // constructor // //=============// - public ClientBlockStateCache(BlockState blockState, IClientLevelWrapper samplingLevel) + public ClientBlockStateColorCache(BlockState blockState, IClientLevelWrapper samplingLevel) { this.blockState = blockState; this.levelWrapper = samplingLevel; @@ -371,7 +372,7 @@ public class ClientBlockStateCache // public getter // //===============// - public int getAndResolveFaceColor(BiomeWrapper biome, DhBlockPos pos) + public int getColor(BiomeWrapper biome, DhBlockPos pos) { // only get the tint if the block needs to be tinted if (!this.needPostTinting) diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ClientLevelWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ClientLevelWrapper.java index c2fb642a6..df01f165c 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ClientLevelWrapper.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ClientLevelWrapper.java @@ -5,9 +5,8 @@ import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderRegist import com.seibel.distanthorizons.common.wrappers.McObjectConverter; import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper; import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper; -import com.seibel.distanthorizons.common.wrappers.block.cache.ClientBlockDetailMap; +import com.seibel.distanthorizons.common.wrappers.block.cache.ClientBlockStateColorCache; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; -import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftClientWrapper; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.level.*; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; @@ -22,6 +21,7 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapp import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkSource; import org.apache.logging.log4j.Logger; @@ -46,7 +46,7 @@ public class ClientLevelWrapper implements IClientLevelWrapper private static final Minecraft MINECRAFT = Minecraft.getInstance(); private final ClientLevel level; - private final ClientBlockDetailMap blockMap = new ClientBlockDetailMap(this); + private final ConcurrentHashMap blockCache = new ConcurrentHashMap<>(); private BlockStateWrapper dirtBlockWrapper; private BiomeWrapper plainsBiomeWrapper; @@ -111,7 +111,7 @@ public class ClientLevelWrapper implements IClientLevelWrapper } catch (Exception e) { - LOGGER.error("Failed to get server side wrapper for client level: " + level); + LOGGER.error("Failed to get server side wrapper for client level: " + this.level); return null; } } @@ -123,9 +123,13 @@ public class ClientLevelWrapper implements IClientLevelWrapper //====================// @Override - public int computeBaseColor(DhBlockPos pos, IBiomeWrapper biome, IBlockStateWrapper blockState) + public int getBlockColor(DhBlockPos pos, IBiomeWrapper biome, IBlockStateWrapper blockWrapper) { - return this.blockMap.getColor(((BlockStateWrapper) blockState).blockState, (BiomeWrapper) biome, pos); + ClientBlockStateColorCache blockColorCache = this.blockCache.computeIfAbsent( + ((BlockStateWrapper) blockWrapper).blockState, + (block) -> new ClientBlockStateColorCache(block, this)); + + return blockColorCache.getColor((BiomeWrapper) biome, pos); } @Override @@ -145,7 +149,7 @@ public class ClientLevelWrapper implements IClientLevelWrapper } } - return this.blockMap.getColor(this.dirtBlockWrapper.blockState, BiomeWrapper.EMPTY_WRAPPER, DhBlockPos.ZERO); + return this.getBlockColor(DhBlockPos.ZERO,BiomeWrapper.EMPTY_WRAPPER, this.dirtBlockWrapper); } @Override From 726f0f3d3ca17982d7d9a1099acf48f43fc6bd42 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 27 Jul 2024 16:51:14 -0500 Subject: [PATCH 05/11] Remove unused ServerBlockStateCache --- .../ClientBlockStateColorCache.java | 2 +- .../block/cache/ServerBlockDetailMap.java | 43 -------- .../block/cache/ServerBlockStateCache.java | 104 ------------------ .../wrappers/world/ClientLevelWrapper.java | 2 +- .../wrappers/world/ServerLevelWrapper.java | 3 - coreSubProjects | 2 +- 6 files changed, 3 insertions(+), 153 deletions(-) rename common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/{cache => }/ClientBlockStateColorCache.java (99%) delete mode 100644 common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ServerBlockDetailMap.java delete mode 100644 common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ServerBlockStateCache.java diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ClientBlockStateColorCache.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/ClientBlockStateColorCache.java similarity index 99% rename from common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ClientBlockStateColorCache.java rename to common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/ClientBlockStateColorCache.java index 99d77e592..eaf2346e6 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ClientBlockStateColorCache.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/ClientBlockStateColorCache.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.seibel.distanthorizons.common.wrappers.block.cache; +package com.seibel.distanthorizons.common.wrappers.block; import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper; import com.seibel.distanthorizons.common.wrappers.block.TextureAtlasSpriteWrapper; diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ServerBlockDetailMap.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ServerBlockDetailMap.java deleted file mode 100644 index 22dfd9ca8..000000000 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ServerBlockDetailMap.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * This file is part of the Distant Horizons mod - * licensed under the GNU LGPL v3 License. - * - * Copyright (C) 2020-2023 James Seibel - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package com.seibel.distanthorizons.common.wrappers.block.cache; - -import java.util.concurrent.ConcurrentHashMap; - -import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper; -import com.seibel.distanthorizons.core.pos.DhBlockPos; -import net.minecraft.world.level.block.state.BlockState; - - -public class ServerBlockDetailMap -{ - private final ConcurrentHashMap blockCache = new ConcurrentHashMap<>(); - //private final ConcurrentHashMap<#if MC_VER < MC_1_18_2 Biome #else Holder #endif, Biome> biomeMap = new ConcurrentHashMap<>(); - private final ServerLevelWrapper level; - public ServerBlockDetailMap(ServerLevelWrapper level) { this.level = level; } - - public ServerBlockStateCache getBlockStateData(BlockState state, DhBlockPos pos) - { //TODO: Allow a per pos unique setting - return blockCache.computeIfAbsent(state, (s) -> new ServerBlockStateCache(s, level, new DhBlockPos(0, 0, 0))); - } - - public void clear() { blockCache.clear(); } - -} diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ServerBlockStateCache.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ServerBlockStateCache.java deleted file mode 100644 index 3cd54a49c..000000000 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/cache/ServerBlockStateCache.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * This file is part of the Distant Horizons mod - * licensed under the GNU LGPL v3 License. - * - * Copyright (C) 2020-2023 James Seibel - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package com.seibel.distanthorizons.common.wrappers.block.cache; - -import com.seibel.distanthorizons.common.wrappers.McObjectConverter; -import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; -import com.seibel.distanthorizons.core.pos.DhBlockPos; -import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.level.LevelReader; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.shapes.VoxelShape; -import org.apache.logging.log4j.Logger; - -import java.util.Arrays; - -/** - * @version 2022-9-16 - */ -public class ServerBlockStateCache -{ - private static final Logger LOGGER = DhLoggerBuilder.getLogger(); - - public final BlockState state; - public final LevelReader level; - public final BlockPos pos; - - public ServerBlockStateCache(BlockState blockState, ILevelWrapper samplingLevel, DhBlockPos samplingPos) - { - state = blockState; - level = (LevelReader) samplingLevel.getWrappedMcObject(); - pos = McObjectConverter.Convert(samplingPos); - resolveShapes(); - //LOGGER.info("ServerBlockState created for {}", blockState); - } - - boolean noCollision = false; - boolean[] occludeFaces = null; - boolean[] fullFaces = null; - boolean isShapeResolved = false; - public void resolveShapes() - { - if (isShapeResolved) return; - if (state.getFluidState().isEmpty()) - { - noCollision = state.getCollisionShape(level, pos).isEmpty(); - occludeFaces = new boolean[6]; - if (state.canOcclude()) - { - for (Direction dir : Direction.values()) - { - // Note: isEmpty() isn't quite correct... best would be a isFull() or something... - occludeFaces[McObjectConverter.Convert(dir).ordinal()] - = !state.getFaceOcclusionShape(level, pos, dir).isEmpty(); - } - } - - VoxelShape voxelShape = state.getShape(level, pos); - fullFaces = new boolean[6]; - if (!voxelShape.isEmpty()) - { - for (Direction dir : Direction.values()) - { - VoxelShape faceShape = voxelShape.getFaceShape(dir); - AABB aabb = faceShape.bounds(); - boolean xFull = aabb.minX <= 0.01 && aabb.maxX >= 0.99; - boolean yFull = aabb.minY <= 0.01 && aabb.maxY >= 0.99; - boolean zFull = aabb.minZ <= 0.01 && aabb.maxZ >= 0.99; - fullFaces[McObjectConverter.Convert(dir).ordinal()] = - (xFull || dir.getAxis().equals(Direction.Axis.X)) - && (yFull || dir.getAxis().equals(Direction.Axis.Y)) - && (zFull || dir.getAxis().equals(Direction.Axis.Z)); - } - } - } - else - { // Liquid Block. Treat as full block - occludeFaces = new boolean[6]; - Arrays.fill(occludeFaces, true); - fullFaces = new boolean[6]; - Arrays.fill(fullFaces, true); - } - } - -} diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ClientLevelWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ClientLevelWrapper.java index df01f165c..0f2931130 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ClientLevelWrapper.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ClientLevelWrapper.java @@ -5,7 +5,7 @@ import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderRegist import com.seibel.distanthorizons.common.wrappers.McObjectConverter; import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper; import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper; -import com.seibel.distanthorizons.common.wrappers.block.cache.ClientBlockStateColorCache; +import com.seibel.distanthorizons.common.wrappers.block.ClientBlockStateColorCache; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.level.*; diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ServerLevelWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ServerLevelWrapper.java index f289673a7..e38e25758 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ServerLevelWrapper.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ServerLevelWrapper.java @@ -27,9 +27,7 @@ import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderRegist import com.seibel.distanthorizons.common.wrappers.McObjectConverter; import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper; import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper; -import com.seibel.distanthorizons.common.wrappers.block.cache.ServerBlockDetailMap; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; -import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftClientWrapper; import com.seibel.distanthorizons.core.level.IDhLevel; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.pos.DhBlockPos; @@ -37,7 +35,6 @@ import com.seibel.distanthorizons.core.pos.DhChunkPos; import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper; -import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper; import net.minecraft.server.level.ServerLevel; diff --git a/coreSubProjects b/coreSubProjects index 19d8c89bd..56303dd82 160000 --- a/coreSubProjects +++ b/coreSubProjects @@ -1 +1 @@ -Subproject commit 19d8c89bd8d5e157d8ce8dfe6e19a99fcec0835c +Subproject commit 56303dd82aa579c6dd05cea2e10e6cabf338b700 From 8c9bb9812530f7c8b8f92226fdbee5e0245d5c5c Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 27 Jul 2024 17:36:57 -0500 Subject: [PATCH 06/11] Update IDhApiRenderProxy.clearRenderDataCache() to also clear cached block colors --- .../common/wrappers/world/ClientLevelWrapper.java | 5 +++++ coreSubProjects | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ClientLevelWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ClientLevelWrapper.java index 0f2931130..cb3649519 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ClientLevelWrapper.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ClientLevelWrapper.java @@ -7,11 +7,13 @@ import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper; import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper; import com.seibel.distanthorizons.common.wrappers.block.ClientBlockStateColorCache; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; +import com.seibel.distanthorizons.core.api.internal.ClientApi; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.level.*; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.pos.DhBlockPos; import com.seibel.distanthorizons.core.pos.DhChunkPos; +import com.seibel.distanthorizons.core.util.ColorUtil; import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper; @@ -152,6 +154,9 @@ public class ClientLevelWrapper implements IClientLevelWrapper return this.getBlockColor(DhBlockPos.ZERO,BiomeWrapper.EMPTY_WRAPPER, this.dirtBlockWrapper); } + @Override + public void clearBlockColorCache() { this.blockCache.clear(); } + @Override public IBiomeWrapper getPlainsBiomeWrapper() { diff --git a/coreSubProjects b/coreSubProjects index 56303dd82..53300a302 160000 --- a/coreSubProjects +++ b/coreSubProjects @@ -1 +1 @@ -Subproject commit 56303dd82aa579c6dd05cea2e10e6cabf338b700 +Subproject commit 53300a3028cb76907f62605e0f25a17e13599bed From 334946ab59a9ee0164d24b54bc9e4a6b5776aa52 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 27 Jul 2024 19:15:00 -0500 Subject: [PATCH 07/11] Potentially fix thread warnings in ClientBlockStateColorCache --- .../block/ClientBlockStateColorCache.java | 117 +++++++++++------- 1 file changed, 69 insertions(+), 48 deletions(-) diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/ClientBlockStateColorCache.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/ClientBlockStateColorCache.java index eaf2346e6..ec9e211cc 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/ClientBlockStateColorCache.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/ClientBlockStateColorCache.java @@ -47,6 +47,7 @@ import org.apache.logging.log4j.Logger; import java.util.HashSet; import java.util.List; +import java.util.concurrent.locks.ReentrantLock; /** * This stores and calculates the colors @@ -62,6 +63,17 @@ public class ClientBlockStateColorCache private static final HashSet BLOCK_STATES_THAT_NEED_LEVEL = new HashSet<>(); private static final HashSet BROKEN_BLOCK_STATES = new HashSet<>(); + /** + * Methods using MC's "RandomSource" object aren't thread safe
+ * so we need to put locks around that logic.
+ * specifically: + * + * getBlockModel(this.blockState).getQuads(this.blockState, direction, RANDOM) + * + */ + private static final ReentrantLock RESOLVE_LOCK = new ReentrantLock(); + + /** This is the order each direction on a block is processed when attempting to get the texture/color */ private static final Direction[] COLOR_RESOLUTION_DIRECTION_ORDER = { Direction.UP, Direction.NORTH, Direction.EAST, Direction.WEST, Direction.SOUTH, Direction.DOWN }; @@ -70,9 +82,10 @@ public class ClientBlockStateColorCache #if MC_VER < MC_1_19_2 - private static final Random random = new Random(0); + private static final Random RANDOM = new Random(0); #else - private static final RandomSource random = RandomSource.create(); + /** Note: this object isn't thread safe and must be put in a lock */ + private static final RandomSource RANDOM = RandomSource.create(); #endif private final IClientLevelWrapper levelWrapper; @@ -176,65 +189,73 @@ public class ClientBlockStateColorCache return; } - if (this.blockState.getFluidState().isEmpty()) + try { - // look for the first non-empty direction - List quads = null; - for (Direction direction : COLOR_RESOLUTION_DIRECTION_ORDER) + // getQuads() isn't thread safe so we need to put this logic in a lock + RESOLVE_LOCK.lock(); + + if (this.blockState.getFluidState().isEmpty()) { - quads = Minecraft.getInstance().getModelManager().getBlockModelShaper(). - // TODO getQuads sometimes throws a "makeThreadingException", is there anything we can do about that? - // Note: this isn't a critical issue, it just prints an ugly error and the render data will need to be regenerated. - getBlockModel(this.blockState).getQuads(this.blockState, direction, random); - - if (quads != null && !quads.isEmpty() - && !( - this.blockState.getBlock() instanceof RotatedPillarBlock - && direction == Direction.UP - ) - ) + // look for the first non-empty direction + List quads = null; + for (Direction direction : COLOR_RESOLUTION_DIRECTION_ORDER) { - break; + quads = Minecraft.getInstance().getModelManager().getBlockModelShaper(). + getBlockModel(this.blockState).getQuads(this.blockState, direction, RANDOM); + + if (quads != null && !quads.isEmpty() + && !( + this.blockState.getBlock() instanceof RotatedPillarBlock + && direction == Direction.UP + ) + ) + { + break; + } + } + + if (quads == null || quads.isEmpty()) + { + quads = Minecraft.getInstance().getModelManager().getBlockModelShaper(). + getBlockModel(this.blockState).getQuads(this.blockState, null, RANDOM); + } + + if (quads != null && !quads.isEmpty()) + { + this.needPostTinting = quads.get(0).isTinted(); + this.needShade = quads.get(0).isShade(); + this.tintIndex = quads.get(0).getTintIndex(); + this.baseColor = calculateColorFromTexture( + #if MC_VER < MC_1_17_1 quads.get(0).sprite, + #else quads.get(0).getSprite(), #endif + ColorMode.getColorMode(this.blockState.getBlock())); + } + else + { + // Backup method. + this.needPostTinting = false; + this.needShade = false; + this.tintIndex = 0; + this.baseColor = calculateColorFromTexture(Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(this.blockState), + ColorMode.getColorMode(this.blockState.getBlock())); } } - - if (quads == null || quads.isEmpty()) - { - quads = Minecraft.getInstance().getModelManager().getBlockModelShaper(). - getBlockModel(this.blockState).getQuads(this.blockState, null, random); - } - - if (quads != null && !quads.isEmpty()) - { - this.needPostTinting = quads.get(0).isTinted(); - this.needShade = quads.get(0).isShade(); - this.tintIndex = quads.get(0).getTintIndex(); - this.baseColor = calculateColorFromTexture( - #if MC_VER < MC_1_17_1 quads.get(0).sprite, - #else quads.get(0).getSprite(), #endif - ColorMode.getColorMode(this.blockState.getBlock())); - } else - { - // Backup method. - this.needPostTinting = false; + { + // Liquid Block + this.needPostTinting = true; this.needShade = false; this.tintIndex = 0; this.baseColor = calculateColorFromTexture(Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(this.blockState), ColorMode.getColorMode(this.blockState.getBlock())); } + + this.isColorResolved = true; } - else - { - // Liquid Block - this.needPostTinting = true; - this.needShade = false; - this.tintIndex = 0; - this.baseColor = calculateColorFromTexture(Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(this.blockState), - ColorMode.getColorMode(this.blockState.getBlock())); + finally + { + RESOLVE_LOCK.unlock(); } - - this.isColorResolved = true; } //TODO: Perhaps make this not just use the first frame? private static int calculateColorFromTexture(TextureAtlasSprite texture, ColorMode colorMode) From e2083a18365476b9c0879fe2aef50d27b568075b Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 27 Jul 2024 20:11:49 -0500 Subject: [PATCH 08/11] Fix LODs flashing twice when changing configs --- coreSubProjects | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreSubProjects b/coreSubProjects index 53300a302..d3d166dd0 160000 --- a/coreSubProjects +++ b/coreSubProjects @@ -1 +1 @@ -Subproject commit 53300a3028cb76907f62605e0f25a17e13599bed +Subproject commit d3d166dd0277e7042786d6694fa07a5820446452 From e2a378250f9f10c36f2d309724fc0ad3f1a5a1f2 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 27 Jul 2024 20:25:58 -0500 Subject: [PATCH 09/11] Fix LOD upload warning --- coreSubProjects | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreSubProjects b/coreSubProjects index d3d166dd0..dbe0461d5 160000 --- a/coreSubProjects +++ b/coreSubProjects @@ -1 +1 @@ -Subproject commit d3d166dd0277e7042786d6694fa07a5820446452 +Subproject commit dbe0461d5f34545514d38b92f348d23337e7843b From 2d567b84be9e3594fbcbb975e315fe1b99242eed Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sat, 27 Jul 2024 21:06:55 -0500 Subject: [PATCH 10/11] Fix holes in LODs boarding different detail levels --- coreSubProjects | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreSubProjects b/coreSubProjects index dbe0461d5..882c5399b 160000 --- a/coreSubProjects +++ b/coreSubProjects @@ -1 +1 @@ -Subproject commit dbe0461d5f34545514d38b92f348d23337e7843b +Subproject commit 882c5399bdab14496104a63f71600e465da69e9e From 05569c03a4dc7a585182bf4b56fa97afb4382b4a Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sun, 28 Jul 2024 08:56:26 -0500 Subject: [PATCH 11/11] Revert and Deprecate DhApiChunk and DhApiTerrainDataPoint constructors --- coreSubProjects | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreSubProjects b/coreSubProjects index 882c5399b..9834b20a9 160000 --- a/coreSubProjects +++ b/coreSubProjects @@ -1 +1 @@ -Subproject commit 882c5399bdab14496104a63f71600e465da69e9e +Subproject commit 9834b20a9fda0ff4444ca46b6b413961948cee81