Compare commits

...

16 Commits

Author SHA1 Message Date
James Seibel 3597d69fa4 remove dev from version number 2025-10-13 17:45:45 -05:00
James Seibel ab10265150 Fix 1.21.9 missing fabric resource loader v1 2025-10-13 17:45:45 -05:00
s809 671ee84136 Handle server keyed level wrappers correctly 2025-10-13 18:07:06 +05:00
James Seibel c489cebae3 Fix world gen progress ui button 2025-10-13 07:43:02 -05:00
James Seibel e55eeda1ac Improve config gui object casting 2025-10-13 07:35:53 -05:00
James Seibel 0086f40053 bug fixing for major config refactoring 2025-10-12 21:11:16 -05:00
James Seibel 71bb151e61 Fix 1.21.10 compile typo 2025-10-12 19:41:42 -05:00
James Seibel a71ceac15d Fix forge compiling 2025-10-12 19:41:03 -05:00
James Seibel ada36c34c7 minor client wrapper refactor for clarity 2025-10-12 15:30:20 -05:00
James Seibel 3cfb4386d9 set default dev version to 1.21.10 2025-10-12 15:07:23 -05:00
James Seibel 352d0f4759 re-add MC 1.21.9 support 2025-10-12 15:04:31 -05:00
James Seibel d158a89592 Fix neoforge rendering 2025-10-12 15:02:09 -05:00
James Seibel 9cc826f8a9 Fix client tinted biomes 2025-10-12 14:49:32 -05:00
James Seibel 22a4c6bc79 Fix neoforge server startup crash 2025-10-12 14:05:27 -05:00
James Seibel 20b9f4f1cb Fix stuttering when flying over un-generated chunks 2025-10-12 13:58:03 -05:00
James Seibel 5c0c1c5e20 up version number 2.3.5 -> 2.3.6 2025-10-11 20:55:45 -05:00
40 changed files with 560 additions and 298 deletions
+1 -1
View File
@@ -36,7 +36,7 @@ build:
parallel:
matrix:
- MC_VER: [
"1.21.10", "1.21.8", "1.21.6", "1.21.5", "1.21.4", "1.21.3", "1.21.1",
"1.21.10", "1.21.9", "1.21.8", "1.21.6", "1.21.5", "1.21.4", "1.21.3", "1.21.1",
"1.20.6", "1.20.4", "1.20.2", "1.20.1",
"1.19.4", "1.19.2",
"1.18.2",
@@ -10,7 +10,7 @@ import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftServerWrapp
import com.seibel.distanthorizons.core.api.internal.ClientApi;
import com.seibel.distanthorizons.core.api.internal.SharedApi;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.config.ConfigBase;
import com.seibel.distanthorizons.core.config.ConfigHandler;
import com.seibel.distanthorizons.core.config.eventHandlers.presets.ThreadPresetConfigEventHandler;
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
@@ -46,7 +46,8 @@ public abstract class AbstractModInitializer
// abstract methods //
//==================//
protected abstract void createInitialBindings();
protected abstract void createInitialSharedBindings();
protected abstract void createInitialClientBindings();
protected abstract IEventProxy createClientProxy();
protected abstract IEventProxy createServerProxy(boolean isDedicated);
protected abstract void initializeModCompat();
@@ -66,6 +67,7 @@ public abstract class AbstractModInitializer
public void onInitializeClient()
{
DependencySetup.createClientBindings();
this.createInitialClientBindings();
LOGGER.info("Initializing " + ModInfo.READABLE_NAME + " client, firing DhApiBeforeDhInitEvent...");
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeDhInitEvent.class, null);
@@ -84,7 +86,7 @@ public abstract class AbstractModInitializer
LOGGER.info(ModInfo.READABLE_NAME + " client Initialized.");
#if MC_VER < MC_1_21_10
#if MC_VER < MC_1_21_9
// debug screen rendering handled via a mixin
#else
DhDebugScreenEntry.register();
@@ -140,7 +142,7 @@ public abstract class AbstractModInitializer
{
DependencySetup.createSharedBindings();
SharedApi.init();
this.createInitialBindings();
this.createInitialSharedBindings();
}
private void logBuildInfo()
@@ -168,7 +170,7 @@ public abstract class AbstractModInitializer
private void initConfig()
{
ConfigBase.RunFirstTimeSetup();
ConfigHandler.tryRunFirstTimeSetup();
Config.completeDelayedSetup();
}
@@ -190,6 +192,12 @@ public abstract class AbstractModInitializer
{
LOGGER.info("Running Delayed setup...");
this.runDelayedSetup();
if (ConfigHandler.INSTANCE == null)
{
throw new IllegalStateException("Config was not initialized. Make sure to call LodCommonMain.initConfig() before calling this method.");
}
LOGGER.info("Delayed setup complete, firing DhApiAfterDhInitEvent event...");
// should be fired after all delayed setup so singletons and config can be accessed
@@ -3,8 +3,8 @@ package com.seibel.distanthorizons.common.commands;
import com.mojang.brigadier.arguments.*;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.seibel.distanthorizons.core.config.ConfigBase;
import com.seibel.distanthorizons.core.config.types.AbstractConfigType;
import com.seibel.distanthorizons.core.config.ConfigHandler;
import com.seibel.distanthorizons.core.config.types.AbstractConfigBase;
import com.seibel.distanthorizons.core.config.types.ConfigEntry;
import net.minecraft.commands.CommandSourceStack;
@@ -43,7 +43,7 @@ public class ConfigCommand extends AbstractCommand
LiteralArgumentBuilder<CommandSourceStack> builder = literal("config");
HashSet<String> addedCommands = new HashSet<>();
for (AbstractConfigType<?, ?> type : ConfigBase.INSTANCE.entries)
for (AbstractConfigBase<?> type : ConfigHandler.INSTANCE.configBaseList)
{
// Skip non-config entries
if (!(type instanceof ConfigEntry))
@@ -79,6 +79,8 @@ public class VersionConstants implements IVersionConstants
#elif MC_VER == MC_1_21_8
return "1.21.8";
#elif MC_VER == MC_1_21_9
return "1.21.9";
#elif MC_VER == MC_1_21_10
return "1.21.10";
#else
@@ -2,15 +2,25 @@ package com.seibel.distanthorizons.common.wrappers.block;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.pos.DhSectionPos;
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPosMutable;
import com.seibel.distanthorizons.core.util.ColorUtil;
import com.seibel.distanthorizons.core.util.FullDataPointUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.ColorResolver;
import net.minecraft.world.level.biome.Biome;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.apache.logging.log4j.Logger;
#if MC_VER >= MC_1_18_2
import net.minecraft.core.Holder;
#endif
@@ -18,10 +28,20 @@ import net.minecraft.core.Holder;
public abstract class AbstractDhTintGetter implements BlockAndTintGetter
{
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
protected final BiomeWrapper biomeWrapper;
protected final int smoothingRadiusInBlocks;
protected final FullDataSourceV2 fullDataSource;
protected final IClientLevelWrapper clientLevelWrapper;
#if MC_VER < MC_1_18_2
public static final ConcurrentMap<String, Biome> BIOME_BY_RESOURCE_STRING = new ConcurrentHashMap<>();
#else
public static final ConcurrentMap<String, Holder<Biome>> BIOME_BY_RESOURCE_STRING = new ConcurrentHashMap<>();
#endif
@@ -29,10 +49,11 @@ public abstract class AbstractDhTintGetter implements BlockAndTintGetter
// constructor //
//=============//
public AbstractDhTintGetter(BiomeWrapper biomeWrapper, FullDataSourceV2 fullDataSource)
public AbstractDhTintGetter(BiomeWrapper biomeWrapper, FullDataSourceV2 fullDataSource, IClientLevelWrapper clientLevelWrapper)
{
this.biomeWrapper = biomeWrapper;
this.fullDataSource = fullDataSource;
this.clientLevelWrapper = clientLevelWrapper;
this.smoothingRadiusInBlocks = Config.Client.Advanced.Graphics.Quality.lodBiomeBlending.get();
}
@@ -57,7 +78,7 @@ public abstract class AbstractDhTintGetter implements BlockAndTintGetter
if (this.smoothingRadiusInBlocks == 0
|| dataSourceLodWidthInBlocks > this.smoothingRadiusInBlocks)
{
return colorResolver.getColor(this.unwrapBiome(this.biomeWrapper.biome), blockPos.getX(), blockPos.getZ());
return colorResolver.getColor(unwrapClientBiome(this.biomeWrapper.biome, this.clientLevelWrapper), blockPos.getX(), blockPos.getZ());
}
@@ -93,7 +114,7 @@ public abstract class AbstractDhTintGetter implements BlockAndTintGetter
// get the color for this nearby position
int id = FullDataPointUtil.getId(dataPoint);
BiomeWrapper biomeWrapper = (BiomeWrapper) this.fullDataSource.mapping.getBiomeWrapper(id);
int color = colorResolver.getColor(this.unwrapBiome(biomeWrapper.biome), mutableBlockPos.getX(), mutableBlockPos.getZ());
int color = colorResolver.getColor(unwrapClientBiome(biomeWrapper.biome, this.clientLevelWrapper), mutableBlockPos.getX(), mutableBlockPos.getZ());
// rolling average
@@ -110,7 +131,7 @@ public abstract class AbstractDhTintGetter implements BlockAndTintGetter
// just use the default center's color
if (dataPointCount == 0)
{
return colorResolver.getColor(this.unwrapBiome(this.biomeWrapper.biome), blockPos.getX(), blockPos.getZ());
return colorResolver.getColor(unwrapClientBiome(this.biomeWrapper.biome, this.clientLevelWrapper), blockPos.getX(), blockPos.getZ());
}
int colorInt = ColorUtil.argbToInt(
@@ -121,7 +142,23 @@ public abstract class AbstractDhTintGetter implements BlockAndTintGetter
return colorInt;
}
protected Biome unwrapBiome(#if MC_VER >= MC_1_18_2 Holder<Biome> #else Biome #endif biome)
protected static Biome unwrapClientBiome(#if MC_VER >= MC_1_18_2 Holder<Biome> #else Biome #endif biome, IClientLevelWrapper clientLevelWrapper)
{
BiomeWrapper biomeWrapper = (BiomeWrapper)BiomeWrapper.getBiomeWrapper(biome, clientLevelWrapper);
String biomeString = biomeWrapper.getSerialString();
if (biomeString == null
|| biomeString.isEmpty()
|| biomeString.equals(BiomeWrapper.EMPTY_BIOME_STRING))
{
// default to "plains" for empty/invalid biomes
biomeString = "minecraft:plains";
}
return unwrapBiome(getClientBiome(biomeString));
}
protected static Biome unwrapBiome(#if MC_VER >= MC_1_18_2 Holder<Biome> #else Biome #endif biome)
{
#if MC_VER >= MC_1_18_2
return biome.value();
@@ -130,6 +167,88 @@ public abstract class AbstractDhTintGetter implements BlockAndTintGetter
#endif
}
/**
* <p>Previously, this class might have immediately unwrapped the Holder like this:</p>
* <pre>{@code
* // Inside constructor (OLD WAY - PROBLEMATIC):
* Holder<Biome> biomeHolder = getTheHolderFromSomewhere();
* this.biome = biomeHolder.value(); // <-- PROBLEM HERE
* }</pre>
*
* <p>This approach is problematic because the {@link net.minecraft.core.Holder} system,
* particularly {@code Holder.Reference}, is designed for <strong>late binding</strong>. Here's why storing
* the Holder itself is now necessary:</p>
* <ol>
* <li>A {@code Holder.Reference<Biome>} might be created initially just with a
* {@link net.minecraft.resources.ResourceKey} (like {@code minecraft:plains}), but its actual
* {@link net.minecraft.core.Holder#value() value()} (the {@code Biome} object itself) might be {@code null}
* at construction time.</li>
* <li>Later, during game loading, registry population, or potentially due to modifications by other mods
* (e.g., Polytone), the system calls internal binding methods (like {@code bindValue(Biome)})
* on the {@code Holder} instance. This sets or <strong>updates</strong> the internal reference to the
* actual {@code Biome} object.</li>
* <li>Crucially, the binding process might assign a completely <strong>new</strong> {@code Biome} object
* instance to the {@code Holder} reference, replacing any previous one.</li>
* </ol>
*
* <p>If we unwrapped the {@code Holder} using {@code .value()} within the constructor (the old way),
* our class's internal {@code biome} field would permanently store a reference to whatever {@code Biome}
* object the {@code Holder} pointed to *at that exact moment*. It would have no link back to the
* {@code Holder} and would be unaware if the {@code Holder} was later updated to point to a different
* (or the initially missing) {@code Biome} object. This would lead to using stale or even {@code null} data.</p>
*
* <p>By storing the {@code Holder<Biome>} itself, this class can call {@link net.minecraft.core.Holder#value()}
* whenever the biome information is needed, ensuring it always retrieves the most current {@code Biome}
* instance associated with the holder at that time.</p>
*/
private static #if MC_VER < MC_1_18_2 Biome #else Holder<Biome> #endif getClientBiome(String biomeResourceString)
{
// cache the client biomes so we don't have to re-parse the resource location every time
return BIOME_BY_RESOURCE_STRING.compute(biomeResourceString,
(resourceString, existingBiome) ->
{
if (existingBiome != null)
{
return existingBiome;
}
ClientLevel clientLevel = Minecraft.getInstance().level;
if (clientLevel == null)
{
// shouldn't happen, but just in case
throw new IllegalStateException("Attempted to get client biome when no client level was loaded.");
}
BiomeWrapper.BiomeDeserializeResult result;
try
{
result = BiomeWrapper.deserializeBiome(resourceString, clientLevel.registryAccess());
}
catch (Exception e)
{
LOGGER.warn("Unable to deserialize client biome ["+resourceString+"], using fallback...");
try
{
result = BiomeWrapper.deserializeBiome(BiomeWrapper.PLAINS_RESOURCE_LOCATION_STRING, clientLevel.registryAccess());
}
catch (IOException ex)
{
// should never happen, if it does this log will explode, but just in case
LOGGER.error("Unable to deserialize fallback client biome ["+BiomeWrapper.PLAINS_RESOURCE_LOCATION_STRING+"], returning NULL.");
return null;
}
}
if (result.success)
{
existingBiome = result.biome;
}
return existingBiome;
});
}
}
@@ -103,6 +103,7 @@ public class BiomeWrapper implements IBiomeWrapper
// constructors //
//==============//
// TODO why not just return BiomeWrapper?
static public IBiomeWrapper getBiomeWrapper(#if MC_VER < MC_1_18_2 Biome #else Holder<Biome> #endif biome, ILevelWrapper levelWrapper)
{
if (biome == null)
@@ -20,7 +20,6 @@
package com.seibel.distanthorizons.common.wrappers.block;
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos;
@@ -464,7 +463,7 @@ public class ClientBlockStateColorCache
// public getter //
//===============//
public int getColor(BiomeWrapper biome, FullDataSourceV2 fullDataSource, DhBlockPos pos)
public int getColor(BiomeWrapper biomeWrapper, FullDataSourceV2 fullDataSource, DhBlockPos pos)
{
// only get the tint if the block needs to be tinted
if (!this.needPostTinting)
@@ -490,14 +489,14 @@ public class ClientBlockStateColorCache
{
tintColor = Minecraft.getInstance().getBlockColors()
.getColor(this.blockState,
new TintWithoutLevelSmoothOverrider(biome, fullDataSource), // TODO can this object be cached?
new TintWithoutLevelOverrider(biomeWrapper, fullDataSource, this.clientLevelWrapper), // TODO can this object be cached?
McObjectConverter.Convert(pos),
this.tintIndex);
}
catch (UnsupportedOperationException e)
{
// this exception generally occurs if the tint requires other blocks besides itself
LOGGER.debug("Unable to use ["+TintWithoutLevelSmoothOverrider.class.getSimpleName()+"] to get the block tint for block: [" + this.blockState + "] and biome: [" + biome + "] at pos: " + pos + ". Error: [" + e.getMessage() + "]. Attempting to use backup method...", e);
LOGGER.debug("Unable to use ["+ TintWithoutLevelOverrider.class.getSimpleName()+"] to get the block tint for block: [" + this.blockState + "] and biome: [" + biomeWrapper + "] at pos: " + pos + ". Error: [" + e.getMessage() + "]. Attempting to use backup method...", e);
BLOCK_STATES_THAT_NEED_LEVEL.add(this.blockState);
}
}
@@ -509,7 +508,7 @@ public class ClientBlockStateColorCache
// specifically oceans don't render correctly
tintColor = Minecraft.getInstance().getBlockColors()
.getColor(this.blockState,
new TintGetterOverrideSmooth(this.level, biome, fullDataSource), // TODO can this object be cached?
new TintGetterOverride(this.level, biomeWrapper, fullDataSource, this.clientLevelWrapper), // TODO can this object be cached?
McObjectConverter.Convert(pos),
this.tintIndex);
}
@@ -519,7 +518,7 @@ public class ClientBlockStateColorCache
// only display the error once per block/biome type to reduce log spam
if (!BROKEN_BLOCK_STATES.contains(this.blockState))
{
LOGGER.warn("Failed to get block color for block: [" + this.blockState + "] and biome: [" + biome + "] at pos: " + pos + ". Error: ["+e.getMessage() + "]. Note: future errors for this block/biome will be ignored.", e);
LOGGER.warn("Failed to get block color for block: [" + this.blockState + "] and biome: [" + biomeWrapper + "] at pos: " + pos + ". Error: ["+e.getMessage() + "]. Note: future errors for this block/biome will be ignored.", e);
BROKEN_BLOCK_STATES.add(this.blockState);
}
}
@@ -20,6 +20,7 @@
package com.seibel.distanthorizons.common.wrappers.block;
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.*;
@@ -38,7 +39,7 @@ import java.util.Optional;
import java.util.function.Supplier;
import java.util.stream.Stream;
public class TintGetterOverrideSmooth extends AbstractDhTintGetter
public class TintGetterOverride extends AbstractDhTintGetter
{
private final LevelReader parent;
@@ -48,9 +49,9 @@ public class TintGetterOverrideSmooth extends AbstractDhTintGetter
// constructor //
//=============//
public TintGetterOverrideSmooth(LevelReader parent, BiomeWrapper biomeWrapper, FullDataSourceV2 fullDataSource)
public TintGetterOverride(LevelReader parent, BiomeWrapper biomeWrapper, FullDataSourceV2 fullDataSource, IClientLevelWrapper clientLevelWrapper)
{
super(biomeWrapper, fullDataSource);
super(biomeWrapper, fullDataSource, clientLevelWrapper);
this.parent = parent;
}
@@ -20,6 +20,7 @@
package com.seibel.distanthorizons.common.wrappers.block;
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.block.entity.BlockEntity;
@@ -28,15 +29,15 @@ import net.minecraft.world.level.lighting.LevelLightEngine;
import net.minecraft.world.level.material.FluidState;
import org.jetbrains.annotations.Nullable;
public class TintWithoutLevelSmoothOverrider extends AbstractDhTintGetter
public class TintWithoutLevelOverrider extends AbstractDhTintGetter
{
//=============//
// constructor //
//=============//
public TintWithoutLevelSmoothOverrider(BiomeWrapper biomeWrapper, FullDataSourceV2 fullDataSource)
{ super(biomeWrapper, fullDataSource); }
public TintWithoutLevelOverrider(BiomeWrapper biomeWrapper, FullDataSourceV2 fullDataSource, IClientLevelWrapper clientLevelWrapper)
{ super(biomeWrapper, fullDataSource, clientLevelWrapper); }
@@ -46,21 +47,21 @@ public class TintWithoutLevelSmoothOverrider extends AbstractDhTintGetter
@Override
public float getShade(Direction direction, boolean shade)
{ throw new UnsupportedOperationException("ERROR: getShade() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); }
{ throw new UnsupportedOperationException("ERROR: getShade() called on TintWithoutLevelOverrider. Object is for tinting only."); }
@Override
public LevelLightEngine getLightEngine()
{ throw new UnsupportedOperationException("ERROR: getLightEngine() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); }
{ throw new UnsupportedOperationException("ERROR: getLightEngine() called on TintWithoutLevelOverrider. Object is for tinting only."); }
@Nullable
@Override
public BlockEntity getBlockEntity(BlockPos pos)
{ throw new UnsupportedOperationException("ERROR: getBlockEntity() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); }
{ throw new UnsupportedOperationException("ERROR: getBlockEntity() called on TintWithoutLevelOverrider. Object is for tinting only."); }
@Override
public BlockState getBlockState(BlockPos pos)
{ throw new UnsupportedOperationException("ERROR: getBlockState() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); }
{ throw new UnsupportedOperationException("ERROR: getBlockState() called on TintWithoutLevelOverrider. Object is for tinting only."); }
@Override
public FluidState getFluidState(BlockPos pos)
{ throw new UnsupportedOperationException("ERROR: getFluidState() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); }
{ throw new UnsupportedOperationException("ERROR: getFluidState() called on TintWithoutLevelOverrider. Object is for tinting only."); }
//==============//
@@ -71,7 +72,7 @@ public class TintWithoutLevelSmoothOverrider extends AbstractDhTintGetter
@Override
public int getHeight()
{ throw new UnsupportedOperationException("ERROR: getHeight() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); }
{ throw new UnsupportedOperationException("ERROR: getHeight() called on TintWithoutLevelOverrider. Object is for tinting only."); }
#if MC_VER < MC_1_21_3
@Override
@@ -80,7 +81,7 @@ public class TintWithoutLevelSmoothOverrider extends AbstractDhTintGetter
#else
@Override
public int getMinY()
{ throw new UnsupportedOperationException("ERROR: getMinY() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); }
{ throw new UnsupportedOperationException("ERROR: getMinY() called on TintWithoutLevelOverrider. Object is for tinting only."); }
#endif
#endif
@@ -7,31 +7,22 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.regex.Pattern;
// Logger (for debug stuff)
import com.seibel.distanthorizons.api.enums.config.DisallowSelectingViaConfigGui;
import com.seibel.distanthorizons.common.wrappers.gui.config.ConfigGuiInfo;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.config.ConfigBase;
import com.seibel.distanthorizons.core.config.ConfigHandler;
import com.seibel.distanthorizons.core.config.types.*;
import com.seibel.distanthorizons.common.wrappers.gui.updater.ChangelogScreen;
// Uses https://github.com/TheElectronWill/night-config for toml (only for Fabric since Forge already includes this)
// Gets info from our own mod
// Minecraft imports
import com.seibel.distanthorizons.core.config.types.enums.EConfigCommentTextPosition;
import com.seibel.distanthorizons.core.config.types.enums.EConfigValidity;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.jar.updater.SelfUpdater;
import com.seibel.distanthorizons.core.logging.ConfigBasedSpamLogger;
import com.seibel.distanthorizons.core.logging.SpamReducedLogger;
import com.seibel.distanthorizons.core.render.renderer.LodRenderer;
import com.seibel.distanthorizons.core.util.AnnotationUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.config.IConfigGui;
import com.seibel.distanthorizons.core.wrapperInterfaces.config.ILangWrapper;
@@ -50,6 +41,7 @@ import net.minecraft.resources.ResourceLocation;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
#if MC_VER < MC_1_20_1
@@ -111,16 +103,6 @@ public class ClassicConfigGUI
}
// TODO
/** The terribly coded old stuff */
public static class EntryInfo
{
Object widget;
Map.Entry<EditBox, Component> error;
String tempValue;
int index;
}
//==============//
@@ -128,10 +110,9 @@ public class ClassicConfigGUI
//==============//
/** if you want to get this config gui's screen call this */
public static Screen getScreen(ConfigBase configBase, Screen parent, String category)
{ return new ConfigScreen(configBase, parent, category); }
public static Screen getScreen(Screen parent, String category)
{ return new ConfigScreen(parent, category); }
/** Pain */
private static class ConfigScreen extends DhScreen
{
private static final ILangWrapper LANG_WRAPPER = SingletonInjector.INSTANCE.get(ILangWrapper.class);
@@ -139,8 +120,6 @@ public class ClassicConfigGUI
private static final String TRANSLATION_PREFIX = ModInfo.ID + ".config.";
private final ConfigBase configBase;
private final Screen parent;
private final String category;
private ConfigListWidget configListWidget;
@@ -154,14 +133,13 @@ public class ClassicConfigGUI
// constructor //
//=============//
protected ConfigScreen(ConfigBase configBase, Screen parent, String category)
protected ConfigScreen(Screen parent, String category)
{
super(Translatable(
LANG_WRAPPER.langExists(ModInfo.ID + ".config" + (category.isEmpty() ? "." + category : "") + ".title") ?
ModInfo.ID + ".config.title" :
ModInfo.ID + ".config" + (category.isEmpty() ? "" : "." + category) + ".title")
);
this.configBase = configBase;
this.parent = parent;
this.category = category;
}
@@ -182,7 +160,7 @@ public class ClassicConfigGUI
super.init();
if (!this.reload)
{
ConfigBase.INSTANCE.configFileHandler.loadFromFile();
ConfigHandler.INSTANCE.configFileHandler.loadFromFile();
}
// Changelog button
@@ -229,7 +207,7 @@ public class ClassicConfigGUI
ConfigScreenConfigs.OPTION_FIELD_WIDTH, ConfigScreenConfigs.OPTION_FIELD_HEIGHT,
(button) ->
{
ConfigBase.INSTANCE.configFileHandler.loadFromFile();
ConfigHandler.INSTANCE.configFileHandler.loadFromFile();
Objects.requireNonNull(this.minecraft).setScreen(this.parent);
}));
@@ -240,7 +218,7 @@ public class ClassicConfigGUI
ConfigScreenConfigs.OPTION_FIELD_WIDTH, ConfigScreenConfigs.OPTION_FIELD_HEIGHT,
(button) ->
{
ConfigBase.INSTANCE.configFileHandler.saveToFile();
ConfigHandler.INSTANCE.configFileHandler.saveToFile();
Objects.requireNonNull(this.minecraft).setScreen(this.parent);
}));
@@ -255,22 +233,22 @@ public class ClassicConfigGUI
this.addWidget(this.configListWidget);
for (AbstractConfigType info : ConfigBase.INSTANCE.entries)
for (AbstractConfigBase<?> configEntry : ConfigHandler.INSTANCE.configBaseList)
{
try
{
if (info.getCategory().matches(this.category)
&& info.getAppearance().showInGui)
if (configEntry.getCategory().matches(this.category)
&& configEntry.getAppearance().showInGui)
{
this.addMenuItem(info);
this.addMenuItem(configEntry);
}
}
catch (Exception e)
{
String message = "ERROR: Failed to show [" + info.getNameWCategory() + "], error: ["+e.getMessage()+"]";
if (info.get() != null)
String message = "ERROR: Failed to show [" + configEntry.getNameAndCategory() + "], error: ["+e.getMessage()+"]";
if (configEntry.get() != null)
{
message += " with the value [" + info.get() + "] with type [" + info.getType() + "]";
message += " with the value [" + configEntry.get() + "] with type [" + configEntry.getType() + "]";
}
LOGGER.error(message, e);
@@ -279,115 +257,63 @@ public class ClassicConfigGUI
CONFIG_CORE_INTERFACE.onScreenChangeListenerList.forEach((listener) -> listener.run());
}
private void addMenuItem(AbstractConfigType configType)
private void addMenuItem(AbstractConfigBase<?> configEntry)
{
trySetupConfigEntry(configType);
trySetupConfigEntry(configEntry);
if (this.tryCreateInputField(configType)) return;
if (this.tryCreateCategoryButton(configType)) return;
if (this.tryCreateButton(configType)) return;
if (this.tryCreateComment(configType)) return;
if (this.tryCreateSpacer(configType)) return;
if (this.tryCreateLinkedEntry(configType)) return;
if (this.tryCreateInputField(configEntry)) return;
if (this.tryCreateCategoryButton(configEntry)) return;
if (this.tryCreateButton(configEntry)) return;
if (this.tryCreateComment(configEntry)) return;
if (this.tryCreateSpacer(configEntry)) return;
if (this.tryCreateLinkedEntry(configEntry)) return;
LOGGER.warn("Config [" + configType.getNameWCategory() + "] failed to show. Please try something like changing its type.");
LOGGER.warn("Config [" + configEntry.getNameAndCategory() + "] failed to show. Please try something like changing its type.");
}
private static void trySetupConfigEntry(AbstractConfigType configType)
private static void trySetupConfigEntry(AbstractConfigBase<?> configMenuOption)
{
configType.guiValue = new EntryInfo();
Class<?> fieldClass = configType.getType();
configMenuOption.guiValue = new ConfigGuiInfo();
Class<?> configValueClass = configMenuOption.getType();
if (configType instanceof ConfigEntry)
if (configMenuOption instanceof ConfigEntry)
{
ConfigEntry configEntry = (ConfigEntry) configType;
ConfigEntry<?> configEntry = (ConfigEntry<?>) configMenuOption;
if (fieldClass == Integer.class)
if (configValueClass == Integer.class)
{
// For int
setupEntryInfoTextField(configEntry, Integer::parseInt, INTEGER_ONLY_REGEX, true);
setupTextMenuOption(configEntry, Integer::parseInt, INTEGER_ONLY_REGEX, true);
}
else if (fieldClass == Double.class)
else if (configValueClass == Double.class)
{
// For double
setupEntryInfoTextField(configEntry, Double::parseDouble, DECIMAL_ONLY_REGEX, false);
setupTextMenuOption(configEntry, Double::parseDouble, DECIMAL_ONLY_REGEX, false);
}
else if (fieldClass == String.class || fieldClass == List.class)
else if (configValueClass == String.class || configValueClass == List.class)
{
// For string or list
setupEntryInfoTextField(configEntry, String::length, null, true);
setupTextMenuOption(configEntry, String::length, null, true);
}
else if (fieldClass == Boolean.class)
else if (configValueClass == Boolean.class)
{
// For boolean
Function<Object, Component> func = value -> Translatable("distanthorizons.general."+((Boolean) value ? "true" : "false")).withStyle((Boolean) value ? ChatFormatting.GREEN : ChatFormatting.RED);
((EntryInfo) configEntry.guiValue).widget =
new AbstractMap.SimpleEntry<Button.OnPress, Function<Object, Component>>(
(button) ->
{
button.active = !configEntry.apiIsOverriding();
configEntry.uiSetWithoutSaving(!(Boolean) configEntry.get());
button.setMessage(func.apply(configEntry.get()));
}, func);
ConfigEntry<Boolean> booleanConfigEntry = (ConfigEntry<Boolean>) configEntry;
setupBooleanMenuOption(booleanConfigEntry);
}
else if (fieldClass.isEnum())
else if (configValueClass.isEnum())
{
// For enum
List<?> values = Arrays.asList(configEntry.getType().getEnumConstants());
Function<Object, Component> func = (value) -> Translatable(TRANSLATION_PREFIX + "enum." + fieldClass.getSimpleName() + "." + configEntry.get().toString());
((EntryInfo) configEntry.guiValue).widget = new AbstractMap.SimpleEntry<Button.OnPress, Function<Object, Component>>((button) ->
{
// get the currently selected enum and enum index
int startingIndex = values.indexOf(configEntry.get());
Enum<?> enumValue = (Enum<?>) values.get(startingIndex);
// search for the next enum that is selectable
int index = startingIndex + 1;
index = (index >= values.size()) ? 0 : index;
while (index != startingIndex)
{
enumValue = (Enum<?>) values.get(index);
if (!AnnotationUtil.doesEnumHaveAnnotation(enumValue, DisallowSelectingViaConfigGui.class))
{
// this enum shouldn't be selectable via the UI,
// skip it
break;
}
index++;
index = (index >= values.size()) ? 0 : index;
}
if (index == startingIndex)
{
// none of the enums should be selectable, this is a programmer error
enumValue = (Enum<?>) values.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 + "].");
}
((ConfigEntry<Enum<?>>) configEntry).uiSetWithoutSaving(enumValue);
if (configEntry.getApiValue() != null)
{
button.active = false;
}
else
{
button.active = true;
}
button.setMessage(func.apply(configEntry.get()));
}, func);
ConfigEntry<Enum<?>> enumConfigEntry = (ConfigEntry<Enum<?>>) configEntry;
Class<? extends Enum<?>> configEnumClass = (Class<? extends Enum<?>>) configValueClass;
setupEnumMenuOption(enumConfigEntry, configEnumClass);
}
}
}
private static void setupEntryInfoTextField(AbstractConfigType info, Function<String, Number> func, Pattern pattern, boolean cast)
private static void setupTextMenuOption(AbstractConfigBase<?> configMenuOption, Function<String, Number> parsingFunc, @Nullable Pattern pattern, boolean cast)
{
((EntryInfo) info.guiValue).widget = (BiFunction<EditBox, Button, Predicate<String>>) (editBox, button) -> stringValue ->
final ConfigGuiInfo configGuiInfo = ((ConfigGuiInfo) configMenuOption.guiValue);
configGuiInfo.tooltipFunction =
(editBox, button) ->
(stringValue) ->
{
boolean isNumber = (pattern != null);
@@ -398,67 +324,137 @@ public class ClassicConfigGUI
}
Number value = info.typeIsFloatingPointNumber() ? 0.0 : 0; // different default values are needed so implicit casting works correctly (if not done casting from 0 (an int) to a double will cause an exception)
((EntryInfo) info.guiValue).error = null;
if (isNumber && !stringValue.isEmpty() && !stringValue.equals("-") && !stringValue.equals("."))
Number numberValue = configMenuOption.typeIsFloatingPointNumber() ? 0.0 : 0; // different default values are needed so implicit casting works correctly (if not done casting from 0 (an int) to a double will cause an exception)
configGuiInfo.errorMessage = null;
if (isNumber
&& !stringValue.isEmpty()
&& !stringValue.equals("-")
&& !stringValue.equals("."))
{
ConfigEntry<Number> numberConfigEntry = (ConfigEntry<Number>) configMenuOption;
try
{
value = func.apply(stringValue);
numberValue = parsingFunc.apply(stringValue);
}
catch (Exception e)
{
value = null;
numberValue = null;
}
byte isValid = ((ConfigEntry) info).isValid(value);
switch (isValid)
EConfigValidity validity = numberConfigEntry.getValidity(numberValue);
switch (validity)
{
case 0:
((EntryInfo) info.guiValue).error = null;
case VALID:
configGuiInfo.errorMessage = null;
break;
case -1:
((EntryInfo) info.guiValue).error = new AbstractMap.SimpleEntry<>(editBox, TextOrTranslatable("§cMinimum length is " + ((ConfigEntry) info).getMin()));
case NUMBER_TOO_LOW:
configGuiInfo.errorMessage = TextOrTranslatable("§cMinimum length is " + numberConfigEntry.getMin());
break;
case 1:
((EntryInfo) info.guiValue).error = new AbstractMap.SimpleEntry<>(editBox, TextOrTranslatable("§cMaximum length is " + ((ConfigEntry) info).getMax()));
case NUMBER_TOO_HIGH:
configGuiInfo.errorMessage = TextOrTranslatable("§cMaximum length is " + numberConfigEntry.getMax());
break;
case 2:
((EntryInfo) info.guiValue).error = new AbstractMap.SimpleEntry<>(editBox, TextOrTranslatable("§cValue is invalid"));
case INVALID:
configGuiInfo.errorMessage = TextOrTranslatable("§cValue is invalid");
break;
}
}
((EntryInfo) info.guiValue).tempValue = stringValue;
editBox.setTextColor(((ConfigEntry) info).isValid(value) == 0 ? 0xFFFFFFFF : 0xFFFF7777); // white and red
editBox.setTextColor(((ConfigEntry<Number>) configMenuOption).getValidity(numberValue) == EConfigValidity.VALID ? 0xFFFFFFFF : 0xFFFF7777); // white and red
if (info.getType() == String.class
|| info.getType() == List.class)
if (configMenuOption.getType() == String.class
|| configMenuOption.getType() == List.class)
{
((ConfigEntry) info).uiSetWithoutSaving(stringValue);
((ConfigEntry<String>) configMenuOption).uiSetWithoutSaving(stringValue);
}
else if (((ConfigEntry) info).isValid(value) == 0)
else if (((ConfigEntry<Number>) configMenuOption).getValidity(numberValue) == EConfigValidity.VALID)
{
if (!cast)
{
((ConfigEntry) info).uiSetWithoutSaving(value);
((ConfigEntry<Number>) configMenuOption).uiSetWithoutSaving(numberValue);
}
else
{
((ConfigEntry) info).uiSetWithoutSaving(value != null ? value.intValue() : 0);
((ConfigEntry<Number>) configMenuOption).uiSetWithoutSaving(numberValue != null ? numberValue.intValue() : 0);
}
}
return true;
};
}
private boolean tryCreateInputField(AbstractConfigType configType)
private static void setupBooleanMenuOption(ConfigEntry<Boolean> booleanConfigEntry)
{
if (configType instanceof ConfigEntry)
// For boolean
Function<Object, Component> func = value -> Translatable("distanthorizons.general."+((Boolean) value ? "true" : "false")).withStyle((Boolean) value ? ChatFormatting.GREEN : ChatFormatting.RED);
final ConfigGuiInfo configGuiInfo = ((ConfigGuiInfo) booleanConfigEntry.guiValue);
configGuiInfo.buttonOptionMap =
new AbstractMap.SimpleEntry<Button.OnPress, Function<Object, Component>>(
(button) ->
{
button.active = !booleanConfigEntry.apiIsOverriding();
booleanConfigEntry.uiSetWithoutSaving(!booleanConfigEntry.get());
button.setMessage(func.apply(booleanConfigEntry.get()));
}, func);
}
private static void setupEnumMenuOption(ConfigEntry<Enum<?>> enumConfigEntry, Class<? extends Enum<?>> enumClass)
{
List<Enum<?>> enumList = Arrays.asList(enumClass.getEnumConstants());
final ConfigGuiInfo configGuiInfo = ((ConfigGuiInfo) enumConfigEntry.guiValue);
Function<Object, Component> getEnumTranslatableFunc = (value) -> Translatable(TRANSLATION_PREFIX + "enum." + enumClass.getSimpleName() + "." + enumConfigEntry.get().toString());
configGuiInfo.buttonOptionMap =
new AbstractMap.SimpleEntry<Button.OnPress, Function<Object, Component>>(
(button) ->
{
ConfigEntry configEntry = (ConfigEntry) configType;
// get the currently selected enum and enum index
int startingIndex = enumList.indexOf(enumConfigEntry.get());
Enum<?> enumValue = enumList.get(startingIndex);
// search for the next enum that is selectable
int index = startingIndex + 1;
index = (index >= enumList.size()) ? 0 : index;
while (index != startingIndex)
{
enumValue = enumList.get(index);
if (!AnnotationUtil.doesEnumHaveAnnotation(enumValue, DisallowSelectingViaConfigGui.class))
{
// this enum shouldn't be selectable via the UI,
// skip it
break;
}
index++;
index = (index >= enumList.size()) ? 0 : index;
}
if (index == startingIndex)
{
// none of the enums should be selectable, this is a programmer error
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 + "].");
}
enumConfigEntry.uiSetWithoutSaving(enumValue);
button.active = !enumConfigEntry.apiIsOverriding();
button.setMessage(getEnumTranslatableFunc.apply(enumConfigEntry.get()));
}, getEnumTranslatableFunc);
}
private boolean tryCreateInputField(AbstractConfigBase<?> configBase)
{
final ConfigGuiInfo configGuiInfo = ((ConfigGuiInfo) configBase.guiValue);
if (configBase instanceof ConfigEntry)
{
ConfigEntry configEntry = (ConfigEntry) configBase;
//==============//
@@ -468,7 +464,6 @@ public class ClassicConfigGUI
Button.OnPress btnAction = (button) ->
{
configEntry.uiSetWithoutSaving(configEntry.getDefaultValue());
((EntryInfo) configEntry.guiValue).index = 0;
this.reload = true;
Objects.requireNonNull(this.minecraft).setScreen(this);
};
@@ -509,11 +504,11 @@ public class ClassicConfigGUI
- ConfigScreenConfigs.OPTION_FIELD_WIDTH;
int optionFieldPosZ = 0;
if (((EntryInfo) configEntry.guiValue).widget instanceof Map.Entry)
if (configGuiInfo.buttonOptionMap != null)
{
// enum/multi option input button
Map.Entry<Button.OnPress, Function<Object, Component>> widget = (Map.Entry<Button.OnPress, Function<Object, Component>>) ((EntryInfo) configEntry.guiValue).widget;
Map.Entry<Button.OnPress, Function<Object, Component>> widget = configGuiInfo.buttonOptionMap;
if (configEntry.getType().isEnum())
{
widget.setValue((value) -> Translatable(TRANSLATION_PREFIX + "enum." + configEntry.getType().getSimpleName() + "." + configEntry.get().toString()));
@@ -537,7 +532,7 @@ public class ClassicConfigGUI
return true;
}
else if (((EntryInfo) configEntry.guiValue).widget != null)
else
{
// text box input
@@ -548,7 +543,7 @@ public class ClassicConfigGUI
widget.setMaxLength(ConfigScreenConfigs.OPTION_FIELD_WIDTH);
widget.insertText(String.valueOf(configEntry.get()));
Predicate<String> processor = ((BiFunction<EditBox, Button, Predicate<String>>) ((EntryInfo) configEntry.guiValue).widget).apply(widget, this.doneButton);
Predicate<String> processor = configGuiInfo.tooltipFunction.apply(widget, this.doneButton);
widget.setFilter(processor);
this.configListWidget.addButton(this, configEntry, widget, resetButton, null, textComponent);
@@ -559,7 +554,7 @@ public class ClassicConfigGUI
return false;
}
private boolean tryCreateCategoryButton(AbstractConfigType configType)
private boolean tryCreateCategoryButton(AbstractConfigBase<?> configType)
{
if (configType instanceof ConfigCategory)
{
@@ -575,8 +570,8 @@ public class ClassicConfigGUI
ConfigScreenConfigs.CATEGORY_BUTTON_WIDTH, ConfigScreenConfigs.CATEGORY_BUTTON_HEIGHT,
((button) ->
{
ConfigBase.INSTANCE.configFileHandler.saveToFile();
Objects.requireNonNull(this.minecraft).setScreen(ClassicConfigGUI.getScreen(this.configBase, this, configCategory.getDestination()));
ConfigHandler.INSTANCE.configFileHandler.saveToFile();
Objects.requireNonNull(this.minecraft).setScreen(ClassicConfigGUI.getScreen(this, configCategory.getDestination()));
}));
this.configListWidget.addButton(this, configType, widget, null, null, null);
@@ -585,7 +580,7 @@ public class ClassicConfigGUI
return false;
}
private boolean tryCreateButton(AbstractConfigType configType)
private boolean tryCreateButton(AbstractConfigBase<?> configType)
{
if (configType instanceof ConfigUIButton)
{
@@ -606,7 +601,7 @@ public class ClassicConfigGUI
return false;
}
private boolean tryCreateComment(AbstractConfigType configType)
private boolean tryCreateComment(AbstractConfigBase<?> configType)
{
if (configType instanceof ConfigUIComment)
{
@@ -625,7 +620,7 @@ public class ClassicConfigGUI
return false;
}
private boolean tryCreateSpacer(AbstractConfigType configType)
private boolean tryCreateSpacer(AbstractConfigBase<?> configType)
{
if (configType instanceof ConfigUISpacer)
{
@@ -642,7 +637,7 @@ public class ClassicConfigGUI
return false;
}
private boolean tryCreateLinkedEntry(AbstractConfigType configType)
private boolean tryCreateLinkedEntry(AbstractConfigBase<?> configType)
{
if (configType instanceof ConfigUiLinkedEntry)
{
@@ -654,8 +649,8 @@ public class ClassicConfigGUI
return false;
}
private Component GetTranslatableTextComponentForConfig(AbstractConfigType configType)
{ return Translatable(TRANSLATION_PREFIX + configType.getNameWCategory());}
private Component GetTranslatableTextComponentForConfig(AbstractConfigBase<?> configType)
{ return Translatable(TRANSLATION_PREFIX + configType.getNameAndCategory());}
@@ -729,33 +724,32 @@ public class ClassicConfigGUI
}
Component text = ButtonEntry.TEXT_BY_WIDGET.get(hoveredWidget);
ButtonEntry button = ButtonEntry.BUTTON_BY_WIDGET.get(hoveredWidget);
// A quick fix for tooltips on linked entries
AbstractConfigType dhConfigType = ConfigUiLinkedEntry.class.isAssignableFrom(button.dhConfigType.getClass()) ?
AbstractConfigBase<?> configBase = ConfigUiLinkedEntry.class.isAssignableFrom(button.dhConfigType.getClass()) ?
((ConfigUiLinkedEntry) button.dhConfigType).get() :
button.dhConfigType;
boolean apiOverrideActive = false;
if (dhConfigType instanceof ConfigEntry)
if (configBase instanceof ConfigEntry)
{
apiOverrideActive = ((ConfigEntry)dhConfigType).apiIsOverriding();
apiOverrideActive = ((ConfigEntry<?>)configBase).apiIsOverriding();
}
Component name = Translatable(TRANSLATION_PREFIX + (dhConfigType.category.isEmpty() ? "" : dhConfigType.category + ".") + dhConfigType.getName());
String key = TRANSLATION_PREFIX + (dhConfigType.category.isEmpty() ? "" : dhConfigType.category + ".") + dhConfigType.getName() + ".@tooltip";
String key = TRANSLATION_PREFIX + (configBase.category.isEmpty() ? "" : configBase.category + ".") + configBase.getName() + ".@tooltip";
if (apiOverrideActive)
{
key = "distanthorizons.general.disabledByApi.@tooltip";
}
// display the validation error if present
if (((EntryInfo) dhConfigType.guiValue).error != null)
// display the validation error tooltip if present
final ConfigGuiInfo configGuiInfo = ((ConfigGuiInfo) configBase.guiValue);
if (configGuiInfo.errorMessage != null)
{
this.DhRenderTooltip(matrices, this.font, ((EntryInfo) dhConfigType.guiValue).error.getValue(), mouseX, mouseY);
this.DhRenderTooltip(matrices, this.font, configGuiInfo.errorMessage, mouseX, mouseY);
}
// display the tooltip if present
else if (LANG_WRAPPER.langExists(key))
@@ -781,7 +775,7 @@ public class ClassicConfigGUI
@Override
public void onClose()
{
ConfigBase.INSTANCE.configFileHandler.saveToFile();
ConfigHandler.INSTANCE.configFileHandler.saveToFile();
Objects.requireNonNull(this.minecraft).setScreen(this.parent);
CONFIG_CORE_INTERFACE.onScreenChangeListenerList.forEach((listener) -> listener.run());
@@ -792,9 +786,9 @@ public class ClassicConfigGUI
//================//
// helper classes //
//================//
public static class ConfigListWidget extends ContainerObjectSelectionList<ButtonEntry>
{
@@ -812,7 +806,7 @@ public class ClassicConfigGUI
this.textRenderer = minecraftClient.font;
}
public void addButton(ConfigScreen gui, AbstractConfigType dhConfigType, AbstractWidget button, AbstractWidget resetButton, AbstractWidget indexButton, Component text)
public void addButton(ConfigScreen gui, AbstractConfigBase dhConfigType, AbstractWidget button, AbstractWidget resetButton, AbstractWidget indexButton, Component text)
{ this.addEntry(new ButtonEntry(gui, dhConfigType, button, text, resetButton, indexButton)); }
@Override
@@ -858,7 +852,7 @@ public class ClassicConfigGUI
private final AbstractWidget button;
private final ConfigScreen gui;
private final AbstractConfigType dhConfigType;
private final AbstractConfigBase dhConfigType;
private final AbstractWidget resetButton;
private final AbstractWidget indexButton;
@@ -869,12 +863,12 @@ public class ClassicConfigGUI
private final EConfigCommentTextPosition textPosition;
public static final Map<AbstractWidget, Component> TEXT_BY_WIDGET = new HashMap<>();
// TODO we should just use a wrapper or something
/// TODO we should just use a wrapper or something
public static final Map<AbstractWidget, ButtonEntry> BUTTON_BY_WIDGET = new HashMap<>();
public ButtonEntry(ConfigScreen gui, AbstractConfigType dhConfigType,
public ButtonEntry(ConfigScreen gui, AbstractConfigBase dhConfigType,
AbstractWidget button, Component text, AbstractWidget resetButton, AbstractWidget indexButton)
{
TEXT_BY_WIDGET.put(button, text);
@@ -920,7 +914,7 @@ public class ClassicConfigGUI
@Override
#if MC_VER < MC_1_20_1
public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta)
#elif MC_VER < MC_1_21_10
#elif MC_VER < MC_1_21_9
public void render(GuiGraphics matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta)
#else
public void renderContent(GuiGraphics matrices, int mouseX, int mouseY, boolean hovered, float tickDelta)
@@ -928,9 +922,9 @@ public class ClassicConfigGUI
{
try
{
#if MC_VER < MC_1_21_10
#if MC_VER < MC_1_21_9
#else
int y = this.getY(); // TODO why is the Y value being set during render?
int y = this.getY(); /// TODO why is the Y value being set during render?
#endif
if (this.button != null)
@@ -1028,13 +1022,11 @@ public class ClassicConfigGUI
//================//
// event handling //
//================//
private static class ConfigCoreInterface implements IConfigGui
public static class ConfigCoreInterface implements IConfigGui
{
/**
* in the future it would be good to pass in the current page and other variables,
@@ -1,6 +1,6 @@
package com.seibel.distanthorizons.common.wrappers.gui;
#if MC_VER < MC_1_21_10
#if MC_VER < MC_1_21_9
// not supported for older MC versions
#else
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
@@ -19,7 +19,7 @@ import net.minecraft.world.level.Level;
import net.minecraft.world.level.chunk.LevelChunk;
#endif
#if MC_VER < MC_1_21_10
#if MC_VER < MC_1_21_9
// not supported for older MC versions
public class DhDebugScreenEntry
{}
@@ -1,14 +1,12 @@
package com.seibel.distanthorizons.common.wrappers.gui;
import com.seibel.distanthorizons.core.config.ConfigHandler;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.coreapi.ModInfo;
import com.seibel.distanthorizons.core.config.ConfigBase;
import com.seibel.distanthorizons.core.config.gui.JavaScreenHandlerScreen;
import net.minecraft.client.gui.screens.Screen;
import org.apache.logging.log4j.Logger;
import java.lang.invoke.MethodHandles;
public class GetConfigScreen
{
protected static final Logger LOGGER = DhLoggerBuilder.getLogger();
@@ -28,7 +26,7 @@ public class GetConfigScreen
// which won't be for sure added until we request a GUI
if (ModInfo.IS_DEV_BUILD)
{
String missingLangEntries = ConfigBase.INSTANCE.generateLang(true, true);
String missingLangEntries = ConfigHandler.INSTANCE.generateLang(true, true);
// trim to remove any newlines/spaces
// that may be present when no lang entries need changing
@@ -45,7 +43,7 @@ public class GetConfigScreen
switch (useScreen)
{
case Classic:
return ClassicConfigGUI.getScreen(ConfigBase.INSTANCE, parent, "client");
return ClassicConfigGUI.getScreen(parent, "client");
case JavaSwing:
//return MinecraftScreen.getScreen(parent, new JavaScreenHandlerScreen(new ConfigScreen()), ModInfo.ID + ".title");
return MinecraftScreen.getScreen(parent, new JavaScreenHandlerScreen(new JavaScreenHandlerScreen.ExampleScreen()), ModInfo.ID + ".title");
@@ -39,7 +39,7 @@ public class MinecraftScreen
protected ConfigScreenRenderer(Screen parent, AbstractScreen screen, String translationName)
{
super(translate(translationName));
#if MC_VER < MC_1_21_10
#if MC_VER < MC_1_21_9
screen.minecraftWindow = Minecraft.getInstance().getWindow().getWindow();
#else
screen.minecraftWindow = Minecraft.getInstance().getWindow().handle();
@@ -0,0 +1,33 @@
package com.seibel.distanthorizons.common.wrappers.gui.config;
import com.seibel.distanthorizons.core.config.gui.IConfigGuiInfo;
import com.seibel.distanthorizons.core.config.types.AbstractConfigBase;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.EditBox;
import net.minecraft.network.chat.Component;
import org.jetbrains.annotations.Nullable;
import java.util.AbstractMap;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;
/**
* holds information needed by the config GUI for rendering.
*
* @see AbstractConfigBase
*/
public class ConfigGuiInfo implements IConfigGuiInfo
{
/**
* Used to display validation errors.
* Null if no error is present.
*/
@Nullable
public Component errorMessage;
public BiFunction<EditBox, Button, Predicate<String>> tooltipFunction;
/** determines which options the button will show */
public AbstractMap.SimpleEntry<Button.OnPress, Function<Object, Component>> buttonOptionMap;
}
@@ -262,7 +262,7 @@ public class ChangelogScreen extends DhScreen
@Override
public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta)
{ GuiComponent.drawString(matrices, textRenderer, text, 12, y + 5, 0xFFFFFF); }
#elif MC_VER < MC_1_21_10
#elif MC_VER < MC_1_21_9
@Override
public void render(GuiGraphics matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta)
{ matrices.drawString(textRenderer, this.text, 12, y + 5, 0xFFFFFF); }
@@ -158,9 +158,17 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
@Override
public boolean hasSinglePlayerServer() { return MINECRAFT.hasSingleplayerServer(); }
@Override
public boolean clientConnectedToDedicatedServer() { return MINECRAFT.getCurrentServer() != null && !this.hasSinglePlayerServer(); }
public boolean clientConnectedToDedicatedServer()
{
return MINECRAFT.getCurrentServer() != null
&& !this.hasSinglePlayerServer();
}
@Override
public boolean connectedToReplay() { return !MINECRAFT.hasSingleplayerServer() && MINECRAFT.getCurrentServer() == null; }
public boolean connectedToReplay()
{
return MINECRAFT.getCurrentServer() == null
&& !this.hasSinglePlayerServer() ;
}
@Override
public String getCurrentServerName()
@@ -315,7 +323,7 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra
#if MC_VER < MC_1_19_2
player.sendMessage(new TextComponent(string), getPlayer().getUUID());
#elif MC_VER < MC_1_21_10
#elif MC_VER < MC_1_21_9
player.displayClientMessage(net.minecraft.network.chat.Component.translatable(string), /*isOverlay*/false);
#else
@@ -401,7 +401,7 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
@Override
public int getTargetFrameBufferViewportWidth()
{
#if MC_VER < MC_1_21_10
#if MC_VER < MC_1_21_9
return this.getRenderTarget().viewWidth;
#else
return this.getRenderTarget().width;
@@ -411,7 +411,7 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
@Override
public int getTargetFrameBufferViewportHeight()
{
#if MC_VER < MC_1_21_10
#if MC_VER < MC_1_21_9
return this.getRenderTarget().viewHeight;
#else
return this.getRenderTarget().height;
@@ -99,6 +99,11 @@ public class ClientLevelWrapper implements IClientLevelWrapper
@Nullable
public static IClientLevelWrapper getWrapperIfDifferent(@Nullable IClientLevelWrapper levelWrapper, @NotNull ClientLevel level)
{
if (KEYED_CLIENT_LEVEL_MANAGER.isEnabled() && KEYED_CLIENT_LEVEL_MANAGER.getServerKeyedLevel() != levelWrapper)
{
return getWrapper(level);
}
ClientLevelWrapper clientLevelWrapper = (ClientLevelWrapper)levelWrapper;
if (clientLevelWrapper == null
|| clientLevelWrapper.level != level)
@@ -113,7 +113,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
#if MC_VER < MC_1_21_5
private static final TicketType<ChunkPos> DH_SERVER_GEN_TICKET = TicketType.create("dh_server_gen_ticket", Comparator.comparingLong(ChunkPos::toLong));
#elif MC_VER < MC_1_21_10
#elif MC_VER < MC_1_21_9
private static final TicketType DH_SERVER_GEN_TICKET = new TicketType(/* timeout, 0 = disabled*/0L, /* persist */ false, TicketType.TicketUse.LOADING);
#else
private static final TicketType DH_SERVER_GEN_TICKET = new TicketType(/* timeout, 0 = disabled*/0L, /* flags */0);
@@ -744,7 +744,7 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv
return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level, level.registryAccess().registryOrThrow(Registries.BIOME), null);
#elif MC_VER < MC_1_21_3
return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level, level.registryAccess().registryOrThrow(Registries.BIOME), null);
#elif MC_VER < MC_1_21_10
#elif MC_VER < MC_1_21_9
return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level, level.registryAccess().lookupOrThrow(Registries.BIOME), null);
#else
return new ProtoChunk(chunkPos, UpgradeData.EMPTY, level, PalettedContainerFactory.create(level.registryAccess()), null);
@@ -94,7 +94,7 @@ public class ChunkFileReader
private static final AtomicBoolean ZERO_CHUNK_POS_ERROR_LOGGED_REF = new AtomicBoolean(false);
#if MC_VER >= MC_1_21_10
#if MC_VER >= MC_1_21_9
// BLOCK_STATE_CODEC can no longer be statically created since
// it needs a level reference
#elif MC_VER >= MC_1_19_2
@@ -263,7 +263,7 @@ public class ChunkFileReader
}
private static LevelChunkSection[] readSections(LevelAccessor level, ChunkPos chunkPos, CompoundTag chunkData)
{
#if MC_VER < MC_1_21_10
#if MC_VER < MC_1_21_9
// BLOCK_STATE_CODEC is created statically
// TODO clean up this code separation
#else
@@ -288,7 +288,7 @@ public class ChunkFileReader
#elif MC_VER < MC_1_21_3
Codec<PalettedContainer<Holder<Biome>>> biomeCodec = PalettedContainer.codecRW(
biomes.asHolderIdMap(), biomes.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getHolderOrThrow(Biomes.PLAINS));
#elif MC_VER < MC_1_21_10
#elif MC_VER < MC_1_21_9
Codec<PalettedContainer<Holder<Biome>>> biomeCodec = PalettedContainer.codecRW(
biomes.asHolderIdMap(), biomes.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getOrThrow(Biomes.PLAINS));
#else
@@ -363,7 +363,7 @@ public class ChunkFileReader
}
else
{
#if MC_VER < MC_1_21_10
#if MC_VER < MC_1_21_9
blockStateContainer = new PalettedContainer<BlockState>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);
#else
blockStateContainer = PalettedContainerFactory.create(level.registryAccess()).createForBlockStates();
@@ -403,7 +403,7 @@ public class ChunkFileReader
biomeContainer = new PalettedContainer<Holder<Biome>>(
biomes.asHolderIdMap(),
biomes.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
#elif MC_VER < MC_1_21_10
#elif MC_VER < MC_1_21_9
biomeContainer = new PalettedContainer<Holder<Biome>>(biomes.asHolderIdMap(),
biomes.getOrThrow(Biomes.PLAINS),
PalettedContainer.Strategy.SECTION_BIOMES);
+5 -3
View File
@@ -19,7 +19,9 @@ loom {
"-Dminecraft.api.session.host=https://nope.invalid",
"-Dminecraft.api.services.host=https://nope.invalid",
// https://netty.io/wiki/reference-counted-objects.html#leak-detection-levels
"-Dio.netty.leakDetection.level=advanced"
"-Dio.netty.leakDetection.level=advanced",
"-XX:+UseZGC",
"-XX:+ZGenerational"
)
programArgs("--username", "Dev")
}
@@ -76,11 +78,11 @@ dependencies {
// Fabric API
addModJar(fabricApi.module("fabric-api-base", rootProject.fabric_api_version))
addModJar(fabricApi.module("fabric-lifecycle-events-v1", rootProject.fabric_api_version))
if (buildVersionBefore(minecraft_version, "1.21.10"))
if (buildVersionBefore(minecraft_version, "1.21.9"))
{
addModJar(fabricApi.module("fabric-resource-loader-v0", rootProject.fabric_api_version))
}
else // > 1.21.10
else // > 1.21.9
{
addModJar(fabricApi.module("fabric-resource-loader-v0", rootProject.fabric_api_version))
addModJar(fabricApi.module("fabric-resource-loader-v1", rootProject.fabric_api_version))
@@ -60,7 +60,7 @@ import java.nio.FloatBuffer;
import java.util.HashSet;
import java.util.concurrent.AbstractExecutorService;
#if MC_VER < MC_1_21_10
#if MC_VER < MC_1_21_9
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
#endif
@@ -130,8 +130,16 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
{
if (MC.clientConnectedToDedicatedServer())
{
IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper(level);
SharedApi.INSTANCE.chunkLoadEvent(new ChunkWrapper(chunk, wrappedLevel), wrappedLevel);
// executor to prevent locking up the render/event thread
AbstractExecutorService executor = ThreadPoolUtil.getFileHandlerExecutor();
if (executor != null)
{
executor.execute(() ->
{
IClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper(level);
SharedApi.INSTANCE.chunkLoadEvent(new ChunkWrapper(chunk, wrappedLevel), wrappedLevel);
});
}
}
});
@@ -145,8 +153,6 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
if (SharedApi.isChunkAtBlockPosAlreadyUpdating(blockPos.getX(), blockPos.getZ()))
{
// executor to prevent locking up the render/event thread
// if the getChunk() takes longer than expected
// (which can be caused by certain mods)
AbstractExecutorService executor = ThreadPoolUtil.getFileHandlerExecutor();
if (executor != null)
{
@@ -185,8 +191,6 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
if (SharedApi.isChunkAtBlockPosAlreadyUpdating(hitResult.getBlockPos().getX(), hitResult.getBlockPos().getZ()))
{
// executor to prevent locking up the render/event thread
// if the getChunk() takes longer than expected
// (which can be caused by certain mods)
AbstractExecutorService executor = ThreadPoolUtil.getFileHandlerExecutor();
if (executor != null)
{
@@ -220,7 +224,7 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy
//==============//
// TODO wait for fabric to re-add their rendering API
#if MC_VER < MC_1_21_10
#if MC_VER < MC_1_21_9
WorldRenderEvents.AFTER_SETUP.register((renderContext) ->
{
ClientApi.RENDER_STATE.mcProjectionMatrix = McObjectConverter.Convert(renderContext.projectionMatrix());
@@ -20,10 +20,8 @@
package com.seibel.distanthorizons.fabric;
import com.mojang.brigadier.CommandDispatcher;
import com.seibel.distanthorizons.api.enums.config.EDhApiMcRenderingFadeMode;
import com.seibel.distanthorizons.common.AbstractModInitializer;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.config.ConfigBase;
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
@@ -71,11 +69,14 @@ public class FabricMain extends AbstractModInitializer implements ClientModIniti
@Override
protected void createInitialBindings()
protected void createInitialSharedBindings()
{
SingletonInjector.INSTANCE.bind(IModChecker.class, ModChecker.INSTANCE);
SingletonInjector.INSTANCE.bind(IPluginPacketSender.class, new FabricPluginPacketSender());
}
@Override
protected void createInitialClientBindings() { /* no additional setup needed currently */ }
@Override
protected IEventProxy createClientProxy() { return new FabricClientProxy(); }
@@ -153,11 +154,6 @@ public class FabricMain extends AbstractModInitializer implements ClientModIniti
ModAccessorInjector.INSTANCE.get(ISodiumAccessor.class).setFogOcclusion(false);
}
#endif
if (ConfigBase.INSTANCE == null)
{
throw new IllegalStateException("Config was not initialized. Make sure to call LodCommonMain.initConfig() before calling this method.");
}
}
}
@@ -19,7 +19,7 @@
package com.seibel.distanthorizons.fabric.mixins.client;
#if MC_VER < MC_1_21_10
#if MC_VER < MC_1_21_9
import net.minecraft.world.entity.Entity;
import org.spongepowered.asm.mixin.Mixin;
@@ -3,8 +3,10 @@ package com.seibel.distanthorizons.fabric.mixins.client;
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
import com.seibel.distanthorizons.core.api.internal.ClientApi;
import com.seibel.distanthorizons.core.api.internal.SharedApi;
import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.multiplayer.ClientPacketListener;
import net.minecraft.world.level.chunk.ChunkAccess;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
@@ -16,6 +18,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import net.minecraft.world.level.chunk.LevelChunk;
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
import java.util.concurrent.AbstractExecutorService;
#endif
@Mixin(ClientPacketListener.class)
@@ -45,8 +49,24 @@ public class MixinClientPacketListener
@Inject(method = "enableChunkLight", at = @At("TAIL"))
void onEnableChunkLight(LevelChunk chunk, int x, int z, CallbackInfo ci)
{
IClientLevelWrapper clientLevel = ClientLevelWrapper.getWrapper((ClientLevel) chunk.getLevel());
SharedApi.INSTANCE.chunkLoadEvent(new ChunkWrapper(chunk, clientLevel), clientLevel);
if (chunk == null)
{
return;
}
// executor to prevent locking up the render thread
AbstractExecutorService executor = ThreadPoolUtil.getFileHandlerExecutor();
if (executor == null)
{
return;
}
executor.execute(() ->
{
IClientLevelWrapper clientLevel = ClientLevelWrapper.getWrapper((ClientLevel) this.level);
SharedApi.INSTANCE.chunkLoadEvent(new ChunkWrapper(chunk, clientLevel), clientLevel);
});
}
#endif
@@ -12,7 +12,7 @@ import java.util.List;
@Mixin(DebugScreenOverlay.class)
public class MixinDebugScreenOverlay
{
#if MC_VER < MC_1_21_10
#if MC_VER < MC_1_21_9
@Inject(method = "getSystemInformation", at = @At("RETURN"))
private void addCustomF3(CallbackInfoReturnable<List<String>> cir)
{
@@ -30,7 +30,7 @@ import net.minecraft.client.renderer.RenderType;
import com.mojang.blaze3d.vertex.PoseStack;
import org.joml.Matrix4f;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
#elif MC_VER < MC_1_21_10
#elif MC_VER < MC_1_21_9
import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.framegraph.FrameGraphBuilder;
import com.mojang.blaze3d.resource.GraphicsResourceAllocator;
@@ -116,7 +116,7 @@ public class MixinLevelRenderer
method = "Lnet/minecraft/client/renderer/LevelRenderer;renderSectionLayer(Lnet/minecraft/client/renderer/RenderType;DDDLorg/joml/Matrix4f;Lorg/joml/Matrix4f;)V",
cancellable = true)
private void renderChunkLayer(RenderType renderType, double x, double y, double z, Matrix4f projectionMatrix, Matrix4f frustumMatrix, CallbackInfo callback)
#elif MC_VER < MC_1_21_10
#elif MC_VER < MC_1_21_9
@Inject(at = @At("HEAD"), method = "prepareChunkRenders", cancellable = true)
private void prepareChunkRenders(Matrix4fc projectionMatrix, double d, double e, double f, CallbackInfoReturnable<ChunkSectionsToRender> callback)
#else
@@ -141,7 +141,7 @@ public class MixinLevelRenderer
// get the matrices directly from MC
ClientApi.RENDER_STATE.mcModelViewMatrix = McObjectConverter.Convert(modelViewMatrixStack.last().pose());
ClientApi.RENDER_STATE.mcProjectionMatrix = McObjectConverter.Convert(projectionMatrix);
#elif MC_VER < MC_1_21_10
#elif MC_VER < MC_1_21_9
// MC combined the model view and projection matricies
ClientApi.RENDER_STATE.mcModelViewMatrix = McObjectConverter.Convert(projectionMatrix);
ClientApi.RENDER_STATE.mcProjectionMatrix = new Mat4f();
@@ -169,7 +169,7 @@ public class MixinLevelRenderer
{
ClientApi.INSTANCE.renderDeferredLodsForShaders();
}
#elif MC_VER < MC_1_21_10
#elif MC_VER < MC_1_21_9
// rendering handled via Fabric Api render event
#else
// handled here and in MixinChunkSectionsToRender
@@ -178,7 +178,7 @@ public class MixinLevelRenderer
#if MC_VER < MC_1_21_10
#if MC_VER < MC_1_21_9
// rendering handled via Fabric Api render event
#else
@Inject(at = @At("HEAD"), method = "prepareChunkRenders")
@@ -29,6 +29,7 @@ import net.minecraft.client.renderer.LightTexture;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@@ -61,28 +62,40 @@ public class MixinLightTexture
private GpuTexture texture;
#endif
@Unique
private MinecraftRenderWrapper renderWrapper = null;
@Inject(method = "updateLightTexture(F)V", at = @At("RETURN"))
public void updateLightTexture(float partialTicks, CallbackInfo ci)
{
IMinecraftClientWrapper mc = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
if (mc == null || mc.getWrappedClientLevel() == null)
if (mc == null)
{
return;
}
IClientLevelWrapper clientLevel = mc.getWrappedClientLevel();
MinecraftRenderWrapper renderWrapper = (MinecraftRenderWrapper)SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
if (clientLevel == null)
{
return;
}
// lazy initialization to make sure we don't call this too early
if (this.renderWrapper == null)
{
this.renderWrapper = (MinecraftRenderWrapper)SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
}
#if MC_VER < MC_1_21_3
renderWrapper.updateLightmap(this.lightPixels, clientLevel);
this.renderWrapper.updateLightmap(this.lightPixels, clientLevel);
#elif MC_VER < MC_1_21_5
renderWrapper.setLightmapId(this.target.getColorTextureId(), clientLevel);
this.renderWrapper.setLightmapId(this.target.getColorTextureId(), clientLevel);
#else
GlTexture glTexture = (GlTexture) this.texture;
renderWrapper.setLightmapId(glTexture.glId(), clientLevel);
this.renderWrapper.setLightmapId(glTexture.glId(), clientLevel);
#endif
}
@@ -86,11 +86,13 @@ public class ForgeMain extends AbstractModInitializer
}
@Override
protected void createInitialBindings()
protected void createInitialSharedBindings()
{
SingletonInjector.INSTANCE.bind(IModChecker.class, ModChecker.INSTANCE);
SingletonInjector.INSTANCE.bind(IPluginPacketSender.class, new ForgePluginPacketSender());
}
@Override
protected void createInitialClientBindings() { /* no additional setup needed currently */ }
@Override
protected IEventProxy createClientProxy() { return new ForgeClientProxy(); }
+1 -1
View File
@@ -5,7 +5,7 @@ org.gradle.caching=true
# Mod Info
mod_name=DistantHorizons
mod_version=2.3.5-b
mod_version=2.3.6-b
api_version=4.1.0
maven_group=com.seibel.distanthorizons
mod_readable_name=Distant Horizons
@@ -149,8 +149,6 @@ public class NeoforgeClientProxy implements AbstractModInitializer.IEventProxy
}
// executor to prevent locking up the render/event thread
// if the getChunk() takes longer than expected
// (which can be caused by certain mods)
AbstractExecutorService executor = ThreadPoolUtil.getFileHandlerExecutor();
if (executor != null)
{
@@ -176,8 +174,6 @@ public class NeoforgeClientProxy implements AbstractModInitializer.IEventProxy
}
// executor to prevent locking up the render/event thread
// if the getChunk() takes longer than expected
// (which can be caused by certain mods)
AbstractExecutorService executor = ThreadPoolUtil.getFileHandlerExecutor();
if (executor != null)
{
@@ -250,7 +246,7 @@ public class NeoforgeClientProxy implements AbstractModInitializer.IEventProxy
@SubscribeEvent
public void afterLevelEntityRenderEvent(RenderLevelStageEvent.AfterEntities event)
{
#if MC_VER < MC_1_21_10
#if MC_VER < MC_1_21_9
ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, (ClientLevel)event.getLevel());
#else
ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, event.getLevelRenderer().level);
@@ -263,7 +259,7 @@ public class NeoforgeClientProxy implements AbstractModInitializer.IEventProxy
@SubscribeEvent
public void afterLevelTranslucentRenderEvent(RenderLevelStageEvent.AfterTranslucentBlocks event)
{
#if MC_VER < MC_1_21_10
#if MC_VER < MC_1_21_9
ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, (ClientLevel)event.getLevel());
#else
ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, event.getLevelRenderer().level);
@@ -275,7 +271,7 @@ public class NeoforgeClientProxy implements AbstractModInitializer.IEventProxy
@SubscribeEvent
public void afterLevelRenderEvent(RenderLevelStageEvent.AfterLevel event)
{
#if MC_VER < MC_1_21_10
#if MC_VER < MC_1_21_9
ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, (ClientLevel)event.getLevel());
#else
ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, event.getLevelRenderer().level);
@@ -124,11 +124,14 @@ public class NeoforgeMain extends AbstractModInitializer
protected IEventProxy createServerProxy(boolean isDedicated) { return new NeoforgeServerProxy(isDedicated); }
@Override
protected void createInitialBindings()
protected void createInitialSharedBindings()
{
SingletonInjector.INSTANCE.bind(IModChecker.class, ModChecker.INSTANCE);
SingletonInjector.INSTANCE.bind(IPluginPacketSender.class, new NeoforgePluginPacketSender());
}
@Override
protected void createInitialClientBindings()
{
// replace MC RenderWrapper with more specific neoforge version
SingletonInjector.INSTANCE.unbind(IMinecraftRenderWrapper.class, MinecraftRenderWrapper.INSTANCE); // TODO replace with a replaceOrBind for simplicity
SingletonInjector.INSTANCE.bind(IMinecraftRenderWrapper.class, NeoforgeMinecraftRenderWrapper.INSTANCE);
@@ -152,7 +152,7 @@ public class NeoforgeServerProxy implements AbstractModInitializer.IEventProxy
private static ServerLevelWrapper getServerLevelWrapper(ServerLevel level) { return ServerLevelWrapper.getWrapper(level); }
private static ServerLevelWrapper getServerLevelWrapper(ResourceKey<Level> resourceKey, PlayerEvent event)
{
#if MC_VER < MC_1_21_10
#if MC_VER < MC_1_21_9
//noinspection DataFlowIssue (possible NPE after getServer())
return getServerLevelWrapper(event.getEntity().getServer().getLevel(resourceKey));
#else
@@ -1,6 +1,6 @@
package com.seibel.distanthorizons.neoforge.mixins.client;
#if MC_VER < MC_1_21_10
#if MC_VER < MC_1_21_9
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
import net.minecraft.client.gui.components.DebugScreenOverlay;
import org.spongepowered.asm.mixin.Mixin;
@@ -18,7 +18,7 @@ import net.minecraft.client.gui.components.DebugScreenOverlay;
public class MixinDebugScreenOverlay
{
#if MC_VER < MC_1_21_10
#if MC_VER < MC_1_21_9
@Inject(method = "getSystemInformation", at = @At("RETURN"))
private void addCustomF3(CallbackInfoReturnable<List<String>> cir)
{
@@ -83,7 +83,7 @@ public class MixinLevelRenderer
#if MC_VER < MC_1_21_6
@Inject(at = @At("HEAD"), method = "renderSectionLayer")
private void renderChunkLayer(RenderType renderType, double x, double y, double z, Matrix4f modelViewMatrix, Matrix4f projectionMatrix, CallbackInfo callback)
#elif MC_VER < MC_1_21_10
#elif MC_VER < MC_1_21_9
@Inject(at = @At("HEAD"), method = "renderLevel")
private void onRenderLevel(
GraphicsResourceAllocator resourceAllocator, DeltaTracker deltaTracker,
@@ -38,7 +38,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.mojang.blaze3d.platform.NativeImage;
#elif MC_VER < MC_1_21_5
import com.mojang.blaze3d.pipeline.TextureTarget;
#elif MC_VER < MC_1_21_10
#elif MC_VER < MC_1_21_9
import com.mojang.blaze3d.opengl.GlTexture;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.textures.GpuTexture;
@@ -82,7 +82,7 @@ public class MixinLightTexture
renderWrapper.updateLightmap(this.lightPixels, clientLevel);
#elif MC_VER < MC_1_21_5
renderWrapper.setLightmapId(this.target.getColorTextureId(), clientLevel);
#elif MC_VER < MC_1_21_10
#elif MC_VER < MC_1_21_9
GlTexture glTexture = (GlTexture) this.texture;
renderWrapper.setLightmapId(glTexture.glId(), clientLevel);
#else
@@ -5,7 +5,7 @@ import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import net.minecraft.client.Minecraft;
import org.apache.logging.log4j.Logger;
#if MC_VER < MC_1_21_10
#if MC_VER < MC_1_21_9
#else
import com.mojang.blaze3d.opengl.GlTexture;
import com.mojang.blaze3d.textures.GpuTexture;
@@ -26,7 +26,7 @@ public class NeoforgeMinecraftRenderWrapper extends MinecraftRenderWrapper
@Override
public int getDepthTextureId()
{
#if MC_VER < MC_1_21_10
#if MC_VER < MC_1_21_9
// no special handling required,
// both neo/fabric uses the same back end objects
return super.getDepthTextureId();
@@ -53,7 +53,7 @@ public class NeoforgeMinecraftRenderWrapper extends MinecraftRenderWrapper
@Override
public int getColorTextureId()
{
#if MC_VER < MC_1_21_10
#if MC_VER < MC_1_21_9
// no special handling required,
// both neo/fabric uses the same back end objects
return super.getColorTextureId();
@@ -1,6 +1,6 @@
package com.seibel.distanthorizons.neoforge.wrappers;
#if MC_VER < MC_1_21_10
#if MC_VER < MC_1_21_9
public class NeoforgeTextureUnwrapper
{ /* not needed for older MC versions */ }
#else
+59
View File
@@ -0,0 +1,59 @@
# 1.21.9 version
java_version=21
minecraft_version=1.21.9
parchment_version=1.21:2024.07.28
compatible_minecraft_versions=["1.21.9"]
accessWidenerVersion=1_21_10
builds_for=fabric,neoforge
# forge is broken due to gradle/build script issues
# Netty
netty_version=4.1.97.Final
# Fabric loader
fabric_loader_version=0.17.3
fabric_api_version=0.134.0+1.21.9
modmenu_version=16.0.0-rc.1
starlight_version_fabric=
phosphor_version_fabric=
lithium_version=
sodium_version=mc1.21.10-0.7.2-fabric
iris_version=1.9.3+1.21.9-fabric
bclib_version=
immersive_portals_version=
canvas_version=
fabric_incompatibility_list={ }
fabric_recommend_list={}
# Fabric mod run
# 0 = Don't enable and don't run
# 1 = Can be referenced in code but doesn't run
# 2 = Can be referenced in code and runs in client
enable_starlight=0
enable_phosphor=0
enable_sodium=1
enable_lithium=0
enable_iris=1
enable_bclib=0
enable_immersive_portals=0
enable_canvas=0
# (Neo)Forge loader
forge_version=
neoforge_version=21.9.15-beta
# sometime before 21.9.15-beta Neoforge changed how their rendering API events handle levels
# so we can't support both versions at once
neoforge_version_range=[21.9.15-beta,)
# (Neo)Forge mod versions
starlight_version_forge=
terraforged_version=
# (Neo)Forge mod run
# 0 = Don't enable and don't run
# 1 = Can be referenced in code but doesn't run
# 2 = Can be referenced in code and runs in client
enable_starlight_forge=0
enable_terraforged=0
enable_terrafirmacraft=0