diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 142ef7668..38aa7f9ad 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,7 +14,7 @@ jobs: - name: checkout repository uses: actions/checkout@v4 - name: validate gradle wrapper - uses: gradle/wrapper-validation-action@v1 + uses: gradle/actions/wrapper-validation@v4 - name: setup java uses: actions/setup-java@v4 with: diff --git a/.gitignore b/.gitignore index 9563893d6..8dfbaeac3 100644 --- a/.gitignore +++ b/.gitignore @@ -22,4 +22,4 @@ bin/ # fabric -run/ \ No newline at end of file +run/ diff --git a/build.gradle b/build.gradle index 106ac879a..35d5b8f60 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ plugins { - id "fabric-loom" version "1.5-SNAPSHOT" + id "fabric-loom" version "1.9-SNAPSHOT" id "maven-publish" } @@ -14,10 +14,17 @@ loom { accessWidenerPath = file("src/main/resources/sodium.accesswidener") } +repositories { + maven { url "https://jitpack.io" } +} + dependencies { minecraft "com.mojang:minecraft:$minecraft_version" mappings "net.fabricmc:yarn:$yarn_mappings:v2" modImplementation "net.fabricmc:fabric-loader:$loader_version" + modImplementation ("com.github.contariaa:speedrunapi:$speedrunapi_version") { + transitive = false + } } processResources { @@ -28,6 +35,7 @@ processResources { tasks.withType(JavaCompile).configureEach { options.encoding = "UTF-8" + options.compilerArgs << "-XDenableSunApiLintControl" << "-Xlint:-sunapi" } java { diff --git a/gradle.properties b/gradle.properties index ef52c59d8..a82f7ef7d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,11 +2,13 @@ org.gradle.jvmargs = -Xmx2G org.gradle.parallel = true org.gradle.caching = true -mod_version = 1.3.1 +mod_version = 1.5.0 minecraft_version = 1.15.2 yarn_mappings = 1.15.2+build.17 -loader_version = 0.15.6 +loader_version = 0.16.9 target_version = 1.15.2 +# https://jitpack.io/#kingcontaria/speedrunapi +speedrunapi_version = 45fa51d142 archives_name = sodium maven_group = me.jellysquid.mods diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index d64cd4917..a4b76b953 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1af9e0930..e0fd02028 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 1aa94a426..f3b75f3b0 100755 --- a/gradlew +++ b/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -84,7 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/gradlew.bat b/gradlew.bat index 93e3f59f1..9d21a2183 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @@ -43,11 +45,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -57,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail diff --git a/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java b/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java index 0b1867b5e..3411b48b7 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/SodiumClientMod.java @@ -11,7 +11,7 @@ import java.io.File; public class SodiumClientMod implements ClientModInitializer { - private static SodiumGameOptions CONFIG; + public static SodiumGameOptions CONFIG; private static Logger LOGGER; private static String MOD_VERSION; @@ -24,14 +24,11 @@ public void onInitializeClient() { MOD_VERSION = mod.getMetadata() .getVersion() - .getFriendlyString(); + .getFriendlyString() + .split("\\+")[0]; } public static SodiumGameOptions options() { - if (CONFIG == null) { - CONFIG = loadConfig(); - } - return CONFIG; } @@ -43,13 +40,6 @@ public static Logger logger() { return LOGGER; } - private static SodiumGameOptions loadConfig() { - SodiumGameOptions config = SodiumGameOptions.load(new File("config/sodium-options.json")); - onConfigChanged(config); - - return config; - } - public static void onConfigChanged(SodiumGameOptions options) { UnsafeUtil.setEnabled(options.advanced.useMemoryIntrinsics); } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java deleted file mode 100644 index 68125ac30..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptionPages.java +++ /dev/null @@ -1,343 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui; - -import com.google.common.collect.ImmutableList; -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.gui.options.*; -import me.jellysquid.mods.sodium.client.gui.options.binding.compat.VanillaBooleanOptionBinding; -import me.jellysquid.mods.sodium.client.gui.options.control.ControlValueFormatter; -import me.jellysquid.mods.sodium.client.gui.options.control.CyclingControl; -import me.jellysquid.mods.sodium.client.gui.options.control.SliderControl; -import me.jellysquid.mods.sodium.client.gui.options.control.TickBoxControl; -import me.jellysquid.mods.sodium.client.gui.options.storage.MinecraftOptionsStorage; -import me.jellysquid.mods.sodium.client.gui.options.storage.SodiumOptionsStorage; -import me.jellysquid.mods.sodium.client.util.UnsafeUtil; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.options.Option; -import net.minecraft.client.options.*; -import net.minecraft.client.util.Window; - -import java.util.ArrayList; -import java.util.List; - -public class SodiumGameOptionPages { - private static final SodiumOptionsStorage sodiumOpts = new SodiumOptionsStorage(); - private static final MinecraftOptionsStorage vanillaOpts = new MinecraftOptionsStorage(); - - public static OptionPage general() { - List groups = new ArrayList<>(); - - groups.add(OptionGroup.createBuilder() - .add(OptionImpl.createBuilder(int.class, vanillaOpts) - .setName("View Distance") - .setTooltip("The view distance controls how far away terrain will be rendered. Lower distances mean that less terrain will be " + - "rendered, improving frame rates.") - .setControl(option -> new SliderControl(option, 2, 32, 1, ControlValueFormatter.quantity("Chunks"))) - .setBinding((options, value) -> options.viewDistance = value, options -> options.viewDistance) - .setImpact(OptionImpact.HIGH) - .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) - .build()) - .add(OptionImpl.createBuilder(int.class, vanillaOpts) - .setName("Brightness") - .setTooltip("Controls the brightness (gamma) of the game.") - .setControl(opt -> new SliderControl(opt, 0, 500, 1, ControlValueFormatter.brightness())) - .setBinding((opts, value) -> opts.gamma = value * 0.01D, (opts) -> (int) (opts.gamma / 0.01D)) - .build()) - .build()); - - groups.add(OptionGroup.createBuilder() - .add(OptionImpl.createBuilder(int.class, vanillaOpts) - .setName("GUI Scale") - .setTooltip("Sets the maximum scale factor to be used for the user interface. If 'auto' is used, then the largest scale factor " + - "will always be used.") - .setControl(option -> new SliderControl(option, 0, 4, 1, ControlValueFormatter.guiScale())) - .setBinding((opts, value) -> { - opts.guiScale = value; - - MinecraftClient client = MinecraftClient.getInstance(); - client.onResolutionChanged(); - }, opts -> opts.guiScale) - .build()) - .add(OptionImpl.createBuilder(boolean.class, vanillaOpts) - .setName("Fullscreen") - .setTooltip("If enabled, the game will display in full-screen (if supported).") - .setControl(TickBoxControl::new) - .setBinding((opts, value) -> { - opts.fullscreen = value; - - MinecraftClient client = MinecraftClient.getInstance(); - Window window = client.getWindow(); - - if (window != null && window.isFullscreen() != opts.fullscreen) { - window.toggleFullscreen(); - - // The client might not be able to enter full-screen mode - opts.fullscreen = window.isFullscreen(); - } - }, (opts) -> opts.fullscreen) - .build()) - .add(OptionImpl.createBuilder(boolean.class, vanillaOpts) - .setName("V-Sync") - .setTooltip("If enabled, the game's frame rate will be synchronized to the monitor's refresh rate, making for a generally smoother experience " + - "at the expense of overall input latency. This setting might reduce performance if your system is too slow.") - .setControl(TickBoxControl::new) - .setBinding(new VanillaBooleanOptionBinding(Option.VSYNC)) - .setImpact(OptionImpact.VARIES) - .build()) - .add(OptionImpl.createBuilder(int.class, vanillaOpts) - .setName("FPS Limit") - .setTooltip("Limits the maximum number of frames per second. In effect, this will throttle the game and can be useful when you want to conserve " + - "battery life or multi-task between other applications. If V-Sync is enabled, this option will be ignored unless it is lower than your " + - "display's refresh rate.") - .setControl(option -> new SliderControl(option, 5, 260, 5, ControlValueFormatter.fpsLimit())) - .setBinding((opts, value) -> { - opts.maxFps = value; - MinecraftClient.getInstance().getWindow().setFramerateLimit(value); - }, opts -> opts.maxFps) - .build()) - .build()); - - groups.add(OptionGroup.createBuilder() - .add(OptionImpl.createBuilder(boolean.class, vanillaOpts) - .setName("View Bobbing") - .setTooltip("If enabled, the player's view will sway and bob when moving around. Players who suffer from motion sickness can benefit from disabling this.") - .setControl(TickBoxControl::new) - .setBinding(new VanillaBooleanOptionBinding(Option.VIEW_BOBBING)) - .build()) - .add(OptionImpl.createBuilder(AttackIndicator.class, vanillaOpts) - .setName("Attack Indicator") - .setTooltip("Controls where the Attack Indicator is displayed on screen.") - .setControl(opts -> new CyclingControl<>(opts, AttackIndicator.class, new String[] { "Off", "Crosshair", "Hotbar" })) - .setBinding((opts, value) -> opts.attackIndicator = value, (opts) -> opts.attackIndicator) - .build()) - .build()); - - return new OptionPage("General", ImmutableList.copyOf(groups)); - } - - public static OptionPage quality() { - List groups = new ArrayList<>(); - - groups.add(OptionGroup.createBuilder() - .add(OptionImpl.createBuilder(SodiumGameOptions.DefaultGraphicsQuality.class, vanillaOpts) - .setName("Graphics Quality") - .setTooltip("The default graphics quality controls some legacy options and is necessary for mod compatibility. If the options below are left to " + - "\"Default\", they will use this setting.") - .setControl(option -> new CyclingControl<>(option, SodiumGameOptions.DefaultGraphicsQuality.class)) - .setBinding( - (opts, value) -> opts.fancyGraphics = value == SodiumGameOptions.DefaultGraphicsQuality.FANCY, - opts -> (opts.fancyGraphics ? SodiumGameOptions.DefaultGraphicsQuality.FANCY : SodiumGameOptions.DefaultGraphicsQuality.FAST)) - .setImpact(OptionImpact.HIGH) - .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) - .build()) - .build()); - - groups.add(OptionGroup.createBuilder() - .add(OptionImpl.createBuilder(CloudRenderMode.class, vanillaOpts) - .setName("Clouds Quality") - .setTooltip("Controls the quality of rendered clouds in the sky.") - .setControl(option -> new CyclingControl<>(option, CloudRenderMode.class, new String[] { "Off", "Fast", "Fancy" })) - .setBinding((opts, value) -> opts.cloudRenderMode = value, opts -> opts.cloudRenderMode) - .setImpact(OptionImpact.LOW) - .setFlags(OptionFlag.REQUIRES_CLOUD_RELOAD) - .build()) - .add(OptionImpl.createBuilder(ParticlesOption.class, vanillaOpts) - .setName("Particle Quality") - .setTooltip("Controls the maximum number of particles which can be present on screen at any one time.") - .setControl(opt -> new CyclingControl<>(opt, ParticlesOption.class, new String[] { "High", "Medium", "Low" })) - .setBinding((opts, value) -> opts.particles = value, (opts) -> opts.particles) - .setImpact(OptionImpact.MEDIUM) - .build()) - .add(OptionImpl.createBuilder(AoOption.class, vanillaOpts) - .setName("Smooth Lighting") - .setTooltip("Controls whether blocks will be smoothly lit and shaded. This slightly increases the amount " + - "of time needed to re-build a chunk, but doesn't affect frame rates.") - .setControl(option -> new CyclingControl<>(option, AoOption.class, new String[] { "Off", "Minimum", "Maximum" })) - .setBinding((opts, value) -> opts.ao = value, opts -> opts.ao) - .setImpact(OptionImpact.LOW) - .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) - .build()) - .add(OptionImpl.createBuilder(int.class, vanillaOpts) - .setName("Biome Blend") - .setTooltip("Controls the range which biomes will be sampled for block colorization. " + - "Higher values greatly increase the amount of time it takes to build chunks for diminishing improvements in quality.") - .setControl(option -> new SliderControl(option, 0, 7, 1, ControlValueFormatter.quantityOrDisabled("block(s)", "None"))) - .setBinding((opts, value) -> opts.biomeBlendRadius = value, opts -> opts.biomeBlendRadius) - .setImpact(OptionImpact.LOW) - .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) - .build()) - .add(OptionImpl.createBuilder(boolean.class, vanillaOpts) - .setName("Entity Shadows") - .setTooltip("If enabled, basic shadows will be rendered beneath mobs and other entities.") - .setControl(TickBoxControl::new) - .setBinding((opts, value) -> opts.entityShadows = value, opts -> opts.entityShadows) - .setImpact(OptionImpact.LOW) - .build()) - .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) - .setName("Vignette") - .setTooltip("If enabled, a vignette effect will be rendered on the player's view. This is very unlikely to make a difference " + - "to frame rates unless you are fill-rate limited.") - .setControl(TickBoxControl::new) - .setBinding((opts, value) -> opts.quality.enableVignette = value, opts -> opts.quality.enableVignette) - .setImpact(OptionImpact.LOW) - .build()) - .build()); - - - groups.add(OptionGroup.createBuilder() - .add(OptionImpl.createBuilder(int.class, vanillaOpts) - .setName("Mipmap Levels") - .setTooltip("Controls the number of mipmaps which will be used for block model textures. Higher values provide better rendering of blocks " + - "in the distance, but may adversely affect performance with many animated textures.") - .setControl(option -> new SliderControl(option, 0, 4, 1, ControlValueFormatter.multiplier())) - .setBinding((opts, value) -> opts.mipmapLevels = value, opts -> opts.mipmapLevels) - .setImpact(OptionImpact.MEDIUM) - .setFlags(OptionFlag.REQUIRES_ASSET_RELOAD) - .build()) - .build()); - - - return new OptionPage("Quality", ImmutableList.copyOf(groups)); - } - - public static OptionPage advanced() { - boolean disableBlacklist = SodiumClientMod.options().advanced.disableDriverBlacklist; - - List groups = new ArrayList<>(); - - groups.add(OptionGroup.createBuilder() - .add(OptionImpl.createBuilder(SodiumGameOptions.ChunkRendererBackendOption.class, sodiumOpts) - .setName("Chunk Renderer") - .setTooltip("Modern versions of OpenGL provide features which can be used to greatly reduce driver overhead when rendering chunks. " + - "You should use the latest feature set allowed by Sodium for optimal performance. If you're experiencing chunk rendering issues " + - "or driver crashes, try using the older (and possibly more stable) feature sets.") - .setControl((opt) -> new CyclingControl<>(opt, SodiumGameOptions.ChunkRendererBackendOption.class, - SodiumGameOptions.ChunkRendererBackendOption.getAvailableOptions(disableBlacklist))) - .setBinding((opts, value) -> opts.advanced.chunkRendererBackend = value, opts -> opts.advanced.chunkRendererBackend) - .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) - .build()) - .build()); - - groups.add(OptionGroup.createBuilder() - .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) - .setName("Use Chunk Face Culling") - .setTooltip("If enabled, an additional culling pass will be performed on the CPU to determine which planes of a chunk mesh are visible. This " + - "can eliminate a large number of block faces very early in the rendering process, saving memory bandwidth and time on the GPU.") - .setControl(TickBoxControl::new) - .setImpact(OptionImpact.MEDIUM) - .setBinding((opts, value) -> opts.advanced.useChunkFaceCulling = value, opts -> opts.advanced.useChunkFaceCulling) - .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) - .build() - ) - .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) - .setName("Use Compact Vertex Format") - .setTooltip("If enabled, a more compact vertex format will be used for chunk meshes which limits the precision of vertex attributes. This format " + - "will reduce graphics memory usage and bandwidth requirements by around 40%, but could cause z-fighting/flickering texture issues in " + - "some edge cases.") - .setControl(TickBoxControl::new) - .setImpact(OptionImpact.MEDIUM) - .setBinding((opts, value) -> opts.advanced.useCompactVertexFormat = value, opts -> opts.advanced.useCompactVertexFormat) - .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) - .build() - ) - .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) - .setName("Use Fog Occlusion") - .setTooltip("If enabled, chunks which are determined to be fully hidden by fog effects will be skipped during rendering. This " + - "will generally provide a modest improvement to the number of chunks rendered each frame, especially " + - "where fog effects are heavier (i.e. while underwater.)") - .setControl(TickBoxControl::new) - .setBinding((opts, value) -> opts.advanced.useFogOcclusion = value, opts -> opts.advanced.useFogOcclusion) - .setImpact(OptionImpact.MEDIUM) - .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) - .build() - ) - .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) - .setName("Use Entity Culling") - .setTooltip("If enabled, a secondary culling pass will be performed before attempting to render an entity. This additional pass " + - "takes into account the current set of visible chunks and removes entities which are not in any visible chunks.") - .setControl(TickBoxControl::new) - .setImpact(OptionImpact.MEDIUM) - .setBinding((opts, value) -> opts.advanced.useEntityCulling = value, opts -> opts.advanced.useEntityCulling) - .build() - ) - .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) - .setName("Use Particle Culling") - .setTooltip("If enabled, only particles which are determined to be visible will be rendered. This can provide a significant improvement " + - "to frame rates when many particles are nearby.") - .setControl(TickBoxControl::new) - .setImpact(OptionImpact.MEDIUM) - .setBinding((opts, value) -> opts.advanced.useParticleCulling = value, opts -> opts.advanced.useParticleCulling) - .build() - ) - .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) - .setName("Animate Only Visible Textures") - .setTooltip("If enabled, only animated textures determined to be visible will be updated. This can provide a significant boost to frame " + - "rates on some hardware. If you experience issues with some textures not being animated, disable this option.") - .setControl(TickBoxControl::new) - .setImpact(OptionImpact.MEDIUM) - .setBinding((opts, value) -> opts.advanced.animateOnlyVisibleTextures = value, opts -> opts.advanced.animateOnlyVisibleTextures) - .build() - ) - .build()); - - groups.add(OptionGroup.createBuilder() - .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) - .setName("Use Memory Intrinsics") - .setTooltip("If enabled, special intrinsics will be used to speed up the copying of client memory in certain vertex-limited scenarios, such " + - "as particle and text rendering. This option only exists for debugging purposes and should be left enabled unless you know what " + - "you are doing.") - .setControl(TickBoxControl::new) - .setImpact(OptionImpact.MEDIUM) - .setEnabled(UnsafeUtil.isSupported()) - .setBinding((opts, value) -> opts.advanced.useMemoryIntrinsics = value, opts -> opts.advanced.useMemoryIntrinsics) - .build() - ) - .build()); - - groups.add(OptionGroup.createBuilder() - .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) - .setName("Disable Driver Blacklist") - .setTooltip("If selected, Sodium will ignore the built-in driver blacklist and enable options which are known to be broken " + - "with your system configuration. This might cause serious problems and should not be used unless you really do know better. The settings " + - "screen must be saved, closed, and re-opened after changing this option in order to reveal previously hidden options.") - .setControl(TickBoxControl::new) - .setBinding((opts, value) -> opts.advanced.disableDriverBlacklist = value, opts -> opts.advanced.disableDriverBlacklist) - .build() - - ) - .build()); - return new OptionPage("Advanced", ImmutableList.copyOf(groups)); - } - - public static OptionPage unofficial() { - List groups = new ArrayList<>(); - - groups.add(OptionGroup.createBuilder() - .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) - .setName("Use Planar Fog") - .setTooltip("If enabled, planar fog will be used rather than radial. Fewer chunks will be hidden by fog, which may noticeably reduce performance " + - "in areas with thick fog such as in the nether. This is vanilla behavior on systems where GL_NV_fog_distance is unavailable, but is not " + - "considered desirable for any reason other than visibility. This option is not included in official releases of Sodium.") - .setControl(TickBoxControl::new) - .setBinding((opts, value) -> opts.speedrun.usePlanarFog = value, opts -> opts.speedrun.usePlanarFog) - .setImpact(OptionImpact.MEDIUM) - .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) - .build() - ) - .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) - .setName("Show Entity Culling") - .setTooltip("If enabled, Entity Culling will be added to the vanilla menu so it can be toggled while in a world.") - .setControl(TickBoxControl::new) - .setBinding((opts, value) -> opts.speedrun.showEntityCulling = value, opts -> opts.speedrun.showEntityCulling) - .build() - ) - .add(OptionImpl.createBuilder(boolean.class, sodiumOpts) - .setName("Show Fog Occlusion") - .setTooltip("If enabled, Fog Occlusion will be added to the vanilla menu so it can be toggled while in a world.") - .setControl(TickBoxControl::new) - .setBinding((opts, value) -> opts.speedrun.showFogOcclusion = value, opts -> opts.speedrun.showFogOcclusion) - .build() - ) - .build()); - return new OptionPage("Speedrun", ImmutableList.copyOf(groups)); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java index 25c14d5f7..1f059b165 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumGameOptions.java @@ -1,76 +1,102 @@ package me.jellysquid.mods.sodium.client.gui; -import com.google.gson.FieldNamingPolicy; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonSyntaxException; +import me.contaria.speedrunapi.config.SpeedrunConfigAPI; +import me.contaria.speedrunapi.config.api.SpeedrunConfig; +import me.contaria.speedrunapi.config.api.SpeedrunConfigStorage; +import me.contaria.speedrunapi.config.api.SpeedrunOption; +import me.contaria.speedrunapi.config.api.annotations.Config; import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.gui.options.TextProvider; import me.jellysquid.mods.sodium.client.render.chunk.backends.gl20.GL20ChunkRenderBackend; import me.jellysquid.mods.sodium.client.render.chunk.backends.gl30.GL30ChunkRenderBackend; import me.jellysquid.mods.sodium.client.render.chunk.backends.gl43.GL43ChunkRenderBackend; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.render.WorldRenderer; +import org.jetbrains.annotations.Nullable; -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.lang.reflect.Modifier; +import java.lang.reflect.Field; import java.util.Arrays; import java.util.stream.Stream; -public class SodiumGameOptions { +// ensure mac sodium is launched before StandardSettings with priority +@Config(init = Config.InitPoint.POSTLAUNCH, priority = 500) +public class SodiumGameOptions implements SpeedrunConfig { + @Config.Category("quality") public final QualitySettings quality = new QualitySettings(); - public final AdvancedSettings advanced = new AdvancedSettings(); - public final SpeedrunSettings speedrun = new SpeedrunSettings(); - private File file; + @Config.Category("advanced") + public final AdvancedSettings advanced = new AdvancedSettings(); - public void notifyListeners() { - SodiumClientMod.onConfigChanged(this); - } + @Config.Category("speedrun") + public final SpeedrunSettings speedrun = new SpeedrunSettings(); - public static class AdvancedSettings { + public static class AdvancedSettings implements SpeedrunConfigStorage { + @Config.Numbers.Whole.Bounds(min = 0, max = 64) + public int maxChunkThreads; + @Config.Numbers.Whole.Bounds(min = 0, max = 64) + public int targetChunkThreads; + @Config.Numbers.Whole.Bounds(min = 0, max = 64) + public int initialChunkThreads; + @Config.Numbers.Whole.Bounds(min = 1, max = 2000) + public int quickThreadCreationInterval = 100; + @Config.Numbers.Whole.Bounds(min = 1, max = 10000) + public int slowThreadCreationInterval = 1000; public ChunkRendererBackendOption chunkRendererBackend = ChunkRendererBackendOption.BEST; - public boolean animateOnlyVisibleTextures = true; + public boolean useChunkFaceCulling = true; + public boolean useCompactVertexFormat = true; + public boolean useFogOcclusion = true; public boolean useEntityCulling = false; public boolean useParticleCulling = true; - public boolean useFogOcclusion = true; - public boolean useCompactVertexFormat = true; - public boolean useChunkFaceCulling = true; + public boolean animateOnlyVisibleTextures = true; public boolean useMemoryIntrinsics = true; public boolean disableDriverBlacklist = false; + + @Override + public @Nullable SpeedrunOption parseField(Field field, SpeedrunConfig config, String... idPrefix) { + if (ChunkRendererBackendOption.class.equals(field.getType())) { + return new SpeedrunConfigAPI.CustomOption.Builder(config, this, field, idPrefix) + .createWidget((option, innerConfig, configStorage, optionField) -> new ButtonWidget(0, 0, 150, 20, option.getText(), button -> { + ChunkRendererBackendOption[] options = ChunkRendererBackendOption.getAvailableOptions(SodiumClientMod.options().advanced.disableDriverBlacklist); + ChunkRendererBackendOption current = option.get(); + int index = -1; + for (int i = 0; i < options.length; ++i) { + if (options[i].equals(current)) { + index = i; + } + } + option.set(options[(index + 1) % options.length]); + button.setMessage(option.getText()); + })) + .build(); + } + // this is how you call default super methods + return SpeedrunConfigStorage.super.parseField(field, config, idPrefix); + } } - public static class QualitySettings { - public boolean enableVignette = true; + public static class QualitySettings implements SpeedrunConfigStorage { + public boolean enableVignette = false; } - public static class SpeedrunSettings { + public static class SpeedrunSettings implements SpeedrunConfigStorage { public boolean usePlanarFog = true; public boolean showEntityCulling = true; public boolean showFogOcclusion = true; } - public enum ChunkRendererBackendOption implements TextProvider { - GL43("Multidraw (GL 4.3)", GL43ChunkRenderBackend::isSupported), - GL30("Oneshot (GL 3.0)", GL30ChunkRenderBackend::isSupported), - GL20("Oneshot (GL 2.0)", GL20ChunkRenderBackend::isSupported); + public enum ChunkRendererBackendOption { + GL43(GL43ChunkRenderBackend::isSupported), + GL30(GL30ChunkRenderBackend::isSupported), + GL20(GL20ChunkRenderBackend::isSupported); public static final ChunkRendererBackendOption BEST = pickBestBackend(); - private final String name; private final SupportCheck supportedFunc; - ChunkRendererBackendOption(String name, SupportCheck supportedFunc) { - this.name = name; + ChunkRendererBackendOption(SupportCheck supportedFunc) { this.supportedFunc = supportedFunc; } - @Override - public String getLocalizedName() { - return this.name; - } - public boolean isSupported(boolean disableBlacklist) { return this.supportedFunc.isSupported(disableBlacklist); } @@ -96,71 +122,19 @@ private interface SupportCheck { } } - public enum DefaultGraphicsQuality implements TextProvider { - FAST("Fast"), - FANCY("Fancy"); - - private final String name; - - DefaultGraphicsQuality(String name) { - this.name = name; - } - - @Override - public String getLocalizedName() { - return this.name; - } - } - - private static final Gson gson = new GsonBuilder() - .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) - .setPrettyPrinting() - .excludeFieldsWithModifiers(Modifier.PRIVATE) - .create(); - - public static SodiumGameOptions load(File file) { - SodiumGameOptions config = null; - - boolean exists = file.exists(); - if (exists) { - try (FileReader reader = new FileReader(file)) { - config = gson.fromJson(reader, SodiumGameOptions.class); - } catch (IOException | JsonSyntaxException e) { - SodiumClientMod.logger().warn("Could not parse config, falling back to default"); - } - } - if (!exists || config == null) { - config = new SodiumGameOptions(); - } - - config.sanitize(); - config.file = file; - config.writeChanges(); - - return config; + { + SodiumClientMod.CONFIG = this; } - private void sanitize() { - if (this.advanced.chunkRendererBackend == null) { - this.advanced.chunkRendererBackend = ChunkRendererBackendOption.BEST; - } + @Override + public void finishSaving() { + SodiumClientMod.onConfigChanged(this); + WorldRenderer worldRenderer = MinecraftClient.getInstance().worldRenderer; + if (worldRenderer != null) worldRenderer.reload(); } - public void writeChanges() { - File dir = this.file.getParentFile(); - - if (!dir.exists()) { - if (!dir.mkdirs()) { - throw new RuntimeException("Could not create parent directories"); - } - } else if (!dir.isDirectory()) { - throw new RuntimeException("The parent file is not a directory"); - } - - try (FileWriter writer = new FileWriter(this.file)) { - gson.toJson(this, writer); - } catch (IOException e) { - throw new RuntimeException("Could not save configuration file", e); - } + @Override + public String modID() { + return "sodium"; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java deleted file mode 100644 index 85a727b76..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/SodiumOptionsGUI.java +++ /dev/null @@ -1,273 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui; - -import me.jellysquid.mods.sodium.client.gui.options.*; -import me.jellysquid.mods.sodium.client.gui.options.control.Control; -import me.jellysquid.mods.sodium.client.gui.options.control.ControlElement; -import me.jellysquid.mods.sodium.client.gui.options.storage.OptionStorage; -import me.jellysquid.mods.sodium.client.gui.widgets.FlatButtonWidget; -import me.jellysquid.mods.sodium.client.util.Dim2i; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.Drawable; -import net.minecraft.client.gui.Element; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.screen.VideoOptionsScreen; -import net.minecraft.client.util.TextFormat; -import net.minecraft.text.TranslatableText; -import net.minecraft.util.Formatting; -import org.lwjgl.glfw.GLFW; - -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.HashSet; -import java.util.List; -import java.util.stream.Stream; - -public class SodiumOptionsGUI extends Screen { - private final List pages = new ArrayList<>(); - - private final List> controls = new ArrayList<>(); - private final List drawable = new ArrayList<>(); - - private final Screen prevScreen; - - private OptionPage currentPage; - - private FlatButtonWidget applyButton, closeButton, undoButton; - private boolean hasPendingChanges; - private ControlElement hoveredElement; - - public SodiumOptionsGUI(Screen prevScreen) { - super(new TranslatableText("Sodium Options")); - - this.prevScreen = prevScreen; - - this.pages.add(SodiumGameOptionPages.general()); - this.pages.add(SodiumGameOptionPages.quality()); - this.pages.add(SodiumGameOptionPages.advanced()); - this.pages.add(SodiumGameOptionPages.unofficial()); - } - - public void setPage(OptionPage page) { - this.currentPage = page; - - this.rebuildGUI(); - } - - @Override - protected void init() { - super.init(); - - this.rebuildGUI(); - } - - private void rebuildGUI() { - this.controls.clear(); - this.children.clear(); - this.drawable.clear(); - - if (this.currentPage == null) { - if (this.pages.isEmpty()) { - throw new IllegalStateException("No pages are available?!"); - } - - // Just use the first page for now - this.currentPage = this.pages.get(0); - } - - this.rebuildGUIPages(); - this.rebuildGUIOptions(); - - this.undoButton = new FlatButtonWidget(new Dim2i(this.width - 211, this.height - 30, 65, 20), "Undo", this::undoChanges); - this.applyButton = new FlatButtonWidget(new Dim2i(this.width - 142, this.height - 30, 65, 20), "Apply", this::applyChanges); - this.closeButton = new FlatButtonWidget(new Dim2i(this.width - 73, this.height - 30, 65, 20), "Close", this::onClose); - - this.children.add(this.undoButton); - this.children.add(this.applyButton); - this.children.add(this.closeButton); - - for (Element element : this.children) { - if (element instanceof Drawable) { - this.drawable.add((Drawable) element); - } - } - } - - private void rebuildGUIPages() { - int x = 10; - int y = 6; - - for (OptionPage page : this.pages) { - int width = 10 + this.font.getStringWidth(page.getName()); - - FlatButtonWidget button = new FlatButtonWidget(new Dim2i(x, y, width, 16), page.getName(), () -> this.setPage(page)); - button.setSelected(this.currentPage == page); - - x += width + 6; - - this.children.add(button); - } - } - - private void rebuildGUIOptions() { - int x = 10; - int y = 28; - - for (OptionGroup group : this.currentPage.getGroups()) { - // Add each option's control element - for (Option option : group.getOptions()) { - Control control = option.getControl(); - ControlElement element = control.createElement(new Dim2i(x, y, 200, 18)); - - this.controls.add(element); - this.children.add(element); - - // Move down to the next option - y += 18; - } - - // Add padding beneath each option group - y += 4; - } - } - - @Override - public void render(int mouseX, int mouseY, float delta) { - super.renderBackground(); - - this.updateControls(); - - for (Drawable drawable : this.drawable) { - drawable.render(mouseX, mouseY, delta); - } - - if (this.hoveredElement != null) { - this.renderOptionTooltip(this.hoveredElement); - } - } - - private void updateControls() { - ControlElement hovered = this.getActiveControls() - .filter(ControlElement::isHovered) - .findFirst() - .orElse(null); - - boolean hasChanges = this.getAllOptions() - .anyMatch(Option::hasChanged); - - for (OptionPage page : this.pages) { - for (Option option : page.getOptions()) { - if (option.hasChanged()) { - hasChanges = true; - } - } - } - - this.applyButton.setEnabled(hasChanges); - this.undoButton.setVisible(hasChanges); - this.closeButton.setEnabled(!hasChanges); - - this.hasPendingChanges = hasChanges; - this.hoveredElement = hovered; - } - - private Stream> getAllOptions() { - return this.pages.stream() - .flatMap(s -> s.getOptions().stream()); - } - - private Stream> getActiveControls() { - return this.controls.stream(); - } - - private void renderOptionTooltip(ControlElement element) { - Dim2i dim = element.getDimensions(); - - int textPadding = 3; - int boxPadding = 3; - - int boxWidth = 200; - - int boxY = dim.getOriginY(); - int boxX = dim.getLimitX() + boxPadding; - - Option option = element.getOption(); - List tooltip = new ArrayList<>(this.font.wrapStringToWidthAsList(option.getTooltip(), boxWidth - (textPadding * 2))); - - OptionImpact impact = option.getImpact(); - - if (impact != null) { - tooltip.add(TextFormat.GRAY + "Performance Impact: " + impact.toDisplayString()); - } - - int boxHeight = (tooltip.size() * 12) + boxPadding; - int boxYLimit = boxY + boxHeight; - int boxYCutoff = this.height - 40; - - // If the box is going to be cutoff on the Y-axis, move it back up the difference - if (boxYLimit > boxYCutoff) { - boxY -= boxYLimit - boxYCutoff; - } - - this.fillGradient(boxX, boxY, boxX + boxWidth, boxY + boxHeight, 0xE0000000, 0xE0000000); - - for (int i = 0; i < tooltip.size(); i++) { - this.font.draw(tooltip.get(i), boxX + textPadding, boxY + textPadding + (i * 12), 0xFFFFFFFF); - } - } - - private void applyChanges() { - final HashSet> dirtyStorages = new HashSet<>(); - final EnumSet flags = EnumSet.noneOf(OptionFlag.class); - - this.getAllOptions().forEach((option -> { - if (!option.hasChanged()) { - return; - } - - option.applyChanges(); - - flags.addAll(option.getFlags()); - dirtyStorages.add(option.getStorage()); - })); - - MinecraftClient client = MinecraftClient.getInstance(); - - if (flags.contains(OptionFlag.REQUIRES_RENDERER_RELOAD)) { - client.worldRenderer.reload(); - } - - if (flags.contains(OptionFlag.REQUIRES_ASSET_RELOAD)) { - client.resetMipmapLevels(client.options.mipmapLevels); - client.reloadResourcesConcurrently(); - } - - for (OptionStorage storage : dirtyStorages) { - storage.save(); - } - } - - private void undoChanges() { - this.getAllOptions() - .forEach(Option::reset); - } - - @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - if (keyCode == GLFW.GLFW_KEY_P && (modifiers & GLFW.GLFW_MOD_SHIFT) != 0) { - MinecraftClient.getInstance().openScreen(new VideoOptionsScreen(this.prevScreen, MinecraftClient.getInstance().options)); - return true; - } - - return super.keyPressed(keyCode, scanCode, modifiers); - } - - @Override - public boolean shouldCloseOnEsc() { - return !this.hasPendingChanges; - } - - @Override - public void onClose() { - this.minecraft.openScreen(this.prevScreen); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/Option.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/Option.java deleted file mode 100644 index 8169fff1f..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/Option.java +++ /dev/null @@ -1,32 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options; - -import me.jellysquid.mods.sodium.client.gui.options.control.Control; -import me.jellysquid.mods.sodium.client.gui.options.storage.OptionStorage; - -import java.util.Collection; - -public interface Option { - String getName(); - - String getTooltip(); - - OptionImpact getImpact(); - - Control getControl(); - - T getValue(); - - void setValue(T value); - - void reset(); - - OptionStorage getStorage(); - - boolean isAvailable(); - - boolean hasChanged(); - - void applyChanges(); - - Collection getFlags(); -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionFlag.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionFlag.java deleted file mode 100644 index d3c7cc44a..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionFlag.java +++ /dev/null @@ -1,8 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options; - -public enum OptionFlag { - REQUIRES_RENDERER_RELOAD, - REQUIRES_CLOUD_RELOAD, - REQUIRES_ASSET_RELOAD, - REQUIRES_GAME_RESTART, -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionGroup.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionGroup.java deleted file mode 100644 index 97426724a..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionGroup.java +++ /dev/null @@ -1,39 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options; - -import com.google.common.collect.ImmutableList; -import org.apache.commons.lang3.Validate; - -import java.util.ArrayList; -import java.util.List; - -public class OptionGroup { - private final ImmutableList> options; - - private OptionGroup(ImmutableList> options) { - this.options = options; - } - - public static Builder createBuilder() { - return new Builder(); - } - - public ImmutableList> getOptions() { - return this.options; - } - - public static class Builder { - private final List> options = new ArrayList<>(); - - public Builder add(Option option) { - this.options.add(option); - - return this; - } - - public OptionGroup build() { - Validate.notEmpty(this.options, "At least one option must be specified"); - - return new OptionGroup(ImmutableList.copyOf(this.options)); - } - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpact.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpact.java deleted file mode 100644 index 5b0a6696a..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpact.java +++ /dev/null @@ -1,23 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options; - -import net.minecraft.client.util.TextFormat; - -public enum OptionImpact { - LOW(TextFormat.GREEN, "Low"), - MEDIUM(TextFormat.YELLOW, "Medium"), - HIGH(TextFormat.GOLD, "High"), - EXTREME(TextFormat.RED, "Extreme"), - VARIES(TextFormat.WHITE, "Varies"); - - private final TextFormat color; - private final String text; - - OptionImpact(TextFormat color, String text) { - this.color = color; - this.text = text; - } - - public String toDisplayString() { - return this.color + this.text; - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpl.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpl.java deleted file mode 100644 index 63d3f44d2..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionImpl.java +++ /dev/null @@ -1,202 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options; - -import me.jellysquid.mods.sodium.client.gui.options.binding.GenericBinding; -import me.jellysquid.mods.sodium.client.gui.options.binding.OptionBinding; -import me.jellysquid.mods.sodium.client.gui.options.control.Control; -import me.jellysquid.mods.sodium.client.gui.options.storage.OptionStorage; -import org.apache.commons.lang3.Validate; - -import java.util.Collection; -import java.util.Collections; -import java.util.EnumSet; -import java.util.function.BiConsumer; -import java.util.function.Function; - -public class OptionImpl implements Option { - private final OptionStorage storage; - - private final OptionBinding binding; - private final Control control; - - private final EnumSet flags; - - private final String name; - private final String tooltip; - - private final OptionImpact impact; - - private T value; - private T modifiedValue; - - private final boolean enabled; - - private OptionImpl(OptionStorage storage, - String name, - String tooltip, - OptionBinding binding, - Function, Control> control, - EnumSet flags, - OptionImpact impact, - boolean enabled) { - this.storage = storage; - this.name = name; - this.tooltip = tooltip; - this.binding = binding; - this.impact = impact; - this.flags = flags; - this.control = control.apply(this); - this.enabled = enabled; - - this.reset(); - } - - @Override - public String getName() { - return this.name; - } - - @Override - public String getTooltip() { - return this.tooltip; - } - - @Override - public OptionImpact getImpact() { - return this.impact; - } - - @Override - public Control getControl() { - return this.control; - } - - @Override - public T getValue() { - return this.modifiedValue; - } - - @Override - public void setValue(T value) { - this.modifiedValue = value; - } - - @Override - public void reset() { - this.value = this.binding.getValue(this.storage.getData()); - this.modifiedValue = this.value; - } - - @Override - public OptionStorage getStorage() { - return this.storage; - } - - @Override - public boolean isAvailable() { - return this.enabled; - } - - @Override - public boolean hasChanged() { - return this.value != this.modifiedValue; - } - - @Override - public void applyChanges() { - this.binding.setValue(this.storage.getData(), this.modifiedValue); - this.value = this.modifiedValue; - } - - @Override - public Collection getFlags() { - return this.flags; - } - - public static OptionImpl.Builder createBuilder(Class type, OptionStorage storage) { - return new Builder<>(storage); - } - - public static class Builder { - private final OptionStorage storage; - private String name; - private String tooltip; - private OptionBinding binding; - private Function, Control> control; - private OptionImpact impact; - private final EnumSet flags = EnumSet.noneOf(OptionFlag.class); - private boolean enabled = true; - - private Builder(OptionStorage storage) { - this.storage = storage; - } - - public Builder setName(String name) { - Validate.notNull(name, "Argument must not be null"); - - this.name = name; - - return this; - } - - public Builder setTooltip(String tooltip) { - Validate.notNull(tooltip, "Argument must not be null"); - - this.tooltip = tooltip; - - return this; - } - - public Builder setBinding(BiConsumer setter, Function getter) { - Validate.notNull(setter, "Setter must not be null"); - Validate.notNull(getter, "Getter must not be null"); - - this.binding = new GenericBinding<>(setter, getter); - - return this; - } - - - public Builder setBinding(OptionBinding binding) { - Validate.notNull(binding, "Argument must not be null"); - - this.binding = binding; - - return this; - } - - public Builder setControl(Function, Control> control) { - Validate.notNull(control, "Argument must not be null"); - - this.control = control; - - return this; - } - - public Builder setImpact(OptionImpact impact) { - this.impact = impact; - - return this; - } - - public Builder setEnabled(boolean value) { - this.enabled = value; - - return this; - } - - public Builder setFlags(OptionFlag... flags) { - Collections.addAll(this.flags, flags); - - return this; - } - - public OptionImpl build() { - Validate.notNull(this.name, "Name must be specified"); - Validate.notNull(this.tooltip, "Tooltip must be specified"); - Validate.notNull(this.binding, "Option binding must be specified"); - Validate.notNull(this.control, "Control must be specified"); - - return new OptionImpl<>(this.storage, this.name, this.tooltip, this.binding, this.control, this.flags, this.impact, this.enabled); - } - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionPage.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionPage.java deleted file mode 100644 index a02254c90..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/OptionPage.java +++ /dev/null @@ -1,35 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options; - -import com.google.common.collect.ImmutableList; - -public class OptionPage { - private final String name; - private final ImmutableList groups; - private final ImmutableList> options; - - public OptionPage(String name, ImmutableList groups) { - this.name = name; - this.groups = groups; - - ImmutableList.Builder> builder = ImmutableList.builder(); - - for (OptionGroup group : groups) { - builder.addAll(group.getOptions()); - } - - this.options = builder.build(); - } - - public ImmutableList getGroups() { - return this.groups; - } - - public ImmutableList> getOptions() { - return this.options; - } - - public String getName() { - return this.name; - } - -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/TextProvider.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/TextProvider.java deleted file mode 100644 index a7ace2ef5..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/TextProvider.java +++ /dev/null @@ -1,5 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options; - -public interface TextProvider { - String getLocalizedName(); -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/GenericBinding.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/GenericBinding.java deleted file mode 100644 index 9e166c93e..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/GenericBinding.java +++ /dev/null @@ -1,24 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options.binding; - -import java.util.function.BiConsumer; -import java.util.function.Function; - -public class GenericBinding implements OptionBinding { - private final BiConsumer setter; - private final Function getter; - - public GenericBinding(BiConsumer setter, Function getter) { - this.setter = setter; - this.getter = getter; - } - - @Override - public void setValue(S storage, T value) { - this.setter.accept(storage, value); - } - - @Override - public T getValue(S storage) { - return this.getter.apply(storage); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/OptionBinding.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/OptionBinding.java deleted file mode 100644 index 5e597a679..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/OptionBinding.java +++ /dev/null @@ -1,7 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options.binding; - -public interface OptionBinding { - void setValue(S storage, T value); - - T getValue(S storage); -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/compat/VanillaBooleanOptionBinding.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/compat/VanillaBooleanOptionBinding.java deleted file mode 100644 index 646d87208..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/binding/compat/VanillaBooleanOptionBinding.java +++ /dev/null @@ -1,23 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options.binding.compat; - -import me.jellysquid.mods.sodium.client.gui.options.binding.OptionBinding; -import net.minecraft.client.options.BooleanOption; -import net.minecraft.client.options.GameOptions; - -public class VanillaBooleanOptionBinding implements OptionBinding { - private final BooleanOption option; - - public VanillaBooleanOptionBinding(BooleanOption option) { - this.option = option; - } - - @Override - public void setValue(GameOptions storage, Boolean value) { - this.option.set(storage, value.toString()); - } - - @Override - public Boolean getValue(GameOptions storage) { - return this.option.get(storage); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/Control.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/Control.java deleted file mode 100644 index 28931db82..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/Control.java +++ /dev/null @@ -1,12 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options.control; - -import me.jellysquid.mods.sodium.client.gui.options.Option; -import me.jellysquid.mods.sodium.client.util.Dim2i; - -public interface Control { - Option getOption(); - - ControlElement createElement(Dim2i dim); - - int getMaxWidth(); -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlElement.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlElement.java deleted file mode 100644 index f1809b971..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlElement.java +++ /dev/null @@ -1,57 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options.control; - -import me.jellysquid.mods.sodium.client.gui.options.Option; -import me.jellysquid.mods.sodium.client.gui.widgets.AbstractWidget; -import me.jellysquid.mods.sodium.client.util.Dim2i; -import net.minecraft.client.util.TextFormat; - -public class ControlElement extends AbstractWidget { - protected final Option option; - - protected final Dim2i dim; - - protected boolean hovered; - - public ControlElement(Option option, Dim2i dim) { - this.option = option; - this.dim = dim; - } - - public boolean isHovered() { - return this.hovered; - } - - @Override - public void render(int mouseX, int mouseY, float delta) { - String name = this.option.getName(); - String label; - - if (this.hovered && this.font.getStringWidth(name) > (this.dim.getWidth() - this.option.getControl().getMaxWidth())) { - name = name.substring(0, Math.min(name.length(), 10)) + "..."; - } - - if (this.option.isAvailable()) { - if (this.option.hasChanged()) { - label = TextFormat.ITALIC + name + " *"; - } else { - label = TextFormat.WHITE + name; - } - } else { - label = String.valueOf(TextFormat.GRAY) + TextFormat.STRIKETHROUGH + name; - } - - this.hovered = this.dim.containsCursor(mouseX, mouseY); - - - this.drawRect(this.dim.getOriginX(), this.dim.getOriginY(), this.dim.getLimitX(), this.dim.getLimitY(), this.hovered ? 0xE0000000 : 0x90000000); - this.drawString(label, this.dim.getOriginX() + 6, this.dim.getCenterY() - 4, 0xFFFFFFFF); - } - - public Option getOption() { - return this.option; - } - - public Dim2i getDimensions() { - return this.dim; - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlValueFormatter.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlValueFormatter.java deleted file mode 100644 index 64a82b8d0..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/ControlValueFormatter.java +++ /dev/null @@ -1,45 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options.control; - -public interface ControlValueFormatter { - static ControlValueFormatter guiScale() { - return (v) -> (v == 0) ? "Auto" : v + "x"; - } - - static ControlValueFormatter fpsLimit() { - return (v) -> (v == 260) ? "Unlimited" : v + " FPS"; - } - - static ControlValueFormatter brightness() { - return (v) -> { - if (v == 0) { - return "Moody"; - } else if (v == 100) { - return "Bright"; - } else { - return v + "%"; - } - }; - } - - String format(int value); - - static ControlValueFormatter percentage() { - return (v) -> v + "%"; - } - - static ControlValueFormatter multiplier() { - return (v) -> v + "x"; - } - - static ControlValueFormatter quantity(String name) { - return (v) -> v + " " + name; - } - - static ControlValueFormatter quantityOrDisabled(String name, String disableText) { - return (v) -> v == 0 ? disableText : v + " " + name; - } - - static ControlValueFormatter number() { - return String::valueOf; - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/CyclingControl.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/CyclingControl.java deleted file mode 100644 index aa0d50e70..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/CyclingControl.java +++ /dev/null @@ -1,108 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options.control; - -import me.jellysquid.mods.sodium.client.gui.options.Option; -import me.jellysquid.mods.sodium.client.gui.options.TextProvider; -import me.jellysquid.mods.sodium.client.util.Dim2i; -import org.apache.commons.lang3.Validate; - -public class CyclingControl> implements Control { - private final Option option; - private final T[] allowedValues; - private final String[] names; - - public CyclingControl(Option option, Class enumType) { - this(option, enumType, enumType.getEnumConstants()); - } - - public CyclingControl(Option option, Class enumType, String[] names) { - T[] universe = enumType.getEnumConstants(); - - Validate.isTrue(universe.length == names.length, "Mismatch between universe length and names array length"); - Validate.notEmpty(universe, "The enum universe must contain at least one item"); - - this.option = option; - this.allowedValues = universe; - this.names = names; - } - - public CyclingControl(Option option, Class enumType, T[] allowedValues) { - T[] universe = enumType.getEnumConstants(); - - this.option = option; - this.allowedValues = allowedValues; - this.names = new String[universe.length]; - - for (int i = 0; i < this.names.length; i++) { - String name; - T value = universe[i]; - - if (value instanceof TextProvider) { - name = ((TextProvider) value).getLocalizedName(); - } else { - name = value.name(); - } - - this.names[i] = name; - } - } - - @Override - public Option getOption() { - return this.option; - } - - @Override - public ControlElement createElement(Dim2i dim) { - return new CyclingControlElement<>(this.option, dim, this.allowedValues, this.names); - } - - @Override - public int getMaxWidth() { - return 70; - } - - private static class CyclingControlElement> extends ControlElement { - private final T[] allowedValues; - private final String[] names; - private int currentIndex; - - public CyclingControlElement(Option option, Dim2i dim, T[] allowedValues, String[] names) { - super(option, dim); - - this.allowedValues = allowedValues; - this.names = names; - this.currentIndex = 0; - - for (int i = 0; i < allowedValues.length; i++) { - if (allowedValues[i] == option.getValue()) { - this.currentIndex = i; - break; - } - } - } - - @Override - public void render(int mouseX, int mouseY, float delta) { - super.render(mouseX, mouseY, delta); - - Enum value = this.option.getValue(); - String name = this.names[value.ordinal()]; - - int strWidth = this.getStringWidth(name); - this.drawString(name, this.dim.getLimitX() - strWidth - 6, this.dim.getCenterY() - 4, 0xFFFFFFFF); - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (this.option.isAvailable() && button == 0 && this.dim.containsCursor(mouseX, mouseY)) { - this.currentIndex = (this.currentIndex + 1) % this.allowedValues.length; - this.option.setValue(this.allowedValues[this.currentIndex]); - this.playClickSound(); - - return true; - } - - return false; - } - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/SliderControl.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/SliderControl.java deleted file mode 100644 index 89c6ff340..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/SliderControl.java +++ /dev/null @@ -1,161 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options.control; - -import me.jellysquid.mods.sodium.client.gui.options.Option; -import me.jellysquid.mods.sodium.client.util.Dim2i; -import net.minecraft.client.util.Rect2i; -import net.minecraft.util.math.MathHelper; -import org.apache.commons.lang3.Validate; - -public class SliderControl implements Control { - private final Option option; - - private final int min, max, interval; - - private final ControlValueFormatter mode; - - public SliderControl(Option option, int min, int max, int interval, ControlValueFormatter mode) { - Validate.isTrue(max > min, "The maximum value must be greater than the minimum value"); - Validate.isTrue(interval > 0, "The slider interval must be greater than zero"); - Validate.isTrue(((max - min) % interval) == 0, "The maximum value must be divisable by the interval"); - Validate.notNull(mode, "The slider mode must not be null"); - - this.option = option; - this.min = min; - this.max = max; - this.interval = interval; - this.mode = mode; - } - - @Override - public ControlElement createElement(Dim2i dim) { - return new Button(this.option, dim, this.min, this.max, this.interval, this.mode); - } - - @Override - public Option getOption() { - return this.option; - } - - @Override - public int getMaxWidth() { - return 130; - } - - private static class Button extends ControlElement { - private static final int THUMB_WIDTH = 2, TRACK_HEIGHT = 1; - - private final Rect2i sliderBounds; - private final ControlValueFormatter formatter; - - private final int min; - private final int range; - private final int interval; - - private double thumbPosition; - - public Button(Option option, Dim2i dim, int min, int max, int interval, ControlValueFormatter formatter) { - super(option, dim); - - this.min = min; - this.range = max - min; - this.interval = interval; - this.thumbPosition = this.getThumbPositionForValue(option.getValue()); - this.formatter = formatter; - - this.sliderBounds = new Rect2i(dim.getLimitX() - 96, dim.getCenterY() - 5, 90, 10); - } - - @Override - public void render(int mouseX, int mouseY, float delta) { - super.render(mouseX, mouseY, delta); - - if (this.option.isAvailable() && this.hovered) { - this.renderSlider(mouseX, mouseY, delta); - } else { - this.renderStandaloneValue(mouseX, mouseY, delta); - } - } - - private void renderStandaloneValue(int mouseX, int mouseY, float delta) { - int sliderX = this.sliderBounds.getX(); - int sliderY = this.sliderBounds.getY(); - int sliderWidth = this.sliderBounds.getWidth(); - int sliderHeight = this.sliderBounds.getHeight(); - - String label = this.formatter.format(this.option.getValue()); - int labelWidth = this.font.getStringWidth(label); - - this.drawString(label, sliderX + sliderWidth - labelWidth, sliderY + (sliderHeight / 2) - 4, 0xFFFFFFFF); - } - - private void renderSlider(int mouseX, int mouseY, float delta) { - int sliderX = this.sliderBounds.getX(); - int sliderY = this.sliderBounds.getY(); - int sliderWidth = this.sliderBounds.getWidth(); - int sliderHeight = this.sliderBounds.getHeight(); - - int thumbOffset = (int) Math.floor((double) (this.getIntValue() - this.min) / this.range * sliderWidth); - - int thumbX = sliderX + thumbOffset - THUMB_WIDTH; - int trackY = sliderY + (sliderHeight / 2) - TRACK_HEIGHT; - - this.drawRect(thumbX, sliderY, thumbX + (THUMB_WIDTH * 2), sliderY + sliderHeight, 0xFFFFFFFF); - this.drawRect(sliderX, trackY, sliderX + sliderWidth, trackY + TRACK_HEIGHT, 0xFFFFFFFF); - - String label = String.valueOf(this.getIntValue()); - - int labelWidth = this.font.getStringWidth(label); - - this.drawString(label, sliderX - labelWidth - 6, sliderY + (sliderHeight / 2) - 4, 0xFFFFFFFF); - } - - public int getIntValue() { - return this.min + (this.interval * (int) Math.round(this.getSnappedThumbPosition() / this.interval)); - } - - public double getSnappedThumbPosition() { - return this.thumbPosition / (1.0D / this.range); - } - - public double getThumbPositionForValue(int value) { - return (value - this.min) * (1.0D / this.range); - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (this.option.isAvailable() && button == 0 && this.sliderBounds.contains((int) mouseX, (int) mouseY)) { - this.setValueFromMouse(mouseX); - - return true; - } - - return false; - } - - private void setValueFromMouse(double d) { - this.setValue((d - (double) (this.sliderBounds.getX() + 4)) / (double) (this.sliderBounds.getWidth() - 8)); - } - - private void setValue(double d) { - this.thumbPosition = MathHelper.clamp(d, 0.0D, 1.0D); - - int value = this.getIntValue(); - - if (this.option.getValue() != value) { - this.option.setValue(value); - } - } - - @Override - public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { - if (this.option.isAvailable() && button == 0) { - this.setValueFromMouse(mouseX); - - return true; - } - - return false; - } - } - -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/TickBoxControl.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/TickBoxControl.java deleted file mode 100644 index 9cadfbbc3..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/control/TickBoxControl.java +++ /dev/null @@ -1,93 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options.control; - -import me.jellysquid.mods.sodium.client.gui.options.Option; -import me.jellysquid.mods.sodium.client.util.Dim2i; -import net.minecraft.client.util.Rect2i; - -public class TickBoxControl implements Control { - private final Option option; - - public TickBoxControl(Option option) { - this.option = option; - } - - @Override - public ControlElement createElement(Dim2i dim) { - return new TickBoxControlElement(this.option, dim); - } - - @Override - public int getMaxWidth() { - return 30; - } - - @Override - public Option getOption() { - return this.option; - } - - private static class TickBoxControlElement extends ControlElement { - private final Rect2i button; - - public TickBoxControlElement(Option option, Dim2i dim) { - super(option, dim); - - this.button = new Rect2i(dim.getLimitX() - 16, dim.getCenterY() - 5, 10, 10); - } - - @Override - public void render(int mouseX, int mouseY, float delta) { - super.render(mouseX, mouseY, delta); - - final int x = this.button.getX(); - final int y = this.button.getY(); - final int w = x + this.button.getWidth(); - final int h = y + this.button.getHeight(); - - final boolean enabled = this.option.isAvailable(); - final boolean ticked = enabled && this.option.getValue(); - - final int color; - - if (enabled) { - color = ticked ? 0xFF94E4D3 : 0xFFFFFFFF; - } else { - color = 0xFFAAAAAA; - } - - if (ticked) { - this.drawRect(x + 2, y + 2, w - 2, h - 2, color); - } - - this.drawRectOutline(x, y, w, h, color); - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (this.option.isAvailable() && button == 0 && this.dim.containsCursor(mouseX, mouseY)) { - this.option.setValue(!this.option.getValue()); - this.playClickSound(); - - return true; - } - - return false; - } - - protected void drawRectOutline(int x, int y, int w, int h, int color) { - final float a = (float) (color >> 24 & 255) / 255.0F; - final float r = (float) (color >> 16 & 255) / 255.0F; - final float g = (float) (color >> 8 & 255) / 255.0F; - final float b = (float) (color & 255) / 255.0F; - - this.drawQuads(vertices -> { - addQuad(vertices, x, y, w, y + 1, a, r, g, b); - addQuad(vertices, x, h - 1, w, h, a, r, g, b); - addQuad(vertices, x, y, x + 1, h, a, r, g, b); - addQuad(vertices, w - 1, y, w, h, a, r, g, b); - }); - } - } - - -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/MinecraftOptionsStorage.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/MinecraftOptionsStorage.java deleted file mode 100644 index f94821c3e..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/MinecraftOptionsStorage.java +++ /dev/null @@ -1,25 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options.storage; - -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.options.GameOptions; - -public class MinecraftOptionsStorage implements OptionStorage { - private final MinecraftClient client; - - public MinecraftOptionsStorage() { - this.client = MinecraftClient.getInstance(); - } - - @Override - public GameOptions getData() { - return this.client.options; - } - - @Override - public void save() { - this.getData().write(); - - SodiumClientMod.logger().info("Flushed changes to Minecraft configuration"); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/OptionStorage.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/OptionStorage.java deleted file mode 100644 index a2e4966da..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/OptionStorage.java +++ /dev/null @@ -1,7 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options.storage; - -public interface OptionStorage { - T getData(); - - void save(); -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/SodiumOptionsStorage.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/SodiumOptionsStorage.java deleted file mode 100644 index 14f0e580e..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/options/storage/SodiumOptionsStorage.java +++ /dev/null @@ -1,25 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.options.storage; - -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions; - -public class SodiumOptionsStorage implements OptionStorage { - private final SodiumGameOptions options; - - public SodiumOptionsStorage() { - this.options = SodiumClientMod.options(); - } - - @Override - public SodiumGameOptions getData() { - return this.options; - } - - @Override - public void save() { - this.options.writeChanges(); - this.options.notifyListeners(); - - SodiumClientMod.logger().info("Flushed changes to Sodium configuration"); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/vanilla/builders/CycleOptionBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/vanilla/builders/CycleOptionBuilder.java index 059531b5a..87414a31a 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/vanilla/builders/CycleOptionBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/vanilla/builders/CycleOptionBuilder.java @@ -1,5 +1,6 @@ package me.jellysquid.mods.sodium.client.gui.vanilla.builders; +import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions; import me.jellysquid.mods.sodium.client.gui.vanilla.option.CyclingOption; import me.jellysquid.mods.sodium.client.gui.vanilla.options.IndexedOption; @@ -32,7 +33,7 @@ public CyclingOption build() { BiFunction, String> textGetter = getTextGetter(); return new CyclingOption<>( getKey(), - sodiumOpts.getData(), + SodiumClientMod.options(), getOptions(), getSetter(), getGetter(), diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/vanilla/builders/OptionBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/vanilla/builders/OptionBuilder.java index 0eb2bd051..6c8d702c6 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/vanilla/builders/OptionBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/gui/vanilla/builders/OptionBuilder.java @@ -1,26 +1,18 @@ package me.jellysquid.mods.sodium.client.gui.vanilla.builders; import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions; -import me.jellysquid.mods.sodium.client.gui.options.OptionFlag; -import me.jellysquid.mods.sodium.client.gui.options.storage.SodiumOptionsStorage; import org.apache.commons.lang3.Validate; -import java.util.EnumSet; -import java.util.Set; import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Function; public abstract class OptionBuilder { - - static final SodiumOptionsStorage sodiumOpts = new SodiumOptionsStorage(); - private String key; private String text; private BiFunction textGetter; private Function getter; private BiConsumer setter; - private final Set localFlags = EnumSet.noneOf(OptionFlag.class); abstract P self(); @@ -34,16 +26,6 @@ public P setText(String text){ return self(); } - private static Set flags; - static { - getFlags(); - } - public static Set getFlags(){ - Set oldFlags = flags; - flags = EnumSet.noneOf(OptionFlag.class); - return oldFlags; - } - public P setGetter(Function getter){ this.getter = getter; return self(); @@ -64,11 +46,6 @@ public P setTextGetter(BiFunction textGetter){ return self(); } - public P flag(OptionFlag flag){ - localFlags.add(flag); - return self(); - } - String getKey(){ Validate.notNull(key, "Key must be specified"); return key; @@ -80,12 +57,6 @@ String getText(){ Function getGetter(){ Validate.notNull(getter, "Getter must be specified"); - if(!localFlags.isEmpty()){ - return (value) -> { - flags.addAll(localFlags); - return getter.apply(value); - }; - } return getter; } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/AbstractWidget.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/AbstractWidget.java deleted file mode 100644 index fe9c6ed67..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/AbstractWidget.java +++ /dev/null @@ -1,67 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.widgets; - -import com.mojang.blaze3d.systems.RenderSystem; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.font.TextRenderer; -import net.minecraft.client.gui.Drawable; -import net.minecraft.client.gui.Element; -import net.minecraft.client.render.*; -import net.minecraft.client.sound.PositionedSoundInstance; -import net.minecraft.sound.SoundEvents; -import org.lwjgl.opengl.GL11; - -import java.util.function.Consumer; - -public abstract class AbstractWidget implements Drawable, Element { - protected final TextRenderer font; - - protected AbstractWidget() { - this.font = MinecraftClient.getInstance().textRenderer; - } - - protected void drawString(String str, int x, int y, int color) { - this.font.draw(str, x, y, color); - } - - protected void drawRect(int x1, int y1, int x2, int y2, int color) { - float a = (float) (color >> 24 & 255) / 255.0F; - float r = (float) (color >> 16 & 255) / 255.0F; - float g = (float) (color >> 8 & 255) / 255.0F; - float b = (float) (color & 255) / 255.0F; - - this.drawQuads(vertices -> addQuad(vertices, x1, y1, x2, y2, a, r, g, b)); - } - - protected void drawQuads(Consumer consumer) { - RenderSystem.enableBlend(); - RenderSystem.disableTexture(); - RenderSystem.defaultBlendFunc(); - - BufferBuilder bufferBuilder = Tessellator.getInstance().getBuffer(); - bufferBuilder.begin(GL11.GL_QUADS, VertexFormats.POSITION_COLOR); - - consumer.accept(bufferBuilder); - - bufferBuilder.end(); - - BufferRenderer.draw(bufferBuilder); - RenderSystem.enableTexture(); - RenderSystem.disableBlend(); - } - - protected static void addQuad(VertexConsumer consumer, int x1, int y1, int x2, int y2, float a, float r, float g, float b) { - consumer.vertex(x2, y1, 0.0D).color(r, g, b, a).next(); - consumer.vertex(x1, y1, 0.0D).color(r, g, b, a).next(); - consumer.vertex(x1, y2, 0.0D).color(r, g, b, a).next(); - consumer.vertex(x2, y2, 0.0D).color(r, g, b, a).next(); - } - - protected void playClickSound() { - MinecraftClient.getInstance().getSoundManager() - .play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK, 1.0F)); - } - - protected int getStringWidth(String text) { - return this.font.getStringWidth(text); - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/FlatButtonWidget.java b/src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/FlatButtonWidget.java deleted file mode 100644 index 45504f029..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/client/gui/widgets/FlatButtonWidget.java +++ /dev/null @@ -1,69 +0,0 @@ -package me.jellysquid.mods.sodium.client.gui.widgets; - -import me.jellysquid.mods.sodium.client.util.Dim2i; -import net.minecraft.client.gui.Drawable; - -public class FlatButtonWidget extends AbstractWidget implements Drawable { - private final Dim2i dim; - private final String label; - private final Runnable action; - - private boolean selected; - private boolean enabled = true; - private boolean visible = true; - - public FlatButtonWidget(Dim2i dim, String label, Runnable action) { - this.dim = dim; - this.label = label; - this.action = action; - } - - @Override - public void render(int mouseX, int mouseY, float delta) { - if (!this.visible) { - return; - } - - boolean hovered = this.dim.containsCursor(mouseX, mouseY); - - int backgroundColor = this.enabled ? (hovered ? 0xE0000000 : 0x90000000) : 0x60000000; - int textColor = this.enabled ? 0xFFFFFFFF : 0x90FFFFFF; - - int strWidth = this.font.getStringWidth(this.label); - - this.drawRect(this.dim.getOriginX(), this.dim.getOriginY(), this.dim.getLimitX(), this.dim.getLimitY(), backgroundColor); - this.drawString(this.label, this.dim.getCenterX() - (strWidth / 2), this.dim.getCenterY() - 4, textColor); - - if (this.enabled && this.selected) { - this.drawRect(this.dim.getOriginX(), this.dim.getLimitY() - 1, this.dim.getLimitX(), this.dim.getLimitY(), 0xFF94E4D3); - } - } - - public void setSelected(boolean selected) { - this.selected = selected; - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (!this.enabled) { - return false; - } - - if (button == 0 && this.dim.containsCursor(mouseX, mouseY)) { - this.action.run(); - this.playClickSound(); - - return true; - } - - return false; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - public void setVisible(boolean visibel) { - this.visible = visibel; - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java index 31d496b94..163722de0 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/SodiumWorldRenderer.java @@ -402,4 +402,8 @@ public ChunkRenderBackend getChunkRenderer() { public boolean getUseEntityCulling() { return this.useEntityCulling; } + + public int getRenderDistance() { + return this.renderDistance; + } } diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java index 139ad6f7e..b623fc0f4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/ChunkRenderManager.java @@ -462,6 +462,8 @@ public void updateChunks() { if (!futures.isEmpty()) { this.backend.upload(new FutureDequeDrain<>(futures)); } + + this.builder.createMoreThreads(); } public void markDirty() { diff --git a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuilder.java b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuilder.java index 6fc453ebe..41458e84c 100644 --- a/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuilder.java +++ b/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuilder.java @@ -1,6 +1,8 @@ package me.jellysquid.mods.sodium.client.render.chunk.compile; +import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.gl.attribute.GlVertexFormat; +import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; import me.jellysquid.mods.sodium.client.render.chunk.ChunkGraphicsState; import me.jellysquid.mods.sodium.client.render.chunk.ChunkRenderBackend; import me.jellysquid.mods.sodium.client.render.chunk.ChunkRenderContainer; @@ -16,6 +18,7 @@ import me.jellysquid.mods.sodium.common.util.pool.ObjectPool; import net.minecraft.client.MinecraftClient; import net.minecraft.client.util.math.Vector3d; +import net.minecraft.util.math.MathHelper; import net.minecraft.client.world.ClientWorld; import net.minecraft.util.math.ChunkSectionPos; import net.minecraft.world.World; @@ -53,23 +56,85 @@ public class ChunkBuilder { private BiomeCacheManager biomeCacheManager; private BlockRenderPassManager renderPassManager; - private final int limitThreads; + // This is the initial number of threads we spin up upon ChunkBuilder creation. + // Default: 2-4 depending on render distance. *Always* less than hardLimitThreads. + private final int initialThreads; + // This is the number of threads we want to 'quickly' get up to. This is calculated + // by getOptimalThreadCount, but can also be configured by the user. Always less than hardLimitThreads. + private final int targetThreads; + // This is the number of threads we are allowed to create in total. + // This is defaulted to targetThreads, but maxes out at 64. Testing would be required to determine what + // actual count is optimal for a specific user and use case. + private final int hardLimitThreads; + // This is the initial time when this builder is created. We use this to create more threads. + private long lastThreadAddition; + // This is the user-configurable time delta to create a new thread, up until targetThreads. + private final long quickThreadCreationInterval; + // This is the user-configurable time delta to create a new thread, up until hardLimitThreads. + private final long slowThreadCreationInterval; + private final GlVertexFormat format; private final ChunkRenderBackend backend; public ChunkBuilder(GlVertexFormat format, ChunkRenderBackend backend) { this.format = format; this.backend = backend; - this.limitThreads = getOptimalThreadCount(); + + // User-configurable options for chunk threads. + int desiredTargetThreads = SodiumClientMod.options().advanced.targetChunkThreads; + int desiredInitialThreads = SodiumClientMod.options().advanced.initialChunkThreads; + + // These are bounded by the options configuration. Both are measured in milliseconds. + this.quickThreadCreationInterval = SodiumClientMod.options().advanced.quickThreadCreationInterval; + this.slowThreadCreationInterval = SodiumClientMod.options().advanced.slowThreadCreationInterval; + + // Our hard limit of threads. Cap user config at 64, prefer desiredMaxThreads, otherwise use logical core count. + this.hardLimitThreads = getMaxThreadCount(); + // Our targeted number of threads. + this.targetThreads = Math.min(desiredTargetThreads == 0 ? getDefaultTargetThreads() : desiredTargetThreads, this.hardLimitThreads); + // Our initial threads. A bit of a silly calculation for this one. + this.initialThreads = Math.min(desiredInitialThreads == 0 ? getDefaultInitialThreads() : desiredInitialThreads, this.targetThreads); this.pool = new ObjectPool<>(this.getSchedulingBudget(), WorldSlice::new); } + private static int getDefaultTargetThreads() { + return MathHelper.clamp(Math.max(getLogicalCoreCount() / 3, getLogicalCoreCount() - 6), 1, 10); + } + + private static int getDefaultInitialThreads() { + return (SodiumWorldRenderer.getInstance().getRenderDistance() / 10) + 2; + } + + private static int getLogicalCoreCount() { + return Runtime.getRuntime().availableProcessors(); + } + + // Split out this function so that SeedQueue can inject into this. + private static int getMaxThreadCount() { + int desiredMaxThreads = SodiumClientMod.options().advanced.maxChunkThreads; + return desiredMaxThreads == 0 ? getLogicalCoreCount() : desiredMaxThreads; + } + /** * Returns the remaining number of build tasks which should be scheduled this frame. If an attempt is made to * spawn more tasks than the budget allows, it will block until resources become available. */ public int getSchedulingBudget() { - return Math.max(0, (this.limitThreads * TASK_QUEUE_LIMIT_PER_WORKER) - this.buildQueue.size()); + return Math.max(0, (Math.max(this.threads.size(), this.targetThreads) * TASK_QUEUE_LIMIT_PER_WORKER) - this.buildQueue.size()); + } + + public void createWorker(MinecraftClient client) { + ChunkBuildBuffers buffers = new ChunkBuildBuffers(this.format, this.renderPassManager); + ChunkRenderContext pipeline = new ChunkRenderContext(client); + + WorkerRunnable worker = new WorkerRunnable(buffers, pipeline); + + Thread thread = new Thread(worker, "Chunk Render Task Executor #" + this.threads.size() + 1); + thread.setPriority(Math.max(0, Thread.NORM_PRIORITY - 2)); + thread.start(); + + this.threads.add(thread); + this.lastThreadAddition = System.currentTimeMillis(); } /** @@ -86,21 +151,32 @@ public void startWorkers() { } MinecraftClient client = MinecraftClient.getInstance(); + for (int i = 0; i < this.initialThreads; i++) { + this.createWorker(client); + } - for (int i = 0; i < this.limitThreads; i++) { - ChunkBuildBuffers buffers = new ChunkBuildBuffers(this.format, this.renderPassManager); - ChunkRenderContext pipeline = new ChunkRenderContext(client); - - WorkerRunnable worker = new WorkerRunnable(buffers, pipeline); - - Thread thread = new Thread(worker, "Chunk Render Task Executor #" + i); - thread.setPriority(Math.max(0, Thread.NORM_PRIORITY - 2)); - thread.start(); + LOGGER.info("Started {} worker threads", this.threads.size()); + } - this.threads.add(thread); + /** + * Spawns workers if we have thread space. + */ + public void createMoreThreads() { + if (this.threads.size() >= this.hardLimitThreads) { + return; } - LOGGER.info("Started {} worker threads", this.threads.size()); + long timeDelta = System.currentTimeMillis() - this.lastThreadAddition; + if (this.threads.size() < this.targetThreads) { + // Check if enough time has elapsed for us to create a target thread. + if (timeDelta > this.quickThreadCreationInterval) { + this.createWorker(MinecraftClient.getInstance()); + } + } + // Check if enough time has elapsed for us to create a target thread. + else if (timeDelta > this.slowThreadCreationInterval) { + this.createWorker(MinecraftClient.getInstance()); + } } /** @@ -220,14 +296,6 @@ public void init(ClientWorld world, BlockRenderPassManager renderPassManager) { this.startWorkers(); } - /** - * Returns the "optimal" number of threads to be used for chunk build tasks. This is always at least one thread, - * but can be up to the number of available processor threads on the system. - */ - private static int getOptimalThreadCount() { - return Math.max(1, Runtime.getRuntime().availableProcessors()); - } - /** * Creates a {@link WorldSlice} around the given chunk section. If the chunk section is empty, null is returned. * @param pos The position of the chunk section diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/block/MixinWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/block/MixinWorldRenderer.java index 47d08f29f..cf8722afc 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/block/MixinWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/block/MixinWorldRenderer.java @@ -9,6 +9,7 @@ import net.minecraft.client.util.math.Matrix4f; import net.minecraft.client.util.math.MatrixStack; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; @@ -16,6 +17,9 @@ @Mixin(WorldRenderer.class) public class MixinWorldRenderer { + @Shadow + public int regularEntityCount; + /** * Reset any global cached state before rendering a frame. This will hopefully ensure that any world state that has * changed is reflected in vanilla-style rendering. @@ -32,6 +36,6 @@ private int hidEntityCount(WorldRenderer instance){ if(SodiumWorldRenderer.getInstance().getUseEntityCulling()){ return -1; } - return instance.regularEntityCount; + return this.regularEntityCount; } } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinWorldRenderer.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinWorldRenderer.java index 28ca814d6..678565452 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinWorldRenderer.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/chunk_rendering/MixinWorldRenderer.java @@ -16,6 +16,7 @@ import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyArg; import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -38,6 +39,12 @@ public SodiumWorldRenderer getSodiumWorldRenderer() { return renderer; } + @ModifyArg(method = "", at = @At(value = "INVOKE", target = "Lit/unimi/dsi/fastutil/objects/ObjectArrayList;(I)V", remap = false)) + private int nullifyVisibleChunksList(int capacity) { + // Sodium doesn't use this list, so we prevent the initial capacity of 69696 to be allocated + return 0; + } + @Redirect(method = "reload", at = @At(value = "FIELD", target = "Lnet/minecraft/client/options/GameOptions;viewDistance:I", ordinal = 1)) private int nullifyBuiltChunkStorage(GameOptions options) { // Do not allow any resources to be allocated diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/debug/MixinDebugHud.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/debug/MixinDebugHud.java index 2564aa60e..8747ea653 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/debug/MixinDebugHud.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/debug/MixinDebugHud.java @@ -2,59 +2,19 @@ import me.jellysquid.mods.sodium.client.SodiumClientMod; import net.minecraft.client.gui.hud.DebugHud; -import net.minecraft.util.Formatting; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; -import java.lang.management.ManagementFactory; import java.util.List; @Mixin(DebugHud.class) public abstract class MixinDebugHud { - @Shadow - private static long toMiB(long bytes) { - throw new UnsupportedOperationException(); - } - @Redirect(method = "renderRightText", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/hud/DebugHud;getRightText()Ljava/util/List;")) private List redirectRightTextEarly(DebugHud instance) { - List strings = ((DebugHudAccessor)instance).invokeGetRightText(); + List strings = ((DebugHudAccessor) instance).invokeGetRightText(); strings.add(""); - strings.add("Sodium Speedrunning Build"); - strings.add(Formatting.UNDERLINE + getFormattedVersionText()); - strings.add(""); - - for (int i = 0; i < strings.size(); i++) { - String str = strings.get(i); - - if (str.startsWith("Allocated:")) { - strings.add(i + 1, getNativeMemoryString()); - - break; - } - } - + strings.add("MCSR Sodium Mac " + SodiumClientMod.getVersion()); return strings; } - - private static String getFormattedVersionText() { - String version = SodiumClientMod.getVersion(); - Formatting color; - - if (version.endsWith("-dirty")) { - color = Formatting.RED; - } else if (version.contains("+rev.")) { - color = Formatting.LIGHT_PURPLE; - } else { - color = Formatting.GREEN; - } - - return color + version; - } - - private static String getNativeMemoryString() { - return "Off-Heap: +" + toMiB(ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage().getUsed()) + "MB"; - } } diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/DoubleOptionAccessor.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/DoubleOptionAccessor.java new file mode 100644 index 000000000..d5da3f601 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/DoubleOptionAccessor.java @@ -0,0 +1,13 @@ +package me.jellysquid.mods.sodium.mixin.features.options; + +import net.minecraft.client.options.DoubleOption; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(DoubleOption.class) +public interface DoubleOptionAccessor { + @Mutable + @Accessor + void setStep(float step); +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinOption.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinOption.java new file mode 100644 index 000000000..65b9cd546 --- /dev/null +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinOption.java @@ -0,0 +1,15 @@ +package me.jellysquid.mods.sodium.mixin.features.options; + +import net.minecraft.client.options.DoubleOption; +import net.minecraft.client.options.Option; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(Option.class) +public abstract class MixinOption { + @Redirect(method = "method_18545", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/options/DoubleOption;getRatio(D)D")) + private static double correctGammaText(DoubleOption instance, double value) { + return instance.getRatio(value) * instance.getMax(); // 1 when in a world + } +} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinSettingsScreen.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinSettingsScreen.java deleted file mode 100644 index dc0ad54cc..000000000 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinSettingsScreen.java +++ /dev/null @@ -1,36 +0,0 @@ -package me.jellysquid.mods.sodium.mixin.features.options; - -import me.jellysquid.mods.sodium.client.SodiumClientMod; -import me.jellysquid.mods.sodium.client.gui.SodiumOptionsGUI; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.screen.SettingsScreen; -import net.minecraft.client.gui.screen.VideoOptionsScreen; -import net.minecraft.client.gui.widget.ButtonWidget; -import net.minecraft.text.Text; -import org.spongepowered.asm.mixin.Dynamic; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(SettingsScreen.class) -public class MixinSettingsScreen extends Screen { - protected MixinSettingsScreen(Text title) { - super(title); - } - - @Dynamic - @Inject(method = "method_19828(Lnet/minecraft/client/gui/widget/ButtonWidget;)V", at = @At("HEAD"), cancellable = true) - private void open(ButtonWidget widget, CallbackInfo ci) { - if (this.minecraft != null) { - if (MinecraftClient.getInstance().world != null) { - this.minecraft.openScreen(new VideoOptionsScreen(this, this.minecraft.options)); - } else { - this.minecraft.openScreen(new SodiumOptionsGUI(this)); - } - - ci.cancel(); - } - } -} diff --git a/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinVideoOptionsScreen.java b/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinVideoOptionsScreen.java index 1be86fc69..abf1a5ea4 100644 --- a/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinVideoOptionsScreen.java +++ b/src/main/java/me/jellysquid/mods/sodium/mixin/features/options/MixinVideoOptionsScreen.java @@ -2,11 +2,7 @@ import me.jellysquid.mods.sodium.client.SodiumClientMod; import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions; -import me.jellysquid.mods.sodium.client.gui.SodiumOptionsGUI; import me.jellysquid.mods.sodium.client.gui.VanillaOptions; -import me.jellysquid.mods.sodium.client.gui.options.OptionFlag; -import me.jellysquid.mods.sodium.client.gui.vanilla.builders.OptionBuilder; -import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.VideoOptionsScreen; import net.minecraft.client.gui.screen.options.GameOptionsScreen; @@ -24,7 +20,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Set; @Mixin(VideoOptionsScreen.class) public class MixinVideoOptionsScreen extends GameOptionsScreen { @@ -33,9 +28,11 @@ public MixinVideoOptionsScreen(Screen parent, GameOptions gameOptions, Text titl super(parent, gameOptions, title); } - @Redirect(method = "init", at=@At(value = "INVOKE", target = "Lnet/minecraft/client/gui/widget/ButtonListWidget;addAll([Lnet/minecraft/client/options/Option;)V")) + @Redirect(method = "init", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/widget/ButtonListWidget;addAll([Lnet/minecraft/client/options/Option;)V")) private void optionsSwap(ButtonListWidget list, Option[] old_options) { - List