From 6adf94cda227ddeaf7728ff83b5d61ea36afdb86 Mon Sep 17 00:00:00 2001 From: gniftygnome Date: Mon, 26 Feb 2024 10:53:41 -0800 Subject: [PATCH] Rewrite Vistas pano capture to use vanilla pano capture and revert ill-advised change to main-menu detection. - Fix accidentally overriding in-game music on dedicated servers - Using vanilla (simpler) panoramic screenshot capture --- .../vistas/mixin/GameRendererMixin.java | 168 ------------------ .../vistas/mixin/MinecraftClientMixin.java | 10 +- .../vistas/mixin/ScreenshotRecorderMixin.java | 25 +++ .../vistas/resource/PanoramicScreenshots.java | 71 ++------ src/main/resources/vistas.mixins.json | 2 +- 5 files changed, 47 insertions(+), 229 deletions(-) delete mode 100644 src/main/java/com/terraformersmc/vistas/mixin/GameRendererMixin.java create mode 100644 src/main/java/com/terraformersmc/vistas/mixin/ScreenshotRecorderMixin.java diff --git a/src/main/java/com/terraformersmc/vistas/mixin/GameRendererMixin.java b/src/main/java/com/terraformersmc/vistas/mixin/GameRendererMixin.java deleted file mode 100644 index 477b1ea..0000000 --- a/src/main/java/com/terraformersmc/vistas/mixin/GameRendererMixin.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * This java file has been adapted from this file: https://github.com/liachmodded/runorama/blob/93316ed7df7140786092140b2d757af12a0ac039/src/main/java/com/github/liachmodded/runorama/mixin/GameRendererMixin.java - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ -package com.terraformersmc.vistas.mixin; - -import com.mojang.datafixers.util.Pair; -import com.terraformersmc.vistas.Vistas; -import com.terraformersmc.vistas.config.VistasConfig; -import com.terraformersmc.vistas.resource.PanoramicScreenshots; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gl.Framebuffer; -import net.minecraft.client.gl.SimpleFramebuffer; -import net.minecraft.client.render.GameRenderer; -import net.minecraft.client.texture.NativeImage; -import net.minecraft.client.util.ScreenshotRecorder; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.text.ClickEvent; -import net.minecraft.text.Text; -import net.minecraft.util.Formatting; -import net.minecraft.util.Util; -import net.minecraft.util.math.Direction; -import org.spongepowered.asm.mixin.Final; -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.At.Shift; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import java.io.File; -import java.nio.file.Path; -import java.util.Optional; - -// TODO: rewrite; i dont know what im doing! -@Mixin(GameRenderer.class) -public abstract class GameRendererMixin { - @Shadow - @Final - MinecraftClient client; - - @Shadow - private boolean renderingPanorama; - - @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/GameRenderer;renderWorld(FJLnet/minecraft/client/util/math/MatrixStack;)V", shift = Shift.BEFORE)) - public void vistas$render(float delta, long startTime, boolean tick, CallbackInfo ci) { - assert client.player != null; - if (PanoramicScreenshots.timeSinceLastKeyPress >= 0.0D) { - PanoramicScreenshots.timeSinceLastKeyPress -= delta; - } - if (PanoramicScreenshots.onShot != -1) { - PanoramicScreenshots.time += delta; - } - if (PanoramicScreenshots.time > 375.0D) { - if (PanoramicScreenshots.startingRotation.isPresent()) { - client.player.setPitch(PanoramicScreenshots.startingRotation.get().getFirst()); - client.player.setYaw(PanoramicScreenshots.startingRotation.get().getSecond()); - } - if (client.player != null) { - client.player.sendMessage(Text.translatable("vistas.panoramic_screenshot.broke"), false); - } - PanoramicScreenshots.onShot = -1; - PanoramicScreenshots.startingRotation = Optional.empty(); - PanoramicScreenshots.currentScreenshotPath = Optional.empty(); - PanoramicScreenshots.time = 0.0D; - PanoramicScreenshots.timeSinceLastKeyPress = 10.0D; - PanoramicScreenshots.needsScreenshot = false; - } - if (PanoramicScreenshots.needsScreenshot) { - Vistas.LOGGER.info("Taking screenshot"); - PanoramicScreenshots.needsScreenshot = false; - - Path root = PanoramicScreenshots.getPanoramicScreenshotFolder(); - File file = root.resolve("panorama_" + PanoramicScreenshots.onShot + ".png").toFile(); - if (PanoramicScreenshots.currentScreenshotPath.isEmpty()) { - PanoramicScreenshots.currentScreenshotPath = Optional.of(root); - } - File rootFile = root.toFile(); - if (!rootFile.exists()) { - //noinspection ResultOfMethodCallIgnored - rootFile.mkdirs(); - } - - if (PanoramicScreenshots.startingRotation.isEmpty()) { - PanoramicScreenshots.startingRotation = Optional.of(Pair.of(VistasConfig.getInstance().lockScreenshotPitch ? 0.0F : client.player.getPitch(), VistasConfig.getInstance().lockScreenshotYaw ? client.player.getHorizontalFacing() == Direction.NORTH ? 180 : client.player.getHorizontalFacing() == Direction.EAST ? -90 : client.player.getHorizontalFacing() == Direction.SOUTH ? 0 : 90 : client.player.getYaw())); - } - - // setup - boolean wasRenderingPanorama = renderingPanorama; - boolean culledBefore = client.chunkCullingEnabled; - client.chunkCullingEnabled = false; - renderingPanorama = true; - Framebuffer framebuffer = new SimpleFramebuffer(this.client.getWindow().getFramebufferWidth(), this.client.getWindow().getFramebufferHeight(), true, MinecraftClient.IS_SYSTEM_MAC); - client.worldRenderer.reloadTransparencyPostProcessor(); - this.setBlockOutlineEnabled(false); - this.setRenderHand(false); - - // take - client.player.setPitch(PanoramicScreenshots.startingRotation.get().getFirst()); - client.player.setYaw(PanoramicScreenshots.startingRotation.get().getSecond()); - framebuffer.beginWrite(true); - MatrixStack stack = new MatrixStack(); - stack.multiply(PanoramicScreenshots.ROTATIONS.get(PanoramicScreenshots.onShot)); - doRender(delta, startTime, stack); - takeScreenshot(root, PanoramicScreenshots.onShot, framebuffer); - - // restore - client.player.setPitch(PanoramicScreenshots.startingRotation.get().getFirst() + PanoramicScreenshots.PITCHES.get(PanoramicScreenshots.onShot)); - client.player.setYaw(PanoramicScreenshots.startingRotation.get().getSecond() + PanoramicScreenshots.YAWS.get(PanoramicScreenshots.onShot)); - renderingPanorama = wasRenderingPanorama; - client.chunkCullingEnabled = culledBefore; - this.setBlockOutlineEnabled(true); - this.setRenderHand(true); - client.worldRenderer.reloadTransparencyPostProcessor(); - framebuffer.delete(); - - if (client.player != null && VistasConfig.getInstance().screenshotIndividually) { - client.player.sendMessage(Text.translatable("vistas.panoramic_screenshot.taken", Text.literal(String.valueOf(PanoramicScreenshots.onShot)), Text.literal(file.getName()).formatted(Formatting.UNDERLINE).styled((style) -> style.withClickEvent(new ClickEvent(ClickEvent.Action.OPEN_FILE, file.getAbsolutePath())))), false); - } - - if (PanoramicScreenshots.onShot == 5) { - PanoramicScreenshots.onShot = -1; - client.player.setPitch(PanoramicScreenshots.startingRotation.get().getFirst()); - client.player.setYaw(PanoramicScreenshots.startingRotation.get().getSecond()); - PanoramicScreenshots.startingRotation = Optional.empty(); - PanoramicScreenshots.currentScreenshotPath = Optional.empty(); - PanoramicScreenshots.time = 0.0D; - PanoramicScreenshots.timeSinceLastKeyPress = 10.0D; - if (client.player != null) { - client.player.sendMessage(Text.translatable("vistas.panoramic_screenshot.saved", Text.literal(root.toAbsolutePath().toString()).styled(style -> style.withClickEvent(new ClickEvent(ClickEvent.Action.OPEN_FILE, root.toAbsolutePath().toString())).withUnderline(true))), false); - } - } else { - // push - client.player.setPitch(PanoramicScreenshots.startingRotation.get().getFirst() + PanoramicScreenshots.PITCHES.get(PanoramicScreenshots.onShot + 1)); - client.player.setYaw(PanoramicScreenshots.startingRotation.get().getSecond() + PanoramicScreenshots.YAWS.get(PanoramicScreenshots.onShot + 1)); - if (!VistasConfig.getInstance().screenshotIndividually) { - PanoramicScreenshots.needsScreenshot = true; - PanoramicScreenshots.onShot++; - vistas$render(delta, startTime, tick, ci); - } - } - } - } - - @Unique - private void doRender(float tickDelta, long startTime, MatrixStack matrixStack) { - this.renderWorld(tickDelta, Util.getMeasuringTimeNano() + startTime, matrixStack); - } - - @Unique - private void takeScreenshot(Path folder, int id, Framebuffer buffer) { - NativeImage shot = ScreenshotRecorder.takeScreenshot(buffer); - PanoramicScreenshots.saveScreenshot(shot, folder, id); - } - - @Shadow - public abstract void renderWorld(float delta, long startTime, MatrixStack matrices); - - @Shadow - public abstract void setBlockOutlineEnabled(boolean blockOutlineEnabled); - - @Shadow - public abstract void setRenderHand(boolean renderHand); -} diff --git a/src/main/java/com/terraformersmc/vistas/mixin/MinecraftClientMixin.java b/src/main/java/com/terraformersmc/vistas/mixin/MinecraftClientMixin.java index bbc80f3..bef8bf4 100644 --- a/src/main/java/com/terraformersmc/vistas/mixin/MinecraftClientMixin.java +++ b/src/main/java/com/terraformersmc/vistas/mixin/MinecraftClientMixin.java @@ -7,8 +7,8 @@ import net.fabricmc.api.Environment; import net.minecraft.client.MinecraftClient; import net.minecraft.client.RunArgs; +import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.resource.ReloadableResourceManagerImpl; -import net.minecraft.server.integrated.IntegratedServer; import net.minecraft.sound.MusicSound; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Final; @@ -23,7 +23,7 @@ @Environment(EnvType.CLIENT) @Mixin(MinecraftClient.class) -public abstract class MinecraftClientMixin implements MinecraftClientAccess { +public class MinecraftClientMixin implements MinecraftClientAccess { @Unique private PanoramaResourceReloader panoramaResourceReloader; @@ -32,8 +32,8 @@ public abstract class MinecraftClientMixin implements MinecraftClientAccess { private ReloadableResourceManagerImpl resourceManager; @Shadow - @Nullable - private IntegratedServer server; + @Nullable + public ClientPlayerEntity player; @Inject( method = "", @@ -51,7 +51,7 @@ public abstract class MinecraftClientMixin implements MinecraftClientAccess { @Inject(method = "getMusicType", at = @At("HEAD"), cancellable = true) private void vistas$getMusicType(CallbackInfoReturnable ci) { - if (this.server == null) { + if (this.player == null) { ci.setReturnValue(VistasTitle.CURRENT.getValue().getMusicSound()); } } diff --git a/src/main/java/com/terraformersmc/vistas/mixin/ScreenshotRecorderMixin.java b/src/main/java/com/terraformersmc/vistas/mixin/ScreenshotRecorderMixin.java new file mode 100644 index 0000000..9d4f9ee --- /dev/null +++ b/src/main/java/com/terraformersmc/vistas/mixin/ScreenshotRecorderMixin.java @@ -0,0 +1,25 @@ +package com.terraformersmc.vistas.mixin; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.terraformersmc.vistas.resource.PanoramicScreenshots; +import net.minecraft.client.util.ScreenshotRecorder; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +import java.io.File; + +@Mixin(ScreenshotRecorder.class) +public class ScreenshotRecorderMixin { + @WrapOperation(method = "saveScreenshotInner", + at = @At(value = "NEW", target = "java/io/File", ordinal = 0) + ) + @SuppressWarnings("unused") + private static File vistas$panoramaPathOverride(File path, String file, Operation original) { + if (path.toString().contains(PanoramicScreenshots.PANORAMAS_PATH)) { + return path; + } + + return original.call(path, file); + } +} diff --git a/src/main/java/com/terraformersmc/vistas/resource/PanoramicScreenshots.java b/src/main/java/com/terraformersmc/vistas/resource/PanoramicScreenshots.java index d983410..3c2c642 100644 --- a/src/main/java/com/terraformersmc/vistas/resource/PanoramicScreenshots.java +++ b/src/main/java/com/terraformersmc/vistas/resource/PanoramicScreenshots.java @@ -7,88 +7,49 @@ */ package com.terraformersmc.vistas.resource; -import com.google.common.collect.ImmutableList; -import com.mojang.datafixers.util.Pair; import com.terraformersmc.vistas.Vistas; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.client.option.KeyBinding; -import net.minecraft.client.texture.NativeImage; -import net.minecraft.util.Util; -import net.minecraft.util.math.RotationAxis; -import org.joml.Quaternionf; +import net.minecraft.text.Text; import java.io.File; -import java.io.IOException; import java.nio.file.Path; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; -import java.util.List; -import java.util.Optional; -//TODO: rewrite; i dont know what im doing! public class PanoramicScreenshots { private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss"); + public static final String PANORAMAS_PATH = "screenshots/panoramas"; - public static final List ROTATIONS = ImmutableList.of(RotationAxis.POSITIVE_Y.rotationDegrees(0), RotationAxis.POSITIVE_Y.rotationDegrees(90), RotationAxis.POSITIVE_Y.rotationDegrees(180), RotationAxis.POSITIVE_Y.rotationDegrees(270), RotationAxis.POSITIVE_X.rotationDegrees(-90), RotationAxis.POSITIVE_X.rotationDegrees(90)); - - public static final List PITCHES = ImmutableList.of(0.0F, 0.0F, 0.0F, 0.0F, 90.0F, -90.0F); - public static final List YAWS = ImmutableList.of(0.0F, 90.0F, 180.0F, -90.0F, 0.0F, 0.0F); - - public static double time = 0.0D; - public static double timeSinceLastKeyPress = -1.0D; - public static boolean needsScreenshot = false; - public static int onShot = -1; - - @SuppressWarnings("OptionalUsedAsFieldOrParameterType") - public static Optional> startingRotation = Optional.empty(); - @SuppressWarnings("OptionalUsedAsFieldOrParameterType") - public static Optional currentScreenshotPath = Optional.empty(); + public static int cooldown = 0; public static void registerKeyBinding() { KeyBinding screenshotKey = new KeyBinding("key.vistas.panoramic_screenshot", 'H', "key.categories.misc"); KeyBindingHelper.registerKeyBinding(screenshotKey); ClientTickEvents.START_CLIENT_TICK.register(client -> { - if (client.currentScreen == null && screenshotKey.isPressed() && timeSinceLastKeyPress <= 0.0D) { - needsScreenshot = true; - onShot++; - timeSinceLastKeyPress = 5.0D; + if (cooldown > 0) { + // 100 client tick cooldown between panoramas. + --cooldown; + return; } - }); - } + if (client.currentScreen == null && screenshotKey.isPressed()) { + cooldown = 100; + + // Capture the largest square view. + int size = Math.min(client.getWindow().getFramebufferWidth(), client.getWindow().getFramebufferHeight()); - public static void saveScreenshot(NativeImage screenshot, Path folder, int i) { - Util.getIoWorkerExecutor().execute(() -> { - try (screenshot) { - int width = screenshot.getWidth(); - int height = screenshot.getHeight(); - int x = 0; - int y = 0; - if (width > height) { - x = (width - height) / 2; - //noinspection SuspiciousNameCombination - width = height; - } else { - y = (height - width) / 2; - //noinspection SuspiciousNameCombination - height = width; - } - NativeImage saved = new NativeImage(width, height, false); - screenshot.resizeSubRectTo(x, y, width, height, saved); - saved.writeTo(folder.resolve("panorama_" + i + ".png")); - } catch (IOException exception) { - Vistas.LOGGER.warn("Couldn't save screenshot", exception); + Text result = client.takePanorama(getPanoramicScreenshotFolder().toFile(), size, size); + Vistas.LOGGER.info("Panorama capture with result: {}", result.getString()); + client.getMessageHandler().onGameMessage(result, false); } }); } public static Path getPanoramicScreenshotFolder() { - if (currentScreenshotPath.isPresent()) { - return currentScreenshotPath.get(); - } - File rootFile = FabricLoader.getInstance().getGameDir().resolve("screenshots/panoramas/").toFile(); + File rootFile = FabricLoader.getInstance().getGameDir().resolve(PANORAMAS_PATH).toFile(); if (!rootFile.exists()) { //noinspection ResultOfMethodCallIgnored rootFile.mkdirs(); diff --git a/src/main/resources/vistas.mixins.json b/src/main/resources/vistas.mixins.json index b579395..4bab596 100644 --- a/src/main/resources/vistas.mixins.json +++ b/src/main/resources/vistas.mixins.json @@ -4,9 +4,9 @@ "package": "com.terraformersmc.vistas.mixin", "compatibilityLevel": "JAVA_17", "client": [ - "GameRendererMixin", "LogoDrawerMixin", "MinecraftClientMixin", + "ScreenshotRecorderMixin", "SplashTextRendererMixin", "SplashTextResourceSupplierMixin", "TitleScreenMixin"