diff --git a/build-logic/src/main/kotlin/dynamic_fps.base.gradle.kts b/build-logic/src/main/kotlin/dynamic_fps.base.gradle.kts index 165fb562..2bf47cae 100644 --- a/build-logic/src/main/kotlin/dynamic_fps.base.gradle.kts +++ b/build-logic/src/main/kotlin/dynamic_fps.base.gradle.kts @@ -24,7 +24,7 @@ if (project.hasProperty("loom.platform")) { tasks.withType { inputs.property("version", modVersion) - filesMatching(listOf("fabric.mod.json", "mods.toml", "neoforge.mods.toml", "quilt.mod.json")) { + filesMatching(listOf("fabric.mod.json", "META-INF/mods.toml", "META-INF/neoforge.mods.toml", "quilt.mod.json")) { expand(inputs.properties) } } diff --git a/build-logic/src/main/kotlin/dynamic_fps.java.gradle.kts b/build-logic/src/main/kotlin/dynamic_fps.java.gradle.kts index 10e67fe4..1acb9758 100644 --- a/build-logic/src/main/kotlin/dynamic_fps.java.gradle.kts +++ b/build-logic/src/main/kotlin/dynamic_fps.java.gradle.kts @@ -6,7 +6,7 @@ java { withSourcesJar() toolchain { - languageVersion = JavaLanguageVersion.of(21) + languageVersion = JavaLanguageVersion.of(17) } } @@ -14,6 +14,6 @@ tasks.withType { options.encoding = "UTF-8" javaCompiler = javaToolchains.compilerFor { - languageVersion = JavaLanguageVersion.of(21) + languageVersion = JavaLanguageVersion.of(17) } } diff --git a/gradle.properties b/gradle.properties index 85079204..d66222d0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,9 +10,9 @@ maven_group = juliand665 archives_name = dynamic-fps # File naming version -minecraft_version = 1.21.0 +minecraft_version = 1.20.0 # Version for publishing -minecraft_version_min = 1.21 -minecraft_version_max = 1.21 +minecraft_version_min = 1.20 +minecraft_version_max = 1.20.4 -enabled_platforms=fabric,neoforge,quilt +enabled_platforms=fabric,forge,neoforge,quilt diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5a0381b0..434ba3da 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,14 +1,14 @@ [versions] -minecraft = "1.21" +minecraft = "1.20.4" # Platform libraries fabric_loader = "0.15.10" -fabric_api = "0.100.1+1.21" +fabric_api = "0.96.1+1.20.4" forge = "1.20.4-49.0.30" -neoforge = "21.0.0-beta" +neoforge = "20.4.237" quilt_loader = "0.25.0" quilt_standard_libraries = "8.0.0-alpha.12+1.20.4" @@ -19,8 +19,8 @@ battery = "1.1.0" # Modding libraries -modmenu = "11.0.0-beta.1" -cloth_config = "15.0.127" +modmenu = "9.0.0" +cloth_config = "13.0.121" mixinextras = "0.3.5" diff --git a/platforms/common/src/main/java/dynamic_fps/impl/DynamicFPSMod.java b/platforms/common/src/main/java/dynamic_fps/impl/DynamicFPSMod.java index 76ce8a60..095250e1 100644 --- a/platforms/common/src/main/java/dynamic_fps/impl/DynamicFPSMod.java +++ b/platforms/common/src/main/java/dynamic_fps/impl/DynamicFPSMod.java @@ -14,12 +14,14 @@ import dynamic_fps.impl.util.FallbackConfigScreen; import dynamic_fps.impl.util.Logging; import dynamic_fps.impl.feature.state.OptionHolder; +import dynamic_fps.impl.util.ModCompatHelper; import dynamic_fps.impl.util.ResourceLocations; import dynamic_fps.impl.util.Version; import dynamic_fps.impl.feature.volume.SmoothVolumeHandler; import dynamic_fps.impl.util.duck.DuckLoadingOverlay; import dynamic_fps.impl.feature.state.WindowObserver; import dynamic_fps.impl.service.Platform; +import dynamic_fps.impl.util.duck.DuckScreen; import net.lostluma.battery.api.State; import net.minecraft.Util; import net.minecraft.client.Minecraft; @@ -174,7 +176,7 @@ public static boolean shouldShowToasts() { } public static boolean shouldShowLevels() { - return isDisabled() || !isLevelCoveredByOverlay(); + return isDisabled() || !(isLevelCoveredByScreen() || isLevelCoveredByOverlay()); } public static void onBatteryChargeChanged(int before, int after) { @@ -196,11 +198,17 @@ public static void onBatteryStatusChanged(State before, State after) { private static void doInit() { // NOTE: Init battery tracker first here // Since the idle handler queries it for info + ModCompatHelper.init(); + BatteryTracker.init(); IdleHandler.init(); SmoothVolumeHandler.init(); } + private static boolean isLevelCoveredByScreen() { + return minecraft.screen != null && ((DuckScreen) minecraft.screen).dynamic_fps$rendersBackground(); + } + private static void showNotification(String titleTranslationKey, String iconPath) { if (!DynamicFPSConfig.INSTANCE.batteryTracker().notifications()) { return; diff --git a/platforms/common/src/main/java/dynamic_fps/impl/feature/battery/BatteryTracker.java b/platforms/common/src/main/java/dynamic_fps/impl/feature/battery/BatteryTracker.java index 483a6d5a..62b15d27 100644 --- a/platforms/common/src/main/java/dynamic_fps/impl/feature/battery/BatteryTracker.java +++ b/platforms/common/src/main/java/dynamic_fps/impl/feature/battery/BatteryTracker.java @@ -58,7 +58,7 @@ public static void init() { } } else { manager = temp; // Keep around to allow updating batteries - Thread.ofVirtual().name("refresh-battery").start(BatteryTracker::updateBatteries); + new Thread(BatteryTracker::updateBatteries, "refresh-battery").start(); } } @@ -127,7 +127,7 @@ private static void updateBatteries() { updateState(); try { - Thread.sleep(updateInterval); + Thread.sleep(updateInterval.toMillis()); } catch (InterruptedException e) { active = false; Thread.currentThread().interrupt(); diff --git a/platforms/common/src/main/java/dynamic_fps/impl/mixin/ScreenMixin.java b/platforms/common/src/main/java/dynamic_fps/impl/mixin/ScreenMixin.java new file mode 100644 index 00000000..7f39e351 --- /dev/null +++ b/platforms/common/src/main/java/dynamic_fps/impl/mixin/ScreenMixin.java @@ -0,0 +1,50 @@ +package dynamic_fps.impl.mixin; + +import dynamic_fps.impl.service.ModCompat; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import dynamic_fps.impl.util.duck.DuckScreen; +import net.minecraft.client.gui.screens.Screen; + +@Mixin(Screen.class) +public class ScreenMixin implements DuckScreen { + @Unique + private boolean dynamic_fps$canOptimize = false; + + @Unique + private boolean dynamic_fps$hasOptedOut = false; + + @Override + public boolean dynamic_fps$rendersBackground() { + return dynamic_fps$canOptimize; + } + + @Override + public void dynamic_fps$setRendersBackground() { + this.dynamic_fps$canOptimize = true; + } + + @Inject(method = "init", at = @At("HEAD")) + private void onInit(CallbackInfo callbackInfo) { + String name = this.getClass().getName(); + + this.dynamic_fps$hasOptedOut = ModCompat.getInstance().isScreenOptedOut(name); + + // Allow other mods to opt out on behalf of vanilla screens + // That Dynamic FPS forced to opt in via its own mod metadata. + if (!this.dynamic_fps$hasOptedOut) { + this.dynamic_fps$canOptimize = ModCompat.getInstance().isScreenOptedIn(name); + } + } + + @Inject(method = "renderDirtBackground", at = @At("HEAD")) + private void onRenderDirtBackground(CallbackInfo callbackInfo) { + if (!this.dynamic_fps$hasOptedOut) { + this.dynamic_fps$canOptimize = true; // Signal to apply optimizations on next frame + } + } +} diff --git a/platforms/common/src/main/java/dynamic_fps/impl/mixin/StatsScreenMixin.java b/platforms/common/src/main/java/dynamic_fps/impl/mixin/StatsScreenMixin.java new file mode 100644 index 00000000..92b1b5ac --- /dev/null +++ b/platforms/common/src/main/java/dynamic_fps/impl/mixin/StatsScreenMixin.java @@ -0,0 +1,17 @@ +package dynamic_fps.impl.mixin; + +import dynamic_fps.impl.util.duck.DuckScreen; +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; + +import net.minecraft.client.gui.screens.achievement.StatsScreen; + +@Mixin(StatsScreen.class) +public class StatsScreenMixin { + @Inject(method = "onStatsUpdated", at = @At("HEAD")) + private void onStatsUpdated(CallbackInfo callbackInfo) { + ((DuckScreen) this).dynamic_fps$setRendersBackground(); + } +} diff --git a/platforms/common/src/main/java/dynamic_fps/impl/service/ModCompat.java b/platforms/common/src/main/java/dynamic_fps/impl/service/ModCompat.java index dea57fdf..bbfdbc53 100644 --- a/platforms/common/src/main/java/dynamic_fps/impl/service/ModCompat.java +++ b/platforms/common/src/main/java/dynamic_fps/impl/service/ModCompat.java @@ -1,10 +1,23 @@ package dynamic_fps.impl.service; +import java.util.Set; + public interface ModCompat { boolean isDisabled(); boolean disableOverlayOptimization(); + Set getOptedInScreens(); + Set getOptedOutScreens(); + + default boolean isScreenOptedIn(String className) { + return getOptedInScreens().contains(className); + } + + default boolean isScreenOptedOut(String className) { + return getOptedOutScreens().contains(className); + } + static ModCompat getInstance() { return Services.MOD_COMPAT; } diff --git a/platforms/common/src/main/java/dynamic_fps/impl/util/FallbackConfigScreen.java b/platforms/common/src/main/java/dynamic_fps/impl/util/FallbackConfigScreen.java index 99f5532b..19a9d9a2 100644 --- a/platforms/common/src/main/java/dynamic_fps/impl/util/FallbackConfigScreen.java +++ b/platforms/common/src/main/java/dynamic_fps/impl/util/FallbackConfigScreen.java @@ -33,6 +33,7 @@ protected void init() { @Override public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTicks) { + this.renderDirtBackground(guiGraphics); super.render(guiGraphics, mouseX, mouseY, partialTicks); int width = guiGraphics.guiWidth() / 2; diff --git a/platforms/common/src/main/java/dynamic_fps/impl/util/ModCompatHelper.java b/platforms/common/src/main/java/dynamic_fps/impl/util/ModCompatHelper.java new file mode 100644 index 00000000..7e629913 --- /dev/null +++ b/platforms/common/src/main/java/dynamic_fps/impl/util/ModCompatHelper.java @@ -0,0 +1,40 @@ +package dynamic_fps.impl.util; + +import dynamic_fps.impl.service.ModCompat; +import dynamic_fps.impl.service.Platform; + +import java.util.Optional; + +public class ModCompatHelper { + public static void init() { + fixFastloadSoftLock(); + } + + /** + * Fix softlock in combination with Fastload <=3.4.0 due to our screen / loading overlay optimization. + * + * See the issue report for more info. + */ + private static void fixFastloadSoftLock() { + Optional optional = Platform.getInstance().getModVersion("fastload"); + + if (optional.isEmpty()) { + return; + } + + Version other; + + try { + other = Version.of("3.4.0"); + } catch (Version.VersionParseException e) { + throw new RuntimeException(e); + } + + // If a version below 3.4.0 is present opt their custom world loading screen out of our optimization + if (optional.get().compareTo(other) <= 0) { + ModCompat.getInstance().getOptedOutScreens().add( + "io.github.bumblesoftware.fastload.client.BuildingTerrainScreen" + ); + } + } +} diff --git a/platforms/common/src/main/java/dynamic_fps/impl/util/ResourceLocations.java b/platforms/common/src/main/java/dynamic_fps/impl/util/ResourceLocations.java index 45e40b8d..c9f0ab50 100644 --- a/platforms/common/src/main/java/dynamic_fps/impl/util/ResourceLocations.java +++ b/platforms/common/src/main/java/dynamic_fps/impl/util/ResourceLocations.java @@ -4,6 +4,6 @@ public class ResourceLocations { public static ResourceLocation of(String namespace, String path) { - return ResourceLocation.fromNamespaceAndPath(namespace, path); + return new ResourceLocation(namespace, path); } } diff --git a/platforms/common/src/main/java/dynamic_fps/impl/util/VariableStepTransformer.java b/platforms/common/src/main/java/dynamic_fps/impl/util/VariableStepTransformer.java index 93bef45f..dc94e8bc 100644 --- a/platforms/common/src/main/java/dynamic_fps/impl/util/VariableStepTransformer.java +++ b/platforms/common/src/main/java/dynamic_fps/impl/util/VariableStepTransformer.java @@ -1,6 +1,7 @@ package dynamic_fps.impl.util; import java.util.ArrayList; +import java.util.Collections; import java.util.Comparator; import java.util.List; @@ -13,9 +14,11 @@ public class VariableStepTransformer { private boolean unsorted; private final List steps; + private final List reversedSteps; public VariableStepTransformer() { this.steps = new ArrayList<>(); + this.reversedSteps = new ArrayList<>(); } /** @@ -27,6 +30,7 @@ public VariableStepTransformer() { public void addStep(int change, int max) { this.unsorted = true; this.steps.add(new Step(change, max)); + this.reversedSteps.add(new Step(change, max)); } /** @@ -42,7 +46,7 @@ public int toStep(int value) { int currentChange = 0; int currentValue = value; - for (Step pair : this.steps.reversed()) { + for (Step pair : this.reversedSteps) { if (currentValue > pair.max && currentChange != 0) { step += Math.floorDiv(currentValue - pair.max, currentChange); currentValue = pair.max; @@ -86,6 +90,14 @@ public int compare(Step self, Step other) { return Integer.compare(self.max, other.max); } }); + + this.reversedSteps.sort(new Comparator() { + @Override + public int compare(Step self, Step other) { + return Integer.compare(self.max, other.max); + } + }); + Collections.reverse(this.reversedSteps); } private record Step(int change, int max) {} diff --git a/platforms/common/src/main/java/dynamic_fps/impl/util/duck/DuckScreen.java b/platforms/common/src/main/java/dynamic_fps/impl/util/duck/DuckScreen.java new file mode 100644 index 00000000..fe72fe3d --- /dev/null +++ b/platforms/common/src/main/java/dynamic_fps/impl/util/duck/DuckScreen.java @@ -0,0 +1,11 @@ +package dynamic_fps.impl.util.duck; + +public interface DuckScreen { + default boolean dynamic_fps$rendersBackground() { + throw new RuntimeException("No implementation for dynamic_fps$rendersBackground was found."); + } + + default void dynamic_fps$setRendersBackground() { + throw new RuntimeException("No implementation for dynamic_fps$rendersBackground was found."); + } +} diff --git a/platforms/common/src/main/resources/dynamic_fps-common.mixins.json b/platforms/common/src/main/resources/dynamic_fps-common.mixins.json index b1453d3f..473d39e9 100644 --- a/platforms/common/src/main/resources/dynamic_fps-common.mixins.json +++ b/platforms/common/src/main/resources/dynamic_fps-common.mixins.json @@ -8,7 +8,9 @@ "GuiMixin", "LoadingOverlayMixin", "MinecraftMixin", + "ScreenMixin", "SoundEngineMixin", + "StatsScreenMixin", "ToastComponentMixin", "WindowMixin", "bugfix.BlockableEventLoopMixin" diff --git a/platforms/fabric/build.gradle b/platforms/fabric/build.gradle index 73716d22..09b7956f 100644 --- a/platforms/fabric/build.gradle +++ b/platforms/fabric/build.gradle @@ -85,13 +85,11 @@ publishMods { accessToken = providers.environmentVariable("CURSEFORGE_SECRET") projectId = "335493" - /* minecraftVersionRange { start = project.property("minecraft_version_min").toString() end = project.property("minecraft_version_max").toString() } - */ - minecraftVersions.add(project.property("minecraft_version_min").toString()) + // minecraftVersions.add(project.property("minecraft_version_min").toString()) clientRequired = true serverRequired = false @@ -104,15 +102,13 @@ publishMods { accessToken = providers.environmentVariable("MODRINTH_SECRET") projectId = "LQ3K71Q1" - /* minecraftVersionRange { start = project.property("minecraft_version_min").toString() end = project.property("minecraft_version_max").toString() includeSnapshots = true } - */ - minecraftVersions.add(project.property("minecraft_version_min").toString()) + // minecraftVersions.add(project.property("minecraft_version_min").toString()) requires("fabric-api") optional("cloth-config", "modmenu") diff --git a/platforms/fabric/src/main/java/net/lostluma/dynamic_fps/impl/fabric/mixin/GuiMixin.java b/platforms/fabric/src/main/java/net/lostluma/dynamic_fps/impl/fabric/mixin/GuiMixin.java index ecfae3d4..61b08a5c 100644 --- a/platforms/fabric/src/main/java/net/lostluma/dynamic_fps/impl/fabric/mixin/GuiMixin.java +++ b/platforms/fabric/src/main/java/net/lostluma/dynamic_fps/impl/fabric/mixin/GuiMixin.java @@ -14,7 +14,13 @@ public class GuiMixin { /** * Render info on whether Dynamic FPS is disabled or always reducing the user's FPS. */ - @Inject(method = "renderSavingIndicator", at = @At("HEAD")) + @Inject( + method = "render", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/gui/Gui;renderSavingIndicator(Lnet/minecraft/client/gui/GuiGraphics;)V" + ) + ) private void renderSavingIndicator(CallbackInfo callbackInfo, @Local(argsOnly = true) GuiGraphics guiGraphics) { HudInfoRenderer.renderInfo(guiGraphics); } diff --git a/platforms/fabric/src/main/java/net/lostluma/dynamic_fps/impl/fabric/service/FabricModCompat.java b/platforms/fabric/src/main/java/net/lostluma/dynamic_fps/impl/fabric/service/FabricModCompat.java index 473389b2..d00cd7a6 100644 --- a/platforms/fabric/src/main/java/net/lostluma/dynamic_fps/impl/fabric/service/FabricModCompat.java +++ b/platforms/fabric/src/main/java/net/lostluma/dynamic_fps/impl/fabric/service/FabricModCompat.java @@ -2,15 +2,22 @@ import dynamic_fps.impl.service.ModCompat; import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.api.MappingResolver; import net.fabricmc.loader.api.ModContainer; import net.fabricmc.loader.api.metadata.CustomValue; import net.fabricmc.loader.api.metadata.ModMetadata; import net.lostluma.dynamic_fps.impl.fabric.compat.FREX; import org.jetbrains.annotations.Nullable; +import java.util.HashSet; +import java.util.Set; + public class FabricModCompat implements ModCompat { private static boolean disableOverlayOptimization = false; + private static final Set optedInScreens = new HashSet<>(); + private static final Set optedOutScreens = new HashSet<>(); + static { FabricLoader.getInstance().getAllMods().forEach(FabricModCompat::parseModMetadata); } @@ -25,6 +32,16 @@ public boolean disableOverlayOptimization() { return disableOverlayOptimization; } + @Override + public Set getOptedInScreens() { + return optedInScreens; + } + + @Override + public Set getOptedOutScreens() { + return optedOutScreens; + } + private static void parseModMetadata(ModContainer mod) { CustomValue.CvObject root; ModMetadata data = mod.getMetadata(); @@ -36,6 +53,9 @@ private static void parseModMetadata(ModContainer mod) { } parseOverlayOverride(root.get("optimized_overlay")); + + parseScreenOverrides(root.get("optimized_screens"), "enabled", optedInScreens); + parseScreenOverrides(root.get("optimized_screens"), "disabled", optedOutScreens); } private static void parseOverlayOverride(@Nullable CustomValue value) { @@ -43,4 +63,25 @@ private static void parseOverlayOverride(@Nullable CustomValue value) { disableOverlayOptimization = true; } } + + private static void parseScreenOverrides(@Nullable CustomValue parent, String type, Set set) { + if (parent == null || parent.getType() != CustomValue.CvType.OBJECT) { + return; + } + + CustomValue values = parent.getAsObject().get(type); + + if (values == null || values.getType() != CustomValue.CvType.ARRAY) { + return; + } + + MappingResolver resolver = FabricLoader.getInstance().getMappingResolver(); + + values.getAsArray().forEach(value -> { + if (value.getType() == CustomValue.CvType.STRING) { + // Translate from intermediary to runtime names for vanilla screens + set.add(resolver.mapClassName("intermediary", value.getAsString())); + } + }); + } } diff --git a/platforms/fabric/src/main/resources/fabric.mod.json b/platforms/fabric/src/main/resources/fabric.mod.json index bf110e52..b0c8e4c7 100644 --- a/platforms/fabric/src/main/resources/fabric.mod.json +++ b/platforms/fabric/src/main/resources/fabric.mod.json @@ -70,7 +70,13 @@ }, "depends": { "fabricloader": ">=0.15.10", - "minecraft": ">=1.21.0-alpha.24.20.a", + "minecraft": [ + "1.20.0", + "1.20.1", + "1.20.2", + "1.20.3", + "1.20.4" + ], "mixinextras": ">=0.3.2", "fabric-resource-loader-v0": "*", "fabric-lifecycle-events-v1": "*" @@ -87,5 +93,43 @@ "dynamic_fps.mixins.json", "dynamic_fps-common.mixins.json" ], - "accessWidener": "dynamic_fps.accesswidener" + "accessWidener": "dynamic_fps.accesswidener", + "custom": { + "dynamic_fps": { + "optimized_screens": { + "enabled": [ + "net.minecraft.class_4189", + "net.minecraft.class_404", + "net.minecraft.class_426", + "net.minecraft.class_4288", + "net.minecraft.class_6777", + "net.minecraft.class_443", + "net.minecraft.class_446", + "net.minecraft.class_445", + "net.minecraft.class_6599" + ], + "disabled": [ + "net.minecraft.class_434" + ], + "_comment": { + "_0": "Mojang mapping names of the enabled / disabled screens.", + "_1": "Sorted by fully qualified name. Translation not needed for mod screens.", + "enabled": { + "net.minecraft.class_4189": "net.minecraft.client.gui.screens.AccessibilityOptionsScreen", + "net.minecraft.class_404": "net.minecraft.client.gui.screens.ChatOptionsScreen", + "net.minecraft.class_426": "net.minecraft.client.gui.screens.LanguageSelectScreen", + "net.minecraft.class_4288": "net.minecraft.client.gui.screens.MouseSettingsScreen", + "net.minecraft.class_6777": "net.minecraft.client.gui.screens.OnlineOptionsScreen", + "net.minecraft.class_443": "net.minecraft.client.gui.screens.SoundOptionsScreen", + "net.minecraft.class_446": "net.minecraft.client.gui.screens.VideoSettingsScreen", + "net.minecraft.class_445": "net.minecraft.client.gui.screens.WinScreen", + "net.minecraft.class_6599": "net.minecraft.client.gui.screens.controls.KeyBindsScreen" + }, + "disabled": { + "net.minecraft.class_434": "net.minecraft.client.gui.screens.ReceivingLevelScreen" + } + } + } + } + } } diff --git a/platforms/forge/build.gradle b/platforms/forge/build.gradle index 5a680012..873bf7b2 100644 --- a/platforms/forge/build.gradle +++ b/platforms/forge/build.gradle @@ -41,6 +41,8 @@ dependencies { include(libs.mixinextras.forge) implementation(libs.mixinextras.forge) + include(libs.battery) + common(project(path: ":platforms:common", configuration: "namedElements")) { transitive false } shadowCommon(project(path: ":platforms:common", configuration: "transformProductionForge")) { transitive = false } } @@ -85,13 +87,11 @@ publishMods { accessToken = providers.environmentVariable("CURSEFORGE_SECRET") projectId = "335493" - /* minecraftVersionRange { start = project.property("minecraft_version_min").toString() end = project.property("minecraft_version_max").toString() } - */ - minecraftVersions.add(project.property("minecraft_version_min").toString()) + // minecraftVersions.add(project.property("minecraft_version_min").toString()) clientRequired = true serverRequired = false @@ -103,14 +103,12 @@ publishMods { accessToken = providers.environmentVariable("MODRINTH_SECRET") projectId = "LQ3K71Q1" - /* minecraftVersionRange { start = project.property("minecraft_version_min").toString() end = project.property("minecraft_version_max").toString() } - */ - minecraftVersions.add(project.property("minecraft_version_min").toString()) + // minecraftVersions.add(project.property("minecraft_version_min").toString()) - optional("modmenu") + optional("cloth-config") } } diff --git a/platforms/forge/src/main/java/net/lostluma/dynamic_fps/impl/forge/service/ForgeModCompat.java b/platforms/forge/src/main/java/net/lostluma/dynamic_fps/impl/forge/service/ForgeModCompat.java index 4f47fadb..814c28eb 100644 --- a/platforms/forge/src/main/java/net/lostluma/dynamic_fps/impl/forge/service/ForgeModCompat.java +++ b/platforms/forge/src/main/java/net/lostluma/dynamic_fps/impl/forge/service/ForgeModCompat.java @@ -1,9 +1,23 @@ package net.lostluma.dynamic_fps.impl.forge.service; +import com.electronwill.nightconfig.core.CommentedConfig; import dynamic_fps.impl.service.ModCompat; +import net.minecraft.client.gui.screens.ReceivingLevelScreen; import net.minecraftforge.fml.ModList; +import net.minecraftforge.forgespi.language.IModInfo; + +import java.util.HashSet; +import java.util.Set; public class ForgeModCompat implements ModCompat { + private static boolean disableOverlayOptimization = false; + private static final Set optedOutScreens = new HashSet<>(); + + static { + optedOutScreens.add(ReceivingLevelScreen.class.getCanonicalName()); + ModList.get().getMods().forEach(ForgeModCompat::parseModMetadata); + } + @Override public boolean isDisabled() { return false; @@ -11,6 +25,30 @@ public boolean isDisabled() { @Override public boolean disableOverlayOptimization() { - return ModList.get().isLoaded("rrls"); + return disableOverlayOptimization || ModList.get().isLoaded("rrls"); + } + + @Override + public Set getOptedInScreens() { + return Set.of(); + } + + @Override + public Set getOptedOutScreens() { + return optedOutScreens; + } + + private static void parseModMetadata(IModInfo modInfo) { + Object config = modInfo.getModProperties().get("dynamic_fps"); + + if (config == null) { + return; + } + + Boolean value = ((CommentedConfig) config).get("optimized_overlay"); + + if (value != null && !value) { + disableOverlayOptimization = true; + } } } diff --git a/platforms/forge/src/main/java/net/lostluma/dynamic_fps/impl/forge/service/ForgePlatform.java b/platforms/forge/src/main/java/net/lostluma/dynamic_fps/impl/forge/service/ForgePlatform.java index 74a7af9e..13be8a2b 100644 --- a/platforms/forge/src/main/java/net/lostluma/dynamic_fps/impl/forge/service/ForgePlatform.java +++ b/platforms/forge/src/main/java/net/lostluma/dynamic_fps/impl/forge/service/ForgePlatform.java @@ -2,6 +2,7 @@ import dynamic_fps.impl.Constants; import dynamic_fps.impl.service.Platform; +import dynamic_fps.impl.util.Version; import net.lostluma.dynamic_fps.impl.forge.DynamicFPSForgeMod; import net.minecraftforge.fml.ModContainer; import net.minecraftforge.fml.ModList; @@ -41,9 +42,20 @@ public boolean isModLoaded(String modId) { } @Override - public Optional getModVersion(String modId) { + public Optional getModVersion(String modId) { Optional optional = ModList.get().getModContainerById(modId); - return optional.map(modContainer -> modContainer.getModInfo().getVersion().toString()); + + if (optional.isEmpty()) { + return Optional.empty(); + } + + String raw = optional.get().getModInfo().getVersion().toString(); + + try { + return Optional.of(Version.of(raw)); + } catch (Version.VersionParseException e) { + throw new RuntimeException(e); + } } @Override diff --git a/platforms/neoforge/build.gradle b/platforms/neoforge/build.gradle index cbc86c59..9191357b 100644 --- a/platforms/neoforge/build.gradle +++ b/platforms/neoforge/build.gradle @@ -90,13 +90,11 @@ publishMods { accessToken = providers.environmentVariable("CURSEFORGE_SECRET") projectId = "335493" - /* minecraftVersionRange { start = project.property("minecraft_version_min").toString() end = project.property("minecraft_version_max").toString() } - */ - minecraftVersions.add(project.property("minecraft_version_min").toString()) + // minecraftVersions.add(project.property("minecraft_version_min").toString()) clientRequired = true serverRequired = false @@ -108,14 +106,12 @@ publishMods { accessToken = providers.environmentVariable("MODRINTH_SECRET") projectId = "LQ3K71Q1" - /* minecraftVersionRange { start = project.property("minecraft_version_min").toString() end = project.property("minecraft_version_max").toString() } - */ - minecraftVersions.add(project.property("minecraft_version_min").toString()) + // minecraftVersions.add(project.property("minecraft_version_min").toString()) - optional("modmenu") + optional("cloth-config") } } diff --git a/platforms/neoforge/gradle.properties b/platforms/neoforge/gradle.properties index 97b48a86..9d26e080 100644 --- a/platforms/neoforge/gradle.properties +++ b/platforms/neoforge/gradle.properties @@ -1,2 +1,5 @@ loom.platform=neoforge supported_platforms=neoforge + +minecraft_version = 1.20.2 +minecraft_version_min = 1.20.2 diff --git a/platforms/neoforge/src/main/java/net/lostluma/dynamic_fps/impl/neoforge/DynamicFPSNeoForgeMod.java b/platforms/neoforge/src/main/java/net/lostluma/dynamic_fps/impl/neoforge/DynamicFPSNeoForgeMod.java index 3f1cb0d5..e0832aa8 100644 --- a/platforms/neoforge/src/main/java/net/lostluma/dynamic_fps/impl/neoforge/DynamicFPSNeoForgeMod.java +++ b/platforms/neoforge/src/main/java/net/lostluma/dynamic_fps/impl/neoforge/DynamicFPSNeoForgeMod.java @@ -8,9 +8,9 @@ import net.neoforged.fml.ModLoadingContext; import net.neoforged.fml.common.Mod; import net.neoforged.fml.loading.FMLLoader; +import net.neoforged.neoforge.client.ConfigScreenHandler; import net.neoforged.neoforge.client.event.RegisterKeyMappingsEvent; import net.neoforged.neoforge.client.event.RenderGuiEvent; -import net.neoforged.neoforge.client.gui.IConfigScreenFactory; import net.neoforged.neoforge.common.NeoForge; @Mod(Constants.MOD_ID) @@ -23,8 +23,10 @@ public DynamicFPSNeoForgeMod(IEventBus modEventBus) { DynamicFPSMod.init(); ModLoadingContext.get().registerExtensionPoint( - IConfigScreenFactory.class, - () -> (minecraft, screen) -> DynamicFPSMod.getConfigScreen(screen) + ConfigScreenHandler.ConfigScreenFactory.class, + () -> new ConfigScreenHandler.ConfigScreenFactory( + (minecraft, screen) -> DynamicFPSMod.getConfigScreen(screen) + ) ); modEventBus.addListener(this::registerKeyMappings); diff --git a/platforms/neoforge/src/main/java/net/lostluma/dynamic_fps/impl/neoforge/service/NeoForgeModCompat.java b/platforms/neoforge/src/main/java/net/lostluma/dynamic_fps/impl/neoforge/service/NeoForgeModCompat.java index 7496aa3a..62735115 100644 --- a/platforms/neoforge/src/main/java/net/lostluma/dynamic_fps/impl/neoforge/service/NeoForgeModCompat.java +++ b/platforms/neoforge/src/main/java/net/lostluma/dynamic_fps/impl/neoforge/service/NeoForgeModCompat.java @@ -2,13 +2,19 @@ import com.electronwill.nightconfig.core.CommentedConfig; import dynamic_fps.impl.service.ModCompat; +import net.minecraft.client.gui.screens.ReceivingLevelScreen; import net.neoforged.fml.ModList; import net.neoforged.neoforgespi.language.IModInfo; +import java.util.HashSet; +import java.util.Set; + public class NeoForgeModCompat implements ModCompat { private static boolean disableOverlayOptimization = false; + private static final Set optedOutScreens = new HashSet<>(); static { + optedOutScreens.add(ReceivingLevelScreen.class.getCanonicalName()); ModList.get().getMods().forEach(NeoForgeModCompat::parseModMetadata); } @@ -22,6 +28,16 @@ public boolean disableOverlayOptimization() { return disableOverlayOptimization || ModList.get().isLoaded("rrls"); } + @Override + public Set getOptedInScreens() { + return Set.of(); + } + + @Override + public Set getOptedOutScreens() { + return optedOutScreens; + } + private static void parseModMetadata(IModInfo modInfo) { Object config = modInfo.getModProperties().get("dynamic_fps"); diff --git a/platforms/neoforge/src/main/java/net/lostluma/dynamic_fps/impl/neoforge/service/NeoForgePlatform.java b/platforms/neoforge/src/main/java/net/lostluma/dynamic_fps/impl/neoforge/service/NeoForgePlatform.java index 08f5b43e..fd4eef6c 100644 --- a/platforms/neoforge/src/main/java/net/lostluma/dynamic_fps/impl/neoforge/service/NeoForgePlatform.java +++ b/platforms/neoforge/src/main/java/net/lostluma/dynamic_fps/impl/neoforge/service/NeoForgePlatform.java @@ -7,8 +7,8 @@ import net.neoforged.fml.ModList; import net.neoforged.fml.loading.FMLLoader; import net.neoforged.fml.loading.FMLPaths; -import net.neoforged.neoforge.client.event.ClientTickEvent; import net.neoforged.neoforge.common.NeoForge; +import net.neoforged.neoforge.event.TickEvent; import java.io.IOException; import java.nio.file.Files; @@ -61,7 +61,7 @@ public Optional getModVersion(String modId) { @Override public void registerStartTickEvent(StartTickEvent event) { - NeoForge.EVENT_BUS.addListener(ClientTickEvent.Pre.class, (unused) -> event.onStartTick()); + NeoForge.EVENT_BUS.addListener(TickEvent.ClientTickEvent.class, (unused) -> event.onStartTick()); } private Path ensureDir(Path path) { diff --git a/platforms/neoforge/src/main/resources/META-INF/neoforge.mods.toml b/platforms/neoforge/src/main/resources/META-INF/mods.toml similarity index 98% rename from platforms/neoforge/src/main/resources/META-INF/neoforge.mods.toml rename to platforms/neoforge/src/main/resources/META-INF/mods.toml index 04dedd3d..37337481 100644 --- a/platforms/neoforge/src/main/resources/META-INF/neoforge.mods.toml +++ b/platforms/neoforge/src/main/resources/META-INF/mods.toml @@ -85,7 +85,7 @@ file="META-INF/accesstransformer.cfg" [[dependencies.dynamic_fps]] modId = "minecraft" mandatory = true -versionRange = "[1.21.0,)" +versionRange = "[1.20.2,1.20.4]" ordering = "NONE" side = "CLIENT" diff --git a/platforms/quilt/build.gradle b/platforms/quilt/build.gradle index 21ee7990..4b4d0b45 100644 --- a/platforms/quilt/build.gradle +++ b/platforms/quilt/build.gradle @@ -39,6 +39,8 @@ dependencies { modApi(libs.modmenu) + include(libs.battery) + common(project(path: ":platforms:common", configuration: "namedElements")) { transitive false } shadowCommon(project(path: ":platforms:common", configuration: "transformProductionQuilt")) { transitive false } } @@ -83,13 +85,11 @@ publishMods { accessToken = providers.environmentVariable("CURSEFORGE_SECRET") projectId = "335493" - /* minecraftVersionRange { start = project.property("minecraft_version_min").toString() end = project.property("minecraft_version_max").toString() } - */ - minecraftVersions.add(project.property("minecraft_version_min").toString()) + // minecraftVersions.add(project.property("minecraft_version_min").toString()) clientRequired = true serverRequired = false @@ -102,15 +102,13 @@ publishMods { accessToken = providers.environmentVariable("MODRINTH_SECRET") projectId = "LQ3K71Q1" - /* minecraftVersionRange { start = project.property("minecraft_version_min").toString() end = project.property("minecraft_version_max").toString() includeSnapshots = true } - */ - minecraftVersions.add(project.property("minecraft_version_min").toString()) + // minecraftVersions.add(project.property("minecraft_version_min").toString()) requires("qsl") optional("cloth-config", "modmenu") diff --git a/platforms/quilt/src/main/java/net/lostluma/dynamic_fps/impl/quilt/mixin/GuiMixin.java b/platforms/quilt/src/main/java/net/lostluma/dynamic_fps/impl/quilt/mixin/GuiMixin.java index 7a0aff08..66079ceb 100644 --- a/platforms/quilt/src/main/java/net/lostluma/dynamic_fps/impl/quilt/mixin/GuiMixin.java +++ b/platforms/quilt/src/main/java/net/lostluma/dynamic_fps/impl/quilt/mixin/GuiMixin.java @@ -14,7 +14,13 @@ public class GuiMixin { /** * Render info on whether Dynamic FPS is disabled or always reducing the user's FPS. */ - @Inject(method = "renderSavingIndicator", at = @At("HEAD")) + @Inject( + method = "render", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/gui/Gui;renderSavingIndicator(Lnet/minecraft/client/gui/GuiGraphics;)V" + ) + ) private void renderSavingIndicator(CallbackInfo callbackInfo, @Local(argsOnly = true) GuiGraphics guiGraphics) { HudInfoRenderer.renderInfo(guiGraphics); } diff --git a/platforms/quilt/src/main/java/net/lostluma/dynamic_fps/impl/quilt/service/QuiltModCompat.java b/platforms/quilt/src/main/java/net/lostluma/dynamic_fps/impl/quilt/service/QuiltModCompat.java index 3a11d11d..efc0142b 100644 --- a/platforms/quilt/src/main/java/net/lostluma/dynamic_fps/impl/quilt/service/QuiltModCompat.java +++ b/platforms/quilt/src/main/java/net/lostluma/dynamic_fps/impl/quilt/service/QuiltModCompat.java @@ -15,6 +15,9 @@ public class QuiltModCompat implements ModCompat { private static boolean disableOverlayOptimization = false; + private static final Set optedInScreens = new HashSet<>(); + private static final Set optedOutScreens = new HashSet<>(); + static { QuiltLoader.getAllMods().forEach(QuiltModCompat::parseModMetadata); } @@ -29,6 +32,16 @@ public boolean disableOverlayOptimization() { return disableOverlayOptimization; } + @Override + public Set getOptedInScreens() { + return optedInScreens; + } + + @Override + public Set getOptedOutScreens() { + return optedOutScreens; + } + private static void parseModMetadata(ModContainer mod) { LoaderValue.LObject root; ModMetadata data = mod.metadata(); @@ -40,6 +53,9 @@ private static void parseModMetadata(ModContainer mod) { } parseOverlayOverride(root.get("optimized_overlay")); + + parseScreenOverrides(root.get("optimized_screens"), "enabled", optedInScreens); + parseScreenOverrides(root.get("optimized_screens"), "disabled", optedOutScreens); } private static void parseOverlayOverride(@Nullable LoaderValue value) { @@ -47,4 +63,25 @@ private static void parseOverlayOverride(@Nullable LoaderValue value) { disableOverlayOptimization = true; } } + + private static void parseScreenOverrides(@Nullable LoaderValue parent, String type, Set set) { + if (parent == null || parent.type() != LoaderValue.LType.OBJECT) { + return; + } + + LoaderValue values = parent.asObject().get(type); + + if (values == null || values.type() != LoaderValue.LType.ARRAY) { + return; + } + + MappingResolver resolver = QuiltLoader.getMappingResolver(); + + values.asArray().forEach(value -> { + if (value.type() == LoaderValue.LType.STRING) { + // Translate from intermediary to runtime names for vanilla screens + set.add(resolver.mapClassName("intermediary", value.asString())); + } + }); + } } diff --git a/platforms/quilt/src/main/resources/quilt.mod.json b/platforms/quilt/src/main/resources/quilt.mod.json index 0c895190..ec78f3f8 100644 --- a/platforms/quilt/src/main/resources/quilt.mod.json +++ b/platforms/quilt/src/main/resources/quilt.mod.json @@ -81,7 +81,9 @@ }, { "id": "minecraft", - "versions": ">=1.21.0-alpha.24.20.a" + "versions": { + "all": [">=1.20.0", "<=1.20.4"] + } }, { "id": "mixinextras", @@ -114,5 +116,41 @@ "dynamic_fps.mixins.json", "dynamic_fps-common.mixins.json" ], - "access_widener": "dynamic_fps.accesswidener" + "access_widener": "dynamic_fps.accesswidener", + "dynamic_fps": { + "optimized_screens": { + "enabled": [ + "net.minecraft.class_4189", + "net.minecraft.class_404", + "net.minecraft.class_426", + "net.minecraft.class_4288", + "net.minecraft.class_6777", + "net.minecraft.class_443", + "net.minecraft.class_446", + "net.minecraft.class_445", + "net.minecraft.class_6599" + ], + "disabled": [ + "net.minecraft.class_434" + ], + "_comment": { + "_0": "Mojang mapping names of the enabled / disabled screens.", + "_1": "Sorted by fully qualified name. Translation not needed for mod screens.", + "enabled": { + "net.minecraft.class_4189": "net.minecraft.client.gui.screens.AccessibilityOptionsScreen", + "net.minecraft.class_404": "net.minecraft.client.gui.screens.ChatOptionsScreen", + "net.minecraft.class_426": "net.minecraft.client.gui.screens.LanguageSelectScreen", + "net.minecraft.class_4288": "net.minecraft.client.gui.screens.MouseSettingsScreen", + "net.minecraft.class_6777": "net.minecraft.client.gui.screens.OnlineOptionsScreen", + "net.minecraft.class_443": "net.minecraft.client.gui.screens.SoundOptionsScreen", + "net.minecraft.class_446": "net.minecraft.client.gui.screens.VideoSettingsScreen", + "net.minecraft.class_445": "net.minecraft.client.gui.screens.WinScreen", + "net.minecraft.class_6599": "net.minecraft.client.gui.screens.controls.KeyBindsScreen" + }, + "disabled": { + "net.minecraft.class_434": "net.minecraft.client.gui.screens.ReceivingLevelScreen" + } + } + } + } } diff --git a/settings.gradle.kts b/settings.gradle.kts index e800d0e8..d3a08dd3 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -17,6 +17,6 @@ includeBuild("build-logic") include(":platforms:common") include(":platforms:fabric") -// include(":platforms:forge") +include(":platforms:forge") include(":platforms:neoforge") include(":platforms:quilt")