Implicit classes for conversion, more fixing

Added 'extension methods' to convert to Scala-friendly formats easily
This commit is contained in:
Norbi Peti 2021-03-09 02:47:11 +01:00
parent 7296ebd2f8
commit a0a7f756c4
No known key found for this signature in database
GPG key ID: DBA4C4549A927E56
17 changed files with 286 additions and 260 deletions

View file

@ -4,7 +4,7 @@ import buttondevteam.discordplugin.ChannelconBroadcast.ChannelconBroadcast
import buttondevteam.discordplugin.mcchat.MCChatUtils
import discord4j.core.`object`.entity.Message
import discord4j.core.`object`.entity.channel.MessageChannel
import reactor.core.publisher.Mono
import reactor.core.scala.publisher.SMono
import javax.annotation.Nullable
@ -20,8 +20,8 @@ object ChromaBot {
*
* @param message The message to send, duh (use {@link MessageChannel# createMessage ( String )})
*/
def sendMessage(message: java.util.function.Function[Mono[MessageChannel], Mono[Message]]): Unit =
MCChatUtils.forPublicPrivateChat(message.apply(_)).subscribe
def sendMessage(message: SMono[MessageChannel] => SMono[Message]): Unit =
MCChatUtils.forPublicPrivateChat(message).subscribe
/**
* Send a message to the chat channels, private chats and custom chats.
@ -29,8 +29,8 @@ object ChromaBot {
* @param message The message to send, duh
* @param toggle The toggle type for channelcon
*/
def sendMessageCustomAsWell(message: Function[Mono[MessageChannel], Mono[Message]], @Nullable toggle: ChannelconBroadcast): Unit =
MCChatUtils.forCustomAndAllMCChat(message.apply, toggle, false).subscribe
def sendMessageCustomAsWell(message: SMono[MessageChannel] => SMono[Message], @Nullable toggle: ChannelconBroadcast): Unit =
MCChatUtils.forCustomAndAllMCChat(message.apply, toggle, hookmsg = false).subscribe
def updatePlayerList(): Unit =
MCChatUtils.updatePlayerList()

View file

@ -5,8 +5,9 @@ import buttondevteam.lib.architecture.{Component, ConfigData, IHaveConfig, ReadO
import discord4j.common.util.Snowflake
import discord4j.core.`object`.entity.channel.MessageChannel
import discord4j.core.`object`.entity.{Guild, Message, Role}
import discord4j.core.spec.EmbedCreateSpec
import reactor.core.scala.publisher.SMono
import discord4j.core.spec.{EmbedCreateSpec, Spec}
import reactor.core.publisher.{Flux, Mono}
import reactor.core.scala.publisher.{SFlux, SMono}
import java.util
import java.util.Comparator
@ -206,4 +207,17 @@ object DPUtils {
getMessageChannel(config.getPath, config.get)
def ignoreError[T](mono: SMono[T]): SMono[T] = mono.onErrorResume((_: Throwable) => SMono.empty)
implicit class MonoExtensions[T](mono: Mono[T]) {
def ^^(): SMono[T] = SMono(mono)
}
implicit class FluxExtensions[T](flux: Flux[T]) {
def ^^(): SFlux[T] = SFlux(flux)
}
implicit class SpecExtensions[T <: Spec[_]](spec: T) {
def ^^(): Unit = ()
}
}

View file

@ -89,7 +89,7 @@ import scala.annotation.tailrec
if (msgsb.nonEmpty) sendMsg(channel.get(), msgsb.toString())
if (modmsgsb.nonEmpty) sendMsg(modChannel.get(), modmsgsb.toString())
if (lastAnnouncementTime.get ne lastanntime) lastAnnouncementTime.set(lastanntime) // If sending succeeded
if (lastAnnouncementTime.get != lastanntime) lastAnnouncementTime.set(lastanntime) // If sending succeeded
} catch {
case e: Exception =>
e.printStackTrace()

View file

@ -17,7 +17,9 @@ import org.bukkit.entity.Player
var WaitingToConnect: HashBiMap[String, String] = HashBiMap.create
}
@CommandClass(helpText = Array(Array("Connect command", "This command lets you connect your account with a Minecraft account. This allows using the private Minecraft chat and other things."))) class ConnectCommand extends ICommand2DC {
@CommandClass(helpText = Array("Connect command",
"This command lets you connect your account with a Minecraft account." +
" This allows using the private Minecraft chat and other things.")) class ConnectCommand extends ICommand2DC {
@Command2.Subcommand def `def`(sender: Command2DCSender, Minecraftname: String): Boolean = {
val message = sender.getMessage
val channel = message.getChannel.block

View file

@ -16,7 +16,7 @@ class DebugCommand extends ICommand2DC {
.map((u: User) => SMono(u.asMember(DiscordPlugin.mainServer.getId))).getOrElse(SMono.empty))
.flatMap((m: Member) => DiscordPlugin.plugin.modRole.get
.map(mr => m.getRoleIds.stream.anyMatch((r: Snowflake) => r == mr.getId))
.switchIfEmpty(SMono.fromCallable(() => DiscordPlugin.mainServer.getOwnerId.asLong eq m.getId.asLong)))
.switchIfEmpty(SMono.fromCallable(() => DiscordPlugin.mainServer.getOwnerId.asLong == m.getId.asLong)))
.onErrorResume(_ => SMono.just(false)) //Role not found
.subscribe(success => {
if (success) {

View file

@ -5,6 +5,7 @@ import buttondevteam.discordplugin.DiscordPlugin
import buttondevteam.lib.TBMCDebugMessageEvent
import discord4j.core.`object`.entity.channel.MessageChannel
import org.bukkit.event.{EventHandler, Listener}
import reactor.core.scala.publisher.SMono
object DebugMessageListener {
private def SendMessage(message: String): Unit = {
@ -16,7 +17,7 @@ object DebugMessageListener {
sb.append("```").append("\n")
sb.append(if (message.length > 2000) message.substring(0, 2000) else message).append("\n")
sb.append("```")
mc.flatMap((ch: MessageChannel) => ch.createMessage(sb.toString)).subscribe
mc.flatMap((ch: MessageChannel) => SMono(ch.createMessage(sb.toString))).subscribe
} catch {
case ex: Exception =>
ex.printStackTrace()

View file

@ -107,7 +107,7 @@ class FunModule extends Component[DiscordPlugin] with Listener {
* Answers for a recognized question. Selected randomly.
*/
final private val serverReadyAnswers: ConfigData[util.ArrayList[String]] =
getConfig.getData("serverReadyAnswers", () => Lists.newArrayList(FunModule.serverReadyStrings))
getConfig.getData("serverReadyAnswers", () => Lists.newArrayList(FunModule.serverReadyStrings): _*)
private def createUsableServerReadyStrings(): Unit =
IntStream.range(0, serverReadyAnswers.get.size).forEach((i: Int) => FunModule.usableServerReadyStrings.add(i.toShort))

View file

@ -39,9 +39,10 @@ object MCChatCustom {
@Nullable def getCustomChat(channel: Snowflake): CustomLMD =
lastmsgCustom.find(_.channel.getId.asLong == channel.asLong).orNull
def removeCustomChat(channel: Snowflake): Unit = {
def removeCustomChat(channel: Snowflake): Boolean = {
lastmsgCustom synchronized {
MCChatUtils.lastmsgfromd.remove(channel.asLong)
val count = lastmsgCustom.size
lastmsgCustom.filterInPlace(lmd => {
if (lmd.channel.getId.asLong != channel.asLong) return true
lmd.mcchannel match {
@ -50,6 +51,7 @@ object MCChatCustom {
}
false
})
lastmsgCustom.size < count
}
}

View file

@ -1,7 +1,6 @@
package buttondevteam.discordplugin.mcchat
import buttondevteam.core.ComponentManager
import buttondevteam.core.component.channel.Channel
import buttondevteam.discordplugin._
import buttondevteam.discordplugin.listeners.CommandListener
import buttondevteam.discordplugin.playerfaker.{VanillaCommandListener, VanillaCommandListener14, VanillaCommandListener15}
@ -24,10 +23,10 @@ import reactor.core.scala.publisher.{SFlux, SMono}
import java.time.Instant
import java.util
import java.util.Optional
import java.util.concurrent.{LinkedBlockingQueue, TimeoutException}
import java.util.function.{Consumer, Function, Predicate}
import java.util.function.{Consumer, Predicate}
import java.util.stream.Collectors
import scala.jdk.CollectionConverters.SetHasAsScala
import scala.jdk.OptionConverters.RichOptional
object MCChatListener {
@ -133,7 +132,7 @@ class MCChatListener(val module: MinecraftChatModule) extends Listener {
val isdifferentchannel: Predicate[Snowflake] = (id: Snowflake) => !((e.getSender.isInstanceOf[DiscordSenderBase])) || (e.getSender.asInstanceOf[DiscordSenderBase]).getChannel.getId.asLong != id.asLong
if (e.getChannel.isGlobal && (e.isFromCommand || isdifferentchannel.test(module.chatChannel.get))) {
if (MCChatUtils.lastmsgdata == null)
MCChatUtils.lastmsgdata = new MCChatUtils.LastMsgData(module.chatChannelMono.block, null)
MCChatUtils.lastmsgdata = new MCChatUtils.LastMsgData(module.chatChannelMono.block(), null)
doit(MCChatUtils.lastmsgdata)
}
@ -146,7 +145,7 @@ class MCChatListener(val module: MinecraftChatModule) extends Listener {
MCChatCustom.lastmsgCustom.filterInPlace(lmd => {
if ((e.isFromCommand || isdifferentchannel.test(lmd.channel.getId)) //Test if msg is from Discord
&& e.getChannel.ID == lmd.mcchannel.ID //If it's from a command, the command msg has been deleted, so we need to send it
&& e.getGroupID == lmd.groupID) { //Check if this is the group we want to test - #58
&& e.getGroupID() == lmd.groupID) { //Check if this is the group we want to test - #58
if (e.shouldSendTo(lmd.dcp)) { //Check original user's permissions
doit(lmd)
}
@ -254,18 +253,17 @@ class MCChatListener(val module: MinecraftChatModule) extends Listener {
.filter(channel => {
MCChatUtils.resetLastMessage(channel)
recevents.add(ev)
if (rectask != null) {
return true
}
recrun = () => {
recthread = Thread.currentThread
processDiscordToMC()
if (DiscordPlugin.plugin.isEnabled && !(stop)) {
rectask = Bukkit.getScheduler.runTaskAsynchronously(DiscordPlugin.plugin, recrun) //Continue message processing
if (rectask == null) {
recrun = () => {
recthread = Thread.currentThread
processDiscordToMC()
if (DiscordPlugin.plugin.isEnabled && !(stop)) {
rectask = Bukkit.getScheduler.runTaskAsynchronously(DiscordPlugin.plugin, recrun) //Continue message processing
}
}
rectask = Bukkit.getScheduler.runTaskAsynchronously(DiscordPlugin.plugin, recrun) //Start message processing
}
rectask = Bukkit.getScheduler.runTaskAsynchronously(DiscordPlugin.plugin, recrun) //Start message processing
return true
true
}).map(_ => false).defaultIfEmpty(true)
}
@ -299,47 +297,44 @@ class MCChatListener(val module: MinecraftChatModule) extends Listener {
val dsender: DiscordSenderBase = MCChatUtils.getSender(event.getMessage.getChannelId, sender)
val user: DiscordPlayer = dsender.getChromaUser
for (u <- SFlux(event.getMessage.getUserMentions).toIterable()) { //TODO: Role mentions
dmessage = dmessage.replace(u.getMention, "@" + u.getUsername) // TODO: IG Formatting
val m: Optional[Member] = u.asMember(DiscordPlugin.mainServer.getId).onErrorResume((t: Throwable) => Mono.empty).blockOptional
if (m.isPresent) {
val mm: Member = m.get
val nick: String = mm.getDisplayName
dmessage = dmessage.replace(mm.getNicknameMention, "@" + nick)
def replaceUserMentions(): Unit = {
for (u <- SFlux(event.getMessage.getUserMentions).toIterable()) { //TODO: Role mentions
dmessage = dmessage.replace(u.getMention, "@" + u.getUsername) // TODO: IG Formatting
val m = u.asMember(DiscordPlugin.mainServer.getId).onErrorResume(_ => Mono.empty).blockOptional
if (m.isPresent) {
val mm: Member = m.get
val nick: String = mm.getDisplayName
dmessage = dmessage.replace(mm.getNicknameMention, "@" + nick)
}
}
}
for (ch <- SFlux(event.getGuild.flux).flatMap(_.getChannels).toIterable()) {
dmessage = dmessage.replace(ch.getMention, "#" + ch.getName)
}
dmessage = EmojiParser.parseToAliases(dmessage, EmojiParser.FitzpatrickAction.PARSE) //Converts emoji to text- TODO: Add option to disable (resource pack?)
dmessage = dmessage.replaceAll(":(\\S+)\\|type_(?:(\\d)|(1)_2):", ":$1::skin-tone-$2:") //Convert to Discord's format so it still shows up
dmessage = dmessage.replaceAll("<a?:(\\S+):(\\d+)>", ":$1:") //We don't need info about the custom emojis, just display their text
val getChatMessage: Function[String, String] = (msg: String) => //
msg + (if (event.getMessage.getAttachments.size > 0) {
"\n" + event.getMessage.getAttachments.stream.map(_.getUrl).collect(Collectors.joining("\n"))
}
else {
""
})
val clmd: MCChatCustom.CustomLMD = MCChatCustom.getCustomChat(event.getMessage.getChannelId)
var react: Boolean = false
val sendChannel: MessageChannel = event.getMessage.getChannel.block
val isPrivate: Boolean = sendChannel.isInstanceOf[PrivateChannel]
if (dmessage.startsWith("/")) { // Ingame command
if (handleIngameCommand(event, dmessage, dsender, user, clmd, isPrivate)) {
return
replaceUserMentions()
def replaceChannelMentions(): Unit = {
for (ch <- SFlux(event.getGuild.flux).flatMap(_.getChannels).toIterable()) {
dmessage = dmessage.replace(ch.getMention, "#" + ch.getName)
}
}
else { // Not a command
react = handleIngameMessage(event, dmessage, dsender, user, getChatMessage, clmd, isPrivate)
replaceChannelMentions()
def replaceEmojis(): Unit = {
dmessage = EmojiParser.parseToAliases(dmessage, EmojiParser.FitzpatrickAction.PARSE) //Converts emoji to text- TODO: Add option to disable (resource pack?)
dmessage = dmessage.replaceAll(":(\\S+)\\|type_(?:(\\d)|(1)_2):", ":$1::skin-tone-$2:") //Convert to Discord's format so it still shows up
dmessage = dmessage.replaceAll("<a?:(\\S+):(\\d+)>", ":$1:") //We don't need info about the custom emojis, just display their text
}
if (react) {
replaceEmojis()
val clmd = MCChatCustom.getCustomChat(event.getMessage.getChannelId)
val sendChannel = event.getMessage.getChannel.block
val isPrivate = sendChannel.isInstanceOf[PrivateChannel]
def addCheckmark() = {
try {
val lmfd: Message = MCChatUtils.lastmsgfromd.get(event.getMessage.getChannelId.asLong)
if (lmfd != null) {
val lmfd = MCChatUtils.lastmsgfromd.get(event.getMessage.getChannelId.asLong)
if (lmfd != null)
lmfd.removeSelfReaction(DiscordPlugin.DELIVERED_REACTION).subscribe // Remove it no matter what, we know it's there 99.99% of the time
}
} catch {
case e: Exception =>
TBMCCoreAPI.SendException("An error occured while removing reactions from chat!", e, module)
@ -347,123 +342,133 @@ class MCChatListener(val module: MinecraftChatModule) extends Listener {
MCChatUtils.lastmsgfromd.put(event.getMessage.getChannelId.asLong, event.getMessage)
event.getMessage.addReaction(DiscordPlugin.DELIVERED_REACTION).subscribe
}
if (dmessage.startsWith("/")) // Ingame command
handleIngameCommand(event, dmessage, dsender, user, clmd, isPrivate)
else if (handleIngameMessage(event, dmessage, dsender, user, clmd, isPrivate)) // Not a command
addCheckmark()
} catch {
case e: Exception =>
TBMCCoreAPI.SendException("An error occured while handling message \"" + dmessage + "\"!", e, module)
}
}
private def handleIngameMessage(event: MessageCreateEvent, dmessage: String, dsender: DiscordSenderBase, user: DiscordPlayer, getChatMessage: Function[String, String], clmd: MCChatCustom.CustomLMD, isPrivate: Boolean): Boolean = {
var react: Boolean = false
if (dmessage.isEmpty && event.getMessage.getAttachments.size == 0 && !(isPrivate) && (event.getMessage.getType eq Message.Type.CHANNEL_PINNED_MESSAGE)) {
val rtr: Channel.RecipientTestResult = if (clmd != null) {
clmd.mcchannel.getRTR(clmd.dcp)
}
else {
dsender.getChromaUser.channel.get.getRTR(dsender)
}
TBMCChatAPI.SendSystemMessage(if (clmd != null) clmd.mcchannel else dsender.getChromaUser.channel.get, rtr,
(dsender match {
case player: Player =>
player.getDisplayName
case _ =>
dsender.getName
}) + " pinned a message on Discord.", TBMCSystemChatEvent.BroadcastTarget.ALL)
/**
* Handles a message coming from Discord to Minecraft.
*
* @param event The Discord event
* @param dmessage The message itself
* @param dsender The sender who sent it
* @param user The Chroma user of the sender
* @param clmd Custom chat last message data (if in a custom chat)
* @param isPrivate Whether the chat is private
* @return Whether the bot should react with a checkmark
*/
private def handleIngameMessage(event: MessageCreateEvent, dmessage: String, dsender: DiscordSenderBase, user: DiscordPlayer,
clmd: MCChatCustom.CustomLMD, isPrivate: Boolean): Boolean = {
def getAttachmentText = {
val att = event.getMessage.getAttachments.asScala
if (att.nonEmpty) att map (_.getUrl) mkString "\n"
else ""
}
if (event.getMessage.getType eq Message.Type.CHANNEL_PINNED_MESSAGE) {
val mcchannel = if (clmd != null) clmd.mcchannel else dsender.getChromaUser.channel.get
val rtr = mcchannel getRTR (if (clmd != null) clmd.dcp else dsender)
TBMCChatAPI.SendSystemMessage(mcchannel, rtr, (dsender match {
case player: Player => player.getDisplayName
case _ => dsender.getName
}) + " pinned a message on Discord.", TBMCSystemChatEvent.BroadcastTarget.ALL)
false
}
else {
val cmb: ChatMessage.ChatMessageBuilder = ChatMessage.builder(dsender, user, getChatMessage.apply(dmessage)).fromCommand(false)
if (clmd != null) {
val cmb = ChatMessage.builder(dsender, user, dmessage + getAttachmentText()).fromCommand(false)
if (clmd != null)
TBMCChatAPI.SendChatMessage(cmb.permCheck(clmd.dcp).build, clmd.mcchannel)
}
else {
else
TBMCChatAPI.SendChatMessage(cmb.build)
}
react = true
true
}
react
}
private def handleIngameCommand(event: MessageCreateEvent, dmessage: String, dsender: DiscordSenderBase, user: DiscordPlayer, clmd: MCChatCustom.CustomLMD, isPrivate: Boolean): Boolean = {
if (!(isPrivate)) {
/**
* Handle a Minecraft command coming from Discord.
*
* @param event The Discord event
* @param dmessage The Discord mewsage, starting with a slash
* @param dsender The sender who sent it
* @param user The Chroma user of the sender
* @param clmd The custom last message data (if in a custom chat)
* @param isPrivate Whether the chat is private
* @return
*/
private def handleIngameCommand(event: MessageCreateEvent, dmessage: String, dsender: DiscordSenderBase, user: DiscordPlayer,
clmd: MCChatCustom.CustomLMD, isPrivate: Boolean): Unit = {
def notWhitelisted(cmd: String) = module.whitelistedCommands.get.stream
.noneMatch(s => cmd == s || cmd.startsWith(s + " "))
def whitelistedCommands = module.whitelistedCommands.get.stream
.map("/" + _).collect(Collectors.joining(", "))
if (!isPrivate)
event.getMessage.delete.subscribe
}
val cmd: String = dmessage.substring(1)
val cmdlowercased: String = cmd.toLowerCase
if (dsender.isInstanceOf[DiscordSender] && module.whitelistedCommands.get.stream.noneMatch((s: String) => cmdlowercased == s || cmdlowercased.startsWith(s + " "))) { // Command not whitelisted
dsender.sendMessage("Sorry, you can only access these commands from here:\n" + module.whitelistedCommands.get.stream.map((uc: String) => "/" + uc).collect(Collectors.joining(", ")) + (if (user.getConnectedID(classOf[TBMCPlayer]) == null) {
"\nTo access your commands, first please connect your accounts, using /connect in " + DPUtils.botmention + "\nThen y"
}
else {
"\nY"
}) + "ou can access all of your regular commands (even offline) in private chat: DM me `mcchat`!")
return true
val cmd = dmessage.substring(1)
val cmdlowercased = cmd.toLowerCase
if (dsender.isInstanceOf[DiscordSender] && notWhitelisted(cmdlowercased)) { // Command not whitelisted
dsender.sendMessage("Sorry, you can only access these commands from here:\n" + whitelistedCommands() +
(if (user.getConnectedID(classOf[TBMCPlayer]) == null)
"\nTo access your commands, first please connect your accounts, using /connect in " + DPUtils.botmention
+ "\nThen y" else "\nY") + "ou can access all of your regular commands (even offline) in private chat: DM me `mcchat`!")
return
}
module.log(dsender.getName + " ran from DC: /" + cmd)
if (dsender.isInstanceOf[DiscordSender] && runCustomCommand(dsender, cmdlowercased)) {
return true
return
}
val channel: Channel = if (clmd == null) {
user.channel.get
}
else {
clmd.mcchannel
}
val ev: TBMCCommandPreprocessEvent = new TBMCCommandPreprocessEvent(dsender, channel, dmessage, if (clmd == null) {
dsender
}
else {
clmd.dcp
val channel = if (clmd == null) user.channel.get else clmd.mcchannel
val ev = new TBMCCommandPreprocessEvent(dsender, channel, dmessage, if (clmd == null) dsender else clmd.dcp)
Bukkit.getScheduler.runTask(DiscordPlugin.plugin, () => { //Commands need to be run sync
Bukkit.getPluginManager.callEvent(ev)
if (!ev.isCancelled)
runMCCommand(dsender, cmd)
})
Bukkit.getScheduler.runTask(DiscordPlugin.plugin, //Commands need to be run sync
() => {
def foo(): Unit = {
Bukkit.getPluginManager.callEvent(ev)
if (ev.isCancelled) {
return
}
try {
val mcpackage: String = Bukkit.getServer.getClass.getPackage.getName
if (!(module.enableVanillaCommands.get)) {
Bukkit.dispatchCommand(dsender, cmd)
}
else {
if (mcpackage.contains("1_12")) {
VanillaCommandListener.runBukkitOrVanillaCommand(dsender, cmd)
}
else {
if (mcpackage.contains("1_14")) {
VanillaCommandListener14.runBukkitOrVanillaCommand(dsender, cmd)
}
else {
if (mcpackage.contains("1_15") || mcpackage.contains("1_16")) {
VanillaCommandListener15.runBukkitOrVanillaCommand(dsender, cmd)
}
else {
Bukkit.dispatchCommand(dsender, cmd)
}
}
}
}
} catch {
case e: NoClassDefFoundError =>
TBMCCoreAPI.SendException("A class is not found when trying to run command " + cmd + "!", e, module)
case e: Exception =>
TBMCCoreAPI.SendException("An error occurred when trying to run command " + cmd + "! Vanilla commands are only supported in some MC versions.", e, module)
}
}
foo()
})
return true
}
private def runMCCommand(dsender: DiscordSenderBase, cmd: String): Unit = {
try {
val mcpackage = Bukkit.getServer.getClass.getPackage.getName
if (!module.enableVanillaCommands.get)
Bukkit.dispatchCommand(dsender, cmd)
else if (mcpackage.contains("1_12"))
VanillaCommandListener.runBukkitOrVanillaCommand(dsender, cmd)
else if (mcpackage.contains("1_14"))
VanillaCommandListener14.runBukkitOrVanillaCommand(dsender, cmd)
else if (mcpackage.contains("1_15") || mcpackage.contains("1_16"))
VanillaCommandListener15.runBukkitOrVanillaCommand(dsender, cmd)
else
Bukkit.dispatchCommand(dsender, cmd)
} catch {
case e: NoClassDefFoundError =>
TBMCCoreAPI.SendException("A class is not found when trying to run command " + cmd + "!", e, module)
case e: Exception =>
TBMCCoreAPI.SendException("An error occurred when trying to run command " + cmd + "! Vanilla commands are only supported in some MC versions.", e, module)
}
}
/**
* Handles custom public commands. Used to hide sensitive information in public chats.
*
* @param dsender The Discord sender
* @param cmdlowercased The command, lowercased
* @return Whether the command was a custom command
*/
private def runCustomCommand(dsender: DiscordSenderBase, cmdlowercased: String): Boolean = {
if (cmdlowercased.startsWith("list")) {
val players: util.Collection[_ <: Player] = Bukkit.getOnlinePlayers
val players = Bukkit.getOnlinePlayers
dsender.sendMessage("There are " + players.stream.filter(MCChatUtils.checkEssentials).count + " out of " + Bukkit.getMaxPlayers + " players online.")
dsender.sendMessage("Players: " + players.stream.filter(MCChatUtils.checkEssentials).map(Player.getDisplayName).collect(Collectors.joining(", ")))
return true
dsender.sendMessage("Players: " + players.stream.filter(MCChatUtils.checkEssentials).map(_.getDisplayName).collect(Collectors.joining(", ")))
true
}
return false
else false
}
}

View file

@ -4,12 +4,12 @@ import buttondevteam.core.ComponentManager
import buttondevteam.discordplugin.mcchat.MCChatUtils.LastMsgData
import buttondevteam.discordplugin.{DiscordConnectedPlayer, DiscordPlayer, DiscordPlugin, DiscordSenderBase}
import buttondevteam.lib.player.TBMCPlayer
import discord4j.common.util.Snowflake
import discord4j.core.`object`.entity.User
import discord4j.core.`object`.entity.channel.{MessageChannel, PrivateChannel}
import org.bukkit.Bukkit
import scala.collection.mutable.ListBuffer
import scala.jdk.javaapi.CollectionConverters.asScala
object MCChatPrivate {
/**
@ -39,7 +39,7 @@ object MCChatPrivate {
def foo(): Unit = {
if ((p == null || p.isInstanceOf[DiscordSenderBase]) // Player is offline - If the player is online, that takes precedence
&& sender.isLoggedIn) { //Don't call the quit event if login failed
MCChatUtils.callLogoutEvent(sender, false) //The next line has to run *after* this one, so can't use the needsSync parameter
MCChatUtils.callLogoutEvent(sender, needsSync = false) //The next line has to run *after* this one, so can't use the needsSync parameter
}
MCChatUtils.LoggedInPlayers.remove(sender.getUniqueId)
@ -61,14 +61,13 @@ object MCChatPrivate {
def isMinecraftChatEnabled(dp: DiscordPlayer): Boolean = isMinecraftChatEnabled(dp.getDiscordID)
def isMinecraftChatEnabled(did: String): Boolean = { // Don't load the player data just for this
lastmsgPerUser.stream.anyMatch((lmd: MCChatUtils.LastMsgData) =>
lmd.channel.asInstanceOf[PrivateChannel].getRecipientIds.stream.anyMatch((u: Snowflake) => u.asString == did))
lastmsgPerUser.exists(_.channel.asInstanceOf[PrivateChannel].getRecipientIds.stream.anyMatch(u => u.asString == did))
}
def logoutAll(): Unit = {
MCChatUtils.ConnectedSenders synchronized {
for (entry <- asScala(MCChatUtils.ConnectedSenders.entrySet)) {
for (valueEntry <- entry.getValue.entrySet) {
for ((_, userMap) <- MCChatUtils.ConnectedSenders) {
for (valueEntry <- asScala(userMap.entrySet)) {
if (MCChatUtils.getSender(MCChatUtils.OnlineSenders, valueEntry.getKey, valueEntry.getValue.getUser) == null) { //If the player is online then the fake player was already logged out
MCChatUtils.callLogoutEvent(valueEntry.getValue, !Bukkit.isPrimaryThread)
}

View file

@ -18,7 +18,6 @@ import org.bukkit.entity.Player
import org.bukkit.event.Event
import org.bukkit.event.player.{AsyncPlayerPreLoginEvent, PlayerJoinEvent, PlayerLoginEvent, PlayerQuitEvent}
import org.bukkit.plugin.AuthorNagException
import org.reactivestreams.Publisher
import reactor.core.scala.publisher.SMono
import java.net.InetAddress
@ -46,7 +45,7 @@ object MCChatUtils {
@Nullable private[mcchat] var lastmsgdata: MCChatUtils.LastMsgData = null
private[mcchat] val lastmsgfromd = new LongObjectHashMap[Message] // Last message sent by a Discord user, used for clearing checkmarks
private var module: MinecraftChatModule = null
private val staticExcludedPlugins = Map[Class[_ <: Event], util.HashSet[String]]()
private val staticExcludedPlugins: concurrent.Map[Class[_ <: Event], util.HashSet[String]] = concurrent.TrieMap()
def updatePlayerList(): Unit = {
val mod = getModule
@ -102,22 +101,22 @@ object MCChatUtils {
addSender(senders, user.getId.asString, sender)
def addSender[T <: DiscordSenderBase](senders: concurrent.Map[String, ConcurrentHashMap[Snowflake, T]], did: String, sender: T): T = {
val origMap = senders.get(did)
val map = if (origMap.isEmpty) new ConcurrentHashMap[Snowflake, T] else origMap.get
val mapOpt = senders.get(did)
val map = if (mapOpt.isEmpty) new ConcurrentHashMap[Snowflake, T] else mapOpt.get
map.put(sender.getChannel.getId, sender)
senders.put(did, map)
sender
}
def getSender[T <: DiscordSenderBase](senders: ConcurrentHashMap[String, ConcurrentHashMap[Snowflake, T]], channel: Snowflake, user: User): T = {
val map = senders.get(user.getId.asString)
if (map != null) map.get(channel)
def getSender[T <: DiscordSenderBase](senders: concurrent.Map[String, ConcurrentHashMap[Snowflake, T]], channel: Snowflake, user: User): T = {
val mapOpt = senders.get(user.getId.asString)
if (mapOpt.nonEmpty) mapOpt.get.get(channel)
else null.asInstanceOf
}
def removeSender[T <: DiscordSenderBase](senders: ConcurrentHashMap[String, ConcurrentHashMap[Snowflake, T]], channel: Snowflake, user: User): T = {
val map = senders.get(user.getId.asString)
if (map != null) map.remove(channel)
def removeSender[T <: DiscordSenderBase](senders: concurrent.Map[String, ConcurrentHashMap[Snowflake, T]], channel: Snowflake, user: User): T = {
val mapOpt = senders.get(user.getId.asString)
if (mapOpt.nonEmpty) mapOpt.get.remove(channel)
else null.asInstanceOf
}
@ -138,11 +137,12 @@ object MCChatUtils {
*/
def forCustomAndAllMCChat(action: SMono[MessageChannel] => SMono[_], @Nullable toggle: ChannelconBroadcast, hookmsg: Boolean): SMono[_] = {
if (notEnabled) return SMono.empty
val list = new ListBuffer[Publisher[_]]
if (!GeneralEventBroadcasterModule.isHooked || !hookmsg) list.append(forPublicPrivateChat(action))
val customLMDFunction = (cc: MCChatCustom.CustomLMD) => action(SMono.just(cc.channel))
if (toggle == null) MCChatCustom.lastmsgCustom.map(customLMDFunction).foreach(list.append(_))
else MCChatCustom.lastmsgCustom.filter((cc) => (cc.toggles & (1 << toggle.id)) ne 0).map(customLMDFunction).foreach(list.append(_))
val list =
List(if (!GeneralEventBroadcasterModule.isHooked || !hookmsg)
forPublicPrivateChat(action) else SMono.empty) ++
(if (toggle == null) MCChatCustom.lastmsgCustom
else MCChatCustom.lastmsgCustom.filter(cc => (cc.toggles & (1 << toggle.id)) != 0))
.map(_.channel).map(SMono.just).map(action)
SMono.whenDelayError(list)
}
@ -156,7 +156,7 @@ object MCChatUtils {
def forAllowedCustomMCChat(action: SMono[MessageChannel] => SMono[_], @Nullable sender: CommandSender, @Nullable toggle: ChannelconBroadcast): SMono[_] = {
if (notEnabled) return SMono.empty
val st = MCChatCustom.lastmsgCustom.filter(clmd => { //new TBMCChannelConnectFakeEvent(sender, clmd.mcchannel).shouldSendTo(clmd.dcp) - Thought it was this simple hehe - Wait, it *should* be this simple
if (toggle != null && ((clmd.toggles & (1 << toggle.id)) eq 0)) false //If null then allow
if (toggle != null && ((clmd.toggles & (1 << toggle.id)) == 0)) false //If null then allow
else if (sender == null) true
else clmd.groupID.equals(clmd.mcchannel.getGroupID(sender))
}).map(cc => action.apply(SMono.just(cc.channel))) //TODO: Send error messages on channel connect
@ -204,13 +204,12 @@ object MCChatUtils {
* This method will find the best sender to use: if the player is online, use that, if not but connected then use that etc.
*/
private[mcchat] def getSender(channel: Snowflake, author: User): DiscordSenderBase = { //noinspection OptionalGetWithoutIsPresent
List[() => DiscordSenderBase]( // https://stackoverflow.com/a/28833677/2703239
() => getSender[DiscordSenderBase](OnlineSenders, channel, author), // Find first non-null
() => getSender[DiscordSenderBase](ConnectedSenders, channel, author), // This doesn't support the public chat, but it'll always return null for it
() => getSender[DiscordSenderBase](UnconnectedSenders, channel, author), //
() => addSender[DiscordSenderBase](UnconnectedSenders, author,
new DiscordSender(author, SMono(DiscordPlugin.dc.getChannelById(channel)).block().asInstanceOf[MessageChannel])))
.map(_.apply()).find(sender => sender != null).get
Option(getSender(OnlineSenders, channel, author)) // Find first non-null
.orElse(Option(getSender(ConnectedSenders, channel, author))) // This doesn't support the public chat, but it'll always return null for it
.orElse(Option(getSender(UnconnectedSenders, channel, author))) //
.orElse(Option(addSender(UnconnectedSenders, author,
new DiscordSender(author, SMono(DiscordPlugin.dc.getChannelById(channel)).block().asInstanceOf[MessageChannel]))))
.get
}
/**

View file

@ -1,22 +1,22 @@
package buttondevteam.discordplugin.mcchat
import buttondevteam.discordplugin.DPUtils.FluxExtensions
import buttondevteam.discordplugin._
import buttondevteam.lib.TBMCSystemChatEvent
import buttondevteam.lib.player.{TBMCPlayer, TBMCPlayerBase, TBMCYEEHAWEvent}
import discord4j.common.util.Snowflake
import discord4j.core.`object`.entity.Role
import discord4j.core.`object`.entity.channel.MessageChannel
import discord4j.core.`object`.entity.{Member, Role, User}
import net.ess3.api.events.{AfkStatusChangeEvent, MuteStatusChangeEvent, NickChangeEvent, VanishStatusChangeEvent}
import org.bukkit.Bukkit
import org.bukkit.entity.Player
import org.bukkit.event.{EventHandler, EventPriority, Listener}
import org.bukkit.event.entity.PlayerDeathEvent
import org.bukkit.event.player.PlayerLoginEvent.Result
import org.bukkit.event.player._
import org.bukkit.event.server.{BroadcastMessageEvent, TabCompleteEvent}
import reactor.core.publisher.{Flux, Mono}
import java.util.Optional
import org.bukkit.event.{EventHandler, EventPriority, Listener}
import reactor.core.publisher.Flux
import reactor.core.scala.publisher.SMono
class MCListener(val module: MinecraftChatModule) extends Listener {
final private val muteRole = DPUtils.roleData(module.getConfig, "muteRole", "Muted")
@ -25,7 +25,7 @@ class MCListener(val module: MinecraftChatModule) extends Listener {
if (e.getResult ne Result.ALLOWED) return
if (e.getPlayer.isInstanceOf[DiscordConnectedPlayer]) return
val dcp = MCChatUtils.LoggedInPlayers.get(e.getPlayer.getUniqueId)
if (dcp != null) MCChatUtils.callLogoutEvent(dcp, needsSync = false)
if (dcp.nonEmpty) MCChatUtils.callLogoutEvent(dcp.get, needsSync = false)
}
@EventHandler(priority = EventPriority.MONITOR) def onPlayerJoin(e: PlayerJoinEvent): Unit = {
@ -34,15 +34,13 @@ class MCListener(val module: MinecraftChatModule) extends Listener {
def foo(): Unit = {
val p = e.getPlayer
val dp = TBMCPlayerBase.getPlayer(p.getUniqueId, classOf[TBMCPlayer]).getAs(classOf[DiscordPlayer])
if (dp != null) DiscordPlugin.dc.getUserById(Snowflake.of(dp.getDiscordID)).flatMap((user) => user.getPrivateChannel.flatMap((chan) => module.chatChannelMono.flatMap((cc: MessageChannel) => {
def foo(cc: MessageChannel) = {
MCChatUtils.addSender(MCChatUtils.OnlineSenders, dp.getDiscordID, DiscordPlayerSender.create(user, chan, p, module))
MCChatUtils.addSender(MCChatUtils.OnlineSenders, dp.getDiscordID, DiscordPlayerSender.create(user, cc, p, module)) //Stored per-channel
Mono.empty
}
foo(cc)
}))).subscribe
if (dp != null)
DiscordPlugin.dc.getUserById(Snowflake.of(dp.getDiscordID)).flatMap(user =>
user.getPrivateChannel.flatMap(chan => module.chatChannelMono.flatMap(cc => {
MCChatUtils.addSender(MCChatUtils.OnlineSenders, dp.getDiscordID, DiscordPlayerSender.create(user, chan, p, module))
MCChatUtils.addSender(MCChatUtils.OnlineSenders, dp.getDiscordID, DiscordPlayerSender.create(user, cc, p, module)) //Stored per-channel
SMono.empty
}))).subscribe
val message = e.getJoinMessage
sendJoinLeaveMessage(message, e.getPlayer)
ChromaBot.updatePlayerList()
@ -58,8 +56,8 @@ class MCListener(val module: MinecraftChatModule) extends Listener {
@EventHandler(priority = EventPriority.MONITOR) def onPlayerLeave(e: PlayerQuitEvent): Unit = {
if (e.getPlayer.isInstanceOf[DiscordConnectedPlayer]) return // Only care about real users
MCChatUtils.OnlineSenders.entrySet.removeIf((entry) => entry.getValue.entrySet.stream.anyMatch((p) => p.getValue.getUniqueId.equals(e.getPlayer.getUniqueId)))
Bukkit.getScheduler.runTaskAsynchronously(DiscordPlugin.plugin, () => Optional.ofNullable(MCChatUtils.LoggedInPlayers.get(e.getPlayer.getUniqueId)).ifPresent(MCChatUtils.callLoginEvents))
MCChatUtils.OnlineSenders.filterInPlace((_, userMap) => userMap.entrySet.stream.noneMatch(_.getValue.getUniqueId.equals(e.getPlayer.getUniqueId)))
Bukkit.getScheduler.runTaskAsynchronously(DiscordPlugin.plugin, () => MCChatUtils.LoggedInPlayers.get(e.getPlayer.getUniqueId).foreach(MCChatUtils.callLoginEvents))
Bukkit.getScheduler.runTaskLaterAsynchronously(DiscordPlugin.plugin, () => ChromaBot.updatePlayerList(), 5)
val message = e.getQuitMessage
sendJoinLeaveMessage(message, e.getPlayer)
@ -89,20 +87,22 @@ class MCListener(val module: MinecraftChatModule) extends Listener {
if (!source.isPlayer) return
val p = TBMCPlayerBase.getPlayer(source.getPlayer.getUniqueId, classOf[TBMCPlayer]).getAs(classOf[DiscordPlayer])
if (p == null) return
DPUtils.ignoreError(DiscordPlugin.dc.getUserById(Snowflake.of(p.getDiscordID)).flatMap((user: User) => user.asMember(DiscordPlugin.mainServer.getId)).flatMap((user: Member) => role.flatMap((r: Role) => {
def foo(r: Role): Mono[_] = {
if (e.getValue) user.addRole(r.getId)
else user.removeRole(r.getId)
val modlog = module.modlogChannel.get
val msg = (if (e.getValue) "M"
else "Unm") + "uted user: " + user.getUsername + "#" + user.getDiscriminator
module.log(msg)
if (modlog != null) return modlog.flatMap((ch: MessageChannel) => ch.createMessage(msg))
Mono.empty
}
DPUtils.ignoreError(SMono(DiscordPlugin.dc.getUserById(Snowflake.of(p.getDiscordID)))
.flatMap(user => SMono(user.asMember(DiscordPlugin.mainServer.getId)))
.flatMap(user => role.flatMap((r: Role) => {
def foo(r: Role): SMono[_] = {
if (e.getValue) user.addRole(r.getId)
else user.removeRole(r.getId)
val modlog = module.modlogChannel.get
val msg = (if (e.getValue) "M"
else "Unm") + "uted user: " + user.getUsername + "#" + user.getDiscriminator
module.log(msg)
if (modlog != null) return modlog.flatMap((ch: MessageChannel) => SMono(ch.createMessage(msg)))
SMono.empty
}
foo(r)
}))).subscribe
foo(r)
}))).subscribe
}
@EventHandler def onChatSystemMessage(event: TBMCSystemChatEvent): Unit =
@ -117,10 +117,10 @@ class MCListener(val module: MinecraftChatModule) extends Listener {
case _ => event.getSender.getName
}
//Channel channel = ChromaGamerBase.getFromSender(event.getSender()).channel().get(); - TODO
DiscordPlugin.mainServer.getEmojis.filter(e => "YEEHAW" == e.getName).take(1).singleOrEmpty
.map(Optional.of(_)).defaultIfEmpty(Optional.empty)
.flatMap((yeehaw) => MCChatUtils.forPublicPrivateChat(MCChatUtils.send(name +
yeehaw.map((guildEmoji) => " <:YEEHAW:" + guildEmoji.getId.asString + ">s").orElse(" YEEHAWs")))).subscribe
DiscordPlugin.mainServer.getEmojis.^^().filter(e => "YEEHAW" == e.getName).take(1).singleOrEmpty
.map(Option.apply).defaultIfEmpty(Option.empty)
.flatMap(yeehaw => MCChatUtils.forPublicPrivateChat(MCChatUtils.send(name +
yeehaw.map(guildEmoji => " <:YEEHAW:" + guildEmoji.getId.asString + ">s").getOrElse(" YEEHAWs")))).subscribe
}
@EventHandler def onNickChange(event: NickChangeEvent): Unit = MCChatUtils.updatePlayerList()

View file

@ -1,6 +1,7 @@
package buttondevteam.discordplugin.mcchat
import buttondevteam.core.component.channel.Channel
import buttondevteam.discordplugin.DPUtils.{MonoExtensions, SpecExtensions}
import buttondevteam.discordplugin.playerfaker.ServerWatcher
import buttondevteam.discordplugin.playerfaker.perm.LPInjector
import buttondevteam.discordplugin.util.DPState
@ -12,12 +13,12 @@ import discord4j.common.util.Snowflake
import discord4j.core.`object`.entity.channel.MessageChannel
import discord4j.rest.util.Color
import org.bukkit.Bukkit
import reactor.core.publisher.Mono
import reactor.core.scala.publisher.SMono
import java.util
import java.util.stream.Collectors
import java.util.{Objects, UUID}
import scala.jdk.CollectionConverters.IterableHasAsScala
/**
* Provides Minecraft chat connection to Discord. Commands may be used either in a public chat (limited) or in a DM.
@ -51,7 +52,7 @@ class MinecraftChatModule extends Component[DiscordPlugin] {
/**
* The channel where the plugin can log when it mutes a player on Discord because of a Minecraft mute
*/
val modlogChannel: ReadOnlyConfigData[Mono[MessageChannel]] = DPUtils.channelData(getConfig, "modlogChannel")
val modlogChannel: ReadOnlyConfigData[SMono[MessageChannel]] = DPUtils.channelData(getConfig, "modlogChannel")
/**
* The plugins to exclude from fake player events used for the 'mcchat' command - some plugins may crash, add them here
*/
@ -113,7 +114,7 @@ class MinecraftChatModule extends Component[DiscordPlugin] {
}
if (chcons != null) {
val chconkeys = chcons.getKeys(false)
for (chconkey <- chconkeys) {
for (chconkey <- chconkeys.asScala) {
val chcon = chcons.getConfigurationSection(chconkey)
val mcch = Channel.getChannels.filter((ch: Channel) => ch.ID == chcon.getString("mcchid")).findAny
val ch = DiscordPlugin.dc.getChannelById(Snowflake.of(chcon.getLong("chid"))).block
@ -122,15 +123,14 @@ class MinecraftChatModule extends Component[DiscordPlugin] {
val groupid = chcon.getString("groupid")
val toggles = chcon.getInt("toggles")
val brtoggles = chcon.getStringList("brtoggles")
if (!mcch.isPresent || ch == null || user == null || groupid == null) continue //todo: continue is not supported
Bukkit.getScheduler.runTask(getPlugin, () => {
def foo() = { //<-- Needed because of occasional ConcurrentModificationExceptions when creating the player (PermissibleBase)
val dcp = DiscordConnectedPlayer.create(user, ch.asInstanceOf[MessageChannel], UUID.fromString(chcon.getString("mcuid")), chcon.getString("mcname"), this)
MCChatCustom.addCustomChat(ch.asInstanceOf[MessageChannel], groupid, mcch.get, user, dcp, toggles, brtoggles.stream.map(TBMCSystemChatEvent.BroadcastTarget.get).filter(Objects.nonNull).collect(Collectors.toSet))
}
foo()
})
if (mcch.isPresent && ch != null && user != null && groupid != null) {
Bukkit.getScheduler.runTask(getPlugin, () => { //<-- Needed because of occasional ConcurrentModificationExceptions when creating the player (PermissibleBase)
val dcp = DiscordConnectedPlayer.create(user, ch.asInstanceOf[MessageChannel],
UUID.fromString(chcon.getString("mcuid")), chcon.getString("mcname"), this)
MCChatCustom.addCustomChat(ch.asInstanceOf[MessageChannel], groupid, mcch.get, user, dcp, toggles,
brtoggles.asScala.map(TBMCSystemChatEvent.BroadcastTarget.get).filter(Objects.nonNull).toSet)
})
}
}
}
try if (lpInjector == null) lpInjector = new LPInjector(DiscordPlugin.plugin)
@ -205,7 +205,7 @@ class MinecraftChatModule extends Component[DiscordPlugin] {
chconc.set("mcname", chcon.dcp.getName)
chconc.set("groupid", chcon.groupID)
chconc.set("toggles", chcon.toggles)
chconc.set("brtoggles", chcon.brtoggles.stream.map(_.getName).collect(Collectors.toList))
chconc.set("brtoggles", chcon.brtoggles.map(_.getName).toList)
}
if (listener != null) { //Can be null if disabled because of a config error
listener.stop(true)
@ -219,10 +219,10 @@ class MinecraftChatModule extends Component[DiscordPlugin] {
* It will block to make sure all messages are sent
*/
private def sendStateMessage(color: Color, message: String) =
MCChatUtils.forCustomAndAllMCChat(_.flatMap(_.createEmbed(_.setColor(color).setTitle(message))),
ChannelconBroadcast.RESTART, hookmsg = false).block
MCChatUtils.forCustomAndAllMCChat(_.flatMap(_.createEmbed(spec => spec.setColor(color).setTitle(message)).^^()),
ChannelconBroadcast.RESTART, hookmsg = false).block()
private def sendStateMessage(color: Color, message: String, extra: String) =
MCChatUtils.forCustomAndAllMCChat(_.flatMap(_.createEmbed(_.setColor(color).setTitle(message).setDescription(extra))
.onErrorResume((_: Throwable) => Mono.empty)), ChannelconBroadcast.RESTART, hookmsg = false).block
MCChatUtils.forCustomAndAllMCChat(_.flatMap(_.createEmbed(_.setColor(color).setTitle(message).setDescription(extra).^^()).^^()
.onErrorResume(_ => SMono.empty)), ChannelconBroadcast.RESTART, hookmsg = false).block()
}

View file

@ -1,9 +1,9 @@
package buttondevteam.discordplugin.mccommands
import buttondevteam.discordplugin.{DPUtils, DiscordPlayer, DiscordPlugin, DiscordSenderBase}
import buttondevteam.discordplugin.commands.{ConnectCommand, VersionCommand}
import buttondevteam.discordplugin.mcchat.{MCChatUtils, MinecraftChatModule}
import buttondevteam.discordplugin.util.DPState
import buttondevteam.discordplugin.{DPUtils, DiscordPlayer, DiscordPlugin, DiscordSenderBase}
import buttondevteam.lib.chat.{Command2, CommandClass, ICommand2MC}
import buttondevteam.lib.player.{ChromaGamerBase, TBMCPlayer, TBMCPlayerBase}
import discord4j.core.`object`.ExtendedInvite
@ -14,10 +14,10 @@ import reactor.core.publisher.Mono
import java.lang.reflect.Method
@CommandClass(path = "discord", helpText = Array(Array(
@CommandClass(path = "discord", helpText = Array(
"Discord",
"This command allows performing Discord-related actions."
))) class DiscordMCCommand extends ICommand2MC {
)) class DiscordMCCommand extends ICommand2MC {
@Command2.Subcommand def accept(player: Player): Boolean = {
if (checkSafeMode(player)) return true
val did = ConnectCommand.WaitingToConnect.get(player.getName)
@ -45,17 +45,17 @@ import java.lang.reflect.Method
true
}
@Command2.Subcommand(permGroup = Command2.Subcommand.MOD_GROUP, helpText = Array(Array(
@Command2.Subcommand(permGroup = Command2.Subcommand.MOD_GROUP, helpText = Array(
"Reload Discord plugin",
"Reloads the config. To apply some changes, you may need to also run /discord restart."
))) def reload(sender: CommandSender): Unit =
)) def reload(sender: CommandSender): Unit =
if (DiscordPlugin.plugin.tryReloadConfig) sender.sendMessage("§bConfig reloaded.")
else sender.sendMessage("§cFailed to reload config.")
@Command2.Subcommand(permGroup = Command2.Subcommand.MOD_GROUP, helpText = Array(Array(
@Command2.Subcommand(permGroup = Command2.Subcommand.MOD_GROUP, helpText = Array(
"Restart the plugin", //
"This command disables and then enables the plugin." //
))) def restart(sender: CommandSender): Unit = {
)) def restart(sender: CommandSender): Unit = {
val task: Runnable = () => {
def foo(): Unit = {
if (!DiscordPlugin.plugin.tryReloadConfig) {
@ -84,16 +84,16 @@ import java.lang.reflect.Method
}
}
@Command2.Subcommand(helpText = Array(Array(
@Command2.Subcommand(helpText = Array(
"Version command",
"Prints the plugin version"))) def version(sender: CommandSender): Unit = {
"Prints the plugin version")) def version(sender: CommandSender): Unit = {
sender.sendMessage(VersionCommand.getVersion)
}
@Command2.Subcommand(helpText = Array(Array(
@Command2.Subcommand(helpText = Array(
"Invite",
"Shows an invite link to the server"
))) def invite(sender: CommandSender): Unit = {
)) def invite(sender: CommandSender): Unit = {
if (checkSafeMode(sender)) {
return
}

View file

@ -36,8 +36,10 @@ class DelegatingMockMaker() extends MockMaker {
override def createStaticMock[T](`type`: Class[T], settings: MockCreationSettings[T], handler: MockHandler[_]): MockMaker.StaticMockControl[T] =
this.mockMaker.createStaticMock(`type`, settings, handler)
override def createConstructionMock[T](`type`: Class[T], settingsFactory: Function[MockedConstruction.Context, MockCreationSettings[T]], handlerFactory: Function[MockedConstruction.Context, MockHandler[T]], mockInitializer: MockedConstruction.MockInitializer[T]): MockMaker.ConstructionMockControl[T] =
this.mockMaker.createConstructionMock[T](`type`, settingsFactory: Function[MockedConstruction.Context, MockCreationSettings[T]], handlerFactory, mockInitializer)
override def createConstructionMock[T](`type`: Class[T], settingsFactory: java.util.function.Function[MockedConstruction.Context,
MockCreationSettings[T]], handlerFactory: java.util.function.Function[MockedConstruction.Context,
MockHandler[T]], mockInitializer: MockedConstruction.MockInitializer[T]): MockMaker.ConstructionMockControl[T] =
this.mockMaker.createConstructionMock[T](`type`, settingsFactory, handlerFactory, mockInitializer)
def setMockMaker(mockMaker: MockMaker): Unit = {
this.mockMaker = mockMaker

View file

@ -4,8 +4,8 @@ import buttondevteam.discordplugin.DiscordConnectedPlayer
import buttondevteam.discordplugin.mcchat.MCChatUtils
import com.destroystokyo.paper.profile.CraftPlayerProfile
import net.bytebuddy.implementation.bind.annotation.IgnoreForBinding
import org.bukkit.{Bukkit, Server}
import org.bukkit.entity.Player
import org.bukkit.{Bukkit, Server}
import org.mockito.Mockito
import org.mockito.internal.creation.bytebuddy.InlineByteBuddyMockMaker
import org.mockito.invocation.InvocationOnMock
@ -46,14 +46,15 @@ class ServerWatcher {
def foo(invocation: InvocationOnMock): AnyRef = {
val method = invocation.getMethod
val pc = method.getParameterCount
var player: DiscordConnectedPlayer = null
var player = Option.empty[DiscordConnectedPlayer]
method.getName match {
case "getPlayer" =>
if (pc == 1 && (method.getParameterTypes()(0) eq classOf[UUID])) player = MCChatUtils.LoggedInPlayers.get(invocation.getArgument[UUID](0))
if (pc == 1 && (method.getParameterTypes()(0) == classOf[UUID]))
player = MCChatUtils.LoggedInPlayers.get(invocation.getArgument[UUID](0))
case "getPlayerExact" =>
if (pc == 1) {
val argument = invocation.getArgument(0)
player = MCChatUtils.LoggedInPlayers.values.stream.filter((dcp) => dcp.getName.equalsIgnoreCase(argument)).findAny.orElse(null)
player = MCChatUtils.LoggedInPlayers.values.find(_.getName.equalsIgnoreCase(argument))
}
/*case "getOnlinePlayers":
@ -65,13 +66,14 @@ class ServerWatcher {
if (pc == 2) {
val uuid = invocation.getArgument(0)
val name = invocation.getArgument(1)
player = if (uuid != null) MCChatUtils.LoggedInPlayers.get(uuid)
else null
if (player == null && name != null) player = MCChatUtils.LoggedInPlayers.values.stream.filter((dcp) => dcp.getName.equalsIgnoreCase(name)).findAny.orElse(null)
if (player != null) return new CraftPlayerProfile(player.getUniqueId, player.getName)
player = if (uuid != null) MCChatUtils.LoggedInPlayers.get(uuid) else Option.empty
if (player.isEmpty && name != null)
player = MCChatUtils.LoggedInPlayers.values.find(_.getName.equalsIgnoreCase(name))
if (player.nonEmpty)
return new CraftPlayerProfile(player.get.getUniqueId, player.get.getName)
}
}
if (player != null) return player
if (player.nonEmpty) return player.get
method.invoke(origServer, invocation.getArguments)
}

View file

@ -8,10 +8,10 @@ import discord4j.core.`object`.entity.Role
import reactor.core.publisher.Mono
@CommandClass class RoleCommand private[role](var grm: GameRoleModule) extends ICommand2DC {
@Command2.Subcommand(helpText = Array(Array(
@Command2.Subcommand(helpText = Array(
"Add role",
"This command adds a role to your account."
))) def add(sender: Command2DCSender, @Command2.TextArg rolename: String): Boolean = {
)) def add(sender: Command2DCSender, @Command2.TextArg rolename: String): Boolean = {
val role = checkAndGetRole(sender, rolename)
if (role == null) return true
try sender.getMessage.getAuthorAsMember.flatMap(m => m.addRole(role.getId).switchIfEmpty(Mono.fromRunnable(() => sender.sendMessage("added role.")))).subscribe
@ -23,10 +23,10 @@ import reactor.core.publisher.Mono
true
}
@Command2.Subcommand(helpText = Array(Array(
@Command2.Subcommand(helpText = Array(
"Remove role",
"This command removes a role from your account."
))) def remove(sender: Command2DCSender, @Command2.TextArg rolename: String): Boolean = {
)) def remove(sender: Command2DCSender, @Command2.TextArg rolename: String): Boolean = {
val role = checkAndGetRole(sender, rolename)
if (role == null) return true
try sender.getMessage.getAuthorAsMember.flatMap(m => m.removeRole(role.getId).switchIfEmpty(Mono.fromRunnable(() => sender.sendMessage("removed role.")))).subscribe