Fixed up the merge
This commit is contained in:
+3
-4
@@ -22,11 +22,10 @@ package com.seibel.lod.core.api.external.methods.config.both;
|
||||
import com.seibel.lod.api.interfaces.config.IDhApiConfigValue;
|
||||
import com.seibel.lod.api.interfaces.config.both.IDhApiWorldGenerationConfig;
|
||||
import com.seibel.lod.api.objects.config.DhApiConfigValue;
|
||||
import com.seibel.lod.core.config.Config;
|
||||
import com.seibel.lod.core.config.Config.Client.Advanced.WorldGenerator;
|
||||
import com.seibel.lod.api.enums.config.EBlocksToAvoid;
|
||||
import com.seibel.lod.api.enums.worldGeneration.EDhApiDistantGeneratorMode;
|
||||
import com.seibel.lod.api.enums.config.EGenerationPriority;
|
||||
import com.seibel.lod.api.enums.config.ELightGenerationMode;
|
||||
|
||||
/**
|
||||
* Distant Horizons' world generation configuration. <br><br>
|
||||
@@ -55,12 +54,12 @@ public class DhApiWorldGenerationConfig implements IDhApiWorldGenerationConfig
|
||||
@Deprecated
|
||||
@Override
|
||||
public IDhApiConfigValue<EBlocksToAvoid> getBlocksToAvoid()
|
||||
{ return new DhApiConfigValue<>(WorldGenerator.blocksToAvoid); }
|
||||
{ return new DhApiConfigValue<>(Config.Client.Advanced.Graphics.Quality.blocksToIgnore); }
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public IDhApiConfigValue<Boolean> getTintWithAvoidedBlocks()
|
||||
{ return new DhApiConfigValue<>(WorldGenerator.tintWithAvoidedBlocks); }
|
||||
{ return new DhApiConfigValue<>(Config.Client.Advanced.Graphics.Quality.tintWithAvoidedBlocks); }
|
||||
|
||||
|
||||
}
|
||||
|
||||
Vendored
+1
-2
@@ -24,7 +24,6 @@ import com.seibel.lod.api.interfaces.config.IDhApiConfigValue;
|
||||
import com.seibel.lod.api.interfaces.config.client.IDhApiGraphicsConfig;
|
||||
import com.seibel.lod.api.objects.config.DhApiConfigValue;
|
||||
import com.seibel.lod.coreapi.util.converters.RenderModeEnabledConverter;
|
||||
import com.seibel.lod.core.config.Config;
|
||||
import com.seibel.lod.api.enums.rendering.ERendererMode;
|
||||
import com.seibel.lod.core.config.Config.Client.Advanced.Graphics.Quality;
|
||||
import com.seibel.lod.core.config.Config.Client.Advanced.Debugging;
|
||||
@@ -94,7 +93,7 @@ public class DhApiGraphicsConfig implements IDhApiGraphicsConfig
|
||||
|
||||
@Override
|
||||
public IDhApiConfigValue<Boolean> getUseExtendedNearClipPlane()
|
||||
{ return new DhApiConfigValue<>(AdvancedGraphics.useExtendedNearClipPlane); }
|
||||
{ return new DhApiConfigValue<>(AdvancedGraphics.overdrawPrevention); }
|
||||
|
||||
@Override
|
||||
public IDhApiConfigValue<Double> getBrightnessMultiplier()
|
||||
|
||||
@@ -21,11 +21,13 @@ package com.seibel.lod.core.config;
|
||||
|
||||
|
||||
import com.seibel.lod.api.enums.config.*;
|
||||
import com.seibel.lod.api.enums.config.quickOptions.EQuickQuality;
|
||||
import com.seibel.lod.api.enums.config.quickOptions.EQuickThread;
|
||||
import com.seibel.lod.api.enums.config.quickOptions.EQualityPreset;
|
||||
import com.seibel.lod.api.enums.config.quickOptions.EThreadPreset;
|
||||
import com.seibel.lod.api.enums.rendering.*;
|
||||
import com.seibel.lod.api.enums.worldGeneration.EDhApiDistantGeneratorMode;
|
||||
import com.seibel.lod.core.config.eventHandlers.presets.RenderQualityPresetConfigEventHandler;
|
||||
import com.seibel.lod.core.config.eventHandlers.RenderCacheConfigEventHandler;
|
||||
import com.seibel.lod.core.config.eventHandlers.presets.ThreadPresetConfigEventHandler;
|
||||
import com.seibel.lod.core.config.types.*;
|
||||
import com.seibel.lod.core.config.types.enums.*;
|
||||
import com.seibel.lod.coreapi.ModInfo;
|
||||
@@ -72,35 +74,38 @@ public class Config
|
||||
.comment(""
|
||||
+ "If true, Distant Horizons will render LODs beyond the vanilla render distance."
|
||||
+ "")
|
||||
.setAppearance(ConfigEntryAppearance.ONLY_IN_GUI) // TODO set when the game boots
|
||||
.setAppearance(EConfigEntryAppearance.ONLY_IN_GUI) // TODO set when the game boots
|
||||
//.addListener(null) // TODO add listener
|
||||
.build();
|
||||
|
||||
public static ConfigLinkedEntry quickLodChunkRenderDistance = new ConfigLinkedEntry(Advanced.Graphics.Quality.lodChunkRenderDistance);
|
||||
|
||||
public static ConfigEntry<EQuickQuality> quickQualitySetting = new ConfigEntry.Builder<EQuickQuality>()
|
||||
.set(EQuickQuality.MEDIUM)
|
||||
public static ConfigEntry<EQualityPreset> qualityPresetSetting = new ConfigEntry.Builder<EQualityPreset>()
|
||||
.set(EQualityPreset.MEDIUM) // the default value is set via the listener when accessed
|
||||
.comment(""
|
||||
+ "Changing this setting will modify a number of different settings that will change the \n"
|
||||
+ "visual fidelity of the rendered LODs.\n"
|
||||
+ "\n"
|
||||
+ "Higher settings will improve the graphical quality while increasing GPU and memory use.\n"
|
||||
+ "")
|
||||
.setAppearance(ConfigEntryAppearance.ONLY_IN_GUI) // TODO set when the game boots
|
||||
//.addListener(null) // TODO add listener
|
||||
.setAppearance(EConfigEntryAppearance.ONLY_IN_GUI)
|
||||
.addListener(RenderQualityPresetConfigEventHandler.INSTANCE)
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<EQuickThread> quickThreadSetting = new ConfigEntry.Builder<EQuickThread>()
|
||||
.set(EQuickThread.BALANCED)
|
||||
public static ConfigEntry<EThreadPreset> threadPresetSetting = new ConfigEntry.Builder<EThreadPreset>()
|
||||
.set(EThreadPreset.LOW_IMPACT) // the default value is set via the listener when accessed
|
||||
.comment(""
|
||||
+ "Changing this setting will modify a number of different settings that will change \n"
|
||||
+ "the load that Distant Horizons is allowed to put on your CPU. \n"
|
||||
+ "\n"
|
||||
+ "Higher options will improve LOD generation and loading speed, \n"
|
||||
+ "but will increase CPU load and may introduce stuttering.\n"
|
||||
+ "\n"
|
||||
+ "Note: on CPUs with 4 cores or less these settings will be less effective \n"
|
||||
+ " and some settings will give similar results. \n"
|
||||
+ "")
|
||||
.setAppearance(ConfigEntryAppearance.ONLY_IN_GUI) // TODO set when the game boots
|
||||
//.addListener(null) // TODO add listener
|
||||
.setAppearance(EConfigEntryAppearance.ONLY_IN_GUI)
|
||||
.addListener(ThreadPresetConfigEventHandler.INSTANCE)
|
||||
.build();
|
||||
|
||||
public static ConfigLinkedEntry quickEnableWorldGenerator = new ConfigLinkedEntry(Advanced.WorldGenerator.enableDistantGeneration);
|
||||
@@ -114,15 +119,14 @@ public class Config
|
||||
|
||||
|
||||
public static ConfigCategory advanced = new ConfigCategory.Builder().set(Advanced.class).build();
|
||||
// public static ConfigCategory resetSettingsConfirmation = new ConfigCategory.Builder().set(ResetConfirmation.class).build();
|
||||
|
||||
public static class Advanced
|
||||
{
|
||||
public static ConfigUIComment advancedConfigScreenNote = new ConfigUIComment();
|
||||
|
||||
public static ConfigCategory graphics = new ConfigCategory.Builder().set(Graphics.class).build();
|
||||
public static ConfigCategory worldGenerator = new ConfigCategory.Builder().set(WorldGenerator.class).build();
|
||||
public static ConfigCategory multiplayer = new ConfigCategory.Builder().set(Multiplayer.class).build();
|
||||
public static ConfigCategory threading = new ConfigCategory.Builder().set(MultiThreading.class).build();
|
||||
public static ConfigCategory multiThreading = new ConfigCategory.Builder().set(MultiThreading.class).build();
|
||||
public static ConfigCategory buffers = new ConfigCategory.Builder().set(GpuBuffers.class).build();
|
||||
public static ConfigCategory autoUpdater = new ConfigCategory.Builder().set(AutoUpdater.class).build();
|
||||
|
||||
@@ -155,13 +159,13 @@ public class Config
|
||||
+ "Lowest Quality: " + EHorizontalResolution.CHUNK + "\n"
|
||||
+ "Highest Quality: " + EHorizontalResolution.BLOCK)
|
||||
.addListener(RenderCacheConfigEventHandler.INSTANCE)
|
||||
.setPerformance(ConfigEntryPerformance.MEDIUM)
|
||||
.setPerformance(EConfigEntryPerformance.MEDIUM)
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<Integer> lodChunkRenderDistance = new ConfigEntry.Builder<Integer>()
|
||||
.setMinDefaultMax(32, 128, 4096)
|
||||
.comment("The radius of the mod's render distance. (measured in chunks)")
|
||||
.setPerformance(ConfigEntryPerformance.HIGH)
|
||||
.setPerformance(EConfigEntryPerformance.HIGH)
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<EVerticalQuality> verticalQuality = new ConfigEntry.Builder<EVerticalQuality>()
|
||||
@@ -173,8 +177,8 @@ public class Config
|
||||
+ "will increase memory and GPU usage. \n"
|
||||
+ "\n"
|
||||
+ "Lowest Quality: " + EVerticalQuality.HEIGHT_MAP + "\n"
|
||||
+ "Highest Quality: " + EVerticalQuality.ULTRA)
|
||||
.setPerformance(ConfigEntryPerformance.VERY_HIGH)
|
||||
+ "Highest Quality: " + EVerticalQuality.EXTREME)
|
||||
.setPerformance(EConfigEntryPerformance.VERY_HIGH)
|
||||
.addListener(RenderCacheConfigEventHandler.INSTANCE)
|
||||
.build();
|
||||
|
||||
@@ -198,7 +202,7 @@ public class Config
|
||||
+ "This indicates how quickly LODs decrease in quality the further away they are. \n"
|
||||
+ "Higher settings will render higher quality fake chunks farther away, \n"
|
||||
+ "but will increase memory and GPU usage.")
|
||||
.setPerformance(ConfigEntryPerformance.MEDIUM)
|
||||
.setPerformance(EConfigEntryPerformance.MEDIUM)
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<ETransparency> transparency = new ConfigEntry.Builder<ETransparency>()
|
||||
@@ -210,7 +214,31 @@ public class Config
|
||||
+ ETransparency.FAKE + ": LODs will be opaque, but shaded to match the blocks underneath. \n"
|
||||
+ ETransparency.DISABLED + ": LODs will be opaque. \n"
|
||||
+ "")
|
||||
.setPerformance(ConfigEntryPerformance.MEDIUM)
|
||||
.setPerformance(EConfigEntryPerformance.MEDIUM)
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<EBlocksToAvoid> blocksToIgnore = new ConfigEntry.Builder<EBlocksToAvoid>()
|
||||
.set(EBlocksToAvoid.NON_COLLIDING)
|
||||
.comment(""
|
||||
+ "What blocks shouldn't be rendered as LODs? \n"
|
||||
+ "\n"
|
||||
+ EBlocksToAvoid.NONE + ": Represent all blocks in the LODs \n"
|
||||
+ EBlocksToAvoid.NON_COLLIDING + ": Only represent solid blocks in the LODs (tall grass, torches, etc. won't count for a LOD's height) \n"
|
||||
+ "")
|
||||
.setPerformance(EConfigEntryPerformance.NONE)
|
||||
.addListener(RenderCacheConfigEventHandler.INSTANCE)
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<Boolean> tintWithAvoidedBlocks = new ConfigEntry.Builder<Boolean>()
|
||||
.set(true)
|
||||
.comment(""
|
||||
+ "Should the blocks underneath avoided blocks gain the color of the avoided block? \n"
|
||||
+ "\n"
|
||||
+ "True: a red flower will tint the grass below it red. \n"
|
||||
+ "False: skipped blocks will not change color of surface below them. "
|
||||
+"")
|
||||
.setPerformance(EConfigEntryPerformance.NONE)
|
||||
.addListener(RenderCacheConfigEventHandler.INSTANCE)
|
||||
.build();
|
||||
|
||||
// TODO fixme
|
||||
@@ -230,12 +258,6 @@ public class Config
|
||||
|
||||
public static class Fog
|
||||
{
|
||||
public static ConfigEntry<EFogDistance> fogDistance = new ConfigEntry.Builder<EFogDistance>()
|
||||
.set(EFogDistance.FAR)
|
||||
.comment("At what distance should Fog be drawn on the LODs?")
|
||||
.setPerformance(ConfigEntryPerformance.NONE)
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<EFogDrawMode> fogDrawMode = new ConfigEntry.Builder<EFogDrawMode>()
|
||||
.set(EFogDrawMode.FOG_ENABLED)
|
||||
.comment(""
|
||||
@@ -247,7 +269,13 @@ public class Config
|
||||
+ EFogDrawMode.FOG_DISABLED + ": Always draw fast fog on the LODs \n"
|
||||
+ "\n"
|
||||
+ "Disabling fog will improve GPU performance.")
|
||||
.setPerformance(ConfigEntryPerformance.VERY_LOW)
|
||||
.setPerformance(EConfigEntryPerformance.VERY_LOW)
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<EFogDistance> fogDistance = new ConfigEntry.Builder<EFogDistance>()
|
||||
.set(EFogDistance.FAR)
|
||||
.comment("At what distance should Fog be drawn on the LODs?")
|
||||
.setPerformance(EConfigEntryPerformance.NONE)
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<EFogColorMode> fogColorMode = new ConfigEntry.Builder<EFogColorMode>()
|
||||
@@ -257,7 +285,7 @@ public class Config
|
||||
+ "\n"
|
||||
+ EFogColorMode.USE_WORLD_FOG_COLOR + ": Use the world's fog color. \n"
|
||||
+ EFogColorMode.USE_SKY_COLOR + ": Use the sky's color.")
|
||||
.setPerformance(ConfigEntryPerformance.NONE)
|
||||
.setPerformance(EConfigEntryPerformance.NONE)
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<Boolean> disableVanillaFog = new ConfigEntry.Builder<Boolean>()
|
||||
@@ -483,13 +511,19 @@ public class Config
|
||||
// + "Disable this if you see LODs disappearing at the corners of your vision.")
|
||||
// .build();
|
||||
|
||||
// TODO replace with better options
|
||||
public static ConfigEntry<Boolean> useExtendedNearClipPlane = new ConfigEntry.Builder<Boolean>()
|
||||
.set(true)
|
||||
public static ConfigEntry<EOverdrawPrevention> overdrawPrevention = new ConfigEntry.Builder<EOverdrawPrevention>()
|
||||
.set(EOverdrawPrevention.MEDIUM)
|
||||
.comment(""
|
||||
+ "Will prevent some overdraw issues, but may cause nearby fake chunks to render incorrectly \n"
|
||||
+ " especially when in/near an ocean.")
|
||||
.setPerformance(ConfigEntryPerformance.NONE)
|
||||
+ "Determines how far Distant Horizon's near clip plane will render. \n"
|
||||
+ "\n"
|
||||
+ "Higher values will prevent LODs from rendering behind vanilla blocks at a higher distance,\n"
|
||||
+ "but may cause holes to appear in the LODs. \n"
|
||||
+ "Holes are most likely at the left and right edges of the screen \n"
|
||||
+ "when flying through unloaded terrain. \n"
|
||||
+ "\n"
|
||||
+ "Increasing the vanilla render distance increases the effectiveness of these options."
|
||||
+ "")
|
||||
.setPerformance(EConfigEntryPerformance.NONE)
|
||||
.build();
|
||||
|
||||
public static ConfigEntry<Double> brightnessMultiplier = new ConfigEntry.Builder<Double>() // TODO: Make this a float (the ClassicConfigGUI doesnt support floats)
|
||||
@@ -512,7 +546,6 @@ public class Config
|
||||
+ "2 = very saturated")
|
||||
.build();
|
||||
|
||||
// TODO replace with better options
|
||||
public static ConfigEntry<Boolean> enableCaveCulling = new ConfigEntry.Builder<Boolean>()
|
||||
.set(true)
|
||||
.comment(""
|
||||
@@ -654,33 +687,9 @@ public class Config
|
||||
+ EGenerationPriority.AUTO + " \n"
|
||||
+ "Uses " + EGenerationPriority.BALANCED + " when on a single player world \n"
|
||||
+ " and " + EGenerationPriority.NEAR_FIRST + " when connected to a server.")
|
||||
.setPerformance(ConfigEntryPerformance.NONE)
|
||||
.setPerformance(EConfigEntryPerformance.NONE)
|
||||
.build();
|
||||
|
||||
// TODO fixme
|
||||
public static ConfigEntry<EBlocksToAvoid> blocksToAvoid = new ConfigEntry.Builder<EBlocksToAvoid>()
|
||||
.set(EBlocksToAvoid.BOTH)
|
||||
.comment(""
|
||||
+ "When generating fake chunks, what blocks should be ignored? \n"
|
||||
+ "Ignored blocks don't affect the height of the fake chunk, but might affect the color. \n"
|
||||
+ "So using " + EBlocksToAvoid.BOTH + " will prevent snow covered blocks from appearing one block too tall, \n"
|
||||
+ " but will still show the snow's color.\n"
|
||||
+ "\n"
|
||||
+ EBlocksToAvoid.NONE + ": Use all blocks when generating fake chunks \n"
|
||||
+ EBlocksToAvoid.NON_FULL + ": Only use full blocks when generating fake chunks (ignores slabs, lanterns, torches, tall grass, etc.) \n"
|
||||
+ EBlocksToAvoid.NO_COLLISION + ": Only use solid blocks when generating fake chunks (ignores tall grass, torches, etc.) \n"
|
||||
+ EBlocksToAvoid.BOTH + ": Only use full solid blocks when generating fake chunks")
|
||||
.setPerformance(ConfigEntryPerformance.NONE)
|
||||
.build();
|
||||
|
||||
// TODO fixme
|
||||
public static ConfigEntry<Boolean> tintWithAvoidedBlocks = new ConfigEntry.Builder<Boolean>()
|
||||
.set(true)
|
||||
.comment(""
|
||||
+ "Should the blocks underneath avoided blocks gain the color of the avoided block? \n"
|
||||
+ " True: a red flower on grass will tint the grass below it red"
|
||||
+ " False: skipped blocks will not change color of surface below them")
|
||||
.build();
|
||||
}
|
||||
|
||||
public static class Multiplayer
|
||||
@@ -995,7 +1004,7 @@ public class Config
|
||||
.build();
|
||||
|
||||
|
||||
// can be set to public to show in the config file and UI
|
||||
// can be set to public inorder to show in the config file and UI
|
||||
private static ConfigCategory exampleConfigScreen = new ConfigCategory.Builder()
|
||||
.set(ExampleConfigScreen.class)
|
||||
.build();
|
||||
@@ -1064,5 +1073,17 @@ public class Config
|
||||
|
||||
}
|
||||
|
||||
public static class ResetConfirmation
|
||||
{
|
||||
public static ConfigUIComment resetConfirmationNote = new ConfigUIComment();
|
||||
|
||||
public static ConfigEntry<Boolean> resetAllSettings = new ConfigEntry.Builder<Boolean>()
|
||||
.set(false)
|
||||
.setAppearance(EConfigEntryAppearance.ONLY_IN_GUI)
|
||||
//.addListener(null) // TODO add listener
|
||||
.build();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.seibel.lod.core.config;
|
||||
|
||||
import com.seibel.lod.core.config.types.ConfigEntry;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
||||
public class ConfigEntryWithPresetOptions<TQuickEnum, TConfig>
|
||||
{
|
||||
public final ConfigEntry<TConfig> configEntry;
|
||||
|
||||
private final HashMap<TQuickEnum, TConfig> configOptionByQualityOption;
|
||||
|
||||
|
||||
|
||||
public ConfigEntryWithPresetOptions(ConfigEntry<TConfig> configEntry, HashMap<TQuickEnum, TConfig> configOptionByQualityOption)
|
||||
{
|
||||
this.configEntry = configEntry;
|
||||
this.configOptionByQualityOption = configOptionByQualityOption;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void updateConfigEntry(TQuickEnum quickQuality)
|
||||
{
|
||||
TConfig newValue = this.configOptionByQualityOption.get(quickQuality);
|
||||
this.configEntry.set(newValue);
|
||||
}
|
||||
|
||||
public HashSet<TQuickEnum> getPossibleQualitiesFromCurrentOptionValue()
|
||||
{
|
||||
TConfig inputOptionValue = this.configEntry.get();
|
||||
HashSet<TQuickEnum> possibleQualities = new HashSet<>();
|
||||
|
||||
for (TQuickEnum key : this.configOptionByQualityOption.keySet())
|
||||
{
|
||||
TConfig optionValue = this.configOptionByQualityOption.get(key);
|
||||
if (optionValue.equals(inputOptionValue))
|
||||
{
|
||||
possibleQualities.add(key);
|
||||
}
|
||||
}
|
||||
|
||||
return possibleQualities;
|
||||
}
|
||||
|
||||
}
|
||||
+1
-3
@@ -4,9 +4,7 @@ import com.seibel.lod.api.DhApiMain;
|
||||
import com.seibel.lod.api.enums.config.EHorizontalResolution;
|
||||
import com.seibel.lod.api.enums.config.EVerticalQuality;
|
||||
import com.seibel.lod.core.config.Config;
|
||||
import com.seibel.lod.core.config.listeners.ConfigChangeListener;
|
||||
import com.seibel.lod.core.config.listeners.IConfigListener;
|
||||
import com.seibel.lod.core.config.types.ConfigEntry;
|
||||
import com.seibel.lod.core.util.DetailDistanceUtil;
|
||||
|
||||
/**
|
||||
@@ -59,7 +57,7 @@ public class RenderCacheConfigEventHandler implements IConfigListener
|
||||
if (refreshRenderData)
|
||||
{
|
||||
// TODO add a timeout to prevent rapidly changing settings causing the render data thrashing.
|
||||
DetailDistanceUtil.minDetail = newHorizontalResolution.detailLevel;
|
||||
DetailDistanceUtil.updateSettings();
|
||||
DhApiMain.Delayed.renderProxy.clearRenderDataCache();
|
||||
}
|
||||
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package com.seibel.lod.core.config.eventHandlers;
|
||||
|
||||
import com.seibel.lod.api.DhApiMain;
|
||||
import com.seibel.lod.api.enums.config.EHorizontalResolution;
|
||||
import com.seibel.lod.api.enums.config.EVerticalQuality;
|
||||
import com.seibel.lod.core.config.Config;
|
||||
import com.seibel.lod.core.config.listeners.ConfigChangeListener;
|
||||
import com.seibel.lod.core.config.listeners.IConfigListener;
|
||||
import com.seibel.lod.core.util.DetailDistanceUtil;
|
||||
|
||||
public class ResetConfigEventHandler
|
||||
{
|
||||
public static ResetConfigEventHandler INSTANCE = new ResetConfigEventHandler();
|
||||
public final ConfigChangeListener<Boolean> configChangeListener;
|
||||
|
||||
|
||||
|
||||
/** private since we only ever need one handler at a time */
|
||||
private ResetConfigEventHandler()
|
||||
{
|
||||
this.configChangeListener = new ConfigChangeListener<>(Config.Client.ResetConfirmation.resetAllSettings, (resetSettings) -> { doStuff(resetSettings); });
|
||||
|
||||
}
|
||||
|
||||
private void doStuff(boolean resetSettings)
|
||||
{
|
||||
if (!resetSettings)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Config.Client.ResetConfirmation.resetAllSettings.set(false);
|
||||
}
|
||||
|
||||
}
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
package com.seibel.lod.core.config.eventHandlers.presets;
|
||||
|
||||
import com.seibel.lod.core.config.ConfigEntryWithPresetOptions;
|
||||
import com.seibel.lod.core.config.listeners.IConfigListener;
|
||||
import com.seibel.lod.coreapi.interfaces.config.IConfigEntry;
|
||||
import com.seibel.lod.coreapi.util.StringUtil;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public abstract class AbstractPresetConfigEventHandler<TPresetEnum extends Enum<?>> implements IConfigListener
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
|
||||
|
||||
protected final ArrayList<ConfigEntryWithPresetOptions<TPresetEnum, ?>> configList = new ArrayList<>();
|
||||
|
||||
protected boolean changingPreset = false;
|
||||
|
||||
|
||||
|
||||
//===========//
|
||||
// listeners //
|
||||
//===========//
|
||||
|
||||
@Override
|
||||
public void onConfigValueSet()
|
||||
{
|
||||
TPresetEnum qualityPreset = this.getPresetConfigEntry().get();
|
||||
if (qualityPreset == null)
|
||||
{
|
||||
// the value will be null when the config menu is first opened,
|
||||
// set the value to what it should be.
|
||||
|
||||
TPresetEnum currentQualitySetting = this.getCurrentQualityPreset();
|
||||
this.getPresetConfigEntry().set(currentQualitySetting);
|
||||
return;
|
||||
}
|
||||
|
||||
// if the quick value is custom, nothing needs to be changed
|
||||
if (qualityPreset == this.getCustomPresetEnum())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
LOGGER.debug("changing preset to: " + qualityPreset);
|
||||
this.changingPreset = true;
|
||||
|
||||
for (ConfigEntryWithPresetOptions<TPresetEnum, ?> configEntry : this.configList)
|
||||
{
|
||||
configEntry.updateConfigEntry(qualityPreset);
|
||||
}
|
||||
|
||||
this.changingPreset = false;
|
||||
LOGGER.debug("preset active: "+qualityPreset);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUiModify() { /* do nothing, we only care about modified config values */ }
|
||||
|
||||
/**
|
||||
* listen for changed graphics settings and set the
|
||||
* quick quality to "custom" if anything was changed
|
||||
*/
|
||||
public void onConfigValueChanged()
|
||||
{
|
||||
if (this.changingPreset)
|
||||
{
|
||||
// if a preset is currently being applied, ignore all changes
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
TPresetEnum newPreset = this.getCurrentQualityPreset();
|
||||
TPresetEnum currentPreset = this.getPresetConfigEntry().get();
|
||||
|
||||
if (newPreset != currentPreset)
|
||||
{
|
||||
this.getPresetConfigEntry().set(this.getCustomPresetEnum());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// helper methods //
|
||||
//================//
|
||||
|
||||
/** @return what {@link TPresetEnum} is currently viable based on the {@link AbstractPresetConfigEventHandler#configList}. */
|
||||
public TPresetEnum getCurrentQualityPreset()
|
||||
{
|
||||
// get all quick options
|
||||
HashSet<TPresetEnum> possiblePresetSet = new HashSet<>(this.getPresetEnumList());
|
||||
|
||||
|
||||
// remove any quick options that aren't possible with the currently selected options
|
||||
for (ConfigEntryWithPresetOptions<TPresetEnum, ?> configEntry : this.configList)
|
||||
{
|
||||
HashSet<TPresetEnum> optionPresetSet = configEntry.getPossibleQualitiesFromCurrentOptionValue();
|
||||
possiblePresetSet.retainAll(optionPresetSet);
|
||||
}
|
||||
|
||||
|
||||
|
||||
ArrayList<TPresetEnum> possiblePrestList = new ArrayList<>(possiblePresetSet);
|
||||
if (possiblePrestList.size() > 1)
|
||||
{
|
||||
// we shouldn't have multiple options, but just in case
|
||||
LOGGER.warn("Multiple potential preset options ["+StringUtil.join(", ", possiblePrestList)+"], defaulting to the first one.");
|
||||
}
|
||||
|
||||
if (possiblePrestList.size() == 0)
|
||||
{
|
||||
// if no options are valid, return "CUSTOM"
|
||||
possiblePrestList.add(this.getCustomPresetEnum());
|
||||
}
|
||||
|
||||
return possiblePrestList.get(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==================//
|
||||
// abstract methods //
|
||||
//==================//
|
||||
|
||||
protected abstract IConfigEntry<TPresetEnum> getPresetConfigEntry();
|
||||
|
||||
protected abstract List<TPresetEnum> getPresetEnumList();
|
||||
protected abstract TPresetEnum getCustomPresetEnum();
|
||||
|
||||
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
package com.seibel.lod.core.config.eventHandlers.presets;
|
||||
|
||||
import com.seibel.lod.api.enums.config.EHorizontalQuality;
|
||||
import com.seibel.lod.api.enums.config.EHorizontalResolution;
|
||||
import com.seibel.lod.api.enums.config.EVerticalQuality;
|
||||
import com.seibel.lod.api.enums.config.quickOptions.EQualityPreset;
|
||||
import com.seibel.lod.api.enums.rendering.ETransparency;
|
||||
import com.seibel.lod.core.config.Config;
|
||||
import com.seibel.lod.core.config.ConfigEntryWithPresetOptions;
|
||||
import com.seibel.lod.core.config.listeners.ConfigChangeListener;
|
||||
import com.seibel.lod.coreapi.interfaces.config.IConfigEntry;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class RenderQualityPresetConfigEventHandler extends AbstractPresetConfigEventHandler<EQualityPreset>
|
||||
{
|
||||
public static final RenderQualityPresetConfigEventHandler INSTANCE = new RenderQualityPresetConfigEventHandler();
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
|
||||
|
||||
private final ConfigEntryWithPresetOptions<EQualityPreset, EHorizontalResolution> drawResolution = new ConfigEntryWithPresetOptions<>(Config.Client.Advanced.Graphics.Quality.drawResolution,
|
||||
new HashMap<EQualityPreset, EHorizontalResolution>()
|
||||
{{
|
||||
this.put(EQualityPreset.MINIMUM, EHorizontalResolution.TWO_BLOCKS);
|
||||
this.put(EQualityPreset.LOW, EHorizontalResolution.BLOCK);
|
||||
this.put(EQualityPreset.MEDIUM, EHorizontalResolution.BLOCK);
|
||||
this.put(EQualityPreset.HIGH, EHorizontalResolution.BLOCK);
|
||||
this.put(EQualityPreset.EXTREME, EHorizontalResolution.BLOCK);
|
||||
}});
|
||||
private final ConfigEntryWithPresetOptions<EQualityPreset, EVerticalQuality> verticalQuality = new ConfigEntryWithPresetOptions<>(Config.Client.Advanced.Graphics.Quality.verticalQuality,
|
||||
new HashMap<EQualityPreset, EVerticalQuality>()
|
||||
{{
|
||||
this.put(EQualityPreset.MINIMUM, EVerticalQuality.HEIGHT_MAP);
|
||||
this.put(EQualityPreset.LOW, EVerticalQuality.LOW);
|
||||
this.put(EQualityPreset.MEDIUM, EVerticalQuality.MEDIUM);
|
||||
this.put(EQualityPreset.HIGH, EVerticalQuality.HIGH);
|
||||
this.put(EQualityPreset.EXTREME, EVerticalQuality.EXTREME);
|
||||
}});
|
||||
private final ConfigEntryWithPresetOptions<EQualityPreset, EHorizontalQuality> horizontalQuality = new ConfigEntryWithPresetOptions<>(Config.Client.Advanced.Graphics.Quality.horizontalQuality,
|
||||
new HashMap<EQualityPreset, EHorizontalQuality>()
|
||||
{{
|
||||
this.put(EQualityPreset.MINIMUM, EHorizontalQuality.LOWEST);
|
||||
this.put(EQualityPreset.LOW, EHorizontalQuality.LOW);
|
||||
this.put(EQualityPreset.MEDIUM, EHorizontalQuality.MEDIUM);
|
||||
this.put(EQualityPreset.HIGH, EHorizontalQuality.HIGH);
|
||||
this.put(EQualityPreset.EXTREME, EHorizontalQuality.EXTREME);
|
||||
}});
|
||||
private final ConfigEntryWithPresetOptions<EQualityPreset, ETransparency> transparency = new ConfigEntryWithPresetOptions<>(Config.Client.Advanced.Graphics.Quality.transparency,
|
||||
new HashMap<EQualityPreset, ETransparency>()
|
||||
{{
|
||||
this.put(EQualityPreset.MINIMUM, ETransparency.DISABLED);
|
||||
this.put(EQualityPreset.LOW, ETransparency.FAKE);
|
||||
this.put(EQualityPreset.MEDIUM, ETransparency.COMPLETE);
|
||||
this.put(EQualityPreset.HIGH, ETransparency.COMPLETE);
|
||||
this.put(EQualityPreset.EXTREME, ETransparency.COMPLETE);
|
||||
}});
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// constructors //
|
||||
//==============//
|
||||
|
||||
/** private since we only ever need one handler at a time */
|
||||
private RenderQualityPresetConfigEventHandler()
|
||||
{
|
||||
// add each config used by this preset
|
||||
this.configList.add(this.drawResolution);
|
||||
this.configList.add(this.verticalQuality);
|
||||
this.configList.add(this.horizontalQuality);
|
||||
this.configList.add(this.transparency);
|
||||
|
||||
|
||||
for (ConfigEntryWithPresetOptions<EQualityPreset, ?> config : this.configList)
|
||||
{
|
||||
// ignore try-using, the listener should only ever be added once and should never be removed
|
||||
new ConfigChangeListener<>(config.configEntry, (val) -> { this.onConfigValueChanged(); });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// enum getters //
|
||||
//==============//
|
||||
|
||||
@Override
|
||||
protected IConfigEntry<EQualityPreset> getPresetConfigEntry() { return Config.Client.qualityPresetSetting; }
|
||||
|
||||
@Override
|
||||
protected List<EQualityPreset> getPresetEnumList() { return Arrays.asList(EQualityPreset.values()); }
|
||||
@Override
|
||||
protected EQualityPreset getCustomPresetEnum() { return EQualityPreset.CUSTOM; }
|
||||
|
||||
}
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
package com.seibel.lod.core.config.eventHandlers.presets;
|
||||
|
||||
import com.seibel.lod.api.enums.config.quickOptions.EThreadPreset;
|
||||
import com.seibel.lod.core.config.Config;
|
||||
import com.seibel.lod.core.config.ConfigEntryWithPresetOptions;
|
||||
import com.seibel.lod.core.config.listeners.ConfigChangeListener;
|
||||
import com.seibel.lod.coreapi.interfaces.config.IConfigEntry;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class ThreadPresetConfigEventHandler extends AbstractPresetConfigEventHandler<EThreadPreset>
|
||||
{
|
||||
public static final ThreadPresetConfigEventHandler INSTANCE = new ThreadPresetConfigEventHandler();
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
|
||||
|
||||
private final ConfigEntryWithPresetOptions<EThreadPreset, Integer> worldGen = new ConfigEntryWithPresetOptions<>(Config.Client.Advanced.MultiThreading.numberOfWorldGenerationThreads,
|
||||
new HashMap<EThreadPreset, Integer>()
|
||||
{{
|
||||
this.put(EThreadPreset.MINIMAL_IMPACT, 1);
|
||||
this.put(EThreadPreset.LOW_IMPACT, getThreadCountByPercent(0.1));
|
||||
this.put(EThreadPreset.BALANCED, getThreadCountByPercent(0.2));
|
||||
this.put(EThreadPreset.AGGRESSIVE, getThreadCountByPercent(0.4));
|
||||
this.put(EThreadPreset.I_PAID_FOR_THE_WHOLE_CPU, getThreadCountByPercent(1.0));
|
||||
}});
|
||||
private final ConfigEntryWithPresetOptions<EThreadPreset, Integer> bufferBuilders = new ConfigEntryWithPresetOptions<>(Config.Client.Advanced.MultiThreading.numberOfBufferBuilderThreads,
|
||||
new HashMap<EThreadPreset, Integer>()
|
||||
{{
|
||||
this.put(EThreadPreset.MINIMAL_IMPACT, 1);
|
||||
this.put(EThreadPreset.LOW_IMPACT, getThreadCountByPercent(0.1));
|
||||
this.put(EThreadPreset.BALANCED, getThreadCountByPercent(0.2));
|
||||
this.put(EThreadPreset.AGGRESSIVE, getThreadCountByPercent(0.4));
|
||||
this.put(EThreadPreset.I_PAID_FOR_THE_WHOLE_CPU, getThreadCountByPercent(1.0));
|
||||
}});
|
||||
private final ConfigEntryWithPresetOptions<EThreadPreset, Integer> fileHandlers = new ConfigEntryWithPresetOptions<>(Config.Client.Advanced.MultiThreading.numberOfFileHandlerThreads,
|
||||
new HashMap<EThreadPreset, Integer>()
|
||||
{{
|
||||
this.put(EThreadPreset.MINIMAL_IMPACT, 1);
|
||||
this.put(EThreadPreset.LOW_IMPACT, getThreadCountByPercent(0.1));
|
||||
this.put(EThreadPreset.BALANCED, getThreadCountByPercent(0.2));
|
||||
this.put(EThreadPreset.AGGRESSIVE, getThreadCountByPercent(0.2));
|
||||
this.put(EThreadPreset.I_PAID_FOR_THE_WHOLE_CPU, getThreadCountByPercent(1.0));
|
||||
}});
|
||||
private final ConfigEntryWithPresetOptions<EThreadPreset, Integer> dataConverters = new ConfigEntryWithPresetOptions<>(Config.Client.Advanced.MultiThreading.numberOfDataConverterThreads,
|
||||
new HashMap<EThreadPreset, Integer>()
|
||||
{{
|
||||
this.put(EThreadPreset.MINIMAL_IMPACT, 1);
|
||||
this.put(EThreadPreset.LOW_IMPACT, getThreadCountByPercent(0.1));
|
||||
this.put(EThreadPreset.BALANCED, getThreadCountByPercent(0.2));
|
||||
this.put(EThreadPreset.AGGRESSIVE, getThreadCountByPercent(0.2));
|
||||
this.put(EThreadPreset.I_PAID_FOR_THE_WHOLE_CPU, getThreadCountByPercent(1.0));
|
||||
}});
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// constructors //
|
||||
//==============//
|
||||
|
||||
/** private since we only ever need one handler at a time */
|
||||
private ThreadPresetConfigEventHandler()
|
||||
{
|
||||
// add each config used by this preset
|
||||
this.configList.add(this.worldGen);
|
||||
this.configList.add(this.bufferBuilders);
|
||||
this.configList.add(this.fileHandlers);
|
||||
this.configList.add(this.dataConverters);
|
||||
|
||||
|
||||
for (ConfigEntryWithPresetOptions<EThreadPreset, ?> config : this.configList)
|
||||
{
|
||||
// ignore try-using, the listener should only ever be added once and should never be removed
|
||||
new ConfigChangeListener<>(config.configEntry, (val) -> { this.onConfigValueChanged(); });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// helper methods //
|
||||
//================//
|
||||
|
||||
/**
|
||||
* Pre-computed values for your convenience: <br>
|
||||
* Format: percent: 4coreCpu-8coreCpu-16coreCpu <br><br>
|
||||
* <code>
|
||||
* 0.1: 1-1-2 <br>
|
||||
* 0.2: 1-2-4 <br>
|
||||
* 0.4: 2-4-7 <br>
|
||||
* 0.6: 3-5-10 <br>
|
||||
* 0.8: 4-7-13 <br>
|
||||
* 1.0: 4-8-16 <br>
|
||||
* </code>
|
||||
*/
|
||||
private static int getThreadCountByPercent(double percent) throws IllegalArgumentException
|
||||
{
|
||||
if (percent <= 0 || percent > 1)
|
||||
{
|
||||
throw new IllegalArgumentException("percent must be greater than 0 and less than or equal to 1.");
|
||||
}
|
||||
|
||||
// this is logical processor count, not physical CPU cores
|
||||
int totalProcessorCount = Runtime.getRuntime().availableProcessors();
|
||||
int coreCount = (int) Math.ceil(totalProcessorCount * percent);
|
||||
return Math.max(1, coreCount);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// enum getters //
|
||||
//==============//
|
||||
|
||||
@Override
|
||||
protected IConfigEntry<EThreadPreset> getPresetConfigEntry() { return Config.Client.threadPresetSetting; }
|
||||
|
||||
@Override
|
||||
protected List<EThreadPreset> getPresetEnumList() { return Arrays.asList(EThreadPreset.values()); }
|
||||
@Override
|
||||
protected EThreadPreset getCustomPresetEnum() { return EThreadPreset.CUSTOM; }
|
||||
|
||||
}
|
||||
@@ -5,7 +5,10 @@ public interface IConfigListener
|
||||
/** Called whenever the value is set (including in core DH code) */
|
||||
void onConfigValueSet();
|
||||
|
||||
/** Called whenever the value is changed through the UI (only when the done button is pressed) */
|
||||
void onUiModify(); // TODO
|
||||
/**
|
||||
* TODO not implemented
|
||||
* Called whenever the value is changed through the UI (only when the done button is pressed)
|
||||
*/
|
||||
void onUiModify();
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.seibel.lod.core.config.types;
|
||||
|
||||
import com.seibel.lod.core.config.ConfigBase;
|
||||
import com.seibel.lod.core.config.types.enums.ConfigEntryAppearance;
|
||||
import com.seibel.lod.core.config.types.enums.EConfigEntryAppearance;
|
||||
|
||||
/**
|
||||
* The class where all config options should extend
|
||||
@@ -16,9 +16,9 @@ public abstract class AbstractConfigType<T, S> { // The S is the class that is e
|
||||
|
||||
public Object guiValue; // This is a storage variable something like the gui can use
|
||||
|
||||
protected ConfigEntryAppearance appearance;
|
||||
protected EConfigEntryAppearance appearance;
|
||||
|
||||
protected AbstractConfigType(ConfigEntryAppearance appearance, T value) {
|
||||
protected AbstractConfigType(EConfigEntryAppearance appearance, T value) {
|
||||
this.appearance = appearance;
|
||||
this.value = value;
|
||||
}
|
||||
@@ -33,10 +33,10 @@ public abstract class AbstractConfigType<T, S> { // The S is the class that is e
|
||||
this.value = newValue;
|
||||
}
|
||||
|
||||
public ConfigEntryAppearance getAppearance() {
|
||||
public EConfigEntryAppearance getAppearance() {
|
||||
return appearance;
|
||||
}
|
||||
public void setAppearance(ConfigEntryAppearance newAppearance) {
|
||||
public void setAppearance(EConfigEntryAppearance newAppearance) {
|
||||
this.appearance = newAppearance;
|
||||
}
|
||||
|
||||
@@ -58,12 +58,12 @@ public abstract class AbstractConfigType<T, S> { // The S is the class that is e
|
||||
}
|
||||
|
||||
protected static abstract class Builder<T, S> {
|
||||
protected ConfigEntryAppearance tmpAppearance = ConfigEntryAppearance.ALL;
|
||||
protected EConfigEntryAppearance tmpAppearance = EConfigEntryAppearance.ALL;
|
||||
protected T tmpValue;
|
||||
|
||||
|
||||
// Put this into your own builder
|
||||
public S setAppearance(ConfigEntryAppearance newAppearance) {
|
||||
public S setAppearance(EConfigEntryAppearance newAppearance) {
|
||||
this.tmpAppearance = newAppearance;
|
||||
return (S) this;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.seibel.lod.core.config.types;
|
||||
|
||||
import com.seibel.lod.core.config.types.enums.ConfigEntryAppearance;
|
||||
import com.seibel.lod.core.config.types.enums.EConfigEntryAppearance;
|
||||
|
||||
/**
|
||||
* Adds a categoty to the config
|
||||
@@ -11,7 +11,7 @@ import com.seibel.lod.core.config.types.enums.ConfigEntryAppearance;
|
||||
public class ConfigCategory extends AbstractConfigType<Class, ConfigCategory> {
|
||||
public String destination; // Where the category goes to
|
||||
|
||||
private ConfigCategory(ConfigEntryAppearance appearance, Class value, String destination) {
|
||||
private ConfigCategory(EConfigEntryAppearance appearance, Class value, String destination) {
|
||||
super(appearance, value);
|
||||
this.destination = destination;
|
||||
}
|
||||
@@ -35,7 +35,7 @@ public class ConfigCategory extends AbstractConfigType<Class, ConfigCategory> {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAppearance(ConfigEntryAppearance newAppearance) {
|
||||
public Builder setAppearance(EConfigEntryAppearance newAppearance) {
|
||||
this.tmpAppearance = newAppearance;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -31,11 +31,11 @@ public class ConfigEntry<T> extends AbstractConfigType<T, ConfigEntry<T>> implem
|
||||
public final boolean allowApiOverride;
|
||||
private T apiValue;
|
||||
|
||||
private final ConfigEntryPerformance performance;
|
||||
private final EConfigEntryPerformance performance;
|
||||
|
||||
|
||||
/** Creates the entry */
|
||||
private ConfigEntry(ConfigEntryAppearance appearance, T value, String comment, T min, T max, boolean allowApiOverride, ConfigEntryPerformance performance, ArrayList<IConfigListener> listenerList)
|
||||
private ConfigEntry(EConfigEntryAppearance appearance, T value, String comment, T min, T max, boolean allowApiOverride, EConfigEntryPerformance performance, ArrayList<IConfigListener> listenerList)
|
||||
{
|
||||
super(appearance, value);
|
||||
this.defaultValue = value;
|
||||
@@ -120,7 +120,7 @@ public class ConfigEntry<T> extends AbstractConfigType<T, ConfigEntry<T>> implem
|
||||
public void setComment(String newComment) { this.comment = newComment; }
|
||||
|
||||
/** Gets the performance impact of an option */
|
||||
public ConfigEntryPerformance getPerformance() { return this.performance; }
|
||||
public EConfigEntryPerformance getPerformance() { return this.performance; }
|
||||
|
||||
public void addListener(IConfigListener newListener) { this.listenerList.add(newListener); }
|
||||
public void removeListener(IConfigListener oldListener) { this.listenerList.remove(oldListener); }
|
||||
@@ -197,7 +197,7 @@ public class ConfigEntry<T> extends AbstractConfigType<T, ConfigEntry<T>> implem
|
||||
private T tmpMin;
|
||||
private T tmpMax;
|
||||
private boolean tmpUseApiOverwrite;
|
||||
private ConfigEntryPerformance tmpPerformance = ConfigEntryPerformance.DONT_SHOW;
|
||||
private EConfigEntryPerformance tmpPerformance = EConfigEntryPerformance.DONT_SHOW;
|
||||
protected ArrayList<IConfigListener> tmpIConfigListener = new ArrayList<>();
|
||||
|
||||
public Builder<T> comment(String newComment)
|
||||
@@ -239,7 +239,7 @@ public class ConfigEntry<T> extends AbstractConfigType<T, ConfigEntry<T>> implem
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder<T> setPerformance(ConfigEntryPerformance newPerformance)
|
||||
public Builder<T> setPerformance(EConfigEntryPerformance newPerformance)
|
||||
{
|
||||
this.tmpPerformance = newPerformance;
|
||||
return this;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.seibel.lod.core.config.types;
|
||||
|
||||
import com.seibel.lod.core.config.types.enums.ConfigEntryAppearance;
|
||||
import com.seibel.lod.core.config.types.enums.EConfigEntryAppearance;
|
||||
|
||||
/**
|
||||
* Creates a UI element that copies everything from another element.
|
||||
@@ -10,12 +10,12 @@ import com.seibel.lod.core.config.types.enums.ConfigEntryAppearance;
|
||||
*/
|
||||
public class ConfigLinkedEntry extends AbstractConfigType<AbstractConfigType, ConfigLinkedEntry> {
|
||||
public ConfigLinkedEntry(AbstractConfigType value) {
|
||||
super(ConfigEntryAppearance.ONLY_IN_GUI, value);
|
||||
super(EConfigEntryAppearance.ONLY_IN_GUI, value);
|
||||
}
|
||||
|
||||
/** Appearance shouldn't be changed */
|
||||
@Override
|
||||
public void setAppearance(ConfigEntryAppearance newAppearance) {}
|
||||
public void setAppearance(EConfigEntryAppearance newAppearance) {}
|
||||
|
||||
/** Value shouldn't be changed after creation */
|
||||
@Override
|
||||
@@ -25,7 +25,7 @@ public class ConfigLinkedEntry extends AbstractConfigType<AbstractConfigType, Co
|
||||
public static class Builder extends AbstractConfigType.Builder<AbstractConfigType, Builder> {
|
||||
/** Appearance shouldn't be changed */
|
||||
@Override
|
||||
public Builder setAppearance(ConfigEntryAppearance newAppearance) {
|
||||
public Builder setAppearance(EConfigEntryAppearance newAppearance) {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.seibel.lod.core.config.types;
|
||||
|
||||
import com.seibel.lod.core.config.types.enums.ConfigEntryAppearance;
|
||||
import com.seibel.lod.core.config.types.enums.EConfigEntryAppearance;
|
||||
|
||||
/**
|
||||
* Adds something like a ConfigEntry but without a button to change the input
|
||||
@@ -9,12 +9,12 @@ import com.seibel.lod.core.config.types.enums.ConfigEntryAppearance;
|
||||
*/
|
||||
public class ConfigUIComment extends AbstractConfigType<String, ConfigUIComment>{
|
||||
public ConfigUIComment() {
|
||||
super(ConfigEntryAppearance.ONLY_IN_GUI, "");
|
||||
super(EConfigEntryAppearance.ONLY_IN_GUI, "");
|
||||
}
|
||||
|
||||
/** Appearance shouldn't be changed */
|
||||
@Override
|
||||
public void setAppearance(ConfigEntryAppearance newAppearance) {}
|
||||
public void setAppearance(EConfigEntryAppearance newAppearance) {}
|
||||
|
||||
/** Pointless to set the value */
|
||||
@Override
|
||||
@@ -23,7 +23,7 @@ public class ConfigUIComment extends AbstractConfigType<String, ConfigUIComment>
|
||||
public static class Builder extends AbstractConfigType.Builder<String, Builder> {
|
||||
/** Appearance shouldn't be changed */
|
||||
@Override
|
||||
public Builder setAppearance(ConfigEntryAppearance newAppearance) {
|
||||
public Builder setAppearance(EConfigEntryAppearance newAppearance) {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
+5
-3
@@ -6,7 +6,7 @@ package com.seibel.lod.core.config.types.enums;
|
||||
*
|
||||
* @author coolGi
|
||||
*/
|
||||
public enum ConfigEntryAppearance
|
||||
public enum EConfigEntryAppearance
|
||||
{
|
||||
/** Defeat option */
|
||||
ALL(true, true),
|
||||
@@ -14,13 +14,15 @@ public enum ConfigEntryAppearance
|
||||
ONLY_IN_GUI(true, false),
|
||||
/** Only show the option in the file. There would be no way to access it using the UI */
|
||||
ONLY_IN_FILE(true, false);
|
||||
|
||||
|
||||
/** Sets whether the option should show in the UI */
|
||||
public final boolean showInGui;
|
||||
/** Sets whether to save an option, <br> If set to false, the option will be reset on game restart */
|
||||
public final boolean showInFile;
|
||||
|
||||
ConfigEntryAppearance(boolean showInGui, boolean showInFile) { // If both are false then the config won't touch the option, but it would still be accessable if explicitly called
|
||||
EConfigEntryAppearance(boolean showInGui, boolean showInFile)
|
||||
{
|
||||
// If both are false then the config won't touch the option, but it would still be accessible if explicitly called
|
||||
this.showInGui = showInGui;
|
||||
this.showInFile = showInFile;
|
||||
}
|
||||
+3
-2
@@ -6,13 +6,14 @@ package com.seibel.lod.core.config.types.enums;
|
||||
*
|
||||
* @author coolGi
|
||||
*/
|
||||
public enum ConfigEntryPerformance {
|
||||
public enum EConfigEntryPerformance
|
||||
{
|
||||
NONE,
|
||||
VERY_LOW,
|
||||
LOW,
|
||||
MEDIUM,
|
||||
HIGH,
|
||||
VERY_HIGH,
|
||||
|
||||
|
||||
DONT_SHOW
|
||||
}
|
||||
+8
-2
@@ -65,6 +65,7 @@ public class HighDetailIncompleteFullDataSource implements IIncompleteFullDataSo
|
||||
public final int dataPointsPerSection;
|
||||
public boolean isEmpty = true;
|
||||
public EDhApiWorldGenerationStep worldGenStep = EDhApiWorldGenerationStep.EMPTY;
|
||||
private boolean isPromoted = false;
|
||||
|
||||
|
||||
|
||||
@@ -614,10 +615,15 @@ public class HighDetailIncompleteFullDataSource implements IIncompleteFullDataSo
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
isPromoted = true;
|
||||
CompleteFullDataSource fullDataSource = CompleteFullDataSource.createEmpty(this.sectionPos);
|
||||
this.applyToFullDataSource(fullDataSource);
|
||||
return fullDataSource;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean hasBeenPromoted() {
|
||||
return isPromoted;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+9
-4
@@ -52,6 +52,7 @@ public class LowDetailIncompleteFullDataSource extends FullDataArrayAccessor imp
|
||||
|
||||
private boolean isEmpty = true;
|
||||
public EDhApiWorldGenerationStep worldGenStep = EDhApiWorldGenerationStep.EMPTY;
|
||||
private boolean isPromoted = false;
|
||||
|
||||
|
||||
|
||||
@@ -514,12 +515,16 @@ public class LowDetailIncompleteFullDataSource extends FullDataArrayAccessor imp
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
isPromoted = true;
|
||||
return new CompleteFullDataSource(this.sectionPos, this.mapping, this.dataArrays);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public boolean hasBeenPromoted() {
|
||||
return isPromoted;
|
||||
}
|
||||
|
||||
|
||||
//================//
|
||||
// helper classes //
|
||||
//================//
|
||||
|
||||
+2
-1
@@ -17,5 +17,6 @@ public interface IIncompleteFullDataSource extends IFullDataSource
|
||||
* @return a new {@link CompleteFullDataSource} if successful, this if the promotion failed, .
|
||||
*/
|
||||
IFullDataSource tryPromotingToCompleteDataSource();
|
||||
|
||||
|
||||
boolean hasBeenPromoted();
|
||||
}
|
||||
|
||||
+11
-8
@@ -3,6 +3,7 @@ package com.seibel.lod.core.dataObjects.render.bufferBuilding;
|
||||
import com.seibel.lod.core.pos.DhBlockPos2D;
|
||||
import com.seibel.lod.core.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.render.renderer.DebugRenderer;
|
||||
import com.seibel.lod.core.render.renderer.IDebugRenderable;
|
||||
import com.seibel.lod.core.render.renderer.LodRenderer;
|
||||
import com.seibel.lod.core.render.AbstractRenderBuffer;
|
||||
import com.seibel.lod.core.config.Config;
|
||||
@@ -27,7 +28,7 @@ import static com.seibel.lod.core.render.glObject.GLProxy.GL_LOGGER;
|
||||
*
|
||||
* @see ColumnRenderBufferBuilder
|
||||
*/
|
||||
public class ColumnRenderBuffer extends AbstractRenderBuffer
|
||||
public class ColumnRenderBuffer extends AbstractRenderBuffer implements IDebugRenderable
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
|
||||
@@ -55,14 +56,16 @@ public class ColumnRenderBuffer extends AbstractRenderBuffer
|
||||
this.debugPos = debugPos;
|
||||
vbos = new GLVertexBuffer[0];
|
||||
vbosTransparent = new GLVertexBuffer[0];
|
||||
DebugRenderer.register(this, (r) -> {
|
||||
if (closed || this.vbos == null) {
|
||||
return;
|
||||
}
|
||||
DebugRenderer.register(this);
|
||||
}
|
||||
|
||||
Color c = Color.green;
|
||||
r.renderBox(debugPos, -32, 32, c);
|
||||
});
|
||||
public void debugRender(DebugRenderer r)
|
||||
{
|
||||
if (closed || vbos == null) {
|
||||
return;
|
||||
}
|
||||
Color c = Color.green;
|
||||
//r.renderBox(debugPos, 128, 128, 0.05f, c);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -65,7 +65,7 @@ public class ColumnRenderBufferBuilder
|
||||
{
|
||||
try
|
||||
{
|
||||
boolean enableTransparency = Config.Client.Advanced.Graphics.Quality.transparency.get().tranparencyEnabled;
|
||||
boolean enableTransparency = Config.Client.Advanced.Graphics.Quality.transparency.get().transparencyEnabled;
|
||||
|
||||
EVENT_LOGGER.trace("RenderRegion start QuadBuild @ "+renderSource.sectionPos);
|
||||
boolean enableSkyLightCulling = Config.Client.Advanced.Graphics.AdvancedGraphics.enableCaveCulling.get();
|
||||
|
||||
+45
-7
@@ -1,5 +1,6 @@
|
||||
package com.seibel.lod.core.dataObjects.transformers;
|
||||
|
||||
import com.seibel.lod.api.enums.config.EBlocksToAvoid;
|
||||
import com.seibel.lod.core.dataObjects.fullData.FullDataPointIdMap;
|
||||
import com.seibel.lod.core.dataObjects.fullData.accessor.SingleColumnFullDataAccessor;
|
||||
import com.seibel.lod.core.dataObjects.fullData.sources.CompleteFullDataSource;
|
||||
@@ -235,9 +236,16 @@ public class FullDataToRenderDataTransformer
|
||||
|
||||
private static void iterateAndConvert(IDhClientLevel level, int blockX, int blockZ, int genMode, ColumnArrayView column, SingleColumnFullDataAccessor data)
|
||||
{
|
||||
FullDataPointIdMap mapping = data.getMapping();
|
||||
boolean avoidSolidBlocks = (Config.Client.Advanced.Graphics.Quality.blocksToIgnore.get() == EBlocksToAvoid.NON_COLLIDING);
|
||||
boolean colorBelowWithAvoidedBlocks = Config.Client.Advanced.Graphics.Quality.tintWithAvoidedBlocks.get();
|
||||
|
||||
FullDataPointIdMap fullDataMapping = data.getMapping();
|
||||
|
||||
boolean isVoid = true;
|
||||
int offset = 0;
|
||||
int colorToApplyToNextBlock = -1;
|
||||
int columnOffset = 0;
|
||||
|
||||
// goes from the top down
|
||||
for (int i = 0; i < data.getSingleLength(); i++)
|
||||
{
|
||||
long fullData = data.getSingle(i);
|
||||
@@ -245,20 +253,50 @@ public class FullDataToRenderDataTransformer
|
||||
int blockHeight = FullDataPointUtil.getHeight(fullData);
|
||||
int id = FullDataPointUtil.getId(fullData);
|
||||
int light = FullDataPointUtil.getLight(fullData);
|
||||
IBiomeWrapper biome = mapping.getBiomeWrapper(id);
|
||||
IBlockStateWrapper block = mapping.getBlockStateWrapper(id);
|
||||
IBiomeWrapper biome = fullDataMapping.getBiomeWrapper(id);
|
||||
IBlockStateWrapper block = fullDataMapping.getBlockStateWrapper(id);
|
||||
if (block.equals(AIR))
|
||||
{
|
||||
// we don't render air
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// solid block check
|
||||
if (avoidSolidBlocks && !block.isSolid() && !block.isLiquid())
|
||||
{
|
||||
if (colorBelowWithAvoidedBlocks)
|
||||
{
|
||||
colorToApplyToNextBlock = level.computeBaseColor(new DhBlockPos(blockX, bottomY + level.getMinY(), blockZ), biome, block);
|
||||
}
|
||||
|
||||
// don't add this block
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
int color;
|
||||
if (colorToApplyToNextBlock == -1)
|
||||
{
|
||||
// use this block's color
|
||||
color = level.computeBaseColor(new DhBlockPos(blockX, bottomY + level.getMinY(), blockZ), biome, block);
|
||||
}
|
||||
else
|
||||
{
|
||||
// use the previous block's color
|
||||
color = colorToApplyToNextBlock;
|
||||
colorToApplyToNextBlock = -1;
|
||||
}
|
||||
|
||||
|
||||
// add the block
|
||||
isVoid = false;
|
||||
int color = level.computeBaseColor(new DhBlockPos(blockX, bottomY + level.getMinY(), blockZ), biome, block);
|
||||
long columnData = RenderDataPointUtil.createDataPoint(bottomY + blockHeight, bottomY, color, light, genMode);
|
||||
column.set(offset, columnData);
|
||||
offset++;
|
||||
column.set(columnOffset, columnData);
|
||||
columnOffset++;
|
||||
}
|
||||
|
||||
|
||||
if (isVoid)
|
||||
{
|
||||
column.set(0, RenderDataPointUtil.createVoidDataPoint((byte) genMode));
|
||||
|
||||
@@ -168,28 +168,28 @@ public class FullDataFileHandler implements IFullDataSourceProvider
|
||||
* @param preexistingFiles the list of {@link FullDataMetaFile}'s that have been created for the given position.
|
||||
* @param missingFilePositions the list of {@link DhSectionPos}'s that don't have {@link FullDataMetaFile} created for them yet.
|
||||
*/
|
||||
protected void getDataFilesForPosition(DhSectionPos basePos, DhSectionPos pos,
|
||||
protected void getDataFilesForPosition(DhSectionPos effectivePos, DhSectionPos posAreaToGet,
|
||||
ArrayList<FullDataMetaFile> preexistingFiles, ArrayList<DhSectionPos> missingFilePositions)
|
||||
{
|
||||
byte sectionDetail = pos.sectionDetailLevel;
|
||||
byte sectionDetail = posAreaToGet.sectionDetailLevel;
|
||||
boolean allEmpty = true;
|
||||
|
||||
outerLoop:
|
||||
while (--sectionDetail >= this.minDetailLevel)
|
||||
{
|
||||
DhLodPos minPos = pos.getCorner().getCornerLodPos(sectionDetail);
|
||||
int count = pos.getSectionBBoxPos().getBlockWidth(sectionDetail);
|
||||
DhLodPos minPos = posAreaToGet.getCorner().getCornerLodPos(sectionDetail);
|
||||
int count = posAreaToGet.getSectionBBoxPos().getWidthAtDetail(sectionDetail);
|
||||
|
||||
for (int xOffset = 0; xOffset < count; xOffset++)
|
||||
{
|
||||
for (int zOffset = 0; zOffset < count; zOffset++)
|
||||
{
|
||||
DhSectionPos subPos = new DhSectionPos(sectionDetail, xOffset+minPos.x, zOffset+minPos.z);
|
||||
LodUtil.assertTrue(pos.overlaps(basePos) && subPos.overlaps(pos));
|
||||
LodUtil.assertTrue(posAreaToGet.overlaps(effectivePos) && subPos.overlaps(posAreaToGet));
|
||||
|
||||
//TODO: The following check is temporary as we only sample corner points, which means
|
||||
// on a very different level, we may not need the entire section at all.
|
||||
if (!CompleteFullDataSource.firstDataPosCanAffectSecond(basePos, subPos))
|
||||
if (!CompleteFullDataSource.firstDataPosCanAffectSecond(effectivePos, subPos))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -207,15 +207,15 @@ public class FullDataFileHandler implements IFullDataSourceProvider
|
||||
{
|
||||
// there are no children to this quad tree,
|
||||
// add this leaf's position
|
||||
missingFilePositions.add(pos);
|
||||
missingFilePositions.add(posAreaToGet);
|
||||
}
|
||||
else
|
||||
{
|
||||
// there are children in this quad tree, search them
|
||||
this.recursiveGetDataFilesForPosition(0, basePos, pos, preexistingFiles, missingFilePositions);
|
||||
this.recursiveGetDataFilesForPosition(1, basePos, pos, preexistingFiles, missingFilePositions);
|
||||
this.recursiveGetDataFilesForPosition(2, basePos, pos, preexistingFiles, missingFilePositions);
|
||||
this.recursiveGetDataFilesForPosition(3, basePos, pos, preexistingFiles, missingFilePositions);
|
||||
this.recursiveGetDataFilesForPosition(0, effectivePos, posAreaToGet, preexistingFiles, missingFilePositions);
|
||||
this.recursiveGetDataFilesForPosition(1, effectivePos, posAreaToGet, preexistingFiles, missingFilePositions);
|
||||
this.recursiveGetDataFilesForPosition(2, effectivePos, posAreaToGet, preexistingFiles, missingFilePositions);
|
||||
this.recursiveGetDataFilesForPosition(3, effectivePos, posAreaToGet, preexistingFiles, missingFilePositions);
|
||||
}
|
||||
}
|
||||
private void recursiveGetDataFilesForPosition(int childIndex, DhSectionPos basePos, DhSectionPos pos, ArrayList<FullDataMetaFile> preexistingFiles, ArrayList<DhSectionPos> missingFilePositions)
|
||||
@@ -403,7 +403,7 @@ public class FullDataFileHandler implements IFullDataSourceProvider
|
||||
|
||||
@Override
|
||||
public IFullDataSource onDataFileLoaded(IFullDataSource source, BaseMetaData metaData,
|
||||
Consumer<IFullDataSource> onUpdated, Function<IFullDataSource, Boolean> updater)
|
||||
Consumer<IFullDataSource> onUpdated, Function<IFullDataSource, Boolean> updater, boolean justCreated)
|
||||
{
|
||||
boolean changed = updater.apply(source);
|
||||
// if (changed)
|
||||
|
||||
@@ -163,7 +163,7 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile
|
||||
this.baseMetaData = this._makeBaseMetaData(fullDataSource);
|
||||
return fullDataSource;
|
||||
})
|
||||
.thenApply((fullDataSource) -> this.fullDataSourceProvider.onDataFileLoaded(fullDataSource, this.baseMetaData, this::_updateAndWriteDataSource, this::_applyWriteQueueToFullDataSource))
|
||||
.thenApply((fullDataSource) -> this.fullDataSourceProvider.onDataFileLoaded(fullDataSource, this.baseMetaData, this::_updateAndWriteDataSource, this::_applyWriteQueueToFullDataSource, true))
|
||||
.whenComplete((fullDataSource, exception) ->
|
||||
{
|
||||
if (exception != null)
|
||||
@@ -225,7 +225,7 @@ public class FullDataMetaFile extends AbstractMetaDataContainerFile
|
||||
"loading one into the cache! Is this a deadlock?");
|
||||
|
||||
// fire the onDataLoaded method
|
||||
fullDataSource = this.fullDataSourceProvider.onDataFileLoaded(fullDataSource, this.baseMetaData, this::_updateAndWriteDataSource, this::_applyWriteQueueToFullDataSource);
|
||||
fullDataSource = this.fullDataSourceProvider.onDataFileLoaded(fullDataSource, this.baseMetaData, this::_updateAndWriteDataSource, this::_applyWriteQueueToFullDataSource, false);
|
||||
return fullDataSource;
|
||||
|
||||
}, executorService)
|
||||
|
||||
+153
-6
@@ -1,10 +1,12 @@
|
||||
package com.seibel.lod.core.file.fullDatafile;
|
||||
|
||||
import com.seibel.lod.core.dataObjects.fullData.accessor.ChunkSizedFullDataAccessor;
|
||||
import com.seibel.lod.core.dataObjects.fullData.sources.CompleteFullDataSource;
|
||||
import com.seibel.lod.core.dataObjects.fullData.sources.HighDetailIncompleteFullDataSource;
|
||||
import com.seibel.lod.core.dataObjects.fullData.sources.interfaces.IFullDataSource;
|
||||
import com.seibel.lod.core.dataObjects.fullData.sources.interfaces.IIncompleteFullDataSource;
|
||||
import com.seibel.lod.core.dataObjects.fullData.sources.LowDetailIncompleteFullDataSource;
|
||||
import com.seibel.lod.core.file.metaData.BaseMetaData;
|
||||
import com.seibel.lod.core.generation.tasks.IWorldGenTaskTracker;
|
||||
import com.seibel.lod.core.generation.WorldGenerationQueue;
|
||||
import com.seibel.lod.core.generation.tasks.WorldGenResult;
|
||||
@@ -15,12 +17,16 @@ import com.seibel.lod.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.lod.core.util.LodUtil;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.File;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class GeneratedFullDataFileHandler extends FullDataFileHandler
|
||||
{
|
||||
@@ -49,7 +55,7 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler
|
||||
{
|
||||
return super.read(pos).whenComplete((fullDataSource, ex) ->
|
||||
{
|
||||
this.checkIfSectionNeedsAdditionalGeneration(pos, fullDataSource);
|
||||
//this.checkIfSectionNeedsAdditionalGeneration(pos, fullDataSource);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -83,11 +89,125 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler
|
||||
//========//
|
||||
// events //
|
||||
//========//
|
||||
|
||||
private CompletableFuture<IFullDataSource> spawnGenTasks(FullDataMetaFile file, @Nullable IIncompleteFullDataSource data)
|
||||
{
|
||||
DhSectionPos pos = file.pos;
|
||||
|
||||
ArrayList<FullDataMetaFile> existingFiles = new ArrayList<>();
|
||||
ArrayList<DhSectionPos> missingPositions = new ArrayList<>();
|
||||
this.getDataFilesForPosition(pos, pos, existingFiles, missingPositions);
|
||||
|
||||
// confirm the quad tree has at least one node in it
|
||||
LodUtil.assertTrue(!missingPositions.isEmpty() || !existingFiles.isEmpty());
|
||||
|
||||
|
||||
|
||||
// determine the type of dataSource that should be used for this position
|
||||
IIncompleteFullDataSource incompleteFullDataSource;
|
||||
if (data == null)
|
||||
{
|
||||
if (pos.sectionDetailLevel <= HighDetailIncompleteFullDataSource.MAX_SECTION_DETAIL)
|
||||
{
|
||||
incompleteFullDataSource = HighDetailIncompleteFullDataSource.createEmpty(pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
incompleteFullDataSource = LowDetailIncompleteFullDataSource.createEmpty(pos);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
incompleteFullDataSource = data;
|
||||
}
|
||||
|
||||
// breaks down the missing positions into the desired detail level that the gen queue could accept
|
||||
byte maxSectDataDetailLevel = worldGenQueueRef.get().largestDataDetail;
|
||||
byte targetDataDetailLevel = incompleteFullDataSource.getDataDetailLevel();
|
||||
if (targetDataDetailLevel > maxSectDataDetailLevel) {
|
||||
byte sectDetailLevel = (byte) (DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL + maxSectDataDetailLevel);
|
||||
missingPositions = missingPositions.stream()
|
||||
.flatMap(missingPos -> {
|
||||
if (missingPos.sectionDetailLevel > sectDetailLevel) {
|
||||
// split this position into smaller positions
|
||||
ArrayList<DhSectionPos> splitPositions = new ArrayList<>();
|
||||
missingPos.forEachChildAtLevel(sectDetailLevel, splitPositions::add);
|
||||
return splitPositions.stream();
|
||||
}
|
||||
else {
|
||||
return Stream.of(missingPos);
|
||||
}
|
||||
})
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
}
|
||||
|
||||
if (missingPositions.size() == 1 && existingFiles.isEmpty() && missingPositions.get(0).equals(pos))
|
||||
{
|
||||
// No LOD data exists for this position yet
|
||||
|
||||
WorldGenerationQueue worldGenQueue = this.worldGenQueueRef.get();
|
||||
if (worldGenQueue != null)
|
||||
{
|
||||
this.incompleteSourceGenRequests.add(pos);
|
||||
|
||||
// queue this section to be generated
|
||||
GenTask genTask = new GenTask(pos, new WeakReference<>(incompleteFullDataSource));
|
||||
worldGenQueue.submitGenTask(new DhLodPos(pos), incompleteFullDataSource.getDataDetailLevel(), genTask)
|
||||
.whenComplete((genTaskResult, ex) ->
|
||||
{
|
||||
this.onWorldGenTaskComplete(genTaskResult, ex, genTask, pos);
|
||||
this.fireOnGenPosSuccessListeners(pos);
|
||||
this.incompleteSourceGenRequests.remove(pos);
|
||||
});
|
||||
}
|
||||
|
||||
// return the empty dataSource (it will be populated later)
|
||||
return CompletableFuture.completedFuture(incompleteFullDataSource);
|
||||
}
|
||||
else
|
||||
{
|
||||
// LOD data exists for this position
|
||||
|
||||
// create the missing metaData files
|
||||
for (DhSectionPos missingPos : missingPositions)
|
||||
{
|
||||
FullDataMetaFile newFile = this.getOrMakeFile(missingPos);
|
||||
if (newFile != null)
|
||||
{
|
||||
existingFiles.add(newFile);
|
||||
}
|
||||
}
|
||||
|
||||
// LOGGER.debug("Creating "+pos+" from sampling "+existingFiles.size()+" files: "+existingFiles);
|
||||
|
||||
// read in the existing data
|
||||
final ArrayList<CompletableFuture<Void>> loadDataFutures = new ArrayList<>(existingFiles.size());
|
||||
for (FullDataMetaFile existingFile : existingFiles)
|
||||
{
|
||||
loadDataFutures.add(existingFile.loadOrGetCachedDataSourceAsync()
|
||||
.exceptionally((ex) -> /*Ignore file read errors*/null)
|
||||
.thenAccept((fullDataSource) ->
|
||||
{
|
||||
if (fullDataSource == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
//this.checkIfSectionNeedsAdditionalGeneration(pos, fullDataSource);
|
||||
//LOGGER.info("Merging data from {} into {}", data.getSectionPos(), pos);
|
||||
incompleteFullDataSource.sampleFrom(fullDataSource);
|
||||
})
|
||||
);
|
||||
}
|
||||
return CompletableFuture.allOf(loadDataFutures.toArray(new CompletableFuture[0]))
|
||||
.thenApply((voidValue) -> incompleteFullDataSource.tryPromotingToCompleteDataSource());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<IFullDataSource> onCreateDataFile(FullDataMetaFile file)
|
||||
{
|
||||
DhSectionPos pos = file.pos;
|
||||
return this.spawnGenTasks(file, null);
|
||||
/* DhSectionPos pos = file.pos;
|
||||
|
||||
ArrayList<FullDataMetaFile> existingFiles = new ArrayList<>();
|
||||
ArrayList<DhSectionPos> missingPositions = new ArrayList<>();
|
||||
@@ -153,7 +273,7 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler
|
||||
for (FullDataMetaFile existingFile : existingFiles)
|
||||
{
|
||||
loadDataFutures.add(existingFile.loadOrGetCachedDataSourceAsync()
|
||||
.exceptionally((ex) -> /*Ignore file read errors*/null)
|
||||
.exceptionally((ex) -> *//*Ignore file read errors*//*null)
|
||||
.thenAccept((fullDataSource) ->
|
||||
{
|
||||
if (fullDataSource == null)
|
||||
@@ -171,9 +291,32 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler
|
||||
|
||||
return CompletableFuture.allOf(loadDataFutures.toArray(new CompletableFuture[0]))
|
||||
.thenApply((voidValue) -> incompleteFullDataSource.tryPromotingToCompleteDataSource());
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
@Override
|
||||
public IFullDataSource onDataFileLoaded(IFullDataSource source, BaseMetaData metaData,
|
||||
Consumer<IFullDataSource> onUpdated, Function<IFullDataSource, Boolean> updater, boolean justCreated)
|
||||
{
|
||||
IFullDataSource fullDataSource = super.onDataFileLoaded(source, metaData, onUpdated, updater, justCreated);
|
||||
if (fullDataSource instanceof CompleteFullDataSource || justCreated) {
|
||||
return fullDataSource;
|
||||
}
|
||||
|
||||
this.spawnGenTasks(getOrMakeFile(metaData.pos), (IIncompleteFullDataSource)fullDataSource);
|
||||
//checkIfSectionNeedsAdditionalGeneration(metaData.pos, fullDataSource);
|
||||
return fullDataSource;
|
||||
}
|
||||
|
||||
/* @Override
|
||||
public CompletableFuture<IFullDataSource> onDataFileRefresh(IFullDataSource source, BaseMetaData metaData, Function<IFullDataSource, Boolean> updater, Consumer<IFullDataSource> onUpdated)
|
||||
{
|
||||
return super.onDataFileRefresh(source, metaData, updater, (IFullDataSource d) -> {
|
||||
if (d instanceof CompleteFullDataSource) {
|
||||
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
/**
|
||||
* Checks if the given {@link IFullDataSource} is fully generated and
|
||||
* if it isn't, creates the necessary world gen request(s) to finish it. <br>
|
||||
@@ -217,6 +360,7 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler
|
||||
// don't queue the same section twice
|
||||
if (this.incompleteSourceGenRequests.contains(ungenChildPos))
|
||||
{
|
||||
LOGGER.warn("checkIfSectionNeedsAdditionalGeneration skipping duplicate gen request for pos: ["+ungenChildPos+"].");
|
||||
continue;
|
||||
}
|
||||
this.incompleteSourceGenRequests.add(ungenChildPos);
|
||||
@@ -351,7 +495,10 @@ public class GeneratedFullDataFileHandler extends FullDataFileHandler
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isMemoryAddressValid() { return this.targetFullDataSourceRef.get() != null; }
|
||||
public boolean isMemoryAddressValid() {
|
||||
IFullDataSource ref = this.targetFullDataSourceRef.get();
|
||||
return ref != null && !((IIncompleteFullDataSource)ref).hasBeenPromoted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Consumer<ChunkSizedFullDataAccessor> getOnGenTaskCompleteConsumer()
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ public interface IFullDataSourceProvider extends AutoCloseable
|
||||
//boolean isCacheVersionValid(DhSectionPos sectionPos, long cacheVersion);
|
||||
|
||||
CompletableFuture<IFullDataSource> onCreateDataFile(FullDataMetaFile file);
|
||||
IFullDataSource onDataFileLoaded(IFullDataSource source, BaseMetaData metaData, Consumer<IFullDataSource> onUpdated, Function<IFullDataSource, Boolean> updater);
|
||||
IFullDataSource onDataFileLoaded(IFullDataSource source, BaseMetaData metaData, Consumer<IFullDataSource> onUpdated, Function<IFullDataSource, Boolean> updater, boolean justCreated);
|
||||
CompletableFuture<IFullDataSource> onDataFileRefresh(IFullDataSource source, BaseMetaData metaData, Function<IFullDataSource, Boolean> updater, Consumer<IFullDataSource> onUpdated);
|
||||
File computeDataFilePath(DhSectionPos pos);
|
||||
ExecutorService getIOExecutor();
|
||||
|
||||
@@ -10,6 +10,8 @@ import com.seibel.lod.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.lod.core.file.fullDatafile.FullDataFileHandler;
|
||||
import com.seibel.lod.core.generation.tasks.*;
|
||||
import com.seibel.lod.core.pos.*;
|
||||
import com.seibel.lod.core.render.renderer.DebugRenderer;
|
||||
import com.seibel.lod.core.render.renderer.IDebugRenderable;
|
||||
import com.seibel.lod.core.util.ThreadUtil;
|
||||
import com.seibel.lod.core.util.objects.quadTree.QuadNode;
|
||||
import com.seibel.lod.core.util.objects.quadTree.QuadTree;
|
||||
@@ -20,12 +22,13 @@ import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory;
|
||||
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.Closeable;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class WorldGenerationQueue implements Closeable
|
||||
public class WorldGenerationQueue implements Closeable, IDebugRenderable
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
|
||||
@@ -41,7 +44,7 @@ public class WorldGenerationQueue implements Closeable
|
||||
public final byte minGranularity;
|
||||
|
||||
/** largest numerical detail level allowed */
|
||||
final byte largestDataDetail;
|
||||
public final byte largestDataDetail;
|
||||
/** lowest numerical detail level allowed */
|
||||
public final byte smallestDataDetail;
|
||||
|
||||
@@ -62,7 +65,7 @@ public class WorldGenerationQueue implements Closeable
|
||||
// debug variables to test for duplicate world generator requests //
|
||||
/** limits how many of the previous world gen requests we should track */
|
||||
private static final int MAX_ALREADY_GENERATED_COUNT = 100;
|
||||
private final HashSet<DhLodPos> alreadyGeneratedPosHashSet = new HashSet<>(MAX_ALREADY_GENERATED_COUNT);
|
||||
private final HashMap<DhLodPos, StackTraceElement[]> alreadyGeneratedPosHashSet = new HashMap<>(MAX_ALREADY_GENERATED_COUNT);
|
||||
private final Queue<DhLodPos> alreadyGeneratedPosQueue = new LinkedList<>();
|
||||
|
||||
private static ExecutorService worldGeneratorThreadPool;
|
||||
@@ -95,6 +98,7 @@ public class WorldGenerationQueue implements Closeable
|
||||
{
|
||||
throw new IllegalArgumentException(IDhApiWorldGenerator.class.getSimpleName() + ": max granularity smaller than min granularity!");
|
||||
}
|
||||
DebugRenderer.register(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -242,7 +246,9 @@ public class WorldGenerationQueue implements Closeable
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
private final Set<WorldGenTask> CheckingTasks = Collections.newSetFromMap(new ConcurrentHashMap<>());
|
||||
|
||||
/**
|
||||
* @param targetPos the position to center the generation around
|
||||
* @return false if no tasks were found to generate
|
||||
@@ -252,6 +258,7 @@ public class WorldGenerationQueue implements Closeable
|
||||
long closestGenDist = Long.MAX_VALUE;
|
||||
|
||||
WorldGenTask closestTask = null;
|
||||
CheckingTasks.clear();
|
||||
|
||||
// TODO improve, having to go over every node isn't super efficient, removing null nodes from the tree would help
|
||||
Iterator<QuadNode<WorldGenTask>> nodeIterator = this.waitingTaskQuadTree.nodeIterator();
|
||||
@@ -263,10 +270,10 @@ public class WorldGenerationQueue implements Closeable
|
||||
|
||||
if (newGenTask != null) // TODO add an option to skip leaves with null values and potentially auto-prune them
|
||||
{
|
||||
// TODO this isn't a long term fix, in the long term the tree should automatically remove out of bound nodes when moved
|
||||
if (!this.waitingTaskQuadTree.isSectionPosInBounds(taskSectionPos))
|
||||
CheckingTasks.add(newGenTask);
|
||||
if (!newGenTask.StillValid())
|
||||
{
|
||||
// skip and remove out-of-bound tasks
|
||||
// skip and remove out-of-bound tasks or tasks that are no longer valid
|
||||
taskNode.value = null;
|
||||
continue;
|
||||
}
|
||||
@@ -289,14 +296,9 @@ public class WorldGenerationQueue implements Closeable
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// remove the task we found, we are going to start it and don't want to run it multiple times
|
||||
// TODO the setValue can fail if the user is moving and the task that was once in range is no longer in range
|
||||
WorldGenTask removedWorldGenTask = this.waitingTaskQuadTree.setValue(new DhSectionPos(closestTask.pos.detailLevel, closestTask.pos.x, closestTask.pos.z), null);
|
||||
|
||||
|
||||
|
||||
// do we need to modify this task to generate it?
|
||||
if(this.canGeneratePos((byte) 0, closestTask.pos)) // TODO should detail level 0 be replaced?
|
||||
{
|
||||
@@ -318,6 +320,8 @@ public class WorldGenerationQueue implements Closeable
|
||||
// Note: Due to concurrency reasons, even if the currently running task is compatible with
|
||||
// the newly selected task, we cannot use it,
|
||||
// as some chunks may have already been written into.
|
||||
|
||||
LOGGER.warn("A task already exists for this position, todo: {}", closestTask.pos);
|
||||
}
|
||||
|
||||
// a task has been started
|
||||
@@ -334,13 +338,6 @@ public class WorldGenerationQueue implements Closeable
|
||||
DhSectionPos sectionPos = new DhSectionPos(closestTask.pos.detailLevel, closestTask.pos.x, closestTask.pos.z);
|
||||
sectionPos.forEachChild((childDhSectionPos) ->
|
||||
{
|
||||
if (!this.waitingTaskQuadTree.isSectionPosInBounds(childDhSectionPos))
|
||||
{
|
||||
// don't attempt to generate terrain outside the user's render distance
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
CompletableFuture<WorldGenResult> newFuture = new CompletableFuture<>();
|
||||
childFutures.add(newFuture);
|
||||
|
||||
@@ -371,18 +368,19 @@ public class WorldGenerationQueue implements Closeable
|
||||
|
||||
DhChunkPos chunkPosMin = new DhChunkPos(taskPos.getCornerBlockPos());
|
||||
|
||||
|
||||
// check if this is a duplicate generation task
|
||||
if (this.alreadyGeneratedPosHashSet.contains(inProgressTaskGroup.group.pos))
|
||||
if (this.alreadyGeneratedPosHashSet.containsKey(inProgressTaskGroup.group.pos))
|
||||
{
|
||||
// temporary solution to prevent generating the same section multiple times
|
||||
LOGGER.warn("Duplicate generation section " + taskPos + " with granularity [" + granularity + "] at " + chunkPosMin + ". Skipping...");
|
||||
|
||||
|
||||
StackTraceElement[] stackTrace = this.alreadyGeneratedPosHashSet.get(inProgressTaskGroup.group.pos);
|
||||
|
||||
// sending a success result is necessary to make sure the render sections are reloaded correctly
|
||||
inProgressTaskGroup.group.worldGenTasks.forEach(worldGenTask -> worldGenTask.future.complete(WorldGenResult.CreateSuccess(new DhSectionPos(granularity, taskPos))));
|
||||
return;
|
||||
}
|
||||
this.alreadyGeneratedPosHashSet.add(inProgressTaskGroup.group.pos);
|
||||
this.alreadyGeneratedPosHashSet.put(inProgressTaskGroup.group.pos, Thread.currentThread().getStackTrace());
|
||||
this.alreadyGeneratedPosQueue.add(inProgressTaskGroup.group.pos);
|
||||
|
||||
// remove extra tracked duplicate positions
|
||||
@@ -578,6 +576,8 @@ public class WorldGenerationQueue implements Closeable
|
||||
|
||||
|
||||
LOGGER.info("Finished closing "+WorldGenerationQueue.class.getSimpleName());
|
||||
|
||||
DebugRenderer.unregister(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -616,6 +616,16 @@ public class WorldGenerationQueue implements Closeable
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void debugRender(DebugRenderer r) {
|
||||
CheckingTasks.forEach((t) -> {
|
||||
DhLodPos pos = t.pos;
|
||||
r.renderBox(pos, -32f, 128f, 0.05f, Color.blue);
|
||||
});
|
||||
this.inProgressGenTasksByLodPos.forEach((pos, t) -> {
|
||||
r.renderBox(pos, -30f, 128f, 0.05f, Color.red);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,5 +25,8 @@ public final class WorldGenTask
|
||||
this.taskTracker = taskTracker;
|
||||
this.future = future;
|
||||
}
|
||||
|
||||
|
||||
public boolean StillValid() {
|
||||
return taskTracker.isMemoryAddressValid();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,6 +84,8 @@ public abstract class AbstractDhClientLevel implements IDhClientLevel
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO this should probably be handled via a config change listener
|
||||
// recreate the RenderState if the render distance changes
|
||||
if (clientRenderState.quadtree.blockRenderDistance != Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistance.get() * LodUtil.CHUNK_WIDTH)
|
||||
{
|
||||
if (!this.ClientRenderStateRef.compareAndSet(clientRenderState, null))
|
||||
|
||||
@@ -39,19 +39,22 @@ public class DhLodPos implements Comparable<DhLodPos>
|
||||
|
||||
public DhLodUnit getX() { return new DhLodUnit(this.detailLevel, this.x); }
|
||||
public DhLodUnit getZ() { return new DhLodUnit(this.detailLevel, this.z); }
|
||||
|
||||
public int getBlockWidth() { return this.getBlockWidth(this.detailLevel); }
|
||||
public int getBlockWidth(byte detailLevel) // TODO this needs some documentation or a better name describing what is happening, why is there an assert here?
|
||||
|
||||
// Get the width of this pos, measured in the mc block unit. (i.e. detail 0)
|
||||
public int getBlockWidth() { return this.getWidthAtDetail((byte)0); }
|
||||
|
||||
// Get the width of this pos, measured in the target detail level.
|
||||
public int getWidthAtDetail(byte targetLevel)
|
||||
{
|
||||
LodUtil.assertTrue(detailLevel <= this.detailLevel);
|
||||
return BitShiftUtil.powerOfTwo(this.detailLevel - detailLevel);
|
||||
LodUtil.assertTrue(targetLevel <= this.detailLevel);
|
||||
return BitShiftUtil.powerOfTwo(this.detailLevel - targetLevel);
|
||||
}
|
||||
|
||||
public DhBlockPos2D getCenterBlockPos()
|
||||
{
|
||||
return new DhBlockPos2D(
|
||||
this.getX().toBlockWidth() + BitShiftUtil.half(this.getBlockWidth()),
|
||||
this.getZ().toBlockWidth() + BitShiftUtil.half(this.getBlockWidth()));
|
||||
this.getZ().toBlockWidth() + BitShiftUtil.half(this.getBlockWidth()));
|
||||
}
|
||||
public DhBlockPos2D getCornerBlockPos() { return new DhBlockPos2D(this.getX().toBlockWidth(), this.getZ().toBlockWidth()); }
|
||||
|
||||
|
||||
@@ -167,6 +167,20 @@ public class DhSectionPos
|
||||
callback.accept(this.getChildByIndex(i));
|
||||
}
|
||||
}
|
||||
|
||||
/** Applies the given consumer to all children of the position at the given section detail level. */
|
||||
public void forEachChildAtLevel(byte sectionDetailLevel, Consumer<DhSectionPos> callback)
|
||||
{
|
||||
if (sectionDetailLevel == this.sectionDetailLevel)
|
||||
{
|
||||
callback.accept(this);
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
this.getChildByIndex(i).forEachChildAtLevel(sectionDetailLevel, callback);
|
||||
}
|
||||
}
|
||||
|
||||
public DhSectionPos getParentPos() { return new DhSectionPos((byte) (this.sectionDetailLevel + 1), BitShiftUtil.half(this.sectionX), BitShiftUtil.half(this.sectionZ)); }
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package com.seibel.lod.core.render;
|
||||
|
||||
import com.seibel.lod.api.enums.config.EHorizontalQuality;
|
||||
import com.seibel.lod.core.config.Config;
|
||||
import com.seibel.lod.core.config.listeners.ConfigChangeListener;
|
||||
import com.seibel.lod.core.dataObjects.render.ColumnRenderSource;
|
||||
import com.seibel.lod.core.level.IDhClientLevel;
|
||||
import com.seibel.lod.core.pos.DhBlockPos2D;
|
||||
@@ -7,14 +10,13 @@ import com.seibel.lod.core.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.file.renderfile.ILodRenderSourceProvider;
|
||||
import com.seibel.lod.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.lod.core.util.DetailDistanceUtil;
|
||||
import com.seibel.lod.core.util.LodUtil;
|
||||
import com.seibel.lod.core.util.objects.quadTree.QuadNode;
|
||||
import com.seibel.lod.core.util.objects.quadTree.QuadTree;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
/**
|
||||
* This quadTree structure is our core data structure and holds
|
||||
@@ -31,12 +33,14 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements AutoClose
|
||||
|
||||
/**
|
||||
* This holds every {@link DhSectionPos} that should be reloaded next tick. <br>
|
||||
* This is a {@link ConcurrentHashMap} because new sections can be added to this list via the world generator threads.
|
||||
* This is a {@link ConcurrentLinkedQueue} because new sections can be added to this list via the world generator threads.
|
||||
*/
|
||||
private final ConcurrentHashMap<DhSectionPos, Boolean> sectionsToReload = new ConcurrentHashMap<>();
|
||||
private final ConcurrentLinkedQueue<DhSectionPos> sectionsToReload = new ConcurrentLinkedQueue<>();
|
||||
|
||||
private final IDhClientLevel level; //FIXME: Proper hierarchy to remove this reference!
|
||||
|
||||
private final ConfigChangeListener<EHorizontalQuality> horizontalScaleChangeListener;
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -52,6 +56,7 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements AutoClose
|
||||
this.renderSourceProvider = provider;
|
||||
this.blockRenderDistance = viewDistanceInBlocks;
|
||||
|
||||
this.horizontalScaleChangeListener = new ConfigChangeListener<>(Config.Client.Advanced.Graphics.Quality.horizontalQuality, (newHorizontalScale) -> this.onHorizontalQualityChange());
|
||||
}
|
||||
|
||||
|
||||
@@ -76,7 +81,7 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements AutoClose
|
||||
try
|
||||
{
|
||||
// recenter if necessary, removing out of bounds sections
|
||||
this.setCenterBlockPos(playerPos, LodRenderSection::disposeRenderData);
|
||||
this.setCenterBlockPos(playerPos, LodRenderSection::dispose);
|
||||
|
||||
updateAllRenderSections(playerPos);
|
||||
}
|
||||
@@ -88,12 +93,11 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements AutoClose
|
||||
private void updateAllRenderSections(DhBlockPos2D playerPos)
|
||||
{
|
||||
// reload any sections that need it
|
||||
DhSectionPos[] reloadSectionArray = this.sectionsToReload.keySet().toArray(new DhSectionPos[0]);
|
||||
this.sectionsToReload.clear();
|
||||
for (DhSectionPos pos : reloadSectionArray)
|
||||
DhSectionPos pos;
|
||||
while ((pos = this.sectionsToReload.poll()) != null)
|
||||
{
|
||||
// walk up the tree until we hit the root node
|
||||
// this is done so any high detail changes flow up to the lower detail render sections as well
|
||||
// this is done so any high detail changes flow up to the lower detail render sections as well
|
||||
while (pos.sectionDetailLevel <= this.treeMaxDetailLevel)
|
||||
{
|
||||
try
|
||||
@@ -106,12 +110,11 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements AutoClose
|
||||
}
|
||||
catch (IndexOutOfBoundsException e)
|
||||
{ /* the section is now out of bounds, it doesn't need to be reloaded */ }
|
||||
|
||||
|
||||
pos = pos.getParentPos();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// walk through each root node
|
||||
Iterator<DhSectionPos> rootPosIterator = this.rootNodePosIterator();
|
||||
while (rootPosIterator.hasNext())
|
||||
@@ -348,7 +351,33 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements AutoClose
|
||||
}
|
||||
|
||||
//LOGGER.info("LodQuadTree reloadPos ["+pos+"].");
|
||||
this.sectionsToReload.put(pos, true);
|
||||
this.sectionsToReload.add(pos);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==================//
|
||||
// config listeners //
|
||||
//==================//
|
||||
|
||||
private void onHorizontalQualityChange()
|
||||
{
|
||||
// TODO this Util should probably be somewhere else or handled differently, but it works for now
|
||||
// Updating this util is necessary whenever the horizontal quality is changed, since it handles the detail drop-off
|
||||
DetailDistanceUtil.updateSettings();
|
||||
|
||||
|
||||
// flush the current render data to make sure the new settings are used
|
||||
Iterator<QuadNode<LodRenderSection>> nodeIterator = this.nodeIterator();
|
||||
while (nodeIterator.hasNext())
|
||||
{
|
||||
QuadNode<LodRenderSection> quadNode = nodeIterator.next();
|
||||
if (quadNode.value != null)
|
||||
{
|
||||
quadNode.value.disposeRenderData();
|
||||
quadNode.value = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -375,6 +404,8 @@ public class LodQuadTree extends QuadTree<LodRenderSection> implements AutoClose
|
||||
{
|
||||
LOGGER.info("Shutting down "+ LodQuadTree.class.getSimpleName()+"...");
|
||||
|
||||
this.horizontalScaleChangeListener.close();
|
||||
|
||||
Iterator<QuadNode<LodRenderSection>> nodeIterator = this.nodeIterator();
|
||||
while (nodeIterator.hasNext())
|
||||
{
|
||||
|
||||
@@ -6,8 +6,12 @@ import com.seibel.lod.core.level.IDhClientLevel;
|
||||
import com.seibel.lod.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.lod.core.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.file.renderfile.ILodRenderSourceProvider;
|
||||
import com.seibel.lod.core.render.renderer.DebugRenderer;
|
||||
import com.seibel.lod.core.render.renderer.IDebugRenderable;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@@ -15,7 +19,7 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||
* A render section represents an area that could be rendered.
|
||||
* For more information see {@link LodQuadTree}.
|
||||
*/
|
||||
public class LodRenderSection
|
||||
public class LodRenderSection implements IDebugRenderable
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
|
||||
@@ -38,7 +42,30 @@ public class LodRenderSection
|
||||
|
||||
|
||||
|
||||
public LodRenderSection(DhSectionPos pos) { this.pos = pos; }
|
||||
public LodRenderSection(DhSectionPos pos) {
|
||||
this.pos = pos;
|
||||
|
||||
DebugRenderer.register(this);
|
||||
}
|
||||
|
||||
public void debugRender(DebugRenderer r)
|
||||
{
|
||||
Color color = Color.red;
|
||||
|
||||
if (this.renderSourceProvider == null) color = Color.black;
|
||||
|
||||
if (this.renderSourceLoadFuture != null) color = Color.yellow;
|
||||
|
||||
if (renderSource != null) {
|
||||
color = Color.blue;
|
||||
if (isRenderingEnabled) color = Color.cyan;
|
||||
if (isRenderingEnabled && isRenderDataLoaded()) color = Color.green;
|
||||
}
|
||||
|
||||
float yOffset = Objects.hashCode(this) / (float) Integer.MAX_VALUE * 16f;
|
||||
|
||||
//r.renderBox(this.pos, yOffset, yOffset, 0.1f, color);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -160,6 +187,8 @@ public class LodRenderSection
|
||||
this.renderSourceLoadFuture.cancel(true);
|
||||
this.renderSourceLoadFuture = null;
|
||||
}
|
||||
|
||||
this.renderSourceProvider = null;
|
||||
}
|
||||
|
||||
|
||||
@@ -208,5 +237,9 @@ public class LodRenderSection
|
||||
", isRenderEnabled=" + this.isRenderingEnabled +
|
||||
'}';
|
||||
}
|
||||
|
||||
|
||||
public void dispose() {
|
||||
DebugRenderer.unregister(this);
|
||||
disposeRenderData();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@ import com.seibel.lod.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.lod.core.logging.ConfigBasedLogger;
|
||||
import com.seibel.lod.core.logging.ConfigBasedSpamLogger;
|
||||
import com.seibel.lod.core.pos.DhBlockPos2D;
|
||||
import com.seibel.lod.core.pos.DhLodPos;
|
||||
import com.seibel.lod.core.pos.DhSectionPos;
|
||||
import com.seibel.lod.core.render.glObject.GLProxy;
|
||||
import com.seibel.lod.core.render.glObject.GLState;
|
||||
import com.seibel.lod.core.render.glObject.buffer.GLElementBuffer;
|
||||
import com.seibel.lod.core.render.glObject.buffer.GLVertexBuffer;
|
||||
@@ -22,11 +22,10 @@ import org.apache.logging.log4j.LogManager;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
|
||||
import java.awt.*;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.*;
|
||||
|
||||
public class DebugRenderer {
|
||||
public static DebugRenderer INSTANCE = new DebugRenderer();
|
||||
@@ -74,12 +73,34 @@ public class DebugRenderer {
|
||||
VertexAttribute va;
|
||||
boolean init = false;
|
||||
|
||||
public static void unregister(IDebugRenderable r) {
|
||||
if (INSTANCE == null) return;
|
||||
INSTANCE.removeRenderer(r);
|
||||
}
|
||||
|
||||
private void removeRenderer(IDebugRenderable r) {
|
||||
synchronized (renderers) {
|
||||
Iterator<WeakReference<IDebugRenderable>> it = renderers.iterator();
|
||||
while (it.hasNext()) {
|
||||
WeakReference<IDebugRenderable> ref = it.next();
|
||||
if (ref.get() == null) {
|
||||
it.remove();
|
||||
continue;
|
||||
}
|
||||
if (ref.get() == r) {
|
||||
it.remove();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void init() {
|
||||
if (init) return;
|
||||
init = true;
|
||||
va = VertexAttribute.create();
|
||||
va.bind();
|
||||
// Pos
|
||||
// Pos\
|
||||
va.setVertexAttribute(0, 0, VertexAttribute.VertexPointer.addVec3Pointer(false));
|
||||
va.completeAndCheck(Float.BYTES * 3);
|
||||
basicShader = new ShaderProgram("shaders/debug/vert.vert", "shaders/debug/frag.frag",
|
||||
@@ -105,30 +126,40 @@ public class DebugRenderer {
|
||||
boxOutlineBuffer.uploadBuffer(buffer, EGpuUploadMethod.DATA, box_outline_indices.length * Integer.BYTES, GL32.GL_STATIC_DRAW);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface IDebugRender {
|
||||
void render(DebugRenderer r);
|
||||
}
|
||||
private final LinkedList<WeakReference<IDebugRenderable>> renderers = new LinkedList<>();
|
||||
|
||||
private final Map<Object, IDebugRender> renderers = Collections.synchronizedMap(new WeakHashMap<>());
|
||||
|
||||
public void addRenderer(Object o, IDebugRender r) {
|
||||
public void addRenderer(IDebugRenderable r) {
|
||||
if (!Config.Client.Advanced.Debugging.debugWireframeRendering.get()) return;
|
||||
renderers.put(o, r);
|
||||
synchronized (renderers) {
|
||||
renderers.add(new WeakReference<>(r));
|
||||
}
|
||||
}
|
||||
|
||||
public static void register(Object o, IDebugRender r) {
|
||||
public static void register(IDebugRenderable r) {
|
||||
if (INSTANCE == null) return;
|
||||
INSTANCE.addRenderer(o, r);
|
||||
INSTANCE.addRenderer(r);
|
||||
}
|
||||
|
||||
private Mat4f transform_this_frame;
|
||||
private Vec3f camf;
|
||||
|
||||
public void renderBox(DhLodPos pos, float minY, float maxY, float marginPercent, Color color) {
|
||||
DhBlockPos2D blockMin = pos.getCornerBlockPos();
|
||||
DhBlockPos2D blockMax = blockMin.add(pos.getBlockWidth(), pos.getBlockWidth());
|
||||
float edge = pos.getBlockWidth() * marginPercent;
|
||||
renderBox(blockMin.x + edge, minY, blockMin.z + edge, blockMax.x - edge, maxY, blockMax.z - edge, color);
|
||||
}
|
||||
|
||||
public void renderBox(DhLodPos pos, float minY, float maxY, Color color) {
|
||||
renderBox(pos, minY, maxY, 0, color);
|
||||
}
|
||||
|
||||
public void renderBox(DhSectionPos sectPos, float minY, float maxY, Color color) {
|
||||
DhBlockPos2D blockMin = sectPos.getCorner().getCornerBlockPos();
|
||||
DhBlockPos2D blockMax = blockMin.add(sectPos.getWidth().toBlockWidth(), sectPos.getWidth().toBlockWidth());
|
||||
renderBox(blockMin.x, minY, blockMin.z, blockMax.x, maxY, blockMax.z, color);
|
||||
renderBox(sectPos.getSectionBBoxPos(), minY, maxY, 0, color);
|
||||
}
|
||||
|
||||
public void renderBox(DhSectionPos sectPos, float minY, float maxY, float marginPercent, Color color) {
|
||||
renderBox(sectPos.getSectionBBoxPos(), minY, maxY, marginPercent, color);
|
||||
}
|
||||
|
||||
public void renderBox(float x, float y, float z, float x2, float y2, float z2, Color color) {
|
||||
@@ -157,7 +188,7 @@ public class DebugRenderer {
|
||||
GL32.glViewport(0,0, MC_RENDER.getTargetFrameBufferViewportWidth(), MC_RENDER.getTargetFrameBufferViewportHeight());
|
||||
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_LINE);
|
||||
//GL32.glLineWidth(2);
|
||||
GL32.glDisable(GL32.GL_DEPTH_TEST);
|
||||
GL32.glEnable(GL32.GL_DEPTH_TEST);
|
||||
GL32.glDisable(GL32.GL_STENCIL_TEST);
|
||||
GL32.glDisable(GL32.GL_BLEND);
|
||||
GL32.glDisable(GL32.GL_SCISSOR_TEST);
|
||||
@@ -165,9 +196,22 @@ public class DebugRenderer {
|
||||
basicShader.bind();
|
||||
va.bind();
|
||||
va.bindBufferToAllBindingPoint(boxBuffer.getId());
|
||||
|
||||
boxOutlineBuffer.bind();
|
||||
|
||||
renderers.forEach((o, r) -> r.render(this));
|
||||
synchronized (renderers)
|
||||
{
|
||||
Iterator<WeakReference<IDebugRenderable>> it = renderers.iterator();
|
||||
while (it.hasNext()) {
|
||||
WeakReference<IDebugRenderable> ref = it.next();
|
||||
IDebugRenderable r = ref.get();
|
||||
if (r == null) {
|
||||
it.remove();
|
||||
continue;
|
||||
}
|
||||
r.debugRender(this);
|
||||
}
|
||||
}
|
||||
|
||||
state.restore();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.seibel.lod.core.render.renderer;
|
||||
|
||||
public interface IDebugRenderable {
|
||||
void debugRender(DebugRenderer r);
|
||||
}
|
||||
@@ -184,7 +184,7 @@ public class LodRenderer
|
||||
|
||||
|
||||
|
||||
transparencyEnabled = Config.Client.Advanced.Graphics.Quality.transparency.get().tranparencyEnabled;
|
||||
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
|
||||
@@ -271,6 +271,7 @@ public class LodRenderer
|
||||
|
||||
shaderProgram.unbind();
|
||||
//lightmapTexture.free();
|
||||
DebugRenderer.INSTANCE.render(modelViewProjectionMatrix);
|
||||
GL32.glClear(GL32.GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
currentState.restore();
|
||||
@@ -280,7 +281,6 @@ public class LodRenderer
|
||||
profiler.pop();
|
||||
tickLogger.incLogTries();
|
||||
|
||||
DebugRenderer.INSTANCE.render(modelViewProjectionMatrix);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
|
||||
package com.seibel.lod.core.util;
|
||||
|
||||
import com.seibel.lod.core.config.Config;
|
||||
import com.seibel.lod.api.enums.config.EHorizontalQuality;
|
||||
import com.seibel.lod.core.config.Config;
|
||||
import com.seibel.lod.coreapi.util.MathUtil;
|
||||
|
||||
/**
|
||||
@@ -31,67 +31,67 @@ import com.seibel.lod.coreapi.util.MathUtil;
|
||||
@Deprecated
|
||||
public class DetailDistanceUtil
|
||||
{
|
||||
public static byte minDetail = Config.Client.Advanced.Graphics.Quality.drawResolution.get().detailLevel;
|
||||
/** smallest numerical detail level */
|
||||
private static byte maxDetailLevel = Config.Client.Advanced.Graphics.Quality.drawResolution.get().detailLevel;
|
||||
|
||||
private static final byte maxDetail = Byte.MAX_VALUE;
|
||||
/** largest numerical detail level */
|
||||
private static final byte minDetailLevel = Byte.MAX_VALUE;
|
||||
private static final double minDistance = 0;
|
||||
private static double distanceUnit = 16 * Config.Client.Advanced.Graphics.Quality.horizontalScale.get();
|
||||
private static double maxDistance = Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistance.get() * 16 * 2;
|
||||
|
||||
// TODO merge with updateSettings() below
|
||||
private static double distanceUnit = Config.Client.Advanced.Graphics.Quality.horizontalQuality.get().distanceUnitInBlocks * LodUtil.CHUNK_WIDTH;
|
||||
private static double maxDistance = Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistance.get() * LodUtil.CHUNK_WIDTH * 2;
|
||||
private static double logBase = Math.log(Config.Client.Advanced.Graphics.Quality.horizontalQuality.get().quadraticBase);
|
||||
|
||||
|
||||
|
||||
public static void updateSettings()
|
||||
{
|
||||
distanceUnit = 16 * Config.Client.Advanced.Graphics.Quality.horizontalScale.get();
|
||||
minDetail = Config.Client.Advanced.Graphics.Quality.drawResolution.get().detailLevel;
|
||||
maxDistance = Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistance.get() * 16 * 8;
|
||||
maxDetailLevel = Config.Client.Advanced.Graphics.Quality.drawResolution.get().detailLevel;
|
||||
|
||||
distanceUnit = Config.Client.Advanced.Graphics.Quality.horizontalQuality.get().distanceUnitInBlocks * LodUtil.CHUNK_WIDTH;
|
||||
maxDistance = Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistance.get() * LodUtil.CHUNK_WIDTH * 2;
|
||||
logBase = Math.log(Config.Client.Advanced.Graphics.Quality.horizontalQuality.get().quadraticBase);
|
||||
}
|
||||
|
||||
public static double baseDistanceFunction(int detail)
|
||||
{
|
||||
if (detail <= minDetail)
|
||||
return minDistance;
|
||||
if (detail >= maxDetail)
|
||||
return maxDistance;
|
||||
|
||||
detail-=minDetail;
|
||||
|
||||
if (Config.Client.Advanced.Graphics.Quality.horizontalQuality.get() == EHorizontalQuality.LOWEST)
|
||||
return ((double)detail * distanceUnit);
|
||||
else
|
||||
if (detail <= maxDetailLevel)
|
||||
{
|
||||
double base = Config.Client.Advanced.Graphics.Quality.horizontalQuality.get().quadraticBase;
|
||||
return Math.pow(base, detail) * distanceUnit;
|
||||
return minDistance;
|
||||
}
|
||||
else if (detail >= minDetailLevel)
|
||||
{
|
||||
return maxDistance;
|
||||
}
|
||||
|
||||
|
||||
double base = Config.Client.Advanced.Graphics.Quality.horizontalQuality.get().quadraticBase;
|
||||
return Math.pow(base, detail) * distanceUnit;
|
||||
}
|
||||
|
||||
public static double getDrawDistanceFromDetail(int detail)
|
||||
{
|
||||
return baseDistanceFunction(detail);
|
||||
}
|
||||
public static double getDrawDistanceFromDetail(int detail) { return baseDistanceFunction(detail); }
|
||||
|
||||
public static byte baseInverseFunction(double distance)
|
||||
{
|
||||
double maxDetailDistance = getDrawDistanceFromDetail(maxDetail-1);
|
||||
if (distance > maxDetailDistance) {
|
||||
//ApiShared.LOGGER.info("DEBUG: Scale as max: {}", distance);
|
||||
return maxDetail-1;
|
||||
// special case, never drop the quality
|
||||
if (Config.Client.Advanced.Graphics.Quality.horizontalQuality.get() == EHorizontalQuality.UNLIMITED)
|
||||
{
|
||||
return maxDetailLevel;
|
||||
}
|
||||
|
||||
int detail;
|
||||
|
||||
if (Config.Client.Advanced.Graphics.Quality.horizontalQuality.get() == EHorizontalQuality.LOWEST)
|
||||
detail = (int) (distance/distanceUnit);
|
||||
else
|
||||
detail = (int) (Math.log(distance/distanceUnit) / logBase);
|
||||
double maxDetailDistance = getDrawDistanceFromDetail(minDetailLevel -1);
|
||||
if (distance > maxDetailDistance)
|
||||
{
|
||||
return minDetailLevel - 1;
|
||||
}
|
||||
|
||||
return (byte) MathUtil.clamp(minDetail, detail+minDetail, maxDetail - 1);
|
||||
|
||||
int detailLevel = (int) (Math.log(distance / distanceUnit) / logBase);
|
||||
return (byte) MathUtil.clamp(maxDetailLevel, detailLevel, minDetailLevel - 1);
|
||||
}
|
||||
|
||||
public static byte getDetailLevelFromDistance(double distance)
|
||||
{
|
||||
return baseInverseFunction(distance);
|
||||
}
|
||||
public static byte getDetailLevelFromDistance(double distance) { return baseInverseFunction(distance); }
|
||||
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
package com.seibel.lod.core.util;
|
||||
|
||||
import com.seibel.lod.api.enums.config.EOverdrawPrevention;
|
||||
import com.seibel.lod.core.level.IDhClientLevel;
|
||||
import com.seibel.lod.core.world.IDhClientWorld;
|
||||
import com.seibel.lod.core.api.internal.SharedApi;
|
||||
@@ -176,20 +177,48 @@ public class RenderUtil
|
||||
|
||||
public static float getNearClipPlaneDistanceInBlocks(float partialTicks)
|
||||
{
|
||||
int vanillaBlockRenderedDistance = MC_RENDER.getRenderDistance() * LodUtil.CHUNK_WIDTH;
|
||||
int chunkRenderDistance = MC_RENDER.getRenderDistance();
|
||||
if (chunkRenderDistance % 2 == 0)
|
||||
{
|
||||
chunkRenderDistance += 1;
|
||||
}
|
||||
|
||||
int vanillaBlockRenderedDistance = chunkRenderDistance * LodUtil.CHUNK_WIDTH;
|
||||
vanillaBlockRenderedDistance *= 2;
|
||||
|
||||
float nearClipPlane;
|
||||
if (Config.Client.Advanced.Debugging.lodOnlyMode.get())
|
||||
{
|
||||
nearClipPlane = 0.1f;
|
||||
}
|
||||
else if (Config.Client.Advanced.Graphics.AdvancedGraphics.useExtendedNearClipPlane.get())
|
||||
else
|
||||
{
|
||||
nearClipPlane = Math.min(vanillaBlockRenderedDistance - LodUtil.CHUNK_WIDTH, (float) 8 * LodUtil.CHUNK_WIDTH); // allow a max near clip plane of 8 chunks
|
||||
}
|
||||
else
|
||||
{
|
||||
nearClipPlane = 16f;
|
||||
// TODO make this option dependent on player speed.
|
||||
// if the player is flying quickly, lower the near clip plane to account for slow chunk loading.
|
||||
// If the player is moving quickly they are less likely to notice overdraw.
|
||||
|
||||
EOverdrawPrevention clipPlaneDistance = Config.Client.Advanced.Graphics.AdvancedGraphics.overdrawPrevention.get();
|
||||
switch (clipPlaneDistance)
|
||||
{
|
||||
default: // shouldn't be necessary, just here to make the compiler happy
|
||||
case NONE:
|
||||
nearClipPlane = 0.1f;
|
||||
break;
|
||||
|
||||
case LIGHT:
|
||||
nearClipPlane = vanillaBlockRenderedDistance * 0.25f;
|
||||
break;
|
||||
|
||||
case MEDIUM:
|
||||
nearClipPlane = vanillaBlockRenderedDistance * 0.4f;
|
||||
break;
|
||||
|
||||
|
||||
case HEAVY:
|
||||
// recommend render distance ot 6 or higher, otherwise holes may appear
|
||||
nearClipPlane = vanillaBlockRenderedDistance * 0.6f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// modify the based on the player's FOV
|
||||
|
||||
@@ -12,8 +12,4 @@ public interface IBlockStateWrapper extends IDhApiBlockStateWrapper
|
||||
{
|
||||
String serialize();
|
||||
|
||||
// TODO:
|
||||
// boolean hasFaceCullingFor(ELodDirection dir);
|
||||
// boolean hasNoCollision();
|
||||
// boolean noFaceIsFullFace();
|
||||
}
|
||||
|
||||
@@ -54,17 +54,17 @@
|
||||
"lod.config.client.quickEnableRendering.@tooltip":
|
||||
"Determines if Distant Horizons Renders LODs.",
|
||||
|
||||
"lod.config.client.quickQualitySetting":
|
||||
"Overall Quality",
|
||||
"lod.config.client.quickQualitySetting.@tooltip":
|
||||
"Will modify a number of settings to quickly change Distant Horizons' rendering quality.",
|
||||
"lod.config.client.quickThreadSetting":
|
||||
"lod.config.client.qualityPresetSetting":
|
||||
"Quality Preset",
|
||||
"lod.config.client.qualityPresetSetting.@tooltip":
|
||||
"Modifies a number of graphical settings to quickly change Distant Horizons' rendering quality. \n\nLower this setting if your GPU is at max usage or you are having framerate issues.",
|
||||
"lod.config.client.threadPresetSetting":
|
||||
"CPU Load",
|
||||
"lod.config.client.quickThreadSetting.@tooltip":
|
||||
"Will modify a number of settings to quickly change how many CPU resources Distant Horizons' is allowed to use. \n\nIncreasing this setting will improve Distant Generator speed and LOD loading speed, \nbut will also increase CPU/memory usage and may introduce stuttering.",
|
||||
"lod.config.client.threadPresetSetting.@tooltip":
|
||||
"Modifies how many threads Distant Horizons' will use. \n\nIncreasing this setting will improve the Distant Generator speed and LOD loading speed, \nbut will also increase CPU/memory usage and may introduce stuttering. \n\nNote: on CPUs with 4 cores or less these settings will be less effective \nand some settings will give similar results.",
|
||||
|
||||
"lod.config.client.optionsButton":
|
||||
"Show options button",
|
||||
"Show The Options Button",
|
||||
"lod.config.client.optionsButton.@tooltip":
|
||||
"Show the config button to the left of the fov button",
|
||||
|
||||
@@ -73,9 +73,6 @@
|
||||
"lod.config.client.advanced":
|
||||
"Advanced options",
|
||||
|
||||
"lod.config.client.advanced.advancedConfigScreenNote":
|
||||
"",
|
||||
|
||||
"lod.config.client.advanced.graphics":
|
||||
"Graphics",
|
||||
"lod.config.client.advanced.graphics.quality":
|
||||
@@ -107,6 +104,14 @@
|
||||
"How far apart drops in quality are.\n\nHigher settings will increase the distance between drops\nbut will increase memory and GPU usage.",
|
||||
"lod.config.client.advanced.graphics.quality.transparency":
|
||||
"Transparency",
|
||||
"lod.config.client.advanced.graphics.quality.blocksToIgnore":
|
||||
"Blocks To Ignore",
|
||||
"lod.config.client.advanced.graphics.quality.blocksToIgnore.@tooltip":
|
||||
"Defines the types of blocks to ignore when generating LODs.",
|
||||
"lod.config.client.advanced.graphics.quality.tintWithAvoidedBlocks":
|
||||
"Tint With Avoided Blocks",
|
||||
"lod.config.client.advanced.graphics.quality.tintWithAvoidedBlocks.@tooltip":
|
||||
"§4Note: makes snow, carpet, and trapdoors look really bad§r\nShould the blocks underneath avoided blocks gain the color of the avoided block?\n§6True:§r a red flower on grass will tint the grass below it red\n§6False:§r skipped blocks will not change color of surface below them",
|
||||
"lod.config.client.advanced.graphics.quality.lodBiomeBlending":
|
||||
"Biome Blending",
|
||||
"lod.config.client.advanced.graphics.quality.lodBiomeBlending.@tooltip":
|
||||
@@ -114,16 +119,16 @@
|
||||
|
||||
|
||||
"lod.config.client.advanced.graphics.fog":
|
||||
"Fog Options",
|
||||
|
||||
"lod.config.client.advanced.graphics.fog.fogDistance":
|
||||
"Fog Distance",
|
||||
"lod.config.client.advanced.graphics.fog.fogDistance.@tooltip":
|
||||
"The distance(s) Fog will be rendered on the LODs.",
|
||||
"Fog",
|
||||
|
||||
"lod.config.client.advanced.graphics.fog.fogDrawMode":
|
||||
"Fog Draw Mode",
|
||||
"lod.config.client.advanced.graphics.fog.fogDrawMode.@tooltip":
|
||||
"When fog will be rendered on the LODs.",
|
||||
"lod.config.client.advanced.graphics.fog.fogDistance":
|
||||
"Fog Distance",
|
||||
"lod.config.client.advanced.graphics.fog.fogDistance.@tooltip":
|
||||
"The distance(s) Fog will be rendered on the LODs.",
|
||||
"lod.config.client.advanced.graphics.fog.fogColorMode":
|
||||
"Fog Color Mode",
|
||||
"lod.config.client.advanced.graphics.fog.fogColorMode.@tooltip":
|
||||
@@ -228,9 +233,9 @@
|
||||
"lod.config.client.advanced.graphics.advancedGraphics":
|
||||
"Advanced Graphics Options",
|
||||
|
||||
"lod.config.client.advanced.graphics.advancedGraphics.useExtendedNearClipPlane":
|
||||
"Use extended near clip plane",
|
||||
"lod.config.client.advanced.graphics.advancedGraphics.useExtendedNearClipPlane.@tooltip":
|
||||
"lod.config.client.advanced.graphics.advancedGraphics.overdrawPrevention":
|
||||
"Overdraw Prevention",
|
||||
"lod.config.client.advanced.graphics.advancedGraphics.overdrawPrevention.@tooltip":
|
||||
"Enabling this will prevent some overdraw issues,\nbut may cause nearby LODs to render incorrectly, especially when near fancy leaves or non-full blocks.\nLess noticeable with a longer vanilla render distance.",
|
||||
"lod.config.client.advanced.graphics.advancedGraphics.brightnessMultiplier":
|
||||
"Brightness Multiplier",
|
||||
@@ -277,14 +282,6 @@
|
||||
"Generation Priority",
|
||||
"lod.config.client.advanced.worldGenerator.generationPriority.@tooltip":
|
||||
"The priority for chunks being generated around the player.",
|
||||
"lod.config.client.advanced.worldGenerator.blocksToAvoid":
|
||||
"Blocks To Avoid",
|
||||
"lod.config.client.advanced.worldGenerator.blocksToAvoid.@tooltip":
|
||||
"Defines the types of blocks to ignore when generating LODs.",
|
||||
"lod.config.client.advanced.worldGenerator.tintWithAvoidedBlocks":
|
||||
"Tint With Avoided Blocks",
|
||||
"lod.config.client.advanced.worldGenerator.tintWithAvoidedBlocks.@tooltip":
|
||||
"§4Note: makes snow, carpet, and trapdoors look really bad§r\nShould the blocks underneath avoided blocks gain the color of the avoided block?\n§6True:§r a red flower on grass will tint the grass below it red\n§6False:§r skipped blocks will not change color of surface below them",
|
||||
|
||||
|
||||
"lod.config.client.advanced.multiplayer":
|
||||
@@ -301,24 +298,24 @@
|
||||
|
||||
|
||||
|
||||
"lod.config.client.advanced.threading":
|
||||
"lod.config.client.advanced.multiThreading":
|
||||
"Threading",
|
||||
|
||||
"lod.config.client.advanced.threading.numberOfWorldGenerationThreads":
|
||||
"lod.config.client.advanced.multiThreading.numberOfWorldGenerationThreads":
|
||||
"NO. of world generation threads",
|
||||
"lod.config.client.advanced.threading.numberOfWorldGenerationThreads.@tooltip":
|
||||
"lod.config.client.advanced.multiThreading.numberOfWorldGenerationThreads.@tooltip":
|
||||
"How many threads should be used when generating LODs \n outside the normal render distance? \n\nIf it this is less than 1, it will be treated as a percentage \nof time a single thread can run before going idle. \n\nIf you experience stuttering when generating distant LODs, \ndecrease this number. If you want to increase LOD \ngeneration speed, increase this number. \n\nThis and the number of buffer builder threads are independent, \nif they add up to more threads than your CPU has cores \nthat is ok.",
|
||||
"lod.config.client.advanced.threading.numberOfBufferBuilderThreads":
|
||||
"lod.config.client.advanced.multiThreading.numberOfBufferBuilderThreads":
|
||||
"NO. of buffer builder threads",
|
||||
"lod.config.client.advanced.threading.numberOfBufferBuilderThreads.@tooltip":
|
||||
"lod.config.client.advanced.multiThreading.numberOfBufferBuilderThreads.@tooltip":
|
||||
"The number of threads used when building geometry data.\nCan only be between 1 and your CPU's processor count.",
|
||||
"lod.config.client.advanced.threading.numberOfFileHandlerThreads":
|
||||
"lod.config.client.advanced.multiThreading.numberOfFileHandlerThreads":
|
||||
"NO. of file handler threads",
|
||||
"lod.config.client.advanced.threading.numberOfFileHandlerThreads.@tooltip":
|
||||
"lod.config.client.advanced.multiThreading.numberOfFileHandlerThreads.@tooltip":
|
||||
"The number of threads used when building vertex buffers\n(The things sent to your GPU to draw the LODs).\nCan only be between 1 and your CPU's processor count.",
|
||||
"lod.config.client.advanced.threading.numberOfDataConverterThreads":
|
||||
"lod.config.client.advanced.multiThreading.numberOfDataConverterThreads":
|
||||
"NO. of data converter threads",
|
||||
"lod.config.client.advanced.threading.numberOfDataConverterThreads.@tooltip":
|
||||
"lod.config.client.advanced.multiThreading.numberOfDataConverterThreads.@tooltip":
|
||||
"The number of threads used when converting ID data to render-able data.\n(This generally happens when generating new terrain or changing graphics settings).\nCan only be between 1 and your CPU's processor count.",
|
||||
|
||||
|
||||
@@ -344,7 +341,11 @@
|
||||
"Only Render LODs",
|
||||
"lod.config.client.advanced.debugging.lodOnlyMode.@tooltip":
|
||||
"If enabled this will disable (most) vanilla Minecraft rendering. \n\nNOTE: Do not report any issues when this mode is on! \nThis setting is only for fun and debugging. \nMod compatibility is not guaranteed.",
|
||||
|
||||
"lod.config.client.advanced.debugging.debugWireframeRendering":
|
||||
"Enable Debug Wireframe Rendering",
|
||||
"lod.config.client.advanced.debugging.debugWireframeRendering.@tooltip":
|
||||
"If enabled, various wireframes for debugging internal functions will be drawn.",
|
||||
|
||||
"lod.config.client.advanced.buffers":
|
||||
"Buffers",
|
||||
"lod.config.client.advanced.buffers.gpuUploadMethod":
|
||||
@@ -426,33 +427,42 @@
|
||||
"Linkable test",
|
||||
"lod.config.client.advanced.debugging.debugConfigScreen.linkableTest.@tooltip":
|
||||
"The value of this should be the same as in Category Test",
|
||||
|
||||
|
||||
"lod.config.client.resetSettingsConfirmation":
|
||||
"Reset All Settings?",
|
||||
|
||||
"lod.config.client.resetSettingsConfirmation.resetConfirmationNote":
|
||||
"Are you sure? This cannot be undone.",
|
||||
"lod.config.client.resetSettingsConfirmation.resetAllSettings":
|
||||
"Reset All Settings",
|
||||
|
||||
|
||||
|
||||
|
||||
"lod.config.enum.EQuickQuality.CUSTOM":
|
||||
"lod.config.enum.EQualityPreset.CUSTOM":
|
||||
"Custom",
|
||||
"lod.config.enum.EQuickQuality.MINIMUM":
|
||||
"lod.config.enum.EQualityPreset.MINIMUM":
|
||||
"Minimum",
|
||||
"lod.config.enum.EQuickQuality.LOW":
|
||||
"lod.config.enum.EQualityPreset.LOW":
|
||||
"Low",
|
||||
"lod.config.enum.EQuickQuality.MEDIUM":
|
||||
"lod.config.enum.EQualityPreset.MEDIUM":
|
||||
"Medium",
|
||||
"lod.config.enum.EQuickQuality.HIGH":
|
||||
"lod.config.enum.EQualityPreset.HIGH":
|
||||
"High",
|
||||
"lod.config.enum.EQuickQuality.EXTREME":
|
||||
"lod.config.enum.EQualityPreset.EXTREME":
|
||||
"Extreme",
|
||||
|
||||
"lod.config.enum.EQuickThread.CUSTOM":
|
||||
"lod.config.enum.EThreadPreset.CUSTOM":
|
||||
"Custom",
|
||||
"lod.config.enum.EQuickThread.MINIMAL_IMPACT":
|
||||
"lod.config.enum.EThreadPreset.MINIMAL_IMPACT":
|
||||
"Minimal Impact",
|
||||
"lod.config.enum.EQuickThread.LOW_IMPACT":
|
||||
"lod.config.enum.EThreadPreset.LOW_IMPACT":
|
||||
"Low Impact",
|
||||
"lod.config.enum.EQuickThread.BALANCED":
|
||||
"lod.config.enum.EThreadPreset.BALANCED":
|
||||
"Balanced",
|
||||
"lod.config.enum.EQuickThread.AGGRESSIVE_LOADING":
|
||||
"Aggressive Loading",
|
||||
"lod.config.enum.EQuickThread.I_PAID_FOR_THE_WHOLE_CPU":
|
||||
"lod.config.enum.EThreadPreset.AGGRESSIVE":
|
||||
"Aggressive",
|
||||
"lod.config.enum.EThreadPreset.I_PAID_FOR_THE_WHOLE_CPU":
|
||||
"I Paid For The Whole CPU",
|
||||
|
||||
"lod.config.enum.EHorizontalResolution.BLOCK":
|
||||
@@ -474,8 +484,8 @@
|
||||
"Medium",
|
||||
"lod.config.enum.EVerticalQuality.HIGH":
|
||||
"High",
|
||||
"lod.config.enum.EVerticalQuality.ULTRA":
|
||||
"Ultra",
|
||||
"lod.config.enum.EVerticalQuality.EXTREME":
|
||||
"Extreme",
|
||||
"lod.config.enum.EHorizontalQuality.LOWEST":
|
||||
"Lowest",
|
||||
"lod.config.enum.EHorizontalQuality.LOW":
|
||||
@@ -484,6 +494,10 @@
|
||||
"Medium",
|
||||
"lod.config.enum.EHorizontalQuality.HIGH":
|
||||
"High",
|
||||
"lod.config.enum.EHorizontalQuality.EXTREME":
|
||||
"Extreme",
|
||||
"lod.config.enum.EHorizontalQuality.UNLIMITED":
|
||||
"Unlimited",
|
||||
|
||||
"lod.config.enum.ETransparency.DISABLED":
|
||||
"Disabled",
|
||||
@@ -589,12 +603,17 @@
|
||||
|
||||
"lod.config.enum.EBlocksToAvoid.NONE":
|
||||
"None",
|
||||
"lod.config.enum.EBlocksToAvoid.NON_FULL":
|
||||
"Non full",
|
||||
"lod.config.enum.EBlocksToAvoid.NO_COLLISION":
|
||||
"No collision",
|
||||
"lod.config.enum.EBlocksToAvoid.BOTH":
|
||||
"Both",
|
||||
"lod.config.enum.EBlocksToAvoid.NON_COLLIDING":
|
||||
"Non-Colliding",
|
||||
|
||||
"lod.config.enum.EOverdrawPrevention.NONE":
|
||||
"None",
|
||||
"lod.config.enum.EOverdrawPrevention.LIGHT":
|
||||
"Light",
|
||||
"lod.config.enum.EOverdrawPrevention.MEDIUM":
|
||||
"Medium",
|
||||
"lod.config.enum.EOverdrawPrevention.HEAVY":
|
||||
"Heavy",
|
||||
|
||||
"lod.config.enum.EServerFolderNameMode.NAME_ONLY":
|
||||
"Name Only",
|
||||
|
||||
Reference in New Issue
Block a user