rendering: wip: chat field

This commit is contained in:
Bixilon 2021-04-10 18:30:23 +02:00
parent c1fa6d5829
commit 4866528802
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
15 changed files with 351 additions and 23 deletions

View File

@ -52,11 +52,16 @@ object KeyBindingsNames {
val WHEN_IN_GAME = ResourceLocation("minosoft:in_game") val WHEN_IN_GAME = ResourceLocation("minosoft:in_game")
val WHEN_PLAYER_IS_FLYING = ResourceLocation("minosoft:is_flying") 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 TAKE_SCREENSHOT = ResourceLocation("minosoft:take_screenshot")
val TOGGLE_HUD = ResourceLocation("minosoft:toggle_hud") 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"), val SELECT_HOTBAR_SLOTS = arrayOf(ResourceLocation("minosoft:select_hotbar_slot_1"),
ResourceLocation("minosoft:select_hotbar_slot_2"), ResourceLocation("minosoft:select_hotbar_slot_2"),
@ -217,5 +222,17 @@ object KeyBindingsNames {
), ),
mutableSetOf(mutableSetOf(WHEN_IN_GAME)) 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))
),
) )
} }

View File

@ -25,4 +25,5 @@ object ElementsNames {
val CROSSHAIR_RESOURCE_LOCATION = ResourceLocation("minosoft:crosshair") val CROSSHAIR_RESOURCE_LOCATION = ResourceLocation("minosoft:crosshair")
val WORLD_DEBUG_SCREEN_RESOURCE_LOCATION = ResourceLocation("minosoft:world_debug_screen") val WORLD_DEBUG_SCREEN_RESOURCE_LOCATION = ResourceLocation("minosoft:world_debug_screen")
val SYSTEM_DEBUG_SCREEN_RESOURCE_LOCATION = ResourceLocation("minosoft:system_debug_screen") val SYSTEM_DEBUG_SCREEN_RESOURCE_LOCATION = ResourceLocation("minosoft:system_debug_screen")
val CHAT_RESOURCE_LOCATION = ResourceLocation("minosoft:chat")
} }

View File

@ -216,8 +216,7 @@ open class TextComponent : ChatComponent {
for (char in charArray) { for (char in charArray) {
if (char == '\n') { if (char == '\n') {
offset.x = 0 offset.x = 0
offset.y = 0 val yOffset = Font.CHAR_HEIGHT + RenderConstants.TEXT_LINE_PADDING
val yOffset = offset.y + Font.CHAR_HEIGHT + RenderConstants.TEXT_LINE_PADDING
offset.y += yOffset offset.y += yOffset
retMaxSize.y += yOffset retMaxSize.y += yOffset
continue continue

View File

@ -125,9 +125,9 @@ class World : BiomeAccessor {
fun getBlocks(start: Vec3i, end: Vec3i): Map<Vec3i, BlockState> { fun getBlocks(start: Vec3i, end: Vec3i): Map<Vec3i, BlockState> {
val blocks: MutableMap<Vec3i, BlockState> = mutableMapOf() val blocks: MutableMap<Vec3i, BlockState> = mutableMapOf()
for (z in start.z until end.z) { for (z in start.z..end.z) {
for (y in start.y until end.y) { for (y in start.y..end.y) {
for (x in start.x until end.x) { for (x in start.x..end.x) {
val blockPosition = Vec3i(x, y, z) val blockPosition = Vec3i(x, y, z)
getBlockState(blockPosition)?.let { getBlockState(blockPosition)?.let {
blocks[blockPosition] = it blocks[blockPosition] = it

View File

@ -95,6 +95,9 @@ class Camera(
var yOffset = yPos - this.lastMouseY var yOffset = yPos - this.lastMouseY
lastMouseX = xPos lastMouseX = xPos
lastMouseY = yPos lastMouseY = yPos
if (!renderWindow.currentElement.contains(KeyBindingsNames.WHEN_IN_GAME)) {
return
}
xOffset *= mouseSensitivity xOffset *= mouseSensitivity
yOffset *= mouseSensitivity yOffset *= mouseSensitivity
var yaw = xOffset.toFloat() + playerEntity.rotation.headYaw var yaw = xOffset.toFloat() + playerEntity.rotation.headYaw
@ -145,7 +148,7 @@ class Camera(
fun handleInput(deltaTime: Double) { fun handleInput(deltaTime: Double) {
var cameraSpeed = movementSpeed * deltaTime var cameraSpeed = movementSpeed * deltaTime
val movementFront = Vec3(cameraFront) val movementFront = Vec3(cameraFront)
if (! Minosoft.getConfig().config.game.camera.noCipMovement) { if (!Minosoft.getConfig().config.game.camera.noCipMovement) {
movementFront.y = 0.0f movementFront.y = 0.0f
movementFront.normalizeAssign() // when moving forwards, do not move down movementFront.normalizeAssign() // when moving forwards, do not move down
} }

View File

@ -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.chunk.WorldRenderer
import de.bixilon.minosoft.gui.rendering.font.Font import de.bixilon.minosoft.gui.rendering.font.Font
import de.bixilon.minosoft.gui.rendering.hud.HUDRenderer 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.Texture
import de.bixilon.minosoft.gui.rendering.textures.TextureArray import de.bixilon.minosoft.gui.rendering.textures.TextureArray
import de.bixilon.minosoft.gui.rendering.util.ScreenshotTaker 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 de.bixilon.minosoft.util.logging.Log
import glm_.vec2.Vec2 import glm_.vec2.Vec2
import glm_.vec2.Vec2i import glm_.vec2.Vec2i
import org.lwjgl.*
import org.lwjgl.glfw.* import org.lwjgl.glfw.*
import org.lwjgl.glfw.GLFW.* import org.lwjgl.glfw.GLFW.*
import org.lwjgl.opengl.* import org.lwjgl.opengl.GL
import org.lwjgl.opengl.GL11.* import org.lwjgl.opengl.GL11.*
import org.lwjgl.system.MemoryStack import org.lwjgl.system.MemoryStack
import org.lwjgl.system.MemoryUtil import org.lwjgl.system.MemoryUtil
@ -81,6 +81,30 @@ class RenderWindow(
val renderQueue = ConcurrentLinkedQueue<Runnable>() val renderQueue = ConcurrentLinkedQueue<Runnable>()
private var _currentInputConsumer: KeyConsumer? = null
val currentElement: MutableList<ResourceLocation> = 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 { init {
connection.registerEvent(EventInvokerCallback<ConnectionStateChangeEvent> { connection.registerEvent(EventInvokerCallback<ConnectionStateChangeEvent> {
if (it.connection.isDisconnected) { if (it.connection.isDisconnected) {
@ -104,7 +128,6 @@ class RenderWindow(
}) })
} }
fun init(latch: CountUpAndDownLatch) { fun init(latch: CountUpAndDownLatch) {
// Setup an error callback. The default implementation // Setup an error callback. The default implementation
// will print the error message in System.err. // will print the error message in System.err.
@ -146,12 +169,37 @@ class RenderWindow(
keysDown.remove(keyCode) keysDown.remove(keyCode)
} }
if (keyAction == KeyAction.PRESS) {
// ToDo: Repeatable keys, long holding, etc
currentInputConsumer?.keyInput(keyCode)
}
for ((_, keyCallbackPair) in keyBindingCallbacks) { for ((_, keyCallbackPair) in keyBindingCallbacks) {
run { run {
val keyBinding = keyCallbackPair.first val keyBinding = keyCallbackPair.first
val keyCallbacks = keyCallbackPair.second val keyCallbacks = keyCallbackPair.second
var anyCheckRun = false 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 { keyBinding.action[KeyAction.MODIFIER]?.let {
val previousKeysDown = if (keyAction == KeyAction.RELEASE) { val previousKeysDown = if (keyAction == KeyAction.RELEASE) {
val previousKeysDown = keysDown.toMutableList() val previousKeysDown = keysDown.toMutableList()
@ -196,11 +244,19 @@ class RenderWindow(
} }
for (keyCallback in keyCallbacks) { for (keyCallback in keyCallbacks) {
keyCallback.invoke(keyCode, keyAction) keyCallback.invoke(keyCode, keyAction)
skipNextChatPress = true
} }
} }
} }
} }
glfwSetCharCallback(windowId) { _: Long, char: Int ->
if (skipNextChatPress) {
skipNextChatPress = false
return@glfwSetCharCallback
}
currentInputConsumer?.charInput(char.toChar())
}
if (mouseCatch) { if (mouseCatch) {
glfwSetInputMode(windowId, GLFW_CURSOR, GLFW_CURSOR_DISABLED) glfwSetInputMode(windowId, GLFW_CURSOR, GLFW_CURSOR_DISABLED)

View File

@ -19,8 +19,8 @@ import glm_.vec2.Vec2
data class HUDElementProperties( data class HUDElementProperties(
val position: Vec2, val position: Vec2,
@Json(name = "x_binding") val xBinding: PositionBindings, @Json(name = "x_binding") val xBinding: PositionBindings = PositionBindings.FURTHEST_POINT_AWAY,
@Json(name = "y_binding") val yBinding: PositionBindings, @Json(name = "y_binding") val yBinding: PositionBindings = PositionBindings.FURTHEST_POINT_AWAY,
@Json(name = "toggle_key_binding") var toggleKeyBinding: ResourceLocation? = null, @Json(name = "toggle_key_binding") var toggleKeyBinding: ResourceLocation? = null,
val scale: Float = 1.0f, val scale: Float = 1.0f,
var enabled: Boolean = true, var enabled: Boolean = true,

View File

@ -22,6 +22,7 @@ import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.Renderer import de.bixilon.minosoft.gui.rendering.Renderer
import de.bixilon.minosoft.gui.rendering.hud.atlas.HUDAtlasElement 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.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.HUDSystemDebugElement
import de.bixilon.minosoft.gui.rendering.hud.elements.debug.HUDWorldDebugElement import de.bixilon.minosoft.gui.rendering.hud.elements.debug.HUDWorldDebugElement
import de.bixilon.minosoft.gui.rendering.hud.elements.other.CrosshairHUDElement 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( addElement(ElementsNames.HOTBAR_RESOURCE_LOCATION, HotbarHUDElement(this), HUDElementProperties(
position = Vec2(0.0f, -1.0f), position = Vec2(0.0f, -1.0f),
xBinding = HUDElementProperties.PositionBindings.CENTER, xBinding = HUDElementProperties.PositionBindings.CENTER,
yBinding = HUDElementProperties.PositionBindings.FURTHEST_POINT_AWAY,
)) ))
addElement(ElementsNames.CROSSHAIR_RESOURCE_LOCATION, CrosshairHUDElement(this), HUDElementProperties( 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( addElement(ElementsNames.WORLD_DEBUG_SCREEN_RESOURCE_LOCATION, HUDWorldDebugElement(this), HUDElementProperties(
position = Vec2(-1.0f, 1.0f), position = Vec2(-1.0f, 1.0f),
xBinding = HUDElementProperties.PositionBindings.FURTHEST_POINT_AWAY,
yBinding = HUDElementProperties.PositionBindings.FURTHEST_POINT_AWAY,
toggleKeyBinding = KeyBindingsNames.TOGGLE_DEBUG_SCREEN, toggleKeyBinding = KeyBindingsNames.TOGGLE_DEBUG_SCREEN,
enabled = false, enabled = false,
)) ))
addElement(ElementsNames.SYSTEM_DEBUG_SCREEN_RESOURCE_LOCATION, HUDSystemDebugElement(this), HUDElementProperties( addElement(ElementsNames.SYSTEM_DEBUG_SCREEN_RESOURCE_LOCATION, HUDSystemDebugElement(this), HUDElementProperties(
position = Vec2(1.0f, 1.0f), position = Vec2(1.0f, 1.0f),
xBinding = HUDElementProperties.PositionBindings.FURTHEST_POINT_AWAY,
yBinding = HUDElementProperties.PositionBindings.FURTHEST_POINT_AWAY,
toggleKeyBinding = KeyBindingsNames.TOGGLE_DEBUG_SCREEN, toggleKeyBinding = KeyBindingsNames.TOGGLE_DEBUG_SCREEN,
enabled = false, enabled = false,
)) ))
addElement(ElementsNames.CHAT_RESOURCE_LOCATION, ChatBoxHUDElement(this), HUDElementProperties(
position = Vec2(0f, -1.0f),
))
} }
fun addElement(resourceLocation: ResourceLocation, hudElement: HUDElement, defaultProperties: HUDElementProperties) { fun addElement(resourceLocation: ResourceLocation, hudElement: HUDElement, defaultProperties: HUDElementProperties) {

View File

@ -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 <https://www.gnu.org/licenses/>.
*
* 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)
}
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*
* 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) {
}
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*
* 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) {}
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*
* 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)
}
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*
* 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()
}
}

View File

@ -34,7 +34,6 @@ import glm_.vec2.Vec2i
class HotbarHUDElement( class HotbarHUDElement(
hudRender: HUDRenderer, hudRender: HUDRenderer,
) : HUDElement(hudRender) { ) : HUDElement(hudRender) {
private lateinit var hotbarBase: HotbarBaseElement private lateinit var hotbarBase: HotbarBaseElement
private lateinit var experienceBar: ProgressBar private lateinit var experienceBar: ProgressBar
@ -55,7 +54,6 @@ class HotbarHUDElement(
z = 1, z = 1,
) )
levelText = TextElement( levelText = TextElement(
font = hudRenderer.renderWindow.font, font = hudRenderer.renderWindow.font,
background = false, background = false,
@ -110,7 +108,6 @@ class HotbarHUDElement(
healthBar.prepare() healthBar.prepare()
prepare() prepare()
}) })
} }
private fun prepare() { private fun prepare() {
@ -166,7 +163,7 @@ class HotbarHUDElement(
private val frame = ImageElement(textureLike = frameHUDAtlasElement, z = 2) private val frame = ImageElement(textureLike = frameHUDAtlasElement, z = 2)
init { init {
fakeX = base.size.x.toInt() fakeX = base.size.x
addChild(base) addChild(base)
addChild(frame) addChild(frame)
} }

View File

@ -33,7 +33,7 @@ import org.checkerframework.common.value.qual.IntRange;
import java.util.UUID; import java.util.UUID;
public class PacketSender { public class PacketSender {
public static final String[] ILLEGAL_CHAT_CHARS = {"§"}; public static final char[] ILLEGAL_CHAT_CHARS = {'§', '\n', '\r'};
private final PlayConnection connection; private final PlayConnection connection;
public PacketSender(PlayConnection connection) { public PacketSender(PlayConnection connection) {
@ -45,8 +45,11 @@ public class PacketSender {
} }
public void sendChatMessage(String message) { public void sendChatMessage(String message) {
for (String illegalChar : ILLEGAL_CHAT_CHARS) { if (message.isBlank()) {
if (message.contains(illegalChar)) { 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)); throw new IllegalArgumentException(String.format("%s is not allowed in chat", illegalChar));
} }
} }