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"
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 += "paper-repo" at "https://papermc.io/repo/repository/maven-public/"
resolvers += Resolver.mavenLocal
@ -23,10 +16,10 @@ libraryDependencies ++= Seq(
"com.discord4j" % "discord4j-core" % "3.2.3",
"com.vdurmont" % "emoji-java" % "5.1.1",
"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,
"net.ess3" % "EssentialsX" % "2.17.1" % Provided,
"net.luckperms" % "api" % "5.4" % Provided,
// https://mvnrepository.com/artifact/com.mojang/brigadier
"com.mojang" % "brigadier" % "1.0.500" % "provided",
// https://mvnrepository.com/artifact/net.kyori/examination-api
@ -52,93 +45,7 @@ assembly / assemblyMergeStrategy := {
val saveConfigComments = TaskKey[Seq[File]]("saveConfigComments")
saveConfigComments := {
val sv = (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"))
Commenter.saveConfigComments((Compile / sources).value)
}
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
scala.version=3.0.0
scala.version=2.13.0

View file

@ -2,5 +2,6 @@
//lazy val root = (project in file(".")).dependsOn(commenter)
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 discord4j.core.`object`.entity.Message
import discord4j.core.`object`.entity.channel.MessageChannel
import reactor.core.publisher.Mono
import reactor.core.scala.publisher.SMono
import javax.annotation.Nullable
@ -20,7 +20,7 @@ object ChromaBot {
*
* @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()
/**
@ -29,7 +29,7 @@ object ChromaBot {
* @param message The message to send, duh
* @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()
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.legacy.{LegacyEmbedCreateSpec, LegacySpec}
import reactor.core.publisher.{Flux, Mono}
import reactor.core.scala.publisher.{SFlux, SMono}
import java.util
import java.util.Comparator
@ -69,21 +70,21 @@ object DPUtils {
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])),
(_: 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]] =
roleData(config, key, defName, Mono.just(DiscordPlugin.mainServer))
def roleData(config: IHaveConfig, key: String, defName: String): IConfigData[SMono[Role]] =
roleData(config, key, defName, SMono.just(DiscordPlugin.mainServer))
/**
* 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 => {
if (!name.isInstanceOf[String] || name.asInstanceOf[String].isEmpty) Mono.empty[Role]
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) SMono.empty[Role]
else guild.flatMapMany(_.getRoles).filter(_.getName == name).onErrorResume(e => {
getLogger.warning("Failed to get role data for " + key + "=" + name + " - " + e.getMessage)
Mono.empty[Role]
SMono.empty[Role]
}).next
}, _ => defName, defName, true)
@ -125,7 +126,7 @@ object DPUtils {
*/
def disableIfConfigErrorRes(@Nullable component: Component[DiscordPlugin], config: IConfigData[_], result: Any): Boolean = {
//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
try {
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 channel The channel to send the message in, defaults to the original
* @param message The message to send
* @return A mono to send the message
*/
def reply(original: Message, @Nullable channel: MessageChannel, message: String): Mono[Message] = {
val ch = if (channel == null) original.getChannel
else Mono.just(channel)
@deprecated("Use reply(Message, SMono<MessageChannel>, String) instead", since = "1.1.0")
def reply(original: Message, @Nullable channel: MessageChannel, message: String): SMono[Message] = {
val ch = if (channel == null) original.getChannel.^^()
else SMono.just(channel)
reply(original, ch, message)
}
/**
* @see #reply(Message, MessageChannel, String)
*/
def reply(original: Message, ch: Mono[MessageChannel], message: String): Mono[Message] =
ch.flatMap(channel => channel.createMessage((if (original.getAuthor.isPresent)
original.getAuthor.get.getMention + ", "
else "") + message))
def reply(original: Message, ch: SMono[MessageChannel], message: String): SMono[Message] =
ch.switchIfEmpty(original.getChannel().^^()).flatMap(channel => channel.createMessage((
if (original.getAuthor.isPresent)
original.getAuthor.get.getMention + ", "
else ""
) + message).^^())
def nickMention(userId: Snowflake): String = "<@!" + userId.asString + ">"
@ -177,19 +181,27 @@ object DPUtils {
* @param id The channel ID
* @return A message channel
*/
def getMessageChannel(key: String, id: Snowflake): Mono[MessageChannel] = {
if (id.asLong == 0L) return Mono.empty[MessageChannel]
def getMessageChannel(key: String, id: Snowflake): SMono[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}")
Mono.empty[Channel]
}).filter(ch => ch.isInstanceOf[MessageChannel]).cast(classOf[MessageChannel])
SMono.empty[Channel]
}).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)
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) {
def ^^(): Unit = ()

View file

@ -1,19 +1,20 @@
package buttondevteam.discordplugin
import buttondevteam.discordplugin.DPUtils.{FluxExtensions, MonoExtensions}
import buttondevteam.discordplugin.DiscordPlugin.dc
import buttondevteam.discordplugin.announcer.AnnouncerModule
import buttondevteam.discordplugin.broadcaster.GeneralEventBroadcasterModule
import buttondevteam.discordplugin.commands.*
import buttondevteam.discordplugin.commands._
import buttondevteam.discordplugin.exceptions.ExceptionListenerModule
import buttondevteam.discordplugin.fun.FunModule
import buttondevteam.discordplugin.listeners.{CommonListeners, MCListener}
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.role.GameRoleModule
import buttondevteam.discordplugin.util.{DPState, Timings}
import buttondevteam.lib.TBMCCoreAPI
import buttondevteam.lib.architecture.*
import buttondevteam.lib.architecture._
import buttondevteam.lib.architecture.config.IConfigData
import buttondevteam.lib.player.ChromaGamerBase
import com.google.common.io.Files
@ -32,11 +33,12 @@ import org.bukkit.configuration.file.YamlConfiguration
import org.mockito.internal.util.MockUtil
import reactor.core.Disposable
import reactor.core.publisher.Mono
import reactor.core.scala.publisher.SMono
import java.io.File
import java.nio.charset.StandardCharsets
import java.util.Optional
import scala.jdk.OptionConverters.*
import scala.jdk.OptionConverters._
@ButtonPlugin.ConfigOpts(disableConfigGen = true) object DiscordPlugin {
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.
*/
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
else DiscordPlugin.dc.getGuildById(Snowflake.of(id.asInstanceOf[Long]))
else DiscordPlugin.dc.getGuildById(Snowflake.of(id.asInstanceOf[Long])).^^()
.onErrorResume(t => {
getLogger.warning("Failed to get guild: " + t.getMessage)
Mono.empty
}).blockOptional().toScala
}, g => g.map(_.getId.asLong).getOrElse(0L), 0L, true)
SMono.empty
}).blockOption()
}, (g: Option[Guild]) => g.map(_.getId.asLong).getOrElse(0L), 0L, true)
/**
* 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.
* 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.
*/
@ -133,7 +135,7 @@ import scala.jdk.OptionConverters.*
foo(t)
}).subscribe((dc: GatewayDiscordClient) => {
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
()
}) /* All guilds have been received, client is fully connected */

View file

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

View file

@ -1,24 +1,24 @@
package buttondevteam.discordplugin.commands
import buttondevteam.discordplugin.DPUtils.MonoExtensions
import buttondevteam.discordplugin.DiscordPlugin
import buttondevteam.discordplugin.listeners.CommonListeners
import buttondevteam.lib.chat.{Command2, CommandClass}
import discord4j.common.util.Snowflake
import discord4j.core.`object`.entity.{Member, User}
import reactor.core.publisher.Mono
import scala.jdk.OptionConverters._
import reactor.core.scala.publisher.SMono
@CommandClass(helpText = Array("Switches debug mode."))
class DebugCommand extends ICommand2DC {
@Command2.Subcommand
override def `def`(sender: Command2DCSender): Boolean = {
Mono.justOrEmpty(sender.authorAsMember.orNull)
SMono.justOrEmpty(sender.authorAsMember.orNull)
.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
.map(mr => m.getRoleIds.stream.anyMatch((r: Snowflake) => r == mr.getId))
.switchIfEmpty(Mono.fromCallable(() => DiscordPlugin.mainServer.getOwnerId.asLong == m.getId.asLong)))
.onErrorResume(_ => Mono.just(false)) //Role not found
.switchIfEmpty(SMono.fromCallable(() => DiscordPlugin.mainServer.getOwnerId.asLong == m.getId.asLong)))
.onErrorResume(_ => SMono.just(false)) //Role not found
.subscribe(success => {
if (success) {
CommonListeners.debug = !CommonListeners.debug

View file

@ -1,11 +1,12 @@
package buttondevteam.discordplugin.commands
import buttondevteam.discordplugin.DPUtils.FluxExtensions
import buttondevteam.discordplugin.DiscordPlugin
import buttondevteam.discordplugin.mcchat.sender.DiscordUser
import buttondevteam.lib.chat.{Command2, CommandClass}
import buttondevteam.lib.player.ChromaGamerBase
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
@ -33,9 +34,9 @@ class UserinfoCommand extends ICommand2DC {
private def getUsers(message: Message, args: String) = {
val guild = message.getGuild.block
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
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
import buttondevteam.core.ComponentManager
import buttondevteam.discordplugin.DPUtils.MonoExtensions
import buttondevteam.discordplugin.DiscordPlugin
import buttondevteam.lib.TBMCDebugMessageEvent
import discord4j.core.`object`.entity.channel.MessageChannel
@ -16,7 +17,7 @@ object DebugMessageListener {
sb.append("```").append("\n")
sb.append(if (message.length > 2000) message.substring(0, 2000) else message).append("\n")
sb.append("```")
mc.flatMap((ch: MessageChannel) => ch.createMessage(sb.toString)).subscribe()
mc.flatMap((ch: MessageChannel) => ch.createMessage(sb.toString).^^()).subscribe()
} catch {
case ex: Exception =>
ex.printStackTrace()

View file

@ -1,15 +1,16 @@
package buttondevteam.discordplugin.exceptions
import buttondevteam.core.ComponentManager
import buttondevteam.discordplugin.DPUtils.MonoExtensions
import buttondevteam.discordplugin.{DPUtils, DiscordPlugin}
import buttondevteam.lib.architecture.Component
import buttondevteam.lib.{TBMCCoreAPI, TBMCExceptionEvent}
import discord4j.core.`object`.entity.Guild
import discord4j.core.`object`.entity.channel.{GuildChannel, MessageChannel}
import discord4j.core.`object`.entity.{Guild, Role}
import org.apache.commons.lang.exception.ExceptionUtils
import org.bukkit.Bukkit
import org.bukkit.event.{EventHandler, Listener}
import reactor.core.publisher.Mono
import reactor.core.scala.publisher.SMono
import java.util
import java.util.stream.Collectors
@ -22,11 +23,10 @@ object ExceptionListenerModule {
if (instance == null) return ()
try getChannel.flatMap(channel => {
val coderRole = channel match {
case ch: GuildChannel => instance.pingRole(ch.getGuild).get
case _ => Mono.empty
case ch: GuildChannel => instance.pingRole(ch.getGuild.^^()).get
case _ => SMono.empty
}
coderRole.map((role: Role) => if (TBMCCoreAPI.IsTestServer) new StringBuilder
else new StringBuilder(role.getMention).append("\n"))
coderRole.map(role => if (TBMCCoreAPI.IsTestServer) new StringBuilder else new StringBuilder(role.getMention).append("\n")) // Ping if prod server
.defaultIfEmpty(new StringBuilder).flatMap(sb => {
sb.append(sourcemessage).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)
sb.append(stackTrace).append("\n")
sb.append("```")
channel.createMessage(sb.toString)
channel.createMessage(sb.toString).^^()
})
}).subscribe()
catch {
@ -47,9 +47,9 @@ object ExceptionListenerModule {
private var instance: ExceptionListenerModule = null
def getChannel: Mono[MessageChannel] = {
def getChannel: SMono[MessageChannel] = {
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.
*/
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 = {
if (DPUtils.disableIfConfigError(this, channel)) return ()

View file

@ -1,6 +1,7 @@
package buttondevteam.discordplugin.fun
import buttondevteam.core.ComponentManager
import buttondevteam.discordplugin.DPUtils.{FluxExtensions, MonoExtensions}
import buttondevteam.discordplugin.{DPUtils, DiscordPlugin}
import buttondevteam.lib.TBMCCoreAPI
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`.presence.Status
import discord4j.core.event.domain.PresenceUpdateEvent
import discord4j.core.spec.{EmbedCreateSpec, MessageCreateSpec}
import discord4j.core.spec.legacy.{LegacyEmbedCreateSpec, LegacyMessageCreateSpec}
import org.bukkit.Bukkit
import org.bukkit.event.player.PlayerJoinEvent
import org.bukkit.event.{EventHandler, Listener}
import reactor.core.publisher.Mono
import reactor.core.scala.publisher.SMono
import java.util
import java.util.Calendar
@ -53,7 +56,7 @@ object FunModule {
ListC += 1
ListC - 1
} > 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
lastlistp = Bukkit.getOnlinePlayers.size.toShort
return true //Handled
@ -63,7 +66,7 @@ object FunModule {
var next = 0
if (usableServerReadyStrings.size == 0) fm.createUsableServerReadyStrings()
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
}
false
@ -79,17 +82,20 @@ object FunModule {
|| event.getCurrent.getStatus == Status.OFFLINE)
return () //If it's not an offline -> online change
fm.fullHouseChannel.get.filter((ch: MessageChannel) => ch.isInstanceOf[GuildChannel])
.flatMap(channel => fm.fullHouseDevRole(channel.asInstanceOf[GuildChannel].getGuild).get
.filterWhen(devrole => event.getMember
.flatMap(m => m.getRoles.any(_.getId.asLong == devrole.getId.asLong)))
.filterWhen(devrole => event.getGuild
.flatMap(channel => fm.fullHouseDevRole(channel.asInstanceOf[GuildChannel].getGuild.^^()).get
.filterWhen(devrole => event.getMember.^^()
.flatMap(m => m.getRoles.^^().any(_.getId.asLong == devrole.getId.asLong)))
.filterWhen(devrole => event.getGuild.^^()
.flatMapMany(g => g.getMembers.filter(_.getRoleIds.stream.anyMatch(_ == devrole.getId)))
.flatMap(_.getPresence).all(_.getStatus != Status.OFFLINE))
.filter(_ => lasttime + 10 < TimeUnit.NANOSECONDS.toHours(System.nanoTime)) //This should stay so it checks this last
.flatMap(_ => {
lasttime = TimeUnit.NANOSECONDS.toHours(System.nanoTime)
channel.createMessage(_.setContent("Full house!")
.setEmbed((ecs: LegacyEmbedCreateSpec) => ecs.setImage("https://cdn.discordapp.com/attachments/249295547263877121/249687682618359808/poker-hand-full-house-aces-kings-playing-cards-15553791.png")))
channel.createMessage(MessageCreateSpec.builder().content("Full house!")
.addEmbed(EmbedCreateSpec.builder()
.image("https://cdn.discordapp.com/attachments/249295547263877121/249687682618359808/poker-hand-full-house-aces-kings-playing-cards-15553791.png")
.build())
.build()).^^()
})).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 finished", "when's the server ready",
"when's the server open", "vhen vill ze server be open?"))
/**
* 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.
*/
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.

View file

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

View file

@ -1,5 +1,6 @@
package buttondevteam.discordplugin.listeners
import buttondevteam.discordplugin.DPUtils.MonoExtensions
import buttondevteam.discordplugin.commands.ConnectCommand
import buttondevteam.discordplugin.mcchat.MinecraftChatModule
import buttondevteam.discordplugin.util.DPState
@ -11,6 +12,8 @@ import discord4j.common.util.Snowflake
import org.bukkit.event.player.PlayerJoinEvent
import org.bukkit.event.{EventHandler, Listener}
import reactor.core.publisher.Mono
import reactor.core.scala.publisher.SMono
import scala.jdk.OptionConverters._
class MCListener extends Listener {
@ -25,12 +28,12 @@ class MCListener extends Listener {
@EventHandler def onGetInfo(e: TBMCPlayerGetInfoEvent): Unit = {
Option(DiscordPlugin.SafeMode).filterNot(identity).flatMap(_ => Option(e.getPlayer.getAs(classOf[DiscordUser])))
.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 => {
e.addInfo("Discord tag: " + user.getUsername + "#" + user.getDiscriminator)
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)
.map(pr => {
e.addInfo(pr.getStatus.toString)

View file

@ -1,26 +1,27 @@
package buttondevteam.discordplugin.mcchat
import buttondevteam.core.component.channel.{Channel, ChatRoom}
import buttondevteam.discordplugin.*
import buttondevteam.discordplugin.ChannelconBroadcast.ChannelconBroadcast
import buttondevteam.discordplugin.DPUtils.MonoExtensions
import buttondevteam.discordplugin._
import buttondevteam.discordplugin.commands.{Command2DCSender, ICommand2DC}
import buttondevteam.discordplugin.mcchat.sender.{DiscordConnectedPlayer, DiscordUser}
import buttondevteam.lib.TBMCSystemChatEvent
import buttondevteam.lib.architecture.config.IConfigData
import buttondevteam.lib.chat.{Command2, CommandClass}
import buttondevteam.lib.player.{ChromaGamerBase, TBMCPlayer}
import discord4j.core.`object`.entity.Message
import discord4j.core.`object`.entity.channel.{GuildChannel, MessageChannel}
import discord4j.rest.util.{Permission, PermissionSet}
import org.bukkit.Bukkit
import reactor.core.publisher.Mono
import reactor.core.scala.publisher.SMono
import java.lang.reflect.Method
import java.util
import java.util.function.Supplier
import java.util.stream.Collectors
import java.util.{Objects, Optional}
import javax.annotation.Nullable
import scala.jdk.Accumulator
import scala.jdk.OptionConverters.RichOptional
import scala.jdk.StreamConverters.StreamHasToScala
@SuppressWarnings(Array("SimplifyOptionalCallChains")) //Java 11
@CommandClass(helpText = Array("Channel connect", //
@ -38,9 +39,9 @@ class ChannelconCommand(private val module: MinecraftChatModule) extends IComman
val message: Message = null // TODO
if (checkPerms(message, null)) return true
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
DPUtils.reply(message, Mono.empty, "this channel isn't connected.").subscribe()
DPUtils.reply(message, SMono.empty, "this channel isn't connected.").subscribe()
true
}
@ -56,11 +57,11 @@ class ChannelconCommand(private val module: MinecraftChatModule) extends IComman
val togglesString: Supplier[String] = () => ChannelconBroadcast.values
.map(t => t.toString.toLowerCase + ": " + (if ((cc.toggles & (1 << t.id)) == 0) "disabled" else "enabled"))
.mkString("\n") + "\n\n" +
TBMCSystemChatEvent.BroadcastTarget.stream.map((target: TBMCSystemChatEvent.BroadcastTarget) =>
target.getName + ": " + (if (cc.brtoggles.contains(target)) "enabled" else "disabled"))
.collect(Collectors.joining("\n"))
TBMCSystemChatEvent.BroadcastTarget.stream.toScala(Accumulator)
.map(target => s"${target.getName}: ${if (cc.brtoggles.contains(target)) "enabled" else "disabled"}")
.mkString("\n")
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
}
val arg: String = toggle.toUpperCase
@ -68,7 +69,7 @@ class ChannelconCommand(private val module: MinecraftChatModule) extends IComman
if (b.isEmpty) {
val bt: TBMCSystemChatEvent.BroadcastTarget = TBMCSystemChatEvent.BroadcastTarget.get(arg)
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
}
val add: Boolean = !cc.brtoggles.contains(bt)
@ -88,7 +89,7 @@ class ChannelconCommand(private val module: MinecraftChatModule) extends IComman
//1 1 | 0
// XOR
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()
true
}
@ -157,7 +158,7 @@ class ChannelconCommand(private val module: MinecraftChatModule) extends IComman
return true
}
//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))) {
DPUtils.reply(message, channel, "you need to have manage permissions for this channel!").subscribe()
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.",
"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="
+ 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>")
}

View file

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

View file

@ -54,7 +54,7 @@ object MCChatPrivate {
// ---- PermissionsEx warning is normal on logout ----
}
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
}
}

View file

@ -1,27 +1,25 @@
package buttondevteam.discordplugin.mcchat
import buttondevteam.core.{ComponentManager, MainPlugin, component}
import buttondevteam.discordplugin.*
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.mcchat.MCChatCustom.CustomLMD
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 com.google.common.collect.Sets
import discord4j.common.util.Snowflake
import discord4j.core.`object`.entity.channel.{Channel, MessageChannel, PrivateChannel, TextChannel}
import discord4j.core.`object`.entity.{Message, User}
import discord4j.core.spec.legacy.LegacyTextChannelEditSpec
import io.netty.util.collection.LongObjectHashMap
import org.bukkit.Bukkit
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player
import org.bukkit.event.Event
import org.bukkit.event.player.{AsyncPlayerPreLoginEvent, PlayerJoinEvent, PlayerLoginEvent, PlayerQuitEvent}
import org.bukkit.plugin.AuthorNagException
import reactor.core.publisher.{Flux, Mono}
import reactor.core.scala.publisher.SMono
import java.net.InetAddress
import java.util
@ -31,12 +29,11 @@ import java.util.concurrent.atomic.AtomicInteger
import java.util.logging.Level
import java.util.stream.Collectors
import javax.annotation.Nullable
import scala.collection.{concurrent, mutable}
import scala.collection.convert.ImplicitConversions.`map AsJavaMap`
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.OptionConverters.*
object MCChatUtils {
/**
@ -84,7 +81,7 @@ object MCChatUtils {
gid = buttondevteam.core.component.channel.Channel.GROUP_EVERYONE // (Though it's a public chat then rn)
}
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)
}
else {
@ -92,7 +89,7 @@ object MCChatUtils {
}
).filter(MCChatUtils.checkEssentials) //If they can see it
.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"
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
}
def forPublicPrivateChat(action: Mono[MessageChannel] => Mono[_]): Mono[_] = {
if (notEnabled) return Mono.empty
val list = MCChatPrivate.lastmsgPerUser.map(data => action(Mono.just(data.channel)))
def forPublicPrivateChat(action: SMono[MessageChannel] => SMono[_]): SMono[_] = {
if (notEnabled) return SMono.empty
val list = MCChatPrivate.lastmsgPerUser.map(data => action(SMono.just(data.channel)))
.prepend(action(module.chatChannelMono))
Mono.whenDelayError(list.asJava)
SMono.whenDelayError(list)
}
/**
@ -140,14 +137,14 @@ object MCChatUtils {
* @param toggle The toggle to check
* @param hookmsg Whether the message is also sent from the hook
*/
def forCustomAndAllMCChat(action: Mono[MessageChannel] => Mono[_], @Nullable toggle: ChannelconBroadcast, hookmsg: Boolean): Mono[_] = {
if (notEnabled) return Mono.empty
def forCustomAndAllMCChat(action: SMono[MessageChannel] => SMono[_], @Nullable toggle: ChannelconBroadcast, hookmsg: Boolean): SMono[_] = {
if (notEnabled) return SMono.empty
val list = List(if (!GeneralEventBroadcasterModule.isHooked || !hookmsg)
forPublicPrivateChat(action) else Mono.empty) ++
forPublicPrivateChat(action) else SMono.empty) ++
(if (toggle == null) MCChatCustom.lastmsgCustom
else MCChatCustom.lastmsgCustom.filter(cc => (cc.toggles & (1 << toggle.id)) != 0))
.map(_.channel).map(Mono.just).map(action)
Mono.whenDelayError(list.asJava)
.map(_.channel).map(SMono.just).map(action)
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 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[_] = {
if (notEnabled) return Mono.empty
def forAllowedCustomMCChat(action: SMono[MessageChannel] => SMono[_], @Nullable permUser: ChromaGamerBase, @Nullable toggle: ChannelconBroadcast): SMono[_] = {
if (notEnabled) return SMono.empty
val st = MCChatCustom.lastmsgCustom.filter(clmd => { //new TBMCChannelConnectFakeEvent(sender, clmd.mcchannel).shouldSendTo(clmd.dcp) - Thought it was this simple hehe - Wait, it *should* be this simple
if (toggle != null && ((clmd.toggles & (1 << toggle.id)) == 0)) false //If null then allow
else if (permUser == null) true
else clmd.groupID.equals(clmd.mcchannel.getGroupID(permUser))
}).map(cc => action.apply(Mono.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.asJava)
}).map(cc => action.apply(SMono.just(cc.channel))) //TODO: Send error messages on channel connect
//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
SMono.whenDelayError(st)
}
/**
@ -176,38 +173,38 @@ object MCChatUtils {
* @param toggle The toggle to check or null to send to all allowed
* @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[_] = {
if (notEnabled) return Mono.empty
def forAllowedCustomAndAllMCChat(action: SMono[MessageChannel] => SMono[_], @Nullable permUser: ChromaGamerBase, @Nullable toggle: ChannelconBroadcast, hookmsg: Boolean): SMono[_] = {
if (notEnabled) return SMono.empty
val cc = forAllowedCustomMCChat(action, permUser, toggle)
if (!GeneralEventBroadcasterModule.isHooked || !hookmsg) return Mono.whenDelayError(forPublicPrivateChat(action), cc)
Mono.whenDelayError(cc)
if (!GeneralEventBroadcasterModule.isHooked || !hookmsg) return SMono.whenDelayError(List(forPublicPrivateChat(action), 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)
mc.createMessage(DPUtils.sanitizeString(message))
mc.createMessage(DPUtils.sanitizeString(message)).^^()
})
def forAllowedMCChat(action: Mono[MessageChannel] => Mono[_], event: TBMCSystemChatEvent): Mono[_] = {
if (notEnabled) return Mono.empty
val list = new ListBuffer[Mono[_]]
def forAllowedMCChat(action: SMono[MessageChannel] => SMono[_], event: TBMCSystemChatEvent): SMono[_] = {
if (notEnabled) return SMono.empty
val list = new ListBuffer[SMono[_]]
if (event.getChannel.isGlobal) list.append(action(module.chatChannelMono))
for (data <- MCChatPrivate.lastmsgPerUser)
if (event.shouldSendTo(getSender(data.channel.getId, data.user)))
list.append(action(Mono.just(data.channel))) //TODO: Only store ID?
if (event.shouldSendTo(data.user))
list.append(action(SMono.just(data.channel))) //TODO: Only store ID?
MCChatCustom.lastmsgCustom.filter(clmd =>
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)
()
})
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.
*/
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
.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))) //
@ -347,13 +344,14 @@ object MCChatUtils {
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 time = 0L
var content: String = 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.mcchannel = mcchannel
}

View file

@ -1,7 +1,8 @@
package buttondevteam.discordplugin.mcchat
import buttondevteam.discordplugin.*
import buttondevteam.discordplugin.mcchat.sender.{DiscordConnectedPlayer, DiscordUser, DiscordPlayerSender}
import buttondevteam.discordplugin.DPUtils.{FluxExtensions, MonoExtensions}
import buttondevteam.discordplugin._
import buttondevteam.discordplugin.mcchat.sender.{DiscordConnectedPlayer, DiscordPlayerSender, DiscordUser}
import buttondevteam.lib.TBMCSystemChatEvent
import buttondevteam.lib.player.{ChromaGamerBase, TBMCPlayer, TBMCPlayerBase, TBMCYEEHAWEvent}
import discord4j.common.util.Snowflake
@ -11,11 +12,12 @@ import net.ess3.api.events.{AfkStatusChangeEvent, MuteStatusChangeEvent, NickCha
import org.bukkit.Bukkit
import org.bukkit.entity.Player
import org.bukkit.event.entity.PlayerDeathEvent
import org.bukkit.event.player.*
import org.bukkit.event.player.PlayerLoginEvent.Result
import org.bukkit.event.player._
import org.bukkit.event.server.{BroadcastMessageEvent, TabCompleteEvent}
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 {
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 dp = TBMCPlayerBase.getPlayer(p.getUniqueId, classOf[TBMCPlayer]).getAs(classOf[DiscordUser])
if (dp != null)
DiscordPlugin.dc.getUserById(Snowflake.of(dp.getDiscordID)).flatMap(user =>
user.getPrivateChannel.flatMap(chan => module.chatChannelMono.flatMap(cc => {
DiscordPlugin.dc.getUserById(Snowflake.of(dp.getDiscordID)).^^().flatMap(user =>
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, cc, p, module)) //Stored per-channel
Mono.empty
SMono.empty
}))).subscribe()
val message = e.getJoinMessage
sendJoinLeaveMessage(message, e.getPlayer)
@ -86,17 +88,17 @@ class MCListener(val module: MinecraftChatModule) extends Listener {
if (!source.isPlayer) return ()
val p = TBMCPlayerBase.getPlayer(source.getPlayer.getUniqueId, classOf[TBMCPlayer]).getAs(classOf[DiscordUser])
if (p == null) return ()
DPUtils.ignoreError(DiscordPlugin.dc.getUserById(Snowflake.of(p.getDiscordID))
.flatMap(user => user.asMember(DiscordPlugin.mainServer.getId))
DPUtils.ignoreError(DiscordPlugin.dc.getUserById(Snowflake.of(p.getDiscordID)).^^()
.flatMap(user => user.asMember(DiscordPlugin.mainServer.getId).^^())
.flatMap(user => role.flatMap((r: Role) => {
def foo(r: Role): Mono[_] = {
def foo(r: Role): SMono[_] = {
if (e.getValue) user.addRole(r.getId)
else user.removeRole(r.getId)
val modlog = module.modlogChannel.get
val msg = s"${(if (e.getValue) "M" else "Unm")}uted user: ${user.getUsername}#${user.getDiscriminator}"
module.log(msg)
if (modlog != null) return modlog.flatMap((ch: MessageChannel) => ch.createMessage(msg))
Mono.empty
if (modlog != null) return modlog.flatMap((ch: MessageChannel) => ch.createMessage(msg).^^())
SMono.empty
}
foo(r)
@ -111,13 +113,13 @@ class MCListener(val module: MinecraftChatModule) extends Listener {
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 {
case player: Player => player.getDisplayName
case _ => event.getSender.getName
}
//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)
.flatMap(yeehaw => MCChatUtils.forPublicPrivateChat(MCChatUtils.send(name +
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
if (!t.startsWith("@")) return ()
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()
}

View file

@ -1,6 +1,7 @@
package buttondevteam.discordplugin.mcchat
import buttondevteam.core.component.channel.Channel
import buttondevteam.discordplugin.DPUtils.MonoExtensions
import buttondevteam.discordplugin.mcchat.sender.DiscordConnectedPlayer
import buttondevteam.discordplugin.util.DPState
import buttondevteam.discordplugin.{ChannelconBroadcast, DPUtils, DiscordPlugin}
@ -10,9 +11,11 @@ import buttondevteam.lib.{TBMCCoreAPI, TBMCSystemChatEvent}
import com.google.common.collect.Lists
import discord4j.common.util.Snowflake
import discord4j.core.`object`.entity.channel.MessageChannel
import discord4j.core.spec.EmbedCreateSpec
import discord4j.rest.util.Color
import org.bukkit.Bukkit
import reactor.core.publisher.Mono
import reactor.core.scala.publisher.SMono
import java.util
import java.util.stream.Collectors
@ -46,12 +49,12 @@ class MinecraftChatModule extends Component[DiscordPlugin] {
*/
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
*/
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
*/
@ -167,7 +170,7 @@ class MinecraftChatModule extends Component[DiscordPlugin] {
}
else {
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
else ""
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)
chconc.set("mcchid", chcon.mcchannel.getIdentifier)
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("mcname", chcon.dcp.getName)
chconc.set("groupid", chcon.groupID)
@ -209,14 +212,14 @@ class MinecraftChatModule extends Component[DiscordPlugin] {
* It will block to make sure all messages are sent
*/
private def sendStateMessage(color: Color, message: String) =
MCChatUtils.forCustomAndAllMCChat(_.flatMap(
_.createEmbed(_.setColor(color).setTitle(message))
.onErrorResume(_ => Mono.empty)
MCChatUtils.forCustomAndAllMCChat(_.flatMap(ch => ch.createMessage(
EmbedCreateSpec.builder().color(color).title(message).build()).^^()
.onErrorResume(_ => SMono.empty)
), ChannelconBroadcast.RESTART, hookmsg = false).block()
private def sendStateMessage(color: Color, message: String, extra: String) =
MCChatUtils.forCustomAndAllMCChat(_.flatMap(
_.createEmbed(_.setColor(color).setTitle(message).setDescription(extra))
.onErrorResume(_ => Mono.empty)
MCChatUtils.forCustomAndAllMCChat(_.flatMap(ch => ch.createMessage(
EmbedCreateSpec.builder().color(color).title(message).description(extra).build()).^^()
.onErrorResume(_ => SMono.empty)
), 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.channel.MessageChannel
import net.kyori.adventure.text.Component
import org.bukkit.*
import org.bukkit._
import org.bukkit.attribute.{Attribute, AttributeInstance, AttributeModifier}
import org.bukkit.entity.{Entity, Player}
import org.bukkit.event.inventory.InventoryType
@ -18,7 +18,7 @@ import org.mockito.{MockSettings, Mockito}
import java.lang.reflect.Modifier
import java.util
import java.util.*
import java.util._
object 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 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 displayName: String = playerName
private var dispName: String = playerName
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)
@ -93,7 +93,7 @@ abstract class DiscordConnectedPlayer(user: User, channel: MessageChannel, val u
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
@ -107,7 +107,7 @@ abstract class DiscordConnectedPlayer(user: User, channel: MessageChannel, val u
override def getUniqueId: UUID = this.uniqueId
override def getDisplayName: String = this.displayName
override def getDisplayName: String = this.dispName
/**
* For testing
@ -191,6 +191,9 @@ abstract class DiscordConnectedPlayer(user: User, channel: MessageChannel, val u
override def getValue: Double = getDefaultValue
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

View file

@ -23,7 +23,7 @@ object DiscordPlayerSender {
}).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
@ -32,8 +32,8 @@ abstract class DiscordPlayerSender(user: User, channel: MessageChannel, var play
super.sendMessage(message)
}
override def sendMessage(messages: Array[? <: String]): Unit = {
player.sendMessage(messages*)
super.sendMessage(messages)
override def sendMessage(messages: String*): Unit = {
player.sendMessage(messages: _*)
super.sendMessage(messages: _*)
}
}

View file

@ -1,5 +1,6 @@
package buttondevteam.discordplugin.mcchat.sender
import buttondevteam.discordplugin.DPUtils.MonoExtensions
import buttondevteam.discordplugin.DiscordPlugin
import discord4j.core.`object`.entity.User
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.{Bukkit, Server}
import reactor.core.publisher.Mono
import reactor.core.scala.publisher.SMono
import scala.jdk.OptionConverters.*
import scala.jdk.OptionConverters._
import java.util
class DiscordSender(user: User, channel: MessageChannel, pname: String) extends DiscordSenderBase(user, channel) with CommandSender {
private val perm = new PermissibleBase(this)
private val senderName: String = Option(pname)
.orElse(Option(user).flatMap(u => u.asMember(DiscordPlugin.mainServer.getId)
.onErrorResume(_ => Mono.empty).blockOptional().toScala
.orElse(Option(user).flatMap(u => u.asMember(DiscordPlugin.mainServer.getId).^^()
.onErrorResume(_ => SMono.empty).blockOption()
.map(u => u.getDisplayName)))
.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)
}
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, 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
import buttondevteam.core.component.channel.Channel
import buttondevteam.discordplugin.DiscordPlugin
import buttondevteam.discordplugin.mcchat.MCChatPrivate
import buttondevteam.lib.player.{ChromaGamerBase, UserClass}
@ -26,4 +27,12 @@ import discord4j.core.`object`.entity.User
* [[MCChatPrivate.privateMCChat]]
*/
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
import buttondevteam.discordplugin.DPUtils.FluxExtensions
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.util.DPState
import buttondevteam.discordplugin.{DPUtils, DiscordPlugin}
@ -96,7 +97,7 @@ import java.lang.reflect.Method
"Version command",
"Prints the plugin version"))
def version(sender: CommandSender): Unit = {
sender.sendMessage(VersionCommand.getVersion*)
sender.sendMessage(VersionCommand.getVersion: _*)
}
@Command2.Subcommand(helpText = Array(
@ -112,9 +113,9 @@ import java.lang.reflect.Method
sender.sendMessage("§bInvite link: " + invi)
return ()
}
DiscordPlugin.mainServer.getInvites.limitRequest(1)
DiscordPlugin.mainServer.getInvites.^^().take(1)
.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] = {

View file

@ -1,6 +1,7 @@
package buttondevteam.discordplugin.role
import buttondevteam.core.ComponentManager
import buttondevteam.discordplugin.DPUtils.{FluxExtensions, MonoExtensions}
import buttondevteam.discordplugin.{DPUtils, DiscordPlugin}
import buttondevteam.lib.architecture.{Component, ComponentMetadata}
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 org.bukkit.Bukkit
import reactor.core.publisher.Mono
import reactor.core.scala.publisher.SMono
import java.util.Collections
import scala.collection.mutable
import scala.collection.mutable.ListBuffer
import scala.jdk.CollectionConverters.SeqHasAsJava
/**
@ -24,19 +28,26 @@ import scala.jdk.CollectionConverters.SeqHasAsJava
val GameRoles = grm.GameRoles
val logChannel = grm.logChannel.get
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 {
case roleCreateEvent: RoleCreateEvent => Bukkit.getScheduler.runTaskLaterAsynchronously(DiscordPlugin.plugin, () => {
val role = roleCreateEvent.getRole
if (!notMainServer(role)) {
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 {
GameRoles.add(role.getName)
GameRoles.addOne(role.getName)
if (logChannel != null)
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
Mono.empty
SMono.empty
}
}).subscribe()
()
@ -46,8 +57,8 @@ import scala.jdk.CollectionConverters.SeqHasAsJava
val role = roleDeleteEvent.getRole.orElse(null)
if (role == null) return ()
if (notMainServer(role)) return ()
if (GameRoles.remove(role.getName) && logChannel != null)
logChannel.flatMap(_.createMessage("Removed " + role.getName + " as a game role.")).subscribe()
if (removeFromList(role.getName) && logChannel != null)
logChannel.flatMap(_.createMessage("Removed " + role.getName + " as a game role.").^^()).subscribe()
case roleUpdateEvent: RoleUpdateEvent =>
if (!roleUpdateEvent.getOld.isPresent) {
grm.logWarn("Old role not stored, cannot update game role!")
@ -58,22 +69,22 @@ import scala.jdk.CollectionConverters.SeqHasAsJava
val cr = roleUpdateEvent.getCurrent
grm.isGameRole(cr).flatMap(isGameRole => {
if (!isGameRole)
if (GameRoles.remove(or.getName) && logChannel != null)
logChannel.flatMap(_.createMessage("Removed " + or.getName + " as a game role because its color changed."))
if (removeFromList(or.getName) && logChannel != null)
logChannel.flatMap(_.createMessage("Removed " + or.getName + " as a game role because its color changed.").^^())
else
Mono.empty
SMono.empty
else if (GameRoles.contains(or.getName) && or.getName == cr.getName)
Mono.empty
SMono.empty
else {
val removed = GameRoles.remove(or.getName) //Regardless of whether it was a game role
GameRoles.add(cr.getName) //Add it because it has no color
val removed = removeFromList(or.getName) //Regardless of whether it was a game role
GameRoles.addOne(cr.getName) //Add it because it has no color
if (logChannel != null)
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
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
Mono.empty
SMono.empty
}
}).subscribe()
case _ =>
@ -82,12 +93,12 @@ import scala.jdk.CollectionConverters.SeqHasAsJava
}
@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)
override protected def enable(): Unit = {
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)
@ -101,15 +112,15 @@ import scala.jdk.CollectionConverters.SeqHasAsJava
* Defaults to the second to last in the upper row - #95a5a6.
*/
final private def roleColor = getConfig.getData("roleColor", Color.of(149, 165, 166),
rgb => Color.of(Integer.parseInt(rgb.asInstanceOf[String].substring(1), 16)),
color => String.format("#%08x", color.getRGB), true)
(rgb: Any) => Color.of(Integer.parseInt(rgb.asInstanceOf[String].substring(1), 16)),
(color: Color) => String.format("#%08x", color.getRGB), true)
private def isGameRole(r: Role): Mono[java.lang.Boolean] = {
if (r.getGuildId.asLong != DiscordPlugin.mainServer.getId.asLong) return Mono.just(false) //Only allow on the main server
private def isGameRole(r: Role): SMono[Boolean] = {
if (r.getGuildId.asLong != DiscordPlugin.mainServer.getId.asLong) return SMono.just(false) //Only allow on the main server
val rc = roleColor.get
if (r.getColor equals rc)
DiscordPlugin.dc.getSelf.flatMap(u => u.asMember(DiscordPlugin.mainServer.getId))
.flatMap(_.hasHigherRoles(Collections.singleton(r.getId))).defaultIfEmpty(false) //Below one of our roles
else Mono.just(false)
DiscordPlugin.dc.getSelf.^^().flatMap(u => u.asMember(DiscordPlugin.mainServer.getId).^^())
.flatMap(_.hasHigherRoles(Collections.singleton(r.getId)).^^()).cast[Boolean].defaultIfEmpty(false) //Below one of our roles
else SMono.just(false)
}
}

View file

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