Compare commits

...

50 Commits

Author SHA1 Message Date
James Seibel 7f11f9bc9c Add proof-of-concept dynamic fade 2026-01-17 10:16:38 -06:00
James Seibel 9972363846 Change render wrapper get Texture error returns 2026-01-17 09:57:25 -06:00
James Seibel 4f171234c4 Remove unneeded resource pack meta files 2026-01-17 08:20:43 -06:00
s809 2716059840 Make sure payload chunk is readable 2026-01-14 22:17:50 +05:00
James Seibel a60887e9a7 Dynamically get beacon base blocks in MC 1.18.2+ 2026-01-10 17:33:51 -06:00
James Seibel 1b6c5a451a Improve concurrent iterating in QuadTree 2026-01-10 17:03:48 -06:00
James Seibel 4e91911e58 Add extra error logging around getCloudColor() 2026-01-10 16:21:17 -06:00
James Seibel bfae194919 remove unused broken import 2026-01-10 16:02:05 -06:00
James Seibel e562b2fdca Fix farmland color (fixes #690) 2026-01-10 12:47:34 -06:00
James Seibel 47fa6d7d8b minor ui reformat 2026-01-10 11:57:01 -06:00
James Seibel 053d1333ca Fix opening DH in forge mod menu (Fixes #678)
Done to fix a forge limitation where logos can't contain a file pathhttps://github.com/MinecraftForge/MinecraftForge/issues/7348
2026-01-10 11:56:39 -06:00
James Seibel 961c4190ad Fix Fabric debug keys 2026-01-10 10:31:56 -06:00
James Seibel 2f2ac0859c let shift click go back in UI options 2026-01-10 10:28:24 -06:00
James Seibel b59781b064 Fix white water/tinting with BCLib 2026-01-10 09:22:57 -06:00
s809 39cc5bb8aa Fix compilation 2026-01-09 21:01:15 +05:00
s809 abdbc73865 Reapply "Run plugin messages on a DH thread" 2026-01-09 20:29:40 +05:00
James Seibel 596f9f834a expand distant beacon beams for visiblity 2026-01-07 07:50:34 -06:00
James Seibel 8f2aaf4ef4 Fix #1152 (beacon beam going through tinted glass) 2026-01-07 07:50:01 -06:00
James Seibel 2320740a4a Change EMinecraftColor -> MinecraftTextFormat 2026-01-06 07:11:04 -06:00
James Seibel 4f0dc07995 Minor refactoring after slab color fix merge 2026-01-05 07:48:34 -06:00
James Seibel 336a9a94c8 Merge Slab Color Fix 2026-01-05 07:45:24 -06:00
James Seibel 1158496d9d increase fabric version in 1.20.1 to latest 2026-01-05 07:38:43 -06:00
s809 84479ed48c Wrong message target 2026-01-04 20:04:34 +05:00
s809 0c71ca96c6 Add a chat message for incompatible messages 2026-01-04 19:34:58 +05:00
s809 43dff26063 Replace the failure state with future exceptions 2025-12-27 00:51:35 +05:00
James Seibel 3cba883ba2 up version number 2.4.5 -> 2.4.6-dev 2025-12-24 22:41:36 -06:00
James Seibel 2d2e7524ae up version number 2.4.4 -> 2.4.5 2025-12-24 22:06:59 -06:00
James Seibel e8ff7abaea Replace MC color code strings with an enum 2025-12-24 22:05:59 -06:00
James Seibel 008ad52bbc remove dev from version number 2025-12-23 22:57:10 -06:00
James Seibel d0b44a1ffc Fix toggling world gen not recreating queue 2025-12-23 22:57:05 -06:00
James Seibel 4ffe430686 up DH api version 5.0.0 -> 5.1.0 2025-12-23 20:01:19 -06:00
James Seibel 19ca97c6c1 add experimental option to ignore rendering dimensions by name 2025-12-23 12:22:05 -06:00
James Seibel 3334394bfd Fix earth curvature shader compiling 2025-12-23 08:47:50 -06:00
James Seibel 180e7cd814 change forge fog config to match neo/fabric 2025-12-22 20:32:41 -06:00
James Seibel 84cf4505f2 merge world gen refactor 2025-12-20 10:54:07 -06:00
James Seibel 1d74eea3ef reduce stuttering at the cost of lighting quality 2025-12-20 10:53:14 -06:00
James Seibel 6ee2e6be25 up manifold version 25.1.27 -> 25.1.28 2025-12-19 16:55:32 -06:00
James Seibel b5c47d67cb up version number 2.4.3 -> 2.4.4-dev 2025-12-18 10:04:57 -06:00
James Seibel ead59d0817 remove dev from version number 2025-12-18 09:35:57 -06:00
James Seibel 1c9229c8f1 Fix 1.21.11 stuttering when flying into new chunks in singleplayer 2025-12-18 09:35:54 -06:00
James Seibel 968a14c6a5 remove chunkWrapper.isStillValid() 2025-12-18 09:35:21 -06:00
ada_aster 5608db9c56 Slab Block Color Fix 2025-12-17 22:12:15 -05:00
ada_aster 81b6a25805 Slab Block Color Fix 2025-12-17 22:08:45 -05:00
ada_aster 276d90b3e6 Slab Block Color Fix 2025-12-17 21:48:31 -05:00
James Seibel 851c7439d5 Fix GLProxy error in multiplayer 2025-12-17 09:02:15 -06:00
s809 c902357a8f Update core 2025-12-17 00:17:27 +05:00
s809 63170078f5 Fix returning wrong dimension name 2025-12-17 00:17:21 +05:00
James Seibel d0dd1f125b ignore chunk update events during all world gen pos 2025-12-15 15:07:01 -06:00
James Seibel 32950d793e slight light engine optimization 2025-12-15 14:37:22 -06:00
James Seibel 54e9bad907 up version number 2.4.2 -> 2.4.3-dev 2025-12-15 10:17:34 -06:00
27 changed files with 396 additions and 263 deletions
@@ -14,6 +14,7 @@ import com.seibel.distanthorizons.core.config.ConfigHandler;
import com.seibel.distanthorizons.core.config.eventHandlers.presets.ThreadPresetConfigEventHandler; import com.seibel.distanthorizons.core.config.eventHandlers.presets.ThreadPresetConfigEventHandler;
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector; import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.enums.MinecraftTextFormat;
import com.seibel.distanthorizons.core.jar.ModJarInfo; import com.seibel.distanthorizons.core.jar.ModJarInfo;
import com.seibel.distanthorizons.core.jar.updater.SelfUpdater; import com.seibel.distanthorizons.core.jar.updater.SelfUpdater;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
@@ -26,7 +27,6 @@ import net.minecraft.server.MinecraftServer;
import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.server.dedicated.DedicatedServer;
import com.seibel.distanthorizons.core.logging.DhLogger; import com.seibel.distanthorizons.core.logging.DhLogger;
import java.lang.invoke.MethodHandles;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Supplier; import java.util.function.Supplier;
@@ -240,8 +240,7 @@ public abstract class AbstractModInitializer
if (showChatWarnings) if (showChatWarnings)
{ {
String message = String message =
// orange text MinecraftTextFormat.ORANGE + "Distant Horizons: Alex's Cave detected." + MinecraftTextFormat.CLEAR_FORMATTING +
"\u00A76" + "Distant Horizons: Alex's Cave detected." + "\u00A7r\n" +
"You may have to change Alex's config for DH to render. "; "You may have to change Alex's config for DH to render. ";
ClientApi.INSTANCE.showChatMessageNextFrame(message); ClientApi.INSTANCE.showChatMessageNextFrame(message);
} }
@@ -263,8 +262,7 @@ public abstract class AbstractModInitializer
if (showChatWarnings) if (showChatWarnings)
{ {
String message = String message =
// orange text MinecraftTextFormat.ORANGE + "Distant Horizons: WWOO detected." + MinecraftTextFormat.CLEAR_FORMATTING + "\n" +
"\u00A76" + "Distant Horizons: WWOO detected." + "\u00A7r\n" +
wwooWarning; wwooWarning;
ClientApi.INSTANCE.showChatMessageNextFrame(message); ClientApi.INSTANCE.showChatMessageNextFrame(message);
} }
@@ -294,8 +292,7 @@ public abstract class AbstractModInitializer
if (showChatWarnings) if (showChatWarnings)
{ {
String message = String message =
// orange text MinecraftTextFormat.ORANGE + "Distant Horizons: Chunky detected." + MinecraftTextFormat.CLEAR_FORMATTING + "\n" +
"\u00A76" + "Distant Horizons: Chunky detected." + "\u00A7r\n" +
chunkyWarning; chunkyWarning;
ClientApi.INSTANCE.showChatMessageNextFrame(message); ClientApi.INSTANCE.showChatMessageNextFrame(message);
} }
@@ -41,6 +41,7 @@ import java.io.IOException;
import java.util.*; import java.util.*;
import java.util.List; import java.util.List;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -49,12 +50,14 @@ import net.minecraft.core.Registry;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.world.level.EmptyBlockGetter; import net.minecraft.world.level.EmptyBlockGetter;
#elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2 #elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2
import net.minecraft.tags.TagKey;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.world.level.EmptyBlockGetter; import net.minecraft.world.level.EmptyBlockGetter;
#else #else
import net.minecraft.tags.TagKey;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.registries.Registries; import net.minecraft.core.registries.Registries;
@@ -88,6 +91,15 @@ public class BlockStateWrapper implements IBlockStateWrapper
public static final String DIRT_RESOURCE_LOCATION_STRING = "minecraft:dirt"; public static final String DIRT_RESOURCE_LOCATION_STRING = "minecraft:dirt";
public static final String WATER_RESOURCE_LOCATION_STRING = "minecraft:water"; public static final String WATER_RESOURCE_LOCATION_STRING = "minecraft:water";
/** Used to handle older MC versions that don't have an simple way of getting the block's tags */
public static final List<String> OLD_BEACON_BASE_BLOCK_NAME_LIST = Arrays.asList(
"iron_block",
"gold_block",
"diamond_block",
"emerald_block",
"netherite_block"
);
public static HashSet<IBlockStateWrapper> rendererIgnoredBlocks = null; public static HashSet<IBlockStateWrapper> rendererIgnoredBlocks = null;
public static HashSet<IBlockStateWrapper> rendererIgnoredCaveBlocks = null; public static HashSet<IBlockStateWrapper> rendererIgnoredCaveBlocks = null;
@@ -176,11 +188,14 @@ public class BlockStateWrapper implements IBlockStateWrapper
String lowercaseSerial = this.serialString.toLowerCase(); String lowercaseSerial = this.serialString.toLowerCase();
// beacon blocks
// beacon base blocks
#if MC_VER <= MC_1_18_2
// Older MC versions are harder to get block tags, so just use a static list to determine beacon blocks
boolean isBeaconBaseBlock = false; boolean isBeaconBaseBlock = false;
for (int i = 0; i < LodUtil.BEACON_BASE_BLOCK_NAME_LIST.size(); i++) for (int i = 0; i < OLD_BEACON_BASE_BLOCK_NAME_LIST.size(); i++)
{ {
String baseBlockName = LodUtil.BEACON_BASE_BLOCK_NAME_LIST.get(i); String baseBlockName = OLD_BEACON_BASE_BLOCK_NAME_LIST.get(i);
if (lowercaseSerial.contains(baseBlockName)) if (lowercaseSerial.contains(baseBlockName))
{ {
isBeaconBaseBlock = true; isBeaconBaseBlock = true;
@@ -188,8 +203,23 @@ public class BlockStateWrapper implements IBlockStateWrapper
} }
} }
this.isBeaconBaseBlock = isBeaconBaseBlock; this.isBeaconBaseBlock = isBeaconBaseBlock;
#else
if (blockState != null)
{
// check if this block has any tags
Stream<TagKey<Block>> tags = blockState.getTags();
this.isBeaconBaseBlock = tags.anyMatch((TagKey<Block> tag) -> tag.location().getPath().toLowerCase().contains("beacon_base_blocks"));
}
else
{
this.isBeaconBaseBlock = false;
}
#endif
// beacon block
this.isBeaconBlock = lowercaseSerial.contains("minecraft:beacon"); this.isBeaconBlock = lowercaseSerial.contains("minecraft:beacon");
// beacon tint color // beacon tint color
Color beaconTintColor = null; Color beaconTintColor = null;
if (this.blockState != null if (this.blockState != null
@@ -225,6 +255,12 @@ public class BlockStateWrapper implements IBlockStateWrapper
// bedrock is a special case fully opaque block that does allow beacons through // bedrock is a special case fully opaque block that does allow beacons through
allowsBeaconBeamPassage = true; allowsBeaconBeamPassage = true;
} }
else if (lowercaseSerial.contains("minecraft:tinted_glass"))
{
// tinted glass is a special case where it isn't fully opaque,
// but should block beacons
allowsBeaconBeamPassage = false;
}
else if (propagatesSkyLightDown || !canOcclude) else if (propagatesSkyLightDown || !canOcclude)
{ {
// stairs, cake, fences, etc. // stairs, cake, fences, etc.
@@ -30,10 +30,7 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.*;
import net.minecraft.world.level.block.FlowerBlock;
import net.minecraft.world.level.block.LeavesBlock;
import net.minecraft.world.level.block.RotatedPillarBlock;
#if MC_VER >= MC_1_19_2 #if MC_VER >= MC_1_19_2
import net.minecraft.util.RandomSource; import net.minecraft.util.RandomSource;
#else #else
@@ -41,6 +38,7 @@ import java.util.Random;
#endif #endif
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import com.seibel.distanthorizons.core.logging.DhLogger; import com.seibel.distanthorizons.core.logging.DhLogger;
import net.minecraft.world.level.block.state.properties.SlabType;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
@@ -64,6 +62,8 @@ public class ClientBlockStateColorCache
{ {
private static final DhLogger LOGGER = new DhLoggerBuilder().build(); private static final DhLogger LOGGER = new DhLoggerBuilder().build();
private static final Minecraft MC = Minecraft.getInstance();
private static final HashSet<BlockState> BLOCK_STATES_THAT_NEED_LEVEL = new HashSet<>(); private static final HashSet<BlockState> BLOCK_STATES_THAT_NEED_LEVEL = new HashSet<>();
private static final HashSet<BlockState> BROKEN_BLOCK_STATES = new HashSet<>(); private static final HashSet<BlockState> BROKEN_BLOCK_STATES = new HashSet<>();
@@ -79,7 +79,16 @@ public class ClientBlockStateColorCache
/** This is the order each direction on a block is processed when attempting to get the texture/color */ /** 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 @Nullable Direction[] COLOR_RESOLUTION_DIRECTION_ORDER =
{
Direction.UP,
null, // null represents "unculled" faces, IE the top of farmland
Direction.NORTH,
Direction.EAST,
Direction.WEST,
Direction.SOUTH,
Direction.DOWN
};
private static final int FLOWER_COLOR_SCALE = 5; private static final int FLOWER_COLOR_SCALE = 5;
@@ -281,14 +290,23 @@ public class ClientBlockStateColorCache
@Nullable @Nullable
private List<BakedQuad> getQuadsForDirection(@Nullable Direction direction) private List<BakedQuad> getQuadsForDirection(@Nullable Direction direction)
{ {
List<BakedQuad> quads = null; BlockState effectiveBlockState = this.blockState;
// if this block is a slab, use it's double variant so we can get the top face,
// otherwise the color will use the side, which isn't as accurate
if (this.blockState.getBlock() instanceof SlabBlock)
{
effectiveBlockState = this.blockState.setValue( SlabBlock.TYPE, SlabType.DOUBLE );
}
List<BakedQuad> quads;
#if MC_VER < MC_1_21_5 #if MC_VER < MC_1_21_5
quads = Minecraft.getInstance().getModelManager().getBlockModelShaper(). quads = MC.getModelManager().getBlockModelShaper().
getBlockModel(this.blockState).getQuads(this.blockState, direction, RANDOM); getBlockModel(effectiveBlockState).getQuads(effectiveBlockState, direction, RANDOM);
#else #else
List<BlockModelPart> blockModelPartList = Minecraft.getInstance().getModelManager().getBlockModelShaper(). List<BlockModelPart> blockModelPartList = MC.getModelManager().getBlockModelShaper().
getBlockModel(this.blockState).collectParts(RANDOM); getBlockModel(effectiveBlockState).collectParts(RANDOM);
quads = new ArrayList<>(); quads = new ArrayList<>();
if (blockModelPartList != null) if (blockModelPartList != null)
@@ -558,10 +576,22 @@ public class ClientBlockStateColorCache
static EColorMode getColorMode(Block block) static EColorMode getColorMode(Block block)
{ {
if (block instanceof LeavesBlock) return Leaves; if (block instanceof LeavesBlock)
if (block instanceof FlowerBlock) return Flower; {
if (block.toString().contains("glass")) return Glass; return Leaves;
if (block.toString().equals("Block{chiselsandbits:chiseled}")) return Chisel; }
if (block instanceof FlowerBlock)
{
return Flower;
}
if (block.toString().contains("glass"))
{
return Glass;
}
if (block.toString().equals("Block{chiselsandbits:chiseled}"))
{
return Chisel;
}
return Default; return Default;
} }
} }
@@ -51,10 +51,10 @@ public class TintGetterOverride extends AbstractDhTintGetter
public TintGetterOverride() { } public TintGetterOverride() { }
public void update(LevelReader parent, BiomeWrapper biomeWrapper, BlockStateWrapper blockStateWrapper, FullDataSourceV2 fullDataSource, IClientLevelWrapper clientLevelWrapper) public void update(BiomeWrapper biomeWrapper, BlockStateWrapper blockStateWrapper, FullDataSourceV2 fullDataSource, IClientLevelWrapper clientLevelWrapper)
{ {
super.update(biomeWrapper, blockStateWrapper, fullDataSource, clientLevelWrapper); super.update(biomeWrapper, blockStateWrapper, fullDataSource, clientLevelWrapper);
this.parent = parent; this.parent = (LevelReader)this.clientLevelWrapper.getWrappedMcObject();
} }
@@ -18,6 +18,7 @@
*/ */
package com.seibel.distanthorizons.common.wrappers.chunk; package com.seibel.distanthorizons.common.wrappers.chunk;
import com.seibel.distanthorizons.api.DhApi;
import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper; import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper;
import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper; import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper;
import com.seibel.distanthorizons.common.wrappers.misc.MutableBlockPosWrapper; import com.seibel.distanthorizons.common.wrappers.misc.MutableBlockPosWrapper;
@@ -80,6 +81,8 @@ public class ChunkWrapper implements IChunkWrapper
private static final ThreadLocal<BlockPos.MutableBlockPos> MUTABLE_BLOCK_POS_REF = ThreadLocal.withInitial(() -> new BlockPos.MutableBlockPos()); private static final ThreadLocal<BlockPos.MutableBlockPos> MUTABLE_BLOCK_POS_REF = ThreadLocal.withInitial(() -> new BlockPos.MutableBlockPos());
private static final ThreadLocal<MutableBlockPosWrapper> MUTABLE_BLOCK_POS_WRAPPER_REF = ThreadLocal.withInitial(() -> new MutableBlockPosWrapper()); private static final ThreadLocal<MutableBlockPosWrapper> MUTABLE_BLOCK_POS_WRAPPER_REF = ThreadLocal.withInitial(() -> new MutableBlockPosWrapper());
private static boolean heightmapThreadWarningLogged = false;
private final ChunkAccess chunk; private final ChunkAccess chunk;
private final DhChunkPos chunkPos; private final DhChunkPos chunkPos;
@@ -107,22 +110,21 @@ public class ChunkWrapper implements IChunkWrapper
// constructor // // constructor //
//=============// //=============//
/**
* Note: this constructor should be very
* fast since it will be called frequently on the MC
* server thread and a slow method will cause server lag.
*/
public ChunkWrapper(ChunkAccess chunk, ILevelWrapper wrappedLevel) public ChunkWrapper(ChunkAccess chunk, ILevelWrapper wrappedLevel)
{
this(chunk, wrappedLevel, true);
}
public ChunkWrapper(ChunkAccess chunk, ILevelWrapper wrappedLevel, boolean recreateHeightmaps)
{ {
this.chunk = chunk; this.chunk = chunk;
this.wrappedLevel = wrappedLevel; this.wrappedLevel = wrappedLevel;
this.chunkPos = new DhChunkPos(chunk.getPos().x, chunk.getPos().z); this.chunkPos = new DhChunkPos(chunk.getPos().x, chunk.getPos().z);
if (recreateHeightmaps)
{
this.createDhHeightMaps();
}
} }
@Override
public ChunkWrapper copy() { return new ChunkWrapper(this.chunk, this.wrappedLevel); }
//=========// //=========//
@@ -242,11 +244,15 @@ public class ChunkWrapper implements IChunkWrapper
} }
private int getChunkSectionMinHeight(int index) { return (index * 16) + this.getInclusiveMinBuildHeight(); } private int getChunkSectionMinHeight(int index) { return (index * 16) + this.getInclusiveMinBuildHeight(); }
@Override
public void createDhHeightMaps() public void createDhHeightMaps()
{ {
// re-calculate the min/max heights for consistency (during world gen these may be wrong) if (heightmapThreadWarningLogged
this.minNonEmptyHeight = Integer.MIN_VALUE; && !DhApi.isDhThread())
this.maxNonEmptyHeight = Integer.MAX_VALUE; {
LOGGER.warn("ChunkWrapper Height maps created on non-DH thread ["+Thread.currentThread().getName()+"]. This may cause stuttering.");
}
this.solidHeightMap = new int[LodUtil.CHUNK_WIDTH][LodUtil.CHUNK_WIDTH]; this.solidHeightMap = new int[LodUtil.CHUNK_WIDTH][LodUtil.CHUNK_WIDTH];
@@ -614,15 +620,6 @@ public class ChunkWrapper implements IChunkWrapper
//===============//
// other methods //
//===============//
@Override
public boolean isStillValid() { return this.wrappedLevel.tryGetChunk(this.chunkPos) == this; }
//================// //================//
// base overrides // // base overrides //
//================// //================//
@@ -13,6 +13,7 @@ import java.util.regex.Pattern;
import com.seibel.distanthorizons.api.enums.config.DisallowSelectingViaConfigGui; import com.seibel.distanthorizons.api.enums.config.DisallowSelectingViaConfigGui;
import com.seibel.distanthorizons.common.wrappers.gui.config.ConfigGuiInfo; import com.seibel.distanthorizons.common.wrappers.gui.config.ConfigGuiInfo;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftClientWrapper;
import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.config.ConfigHandler; import com.seibel.distanthorizons.core.config.ConfigHandler;
import com.seibel.distanthorizons.core.config.types.*; import com.seibel.distanthorizons.core.config.types.*;
@@ -26,6 +27,7 @@ import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.util.AnnotationUtil; import com.seibel.distanthorizons.core.util.AnnotationUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.config.IConfigGui; import com.seibel.distanthorizons.core.wrapperInterfaces.config.IConfigGui;
import com.seibel.distanthorizons.core.wrapperInterfaces.config.ILangWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.config.ILangWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.coreapi.ModInfo; import com.seibel.distanthorizons.coreapi.ModInfo;
import net.minecraft.ChatFormatting; import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
@@ -59,6 +61,9 @@ import net.minecraft.resources.ResourceLocation;
import net.minecraft.resources.Identifier; import net.minecraft.resources.Identifier;
#endif #endif
import org.lwjgl.glfw.GLFW;
import com.mojang.blaze3d.platform.InputConstants;
import static com.seibel.distanthorizons.common.wrappers.gui.GuiHelper.*; import static com.seibel.distanthorizons.common.wrappers.gui.GuiHelper.*;
import static com.seibel.distanthorizons.common.wrappers.gui.GuiHelper.Translatable; import static com.seibel.distanthorizons.common.wrappers.gui.GuiHelper.Translatable;
@@ -84,6 +89,8 @@ public class ClassicConfigGUI
public static final ConfigCoreInterface CONFIG_CORE_INTERFACE = new ConfigCoreInterface(); public static final ConfigCoreInterface CONFIG_CORE_INTERFACE = new ConfigCoreInterface();
private static final MinecraftClientWrapper MC_CLIENT = MinecraftClientWrapper.INSTANCE;
//==============// //==============//
@@ -175,36 +182,36 @@ public class ClassicConfigGUI
&& !ModInfo.IS_DEV_BUILD) && !ModInfo.IS_DEV_BUILD)
{ {
this.addBtn(new TexturedButtonWidget( this.addBtn(new TexturedButtonWidget(
// Where the button is on the screen // Where the button is on the screen
this.width - 28, this.height - 28, this.width - 28, this.height - 28,
// Width and height of the button // Width and height of the button
20, 20, 20, 20,
// texture UV Offset // texture UV Offset
0, 0, 0, 0,
// Some texture stuff // Some texture stuff
0, 0,
#if MC_VER < MC_1_21_1 #if MC_VER < MC_1_21_1
new ResourceLocation(ModInfo.ID, "textures/gui/changelog.png"), new ResourceLocation(ModInfo.ID, "textures/gui/changelog.png"),
#elif MC_VER <= MC_1_21_10 #elif MC_VER <= MC_1_21_10
ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "textures/gui/changelog.png"), ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "textures/gui/changelog.png"),
#else #else
Identifier.fromNamespaceAndPath(ModInfo.ID, "textures/gui/changelog.png"), Identifier.fromNamespaceAndPath(ModInfo.ID, "textures/gui/changelog.png"),
#endif #endif
20, 20, 20, 20,
// Create the button and tell it where to go // Create the button and tell it where to go
(buttonWidget) -> { (buttonWidget) -> {
ChangelogScreen changelogScreen = new ChangelogScreen(this); ChangelogScreen changelogScreen = new ChangelogScreen(this);
if (changelogScreen.usable) if (changelogScreen.usable)
{ {
Objects.requireNonNull(this.minecraft).setScreen(changelogScreen); Objects.requireNonNull(this.minecraft).setScreen(changelogScreen);
} }
else else
{ {
LOGGER.warn("Changelog was not able to open"); LOGGER.warn("Changelog was not able to open");
} }
}, },
// Add a title to the button // Add a title to the button
Translatable(ModInfo.ID + ".updater.title") Translatable(ModInfo.ID + ".updater.title")
)); ));
} }
@@ -416,16 +423,24 @@ public class ClassicConfigGUI
Function<Object, Component> getEnumTranslatableFunc = (value) -> Translatable(TRANSLATION_PREFIX + "enum." + enumClass.getSimpleName() + "." + enumConfigEntry.get().toString()); Function<Object, Component> getEnumTranslatableFunc = (value) -> Translatable(TRANSLATION_PREFIX + "enum." + enumClass.getSimpleName() + "." + enumConfigEntry.get().toString());
configGuiInfo.buttonOptionMap = configGuiInfo.buttonOptionMap =
new AbstractMap.SimpleEntry<Button.OnPress, Function<Object, Component>>( new AbstractMap.SimpleEntry<Button.OnPress, Function<Object, Component>>(
(button) -> (button) ->
{ {
// get the currently selected enum and enum index // get the currently selected enum and enum index
int startingIndex = enumList.indexOf(enumConfigEntry.get()); int startingIndex = enumList.indexOf(enumConfigEntry.get());
Enum<?> enumValue = enumList.get(startingIndex); Enum<?> enumValue = enumList.get(startingIndex);
// search for the next enum that is selectable boolean shiftPressed =
int index = startingIndex + 1; InputConstants.isKeyDown(MC_CLIENT.getGlfwWindowId(), GLFW.GLFW_KEY_LEFT_SHIFT)
|| InputConstants.isKeyDown(MC_CLIENT.getGlfwWindowId(), GLFW.GLFW_KEY_RIGHT_SHIFT);
// move forward or backwards depending on if the shift key is pressed
int index = shiftPressed ? startingIndex-1 : startingIndex+1;
index = (index >= enumList.size()) ? 0 : index; index = (index >= enumList.size()) ? 0 : index;
// walk through the enums to find the next selectable one
while (index != startingIndex) while (index != startingIndex)
{ {
enumValue = enumList.get(index); enumValue = enumList.get(index);
@@ -436,13 +451,24 @@ public class ClassicConfigGUI
break; break;
} }
index++; // move forward or backwards depending on if the shift key is pressed
index = (index >= enumList.size()) ? 0 : index; index = shiftPressed ? index-1 : index+1;
// wrap around to the other side of the array when necessary
if (index >= enumList.size())
{
index = 0;
}
else if (index < 0)
{
index = enumList.size() - 1;
}
} }
if (index == startingIndex) if (index == startingIndex)
{ {
// none of the enums should be selectable, this is a programmer error // one of the enums should be selectable, this is a programmer error
enumValue = enumList.get(startingIndex); enumValue = enumList.get(startingIndex);
LOGGER.warn("Enum [" + enumValue.getClass() + "] doesn't contain any values that should be selectable via the UI, sticking to the currently selected value [" + enumValue + "]."); LOGGER.warn("Enum [" + enumValue.getClass() + "] doesn't contain any values that should be selectable via the UI, sticking to the currently selected value [" + enumValue + "].");
} }
@@ -120,26 +120,26 @@ public class UpdateModScreen extends DhScreen
if (!ModInfo.IS_DEV_BUILD) if (!ModInfo.IS_DEV_BUILD)
{ {
this.addBtn(new TexturedButtonWidget( this.addBtn(new TexturedButtonWidget(
// Where the button is on the screen // Where the button is on the screen
this.width / 2 - 97, this.height / 2 + 8, this.width / 2 - 97, this.height / 2 + 8,
// Width and height of the button // Width and height of the button
20, 20, 20, 20,
// Offset // Offset
0, 0, 0, 0,
// Some textuary stuff // Some textuary stuff
0, 0,
#if MC_VER < MC_1_21_1 #if MC_VER < MC_1_21_1
new ResourceLocation(ModInfo.ID, "textures/gui/changelog.png"), new ResourceLocation(ModInfo.ID, "textures/gui/changelog.png"),
#elif MC_VER <= MC_1_21_10 #elif MC_VER <= MC_1_21_10
ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "textures/gui/changelog.png"), ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "textures/gui/changelog.png"),
#else #else
Identifier.fromNamespaceAndPath(ModInfo.ID, "textures/gui/changelog.png"), Identifier.fromNamespaceAndPath(ModInfo.ID, "textures/gui/changelog.png"),
#endif #endif
20, 20, 20, 20,
// Create the button and tell it where to go // Create the button and tell it where to go
(buttonWidget) -> Objects.requireNonNull(this.minecraft).setScreen(new ChangelogScreen(this, this.newVersionID)), (buttonWidget) -> Objects.requireNonNull(this.minecraft).setScreen(new ChangelogScreen(this, this.newVersionID)),
// Add a title to the button // Add a title to the button
Translatable(ModInfo.ID + ".updater.title") Translatable(ModInfo.ID + ".updater.title")
)); ));
} }
@@ -21,6 +21,7 @@ package com.seibel.distanthorizons.common.wrappers.minecraft;
import java.io.File; import java.io.File;
import com.mojang.blaze3d.platform.Window;
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper; import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
import com.seibel.distanthorizons.core.file.structure.ClientOnlySaveStructure; import com.seibel.distanthorizons.core.file.structure.ClientOnlySaveStructure;
import com.seibel.distanthorizons.core.render.glObject.GLProxy; import com.seibel.distanthorizons.core.render.glObject.GLProxy;
@@ -203,19 +204,13 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
return; return;
} }
if (!GLProxy.hasInstance())
{
// rendering setup hasn't finished
return;
}
#if MC_VER < MC_1_19_2 #if MC_VER < MC_1_19_2
player.sendMessage(new TextComponent(string), getPlayer().getUUID()); player.sendMessage(new TextComponent(string), getPlayer().getUUID());
#elif MC_VER < MC_1_21_9 #elif MC_VER < MC_1_21_9
player.displayClientMessage(net.minecraft.network.chat.Component.translatable(string), /*isOverlay*/false); player.displayClientMessage(net.minecraft.network.chat.Component.translatable(string), /*isOverlay*/false);
#else #else
GLProxy.getInstance().queueRunningOnRenderThread(() -> GLProxy.queueRunningOnRenderThread(() ->
{ {
player.displayClientMessage(net.minecraft.network.chat.Component.translatable(string), /*isOverlay*/false); player.displayClientMessage(net.minecraft.network.chat.Component.translatable(string), /*isOverlay*/false);
}); });
@@ -268,6 +263,24 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
// misc // // misc //
//======// //======//
/**
* no override and not included in {@link IMinecraftClientWrapper}
* since this would only be used in common/client, not core.
*/
public
#if MC_VER < MC_1_21_9 long
#else Window
#endif
getGlfwWindowId()
{
#if MC_VER < MC_1_21_9
long glfwWindowId = MINECRAFT.getWindow().getWindow();
return glfwWindowId;
#else
return MINECRAFT.getWindow();
#endif
}
@Override @Override
public IProfilerWrapper getProfiler() public IProfilerWrapper getProfiler()
{ {
@@ -362,7 +362,7 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
if (glTexture == null) if (glTexture == null)
{ {
// shouldn't happen, but just in case // shouldn't happen, but just in case
return 0; return -1;
} }
return glTexture.glId(); return glTexture.glId();
@@ -376,7 +376,7 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
this.depthTextureCastFailLogged = true; this.depthTextureCastFailLogged = true;
LOGGER.error("Unable to cast render Target depth texture to GlTexture. MC or a rendering mod may have changed the object type.", e); LOGGER.error("Unable to cast render Target depth texture to GlTexture. MC or a rendering mod may have changed the object type.", e);
} }
return 0; return -1;
} }
#endif #endif
} }
@@ -392,7 +392,7 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
if (glTexture == null) if (glTexture == null)
{ {
// shouldn't happen, but just in case // shouldn't happen, but just in case
return 0; return -1;
} }
return glTexture.glId(); return glTexture.glId();
@@ -405,7 +405,7 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
this.colorTextureCastFailLogged = true; this.colorTextureCastFailLogged = true;
LOGGER.error("Unable to cast render Target color texture to GlTexture. MC or a rendering mod may have changed the object type.", e); LOGGER.error("Unable to cast render Target color texture to GlTexture. MC or a rendering mod may have changed the object type.", e);
} }
return 0; return -1;
} }
#endif #endif
} }
@@ -77,6 +77,8 @@ public class ClientLevelWrapper implements IClientLevelWrapper
private final Function<BlockState, ClientBlockStateColorCache> createCachedBlockColorCacheFunc = (blockState) -> new ClientBlockStateColorCache(blockState, this); private final Function<BlockState, ClientBlockStateColorCache> createCachedBlockColorCacheFunc = (blockState) -> new ClientBlockStateColorCache(blockState, this);
private boolean cloudColorFailLogged = false;
private BlockStateWrapper dirtBlockWrapper; private BlockStateWrapper dirtBlockWrapper;
private IDhLevel dhLevel; private IDhLevel dhLevel;
@@ -259,9 +261,7 @@ public class ClientLevelWrapper implements IClientLevelWrapper
#if MC_VER <= MC_1_21_10 #if MC_VER <= MC_1_21_10
return this.level.dimension().location().toString(); return this.level.dimension().location().toString();
#else #else
String namespace = this.level.dimension().identifier().getNamespace(); return this.level.dimension().identifier().toString();
String path = this.level.dimension().identifier().getPath();
return namespace + "@@" + path;
#endif #endif
} }
@@ -297,23 +297,6 @@ public class ClientLevelWrapper implements IClientLevelWrapper
#endif #endif
} }
@Override
public IChunkWrapper tryGetChunk(DhChunkPos pos)
{
if (!this.level.hasChunk(pos.getX(), pos.getZ()))
{
return null;
}
ChunkAccess chunk = this.level.getChunk(pos.getX(), pos.getZ(), ChunkStatus.EMPTY, false);
if (chunk == null)
{
return null;
}
return new ChunkWrapper(chunk, this);
}
@Override @Override
public ClientLevel getWrappedMcObject() { return this.level; } public ClientLevel getWrappedMcObject() { return this.level; }
@@ -362,14 +345,68 @@ public class ClientLevelWrapper implements IClientLevelWrapper
public Color getCloudColor(float tickDelta) public Color getCloudColor(float tickDelta)
{ {
#if MC_VER < MC_1_21_3 #if MC_VER < MC_1_21_3
Vec3 colorVec3 = this.level.getCloudColor(tickDelta); Vec3 colorVec3 = null;
return new Color((float)colorVec3.x, (float)colorVec3.y, (float)colorVec3.z); try
{
colorVec3 = this.level.getCloudColor(tickDelta);
return new Color((float)colorVec3.x, (float)colorVec3.y, (float)colorVec3.z);
}
catch (Exception e)
{
// extra logging is due to some mods returning weird values, this way we can track down the issue better
if (!this.cloudColorFailLogged)
{
this.cloudColorFailLogged = true;
String colorString = "NULL";
if (colorVec3 != null)
{
colorString = "r["+(float)colorVec3.x+"] g["+(float)colorVec3.y+"] b["+(float)colorVec3.z+"]";
}
LOGGER.warn("Failed to get cloud color for ["+this.getDhIdentifier()+"]. vec3 ["+colorString+"], error: ["+e.getMessage()+"].", e);
}
// default to white if there's an issue
return Color.WHITE;
}
#elif MC_VER <= MC_1_21_10 #elif MC_VER <= MC_1_21_10
int argbColor = this.level.getCloudColor(tickDelta); int argbColor = 0;
return ColorUtil.toColorObjARGB(argbColor); try
{
argbColor = this.level.getCloudColor(tickDelta);
return ColorUtil.toColorObjARGB(argbColor);
}
catch (Exception e)
{
// extra logging is due to some mods returning weird values, this way we can track down the issue better
if (!this.cloudColorFailLogged)
{
this.cloudColorFailLogged = true;
LOGGER.warn("Failed to get cloud color for ["+this.getDhIdentifier()+"]. Int ["+argbColor+"], col ["+ColorUtil.toString(argbColor)+"], error: ["+e.getMessage()+"].", e);
}
// default to white if there's an issue
return Color.WHITE;
}
#else #else
int argbColor = this.level.environmentAttributes().getValue(EnvironmentAttributes.CLOUD_COLOR, BlockPos.ZERO); int argbColor = 0;
return new Color(ColorUtil.getRed(argbColor), ColorUtil.getGreen(argbColor), ColorUtil.getBlue(argbColor), 255 /* ignore alpha since DH clouds don't render correctly with transparency */); try
{
argbColor = this.level.environmentAttributes().getValue(EnvironmentAttributes.CLOUD_COLOR, BlockPos.ZERO);
return new Color(ColorUtil.getRed(argbColor), ColorUtil.getGreen(argbColor), ColorUtil.getBlue(argbColor), 255 /* ignore alpha since DH clouds don't render correctly with transparency */);
}
catch (Exception e)
{
// extra logging is due to some mods returning weird values, this way we can track down the issue better
if (!this.cloudColorFailLogged)
{
this.cloudColorFailLogged = true;
LOGGER.warn("Failed to get cloud color for ["+this.getDhIdentifier()+"]. Int ["+argbColor+"], col ["+ColorUtil.toString(argbColor)+"], error: ["+e.getMessage()+"].", e);
}
// default to white if there's an issue
return Color.WHITE;
}
#endif #endif
} }
@@ -187,9 +187,7 @@ public class ServerLevelWrapper implements IServerLevelWrapper
#if MC_VER <= MC_1_21_10 #if MC_VER <= MC_1_21_10
return this.level.dimension().location().toString(); return this.level.dimension().location().toString();
#else #else
String namespace = this.level.dimension().identifier().getNamespace(); return this.level.dimension().identifier().toString();
String path = this.level.dimension().identifier().getPath();
return namespace + "@@" + path;
#endif #endif
} }
@@ -225,23 +223,6 @@ public class ServerLevelWrapper implements IServerLevelWrapper
#endif #endif
} }
@Override
public IChunkWrapper tryGetChunk(DhChunkPos pos)
{
if (!this.level.hasChunk(pos.getX(), pos.getZ()))
{
return null;
}
ChunkAccess chunk = this.level.getChunk(pos.getX(), pos.getZ(), ChunkStatus.FULL, false);
if (chunk == null)
{
return null;
}
return new ChunkWrapper(chunk, this);
}
@Override @Override
public ServerLevel getWrappedMcObject() { return this.level; } public ServerLevel getWrappedMcObject() { return this.level; }
@@ -28,6 +28,7 @@ import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
import com.seibel.distanthorizons.common.wrappers.worldGeneration.chunkFileHandling.ChunkFileReader; import com.seibel.distanthorizons.common.wrappers.worldGeneration.chunkFileHandling.ChunkFileReader;
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.*; import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.*;
import com.seibel.distanthorizons.common.wrappers.worldGeneration.params.GlobalWorldGenParams; import com.seibel.distanthorizons.common.wrappers.worldGeneration.params.GlobalWorldGenParams;
import com.seibel.distanthorizons.core.api.internal.SharedApi;
import com.seibel.distanthorizons.core.generation.DhLightingEngine; import com.seibel.distanthorizons.core.generation.DhLightingEngine;
import com.seibel.distanthorizons.core.level.IDhServerLevel; import com.seibel.distanthorizons.core.level.IDhServerLevel;
import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.config.Config;
@@ -37,6 +38,7 @@ import com.seibel.distanthorizons.core.pos.DhChunkPos;
import com.seibel.distanthorizons.core.sql.dto.BeaconBeamDTO; import com.seibel.distanthorizons.core.sql.dto.BeaconBeamDTO;
import com.seibel.distanthorizons.core.util.ExceptionUtil; import com.seibel.distanthorizons.core.util.ExceptionUtil;
import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.util.TimerUtil;
import com.seibel.distanthorizons.core.util.gridList.ArrayGridList; import com.seibel.distanthorizons.core.util.gridList.ArrayGridList;
import com.seibel.distanthorizons.core.util.objects.UncheckedInterruptedException; import com.seibel.distanthorizons.core.util.objects.UncheckedInterruptedException;
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.ChunkLightStorage; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.ChunkLightStorage;
@@ -100,6 +102,15 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm
public static final long EXCEPTION_TIMER_RESET_TIME = TimeUnit.NANOSECONDS.convert(1, TimeUnit.SECONDS); public static final long EXCEPTION_TIMER_RESET_TIME = TimeUnit.NANOSECONDS.convert(1, TimeUnit.SECONDS);
public static final int EXCEPTION_COUNTER_TRIGGER = 20; public static final int EXCEPTION_COUNTER_TRIGGER = 20;
/**
* Used to revert the ignore logic in {@link SharedApi} so
* that a given chunk pos can be handled again.
* A timer is used so we don't have to inject into MC's code and it works sell enough
* most of the time.
* If a chunk does get through due the timeout not being long enough that isn't the end of the world.
*/
private static final int MS_TO_IGNORE_CHUNK_AFTER_COMPLETION = 5_000;
private final IDhServerLevel dhServerLevel; private final IDhServerLevel dhServerLevel;
@@ -107,6 +118,8 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm
public final InternalServerGenerator internalServerGenerator; public final InternalServerGenerator internalServerGenerator;
public final ChunkFileReader chunkFileReader; public final ChunkFileReader chunkFileReader;
private final Timer chunkSaveIgnoreTimer = TimerUtil.CreateTimer("ChunkSaveIgnoreTimer");
public final LinkedBlockingQueue<GenerationEvent> generationEventQueue = new LinkedBlockingQueue<>(); public final LinkedBlockingQueue<GenerationEvent> generationEventQueue = new LinkedBlockingQueue<>();
@@ -435,10 +448,9 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm
//=============================// //=========================//
// process existing chunks // // process existing chunks //
// //=========================//
//=============================//
ArrayGridList<ChunkWrapper> chunkWrapperList = new ArrayGridList<>(regionChunks.gridSize); ArrayGridList<ChunkWrapper> chunkWrapperList = new ArrayGridList<>(regionChunks.gridSize);
regionChunks.forEachPos((relX, relZ) -> regionChunks.forEachPos((relX, relZ) ->
@@ -454,8 +466,8 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm
} }
else if (chunk != null) else if (chunk != null)
{ {
//
ChunkWrapper chunkWrapper = new ChunkWrapper(chunk, this.dhServerLevel.getLevelWrapper()); ChunkWrapper chunkWrapper = new ChunkWrapper(chunk, this.dhServerLevel.getLevelWrapper());
chunkWrapper.createDhHeightMaps();
chunkWrapperList.set(relX, relZ, chunkWrapper); chunkWrapperList.set(relX, relZ, chunkWrapper);
// try setting the wrapper's lighting // try setting the wrapper's lighting
@@ -575,6 +587,11 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm
ProtoChunk protoChunk = ((ProtoChunk) chunk); ProtoChunk protoChunk = ((ProtoChunk) chunk);
protoChunk.setLightEngine(region.getLightEngine()); protoChunk.setLightEngine(region.getLightEngine());
} }
// usually ignoring the chunk's position is unnecessary,
// but this improves performance if a chunk update event does sneak through
SharedApi.CHUNK_UPDATE_QUEUE_MANAGER.addPosToIgnore(chunkWrapper.getChunkPos());
}); });
@@ -684,6 +701,24 @@ public final class BatchGenerationEnvironment implements IBatchGeneratorEnvironm
this.dhServerLevel.updateBeaconBeamsForChunkPos(centerChunkWrapper.getChunkPos(), activeBeamList); this.dhServerLevel.updateBeaconBeamsForChunkPos(centerChunkWrapper.getChunkPos(), activeBeamList);
} }
} }
for (int i = 0; i < iChunkWrapperList.size(); i++)
{
ChunkWrapper chunkWrapper = (ChunkWrapper) iChunkWrapperList.get(i);
if (chunkWrapper == null)
{
continue;
}
// give MC a few seconds to save the chunk before
// we can process update events there again
this.chunkSaveIgnoreTimer.schedule(new TimerTask()
{
@Override
public void run() { SharedApi.CHUNK_UPDATE_QUEUE_MANAGER.removePosToIgnore(chunkWrapper.getChunkPos()); }
}, MS_TO_IGNORE_CHUNK_AFTER_COMPLETION);
}
} }
} }
private static <T> ArrayGridList<T> GetCutoutFrom(ArrayGridList<T> total, int border) { return new ArrayGridList<>(total, border, total.gridSize - border); } private static <T> ArrayGridList<T> GetCutoutFrom(ArrayGridList<T> total, int border) { return new ArrayGridList<>(total, border, total.gridSize - border); }
@@ -7,6 +7,7 @@ import com.seibel.distanthorizons.core.api.internal.ClientApi;
import com.seibel.distanthorizons.core.api.internal.SharedApi; import com.seibel.distanthorizons.core.api.internal.SharedApi;
import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector; import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
import com.seibel.distanthorizons.core.enums.MinecraftTextFormat;
import com.seibel.distanthorizons.core.generation.DhLightingEngine; import com.seibel.distanthorizons.core.generation.DhLightingEngine;
import com.seibel.distanthorizons.core.level.IDhServerLevel; import com.seibel.distanthorizons.core.level.IDhServerLevel;
import com.seibel.distanthorizons.core.logging.DhLogger; import com.seibel.distanthorizons.core.logging.DhLogger;
@@ -51,7 +52,7 @@ public class InternalServerGenerator
/** /**
* Used to revert the ignore logic in {@link SharedApi} so * Used to revert the ignore logic in {@link SharedApi} so
* that given chunk pos can be handled again. * that a given chunk pos can be handled again.
* A timer is used so we don't have to inject into MC's code and it works sell enough * A timer is used so we don't have to inject into MC's code and it works sell enough
* most of the time. * most of the time.
* If a chunk does get through due the timeout not being long enough that isn't the end of the world. * If a chunk does get through due the timeout not being long enough that isn't the end of the world.
@@ -156,6 +157,7 @@ public class InternalServerGenerator
if (chunk != null) if (chunk != null)
{ {
ChunkWrapper chunkWrapper = new ChunkWrapper(chunk, this.dhServerLevel.getLevelWrapper()); ChunkWrapper chunkWrapper = new ChunkWrapper(chunk, this.dhServerLevel.getLevelWrapper());
chunkWrapper.createDhHeightMaps();
chunkWrappers.add(chunkWrapper); chunkWrappers.add(chunkWrapper);
} }
} }
@@ -217,8 +219,7 @@ public class InternalServerGenerator
if (Config.Common.Logging.Warning.showSlowWorldGenSettingWarnings.get()) if (Config.Common.Logging.Warning.showSlowWorldGenSettingWarnings.get())
{ {
String message = String message =
// orange text MinecraftTextFormat.ORANGE + "Distant Horizons: slow world gen." + MinecraftTextFormat.CLEAR_FORMATTING + "\n" +
"\u00A76" + "Distant Horizons: slow world gen." + "\u00A7r\n" +
c2meWarning; c2meWarning;
ClientApi.INSTANCE.showChatMessageNextFrame(message); ClientApi.INSTANCE.showChatMessageNextFrame(message);
} }
@@ -222,7 +222,8 @@ public class ChunkCompoundTagParser
boolean hasHeightmapData = readHeightmaps(chunk, chunkData); boolean hasHeightmapData = readHeightmaps(chunk, chunkData);
// chunk wrapper so we can pass along extra data more easily // chunk wrapper so we can pass along extra data more easily
ChunkWrapper chunkWrapper = new ChunkWrapper(chunk, dhServerLevel.getServerLevelWrapper(), !hasHeightmapData); ChunkWrapper chunkWrapper = new ChunkWrapper(chunk, dhServerLevel.getServerLevelWrapper());
chunkWrapper.createDhHeightMaps();
@@ -293,7 +293,7 @@ public class ChunkFileReader implements AutoCloseable
public ChunkWrapper CreateProtoChunkWrapper(ServerLevel level, ChunkPos chunkPos) public ChunkWrapper CreateProtoChunkWrapper(ServerLevel level, ChunkPos chunkPos)
{ {
ProtoChunk chunk = CreateProtoChunk(level, chunkPos); ProtoChunk chunk = CreateProtoChunk(level, chunkPos);
return new ChunkWrapper(chunk, this.params.dhServerLevel.getLevelWrapper(), false); return new ChunkWrapper(chunk, this.params.dhServerLevel.getLevelWrapper());
} }
public static ProtoChunk CreateProtoChunk(ServerLevel level, ChunkPos chunkPos) public static ProtoChunk CreateProtoChunk(ServerLevel level, ChunkPos chunkPos)
{ {
@@ -24,6 +24,9 @@ accessible method net/minecraft/server/level/ChunkMap tick (Ljava/util/function/
accessible field net/minecraft/server/level/ServerLevel entityManager Lnet/minecraft/world/level/entity/PersistentEntitySectionManager; accessible field net/minecraft/server/level/ServerLevel entityManager Lnet/minecraft/world/level/entity/PersistentEntitySectionManager;
accessible field net/minecraft/server/level/ChunkMap mainThreadExecutor Lnet/minecraft/util/thread/BlockableEventLoop; accessible field net/minecraft/server/level/ChunkMap mainThreadExecutor Lnet/minecraft/util/thread/BlockableEventLoop;
# getting existing chunks outside the main thread
accessible method net/minecraft/server/level/ChunkMap getVisibleChunkIfPresent (J)Lnet/minecraft/server/level/ChunkHolder;
# lod generation from save file # lod generation from save file
accessible field net/minecraft/world/level/chunk/storage/SimpleRegionStorage worker Lnet/minecraft/world/level/chunk/storage/IOWorker; accessible field net/minecraft/world/level/chunk/storage/SimpleRegionStorage 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; accessible field net/minecraft/world/level/chunk/storage/IOWorker storage Lnet/minecraft/world/level/chunk/storage/RegionFileStorage;
@@ -22,8 +22,10 @@ package com.seibel.distanthorizons.fabric;
import com.seibel.distanthorizons.common.AbstractModInitializer; import com.seibel.distanthorizons.common.AbstractModInitializer;
import com.seibel.distanthorizons.common.AbstractPluginPacketSender; import com.seibel.distanthorizons.common.AbstractPluginPacketSender;
import com.seibel.distanthorizons.common.wrappers.McObjectConverter; import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftClientWrapper;
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper; import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
import com.seibel.distanthorizons.core.api.internal.ClientApi; import com.seibel.distanthorizons.core.api.internal.ClientApi;
import com.seibel.distanthorizons.core.logging.DhLogger;
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
import com.seibel.distanthorizons.core.api.internal.SharedApi; import com.seibel.distanthorizons.core.api.internal.SharedApi;
@@ -64,11 +66,13 @@ import java.util.concurrent.AbstractExecutorService;
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
#endif #endif
import com.mojang.blaze3d.platform.InputConstants;
import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.world.InteractionResult; import net.minecraft.world.InteractionResult;
import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.HitResult;
import com.seibel.distanthorizons.core.logging.DhLogger;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFW;
/** /**
@@ -82,13 +86,12 @@ import org.lwjgl.glfw.GLFW;
@Environment(EnvType.CLIENT) @Environment(EnvType.CLIENT)
public class FabricClientProxy implements AbstractModInitializer.IEventProxy public class FabricClientProxy implements AbstractModInitializer.IEventProxy
{ {
private final ClientApi clientApi = ClientApi.INSTANCE;
private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
private static final AbstractPluginPacketSender PACKET_SENDER = (AbstractPluginPacketSender) SingletonInjector.INSTANCE.get(IPluginPacketSender.class);
private static final DhLogger LOGGER = new DhLoggerBuilder().build(); private static final DhLogger LOGGER = new DhLoggerBuilder().build();
// TODO we shouldn't be filtering keys on the Forge/Fabric side, only in ClientApi private static final MinecraftClientWrapper MC = MinecraftClientWrapper.INSTANCE;
private static final int[] KEY_TO_CHECK_FOR = { GLFW.GLFW_KEY_F6, GLFW.GLFW_KEY_F8, GLFW.GLFW_KEY_P}; private static final AbstractPluginPacketSender PACKET_SENDER = (AbstractPluginPacketSender) SingletonInjector.INSTANCE.get(IPluginPacketSender.class);
private static final ClientApi clientApi = ClientApi.INSTANCE;
HashSet<Integer> previouslyPressKeyCodes = new HashSet<>(); HashSet<Integer> previouslyPressKeyCodes = new HashSet<>();
@@ -336,23 +339,13 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
{ {
HashSet<Integer> currentKeyDown = new HashSet<>(); HashSet<Integer> currentKeyDown = new HashSet<>();
// Note: Minecraft's InputConstants is same as GLFW Key values // Note: Minecraft's InputConstants are the same as GLFW Key values
//TODO: Use mixin to hook directly into the GLFW Keyboard event in minecraft KeyboardHandler for (int keyCode = GLFW.GLFW_KEY_0; keyCode <= GLFW.GLFW_KEY_LAST; keyCode++)
// Check all keys we need
for (int keyCode = GLFW.GLFW_KEY_A; keyCode <= GLFW.GLFW_KEY_Z; keyCode++)
{ {
//if (InputConstants.isKeyDown(Minecraft.getInstance().getWindow().getWindow(), keyCode)) if (InputConstants.isKeyDown(MC.getGlfwWindowId(), keyCode))
//{ {
// currentKeyDown.add(keyCode); currentKeyDown.add(keyCode);
//} }
}
for (int keyCode : KEY_TO_CHECK_FOR)
{
//if (InputConstants.isKeyDown(Minecraft.getInstance().getWindow().getWindow(), keyCode))
//{
// currentKeyDown.add(keyCode);
//}
} }
// Diff and trigger events // Diff and trigger events
@@ -137,24 +137,24 @@ public class MixinOptionsScreen extends Screen
if (this.optionsButton == null) if (this.optionsButton == null)
{ {
this.optionsButton this.optionsButton
= new TexturedButtonWidget( = new TexturedButtonWidget(
// Where the button is on the screen // Where the button is on the screen
this.width / 2 - 180, this.height / 6 - 12, this.width / 2 - 180, this.height / 6 - 12,
// Width and height of the button // Width and height of the button
20, 20, 20, 20,
// texture UV Offset // texture UV Offset
0, 0, 0, 0,
// Some textuary stuff // Some textuary stuff
20, ICON_TEXTURE, 20, 40, 20, ICON_TEXTURE, 20, 40,
// Create the button and tell it where to go // Create the button and tell it where to go
// For now it goes to the client option by default // For now it goes to the client option by default
(buttonWidget) -> Objects.requireNonNull(this.minecraft).setScreen(GetConfigScreen.getScreen(this)), (buttonWidget) -> Objects.requireNonNull(this.minecraft).setScreen(GetConfigScreen.getScreen(this)),
// Add a title to the button // Add a title to the button
#if MC_VER < MC_1_19_2 #if MC_VER < MC_1_19_2
new TranslatableComponent(ModInfo.ID + ".title")); new TranslatableComponent(ModInfo.ID + ".title"));
#else #else
Component.translatable(ModInfo.ID + ".title")); Component.translatable(ModInfo.ID + ".title"));
#endif #endif
} }
return this.optionsButton; return this.optionsButton;
@@ -67,9 +67,11 @@ public class MixinFogRenderer
Entity entity = camera.getEntity(); Entity entity = camera.getEntity();
boolean isSpecialFog = (entity instanceof LivingEntity) && ((LivingEntity) entity).hasEffect(MobEffects.BLINDNESS); boolean isSpecialFog = (entity instanceof LivingEntity) && ((LivingEntity) entity).hasEffect(MobEffects.BLINDNESS);
if (!isSpecialFog && cameraNotInFluid && fogMode == FogMode.FOG_TERRAIN if (!isSpecialFog
&& !SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class).isFogStateSpecial() && cameraNotInFluid
&& Config.Client.Advanced.Graphics.Fog.disableVanillaFog.get()) && fogMode == FogMode.FOG_TERRAIN
&& !SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class).isFogStateSpecial()
&& !Config.Client.Advanced.Graphics.Fog.enableVanillaFog.get())
{ {
#if MC_VER < MC_1_17_1 #if MC_VER < MC_1_17_1
RenderSystem.fogStart(A_REALLY_REALLY_BIG_VALUE); RenderSystem.fogStart(A_REALLY_REALLY_BIG_VALUE);
@@ -57,25 +57,27 @@ public class MixinOptionsScreen extends Screen
private void lodconfig$init(CallbackInfo ci) private void lodconfig$init(CallbackInfo ci)
{ {
if (Config.Client.showDhOptionsButtonInMinecraftUi.get()) if (Config.Client.showDhOptionsButtonInMinecraftUi.get())
{
this. #if MC_VER < MC_1_17_1 addButton #else addRenderableWidget #endif this. #if MC_VER < MC_1_17_1 addButton #else addRenderableWidget #endif
(new TexturedButtonWidget( (new TexturedButtonWidget(
// Where the button is on the screen // Where the button is on the screen
this.width / 2 - 180, this.height / 6 - 12, this.width / 2 - 180, this.height / 6 - 12,
// Width and height of the button // Width and height of the button
20, 20, 20, 20,
// Offset // Offset
0, 0, 0, 0,
// Some textuary stuff // Some textuary stuff
20, ICON_TEXTURE, 20, 40, 20, ICON_TEXTURE, 20, 40,
// Create the button and tell it where to go // Create the button and tell it where to go
// For now it goes to the client option by default // For now it goes to the client option by default
(buttonWidget) -> Objects.requireNonNull(minecraft).setScreen(GetConfigScreen.getScreen(this)), (buttonWidget) -> Objects.requireNonNull(minecraft).setScreen(GetConfigScreen.getScreen(this)),
// Add a title to the button // Add a title to the button
#if MC_VER < MC_1_19_2 #if MC_VER < MC_1_19_2
new TranslatableComponent(ModInfo.ID + ".title"))); new TranslatableComponent(ModInfo.ID + ".title")));
#else #else
Component.translatable(ModInfo.ID + ".title"))); Component.translatable(ModInfo.ID + ".title")));
#endif #endif
}
} }
} }
+3 -4
View File
@@ -12,14 +12,13 @@ issueTrackerURL = "${issues}"
#//updateJSONURL="https://change.me.example.invalid/updates.json" # A URL to query for updates for this mod. See the JSON update specification https://mcforge.readthedocs.io/en/latest/gettingstarted/autoupdate/ #//updateJSONURL="https://change.me.example.invalid/updates.json" # A URL to query for updates for this mod. See the JSON update specification https://mcforge.readthedocs.io/en/latest/gettingstarted/autoupdate/
displayURL = "${homepage}" displayURL = "${homepage}"
description = "${description}" #//mandatory. The description text for the mod description = "${description}" #//mandatory. The description text for the mod
logoFile = "assets/distanthorizons/logo.png" logoFile = "dh_forge_logo.png" #// can't contain a file path due to an old forge limitation https://github.com/MinecraftForge/MinecraftForge/issues/7348
catalogueImageIcon = "assets/distanthorizons/icon.png" catalogueImageIcon = "dh_forge_icon.png" #// can't contain a file path due to an old forge limitation https://github.com/MinecraftForge/MinecraftForge/issues/7348
credits = "Massive thanks to all the developers for their hard work to bring Distant Horizons to where it is today. - James" credits = "Massive thanks to all the developers for their hard work to bring Distant Horizons to where it is today. - James"
#// if not set defaults to "false" #// if not set defaults to "false"
clientSideOnly = "true" clientSideOnly = "true"
#// if not set side defaults to "BOTH" #// if not set side defaults to "BOTH"
#// TODO change to "BOTH" when we add server support side = "BOTH"
side = "CLIENT"
#// Allow any version to be present (or not) on the server #// Allow any version to be present (or not) on the server
acceptableRemoteVersions = "*" acceptableRemoteVersions = "*"
-10
View File
@@ -1,10 +0,0 @@
{
"pack": {
"pack_format": 7,
"supported_formats": {
"min_inclusive": 7,
"max_inclusive": 90000
},
"description": "Distant Horizons"
}
}
+3 -3
View File
@@ -5,8 +5,8 @@ org.gradle.caching=true
# Mod Info # Mod Info
mod_name=DistantHorizons mod_name=DistantHorizons
mod_version=2.4.2-b mod_version=2.4.6-b-dev
api_version=5.0.0 api_version=5.1.0
maven_group=com.seibel.distanthorizons maven_group=com.seibel.distanthorizons
mod_readable_name=Distant Horizons mod_readable_name=Distant Horizons
mod_description=This mod generates and renders simplified terrain beyond the normal view distance at a low performance cost. Allowing you to see much farther without turning your game into a slideshow. mod_description=This mod generates and renders simplified terrain beyond the normal view distance at a low performance cost. Allowing you to see much farther without turning your game into a slideshow.
@@ -18,7 +18,7 @@ mod_issues=https://gitlab.com/jeseibel/distant-horizons/-/issues
mod_discord=https://discord.gg/xAB8G4cENx mod_discord=https://discord.gg/xAB8G4cENx
# Global Plugin Versions # Global Plugin Versions
manifold_version=2025.1.27 manifold_version=2025.1.28
# 2023.1.17 can be used if there are mystery Java compiler issues # 2023.1.17 can be used if there are mystery Java compiler issues
nightconfig_version=3.6.6 nightconfig_version=3.6.6
lz4_version=1.8.0 lz4_version=1.8.0
@@ -45,7 +45,7 @@ public class NeoforgeMinecraftRenderWrapper extends MinecraftRenderWrapper
this.depthTextureCastFailLogged = true; this.depthTextureCastFailLogged = true;
LOGGER.error("Unable to cast render Target depth texture to GlTexture. MC or a rendering mod may have changed the object type.", e); LOGGER.error("Unable to cast render Target depth texture to GlTexture. MC or a rendering mod may have changed the object type.", e);
} }
return 0; return -1;
} }
#endif #endif
} }
@@ -72,7 +72,7 @@ public class NeoforgeMinecraftRenderWrapper extends MinecraftRenderWrapper
this.colorTextureCastFailLogged = true; this.colorTextureCastFailLogged = true;
LOGGER.error("Unable to cast render Target color texture to ValidationGpuTexture or GlTexture. MC, Neoforge, or a rendering mod may have changed the object type.", e); LOGGER.error("Unable to cast render Target color texture to ValidationGpuTexture or GlTexture. MC, Neoforge, or a rendering mod may have changed the object type.", e);
} }
return 0; return -1;
} }
#endif #endif
} }
-10
View File
@@ -1,10 +0,0 @@
{
"pack": {
"pack_format": 7,
"supported_formats": {
"min_inclusive": 7,
"max_inclusive": 90000
},
"description": "Distant Horizons"
}
}
+2 -2
View File
@@ -10,8 +10,8 @@ builds_for=fabric,forge
netty_version=4.1.82.Final netty_version=4.1.82.Final
# Fabric loader # Fabric loader
fabric_loader_version=0.15.6 fabric_loader_version=0.16.10
fabric_api_version=0.90.4+1.20.1 fabric_api_version=0.92.6+1.20.1
# Fabric mod versions # Fabric mod versions
modmenu_version=7.2.2 modmenu_version=7.2.2
starlight_version_fabric= starlight_version_fabric=