From c0ec62d186cf32dc182cbdea121403a043a4340f Mon Sep 17 00:00:00 2001 From: videogame hacker Date: Sun, 13 Feb 2022 06:01:20 +0000 Subject: [PATCH] Support reloading features and commands at runtime This means that if you add a new feature, you do not need to restart the game to hot-swap it into a running game (provided you're in debug mode) --- .../kotlin/codes/som/hibiscus/HibiscusMod.kt | 14 ++++++++-- .../hibiscus/api/command/CommandManager.kt | 7 +++-- .../codes/som/hibiscus/api/event/EventBus.kt | 7 ++++- .../hibiscus/api/keybinds/KeybindRegistry.kt | 6 ++-- .../som/hibiscus/commands/CommandRegistry.kt | 23 +++++++++++++++ .../codes/som/hibiscus/commands/Reload.kt | 13 +++++++++ .../som/hibiscus/features/FeaturesRegistry.kt | 28 ++++++++++++++----- .../codes/som/hibiscus/util/Resettable.kt | 5 ++++ 8 files changed, 88 insertions(+), 15 deletions(-) create mode 100644 src/main/kotlin/codes/som/hibiscus/commands/CommandRegistry.kt create mode 100644 src/main/kotlin/codes/som/hibiscus/commands/Reload.kt create mode 100644 src/main/kotlin/codes/som/hibiscus/util/Resettable.kt diff --git a/src/main/kotlin/codes/som/hibiscus/HibiscusMod.kt b/src/main/kotlin/codes/som/hibiscus/HibiscusMod.kt index 3cea3e2..f33e0b1 100644 --- a/src/main/kotlin/codes/som/hibiscus/HibiscusMod.kt +++ b/src/main/kotlin/codes/som/hibiscus/HibiscusMod.kt @@ -1,9 +1,9 @@ package codes.som.hibiscus -import codes.som.hibiscus.api.command.CommandManager import codes.som.hibiscus.api.event.EventBus import codes.som.hibiscus.api.event.EventPhase import codes.som.hibiscus.api.keybinds.KeybindRegistry +import codes.som.hibiscus.commands.CommandRegistry import codes.som.hibiscus.events.KeyEvent import codes.som.hibiscus.features.FeaturesRegistry import codes.som.hibiscus.gui.ImGuiScreen @@ -23,7 +23,7 @@ object HibiscusMod : ModInitializer { val bus = EventBus() val features = FeaturesRegistry() - val commands = CommandManager() + val commands = CommandRegistry() val keybinds = KeybindRegistry() override fun onInitialize() { @@ -44,5 +44,15 @@ object HibiscusMod : ModInitializer { bus.register(NetworkMovingDispatcher(), EventPhase.AFTER) bus.register(ChatCommandListener()) bus.register(KeybindDispatcher()) + + // TODO: Load files + } + + fun shutdown() { + // TODO: Save files + + for (system in sequenceOf(bus, features, commands, keybinds)) { + system.reset() + } } } diff --git a/src/main/kotlin/codes/som/hibiscus/api/command/CommandManager.kt b/src/main/kotlin/codes/som/hibiscus/api/command/CommandManager.kt index c63e72b..2604788 100644 --- a/src/main/kotlin/codes/som/hibiscus/api/command/CommandManager.kt +++ b/src/main/kotlin/codes/som/hibiscus/api/command/CommandManager.kt @@ -6,11 +6,12 @@ import codes.som.hibiscus.api.command.exceptions.* import codes.som.hibiscus.api.command.parser.ArgumentParser import codes.som.hibiscus.api.command.utils.PeekableIterator import codes.som.hibiscus.api.command.utils.splitExceptingQuotes +import codes.som.hibiscus.util.Resettable import java.util.* -class CommandManager(private val registerDefaultParsers: Boolean = true) { +abstract class CommandManager(private val registerDefaultParsers: Boolean = true) : Resettable { private val parserRegistry = mutableMapOf, ArgumentParser<*>>() - val commands = mutableListOf() + private val commands = mutableListOf() var context: CommandContext = CommandContext.OTHER @@ -226,7 +227,7 @@ class CommandManager(private val registerDefaultParsers: Boolean = true) { branch.aliases.any { it.equals(args[1], ignoreCase = true) })) } - fun reset() { + override fun reset() { commands.clear() parserRegistry.clear() registerDefaultParsersIfApplicable() diff --git a/src/main/kotlin/codes/som/hibiscus/api/event/EventBus.kt b/src/main/kotlin/codes/som/hibiscus/api/event/EventBus.kt index 2d7eb17..f3eb615 100644 --- a/src/main/kotlin/codes/som/hibiscus/api/event/EventBus.kt +++ b/src/main/kotlin/codes/som/hibiscus/api/event/EventBus.kt @@ -1,8 +1,9 @@ package codes.som.hibiscus.api.event +import codes.som.hibiscus.util.Resettable import java.util.concurrent.CopyOnWriteArrayList -class EventBus { +class EventBus : Resettable { private val allListeners = mutableMapOf, MutableList>>>() inline fun register(listener: Listener, phase: EventPhase) { @@ -35,4 +36,8 @@ class EventBus { listeners.forEach { it.on(event) } } } + + override fun reset() { + allListeners.clear() + } } diff --git a/src/main/kotlin/codes/som/hibiscus/api/keybinds/KeybindRegistry.kt b/src/main/kotlin/codes/som/hibiscus/api/keybinds/KeybindRegistry.kt index 6f75ded..92d26d0 100644 --- a/src/main/kotlin/codes/som/hibiscus/api/keybinds/KeybindRegistry.kt +++ b/src/main/kotlin/codes/som/hibiscus/api/keybinds/KeybindRegistry.kt @@ -1,6 +1,8 @@ package codes.som.hibiscus.api.keybinds -class KeybindRegistry { +import codes.som.hibiscus.util.Resettable + +class KeybindRegistry : Resettable { private val keybinds = mutableMapOf>() fun register(key: Int, command: String) { @@ -16,7 +18,7 @@ class KeybindRegistry { fun getBinds(key: Int): List = keybinds.getOrDefault(key, emptyList()) - fun reset() { + override fun reset() { keybinds.clear() } } diff --git a/src/main/kotlin/codes/som/hibiscus/commands/CommandRegistry.kt b/src/main/kotlin/codes/som/hibiscus/commands/CommandRegistry.kt new file mode 100644 index 0000000..16e706d --- /dev/null +++ b/src/main/kotlin/codes/som/hibiscus/commands/CommandRegistry.kt @@ -0,0 +1,23 @@ +package codes.som.hibiscus.commands + +import codes.som.hibiscus.api.command.Command +import codes.som.hibiscus.api.command.CommandManager + +fun allCommandClasses(): Array<() -> Command> = arrayOf( + ::Reload, +) + +class CommandRegistry : CommandManager() { + init { + registerCommands() + } + + private fun registerCommands() { + allCommandClasses().map { it() }.forEach(this::register) + } + + override fun reset() { + super.reset() + registerCommands() + } +} diff --git a/src/main/kotlin/codes/som/hibiscus/commands/Reload.kt b/src/main/kotlin/codes/som/hibiscus/commands/Reload.kt new file mode 100644 index 0000000..434fcc1 --- /dev/null +++ b/src/main/kotlin/codes/som/hibiscus/commands/Reload.kt @@ -0,0 +1,13 @@ +package codes.som.hibiscus.commands + +import codes.som.hibiscus.HibiscusMod +import codes.som.hibiscus.api.command.Command + +class Reload : Command("reload") { + init { + branch { + HibiscusMod.shutdown() + HibiscusMod.onInitialize() + } + } +} diff --git a/src/main/kotlin/codes/som/hibiscus/features/FeaturesRegistry.kt b/src/main/kotlin/codes/som/hibiscus/features/FeaturesRegistry.kt index 5f42b4f..c597d81 100644 --- a/src/main/kotlin/codes/som/hibiscus/features/FeaturesRegistry.kt +++ b/src/main/kotlin/codes/som/hibiscus/features/FeaturesRegistry.kt @@ -3,13 +3,14 @@ package codes.som.hibiscus.features import codes.som.hibiscus.api.feature.Feature import codes.som.hibiscus.features.combat.Criticals import codes.som.hibiscus.features.exploits.AntiGhost +import codes.som.hibiscus.features.exploits.Ghost import codes.som.hibiscus.features.movement.Flight import codes.som.hibiscus.features.movement.Speed import codes.som.hibiscus.features.overlay.Overlay -import codes.som.hibiscus.features.exploits.Ghost import codes.som.hibiscus.features.player.NoFallDamage +import codes.som.hibiscus.util.Resettable -val ALL_FEATURES: Array<() -> Feature> = arrayOf( +fun allFeatureClasses(): Array<() -> Feature> = arrayOf( ::NoFallDamage, ::Flight, ::Overlay, @@ -19,14 +20,27 @@ val ALL_FEATURES: Array<() -> Feature> = arrayOf( ::AntiGhost, ) -class FeaturesRegistry { - private val features = ALL_FEATURES.map { it() }.sortedBy { it.name } +class FeaturesRegistry : Resettable { + private val features = mutableListOf() + + init { + registerFeatures() + } + fun getAllFeatures() = features.asSequence() - inline fun getFeature() = getFeature(T::class.java) - + @Suppress("UNCHECKED_CAST") fun getFeature(type: Class) = - features.first { it.javaClass == type } as T + getAllFeatures().first { it.javaClass == type } as T + + private fun registerFeatures() { + features.addAll(allFeatureClasses().map { it() }) + } + + override fun reset() { + features.clear() + registerFeatures() + } } diff --git a/src/main/kotlin/codes/som/hibiscus/util/Resettable.kt b/src/main/kotlin/codes/som/hibiscus/util/Resettable.kt new file mode 100644 index 0000000..f6d3c14 --- /dev/null +++ b/src/main/kotlin/codes/som/hibiscus/util/Resettable.kt @@ -0,0 +1,5 @@ +package codes.som.hibiscus.util + +interface Resettable { + fun reset() +}