Reverted back to Scala 2.13

- The IntelliJ plugin still isn't working properly after 2 years so it's really annoying to dev using Scala 3
- (Probably) fixed DPUtils.reply not sending a message if a Mono.empty() was passed as a channel
- Moved the Discord user property from LastMessageData to CustomLMD as we don't need the user anymore to check permissions (we don't need to create a fake sender)
- ...even if we do, it should store the sender itself maybe

- Spent hours reverting and debugging Scala 2 issues because apaprently that's also very buggy
- Implemented Player interface directly in some senders because it was required for... reasons
- Moved the commenter to a separate class after a looot of debugging (API was provided)
This commit is contained in:
Norbi Peti 2023-06-30 02:29:01 +02:00
parent 222d393420
commit 0d59dff86e
No known key found for this signature in database
GPG key ID: DBA4C4549A927E56
30 changed files with 388 additions and 327 deletions

View file

@ -1,16 +1,9 @@
import org.bukkit.configuration.file.YamlConfiguration
import java.util.regex.Pattern
import scala.io.Source
import scala.util.Using
name := "Chroma-Discord" name := "Chroma-Discord"
version := "1.1" version := "1.1"
scalaVersion := "3.3.0" scalaVersion := "2.13.0"
resolvers += "spigot-repo" at "https://hub.spigotmc.org/nexus/content/repositories/snapshots/"
resolvers += "jitpack.io" at "https://jitpack.io" resolvers += "jitpack.io" at "https://jitpack.io"
resolvers += "paper-repo" at "https://papermc.io/repo/repository/maven-public/" resolvers += "paper-repo" at "https://papermc.io/repo/repository/maven-public/"
resolvers += Resolver.mavenLocal resolvers += Resolver.mavenLocal
@ -23,10 +16,10 @@ libraryDependencies ++= Seq(
"com.discord4j" % "discord4j-core" % "3.2.3", "com.discord4j" % "discord4j-core" % "3.2.3",
"com.vdurmont" % "emoji-java" % "5.1.1", "com.vdurmont" % "emoji-java" % "5.1.1",
"org.mockito" % "mockito-core" % "5.2.0", "org.mockito" % "mockito-core" % "5.2.0",
"io.projectreactor" % "reactor-scala-extensions_2.13" % "0.8.0",
"com.github.TBMCPlugins.ChromaCore" % "Chroma-Core" % "v2.0.0-SNAPSHOT" % Provided, "com.github.TBMCPlugins.ChromaCore" % "Chroma-Core" % "v2.0.0-SNAPSHOT" % Provided,
"net.ess3" % "EssentialsX" % "2.17.1" % Provided, "net.ess3" % "EssentialsX" % "2.17.1" % Provided,
"net.luckperms" % "api" % "5.4" % Provided,
// https://mvnrepository.com/artifact/com.mojang/brigadier // https://mvnrepository.com/artifact/com.mojang/brigadier
"com.mojang" % "brigadier" % "1.0.500" % "provided", "com.mojang" % "brigadier" % "1.0.500" % "provided",
// https://mvnrepository.com/artifact/net.kyori/examination-api // https://mvnrepository.com/artifact/net.kyori/examination-api
@ -52,93 +45,7 @@ assembly / assemblyMergeStrategy := {
val saveConfigComments = TaskKey[Seq[File]]("saveConfigComments") val saveConfigComments = TaskKey[Seq[File]]("saveConfigComments")
saveConfigComments := { saveConfigComments := {
val sv = (Compile / sources).value Commenter.saveConfigComments((Compile / sources).value)
val cdataRegex = Pattern.compile("(?:def|val|var) (\\w+)(?::[^=]+)? = (?:getI?Config|DPUtils.\\w+Data)") //Hack: DPUtils
val clRegex = Pattern.compile("class (\\w+).* extends ((?:\\w|\\d)+)")
val objRegex = Pattern.compile("object (\\w+)")
val subRegex = Pattern.compile("def `?(\\w+)`?")
val subParamRegex = Pattern.compile("((?:\\w|\\d)+): ((?:\\w|\\d)+)")
val configConfig = new YamlConfiguration()
val commandConfig = new YamlConfiguration()
def getConfigComments(line: String, clKey: String, comment: String, justCommented: Boolean): (String, String, Boolean) = {
val clMatcher = clRegex.matcher(line)
if (clKey == null && clMatcher.find()) { //First occurrence
(if (clMatcher.group(2).contains("Component"))
"components." + clMatcher.group(1)
else "global", comment, justCommented)
} else if (line.contains("/**")) {
(clKey, "", false)
} else if (line.contains("*/") && comment != null)
(clKey, comment, true)
else if (comment != null) {
if (justCommented) {
if (clKey != null) {
val matcher = cdataRegex.matcher(line)
if (matcher.find())
configConfig.set(s"$clKey.${matcher.group(1)}", comment.trim)
}
else {
val matcher = objRegex.matcher(line)
if (matcher.find()) {
val clName = matcher.group(1)
val compKey = if (clName.contains("Module")) s"component.$clName"
else if (clName.contains("Plugin")) "global"
else null
if (compKey != null)
configConfig.set(s"$compKey.generalDescriptionInsteadOfAConfig", comment.trim)
}
}
(clKey, null, false)
}
else (clKey, comment + line.replaceFirst("^\\s*\\*\\s+", "") + "\n", justCommented)
}
else (clKey, comment, justCommented)
}
for (file <- sv) {
Using(Source.fromFile(file)) { src =>
var clKey: String = null
var comment: String = null
var justCommented: Boolean = false
var subCommand = false
var pkg: String = null
var clName: String = null
for (line <- src.getLines) {
val (clk, c, jc) = getConfigComments(line, clKey, comment, justCommented)
clKey = clk; comment = c; justCommented = jc
val objMatcher = objRegex.matcher(line)
val clMatcher = clRegex.matcher(line)
if (pkg == null && line.startsWith("package "))
pkg = line.substring("package ".length)
else if (clName == null && objMatcher.find())
clName = objMatcher.group(1)
else if (clName == null && clMatcher.find())
clName = clMatcher.group(1)
val subMatcher = subRegex.matcher(line)
val subParamMatcher = subParamRegex.matcher(line)
val sub = line.contains("@Subcommand") || line.contains("@Command2.Subcommand")
if (sub) subCommand = true
else if (line.contains("}")) subCommand = false
if (subCommand && subMatcher.find()) {
/*val groups = (2 to subMatcher.groupCount()).map(subMatcher.group)
val pairs = for (i <- groups.indices by 2) yield (groups(i), groups(i + 1))*/
val mname = subMatcher.group(1)
val params = Iterator.continually(()).takeWhile(_ => subParamMatcher.find())
.map(_ => subParamMatcher.group(1)).drop(1)
val section = commandConfig.createSection(s"$pkg.$clName.$mname")
section.set("method", s"$mname()")
section.set("params", params.mkString(" "))
subCommand = false
}
}
configConfig.save("target/configHelp.yml")
commandConfig.save("target/commands.yml")
}.recover[Unit]({ case t => t.printStackTrace() })
}
Seq(file("target/configHelp.yml"), file("target/commands.yml"))
} }
Compile / resourceGenerators += saveConfigComments Compile / resourceGenerators += saveConfigComments

96
project/Commenter.scala Normal file
View file

@ -0,0 +1,96 @@
import java.util.regex.Pattern
import sbt.*
import org.bukkit.configuration.file.YamlConfiguration
import scala.io.Source
import scala.util.Using
object Commenter {
def saveConfigComments(sv: Seq[File]): Seq[File] = {
val cdataRegex = Pattern.compile("(?:def|val|var) (\\w+)(?::[^=]+)? = (?:getI?Config|DPUtils.\\w+Data)") //Hack: DPUtils
val clRegex = Pattern.compile("class (\\w+).* extends ((?:\\w|\\d)+)")
val objRegex = Pattern.compile("object (\\w+)")
val subRegex = Pattern.compile("def `?(\\w+)`?")
val subParamRegex = Pattern.compile("((?:\\w|\\d)+): ((?:\\w|\\d)+)")
val configConfig = new YamlConfiguration()
val commandConfig = new YamlConfiguration()
def getConfigComments(line: String, clKey: String, comment: String, justCommented: Boolean): (String, String, Boolean) = {
val clMatcher = clRegex.matcher(line)
if (clKey == null && clMatcher.find()) { //First occurrence
(if (clMatcher.group(2).contains("Component"))
"components." + clMatcher.group(1)
else "global", comment, justCommented)
} else if (line.contains("/**")) {
(clKey, "", false)
} else if (line.contains("*/") && comment != null)
(clKey, comment, true)
else if (comment != null) {
if (justCommented) {
if (clKey != null) {
val matcher = cdataRegex.matcher(line)
if (matcher.find())
configConfig.set(s"$clKey.${matcher.group(1)}", comment.trim)
}
else {
val matcher = objRegex.matcher(line)
if (matcher.find()) {
val clName = matcher.group(1)
val compKey = if (clName.contains("Module")) s"component.$clName"
else if (clName.contains("Plugin")) "global"
else null
if (compKey != null)
configConfig.set(s"$compKey.generalDescriptionInsteadOfAConfig", comment.trim)
}
}
(clKey, null, false)
}
else (clKey, comment + line.replaceFirst("^\\s*\\*\\s+", "") + "\n", justCommented)
}
else (clKey, comment, justCommented)
}
for (file <- sv) {
Using(Source.fromFile(file)) { src =>
var clKey: String = null
var comment: String = null
var justCommented: Boolean = false
var subCommand = false
var pkg: String = null
var clName: String = null
for (line <- src.getLines) {
val (clk, c, jc) = getConfigComments(line, clKey, comment, justCommented)
clKey = clk; comment = c; justCommented = jc
val objMatcher = objRegex.matcher(line)
val clMatcher = clRegex.matcher(line)
if (pkg == null && line.startsWith("package "))
pkg = line.substring("package ".length)
else if (clName == null && objMatcher.find())
clName = objMatcher.group(1)
else if (clName == null && clMatcher.find())
clName = clMatcher.group(1)
val subMatcher = subRegex.matcher(line)
val subParamMatcher = subParamRegex.matcher(line)
val sub = line.contains("@Subcommand") || line.contains("@Command2.Subcommand")
if (sub) subCommand = true
else if (line.contains("}")) subCommand = false
if (subCommand && subMatcher.find()) {
/*val groups = (2 to subMatcher.groupCount()).map(subMatcher.group)
val pairs = for (i <- groups.indices by 2) yield (groups(i), groups(i + 1))*/
val mname = subMatcher.group(1)
val params = Iterator.continually(()).takeWhile(_ => subParamMatcher.find())
.map(_ => subParamMatcher.group(1)).drop(1)
val section = commandConfig.createSection(s"$pkg.$clName.$mname")
section.set("method", s"$mname()")
section.set("params", params.mkString(" "))
subCommand = false
}
}
configConfig.save("target/configHelp.yml")
commandConfig.save("target/commands.yml")
}.recover[Unit]({ case t => t.printStackTrace() })
}
Seq(file("target/configHelp.yml"), file("target/commands.yml"))
}
}

View file

@ -1,2 +1,2 @@
sbt.version=1.8.2 sbt.version=1.8.2
scala.version=3.0.0 scala.version=2.13.0

View file

@ -2,5 +2,6 @@
//lazy val root = (project in file(".")).dependsOn(commenter) //lazy val root = (project in file(".")).dependsOn(commenter)
resolvers += Resolver.mavenLocal resolvers += Resolver.mavenLocal
resolvers += "paper-repo" at "https://papermc.io/repo/repository/maven-public/"
libraryDependencies += "org.spigotmc" % "spigot-api" % "1.19.4-R0.1-SNAPSHOT" libraryDependencies += "io.papermc.paper" % "paper-api" % "1.19.4-R0.1-SNAPSHOT" % Compile

View file

@ -4,7 +4,7 @@ import buttondevteam.discordplugin.ChannelconBroadcast.ChannelconBroadcast
import buttondevteam.discordplugin.mcchat.MCChatUtils import buttondevteam.discordplugin.mcchat.MCChatUtils
import discord4j.core.`object`.entity.Message import discord4j.core.`object`.entity.Message
import discord4j.core.`object`.entity.channel.MessageChannel import discord4j.core.`object`.entity.channel.MessageChannel
import reactor.core.publisher.Mono import reactor.core.scala.publisher.SMono
import javax.annotation.Nullable import javax.annotation.Nullable
@ -20,7 +20,7 @@ object ChromaBot {
* *
* @param message The message to send, duh (use [[MessageChannel.createMessage]]) * @param message The message to send, duh (use [[MessageChannel.createMessage]])
*/ */
def sendMessage(message: Mono[MessageChannel] => Mono[Message]): Unit = def sendMessage(message: SMono[MessageChannel] => SMono[Message]): Unit =
MCChatUtils.forPublicPrivateChat(message).subscribe() MCChatUtils.forPublicPrivateChat(message).subscribe()
/** /**
@ -29,7 +29,7 @@ object ChromaBot {
* @param message The message to send, duh * @param message The message to send, duh
* @param toggle The toggle type for channelcon * @param toggle The toggle type for channelcon
*/ */
def sendMessageCustomAsWell(message: Mono[MessageChannel] => Mono[Message], @Nullable toggle: ChannelconBroadcast): Unit = def sendMessageCustomAsWell(message: SMono[MessageChannel] => SMono[Message], @Nullable toggle: ChannelconBroadcast): Unit =
MCChatUtils.forCustomAndAllMCChat(message.apply, toggle, hookmsg = false).subscribe() MCChatUtils.forCustomAndAllMCChat(message.apply, toggle, hookmsg = false).subscribe()
def updatePlayerList(): Unit = def updatePlayerList(): Unit =

View file

@ -9,6 +9,7 @@ import discord4j.core.`object`.entity.{Guild, Message, Role}
import discord4j.core.spec.EmbedCreateSpec import discord4j.core.spec.EmbedCreateSpec
import discord4j.core.spec.legacy.{LegacyEmbedCreateSpec, LegacySpec} import discord4j.core.spec.legacy.{LegacyEmbedCreateSpec, LegacySpec}
import reactor.core.publisher.{Flux, Mono} import reactor.core.publisher.{Flux, Mono}
import reactor.core.scala.publisher.{SFlux, SMono}
import java.util import java.util
import java.util.Comparator import java.util.Comparator
@ -69,21 +70,21 @@ object DPUtils {
else DiscordPlugin.plugin.getLogger else DiscordPlugin.plugin.getLogger
} }
def channelData(config: IHaveConfig, key: String): IConfigData[Mono[MessageChannel]] = def channelData(config: IHaveConfig, key: String): IConfigData[SMono[MessageChannel]] =
config.getData(key, id => getMessageChannel(key, Snowflake.of(id.asInstanceOf[Long])), config.getData(key, id => getMessageChannel(key, Snowflake.of(id.asInstanceOf[Long])),
(_: Mono[MessageChannel]) => 0L, 0L, true) //We can afford to search for the channel in the cache once (instead of using mainServer) (_: SMono[MessageChannel]) => 0L, 0L, true) //We can afford to search for the channel in the cache once (instead of using mainServer)
def roleData(config: IHaveConfig, key: String, defName: String): IConfigData[Mono[Role]] = def roleData(config: IHaveConfig, key: String, defName: String): IConfigData[SMono[Role]] =
roleData(config, key, defName, Mono.just(DiscordPlugin.mainServer)) roleData(config, key, defName, SMono.just(DiscordPlugin.mainServer))
/** /**
* Needs to be a [[ConfigData]] for checking if it's set * Needs to be a [[ConfigData]] for checking if it's set
*/ */
def roleData(config: IHaveConfig, key: String, defName: String, guild: Mono[Guild]): IConfigData[Mono[Role]] = config.getData(key, name => { def roleData(config: IHaveConfig, key: String, defName: String, guild: SMono[Guild]): IConfigData[SMono[Role]] = config.getData(key, name => {
if (!name.isInstanceOf[String] || name.asInstanceOf[String].isEmpty) Mono.empty[Role] if (!name.isInstanceOf[String] || name.asInstanceOf[String].isEmpty) SMono.empty[Role]
else guild.flatMapMany(_.getRoles).filter(_.getName == name).onErrorResume(e => { else guild.flatMapMany(_.getRoles).filter(_.getName == name).onErrorResume(e => {
getLogger.warning("Failed to get role data for " + key + "=" + name + " - " + e.getMessage) getLogger.warning("Failed to get role data for " + key + "=" + name + " - " + e.getMessage)
Mono.empty[Role] SMono.empty[Role]
}).next }).next
}, _ => defName, defName, true) }, _ => defName, defName, true)
@ -125,7 +126,7 @@ object DPUtils {
*/ */
def disableIfConfigErrorRes(@Nullable component: Component[DiscordPlugin], config: IConfigData[_], result: Any): Boolean = { def disableIfConfigErrorRes(@Nullable component: Component[DiscordPlugin], config: IConfigData[_], result: Any): Boolean = {
//noinspection ConstantConditions //noinspection ConstantConditions
if (result == null || (result.isInstanceOf[Mono[_]] && !result.asInstanceOf[Mono[_]].hasElement.block())) { if (result == null || (result.isInstanceOf[SMono[_]] && !result.asInstanceOf[SMono[_]].hasElement.block())) {
var path: String = null var path: String = null
try { try {
if (component != null) Component.setComponentEnabled(component, false) if (component != null) Component.setComponentEnabled(component, false)
@ -145,26 +146,29 @@ object DPUtils {
} }
/** /**
* Send a response in the form of "@User, message". Use Mono.empty() if you don't have a channel object. * Send a response in the form of "@User, message". Use SMono.empty() if you don't have a channel object.
* *
* @param original The original message to reply to * @param original The original message to reply to
* @param channel The channel to send the message in, defaults to the original * @param channel The channel to send the message in, defaults to the original
* @param message The message to send * @param message The message to send
* @return A mono to send the message * @return A mono to send the message
*/ */
def reply(original: Message, @Nullable channel: MessageChannel, message: String): Mono[Message] = { @deprecated("Use reply(Message, SMono<MessageChannel>, String) instead", since = "1.1.0")
val ch = if (channel == null) original.getChannel def reply(original: Message, @Nullable channel: MessageChannel, message: String): SMono[Message] = {
else Mono.just(channel) val ch = if (channel == null) original.getChannel.^^()
else SMono.just(channel)
reply(original, ch, message) reply(original, ch, message)
} }
/** /**
* @see #reply(Message, MessageChannel, String) * @see #reply(Message, MessageChannel, String)
*/ */
def reply(original: Message, ch: Mono[MessageChannel], message: String): Mono[Message] = def reply(original: Message, ch: SMono[MessageChannel], message: String): SMono[Message] =
ch.flatMap(channel => channel.createMessage((if (original.getAuthor.isPresent) ch.switchIfEmpty(original.getChannel().^^()).flatMap(channel => channel.createMessage((
if (original.getAuthor.isPresent)
original.getAuthor.get.getMention + ", " original.getAuthor.get.getMention + ", "
else "") + message)) else ""
) + message).^^())
def nickMention(userId: Snowflake): String = "<@!" + userId.asString + ">" def nickMention(userId: Snowflake): String = "<@!" + userId.asString + ">"
@ -177,19 +181,27 @@ object DPUtils {
* @param id The channel ID * @param id The channel ID
* @return A message channel * @return A message channel
*/ */
def getMessageChannel(key: String, id: Snowflake): Mono[MessageChannel] = { def getMessageChannel(key: String, id: Snowflake): SMono[MessageChannel] = {
if (id.asLong == 0L) return Mono.empty[MessageChannel] if (id.asLong == 0L) return SMono.empty[MessageChannel]
DiscordPlugin.dc.getChannelById(id).onErrorResume(e => { DiscordPlugin.dc.getChannelById(id).^^().onErrorResume(e => {
getLogger.warning(s"Failed to get channel data for $key=$id - ${e.getMessage}") getLogger.warning(s"Failed to get channel data for $key=$id - ${e.getMessage}")
Mono.empty[Channel] SMono.empty[Channel]
}).filter(ch => ch.isInstanceOf[MessageChannel]).cast(classOf[MessageChannel]) }).filter(ch => ch.isInstanceOf[MessageChannel]).cast[MessageChannel]
} }
def getMessageChannel(config: IConfigData[Snowflake]): Mono[MessageChannel] = def getMessageChannel(config: IConfigData[Snowflake]): SMono[MessageChannel] =
getMessageChannel(config.getPath, config.get) getMessageChannel(config.getPath, config.get)
def ignoreError[T](mono: Mono[T]): Mono[T] = mono.onErrorResume((_: Throwable) => Mono.empty) 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 <: LegacySpec[_]](spec: T) { implicit class SpecExtensions[T <: LegacySpec[_]](spec: T) {
def ^^(): Unit = () def ^^(): Unit = ()

View file

@ -1,19 +1,20 @@
package buttondevteam.discordplugin package buttondevteam.discordplugin
import buttondevteam.discordplugin.DPUtils.{FluxExtensions, MonoExtensions}
import buttondevteam.discordplugin.DiscordPlugin.dc import buttondevteam.discordplugin.DiscordPlugin.dc
import buttondevteam.discordplugin.announcer.AnnouncerModule import buttondevteam.discordplugin.announcer.AnnouncerModule
import buttondevteam.discordplugin.broadcaster.GeneralEventBroadcasterModule import buttondevteam.discordplugin.broadcaster.GeneralEventBroadcasterModule
import buttondevteam.discordplugin.commands.* import buttondevteam.discordplugin.commands._
import buttondevteam.discordplugin.exceptions.ExceptionListenerModule import buttondevteam.discordplugin.exceptions.ExceptionListenerModule
import buttondevteam.discordplugin.fun.FunModule import buttondevteam.discordplugin.fun.FunModule
import buttondevteam.discordplugin.listeners.{CommonListeners, MCListener} import buttondevteam.discordplugin.listeners.{CommonListeners, MCListener}
import buttondevteam.discordplugin.mcchat.MinecraftChatModule import buttondevteam.discordplugin.mcchat.MinecraftChatModule
import buttondevteam.discordplugin.mcchat.sender.{DiscordUser, DiscordSenderBase} import buttondevteam.discordplugin.mcchat.sender.{DiscordSenderBase, DiscordUser}
import buttondevteam.discordplugin.mccommands.DiscordMCCommand import buttondevteam.discordplugin.mccommands.DiscordMCCommand
import buttondevteam.discordplugin.role.GameRoleModule import buttondevteam.discordplugin.role.GameRoleModule
import buttondevteam.discordplugin.util.{DPState, Timings} import buttondevteam.discordplugin.util.{DPState, Timings}
import buttondevteam.lib.TBMCCoreAPI import buttondevteam.lib.TBMCCoreAPI
import buttondevteam.lib.architecture.* import buttondevteam.lib.architecture._
import buttondevteam.lib.architecture.config.IConfigData import buttondevteam.lib.architecture.config.IConfigData
import buttondevteam.lib.player.ChromaGamerBase import buttondevteam.lib.player.ChromaGamerBase
import com.google.common.io.Files import com.google.common.io.Files
@ -32,11 +33,12 @@ import org.bukkit.configuration.file.YamlConfiguration
import org.mockito.internal.util.MockUtil import org.mockito.internal.util.MockUtil
import reactor.core.Disposable import reactor.core.Disposable
import reactor.core.publisher.Mono import reactor.core.publisher.Mono
import reactor.core.scala.publisher.SMono
import java.io.File import java.io.File
import java.nio.charset.StandardCharsets import java.nio.charset.StandardCharsets
import java.util.Optional import java.util.Optional
import scala.jdk.OptionConverters.* import scala.jdk.OptionConverters._
@ButtonPlugin.ConfigOpts(disableConfigGen = true) object DiscordPlugin { @ButtonPlugin.ConfigOpts(disableConfigGen = true) object DiscordPlugin {
private[discordplugin] var dc: GatewayDiscordClient = null private[discordplugin] var dc: GatewayDiscordClient = null
@ -66,14 +68,14 @@ import scala.jdk.OptionConverters.*
/** /**
* The main server where the roles and other information is pulled from. It's automatically set to the first server the bot's invited to. * The main server where the roles and other information is pulled from. It's automatically set to the first server the bot's invited to.
*/ */
private def mainServer = getIConfig.getData("mainServer", id => { //It attempts to get the default as well private def mainServer = getIConfig.getData("mainServer", (id: Any) => { //It attempts to get the default as well
if (id.asInstanceOf[Long] == 0L) Option.empty if (id.asInstanceOf[Long] == 0L) Option.empty
else DiscordPlugin.dc.getGuildById(Snowflake.of(id.asInstanceOf[Long])) else DiscordPlugin.dc.getGuildById(Snowflake.of(id.asInstanceOf[Long])).^^()
.onErrorResume(t => { .onErrorResume(t => {
getLogger.warning("Failed to get guild: " + t.getMessage) getLogger.warning("Failed to get guild: " + t.getMessage)
Mono.empty SMono.empty
}).blockOptional().toScala }).blockOption()
}, g => g.map(_.getId.asLong).getOrElse(0L), 0L, true) }, (g: Option[Guild]) => g.map(_.getId.asLong).getOrElse(0L), 0L, true)
/** /**
* The (bot) channel to use for Discord commands like /role. * The (bot) channel to use for Discord commands like /role.
@ -83,7 +85,7 @@ import scala.jdk.OptionConverters.*
* The role that allows using mod-only Discord commands. * The role that allows using mod-only Discord commands.
* If empty (&#39;&#39;), then it will only allow for the owner. * If empty (&#39;&#39;), then it will only allow for the owner.
*/ */
def modRole: IConfigData[Mono[Role]] = DPUtils.roleData(getIConfig, "modRole", "Moderator") def modRole: IConfigData[SMono[Role]] = DPUtils.roleData(getIConfig, "modRole", "Moderator")
/** /**
* The invite link to show by /discord invite. If empty, it defaults to the first invite if the bot has access. * The invite link to show by /discord invite. If empty, it defaults to the first invite if the bot has access.
*/ */
@ -133,7 +135,7 @@ import scala.jdk.OptionConverters.*
foo(t) foo(t)
}).subscribe((dc: GatewayDiscordClient) => { }).subscribe((dc: GatewayDiscordClient) => {
DiscordPlugin.dc = dc //Set to gateway client DiscordPlugin.dc = dc //Set to gateway client
dc.on(classOf[ReadyEvent]).map(_.getGuilds.size).flatMap(dc.on(classOf[GuildCreateEvent]).take(_).collectList) dc.on(classOf[ReadyEvent]).^^().map(_.getGuilds.size).flatMap(dc.on(classOf[GuildCreateEvent]).take(_).collectList)
.doOnError(_ => stopStarting()).subscribe(this.handleReady _) // Take all received GuildCreateEvents and make it a List .doOnError(_ => stopStarting()).subscribe(this.handleReady _) // Take all received GuildCreateEvents and make it a List
() ()
}) /* All guilds have been received, client is fully connected */ }) /* All guilds have been received, client is fully connected */

View file

@ -1,5 +1,6 @@
package buttondevteam.discordplugin.announcer package buttondevteam.discordplugin.announcer
import buttondevteam.discordplugin.DPUtils.MonoExtensions
import buttondevteam.discordplugin.mcchat.sender.DiscordUser import buttondevteam.discordplugin.mcchat.sender.DiscordUser
import buttondevteam.discordplugin.{DPUtils, DiscordPlugin} import buttondevteam.discordplugin.{DPUtils, DiscordPlugin}
import buttondevteam.lib.TBMCCoreAPI import buttondevteam.lib.TBMCCoreAPI
@ -7,7 +8,7 @@ import buttondevteam.lib.architecture.{Component, ComponentMetadata}
import buttondevteam.lib.player.ChromaGamerBase import buttondevteam.lib.player.ChromaGamerBase
import com.google.gson.JsonParser import com.google.gson.JsonParser
import discord4j.core.`object`.entity.channel.MessageChannel import discord4j.core.`object`.entity.channel.MessageChannel
import reactor.core.publisher.Mono import reactor.core.scala.publisher.SMono
import scala.annotation.tailrec import scala.annotation.tailrec
import scala.collection.mutable import scala.collection.mutable
@ -86,8 +87,8 @@ import scala.collection.mutable
} }
} }
def sendMsg(ch: Mono[MessageChannel], msg: String) = def sendMsg(ch: SMono[MessageChannel], msg: String) =
ch.flatMap(c => c.createMessage(msg)).flatMap(_.pin).subscribe() ch.flatMap(c => c.createMessage(msg).^^()).flatMap(_.pin.^^()).subscribe()
if (msgsb.nonEmpty) sendMsg(channel.get(), msgsb.toString()) if (msgsb.nonEmpty) sendMsg(channel.get(), msgsb.toString())
if (modmsgsb.nonEmpty) sendMsg(modChannel.get(), modmsgsb.toString()) if (modmsgsb.nonEmpty) sendMsg(modChannel.get(), modmsgsb.toString())

View file

@ -1,24 +1,24 @@
package buttondevteam.discordplugin.commands package buttondevteam.discordplugin.commands
import buttondevteam.discordplugin.DPUtils.MonoExtensions
import buttondevteam.discordplugin.DiscordPlugin import buttondevteam.discordplugin.DiscordPlugin
import buttondevteam.discordplugin.listeners.CommonListeners import buttondevteam.discordplugin.listeners.CommonListeners
import buttondevteam.lib.chat.{Command2, CommandClass} import buttondevteam.lib.chat.{Command2, CommandClass}
import discord4j.common.util.Snowflake import discord4j.common.util.Snowflake
import discord4j.core.`object`.entity.{Member, User} import discord4j.core.`object`.entity.{Member, User}
import reactor.core.publisher.Mono import reactor.core.scala.publisher.SMono
import scala.jdk.OptionConverters._
@CommandClass(helpText = Array("Switches debug mode.")) @CommandClass(helpText = Array("Switches debug mode."))
class DebugCommand extends ICommand2DC { class DebugCommand extends ICommand2DC {
@Command2.Subcommand @Command2.Subcommand
override def `def`(sender: Command2DCSender): Boolean = { override def `def`(sender: Command2DCSender): Boolean = {
Mono.justOrEmpty(sender.authorAsMember.orNull) SMono.justOrEmpty(sender.authorAsMember.orNull)
.switchIfEmpty(Option(sender.author) //Support DMs .switchIfEmpty(Option(sender.author) //Support DMs
.map((u: User) => u.asMember(DiscordPlugin.mainServer.getId)).toJava.orElse(Mono.empty[Member])) .map((u: User) => u.asMember(DiscordPlugin.mainServer.getId).^^()).getOrElse(SMono.empty[Member]))
.flatMap((m: Member) => DiscordPlugin.plugin.modRole.get .flatMap((m: Member) => DiscordPlugin.plugin.modRole.get
.map(mr => m.getRoleIds.stream.anyMatch((r: Snowflake) => r == mr.getId)) .map(mr => m.getRoleIds.stream.anyMatch((r: Snowflake) => r == mr.getId))
.switchIfEmpty(Mono.fromCallable(() => DiscordPlugin.mainServer.getOwnerId.asLong == m.getId.asLong))) .switchIfEmpty(SMono.fromCallable(() => DiscordPlugin.mainServer.getOwnerId.asLong == m.getId.asLong)))
.onErrorResume(_ => Mono.just(false)) //Role not found .onErrorResume(_ => SMono.just(false)) //Role not found
.subscribe(success => { .subscribe(success => {
if (success) { if (success) {
CommonListeners.debug = !CommonListeners.debug CommonListeners.debug = !CommonListeners.debug

View file

@ -1,11 +1,12 @@
package buttondevteam.discordplugin.commands package buttondevteam.discordplugin.commands
import buttondevteam.discordplugin.DPUtils.FluxExtensions
import buttondevteam.discordplugin.DiscordPlugin import buttondevteam.discordplugin.DiscordPlugin
import buttondevteam.discordplugin.mcchat.sender.DiscordUser import buttondevteam.discordplugin.mcchat.sender.DiscordUser
import buttondevteam.lib.chat.{Command2, CommandClass} import buttondevteam.lib.chat.{Command2, CommandClass}
import buttondevteam.lib.player.ChromaGamerBase import buttondevteam.lib.player.ChromaGamerBase
import buttondevteam.lib.player.ChromaGamerBase.InfoTarget import buttondevteam.lib.player.ChromaGamerBase.InfoTarget
import discord4j.core.`object`.entity.{Message, User} import discord4j.core.`object`.entity.{Member, Message, User}
import scala.jdk.CollectionConverters.ListHasAsScala import scala.jdk.CollectionConverters.ListHasAsScala
@ -33,9 +34,9 @@ class UserinfoCommand extends ICommand2DC {
private def getUsers(message: Message, args: String) = { private def getUsers(message: Message, args: String) = {
val guild = message.getGuild.block val guild = message.getGuild.block
if (guild == null) { //Private channel if (guild == null) { //Private channel
DiscordPlugin.dc.getUsers.filter(u => u.getUsername.equalsIgnoreCase(args)).collectList().block() DiscordPlugin.dc.getUsers.^^().filter(u => u.getUsername.equalsIgnoreCase(args)).collectSeq().block()
} }
else else
guild.getMembers.filter(_.getUsername.equalsIgnoreCase(args)).map(_.asInstanceOf[User]).collectList().block() guild.getMembers.^^().filter(_.getUsername.equalsIgnoreCase(args)).map(_.asInstanceOf[User]).collectSeq().block()
} }
} }

View file

@ -1,6 +1,7 @@
package buttondevteam.discordplugin.exceptions package buttondevteam.discordplugin.exceptions
import buttondevteam.core.ComponentManager import buttondevteam.core.ComponentManager
import buttondevteam.discordplugin.DPUtils.MonoExtensions
import buttondevteam.discordplugin.DiscordPlugin import buttondevteam.discordplugin.DiscordPlugin
import buttondevteam.lib.TBMCDebugMessageEvent import buttondevteam.lib.TBMCDebugMessageEvent
import discord4j.core.`object`.entity.channel.MessageChannel import discord4j.core.`object`.entity.channel.MessageChannel
@ -16,7 +17,7 @@ object DebugMessageListener {
sb.append("```").append("\n") sb.append("```").append("\n")
sb.append(if (message.length > 2000) message.substring(0, 2000) else message).append("\n") sb.append(if (message.length > 2000) message.substring(0, 2000) else message).append("\n")
sb.append("```") sb.append("```")
mc.flatMap((ch: MessageChannel) => ch.createMessage(sb.toString)).subscribe() mc.flatMap((ch: MessageChannel) => ch.createMessage(sb.toString).^^()).subscribe()
} catch { } catch {
case ex: Exception => case ex: Exception =>
ex.printStackTrace() ex.printStackTrace()

View file

@ -1,15 +1,16 @@
package buttondevteam.discordplugin.exceptions package buttondevteam.discordplugin.exceptions
import buttondevteam.core.ComponentManager import buttondevteam.core.ComponentManager
import buttondevteam.discordplugin.DPUtils.MonoExtensions
import buttondevteam.discordplugin.{DPUtils, DiscordPlugin} import buttondevteam.discordplugin.{DPUtils, DiscordPlugin}
import buttondevteam.lib.architecture.Component import buttondevteam.lib.architecture.Component
import buttondevteam.lib.{TBMCCoreAPI, TBMCExceptionEvent} import buttondevteam.lib.{TBMCCoreAPI, TBMCExceptionEvent}
import discord4j.core.`object`.entity.Guild
import discord4j.core.`object`.entity.channel.{GuildChannel, MessageChannel} import discord4j.core.`object`.entity.channel.{GuildChannel, MessageChannel}
import discord4j.core.`object`.entity.{Guild, Role}
import org.apache.commons.lang.exception.ExceptionUtils import org.apache.commons.lang.exception.ExceptionUtils
import org.bukkit.Bukkit import org.bukkit.Bukkit
import org.bukkit.event.{EventHandler, Listener} import org.bukkit.event.{EventHandler, Listener}
import reactor.core.publisher.Mono import reactor.core.scala.publisher.SMono
import java.util import java.util
import java.util.stream.Collectors import java.util.stream.Collectors
@ -22,11 +23,10 @@ object ExceptionListenerModule {
if (instance == null) return () if (instance == null) return ()
try getChannel.flatMap(channel => { try getChannel.flatMap(channel => {
val coderRole = channel match { val coderRole = channel match {
case ch: GuildChannel => instance.pingRole(ch.getGuild).get case ch: GuildChannel => instance.pingRole(ch.getGuild.^^()).get
case _ => Mono.empty case _ => SMono.empty
} }
coderRole.map((role: Role) => if (TBMCCoreAPI.IsTestServer) new StringBuilder coderRole.map(role => if (TBMCCoreAPI.IsTestServer) new StringBuilder else new StringBuilder(role.getMention).append("\n")) // Ping if prod server
else new StringBuilder(role.getMention).append("\n"))
.defaultIfEmpty(new StringBuilder).flatMap(sb => { .defaultIfEmpty(new StringBuilder).flatMap(sb => {
sb.append(sourcemessage).append("\n") sb.append(sourcemessage).append("\n")
sb.append("```").append("\n") sb.append("```").append("\n")
@ -36,7 +36,7 @@ object ExceptionListenerModule {
if (sb.length + stackTrace.length >= 1980) stackTrace = stackTrace.substring(0, 1980 - sb.length) if (sb.length + stackTrace.length >= 1980) stackTrace = stackTrace.substring(0, 1980 - sb.length)
sb.append(stackTrace).append("\n") sb.append(stackTrace).append("\n")
sb.append("```") sb.append("```")
channel.createMessage(sb.toString) channel.createMessage(sb.toString).^^()
}) })
}).subscribe() }).subscribe()
catch { catch {
@ -47,9 +47,9 @@ object ExceptionListenerModule {
private var instance: ExceptionListenerModule = null private var instance: ExceptionListenerModule = null
def getChannel: Mono[MessageChannel] = { def getChannel: SMono[MessageChannel] = {
if (instance != null) return instance.channel.get if (instance != null) return instance.channel.get
Mono.empty SMono.empty
} }
} }
@ -80,7 +80,7 @@ class ExceptionListenerModule extends Component[DiscordPlugin] with Listener {
/** /**
* The role to ping if an error occurs. Set to empty ('') to disable. * The role to ping if an error occurs. Set to empty ('') to disable.
*/ */
private def pingRole(guild: Mono[Guild]) = DPUtils.roleData(getConfig, "pingRole", "Coder", guild) private def pingRole(guild: SMono[Guild]) = DPUtils.roleData(getConfig, "pingRole", "Coder", guild)
override protected def enable(): Unit = { override protected def enable(): Unit = {
if (DPUtils.disableIfConfigError(this, channel)) return () if (DPUtils.disableIfConfigError(this, channel)) return ()

View file

@ -1,6 +1,7 @@
package buttondevteam.discordplugin.fun package buttondevteam.discordplugin.fun
import buttondevteam.core.ComponentManager import buttondevteam.core.ComponentManager
import buttondevteam.discordplugin.DPUtils.{FluxExtensions, MonoExtensions}
import buttondevteam.discordplugin.{DPUtils, DiscordPlugin} import buttondevteam.discordplugin.{DPUtils, DiscordPlugin}
import buttondevteam.lib.TBMCCoreAPI import buttondevteam.lib.TBMCCoreAPI
import buttondevteam.lib.architecture.config.IConfigData import buttondevteam.lib.architecture.config.IConfigData
@ -10,11 +11,13 @@ import discord4j.core.`object`.entity.channel.{GuildChannel, MessageChannel}
import discord4j.core.`object`.entity.{Guild, Message} import discord4j.core.`object`.entity.{Guild, Message}
import discord4j.core.`object`.presence.Status import discord4j.core.`object`.presence.Status
import discord4j.core.event.domain.PresenceUpdateEvent import discord4j.core.event.domain.PresenceUpdateEvent
import discord4j.core.spec.{EmbedCreateSpec, MessageCreateSpec}
import discord4j.core.spec.legacy.{LegacyEmbedCreateSpec, LegacyMessageCreateSpec} import discord4j.core.spec.legacy.{LegacyEmbedCreateSpec, LegacyMessageCreateSpec}
import org.bukkit.Bukkit import org.bukkit.Bukkit
import org.bukkit.event.player.PlayerJoinEvent import org.bukkit.event.player.PlayerJoinEvent
import org.bukkit.event.{EventHandler, Listener} import org.bukkit.event.{EventHandler, Listener}
import reactor.core.publisher.Mono import reactor.core.publisher.Mono
import reactor.core.scala.publisher.SMono
import java.util import java.util
import java.util.Calendar import java.util.Calendar
@ -53,7 +56,7 @@ object FunModule {
ListC += 1 ListC += 1
ListC - 1 ListC - 1
} > 2) { // Lowered already } > 2) { // Lowered already
DPUtils.reply(message, Mono.empty, "stop it. You know the answer.").subscribe() DPUtils.reply(message, SMono.empty, "stop it. You know the answer.").subscribe()
lastlist = 0 lastlist = 0
lastlistp = Bukkit.getOnlinePlayers.size.toShort lastlistp = Bukkit.getOnlinePlayers.size.toShort
return true //Handled return true //Handled
@ -63,7 +66,7 @@ object FunModule {
var next = 0 var next = 0
if (usableServerReadyStrings.size == 0) fm.createUsableServerReadyStrings() if (usableServerReadyStrings.size == 0) fm.createUsableServerReadyStrings()
next = usableServerReadyStrings.remove(serverReadyRandom.nextInt(usableServerReadyStrings.size)) next = usableServerReadyStrings.remove(serverReadyRandom.nextInt(usableServerReadyStrings.size))
DPUtils.reply(message, Mono.empty, fm.serverReadyAnswers.get.get(next)).subscribe() DPUtils.reply(message, SMono.empty, fm.serverReadyAnswers.get.get(next)).subscribe()
return false //Still process it as a command/mcchat if needed return false //Still process it as a command/mcchat if needed
} }
false false
@ -79,17 +82,20 @@ object FunModule {
|| event.getCurrent.getStatus == Status.OFFLINE) || event.getCurrent.getStatus == Status.OFFLINE)
return () //If it's not an offline -> online change return () //If it's not an offline -> online change
fm.fullHouseChannel.get.filter((ch: MessageChannel) => ch.isInstanceOf[GuildChannel]) fm.fullHouseChannel.get.filter((ch: MessageChannel) => ch.isInstanceOf[GuildChannel])
.flatMap(channel => fm.fullHouseDevRole(channel.asInstanceOf[GuildChannel].getGuild).get .flatMap(channel => fm.fullHouseDevRole(channel.asInstanceOf[GuildChannel].getGuild.^^()).get
.filterWhen(devrole => event.getMember .filterWhen(devrole => event.getMember.^^()
.flatMap(m => m.getRoles.any(_.getId.asLong == devrole.getId.asLong))) .flatMap(m => m.getRoles.^^().any(_.getId.asLong == devrole.getId.asLong)))
.filterWhen(devrole => event.getGuild .filterWhen(devrole => event.getGuild.^^()
.flatMapMany(g => g.getMembers.filter(_.getRoleIds.stream.anyMatch(_ == devrole.getId))) .flatMapMany(g => g.getMembers.filter(_.getRoleIds.stream.anyMatch(_ == devrole.getId)))
.flatMap(_.getPresence).all(_.getStatus != Status.OFFLINE)) .flatMap(_.getPresence).all(_.getStatus != Status.OFFLINE))
.filter(_ => lasttime + 10 < TimeUnit.NANOSECONDS.toHours(System.nanoTime)) //This should stay so it checks this last .filter(_ => lasttime + 10 < TimeUnit.NANOSECONDS.toHours(System.nanoTime)) //This should stay so it checks this last
.flatMap(_ => { .flatMap(_ => {
lasttime = TimeUnit.NANOSECONDS.toHours(System.nanoTime) lasttime = TimeUnit.NANOSECONDS.toHours(System.nanoTime)
channel.createMessage(_.setContent("Full house!") channel.createMessage(MessageCreateSpec.builder().content("Full house!")
.setEmbed((ecs: LegacyEmbedCreateSpec) => ecs.setImage("https://cdn.discordapp.com/attachments/249295547263877121/249687682618359808/poker-hand-full-house-aces-kings-playing-cards-15553791.png"))) .addEmbed(EmbedCreateSpec.builder()
.image("https://cdn.discordapp.com/attachments/249295547263877121/249687682618359808/poker-hand-full-house-aces-kings-playing-cards-15553791.png")
.build())
.build()).^^()
})).subscribe() })).subscribe()
} }
} }
@ -104,6 +110,7 @@ class FunModule extends Component[DiscordPlugin] with Listener {
"when will the server be done", "when will the server be complete", "when will the server be done", "when will the server be complete",
"when will the server be finished", "when's the server ready", "when will the server be finished", "when's the server ready",
"when's the server open", "vhen vill ze server be open?")) "when's the server open", "vhen vill ze server be open?"))
/** /**
* Answers for a recognized question. Selected randomly. * Answers for a recognized question. Selected randomly.
*/ */
@ -126,7 +133,7 @@ class FunModule extends Component[DiscordPlugin] with Listener {
/** /**
* If all of the people who have this role are online, the bot will post a full house. * If all of the people who have this role are online, the bot will post a full house.
*/ */
private def fullHouseDevRole(guild: Mono[Guild]) = DPUtils.roleData(getConfig, "fullHouseDevRole", "Developer", guild) private def fullHouseDevRole(guild: SMono[Guild]) = DPUtils.roleData(getConfig, "fullHouseDevRole", "Developer", guild)
/** /**
* The channel to post the full house to. * The channel to post the full house to.

View file

@ -1,5 +1,6 @@
package buttondevteam.discordplugin.listeners package buttondevteam.discordplugin.listeners
import buttondevteam.discordplugin.DPUtils.FluxExtensions
import buttondevteam.discordplugin.commands.{Command2DCSender, ConnectCommand} import buttondevteam.discordplugin.commands.{Command2DCSender, ConnectCommand}
import buttondevteam.discordplugin.fun.FunModule import buttondevteam.discordplugin.fun.FunModule
import buttondevteam.discordplugin.mcchat.MinecraftChatModule import buttondevteam.discordplugin.mcchat.MinecraftChatModule
@ -17,35 +18,34 @@ import discord4j.core.event.domain.message.MessageCreateEvent
import discord4j.core.event.domain.role.{RoleCreateEvent, RoleDeleteEvent, RoleUpdateEvent} import discord4j.core.event.domain.role.{RoleCreateEvent, RoleDeleteEvent, RoleUpdateEvent}
import reactor.core.Disposable import reactor.core.Disposable
import reactor.core.publisher.Mono import reactor.core.publisher.Mono
import reactor.core.scala.publisher.SMono
object CommonListeners { object CommonListeners {
val timings = new Timings val timings = new Timings
def register(dispatcher: EventDispatcher): Unit = { def register(dispatcher: EventDispatcher): Unit = {
dispatcher.on(classOf[MessageCreateEvent]).flatMap((event: MessageCreateEvent) => { dispatcher.on(classOf[MessageCreateEvent]).flatMap((event: MessageCreateEvent) => {
Mono.just(event.getMessage).filter(_ => !DiscordPlugin.SafeMode) SMono.just(event.getMessage).filter(_ => !DiscordPlugin.SafeMode)
.filter(message => message.getAuthor.filter(!_.isBot).isPresent) .filter(message => message.getAuthor.filter(!_.isBot).isPresent)
.filter(message => !FunModule.executeMemes(message)) .filter(message => !FunModule.executeMemes(message))
.filterWhen(message => { .filterWhen(message => {
Option(Component.getComponents.get(classOf[MinecraftChatModule])).filter(_.isEnabled) Option(Component.getComponents.get(classOf[MinecraftChatModule])).filter(_.isEnabled)
.map(_.asInstanceOf[MinecraftChatModule].getListener.handleDiscord(event).asInstanceOf[Mono[java.lang.Boolean]]) .map(_.asInstanceOf[MinecraftChatModule].getListener.handleDiscord(event))
.getOrElse(Mono.just(true)) //Wasn't handled, continue .getOrElse(SMono.just(true)) //Wasn't handled, continue
}) })
}).onErrorContinue((err, _) => TBMCCoreAPI.SendException("An error occured while handling a message!", err, DiscordPlugin.plugin)).subscribe() }).onErrorContinue((err, _) => TBMCCoreAPI.SendException("An error occured while handling a message!", err, DiscordPlugin.plugin)).subscribe()
dispatcher.on(classOf[PresenceUpdateEvent]).subscribe((event: PresenceUpdateEvent) => { dispatcher.on(classOf[PresenceUpdateEvent]).subscribe((event: PresenceUpdateEvent) => {
if (!DiscordPlugin.SafeMode) if (!DiscordPlugin.SafeMode)
FunModule.handleFullHouse(event) FunModule.handleFullHouse(event)
}) })
dispatcher.on(classOf[RoleCreateEvent]).subscribe(GameRoleModule.handleRoleEvent) dispatcher.on(classOf[RoleCreateEvent]).^^().subscribe(GameRoleModule.handleRoleEvent _)
dispatcher.on(classOf[RoleDeleteEvent]).subscribe(GameRoleModule.handleRoleEvent) dispatcher.on(classOf[RoleDeleteEvent]).^^().subscribe(GameRoleModule.handleRoleEvent _)
dispatcher.on(classOf[RoleUpdateEvent]).subscribe(GameRoleModule.handleRoleEvent) dispatcher.on(classOf[RoleUpdateEvent]).^^().subscribe(GameRoleModule.handleRoleEvent _)
dispatcher.on(classOf[ChatInputInteractionEvent], event => { dispatcher.on(classOf[ChatInputInteractionEvent]).^^().subscribe((event: ChatInputInteractionEvent) => {
if(event.getCommandName() equals "connect") { if (event.getCommandName equals "connect") {
val asd = Mono.just(new ConnectCommand().`def`(new Command2DCSender(event), event.getOption("name").get.getValue.get.asString)) new ConnectCommand().`def`(new Command2DCSender(event), event.getOption("name").get.getValue.get.asString)
asd }
} else })
Mono.empty()
}).subscribe()
} }
var debug = false var debug = false

View file

@ -1,5 +1,6 @@
package buttondevteam.discordplugin.listeners package buttondevteam.discordplugin.listeners
import buttondevteam.discordplugin.DPUtils.MonoExtensions
import buttondevteam.discordplugin.commands.ConnectCommand import buttondevteam.discordplugin.commands.ConnectCommand
import buttondevteam.discordplugin.mcchat.MinecraftChatModule import buttondevteam.discordplugin.mcchat.MinecraftChatModule
import buttondevteam.discordplugin.util.DPState import buttondevteam.discordplugin.util.DPState
@ -11,6 +12,8 @@ import discord4j.common.util.Snowflake
import org.bukkit.event.player.PlayerJoinEvent import org.bukkit.event.player.PlayerJoinEvent
import org.bukkit.event.{EventHandler, Listener} import org.bukkit.event.{EventHandler, Listener}
import reactor.core.publisher.Mono import reactor.core.publisher.Mono
import reactor.core.scala.publisher.SMono
import scala.jdk.OptionConverters._ import scala.jdk.OptionConverters._
class MCListener extends Listener { class MCListener extends Listener {
@ -25,12 +28,12 @@ class MCListener extends Listener {
@EventHandler def onGetInfo(e: TBMCPlayerGetInfoEvent): Unit = { @EventHandler def onGetInfo(e: TBMCPlayerGetInfoEvent): Unit = {
Option(DiscordPlugin.SafeMode).filterNot(identity).flatMap(_ => Option(e.getPlayer.getAs(classOf[DiscordUser]))) Option(DiscordPlugin.SafeMode).filterNot(identity).flatMap(_ => Option(e.getPlayer.getAs(classOf[DiscordUser])))
.flatMap(dp => Option(dp.getDiscordID)).filter(_.nonEmpty) .flatMap(dp => Option(dp.getDiscordID)).filter(_.nonEmpty)
.map(Snowflake.of).flatMap(id => DiscordPlugin.dc.getUserById(id).onErrorResume(_ => Mono.empty).blockOptional().toScala) .map(Snowflake.of).flatMap(id => DiscordPlugin.dc.getUserById(id).^^().onErrorResume(_ => SMono.empty).blockOption())
.map(user => { .map(user => {
e.addInfo("Discord tag: " + user.getUsername + "#" + user.getDiscriminator) e.addInfo("Discord tag: " + user.getUsername + "#" + user.getDiscriminator)
user user
}) })
.flatMap(user => user.asMember(DiscordPlugin.mainServer.getId).onErrorResume(t => Mono.empty).blockOptional().toScala) .flatMap(user => user.asMember(DiscordPlugin.mainServer.getId).^^().onErrorResume(t => SMono.empty).blockOption())
.flatMap(member => member.getPresence.blockOptional().toScala) .flatMap(member => member.getPresence.blockOptional().toScala)
.map(pr => { .map(pr => {
e.addInfo(pr.getStatus.toString) e.addInfo(pr.getStatus.toString)

View file

@ -1,26 +1,27 @@
package buttondevteam.discordplugin.mcchat package buttondevteam.discordplugin.mcchat
import buttondevteam.core.component.channel.{Channel, ChatRoom} import buttondevteam.core.component.channel.{Channel, ChatRoom}
import buttondevteam.discordplugin.*
import buttondevteam.discordplugin.ChannelconBroadcast.ChannelconBroadcast import buttondevteam.discordplugin.ChannelconBroadcast.ChannelconBroadcast
import buttondevteam.discordplugin.DPUtils.MonoExtensions
import buttondevteam.discordplugin._
import buttondevteam.discordplugin.commands.{Command2DCSender, ICommand2DC} import buttondevteam.discordplugin.commands.{Command2DCSender, ICommand2DC}
import buttondevteam.discordplugin.mcchat.sender.{DiscordConnectedPlayer, DiscordUser} import buttondevteam.discordplugin.mcchat.sender.{DiscordConnectedPlayer, DiscordUser}
import buttondevteam.lib.TBMCSystemChatEvent import buttondevteam.lib.TBMCSystemChatEvent
import buttondevteam.lib.architecture.config.IConfigData
import buttondevteam.lib.chat.{Command2, CommandClass} import buttondevteam.lib.chat.{Command2, CommandClass}
import buttondevteam.lib.player.{ChromaGamerBase, TBMCPlayer} import buttondevteam.lib.player.{ChromaGamerBase, TBMCPlayer}
import discord4j.core.`object`.entity.Message import discord4j.core.`object`.entity.Message
import discord4j.core.`object`.entity.channel.{GuildChannel, MessageChannel} import discord4j.core.`object`.entity.channel.{GuildChannel, MessageChannel}
import discord4j.rest.util.{Permission, PermissionSet} import discord4j.rest.util.{Permission, PermissionSet}
import org.bukkit.Bukkit import org.bukkit.Bukkit
import reactor.core.publisher.Mono import reactor.core.scala.publisher.SMono
import java.lang.reflect.Method import java.lang.reflect.Method
import java.util
import java.util.function.Supplier import java.util.function.Supplier
import java.util.stream.Collectors
import java.util.{Objects, Optional} import java.util.{Objects, Optional}
import javax.annotation.Nullable import javax.annotation.Nullable
import scala.jdk.Accumulator
import scala.jdk.OptionConverters.RichOptional
import scala.jdk.StreamConverters.StreamHasToScala
@SuppressWarnings(Array("SimplifyOptionalCallChains")) //Java 11 @SuppressWarnings(Array("SimplifyOptionalCallChains")) //Java 11
@CommandClass(helpText = Array("Channel connect", // @CommandClass(helpText = Array("Channel connect", //
@ -38,9 +39,9 @@ class ChannelconCommand(private val module: MinecraftChatModule) extends IComman
val message: Message = null // TODO val message: Message = null // TODO
if (checkPerms(message, null)) return true if (checkPerms(message, null)) return true
else if (MCChatCustom.removeCustomChat(message.getChannelId)) else if (MCChatCustom.removeCustomChat(message.getChannelId))
DPUtils.reply(message, Mono.empty, "channel connection removed.").subscribe() DPUtils.reply(message, SMono.empty, "channel connection removed.").subscribe()
else else
DPUtils.reply(message, Mono.empty, "this channel isn't connected.").subscribe() DPUtils.reply(message, SMono.empty, "this channel isn't connected.").subscribe()
true true
} }
@ -56,11 +57,11 @@ class ChannelconCommand(private val module: MinecraftChatModule) extends IComman
val togglesString: Supplier[String] = () => ChannelconBroadcast.values val togglesString: Supplier[String] = () => ChannelconBroadcast.values
.map(t => t.toString.toLowerCase + ": " + (if ((cc.toggles & (1 << t.id)) == 0) "disabled" else "enabled")) .map(t => t.toString.toLowerCase + ": " + (if ((cc.toggles & (1 << t.id)) == 0) "disabled" else "enabled"))
.mkString("\n") + "\n\n" + .mkString("\n") + "\n\n" +
TBMCSystemChatEvent.BroadcastTarget.stream.map((target: TBMCSystemChatEvent.BroadcastTarget) => TBMCSystemChatEvent.BroadcastTarget.stream.toScala(Accumulator)
target.getName + ": " + (if (cc.brtoggles.contains(target)) "enabled" else "disabled")) .map(target => s"${target.getName}: ${if (cc.brtoggles.contains(target)) "enabled" else "disabled"}")
.collect(Collectors.joining("\n")) .mkString("\n")
if (toggle == null) { if (toggle == null) {
DPUtils.reply(message, Mono.empty, "toggles:\n" + togglesString.get).subscribe() DPUtils.reply(message, SMono.empty, "toggles:\n" + togglesString.get).subscribe()
return true return true
} }
val arg: String = toggle.toUpperCase val arg: String = toggle.toUpperCase
@ -68,7 +69,7 @@ class ChannelconCommand(private val module: MinecraftChatModule) extends IComman
if (b.isEmpty) { if (b.isEmpty) {
val bt: TBMCSystemChatEvent.BroadcastTarget = TBMCSystemChatEvent.BroadcastTarget.get(arg) val bt: TBMCSystemChatEvent.BroadcastTarget = TBMCSystemChatEvent.BroadcastTarget.get(arg)
if (bt == null) { if (bt == null) {
DPUtils.reply(message, Mono.empty, "cannot find toggle. Toggles:\n" + togglesString.get).subscribe() DPUtils.reply(message, SMono.empty, "cannot find toggle. Toggles:\n" + togglesString.get).subscribe()
return true return true
} }
val add: Boolean = !cc.brtoggles.contains(bt) val add: Boolean = !cc.brtoggles.contains(bt)
@ -88,7 +89,7 @@ class ChannelconCommand(private val module: MinecraftChatModule) extends IComman
//1 1 | 0 //1 1 | 0
// XOR // XOR
cc.toggles ^= (1 << b.get.id) cc.toggles ^= (1 << b.get.id)
DPUtils.reply(message, Mono.empty, "'" + b.get.toString.toLowerCase + "' " DPUtils.reply(message, SMono.empty, "'" + b.get.toString.toLowerCase + "' "
+ (if ((cc.toggles & (1 << b.get.id)) == 0) "disabled" else "enabled")).subscribe() + (if ((cc.toggles & (1 << b.get.id)) == 0) "disabled" else "enabled")).subscribe()
true true
} }
@ -157,7 +158,7 @@ class ChannelconCommand(private val module: MinecraftChatModule) extends IComman
return true return true
} }
//noinspection OptionalGetWithoutIsPresent //noinspection OptionalGetWithoutIsPresent
val perms: PermissionSet = (channel.asInstanceOf[GuildChannel]).getEffectivePermissions(message.getAuthor.map(_.getId).get).block val perms: PermissionSet = (channel.asInstanceOf[GuildChannel]).getEffectivePermissions(message.getAuthor.toScala.map(_.getId).get).block
if (!(perms.contains(Permission.ADMINISTRATOR)) && !(perms.contains(Permission.MANAGE_CHANNELS))) { if (!(perms.contains(Permission.ADMINISTRATOR)) && !(perms.contains(Permission.MANAGE_CHANNELS))) {
DPUtils.reply(message, channel, "you need to have manage permissions for this channel!").subscribe() DPUtils.reply(message, channel, "you need to have manage permissions for this channel!").subscribe()
return true return true
@ -176,6 +177,6 @@ class ChannelconCommand(private val module: MinecraftChatModule) extends IComman
"To remove a connection use @ChromaBot channelcon remove in the channel.", "To remove a connection use @ChromaBot channelcon remove in the channel.",
"Mentioning the bot is needed in this case because the " + DiscordPlugin.getPrefix + " prefix only works in " + DPUtils.botmention + ".", "Mentioning the bot is needed in this case because the " + DiscordPlugin.getPrefix + " prefix only works in " + DPUtils.botmention + ".",
"Invite link: <https://discordapp.com/oauth2/authorize?client_id=" "Invite link: <https://discordapp.com/oauth2/authorize?client_id="
+ DiscordPlugin.dc.getApplicationInfo.map(info => info.getId.asString).blockOptional().orElse("Unknown") + DiscordPlugin.dc.getApplicationInfo.^^().map(info => info.getId.asString).blockOption().getOrElse("Unknown")
+ "&scope=bot&permissions=268509264>") + "&scope=bot&permissions=268509264>")
} }

View file

@ -59,9 +59,9 @@ object MCChatCustom {
def getCustomChats: List[CustomLMD] = lastmsgCustom.toList def getCustomChats: List[CustomLMD] = lastmsgCustom.toList
// TODO: Store Chroma user only // TODO: Store Chroma user only
class CustomLMD private[mcchat](channel: MessageChannel, user: User, val groupID: String, class CustomLMD private[mcchat](channel: MessageChannel, val dcUser: User, val groupID: String,
mcchannel: Channel, val dcp: DiscordConnectedPlayer, var toggles: Int, mcchannel: Channel, val dcp: DiscordConnectedPlayer, var toggles: Int,
var brtoggles: Set[TBMCSystemChatEvent.BroadcastTarget]) extends MCChatUtils.LastMsgData(channel, user, mcchannel) { var brtoggles: Set[TBMCSystemChatEvent.BroadcastTarget]) extends MCChatUtils.LastMsgData(channel, mcchannel, dcp.getChromaUser) {
} }
} }

View file

@ -1,10 +1,10 @@
package buttondevteam.discordplugin.mcchat package buttondevteam.discordplugin.mcchat
import buttondevteam.core.ComponentManager import buttondevteam.core.ComponentManager
import buttondevteam.discordplugin.* import buttondevteam.discordplugin._
import buttondevteam.discordplugin.DPUtils.SpecExtensions import buttondevteam.discordplugin.DPUtils.{MonoExtensions, SpecExtensions}
import buttondevteam.discordplugin.mcchat.sender.{DiscordUser, DiscordSender, DiscordSenderBase} import buttondevteam.discordplugin.mcchat.sender.{DiscordSender, DiscordSenderBase, DiscordUser}
import buttondevteam.lib.* import buttondevteam.lib._
import buttondevteam.lib.chat.{ChatMessage, TBMCChatAPI} import buttondevteam.lib.chat.{ChatMessage, TBMCChatAPI}
import buttondevteam.lib.player.TBMCPlayer import buttondevteam.lib.player.TBMCPlayer
import com.vdurmont.emoji.EmojiParser import com.vdurmont.emoji.EmojiParser
@ -22,6 +22,7 @@ import org.bukkit.entity.Player
import org.bukkit.event.{EventHandler, Listener} import org.bukkit.event.{EventHandler, Listener}
import org.bukkit.scheduler.BukkitTask import org.bukkit.scheduler.BukkitTask
import reactor.core.publisher.Mono import reactor.core.publisher.Mono
import reactor.core.scala.publisher.SMono
import java.time.Instant import java.time.Instant
import java.util import java.util
@ -148,7 +149,7 @@ class MCChatListener(val module: MinecraftChatModule) extends Listener {
} }
for (data <- MCChatPrivate.lastmsgPerUser) { for (data <- MCChatPrivate.lastmsgPerUser) {
if ((e.isFromCommand || isdifferentchannel.test(data.channel.getId)) && e.shouldSendTo(MCChatUtils.getSender(data.channel.getId, data.user))) { if ((e.isFromCommand || isdifferentchannel.test(data.channel.getId)) && e.shouldSendTo(data.user)) {
doit(data) doit(data)
} }
} }
@ -254,11 +255,11 @@ class MCChatListener(val module: MinecraftChatModule) extends Listener {
private var recthread: Thread = null private var recthread: Thread = null
// Discord // Discord
def handleDiscord(ev: MessageCreateEvent): Mono[Boolean] = { def handleDiscord(ev: MessageCreateEvent): SMono[Boolean] = {
val author = Option(ev.getMessage.getAuthor.orElse(null)) val author = Option(ev.getMessage.getAuthor.orElse(null))
val hasCustomChat = MCChatCustom.hasCustomChat(ev.getMessage.getChannelId) val hasCustomChat = MCChatCustom.hasCustomChat(ev.getMessage.getChannelId)
val prefix = DiscordPlugin.getPrefix val prefix = DiscordPlugin.getPrefix
ev.getMessage.getChannel ev.getMessage.getChannel.^^()
.filter(channel => isChatEnabled(channel, author, hasCustomChat)) .filter(channel => isChatEnabled(channel, author, hasCustomChat))
.filter(channel => !isRunningMCChatCommand(channel, ev.getMessage.getContent, prefix)) .filter(channel => !isRunningMCChatCommand(channel, ev.getMessage.getContent, prefix))
.filter(channel => { .filter(channel => {
@ -311,8 +312,8 @@ class MCChatListener(val module: MinecraftChatModule) extends Listener {
def replaceUserMentions(): Unit = { def replaceUserMentions(): Unit = {
for (u <- event.getMessage.getUserMentions.asScala) { //TODO: Role mentions for (u <- event.getMessage.getUserMentions.asScala) { //TODO: Role mentions
dmessage = dmessage.replace(u.getMention, "@" + u.getUsername) // TODO: IG Formatting dmessage = dmessage.replace(u.getMention, "@" + u.getUsername) // TODO: IG Formatting
val m = u.asMember(DiscordPlugin.mainServer.getId).onErrorResume(_ => Mono.empty).blockOptional val m = u.asMember(DiscordPlugin.mainServer.getId).^^().onErrorResume(_ => SMono.empty).blockOption()
if (m.isPresent) { if (m.nonEmpty) {
val mm: Member = m.get val mm: Member = m.get
val nick: String = mm.getDisplayName val nick: String = mm.getDisplayName
dmessage = dmessage.replace(mm.getNicknameMention, "@" + nick) dmessage = dmessage.replace(mm.getNicknameMention, "@" + nick)
@ -418,8 +419,7 @@ class MCChatListener(val module: MinecraftChatModule) extends Listener {
def notWhitelisted(cmd: String) = module.whitelistedCommands.get.stream def notWhitelisted(cmd: String) = module.whitelistedCommands.get.stream
.noneMatch(s => cmd == s || cmd.startsWith(s + " ")) .noneMatch(s => cmd == s || cmd.startsWith(s + " "))
def whitelistedCommands = module.whitelistedCommands.get.stream def whitelistedCommands = module.whitelistedCommands.get.asScala.map("/" + _).mkString(", ")
.map("/" + _).collect(Collectors.joining(", "))
if (!isPrivate) if (!isPrivate)
event.getMessage.delete.subscribe() event.getMessage.delete.subscribe()
@ -469,9 +469,9 @@ class MCChatListener(val module: MinecraftChatModule) extends Listener {
*/ */
private def runCustomCommand(dsender: DiscordSenderBase, cmdlowercased: String): Boolean = { private def runCustomCommand(dsender: DiscordSenderBase, cmdlowercased: String): Boolean = {
if (cmdlowercased.startsWith("list")) { if (cmdlowercased.startsWith("list")) {
val players = Bukkit.getOnlinePlayers val players = Bukkit.getOnlinePlayers.asScala
dsender.sendMessage("There are " + players.stream.filter(MCChatUtils.checkEssentials).count + " out of " + Bukkit.getMaxPlayers + " players online.") dsender.sendMessage("There are " + players.count(MCChatUtils.checkEssentials) + " out of " + Bukkit.getMaxPlayers + " players online.")
dsender.sendMessage("Players: " + players.stream.filter(MCChatUtils.checkEssentials).map(_.getDisplayName).collect(Collectors.joining(", "))) dsender.sendMessage("Players: " + players.filter(MCChatUtils.checkEssentials).map(_.getDisplayName).mkString(", "))
true true
} }
else false else false

View file

@ -54,7 +54,7 @@ object MCChatPrivate {
// ---- PermissionsEx warning is normal on logout ---- // ---- PermissionsEx warning is normal on logout ----
} }
if (!start) MCChatUtils.lastmsgfromd.remove(channel.getId.asLong) if (!start) MCChatUtils.lastmsgfromd.remove(channel.getId.asLong)
if (start) lastmsgPerUser += new MCChatUtils.LastMsgData(channel, user) // Doesn't support group DMs if (start) lastmsgPerUser += new MCChatUtils.LastMsgData(channel, dp) // Doesn't support group DMs
else lastmsgPerUser.filterInPlace(_.channel.getId.asLong != channel.getId.asLong) //Remove else lastmsgPerUser.filterInPlace(_.channel.getId.asLong != channel.getId.asLong) //Remove
} }
} }

View file

@ -1,27 +1,25 @@
package buttondevteam.discordplugin.mcchat package buttondevteam.discordplugin.mcchat
import buttondevteam.core.{ComponentManager, MainPlugin, component} import buttondevteam.core.{ComponentManager, MainPlugin, component}
import buttondevteam.discordplugin.*
import buttondevteam.discordplugin.ChannelconBroadcast.ChannelconBroadcast import buttondevteam.discordplugin.ChannelconBroadcast.ChannelconBroadcast
import buttondevteam.discordplugin.DPUtils.SpecExtensions import buttondevteam.discordplugin.DPUtils.MonoExtensions
import buttondevteam.discordplugin._
import buttondevteam.discordplugin.broadcaster.GeneralEventBroadcasterModule import buttondevteam.discordplugin.broadcaster.GeneralEventBroadcasterModule
import buttondevteam.discordplugin.mcchat.MCChatCustom.CustomLMD import buttondevteam.discordplugin.mcchat.MCChatCustom.CustomLMD
import buttondevteam.discordplugin.mcchat.sender.{DiscordConnectedPlayer, DiscordPlayerSender, DiscordSender, DiscordSenderBase} import buttondevteam.discordplugin.mcchat.sender.{DiscordConnectedPlayer, DiscordPlayerSender, DiscordSender, DiscordSenderBase}
import buttondevteam.lib.player.{ChromaGamerBase, TBMCPlayerBase} import buttondevteam.lib.player.ChromaGamerBase
import buttondevteam.lib.{TBMCCoreAPI, TBMCSystemChatEvent} import buttondevteam.lib.{TBMCCoreAPI, TBMCSystemChatEvent}
import com.google.common.collect.Sets import com.google.common.collect.Sets
import discord4j.common.util.Snowflake import discord4j.common.util.Snowflake
import discord4j.core.`object`.entity.channel.{Channel, MessageChannel, PrivateChannel, TextChannel} import discord4j.core.`object`.entity.channel.{Channel, MessageChannel, PrivateChannel, TextChannel}
import discord4j.core.`object`.entity.{Message, User} import discord4j.core.`object`.entity.{Message, User}
import discord4j.core.spec.legacy.LegacyTextChannelEditSpec
import io.netty.util.collection.LongObjectHashMap import io.netty.util.collection.LongObjectHashMap
import org.bukkit.Bukkit import org.bukkit.Bukkit
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player import org.bukkit.entity.Player
import org.bukkit.event.Event import org.bukkit.event.Event
import org.bukkit.event.player.{AsyncPlayerPreLoginEvent, PlayerJoinEvent, PlayerLoginEvent, PlayerQuitEvent} import org.bukkit.event.player.{AsyncPlayerPreLoginEvent, PlayerJoinEvent, PlayerLoginEvent, PlayerQuitEvent}
import org.bukkit.plugin.AuthorNagException import org.bukkit.plugin.AuthorNagException
import reactor.core.publisher.{Flux, Mono} import reactor.core.scala.publisher.SMono
import java.net.InetAddress import java.net.InetAddress
import java.util import java.util
@ -31,12 +29,11 @@ import java.util.concurrent.atomic.AtomicInteger
import java.util.logging.Level import java.util.logging.Level
import java.util.stream.Collectors import java.util.stream.Collectors
import javax.annotation.Nullable import javax.annotation.Nullable
import scala.collection.{concurrent, mutable}
import scala.collection.convert.ImplicitConversions.`map AsJavaMap` import scala.collection.convert.ImplicitConversions.`map AsJavaMap`
import scala.collection.mutable.ListBuffer import scala.collection.mutable.ListBuffer
import scala.jdk.CollectionConverters.{CollectionHasAsScala, SeqHasAsJava} import scala.collection.{concurrent, mutable}
import scala.jdk.CollectionConverters.CollectionHasAsScala
import scala.jdk.javaapi.CollectionConverters.asScala import scala.jdk.javaapi.CollectionConverters.asScala
import scala.jdk.javaapi.OptionConverters.*
object MCChatUtils { object MCChatUtils {
/** /**
@ -84,7 +81,7 @@ object MCChatUtils {
gid = buttondevteam.core.component.channel.Channel.GROUP_EVERYONE // (Though it's a public chat then rn) gid = buttondevteam.core.component.channel.Channel.GROUP_EVERYONE // (Though it's a public chat then rn)
} }
val C = new AtomicInteger val C = new AtomicInteger
s(s.length - 1) = "Players: " + Bukkit.getOnlinePlayers.stream.filter(p => if (lmd.mcchannel == null) { s(s.length - 1) = "Players: " + Bukkit.getOnlinePlayers.asScala.filter(p => if (lmd.mcchannel == null) {
gid == buttondevteam.core.component.channel.Channel.GROUP_EVERYONE //If null, allow if public (custom chats will have their channel stored anyway) gid == buttondevteam.core.component.channel.Channel.GROUP_EVERYONE //If null, allow if public (custom chats will have their channel stored anyway)
} }
else { else {
@ -92,7 +89,7 @@ object MCChatUtils {
} }
).filter(MCChatUtils.checkEssentials) //If they can see it ).filter(MCChatUtils.checkEssentials) //If they can see it
.filter(_ => C.incrementAndGet > 0) //Always true .filter(_ => C.incrementAndGet > 0) //Always true
.map((p) => DPUtils.sanitizeString(p.getDisplayName)).collect(Collectors.joining(", ")) .map((p) => DPUtils.sanitizeString(p.getDisplayName)).mkString(", ")
s(0) = s"$C player${if (C.get != 1) "s" else ""} online" s(0) = s"$C player${if (C.get != 1) "s" else ""} online"
lmd.channel.asInstanceOf[TextChannel].edit().withTopic(String.join("\n----\n", s: _*)).withReason("Player list update").subscribe() //Don't wait lmd.channel.asInstanceOf[TextChannel].edit().withTopic(String.join("\n----\n", s: _*)).withReason("Player list update").subscribe() //Don't wait
} }
@ -126,11 +123,11 @@ object MCChatUtils {
else null.asInstanceOf else null.asInstanceOf
} }
def forPublicPrivateChat(action: Mono[MessageChannel] => Mono[_]): Mono[_] = { def forPublicPrivateChat(action: SMono[MessageChannel] => SMono[_]): SMono[_] = {
if (notEnabled) return Mono.empty if (notEnabled) return SMono.empty
val list = MCChatPrivate.lastmsgPerUser.map(data => action(Mono.just(data.channel))) val list = MCChatPrivate.lastmsgPerUser.map(data => action(SMono.just(data.channel)))
.prepend(action(module.chatChannelMono)) .prepend(action(module.chatChannelMono))
Mono.whenDelayError(list.asJava) SMono.whenDelayError(list)
} }
/** /**
@ -140,14 +137,14 @@ object MCChatUtils {
* @param toggle The toggle to check * @param toggle The toggle to check
* @param hookmsg Whether the message is also sent from the hook * @param hookmsg Whether the message is also sent from the hook
*/ */
def forCustomAndAllMCChat(action: Mono[MessageChannel] => Mono[_], @Nullable toggle: ChannelconBroadcast, hookmsg: Boolean): Mono[_] = { def forCustomAndAllMCChat(action: SMono[MessageChannel] => SMono[_], @Nullable toggle: ChannelconBroadcast, hookmsg: Boolean): SMono[_] = {
if (notEnabled) return Mono.empty if (notEnabled) return SMono.empty
val list = List(if (!GeneralEventBroadcasterModule.isHooked || !hookmsg) val list = List(if (!GeneralEventBroadcasterModule.isHooked || !hookmsg)
forPublicPrivateChat(action) else Mono.empty) ++ forPublicPrivateChat(action) else SMono.empty) ++
(if (toggle == null) MCChatCustom.lastmsgCustom (if (toggle == null) MCChatCustom.lastmsgCustom
else MCChatCustom.lastmsgCustom.filter(cc => (cc.toggles & (1 << toggle.id)) != 0)) else MCChatCustom.lastmsgCustom.filter(cc => (cc.toggles & (1 << toggle.id)) != 0))
.map(_.channel).map(Mono.just).map(action) .map(_.channel).map(SMono.just).map(action)
Mono.whenDelayError(list.asJava) SMono.whenDelayError(list)
} }
/** /**
@ -157,15 +154,15 @@ object MCChatUtils {
* @param permUser The user to check perms of or null to send to all that has it toggled * @param permUser The user to check perms of or null to send to all that has it toggled
* @param toggle The toggle to check or null to send to all allowed * @param toggle The toggle to check or null to send to all allowed
*/ */
def forAllowedCustomMCChat(action: Mono[MessageChannel] => Mono[_], @Nullable permUser: ChromaGamerBase, @Nullable toggle: ChannelconBroadcast): Mono[_] = { def forAllowedCustomMCChat(action: SMono[MessageChannel] => SMono[_], @Nullable permUser: ChromaGamerBase, @Nullable toggle: ChannelconBroadcast): SMono[_] = {
if (notEnabled) return Mono.empty 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 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)) == 0)) false //If null then allow if (toggle != null && ((clmd.toggles & (1 << toggle.id)) == 0)) false //If null then allow
else if (permUser == null) true else if (permUser == null) true
else clmd.groupID.equals(clmd.mcchannel.getGroupID(permUser)) else clmd.groupID.equals(clmd.mcchannel.getGroupID(permUser))
}).map(cc => action.apply(Mono.just(cc.channel))) //TODO: Send error messages on channel connect }).map(cc => action.apply(SMono.just(cc.channel))) //TODO: Send error messages on channel connect
//Mono.whenDelayError((() => st.iterator).asInstanceOf[java.lang.Iterable[Mono[_]]]) //Can't convert as an iterator or inside the stream, but I can convert it as a stream //Mono.whenDelayError((() => st.iterator).asInstanceOf[java.lang.Iterable[SMono[_]]]) //Can't convert as an iterator or inside the stream, but I can convert it as a stream
Mono.whenDelayError(st.asJava) SMono.whenDelayError(st)
} }
/** /**
@ -176,38 +173,38 @@ object MCChatUtils {
* @param toggle The toggle to check or null to send to all allowed * @param toggle The toggle to check or null to send to all allowed
* @param hookmsg Whether the message is also sent from the hook * @param hookmsg Whether the message is also sent from the hook
*/ */
def forAllowedCustomAndAllMCChat(action: Mono[MessageChannel] => Mono[_], @Nullable permUser: ChromaGamerBase, @Nullable toggle: ChannelconBroadcast, hookmsg: Boolean): Mono[_] = { def forAllowedCustomAndAllMCChat(action: SMono[MessageChannel] => SMono[_], @Nullable permUser: ChromaGamerBase, @Nullable toggle: ChannelconBroadcast, hookmsg: Boolean): SMono[_] = {
if (notEnabled) return Mono.empty if (notEnabled) return SMono.empty
val cc = forAllowedCustomMCChat(action, permUser, toggle) val cc = forAllowedCustomMCChat(action, permUser, toggle)
if (!GeneralEventBroadcasterModule.isHooked || !hookmsg) return Mono.whenDelayError(forPublicPrivateChat(action), cc) if (!GeneralEventBroadcasterModule.isHooked || !hookmsg) return SMono.whenDelayError(List(forPublicPrivateChat(action), cc))
Mono.whenDelayError(cc) SMono.whenDelayError(List(cc))
} }
def send(message: String): Mono[MessageChannel] => Mono[_] = _.flatMap((mc: MessageChannel) => { def send(message: String): SMono[MessageChannel] => SMono[_] = _.flatMap((mc: MessageChannel) => {
resetLastMessage(mc) resetLastMessage(mc)
mc.createMessage(DPUtils.sanitizeString(message)) mc.createMessage(DPUtils.sanitizeString(message)).^^()
}) })
def forAllowedMCChat(action: Mono[MessageChannel] => Mono[_], event: TBMCSystemChatEvent): Mono[_] = { def forAllowedMCChat(action: SMono[MessageChannel] => SMono[_], event: TBMCSystemChatEvent): SMono[_] = {
if (notEnabled) return Mono.empty if (notEnabled) return SMono.empty
val list = new ListBuffer[Mono[_]] val list = new ListBuffer[SMono[_]]
if (event.getChannel.isGlobal) list.append(action(module.chatChannelMono)) if (event.getChannel.isGlobal) list.append(action(module.chatChannelMono))
for (data <- MCChatPrivate.lastmsgPerUser) for (data <- MCChatPrivate.lastmsgPerUser)
if (event.shouldSendTo(getSender(data.channel.getId, data.user))) if (event.shouldSendTo(data.user))
list.append(action(Mono.just(data.channel))) //TODO: Only store ID? list.append(action(SMono.just(data.channel))) //TODO: Only store ID?
MCChatCustom.lastmsgCustom.filter(clmd => MCChatCustom.lastmsgCustom.filter(clmd =>
clmd.brtoggles.contains(event.getTarget) && event.shouldSendTo(clmd.dcp.getChromaUser)) clmd.brtoggles.contains(event.getTarget) && event.shouldSendTo(clmd.dcp.getChromaUser))
.map(clmd => action(Mono.just(clmd.channel))).foreach(elem => { .map(clmd => action(SMono.just(clmd.channel))).foreach(elem => {
list.append(elem) list.append(elem)
() ()
}) })
Mono.whenDelayError(list.asJava) SMono.whenDelayError(list)
} }
/** /**
* This method will find the best sender to use: if the player is online, use that, if not but connected then use that etc. * 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 private[mcchat] def getSender(channel: Snowflake, author: User): DiscordSenderBase = {
Option(getSenderFrom(OnlineSenders, channel, author)) // Find first non-null Option(getSenderFrom(OnlineSenders, channel, author)) // Find first non-null
.orElse(Option(getSenderFrom(ConnectedSenders, channel, author))) // This doesn't support the public chat, but it'll always return null for it .orElse(Option(getSenderFrom(ConnectedSenders, channel, author))) // This doesn't support the public chat, but it'll always return null for it
.orElse(Option(getSenderFrom(UnconnectedSenders, channel, author))) // .orElse(Option(getSenderFrom(UnconnectedSenders, channel, author))) //
@ -347,13 +344,14 @@ object MCChatUtils {
private[mcchat] def callEventSync(event: Event) = Bukkit.getScheduler.runTask(DiscordPlugin.plugin, () => callEventExcludingSome(event)) private[mcchat] def callEventSync(event: Event) = Bukkit.getScheduler.runTask(DiscordPlugin.plugin, () => callEventExcludingSome(event))
class LastMsgData(val channel: MessageChannel, val user: User) { class LastMsgData(val channel: MessageChannel, @Nullable val user: ChromaGamerBase) {
var message: Message = null var message: Message = null
var time = 0L var time = 0L
var content: String = null var content: String = null
var mcchannel: component.channel.Channel = null var mcchannel: component.channel.Channel = null
protected def this(channel: MessageChannel, user: User, mcchannel: component.channel.Channel) = { protected def this(channel: MessageChannel, mcchannel: component.channel.Channel, user: ChromaGamerBase) = {
this(channel, user) this(channel, user)
this.mcchannel = mcchannel this.mcchannel = mcchannel
} }

View file

@ -1,7 +1,8 @@
package buttondevteam.discordplugin.mcchat package buttondevteam.discordplugin.mcchat
import buttondevteam.discordplugin.* import buttondevteam.discordplugin.DPUtils.{FluxExtensions, MonoExtensions}
import buttondevteam.discordplugin.mcchat.sender.{DiscordConnectedPlayer, DiscordUser, DiscordPlayerSender} import buttondevteam.discordplugin._
import buttondevteam.discordplugin.mcchat.sender.{DiscordConnectedPlayer, DiscordPlayerSender, DiscordUser}
import buttondevteam.lib.TBMCSystemChatEvent import buttondevteam.lib.TBMCSystemChatEvent
import buttondevteam.lib.player.{ChromaGamerBase, TBMCPlayer, TBMCPlayerBase, TBMCYEEHAWEvent} import buttondevteam.lib.player.{ChromaGamerBase, TBMCPlayer, TBMCPlayerBase, TBMCYEEHAWEvent}
import discord4j.common.util.Snowflake import discord4j.common.util.Snowflake
@ -11,11 +12,12 @@ import net.ess3.api.events.{AfkStatusChangeEvent, MuteStatusChangeEvent, NickCha
import org.bukkit.Bukkit import org.bukkit.Bukkit
import org.bukkit.entity.Player import org.bukkit.entity.Player
import org.bukkit.event.entity.PlayerDeathEvent import org.bukkit.event.entity.PlayerDeathEvent
import org.bukkit.event.player.*
import org.bukkit.event.player.PlayerLoginEvent.Result import org.bukkit.event.player.PlayerLoginEvent.Result
import org.bukkit.event.player._
import org.bukkit.event.server.{BroadcastMessageEvent, TabCompleteEvent} import org.bukkit.event.server.{BroadcastMessageEvent, TabCompleteEvent}
import org.bukkit.event.{EventHandler, EventPriority, Listener} import org.bukkit.event.{EventHandler, EventPriority, Listener}
import reactor.core.publisher.{Flux, Mono} import reactor.core.publisher.Flux
import reactor.core.scala.publisher.SMono
class MCListener(val module: MinecraftChatModule) extends Listener { class MCListener(val module: MinecraftChatModule) extends Listener {
final private val muteRole = DPUtils.roleData(module.getConfig, "muteRole", "Muted") final private val muteRole = DPUtils.roleData(module.getConfig, "muteRole", "Muted")
@ -34,11 +36,11 @@ class MCListener(val module: MinecraftChatModule) extends Listener {
val p = e.getPlayer val p = e.getPlayer
val dp = TBMCPlayerBase.getPlayer(p.getUniqueId, classOf[TBMCPlayer]).getAs(classOf[DiscordUser]) val dp = TBMCPlayerBase.getPlayer(p.getUniqueId, classOf[TBMCPlayer]).getAs(classOf[DiscordUser])
if (dp != null) if (dp != null)
DiscordPlugin.dc.getUserById(Snowflake.of(dp.getDiscordID)).flatMap(user => DiscordPlugin.dc.getUserById(Snowflake.of(dp.getDiscordID)).^^().flatMap(user =>
user.getPrivateChannel.flatMap(chan => module.chatChannelMono.flatMap(cc => { user.getPrivateChannel.^^().flatMap(chan => module.chatChannelMono.flatMap(cc => {
MCChatUtils.addSenderTo(MCChatUtils.OnlineSenders, dp.getDiscordID, DiscordPlayerSender.create(user, chan, p, module)) MCChatUtils.addSenderTo(MCChatUtils.OnlineSenders, dp.getDiscordID, DiscordPlayerSender.create(user, chan, p, module))
MCChatUtils.addSenderTo(MCChatUtils.OnlineSenders, dp.getDiscordID, DiscordPlayerSender.create(user, cc, p, module)) //Stored per-channel MCChatUtils.addSenderTo(MCChatUtils.OnlineSenders, dp.getDiscordID, DiscordPlayerSender.create(user, cc, p, module)) //Stored per-channel
Mono.empty SMono.empty
}))).subscribe() }))).subscribe()
val message = e.getJoinMessage val message = e.getJoinMessage
sendJoinLeaveMessage(message, e.getPlayer) sendJoinLeaveMessage(message, e.getPlayer)
@ -86,17 +88,17 @@ class MCListener(val module: MinecraftChatModule) extends Listener {
if (!source.isPlayer) return () if (!source.isPlayer) return ()
val p = TBMCPlayerBase.getPlayer(source.getPlayer.getUniqueId, classOf[TBMCPlayer]).getAs(classOf[DiscordUser]) val p = TBMCPlayerBase.getPlayer(source.getPlayer.getUniqueId, classOf[TBMCPlayer]).getAs(classOf[DiscordUser])
if (p == null) return () if (p == null) return ()
DPUtils.ignoreError(DiscordPlugin.dc.getUserById(Snowflake.of(p.getDiscordID)) DPUtils.ignoreError(DiscordPlugin.dc.getUserById(Snowflake.of(p.getDiscordID)).^^()
.flatMap(user => user.asMember(DiscordPlugin.mainServer.getId)) .flatMap(user => user.asMember(DiscordPlugin.mainServer.getId).^^())
.flatMap(user => role.flatMap((r: Role) => { .flatMap(user => role.flatMap((r: Role) => {
def foo(r: Role): Mono[_] = { def foo(r: Role): SMono[_] = {
if (e.getValue) user.addRole(r.getId) if (e.getValue) user.addRole(r.getId)
else user.removeRole(r.getId) else user.removeRole(r.getId)
val modlog = module.modlogChannel.get val modlog = module.modlogChannel.get
val msg = s"${(if (e.getValue) "M" else "Unm")}uted user: ${user.getUsername}#${user.getDiscriminator}" val msg = s"${(if (e.getValue) "M" else "Unm")}uted user: ${user.getUsername}#${user.getDiscriminator}"
module.log(msg) module.log(msg)
if (modlog != null) return modlog.flatMap((ch: MessageChannel) => ch.createMessage(msg)) if (modlog != null) return modlog.flatMap((ch: MessageChannel) => ch.createMessage(msg).^^())
Mono.empty SMono.empty
} }
foo(r) foo(r)
@ -111,13 +113,13 @@ class MCListener(val module: MinecraftChatModule) extends Listener {
MCChatUtils.forCustomAndAllMCChat(MCChatUtils.send(event.getMessage), ChannelconBroadcast.BROADCAST, hookmsg = false).subscribe() MCChatUtils.forCustomAndAllMCChat(MCChatUtils.send(event.getMessage), ChannelconBroadcast.BROADCAST, hookmsg = false).subscribe()
} }
@EventHandler def onYEEHAW(event: TBMCYEEHAWEvent): Unit = { //TODO: Inherit from the chat event base to have channel support @EventHandler def onYEEHAW(event: TBMCYEEHAWEvent): Unit = { //TODO: Implement as a colored system message to have channel support
val name = event.getSender match { val name = event.getSender match {
case player: Player => player.getDisplayName case player: Player => player.getDisplayName
case _ => event.getSender.getName case _ => event.getSender.getName
} }
//Channel channel = ChromaGamerBase.getFromSender(event.getSender()).channel().get(); - TODO //Channel channel = ChromaGamerBase.getFromSender(event.getSender()).channel().get(); - TODO
DiscordPlugin.mainServer.getEmojis.filter(e => "YEEHAW" == e.getName).take(1).singleOrEmpty DiscordPlugin.mainServer.getEmojis.^^().filter(e => "YEEHAW" == e.getName).take(1).singleOrEmpty
.map(Option.apply).defaultIfEmpty(Option.empty) .map(Option.apply).defaultIfEmpty(Option.empty)
.flatMap(yeehaw => MCChatUtils.forPublicPrivateChat(MCChatUtils.send(name + .flatMap(yeehaw => MCChatUtils.forPublicPrivateChat(MCChatUtils.send(name +
yeehaw.map(guildEmoji => " <:YEEHAW:" + guildEmoji.getId.asString + ">s").getOrElse(" YEEHAWs")))).subscribe() yeehaw.map(guildEmoji => " <:YEEHAW:" + guildEmoji.getId.asString + ">s").getOrElse(" YEEHAWs")))).subscribe()
@ -130,7 +132,7 @@ class MCListener(val module: MinecraftChatModule) extends Listener {
val t = event.getBuffer.substring(i + 1) //0 if not found val t = event.getBuffer.substring(i + 1) //0 if not found
if (!t.startsWith("@")) return () if (!t.startsWith("@")) return ()
val token = t.substring(1) val token = t.substring(1)
val x = DiscordPlugin.mainServer.getMembers.flatMap(m => Flux.just(m.getUsername, m.getNickname.orElse(""))) val x = DiscordPlugin.mainServer.getMembers.^^().flatMap(m => Flux.just(m.getUsername, m.getNickname.orElse("")))
.filter(_.startsWith(token)).map("@" + _).doOnNext(event.getCompletions.add(_)).blockLast() .filter(_.startsWith(token)).map("@" + _).doOnNext(event.getCompletions.add(_)).blockLast()
} }

View file

@ -1,6 +1,7 @@
package buttondevteam.discordplugin.mcchat package buttondevteam.discordplugin.mcchat
import buttondevteam.core.component.channel.Channel import buttondevteam.core.component.channel.Channel
import buttondevteam.discordplugin.DPUtils.MonoExtensions
import buttondevteam.discordplugin.mcchat.sender.DiscordConnectedPlayer import buttondevteam.discordplugin.mcchat.sender.DiscordConnectedPlayer
import buttondevteam.discordplugin.util.DPState import buttondevteam.discordplugin.util.DPState
import buttondevteam.discordplugin.{ChannelconBroadcast, DPUtils, DiscordPlugin} import buttondevteam.discordplugin.{ChannelconBroadcast, DPUtils, DiscordPlugin}
@ -10,9 +11,11 @@ import buttondevteam.lib.{TBMCCoreAPI, TBMCSystemChatEvent}
import com.google.common.collect.Lists import com.google.common.collect.Lists
import discord4j.common.util.Snowflake import discord4j.common.util.Snowflake
import discord4j.core.`object`.entity.channel.MessageChannel import discord4j.core.`object`.entity.channel.MessageChannel
import discord4j.core.spec.EmbedCreateSpec
import discord4j.rest.util.Color import discord4j.rest.util.Color
import org.bukkit.Bukkit import org.bukkit.Bukkit
import reactor.core.publisher.Mono import reactor.core.publisher.Mono
import reactor.core.scala.publisher.SMono
import java.util import java.util
import java.util.stream.Collectors import java.util.stream.Collectors
@ -46,12 +49,12 @@ class MinecraftChatModule extends Component[DiscordPlugin] {
*/ */
def chatChannel: IConfigData[Snowflake] = DPUtils.snowflakeData(getConfig, "chatChannel", 0L) def chatChannel: IConfigData[Snowflake] = DPUtils.snowflakeData(getConfig, "chatChannel", 0L)
def chatChannelMono: Mono[MessageChannel] = DPUtils.getMessageChannel(chatChannel.getPath, chatChannel.get) def chatChannelMono: SMono[MessageChannel] = DPUtils.getMessageChannel(chatChannel.getPath, chatChannel.get)
/** /**
* The channel where the plugin can log when it mutes a player on Discord because of a Minecraft mute * The channel where the plugin can log when it mutes a player on Discord because of a Minecraft mute
*/ */
def modlogChannel: IConfigData[Mono[MessageChannel]] = DPUtils.channelData(getConfig, "modlogChannel") def modlogChannel: IConfigData[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 * The plugins to exclude from fake player events used for the 'mcchat' command - some plugins may crash, add them here
*/ */
@ -167,7 +170,7 @@ class MinecraftChatModule extends Component[DiscordPlugin] {
} }
else { else {
val kickmsg = if (Bukkit.getOnlinePlayers.size > 0) val kickmsg = if (Bukkit.getOnlinePlayers.size > 0)
DPUtils.sanitizeString(Bukkit.getOnlinePlayers.stream.map(_.getDisplayName).collect(Collectors.joining(", "))) + DPUtils.sanitizeString(Bukkit.getOnlinePlayers.asScala.map(_.getDisplayName).mkString(", ")) +
(if (Bukkit.getOnlinePlayers.size == 1) " was " else " were ") + "thrown out" //TODO: Make configurable (if (Bukkit.getOnlinePlayers.size == 1) " was " else " were ") + "thrown out" //TODO: Make configurable
else "" else ""
if (MinecraftChatModule.state eq DPState.RESTARTING_SERVER) sendStateMessage(Color.ORANGE, "Server restarting", kickmsg) if (MinecraftChatModule.state eq DPState.RESTARTING_SERVER) sendStateMessage(Color.ORANGE, "Server restarting", kickmsg)
@ -190,7 +193,7 @@ class MinecraftChatModule extends Component[DiscordPlugin] {
val chconc = chconsc.createSection(chcon.channel.getId.asString) val chconc = chconsc.createSection(chcon.channel.getId.asString)
chconc.set("mcchid", chcon.mcchannel.getIdentifier) chconc.set("mcchid", chcon.mcchannel.getIdentifier)
chconc.set("chid", chcon.channel.getId.asLong) chconc.set("chid", chcon.channel.getId.asLong)
chconc.set("did", chcon.user.getId.asLong) chconc.set("did", chcon.dcUser.getId.asLong)
chconc.set("mcuid", chcon.dcp.getUniqueId.toString) chconc.set("mcuid", chcon.dcp.getUniqueId.toString)
chconc.set("mcname", chcon.dcp.getName) chconc.set("mcname", chcon.dcp.getName)
chconc.set("groupid", chcon.groupID) chconc.set("groupid", chcon.groupID)
@ -209,14 +212,14 @@ class MinecraftChatModule extends Component[DiscordPlugin] {
* It will block to make sure all messages are sent * It will block to make sure all messages are sent
*/ */
private def sendStateMessage(color: Color, message: String) = private def sendStateMessage(color: Color, message: String) =
MCChatUtils.forCustomAndAllMCChat(_.flatMap( MCChatUtils.forCustomAndAllMCChat(_.flatMap(ch => ch.createMessage(
_.createEmbed(_.setColor(color).setTitle(message)) EmbedCreateSpec.builder().color(color).title(message).build()).^^()
.onErrorResume(_ => Mono.empty) .onErrorResume(_ => SMono.empty)
), ChannelconBroadcast.RESTART, hookmsg = false).block() ), ChannelconBroadcast.RESTART, hookmsg = false).block()
private def sendStateMessage(color: Color, message: String, extra: String) = private def sendStateMessage(color: Color, message: String, extra: String) =
MCChatUtils.forCustomAndAllMCChat(_.flatMap( MCChatUtils.forCustomAndAllMCChat(_.flatMap(ch => ch.createMessage(
_.createEmbed(_.setColor(color).setTitle(message).setDescription(extra)) EmbedCreateSpec.builder().color(color).title(message).description(extra).build()).^^()
.onErrorResume(_ => Mono.empty) .onErrorResume(_ => SMono.empty)
), ChannelconBroadcast.RESTART, hookmsg = false).block() ), ChannelconBroadcast.RESTART, hookmsg = false).block()
} }

View file

@ -4,7 +4,7 @@ import buttondevteam.discordplugin.mcchat.MinecraftChatModule
import discord4j.core.`object`.entity.User import discord4j.core.`object`.entity.User
import discord4j.core.`object`.entity.channel.MessageChannel import discord4j.core.`object`.entity.channel.MessageChannel
import net.kyori.adventure.text.Component import net.kyori.adventure.text.Component
import org.bukkit.* import org.bukkit._
import org.bukkit.attribute.{Attribute, AttributeInstance, AttributeModifier} import org.bukkit.attribute.{Attribute, AttributeInstance, AttributeModifier}
import org.bukkit.entity.{Entity, Player} import org.bukkit.entity.{Entity, Player}
import org.bukkit.event.inventory.InventoryType import org.bukkit.event.inventory.InventoryType
@ -18,7 +18,7 @@ import org.mockito.{MockSettings, Mockito}
import java.lang.reflect.Modifier import java.lang.reflect.Modifier
import java.util import java.util
import java.util.* import java.util._
object DiscordConnectedPlayer { object DiscordConnectedPlayer {
def create(user: User, channel: MessageChannel, uuid: UUID, mcname: String, module: MinecraftChatModule): DiscordConnectedPlayer = def create(user: User, channel: MessageChannel, uuid: UUID, mcname: String, module: MinecraftChatModule): DiscordConnectedPlayer =
@ -53,9 +53,9 @@ object DiscordConnectedPlayer {
* @param playerName The Minecraft name of the player. * @param playerName The Minecraft name of the player.
* @param module The MinecraftChatModule or null if testing. * @param module The MinecraftChatModule or null if testing.
*/ */
abstract class DiscordConnectedPlayer(user: User, channel: MessageChannel, val uniqueId: UUID, val playerName: String, val module: MinecraftChatModule) extends DiscordSenderBase(user, channel) with IMCPlayer[DiscordConnectedPlayer] { abstract class DiscordConnectedPlayer(user: User, channel: MessageChannel, val uniqueId: UUID, val playerName: String, val module: MinecraftChatModule) extends DiscordSenderBase(user, channel) with IMCPlayer[DiscordConnectedPlayer] with Player {
private var loggedIn = false private var loggedIn = false
private var displayName: String = playerName private var dispName: String = playerName
private var location: Location = if (module == null) null else Bukkit.getWorlds.get(0).getSpawnLocation private var location: Location = if (module == null) null else Bukkit.getWorlds.get(0).getSpawnLocation
private val basePlayer: OfflinePlayer = if (module == null) null else Bukkit.getOfflinePlayer(uniqueId) private val basePlayer: OfflinePlayer = if (module == null) null else Bukkit.getOfflinePlayer(uniqueId)
@ -93,7 +93,7 @@ abstract class DiscordConnectedPlayer(user: User, channel: MessageChannel, val u
def setPerm(perm: PermissibleBase): Unit = this.perm = perm def setPerm(perm: PermissibleBase): Unit = this.perm = perm
override def setDisplayName(displayName: String): Unit = this.displayName = displayName override def setDisplayName(displayName: String): Unit = this.dispName = displayName
override def getVanillaCmdListener = this.vanillaCmdListener override def getVanillaCmdListener = this.vanillaCmdListener
@ -107,7 +107,7 @@ abstract class DiscordConnectedPlayer(user: User, channel: MessageChannel, val u
override def getUniqueId: UUID = this.uniqueId override def getUniqueId: UUID = this.uniqueId
override def getDisplayName: String = this.displayName override def getDisplayName: String = this.dispName
/** /**
* For testing * For testing
@ -191,6 +191,9 @@ abstract class DiscordConnectedPlayer(user: User, channel: MessageChannel, val u
override def getValue: Double = getDefaultValue override def getValue: Double = getDefaultValue
override def getDefaultValue: Double = 20 //Works for max health, should be okay for the rest override def getDefaultValue: Double = 20 //Works for max health, should be okay for the rest
override def addTransientModifier(modifier: AttributeModifier): Unit = {
}
} }
override def getGameMode = GameMode.SPECTATOR override def getGameMode = GameMode.SPECTATOR

View file

@ -23,7 +23,7 @@ object DiscordPlayerSender {
}).useConstructor(user, channel, player, module)) }).useConstructor(user, channel, player, module))
} }
abstract class DiscordPlayerSender(user: User, channel: MessageChannel, var player: Player, val module: Nothing) extends DiscordSenderBase(user, channel) with IMCPlayer[DiscordPlayerSender] { abstract class DiscordPlayerSender(user: User, channel: MessageChannel, var player: Player, val module: Nothing) extends DiscordSenderBase(user, channel) with IMCPlayer[DiscordPlayerSender] with Player {
override def getVanillaCmdListener = null override def getVanillaCmdListener = null
@ -32,8 +32,8 @@ abstract class DiscordPlayerSender(user: User, channel: MessageChannel, var play
super.sendMessage(message) super.sendMessage(message)
} }
override def sendMessage(messages: Array[? <: String]): Unit = { override def sendMessage(messages: String*): Unit = {
player.sendMessage(messages*) player.sendMessage(messages: _*)
super.sendMessage(messages) super.sendMessage(messages: _*)
} }
} }

View file

@ -1,5 +1,6 @@
package buttondevteam.discordplugin.mcchat.sender package buttondevteam.discordplugin.mcchat.sender
import buttondevteam.discordplugin.DPUtils.MonoExtensions
import buttondevteam.discordplugin.DiscordPlugin import buttondevteam.discordplugin.DiscordPlugin
import discord4j.core.`object`.entity.User import discord4j.core.`object`.entity.User
import discord4j.core.`object`.entity.channel.MessageChannel import discord4j.core.`object`.entity.channel.MessageChannel
@ -9,15 +10,16 @@ import org.bukkit.permissions.{PermissibleBase, Permission, PermissionAttachment
import org.bukkit.plugin.Plugin import org.bukkit.plugin.Plugin
import org.bukkit.{Bukkit, Server} import org.bukkit.{Bukkit, Server}
import reactor.core.publisher.Mono import reactor.core.publisher.Mono
import reactor.core.scala.publisher.SMono
import scala.jdk.OptionConverters.* import scala.jdk.OptionConverters._
import java.util import java.util
class DiscordSender(user: User, channel: MessageChannel, pname: String) extends DiscordSenderBase(user, channel) with CommandSender { class DiscordSender(user: User, channel: MessageChannel, pname: String) extends DiscordSenderBase(user, channel) with CommandSender {
private val perm = new PermissibleBase(this) private val perm = new PermissibleBase(this)
private val senderName: String = Option(pname) private val senderName: String = Option(pname)
.orElse(Option(user).flatMap(u => u.asMember(DiscordPlugin.mainServer.getId) .orElse(Option(user).flatMap(u => u.asMember(DiscordPlugin.mainServer.getId).^^()
.onErrorResume(_ => Mono.empty).blockOptional().toScala .onErrorResume(_ => SMono.empty).blockOption()
.map(u => u.getDisplayName))) .map(u => u.getDisplayName)))
.getOrElse("Discord user") .getOrElse("Discord user")

View file

@ -64,8 +64,8 @@ abstract class DiscordSenderBase protected(var user: User, var channel: MessageC
TBMCCoreAPI.SendException("An error occured while sending message to DiscordSender", e, DiscordPlugin.plugin) TBMCCoreAPI.SendException("An error occured while sending message to DiscordSender", e, DiscordPlugin.plugin)
} }
override def sendMessage(messages: Array[? <: String]): Unit = sendMessage(String.join("\n", messages: _*)) override def sendMessage(messages: String*): Unit = sendMessage(messages.mkString("\n"))
override def sendMessage(sender: UUID, message: String): Unit = sendMessage(message) override def sendMessage(sender: UUID, message: String): Unit = sendMessage(message)
override def sendMessage(sender: UUID, messages: Array[? <: String]): Unit = sendMessage(messages) override def sendMessage(sender: UUID, messages: String*): Unit = sendMessage(messages : _*)
} }

View file

@ -1,5 +1,6 @@
package buttondevteam.discordplugin.mcchat.sender package buttondevteam.discordplugin.mcchat.sender
import buttondevteam.core.component.channel.Channel
import buttondevteam.discordplugin.DiscordPlugin import buttondevteam.discordplugin.DiscordPlugin
import buttondevteam.discordplugin.mcchat.MCChatPrivate import buttondevteam.discordplugin.mcchat.MCChatPrivate
import buttondevteam.lib.player.{ChromaGamerBase, UserClass} import buttondevteam.lib.player.{ChromaGamerBase, UserClass}
@ -26,4 +27,12 @@ import discord4j.core.`object`.entity.User
* [[MCChatPrivate.privateMCChat]] * [[MCChatPrivate.privateMCChat]]
*/ */
def isMinecraftChatEnabled: Boolean = MCChatPrivate.isMinecraftChatEnabled(this) def isMinecraftChatEnabled: Boolean = MCChatPrivate.isMinecraftChatEnabled(this)
override def checkChannelInGroup(s: String): Channel.RecipientTestResult = ???
override def sendMessage(message: String): Unit = ??? // TODO: Somehow check which message is this a response to
override def sendMessage(message: Array[String]): Unit = ???
override def getName: String = ???
} }

View file

@ -1,7 +1,8 @@
package buttondevteam.discordplugin.mccommands package buttondevteam.discordplugin.mccommands
import buttondevteam.discordplugin.DPUtils.FluxExtensions
import buttondevteam.discordplugin.commands.{ConnectCommand, VersionCommand} import buttondevteam.discordplugin.commands.{ConnectCommand, VersionCommand}
import buttondevteam.discordplugin.mcchat.sender.{DiscordUser, DiscordSenderBase} import buttondevteam.discordplugin.mcchat.sender.{DiscordSenderBase, DiscordUser}
import buttondevteam.discordplugin.mcchat.{MCChatUtils, MinecraftChatModule} import buttondevteam.discordplugin.mcchat.{MCChatUtils, MinecraftChatModule}
import buttondevteam.discordplugin.util.DPState import buttondevteam.discordplugin.util.DPState
import buttondevteam.discordplugin.{DPUtils, DiscordPlugin} import buttondevteam.discordplugin.{DPUtils, DiscordPlugin}
@ -96,7 +97,7 @@ import java.lang.reflect.Method
"Version command", "Version command",
"Prints the plugin version")) "Prints the plugin version"))
def version(sender: CommandSender): Unit = { def version(sender: CommandSender): Unit = {
sender.sendMessage(VersionCommand.getVersion*) sender.sendMessage(VersionCommand.getVersion: _*)
} }
@Command2.Subcommand(helpText = Array( @Command2.Subcommand(helpText = Array(
@ -112,9 +113,9 @@ import java.lang.reflect.Method
sender.sendMessage("§bInvite link: " + invi) sender.sendMessage("§bInvite link: " + invi)
return () return ()
} }
DiscordPlugin.mainServer.getInvites.limitRequest(1) DiscordPlugin.mainServer.getInvites.^^().take(1)
.switchIfEmpty(Mono.fromRunnable(() => sender.sendMessage("§cNo invites found for the server."))) .switchIfEmpty(Mono.fromRunnable(() => sender.sendMessage("§cNo invites found for the server.")))
.subscribe((inv: ExtendedInvite) => sender.sendMessage("§bInvite link: https://discord.gg/" + inv.getCode), _ => sender.sendMessage("§cThe invite link is not set and the bot has no permission to get it.")) .subscribe((inv: ExtendedInvite) => sender.sendMessage("§bInvite link: https://discord.gg/" + inv.getCode), Some(_ => sender.sendMessage("§cThe invite link is not set and the bot has no permission to get it.")))
} }
override def getHelpText(method: Method, ann: Command2.Subcommand): Array[String] = { override def getHelpText(method: Method, ann: Command2.Subcommand): Array[String] = {

View file

@ -1,6 +1,7 @@
package buttondevteam.discordplugin.role package buttondevteam.discordplugin.role
import buttondevteam.core.ComponentManager import buttondevteam.core.ComponentManager
import buttondevteam.discordplugin.DPUtils.{FluxExtensions, MonoExtensions}
import buttondevteam.discordplugin.{DPUtils, DiscordPlugin} import buttondevteam.discordplugin.{DPUtils, DiscordPlugin}
import buttondevteam.lib.architecture.{Component, ComponentMetadata} import buttondevteam.lib.architecture.{Component, ComponentMetadata}
import discord4j.core.`object`.entity.Role import discord4j.core.`object`.entity.Role
@ -9,8 +10,11 @@ import discord4j.core.event.domain.role.{RoleCreateEvent, RoleDeleteEvent, RoleE
import discord4j.rest.util.Color import discord4j.rest.util.Color
import org.bukkit.Bukkit import org.bukkit.Bukkit
import reactor.core.publisher.Mono import reactor.core.publisher.Mono
import reactor.core.scala.publisher.SMono
import java.util.Collections import java.util.Collections
import scala.collection.mutable
import scala.collection.mutable.ListBuffer
import scala.jdk.CollectionConverters.SeqHasAsJava import scala.jdk.CollectionConverters.SeqHasAsJava
/** /**
@ -24,19 +28,26 @@ import scala.jdk.CollectionConverters.SeqHasAsJava
val GameRoles = grm.GameRoles val GameRoles = grm.GameRoles
val logChannel = grm.logChannel.get val logChannel = grm.logChannel.get
val notMainServer = (_: Role).getGuildId.asLong != DiscordPlugin.mainServer.getId.asLong val notMainServer = (_: Role).getGuildId.asLong != DiscordPlugin.mainServer.getId.asLong
def removeFromList = (name: String) => {
val c = GameRoles.size
GameRoles.subtractOne(name)
c > GameRoles.size
}
roleEvent match { roleEvent match {
case roleCreateEvent: RoleCreateEvent => Bukkit.getScheduler.runTaskLaterAsynchronously(DiscordPlugin.plugin, () => { case roleCreateEvent: RoleCreateEvent => Bukkit.getScheduler.runTaskLaterAsynchronously(DiscordPlugin.plugin, () => {
val role = roleCreateEvent.getRole val role = roleCreateEvent.getRole
if (!notMainServer(role)) { if (!notMainServer(role)) {
grm.isGameRole(role).flatMap(b => { grm.isGameRole(role).flatMap(b => {
if (!b) Mono.empty //Deleted or not a game role if (!b) SMono.empty //Deleted or not a game role
else { else {
GameRoles.add(role.getName) GameRoles.addOne(role.getName)
if (logChannel != null) if (logChannel != null)
logChannel.flatMap(_.createMessage("Added " + role.getName + " as game role." + logChannel.flatMap(_.createMessage("Added " + role.getName + " as game role." +
" If you don't want this, change the role's color from the game role color.")) " If you don't want this, change the role's color from the game role color.").^^())
else else
Mono.empty SMono.empty
} }
}).subscribe() }).subscribe()
() ()
@ -46,8 +57,8 @@ import scala.jdk.CollectionConverters.SeqHasAsJava
val role = roleDeleteEvent.getRole.orElse(null) val role = roleDeleteEvent.getRole.orElse(null)
if (role == null) return () if (role == null) return ()
if (notMainServer(role)) return () if (notMainServer(role)) return ()
if (GameRoles.remove(role.getName) && logChannel != null) if (removeFromList(role.getName) && logChannel != null)
logChannel.flatMap(_.createMessage("Removed " + role.getName + " as a game role.")).subscribe() logChannel.flatMap(_.createMessage("Removed " + role.getName + " as a game role.").^^()).subscribe()
case roleUpdateEvent: RoleUpdateEvent => case roleUpdateEvent: RoleUpdateEvent =>
if (!roleUpdateEvent.getOld.isPresent) { if (!roleUpdateEvent.getOld.isPresent) {
grm.logWarn("Old role not stored, cannot update game role!") grm.logWarn("Old role not stored, cannot update game role!")
@ -58,22 +69,22 @@ import scala.jdk.CollectionConverters.SeqHasAsJava
val cr = roleUpdateEvent.getCurrent val cr = roleUpdateEvent.getCurrent
grm.isGameRole(cr).flatMap(isGameRole => { grm.isGameRole(cr).flatMap(isGameRole => {
if (!isGameRole) if (!isGameRole)
if (GameRoles.remove(or.getName) && logChannel != null) if (removeFromList(or.getName) && logChannel != null)
logChannel.flatMap(_.createMessage("Removed " + or.getName + " as a game role because its color changed.")) logChannel.flatMap(_.createMessage("Removed " + or.getName + " as a game role because its color changed.").^^())
else else
Mono.empty SMono.empty
else if (GameRoles.contains(or.getName) && or.getName == cr.getName) else if (GameRoles.contains(or.getName) && or.getName == cr.getName)
Mono.empty SMono.empty
else { else {
val removed = GameRoles.remove(or.getName) //Regardless of whether it was a game role val removed = removeFromList(or.getName) //Regardless of whether it was a game role
GameRoles.add(cr.getName) //Add it because it has no color GameRoles.addOne(cr.getName) //Add it because it has no color
if (logChannel != null) if (logChannel != null)
if (removed) if (removed)
logChannel.flatMap((ch: MessageChannel) => ch.createMessage("Changed game role from " + or.getName + " to " + cr.getName + ".")) logChannel.flatMap((ch: MessageChannel) => ch.createMessage("Changed game role from " + or.getName + " to " + cr.getName + ".").^^())
else else
logChannel.flatMap((ch: MessageChannel) => ch.createMessage("Added " + cr.getName + " as game role because it has the color of one.")) logChannel.flatMap((ch: MessageChannel) => ch.createMessage("Added " + cr.getName + " as game role because it has the color of one.").^^())
else else
Mono.empty SMono.empty
} }
}).subscribe() }).subscribe()
case _ => case _ =>
@ -82,12 +93,12 @@ import scala.jdk.CollectionConverters.SeqHasAsJava
} }
@ComponentMetadata(enabledByDefault = false) class GameRoleModule extends Component[DiscordPlugin] { @ComponentMetadata(enabledByDefault = false) class GameRoleModule extends Component[DiscordPlugin] {
var GameRoles: java.util.List[String] = null var GameRoles: mutable.Buffer[String] = null
final private val command = new RoleCommand(this) final private val command = new RoleCommand(this)
override protected def enable(): Unit = { override protected def enable(): Unit = {
getPlugin.manager.registerCommand(command) getPlugin.manager.registerCommand(command)
GameRoles = DiscordPlugin.mainServer.getRoles.filterWhen(this.isGameRole).map(_.getName).collectList().block() GameRoles = DiscordPlugin.mainServer.getRoles.^^().filterWhen(this.isGameRole).map(_.getName).collectSeq().block().toBuffer
} }
override protected def disable(): Unit = getPlugin.manager.unregisterCommand(command) override protected def disable(): Unit = getPlugin.manager.unregisterCommand(command)
@ -101,15 +112,15 @@ import scala.jdk.CollectionConverters.SeqHasAsJava
* Defaults to the second to last in the upper row - #95a5a6. * Defaults to the second to last in the upper row - #95a5a6.
*/ */
final private def roleColor = getConfig.getData("roleColor", Color.of(149, 165, 166), final private def roleColor = getConfig.getData("roleColor", Color.of(149, 165, 166),
rgb => Color.of(Integer.parseInt(rgb.asInstanceOf[String].substring(1), 16)), (rgb: Any) => Color.of(Integer.parseInt(rgb.asInstanceOf[String].substring(1), 16)),
color => String.format("#%08x", color.getRGB), true) (color: Color) => String.format("#%08x", color.getRGB), true)
private def isGameRole(r: Role): Mono[java.lang.Boolean] = { private def isGameRole(r: Role): SMono[Boolean] = {
if (r.getGuildId.asLong != DiscordPlugin.mainServer.getId.asLong) return Mono.just(false) //Only allow on the main server if (r.getGuildId.asLong != DiscordPlugin.mainServer.getId.asLong) return SMono.just(false) //Only allow on the main server
val rc = roleColor.get val rc = roleColor.get
if (r.getColor equals rc) if (r.getColor equals rc)
DiscordPlugin.dc.getSelf.flatMap(u => u.asMember(DiscordPlugin.mainServer.getId)) DiscordPlugin.dc.getSelf.^^().flatMap(u => u.asMember(DiscordPlugin.mainServer.getId).^^())
.flatMap(_.hasHigherRoles(Collections.singleton(r.getId))).defaultIfEmpty(false) //Below one of our roles .flatMap(_.hasHigherRoles(Collections.singleton(r.getId)).^^()).cast[Boolean].defaultIfEmpty(false) //Below one of our roles
else Mono.just(false) else SMono.just(false)
} }
} }

View file

@ -41,7 +41,7 @@ import reactor.core.publisher.Mono
@Command2.Subcommand def list(sender: Command2DCSender): Unit = { @Command2.Subcommand def list(sender: Command2DCSender): Unit = {
val sb = new StringBuilder val sb = new StringBuilder
var b = false var b = false
for (role <- grm.GameRoles.stream.sorted.iterator.asInstanceOf[Iterable[String]]) { for (role <- grm.GameRoles.sorted.iterator.asInstanceOf[Iterable[String]]) {
sb.append(role) sb.append(role)
if (!b) for (_ <- 0 until Math.max(1, 20 - role.length)) { if (!b) for (_ <- 0 until Math.max(1, 20 - role.length)) {
sb.append(" ") sb.append(" ")
@ -56,8 +56,8 @@ import reactor.core.publisher.Mono
private def checkAndGetRole(sender: Command2DCSender, rolename: String): Role = { private def checkAndGetRole(sender: Command2DCSender, rolename: String): Role = {
var rname = rolename var rname = rolename
if (!grm.GameRoles.contains(rolename)) { //If not found as-is, correct case if (!grm.GameRoles.contains(rolename)) { //If not found as-is, correct case
val orn = grm.GameRoles.stream.filter(r => r.equalsIgnoreCase(rolename)).findAny val orn = grm.GameRoles.find(r => r.equalsIgnoreCase(rolename))
if (!orn.isPresent) { if (orn.isEmpty) {
sender.sendMessage("that role cannot be found.") sender.sendMessage("that role cannot be found.")
list(sender) list(sender)
return null return null
@ -72,7 +72,7 @@ import reactor.core.publisher.Mono
} }
if (roles.size == 0) { if (roles.size == 0) {
sender.sendMessage("the specified role cannot be found on Discord! Removing from the list.") sender.sendMessage("the specified role cannot be found on Discord! Removing from the list.")
grm.GameRoles.remove(rolename) grm.GameRoles.subtractOne(rolename)
return null return null
} }
if (roles.size > 1) { if (roles.size > 1) {