diff --git a/api/src/main/java/com/seibel/distanthorizons/api/enums/config/EGLErrorHandlingMode.java b/api/src/main/java/com/seibel/distanthorizons/api/enums/config/EGLErrorHandlingMode.java
new file mode 100644
index 000000000..6fb4c7d99
--- /dev/null
+++ b/api/src/main/java/com/seibel/distanthorizons/api/enums/config/EGLErrorHandlingMode.java
@@ -0,0 +1,30 @@
+/*
+ * This file is part of the Distant Horizons mod (formerly the LOD Mod),
+ * licensed under the GNU LGPL v3 License.
+ *
+ * Copyright (C) 2020-2022 James Seibel
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package com.seibel.distanthorizons.api.enums.config;
+
+/**
+ * @since API 1.0.0
+ */
+public enum EGLErrorHandlingMode
+{
+ IGNORE,
+ LOG,
+ LOG_THROW;
+}
diff --git a/api/src/main/java/com/seibel/distanthorizons/api/interfaces/override/worldGenerator/IDhApiWorldGenerator.java b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/override/worldGenerator/IDhApiWorldGenerator.java
index 572356810..8396ff340 100644
--- a/api/src/main/java/com/seibel/distanthorizons/api/interfaces/override/worldGenerator/IDhApiWorldGenerator.java
+++ b/api/src/main/java/com/seibel/distanthorizons/api/interfaces/override/worldGenerator/IDhApiWorldGenerator.java
@@ -85,9 +85,9 @@ public interface IDhApiWorldGenerator extends Closeable, IDhApiOverrideable
* Please run your generator in game at least once to confirm the objects you are returning are correct.
*
* Consumer expected inputs for each minecraft version (in order):
- * 1.18: [net.minecraft.world.level.chunk.ChunkAccess] and [net.minecraft.world.level.LevelReader]
- * 1.19: [net.minecraft.world.level.chunk.ChunkAccess] and [net.minecraft.world.level.LevelReader]
- * 1.20: [net.minecraft.world.level.chunk.ChunkAccess] and [net.minecraft.world.level.LevelReader]
+ * 1.16, 1.17, 1.18, 1.19, 1.20:
+ * - [net.minecraft.world.level.chunk.ChunkAccess]
+ * - [net.minecraft.world.level.ServerLevel] or [net.minecraft.world.level.ClientLevel]
*/
CompletableFuture generateChunks(
int chunkPosMinX, int chunkPosMinZ,
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ClientApi.java b/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ClientApi.java
index 15e950e4a..5066e2517 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ClientApi.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ClientApi.java
@@ -319,7 +319,12 @@ public class ClientApi
if (clientWorld != null)
{
clientWorld.clientTick();
- SharedApi.worldGenTick(clientWorld::doWorldGen);
+
+ // Ignore local world gen, as it's managed by server ticking
+ if (!(clientWorld instanceof DhClientServerWorld))
+ {
+ SharedApi.worldGenTick(clientWorld::doWorldGen);
+ }
}
profiler.pop();
}
@@ -329,7 +334,7 @@ public class ClientApi
//============//
// networking //
//============//
-
+
/** @param byteBuf is Netty's {@link ByteBuffer} wrapper. */
public void serverMessageReceived(ByteBuf byteBuf)
{
@@ -568,4 +573,6 @@ public class ClientApi
MC.sendChatMessage("P: Debug Pref Logger is " + (prefLoggerEnabled ? "enabled" : "disabled"));
}
}
+
+
}
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/api/internal/SharedApi.java b/core/src/main/java/com/seibel/distanthorizons/core/api/internal/SharedApi.java
index ff2fdca79..8abbd0609 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/api/internal/SharedApi.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/api/internal/SharedApi.java
@@ -14,10 +14,16 @@ public class SharedApi
private static AbstractDhWorld currentWorld;
private static int lastWorldGenTickDelta = 0;
+
+
+
public static void init() { Initializer.init(); }
+
+
public static EWorldEnvironment getEnvironment() { return (currentWorld == null) ? null : currentWorld.environment; }
+
public static void setDhWorld(AbstractDhWorld newWorld)
{
currentWorld = newWorld;
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/AppliedConfigState.java b/core/src/main/java/com/seibel/distanthorizons/core/config/AppliedConfigState.java
index 8c8a6be15..badbb60d0 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/config/AppliedConfigState.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/config/AppliedConfigState.java
@@ -2,7 +2,7 @@ package com.seibel.distanthorizons.core.config;
import com.seibel.distanthorizons.core.config.types.ConfigEntry;
-// TODO: Make this intergrate with the config system
+// TODO: Make this integrate with the config system
public class AppliedConfigState
{
final ConfigEntry entry;
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java b/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java
index 15abd43d7..e6e28024c 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java
@@ -31,7 +31,6 @@ import com.seibel.distanthorizons.core.config.eventHandlers.UnsafeValuesConfigLi
import com.seibel.distanthorizons.core.config.eventHandlers.WorldCurvatureConfigEventHandler;
import com.seibel.distanthorizons.core.config.eventHandlers.presets.ThreadPresetConfigEventHandler;
import com.seibel.distanthorizons.core.config.eventHandlers.presets.RenderQualityPresetConfigEventHandler;
-import com.seibel.distanthorizons.core.config.listeners.ConfigChangeListener;
import com.seibel.distanthorizons.core.config.types.*;
import com.seibel.distanthorizons.core.config.types.enums.EConfigEntryAppearance;
import com.seibel.distanthorizons.core.config.types.enums.EConfigEntryPerformance;
@@ -62,6 +61,7 @@ public class Config
public static ConfigCategory client = new ConfigCategory.Builder().set(Client.class).build();
+
public static class Client
{
public static ConfigEntry quickEnableRendering = new ConfigEntry.Builder()
@@ -200,6 +200,7 @@ public class Config
+ ETransparency.DISABLED + ": LODs will be opaque. \n"
+ "")
.setPerformance(EConfigEntryPerformance.MEDIUM)
+ .addListener(RenderCacheConfigEventHandler.INSTANCE)
.build();
public static ConfigEntry blocksToIgnore = new ConfigEntry.Builder()
@@ -531,6 +532,7 @@ public class Config
+ "0 = black \n"
+ "1 = normal \n"
+ "2 = near white")
+ .addListener(RenderCacheConfigEventHandler.INSTANCE)
.build();
public static ConfigEntry saturationMultiplier = new ConfigEntry.Builder() // TODO: Make this a float (the ClassicConfigGUI doesnt support floats)
@@ -541,6 +543,7 @@ public class Config
+ "0 = black and white \n"
+ "1 = normal \n"
+ "2 = very saturated")
+ .addListener(RenderCacheConfigEventHandler.INSTANCE)
.build();
public static ConfigEntry enableCaveCulling = new ConfigEntry.Builder()
@@ -1101,6 +1104,26 @@ public class Config
.addListener(UnsafeValuesConfigListener.INSTANCE)
.build();
+ public static ConfigEntry overrideVanillaGLLogger = new ConfigEntry.Builder()
+ .set(ModInfo.IS_DEV_BUILD)
+ .comment(""
+ + "Requires a reboot to change. \n"
+ + "")
+ .build();
+
+ public static ConfigEntry glErrorHandlingMode = new ConfigEntry.Builder()
+ .set(ModInfo.IS_DEV_BUILD ? EGLErrorHandlingMode.LOG : EGLErrorHandlingMode.IGNORE)
+ .comment(""
+ + "Defines how OpenGL errors are handled. \n"
+ + "May incorrectly catch OpenGL errors thrown by other mods. \n"
+ + "\n"
+ + EGLErrorHandlingMode.IGNORE + ": Do nothing. \n"
+ + EGLErrorHandlingMode.LOG + ": write an error to the log. \n"
+ + EGLErrorHandlingMode.LOG_THROW + ": write to the log and throw an exception. \n"
+ + " Warning: this should only be enabled when debugging the LOD renderer \n"
+ + " as it may break Minecraft's renderer when an exception is thrown. \n"
+ + "")
+ .build();
// can be set to public inorder to show in the config file and UI
public static ConfigCategory exampleConfigScreen = new ConfigCategory.Builder()
@@ -1155,10 +1178,10 @@ public class Config
.set(new HashMap())
.build();
- public static ConfigUIButton uiButtonTest = new ConfigUIButton(() -> {
- System.setProperty("java.awt.headless", "false"); // Required to make it work
- JOptionPane.showMessageDialog(null, "Button pressed!", "UITester dialog", JOptionPane.INFORMATION_MESSAGE);
- });
+ public static ConfigUIButton uiButtonTest = new ConfigUIButton(() -> { new Thread(() -> {
+ System.setProperty("java.awt.headless", "false"); // Required to make it work
+ JOptionPane.showMessageDialog(null, "Button pressed!", "UITester dialog", JOptionPane.INFORMATION_MESSAGE);
+ });});
public static ConfigCategory categoryTest = new ConfigCategory.Builder().set(CategoryTest.class).build();
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/ConfigBase.java b/core/src/main/java/com/seibel/distanthorizons/core/config/ConfigBase.java
index 0df37a368..eb0f54305 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/config/ConfigBase.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/config/ConfigBase.java
@@ -18,37 +18,43 @@ import java.util.*;
*
* @author coolGi
* @author Ran
+ * @version 2023-8-26
*/
// Init the config after singletons have been blinded
public class ConfigBase
{
- /** Our own config instance, don't modify */
+ /** Our own config instance, don't modify unless you are the DH mod */
public static ConfigBase INSTANCE;
public ConfigFileHandling configFileINSTANCE;
- public static final Logger LOGGER = LogManager.getLogger(ConfigBase.class.getSimpleName());
+ private final Logger LOGGER;
public final String modID;
public final String modName;
public final int configVersion;
+ public boolean isLoaded = false;
+
+
+
/**
- * What the config works with
- *
- * Enum
- * Boolean
- * Byte
- * Integer
- * Double
- * Short
- * Long
- * Float
- * String
- *
- * // Below, "T" should be a value from above
- * List
- * ArrayList
- * Map
- * HashMap
+ * What the config works with
+ *
+ *
{@link Enum}
+ *
{@link Boolean}
+ *
{@link Byte}
+ *
{@link Integer}
+ *
{@link Double}
+ *
{@link Short}
+ *
{@link Long}
+ *
{@link Float}
+ *
{@link String}
+ *
+ *
// Below, "T" should be a value from above
+ *
// Note: This is not checked, so we trust that you are doing the right thing
+ *
List
+ *
ArrayList
+ *
Map
+ *
HashMap
*/
public static final List> acceptableInputs = new ArrayList>()
{{
@@ -75,6 +81,8 @@ public class ConfigBase
public ConfigBase(String modID, String modName, Class> config, int configVersion)
{
+ this.LOGGER = LogManager.getLogger(this.getClass().getSimpleName() + ", " + modID);
+
LOGGER.info("Initialising config for " + modName);
this.modID = modID;
this.modName = modName;
@@ -85,6 +93,8 @@ public class ConfigBase
// File handling (load from file)
this.configFileINSTANCE = new ConfigFileHandling(this);
this.configFileINSTANCE.loadFromFile();
+
+ isLoaded = true;
LOGGER.info("Config for " + modName + " initialised");
}
@@ -102,7 +112,7 @@ public class ConfigBase
}
catch (IllegalAccessException exception)
{
- exception.printStackTrace();
+ LOGGER.warn(exception);
}
AbstractConfigType, ?> entry = entries.get(entries.size() - 1);
@@ -151,10 +161,11 @@ public class ConfigBase
* @param checkEnums Checks if all the lang for the enum's exist
*/
// This is just to re-format the lang or check if there is something in the lang that is missing
+ @SuppressWarnings("unchecked")
public String generateLang(boolean onlyShowNew, boolean checkEnums)
{
ILangWrapper langWrapper = SingletonInjector.INSTANCE.get(ILangWrapper.class);
- List> enumList = new ArrayList<>();
+ List>> enumList = new ArrayList<>();
String generatedLang = "";
@@ -168,7 +179,7 @@ public class ConfigBase
if (checkEnums && entry.getType().isEnum() && !enumList.contains(entry.getType()))
{ // Put it in an enum list to work with at the end
- enumList.add((Class extends Enum>) entry.getType());
+ enumList.add((Class extends Enum>>) entry.getType());
}
if (!onlyShowNew || langWrapper.langExists(entryPrefix))
{
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/NumberUtil.java b/core/src/main/java/com/seibel/distanthorizons/core/config/NumberUtil.java
index b53e59f89..b09954a0b 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/config/NumberUtil.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/config/NumberUtil.java
@@ -13,7 +13,7 @@ import java.util.Map;
public class NumberUtil
{
// Is there no better way of doing this?
- public static Map minValues = new HashMap()
+ public static Map, Number> minValues = new HashMap, Number>()
{{
put(Byte.class, Byte.MIN_VALUE);
put(Short.class, Short.MIN_VALUE);
@@ -22,7 +22,7 @@ public class NumberUtil
put(Double.class, Double.MIN_VALUE);
put(Float.class, Float.MIN_VALUE);
}};
- public static Map maxValues = new HashMap()
+ public static Map, Number> maxValues = new HashMap, Number>()
{{
put(Byte.class, Byte.MAX_VALUE);
put(Short.class, Short.MAX_VALUE);
@@ -32,11 +32,11 @@ public class NumberUtil
put(Float.class, Float.MAX_VALUE);
}};
- public static Number getMinimum(Class c)
+ public static Number getMinimum(Class> c)
{
return minValues.get(c);
}
- public static Number getMaximum(Class c)
+ public static Number getMaximum(Class> c)
{
return maxValues.get(c);
}
@@ -46,7 +46,7 @@ public class NumberUtil
{
if (a.getClass() != b.getClass())
return false;
- Class typeClass = a.getClass();
+ Class> typeClass = a.getClass();
if (typeClass == Byte.class) return a.byteValue() > b.byteValue();
if (typeClass == Short.class) return a.shortValue() > b.shortValue();
@@ -62,7 +62,7 @@ public class NumberUtil
{
if (a.getClass() != b.getClass())
return false;
- Class typeClass = a.getClass();
+ Class> typeClass = a.getClass();
if (typeClass == Byte.class) return a.byteValue() < b.byteValue();
if (typeClass == Short.class) return a.shortValue() < b.shortValue();
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/eventHandlers/RenderCacheConfigEventHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/config/eventHandlers/RenderCacheConfigEventHandler.java
index 4f69ce2ed..4ad052173 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/config/eventHandlers/RenderCacheConfigEventHandler.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/config/eventHandlers/RenderCacheConfigEventHandler.java
@@ -20,13 +20,8 @@ public class RenderCacheConfigEventHandler implements IConfigListener
{
public static RenderCacheConfigEventHandler INSTANCE = new RenderCacheConfigEventHandler();
- // previous values used to check if a watched setting was actually modified
- private EVerticalQuality previousVerticalQualitySetting = null;
- private EMaxHorizontalResolution previousHorizontalResolution = null;
- private ELodShading lodShading = null;
-
/** how long to wait in milliseconds before applying the config changes */
- private static final long TIMEOUT_IN_MS = 400L;
+ private static final long TIMEOUT_IN_MS = 4_000L;
private Timer cacheClearingTimer;
@@ -38,38 +33,7 @@ public class RenderCacheConfigEventHandler implements IConfigListener
@Override
public void onConfigValueSet()
{
- // confirm a setting was actually changed
- boolean refreshRenderData = false;
-
-
- EVerticalQuality newVerticalQuality = Config.Client.Advanced.Graphics.Quality.verticalQuality.get();
- if (this.previousVerticalQualitySetting != newVerticalQuality)
- {
- this.previousVerticalQualitySetting = newVerticalQuality;
- refreshRenderData = true;
- }
-
- EMaxHorizontalResolution newHorizontalResolution = Config.Client.Advanced.Graphics.Quality.maxHorizontalResolution.get();
- if (this.previousHorizontalResolution != newHorizontalResolution)
- {
- this.previousHorizontalResolution = newHorizontalResolution;
- refreshRenderData = true;
- }
-
- ELodShading newLodShading = Config.Client.Advanced.Graphics.AdvancedGraphics.lodShading.get();
- if (this.lodShading != newLodShading)
- {
- this.lodShading = newLodShading;
- refreshRenderData = true;
- }
-
-
-
- if (refreshRenderData)
- {
- this.refreshRenderDataAfterTimeout();
- }
-
+ this.refreshRenderDataAfterTimeout();
}
@Override
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/eventHandlers/presets/AbstractPresetConfigEventHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/config/eventHandlers/presets/AbstractPresetConfigEventHandler.java
index 8e3681f34..4c42da829 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/config/eventHandlers/presets/AbstractPresetConfigEventHandler.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/config/eventHandlers/presets/AbstractPresetConfigEventHandler.java
@@ -1,5 +1,7 @@
package com.seibel.distanthorizons.core.config.eventHandlers.presets;
+import com.seibel.distanthorizons.core.config.Config;
+import com.seibel.distanthorizons.core.config.ConfigBase;
import com.seibel.distanthorizons.core.config.ConfigEntryWithPresetOptions;
import com.seibel.distanthorizons.core.config.listeners.IConfigListener;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
@@ -64,6 +66,12 @@ public abstract class AbstractPresetConfigEventHandler entry : this.configBase.entries)
{
if (ConfigEntry.class.isAssignableFrom(entry.getClass()))
{
- createComment((ConfigEntry>) entry, config);
- saveEntry((ConfigEntry>) entry, config);
+ createComment((ConfigEntry>) entry, nightConfig);
+ saveEntry((ConfigEntry>) entry, nightConfig);
}
}
try
{
- config.save();
+ nightConfig.save();
}
catch (Exception e)
{
// If it fails to save, crash game
SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class).crashMinecraft("Failed to save config at [" + configPath.toString() + "]", e);
}
- config.close();
}
+
/**
* Loads the entire config from the file
*
@@ -83,46 +86,50 @@ public class ConfigFileHandling
*/
public void loadFromFile()
{
- CommentedFileConfig config = CommentedFileConfig.builder(configPath.toFile()).build();
+ loadFromFile(nightConfig);
+ }
+ /**
+ * Loads the entire config from the file
+ *
+ * @apiNote This overwrites any value currently stored in the config
+ */
+ public void loadFromFile(CommentedFileConfig nightConfig)
+ {
// Attempt to load the file and if it fails then save config to file
- try
+ if (Files.exists(configPath))
{
- if (Files.exists(configPath))
- config.load();
- else
- {
- saveToFile();
- return;
- }
+ loadNightConfig(nightConfig);
}
- catch (Exception e)
+ else
{
- e.printStackTrace();
- saveToFile();
+ reCreateFile(configPath);
return;
}
+
// Load all the entries
for (AbstractConfigType, ?> entry : this.configBase.entries)
{
- if (ConfigEntry.class.isAssignableFrom(entry.getClass()))
+ if (
+ ConfigEntry.class.isAssignableFrom(entry.getClass()) &&
+ entry.getAppearance().showInFile
+ )
{
- createComment((ConfigEntry>) entry, config);
- loadEntry((ConfigEntry>) entry, config);
+ createComment((ConfigEntry>) entry, nightConfig);
+ loadEntry((ConfigEntry>) entry, nightConfig);
}
}
try
{
- config.save();
+ nightConfig.save();
}
catch (Exception e)
{
// If it fails to save, crash game
SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class).crashMinecraft("Failed to save config at [" + configPath.toString() + "]", e);
}
- config.close();
}
@@ -131,142 +138,148 @@ public class ConfigFileHandling
// Save an entry when only given the entry
public void saveEntry(ConfigEntry> entry)
{
- CommentedFileConfig config = CommentedFileConfig.builder(configPath.toFile()).build();
- loadConfig(config);
- saveEntry(entry, config);
- config.save();
- config.close();
+ saveEntry(entry, nightConfig);
+ nightConfig.save();
}
- // Save an entry
- @SuppressWarnings("unchecked")
+ /** Save an entry */
public void saveEntry(ConfigEntry> entry, CommentedFileConfig workConfig)
{
if (!entry.getAppearance().showInFile) return;
if (entry.getTrueValue() == null)
throw new IllegalArgumentException("Entry [" + entry.getNameWCategory() + "] is null, this may be a problem with [" + configBase.modName + "]. Please contact the authors");
- Class> originalClass = ConfigTypeConverters.isClassConvertable(entry.getType());
- if (originalClass != null)
- {
- workConfig.set(entry.getNameWCategory(), ConfigTypeConverters.convertToString(originalClass, entry.getTrueValue()));
- return;
- }
- workConfig.set(entry.getNameWCategory(), entry.getTrueValue());
+ workConfig.set(entry.getNameWCategory(), ConfigTypeConverters.attemptToConvertToString(entry.getType(), entry.getTrueValue()));
}
- // Loads an entry when only given the entry
+ /** Loads an entry when only given the entry */
public void loadEntry(ConfigEntry> entry)
{
- CommentedFileConfig config = CommentedFileConfig.builder(configPath.toFile()).autosave().build();
- loadConfig(config);
- loadEntry(entry, config);
- config.close();
-
+ loadEntry(entry, nightConfig);
}
- // Loads an entry
- @SuppressWarnings("unchecked") // Suppress due to its always safe
- public void loadEntry(ConfigEntry entry, CommentedFileConfig workConfig)
+ /** Loads an entry */
+ @SuppressWarnings("unchecked")
+ public void loadEntry(ConfigEntry entry, CommentedFileConfig nightConfig)
{
- if (!entry.getAppearance().showInFile) return;
+ if (!entry.getAppearance().showInFile)
+ return;
- if (workConfig.contains(entry.getNameWCategory()))
+ if (!nightConfig.contains(entry.getNameWCategory()))
{
- try
+ saveEntry(entry, nightConfig);
+ return;
+ }
+
+
+ try
+ {
+ if (entry.getType().isEnum())
{
- if (entry.getType().isEnum())
- {
- entry.pureSet((T) (workConfig.getEnum(entry.getNameWCategory(), (Class extends Enum>) entry.getType())));
- return;
- }
- Class> originalClass = ConfigTypeConverters.isClassConvertable(entry.getType());
- if (originalClass != null)
- {
- entry.pureSet((T) ConfigTypeConverters.convertFromString(originalClass, workConfig.get(entry.getNameWCategory())));
- return;
- }
-
- if (entry.getType() == workConfig.get(entry.getNameWCategory()).getClass())
- { // If the types are the same
- entry.pureSet((T) workConfig.get(entry.getNameWCategory()));
- entry.clampWithinRange();
- return;
- }
-
- LOGGER.warn("Entry [" + entry.getNameWCategory() + "] is invalid. Expected " + entry.getType() + " but got " + workConfig.get(entry.getNameWCategory()).getClass() + ". Using default value.");
- saveEntry(entry, workConfig);
+ entry.pureSet((T) (nightConfig.getEnum(entry.getNameWCategory(), (Class extends Enum>) entry.getType())));
+ return;
}
- catch (Exception e)
- {
-// e.printStackTrace();
- LOGGER.warn("Entry [" + entry.getNameWCategory() + "] had an invalid value when loading the config. Using default value.");
- saveEntry(entry, workConfig);
+
+ entry.pureSet((T) ConfigTypeConverters.attemptToConvertFromString(entry.getType(), nightConfig.get(entry.getNameWCategory())));
+
+ if (entry.getTrueValue() == null) {
+ LOGGER.warn("Entry [" + entry.getNameWCategory() + "] returned as null from the config. Using default value.");
+ entry.pureSet(entry.getDefaultValue());
}
}
- else
+ catch (Exception e)
{
- saveEntry(entry, workConfig);
+// e.printStackTrace();
+ LOGGER.warn("Entry [" + entry.getNameWCategory() + "] had an invalid value when loading the config. Using default value.");
+ entry.pureSet(entry.getDefaultValue());
}
}
// Creates the comment for an entry when only given the entry
public void createComment(ConfigEntry> entry)
{
- CommentedFileConfig config = CommentedFileConfig.builder(configPath.toFile()).autosave().build();
- loadConfig(config);
- createComment(entry, config);
- config.close();
+ createComment(entry, nightConfig);
}
// Creates a comment for an entry
- public void createComment(ConfigEntry> entry, CommentedFileConfig workConfig)
+ public void createComment(ConfigEntry> entry, CommentedFileConfig nightConfig)
{
- if (!entry.getAppearance().showInFile)
+ if (
+ !entry.getAppearance().showInFile ||
+ entry.getComment() == null
+ )
return;
- if (entry.getComment() != null)
- {
- workConfig.setComment(entry.getNameWCategory(), " " + entry.getComment().replaceAll("\n", "\n ") + "\n ");
- }
+
+ nightConfig.setComment(entry.getNameWCategory(), " " + entry.getComment().replaceAll("\n", "\n ") + "\n ");
}
- /** Does config.load(); but with error checking */
- public void loadConfig(CommentedFileConfig config)
+
+ /**
+ * Uses {@link ConfigFileHandling#nightConfig} to do {@link CommentedFileConfig#load()} but with error checking
+ *
+ * @apiNote This overwrites any value currently stored in the config
+ */
+ public void loadNightConfig()
+ {
+ loadNightConfig(this.nightConfig);
+ }
+ /**
+ * Does {@link CommentedFileConfig#load()} but with error checking
+ *
+ * @apiNote This overwrites any value currently stored in the config
+ */
+ public void loadNightConfig(CommentedFileConfig nightConfig)
{
try
{
- config.load();
- }
- catch (Exception e)
- {
- System.out.println("Loading file failed because of this expectation:\n" + e);
try
- { // Now try remaking the file and loading it
- if (!this.configPath.getParent().toFile().exists())
- {
- Files.createDirectory(this.configPath.getParent());
- }
-
- boolean fileDeleted = Files.deleteIfExists(this.configPath);
- System.out.println("File at [" + this.configPath + "] was " + (fileDeleted ? "" : "not ") + "able to be deleted.");
-
-
- Files.createFile(this.configPath);
-
- config.load();
- }
- catch (IOException ex)
{
- System.out.println("Creating file failed");
- ex.printStackTrace();
- SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class).crashMinecraft("Loading file and resetting config file failed at path [" + configPath + "]. Please check the file is ok and you have the permissions", ex);
+ if (!Files.exists(this.configPath))
+ Files.createFile(this.configPath);
+ nightConfig.load();
}
+ catch (Exception e)
+ {
+ LOGGER.warn("Loading file failed because of this expectation:\n" + e);
+
+ reCreateFile(this.configPath);
+
+ nightConfig.load();
+ }
+ }
+ catch (Exception ex)
+ {
+ System.out.println("Creating file failed");
+ LOGGER.error(ex);
+ SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class).crashMinecraft("Loading file and resetting config file failed at path [" + configPath + "]. Please check the file is ok and you have the permissions", ex);
}
}
+
+ public static void reCreateFile(Path path)
+ {
+ try
+ {
+ Files.deleteIfExists(path);
+
+ if (!path.getParent().toFile().exists())
+ {
+ Files.createDirectory(path.getParent());
+ }
+ Files.createFile(path);
+ }
+ catch (IOException ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+
+
+
+
// ========== API (server) STUFF ========== //
- /** ALWAYS CLEAR WHEN NOT ON SERVER!!!! */
+ /* * ALWAYS CLEAR WHEN NOT ON SERVER!!!! */
// We are not using this stuff, so comment it out for now (if we ever do need it then we can uncomment it)
/*
@SuppressWarnings("unchecked")
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/file/ConfigTypeConverters.java b/core/src/main/java/com/seibel/distanthorizons/core/config/file/ConfigTypeConverters.java
index 489c9d191..e35359770 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/config/file/ConfigTypeConverters.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/config/file/ConfigTypeConverters.java
@@ -37,6 +37,32 @@ public class ConfigTypeConverters
return null;
}
+ public static Object attemptToConvertToString(Object value)
+ {
+ return attemptToConvertToString(value.getClass(), value);
+ }
+ public static Object attemptToConvertToString(Class> clazz, Object value)
+ {
+ Class> convertablClass = isClassConvertable(clazz);
+ if (convertablClass != null) {
+ return convertToString(convertablClass, value);
+ }
+ return value;
+ }
+
+ public static Object attemptToConvertFromString(Object value)
+ {
+ return attemptToConvertFromString(value.getClass(), value);
+ }
+ public static Object attemptToConvertFromString(Class> clazz, Object value)
+ {
+ Class> convertablClass = isClassConvertable(clazz);
+ if (convertablClass != null) {
+ return convertFromString(convertablClass, (String) value);
+ }
+ return value;
+ }
+
public static String convertToString(Class> clazz, Object value)
{
try
@@ -116,9 +142,11 @@ public class ConfigTypeConverters
Map mapObject = (Map) item;
Config jsonObject = Config.inMemory();
+ Object[] keyArray = mapObject.keySet().toArray();
+
for (int i = 0; i < mapObject.size(); i++)
{
- jsonObject.add(mapObject.keySet().toArray()[i].toString(), mapObject.get(mapObject.keySet().toArray()[i]));
+ jsonObject.add(keyArray[i].toString(), mapObject.get(keyArray[i]));
}
return JsonFormat.minimalInstance().createWriter().writeToString(jsonObject);
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/types/AbstractConfigType.java b/core/src/main/java/com/seibel/distanthorizons/core/config/types/AbstractConfigType.java
index 218d4bcc4..f7aaa3b15 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/config/types/AbstractConfigType.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/config/types/AbstractConfigType.java
@@ -8,10 +8,12 @@ import com.seibel.distanthorizons.core.config.types.enums.EConfigEntryAppearance
*
* @author coolGi
*/
+// Note for devs: The "S" is the class that is extending this
public abstract class AbstractConfigType
-{ // The S is the class that is extending this
+{
public String category = ""; // This should only be set once in the init
public String name; // This should only be set once in the init
+ protected final T defaultValue;
protected T value;
public ConfigBase configBase;
@@ -21,8 +23,9 @@ public abstract class AbstractConfigType
protected AbstractConfigType(EConfigEntryAppearance appearance, T value)
{
- this.appearance = appearance;
+ this.defaultValue = value;
this.value = value;
+ this.appearance = appearance;
}
@@ -64,7 +67,7 @@ public abstract class AbstractConfigType
// Gets the class of T
public Class> getType()
{
- return value.getClass();
+ return this.defaultValue.getClass();
}
protected static abstract class Builder
@@ -74,11 +77,13 @@ public abstract class AbstractConfigType
// Put this into your own builder
+ @SuppressWarnings("unchecked")
public S setAppearance(EConfigEntryAppearance newAppearance)
{
this.tmpAppearance = newAppearance;
return (S) this;
}
+ @SuppressWarnings("unchecked")
public S set(T newValue)
{
this.tmpValue = newValue;
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/types/ConfigCategory.java b/core/src/main/java/com/seibel/distanthorizons/core/config/types/ConfigCategory.java
index 07d5dea9a..0e25ff232 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/config/types/ConfigCategory.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/config/types/ConfigCategory.java
@@ -8,12 +8,12 @@ import com.seibel.distanthorizons.core.config.types.enums.EConfigEntryAppearance
*
* @author coolGi
*/
-public class ConfigCategory extends AbstractConfigType
+public class ConfigCategory extends AbstractConfigType, ConfigCategory>
{
/** This should not be set by anything other than the config system itself */
public String destination; // Where the category goes to
- private ConfigCategory(EConfigEntryAppearance appearance, Class value, String destination)
+ private ConfigCategory(EConfigEntryAppearance appearance, Class> value, String destination)
{
super(appearance, value);
this.destination = destination;
@@ -32,7 +32,7 @@ public class ConfigCategory extends AbstractConfigType
return value;
}
- public static class Builder extends AbstractConfigType.Builder
+ public static class Builder extends AbstractConfigType.Builder, Builder>
{
private String tmpDestination = null;
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/types/ConfigEntry.java b/core/src/main/java/com/seibel/distanthorizons/core/config/types/ConfigEntry.java
index cf3a820d1..2fbd85471 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/config/types/ConfigEntry.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/config/types/ConfigEntry.java
@@ -19,7 +19,6 @@ import java.util.Arrays;
*/
public class ConfigEntry extends AbstractConfigType> implements IConfigEntry
{
- private final T defaultValue;
private String comment;
private T min;
private T max;
@@ -41,7 +40,6 @@ public class ConfigEntry extends AbstractConfigType> implem
{
super(appearance, value);
- this.defaultValue = value;
this.comment = comment;
this.min = min;
this.max = max;
@@ -54,7 +52,7 @@ public class ConfigEntry extends AbstractConfigType> implem
/** Gets the default value of the option */
@Override
- public T getDefaultValue() { return this.defaultValue; }
+ public T getDefaultValue() { return super.defaultValue; }
@Override
public void setApiValue(T newApiValue)
@@ -70,7 +68,7 @@ public class ConfigEntry extends AbstractConfigType> implem
/**
* DONT USE THIS IN YOUR CODE
* Sets the value without informing the rest of the code (ie, doesnt call listeners, or saves the value).
- * Should only be used when loading the config from the file
+ * Should only be used when loading the config from the file (in places like the {@link com.seibel.distanthorizons.core.config.file.ConfigFileHandling} or {@link com.seibel.distanthorizons.core.config.ConfigBase})
*/
public void pureSet(T newValue) {
super.set(newValue);
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/types/ConfigLinkedEntry.java b/core/src/main/java/com/seibel/distanthorizons/core/config/types/ConfigLinkedEntry.java
index b4c8f275b..f7fbdcb47 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/config/types/ConfigLinkedEntry.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/config/types/ConfigLinkedEntry.java
@@ -8,9 +8,9 @@ import com.seibel.distanthorizons.core.config.types.enums.EConfigEntryAppearance
*
* @author coolGi
*/
-public class ConfigLinkedEntry extends AbstractConfigType
+public class ConfigLinkedEntry extends AbstractConfigType, ConfigLinkedEntry>
{
- public ConfigLinkedEntry(AbstractConfigType value)
+ public ConfigLinkedEntry(AbstractConfigType, ?> value)
{
super(EConfigEntryAppearance.ONLY_IN_GUI, value);
}
@@ -21,10 +21,10 @@ public class ConfigLinkedEntry extends AbstractConfigType newValue) { }
- public static class Builder extends AbstractConfigType.Builder
+ public static class Builder extends AbstractConfigType.Builder, Builder>
{
/** Appearance shouldn't be changed */
@Override
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/types/ConfigUIButton.java b/core/src/main/java/com/seibel/distanthorizons/core/config/types/ConfigUIButton.java
index d96afea82..e60fbb680 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/config/types/ConfigUIButton.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/config/types/ConfigUIButton.java
@@ -9,9 +9,10 @@ public class ConfigUIButton extends AbstractConfigType
super(EConfigEntryAppearance.ONLY_IN_GUI, runnable);
}
+ /** Runs the action of the button. NOTE: Will run on the main thread (so can halt the main process if not offloaded to a different thread) */
public void runAction()
{
- new Thread(this.value).start();
+ this.value.run();
}
public static class Builder extends AbstractConfigType.Builder
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/FullDataPointIdMap.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/FullDataPointIdMap.java
index 27c22b309..a12e9a8ee 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/FullDataPointIdMap.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/FullDataPointIdMap.java
@@ -1,24 +1,19 @@
package com.seibel.distanthorizons.core.dataObjects.fullData;
-import com.seibel.distanthorizons.api.enums.config.ELoggerMode;
-import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.pos.DhSectionPos;
import com.seibel.distanthorizons.core.util.objects.dataStreams.DhDataInputStream;
import com.seibel.distanthorizons.core.util.objects.dataStreams.DhDataOutputStream;
-import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory;
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
+import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
-import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
-import java.io.IOException;
+import java.io.*;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.HashMap;
-import java.util.Objects;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
@@ -37,7 +32,7 @@ public class FullDataPointIdMap
* Has the system check if any duplicate Entries were read/written
* when (de)serializing.
*/
- private static final boolean RUN_SERIALIZATION_DUPLICATE_VALIDATION = true;
+ private static final boolean RUN_SERIALIZATION_DUPLICATE_VALIDATION = false;
/** Distant Horizons - Block State Wrapper */
private static final String BLOCK_STATE_SEPARATOR_STRING = "_DH-BSW_";
@@ -45,28 +40,28 @@ public class FullDataPointIdMap
// FIXME: Improve performance maybe?
/** used when the data point map is running normally */
private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
-
+
/** should only be used for debugging */
private final DhSectionPos pos;
/** The index should be the same as the Entry's ID */
private final ArrayList entryList = new ArrayList<>();
private final HashMap idMap = new HashMap<>();
-
-
-
+
+
+
//=============//
// constructor //
//=============//
-
+
public FullDataPointIdMap(DhSectionPos pos) { this.pos = pos; }
-
-
-
+
+
+
//=========//
// methods //
//=========//
-
+
private Entry getEntry(int id)
{
this.readWriteLock.readLock().lock();
@@ -80,7 +75,7 @@ public class FullDataPointIdMap
LOGGER.error("FullData ID Map out of sync for pos: " + this.pos + ". ID: [" + id + "] greater than the number of known ID's: [" + this.entryList.size() + "].");
throw e;
}
-
+
this.readWriteLock.readLock().unlock();
return entry;
}
@@ -96,9 +91,12 @@ public class FullDataPointIdMap
/** @param useWriteLocks should only be false if this method is already in a write lock to prevent unlocking at the wrong time */
private int addIfNotPresentAndGetId(Entry biomeBlockStateEntry, boolean useWriteLocks)
{
- if (useWriteLocks) { this.readWriteLock.writeLock().lock(); }
-
-
+ if (useWriteLocks)
+ {
+ this.readWriteLock.writeLock().lock();
+ }
+
+
int id;
if (this.idMap.containsKey(biomeBlockStateEntry))
{
@@ -112,10 +110,13 @@ public class FullDataPointIdMap
this.entryList.add(biomeBlockStateEntry);
this.idMap.put(biomeBlockStateEntry, id);
}
-
-
- if (useWriteLocks) { this.readWriteLock.writeLock().unlock(); }
-
+
+
+ if (useWriteLocks)
+ {
+ this.readWriteLock.writeLock().unlock();
+ }
+
return id;
}
@@ -131,7 +132,7 @@ public class FullDataPointIdMap
target.readWriteLock.readLock().lock();
this.readWriteLock.writeLock().lock();
-
+
ArrayList entriesToMerge = target.entryList;
int[] remappedEntryIds = new int[entriesToMerge.size()];
for (int i = 0; i < entriesToMerge.size(); i++)
@@ -140,7 +141,7 @@ public class FullDataPointIdMap
int id = this.addIfNotPresentAndGetId(entity, false);
remappedEntryIds[i] = id;
}
-
+
this.readWriteLock.writeLock().unlock();
target.readWriteLock.readLock().unlock();
@@ -150,19 +151,19 @@ public class FullDataPointIdMap
}
/** Serializes all contained entries into the given stream, formatted in UTF */
- public void serialize(DhDataOutputStream outputStream, ILevelWrapper levelWrapper) throws IOException
+ public void serialize(DhDataOutputStream outputStream) throws IOException
{
this.readWriteLock.readLock().lock();
outputStream.writeInt(this.entryList.size());
-
+
// only used when debugging
HashMap dataPointEntryBySerialization = new HashMap<>();
-
+
for (Entry entry : this.entryList)
{
String entryString = entry.serialize();
outputStream.writeUTF(entryString);
-
+
if (RUN_SERIALIZATION_DUPLICATE_VALIDATION)
{
if (dataPointEntryBySerialization.containsKey(entryString))
@@ -185,20 +186,17 @@ public class FullDataPointIdMap
public static FullDataPointIdMap deserialize(DhDataInputStream inputStream, DhSectionPos pos, ILevelWrapper levelWrapper) throws IOException, InterruptedException
{
int entityCount = inputStream.readInt();
-
+
// only used when debugging
HashMap dataPointEntryBySerialization = new HashMap<>();
-
+
FullDataPointIdMap newMap = new FullDataPointIdMap(pos);
for (int i = 0; i < entityCount; i++)
{
String entryString = inputStream.readUTF();
Entry newEntry = Entry.deserialize(entryString, levelWrapper);
- // Required check because of an underlying issue where the BiomeWrapper and BlockStateWrapper get null ILevelWrappers
- if (newEntry != null) {
- newMap.entryList.add(newEntry);
- }
-
+ newMap.entryList.add(newEntry);
+
if (RUN_SERIALIZATION_DUPLICATE_VALIDATION)
{
if (dataPointEntryBySerialization.containsKey(entryString))
@@ -212,9 +210,9 @@ public class FullDataPointIdMap
dataPointEntryBySerialization.put(entryString, newEntry);
}
}
-
- LOGGER.trace("deserialized "+pos+" "+newMap.entryList.size()+"-"+entityCount);
-
+
+ LOGGER.trace("deserialized " + pos + " " + newMap.entryList.size() + "-" + entityCount);
+
return newMap;
}
@@ -246,10 +244,10 @@ public class FullDataPointIdMap
public final IBlockStateWrapper blockState;
private Integer hashCode = null;
-
-
+
+
// constructor //
-
+
public Entry(IBiomeWrapper biome, IBlockStateWrapper blockState)
{
this.biome = biome;
@@ -257,9 +255,9 @@ public class FullDataPointIdMap
}
-
+
// methods //
-
+
@Override
public int hashCode()
{
@@ -268,7 +266,7 @@ public class FullDataPointIdMap
{
this.hashCode = this.serialize().hashCode();
}
-
+
return this.hashCode;
}
@@ -282,30 +280,26 @@ public class FullDataPointIdMap
return false;
Entry other = (Entry) otherObj;
- return other.biome.serialize().equals(this.biome.serialize())
- && other.blockState.serialize().equals(this.blockState.serialize());
- }
-
- @Override
- public String toString() {
- return this.serialize();
+ return other.biome.getSerialString().equals(this.biome.getSerialString())
+ && other.blockState.getSerialString().equals(this.blockState.getSerialString());
}
- public String serialize() {
- return this.biome.serialize() + BLOCK_STATE_SEPARATOR_STRING + this.blockState.serialize();
- }
-
+ @Override
+ public String toString() { return this.serialize(); }
+
+
+
+ public String serialize() { return this.biome.getSerialString() + BLOCK_STATE_SEPARATOR_STRING + this.blockState.getSerialString(); }
+
public static Entry deserialize(String str, ILevelWrapper levelWrapper) throws IOException, InterruptedException
{
String[] stringArray = str.split(BLOCK_STATE_SEPARATOR_STRING);
if (stringArray.length != 2)
{
- // This situation should never occur, both the biome and the blockstate in the entry will always have a value, even if it's default
- // The default values will be handled by the biome and blockstate's deserialize functions
throw new IOException("Failed to deserialize BiomeBlockStateEntry");
}
- // Necessary to prevent issues with deserializing objects after the level has been closed
+ // necessary to prevent issues with deserializing objects after the level has been closed
if (Thread.interrupted())
{
throw new InterruptedException(FullDataPointIdMap.class.getSimpleName() + " task interrupted.");
@@ -315,5 +309,8 @@ public class FullDataPointIdMap
IBlockStateWrapper blockState = WRAPPER_FACTORY.deserializeBlockStateWrapper(stringArray[1], levelWrapper);
return new Entry(biome, blockState);
}
+
}
+
+
}
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/accessor/ChunkSizedFullDataAccessor.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/accessor/ChunkSizedFullDataAccessor.java
index 51da8db2d..a846ad42e 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/accessor/ChunkSizedFullDataAccessor.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/accessor/ChunkSizedFullDataAccessor.java
@@ -152,10 +152,10 @@ public class ChunkSizedFullDataAccessor extends FullDataArrayAccessor
}
- public void writeIdMappings(DhDataOutputStream outputStream, ILevelWrapper levelWrapper) throws IOException
+ public void writeIdMappings(DhDataOutputStream outputStream) throws IOException
{
outputStream.writeInt(IFullDataSource.DATA_GUARD_BYTE);
- this.mapping.serialize(outputStream, levelWrapper);
+ this.mapping.serialize(outputStream);
}
public FullDataPointIdMap readIdMappings(DhDataInputStream inputStream, ILevelWrapper levelWrapper) throws IOException, InterruptedException
{
@@ -197,7 +197,7 @@ public class ChunkSizedFullDataAccessor extends FullDataArrayAccessor
return;
}
- this.writeIdMappings(outputStream, level.getLevelWrapper());
+ this.writeIdMappings(outputStream);
}
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/CompleteFullDataSource.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/CompleteFullDataSource.java
index 99558e014..762ed4c1c 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/CompleteFullDataSource.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/CompleteFullDataSource.java
@@ -230,10 +230,10 @@ public class CompleteFullDataSource extends FullDataArrayAccessor implements IFu
@Override
- public void writeIdMappings(DhDataOutputStream outputStream, ILevelWrapper levelWrapper) throws IOException
+ public void writeIdMappings(DhDataOutputStream outputStream) throws IOException
{
outputStream.writeInt(IFullDataSource.DATA_GUARD_BYTE);
- this.mapping.serialize(outputStream, levelWrapper);
+ this.mapping.serialize(outputStream);
}
@Override
public FullDataPointIdMap readIdMappings(long[][] dataPoints, DhDataInputStream inputStream, ILevelWrapper levelWrapper) throws IOException, InterruptedException
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/HighDetailIncompleteFullDataSource.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/HighDetailIncompleteFullDataSource.java
index 5795b4245..c717ac67a 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/HighDetailIncompleteFullDataSource.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/HighDetailIncompleteFullDataSource.java
@@ -365,10 +365,10 @@ public class HighDetailIncompleteFullDataSource implements IIncompleteFullDataSo
}
@Override
- public void writeIdMappings(DhDataOutputStream outputStream, ILevelWrapper levelWrapper) throws IOException
+ public void writeIdMappings(DhDataOutputStream outputStream) throws IOException
{
outputStream.writeInt(IFullDataSource.DATA_GUARD_BYTE);
- this.mapping.serialize(outputStream, levelWrapper);
+ this.mapping.serialize(outputStream);
}
@Override
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/LowDetailIncompleteFullDataSource.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/LowDetailIncompleteFullDataSource.java
index d0b280007..03cb238c2 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/LowDetailIncompleteFullDataSource.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/LowDetailIncompleteFullDataSource.java
@@ -238,10 +238,10 @@ public class LowDetailIncompleteFullDataSource extends FullDataArrayAccessor imp
@Override
- public void writeIdMappings(DhDataOutputStream outputStream, ILevelWrapper levelWrapper) throws IOException
+ public void writeIdMappings(DhDataOutputStream outputStream) throws IOException
{
outputStream.writeInt(IFullDataSource.DATA_GUARD_BYTE);
- this.mapping.serialize(outputStream, levelWrapper);
+ this.mapping.serialize(outputStream);
}
@Override
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/interfaces/IStreamableFullDataSource.java b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/interfaces/IStreamableFullDataSource.java
index ff54ee9ba..147ad5b06 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/interfaces/IStreamableFullDataSource.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/dataObjects/fullData/sources/interfaces/IStreamableFullDataSource.java
@@ -70,7 +70,7 @@ public interface IStreamableFullDataSource RENDERER_IGNORED_BLOCKS = WRAPPER_FACTORY.getRendererIgnoredBlocks();
@@ -292,6 +291,7 @@ public class FullDataToRenderDataTransformer
boolean colorBelowWithAvoidedBlocks = Config.Client.Advanced.Graphics.Quality.tintWithAvoidedBlocks.get();
FullDataPointIdMap fullDataMapping = data.getMapping();
+ HashSet blockStatesToIgnore = WRAPPER_FACTORY.getRendererIgnoredBlocks(level.getLevelWrapper());
boolean isVoid = true;
int colorToApplyToNextBlock = -1;
@@ -308,10 +308,9 @@ public class FullDataToRenderDataTransformer
IBiomeWrapper biome = fullDataMapping.getBiomeWrapper(id);
IBlockStateWrapper block = fullDataMapping.getBlockStateWrapper(id);
- if (RENDERER_IGNORED_BLOCKS.containsValue(block))
+ if (blockStatesToIgnore.contains(block))
{
- // Don't render a block that's marked as ignored by the renderer
- // This map should include air (if it doesn't, the map either got refactored or something is wrong)
+ // Don't render: air, barriers, light blocks, etc.
continue;
}
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataFileHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataFileHandler.java
index ca336efb6..b0164d2f7 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataFileHandler.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/file/fullDatafile/GeneratedFullDataFileHandler.java
@@ -6,12 +6,10 @@ import com.seibel.distanthorizons.core.dataObjects.fullData.sources.interfaces.I
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.interfaces.IIncompleteFullDataSource;
import com.seibel.distanthorizons.core.file.structure.AbstractSaveStructure;
import com.seibel.distanthorizons.core.generation.IWorldGenerationQueue;
-import com.seibel.distanthorizons.core.generation.WorldGenerationQueue;
import com.seibel.distanthorizons.core.generation.tasks.IWorldGenTaskTracker;
import com.seibel.distanthorizons.core.generation.tasks.WorldGenResult;
import com.seibel.distanthorizons.core.level.DhLevel;
import com.seibel.distanthorizons.core.level.IDhLevel;
-import com.seibel.distanthorizons.core.level.IDhServerLevel;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.pos.DhLodPos;
import com.seibel.distanthorizons.core.pos.DhSectionPos;
@@ -80,8 +78,9 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler
this.worldGenQueueRef.set(null);
incompleteDataSources.clear(); // clear the incomplete data sources
}
-
- public void removeGenRequestIf(Function removeIf) {
+
+ public void removeGenRequestIf(Function removeIf)
+ {
HashSet removedRequests = new HashSet<>();
this.incompleteDataSources.forEach((pos, dataSource) ->
@@ -119,7 +118,8 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler
//========//
@Nullable
- private CompletableFuture tryStartGenTask(FullDataMetaFile file, IIncompleteFullDataSource dataSource) {
+ private CompletableFuture tryStartGenTask(FullDataMetaFile file, IIncompleteFullDataSource dataSource)
+ {
IWorldGenerationQueue worldGenQueue = this.worldGenQueueRef.get();
// breaks down the missing positions into the desired detail level that the gen queue could accept
if (worldGenQueue != null && !file.genQueueChecked)
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/subDimMatching/SubDimensionLevelMatcher.java b/core/src/main/java/com/seibel/distanthorizons/core/file/subDimMatching/SubDimensionLevelMatcher.java
index 11e4e2a57..69321a724 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/file/subDimMatching/SubDimensionLevelMatcher.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/file/subDimMatching/SubDimensionLevelMatcher.java
@@ -188,12 +188,12 @@ public class SubDimensionLevelMatcher implements AutoCloseable
{
// the chunk isn't empty but the LOD is...
- String message = "Error: the chunk at (" + playerChunkPos.getX() + "," + playerChunkPos.getZ() + ") has a height of [" + newlyLoadedChunk.getHeight() + "] but the LOD generated is empty!";
+ String message = "Error: the chunk at (" + playerChunkPos.x + "," + playerChunkPos.z + ") has a height of [" + newlyLoadedChunk.getHeight() + "] but the LOD generated is empty!";
LOGGER.error(message);
}
else
{
- String message = "Warning: The chunk at (" + playerChunkPos.getX() + "," + playerChunkPos.getZ() + ") is empty.";
+ String message = "Warning: The chunk at (" + playerChunkPos.x + "," + playerChunkPos.z + ") is empty.";
LOGGER.warn(message);
}
return null;
@@ -264,7 +264,7 @@ public class SubDimensionLevelMatcher implements AutoCloseable
// stop if the test chunk doesn't contain any data
if (!testLodDataExists)
{
- String message = "The test chunk for dimension folder [" + LodUtil.shortenString(testLevelFolder.getName(), 8) + "] and chunk pos (" + playerChunkPos.getX() + "," + playerChunkPos.getZ() + ") is empty. This is expected if the position is outside the sub-dimension's generated area.";
+ String message = "The test chunk for dimension folder [" + LodUtil.shortenString(testLevelFolder.getName(), 8) + "] and chunk pos (" + playerChunkPos.x + "," + playerChunkPos.z + ") is empty. This is expected if the position is outside the sub-dimension's generated area.";
LOGGER.info(message);
continue;
}
@@ -272,7 +272,7 @@ public class SubDimensionLevelMatcher implements AutoCloseable
// get the player data for this dimension folder
SubDimensionPlayerData testPlayerData = new SubDimensionPlayerData(testLevelFolder);
- LOGGER.info("Last known player pos: [" + testPlayerData.playerBlockPos.getX() + "," + testPlayerData.playerBlockPos.getY() + "," + testPlayerData.playerBlockPos.getZ() + "]");
+ LOGGER.info("Last known player pos: [" + testPlayerData.playerBlockPos.x + "," + testPlayerData.playerBlockPos.y + "," + testPlayerData.playerBlockPos.z + "]");
// check if the block positions are close
int playerBlockDist = testPlayerData.playerBlockPos.getManhattanDistance(playerData.playerBlockPos);
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/generation/IWorldGenerationQueue.java b/core/src/main/java/com/seibel/distanthorizons/core/generation/IWorldGenerationQueue.java
index e1aa2e376..7181ae80e 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/generation/IWorldGenerationQueue.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/generation/IWorldGenerationQueue.java
@@ -11,11 +11,13 @@ import java.util.concurrent.CompletableFuture;
public interface IWorldGenerationQueue extends Closeable
{
+ /** the largest numerical detail level */
byte largestDataDetail();
CompletableFuture submitGenTask(DhLodPos pos, byte requiredDataDetail, IWorldGenTaskTracker tracker);
void cancelGenTasks(Iterable positions);
+ /** @param targetPos the position that world generation should be centered around, generally this will be the player's position. */
void runCurrentGenTasksUntilBusy(DhBlockPos2D targetPos);
int getWaitingTaskCount();
@@ -23,4 +25,5 @@ public interface IWorldGenerationQueue extends Closeable
CompletableFuture startClosing(boolean cancelCurrentGeneration, boolean alsoInterruptRunning);
void close();
+
}
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/generation/WorldGenerationQueue.java b/core/src/main/java/com/seibel/distanthorizons/core/generation/WorldGenerationQueue.java
index 53260b68e..51e34783f 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/generation/WorldGenerationQueue.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/generation/WorldGenerationQueue.java
@@ -51,7 +51,8 @@ public class WorldGenerationQueue implements IWorldGenerationQueue, IDebugRender
/** largest numerical detail level allowed */
public final byte largestDataDetail;
- @Override public byte largestDataDetail() { return this.largestDataDetail; }
+ @Override
+ public byte largestDataDetail() { return this.largestDataDetail; }
/** lowest numerical detail level allowed */
public final byte smallestDataDetail;
@@ -159,7 +160,7 @@ public class WorldGenerationQueue implements IWorldGenerationQueue, IDebugRender
@Override
public void cancelGenTasks(Iterable positions)
{
- // TODO Cancel gen tasks properly
+ // TODO Should we cancel generation of chunks that were loaded by the player?
}
//===============//
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/jar/DarkModeDetector.java b/core/src/main/java/com/seibel/distanthorizons/core/jar/DarkModeDetector.java
index bb690e039..5bddb1512 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/jar/DarkModeDetector.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/jar/DarkModeDetector.java
@@ -11,7 +11,7 @@ import java.util.regex.Pattern;
*
* @author HanSolo
* @author IMS
- * @author coolGi2007
+ * @author coolGi
*/
public class DarkModeDetector
{
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/jar/Platform.java b/core/src/main/java/com/seibel/distanthorizons/core/jar/Platform.java
index 141ad25e6..74820fe9d 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/jar/Platform.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/jar/Platform.java
@@ -1,7 +1,7 @@
package com.seibel.distanthorizons.core.jar;
/**
- * A simple OS getting util based off LWJGL's Platform at org.lwjgl.system.Platform.
+ * A simple OS getting util based off LWJGL's Platform at {@link org.lwjgl.system.Platform}.
* This version includes some extra utils that we need and removes stuff which we don't.
*
* @author coolGi
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java
index bea8afdcf..7a7a22d95 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java
@@ -36,7 +36,7 @@ public class DhClientLevel extends DhLevel implements IDhClientLevel
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
private static final IMinecraftClientWrapper MC_CLIENT = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
- private static class WorldGenState extends WorldGenModule.WorldGenState
+ private static class WorldGenState extends WorldGenModule.AbstractWorldGenState
{
WorldGenState(IDhClientLevel level, ClientNetworkState networkState)
{
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientServerLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientServerLevel.java
index acc6ce14a..8417a7f74 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientServerLevel.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientServerLevel.java
@@ -42,7 +42,7 @@ public class DhClientServerLevel extends DhLevel implements IDhClientLevel, IDhS
LOGGER.warn("unable to create data folder.");
}
this.serverLevelWrapper = serverLevelWrapper;
- this.serverside = new ServerLevelModule(this, serverLevelWrapper, saveStructure);
+ this.serverside = new ServerLevelModule(this, saveStructure);
this.clientside = new ClientLevelModule(this);
LOGGER.info("Started " + DhClientServerLevel.class.getSimpleName() + " for " + serverLevelWrapper + " with saves at " + saveStructure);
}
@@ -129,7 +129,7 @@ public class DhClientServerLevel extends DhLevel implements IDhClientLevel, IDhS
}
@Override
- public IClientLevelWrapper getClientLevelWrapper() { return serverside.levelWrapper.tryGetClientLevelWrapper(); }
+ public IClientLevelWrapper getClientLevelWrapper() { return this.serverLevelWrapper.tryGetClientLevelWrapper(); }
@Override
public void clearRenderCache()
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/DhServerLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/DhServerLevel.java
index ac1934c88..46d8c41a4 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/level/DhServerLevel.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/level/DhServerLevel.java
@@ -53,7 +53,7 @@ public class DhServerLevel extends DhLevel implements IDhServerLevel
LOGGER.warn("unable to create data folder.");
}
this.serverLevelWrapper = serverLevelWrapper;
- serverside = new ServerLevelModule(this, serverLevelWrapper, saveStructure);
+ this.serverside = new ServerLevelModule(this, saveStructure);
LOGGER.info("Started DHLevel for {} with saves at {}", serverLevelWrapper, saveStructure);
this.remotePlayerConnectionHandler = remotePlayerConnectionHandler;
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/IDhServerLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/IDhServerLevel.java
index e142d2417..b6ed06b04 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/level/IDhServerLevel.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/level/IDhServerLevel.java
@@ -3,7 +3,7 @@ package com.seibel.distanthorizons.core.level;
import com.seibel.distanthorizons.core.file.fullDatafile.GeneratedFullDataFileHandler;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
-public interface IDhServerLevel extends IDhWorldGenLevel, GeneratedFullDataFileHandler.IOnWorldGenCompleteListener
+public interface IDhServerLevel extends IDhWorldGenLevel
{
void serverTick();
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/ServerLevelModule.java b/core/src/main/java/com/seibel/distanthorizons/core/level/ServerLevelModule.java
index ccac9303e..f3537f03c 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/level/ServerLevelModule.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/level/ServerLevelModule.java
@@ -8,17 +8,48 @@ import com.seibel.distanthorizons.core.file.structure.AbstractSaveStructure;
import com.seibel.distanthorizons.core.generation.BatchGenerator;
import com.seibel.distanthorizons.core.generation.WorldGenerationQueue;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
-import com.seibel.distanthorizons.core.pos.DhBlockPos2D;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
import com.seibel.distanthorizons.coreapi.DependencyInjection.WorldGeneratorInjector;
import org.apache.logging.log4j.Logger;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.atomic.AtomicReference;
-
public class ServerLevelModule
{
- public static class WorldGenState extends WorldGenModule.WorldGenState
+ private static final Logger LOGGER = DhLoggerBuilder.getLogger();
+
+ public final IDhServerLevel parentServerLevel;
+ public final AbstractSaveStructure saveStructure;
+ public final GeneratedFullDataFileHandler dataFileHandler;
+ public final AppliedConfigState worldGeneratorEnabledConfig;
+
+ public final WorldGenModule worldGenModule;
+
+
+
+ public ServerLevelModule(IDhServerLevel parentServerLevel, AbstractSaveStructure saveStructure)
+ {
+ this.parentServerLevel = parentServerLevel;
+ this.saveStructure = saveStructure;
+ this.dataFileHandler = new GeneratedFullDataFileHandler(parentServerLevel, saveStructure);
+ this.worldGeneratorEnabledConfig = new AppliedConfigState<>(Config.Client.Advanced.WorldGenerator.enableDistantGeneration);
+ this.worldGenModule = new WorldGenModule(this.dataFileHandler, this.parentServerLevel);
+ }
+
+
+
+ public void close()
+ {
+ // shutdown the world-gen
+ this.worldGenModule.close();
+ this.dataFileHandler.close();
+ }
+
+
+
+ //================//
+ // helper classes //
+ //================//
+
+ public static class WorldGenState extends WorldGenModule.AbstractWorldGenState
{
WorldGenState(IDhServerLevel level)
{
@@ -36,43 +67,4 @@ public class ServerLevelModule
}
- private static final Logger LOGGER = DhLoggerBuilder.getLogger();
- public final IServerLevelWrapper levelWrapper;
- public final IDhServerLevel parent;
- public final AbstractSaveStructure saveStructure;
- public final GeneratedFullDataFileHandler dataFileHandler;
- public final AppliedConfigState worldGeneratorEnabledConfig;
- public final WorldGenModule worldGenModule;
-
- public ServerLevelModule(IDhServerLevel parent, IServerLevelWrapper levelWrapper, AbstractSaveStructure saveStructure)
- {
- this.parent = parent;
- this.levelWrapper = levelWrapper;
- this.saveStructure = saveStructure;
- this.dataFileHandler = new GeneratedFullDataFileHandler(parent, saveStructure);
- this.worldGeneratorEnabledConfig = new AppliedConfigState<>(Config.Client.Advanced.WorldGenerator.enableDistantGeneration);
- this.worldGenModule = new WorldGenModule(this.dataFileHandler, this.parent);
- }
-
- //===============//
- // data handling //
- //===============//
- public void close()
- {
- // shutdown the world-gen
- this.worldGenModule.close();
- dataFileHandler.close();
- }
-
-
-
- //=======================//
- // misc helper functions //
- //=======================//
-
- public void dumpRamUsage()
- {
- //TODO
- }
-
}
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/WorldGenModule.java b/core/src/main/java/com/seibel/distanthorizons/core/level/WorldGenModule.java
index 97b0c9232..1f3b26c1b 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/level/WorldGenModule.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/level/WorldGenModule.java
@@ -18,10 +18,127 @@ public class WorldGenModule implements Closeable
private final GeneratedFullDataFileHandler dataFileHandler;
private final GeneratedFullDataFileHandler.IOnWorldGenCompleteListener onWorldGenCompleteListener;
- private final AtomicReference worldGenStateRef = new AtomicReference<>();
+ private final AtomicReference worldGenStateRef = new AtomicReference<>();
private final F3Screen.DynamicMessage worldGenF3Message;
- public static abstract class WorldGenState
+
+
+ public WorldGenModule(GeneratedFullDataFileHandler dataFileHandler, GeneratedFullDataFileHandler.IOnWorldGenCompleteListener onWorldGenCompleteListener)
+ {
+ this.dataFileHandler = dataFileHandler;
+ this.onWorldGenCompleteListener = onWorldGenCompleteListener;
+ this.worldGenF3Message = new F3Screen.DynamicMessage(() ->
+ {
+ AbstractWorldGenState worldGenState = this.worldGenStateRef.get();
+ if (worldGenState != null)
+ {
+ int waitingCount = worldGenState.worldGenerationQueue.getWaitingTaskCount();
+ int inProgressCount = worldGenState.worldGenerationQueue.getInProgressTaskCount();
+
+ return "World Gen Tasks: "+waitingCount+", (in progress: "+inProgressCount+")";
+ }
+ else
+ {
+ return "World Gen Disabled";
+ }
+ });
+
+ }
+
+
+
+ //===================//
+ // world gen control //
+ //===================//
+
+ public void startWorldGen(GeneratedFullDataFileHandler dataFileHandler, AbstractWorldGenState newWgs)
+ {
+ // create the new world generator
+ if (!this.worldGenStateRef.compareAndSet(null, newWgs))
+ {
+ LOGGER.warn("Failed to start world gen due to concurrency");
+ newWgs.closeAsync(false);
+ }
+ dataFileHandler.addWorldGenCompleteListener(this.onWorldGenCompleteListener);
+ dataFileHandler.setGenerationQueue(newWgs.worldGenerationQueue);
+ }
+
+ public void stopWorldGen(GeneratedFullDataFileHandler dataFileHandler)
+ {
+ AbstractWorldGenState worldGenState = this.worldGenStateRef.get();
+ if (worldGenState == null)
+ {
+ LOGGER.warn("Attempted to stop world gen when it was not running");
+ return;
+ }
+
+ // shut down the world generator
+ while (!this.worldGenStateRef.compareAndSet(worldGenState, null))
+ {
+ worldGenState = this.worldGenStateRef.get();
+ if (worldGenState == null)
+ {
+ return;
+ }
+ }
+ dataFileHandler.clearGenerationQueue();
+ worldGenState.closeAsync(true).join(); //TODO: Make it async.
+ dataFileHandler.removeWorldGenCompleteListener(this.onWorldGenCompleteListener);
+ }
+
+ /** @param targetPosForGeneration the position that world generation should be centered around */
+ public void worldGenTick(DhBlockPos2D targetPosForGeneration)
+ {
+ AbstractWorldGenState worldGenState = this.worldGenStateRef.get();
+ if (worldGenState != null)
+ {
+ // queue new world generation requests
+ worldGenState.tick(targetPosForGeneration);
+ }
+ }
+
+ @Override
+ public void close()
+ {
+ // shutdown the world-gen
+ AbstractWorldGenState worldGenState = this.worldGenStateRef.get();
+ if (worldGenState != null)
+ {
+ while (!this.worldGenStateRef.compareAndSet(worldGenState, null))
+ {
+ worldGenState = this.worldGenStateRef.get();
+ if (worldGenState == null)
+ {
+ break;
+ }
+ }
+
+ if (worldGenState != null)
+ {
+ worldGenState.closeAsync(true).join(); //TODO: Make it async.
+ }
+ }
+
+ this.dataFileHandler.close();
+ this.worldGenF3Message.close();
+ }
+
+
+
+ //=========//
+ // getters //
+ //=========//
+
+ public boolean isWorldGenRunning() { return this.worldGenStateRef.get() != null; }
+
+
+
+ //================//
+ // helper classes //
+ //================//
+
+ /** Handles the {@link IWorldGenerationQueue} and any other necessary world gen information. */
+ public static abstract class AbstractWorldGenState
{
public IWorldGenerationQueue worldGenerationQueue;
@@ -41,105 +158,8 @@ public class WorldGenModule implements Closeable
});
}
- public void tick(DhBlockPos2D targetPosForGeneration)
- {
- worldGenerationQueue.runCurrentGenTasksUntilBusy(targetPosForGeneration);
- }
+ /** @param targetPosForGeneration the position that world generation should be centered around */
+ public void tick(DhBlockPos2D targetPosForGeneration) { this.worldGenerationQueue.runCurrentGenTasksUntilBusy(targetPosForGeneration); }
}
- public WorldGenModule(GeneratedFullDataFileHandler dataFileHandler, GeneratedFullDataFileHandler.IOnWorldGenCompleteListener onWorldGenCompleteListener)
- {
- this.dataFileHandler = dataFileHandler;
- this.onWorldGenCompleteListener = onWorldGenCompleteListener;
- this.worldGenF3Message = new F3Screen.DynamicMessage(() ->
- {
- WorldGenState worldGenState = this.worldGenStateRef.get();
- if (worldGenState != null)
- {
- int waiting = worldGenState.worldGenerationQueue.getWaitingTaskCount();
- int inProgress = worldGenState.worldGenerationQueue.getInProgressTaskCount();
-
- return "World Gen Tasks: "+waiting+", (in progress: "+inProgress+")";
- }
- else
- {
- return "World Gen Disabled";
- }
- });
-
- }
-
- public void startWorldGen(GeneratedFullDataFileHandler dataFileHandler, WorldGenState newWgs)
- {
- // create the new world generator
- if (!this.worldGenStateRef.compareAndSet(null, newWgs))
- {
- LOGGER.warn("Failed to start world gen due to concurrency");
- newWgs.closeAsync(false);
- }
- dataFileHandler.addWorldGenCompleteListener(onWorldGenCompleteListener);
- dataFileHandler.setGenerationQueue(newWgs.worldGenerationQueue);
- }
-
- public void stopWorldGen(GeneratedFullDataFileHandler dataFileHandler)
- {
- WorldGenState worldGenState = this.worldGenStateRef.get();
- if (worldGenState == null)
- {
- LOGGER.warn("Attempted to stop world gen when it was not running");
- return;
- }
-
- // shut down the world generator
- while (!this.worldGenStateRef.compareAndSet(worldGenState, null))
- {
- worldGenState = this.worldGenStateRef.get();
- if (worldGenState == null)
- {
- return;
- }
- }
- dataFileHandler.clearGenerationQueue();
- worldGenState.closeAsync(true).join(); //TODO: Make it async.
- dataFileHandler.removeWorldGenCompleteListener(onWorldGenCompleteListener);
- }
-
- public boolean isWorldGenRunning()
- {
- return this.worldGenStateRef.get() != null;
- }
-
- public void worldGenTick(DhBlockPos2D targetPosForGeneration)
- {
- WorldGenState worldGenState = this.worldGenStateRef.get();
- if (worldGenState != null)
- {
- // queue new world generation requests
- worldGenState.tick(targetPosForGeneration);
- }
- }
-
- public void close()
- {
- // shutdown the world-gen
- WorldGenState worldGenState = this.worldGenStateRef.get();
- if (worldGenState != null)
- {
- while (!this.worldGenStateRef.compareAndSet(worldGenState, null))
- {
- worldGenState = this.worldGenStateRef.get();
- if (worldGenState == null)
- {
- break;
- }
- }
-
- if (worldGenState != null)
- {
- worldGenState.closeAsync(true).join(); //TODO: Make it async.
- }
- }
- dataFileHandler.close();
- this.worldGenF3Message.close();
- }
}
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhChunkPos.java b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhChunkPos.java
index ff7d77be8..0526c25dc 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhChunkPos.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhChunkPos.java
@@ -21,8 +21,6 @@ package com.seibel.distanthorizons.core.pos;
import com.seibel.distanthorizons.coreapi.util.math.Vec3d;
-import java.util.Objects;
-
public class DhChunkPos
{
public final int x; // Low 32 bits
@@ -32,6 +30,7 @@ public class DhChunkPos
public final int hashCode;
+
public DhChunkPos(int x, int z)
{
this.x = x;
@@ -54,29 +53,24 @@ public class DhChunkPos
{
this(((int)pos.x) >> 4, ((int)pos.z) >> 4);
}
- public DhChunkPos(long packed) { this(getX(packed), getZ(packed)); }
+ public DhChunkPos(long packed) { this(getXFromPackedLong(packed), getZFromPackedLong(packed)); }
- public DhBlockPos center() { return new DhBlockPos(8 + x << 4, 0, 8 + z << 4); }
- public DhBlockPos corner() { return new DhBlockPos(x << 4, 0, z << 4); }
+ public DhBlockPos center() { return new DhBlockPos(8 + this.x << 4, 0, 8 + this.z << 4); }
+ public DhBlockPos corner() { return new DhBlockPos(this.x << 4, 0, this.z << 4); }
public static long toLong(int x, int z) { return ((long) x & 0xFFFFFFFFL) << 32 | (long) z & 0xFFFFFFFFL; }
- public static int getX(long chunkPos) { return (int) (chunkPos >> 32); }
- public static int getZ(long chunkPos) { return (int) (chunkPos & 0xFFFFFFFFL); }
+ private static int getXFromPackedLong(long chunkPos) { return (int) (chunkPos >> 32); }
+ private static int getZFromPackedLong(long chunkPos) { return (int) (chunkPos & 0xFFFFFFFFL); }
- @Deprecated
- public int getX() { return x; }
- @Deprecated
- public int getZ() { return z; }
+ public int getMinBlockX() { return this.x << 4; }
+ public int getMinBlockZ() { return this.z << 4; }
- public int getMinBlockX() { return x << 4; }
- public int getMinBlockZ() { return z << 4; }
+ public DhBlockPos2D getMinBlockPos() { return new DhBlockPos2D(this.x << 4, this.z << 4); }
- public DhBlockPos2D getMinBlockPos() { return new DhBlockPos2D(x << 4, z << 4); }
-
- public long getLong() { return toLong(x, z); }
+ public long getLong() { return toLong(this.x, this.z); }
public double distance(DhChunkPos other)
{
@@ -90,14 +84,14 @@ public class DhChunkPos
{
return true;
}
- else if (obj == null || getClass() != obj.getClass())
+ else if (obj == null || this.getClass() != obj.getClass())
{
return false;
}
else
{
DhChunkPos that = (DhChunkPos) obj;
- return x == that.x && z == that.z;
+ return this.x == that.x && this.z == that.z;
}
}
@@ -105,7 +99,7 @@ public class DhChunkPos
public int hashCode() { return this.hashCode; }
@Override
- public String toString() { return "C[" + x + "," + z + "]"; }
+ public String toString() { return "C[" + this.x + "," + this.z + "]"; }
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/GLProxy.java b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/GLProxy.java
index f5d935993..b30b40894 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/GLProxy.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/GLProxy.java
@@ -25,6 +25,7 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
+import com.seibel.distanthorizons.api.enums.config.EGLErrorHandlingMode;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.ConfigBasedLogger;
import com.seibel.distanthorizons.core.config.Config;
@@ -65,8 +66,6 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftCli
*/
public class GLProxy
{
- public static final boolean OVERRIDE_VANILLA_GL_LOGGER = ModInfo.IS_DEV_BUILD;
-
private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
private ExecutorService workerThread = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat(GLProxy.class.getSimpleName() + "-Worker-Thread").build());
@@ -141,7 +140,7 @@ public class GLProxy
}
GL_LOGGER.info("minecraftGlCapabilities:\n" + getVersionInfo(minecraftGlCapabilities));
- if (OVERRIDE_VANILLA_GL_LOGGER)
+ if (Config.Client.Advanced.Debugging.overrideVanillaGLLogger.get())
{
GLUtil.setupDebugMessageCallback(new PrintStream(new GLMessageOutputStream(GLProxy::logMessage, vanillaDebugMessageBuilder), true));
}
@@ -461,29 +460,47 @@ public class GLProxy
private static void logMessage(GLMessage msg)
{
- GLMessage.ESeverity s = msg.severity;
- if (msg.type == GLMessage.EType.ERROR ||
- msg.type == GLMessage.EType.UNDEFINED_BEHAVIOR)
+ EGLErrorHandlingMode errorHandlingMode = Config.Client.Advanced.Debugging.glErrorHandlingMode.get();
+ if (errorHandlingMode == EGLErrorHandlingMode.IGNORE)
{
- GL_LOGGER.error("GL ERROR {} from {}: {}", msg.id, msg.source, msg.message);
- throw new RuntimeException("GL ERROR: " + msg.toString());
+ return;
}
- RuntimeException e = new RuntimeException("GL MESSAGE: " + msg.toString());
- switch (s)
+
+
+ if (msg.type == GLMessage.EType.ERROR || msg.type == GLMessage.EType.UNDEFINED_BEHAVIOR)
{
- case HIGH:
- GL_LOGGER.error("{}", e);
- break;
- case MEDIUM:
- GL_LOGGER.warn("{}", e);
- break;
- case LOW:
- GL_LOGGER.info("{}", e);
- break;
- case NOTIFICATION:
- GL_LOGGER.debug("{}", e);
- break;
+ // critical error
+
+ GL_LOGGER.error("GL ERROR " + msg.id + " from " + msg.source + ": " + msg.message);
+
+ if (errorHandlingMode == EGLErrorHandlingMode.LOG_THROW)
+ {
+ throw new RuntimeException("GL ERROR: " + msg);
+ }
+
+ }
+ else
+ {
+ // non-critical log
+
+ GLMessage.ESeverity severity = msg.severity;
+ RuntimeException ex = new RuntimeException("GL MESSAGE: " + msg);
+ switch (severity)
+ {
+ case HIGH:
+ GL_LOGGER.error("{}", ex);
+ break;
+ case MEDIUM:
+ GL_LOGGER.warn("{}", ex);
+ break;
+ case LOW:
+ GL_LOGGER.info("{}", ex);
+ break;
+ case NOTIFICATION:
+ GL_LOGGER.debug("{}", ex);
+ break;
+ }
}
}
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java
index ce8721347..4e8b1cbe9 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java
@@ -50,6 +50,7 @@ import org.lwjgl.opengl.GL32;
import java.awt.*;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.ReentrantLock;
/**
* This is where all the magic happens.
@@ -72,11 +73,21 @@ public class LodRenderer
public static boolean transparencyEnabled = true;
public static boolean fakeOceanFloor = true;
- public void setupOffset(DhBlockPos pos)
+ /** used to prevent cleaning up render resources while they are being used */
+ private static final ReentrantLock renderLock = new ReentrantLock();
+
+
+
+ public void setupOffset(DhBlockPos pos) throws IllegalStateException
{
Vec3d cam = MC_RENDER.getCameraExactPosition();
Vec3f modelPos = new Vec3f((float) (pos.x - cam.x), (float) (pos.y - cam.y), (float) (pos.z - cam.z));
+ if (!GL32.glIsProgram(this.shaderProgram.id))
+ {
+ throw new IllegalStateException("No GL program exists with the ID: ["+this.shaderProgram.id+"]. This either means a shader program was freed while it was still in use or was never created.");
+ }
+
this.shaderProgram.bind();
this.shaderProgram.setModelPos(modelPos);
}
@@ -138,13 +149,24 @@ public class LodRenderer
return;
}
- EVENT_LOGGER.info("Shutting down " + LodRenderer.class.getSimpleName() + "...");
this.rendererClosed = true;
- GLProxy.getInstance().recordOpenGlCall(this::cleanup);
- this.bufferHandler.close();
- EVENT_LOGGER.info("Finished shutting down " + LodRenderer.class.getSimpleName());
+ // wait for the renderer to finish before closing (to prevent closing resources that are currently in use)
+ renderLock.lock();
+ try
+ {
+ EVENT_LOGGER.info("Shutting down " + LodRenderer.class.getSimpleName() + "...");
+
+ this.cleanup();
+ this.bufferHandler.close();
+
+ EVENT_LOGGER.info("Finished shutting down " + LodRenderer.class.getSimpleName());
+ }
+ finally
+ {
+ renderLock.unlock();
+ }
}
public void drawLODs(Mat4f baseModelViewMatrix, Mat4f baseProjectionMatrix, float partialTicks, IProfilerWrapper profiler)
@@ -156,169 +178,183 @@ public class LodRenderer
}
- // get MC's shader program and save MC's render state so we can restore it later
- LagSpikeCatcher drawSaveGLState = new LagSpikeCatcher();
- GLState minecraftGlState = new GLState();
- if (ENABLE_DUMP_GL_STATE)
+
+ if (!renderLock.tryLock())
{
- tickLogger.debug("Saving GL state: " + minecraftGlState);
+ // never lock the render thread, if the lock isn't available don't wait for it
+ return;
}
- drawSaveGLState.end("drawSaveGLState");
- // make sure everything has been initialized
- GLProxy glProxy = GLProxy.getInstance();
-
-
-
- //===================//
- // draw params setup //
- //===================//
-
- profiler.push("LOD draw setup");
- /*---------Set GL State--------*/
- GL32.glViewport(0, 0, MC_RENDER.getTargetFrameBufferViewportWidth(), MC_RENDER.getTargetFrameBufferViewportHeight());
- GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, 0);
- boolean renderWireframe = Config.Client.Advanced.Debugging.renderWireframe.get();
- if (renderWireframe)
+ try
{
- GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_LINE);
- //GL32.glDisable(GL32.GL_CULL_FACE);
- }
- else
- {
- GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_FILL);
- GL32.glEnable(GL32.GL_CULL_FACE);
- }
- GL32.glEnable(GL32.GL_DEPTH_TEST);
- GL32.glDepthFunc(GL32.GL_LESS);
-
-
-
- transparencyEnabled = Config.Client.Advanced.Graphics.Quality.transparency.get().transparencyEnabled;
- fakeOceanFloor = Config.Client.Advanced.Graphics.Quality.transparency.get().fakeTransparencyEnabled;
-
- GL32.glDisable(GL32.GL_BLEND); // We render opaque first, then transparent
- GL32.glDepthMask(true);
- GL32.glClear(GL32.GL_DEPTH_BUFFER_BIT);
-
- /*---------Bind required objects--------*/
- // Setup LodRenderProgram and the LightmapTexture if it has not yet been done
- // also binds LightmapTexture, VAO, and ShaderProgram
- if (!this.isSetupComplete)
- {
- this.setup();
- }
- else
- {
- LodFogConfig newFogConfig = this.shaderProgram.isShaderUsable();
- if (newFogConfig != null)
+ // get MC's shader program and save MC's render state so we can restore it later
+ LagSpikeCatcher drawSaveGLState = new LagSpikeCatcher();
+ GLState minecraftGlState = new GLState();
+ if (ENABLE_DUMP_GL_STATE)
{
- this.shaderProgram.free();
- this.shaderProgram = new LodRenderProgram(newFogConfig);
- FogShader.INSTANCE.free();
- FogShader.INSTANCE = new FogShader(newFogConfig);
+ tickLogger.debug("Saving GL state: " + minecraftGlState);
}
- this.shaderProgram.bind();
- }
- GL32.glActiveTexture(GL32.GL_TEXTURE0);
-
- /*---------Get required data--------*/
- int vanillaBlockRenderedDistance = MC_RENDER.getRenderDistance() * LodUtil.CHUNK_WIDTH;
- Mat4f modelViewProjectionMatrix = RenderUtil.createCombinedModelViewProjectionMatrix(baseProjectionMatrix, baseModelViewMatrix, partialTicks);
-
- /*---------Fill uniform data--------*/
- this.shaderProgram.fillUniformData(modelViewProjectionMatrix, /*Light map = GL_TEXTURE0*/ 0,
- MC.getWrappedClientWorld().getMinHeight(), vanillaBlockRenderedDistance);
-
- // Note: Since lightmapTexture is changing every frame, it's faster to recreate it than to reuse the old one.
- ILightMapWrapper lightmap = MC_RENDER.getLightmapWrapper();
- lightmap.bind();
- if (ENABLE_IBO)
- {
- this.quadIBO.bind();
- }
-
- this.bufferHandler.buildRenderListAndUpdateSections(this.getLookVector());
-
-
-
- //===========//
- // rendering //
- //===========//
-
- LagSpikeCatcher drawLagSpikeCatcher = new LagSpikeCatcher();
-
- profiler.popPush("LOD Opaque");
- // TODO: Directional culling
- this.bufferHandler.renderOpaque(this);
-
- if (Config.Client.Advanced.Graphics.Quality.ssao.get())
- {
- profiler.popPush("LOD SSAO");
- SSAORenderer.INSTANCE.render(partialTicks);
+ drawSaveGLState.end("drawSaveGLState");
- // TODO: Fix this file (or check the result is the same) so that SSAORenderer could be deleted
- //SSAOShader.INSTANCE.render(partialTicks); // For some reason this looks slightly different :/
- }
-
-
- profiler.popPush("LOD Fog");
- // TODO add the model view/projection matrices to the render() function
- FogShader.INSTANCE.setModelViewProjectionMatrix(modelViewProjectionMatrix);
- FogShader.INSTANCE.render(partialTicks);
-
- // DarkShader.INSTANCE.render(partialTicks); // A test shader to make the world darker
-
-
- if (Config.Client.Advanced.Graphics.Quality.transparency.get().transparencyEnabled)
- {
- profiler.popPush("LOD Transparent");
+ // make sure everything has been initialized
+ GLProxy glProxy = GLProxy.getInstance();
- GL32.glEnable(GL32.GL_BLEND);
- GL32.glBlendFunc(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA);
- this.bufferHandler.renderTransparent(this);
- GL32.glDepthMask(true); // Apparently the depth mask state is stored in the FBO, so glState fails to restore it...
+
+ //===================//
+ // draw params setup //
+ //===================//
+
+ profiler.push("LOD draw setup");
+ /*---------Set GL State--------*/
+ GL32.glViewport(0, 0, MC_RENDER.getTargetFrameBufferViewportWidth(), MC_RENDER.getTargetFrameBufferViewportHeight());
+ GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, 0);
+ boolean renderWireframe = Config.Client.Advanced.Debugging.renderWireframe.get();
+ if (renderWireframe)
+ {
+ GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_LINE);
+ //GL32.glDisable(GL32.GL_CULL_FACE);
+ }
+ else
+ {
+ GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_FILL);
+ GL32.glEnable(GL32.GL_CULL_FACE);
+ }
+ GL32.glEnable(GL32.GL_DEPTH_TEST);
+ GL32.glDepthFunc(GL32.GL_LESS);
+
+
+
+ transparencyEnabled = Config.Client.Advanced.Graphics.Quality.transparency.get().transparencyEnabled;
+ fakeOceanFloor = Config.Client.Advanced.Graphics.Quality.transparency.get().fakeTransparencyEnabled;
+
+ GL32.glDisable(GL32.GL_BLEND); // We render opaque first, then transparent
+ GL32.glDepthMask(true);
+ GL32.glClear(GL32.GL_DEPTH_BUFFER_BIT);
+
+ /*---------Bind required objects--------*/
+ // Setup LodRenderProgram and the LightmapTexture if it has not yet been done
+ // also binds LightmapTexture, VAO, and ShaderProgram
+ if (!this.isSetupComplete)
+ {
+ this.setup();
+ }
+ else
+ {
+ LodFogConfig newFogConfig = this.shaderProgram.isShaderUsable();
+ if (newFogConfig != null)
+ {
+ this.shaderProgram.free();
+ this.shaderProgram = new LodRenderProgram(newFogConfig);
+ FogShader.INSTANCE.free();
+ FogShader.INSTANCE = new FogShader(newFogConfig);
+ }
+ this.shaderProgram.bind();
+ }
+ GL32.glActiveTexture(GL32.GL_TEXTURE0);
+
+ /*---------Get required data--------*/
+ int vanillaBlockRenderedDistance = MC_RENDER.getRenderDistance() * LodUtil.CHUNK_WIDTH;
+ Mat4f modelViewProjectionMatrix = RenderUtil.createCombinedModelViewProjectionMatrix(baseProjectionMatrix, baseModelViewMatrix, partialTicks);
+
+ /*---------Fill uniform data--------*/
+ this.shaderProgram.fillUniformData(modelViewProjectionMatrix, /*Light map = GL_TEXTURE0*/ 0,
+ MC.getWrappedClientWorld().getMinHeight(), vanillaBlockRenderedDistance);
+
+ // Note: Since lightmapTexture is changing every frame, it's faster to recreate it than to reuse the old one.
+ ILightMapWrapper lightmap = MC_RENDER.getLightmapWrapper();
+ lightmap.bind();
+ if (ENABLE_IBO)
+ {
+ this.quadIBO.bind();
+ }
+
+ this.bufferHandler.buildRenderListAndUpdateSections(this.getLookVector());
+
+
+
+ //===========//
+ // rendering //
+ //===========//
+
+ LagSpikeCatcher drawLagSpikeCatcher = new LagSpikeCatcher();
+
+ profiler.popPush("LOD Opaque");
+ // TODO: Directional culling
+ this.bufferHandler.renderOpaque(this);
+
+ if (Config.Client.Advanced.Graphics.Quality.ssao.get())
+ {
+ profiler.popPush("LOD SSAO");
+ SSAORenderer.INSTANCE.render(partialTicks);
+
+ // TODO: Fix this file (or check the result is the same) so that SSAORenderer could be deleted
+ //SSAOShader.INSTANCE.render(partialTicks); // For some reason this looks slightly different :/
+ }
+
+
+ profiler.popPush("LOD Fog");
+ // TODO add the model view/projection matrices to the render() function
+ FogShader.INSTANCE.setModelViewProjectionMatrix(modelViewProjectionMatrix);
FogShader.INSTANCE.render(partialTicks);
- }
-
- drawLagSpikeCatcher.end("LodDraw");
-
-
-
- //================//
- // render cleanup //
- //================//
-
- profiler.popPush("LOD cleanup");
- LagSpikeCatcher drawCleanup = new LagSpikeCatcher();
- lightmap.unbind();
- if (ENABLE_IBO)
- {
- this.quadIBO.unbind();
- }
-
- GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, 0);
-
- this.shaderProgram.unbind();
-
- if (Config.Client.Advanced.Debugging.debugWireframeRendering.get())
- {
- profiler.popPush("Debug wireframes");
- // Note: this can be very slow if a lot of boxes are being rendered
- DebugRenderer.INSTANCE.render(modelViewProjectionMatrix);
+
+ // DarkShader.INSTANCE.render(partialTicks); // A test shader to make the world darker
+
+
+ if (Config.Client.Advanced.Graphics.Quality.transparency.get().transparencyEnabled)
+ {
+ profiler.popPush("LOD Transparent");
+
+ GL32.glEnable(GL32.GL_BLEND);
+ GL32.glBlendFunc(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA);
+ this.bufferHandler.renderTransparent(this);
+ GL32.glDepthMask(true); // Apparently the depth mask state is stored in the FBO, so glState fails to restore it...
+
+ FogShader.INSTANCE.render(partialTicks);
+ }
+
+ drawLagSpikeCatcher.end("LodDraw");
+
+
+
+ //================//
+ // render cleanup //
+ //================//
+
profiler.popPush("LOD cleanup");
+ LagSpikeCatcher drawCleanup = new LagSpikeCatcher();
+ lightmap.unbind();
+ if (ENABLE_IBO)
+ {
+ this.quadIBO.unbind();
+ }
+
+ GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, 0);
+
+ this.shaderProgram.unbind();
+
+ if (Config.Client.Advanced.Debugging.debugWireframeRendering.get())
+ {
+ profiler.popPush("Debug wireframes");
+ // Note: this can be very slow if a lot of boxes are being rendered
+ DebugRenderer.INSTANCE.render(modelViewProjectionMatrix);
+ profiler.popPush("LOD cleanup");
+ }
+
+ GL32.glClear(GL32.GL_DEPTH_BUFFER_BIT);
+
+ minecraftGlState.restore();
+ drawCleanup.end("LodDrawCleanup");
+
+ // end of internal LOD profiling
+ profiler.pop();
+ tickLogger.incLogTries();
+
+ }
+ finally
+ {
+ renderLock.unlock();
}
-
- GL32.glClear(GL32.GL_DEPTH_BUFFER_BIT);
-
- minecraftGlState.restore();
- drawCleanup.end("LodDrawCleanup");
-
- // end of internal LOD profiling
- profiler.pop();
- tickLogger.incLogTries();
-
}
@@ -376,7 +412,7 @@ public class LodRenderer
//======================//
/**
- * cleanup and free all render objects. REQUIRES to be in render thread
+ * cleanup and free all render objects. MUST be on the render thread
* (Many objects are Native, outside of JVM, and need manual cleanup)
*/
private void cleanup()
@@ -393,13 +429,20 @@ public class LodRenderer
}
this.isSetupComplete = false;
- EVENT_LOGGER.info("Renderer Cleanup Started");
- this.shaderProgram.free();
- if (this.quadIBO != null)
+
+ GLProxy.getInstance().recordOpenGlCall(() ->
{
- this.quadIBO.destroy(false);
- }
- EVENT_LOGGER.info("Renderer Cleanup Complete");
+ EVENT_LOGGER.info("Renderer Cleanup Started");
+
+ this.shaderProgram.free();
+ this.shaderProgram = null;
+ if (this.quadIBO != null)
+ {
+ this.quadIBO.destroy(false);
+ }
+
+ EVENT_LOGGER.info("Renderer Cleanup Complete");
+ });
}
}
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/LodUtil.java b/core/src/main/java/com/seibel/distanthorizons/core/util/LodUtil.java
index 487a0dcf7..407097569 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/util/LodUtil.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/util/LodUtil.java
@@ -221,11 +221,11 @@ public class LodUtil
public Pos2D next()
{
DhChunkPos pos = posIter.next();
- return new Pos2D(pos.getX(), pos.getZ());
+ return new Pos2D(pos.x, pos.z);
}
},
- MC_CLIENT.getPlayerChunkPos().getX() - renderDist,
- MC_CLIENT.getPlayerChunkPos().getZ() - renderDist,
+ MC_CLIENT.getPlayerChunkPos().x - renderDist,
+ MC_CLIENT.getPlayerChunkPos().z - renderDist,
renderDist * 2 + 1);
}
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/RenderUtil.java b/core/src/main/java/com/seibel/distanthorizons/core/util/RenderUtil.java
index e89a66960..d0a5813db 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/util/RenderUtil.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/util/RenderUtil.java
@@ -58,11 +58,11 @@ public class RenderUtil
*/
public static boolean isChunkPosInLoadedArea(DhChunkPos pos, DhChunkPos center)
{
- return (pos.getX() >= center.getX() - MC_RENDER.getRenderDistance()
- && pos.getX() <= center.getX() + MC_RENDER.getRenderDistance())
+ return (pos.x >= center.x - MC_RENDER.getRenderDistance()
+ && pos.x <= center.x + MC_RENDER.getRenderDistance())
&&
- (pos.getZ() >= center.getZ() - MC_RENDER.getRenderDistance()
- && pos.getZ() <= center.getZ() + MC_RENDER.getRenderDistance());
+ (pos.z >= center.z - MC_RENDER.getRenderDistance()
+ && pos.z <= center.z + MC_RENDER.getRenderDistance());
}
/**
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/IWrapperFactory.java b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/IWrapperFactory.java
index cc832130f..f7e53aae9 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/IWrapperFactory.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/IWrapperFactory.java
@@ -28,7 +28,7 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.worldGeneration.Abstrac
import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IBindable;
import java.io.IOException;
-import java.util.HashMap;
+import java.util.HashSet;
/**
* This handles creating abstract wrapper objects.
@@ -42,7 +42,11 @@ public interface IWrapperFactory extends IBindable
IBiomeWrapper deserializeBiomeWrapper(String str, ILevelWrapper levelWrapper) throws IOException;
IBlockStateWrapper deserializeBlockStateWrapper(String str, ILevelWrapper levelWrapper) throws IOException;
IBlockStateWrapper getAirBlockStateWrapper();
- HashMap getRendererIgnoredBlocks();
+ /**
+ * Returns the set of {@link IBlockStateWrapper}'s that shouldn't be rendered.
+ * Generally this contains blocks like: air, barriers, light blocks, etc.
+ */
+ HashSet getRendererIgnoredBlocks(ILevelWrapper levelWrapper);
/**
* Specifically designed to be used with the API.
diff --git a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/block/IBlockStateWrapper.java b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/block/IBlockStateWrapper.java
index a89495858..ecf66e087 100644
--- a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/block/IBlockStateWrapper.java
+++ b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/block/IBlockStateWrapper.java
@@ -6,9 +6,7 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
/** A Minecraft version independent way of handling Blocks. */
public interface IBlockStateWrapper extends IDhApiBlockStateWrapper
{
- String serialize();
-
- ILevelWrapper getLevelWrapper();
+ String getSerialString();
/**
* Returning a value of 0 means the block is completely transparent.
-
+
%d %p %c{1.} [%t] %m%n