diff --git a/CHANGELOG.md b/CHANGELOG.md index 78ff9dd..4980fc0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,12 @@ -## Snapper 1.1.2 +## Snapper 1.1.3 ### Features -- 26.1 support -- Parallel image loading (much faster!) -- Reload Button +- 26.2 support + +### Changes +- Moved View Screenshots button to align with vanilla. +- Changed default key mapping for `Open Latest Screenshot` from O to B as O is now used for the friends menu in vanilla. ### Bug Fixes -- Many many bugfixes related to reloading \ No newline at end of file +- Changes to the `View Mode` setting will now apply immediately after exiting the config menu. +- Exiting the Screenshot Viewer screen now correctly returns to the previous screen instead of closing all screens. \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 8d03b4c..ad9447f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,7 +5,7 @@ plugins { alias(libs.plugins.modpublish) } -val modVersion = "1.1.2" +val modVersion = "1.1.3" val modId = "snapper" val modName = "Snapper" @@ -34,11 +34,6 @@ repositories { content { includeGroupAndSubgroups("lgbt.greenhouse") } } - maven("https://maven.greenhouse.lgbt/snapshots/") { - name = "Greenhouse Snapshots" - content { includeGroupAndSubgroups("lgbt.greenhouse") } - } - mavenCentral() } @@ -73,16 +68,23 @@ loom { runs.configureEach { jvmArguments.addAll(debugArgs) } } +val greenhouseModdingApiAttribute = Attribute.of("lgbt.greenhouse.modding.api", String::class.java) +val greenhouseModdingPlatformAttribute = Attribute.of("lgbt.greenhouse.modding.platform", String::class.java) + dependencies { minecraft(libs.minecraft) implementation(libs.fabric.loader) implementation(libs.fabric.api) - compileOnlyApi(libs.greenhouse.config.api) + compileOnly(libs.greenhouse.config) { + attributes { + attribute(greenhouseModdingApiAttribute, "") // The value of the attribute must remain an empty string. + } + } - runtimeOnly(libs.greenhouse.config.fabric) - include(libs.greenhouse.config.fabric) + runtimeOnly(libs.greenhouse.config) + include(libs.greenhouse.config) compileOnly(libs.modmenu) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fc17e13..8c496e1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,13 +2,13 @@ fabric_loom = "1.17-SNAPSHOT" modpublish = "2.0.0" -minecraft = "26.1.2" +minecraft = "26.2" -fabric_loader = "0.18.4" -fabric_api = "0.151.0+26.1.2" +fabric_loader = "0.19.3" +fabric_api = "0.154.2+26.2" -greenhouse_config = "3.0.0-beta.5+26.1.x" -modmenu = "18.0.0-beta.1" +greenhouse_config = "3.0.1+26.2.x" +modmenu = "20.0.0-beta.4" objc_bridge = "1.0.0" @@ -22,8 +22,7 @@ minecraft = { group = "mojang", name = "minecraft", version.ref = "minecraft" } fabric_loader = { group = "net.fabricmc", name = "fabric-loader", version.ref = "fabric_loader" } fabric_api = { group = "net.fabricmc.fabric-api", name = "fabric-api", version.ref = "fabric_api" } -greenhouse_config_api = { group = "lgbt.greenhouse.config", name = "greenhouse-config-api", version.ref = "greenhouse_config" } -greenhouse_config_fabric = { group = "lgbt.greenhouse.config", name = "greenhouse-config-fabric", version.ref = "greenhouse_config" } +greenhouse_config = { group = "lgbt.greenhouse.config", name = "greenhouse-config", version.ref = "greenhouse_config" } modmenu = { group = "com.terraformersmc", name = "modmenu", version.ref = "modmenu" } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index d997cfc..b1b8ef5 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 1a70468..a9db115 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,9 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-bin.zip networkTimeout=10000 +retries=0 +retryBackOffMs=500 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 0262dcb..249efbb 100755 --- a/gradlew +++ b/gradlew @@ -20,7 +20,7 @@ ############################################################################## # -# Gradle start up script for POSIX generated by Gradle. +# gradlew start up script for POSIX generated by Gradle. # # Important for running: # @@ -29,7 +29,7 @@ # bash, then to run this script, type that shell name before the whole # command line, like: # -# ksh Gradle +# ksh gradlew # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: @@ -57,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/b631911858264c0b6e4d6603d677ff5218766cee/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/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/. diff --git a/gradlew.bat b/gradlew.bat index c4bdd3a..a51ec4f 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -19,12 +19,12 @@ @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem -@rem Gradle startup script for Windows +@rem gradlew startup script for Windows @rem @rem ########################################################################## -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal +@rem Set local scope for the variables, and ensure extensions are enabled +setlocal EnableExtensions set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. @@ -51,7 +51,7 @@ 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 +"%COMSPEC%" /c exit 1 :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% @@ -65,29 +65,18 @@ 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 +"%COMSPEC%" /c exit 1 :execute @rem Setup the command line -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* +@rem Execute gradlew +@rem endlocal doesn't take effect until after the line is parsed and variables are expanded +@rem which allows us to clear the local environment before executing the java command +endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +:exitWithErrorLevel +@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts +"%COMSPEC%" /c exit %ERRORLEVEL% diff --git a/src/client/java/dev/spiritstudios/snapper/Snapper.java b/src/client/java/dev/spiritstudios/snapper/Snapper.java index 7e3fdea..42bd686 100644 --- a/src/client/java/dev/spiritstudios/snapper/Snapper.java +++ b/src/client/java/dev/spiritstudios/snapper/Snapper.java @@ -3,6 +3,9 @@ import dev.spiritstudios.snapper.util.uploading.ScreenshotUploading; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.components.SpriteIconButton; +import net.minecraft.network.chat.Component; import net.minecraft.resources.Identifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -20,6 +23,19 @@ public void onInitializeClient() { ClientLifecycleEvents.CLIENT_STOPPING.register(_ -> ScreenshotUploading.close()); } + public static SpriteIconButton createSnapperButton(final int width, final Button.OnPress onPress) { + return SpriteIconButton.builder( + Component.translatable("button.snapper.screenshots"), + onPress, + true + ) + .width(width) + .sprite(Snapper.id("screenshots/screenshot"), 15, 15) + .tooltip(Component.translatable("button.snapper.screenshots")) + .narration(_ -> Component.translatable("button.snapper.screenshots")) + .build(); + } + public static Identifier id(String path) { return Identifier.fromNamespaceAndPath(MOD_ID, path); } diff --git a/src/client/java/dev/spiritstudios/snapper/SnapperConfig.java b/src/client/java/dev/spiritstudios/snapper/SnapperConfig.java index 742abe7..952b750 100644 --- a/src/client/java/dev/spiritstudios/snapper/SnapperConfig.java +++ b/src/client/java/dev/spiritstudios/snapper/SnapperConfig.java @@ -2,6 +2,7 @@ import com.mojang.serialization.Codec; import dev.spiritstudios.snapper.gui.screen.ScreenshotListScreen; +import dev.spiritstudios.snapper.gui.toast.SnapperToast; import dev.spiritstudios.snapper.util.SnapperUtil; import dev.spiritstudios.snapper.util.DirectoryConfigUtil; import dev.spiritstudios.snapper.util.uploading.AxolotlClientApi; @@ -12,6 +13,8 @@ import lgbt.greenhouse.config.api.v3.dfu.fix.GreenhouseConfigRelocateFieldsFix; import lgbt.greenhouse.config.api.v3.lang.GreenhouseConfigJsonCLang; import lgbt.greenhouse.config.api.v3.lang.GreenhouseConfigJsonLang; +import net.minecraft.client.Minecraft; +import net.minecraft.network.chat.Component; import net.minecraft.util.Util; import java.nio.file.Path; @@ -175,15 +178,10 @@ public static Mutable mutable() { return new Mutable(); } - public static void edit(Consumer editor) { - var mutable = mutable(); - editor.accept(mutable); - mutable.save(); - } - public static CompletableFuture editAsync(Consumer editor) { - var mutable = mutable(); + Mutable mutable = mutable(); editor.accept(mutable); + return mutable.saveAsync(); } @@ -219,12 +217,27 @@ public Mutable() { termsAccepted = config.axolotlClient.termsStatus; } - public void save() { - HOLDER.save(build(), null); - } public CompletableFuture saveAsync() { - return CompletableFuture.runAsync(this::save, Util.ioPool()); + SnapperConfig newValue = this.build(); + + var oldValue = HOLDER.get(); + HOLDER.set(newValue, null); + + return CompletableFuture.runAsync( + () -> HOLDER.save(newValue, null), + Util.ioPool() + ).exceptionallyCompose(error -> Minecraft.getInstance().submit(() -> { + Snapper.LOGGER.error("Failed to save configuration file.", error); + + HOLDER.set(oldValue, null); + + SnapperToast.push( + SnapperToast.Type.DENY, + Component.translatable("toast.snapper.config.failure.title"), + Component.translatable("toast.snapper.config.failure.description") + ); + })); } private SnapperConfig build() { diff --git a/src/client/java/dev/spiritstudios/snapper/SnapperKeyMappings.java b/src/client/java/dev/spiritstudios/snapper/SnapperKeyMappings.java index b25999c..f0013a1 100644 --- a/src/client/java/dev/spiritstudios/snapper/SnapperKeyMappings.java +++ b/src/client/java/dev/spiritstudios/snapper/SnapperKeyMappings.java @@ -26,7 +26,7 @@ public final class SnapperKeyMappings { public static final KeyMapping RECENT_SCREENSHOT_KEY = new KeyMapping( "key.snapper.recent", - GLFW.GLFW_KEY_O, + GLFW.GLFW_KEY_B, SNAPPER_CATEGORY ); @@ -41,10 +41,10 @@ public static void init() { KeyMappingHelper.registerKeyMapping(RECENT_SCREENSHOT_KEY); KeyMappingHelper.registerKeyMapping(SCREENSHOT_MENU_KEY); - ClientTickEvents.END_CLIENT_TICK.register(client -> { - while (PANORAMA_KEY.consumeClick()) SnapperKeyMappings.takePanorama(client); - while (RECENT_SCREENSHOT_KEY.consumeClick()) SnapperKeyMappings.openRecentScreenshot(client); - while (SCREENSHOT_MENU_KEY.consumeClick()) client.setScreen(new ScreenshotListScreen(client.screen)); + ClientTickEvents.END_CLIENT_TICK.register(minecraft -> { + while (PANORAMA_KEY.consumeClick()) SnapperKeyMappings.takePanorama(minecraft); + while (RECENT_SCREENSHOT_KEY.consumeClick()) SnapperKeyMappings.openRecentScreenshot(minecraft); + while (SCREENSHOT_MENU_KEY.consumeClick()) minecraft.gui.setScreen(new ScreenshotListScreen(minecraft.gui.screen())); }); } @@ -62,7 +62,7 @@ private static void takePanorama(Minecraft client) { ); } - private static void openRecentScreenshot(Minecraft client) { + private static void openRecentScreenshot(Minecraft minecraft) { List screenshots = ScreenshotActions.getScreenshots(); if (screenshots.isEmpty()) { SnapperToast.push( @@ -74,12 +74,12 @@ private static void openRecentScreenshot(Minecraft client) { } Path latestPath = screenshots.getFirst(); - ScreenshotTexture.createScreenshot(client.getTextureManager(), latestPath) + ScreenshotTexture.createScreenshot(minecraft.getTextureManager(), latestPath) .ifPresentOrElse( image -> { - client.setScreen(new ScreenshotViewerScreen( + minecraft.gui.setScreen(new ScreenshotViewerScreen( image, - client.screen + minecraft.gui.screen() )); }, () -> SnapperToast.push( diff --git a/src/client/java/dev/spiritstudios/snapper/gui/SnapperButtonBar.java b/src/client/java/dev/spiritstudios/snapper/gui/SnapperButtonBar.java index 2f5525e..f257164 100644 --- a/src/client/java/dev/spiritstudios/snapper/gui/SnapperButtonBar.java +++ b/src/client/java/dev/spiritstudios/snapper/gui/SnapperButtonBar.java @@ -65,7 +65,7 @@ public SnapperButtonBar( bottomRow.addChild(SpriteIconButton.builder( Component.translatable("config.snapper.title"), - _ -> minecraft.setScreen(new ConfigScreen(screen)), + _ -> minecraft.gui.setScreen(new ConfigScreen(screen)), true ).width(20).sprite(SETTINGS_ICON, 15, 15).build()); @@ -95,7 +95,7 @@ public SnapperButtonBar( SpriteIconButton panoramaButton = bottomRow.addChild( SpriteIconButton.builder( Component.translatable("button.snapper.screenshots"), - _ -> minecraft.setScreen(new PanoramaViewerScreen(Component.translatable("menu.snapper.panorama").getString(), screen)), + _ -> minecraft.gui.setScreen(new PanoramaViewerScreen(Component.translatable("menu.snapper.panorama").getString(), screen)), true ).width(20).sprite(hasPanorama ? PANORAMA_BUTTON_ICON : PANORAMA_BUTTON_DISABLED_ICON, 15, 15).build()); @@ -135,7 +135,7 @@ public SnapperButtonBar( ScreenshotTexture selected = getTexture.get(); if (selected != null) { - minecraft.setScreen(new ScreenshotRenameScreen(selected.path, screen)); + minecraft.gui.setScreen(new ScreenshotRenameScreen(selected.path, screen)); } } ).width(buttonWidth).build()); diff --git a/src/client/java/dev/spiritstudios/snapper/gui/overlay/ExternalDialogOverlay.java b/src/client/java/dev/spiritstudios/snapper/gui/overlay/ExternalDialogOverlay.java index b53bb3e..8a6f4c6 100644 --- a/src/client/java/dev/spiritstudios/snapper/gui/overlay/ExternalDialogOverlay.java +++ b/src/client/java/dev/spiritstudios/snapper/gui/overlay/ExternalDialogOverlay.java @@ -17,8 +17,10 @@ public class ExternalDialogOverlay extends Overlay { @Override public void extractRenderState(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float a) { - if (this.minecraft.screen != null) { - this.minecraft.screen.extractRenderStateWithTooltipAndSubtitles(graphics, mouseX, mouseY, a); + if (this.minecraft.gui.screen() != null) { + this.minecraft.gui.screen().extractRenderStateWithTooltipAndSubtitles(graphics, 0, 0, a); + } else { + this.minecraft.gui.hud.extractDeferredSubtitles(); } graphics.nextStratum(); @@ -43,6 +45,6 @@ public void extractRenderState(GuiGraphicsExtractor graphics, int mouseX, int mo } public void close() { - this.minecraft.setOverlay(null); + this.minecraft.gui.setOverlay(null); } } diff --git a/src/client/java/dev/spiritstudios/snapper/gui/screen/ConfigScreen.java b/src/client/java/dev/spiritstudios/snapper/gui/screen/ConfigScreen.java index d3cba0b..f0b7592 100644 --- a/src/client/java/dev/spiritstudios/snapper/gui/screen/ConfigScreen.java +++ b/src/client/java/dev/spiritstudios/snapper/gui/screen/ConfigScreen.java @@ -252,15 +252,15 @@ public void reset() { public void onClose() { var viewMode = SnapperConfig.HOLDER.get().viewMode(); - config.saveAsync().thenRun(() -> { - if (lastScreen instanceof ReloadableScreen reloadableScreen) { - Minecraft.getInstance().submit(reloadableScreen::reload); - if (config.viewMode != viewMode) { - reloadableScreen.recreateList(); - } + config.saveAsync(); + + if (lastScreen instanceof ReloadableScreen reloadableScreen) { + Minecraft.getInstance().submit(reloadableScreen::reload); + if (config.viewMode != viewMode) { + reloadableScreen.recreateList(); } - }); + } - minecraft.setScreen(lastScreen); + minecraft.gui.setScreen(lastScreen); } } diff --git a/src/client/java/dev/spiritstudios/snapper/gui/screen/PanoramaViewerScreen.java b/src/client/java/dev/spiritstudios/snapper/gui/screen/PanoramaViewerScreen.java index 5e4a429..c129ed7 100644 --- a/src/client/java/dev/spiritstudios/snapper/gui/screen/PanoramaViewerScreen.java +++ b/src/client/java/dev/spiritstudios/snapper/gui/screen/PanoramaViewerScreen.java @@ -71,7 +71,7 @@ public void onClose() { texture.close(); } - Minecraft.getInstance().setScreen(this.parent); + this.minecraft.gui.setScreen(this.parent); } @Override @@ -97,10 +97,10 @@ protected void init() { @Override public void extractRenderState(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float a) { Minecraft minecraft = Minecraft.getInstance(); - float delta = (float) ((double) a * minecraft.gameRenderer.getGameRenderState().optionsRenderState.panoramaSpeed); + float delta = (float) ((double) a * minecraft.gameRenderer.gameRenderState().optionsRenderState.panoramaSpeed); this.spin = Mth.wrapDegrees(this.spin + delta * 0.1F); - minecraft.gameRenderer.getGameRenderState().guiRenderState.setData(SNAPPER_PANORAMA, new PanoramaRenderState(-this.spin)); + minecraft.gameRenderer.gameRenderState().guiRenderState.setData(SNAPPER_PANORAMA, new PanoramaRenderState(-this.spin)); graphics.centeredText( this.font, diff --git a/src/client/java/dev/spiritstudios/snapper/gui/screen/PrivacyNoticeScreen.java b/src/client/java/dev/spiritstudios/snapper/gui/screen/PrivacyNoticeScreen.java index c27b010..bfdff62 100644 --- a/src/client/java/dev/spiritstudios/snapper/gui/screen/PrivacyNoticeScreen.java +++ b/src/client/java/dev/spiritstudios/snapper/gui/screen/PrivacyNoticeScreen.java @@ -95,13 +95,13 @@ private void addButtons(int y) { Util.getPlatform().openUri(TERMS_URI)).bounds(width / 2 - (buttonWidth / 2) - buttonWidth - 5, y, buttonWidth, 20).build()); addRenderableWidget(Button.builder(Component.translatable("snapper.privacy_notice.accept"), _ -> { - Minecraft.getInstance().setScreen(parent); + minecraft.gui.setScreen(parent); SnapperConfig.editAsync(m -> m.termsAccepted = AxolotlClientApi.TermsAcceptance.ACCEPTED); accepted.accept(true); }).bounds(width / 2 - (buttonWidth / 2), y, buttonWidth, 20).build()); addRenderableWidget(Button.builder(Component.translatable("snapper.privacy_notice.deny"), _ -> { - Minecraft.getInstance().setScreen(parent); + minecraft.gui.setScreen(parent); SnapperConfig.editAsync(m -> m.termsAccepted = AxolotlClientApi.TermsAcceptance.DENIED); accepted.accept(false); }).bounds(width / 2 - (buttonWidth / 2) + buttonWidth + 5, y, buttonWidth, 20).build()); diff --git a/src/client/java/dev/spiritstudios/snapper/gui/screen/ScreenshotListScreen.java b/src/client/java/dev/spiritstudios/snapper/gui/screen/ScreenshotListScreen.java index 9677b7f..4e73692 100644 --- a/src/client/java/dev/spiritstudios/snapper/gui/screen/ScreenshotListScreen.java +++ b/src/client/java/dev/spiritstudios/snapper/gui/screen/ScreenshotListScreen.java @@ -100,7 +100,7 @@ public ScreenshotsWidget getScreenshots() { @Override public void onClose() { - super.onClose(); + this.minecraft.gui.setScreen(this.parent); screenshots.clearEntries(); } @@ -116,7 +116,7 @@ public void imageSelected(@Nullable ScreenshotListWidget.ScreenshotEntry screens } public void toggleGrid() { - SnapperConfig.edit(m -> m.viewMode = SnapperConfig.HOLDER.get().viewMode() == ViewMode.GRID ? ViewMode.LIST : ViewMode.GRID); + SnapperConfig.editAsync(m -> m.viewMode = SnapperConfig.HOLDER.get().viewMode() == ViewMode.GRID ? ViewMode.LIST : ViewMode.GRID); recreateList(); } @@ -128,7 +128,7 @@ public boolean keyPressed(KeyEvent input) { } if (input.key() == InputConstants.KEY_F5) { - minecraft.setScreen(new ScreenshotListScreen(this.parent)); + minecraft.gui.setScreen(new ScreenshotListScreen(this.parent)); return true; } @@ -141,7 +141,7 @@ public boolean keyPressed(KeyEvent input) { } if (input.key() == InputConstants.KEY_RETURN) { - minecraft.setScreen(new ScreenshotViewerScreen(selectedScreenshot.texture, this)); + minecraft.gui.setScreen(new ScreenshotViewerScreen(selectedScreenshot.texture, this)); return true; } diff --git a/src/client/java/dev/spiritstudios/snapper/gui/screen/ScreenshotRenameScreen.java b/src/client/java/dev/spiritstudios/snapper/gui/screen/ScreenshotRenameScreen.java index 93d8c6a..d206010 100644 --- a/src/client/java/dev/spiritstudios/snapper/gui/screen/ScreenshotRenameScreen.java +++ b/src/client/java/dev/spiritstudios/snapper/gui/screen/ScreenshotRenameScreen.java @@ -16,8 +16,7 @@ public class ScreenshotRenameScreen extends Screen { private final Path screenshot; private final EditBox renameInput; private final Component RENAME_INPUT_TEXT = Component.translatable("text.snapper.rename_input"); - private final Minecraft client = Minecraft.getInstance(); - private final Font textRenderer = client.font; + private final Font textRenderer = minecraft.font; private final Screen parent; public ScreenshotRenameScreen(Path screenshot, Screen parent) { @@ -56,11 +55,11 @@ private void renameScreenshot(String newName) { reloadableScreen.reload(); } - client.setScreen(this.parent); + minecraft.gui.setScreen(this.parent); } @Override public void onClose() { - this.client.setScreen(this.parent); + this.minecraft.gui.setScreen(this.parent); } } diff --git a/src/client/java/dev/spiritstudios/snapper/gui/screen/ScreenshotViewerScreen.java b/src/client/java/dev/spiritstudios/snapper/gui/screen/ScreenshotViewerScreen.java index 642f9fb..6d5e521 100644 --- a/src/client/java/dev/spiritstudios/snapper/gui/screen/ScreenshotViewerScreen.java +++ b/src/client/java/dev/spiritstudios/snapper/gui/screen/ScreenshotViewerScreen.java @@ -29,7 +29,6 @@ public class ScreenshotViewerScreen extends Screen implements ReloadableScreen { private static final Identifier MENU_LIST_BACKGROUND = Identifier.withDefaultNamespace("textures/gui/menu_list_background.png"); private static final Identifier INWORLD_MENU_LIST_BACKGROUND = Identifier.withDefaultNamespace("textures/gui/inworld_menu_list_background.png"); - private final Minecraft client = Minecraft.getInstance(); private final ScreenshotTexture texture; private final Screen parent; @@ -67,7 +66,7 @@ public void onClose() { if (shouldRecreateParent) reloadable.recreateList(); } - this.client.setScreen(this.parent); + this.minecraft.gui.setScreen(this.parent); } @Override diff --git a/src/client/java/dev/spiritstudios/snapper/gui/toast/SnapperToast.java b/src/client/java/dev/spiritstudios/snapper/gui/toast/SnapperToast.java index d1c4200..cdc42d0 100644 --- a/src/client/java/dev/spiritstudios/snapper/gui/toast/SnapperToast.java +++ b/src/client/java/dev/spiritstudios/snapper/gui/toast/SnapperToast.java @@ -42,7 +42,7 @@ public SnapperToast(Type type, Component title, Component description) { } public static void push(Type type, Component title, Component description) { - Minecraft.getInstance().getToastManager().addToast( + Minecraft.getInstance().gui.toastManager().addToast( new SnapperToast( type, title, diff --git a/src/client/java/dev/spiritstudios/snapper/gui/widget/FolderSelectWidget.java b/src/client/java/dev/spiritstudios/snapper/gui/widget/FolderSelectWidget.java index 14e6136..47d5c12 100644 --- a/src/client/java/dev/spiritstudios/snapper/gui/widget/FolderSelectWidget.java +++ b/src/client/java/dev/spiritstudios/snapper/gui/widget/FolderSelectWidget.java @@ -76,7 +76,7 @@ public FolderSelectWidget(int x, int y, int width, int height, PathFunctions pat Component.translatable("config.snapper.customScreenshotFolder.select"), button -> { ExternalDialogOverlay overlay = new ExternalDialogOverlay(); - client.setOverlay(overlay); + client.gui.setOverlay(overlay); DirectoryConfigUtil.openFolderSelect( Component.translatable("prompt.snapper.folder_select") diff --git a/src/client/java/dev/spiritstudios/snapper/gui/widget/ScreenshotGridWidget.java b/src/client/java/dev/spiritstudios/snapper/gui/widget/ScreenshotGridWidget.java index 2932458..57f8233 100644 --- a/src/client/java/dev/spiritstudios/snapper/gui/widget/ScreenshotGridWidget.java +++ b/src/client/java/dev/spiritstudios/snapper/gui/widget/ScreenshotGridWidget.java @@ -30,8 +30,9 @@ public ScreenshotGridWidget( } private int getColumnCount() { - if (minecraft.screen != null) { - int width = minecraft.screen.width; + Screen screen = minecraft.gui.screen(); + if (screen != null) { + int width = screen.width; if (width < 480) { return 2; @@ -163,7 +164,7 @@ public void extractContent(GuiGraphicsExtractor graphics, int mouseX, int mouseY ); } - if (minecraft.options.touchscreen().get() || (isHovering && mouseX < getX() + getWidth()) || safeIsSelected(this)) { + if ((isHovering && mouseX < getX() + getWidth()) || safeIsSelected(this)) { graphics.blit( RenderPipelines.GUI_TEXTURED, GRID_SELECTION_BACKGROUND_TEXTURE, diff --git a/src/client/java/dev/spiritstudios/snapper/gui/widget/ScreenshotListWidget.java b/src/client/java/dev/spiritstudios/snapper/gui/widget/ScreenshotListWidget.java index cfb9cf3..dc56b60 100644 --- a/src/client/java/dev/spiritstudios/snapper/gui/widget/ScreenshotListWidget.java +++ b/src/client/java/dev/spiritstudios/snapper/gui/widget/ScreenshotListWidget.java @@ -88,7 +88,7 @@ public void extractContent(GuiGraphicsExtractor graphics, int mouseX, int mouseY ); } - if (minecraft.options.touchscreen().get() || isHovering) { + if (isHovering) { graphics.fill(getContentX(), getContentY(), getContentX() + 32, getContentY() + 32, 0xA0909090); graphics.blitSprite( RenderPipelines.GUI_TEXTURED, diff --git a/src/client/java/dev/spiritstudios/snapper/gui/widget/ScreenshotsWidget.java b/src/client/java/dev/spiritstudios/snapper/gui/widget/ScreenshotsWidget.java index a26ff68..ddc3326 100644 --- a/src/client/java/dev/spiritstudios/snapper/gui/widget/ScreenshotsWidget.java +++ b/src/client/java/dev/spiritstudios/snapper/gui/widget/ScreenshotsWidget.java @@ -166,10 +166,10 @@ public void close() { public static class LoadingEntry extends Entry implements AutoCloseable { private static final Component LOADING_LIST_TEXT = Component.translatable("text.snapper.loading"); - private final Minecraft client; + private final Minecraft minecraft; public LoadingEntry(Minecraft client) { - this.client = client; + this.minecraft = client; } @Override @@ -179,12 +179,13 @@ public LoadingEntry(Minecraft client) { @Override public void extractContent(GuiGraphicsExtractor context, int mouseX, int mouseY, boolean isHovering, float partialTick) { - if (this.client.screen == null) throw new IllegalStateException(); + Screen screen = this.minecraft.gui.screen(); + if (screen == null) throw new IllegalStateException(); context.text( - this.client.font, + this.minecraft.font, LOADING_LIST_TEXT, - (this.client.screen.width - this.client.font.width(LOADING_LIST_TEXT)) / 2, + (screen.width - this.minecraft.font.width(LOADING_LIST_TEXT)) / 2, getY() + (getHeight() - 9) / 2, CommonColors.WHITE, false @@ -193,9 +194,9 @@ public void extractContent(GuiGraphicsExtractor context, int mouseX, int mouseY, String loadString = LoadingDotsText.get(Util.getMillis()); context.text( - this.client.font, + this.minecraft.font, loadString, - (this.client.screen.width - this.client.font.width(loadString)) / 2, + (screen.width - this.minecraft.font.width(loadString)) / 2, getY() + (getHeight() - 9) / 2 + 9, CommonColors.GRAY, false @@ -219,12 +220,13 @@ public EmptyEntry(Minecraft minecraft) { @Override public void extractContent(GuiGraphicsExtractor context, int mouseX, int mouseY, boolean isHovering, float partialTick) { - if (this.minecraft.screen == null) throw new IllegalStateException(); + Screen screen = this.minecraft.gui.screen(); + if (screen == null) throw new IllegalStateException(); context.text( this.minecraft.font, EMPTY_LIST_TEXT, - (this.minecraft.screen.width - this.minecraft.font.width(EMPTY_LIST_TEXT)) / 2, + (screen.width - this.minecraft.font.width(EMPTY_LIST_TEXT)) / 2, getY() + getHeight() / 2, CommonColors.WHITE, false @@ -233,7 +235,7 @@ public void extractContent(GuiGraphicsExtractor context, int mouseX, int mouseY, context.text( this.minecraft.font, EMPTY_CUSTOM_LIST_TEXT, - (this.minecraft.screen.width - this.minecraft.font.width(EMPTY_CUSTOM_LIST_TEXT)) / 2, + (screen.width - this.minecraft.font.width(EMPTY_CUSTOM_LIST_TEXT)) / 2, getY() + getHeight() / 2 + 10, CommonColors.WHITE, false @@ -301,7 +303,7 @@ public void setFocused(boolean focused) { public boolean click() { playButtonClickSound(minecraft.getSoundManager()); - minecraft.setScreen(new ScreenshotViewerScreen(texture, parent, null)); + minecraft.gui.setScreen(new ScreenshotViewerScreen(texture, parent, null)); return true; } } diff --git a/src/client/java/dev/spiritstudios/snapper/mixin/GuiRendererMixin.java b/src/client/java/dev/spiritstudios/snapper/mixin/GuiRendererMixin.java index 7771261..a3cb749 100644 --- a/src/client/java/dev/spiritstudios/snapper/mixin/GuiRendererMixin.java +++ b/src/client/java/dev/spiritstudios/snapper/mixin/GuiRendererMixin.java @@ -1,6 +1,5 @@ package dev.spiritstudios.snapper.mixin; -import com.mojang.blaze3d.buffers.GpuBufferSlice; import dev.spiritstudios.snapper.Snapper; import dev.spiritstudios.snapper.gui.screen.PanoramaViewerScreen; import net.minecraft.client.gui.render.GuiRenderer; @@ -24,8 +23,8 @@ public class GuiRendererMixin { @Final private CubeMap cubeMap; - @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/profiling/ProfilerFiller;push(Ljava/lang/String;)V", ordinal = 0)) - private void renderSnapperPanorama(GpuBufferSlice fogBuffer, CallbackInfo ci) { + @Inject(method = "render", at = @At("HEAD")) + private void renderSnapperPanorama(CallbackInfo ci) { PanoramaRenderState pano = renderState.getData(PanoramaViewerScreen.SNAPPER_PANORAMA); if (pano != null) { diff --git a/src/client/java/dev/spiritstudios/snapper/mixin/InGameHudMixin.java b/src/client/java/dev/spiritstudios/snapper/mixin/HudMixin.java similarity index 64% rename from src/client/java/dev/spiritstudios/snapper/mixin/InGameHudMixin.java rename to src/client/java/dev/spiritstudios/snapper/mixin/HudMixin.java index 21e0984..a801cd7 100644 --- a/src/client/java/dev/spiritstudios/snapper/mixin/InGameHudMixin.java +++ b/src/client/java/dev/spiritstudios/snapper/mixin/HudMixin.java @@ -5,25 +5,26 @@ import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import dev.spiritstudios.snapper.gui.screen.PanoramaViewerScreen; import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.Hud; import net.minecraft.client.gui.screens.LevelLoadingScreen; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; -@Mixin(Gui.class) -public class InGameHudMixin { +@Mixin(Hud.class) +public class HudMixin { @Shadow @Final private Minecraft minecraft; @Definition(id = "LevelLoadingScreen", type = LevelLoadingScreen.class) - @Definition(id = "minecraft", field = "Lnet/minecraft/client/gui/Gui;minecraft:Lnet/minecraft/client/Minecraft;") - @Definition(id = "screen", field = "Lnet/minecraft/client/Minecraft;screen:Lnet/minecraft/client/gui/screens/Screen;") - @Expression("(this.minecraft.screen instanceof LevelLoadingScreen)") + @Definition(id = "minecraft", field = "Lnet/minecraft/client/gui/Hud;minecraft:Lnet/minecraft/client/Minecraft;") + @Definition(id = "gui", field = "Lnet/minecraft/client/Minecraft;gui:Lnet/minecraft/client/gui/Gui;") + @Definition(id = "screen", method = "Lnet/minecraft/client/gui/Gui;screen()Lnet/minecraft/client/gui/screens/Screen;") + @Expression("this.minecraft.gui.screen() instanceof LevelLoadingScreen") @ModifyExpressionValue(method = "extractRenderState", at = @At(value = "MIXINEXTRAS:EXPRESSION")) private boolean cancelRenderingHudInPanoramaScreen(boolean original) { - return original || minecraft.screen instanceof PanoramaViewerScreen; + return original || this.minecraft.gui.screen() instanceof PanoramaViewerScreen; } } diff --git a/src/client/java/dev/spiritstudios/snapper/mixin/KeyboardHandlerMixin.java b/src/client/java/dev/spiritstudios/snapper/mixin/KeyboardHandlerMixin.java deleted file mode 100644 index fe35fbd..0000000 --- a/src/client/java/dev/spiritstudios/snapper/mixin/KeyboardHandlerMixin.java +++ /dev/null @@ -1,49 +0,0 @@ -package dev.spiritstudios.snapper.mixin; - -import com.llamalad7.mixinextras.injector.wrapoperation.Operation; -import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; -import com.mojang.blaze3d.pipeline.RenderTarget; -import dev.spiritstudios.snapper.SnapperConfig; -import dev.spiritstudios.snapper.SnapperKeyMappings; -import dev.spiritstudios.snapper.gui.toast.SnapperToast; -import net.minecraft.client.KeyboardHandler; -import net.minecraft.client.Minecraft; -import net.minecraft.network.chat.Component; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; - -import java.io.File; -import java.util.function.Consumer; - -@Mixin(KeyboardHandler.class) -public abstract class KeyboardHandlerMixin { - @Shadow - @Final - private Minecraft minecraft; - - @WrapOperation(method = "keyPress", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Screenshot;grab(Ljava/io/File;Lcom/mojang/blaze3d/pipeline/RenderTarget;Ljava/util/function/Consumer;)V")) - private void showDebugChat(File workDir, RenderTarget target, Consumer callback, Operation original) { - original.call( - workDir, - target, - (Consumer) message -> { - // Execute on the render thread. - Minecraft.getInstance().execute(() -> { - // Lovely tree of decisions to decide what instructions make sense. <3 Lynn - String inGameDeterminedDescription = minecraft.screen == null ? "toast.snapper.screenshot.created.description" - : "toast.snapper.screenshot.created.description_in_menu"; - String copyDeterminedDescription = SnapperConfig.HOLDER.get().copyTakenScreenshot() ? - "toast.snapper.screenshot.created.description_copy" : inGameDeterminedDescription; - - SnapperToast.push( - SnapperToast.Type.SCREENSHOT, - Component.translatable("toast.snapper.screenshot.created"), - Component.translatable(copyDeterminedDescription, message, SnapperKeyMappings.RECENT_SCREENSHOT_KEY.getTranslatedKeyMessage()) - ); - }); - } - ); - } -} diff --git a/src/client/java/dev/spiritstudios/snapper/mixin/MinecraftMixin.java b/src/client/java/dev/spiritstudios/snapper/mixin/MinecraftMixin.java index f43aad3..050f15c 100644 --- a/src/client/java/dev/spiritstudios/snapper/mixin/MinecraftMixin.java +++ b/src/client/java/dev/spiritstudios/snapper/mixin/MinecraftMixin.java @@ -70,7 +70,7 @@ private void captureSetYaw(LocalPlayer player, float value, Operation op, ) private void applyThirdPersonCameraRotation(LocalPlayer player, float value, Operation op, @Share("yaw") LocalFloatRef yaw) { if (!this.options.getCameraType().isFirstPerson()) - ((CameraAccessor) this.gameRenderer.getMainCamera()).invokeSetRotation(yaw.get(), value); + ((CameraAccessor) this.gameRenderer.mainCamera()).invokeSetRotation(yaw.get(), value); else op.call(player, value); } diff --git a/src/client/java/dev/spiritstudios/snapper/mixin/PauseScreenMixin.java b/src/client/java/dev/spiritstudios/snapper/mixin/PauseScreenMixin.java index 0bbdf5c..1e6fc92 100644 --- a/src/client/java/dev/spiritstudios/snapper/mixin/PauseScreenMixin.java +++ b/src/client/java/dev/spiritstudios/snapper/mixin/PauseScreenMixin.java @@ -1,16 +1,17 @@ package dev.spiritstudios.snapper.mixin; +import com.llamalad7.mixinextras.expression.Definition; +import com.llamalad7.mixinextras.expression.Expression; +import com.llamalad7.mixinextras.sugar.Local; import dev.spiritstudios.snapper.Snapper; import dev.spiritstudios.snapper.SnapperConfig; import dev.spiritstudios.snapper.gui.screen.ScreenshotListScreen; -import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.SpriteIconButton; +import net.minecraft.client.gui.layouts.LinearLayout; import net.minecraft.client.gui.screens.PauseScreen; import net.minecraft.client.gui.screens.Screen; import net.minecraft.network.chat.Component; -import net.minecraft.resources.Identifier; 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; @@ -21,22 +22,19 @@ protected PauseScreenMixin(Component title) { super(title); } - @Unique - private static final Identifier SNAPPER_BUTTON_ICON = Snapper.id("screenshots/screenshot"); - + @Definition(id = "iconButtonRow", local = @Local(type = LinearLayout.class, name = "iconButtonRow")) + @Definition(id = "addChild", method = "Lnet/minecraft/client/gui/layouts/LinearLayout;addChild(Lnet/minecraft/client/gui/layouts/LayoutElement;)Lnet/minecraft/client/gui/layouts/LayoutElement;") + @Definition(id = "playerReportingButton", local = @Local(type = SpriteIconButton.class, name = "playerReportingButton")) + @Expression("iconButtonRow.addChild(playerReportingButton)") @Inject( - method = "init", - at = @At("TAIL") + method = "createPauseMenu", + at = @At(value = "MIXINEXTRAS:EXPRESSION", shift = At.Shift.AFTER) ) - protected void initWidgets(CallbackInfo ci) { + protected void addSnapperButton(CallbackInfo ci, @Local(name = "iconButtonRow") LinearLayout iconButtonRow) { if (SnapperConfig.HOLDER.get().snapperButton().showInGameMenu()) { - this.addRenderableWidget( - SpriteIconButton.builder( - Component.translatable("button.snapper.screenshots"), - _ -> Minecraft.getInstance().setScreen(new ScreenshotListScreen(new PauseScreen(true))), - true - ).width(20).sprite(SNAPPER_BUTTON_ICON, 15, 15).build() - ).setPosition(this.width / 2 - 130, height / 4 + 32); + iconButtonRow.addChild(Snapper.createSnapperButton(20, _ -> { + this.minecraft.gui.setScreen(new ScreenshotListScreen(this)); + })); } } } diff --git a/src/client/java/dev/spiritstudios/snapper/mixin/ScreenshotMixin.java b/src/client/java/dev/spiritstudios/snapper/mixin/ScreenshotMixin.java index 93a702a..640f1e6 100644 --- a/src/client/java/dev/spiritstudios/snapper/mixin/ScreenshotMixin.java +++ b/src/client/java/dev/spiritstudios/snapper/mixin/ScreenshotMixin.java @@ -2,10 +2,15 @@ import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.llamalad7.mixinextras.sugar.Local; import com.mojang.blaze3d.pipeline.RenderTarget; import com.mojang.blaze3d.platform.NativeImage; import dev.spiritstudios.snapper.SnapperConfig; +import dev.spiritstudios.snapper.SnapperKeyMappings; +import dev.spiritstudios.snapper.gui.toast.SnapperToast; import dev.spiritstudios.snapper.util.PlatformHelper; +import net.minecraft.client.Minecraft; import net.minecraft.client.Screenshot; import net.minecraft.network.chat.Component; import org.spongepowered.asm.mixin.Mixin; @@ -27,7 +32,7 @@ public abstract class ScreenshotMixin { */ @SuppressWarnings("ResultOfMethodCallIgnored") @Inject( - method = "lambda$grab$1", + method = "lambda$grab$3", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/platform/NativeImage;writeToFile(Ljava/io/File;)V") ) private static void lookBeforeYouLeap(NativeImage image, File file, Consumer callback, CallbackInfo ci) throws IOException { @@ -36,7 +41,7 @@ private static void lookBeforeYouLeap(NativeImage image, File file, Consumer callback, CallbackInfo ci) { @@ -49,8 +54,8 @@ private static void saveWrittenFileToClipboard(NativeImage image, File file, Con * @author WorldWidePixel * @reason Okay, I know this is weird but it's so we can use our own wrapper text for the push. */ - @ModifyArg(method = "lambda$grab$1", - at = @At(value = "INVOKE", target = "Lnet/minecraft/network/chat/Component;translatable(Ljava/lang/String;[Ljava/lang/Object;)Lnet/minecraft/network/chat/MutableComponent;", ordinal = 0)) + @ModifyArg(method = "lambda$grab$3", + at = @At(value = "INVOKE", target = "Lnet/minecraft/network/chat/Component;translatable(Ljava/lang/String;[Ljava/lang/Object;)Lnet/minecraft/network/chat/MutableComponent;", ordinal = 0)) private static String changeSuccessTranslation(String existing) { return "toast.snapper.screenshot.created.success"; } @@ -67,4 +72,34 @@ private static void getConfiguredGameDirectory(File workDir, String forceName, R callback ); } + + @WrapOperation(method = "grab(Lnet/minecraft/client/Minecraft;Z)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Screenshot;grab(Ljava/io/File;Lcom/mojang/blaze3d/pipeline/RenderTarget;Ljava/util/function/Consumer;)V")) + private static void showDebugChat( + File workDir, + RenderTarget target, + Consumer callback, + Operation original, + @Local(argsOnly = true, name = "minecraft") Minecraft minecraft + ) { + original.call( + workDir, + target, + (Consumer) message -> { + // Execute on the render thread. + Minecraft.getInstance().execute(() -> { + // Lovely tree of decisions to decide what instructions make sense. <3 Lynn + String inGameDeterminedDescription = minecraft.gui.screen() == null ? "toast.snapper.screenshot.created.description" + : "toast.snapper.screenshot.created.description_in_menu"; + String copyDeterminedDescription = SnapperConfig.HOLDER.get().copyTakenScreenshot() ? + "toast.snapper.screenshot.created.description_copy" : inGameDeterminedDescription; + + SnapperToast.push( + SnapperToast.Type.SCREENSHOT, + Component.translatable("toast.snapper.screenshot.created"), + Component.translatable(copyDeterminedDescription, message, SnapperKeyMappings.RECENT_SCREENSHOT_KEY.getTranslatedKeyMessage()) + ); + }); + } + ); + } } diff --git a/src/client/java/dev/spiritstudios/snapper/mixin/TitleScreenMixin.java b/src/client/java/dev/spiritstudios/snapper/mixin/TitleScreenMixin.java index 835e08e..ae40d49 100644 --- a/src/client/java/dev/spiritstudios/snapper/mixin/TitleScreenMixin.java +++ b/src/client/java/dev/spiritstudios/snapper/mixin/TitleScreenMixin.java @@ -1,48 +1,70 @@ package dev.spiritstudios.snapper.mixin; +import com.llamalad7.mixinextras.expression.Definition; +import com.llamalad7.mixinextras.expression.Expression; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.llamalad7.mixinextras.sugar.Local; +import com.llamalad7.mixinextras.sugar.ref.LocalIntRef; import dev.spiritstudios.snapper.Snapper; import dev.spiritstudios.snapper.SnapperConfig; import dev.spiritstudios.snapper.gui.screen.ScreenshotListScreen; +import net.minecraft.client.gui.components.CommonButtons; import net.minecraft.client.gui.components.SpriteIconButton; import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.TitleScreen; +import net.minecraft.client.gui.screens.options.AccessibilityOptionsScreen; import net.minecraft.network.chat.Component; import net.minecraft.resources.Identifier; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; 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 java.util.Objects; - @Mixin(TitleScreen.class) public abstract class TitleScreenMixin extends Screen { - @Unique - private static final Identifier SNAPPER_BUTTON_ICON = Snapper.id("screenshots/screenshot"); + @Shadow + protected abstract int getHorizontalPosition(int currentButton, int numberOfButtons, int buttonWidth); protected TitleScreenMixin(Component title) { super(title); } - @Inject( - method = "init", - at = @At("HEAD") - ) - protected void init(CallbackInfo ci) { + @Definition(id = "numberOfButtons", local = @Local(type = int.class, name = "numberOfButtons")) + @Expression("numberOfButtons = ?") + @Inject(method = "init", at = @At(value = "MIXINEXTRAS:EXPRESSION", shift = At.Shift.AFTER)) + private void increaseNumberOfButtons(CallbackInfo ci, @Local(name = "numberOfButtons") LocalIntRef numberOfButtons) { if (SnapperConfig.HOLDER.get().snapperButton().showOnTitleScreen()) { - Objects.requireNonNull(minecraft); - - int y = this.height / 4 + 48; - int spacingY = 24; - - this.addRenderableWidget( - SpriteIconButton.builder( - Component.translatable("button.snapper.screenshots"), - _ -> this.minecraft.setScreen(new ScreenshotListScreen((TitleScreen) ((Object) this))), - true - ).width(20).sprite(SNAPPER_BUTTON_ICON, 15, 15).build() - ).setPosition(this.width / 2 - 124, y + spacingY); + numberOfButtons.set(numberOfButtons.get() + 1); + } + } + + @WrapOperation(method = "init", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/TitleScreen;getHorizontalPosition(III)I")) + private int unInlineNumberOfButtons(TitleScreen instance, int currentButton, int ignored, int buttonWidth, Operation original, @Local(name = "numberOfButtons") int numberOfButtons) { + return original.call(instance, currentButton, numberOfButtons, buttonWidth); + } + + @Definition(id = "accessibility", local = @Local(type = SpriteIconButton.class, name = "accessibility")) + @Definition(id = "setPosition", method = "Lnet/minecraft/client/gui/components/SpriteIconButton;setPosition(II)V") + @Expression("accessibility.setPosition(?, ?)") + @Inject(method = "init", at = @At(value = "MIXINEXTRAS:EXPRESSION", shift = At.Shift.AFTER)) + private void addButton( + CallbackInfo ci, + @Local(name = "currentButton") LocalIntRef currentButton, + @Local(name = "numberOfButtons") int numberOfButtons, + @Local(name = "topPos") int topPos + ) { + if (SnapperConfig.HOLDER.get().snapperButton().showOnTitleScreen()) { + SpriteIconButton snapperButton = this.addRenderableWidget(Snapper.createSnapperButton(20, _ -> { + this.minecraft.gui.setScreen(new ScreenshotListScreen(this)); + })); + + var buttonIndex = currentButton.get() + 1; + currentButton.set(buttonIndex); + + snapperButton.setPosition(this.getHorizontalPosition(buttonIndex, numberOfButtons, 20), topPos); } } } diff --git a/src/client/java/dev/spiritstudios/snapper/util/ScreenshotActions.java b/src/client/java/dev/spiritstudios/snapper/util/ScreenshotActions.java index fa49e7a..54cf5fc 100644 --- a/src/client/java/dev/spiritstudios/snapper/util/ScreenshotActions.java +++ b/src/client/java/dev/spiritstudios/snapper/util/ScreenshotActions.java @@ -21,12 +21,12 @@ public class ScreenshotActions { public static void deleteScreenshot(Path path, Screen screen) { if (!Files.exists(path)) return; - Minecraft client = Minecraft.getInstance(); - client.setScreen( + Minecraft minecraft = Minecraft.getInstance(); + minecraft.gui.setScreen( new ConfirmScreen( confirmed -> { if (confirmed) { - client.setScreen(new ProgressScreen(true)); + minecraft.gui.setScreen(new ProgressScreen(true)); try { Files.deleteIfExists(path); } catch (IOException e) { @@ -38,7 +38,7 @@ public static void deleteScreenshot(Path path, Screen screen) { } } - client.setScreen(screen); + minecraft.gui.setScreen(screen); }, Component.translatable("text.snapper.delete_question"), Component.translatable("text.snapper.delete_warning", path.getFileName()), diff --git a/src/client/java/dev/spiritstudios/snapper/util/uploading/ScreenshotUploading.java b/src/client/java/dev/spiritstudios/snapper/util/uploading/ScreenshotUploading.java index 5592825..5e6c192 100644 --- a/src/client/java/dev/spiritstudios/snapper/util/uploading/ScreenshotUploading.java +++ b/src/client/java/dev/spiritstudios/snapper/util/uploading/ScreenshotUploading.java @@ -31,10 +31,10 @@ public static CompletableFuture upload(Path image) { } if (SnapperConfig.HOLDER.get().axolotlClient().termsStatus() == AxolotlClientApi.TermsAcceptance.UNSET) { - Minecraft client = Minecraft.getInstance(); + Minecraft minecraft = Minecraft.getInstance(); CompletableFuture success = new CompletableFuture<>(); - client.setScreen(new PrivacyNoticeScreen(client.screen, v -> { + minecraft.gui.setScreen(new PrivacyNoticeScreen(minecraft.gui.screen(), v -> { if (v) upload(image).thenAccept(success::complete); })); diff --git a/src/client/resources/assets/snapper/lang/en_us.json b/src/client/resources/assets/snapper/lang/en_us.json index bca78da..d8a0f4d 100644 --- a/src/client/resources/assets/snapper/lang/en_us.json +++ b/src/client/resources/assets/snapper/lang/en_us.json @@ -81,6 +81,8 @@ "toast.snapper.upload.axolotlclient.api_disabled": "You didn't accept AxolotlClient's terms, therefore image uploading isn't available.", "toast.snapper.upload.offline": "You are currently offline.", "toast.snapper.upload.failure.generic": "More information may be found in the log file.", + "toast.snapper.config.failure.title": "Failed to save configuration file.", + "toast.snapper.config.failure.description": "More information may be found in the log file.", "prompt.snapper.folder_select": "Select a custom screenshot folder for Snapper.", "overlay.snapper.external_dialog.folder": "Folder select dialog opened. Exit by clicking \"Cancel\" in the selector.", "snapper.privacy_notice.description": "Image uploading in Snapper is powered by AxolotlClient. Therefore, this feature is subject to AxolotlClient's terms which you will have to accept in order to upload images. This decision can be updated or changed at any time.", diff --git a/src/client/resources/snapper.mixins.json b/src/client/resources/snapper.mixins.json index 0539220..6099a38 100644 --- a/src/client/resources/snapper.mixins.json +++ b/src/client/resources/snapper.mixins.json @@ -3,8 +3,7 @@ "package": "dev.spiritstudios.snapper.mixin", "compatibilityLevel": "JAVA_25", "client": [ - "InGameHudMixin", - "KeyboardHandlerMixin", + "HudMixin", "MinecraftMixin", "PauseScreenMixin", "ScreenshotMixin", diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 1b78c46..8a19a8d 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -39,7 +39,7 @@ ], "depends": { "fabricloader": ">=${loader_version}", - "minecraft": "~26.1.2", + "minecraft": "~26.2", "fabric-api": "*", "java": ">=25" },