Fix loading ClientLevel on server
This commit is contained in:
+30
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.api.enums.config;
|
||||
|
||||
/**
|
||||
* @since API 1.0.0
|
||||
*/
|
||||
public enum EGLErrorHandlingMode
|
||||
{
|
||||
IGNORE,
|
||||
LOG,
|
||||
LOG_THROW;
|
||||
}
|
||||
+3
-3
@@ -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. <br><br>
|
||||
*
|
||||
* Consumer expected inputs for each minecraft version (in order): <br>
|
||||
* <strong>1.18:</strong> [net.minecraft.world.level.chunk.ChunkAccess] and [net.minecraft.world.level.LevelReader] <br>
|
||||
* <strong>1.19:</strong> [net.minecraft.world.level.chunk.ChunkAccess] and [net.minecraft.world.level.LevelReader] <br>
|
||||
* <strong>1.20:</strong> [net.minecraft.world.level.chunk.ChunkAccess] and [net.minecraft.world.level.LevelReader] <br>
|
||||
* <strong>1.16</strong>, <strong>1.17</strong>, <strong>1.18</strong>, <strong>1.19</strong>, <strong>1.20</strong>: <br>
|
||||
* - [net.minecraft.world.level.chunk.ChunkAccess] <br>
|
||||
* - [net.minecraft.world.level.ServerLevel] or [net.minecraft.world.level.ClientLevel] <br>
|
||||
*/
|
||||
CompletableFuture<Void> generateChunks(
|
||||
int chunkPosMinX, int chunkPosMinZ,
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<T>
|
||||
{
|
||||
final ConfigEntry<T> entry;
|
||||
|
||||
@@ -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<Boolean> quickEnableRendering = new ConfigEntry.Builder<Boolean>()
|
||||
@@ -200,6 +200,7 @@ public class Config
|
||||
+ ETransparency.DISABLED + ": LODs will be opaque. \n"
|
||||
+ "")
|
||||
.setPerformance(EConfigEntryPerformance.MEDIUM)
|
||||
.addListener(RenderCacheConfigEventHandler.INSTANCE)
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<EBlocksToAvoid> blocksToIgnore = new ConfigEntry.Builder<EBlocksToAvoid>()
|
||||
@@ -531,6 +532,7 @@ public class Config
|
||||
+ "0 = black \n"
|
||||
+ "1 = normal \n"
|
||||
+ "2 = near white")
|
||||
.addListener(RenderCacheConfigEventHandler.INSTANCE)
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<Double> saturationMultiplier = new ConfigEntry.Builder<Double>() // 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<Boolean> enableCaveCulling = new ConfigEntry.Builder<Boolean>()
|
||||
@@ -1101,6 +1104,26 @@ public class Config
|
||||
.addListener(UnsafeValuesConfigListener.INSTANCE)
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<Boolean> overrideVanillaGLLogger = new ConfigEntry.Builder<Boolean>()
|
||||
.set(ModInfo.IS_DEV_BUILD)
|
||||
.comment(""
|
||||
+ "Requires a reboot to change. \n"
|
||||
+ "")
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<EGLErrorHandlingMode> glErrorHandlingMode = new ConfigEntry.Builder<EGLErrorHandlingMode>()
|
||||
.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<String, String>())
|
||||
.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();
|
||||
|
||||
|
||||
@@ -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<T>
|
||||
* ArrayList<T>
|
||||
* Map<String, T>
|
||||
* HashMap<String, T>
|
||||
* What the config works with
|
||||
* <br>
|
||||
* <br> {@link Enum}
|
||||
* <br> {@link Boolean}
|
||||
* <br> {@link Byte}
|
||||
* <br> {@link Integer}
|
||||
* <br> {@link Double}
|
||||
* <br> {@link Short}
|
||||
* <br> {@link Long}
|
||||
* <br> {@link Float}
|
||||
* <br> {@link String}
|
||||
* <br>
|
||||
* <br> // Below, "T" should be a value from above
|
||||
* <br> // Note: This is not checked, so we trust that you are doing the right thing
|
||||
* <br> List<T>
|
||||
* <br> ArrayList<T>
|
||||
* <br> Map<String, T>
|
||||
* <br> HashMap<String, T>
|
||||
*/
|
||||
public static final List<Class<?>> acceptableInputs = new ArrayList<Class<?>>()
|
||||
{{
|
||||
@@ -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<Class<? extends Enum>> enumList = new ArrayList<>();
|
||||
List<Class<? extends Enum<?>>> enumList = new ArrayList<>();
|
||||
|
||||
String generatedLang = "";
|
||||
|
||||
@@ -168,7 +179,7 @@ public class ConfigBase
|
||||
|
||||
if (checkEnums && entry.getType().isEnum() && !enumList.contains(entry.getType()))
|
||||
{ // Put it in an enum list to work with at the end
|
||||
enumList.add((Class<? extends Enum>) entry.getType());
|
||||
enumList.add((Class<? extends Enum<?>>) entry.getType());
|
||||
}
|
||||
if (!onlyShowNew || langWrapper.langExists(entryPrefix))
|
||||
{
|
||||
|
||||
@@ -13,7 +13,7 @@ import java.util.Map;
|
||||
public class NumberUtil
|
||||
{
|
||||
// Is there no better way of doing this?
|
||||
public static Map<Class, Number> minValues = new HashMap<Class, Number>()
|
||||
public static Map<Class<?>, Number> minValues = new HashMap<Class<?>, 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<Class, Number> maxValues = new HashMap<Class, Number>()
|
||||
public static Map<Class<?>, Number> maxValues = new HashMap<Class<?>, 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();
|
||||
|
||||
+2
-38
@@ -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
|
||||
|
||||
+8
@@ -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<TPresetEnum extends Enum<
|
||||
@Override
|
||||
public void onConfigValueSet()
|
||||
{
|
||||
// don't try modifying the config before it's been loaded from file
|
||||
if (!ConfigBase.INSTANCE.isLoaded)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// don't have this method run on top of itself
|
||||
if (this.changingPreset)
|
||||
{
|
||||
|
||||
+143
-130
@@ -7,11 +7,10 @@ import com.seibel.distanthorizons.core.config.types.AbstractConfigType;
|
||||
import com.seibel.distanthorizons.core.config.types.ConfigEntry;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.AccessDeniedException;
|
||||
import java.nio.file.FileAlreadyExistsException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
@@ -19,63 +18,67 @@ import java.nio.file.Path;
|
||||
* Handles reading and writing config files.
|
||||
*
|
||||
* @author coolGi
|
||||
* @version 2023-7-16
|
||||
* @version 2023-8-26
|
||||
*/
|
||||
public class ConfigFileHandling
|
||||
{
|
||||
private static final Logger LOGGER = ConfigBase.LOGGER;
|
||||
|
||||
public final ConfigBase configBase;
|
||||
public final Path configPath;
|
||||
|
||||
private final Logger LOGGER;
|
||||
|
||||
/** This is the object for night-config */
|
||||
private final CommentedFileConfig nightConfig;
|
||||
|
||||
public ConfigFileHandling(ConfigBase configBase)
|
||||
{
|
||||
this.LOGGER = LogManager.getLogger(this.getClass().getSimpleName() + ", " + configBase.modID);
|
||||
this.configBase = configBase;
|
||||
|
||||
configPath = SingletonInjector.INSTANCE.get(IMinecraftSharedWrapper.class)
|
||||
.getInstallationDirectory().toPath().resolve("config").resolve(this.configBase.modName + ".toml");
|
||||
|
||||
this.nightConfig = CommentedFileConfig.builder(configPath.toFile()).build();
|
||||
}
|
||||
|
||||
/** Saves the entire config to the file */
|
||||
public void saveToFile()
|
||||
{
|
||||
CommentedFileConfig config = CommentedFileConfig.builder(configPath.toFile()).build();
|
||||
saveToFile(this.nightConfig);
|
||||
}
|
||||
/** Saves the entire config to the file */
|
||||
public void saveToFile(CommentedFileConfig nightConfig)
|
||||
{
|
||||
if (!Files.exists(configPath)) // Try to check if the config exists
|
||||
try
|
||||
{
|
||||
if (!this.configPath.getParent().toFile().exists())
|
||||
{
|
||||
Files.createDirectory(this.configPath.getParent());
|
||||
}
|
||||
Files.createFile(configPath);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
}
|
||||
{
|
||||
reCreateFile(configPath);
|
||||
}
|
||||
|
||||
|
||||
loadNightConfig(nightConfig);
|
||||
|
||||
loadConfig(config);
|
||||
|
||||
for (AbstractConfigType<?, ?> 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 <T> void loadEntry(ConfigEntry<T> entry, CommentedFileConfig workConfig)
|
||||
/** Loads an entry */
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> void loadEntry(ConfigEntry<T> entry, CommentedFileConfig nightConfig)
|
||||
{
|
||||
if (!entry.getAppearance().showInFile) return;
|
||||
if (!entry.getAppearance().showInFile)
|
||||
return;
|
||||
|
||||
if (workConfig.contains(entry.getNameWCategory()))
|
||||
if (!nightConfig.contains(entry.getNameWCategory()))
|
||||
{
|
||||
try
|
||||
saveEntry(entry, nightConfig);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
if (entry.getType().isEnum())
|
||||
{
|
||||
if (entry.getType().isEnum())
|
||||
{
|
||||
entry.pureSet((T) (workConfig.getEnum(entry.getNameWCategory(), (Class<? extends Enum>) entry.getType())));
|
||||
return;
|
||||
}
|
||||
Class<?> originalClass = ConfigTypeConverters.isClassConvertable(entry.getType());
|
||||
if (originalClass != null)
|
||||
{
|
||||
entry.pureSet((T) ConfigTypeConverters.convertFromString(originalClass, workConfig.get(entry.getNameWCategory())));
|
||||
return;
|
||||
}
|
||||
|
||||
if (entry.getType() == workConfig.get(entry.getNameWCategory()).getClass())
|
||||
{ // If the types are the same
|
||||
entry.pureSet((T) workConfig.get(entry.getNameWCategory()));
|
||||
entry.clampWithinRange();
|
||||
return;
|
||||
}
|
||||
|
||||
LOGGER.warn("Entry [" + entry.getNameWCategory() + "] is invalid. Expected " + entry.getType() + " but got " + workConfig.get(entry.getNameWCategory()).getClass() + ". Using default value.");
|
||||
saveEntry(entry, workConfig);
|
||||
entry.pureSet((T) (nightConfig.getEnum(entry.getNameWCategory(), (Class<? extends Enum>) entry.getType())));
|
||||
return;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// e.printStackTrace();
|
||||
LOGGER.warn("Entry [" + entry.getNameWCategory() + "] had an invalid value when loading the config. Using default value.");
|
||||
saveEntry(entry, workConfig);
|
||||
|
||||
entry.pureSet((T) ConfigTypeConverters.attemptToConvertFromString(entry.getType(), nightConfig.get(entry.getNameWCategory())));
|
||||
|
||||
if (entry.getTrueValue() == null) {
|
||||
LOGGER.warn("Entry [" + entry.getNameWCategory() + "] returned as null from the config. Using default value.");
|
||||
entry.pureSet(entry.getDefaultValue());
|
||||
}
|
||||
}
|
||||
else
|
||||
catch (Exception e)
|
||||
{
|
||||
saveEntry(entry, workConfig);
|
||||
// e.printStackTrace();
|
||||
LOGGER.warn("Entry [" + entry.getNameWCategory() + "] had an invalid value when loading the config. Using default value.");
|
||||
entry.pureSet(entry.getDefaultValue());
|
||||
}
|
||||
}
|
||||
|
||||
// Creates the comment for an entry when only given the entry
|
||||
public void createComment(ConfigEntry<?> entry)
|
||||
{
|
||||
CommentedFileConfig config = CommentedFileConfig.builder(configPath.toFile()).autosave().build();
|
||||
loadConfig(config);
|
||||
createComment(entry, config);
|
||||
config.close();
|
||||
createComment(entry, nightConfig);
|
||||
}
|
||||
// Creates a comment for an entry
|
||||
public void createComment(ConfigEntry<?> entry, CommentedFileConfig workConfig)
|
||||
public void createComment(ConfigEntry<?> entry, CommentedFileConfig nightConfig)
|
||||
{
|
||||
if (!entry.getAppearance().showInFile)
|
||||
if (
|
||||
!entry.getAppearance().showInFile ||
|
||||
entry.getComment() == null
|
||||
)
|
||||
return;
|
||||
if (entry.getComment() != null)
|
||||
{
|
||||
workConfig.setComment(entry.getNameWCategory(), " " + entry.getComment().replaceAll("\n", "\n ") + "\n ");
|
||||
}
|
||||
|
||||
nightConfig.setComment(entry.getNameWCategory(), " " + entry.getComment().replaceAll("\n", "\n ") + "\n ");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** Does config.load(); but with error checking */
|
||||
public void loadConfig(CommentedFileConfig config)
|
||||
|
||||
/**
|
||||
* Uses {@link ConfigFileHandling#nightConfig} to do {@link CommentedFileConfig#load()} but with error checking
|
||||
*
|
||||
* @apiNote This overwrites any value currently stored in the config
|
||||
*/
|
||||
public void loadNightConfig()
|
||||
{
|
||||
loadNightConfig(this.nightConfig);
|
||||
}
|
||||
/**
|
||||
* Does {@link CommentedFileConfig#load()} but with error checking
|
||||
*
|
||||
* @apiNote This overwrites any value currently stored in the config
|
||||
*/
|
||||
public void loadNightConfig(CommentedFileConfig nightConfig)
|
||||
{
|
||||
try
|
||||
{
|
||||
config.load();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
System.out.println("Loading file failed because of this expectation:\n" + e);
|
||||
try
|
||||
{ // Now try remaking the file and loading it
|
||||
if (!this.configPath.getParent().toFile().exists())
|
||||
{
|
||||
Files.createDirectory(this.configPath.getParent());
|
||||
}
|
||||
|
||||
boolean fileDeleted = Files.deleteIfExists(this.configPath);
|
||||
System.out.println("File at [" + this.configPath + "] was " + (fileDeleted ? "" : "not ") + "able to be deleted.");
|
||||
|
||||
|
||||
Files.createFile(this.configPath);
|
||||
|
||||
config.load();
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
System.out.println("Creating file failed");
|
||||
ex.printStackTrace();
|
||||
SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class).crashMinecraft("Loading file and resetting config file failed at path [" + configPath + "]. Please check the file is ok and you have the permissions", ex);
|
||||
if (!Files.exists(this.configPath))
|
||||
Files.createFile(this.configPath);
|
||||
nightConfig.load();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.warn("Loading file failed because of this expectation:\n" + e);
|
||||
|
||||
reCreateFile(this.configPath);
|
||||
|
||||
nightConfig.load();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.out.println("Creating file failed");
|
||||
LOGGER.error(ex);
|
||||
SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class).crashMinecraft("Loading file and resetting config file failed at path [" + configPath + "]. Please check the file is ok and you have the permissions", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void reCreateFile(Path path)
|
||||
{
|
||||
try
|
||||
{
|
||||
Files.deleteIfExists(path);
|
||||
|
||||
if (!path.getParent().toFile().exists())
|
||||
{
|
||||
Files.createDirectory(path.getParent());
|
||||
}
|
||||
Files.createFile(path);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// ========== API (server) STUFF ========== //
|
||||
/** ALWAYS CLEAR WHEN NOT ON SERVER!!!! */
|
||||
/* * ALWAYS CLEAR WHEN NOT ON SERVER!!!! */
|
||||
// We are not using this stuff, so comment it out for now (if we ever do need it then we can uncomment it)
|
||||
/*
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
+29
-1
@@ -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<String, Object> mapObject = (Map<String, Object>) 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);
|
||||
|
||||
+8
-3
@@ -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<T, S>
|
||||
{ // 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<T, S>
|
||||
|
||||
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<T, S>
|
||||
// Gets the class of T
|
||||
public Class<?> getType()
|
||||
{
|
||||
return value.getClass();
|
||||
return this.defaultValue.getClass();
|
||||
}
|
||||
|
||||
protected static abstract class Builder<T, S>
|
||||
@@ -74,11 +77,13 @@ public abstract class AbstractConfigType<T, S>
|
||||
|
||||
|
||||
// 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;
|
||||
|
||||
@@ -8,12 +8,12 @@ import com.seibel.distanthorizons.core.config.types.enums.EConfigEntryAppearance
|
||||
*
|
||||
* @author coolGi
|
||||
*/
|
||||
public class ConfigCategory extends AbstractConfigType<Class, ConfigCategory>
|
||||
public class ConfigCategory extends AbstractConfigType<Class<?>, 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<Class, ConfigCategory>
|
||||
return value;
|
||||
}
|
||||
|
||||
public static class Builder extends AbstractConfigType.Builder<Class, Builder>
|
||||
public static class Builder extends AbstractConfigType.Builder<Class<?>, Builder>
|
||||
{
|
||||
private String tmpDestination = null;
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ import java.util.Arrays;
|
||||
*/
|
||||
public class ConfigEntry<T> extends AbstractConfigType<T, ConfigEntry<T>> implements IConfigEntry<T>
|
||||
{
|
||||
private final T defaultValue;
|
||||
private String comment;
|
||||
private T min;
|
||||
private T max;
|
||||
@@ -41,7 +40,6 @@ public class ConfigEntry<T> extends AbstractConfigType<T, ConfigEntry<T>> implem
|
||||
{
|
||||
super(appearance, value);
|
||||
|
||||
this.defaultValue = value;
|
||||
this.comment = comment;
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
@@ -54,7 +52,7 @@ public class ConfigEntry<T> extends AbstractConfigType<T, ConfigEntry<T>> 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<T> extends AbstractConfigType<T, ConfigEntry<T>> implem
|
||||
/**
|
||||
* DONT USE THIS IN YOUR CODE <br>
|
||||
* Sets the value without informing the rest of the code (ie, doesnt call listeners, or saves the value). <br>
|
||||
* 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);
|
||||
|
||||
+4
-4
@@ -8,9 +8,9 @@ import com.seibel.distanthorizons.core.config.types.enums.EConfigEntryAppearance
|
||||
*
|
||||
* @author coolGi
|
||||
*/
|
||||
public class ConfigLinkedEntry extends AbstractConfigType<AbstractConfigType, ConfigLinkedEntry>
|
||||
public class ConfigLinkedEntry extends AbstractConfigType<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<AbstractConfigType, Co
|
||||
|
||||
/** Value shouldn't be changed after creation */
|
||||
@Override
|
||||
public void set(AbstractConfigType newValue) { }
|
||||
public void set(AbstractConfigType<?, ?> newValue) { }
|
||||
|
||||
|
||||
public static class Builder extends AbstractConfigType.Builder<AbstractConfigType, Builder>
|
||||
public static class Builder extends AbstractConfigType.Builder<AbstractConfigType<?, ?>, Builder>
|
||||
{
|
||||
/** Appearance shouldn't be changed */
|
||||
@Override
|
||||
|
||||
@@ -9,9 +9,10 @@ public class ConfigUIButton extends AbstractConfigType<Runnable, ConfigUIButton>
|
||||
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<Runnable, Builder>
|
||||
|
||||
+58
-61
@@ -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<Entry> entryList = new ArrayList<>();
|
||||
private final HashMap<Entry, Integer> 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<Entry> 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<String, FullDataPointIdMap.Entry> 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<String, FullDataPointIdMap.Entry> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+3
-3
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
+2
-2
@@ -70,7 +70,7 @@ public interface IStreamableFullDataSource<SummaryDataType extends IStreamableFu
|
||||
return;
|
||||
}
|
||||
|
||||
this.writeIdMappings(outputStream, level.getLevelWrapper());
|
||||
this.writeIdMappings(outputStream);
|
||||
}
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ public interface IStreamableFullDataSource<SummaryDataType extends IStreamableFu
|
||||
void setDataPoints(DataContainerType dataPoints);
|
||||
|
||||
|
||||
void writeIdMappings(DhDataOutputStream outputStream, ILevelWrapper levelWrapper) throws IOException;
|
||||
void writeIdMappings(DhDataOutputStream outputStream) throws IOException;
|
||||
FullDataPointIdMap readIdMappings(DataContainerType dataPoints, DhDataInputStream inputStream, ILevelWrapper levelWrapper) throws IOException, InterruptedException;
|
||||
void setIdMapping(FullDataPointIdMap mappings);
|
||||
|
||||
|
||||
+21
-12
@@ -224,22 +224,31 @@ public class ColumnRenderBuffer extends AbstractRenderBuffer implements IDebugRe
|
||||
{
|
||||
boolean hasRendered = false;
|
||||
|
||||
renderContext.setupOffset(this.pos);
|
||||
for (GLVertexBuffer vbo : this.vbosTransparent)
|
||||
try
|
||||
{
|
||||
if (vbo == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// can throw an IllegalStateException if the GL program was freed before it should've been
|
||||
renderContext.setupOffset(this.pos);
|
||||
|
||||
if (vbo.getVertexCount() == 0)
|
||||
for (GLVertexBuffer vbo : this.vbosTransparent)
|
||||
{
|
||||
continue;
|
||||
if (vbo == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (vbo.getVertexCount() == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
hasRendered = true;
|
||||
renderContext.drawVbo(vbo);
|
||||
//LodRenderer.tickLogger.info("Vertex buffer: {}", vbo);
|
||||
}
|
||||
|
||||
hasRendered = true;
|
||||
renderContext.drawVbo(vbo);
|
||||
//LodRenderer.tickLogger.info("Vertex buffer: {}", vbo);
|
||||
}
|
||||
catch (IllegalStateException e)
|
||||
{
|
||||
LOGGER.error("renderContext program doesn't exist for pos: "+this.pos, e);
|
||||
}
|
||||
|
||||
return hasRendered;
|
||||
|
||||
+4
-5
@@ -23,7 +23,7 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrappe
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
||||
import com.seibel.distanthorizons.coreapi.util.BitShiftUtil;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
* Handles converting {@link ChunkSizedFullDataAccessor}, {@link IIncompleteFullDataSource},
|
||||
@@ -32,7 +32,6 @@ import java.util.HashMap;
|
||||
public class FullDataToRenderDataTransformer
|
||||
{
|
||||
private static final IWrapperFactory WRAPPER_FACTORY = SingletonInjector.INSTANCE.get(IWrapperFactory.class);
|
||||
private static final HashMap<String, ? extends IBlockStateWrapper> 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<IBlockStateWrapper> 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;
|
||||
}
|
||||
|
||||
|
||||
+5
-5
@@ -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<DhSectionPos, Boolean> removeIf) {
|
||||
|
||||
public void removeGenRequestIf(Function<DhSectionPos, Boolean> removeIf)
|
||||
{
|
||||
HashSet<DhSectionPos> removedRequests = new HashSet<>();
|
||||
|
||||
this.incompleteDataSources.forEach((pos, dataSource) ->
|
||||
@@ -119,7 +118,8 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler
|
||||
//========//
|
||||
|
||||
@Nullable
|
||||
private CompletableFuture<IFullDataSource> tryStartGenTask(FullDataMetaFile file, IIncompleteFullDataSource dataSource) {
|
||||
private CompletableFuture<IFullDataSource> 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)
|
||||
|
||||
+4
-4
@@ -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);
|
||||
|
||||
+3
@@ -11,11 +11,13 @@ import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public interface IWorldGenerationQueue extends Closeable
|
||||
{
|
||||
/** the largest numerical detail level */
|
||||
byte largestDataDetail();
|
||||
|
||||
CompletableFuture<WorldGenResult> submitGenTask(DhLodPos pos, byte requiredDataDetail, IWorldGenTaskTracker tracker);
|
||||
void cancelGenTasks(Iterable<DhSectionPos> 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<Void> startClosing(boolean cancelCurrentGeneration, boolean alsoInterruptRunning);
|
||||
void close();
|
||||
|
||||
}
|
||||
|
||||
+3
-2
@@ -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<DhSectionPos> positions)
|
||||
{
|
||||
// TODO Cancel gen tasks properly
|
||||
// TODO Should we cancel generation of chunks that were loaded by the player?
|
||||
}
|
||||
|
||||
//===============//
|
||||
|
||||
@@ -11,7 +11,7 @@ import java.util.regex.Pattern;
|
||||
*
|
||||
* @author HanSolo
|
||||
* @author IMS
|
||||
* @author coolGi2007
|
||||
* @author coolGi
|
||||
*/
|
||||
public class DarkModeDetector
|
||||
{
|
||||
|
||||
@@ -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. <br>
|
||||
* A simple OS getting util based off LWJGL's Platform at {@link org.lwjgl.system.Platform}. <br>
|
||||
* This version includes some extra utils that we need and removes stuff which we don't.
|
||||
*
|
||||
* @author coolGi
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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<Boolean> 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<Boolean> 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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,10 +18,127 @@ public class WorldGenModule implements Closeable
|
||||
private final GeneratedFullDataFileHandler dataFileHandler;
|
||||
private final GeneratedFullDataFileHandler.IOnWorldGenCompleteListener onWorldGenCompleteListener;
|
||||
|
||||
private final AtomicReference<WorldGenState> worldGenStateRef = new AtomicReference<>();
|
||||
private final AtomicReference<AbstractWorldGenState> 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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 + "]"; }
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+206
-163
@@ -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. <br>
|
||||
@@ -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");
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+6
-2
@@ -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<String, ? extends IBlockStateWrapper> getRendererIgnoredBlocks();
|
||||
/**
|
||||
* Returns the set of {@link IBlockStateWrapper}'s that shouldn't be rendered. <br>
|
||||
* Generally this contains blocks like: air, barriers, light blocks, etc.
|
||||
*/
|
||||
HashSet<IBlockStateWrapper> getRendererIgnoredBlocks(ILevelWrapper levelWrapper);
|
||||
|
||||
/**
|
||||
* Specifically designed to be used with the API.
|
||||
|
||||
+1
-3
@@ -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. <br.
|
||||
|
||||
+2
-2
@@ -113,8 +113,8 @@ public interface IMinecraftRenderWrapper extends IBindable
|
||||
int chunkDist = this.getRenderDistance() + 1; // For some reason having '+1' is actually closer to real value
|
||||
|
||||
DhChunkPos centerChunkPos = mcWrapper.getPlayerChunkPos();
|
||||
int centerChunkX = centerChunkPos.getX();
|
||||
int centerChunkZ = centerChunkPos.getZ();
|
||||
int centerChunkX = centerChunkPos.x;
|
||||
int centerChunkZ = centerChunkPos.z;
|
||||
int chunkDist2Mul4 = chunkDist * chunkDist * 4;
|
||||
|
||||
// add every position within render distance
|
||||
|
||||
+2
-2
@@ -29,6 +29,6 @@ import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IBindab
|
||||
public interface IBiomeWrapper extends IDhApiBiomeWrapper, IBindable
|
||||
{
|
||||
String getName();
|
||||
String serialize();
|
||||
ILevelWrapper getLevelWrapper();
|
||||
String getSerialString();
|
||||
|
||||
}
|
||||
|
||||
@@ -392,7 +392,16 @@
|
||||
"Allow Unsafe UI Values",
|
||||
"distanthorizons.config.client.advanced.debugging.allowUnsafeValues.@tooltip":
|
||||
"If enabled, very limited config input validation will be performed. \n\nWarning: enabling this can cause instability or crashing, use at your own risk. \nNote: this is option isn't saved between sessions.",
|
||||
|
||||
"distanthorizons.config.client.advanced.debugging.overrideVanillaGLLogger":
|
||||
"Override Vanilla OpenGL Logger",
|
||||
"distanthorizons.config.client.advanced.debugging.overrideVanillaGLLogger.@tooltip":
|
||||
"Requires a reboot to change.",
|
||||
"distanthorizons.config.client.advanced.debugging.glErrorHandlingMode":
|
||||
"OpenGL Error Handling Mode",
|
||||
"distanthorizons.config.client.advanced.debugging.glErrorHandlingMode.@tooltip":
|
||||
"Defines how OpenGL errors are handled. \nMay incorrectly catch OpenGL errors thrown by other mods.",
|
||||
|
||||
|
||||
"distanthorizons.config.client.advanced.buffers":
|
||||
"Buffers",
|
||||
"distanthorizons.config.client.advanced.buffers.gpuUploadMethod":
|
||||
@@ -691,6 +700,13 @@
|
||||
"distanthorizons.config.enum.EDebugRendering.SHOW_RENDER_SOURCE_FLAG":
|
||||
"Show render source flag",
|
||||
|
||||
"distanthorizons.config.enum.EGLErrorHandlingMode.IGNORE":
|
||||
"Ignore",
|
||||
"distanthorizons.config.enum.EGLErrorHandlingMode.LOG":
|
||||
"Log",
|
||||
"distanthorizons.config.enum.EGLErrorHandlingMode.LOG_THROW":
|
||||
"Log-Throw",
|
||||
|
||||
"distanthorizons.config.enum.ELoggerMode.DISABLED":
|
||||
"Disabled",
|
||||
"distanthorizons.config.enum.ELoggerMode.LOG_ALL_TO_FILE":
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
<File name="important_logs_file" fileName="logs/important.log">
|
||||
<Filters>
|
||||
<ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/>
|
||||
<ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/>
|
||||
</Filters>
|
||||
<PatternLayout>
|
||||
<pattern>%d %p %c{1.} [%t] %m%n</pattern>
|
||||
|
||||
Reference in New Issue
Block a user