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)
This commit is contained in:
parent
e28dd79cee
commit
c0ec62d186
8 changed files with 88 additions and 15 deletions
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Class<*>, ArgumentParser<*>>()
|
||||
val commands = mutableListOf<ExecutableCommand>()
|
||||
private val commands = mutableListOf<ExecutableCommand>()
|
||||
|
||||
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()
|
||||
|
|
|
@ -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<EventPhase, MutableMap<Class<*>, MutableList<Listener<*>>>>()
|
||||
|
||||
inline fun <reified T : Event> register(listener: Listener<T>, phase: EventPhase) {
|
||||
|
@ -35,4 +36,8 @@ class EventBus {
|
|||
listeners.forEach { it.on(event) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun reset() {
|
||||
allListeners.clear()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Int, MutableList<String>>()
|
||||
|
||||
fun register(key: Int, command: String) {
|
||||
|
@ -16,7 +18,7 @@ class KeybindRegistry {
|
|||
fun getBinds(key: Int): List<String> =
|
||||
keybinds.getOrDefault(key, emptyList())
|
||||
|
||||
fun reset() {
|
||||
override fun reset() {
|
||||
keybinds.clear()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
13
src/main/kotlin/codes/som/hibiscus/commands/Reload.kt
Normal file
13
src/main/kotlin/codes/som/hibiscus/commands/Reload.kt
Normal file
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<Feature>()
|
||||
|
||||
init {
|
||||
registerFeatures()
|
||||
}
|
||||
|
||||
fun getAllFeatures() = features.asSequence()
|
||||
|
||||
inline fun <reified T : Feature> getFeature() =
|
||||
getFeature(T::class.java)
|
||||
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T : Feature> getFeature(type: Class<T>) =
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
|
5
src/main/kotlin/codes/som/hibiscus/util/Resettable.kt
Normal file
5
src/main/kotlin/codes/som/hibiscus/util/Resettable.kt
Normal file
|
@ -0,0 +1,5 @@
|
|||
package codes.som.hibiscus.util
|
||||
|
||||
interface Resettable {
|
||||
fun reset()
|
||||
}
|
Loading…
Reference in a new issue