From 50045e8c70176ed5cea4cc61356c8024e51cd112 Mon Sep 17 00:00:00 2001 From: Bixilon Date: Thu, 29 Jun 2023 17:56:20 +0200 Subject: [PATCH] wip input manager refactor + tests --- .../binding/actions/KeyActionFilterTest.kt | 362 ++++++++++++++++++ .../gui/rendering/camera/view/ViewManager.kt | 4 +- .../gui/rendering/entity/EntityRenderer.kt | 4 +- .../framebuffer/world/fun/FunEffectManager.kt | 2 +- .../minosoft/gui/rendering/gui/GUIRenderer.kt | 7 +- .../gui/elements/text/TextFlowElement.kt | 5 +- .../gui/rendering/gui/gui/AbstractLayout.kt | 7 +- .../gui/rendering/gui/gui/GUIManager.kt | 19 +- .../gui/rendering/gui/gui/GUIMeshElement.kt | 13 +- .../gui/rendering/gui/gui/dragged/Dragged.kt | 5 +- .../gui/gui/dragged/DraggedManager.kt | 15 +- .../rendering/gui/gui/popper/PopperManager.kt | 9 +- .../screen/container/ContainerGUIManager.kt | 2 +- .../gui/rendering/gui/gui/screen/menu/Menu.kt | 5 +- .../gui/rendering/gui/hud/HUDManager.kt | 6 +- .../hud/elements/chat/AbstractChatElement.kt | 5 +- .../gui/hud/elements/chat/ChatElement.kt | 4 +- .../gui/rendering/gui/input/DragTarget.kt | 5 +- .../rendering/gui/input/DraggableHandler.kt | 5 +- .../gui/rendering/gui/input/InputElement.kt | 5 +- .../gui/rendering/gui/input/ModifierKeys.kt | 14 +- .../gui/rendering/input/CameraInput.kt | 26 +- .../gui/rendering/input/InputHandler.kt | 7 +- .../interaction/InteractionManagerKeys.kt | 19 +- .../rendering/input/key/DebugKeyBindings.kt | 25 +- .../rendering/input/key/DefaultKeyBindings.kt | 6 +- .../input/key/manager/InputHandlerManager.kt | 89 +++++ .../input/key/manager/InputManager.kt | 321 +++------------- .../key/manager/binding/BindingsManager.kt | 142 +++++++ .../key/manager/binding/KeyBindingCallback.kt | 16 + .../manager/binding/KeyBindingFilterState.kt | 21 + .../binding/KeyBindingState.kt} | 12 +- .../binding/actions/KeyActionFilter.kt | 139 +++++++ .../gui/rendering/world/WorldRenderer.kt | 2 +- .../world/chunk/ChunkBorderRenderer.kt | 4 +- .../gui/rendering/world/light/RenderLight.kt | 23 +- 36 files changed, 957 insertions(+), 398 deletions(-) create mode 100644 src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/input/key/manager/binding/actions/KeyActionFilterTest.kt create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/input/key/manager/InputHandlerManager.kt create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/input/key/manager/binding/BindingsManager.kt create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/input/key/manager/binding/KeyBindingCallback.kt create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/input/key/manager/binding/KeyBindingFilterState.kt rename src/main/java/de/bixilon/minosoft/gui/rendering/input/key/{KeyBindingRegister.kt => manager/binding/KeyBindingState.kt} (76%) create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/input/key/manager/binding/actions/KeyActionFilter.kt diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/input/key/manager/binding/actions/KeyActionFilterTest.kt b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/input/key/manager/binding/actions/KeyActionFilterTest.kt new file mode 100644 index 000000000..484fb1c16 --- /dev/null +++ b/src/integration-test/kotlin/de/bixilon/minosoft/gui/rendering/input/key/manager/binding/actions/KeyActionFilterTest.kt @@ -0,0 +1,362 @@ +/* + * Minosoft + * Copyright (C) 2020-2023 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.input.key.manager.binding.actions + +import de.bixilon.kutil.cast.CastUtil.unsafeCast +import de.bixilon.kutil.reflection.ReflectionUtil.forceSet +import de.bixilon.minosoft.config.key.KeyActions +import de.bixilon.minosoft.config.key.KeyBinding +import de.bixilon.minosoft.config.key.KeyCodes +import de.bixilon.minosoft.data.registries.identified.Namespaces.minosoft +import de.bixilon.minosoft.data.registries.identified.ResourceLocation +import de.bixilon.minosoft.gui.rendering.input.key.manager.InputManager +import de.bixilon.minosoft.gui.rendering.input.key.manager.binding.BindingsManager +import de.bixilon.minosoft.gui.rendering.input.key.manager.binding.KeyBindingFilterState +import de.bixilon.minosoft.gui.rendering.input.key.manager.binding.KeyBindingState +import de.bixilon.minosoft.test.IT.OBJENESIS +import org.testng.Assert.assertFalse +import org.testng.Assert.assertTrue +import org.testng.annotations.Test + + +val keysPressed = InputManager::class.java.getDeclaredField("pressed").apply { isAccessible = true } +val bindingsPressed = BindingsManager::class.java.getDeclaredField("pressed").apply { isAccessible = true } +val name = minosoft("dummy") + +fun input(): InputManager { + val manager = OBJENESIS.newInstance(InputManager::class.java) + val bindings = OBJENESIS.newInstance(BindingsManager::class.java) + bindingsPressed[bindings] = mutableSetOf() + manager::bindings.forceSet(bindings) + + keysPressed[manager] = mutableSetOf() + + return manager +} + +@Test(groups = ["input"]) +class Press { + + fun `simple press`() { + val state = KeyBindingFilterState(true) + KeyActionFilter.Press.check( + state, setOf(KeyCodes.KEY_0), input(), name, + KeyBindingState(KeyBinding(mapOf(KeyActions.PRESS to setOf(KeyCodes.KEY_0)))), + KeyCodes.KEY_0, + pressed = true, + 0L, + ) + + assertTrue(state.satisfied) + } + + fun `wrong key`() { + val state = KeyBindingFilterState(true) + KeyActionFilter.Press.check( + state, setOf(KeyCodes.KEY_0), input(), name, + KeyBindingState(KeyBinding(mapOf(KeyActions.PRESS to setOf(KeyCodes.KEY_0)))), + KeyCodes.KEY_1, + pressed = true, + 0L, + ) + + assertFalse(state.satisfied) + } + + fun `multiple keys`() { + val state = KeyBindingFilterState(true) + KeyActionFilter.Press.check( + state, setOf(KeyCodes.KEY_0, KeyCodes.KEY_1, KeyCodes.KEY_2), input(), name, + KeyBindingState(KeyBinding(mapOf(KeyActions.PRESS to setOf(KeyCodes.KEY_0)))), + KeyCodes.KEY_1, + pressed = true, + 0L, + ) + + assertTrue(state.result) + } + + fun `not pressed`() { + val state = KeyBindingFilterState(true) + KeyActionFilter.Press.check( + state, setOf(KeyCodes.KEY_0), input(), name, + KeyBindingState(KeyBinding(mapOf(KeyActions.PRESS to setOf(KeyCodes.KEY_0)))), + KeyCodes.KEY_1, + pressed = false, + 0L, + ) + + assertFalse(state.satisfied) + } +} + +@Test(groups = ["input"]) +class Release { + + fun `simple release`() { + val state = KeyBindingFilterState(true) + KeyActionFilter.Release.check( + state, setOf(KeyCodes.KEY_0), input(), name, + KeyBindingState(KeyBinding(mapOf(KeyActions.RELEASE to setOf(KeyCodes.KEY_0)))), + KeyCodes.KEY_0, + pressed = false, + 0L, + ) + + assertTrue(state.result) + assertTrue(state.satisfied) + } + + fun `wrong key`() { + val state = KeyBindingFilterState(false) + KeyActionFilter.Release.check( + state, setOf(KeyCodes.KEY_0), input(), name, + KeyBindingState(KeyBinding(mapOf(KeyActions.RELEASE to setOf(KeyCodes.KEY_0)))), + KeyCodes.KEY_1, + pressed = false, + 0L, + ) + + assertFalse(state.satisfied) + } + + fun `multiple keys`() { + val state = KeyBindingFilterState(true) + KeyActionFilter.Release.check( + state, setOf(KeyCodes.KEY_0, KeyCodes.KEY_1, KeyCodes.KEY_2), input(), name, + KeyBindingState(KeyBinding(mapOf(KeyActions.RELEASE to setOf(KeyCodes.KEY_0)))), + KeyCodes.KEY_1, + pressed = false, + 0L, + ) + + assertTrue(state.satisfied) + } + + fun pressed() { + val state = KeyBindingFilterState(true) + KeyActionFilter.Release.check( + state, setOf(KeyCodes.KEY_0), input(), name, + KeyBindingState(KeyBinding(mapOf(KeyActions.RELEASE to setOf(KeyCodes.KEY_0)))), + KeyCodes.KEY_1, + pressed = true, + 0L, + ) + + assertFalse(state.satisfied) + } +} + +@Test(groups = ["input"]) +class Change { + + fun `simple press`() { + val state = KeyBindingFilterState(false) + KeyActionFilter.Change.check( + state, setOf(KeyCodes.KEY_0), input(), name, + KeyBindingState(KeyBinding(mapOf(KeyActions.CHANGE to setOf(KeyCodes.KEY_0)))), + KeyCodes.KEY_0, + pressed = true, + 0L, + ) + + assertTrue(state.satisfied) + assertTrue(state.forceNotify) + } + + fun `simple release`() { + val state = KeyBindingFilterState(false) + KeyActionFilter.Change.check( + state, setOf(KeyCodes.KEY_0), input(), name, + KeyBindingState(KeyBinding(mapOf(KeyActions.CHANGE to setOf(KeyCodes.KEY_0)))), + KeyCodes.KEY_0, + pressed = false, + 0L, + ) + + assertTrue(state.satisfied) + assertTrue(state.forceNotify) + } + + fun `wrong key`() { + val state = KeyBindingFilterState(false) + KeyActionFilter.Change.check( + state, setOf(KeyCodes.KEY_0), input(), name, + KeyBindingState(KeyBinding(mapOf(KeyActions.CHANGE to setOf(KeyCodes.KEY_0)))), + KeyCodes.KEY_1, + pressed = false, + 0L, + ) + + assertFalse(state.satisfied) + assertFalse(state.forceNotify) + } + + fun `multiple keys`() { + val state = KeyBindingFilterState(true) + KeyActionFilter.Change.check( + state, setOf(KeyCodes.KEY_0, KeyCodes.KEY_1, KeyCodes.KEY_2), input(), name, + KeyBindingState(KeyBinding(mapOf(KeyActions.CHANGE to setOf(KeyCodes.KEY_0)))), + KeyCodes.KEY_1, + pressed = true, + 0L, + ) + + assertTrue(state.satisfied) + assertTrue(state.forceNotify) + } +} + +@Test(groups = ["input"]) +class Modifier { + + fun `simple press`() { + val state = KeyBindingFilterState(false) + KeyActionFilter.Modifier.check( + state, setOf(KeyCodes.KEY_0), input(), name, + KeyBindingState(KeyBinding(mapOf(KeyActions.MODIFIER to setOf(KeyCodes.KEY_0)))), + KeyCodes.KEY_0, + pressed = true, + 0L, + ) + + assertFalse(state.skip) + assertTrue(state.satisfied) + } + + fun `simple release`() { + val state = KeyBindingFilterState(false) + KeyActionFilter.Modifier.check( + state, setOf(KeyCodes.KEY_0), input(), name, + KeyBindingState(KeyBinding(mapOf(KeyActions.MODIFIER to setOf(KeyCodes.KEY_0)))), + KeyCodes.KEY_0, + pressed = false, + 0L, + ) + + assertFalse(state.skip) + assertFalse(state.satisfied) + } + + fun `wrong key`() { + val state = KeyBindingFilterState(false) + KeyActionFilter.Modifier.check( + state, setOf(KeyCodes.KEY_0), input(), name, + KeyBindingState(KeyBinding(mapOf(KeyActions.MODIFIER to setOf(KeyCodes.KEY_0)))), + KeyCodes.KEY_1, + pressed = false, + 0L, + ) + + assertTrue(state.skip) + } + + fun `multiple keys, not all pressed`() { + val state = KeyBindingFilterState(true) + KeyActionFilter.Modifier.check( + state, setOf(KeyCodes.KEY_0, KeyCodes.KEY_1, KeyCodes.KEY_2), input(), name, + KeyBindingState(KeyBinding(mapOf(KeyActions.MODIFIER to setOf(KeyCodes.KEY_0)))), + KeyCodes.KEY_1, + pressed = true, + 0L, + ) + + assertFalse(state.satisfied) + } + + fun `multiple keys, all pressed`() { + val state = KeyBindingFilterState(true) + val input = input() + val pressed = keysPressed.get(input).unsafeCast>() + pressed += KeyCodes.KEY_0 + pressed += KeyCodes.KEY_1 + pressed += KeyCodes.KEY_2 + + KeyActionFilter.Modifier.check( + state, setOf(KeyCodes.KEY_0, KeyCodes.KEY_1, KeyCodes.KEY_2), input, name, + KeyBindingState(KeyBinding(mapOf(KeyActions.MODIFIER to setOf(KeyCodes.KEY_0)))), + KeyCodes.KEY_1, + pressed = true, + 0L, + ) + + assertTrue(state.satisfied) + assertFalse(state.skip) + } +} + +@Test(groups = ["input"]) +class Sticky { + + fun `press key`() { + val state = KeyBindingFilterState(false) + KeyActionFilter.Sticky.check( + state, setOf(KeyCodes.KEY_0), input(), name, + KeyBindingState(KeyBinding(mapOf(KeyActions.STICKY to setOf(KeyCodes.KEY_0)))), + KeyCodes.KEY_0, + pressed = true, + 0L, + ) + + assertTrue(state.result) + assertFalse(state.skip) + assertTrue(state.satisfied) + } + + fun `release key`() { + val state = KeyBindingFilterState(false) + KeyActionFilter.Sticky.check( + state, setOf(KeyCodes.KEY_0), input(), name, + KeyBindingState(KeyBinding(mapOf(KeyActions.STICKY to setOf(KeyCodes.KEY_0)))), + KeyCodes.KEY_0, + pressed = false, + 0L, + ) + + assertTrue(state.skip) + } + + fun `wrong key`() { + val state = KeyBindingFilterState(false) + KeyActionFilter.Sticky.check( + state, setOf(KeyCodes.KEY_1), input(), name, + KeyBindingState(KeyBinding(mapOf(KeyActions.STICKY to setOf(KeyCodes.KEY_1)))), + KeyCodes.KEY_0, + pressed = true, + 0L, + ) + + assertTrue(state.skip) + } + + fun `unpress`() { + val state = KeyBindingFilterState(true) + val input = input() + val binding = KeyBinding(mapOf(KeyActions.STICKY to setOf(KeyCodes.KEY_0))) + + val pressed = bindingsPressed[input.bindings].unsafeCast>() + pressed += name + + KeyActionFilter.Sticky.check( + state, setOf(KeyCodes.KEY_0), input, name, + KeyBindingState(binding), + KeyCodes.KEY_0, + pressed = true, + 0L, + ) + + assertFalse(state.result) + assertFalse(state.skip) + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/view/ViewManager.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/view/ViewManager.kt index 855be1149..299a020d6 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/camera/view/ViewManager.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/camera/view/ViewManager.kt @@ -36,7 +36,7 @@ class ViewManager(private val camera: Camera) { fun init() { - camera.context.input.registerKeyCallback( + camera.context.input.bindings.register( "minosoft:camera_debug_view".toResourceLocation(), KeyBinding( KeyActions.MODIFIER to setOf(KeyCodes.KEY_F4), @@ -48,7 +48,7 @@ class ViewManager(private val camera: Camera) { camera.context.connection.util.sendDebugMessage("Camera debug view: ${it.format()}") } - camera.context.input.registerKeyCallback( + camera.context.input.bindings.register( "minosoft:camera_third_person".toResourceLocation(), KeyBinding( KeyActions.STICKY to setOf(KeyCodes.KEY_F5), diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/entity/EntityRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/entity/EntityRenderer.kt index bfdc480c5..0fb45066e 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/entity/EntityRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/entity/EntityRenderer.kt @@ -78,12 +78,12 @@ class EntityRenderer( profile.hitbox::enabled.observe(this) { this.hitboxes = it } context.camera.offset::offset.observe(this) { reset = true } - context.input.registerKeyCallback( + context.input.bindings.register( HITBOX_TOGGLE_KEY_COMBINATION, KeyBinding( KeyActions.MODIFIER to setOf(KeyCodes.KEY_F3), KeyActions.STICKY to setOf(KeyCodes.KEY_B), - ), defaultPressed = profile.hitbox.enabled + ), pressed = profile.hitbox.enabled ) { profile.hitbox.enabled = it connection.util.sendDebugMessage("Entity hit boxes: ${it.format()}") diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/framebuffer/world/fun/FunEffectManager.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/framebuffer/world/fun/FunEffectManager.kt index 4475eaaf0..dfe3f2deb 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/framebuffer/world/fun/FunEffectManager.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/framebuffer/world/fun/FunEffectManager.kt @@ -33,7 +33,7 @@ class FunEffectManager( init { - context.input.registerKeyCallback( + context.input.bindings.register( "minosoft:switch_fun_settings".toResourceLocation(), KeyBinding( KeyActions.MODIFIER to setOf(KeyCodes.KEY_F4), diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/GUIRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/GUIRenderer.kt index 28ae05c01..3e17140e7 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/GUIRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/GUIRenderer.kt @@ -14,7 +14,6 @@ package de.bixilon.minosoft.gui.rendering.gui import de.bixilon.kotlinglm.vec2.Vec2 -import de.bixilon.kotlinglm.vec2.Vec2d import de.bixilon.kutil.latch.AbstractLatch import de.bixilon.kutil.observer.DataObserver.Companion.observe import de.bixilon.kutil.observer.DataObserver.Companion.observed @@ -120,11 +119,11 @@ class GUIRenderer( return popper.onCharPress(char) || dragged.onCharPress(char) || gui.onCharPress(char) } - override fun onKey(type: KeyChangeTypes, key: KeyCodes): Boolean { - return popper.onKey(type, key) || dragged.onKey(type, key) || gui.onKey(type, key) + override fun onKey(code: KeyCodes, change: KeyChangeTypes): Boolean { + return popper.onKey(code, change) || dragged.onKey(code, change) || gui.onKey(code, change) } - override fun onScroll(scrollOffset: Vec2d): Boolean { + override fun onScroll(scrollOffset: Vec2): Boolean { return popper.onScroll(scrollOffset) || dragged.onScroll(scrollOffset) || gui.onScroll(scrollOffset) } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/text/TextFlowElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/text/TextFlowElement.kt index 2e61a3015..4514b7e4e 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/text/TextFlowElement.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/text/TextFlowElement.kt @@ -1,6 +1,6 @@ /* * Minosoft - * Copyright (C) 2020-2022 Moritz Zwerger + * Copyright (C) 2020-2023 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. * @@ -14,7 +14,6 @@ package de.bixilon.minosoft.gui.rendering.gui.elements.text import de.bixilon.kotlinglm.vec2.Vec2 -import de.bixilon.kotlinglm.vec2.Vec2d import de.bixilon.kutil.collections.CollectionUtil.synchronizedListOf import de.bixilon.kutil.collections.CollectionUtil.toSynchronizedList import de.bixilon.kutil.time.TimeUtil.millis @@ -93,7 +92,7 @@ open class TextFlowElement( } } - override fun onScroll(position: Vec2, scrollOffset: Vec2d): Boolean { + override fun onScroll(position: Vec2, scrollOffset: Vec2): Boolean { this.scrollOffset += scrollOffset.y.toInt() return true } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/AbstractLayout.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/AbstractLayout.kt index 323d93dc6..80938442e 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/AbstractLayout.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/AbstractLayout.kt @@ -1,6 +1,6 @@ /* * Minosoft - * Copyright (C) 2020-2022 Moritz Zwerger + * Copyright (C) 2020-2023 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. * @@ -14,7 +14,6 @@ package de.bixilon.minosoft.gui.rendering.gui.gui import de.bixilon.kotlinglm.vec2.Vec2 -import de.bixilon.kotlinglm.vec2.Vec2d import de.bixilon.minosoft.config.key.KeyCodes import de.bixilon.minosoft.gui.rendering.gui.elements.Element import de.bixilon.minosoft.gui.rendering.gui.elements.HorizontalAlignments @@ -72,7 +71,7 @@ interface AbstractLayout : InputElement, DragTarget { return activeElement?.onCharPress(char) ?: false } - override fun onScroll(position: Vec2, scrollOffset: Vec2d): Boolean { + override fun onScroll(position: Vec2, scrollOffset: Vec2): Boolean { val (element, offset) = getAt(position) ?: return false return element.onScroll(offset, scrollOffset) } @@ -104,7 +103,7 @@ interface AbstractLayout : InputElement, DragTarget { return activeDragElement?.onDragLeave(draggable) } - override fun onDragScroll(position: Vec2, scrollOffset: Vec2d, draggable: Dragged): Element? { + override fun onDragScroll(position: Vec2, scrollOffset: Vec2, draggable: Dragged): Element? { val (element, offset) = getAt(position) ?: return null return element.onDragScroll(offset, scrollOffset, draggable) } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/GUIManager.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/GUIManager.kt index acfbaaf8d..36ac262ae 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/GUIManager.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/GUIManager.kt @@ -14,7 +14,6 @@ package de.bixilon.minosoft.gui.rendering.gui.gui import de.bixilon.kotlinglm.vec2.Vec2 -import de.bixilon.kotlinglm.vec2.Vec2d import de.bixilon.kutil.cast.CastUtil.unsafeCast import de.bixilon.kutil.concurrent.lock.simple.SimpleLock import de.bixilon.kutil.concurrent.pool.DefaultThreadPool @@ -71,7 +70,7 @@ class GUIManager( } override fun postInit() { - context.input.registerKeyCallback( + context.input.bindings.register( "minosoft:back".toResourceLocation(), KeyBinding( KeyActions.RELEASE to setOf(KeyCodes.KEY_ESCAPE), @@ -210,11 +209,11 @@ class GUIManager( return runForEach { it.onMouseMove(position) } } - override fun onKey(type: KeyChangeTypes, key: KeyCodes): Boolean { - return runForEach { it.onKey(type, key) } + override fun onKey(code: KeyCodes, change: KeyChangeTypes): Boolean { + return runForEach { it.onKey(code, change) } } - override fun onScroll(scrollOffset: Vec2d): Boolean { + override fun onScroll(scrollOffset: Vec2): Boolean { return runForEach { it.onScroll(scrollOffset) } } @@ -240,7 +239,7 @@ class GUIManager( return runForEachDrag { it.onDragKey(type, key, dragged) } } - override fun onDragScroll(scrollOffset: Vec2d, dragged: Dragged): Element? { + override fun onDragScroll(scrollOffset: Vec2, dragged: Dragged): Element? { return runForEachDrag { it.onDragScroll(scrollOffset, dragged) } } @@ -266,7 +265,7 @@ class GUIManager( private fun _push(element: GUIElement) { if (elementOrder.isEmpty()) { - context.input.inputHandler = guiRenderer + context.input.handler.handler = guiRenderer } orderLock.acquire() val copy = elementOrder.toList() @@ -313,7 +312,7 @@ class GUIManager( orderLock.acquire() if (elementOrder.isEmpty()) { - context.input.inputHandler = null + context.input.handler.handler = null guiRenderer.popper.clear() guiRenderer.dragged.element = null } @@ -337,7 +336,7 @@ class GUIManager( toPop.onClose() orderLock.acquire() if (elementOrder.isEmpty()) { - context.input.inputHandler = null + context.input.handler.handler = null guiRenderer.popper.clear() guiRenderer.dragged.element = null orderLock.release() @@ -365,7 +364,7 @@ class GUIManager( orderLock.unlock() guiRenderer.popper.clear() guiRenderer.dragged.element = null - context.input.inputHandler = null + context.input.handler.handler = null } operator fun get(builder: GUIBuilder): T { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/GUIMeshElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/GUIMeshElement.kt index 1a6cb5609..23c8e8095 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/GUIMeshElement.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/GUIMeshElement.kt @@ -1,6 +1,6 @@ /* * Minosoft - * Copyright (C) 2020-2022 Moritz Zwerger + * Copyright (C) 2020-2023 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. * @@ -14,7 +14,6 @@ package de.bixilon.minosoft.gui.rendering.gui.gui import de.bixilon.kotlinglm.vec2.Vec2 -import de.bixilon.kotlinglm.vec2.Vec2d import de.bixilon.kutil.time.TimeUtil.millis import de.bixilon.minosoft.config.key.KeyCodes import de.bixilon.minosoft.gui.rendering.RenderContext @@ -147,16 +146,16 @@ open class GUIMeshElement( return element.onMouseMove(position, position) } - override fun onKey(type: KeyChangeTypes, key: KeyCodes): Boolean { - val mouseButton = MouseButtons[key] ?: return element.onKey(key, type) + override fun onKey(code: KeyCodes, change: KeyChangeTypes): Boolean { + val mouseButton = MouseButtons[code] ?: return element.onKey(code, change) val position = Vec2(lastPosition ?: return false) - val mouseAction = MouseActions[type] ?: return false + val mouseAction = MouseActions[change] ?: return false return element.onMouseAction(position, mouseButton, mouseAction, clickCounter.getClicks(mouseButton, mouseAction, position, millis())) } - override fun onScroll(scrollOffset: Vec2d): Boolean { + override fun onScroll(scrollOffset: Vec2): Boolean { val position = Vec2(lastPosition ?: return false) return element.onScroll(position, scrollOffset) } @@ -179,7 +178,7 @@ open class GUIMeshElement( return element.onDragMouseAction(position, mouseButton, mouseAction, clickCounter.getClicks(mouseButton, mouseAction, position, millis()), dragged) } - override fun onDragScroll(scrollOffset: Vec2d, dragged: Dragged): Element? { + override fun onDragScroll(scrollOffset: Vec2, dragged: Dragged): Element? { return element.onDragScroll(Vec2(lastDragPosition ?: return null), scrollOffset, dragged) } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/dragged/Dragged.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/dragged/Dragged.kt index 7571f4918..c849adf48 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/dragged/Dragged.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/dragged/Dragged.kt @@ -1,6 +1,6 @@ /* * Minosoft - * Copyright (C) 2020-2022 Moritz Zwerger + * Copyright (C) 2020-2023 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. * @@ -14,7 +14,6 @@ package de.bixilon.minosoft.gui.rendering.gui.gui.dragged import de.bixilon.kotlinglm.vec2.Vec2 -import de.bixilon.kotlinglm.vec2.Vec2d import de.bixilon.minosoft.config.key.KeyCodes import de.bixilon.minosoft.gui.rendering.gui.GUIRenderer import de.bixilon.minosoft.gui.rendering.gui.elements.Element @@ -31,7 +30,7 @@ abstract class Dragged(guiRenderer: GUIRenderer) : Element(guiRenderer) { open fun onDragMove(position: Vec2, target: Element?) = Unit open fun onDragEnd(position: Vec2, target: Element?) = Unit - open fun onDragScroll(position: Vec2, scrollOffset: Vec2d, target: Element?) = Unit + open fun onDragScroll(position: Vec2, scrollOffset: Vec2, target: Element?) = Unit open fun onDragMouseAction(position: Vec2, button: MouseButtons, action: MouseActions, count: Int, target: Element?) = Unit open fun onDragKey(key: KeyCodes, type: KeyChangeTypes, target: Element?) = Unit diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/dragged/DraggedManager.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/dragged/DraggedManager.kt index ec1bbbe50..3faff033e 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/dragged/DraggedManager.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/dragged/DraggedManager.kt @@ -1,6 +1,6 @@ /* * Minosoft - * Copyright (C) 2020-2022 Moritz Zwerger + * Copyright (C) 2020-2023 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. * @@ -14,7 +14,6 @@ package de.bixilon.minosoft.gui.rendering.gui.gui.dragged import de.bixilon.kotlinglm.vec2.Vec2 -import de.bixilon.kotlinglm.vec2.Vec2d import de.bixilon.kutil.time.TimeUtil.millis import de.bixilon.minosoft.config.key.KeyCodes import de.bixilon.minosoft.gui.rendering.gui.GUIRenderer @@ -120,22 +119,22 @@ class DraggedManager( return true } - override fun onKey(type: KeyChangeTypes, key: KeyCodes): Boolean { + override fun onKey(code: KeyCodes, change: KeyChangeTypes): Boolean { val element = element ?: return false - val target = guiRenderer.gui.onDragKey(type, key, element.element) - val mouseButton = MouseButtons[key] + val target = guiRenderer.gui.onDragKey(change, code, element.element) + val mouseButton = MouseButtons[code] if (mouseButton == null) { - element.element.onDragKey(key, type, target) + element.element.onDragKey(code, change, target) return true } - val mouseAction = MouseActions[type] ?: return false + val mouseAction = MouseActions[change] ?: return false element.element.onDragMouseAction(guiRenderer.currentMousePosition, mouseButton, mouseAction, clickCounter.getClicks(mouseButton, mouseAction, guiRenderer.currentMousePosition, millis()), target) return true } - override fun onScroll(scrollOffset: Vec2d): Boolean { + override fun onScroll(scrollOffset: Vec2): Boolean { val element = element ?: return false val target = guiRenderer.gui.onDragScroll(scrollOffset, element.element) element.element.onDragScroll(guiRenderer.currentMousePosition, scrollOffset, target) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/popper/PopperManager.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/popper/PopperManager.kt index ea44eeb70..4be6a46ef 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/popper/PopperManager.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/popper/PopperManager.kt @@ -1,6 +1,6 @@ /* * Minosoft - * Copyright (C) 2020-2022 Moritz Zwerger + * Copyright (C) 2020-2023 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. * @@ -14,7 +14,6 @@ package de.bixilon.minosoft.gui.rendering.gui.gui.popper import de.bixilon.kotlinglm.vec2.Vec2 -import de.bixilon.kotlinglm.vec2.Vec2d import de.bixilon.kutil.concurrent.pool.DefaultThreadPool import de.bixilon.kutil.latch.SimpleLatch import de.bixilon.kutil.time.TimeUtil.millis @@ -111,19 +110,19 @@ class PopperManager( return false } - override fun onKey(type: KeyChangeTypes, key: KeyCodes): Boolean { + override fun onKey(code: KeyCodes, change: KeyChangeTypes): Boolean { for ((index, element) in poppers.toList().withIndex()) { if (index != 0 && !element.activeWhenHidden) { continue } - if (element.onKey(type, key)) { + if (element.onKey(code, change)) { return true } } return false } - override fun onScroll(scrollOffset: Vec2d): Boolean { + override fun onScroll(scrollOffset: Vec2): Boolean { for ((index, element) in poppers.toList().withIndex()) { if (index != 0 && !element.activeWhenHidden) { continue diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/screen/container/ContainerGUIManager.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/screen/container/ContainerGUIManager.kt index eb24de424..63e5f3d77 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/screen/container/ContainerGUIManager.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/screen/container/ContainerGUIManager.kt @@ -28,7 +28,7 @@ import de.bixilon.minosoft.util.KUtil.toResourceLocation object ContainerGUIManager { private fun registerLocalContainerEvent(guiRenderer: GUIRenderer) { - guiRenderer.context.input.registerKeyCallback("minosoft:local_inventory".toResourceLocation(), KeyBinding( + guiRenderer.context.input.bindings.register("minosoft:local_inventory".toResourceLocation(), KeyBinding( KeyActions.PRESS to setOf(KeyCodes.KEY_E), )) { guiRenderer.gui.open(LocalInventoryScreen) } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/screen/menu/Menu.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/screen/menu/Menu.kt index 62d97bdfb..943dc9fc3 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/screen/menu/Menu.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/screen/menu/Menu.kt @@ -1,6 +1,6 @@ /* * Minosoft - * Copyright (C) 2020-2022 Moritz Zwerger + * Copyright (C) 2020-2023 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. * @@ -14,7 +14,6 @@ package de.bixilon.minosoft.gui.rendering.gui.gui.screen.menu import de.bixilon.kotlinglm.vec2.Vec2 -import de.bixilon.kotlinglm.vec2.Vec2d import de.bixilon.kotlinglm.vec2.Vec2i import de.bixilon.minosoft.config.key.KeyCodes import de.bixilon.minosoft.gui.rendering.gui.GUIRenderer @@ -191,7 +190,7 @@ abstract class Menu( return true } - override fun onScroll(position: Vec2, scrollOffset: Vec2d): Boolean { + override fun onScroll(position: Vec2, scrollOffset: Vec2): Boolean { val (element, delta) = getAt(position) ?: return true element.onScroll(delta, scrollOffset) return true diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/HUDManager.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/HUDManager.kt index 273103639..9fa6ab23b 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/HUDManager.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/HUDManager.kt @@ -61,7 +61,7 @@ class HUDManager( val toggleKeyBinding = hudBuilder.ENABLE_KEY_BINDING ?: return val toggleKeyBindingName = hudBuilder.ENABLE_KEY_BINDING_NAME ?: return - context.input.registerKeyCallback(toggleKeyBindingName, toggleKeyBinding, defaultPressed = hudBuilder.DEFAULT_ENABLED) { hudElement.enabled = it } + context.input.bindings.register(toggleKeyBindingName, toggleKeyBinding, pressed = hudBuilder.DEFAULT_ENABLED) { hudElement.enabled = it } } private fun registerDefaultElements() { @@ -93,10 +93,10 @@ class HUDManager( element.init() } - context.input.registerKeyCallback( + context.input.bindings.register( "minosoft:enable_hud".toResourceLocation(), KeyBinding( KeyActions.STICKY to setOf(KeyCodes.KEY_F1), - ), defaultPressed = enabled + ), pressed = enabled ) { enabled = it } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/chat/AbstractChatElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/chat/AbstractChatElement.kt index 76f75eadf..007d68c1a 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/chat/AbstractChatElement.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/chat/AbstractChatElement.kt @@ -1,6 +1,6 @@ /* * Minosoft - * Copyright (C) 2020-2022 Moritz Zwerger + * Copyright (C) 2020-2023 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. * @@ -14,7 +14,6 @@ package de.bixilon.minosoft.gui.rendering.gui.hud.elements.chat import de.bixilon.kotlinglm.vec2.Vec2 -import de.bixilon.kotlinglm.vec2.Vec2d import de.bixilon.kotlinglm.vec2.Vec2i import de.bixilon.minosoft.gui.rendering.gui.GUIRenderer import de.bixilon.minosoft.gui.rendering.gui.elements.Element @@ -36,7 +35,7 @@ abstract class AbstractChatElement(guiRenderer: GUIRenderer) : Element(guiRender messages.render(offset + Vec2i(ChatElement.CHAT_INPUT_MARGIN, 0), consumer, options) } - override fun onScroll(position: Vec2, scrollOffset: Vec2d): Boolean { + override fun onScroll(position: Vec2, scrollOffset: Vec2): Boolean { val size = messages.size if (position.y > size.y || position.x > messages.size.x) { return false diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/chat/ChatElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/chat/ChatElement.kt index 06b749c13..4bcb5844e 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/chat/ChatElement.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/chat/ChatElement.kt @@ -94,13 +94,13 @@ class ChatElement(guiRenderer: GUIRenderer) : AbstractChatElement(guiRenderer), messages += it.message.text } - context.input.registerKeyCallback( + context.input.bindings.register( "minosoft:open_chat".toResourceLocation(), KeyBinding( KeyActions.PRESS to setOf(KeyCodes.KEY_T), ) ) { guiRenderer.gui.open(ChatElement) } - context.input.registerKeyCallback( + context.input.bindings.register( minosoft("open_command_chat"), KeyBinding(KeyActions.PRESS to setOf(KeyCodes.KEY_SLASH)) ) { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/input/DragTarget.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/input/DragTarget.kt index 617d750e8..dd2dae984 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/input/DragTarget.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/input/DragTarget.kt @@ -1,6 +1,6 @@ /* * Minosoft - * Copyright (C) 2020-2022 Moritz Zwerger + * Copyright (C) 2020-2023 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. * @@ -14,7 +14,6 @@ package de.bixilon.minosoft.gui.rendering.gui.input import de.bixilon.kotlinglm.vec2.Vec2 -import de.bixilon.kotlinglm.vec2.Vec2d import de.bixilon.kutil.cast.CastUtil.nullCast import de.bixilon.minosoft.config.key.KeyCodes import de.bixilon.minosoft.gui.rendering.gui.elements.Element @@ -29,7 +28,7 @@ interface DragTarget { fun onDragMove(position: Vec2, absolute: Vec2, draggable: Dragged): Element? = this.nullCast() fun onDragLeave(draggable: Dragged): Element? = this.nullCast() - fun onDragScroll(position: Vec2, scrollOffset: Vec2d, draggable: Dragged): Element? = this.nullCast() + fun onDragScroll(position: Vec2, scrollOffset: Vec2, draggable: Dragged): Element? = this.nullCast() fun onDragMouseAction(position: Vec2, button: MouseButtons, action: MouseActions, count: Int, draggable: Dragged): Element? = this.nullCast() fun onDragKey(key: KeyCodes, type: KeyChangeTypes, draggable: Dragged): Element? = this.nullCast() diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/input/DraggableHandler.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/input/DraggableHandler.kt index 35872bdc7..0191e9b72 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/input/DraggableHandler.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/input/DraggableHandler.kt @@ -1,6 +1,6 @@ /* * Minosoft - * Copyright (C) 2020-2022 Moritz Zwerger + * Copyright (C) 2020-2023 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. * @@ -14,7 +14,6 @@ package de.bixilon.minosoft.gui.rendering.gui.input import de.bixilon.kotlinglm.vec2.Vec2 -import de.bixilon.kotlinglm.vec2.Vec2d import de.bixilon.minosoft.config.key.KeyCodes import de.bixilon.minosoft.gui.rendering.gui.elements.Element import de.bixilon.minosoft.gui.rendering.gui.gui.dragged.Dragged @@ -24,6 +23,6 @@ interface DraggableHandler { fun onDragMove(position: Vec2, dragged: Dragged): Element? = null fun onDragKey(type: KeyChangeTypes, key: KeyCodes, dragged: Dragged): Element? = null - fun onDragScroll(scrollOffset: Vec2d, dragged: Dragged): Element? = null + fun onDragScroll(scrollOffset: Vec2, dragged: Dragged): Element? = null fun onDragChar(char: Int, dragged: Dragged): Element? = null } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/input/InputElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/input/InputElement.kt index 789c31d0c..a820ada53 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/input/InputElement.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/input/InputElement.kt @@ -1,6 +1,6 @@ /* * Minosoft - * Copyright (C) 2020-2022 Moritz Zwerger + * Copyright (C) 2020-2023 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. * @@ -14,7 +14,6 @@ package de.bixilon.minosoft.gui.rendering.gui.input import de.bixilon.kotlinglm.vec2.Vec2 -import de.bixilon.kotlinglm.vec2.Vec2d import de.bixilon.minosoft.config.key.KeyCodes import de.bixilon.minosoft.gui.rendering.gui.input.mouse.MouseActions import de.bixilon.minosoft.gui.rendering.gui.input.mouse.MouseButtons @@ -23,7 +22,7 @@ import de.bixilon.minosoft.gui.rendering.system.window.KeyChangeTypes interface InputElement : MouseInputElement { fun onMouseAction(position: Vec2, button: MouseButtons, action: MouseActions, count: Int) = false - fun onScroll(position: Vec2, scrollOffset: Vec2d) = false + fun onScroll(position: Vec2, scrollOffset: Vec2) = false fun onKey(key: KeyCodes, type: KeyChangeTypes) = false fun onCharPress(char: Int) = false diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/input/ModifierKeys.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/input/ModifierKeys.kt index b239f7d48..e56299636 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/input/ModifierKeys.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/input/ModifierKeys.kt @@ -1,6 +1,6 @@ /* * Minosoft - * Copyright (C) 2022 Moritz Zwerger + * Copyright (C) 2020-2023 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. * @@ -13,10 +13,12 @@ package de.bixilon.minosoft.gui.rendering.gui.input -enum class ModifierKeys { - CONTROL, - ALT, - SHIFT, - SUPER, +import de.bixilon.minosoft.config.key.KeyCodes + +enum class ModifierKeys(vararg val codes: KeyCodes) { + CONTROL(KeyCodes.KEY_LEFT_CONTROL, KeyCodes.KEY_RIGHT_CONTROL), + ALT(KeyCodes.KEY_LEFT_ALT, KeyCodes.KEY_RIGHT_ALT), + SHIFT(KeyCodes.KEY_LEFT_SHIFT, KeyCodes.KEY_RIGHT_SHIFT), + SUPER(KeyCodes.KEY_LEFT_SUPER, KeyCodes.KEY_RIGHT_SUPER), ; } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/input/CameraInput.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/input/CameraInput.kt index 4106e569d..a995f568b 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/input/CameraInput.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/input/CameraInput.kt @@ -37,7 +37,7 @@ class CameraInput( private var changeFly = false private fun registerKeyBindings() { - context.input.registerCheckCallback( + context.input.bindings.registerCheck( MOVE_SPRINT_KEYBINDING to KeyBinding( KeyActions.CHANGE to setOf(KeyCodes.KEY_LEFT_CONTROL), ), @@ -74,7 +74,7 @@ class CameraInput( ) - context.input.registerKeyCallback( + context.input.bindings.register( ZOOM_KEYBINDING, KeyBinding( KeyActions.CHANGE to setOf(KeyCodes.KEY_C), ) @@ -87,19 +87,19 @@ class CameraInput( fun updateInput(delta: Double) { val input = PlayerMovementInput( - forward = context.input.isKeyBindingDown(MOVE_FORWARDS_KEYBINDING), - backward = context.input.isKeyBindingDown(MOVE_BACKWARDS_KEYBINDING), - left = context.input.isKeyBindingDown(MOVE_LEFT_KEYBINDING), - right = context.input.isKeyBindingDown(MOVE_RIGHT_KEYBINDING), - jump = context.input.isKeyBindingDown(JUMP_KEYBINDING), - sneak = context.input.isKeyBindingDown(SNEAK_KEYBINDING), - sprint = context.input.isKeyBindingDown(MOVE_SPRINT_KEYBINDING), - flyDown = context.input.isKeyBindingDown(FLY_DOWN_KEYBINDING), - flyUp = context.input.isKeyBindingDown(FLY_UP_KEYBINDING), + forward = MOVE_FORWARDS_KEYBINDING in context.input.bindings, + backward = MOVE_BACKWARDS_KEYBINDING in context.input.bindings, + left = MOVE_LEFT_KEYBINDING in context.input.bindings, + right = MOVE_RIGHT_KEYBINDING in context.input.bindings, + jump = JUMP_KEYBINDING in context.input.bindings, + sneak = SNEAK_KEYBINDING in context.input.bindings, + sprint = MOVE_SPRINT_KEYBINDING in context.input.bindings, + flyDown = FLY_DOWN_KEYBINDING in context.input.bindings, + flyUp = FLY_UP_KEYBINDING in context.input.bindings, ) - val changeFly = context.input.isKeyBindingDown(CHANGE_FLY_KEYBINDING) - val startElytraFly = context.input.isKeyBindingDown(START_ELYTRA_FLY_KEYBINDING) + val changeFly = CHANGE_FLY_KEYBINDING in context.input.bindings + val startElytraFly = START_ELYTRA_FLY_KEYBINDING in context.input.bindings val inputActions = MovementInputActions( toggleFly = changeFly != this.changeFly, startElytraFly = startElytraFly, diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/input/InputHandler.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/input/InputHandler.kt index 7a51fb970..1496132b2 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/input/InputHandler.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/input/InputHandler.kt @@ -1,6 +1,6 @@ /* * Minosoft - * Copyright (C) 2020-2022 Moritz Zwerger + * Copyright (C) 2020-2023 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. * @@ -14,14 +14,13 @@ package de.bixilon.minosoft.gui.rendering.input import de.bixilon.kotlinglm.vec2.Vec2 -import de.bixilon.kotlinglm.vec2.Vec2d import de.bixilon.minosoft.config.key.KeyCodes import de.bixilon.minosoft.gui.rendering.system.window.KeyChangeTypes interface InputHandler { fun onMouseMove(position: Vec2) = false - fun onKey(type: KeyChangeTypes, key: KeyCodes) = false - fun onScroll(scrollOffset: Vec2d) = false + fun onKey(code: KeyCodes, change: KeyChangeTypes) = false + fun onScroll(scrollOffset: Vec2) = false fun onCharPress(char: Int) = false } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/input/interaction/InteractionManagerKeys.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/input/interaction/InteractionManagerKeys.kt index 11f8976c7..5a55ad2ea 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/input/interaction/InteractionManagerKeys.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/input/interaction/InteractionManagerKeys.kt @@ -17,6 +17,7 @@ import de.bixilon.minosoft.config.key.KeyActions import de.bixilon.minosoft.config.key.KeyBinding import de.bixilon.minosoft.config.key.KeyCodes import de.bixilon.minosoft.data.container.types.PlayerInventory +import de.bixilon.minosoft.data.registries.identified.Namespaces.minosoft import de.bixilon.minosoft.gui.rendering.events.input.MouseScrollEvent import de.bixilon.minosoft.gui.rendering.input.key.manager.InputManager import de.bixilon.minosoft.input.interaction.InteractionManager @@ -29,19 +30,19 @@ class InteractionManagerKeys( ) { private fun registerAttack() { - input.registerKeyCallback(ATTACK, KeyBinding( + input.bindings.register(ATTACK, KeyBinding( KeyActions.CHANGE to setOf(KeyCodes.MOUSE_BUTTON_LEFT), )) { interactions.tryAttack(it) } } private fun registerInteraction() { - input.registerKeyCallback(USE_ITEM, KeyBinding( + input.bindings.register(USE_ITEM, KeyBinding( KeyActions.CHANGE to setOf(KeyCodes.MOUSE_BUTTON_RIGHT), )) { interactions.use.change(it) } } private fun registerPick() { - input.registerKeyCallback("minosoft:pick_item".toResourceLocation(), KeyBinding( + input.bindings.register(PICK, KeyBinding( KeyActions.PRESS to setOf(KeyCodes.MOUSE_BUTTON_MIDDLE), ) ) { interactions.pick.pickItem(false) } // ToDo: Combination for not copying nbt @@ -50,25 +51,25 @@ class InteractionManagerKeys( private fun registerDrop() { // ToDo: This creates a weird condition, because we first drop the stack and then the single item // ToDo: Does this swing the arm? - input.registerKeyCallback(DROP_ITEM_STACK, KeyBinding( + input.bindings.register(DROP_ITEM_STACK, KeyBinding( KeyActions.PRESS to setOf(KeyCodes.KEY_Q), KeyActions.MODIFIER to setOf(KeyCodes.KEY_LEFT_CONTROL) )) { interactions.drop.dropItem(true) } - input.registerKeyCallback(DROP_ITEM, KeyBinding( + input.bindings.register(DROP_ITEM, KeyBinding( KeyActions.PRESS to setOf(KeyCodes.KEY_Q), )) { interactions.drop.dropItem(false) } } private fun registerSpectate() { - input.registerKeyCallback(STOP_SPECTATING, KeyBinding( + input.bindings.register(STOP_SPECTATING, KeyBinding( KeyActions.PRESS to setOf(KeyCodes.KEY_LEFT_SHIFT), )) { interactions.spectate.spectate(null) } } private fun registerHotbar() { for (i in 1..PlayerInventory.HOTBAR_SLOTS) { - input.registerKeyCallback("minosoft:hotbar_slot_$i".toResourceLocation(), KeyBinding( + input.bindings.register("minosoft:hotbar_slot_$i".toResourceLocation(), KeyBinding( KeyActions.PRESS to setOf(KeyCodes.KEY_CODE_MAP["$i"]!!), )) { interactions.hotbar.selectSlot(i - 1) } } @@ -98,7 +99,7 @@ class InteractionManagerKeys( } - input.registerKeyCallback("minosoft:swap_items".toResourceLocation(), KeyBinding( + input.bindings.register(SWAP, KeyBinding( KeyActions.PRESS to setOf(KeyCodes.KEY_F), )) { interactions.hotbar.trySwap() } } @@ -120,6 +121,8 @@ class InteractionManagerKeys( companion object { private val ATTACK = "minosoft:attack".toResourceLocation() private val USE_ITEM = "minosoft:use_item".toResourceLocation() + private val SWAP = minosoft("swap_items") + private val PICK = minosoft("pick_item") private val DROP_ITEM = "minosoft:drop_item".toResourceLocation() private val DROP_ITEM_STACK = "minosoft:drop_item_stack".toResourceLocation() diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/input/key/DebugKeyBindings.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/input/key/DebugKeyBindings.kt index fac6f21ef..cdea77545 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/input/key/DebugKeyBindings.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/input/key/DebugKeyBindings.kt @@ -20,9 +20,10 @@ import de.bixilon.minosoft.config.key.KeyBinding import de.bixilon.minosoft.config.key.KeyCodes import de.bixilon.minosoft.data.registries.identified.Namespaces.minosoft import de.bixilon.minosoft.gui.rendering.RenderContext -import de.bixilon.minosoft.gui.rendering.input.key.manager.InputManager +import de.bixilon.minosoft.gui.rendering.input.key.manager.binding.BindingsManager import de.bixilon.minosoft.gui.rendering.system.base.PolygonModes import de.bixilon.minosoft.gui.rendering.system.window.CursorModes +import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection import de.bixilon.minosoft.util.KUtil.format object DebugKeyBindings { @@ -33,14 +34,14 @@ object DebugKeyBindings { val PAUSE_OUTGOING = minosoft("network_pause_outgoing") fun register(context: RenderContext) { - val manager = context.input + val bindings = context.input.bindings - manager.registerNetwork() - manager.registerRendering() + bindings.registerNetwork(context.connection) + bindings.registerRendering(context) } - private fun InputManager.registerNetwork() { - registerKeyCallback(PAUSE_INCOMING, KeyBinding( + private fun BindingsManager.registerNetwork(connection: PlayConnection) { + register(PAUSE_INCOMING, KeyBinding( KeyActions.MODIFIER to setOf(KeyCodes.KEY_F4), KeyActions.STICKY to setOf(KeyCodes.KEY_I), ignoreConsumer = true, @@ -49,7 +50,7 @@ object DebugKeyBindings { connection.network.pauseReceiving(it) } - registerKeyCallback(PAUSE_OUTGOING, KeyBinding( + register(PAUSE_OUTGOING, KeyBinding( KeyActions.MODIFIER to setOf(KeyCodes.KEY_F4), KeyActions.STICKY to setOf(KeyCodes.KEY_O), ignoreConsumer = true, @@ -59,8 +60,10 @@ object DebugKeyBindings { } } - private fun InputManager.registerRendering() { - registerKeyCallback(DEBUG_POLYGON, KeyBinding( + private fun BindingsManager.registerRendering(context: RenderContext) { + val connection = context.connection + + register(DEBUG_POLYGON, KeyBinding( KeyActions.MODIFIER to setOf(KeyCodes.KEY_F4), KeyActions.STICKY to setOf(KeyCodes.KEY_P), )) { @@ -70,11 +73,11 @@ object DebugKeyBindings { } - registerKeyCallback(CURSOR_MODE, KeyBinding( + register(CURSOR_MODE, KeyBinding( KeyActions.MODIFIER to setOf(KeyCodes.KEY_F4), KeyActions.PRESS to setOf(KeyCodes.KEY_M), ignoreConsumer = true, - ), defaultPressed = StaticConfiguration.DEBUG_MODE) { + ), pressed = StaticConfiguration.DEBUG_MODE) { val next = when (context.window.cursorMode) { CursorModes.DISABLED -> CursorModes.NORMAL CursorModes.NORMAL -> CursorModes.DISABLED diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/input/key/DefaultKeyBindings.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/input/key/DefaultKeyBindings.kt index 03ea74f14..e9a1a23d2 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/input/key/DefaultKeyBindings.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/input/key/DefaultKeyBindings.kt @@ -25,17 +25,17 @@ object DefaultKeyBindings { val FULLSCREEN = minosoft("toggle_fullscreen") fun register(context: RenderContext) { - val inputHandler = context.input + val bindings = context.input.bindings val window = context.window val connection = context.connection - inputHandler.registerKeyCallback(SCREENSHOT, KeyBinding( + bindings.register(SCREENSHOT, KeyBinding( KeyActions.PRESS to setOf(KeyCodes.KEY_F2), ignoreConsumer = true, )) { context.screenshotTaker.takeScreenshot() } - inputHandler.registerKeyCallback(FULLSCREEN, KeyBinding( + bindings.register(FULLSCREEN, KeyBinding( KeyActions.PRESS to setOf(KeyCodes.KEY_F11), ignoreConsumer = true, )) { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/input/key/manager/InputHandlerManager.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/input/key/manager/InputHandlerManager.kt new file mode 100644 index 000000000..2a58d3536 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/input/key/manager/InputHandlerManager.kt @@ -0,0 +1,89 @@ +/* + * Minosoft + * Copyright (C) 2020-2023 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.input.key.manager + +import de.bixilon.kotlinglm.vec2.Vec2 +import de.bixilon.minosoft.config.key.KeyCodes +import de.bixilon.minosoft.gui.rendering.input.InputHandler +import de.bixilon.minosoft.gui.rendering.system.window.CursorModes +import de.bixilon.minosoft.gui.rendering.system.window.KeyChangeTypes + +class InputHandlerManager( + val input: InputManager, +) { + private val context = input.context + var handler: InputHandler? = null + set(value) { + if (field == value) { + return + } + field = value + + if (value == null) { + disable() + } else { + enable() + } + } + private var skipChar = false + private var skipMouse = false + private var skipKey = false + + + fun onMouse(position: Vec2): Boolean { + if (skipMouse) { + skipMouse = false + return true + } + val handler = this.handler ?: return false + + handler.onMouseMove(position) + return true + } + + fun onKey(code: KeyCodes, change: KeyChangeTypes) { + if (skipKey) { + skipKey = false + return + } + val handler = this.handler ?: return + handler.onKey(code, change) + } + + fun onChar(char: Int) { + if (skipChar) { + skipChar = false + return + } + val handler = this.handler ?: return + handler.onCharPress(char) + } + + fun onScroll(delta: Vec2): Boolean { + val handler = this.handler ?: return false + handler.onScroll(delta) + + return true + } + + + private fun enable() { + context.window.cursorMode = CursorModes.NORMAL + // todo: disable all key combinations + } + + private fun disable() { + context.window.cursorMode = CursorModes.DISABLED + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/input/key/manager/InputManager.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/input/key/manager/InputManager.kt index 93d20230c..31de06208 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/input/key/manager/InputManager.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/input/key/manager/InputManager.kt @@ -15,16 +15,8 @@ package de.bixilon.minosoft.gui.rendering.input.key.manager import de.bixilon.kotlinglm.vec2.Vec2 import de.bixilon.kotlinglm.vec2.Vec2d -import de.bixilon.kutil.collections.CollectionUtil.synchronizedMapOf -import de.bixilon.kutil.collections.map.SynchronizedMap -import de.bixilon.kutil.observer.map.MapObserver.Companion.observeMap import de.bixilon.kutil.time.TimeUtil.millis -import de.bixilon.minosoft.config.StaticConfiguration -import de.bixilon.minosoft.config.key.KeyActions -import de.bixilon.minosoft.config.key.KeyBinding import de.bixilon.minosoft.config.key.KeyCodes -import de.bixilon.minosoft.data.registries.identified.ResourceLocation -import de.bixilon.minosoft.gui.rendering.RenderConstants import de.bixilon.minosoft.gui.rendering.RenderContext import de.bixilon.minosoft.gui.rendering.events.input.CharInputEvent import de.bixilon.minosoft.gui.rendering.events.input.KeyInputEvent @@ -32,311 +24,113 @@ import de.bixilon.minosoft.gui.rendering.events.input.MouseMoveEvent import de.bixilon.minosoft.gui.rendering.events.input.MouseScrollEvent import de.bixilon.minosoft.gui.rendering.gui.input.ModifierKeys import de.bixilon.minosoft.gui.rendering.input.CameraInput -import de.bixilon.minosoft.gui.rendering.input.InputHandler import de.bixilon.minosoft.gui.rendering.input.interaction.InteractionManagerKeys -import de.bixilon.minosoft.gui.rendering.input.key.KeyBindingRegister -import de.bixilon.minosoft.gui.rendering.system.window.CursorModes +import de.bixilon.minosoft.gui.rendering.input.key.manager.binding.BindingsManager import de.bixilon.minosoft.gui.rendering.system.window.KeyChangeTypes import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2dUtil.EMPTY import de.bixilon.minosoft.modding.EventPriorities import de.bixilon.minosoft.modding.event.listener.CallbackEventListener.Companion.listen import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection -import de.bixilon.minosoft.util.KUtil.format -import de.bixilon.minosoft.util.KUtil.toResourceLocation +import it.unimi.dsi.fastutil.objects.Object2LongMap +import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap class InputManager( val context: RenderContext, ) { val connection: PlayConnection = context.connection val cameraInput = CameraInput(context, context.camera.matrixHandler) - private val profile = connection.profiles.controls + val bindings = BindingsManager(this) + val handler = InputHandlerManager(this) - private val keyBindingCallbacks: SynchronizedMap = synchronizedMapOf() - private val keysDown: MutableList = mutableListOf() - private val keyBindingsDown: MutableList = mutableListOf() - private val keysLastDownTime: MutableMap = mutableMapOf() + private val pressed: MutableSet = mutableSetOf() + private val times: Object2LongMap = Object2LongOpenHashMap().apply { defaultReturnValue(-1L) } var mousePosition: Vec2d = Vec2d.EMPTY private set val interactionKeys = InteractionManagerKeys(this, connection.camera.interactions) - var inputHandler: InputHandler? = null - set(value) { - if (field == value) { - return - } - field = value - deactivateAll() - - context.window.cursorMode = if (value == null) { - CursorModes.DISABLED - } else { - CursorModes.NORMAL - } - } - private var skipCharPress = false - private var skipMouseMove = false - - init { - registerKeyCallback("minosoft:debug_change_cursor_mode".toResourceLocation(), - KeyBinding( - KeyActions.MODIFIER to setOf(KeyCodes.KEY_F4), - KeyActions.PRESS to setOf(KeyCodes.KEY_M), - ignoreConsumer = true, - ), defaultPressed = StaticConfiguration.DEBUG_MODE) { - val next = when (context.window.cursorMode) { - CursorModes.DISABLED -> CursorModes.NORMAL - CursorModes.NORMAL -> CursorModes.DISABLED - CursorModes.HIDDEN -> CursorModes.NORMAL - } - context.window.cursorMode = next - connection.util.sendDebugMessage("Cursor mode: ${next.format()}") - } - } fun init() { interactionKeys.register() - connection.events.listen { charInput(it.char) } - connection.events.listen { keyInput(it.code, it.change) } + connection.events.listen { onChar(it.char) } + connection.events.listen { onKey(it.code, it.change) } connection.events.listen(priority = EventPriorities.LOW) { scroll(it.offset, it) } + connection.events.listen { onMouse(it.delta, it.position) } - connection.events.listen { - val inputHandler = inputHandler - mousePosition = it.position - if (inputHandler != null) { - if (skipMouseMove) { - skipMouseMove = false - return@listen - } - inputHandler.onMouseMove(Vec2(it.position)) - return@listen - } - - cameraInput.updateMouse(it.delta) - } - - profile::keyBindings.observeMap(this) { - for ((key, value) in it.adds) { - val binding = keyBindingCallbacks[key] ?: continue - binding.keyBinding = value - } - for ((key, value) in it.removes) { - val binding = keyBindingCallbacks[key] ?: continue - binding.keyBinding = binding.default - } - } cameraInput.init() } private fun deactivateAll() { - keysDown.clear() - keysLastDownTime.clear() + pressed.clear() + times.clear() - for ((name, pair) in keyBindingCallbacks) { - val down = name in keyBindingsDown - if (!down || pair.defaultPressed) { - continue - } - - // ToDo - if (pair.keyBinding.action[KeyActions.DOUBLE_PRESS] != null) { - continue - } - if (pair.keyBinding.action[KeyActions.STICKY] != null) { - continue - } - - - for (callback in pair.callback) { - callback(false) - } - keyBindingsDown -= name - } + // TODO: disable key bindings } - private fun keyInput(keyCode: KeyCodes, keyChangeType: KeyChangeTypes) { - val inputHandler = inputHandler - inputHandler?.onKey(keyChangeType, keyCode) + private fun onMouse(delta: Vec2d, position: Vec2d) { + this.mousePosition = position + if (handler.onMouse(Vec2(position))) return + cameraInput.updateMouse(delta) + } - val keyDown = when (keyChangeType) { + private fun onKey(code: KeyCodes, change: KeyChangeTypes) { + this.handler.onKey(code, change) + + val pressed = when (change) { KeyChangeTypes.PRESS -> true KeyChangeTypes.RELEASE -> false KeyChangeTypes.REPEAT -> return } - val currentTime = millis() + val millis = millis() - if (keyDown) { - keysDown += keyCode + + if (pressed) { + this.pressed += code } else { - keysDown -= keyCode + this.pressed -= code } - for ((resourceLocation, pair) in keyBindingCallbacks) { - if (inputHandler != null && !pair.keyBinding.ignoreConsumer) { - continue - } - var thisKeyBindingDown = keyDown - var checksRun = 0 - var thisIsChange = true - var saveDown = true + bindings.onKey(code, pressed, millis) - pair.keyBinding.action[KeyActions.PRESS]?.let { - if (!keyDown) { - thisIsChange = false - } - if (it.contains(keyCode)) { - saveDown = false - } else { - thisIsChange = false - } - checksRun++ - } - - pair.keyBinding.action[KeyActions.RELEASE]?.let { - if (keyDown) { - thisIsChange = false - } - if (it.contains(keyCode)) { - saveDown = false - } else { - thisIsChange = false - } - checksRun++ - } - - pair.keyBinding.action[KeyActions.CHANGE]?.let { - if (!it.contains(keyCode)) { - thisIsChange = false - } - checksRun++ - } - - pair.keyBinding.action[KeyActions.MODIFIER]?.let { - if (!keysDown.containsAll(it)) { - thisIsChange = false - } - checksRun++ - } - - pair.keyBinding.action[KeyActions.STICKY]?.let { - checksRun++ - if (!it.contains(keyCode)) { - thisIsChange = false - return@let - } - if (!keyDown) { - thisIsChange = false - return@let - } - thisKeyBindingDown = !keyBindingsDown.contains(resourceLocation) - } - - pair.keyBinding.action[KeyActions.DOUBLE_PRESS]?.let { - checksRun++ - if (!keyDown) { - thisIsChange = false - return@let - } - if (!it.contains(keyCode)) { - thisIsChange = false - return@let - } - val lastDownTime = keysLastDownTime[keyCode] - if (lastDownTime == null) { - thisIsChange = false - return@let - } - if (currentTime - lastDownTime > RenderConstants.DOUBLE_PRESS_KEY_PRESS_MAX_DELAY) { - thisIsChange = false - return@let - } - if (currentTime - pair.lastChange <= RenderConstants.DOUBLE_PRESS_DELAY_BETWEEN_PRESSED) { - thisIsChange = false - return@let - } - thisKeyBindingDown = !isKeyBindingDown(resourceLocation) - } - - if (!thisIsChange || checksRun == 0) { - continue - } - - pair.lastChange = millis() - for (callback in pair.callback) { - callback(thisKeyBindingDown) - } - - if (saveDown) { - if (thisKeyBindingDown) { - keyBindingsDown += resourceLocation - } else { - keyBindingsDown -= resourceLocation - } - } - skipCharPress = true - } - if (keyDown) { - keysLastDownTime[keyCode] = currentTime - } - - if (this.inputHandler == null) { - skipCharPress = false - skipMouseMove = false - } else if (inputHandler != this.inputHandler) { - skipCharPress = true - skipMouseMove = true + if (pressed) { + times[code] = millis } } - private fun charInput(char: Int) { - val inputHandler = inputHandler ?: return - if (skipCharPress) { - skipCharPress = false - return + private fun onChar(char: Int) { + handler.onChar(char) + } + + private fun scroll(scrollOffset: Vec2d, event: MouseScrollEvent) { + if (handler.onScroll(Vec2(scrollOffset))) return + event.cancelled = true + } + + fun areKeysDown(vararg keys: KeyCodes): Boolean { + for (key in keys) { + if (key !in pressed) { + return false + } } - inputHandler.onCharPress(char) - return + return true } - private fun scroll(scrollOffset: Vec2d, event: MouseScrollEvent? = null) { - val inputHandler = inputHandler - if (inputHandler != null) { - inputHandler.onScroll(scrollOffset) - event?.cancelled = true + fun areKeysDown(keys: Collection): Boolean { + for (key in keys) { + if (key !in pressed) { + return false + } } - } - - fun registerKeyCallback(resourceLocation: ResourceLocation, defaultKeyBinding: KeyBinding, defaultPressed: Boolean = false, callback: ((keyDown: Boolean) -> Unit)) { - val keyBinding = profile.keyBindings.getOrPut(resourceLocation) { defaultKeyBinding } - val callbackPair = keyBindingCallbacks.synchronizedGetOrPut(resourceLocation) { KeyBindingRegister(keyBinding, defaultKeyBinding, defaultPressed) } - callbackPair.callback += callback - - if (keyBinding.action.containsKey(KeyActions.STICKY) && defaultPressed) { - keyBindingsDown += resourceLocation - } - } - - fun registerCheckCallback(vararg checks: Pair) { - for ((resourceLocation, defaultKeyBinding) in checks) { - keyBindingCallbacks.synchronizedGetOrPut(resourceLocation) { KeyBindingRegister(profile.keyBindings.getOrPut(resourceLocation) { defaultKeyBinding }, defaultKeyBinding) } - } - } - - fun isKeyBindingDown(resourceLocation: ResourceLocation): Boolean { - return keyBindingsDown.contains(resourceLocation) - } - - fun unregisterKeyBinding(it: ResourceLocation) { - keyBindingCallbacks.remove(it) + return true } fun isKeyDown(vararg keys: KeyCodes): Boolean { for (key in keys) { - if (keysDown.contains(key)) { + if (key in pressed) { return true } } @@ -344,16 +138,15 @@ class InputManager( } fun isKeyDown(modifier: ModifierKeys): Boolean { - return context.inputManager.isKeyDown(*when (modifier) { - ModifierKeys.CONTROL -> arrayOf(KeyCodes.KEY_LEFT_CONTROL, KeyCodes.KEY_RIGHT_CONTROL) - ModifierKeys.ALT -> arrayOf(KeyCodes.KEY_LEFT_ALT, KeyCodes.KEY_RIGHT_ALT) - ModifierKeys.SHIFT -> arrayOf(KeyCodes.KEY_LEFT_SHIFT, KeyCodes.KEY_RIGHT_SHIFT) - ModifierKeys.SUPER -> arrayOf(KeyCodes.KEY_LEFT_SUPER, KeyCodes.KEY_RIGHT_SUPER) - }) + return isKeyDown(*modifier.codes) } fun draw(delta: Double) { cameraInput.updateInput(delta) interactionKeys.draw() } + + fun getLastPressed(key: KeyCodes): Long { + return this.times.getLong(key) + } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/input/key/manager/binding/BindingsManager.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/input/key/manager/binding/BindingsManager.kt new file mode 100644 index 000000000..92f3ed937 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/input/key/manager/binding/BindingsManager.kt @@ -0,0 +1,142 @@ +/* + * Minosoft + * Copyright (C) 2020-2023 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.input.key.manager.binding + +import de.bixilon.kutil.collections.CollectionUtil.synchronizedMapOf +import de.bixilon.kutil.collections.map.SynchronizedMap +import de.bixilon.kutil.observer.map.MapObserver.Companion.observeMap +import de.bixilon.minosoft.config.key.KeyActions +import de.bixilon.minosoft.config.key.KeyBinding +import de.bixilon.minosoft.config.key.KeyCodes +import de.bixilon.minosoft.data.registries.identified.ResourceLocation +import de.bixilon.minosoft.gui.rendering.input.key.manager.InputManager +import de.bixilon.minosoft.gui.rendering.input.key.manager.binding.actions.KeyActionFilter.Companion.filter + +class BindingsManager( + val input: InputManager, +) { + private val connection = input.context.connection + private val profile = connection.profiles.controls + + private val bindings: SynchronizedMap = synchronizedMapOf() + private val pressed: MutableSet = mutableSetOf() + + + init { + profile::keyBindings.observeMap(this) { + for ((key, value) in it.adds) { + val binding = bindings[key] ?: continue + binding.binding = value + } + for ((key, value) in it.removes) { + val binding = bindings[key] ?: continue + binding.binding = binding.default + } + } + } + + private fun deactivateAll() { + for ((name, pair) in bindings) { + val down = name in pressed + if (!down || pair.pressed) { + continue + } + + // ToDo + if (pair.binding.action[KeyActions.DOUBLE_PRESS] != null) { + continue + } + if (pair.binding.action[KeyActions.STICKY] != null) { + continue + } + + + for (callback in pair.callback) { + callback(false) + } + pressed -= name + } + } + + private fun onKey(name: ResourceLocation, state: KeyBindingState, pressed: Boolean, code: KeyCodes, millis: Long) { + val filterState = KeyBindingFilterState(pressed) + + val binding = state.binding + + if (binding.action.isEmpty()) return + + for ((action, keys) in binding.action) { + val filter = action.filter() + filter.check(filterState, keys, input, name, state, code, pressed, millis) + } + if (filterState.skip) return + + val result = if (filterState.satisfied) filterState.result else false + val previous = name in this + if (previous == result && !filterState.forceNotify) return + + for (callback in state.callback) { + callback(result) + } + if (previous == result) return + + state.lastChange = millis + + if (result) { + this.pressed += name + } else { + this.pressed -= name + } + // skipCharPress = true + } + + fun onKey(code: KeyCodes, pressed: Boolean, millis: Long) { + val handler = input.handler.handler + + for ((name, state) in bindings) { + if (handler != null && !state.binding.ignoreConsumer) { + continue + } + onKey(name, state, pressed, code, millis) + } + } + + fun register(name: ResourceLocation, default: KeyBinding, pressed: Boolean = false, callback: KeyBindingCallback) { + val keyBinding = profile.keyBindings.getOrPut(name) { default } + val callbackPair = bindings.synchronizedGetOrPut(name) { KeyBindingState(keyBinding, default, pressed) } + callbackPair.callback += callback + + if (keyBinding.action.containsKey(KeyActions.STICKY) && pressed) { + this.pressed += name + } + } + + fun registerCheck(vararg checks: Pair) { + for ((name, binding) in checks) { + bindings.synchronizedGetOrPut(name) { KeyBindingState(profile.keyBindings.getOrPut(name) { binding }, binding) } + } + } + + fun isDown(name: ResourceLocation): Boolean { + return name in pressed + } + + operator fun contains(name: ResourceLocation) = isDown(name) + + fun unregister(name: ResourceLocation) { + bindings.remove(name) + } + + operator fun minusAssign(name: ResourceLocation) = unregister(name) +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/input/key/manager/binding/KeyBindingCallback.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/input/key/manager/binding/KeyBindingCallback.kt new file mode 100644 index 000000000..e985d2ab8 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/input/key/manager/binding/KeyBindingCallback.kt @@ -0,0 +1,16 @@ +/* + * Minosoft + * Copyright (C) 2020-2023 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.input.key.manager.binding + +typealias KeyBindingCallback = (Boolean) -> Unit diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/input/key/manager/binding/KeyBindingFilterState.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/input/key/manager/binding/KeyBindingFilterState.kt new file mode 100644 index 000000000..1b848b3ed --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/input/key/manager/binding/KeyBindingFilterState.kt @@ -0,0 +1,21 @@ +/* + * Minosoft + * Copyright (C) 2020-2023 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.input.key.manager.binding + +data class KeyBindingFilterState( + var result: Boolean, + var satisfied: Boolean = true, + var skip: Boolean = false, + var forceNotify: Boolean = false, +) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/input/key/KeyBindingRegister.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/input/key/manager/binding/KeyBindingState.kt similarity index 76% rename from src/main/java/de/bixilon/minosoft/gui/rendering/input/key/KeyBindingRegister.kt rename to src/main/java/de/bixilon/minosoft/gui/rendering/input/key/manager/binding/KeyBindingState.kt index 1ce5451dc..c19181675 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/input/key/KeyBindingRegister.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/input/key/manager/binding/KeyBindingState.kt @@ -11,15 +11,15 @@ * This software is not affiliated with Mojang AB, the original developer of Minecraft. */ -package de.bixilon.minosoft.gui.rendering.input.key +package de.bixilon.minosoft.gui.rendering.input.key.manager.binding import de.bixilon.minosoft.config.key.KeyBinding -data class KeyBindingRegister( - var keyBinding: KeyBinding, - val default: KeyBinding, - val defaultPressed: Boolean = false, - val callback: MutableSet<(keyDown: Boolean) -> Unit> = mutableSetOf(), +data class KeyBindingState( + var binding: KeyBinding, + val default: KeyBinding = binding, + val pressed: Boolean = false, + val callback: MutableSet = mutableSetOf(), ) { var lastChange = 0L } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/input/key/manager/binding/actions/KeyActionFilter.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/input/key/manager/binding/actions/KeyActionFilter.kt new file mode 100644 index 000000000..0f07ab4dd --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/input/key/manager/binding/actions/KeyActionFilter.kt @@ -0,0 +1,139 @@ +/* + * Minosoft + * Copyright (C) 2020-2023 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.input.key.manager.binding.actions + +import de.bixilon.minosoft.config.key.KeyActions +import de.bixilon.minosoft.config.key.KeyCodes +import de.bixilon.minosoft.data.registries.identified.ResourceLocation +import de.bixilon.minosoft.gui.rendering.RenderConstants +import de.bixilon.minosoft.gui.rendering.input.key.manager.InputManager +import de.bixilon.minosoft.gui.rendering.input.key.manager.binding.KeyBindingFilterState +import de.bixilon.minosoft.gui.rendering.input.key.manager.binding.KeyBindingState + +interface KeyActionFilter { + + fun check(filter: KeyBindingFilterState, codes: Set, input: InputManager, name: ResourceLocation, state: KeyBindingState, code: KeyCodes, pressed: Boolean, millis: Long) + + + object Press : KeyActionFilter { + + override fun check(filter: KeyBindingFilterState, codes: Set, input: InputManager, name: ResourceLocation, state: KeyBindingState, code: KeyCodes, pressed: Boolean, millis: Long) { + if (code in codes) return + + filter.satisfied = false + } + } + + object Release : KeyActionFilter { + + override fun check(filter: KeyBindingFilterState, codes: Set, input: InputManager, name: ResourceLocation, state: KeyBindingState, code: KeyCodes, pressed: Boolean, millis: Long) { + if (code in codes) return + + filter.satisfied = false + } + } + + object Change : KeyActionFilter { + + override fun check(filter: KeyBindingFilterState, codes: Set, input: InputManager, name: ResourceLocation, state: KeyBindingState, code: KeyCodes, pressed: Boolean, millis: Long) { + if (code !in codes) { + filter.satisfied = false + return + } + + filter.forceNotify = true + } + } + + object Modifier : KeyActionFilter { + + override fun check(filter: KeyBindingFilterState, codes: Set, input: InputManager, name: ResourceLocation, state: KeyBindingState, code: KeyCodes, pressed: Boolean, millis: Long) { + if (code !in codes) { + filter.skip = true + return + } + if (codes.size == 1) { // optimize if (as most) key has just one modifier key + if (pressed) return + filter.satisfied = false + return + } + if (input.areKeysDown(codes)) return + + filter.satisfied = false + } + } + + object Sticky : KeyActionFilter { + + override fun check(filter: KeyBindingFilterState, codes: Set, input: InputManager, name: ResourceLocation, state: KeyBindingState, code: KeyCodes, pressed: Boolean, millis: Long) { + if (!pressed) { + // sticky keys are invoked on press and not on release + filter.skip = true + return + } + if (code !in codes) { + filter.skip = true + return + } + val wasPressed = name in input.bindings + + filter.result = !wasPressed + } + } + + + object DoublePress : KeyActionFilter { + + override fun check(filter: KeyBindingFilterState, codes: Set, input: InputManager, name: ResourceLocation, state: KeyBindingState, code: KeyCodes, pressed: Boolean, millis: Long) { + if (!pressed) { + filter.skip = true + return + } + if (code !in codes) { + filter.skip = true + return + } + val previous = input.getLastPressed(code) + if (previous < 0L) { + filter.skip = true + return + } + + if (millis - previous > RenderConstants.DOUBLE_PRESS_KEY_PRESS_MAX_DELAY) { + filter.skip = true + return + } + if (millis - state.lastChange <= RenderConstants.DOUBLE_PRESS_DELAY_BETWEEN_PRESSED) { + filter.skip = false + return + } + filter.result = input.bindings.isDown(name) + } + } + + + companion object { + + fun KeyActions.filter(): KeyActionFilter { + return when (this) { + KeyActions.PRESS -> Press + KeyActions.RELEASE -> Release + KeyActions.CHANGE -> Change + KeyActions.MODIFIER -> Modifier + KeyActions.STICKY -> Sticky + KeyActions.DOUBLE_PRESS -> DoublePress + } + } + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/WorldRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/WorldRenderer.kt index f0d87faab..156243c92 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/world/WorldRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/WorldRenderer.kt @@ -115,7 +115,7 @@ class WorldRenderer( } context.camera.offset::offset.observe(this) { silentlyClearChunkCache() } - context.input.registerKeyCallback("minosoft:clear_chunk_cache".toResourceLocation(), KeyBinding( + context.input.bindings.register("minosoft:clear_chunk_cache".toResourceLocation(), KeyBinding( KeyActions.MODIFIER to setOf(KeyCodes.KEY_F3), KeyActions.PRESS to setOf(KeyCodes.KEY_A), )) { clearChunkCache() } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/chunk/ChunkBorderRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/chunk/ChunkBorderRenderer.kt index ef01e9e4c..757741e8a 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/world/chunk/ChunkBorderRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/chunk/ChunkBorderRenderer.kt @@ -59,12 +59,12 @@ class ChunkBorderRenderer( get() = mesh == null || !profile.chunkBorder.enabled override fun init(latch: AbstractLatch) { - context.input.registerKeyCallback( + context.input.bindings.register( CHUNK_BORDER_TOGGLE_KEY_COMBINATION, KeyBinding( KeyActions.MODIFIER to setOf(KeyCodes.KEY_F3), KeyActions.STICKY to setOf(KeyCodes.KEY_G), - ), defaultPressed = profile.chunkBorder.enabled + ), pressed = profile.chunkBorder.enabled ) { profile.chunkBorder.enabled = it connection.util.sendDebugMessage("Chunk borders: ${it.format()}") diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/light/RenderLight.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/light/RenderLight.kt index 8c1c47a1c..b45280cb3 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/world/light/RenderLight.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/light/RenderLight.kt @@ -18,12 +18,12 @@ import de.bixilon.minosoft.config.DebugOptions import de.bixilon.minosoft.config.key.KeyActions import de.bixilon.minosoft.config.key.KeyBinding import de.bixilon.minosoft.config.key.KeyCodes +import de.bixilon.minosoft.data.registries.identified.Namespaces.minosoft import de.bixilon.minosoft.gui.eros.util.JavaFXUtil import de.bixilon.minosoft.gui.rendering.RenderContext import de.bixilon.minosoft.gui.rendering.RenderingStates import de.bixilon.minosoft.gui.rendering.world.light.debug.LightmapDebugWindow import de.bixilon.minosoft.util.KUtil.format -import de.bixilon.minosoft.util.KUtil.toResourceLocation import de.bixilon.minosoft.util.delegate.JavaFXDelegate.observeFX class RenderLight(val context: RenderContext) { @@ -34,25 +34,23 @@ class RenderLight(val context: RenderContext) { fun init() { map.init() - context.input.registerKeyCallback( - "minosoft:recalculate_light".toResourceLocation(), - KeyBinding( - KeyActions.MODIFIER to setOf(KeyCodes.KEY_F4), - KeyActions.PRESS to setOf(KeyCodes.KEY_A), - ) + context.input.bindings.register(RECALCULATE, KeyBinding( + KeyActions.MODIFIER to setOf(KeyCodes.KEY_F4), + KeyActions.PRESS to setOf(KeyCodes.KEY_A), + ) ) { DefaultThreadPool += { connection.world.recalculateLight() connection.util.sendDebugMessage("Light recalculated and chunk cache cleared!") } } - context.input.registerKeyCallback( - "minosoft:toggle_fullbright".toResourceLocation(), + context.input.bindings.register( + FULLBRIGHT, KeyBinding( KeyActions.MODIFIER to setOf(KeyCodes.KEY_F4), KeyActions.STICKY to setOf(KeyCodes.KEY_C), ), - defaultPressed = connection.profiles.rendering.light.fullbright, + pressed = connection.profiles.rendering.light.fullbright, ) { connection.profiles.rendering.light.fullbright = it connection.util.sendDebugMessage("Fullbright: ${it.format()}") @@ -76,4 +74,9 @@ class RenderLight(val context: RenderContext) { map.update() debugWindow?.update() } + + private companion object { + val RECALCULATE = minosoft("recalculate") + val FULLBRIGHT = minosoft("fullbright") + } }