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) entry.getType()); + enumList.add((Class>) 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) 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) 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