From 2b0f7a0c13b4d763f59c673510bdb4645d2ae78c Mon Sep 17 00:00:00 2001 From: Bixilon Date: Sun, 28 Feb 2021 14:58:35 +0100 Subject: [PATCH] rendering: screenshot saver, auto add missing hotkeys to config --- .../minosoft/config/StaticConfiguration.java | 2 +- .../game/controls/KeyBindingsGameConfig.kt | 83 ++++++++++--------- .../bixilon/minosoft/config/key/KeyBinding.kt | 4 +- .../minosoft/gui/rendering/RenderConstants.kt | 2 + .../minosoft/gui/rendering/RenderWindow.kt | 58 ++++++++----- .../gui/rendering/util/ScreenshotTaker.kt | 71 ++++++++++++++++ .../clientbound/play/PacketUpdateLight.kt | 3 - 7 files changed, 157 insertions(+), 66 deletions(-) create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/util/ScreenshotTaker.kt diff --git a/src/main/java/de/bixilon/minosoft/config/StaticConfiguration.java b/src/main/java/de/bixilon/minosoft/config/StaticConfiguration.java index 280ceecc3..9be6929e2 100644 --- a/src/main/java/de/bixilon/minosoft/config/StaticConfiguration.java +++ b/src/main/java/de/bixilon/minosoft/config/StaticConfiguration.java @@ -22,7 +22,7 @@ public class StaticConfiguration { public static final boolean DEBUG_MODE = true; // if true, additional checks will be made to validate data, ... Decreases performance public static final boolean BIOME_DEBUG_MODE = false; // colors all biomes according to the biome hashCode public static final boolean DEBUG_SLOW_LOADING = false; // if true, many Thread.sleep will be executed and the start will be delayed (by a lot) - public static final boolean SHOW_LOG_MESSAGES_IN_CHAT = false; // prints all console messages in the chat box + public static final boolean SHOW_LOG_MESSAGES_IN_CHAT = true; // prints all console messages in the chat box public static String CONFIG_FILENAME = "minosoft.json"; // Filename of minosoft's base configuration (located in AppData/Minosoft/config) public static boolean SKIP_MOJANG_AUTHENTICATION; // disables all connections to mojang public static boolean COLORED_LOG = true; // the log should be colored with ANSI (does not affect base components) diff --git a/src/main/java/de/bixilon/minosoft/config/config/game/controls/KeyBindingsGameConfig.kt b/src/main/java/de/bixilon/minosoft/config/config/game/controls/KeyBindingsGameConfig.kt index bf9a6215a..fca7ecc8d 100644 --- a/src/main/java/de/bixilon/minosoft/config/config/game/controls/KeyBindingsGameConfig.kt +++ b/src/main/java/de/bixilon/minosoft/config/config/game/controls/KeyBindingsGameConfig.kt @@ -13,28 +13,49 @@ package de.bixilon.minosoft.config.config.game.controls -import de.bixilon.minosoft.config.config.game.controls.KeyBindingsNames.DEBUG_CLEAR_CHUNK_CACHE -import de.bixilon.minosoft.config.config.game.controls.KeyBindingsNames.DEBUG_MOUSE_CATCH -import de.bixilon.minosoft.config.config.game.controls.KeyBindingsNames.DEBUG_POLYGEN -import de.bixilon.minosoft.config.config.game.controls.KeyBindingsNames.DEBUG_SCREEN -import de.bixilon.minosoft.config.config.game.controls.KeyBindingsNames.MOVE_BACKWARDS -import de.bixilon.minosoft.config.config.game.controls.KeyBindingsNames.MOVE_FLY_DOWN -import de.bixilon.minosoft.config.config.game.controls.KeyBindingsNames.MOVE_FLY_UP -import de.bixilon.minosoft.config.config.game.controls.KeyBindingsNames.MOVE_FORWARD -import de.bixilon.minosoft.config.config.game.controls.KeyBindingsNames.MOVE_LEFT -import de.bixilon.minosoft.config.config.game.controls.KeyBindingsNames.MOVE_RIGHT -import de.bixilon.minosoft.config.config.game.controls.KeyBindingsNames.MOVE_SPRINT -import de.bixilon.minosoft.config.config.game.controls.KeyBindingsNames.QUIT_RENDERING -import de.bixilon.minosoft.config.config.game.controls.KeyBindingsNames.WHEN_IN_GAME -import de.bixilon.minosoft.config.config.game.controls.KeyBindingsNames.WHEN_PLAYER_IS_FLYING -import de.bixilon.minosoft.config.config.game.controls.KeyBindingsNames.ZOOM +import de.bixilon.minosoft.config.config.game.controls.KeyBindingsNames.DEFAULT_KEY_BINDINGS import de.bixilon.minosoft.config.key.KeyAction import de.bixilon.minosoft.config.key.KeyBinding import de.bixilon.minosoft.config.key.KeyCodes import de.bixilon.minosoft.data.mappings.ResourceLocation data class KeyBindingsGameConfig( - val entries: MutableMap = mutableMapOf( + val entries: MutableMap = mutableMapOf(), +) { + init { + for ((resourceLocation, keyBinding) in DEFAULT_KEY_BINDINGS) { + if (!entries.containsKey(resourceLocation)) { + // add key binding + entries[resourceLocation] = KeyBinding(keyBinding) + } + } + } +} + +object KeyBindingsNames { + val MOVE_FORWARD = ResourceLocation("minosoft:move_forward") + val MOVE_BACKWARDS = ResourceLocation("minosoft:move_backwards") + val MOVE_LEFT = ResourceLocation("minosoft:move_left") + val MOVE_RIGHT = ResourceLocation("minosoft:move_right") + val MOVE_SPRINT = ResourceLocation("minosoft:move_sprint") + val MOVE_FLY_UP = ResourceLocation("minosoft:move_fly_up") + val MOVE_FLY_DOWN = ResourceLocation("minosoft:move_fly_down") + + val ZOOM = ResourceLocation("minosoft:zoom") + + val QUIT_RENDERING = ResourceLocation("minosoft:quit_rendering") + + val DEBUG_SCREEN = ResourceLocation("minosoft:debug_screen") + val DEBUG_CLEAR_CHUNK_CACHE = ResourceLocation("minosoft:debug_clear_chunk_cache") + val DEBUG_POLYGEN = ResourceLocation("minosoft:debug_polygen") + val DEBUG_MOUSE_CATCH = ResourceLocation("minosoft:debug_mouse_catch") + + val WHEN_IN_GAME = ResourceLocation("minosoft:in_game") + val WHEN_PLAYER_IS_FLYING = ResourceLocation("minosoft:is_flying") + + val TAKE_SCREENSHOT = ResourceLocation("minosoft:take_screenshot") + + val DEFAULT_KEY_BINDINGS: Map = mapOf( MOVE_FORWARD to KeyBinding( mutableMapOf( KeyAction.CHANGE to mutableSetOf(KeyCodes.KEY_W) @@ -116,27 +137,11 @@ data class KeyBindingsGameConfig( ), mutableSetOf(mutableSetOf(WHEN_IN_GAME)) ), - ), -) - -object KeyBindingsNames { - val MOVE_FORWARD = ResourceLocation("minosoft:move_forward") - val MOVE_BACKWARDS = ResourceLocation("minosoft:move_backwards") - val MOVE_LEFT = ResourceLocation("minosoft:move_left") - val MOVE_RIGHT = ResourceLocation("minosoft:move_right") - val MOVE_SPRINT = ResourceLocation("minosoft:move_sprint") - val MOVE_FLY_UP = ResourceLocation("minosoft:move_fly_up") - val MOVE_FLY_DOWN = ResourceLocation("minosoft:move_fly_down") - - val ZOOM = ResourceLocation("minosoft:zoom") - - val QUIT_RENDERING = ResourceLocation("minosoft:quit_rendering") - - val DEBUG_SCREEN = ResourceLocation("minosoft:debug_screen") - val DEBUG_CLEAR_CHUNK_CACHE = ResourceLocation("minosoft:debug_clear_chunk_cache") - val DEBUG_POLYGEN = ResourceLocation("minosoft:debug_polygen") - val DEBUG_MOUSE_CATCH = ResourceLocation("minosoft:debug_mouse_catch") - - val WHEN_IN_GAME = ResourceLocation("minosoft:in_game") - val WHEN_PLAYER_IS_FLYING = ResourceLocation("minosoft:is_flying") + TAKE_SCREENSHOT to KeyBinding( + mutableMapOf( + KeyAction.RELEASE to mutableSetOf(KeyCodes.KEY_F2) + ), + mutableSetOf() + ), + ) } diff --git a/src/main/java/de/bixilon/minosoft/config/key/KeyBinding.kt b/src/main/java/de/bixilon/minosoft/config/key/KeyBinding.kt index 7416466ea..0321c9d19 100644 --- a/src/main/java/de/bixilon/minosoft/config/key/KeyBinding.kt +++ b/src/main/java/de/bixilon/minosoft/config/key/KeyBinding.kt @@ -18,4 +18,6 @@ import de.bixilon.minosoft.data.mappings.ResourceLocation class KeyBinding( val action: MutableMap>, val `when`: MutableSet>, -) +) { + constructor(keyBinding: KeyBinding) : this(keyBinding.action.toMutableMap(), keyBinding.`when`.toMutableSet()) // ToDo: Deep copy +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/RenderConstants.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/RenderConstants.kt index dbc00a6f9..aca198442 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/RenderConstants.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/RenderConstants.kt @@ -28,4 +28,6 @@ object RenderConstants { val LILY_PAD_BLOCK_COLOR = RGBColor("#208030") const val COLORMAP_SIZE = 255 + + const val DEBUG_MESSAGES_PREFIX = "§f[§e§lDEBUG§f] §9" } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt index 063384dd9..57b02a719 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt @@ -24,6 +24,7 @@ import de.bixilon.minosoft.data.text.RGBColor import de.bixilon.minosoft.gui.rendering.chunk.WorldRenderer import de.bixilon.minosoft.gui.rendering.hud.HUDRenderer import de.bixilon.minosoft.gui.rendering.hud.elements.RenderStats +import de.bixilon.minosoft.gui.rendering.util.ScreenshotTaker import de.bixilon.minosoft.modding.event.EventInvokerCallback import de.bixilon.minosoft.modding.event.events.ConnectionStateChangeEvent import de.bixilon.minosoft.modding.event.events.PacketReceiveEvent @@ -40,7 +41,7 @@ import org.lwjgl.system.MemoryStack import org.lwjgl.system.MemoryUtil import java.util.concurrent.ConcurrentLinkedQueue -class RenderWindow(private val connection: Connection, val rendering: Rendering) { +class RenderWindow(val connection: Connection, val rendering: Rendering) { private val keyBindingCallbacks: MutableMap Unit)>>> = mutableMapOf() private val keysDown: MutableSet = mutableSetOf() private val keyBindingDown: MutableSet = mutableSetOf() @@ -59,6 +60,7 @@ class RenderWindow(private val connection: Connection, val rendering: Rendering) private var polygonEnabled = false private var mouseCatch = !StaticConfiguration.DEBUG_MODE + private val screenshotTaker = ScreenshotTaker(this) val tintColorCalculator = TintColorCalculator() // all renderers @@ -259,27 +261,8 @@ class RenderWindow(private val connection: Connection, val rendering: Rendering) } }) - registerKeyCallback(KeyBindingsNames.DEBUG_POLYGEN) { _: KeyCodes, _: KeyAction -> - polygonEnabled = !polygonEnabled - glPolygonMode(GL_FRONT_AND_BACK, if (polygonEnabled) { - GL_LINE - } else { - GL_FILL - }) - connection.sender.sendFakeChatMessage("§f[§e§lDEBUG§f] §9Toggled polygen mode!") - } - registerKeyCallback(KeyBindingsNames.DEBUG_MOUSE_CATCH) { _: KeyCodes, _: KeyAction -> - mouseCatch = !mouseCatch - if (mouseCatch) { - glfwSetInputMode(windowId, GLFW_CURSOR, GLFW_CURSOR_DISABLED) - } else { - glfwSetInputMode(windowId, GLFW_CURSOR, GLFW_CURSOR_NORMAL) - } - connection.sender.sendFakeChatMessage("§f[§e§lDEBUG§f] §9Toggled mouse catch!") - } - registerKeyCallback(KeyBindingsNames.QUIT_RENDERING) { _: KeyCodes, _: KeyAction -> - glfwSetWindowShouldClose(windowId, true) - } + + registerGlobalKeyCombinations() hudRenderer.screenChangeResizeCallback(screenWidth, screenHeight) @@ -296,6 +279,33 @@ class RenderWindow(private val connection: Connection, val rendering: Rendering) glfwShowWindow(windowId) } + private fun registerGlobalKeyCombinations() { + registerKeyCallback(KeyBindingsNames.DEBUG_POLYGEN) { _: KeyCodes, _: KeyAction -> + polygonEnabled = !polygonEnabled + glPolygonMode(GL_FRONT_AND_BACK, if (polygonEnabled) { + GL_LINE + } else { + GL_FILL + }) + sendDebugMessage("Toggled polygen mode!") + } + registerKeyCallback(KeyBindingsNames.DEBUG_MOUSE_CATCH) { _: KeyCodes, _: KeyAction -> + mouseCatch = !mouseCatch + if (mouseCatch) { + glfwSetInputMode(windowId, GLFW_CURSOR, GLFW_CURSOR_DISABLED) + } else { + glfwSetInputMode(windowId, GLFW_CURSOR, GLFW_CURSOR_NORMAL) + } + sendDebugMessage("Toggled mouse catch!") + } + registerKeyCallback(KeyBindingsNames.QUIT_RENDERING) { _: KeyCodes, _: KeyAction -> + glfwSetWindowShouldClose(windowId, true) + } + registerKeyCallback(KeyBindingsNames.TAKE_SCREENSHOT) { _: KeyCodes, _: KeyAction -> + screenshotTaker.takeScreenshot() + } + } + fun startRenderLoop() { while (!glfwWindowShouldClose(windowId)) { if (renderingStatus == RenderingStates.PAUSED) { @@ -382,4 +392,8 @@ class RenderWindow(private val connection: Connection, val rendering: Rendering) fun setSkyColor(color: RGBColor) { glClearColor(color.floatRed, color.floatGreen, color.floatBlue, 1.0f) } + + fun sendDebugMessage(message: String) { + connection.sender.sendFakeChatMessage(RenderConstants.DEBUG_MESSAGES_PREFIX + message) + } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/util/ScreenshotTaker.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/util/ScreenshotTaker.kt new file mode 100644 index 000000000..90a59a834 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/util/ScreenshotTaker.kt @@ -0,0 +1,71 @@ +/* + * Minosoft + * Copyright (C) 2021 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program.If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.util + +import de.bixilon.minosoft.config.StaticConfiguration +import de.bixilon.minosoft.gui.rendering.RenderWindow +import de.bixilon.minosoft.util.Util +import de.matthiasmann.twl.utils.PNGDecoder +import org.lwjgl.BufferUtils +import org.lwjgl.opengl.GL11.* +import java.awt.image.BufferedImage +import java.io.File +import java.nio.ByteBuffer +import java.text.SimpleDateFormat +import javax.imageio.ImageIO + + +class ScreenshotTaker( + private val renderWindow: RenderWindow, +) { + fun takeScreenshot() { + try { + val basePath = "${StaticConfiguration.HOME_DIRECTORY}/screenshots/${renderWindow.connection.address.hostname}/${DATE_FORMATTER.format(System.currentTimeMillis())}" + Util.createParentFolderIfNotExist(basePath) + var path = "$basePath.png" + var i = 1 + while (File(path).exists()) { + path = "${basePath}_${i++}.png" + } + + val width = renderWindow.screenWidth + val height = renderWindow.screenHeight + val buffer: ByteBuffer = BufferUtils.createByteBuffer(width * height * PNGDecoder.Format.RGBA.numComponents) + glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer) + + val bufferedImage = BufferedImage(width, height, BufferedImage.TYPE_INT_RGB) + + for (x in 0 until width) { + for (y in 0 until height) { + val index: Int = (x + width * y) * 4 + val red: Int = buffer[index].toInt() and 0xFF + val green: Int = buffer[index + 1].toInt() and 0xFF + val blue: Int = buffer[index + 2].toInt() and 0xFF + bufferedImage.setRGB(x, height - (y + 1), 0xFF shl 24 or (red shl 16) or (green shl 8) or blue) + } + } + + ImageIO.write(bufferedImage, "png", File(path)) + + renderWindow.sendDebugMessage("§aScreenshot saved to §f$path") + } catch (exception: Exception) { + exception.printStackTrace() + renderWindow.sendDebugMessage("§cFailed to make a screenshot!") + } + } + + companion object { + private val DATE_FORMATTER = SimpleDateFormat("yyyy-MM-dd_HH.mm.ss") + } +} diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketUpdateLight.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketUpdateLight.kt index 546317a4f..e819dc292 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketUpdateLight.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/play/PacketUpdateLight.kt @@ -28,9 +28,6 @@ class PacketUpdateLight : ClientboundPacket() { override fun read(buffer: InByteBuffer): Boolean { position = ChunkPosition(buffer.readVarInt(), buffer.readVarInt()) - if (position == ChunkPosition(-6, 20)) { - Log.debug("") - } if (buffer.versionId >= ProtocolVersions.V_1_16_PRE3) { val trustEdges = buffer.readBoolean() }