diff --git a/src/main/java/rs117/hd/HdPlugin.java b/src/main/java/rs117/hd/HdPlugin.java index e08fa46dd5..c5356c0d5a 100644 --- a/src/main/java/rs117/hd/HdPlugin.java +++ b/src/main/java/rs117/hd/HdPlugin.java @@ -118,6 +118,7 @@ import rs117.hd.utils.DestructibleHandler; import rs117.hd.utils.DeveloperTools; import rs117.hd.utils.FileWatcher; +import rs117.hd.utils.GraphicsPresets; import rs117.hd.utils.GsonUtils; import rs117.hd.utils.HDUtils; import rs117.hd.utils.HDVariables; @@ -251,6 +252,9 @@ public class HdPlugin extends Plugin { @Inject private HdPluginConfig config; + @Inject + private GraphicsPresets graphicsPresets; + @Inject private GamevalManager gamevalManager; @@ -672,6 +676,7 @@ protected void startUp() { } } + graphicsPresets.startUp(); updateCachedConfigs(); developerTools.activate(); @@ -1749,6 +1754,7 @@ public void processPendingConfigChanges() { log.debug("Processing {} pending config changes: {}", pendingConfigChanges.size(), pendingConfigChanges); + graphicsPresets.processConfigChange(pendingConfigChanges); renderer.processConfigChanges(pendingConfigChanges); boolean recompilePrograms = false; diff --git a/src/main/java/rs117/hd/HdPluginConfig.java b/src/main/java/rs117/hd/HdPluginConfig.java index b24ab75201..c3b03e80ff 100644 --- a/src/main/java/rs117/hd/HdPluginConfig.java +++ b/src/main/java/rs117/hd/HdPluginConfig.java @@ -41,6 +41,7 @@ import rs117.hd.config.DynamicLights; import rs117.hd.config.FogDepthMode; import rs117.hd.config.InfernalCape; +import rs117.hd.config.Presets; import rs117.hd.config.Saturation; import rs117.hd.config.SceneScalingMode; import rs117.hd.config.SeasonalHemisphere; @@ -53,6 +54,7 @@ import rs117.hd.config.TextureResolution; import rs117.hd.config.UIScalingMode; import rs117.hd.config.VanillaShadowMode; +import rs117.hd.utils.GraphicsPresets; import static rs117.hd.HdPlugin.MAX_DISTANCE; import static rs117.hd.HdPlugin.MAX_FOG_DEPTH; @@ -64,6 +66,14 @@ public interface HdPluginConfig extends Config { String CONFIG_GROUP = "hd"; + String KEY_GRAPHICS_PRESET = "graphicsPreset"; + @ConfigItem( + keyName = KEY_GRAPHICS_PRESET, + name = "Graphics Preset", + description = "" + ) + default GraphicsPresets.QualityLevel graphicsPreset() { return GraphicsPresets.QualityLevel.HIGH; } + /*====== General settings ======*/ @ConfigSection( @@ -86,6 +96,7 @@ public interface HdPluginConfig extends Config position = 1, section = generalSettings ) + @Presets(ints = {50, 100, 125, 184}) default int drawDistance() { return 50; } @@ -104,8 +115,9 @@ default int drawDistance() { position = 2, section = generalSettings ) + @Presets(ints = {25, 50, 75, 100}) default int detailDrawDistance() { - return 70; + return 75; } String KEY_EXPANDED_MAP_LOADING_CHUNKS = "expandedMapLoadingChunks"; @@ -148,6 +160,7 @@ default boolean hideUnrelatedAreas() { position = 5, section = generalSettings ) + @Presets(enums = {"DISABLED", "MSAA_2", "MSAA_4", "MSAA_16"}) default AntiAliasingMode antiAliasingMode() { return AntiAliasingMode.MSAA_8; @@ -212,6 +225,7 @@ default UIScalingMode uiScalingMode() { position = 9, section = generalSettings ) + @Presets(ints = {1, 4, 8, 16}) default int anisotropicFilteringLevel() { return 16; @@ -396,6 +410,7 @@ default int brightness() { position = 1, section = shadowSettings ) + @Presets(enums = {"FAST", "FAST", "DETAILED", "DETAILED"}) default ShadowMode shadowMode() { return ShadowMode.DETAILED; } @@ -410,6 +425,7 @@ default ShadowMode shadowMode() { position = 2, section = shadowSettings ) + @Presets(enums = {"RES_1024", "RES_2048", "RES_4096", "RES_8192"}) default ShadowResolution shadowResolution() { return ShadowResolution.RES_8192; } @@ -438,6 +454,7 @@ default ShadowFiltering shadowFiltering() { position = 4, section = shadowSettings ) + @Presets(bools = {false, false, true, true}) default boolean shadowTransparency() { return true; } @@ -464,6 +481,7 @@ default boolean roofShadows() { position = 6, section = shadowSettings ) + @Presets(bools = {false, true, true, true}) default boolean expandShadowDraw() { return false; } @@ -489,6 +507,7 @@ default boolean expandShadowDraw() { position = 0, section = lightingSettings ) + @Presets(enums = {"NONE", "FEW", "MANY", "MANY"}) default DynamicLights dynamicLights() { return DynamicLights.SOME; } @@ -515,6 +534,7 @@ default boolean tiledLighting() { position = 2, section = lightingSettings ) + @Presets(bools = {false, true, true, true}) default boolean projectileLights() { return true; } @@ -527,6 +547,7 @@ default boolean projectileLights() { position = 3, section = lightingSettings ) + @Presets(bools = {false, true, true, true}) default boolean npcLights() { return true; } @@ -566,6 +587,7 @@ default VanillaShadowMode vanillaShadowMode() { position = 12, section = lightingSettings ) + @Presets(bools = {false, true, true, true}) default boolean normalMapping() { return true; } @@ -578,6 +600,7 @@ default boolean normalMapping() { position = 13, section = lightingSettings ) + @Presets(bools = {false, false, true, true}) default boolean parallaxOcclusionMapping() { return true; } @@ -722,6 +745,7 @@ default boolean groundTextures() position = 9, section = environmentSettings ) + @Presets(enums = {"RES_128", "RES_256", "RES_256", "RES_256"}) default TextureResolution textureResolution() { return TextureResolution.RES_256; @@ -747,6 +771,7 @@ default boolean groundBlending() position = 11, section = environmentSettings ) + @Presets(bools = {false, true, true, true}) default boolean underwaterCaustics() { return true; @@ -760,6 +785,7 @@ default boolean underwaterCaustics() position = 13, section = environmentSettings ) + @Presets(bools = {false, false, true, true}) default boolean windDisplacement() { return true; } @@ -772,6 +798,7 @@ default boolean windDisplacement() { position = 14, section = environmentSettings ) + @Presets(bools = {false, false, true, true}) default boolean characterDisplacement() { return true; } @@ -1259,4 +1286,5 @@ default boolean multithreadedModelProcessing() { default int getPluginUpdateMessage() { return 0; } + } diff --git a/src/main/java/rs117/hd/config/Presets.java b/src/main/java/rs117/hd/config/Presets.java new file mode 100644 index 0000000000..a055ed58e2 --- /dev/null +++ b/src/main/java/rs117/hd/config/Presets.java @@ -0,0 +1,15 @@ +package rs117.hd.config; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface Presets { + int[] ints() default {}; + double[] floats() default {}; + String[] enums() default {}; + boolean[] bools() default {}; +} diff --git a/src/main/java/rs117/hd/utils/GraphicsPresets.java b/src/main/java/rs117/hd/utils/GraphicsPresets.java new file mode 100644 index 0000000000..88d62c71a1 --- /dev/null +++ b/src/main/java/rs117/hd/utils/GraphicsPresets.java @@ -0,0 +1,185 @@ +package rs117.hd.utils; + +import java.lang.reflect.Array; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Set; +import javax.inject.Inject; +import javax.inject.Singleton; +import lombok.extern.slf4j.Slf4j; +import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.eventbus.EventBus; +import net.runelite.client.events.ExternalPluginsChanged; +import rs117.hd.HdPlugin; +import rs117.hd.HdPluginConfig; +import rs117.hd.config.Presets; + +import static rs117.hd.HdPluginConfig.*; + +@Slf4j +@Singleton +public class GraphicsPresets { + public static final QualityLevel[] QUALITY_LEVELS = QualityLevel.values(); + public static final int QUALITY_LEVEL_COUNT = QUALITY_LEVELS.length; + + @Inject + private HdPlugin plugin; + + @Inject + private EventBus eventBus; + + @Inject + private ConfigManager configManager; + + @Inject + private HdPluginConfig config; + + private QualityLevel currentQualityLevel; + private GraphicsProperty[] graphicsProperties; + + public void startUp() { + ArrayList properties = new ArrayList<>(); + for(Method configMethod : HdPluginConfig.class.getMethods()) { + Presets configPresets = configMethod.getAnnotation(Presets.class); + if(configPresets == null) + continue; + + final String methodName = configMethod.getName(); + int boolCount = configPresets.bools() == null ? 0 : configPresets.bools().length; + int intCount = configPresets.ints() == null ? 0 : configPresets.ints().length; + int floatCount = configPresets.floats() == null ? 0 : configPresets.floats().length; + int enumCount = configPresets.enums() == null ? 0 : configPresets.enums().length; + + assert boolCount + intCount + floatCount + enumCount == QUALITY_LEVEL_COUNT - 1 : "Invalid number of presets in " + methodName; + + ConfigItem configItem = configMethod.getAnnotation(ConfigItem.class); + if(configItem == null) + continue; + + GraphicsProperty property = new GraphicsProperty(); + property.key = configItem.keyName(); + + if(boolCount > 0) { + property.values = configPresets.bools(); + property.type = boolean.class; + } else if(intCount > 0) { + property.values = configPresets.ints(); + property.type = int.class; + } else if(floatCount > 0) { + property.values = configPresets.floats(); + property.type = float.class; + } else if(enumCount > 0) { + property.type = configMethod.getReturnType(); + assert property.type.isEnum() : "Config method must return an enum"; + + String[] enums = configPresets.enums(); + Enum[] enumValues = (Enum[]) property.type.getEnumConstants(); + + property.values = new Enum[enums.length]; + for (int i = 0; i < enums.length; i++) { + for(int k = 0; k < enumValues.length; k++) { + if(enums[i].equals(enumValues[k].name())) { + ((Enum[])property.values)[i] = enumValues[k]; + break; + } + } + } + } + + properties.add(property); + } + + graphicsProperties = new GraphicsProperty[properties.size()]; + properties.toArray(graphicsProperties); + + currentQualityLevel = config.graphicsPreset(); + } + + public void processConfigChange(Set keys) { + QualityLevel currentLevel = config.graphicsPreset(); + if(currentLevel == QualityLevel.CUSTOM) + return; + + if(keys.contains(KEY_GRAPHICS_PRESET)) { + log.debug("Detected Graphics preset change, switching from: {} to: {}", currentQualityLevel, currentLevel); + applyQualityLevel(currentLevel); + return; + } + + // Check if a config setting that has a preset value differs from the current set Quality Level + boolean isCustomQualityLevel = false; + for(GraphicsProperty property : graphicsProperties) { + if(!keys.contains(property.key)) + continue; + + if(!property.isLevelValue(currentLevel)) { + isCustomQualityLevel = true; + break; + } + } + + if(isCustomQualityLevel) { + log.debug("Detected custom quality level"); + configManager.setConfiguration(CONFIG_GROUP, KEY_GRAPHICS_PRESET, QualityLevel.CUSTOM); + eventBus.post(new ExternalPluginsChanged()); + } + } + + private void applyQualityLevel(QualityLevel level) { + if(graphicsProperties == null || graphicsProperties.length == 0) + return; + + boolean hasConfigChanged = false; + for(GraphicsProperty property : graphicsProperties) { + if(property.applyLevel(level)) + hasConfigChanged = true; + } + + if(hasConfigChanged) + eventBus.post(new ExternalPluginsChanged()); + currentQualityLevel = level; + } + + public enum QualityLevel { + LOW, MEDIUM, HIGH, ULTRA, CUSTOM + } + + public class GraphicsProperty { + public String key; + public Class type; + public Object values; + + public Object getValue(QualityLevel level) { + assert level != QualityLevel.CUSTOM; + Object value = Array.get(values, level.ordinal()); + assert value != null : "Failed to get value for " + key + " level " + level.name(); + return value; + } + + public Object readValue() { + Object value = configManager.getConfiguration(CONFIG_GROUP, key, type); + assert value != null : "Failed to read value for " + key; + return value; + } + + public boolean isLevelValue(QualityLevel level) { + return getValue(level).equals(readValue()); + } + + public boolean applyLevel(QualityLevel level) { + Object currentValue = readValue(); + Object presetValue = getValue(level); + if(presetValue.equals(currentValue)) + return false; + + configManager.setConfiguration(CONFIG_GROUP, key, presetValue); + + if(Props.DEVELOPMENT) { + Object newValue = readValue(); + assert newValue.equals(presetValue) : "Failed to set config value - expected " + presetValue + " but got " + newValue + " for " + key; + } + return true; + } + } +}