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 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"); }