Implement channel handling for Chroma users
- This allows properly implementing Minecraft chat for Discord users instead of creating fake CommandSenders - Channel access needs to be implemented on all platforms - this could allow automatically managing who has access to a Discord channel for example - In the future custom commands could be supported without having to connect accounts - Also any information can be retrieved about the user when they chat, not just their name
This commit is contained in:
parent
291fc068fd
commit
cd108dc787
9 changed files with 80 additions and 52 deletions
|
@ -57,6 +57,11 @@ class MainPlugin : ButtonPlugin() {
|
|||
*/
|
||||
val prioritizeCustomCommands = iConfig.getData("prioritizeCustomCommands", false)
|
||||
|
||||
/**
|
||||
* The permission group to use for players who are not in the server.
|
||||
*/ // TODO: Combine the channel access test with command permissions (with a generic implementation)
|
||||
val externalPlayerPermissionGroup get() = iConfig.getData("externalPlayerPermissionGroup", "default")
|
||||
|
||||
public override fun pluginEnable() {
|
||||
instance = this
|
||||
val pdf = description
|
||||
|
|
|
@ -67,7 +67,7 @@ class PlayerListener(val plugin: MainPlugin) : Listener {
|
|||
private fun handlePreprocess(sender: CommandSender, message: String, event: Cancellable) {
|
||||
if (event.isCancelled) return
|
||||
val cg = ChromaGamerBase.getFromSender(sender)
|
||||
val ev = TBMCCommandPreprocessEvent(cg, cg.channel.get(), message, sender)
|
||||
val ev = TBMCCommandPreprocessEvent(cg, cg.channel.get(), message, cg)
|
||||
Bukkit.getPluginManager().callEvent(ev)
|
||||
if (ev.isCancelled) event.isCancelled = true //Cancel the original event
|
||||
}
|
||||
|
@ -76,13 +76,7 @@ class PlayerListener(val plugin: MainPlugin) : Listener {
|
|||
fun onTBMCPreprocess(event: TBMCCommandPreprocessEvent) {
|
||||
if (event.isCancelled) return
|
||||
try {
|
||||
val mcuser = event.sender.getAs(TBMCPlayerBase::class.java)
|
||||
if (mcuser == null) { // TODO: The chat should continue to support unconnected accounts.
|
||||
event.sender.sendMessage("You need to have your Minecraft account connected to send commands.")
|
||||
event.isCancelled = true
|
||||
return
|
||||
}
|
||||
val sender = Command2MCSender(mcuser, event.channel, event.permCheck)
|
||||
val sender = Command2MCSender(event.sender, event.channel, event.permCheck)
|
||||
event.isCancelled = ButtonPlugin.command2MC.handleCommand(sender, event.message)
|
||||
} catch (e: Exception) {
|
||||
TBMCCoreAPI.SendException(
|
||||
|
|
|
@ -1,15 +1,12 @@
|
|||
package buttondevteam.core.component.channel
|
||||
|
||||
import buttondevteam.core.ComponentManager.get
|
||||
import buttondevteam.core.MainPlugin
|
||||
import buttondevteam.lib.architecture.ConfigData
|
||||
import buttondevteam.lib.architecture.IHaveConfig
|
||||
import buttondevteam.lib.architecture.ListConfigData
|
||||
import buttondevteam.lib.chat.Color
|
||||
import buttondevteam.lib.player.ChromaGamerBase
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.command.CommandSender
|
||||
import org.bukkit.entity.Player
|
||||
import java.util.*
|
||||
import java.util.function.Function
|
||||
import java.util.function.Predicate
|
||||
|
@ -45,7 +42,7 @@ open class Channel
|
|||
* Only those with access can see the messages.
|
||||
* If null, everyone has access.
|
||||
*/
|
||||
private val filterAndErrorMSG: Function<CommandSender, RecipientTestResult>?
|
||||
private val filterAndErrorMSG: Function<ChromaGamerBase, RecipientTestResult>?
|
||||
) {
|
||||
private val config: IHaveConfig? = null // TODO: Use this
|
||||
|
||||
|
@ -188,28 +185,27 @@ open class Channel
|
|||
* @param permgroup The group that can access the channel or **null** to only allow OPs.
|
||||
* @return If has access
|
||||
*/
|
||||
fun inGroupFilter(permgroup: String?): Function<CommandSender, RecipientTestResult> {
|
||||
// TODO: This is Minecraft specific. Change all of this so it supports other ways of checking permissions.
|
||||
// TODO: The commands have to be Minecraft specific, but the channels should be generic.
|
||||
// TODO: Implement a way to check permissions for other platforms. Maybe specific strings, like "admin" or "mod"?
|
||||
return noScoreResult(
|
||||
{ s ->
|
||||
s.isOp || s is Player && permgroup?.let { pg ->
|
||||
MainPlugin.permission.playerInGroup(s, pg)
|
||||
} ?: false
|
||||
},
|
||||
"You need to be a(n) " + (permgroup ?: "OP") + " to use this channel."
|
||||
)
|
||||
@JvmStatic
|
||||
fun inGroupFilter(permgroup: String?): Function<ChromaGamerBase, RecipientTestResult> {
|
||||
return Function { it.checkChannelInGroup(permgroup) }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun noScoreResult(
|
||||
filter: Predicate<CommandSender>,
|
||||
filter: Predicate<ChromaGamerBase>,
|
||||
errormsg: String?
|
||||
): Function<CommandSender, RecipientTestResult> {
|
||||
return Function { s ->
|
||||
if (filter.test(s)) RecipientTestResult(SCORE_SEND_OK, GROUP_EVERYONE)
|
||||
else RecipientTestResult(errormsg)
|
||||
}
|
||||
): Function<ChromaGamerBase, RecipientTestResult> {
|
||||
return Function { noScoreResult(filter, errormsg, it) }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun noScoreResult(
|
||||
filter: Predicate<ChromaGamerBase>,
|
||||
errormsg: String?,
|
||||
user: ChromaGamerBase
|
||||
): RecipientTestResult {
|
||||
return if (filter.test(user)) RecipientTestResult(SCORE_SEND_OK, GROUP_EVERYONE)
|
||||
else RecipientTestResult(errormsg)
|
||||
}
|
||||
|
||||
lateinit var globalChat: Channel
|
||||
|
|
|
@ -2,7 +2,6 @@ package buttondevteam.lib
|
|||
|
||||
import buttondevteam.core.component.channel.Channel
|
||||
import buttondevteam.lib.player.ChromaGamerBase
|
||||
import org.bukkit.command.CommandSender
|
||||
import org.bukkit.event.Cancellable
|
||||
import org.bukkit.event.Event
|
||||
import org.bukkit.event.HandlerList
|
||||
|
@ -17,7 +16,7 @@ class TBMCCommandPreprocessEvent(
|
|||
val sender: ChromaGamerBase,
|
||||
val channel: Channel,
|
||||
val message: String,
|
||||
val permCheck: CommandSender
|
||||
val permCheck: ChromaGamerBase
|
||||
) : Event(), Cancellable {
|
||||
private var cancelled = false
|
||||
override fun getHandlers(): HandlerList {
|
||||
|
|
|
@ -59,7 +59,22 @@ class Command2MC : Command2<ICommand2MC, Command2MCSender>('/', true), Listener
|
|||
}
|
||||
|
||||
override fun hasPermission(sender: Command2MCSender, data: SubcommandData<ICommand2MC, Command2MCSender>): Boolean {
|
||||
if (sender.sender.isConsole) return true //Always allow the console
|
||||
val defWorld = Bukkit.getWorlds().first().name
|
||||
val check = if (sender.permCheck !is TBMCPlayerBase) ({
|
||||
MainPlugin.permission.groupHas(
|
||||
defWorld,
|
||||
MainPlugin.instance.externalPlayerPermissionGroup.get(),
|
||||
it
|
||||
)
|
||||
})
|
||||
else if (sender.permCheck.isConsole) ({ true }) //Always allow the console
|
||||
else ({ perm: String ->
|
||||
MainPlugin.permission.playerHas(
|
||||
sender.permCheck.player?.location?.world?.name ?: defWorld,
|
||||
sender.permCheck.offlinePlayer,
|
||||
perm
|
||||
)
|
||||
})
|
||||
|
||||
var p = true
|
||||
val cmdperm = "chroma.command.${data.fullPath.replace(' ', '.')}"
|
||||
|
@ -71,11 +86,7 @@ class Command2MC : Command2<ICommand2MC, Command2MCSender>('/', true), Listener
|
|||
for (perm in perms) {
|
||||
if (perm != null) {
|
||||
if (p) { //Use OfflinePlayer to avoid fetching player data
|
||||
p = MainPlugin.permission.playerHas(
|
||||
sender.sender.player?.location?.world?.name,
|
||||
sender.sender.offlinePlayer,
|
||||
perm
|
||||
)
|
||||
p = check(perm)
|
||||
} else break //If any of the permissions aren't granted then don't allow
|
||||
}
|
||||
}
|
||||
|
@ -113,14 +124,18 @@ class Command2MC : Command2<ICommand2MC, Command2MCSender>('/', true), Listener
|
|||
if (original != null) {
|
||||
return original
|
||||
}
|
||||
// Check Bukkit sender type - TODO: This is no longer the Bukkit sender type
|
||||
if (senderType.isAssignableFrom(sender.sender.javaClass))
|
||||
return sender.sender
|
||||
val cg = sender.sender
|
||||
if (senderType.isAssignableFrom(cg.javaClass))
|
||||
return cg
|
||||
// Check Bukkit sender type
|
||||
if (cg is TBMCPlayerBase) {
|
||||
if (senderType.isAssignableFrom(cg.offlinePlayer.javaClass)) return cg.offlinePlayer
|
||||
if (cg.player?.javaClass?.let { senderType.isAssignableFrom(it) } == true) return cg.player
|
||||
}
|
||||
//The command expects a user of our system
|
||||
if (ChromaGamerBase::class.java.isAssignableFrom(senderType)) {
|
||||
val cg = sender.sender
|
||||
if (cg.javaClass == senderType)
|
||||
return cg
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return sender.sender.getAs(senderType as Class<out ChromaGamerBase>)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
@ -187,7 +202,7 @@ class Command2MC : Command2<ICommand2MC, Command2MCSender>('/', true), Listener
|
|||
val user = ChromaGamerBase.getFromSender(sender) // TODO: Senders should only be used for TBMCPlayerBase classes.
|
||||
///trim(): remove space if there are no args
|
||||
handleCommand(
|
||||
Command2MCSender(user as TBMCPlayerBase, user.channel.get(), sender),
|
||||
Command2MCSender(user as TBMCPlayerBase, user.channel.get(), user),
|
||||
("/${command.name} ${args.joinToString(" ")}").trim { it <= ' ' }, false
|
||||
)
|
||||
return true
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
package buttondevteam.lib.chat
|
||||
|
||||
import buttondevteam.core.component.channel.Channel
|
||||
import buttondevteam.lib.player.TBMCPlayerBase
|
||||
import org.bukkit.command.CommandSender
|
||||
import buttondevteam.lib.player.ChromaGamerBase
|
||||
|
||||
class Command2MCSender(val sender: TBMCPlayerBase, val channel: Channel, val permCheck: CommandSender) : Command2Sender {
|
||||
class Command2MCSender(val sender: ChromaGamerBase, val channel: Channel, val permCheck: ChromaGamerBase) : Command2Sender {
|
||||
// TODO: Remove this class and only use the user classes.
|
||||
// TODO: The command context should be stored separately.
|
||||
override fun sendMessage(message: String) {
|
||||
|
|
|
@ -10,9 +10,9 @@ import buttondevteam.lib.TBMCChatEvent
|
|||
import buttondevteam.lib.TBMCChatPreprocessEvent
|
||||
import buttondevteam.lib.TBMCSystemChatEvent
|
||||
import buttondevteam.lib.TBMCSystemChatEvent.BroadcastTarget
|
||||
import buttondevteam.lib.player.ChromaGamerBase
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.ChatColor
|
||||
import org.bukkit.command.CommandSender
|
||||
import java.util.function.Supplier
|
||||
|
||||
object TBMCChatAPI {
|
||||
|
@ -38,7 +38,7 @@ object TBMCChatAPI {
|
|||
val rtr = getScoreOrSendError(channel, cm.permCheck)
|
||||
val score = rtr.score
|
||||
if (score == Channel.SCORE_SEND_NOPE || rtr.groupID == null) return@Supplier true
|
||||
val eventPre = TBMCChatPreprocessEvent(cm.sender, channel, cm.message)
|
||||
val eventPre = TBMCChatPreprocessEvent(cm.user, channel, cm.message)
|
||||
Bukkit.getPluginManager().callEvent(eventPre)
|
||||
if (eventPre.isCancelled) return@Supplier true
|
||||
cm.message = eventPre.message
|
||||
|
@ -74,7 +74,7 @@ object TBMCChatAPI {
|
|||
return callEventAsync(event)
|
||||
}
|
||||
|
||||
private fun getScoreOrSendError(channel: Channel, sender: CommandSender): RecipientTestResult {
|
||||
private fun getScoreOrSendError(channel: Channel, sender: ChromaGamerBase): RecipientTestResult {
|
||||
val result = channel.getRTR(sender)
|
||||
if (result.errormessage != null) sender.sendMessage("${ChatColor.RED}" + result.errormessage)
|
||||
return result
|
||||
|
|
|
@ -167,6 +167,13 @@ abstract class ChromaGamerBase : Command2Sender {
|
|||
.findAny().orElseThrow { RuntimeException("Channel $id not found!") }
|
||||
}, { ch -> ch.identifier })
|
||||
|
||||
/**
|
||||
* Check channel access by checking if the user is in the given group. If the group is null, check if the user is OP.
|
||||
*
|
||||
* Note that these groups originally come from Minecraft.
|
||||
*/ // TODO: Allow if a connected account has access
|
||||
abstract fun checkChannelInGroup(group: String?): Channel.RecipientTestResult
|
||||
|
||||
companion object {
|
||||
private const val TBMC_PLAYERS_DIR = "TBMC/players/"
|
||||
private val senderConverters = ArrayList<Function<CommandSender, out Optional<out ChromaGamerBase>>>()
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package buttondevteam.lib.player
|
||||
|
||||
import buttondevteam.core.MainPlugin
|
||||
import buttondevteam.core.component.channel.Channel
|
||||
import buttondevteam.lib.architecture.IHaveConfig
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.entity.Player
|
||||
|
@ -45,7 +47,6 @@ abstract class TBMCPlayerBase : ChromaGamerBase() {
|
|||
}
|
||||
|
||||
override fun sendMessage(message: String) {
|
||||
// TODO: Random senders (Discord) won't receive messages. Including when trying to chat.
|
||||
player?.sendMessage(message)
|
||||
}
|
||||
|
||||
|
@ -57,6 +58,18 @@ abstract class TBMCPlayerBase : ChromaGamerBase() {
|
|||
return playerName.get()
|
||||
}
|
||||
|
||||
override fun checkChannelInGroup(group: String?): Channel.RecipientTestResult {
|
||||
return Channel.noScoreResult(
|
||||
{ s ->
|
||||
s is TBMCPlayerBase && (s.offlinePlayer.isOp || s.player != null && group?.let { pg ->
|
||||
MainPlugin.permission.playerInGroup(s.player, pg)
|
||||
} ?: false)
|
||||
},
|
||||
"You need to be a(n) ${group ?: "OP"} to use this channel.",
|
||||
this
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Get player as a plugin player.
|
||||
|
|
Loading…
Reference in a new issue