From 48665288028fabe33f105cebd598784845d9d02e Mon Sep 17 00:00:00 2001 From: Bixilon Date: Sat, 10 Apr 2021 18:30:23 +0200 Subject: [PATCH] rendering: wip: chat field --- .../game/controls/KeyBindingsGameConfig.kt | 17 +++ .../game/elements/ElementsGameConfig.kt | 1 + .../minosoft/data/text/TextComponent.kt | 3 +- .../de/bixilon/minosoft/data/world/World.kt | 6 +- .../bixilon/minosoft/gui/rendering/Camera.kt | 5 +- .../minosoft/gui/rendering/RenderWindow.kt | 62 ++++++++++- .../gui/rendering/hud/HUDElementProperties.kt | 4 +- .../minosoft/gui/rendering/hud/HUDRenderer.kt | 9 +- .../hud/elements/chat/ChatBoxHUDElement.kt | 58 ++++++++++ .../hud/elements/input/KeyConsumer.kt | 26 +++++ .../hud/elements/input/MouseConsumer.kt | 22 ++++ .../elements/input/SubmittableTextField.kt | 46 ++++++++ .../rendering/hud/elements/input/TextField.kt | 101 ++++++++++++++++++ .../hud/elements/other/HotbarHUDElement.kt | 5 +- .../protocol/protocol/PacketSender.java | 9 +- 15 files changed, 351 insertions(+), 23 deletions(-) create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/chat/ChatBoxHUDElement.kt create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/input/KeyConsumer.kt create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/input/MouseConsumer.kt create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/input/SubmittableTextField.kt create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/input/TextField.kt 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 200f6907a..ea2e2434a 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 @@ -52,11 +52,16 @@ object KeyBindingsNames { val WHEN_IN_GAME = ResourceLocation("minosoft:in_game") val WHEN_PLAYER_IS_FLYING = ResourceLocation("minosoft:is_flying") + val WHEN_IN_CHAT = ResourceLocation("minosoft:in_chat") val TAKE_SCREENSHOT = ResourceLocation("minosoft:take_screenshot") val TOGGLE_HUD = ResourceLocation("minosoft:toggle_hud") + val OPEN_CHAT = ResourceLocation("minosoft:open_chat") + + val CLOSE_CHAT = ResourceLocation("minosoft:close_chat") + val SELECT_HOTBAR_SLOTS = arrayOf(ResourceLocation("minosoft:select_hotbar_slot_1"), ResourceLocation("minosoft:select_hotbar_slot_2"), @@ -217,5 +222,17 @@ object KeyBindingsNames { ), mutableSetOf(mutableSetOf(WHEN_IN_GAME)) ), + OPEN_CHAT to KeyBinding( + mutableMapOf( + KeyAction.PRESS to mutableSetOf(KeyCodes.KEY_T) + ), + mutableSetOf(mutableSetOf(WHEN_IN_GAME)) + ), + CLOSE_CHAT to KeyBinding( + mutableMapOf( + KeyAction.PRESS to mutableSetOf(KeyCodes.KEY_ESCAPE) + ), + mutableSetOf(mutableSetOf(WHEN_IN_CHAT)) + ), ) } diff --git a/src/main/java/de/bixilon/minosoft/config/config/game/elements/ElementsGameConfig.kt b/src/main/java/de/bixilon/minosoft/config/config/game/elements/ElementsGameConfig.kt index 02e1364d6..718f57715 100644 --- a/src/main/java/de/bixilon/minosoft/config/config/game/elements/ElementsGameConfig.kt +++ b/src/main/java/de/bixilon/minosoft/config/config/game/elements/ElementsGameConfig.kt @@ -25,4 +25,5 @@ object ElementsNames { val CROSSHAIR_RESOURCE_LOCATION = ResourceLocation("minosoft:crosshair") val WORLD_DEBUG_SCREEN_RESOURCE_LOCATION = ResourceLocation("minosoft:world_debug_screen") val SYSTEM_DEBUG_SCREEN_RESOURCE_LOCATION = ResourceLocation("minosoft:system_debug_screen") + val CHAT_RESOURCE_LOCATION = ResourceLocation("minosoft:chat") } diff --git a/src/main/java/de/bixilon/minosoft/data/text/TextComponent.kt b/src/main/java/de/bixilon/minosoft/data/text/TextComponent.kt index 1ecb3fd0d..43f5c4f51 100644 --- a/src/main/java/de/bixilon/minosoft/data/text/TextComponent.kt +++ b/src/main/java/de/bixilon/minosoft/data/text/TextComponent.kt @@ -216,8 +216,7 @@ open class TextComponent : ChatComponent { for (char in charArray) { if (char == '\n') { offset.x = 0 - offset.y = 0 - val yOffset = offset.y + Font.CHAR_HEIGHT + RenderConstants.TEXT_LINE_PADDING + val yOffset = Font.CHAR_HEIGHT + RenderConstants.TEXT_LINE_PADDING offset.y += yOffset retMaxSize.y += yOffset continue diff --git a/src/main/java/de/bixilon/minosoft/data/world/World.kt b/src/main/java/de/bixilon/minosoft/data/world/World.kt index 481f7cb82..565451c2b 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/World.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/World.kt @@ -125,9 +125,9 @@ class World : BiomeAccessor { fun getBlocks(start: Vec3i, end: Vec3i): Map { val blocks: MutableMap = mutableMapOf() - for (z in start.z until end.z) { - for (y in start.y until end.y) { - for (x in start.x until end.x) { + for (z in start.z..end.z) { + for (y in start.y..end.y) { + for (x in start.x..end.x) { val blockPosition = Vec3i(x, y, z) getBlockState(blockPosition)?.let { blocks[blockPosition] = it diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/Camera.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/Camera.kt index 453da448e..d4a4194f6 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/Camera.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/Camera.kt @@ -95,6 +95,9 @@ class Camera( var yOffset = yPos - this.lastMouseY lastMouseX = xPos lastMouseY = yPos + if (!renderWindow.currentElement.contains(KeyBindingsNames.WHEN_IN_GAME)) { + return + } xOffset *= mouseSensitivity yOffset *= mouseSensitivity var yaw = xOffset.toFloat() + playerEntity.rotation.headYaw @@ -145,7 +148,7 @@ class Camera( fun handleInput(deltaTime: Double) { var cameraSpeed = movementSpeed * deltaTime val movementFront = Vec3(cameraFront) - if (! Minosoft.getConfig().config.game.camera.noCipMovement) { + if (!Minosoft.getConfig().config.game.camera.noCipMovement) { movementFront.y = 0.0f movementFront.normalizeAssign() // when moving forwards, do not move down } 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 b44f0ba05..f9d5b6d65 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.font.Font import de.bixilon.minosoft.gui.rendering.hud.HUDRenderer +import de.bixilon.minosoft.gui.rendering.hud.elements.input.KeyConsumer import de.bixilon.minosoft.gui.rendering.textures.Texture import de.bixilon.minosoft.gui.rendering.textures.TextureArray import de.bixilon.minosoft.gui.rendering.util.ScreenshotTaker @@ -36,10 +37,9 @@ import de.bixilon.minosoft.util.CountUpAndDownLatch import de.bixilon.minosoft.util.logging.Log import glm_.vec2.Vec2 import glm_.vec2.Vec2i -import org.lwjgl.* import org.lwjgl.glfw.* import org.lwjgl.glfw.GLFW.* -import org.lwjgl.opengl.* +import org.lwjgl.opengl.GL import org.lwjgl.opengl.GL11.* import org.lwjgl.system.MemoryStack import org.lwjgl.system.MemoryUtil @@ -81,6 +81,30 @@ class RenderWindow( val renderQueue = ConcurrentLinkedQueue() + private var _currentInputConsumer: KeyConsumer? = null + val currentElement: MutableList = mutableListOf(KeyBindingsNames.WHEN_IN_GAME, KeyBindingsNames.WHEN_PLAYER_IS_FLYING) + + private var skipNextChatPress = false + + var currentInputConsumer: KeyConsumer? + get() = _currentInputConsumer + set(value) { + _currentInputConsumer = value + for ((_, binding) in keyBindingCallbacks) { + if (!keyBindingDown.contains(binding.first)) { + continue + } + if (!binding.first.action.containsKey(KeyAction.TOGGLE) && !binding.first.action.containsKey(KeyAction.CHANGE)) { + continue + } + + for (keyCallback in binding.second) { + keyCallback.invoke(KeyCodes.KEY_UNKNOWN, KeyAction.RELEASE) + } + } + keyBindingDown.clear() + } + init { connection.registerEvent(EventInvokerCallback { if (it.connection.isDisconnected) { @@ -104,7 +128,6 @@ class RenderWindow( }) } - fun init(latch: CountUpAndDownLatch) { // Setup an error callback. The default implementation // will print the error message in System.err. @@ -146,12 +169,37 @@ class RenderWindow( keysDown.remove(keyCode) } + if (keyAction == KeyAction.PRESS) { + // ToDo: Repeatable keys, long holding, etc + + currentInputConsumer?.keyInput(keyCode) + } + for ((_, keyCallbackPair) in keyBindingCallbacks) { run { val keyBinding = keyCallbackPair.first val keyCallbacks = keyCallbackPair.second var anyCheckRun = false + + var andWhenValid = false + for (or in keyBinding.`when`) { + var andValid = true + for (and in or) { + if (!currentElement.contains(and)) { + andValid = false + break + } + } + if (andValid) { + andWhenValid = true + break + } + } + if (!andWhenValid) { + return@run + } + keyBinding.action[KeyAction.MODIFIER]?.let { val previousKeysDown = if (keyAction == KeyAction.RELEASE) { val previousKeysDown = keysDown.toMutableList() @@ -196,11 +244,19 @@ class RenderWindow( } for (keyCallback in keyCallbacks) { keyCallback.invoke(keyCode, keyAction) + skipNextChatPress = true } } } } + glfwSetCharCallback(windowId) { _: Long, char: Int -> + if (skipNextChatPress) { + skipNextChatPress = false + return@glfwSetCharCallback + } + currentInputConsumer?.charInput(char.toChar()) + } if (mouseCatch) { glfwSetInputMode(windowId, GLFW_CURSOR, GLFW_CURSOR_DISABLED) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/HUDElementProperties.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/HUDElementProperties.kt index 1ab8a0ab8..8fd17f845 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/HUDElementProperties.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/HUDElementProperties.kt @@ -19,8 +19,8 @@ import glm_.vec2.Vec2 data class HUDElementProperties( val position: Vec2, - @Json(name = "x_binding") val xBinding: PositionBindings, - @Json(name = "y_binding") val yBinding: PositionBindings, + @Json(name = "x_binding") val xBinding: PositionBindings = PositionBindings.FURTHEST_POINT_AWAY, + @Json(name = "y_binding") val yBinding: PositionBindings = PositionBindings.FURTHEST_POINT_AWAY, @Json(name = "toggle_key_binding") var toggleKeyBinding: ResourceLocation? = null, val scale: Float = 1.0f, var enabled: Boolean = true, diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/HUDRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/HUDRenderer.kt index c6fbaf9b0..df9e1c372 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/HUDRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/HUDRenderer.kt @@ -22,6 +22,7 @@ import de.bixilon.minosoft.gui.rendering.RenderWindow import de.bixilon.minosoft.gui.rendering.Renderer import de.bixilon.minosoft.gui.rendering.hud.atlas.HUDAtlasElement import de.bixilon.minosoft.gui.rendering.hud.elements.HUDElement +import de.bixilon.minosoft.gui.rendering.hud.elements.chat.ChatBoxHUDElement import de.bixilon.minosoft.gui.rendering.hud.elements.debug.HUDSystemDebugElement import de.bixilon.minosoft.gui.rendering.hud.elements.debug.HUDWorldDebugElement import de.bixilon.minosoft.gui.rendering.hud.elements.other.CrosshairHUDElement @@ -75,7 +76,6 @@ class HUDRenderer(val connection: PlayConnection, val renderWindow: RenderWindow addElement(ElementsNames.HOTBAR_RESOURCE_LOCATION, HotbarHUDElement(this), HUDElementProperties( position = Vec2(0.0f, -1.0f), xBinding = HUDElementProperties.PositionBindings.CENTER, - yBinding = HUDElementProperties.PositionBindings.FURTHEST_POINT_AWAY, )) addElement(ElementsNames.CROSSHAIR_RESOURCE_LOCATION, CrosshairHUDElement(this), HUDElementProperties( @@ -85,18 +85,17 @@ class HUDRenderer(val connection: PlayConnection, val renderWindow: RenderWindow )) addElement(ElementsNames.WORLD_DEBUG_SCREEN_RESOURCE_LOCATION, HUDWorldDebugElement(this), HUDElementProperties( position = Vec2(-1.0f, 1.0f), - xBinding = HUDElementProperties.PositionBindings.FURTHEST_POINT_AWAY, - yBinding = HUDElementProperties.PositionBindings.FURTHEST_POINT_AWAY, toggleKeyBinding = KeyBindingsNames.TOGGLE_DEBUG_SCREEN, enabled = false, )) addElement(ElementsNames.SYSTEM_DEBUG_SCREEN_RESOURCE_LOCATION, HUDSystemDebugElement(this), HUDElementProperties( position = Vec2(1.0f, 1.0f), - xBinding = HUDElementProperties.PositionBindings.FURTHEST_POINT_AWAY, - yBinding = HUDElementProperties.PositionBindings.FURTHEST_POINT_AWAY, toggleKeyBinding = KeyBindingsNames.TOGGLE_DEBUG_SCREEN, enabled = false, )) + addElement(ElementsNames.CHAT_RESOURCE_LOCATION, ChatBoxHUDElement(this), HUDElementProperties( + position = Vec2(0f, -1.0f), + )) } fun addElement(resourceLocation: ResourceLocation, hudElement: HUDElement, defaultProperties: HUDElementProperties) { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/chat/ChatBoxHUDElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/chat/ChatBoxHUDElement.kt new file mode 100644 index 000000000..11ea5cd23 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/chat/ChatBoxHUDElement.kt @@ -0,0 +1,58 @@ +/* + * 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.hud.elements.chat + +import de.bixilon.minosoft.config.config.game.controls.KeyBindingsNames +import de.bixilon.minosoft.gui.rendering.hud.HUDRenderer +import de.bixilon.minosoft.gui.rendering.hud.elements.HUDElement +import de.bixilon.minosoft.gui.rendering.hud.elements.input.SubmittableTextField + +class ChatBoxHUDElement(hudRenderer: HUDRenderer) : HUDElement(hudRenderer) { + private lateinit var inputField: SubmittableTextField + + override fun init() { + inputField = SubmittableTextField(font = hudRenderer.renderWindow.font, z = 100, maxLength = 256, onSubmit = { + try { + hudRenderer.renderWindow.connection.sender.sendChatMessage(it) + closeChat() + return@SubmittableTextField true + } catch (exception: Exception) { + closeChat() + return@SubmittableTextField false + } + }) + + layout.addChild(inputField) + + hudRenderer.renderWindow.registerKeyCallback(KeyBindingsNames.OPEN_CHAT) { _, _ -> + openChat() + } + hudRenderer.renderWindow.registerKeyCallback(KeyBindingsNames.CLOSE_CHAT) { _, _ -> + closeChat() + } + } + + fun openChat() { + hudRenderer.renderWindow.currentInputConsumer = inputField + hudRenderer.renderWindow.currentElement.remove(KeyBindingsNames.WHEN_IN_GAME) + hudRenderer.renderWindow.currentElement.add(KeyBindingsNames.WHEN_IN_CHAT) + } + + fun closeChat() { + inputField.clearText() + hudRenderer.renderWindow.currentInputConsumer = null + hudRenderer.renderWindow.currentElement.remove(KeyBindingsNames.WHEN_IN_CHAT) + hudRenderer.renderWindow.currentElement.add(KeyBindingsNames.WHEN_IN_GAME) + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/input/KeyConsumer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/input/KeyConsumer.kt new file mode 100644 index 000000000..72f658a03 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/input/KeyConsumer.kt @@ -0,0 +1,26 @@ +/* + * 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.hud.elements.input + +import de.bixilon.minosoft.config.key.KeyCodes + +interface KeyConsumer { + + val focused: Boolean + + fun charInput(char: Char) {} + + fun keyInput(keyCodes: KeyCodes) { + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/input/MouseConsumer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/input/MouseConsumer.kt new file mode 100644 index 000000000..311858b3c --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/input/MouseConsumer.kt @@ -0,0 +1,22 @@ +/* + * 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.hud.elements.input + +import glm_.vec2.Vec2i + +interface MouseConsumer { + val focused: Boolean + + fun mouseMove(position: Vec2i) {} +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/input/SubmittableTextField.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/input/SubmittableTextField.kt new file mode 100644 index 000000000..417aa3416 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/input/SubmittableTextField.kt @@ -0,0 +1,46 @@ +/* + * 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.hud.elements.input + +import de.bixilon.minosoft.config.key.KeyCodes +import de.bixilon.minosoft.gui.rendering.font.Font +import glm_.vec2.Vec2i + +class SubmittableTextField( + start: Vec2i = Vec2i(0, 0), + z: Int = 0, + font: Font, + defaultText: String = "", + maxLength: Int = 256, + private val onSubmit: (text: String) -> Boolean, +) : TextField(start, z, font, defaultText, maxLength) { + + fun submit() { + if (!onSubmit.invoke(text)) { + // failed + return + } + text = "" + } + + + override fun keyInput(keyCodes: KeyCodes) { + if (keyCodes == KeyCodes.KEY_ENTER) { + // submit + submit() + return + } + super.keyInput(keyCodes) + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/input/TextField.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/input/TextField.kt new file mode 100644 index 000000000..9f691bf87 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/input/TextField.kt @@ -0,0 +1,101 @@ +/* + * 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.hud.elements.input + +import de.bixilon.minosoft.config.key.KeyCodes +import de.bixilon.minosoft.data.text.ChatComponent +import de.bixilon.minosoft.gui.rendering.font.Font +import de.bixilon.minosoft.gui.rendering.hud.elements.primitive.Layout +import de.bixilon.minosoft.gui.rendering.hud.elements.primitive.TextElement +import de.bixilon.minosoft.util.MMath +import glm_.vec2.Vec2i + +open class TextField( + start: Vec2i = Vec2i(0, 0), + z: Int = 0, + font: Font, + defaultText: String = "", + val maxLength: Int = 256, +) : Layout(start, z), KeyConsumer, MouseConsumer { + override var focused: Boolean = true + private var textBuilder: StringBuilder = StringBuilder(defaultText) + private val textElement = TextElement(ChatComponent.valueOf(text), font) + private var position = text.length + + var text: String + get() = textBuilder.toString() + set(value) { + position = value.length + textBuilder = StringBuilder(value) + update() + } + + init { + addChild(textElement) + } + + fun clearText() { + textBuilder.clear() + update() + } + + private fun update() { + textElement.text = ChatComponent.valueOf(text) + } + + override fun keyInput(keyCodes: KeyCodes) { + when (keyCodes) { + KeyCodes.KEY_BACKSPACE -> { + if (textBuilder.isEmpty()) { + return + } + textBuilder.deleteCharAt(--position) + } + KeyCodes.KEY_DELETE -> { + if (textBuilder.isEmpty() || position == textBuilder.length) { + return + } + textBuilder.deleteCharAt(position) + } + KeyCodes.KEY_ENTER -> { + if (position > maxLength) { + return + } + textBuilder.insert(position++, '\n') + } + KeyCodes.KEY_LEFT -> { + position = MMath.clamp(position - 1, 0, text.length) + return + } + KeyCodes.KEY_RIGHT -> { + position = MMath.clamp(position + 1, 0, text.length) + return + } + // ToDo: Up and down for line breaks, shift and ctrl modifier, ... + else -> { + return + } + } + update() + super.keyInput(keyCodes) + } + + override fun charInput(char: Char) { + if (position >= maxLength) { + return + } + textBuilder.insert(position++, char.toString()) + update() + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/other/HotbarHUDElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/other/HotbarHUDElement.kt index f287a350d..22468d87c 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/other/HotbarHUDElement.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/hud/elements/other/HotbarHUDElement.kt @@ -34,7 +34,6 @@ import glm_.vec2.Vec2i class HotbarHUDElement( hudRender: HUDRenderer, ) : HUDElement(hudRender) { - private lateinit var hotbarBase: HotbarBaseElement private lateinit var experienceBar: ProgressBar @@ -55,7 +54,6 @@ class HotbarHUDElement( z = 1, ) - levelText = TextElement( font = hudRenderer.renderWindow.font, background = false, @@ -110,7 +108,6 @@ class HotbarHUDElement( healthBar.prepare() prepare() }) - } private fun prepare() { @@ -166,7 +163,7 @@ class HotbarHUDElement( private val frame = ImageElement(textureLike = frameHUDAtlasElement, z = 2) init { - fakeX = base.size.x.toInt() + fakeX = base.size.x addChild(base) addChild(frame) } diff --git a/src/main/java/de/bixilon/minosoft/protocol/protocol/PacketSender.java b/src/main/java/de/bixilon/minosoft/protocol/protocol/PacketSender.java index 2213c3564..a53ef2c7f 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/protocol/PacketSender.java +++ b/src/main/java/de/bixilon/minosoft/protocol/protocol/PacketSender.java @@ -33,7 +33,7 @@ import org.checkerframework.common.value.qual.IntRange; import java.util.UUID; public class PacketSender { - public static final String[] ILLEGAL_CHAT_CHARS = {"§"}; + public static final char[] ILLEGAL_CHAT_CHARS = {'§', '\n', '\r'}; private final PlayConnection connection; public PacketSender(PlayConnection connection) { @@ -45,8 +45,11 @@ public class PacketSender { } public void sendChatMessage(String message) { - for (String illegalChar : ILLEGAL_CHAT_CHARS) { - if (message.contains(illegalChar)) { + if (message.isBlank()) { + throw new IllegalArgumentException(("Chat message is blank!")); + } + for (char illegalChar : ILLEGAL_CHAT_CHARS) { + if (message.indexOf(illegalChar) != -1) { throw new IllegalArgumentException(String.format("%s is not allowed in chat", illegalChar)); } }