Implement command handling

This commit is contained in:
Gabriel Tofvesson 2021-09-27 01:13:45 +02:00
parent a3c13effdc
commit 67f2901c26
2 changed files with 231 additions and 16 deletions

View File

@ -1,33 +1,233 @@
import net.md_5.bungee.api.chat.TextComponent
import org.bukkit.OfflinePlayer
import org.bukkit.command.Command
import org.bukkit.command.CommandExecutor
import org.bukkit.command.CommandSender
import org.bukkit.command.TabCompleter
import org.bukkit.entity.Player
import org.bukkit.permissions.Permission
import java.util.*
private const val RESULT_ERROR_NOPORTAL = "Given portal doesn't exist"
private const val RESULT_ERROR_NOINVITE = "Invitation to given portal does not exist"
private const val RESULT_ERROR_PORTALEXISTS = "Portal with this name already exists"
private const val RESULT_ERROR_NOTINVITED = "%s is not invited to portal"
private const val RESULT_ERROR_SELFREF = "Cannot link portal to itself"
private const val RESULT_ERROR_NOPORTALS = "%s has no portals"
private const val RESULT_ERROR_INVITED = "%s is already invited"
private const val RESULT_ERROR_BANOWNER = "Cannot ban portal owner"
private const val RESULT_ERROR_UNKNOWN = "An unknown error occurred"
private const val RESULT_SUCCESS_NEWPORTAL = "Created portal \"%s\""
private const val RESULT_SUCCESS_DELPORTAL = "Removed portal \"%s\""
private const val RESULT_SUCCESS_DELPORTALOTHER = "Removed portal \"%s\", owned by %s"
private const val RESULT_SUCCESS_BAN = "%s has been banned from using portal \"%s\""
private const val RESULT_SUCCESS_BANOTHER = "%s has been banned from using portal \"%s\", owned by %s"
private const val RESULT_SUCCESS_LINK = "Linked portal \"%s\" to portal \"%s\""
private const val RESULT_SUCCESS_UNLINK = "Unlinked portal \"%s\""
private const val RESULT_SUCCESS_INVITE = "Invited %s to portal \"%s\""
private const val RESULT_SUCCESS_INVITEOTHER = "Invited %s to portal \"%s\", owned by %s"
private const val RESULT_SUCCESS_CANCEL = "Cancelled invitation of %s to portal \"%s\""
private const val RESULT_SUCCESS_ACCEPT = "Accepted invite from %s to portal \"%s\""
private const val RESULT_SUCCESS_DECLINE = "Declined invite from %s to portal \"%s\""
private const val RESULT_INFO_LIST = "List of portals owned by %s:"
private val OfflinePlayer.playerName: String
get() = name ?: "<Name Missing>"
class PortalCommand(
private val portalManager: PortalManager,
permissionCreate: Permission,
permissionRemove: Permission,
permissionRemoveOther: Permission,
permissionInvite: Permission,
permissionInviteOther: Permission,
permissionListOther: Permission
): CommandExecutor {
): CommandExecutor, TabCompleter {
// Arg parse node for targeting a portal owned by the sender
private val senderPortalParseNode: ArgNode<Portal> =
{ parsed: List<*>, current: String, sender: CommandSender ->
val portal = portalManager.getPortal(sender as OfflinePlayer, current)
if (portal == null) NodeParseResult.FailResult(RESULT_ERROR_NOPORTAL)
else NodeParseResult.SuccessResult(portal)
} to { parsed: List<*>, sender: CommandSender, current: String ->
portalManager.getPortalsByPartialName(sender as OfflinePlayer, current)?.mapTo(ArrayList(), Portal::name)
}
// Arg parse node for targeting a portal owned by a named player
private val otherPortalParseNode: ArgNode<Portal> =
{ parsed: List<*>, current: String, _: CommandSender ->
val portal = portalManager.getPortal(parsed.last() as OfflinePlayer, current)
if (portal == null) NodeParseResult.FailResult(RESULT_ERROR_NOPORTAL)
else NodeParseResult.SuccessResult(portal)
} to { parsed: List<*>, _: CommandSender, current: String ->
portalManager.getPortalsByPartialName(parsed.last() as OfflinePlayer, current)?.mapTo(ArrayList(), Portal::name)
}
private val recipientInviteParseNode: ArgNode<Invite> =
parse@{ parsed: List<*>, current: String, sender: CommandSender ->
NodeParseResult.SuccessResult(
portalManager.getInvitationsForPlayerFromPlayer(sender as OfflinePlayer, parsed.last() as OfflinePlayer)
?.firstOrNull { portalManager.getPortal(it.portalID)?.name?.equals(current) == true }
?: return@parse NodeParseResult.FailResult<Invite>(RESULT_ERROR_NOINVITE)
)
} to { parsed: List<*>, sender: CommandSender, current: String ->
portalManager.getInvitationsForPlayerFromPlayer(sender as OfflinePlayer, parsed.last() as OfflinePlayer)
?.mapNotNull {
val name = portalManager.getPortal(it.portalID)?.name ?: return@mapNotNull null
if (name.startsWith(current)) name
else null
}
}
private val senderInviteParseNode: ArgNode<Invite> =
parse@{ parsed: List<*>, current: String, sender: CommandSender ->
NodeParseResult.SuccessResult(
portalManager.getInvitationsForPortal(
portalManager.getPortal(sender as OfflinePlayer, current)
?: return@parse NodeParseResult.FailResult<Invite>(RESULT_ERROR_NOPORTAL)
)
?.firstOrNull { it.recipient.uniqueId == (parsed.last() as OfflinePlayer).uniqueId }
?: return@parse NodeParseResult.FailResult<Invite>(RESULT_ERROR_NOINVITE)
)
} to { parsed: List<*>, sender: CommandSender, current: String ->
portalManager.getInvitationsForPlayerFromPlayer(parsed.last() as OfflinePlayer, sender as OfflinePlayer)
?.mapNotNull {
val name = portalManager.getPortal(it.portalID)?.name ?: return@mapNotNull null
if (name.startsWith(current)) name
else null
}
}
private val portalParse = ParseTree()
.branch(PermissionParseBranch(permissionCreate, constantParseNode("create"), PARSE_NODE_STRING, PARSE_NODE_STRING)) // portal create [name] [linkName]
.branch(PermissionParseBranch(permissionCreate, constantParseNode("create"), PARSE_NODE_STRING)) // portal create [name]
.branch(PermissionParseBranch(permissionRemove, constantParseNode("remove"), PARSE_NODE_STRING)) // portal remove [name]
.branch(PermissionParseBranch(permissionRemoveOther, constantParseNode("remove"), PARSE_NODE_STRING, PARSE_NODE_PLAYER)) // portal remove [name] [player]
.branch(PermissionParseBranch(permissionInvite, constantParseNode("invite"), PARSE_NODE_STRING, PARSE_NODE_PLAYER)) // portal invite [name] [player]
.branch(PermissionParseBranch(permissionInviteOther, constantParseNode("invite"), PARSE_NODE_PLAYER, PARSE_NODE_STRING, PARSE_NODE_PLAYER)) // portal invite [owner] [name] [player]
.branch(constantParseNode("invite"), constantParseNode("cancel"), PARSE_NODE_PLAYER, PARSE_NODE_STRING) // portal invite cancel [player] [name]
.branch(constantParseNode("invite"), constantParseNode("accept"), PARSE_NODE_PLAYER, PARSE_NODE_STRING) // portal invite accept [player] [name]
.branch(constantParseNode("invite"), constantParseNode("decline"), PARSE_NODE_PLAYER, PARSE_NODE_STRING) // portal invite decline [player] [name]
.branch(constantParseNode("uninvite"), PARSE_NODE_PLAYER, PARSE_NODE_STRING) // portal uninvite [player] [name]
.branch(constantParseNode("link"), PARSE_NODE_STRING, PARSE_NODE_STRING) // portal link [name] [linkName]
.branch(constantParseNode("unlink"), PARSE_NODE_STRING) // portal unlink [name]
.branch(constantParseNode("list")) // portal list
.branch(PermissionParseBranch(permissionListOther, constantParseNode("list"), PARSE_NODE_PLAYER)) // portal list [player]
.branch(PermissionParseBranch(permissionCreate, false, constantParseNode("create"), PARSE_NODE_STRING, senderPortalParseNode)) // portals create [name] [linkName]
.branch(PermissionParseBranch(permissionCreate, false, constantParseNode("create"), PARSE_NODE_STRING)) // portals create [name]
.branch(PermissionParseBranch(permissionRemove, false, constantParseNode("remove"), PARSE_NODE_STRING)) // portals remove [name]
.branch(PermissionParseBranch(permissionRemoveOther, constantParseNode("remove"), PARSE_NODE_PLAYER, otherPortalParseNode)) // portals remove [player] [name]
.branch(PlayerParseBranch(constantParseNode("uninvite"), senderPortalParseNode, PARSE_NODE_PLAYER)) // portals uninvite [name] [player]
.branch(PermissionParseBranch(permissionInviteOther, false, constantParseNode("uninvite"), PARSE_NODE_PLAYER, otherPortalParseNode, PARSE_NODE_PLAYER)) // portals uninvite [owner] [name] [player]
.branch(constantParseNode("link"), senderPortalParseNode, senderPortalParseNode) // portals link [name] [linkName]
.branch(constantParseNode("unlink"), senderPortalParseNode) // portals unlink [name]
.branch(constantParseNode("list")) // portals list
.branch(PermissionParseBranch(permissionListOther, constantParseNode("list"), PARSE_NODE_PLAYER)) // portals list [player]
.branch(PermissionParseBranch(permissionInvite, constantParseNode("invite"), senderPortalParseNode, PARSE_NODE_PLAYER)) // portals invite [name] [player]
.branch(PermissionParseBranch(permissionInviteOther, constantParseNode("invite"), PARSE_NODE_PLAYER, otherPortalParseNode, PARSE_NODE_PLAYER)) // portals invite [owner] [name] [player]
.branch(constantParseNode("invite"), constantParseNode("cancel"), PARSE_NODE_PLAYER, senderInviteParseNode) // portals invite cancel [player] [name]
.branch(constantParseNode("invite"), constantParseNode("accept"), PARSE_NODE_PLAYER, recipientInviteParseNode) // portals invite accept [player] [name]
.branch(constantParseNode("invite"), constantParseNode("decline"), PARSE_NODE_PLAYER, recipientInviteParseNode) // portals invite decline [player] [name]
override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array<out String>): Boolean {
TODO("Not yet implemented")
when (val result = portalParse.getMatch(args, sender)) {
is ParseResult.FailResult -> sender.spigot().sendMessage(TextComponent(result.reason))
is ParseResult.SuccessResult ->
sender.spigot().sendMessage(TextComponent(when(result.match[0] as String) {
"create" -> {
val portal = portalManager.makePortal(sender as Player, result.match[1] as String, sender.location, if (result.match.size == 2) null else result.match[2] as Portal)
if (portal == null) RESULT_ERROR_PORTALEXISTS else RESULT_SUCCESS_NEWPORTAL.format(Locale.ROOT, result.match[1] as String)
}
"remove" -> {
val portal = result.match.last() as Portal
portalManager.removePortal(portal)
if (result.match.size == 2) RESULT_SUCCESS_DELPORTAL.format(Locale.ROOT, portal.name)
else RESULT_SUCCESS_DELPORTALOTHER.format(Locale.ROOT, portal.name, portal.owner.playerName)
}
"uninvite" -> {
val toRemove = result.match.last() as OfflinePlayer
val portal = result.match[result.match.size - 2] as Portal
if (toRemove.uniqueId == portal.owner.uniqueId) RESULT_ERROR_BANOWNER
else if (!portal.public) {
portal.accessExclusions.remove(toRemove)
RESULT_SUCCESS_BAN.format(toRemove.playerName, portal.name)
} else {
portal.accessExclusions.add(toRemove)
RESULT_SUCCESS_BANOTHER.format(toRemove.playerName, portal.name, portal.owner.playerName)
}
}
"link" -> {
val portal = result.match[result.match.size - 2] as Portal
val link = result.match.last() as Portal
if (portal.link(link)) RESULT_SUCCESS_LINK.format(portal.name, link.name)
else RESULT_ERROR_SELFREF
}
"unlink" -> {
val portal = result.match.last() as Portal
portal.unlink()
RESULT_SUCCESS_UNLINK.format(portal.name)
}
"list" -> {
val owner = sender as? OfflinePlayer ?: result.match.last() as OfflinePlayer
val portals = portalManager.getPortals(owner)
if (portals == null || !portals.iterator().hasNext()) RESULT_ERROR_NOPORTALS
else {
val builder = StringBuilder(RESULT_INFO_LIST)
var counter = 0
for (portal in portals)
builder.append(counter++).append(". ").append(portal.name)
builder.toString()
}
}
"invite" ->
when(result.match[1]) {
is Portal, is OfflinePlayer -> {
val recipient = result.match.last() as OfflinePlayer
val portal = result.match[result.match.size - 2] as Portal
if (recipient.uniqueId == portal.owner.uniqueId || !portalManager.invitePlayer(recipient, portal)) RESULT_ERROR_INVITED
else if (sender !is OfflinePlayer || portal.owner.uniqueId != (sender as OfflinePlayer).uniqueId)
RESULT_SUCCESS_INVITEOTHER.format(recipient.playerName, portal.name, portal.owner.playerName)
else RESULT_SUCCESS_INVITE.format(recipient.playerName, portal.name)
}
"cancel" -> {
val invite = result.match.last() as Invite
val portal = portalManager.getPortal(invite.portalID)
if (portal == null || !portalManager.cancelInvite(invite)) RESULT_ERROR_UNKNOWN
else RESULT_SUCCESS_CANCEL.format(invite.recipient.playerName, portal.name)
}
"accept" -> {
val invite = result.match.last() as Invite
val portal = portalManager.getPortal(invite.portalID)
if (portal == null || !portalManager.acceptInvite(invite)) RESULT_ERROR_UNKNOWN
else RESULT_SUCCESS_ACCEPT.format(portal.owner.playerName, portal.name)
}
"decline" -> {
val invite = result.match.last() as Invite
val portal = portalManager.getPortal(invite.portalID)
if (portal == null || !portalManager.declineInvite(invite)) RESULT_ERROR_UNKNOWN
else RESULT_SUCCESS_DECLINE.format(portal.owner.playerName, portal.name)
}
else -> RESULT_ERROR_UNKNOWN
}
else -> RESULT_ERROR_UNKNOWN
}))
}
return true
}
override fun onTabComplete(
sender: CommandSender,
command: Command,
alias: String,
args: Array<out String>
) = portalParse.getSuggestions(args, sender).toMutableList()
}

View File

@ -13,6 +13,21 @@ class PortalsPlugin: JavaPlugin() {
reloadConfig()
portalManager.onEnable(this)
val command = PortalCommand(
portalManager,
description.permissions.first { it.name == "portals.create" },
description.permissions.first { it.name == "portals.modify.remove" },
description.permissions.first { it.name == "portals.modify.other" },
description.permissions.first { it.name == "portals.invite" },
description.permissions.first { it.name == "portals.invite.other" },
description.permissions.first { it.name == "portals.list.other" },
)
val pluginCommand = getCommand("portals")!!
pluginCommand.tabCompleter = command
pluginCommand.setExecutor(command)
}
override fun reloadConfig() {