Skip to content

Commit

Permalink
fix(spigot): unregister commands on shutdown
Browse files Browse the repository at this point in the history
  • Loading branch information
Apehum committed Dec 27, 2024
1 parent b02a840 commit 89a91b2
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ class SpigotServerLib(
}

fun onShutdown() {
commandManager.clear()
commandManager.clear(loader)
permissionManager.clear()
adventure.close()
}
Expand Down
22 changes: 18 additions & 4 deletions spigot/src/main/kotlin/su/plo/slib/spigot/command/SpigotCommand.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ class SpigotCommand(
) : Command(name) {

override fun execute(sender: CommandSender, commandLabel: String, args: Array<String>): Boolean {
if (!isRegistered) {
return false
}

val source = commandManager.getCommandSource(sender)
if (!command.hasPermission(source, args)) {
source.sendMessage(minecraftServer.permissionManager.noPermissionMessage)
Expand All @@ -30,9 +34,19 @@ class SpigotCommand(
alias: String,
args: Array<String>,
location: Location?
): List<String> =
command.suggest(commandManager.getCommandSource(sender), args)
): List<String> {
if (!isRegistered) {
return super.tabComplete(sender, alias, args)
}

return command.suggest(commandManager.getCommandSource(sender), args)
}

override fun testPermissionSilent(target: CommandSender): Boolean {
if (!isRegistered) {
return super.testPermissionSilent(target)
}

override fun testPermissionSilent(target: CommandSender): Boolean =
command.hasPermission(commandManager.getCommandSource(target), null)
return command.hasPermission(commandManager.getCommandSource(target), null)
}
}
Original file line number Diff line number Diff line change
@@ -1,42 +1,73 @@
package su.plo.slib.spigot.command

import org.bukkit.command.Command
import org.bukkit.command.CommandSender
import org.bukkit.command.SimpleCommandMap
import org.bukkit.entity.Player
import org.bukkit.plugin.java.JavaPlugin
import su.plo.slib.api.command.McCommand
import su.plo.slib.api.command.McCommandManager
import su.plo.slib.api.command.McCommandSource
import su.plo.slib.api.logging.McLoggerFactory
import su.plo.slib.api.server.event.command.McServerCommandsRegisterEvent
import su.plo.slib.spigot.SpigotServerLib

class SpigotCommandManager(
private val minecraftServer: SpigotServerLib
) : McCommandManager<McCommand>() {

private val logger = McLoggerFactory.createLogger("SpigotCommandManager")

@Synchronized
fun registerCommands(loader: JavaPlugin) {
McServerCommandsRegisterEvent.invoker.onCommandsRegister(this, minecraftServer)

commandByName.forEach { (name, command) ->
val spigotCommand = SpigotCommand(minecraftServer, this, command, name)

val commandMap = loader.server.javaClass
.getDeclaredField("commandMap").also {
it.isAccessible = true
}
.get(loader.server) as SimpleCommandMap
val commandMap = loader.commandMap()

commandMap.register("plasmovoice", spigotCommand)
}

registered = true
}

@Synchronized
fun clear(loader: JavaPlugin) {
val commandMap = loader.commandMap()

commandByName.keys
.mapNotNull { commandMap.getCommand(it) }
.forEach { commandMap.unregister(it) }

super.clear()
}

override fun getCommandSource(source: Any): McCommandSource {
require(source is CommandSender) { "source is not ${CommandSender::class.java}" }

return if (source is Player) minecraftServer.getPlayerByInstance(source)
else SpigotDefaultCommandSource(minecraftServer, source)
}

@Suppress("UNCHECKED_CAST")
private fun SimpleCommandMap.unregister(command: Command) {
try {
command.unregister(this)

val knownCommandsField = SimpleCommandMap::class.java.getDeclaredField("knownCommands")
knownCommandsField.isAccessible = true

val knownCommands = knownCommandsField.get(this) as MutableMap<String, Command>
knownCommands.remove(command.name)
} catch (e: Throwable) {
logger.error("Failed to unregister command ${command.name}", e)
}
}

private fun JavaPlugin.commandMap(): SimpleCommandMap =
server.javaClass
.getDeclaredField("commandMap")
.also { it.isAccessible = true }
.get(server) as SimpleCommandMap
}

0 comments on commit 89a91b2

Please sign in to comment.