diff --git a/api/src/main/java/com/seibel/lod/api/DhApiMain.java b/api/src/main/java/com/seibel/lod/api/DhApiMain.java
index b3ea13ae7..34f302183 100644
--- a/api/src/main/java/com/seibel/lod/api/DhApiMain.java
+++ b/api/src/main/java/com/seibel/lod/api/DhApiMain.java
@@ -3,6 +3,7 @@ package com.seibel.lod.api;
import com.seibel.lod.api.interfaces.config.IDhApiConfig;
import com.seibel.lod.api.interfaces.override.IDhApiOverrideable;
import com.seibel.lod.api.interfaces.override.worldGenerator.IDhApiWorldGeneratorOverrideRegister;
+import com.seibel.lod.api.interfaces.render.IDhApiRenderProxy;
import com.seibel.lod.api.interfaces.world.IDhApiWorldProxy;
import com.seibel.lod.api.methods.override.DhApiWorldGeneratorOverrideRegister;
import com.seibel.lod.core.DependencyInjection.ApiEventInjector;
@@ -25,7 +26,7 @@ import com.seibel.lod.core.interfaces.dependencyInjection.IOverrideInjector;
* the concrete object we replaced, there would be issues.
*
* @author James Seibel
- * @version 2022-11-24
+ * @version 2023-2-9
*/
public class DhApiMain
{
@@ -53,6 +54,10 @@ public class DhApiMain
* Designed to be used in conjunction with {@link DhApiMain.Delayed#terrainRepo}.
*/
public static IDhApiWorldProxy worldProxy = null;
+
+ /** Used to interact with Distant Horizons' rendering system. */
+ public static IDhApiRenderProxy renderProxy = null;
+
}
diff --git a/api/src/main/java/com/seibel/lod/api/interfaces/render/IDhApiRenderProxy.java b/api/src/main/java/com/seibel/lod/api/interfaces/render/IDhApiRenderProxy.java
new file mode 100644
index 000000000..8f79ed4cd
--- /dev/null
+++ b/api/src/main/java/com/seibel/lod/api/interfaces/render/IDhApiRenderProxy.java
@@ -0,0 +1,47 @@
+/*
+ * 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.lod.api.interfaces.render;
+
+import com.seibel.lod.api.objects.DhApiResult;
+
+/**
+ * Used to interact with Distant Horizons rendering systems.
+ *
+ * @author James Seibel
+ * @version 2023-2-8
+ */
+public interface IDhApiRenderProxy
+{
+ /**
+ * Forces any cached render data to be deleted and regenerated.
+ * This is generally called whenever resource packs are changed or specific
+ * rendering settings are changed in Distant Horizon's config.
+ *
+ * If this is called on a dedicated server it won't do anything and will return {@link DhApiResult#success} = false
+ *
+ * Background:
+ * Distant Horizons has two different file formats: Full data and Render data.
+ * - Full data files store the block, biome, etc. information and is the result of loading or generating new chunks.
+ * - Render data files store LOD colors and are created using the Full data and currently loaded resource packs.
+ * This is the data cleared by this method.
+ */
+ DhApiResult clearRenderDataCache();
+
+}
diff --git a/core/src/main/java/com/seibel/lod/core/Initializer.java b/core/src/main/java/com/seibel/lod/core/Initializer.java
index 4046186b3..1e7a1fd5c 100644
--- a/core/src/main/java/com/seibel/lod/core/Initializer.java
+++ b/core/src/main/java/com/seibel/lod/core/Initializer.java
@@ -7,13 +7,14 @@ import com.seibel.lod.core.datatype.full.FullDataLoader;
import com.seibel.lod.core.datatype.full.SparseDataLoader;
import com.seibel.lod.api.DhApiMain;
import com.seibel.lod.core.datatype.full.SpottyDataLoader;
+import com.seibel.lod.core.render.DhApiRenderProxy;
import com.seibel.lod.core.world.DhApiWorldProxy;
/**
* Handles first time Core setup.
*
* @author Leetom
- * @version 2022-11-20
+ * @version 2023-2-8
*/
public class Initializer
{
@@ -28,6 +29,7 @@ public class Initializer
DhApiMain.Delayed.configs = DhApiConfig.INSTANCE;
DhApiMain.Delayed.terrainRepo = DhApiTerrainDataRepo.INSTANCE;
DhApiMain.Delayed.worldProxy = DhApiWorldProxy.INSTANCE;
+ DhApiMain.Delayed.renderProxy = DhApiRenderProxy.INSTANCE;
}
}
diff --git a/core/src/main/java/com/seibel/lod/core/config/Config.java b/core/src/main/java/com/seibel/lod/core/config/Config.java
index b1e9afef4..3ad867de8 100644
--- a/core/src/main/java/com/seibel/lod/core/config/Config.java
+++ b/core/src/main/java/com/seibel/lod/core/config/Config.java
@@ -23,6 +23,7 @@ package com.seibel.lod.core.config;
import com.seibel.lod.api.enums.config.*;
import com.seibel.lod.api.enums.rendering.*;
import com.seibel.lod.api.enums.worldGeneration.EDhApiDistantGeneratorMode;
+import com.seibel.lod.core.config.eventHandlers.RenderCacheConfigEventHandler;
import com.seibel.lod.core.config.types.*;
@@ -124,6 +125,7 @@ public class Config
+ "\n"
+ "Lowest Quality: " + EVerticalQuality.LOW + "\n"
+ "Highest Quality: " + EVerticalQuality.HIGH)
+ .addListener(RenderCacheConfigEventHandler.INSTANCE)
.build();
public static ConfigEntry horizontalScale = new ConfigEntry.Builder()
diff --git a/core/src/main/java/com/seibel/lod/core/config/eventHandlers/RenderCacheConfigEventHandler.java b/core/src/main/java/com/seibel/lod/core/config/eventHandlers/RenderCacheConfigEventHandler.java
new file mode 100644
index 000000000..427140940
--- /dev/null
+++ b/core/src/main/java/com/seibel/lod/core/config/eventHandlers/RenderCacheConfigEventHandler.java
@@ -0,0 +1,52 @@
+package com.seibel.lod.core.config.eventHandlers;
+
+import com.seibel.lod.api.DhApiMain;
+import com.seibel.lod.api.enums.config.EVerticalQuality;
+import com.seibel.lod.core.config.Config;
+import com.seibel.lod.core.config.types.ConfigEntry;
+
+/**
+ * Listens to the config and will automatically
+ * clear the current render cache if certain settings are changed.
+ *
+ * Note: if additional settings should clear the render cache, add those to this listener, don't create a new listener
+ *
+ * @author James Seibel
+ * @version 2023-2-9
+ */
+public class RenderCacheConfigEventHandler implements ConfigEntry.Listener
+{
+ public static RenderCacheConfigEventHandler INSTANCE = new RenderCacheConfigEventHandler();
+
+ private EVerticalQuality previousVerticalQualitySetting = null;
+
+
+
+ /** private since we only ever need one handler at a time */
+ private RenderCacheConfigEventHandler() { }
+
+
+
+ @Override
+ public void onModify()
+ {
+ // check if the vertical quality changed
+ EVerticalQuality newVerticalQuality = Config.Client.Graphics.Quality.verticalQuality.get();
+ if (this.previousVerticalQualitySetting != newVerticalQuality)
+ {
+ // TODO add a cancelable delay between the method being fired and any data getting cleared,
+ // this would be to prevent clearing the same data 5 times in rapid succession
+ // when the user is switching through settings in the config UI
+
+ if (DhApiMain.Delayed.renderProxy.clearRenderDataCache().success)
+ {
+ this.previousVerticalQualitySetting = newVerticalQuality;
+ }
+ }
+
+ }
+
+ @Override
+ public void onUiModify() { /* do nothing, we only care about modified config values */ }
+
+}
diff --git a/core/src/main/java/com/seibel/lod/core/config/types/ConfigEntry.java b/core/src/main/java/com/seibel/lod/core/config/types/ConfigEntry.java
index e11ebd437..012c06d02 100644
--- a/core/src/main/java/com/seibel/lod/core/config/types/ConfigEntry.java
+++ b/core/src/main/java/com/seibel/lod/core/config/types/ConfigEntry.java
@@ -15,7 +15,8 @@ import java.util.Arrays;
*/
public class ConfigEntry extends AbstractConfigType> implements IConfigEntry
{
- public interface Listener {
+ public interface Listener
+ {
/** Called whenever the value changes at all (including in the code itself) */
void onModify();
/** Called whenever the value is changed through the UI (only when the done button is pressed) */
diff --git a/core/src/main/java/com/seibel/lod/core/level/DhClientLevel.java b/core/src/main/java/com/seibel/lod/core/level/DhClientLevel.java
index a75ca4e1f..1abea326f 100644
--- a/core/src/main/java/com/seibel/lod/core/level/DhClientLevel.java
+++ b/core/src/main/java/com/seibel/lod/core/level/DhClientLevel.java
@@ -91,6 +91,15 @@ public class DhClientLevel implements IDhClientLevel
@Override
public IDataSourceProvider getFileHandler() { return this.dataFileHandler; }
+ @Override
+ public void clearRenderDataCache()
+ {
+ if (this.tree != null)
+ {
+ this.tree.clearRenderDataCache();
+ }
+ }
+
@Override
public void updateChunk(IChunkWrapper chunk)
{
diff --git a/core/src/main/java/com/seibel/lod/core/level/DhClientServerLevel.java b/core/src/main/java/com/seibel/lod/core/level/DhClientServerLevel.java
index eeb1af617..113c9820c 100644
--- a/core/src/main/java/com/seibel/lod/core/level/DhClientServerLevel.java
+++ b/core/src/main/java/com/seibel/lod/core/level/DhClientServerLevel.java
@@ -339,6 +339,16 @@ public class DhClientServerLevel implements IDhClientLevel, IDhServerLevel
@Override
public IDataSourceProvider getFileHandler() { return this.dataFileHandler; }
+ @Override
+ public void clearRenderDataCache()
+ {
+ RenderState renderState = this.renderState.get();
+ if (renderState != null && renderState.tree != null)
+ {
+ renderState.tree.clearRenderDataCache();
+ }
+ }
+
diff --git a/core/src/main/java/com/seibel/lod/core/level/DhServerLevel.java b/core/src/main/java/com/seibel/lod/core/level/DhServerLevel.java
index 13127cca5..a73a59978 100644
--- a/core/src/main/java/com/seibel/lod/core/level/DhServerLevel.java
+++ b/core/src/main/java/com/seibel/lod/core/level/DhServerLevel.java
@@ -69,6 +69,12 @@ public class DhServerLevel implements IDhServerLevel
@Override
public IDataSourceProvider getFileHandler() { return this.dataFileHandler; }
+ @Override
+ public void clearRenderDataCache()
+ {
+ // Do nothing, there is no render data on the server
+ }
+
@Override
public void updateChunk(IChunkWrapper chunk)
{
diff --git a/core/src/main/java/com/seibel/lod/core/level/IDhLevel.java b/core/src/main/java/com/seibel/lod/core/level/IDhLevel.java
index 4e1c547fb..6e68acf5f 100644
--- a/core/src/main/java/com/seibel/lod/core/level/IDhLevel.java
+++ b/core/src/main/java/com/seibel/lod/core/level/IDhLevel.java
@@ -1,6 +1,5 @@
package com.seibel.lod.core.level;
-import com.seibel.lod.core.file.datafile.DataFileHandler;
import com.seibel.lod.core.file.datafile.IDataSourceProvider;
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
@@ -21,4 +20,10 @@ public interface IDhLevel extends AutoCloseable
IDataSourceProvider getFileHandler();
+ /**
+ * Re-creates the color, render data.
+ * This method should be called after resource packs are changed or LOD settings are modified.
+ */
+ void clearRenderDataCache(); // TODO make all methods in this stack named the same
+
}
diff --git a/core/src/main/java/com/seibel/lod/core/render/DhApiRenderProxy.java b/core/src/main/java/com/seibel/lod/core/render/DhApiRenderProxy.java
new file mode 100644
index 000000000..dbc3318dc
--- /dev/null
+++ b/core/src/main/java/com/seibel/lod/core/render/DhApiRenderProxy.java
@@ -0,0 +1,47 @@
+package com.seibel.lod.core.render;
+
+import com.seibel.lod.api.interfaces.render.IDhApiRenderProxy;
+import com.seibel.lod.api.objects.DhApiResult;
+import com.seibel.lod.core.api.internal.SharedApi;
+import com.seibel.lod.core.level.IDhLevel;
+
+/**
+ * Used to interact with Distant Horizons' rendering systems.
+ *
+ * @author James Seibel
+ * @version 2023-2-8
+ */
+public class DhApiRenderProxy implements IDhApiRenderProxy
+{
+ public static DhApiRenderProxy INSTANCE = new DhApiRenderProxy();
+
+
+
+ private DhApiRenderProxy() { }
+
+
+
+ public DhApiResult clearRenderDataCache()
+ {
+ // make sure this is a valid time to run the method
+ if (SharedApi.currentWorld == null)
+ {
+ return DhApiResult.createFail("No world loaded");
+ }
+
+
+ // clear the render caches for each level
+ Iterable extends IDhLevel> loadedLevels = SharedApi.currentWorld.getAllLoadedLevels();
+ for (IDhLevel level : loadedLevels)
+ {
+ if (level != null)
+ {
+ level.clearRenderDataCache();
+ }
+ }
+
+ return DhApiResult.createSuccess();
+ }
+
+
+}
diff --git a/core/src/main/java/com/seibel/lod/core/render/LodQuadTree.java b/core/src/main/java/com/seibel/lod/core/render/LodQuadTree.java
index f9f9750c4..a8e835c44 100644
--- a/core/src/main/java/com/seibel/lod/core/render/LodQuadTree.java
+++ b/core/src/main/java/com/seibel/lod/core/render/LodQuadTree.java
@@ -1,7 +1,5 @@
package com.seibel.lod.core.render;
-import com.seibel.lod.api.enums.config.EVerticalQuality;
-import com.seibel.lod.core.config.Config;
import com.seibel.lod.core.datatype.column.ColumnRenderSource;
import com.seibel.lod.core.level.IDhClientLevel;
import com.seibel.lod.core.pos.DhBlockPos2D;
@@ -17,7 +15,8 @@ import com.seibel.lod.core.util.gridList.MovableGridRingList;
import org.apache.logging.log4j.Logger;
/**
- * This quadTree structure is the core of the DH mod.
+ * This quadTree structure is our core data structure and holds
+ * all rendering data.
*
* This class represent a circular quadTree of lodSections.
* Each section at level n is populated in one or more ways:
@@ -57,11 +56,6 @@ public class LodQuadTree implements AutoCloseable
private final IDhClientLevel level; //FIXME: Proper hierarchy to remove this reference!
- // used to determine if the render data needs to be regenerated
- // TODO there should be a better way of determining when the render data should be regenerated
- private EVerticalQuality previousVerticalQualitySetting = null;
-
-
/**
@@ -235,24 +229,6 @@ public class LodQuadTree implements AutoCloseable
- // determine if the render data should be regenerated
- // TODO this should be replaced with an API method call that is fired by modified config values
- boolean invalidateRenderCaches = false;
- if (this.previousVerticalQualitySetting == null)
- {
- this.previousVerticalQualitySetting = Config.Client.Graphics.Quality.verticalQuality.get();
- }
- else if (this.previousVerticalQualitySetting != Config.Client.Graphics.Quality.verticalQuality.get())
- {
- invalidateRenderCaches = true;
- }
-
- if (invalidateRenderCaches)
- {
- this.invalidateRenderCache();
- }
-
-
// TODO: inline comments should be added everywhere for this tick pass, so this comment block should be removed (having duplicate comments in two places is a bad idea)
// First tick pass: update all sections' childCount from bottom level to top level. Step:
@@ -649,13 +625,9 @@ public class LodQuadTree implements AutoCloseable
* Re-creates the color, render data.
* This method should be called after resource packs are changed or LOD settings are modified.
*/
- private void invalidateRenderCache()
+ public void clearRenderDataCache()
{
- // TODO add a delay between the method being fired and any data getting cleared,
- // this would be to prevent clearing the same data 5 times in rapid succession
- // when the user is switching through settings in the config
-
- LOGGER.info("Render cache invalidated");
+ LOGGER.info("Clearing render cache...");
// clear each ring list
for (byte sectionDetailLevel = TREE_LOWEST_DETAIL_LEVEL; sectionDetailLevel < this.numbersOfSectionDetailLevels; sectionDetailLevel++)
@@ -672,8 +644,7 @@ public class LodQuadTree implements AutoCloseable
// delete the cache files
this.renderSourceProvider.deleteRenderCache();
- // update the previous quality setting
- this.previousVerticalQualitySetting = Config.Client.Graphics.Quality.verticalQuality.get();
+ LOGGER.info("Render cache invalidated");
}