Tailrec announcer method, fix some compile issues
This commit is contained in:
parent
d416eef144
commit
7296ebd2f8
18 changed files with 272 additions and 292 deletions
|
@ -13,7 +13,7 @@ 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 name: String = Option(pname)
|
||||
.orElse(Option(user).map(u => SMono(u.asMember(DiscordPlugin.mainServer.getId))
|
||||
.orElse(Option(user).flatMap(u => SMono(u.asMember(DiscordPlugin.mainServer.getId))
|
||||
.onErrorResume(_ => SMono.empty).blockOption()
|
||||
.map(u => u.getDisplayName)))
|
||||
.getOrElse("Discord user")
|
||||
|
|
|
@ -44,21 +44,23 @@ abstract class DiscordSenderBase protected(var user: User, var channel: MessageC
|
|||
return
|
||||
}
|
||||
val sendmsg = DPUtils.sanitizeString(message)
|
||||
this synchronized msgtosend += "\n" + sendmsg
|
||||
if (sendtask == null) sendtask = Bukkit.getScheduler.runTaskLaterAsynchronously(DiscordPlugin.plugin, () => {
|
||||
def foo(): Unit = {
|
||||
channel.createMessage((if (user != null) user.getMention + "\n"
|
||||
else "") + msgtosend.trim).subscribe
|
||||
sendtask = null
|
||||
msgtosend = ""
|
||||
}
|
||||
this synchronized {
|
||||
msgtosend += "\n" + sendmsg
|
||||
if (sendtask == null) sendtask = Bukkit.getScheduler.runTaskLaterAsynchronously(DiscordPlugin.plugin, () => {
|
||||
def foo(): Unit = {
|
||||
channel.createMessage((if (user != null) user.getMention + "\n"
|
||||
else "") + msgtosend.trim).subscribe
|
||||
sendtask = null
|
||||
msgtosend = ""
|
||||
}
|
||||
|
||||
foo()
|
||||
}, 4) // Waits a 0.2 second to gather all/most of the different messages
|
||||
foo()
|
||||
}, 4) // Waits a 0.2 second to gather all/most of the different messages
|
||||
}
|
||||
} catch {
|
||||
case e: Exception =>
|
||||
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: Array[String]): Unit = sendMessage(String.join("\n", messages: _*))
|
||||
}
|
|
@ -5,9 +5,10 @@ import buttondevteam.lib.TBMCCoreAPI
|
|||
import buttondevteam.lib.architecture.{Component, ComponentMetadata}
|
||||
import buttondevteam.lib.player.ChromaGamerBase
|
||||
import com.google.gson.JsonParser
|
||||
import discord4j.core.`object`.entity.Message
|
||||
import discord4j.core.`object`.entity.channel.MessageChannel
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.scala.publisher.SMono
|
||||
|
||||
import scala.annotation.tailrec
|
||||
|
||||
/**
|
||||
* Posts new posts from Reddit to the specified channel(s). It will pin the regular posts (not the mod posts).
|
||||
|
@ -39,23 +40,19 @@ import reactor.core.publisher.Flux
|
|||
override protected def enable(): Unit = {
|
||||
if (DPUtils.disableIfConfigError(this, channel, modChannel)) return
|
||||
AnnouncerModule.stop = false //If not the first time
|
||||
val kp = keepPinned.get
|
||||
if (kp eq 0) return
|
||||
val msgs: Flux[Message] = channel.get.flatMapMany(_.getPinnedMessages).takeLast(kp)
|
||||
val kp: Short = keepPinned.get
|
||||
if (kp <= 0) return
|
||||
val msgs = channel.get.flatMapMany(_.getPinnedMessages).takeLast(kp)
|
||||
msgs.subscribe(_.unpin)
|
||||
new Thread(() => this.AnnouncementGetterThreadMethod()).start()
|
||||
}
|
||||
|
||||
override protected def disable(): Unit = AnnouncerModule.stop = true
|
||||
|
||||
private def AnnouncementGetterThreadMethod(): Unit = while ( {
|
||||
!AnnouncerModule.stop
|
||||
}) {
|
||||
try {
|
||||
if (!isEnabled) { //noinspection BusyWait
|
||||
Thread.sleep(10000)
|
||||
continue //todo: continue is not supported
|
||||
}
|
||||
@tailrec
|
||||
private def AnnouncementGetterThreadMethod() {
|
||||
if (AnnouncerModule.stop) return
|
||||
if (isEnabled) try { //If not enabled, just wait
|
||||
val body = TBMCCoreAPI.DownloadString(subredditURL.get + "/new/.json?limit=10")
|
||||
val json = new JsonParser().parse(body).getAsJsonObject.get("data").getAsJsonObject.get("children").getAsJsonArray
|
||||
val msgsb = new StringBuilder
|
||||
|
@ -66,30 +63,32 @@ import reactor.core.publisher.Flux
|
|||
val data = item.get("data").getAsJsonObject
|
||||
var author = data.get("author").getAsString
|
||||
val distinguishedjson = data.get("distinguished")
|
||||
var distinguished = null
|
||||
if (distinguishedjson.isJsonNull) distinguished = null
|
||||
else distinguished = distinguishedjson.getAsString
|
||||
val distinguished = if (distinguishedjson.isJsonNull) null else distinguishedjson.getAsString
|
||||
val permalink = "https://www.reddit.com" + data.get("permalink").getAsString
|
||||
val date = data.get("created_utc").getAsLong
|
||||
if (date > lastSeenTime.get) lastSeenTime.set(date)
|
||||
else if (date > lastAnnouncementTime.get) { //noinspection ConstantConditions
|
||||
do {
|
||||
{
|
||||
val reddituserclass = ChromaGamerBase.getTypeForFolder("reddit")
|
||||
if (reddituserclass == null) break //todo: break is not supported
|
||||
val user = ChromaGamerBase.getUser(author, reddituserclass)
|
||||
val id = user.getConnectedID(classOf[DiscordPlayer])
|
||||
if (id != null) author = "<@" + id + ">"
|
||||
} while ( {
|
||||
false
|
||||
})
|
||||
if (reddituserclass != null) {
|
||||
val user = ChromaGamerBase.getUser(author, reddituserclass)
|
||||
val id = user.getConnectedID(classOf[DiscordPlayer])
|
||||
if (id != null) author = "<@" + id + ">"
|
||||
}
|
||||
}
|
||||
if (!author.startsWith("<")) author = "/u/" + author
|
||||
(if (distinguished != null && distinguished == "moderator") modmsgsb
|
||||
else msgsb).append("A new post was submitted to the subreddit by ").append(author).append("\n").append(permalink).append("\n")
|
||||
(if (distinguished != null && distinguished == "moderator") modmsgsb else msgsb)
|
||||
.append("A new post was submitted to the subreddit by ").append(author).append("\n")
|
||||
.append(permalink).append("\n")
|
||||
lastanntime = date
|
||||
}
|
||||
}
|
||||
if (msgsb.length > 0) channel.get.flatMap((ch: MessageChannel) => ch.createMessage(msgsb.toString)).flatMap(Message.pin).subscribe
|
||||
if (modmsgsb.length > 0) modChannel.get.flatMap((ch: MessageChannel) => ch.createMessage(modmsgsb.toString)).flatMap(Message.pin).subscribe
|
||||
|
||||
def sendMsg(ch: SMono[MessageChannel], msg: String) =
|
||||
ch.asJava().flatMap(c => c.createMessage(msg)).flatMap(_.pin).subscribe
|
||||
|
||||
if (msgsb.nonEmpty) sendMsg(channel.get(), msgsb.toString())
|
||||
if (modmsgsb.nonEmpty) sendMsg(modChannel.get(), modmsgsb.toString())
|
||||
if (lastAnnouncementTime.get ne lastanntime) lastAnnouncementTime.set(lastanntime) // If sending succeeded
|
||||
} catch {
|
||||
case e: Exception =>
|
||||
|
@ -100,5 +99,6 @@ import reactor.core.publisher.Flux
|
|||
case ex: InterruptedException =>
|
||||
Thread.currentThread.interrupt()
|
||||
}
|
||||
AnnouncementGetterThreadMethod()
|
||||
}
|
||||
}
|
|
@ -16,7 +16,7 @@ import lombok.RequiredArgsConstructor
|
|||
this.message.getChannel.flatMap((ch: MessageChannel) => ch.createMessage(this.message.getAuthor.map((u: User) => DPUtils.nickMention(u.getId) + ", ").orElse("") + msg)).subscribe
|
||||
}
|
||||
|
||||
override def sendMessage(message: Array[String]): Unit = sendMessage(String.join("\n", message))
|
||||
override def sendMessage(message: Array[String]): Unit = sendMessage(String.join("\n", message: _*))
|
||||
|
||||
override def getName = message.getAuthor.map(_.getUsername).orElse("Discord")
|
||||
override def getName: String = Option(message.getAuthor.orElse(null)).map(_.getUsername).getOrElse("Discord")
|
||||
}
|
|
@ -7,8 +7,9 @@ import com.google.common.collect.HashBiMap
|
|||
import org.bukkit.Bukkit
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
@CommandClass(helpText = Array(Array("Connect command", //
|
||||
"This command lets you connect your account with a Minecraft account. This allows using the private Minecraft chat and other things."))) object ConnectCommand {
|
||||
@CommandClass(helpText = Array("Connect command", //
|
||||
"This command lets you connect your account with a Minecraft account." +
|
||||
" This allows using the private Minecraft chat and other things.")) object ConnectCommand {
|
||||
/**
|
||||
* Key: Minecraft name<br>
|
||||
* Value: Discord ID
|
||||
|
|
|
@ -3,24 +3,27 @@ package buttondevteam.discordplugin.commands
|
|||
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 reactor.core.scala.publisher.SMono
|
||||
|
||||
@CommandClass(helpText = Array(Array("Switches debug mode.")))
|
||||
@CommandClass(helpText = Array("Switches debug mode."))
|
||||
class DebugCommand extends ICommand2DC {
|
||||
@Command2.Subcommand
|
||||
override def `def`(sender: Command2DCSender): Boolean = {
|
||||
sender.getMessage.getAuthorAsMember.switchIfEmpty(sender.getMessage.getAuthor.map //Support DMs
|
||||
((u: User) => u.asMember(DiscordPlugin.mainServer.getId)).orElse(Mono.empty)).flatMap((m: Member) => DiscordPlugin.plugin.modRole.get.map((mr) => m.getRoleIds.stream.anyMatch((r: Snowflake) => r == mr.getId)).switchIfEmpty(Mono.fromSupplier(() => DiscordPlugin.mainServer.getOwnerId.asLong eq m.getId.asLong)))
|
||||
.onErrorReturn(false) //Role not found
|
||||
.subscribe((success: Any) => {
|
||||
def foo(success: Any) = {
|
||||
if (success) sender.sendMessage("debug " + (if (CommonListeners.debug) "enabled"
|
||||
else "disabled"))
|
||||
else sender.sendMessage("you need to be a moderator to use this command.")
|
||||
}
|
||||
|
||||
foo(success)
|
||||
SMono(sender.getMessage.getAuthorAsMember)
|
||||
.switchIfEmpty(Option(sender.getMessage.getAuthor.orElse(null)) //Support DMs
|
||||
.map((u: User) => SMono(u.asMember(DiscordPlugin.mainServer.getId))).getOrElse(SMono.empty))
|
||||
.flatMap((m: Member) => DiscordPlugin.plugin.modRole.get
|
||||
.map(mr => m.getRoleIds.stream.anyMatch((r: Snowflake) => r == mr.getId))
|
||||
.switchIfEmpty(SMono.fromCallable(() => DiscordPlugin.mainServer.getOwnerId.asLong eq m.getId.asLong)))
|
||||
.onErrorResume(_ => SMono.just(false)) //Role not found
|
||||
.subscribe(success => {
|
||||
if (success) {
|
||||
CommonListeners.debug = !CommonListeners.debug;
|
||||
sender.sendMessage("debug " + (if (CommonListeners.debug) "enabled" else "disabled"))
|
||||
} else
|
||||
sender.sendMessage("you need to be a moderator to use this command.")
|
||||
})
|
||||
true
|
||||
}
|
||||
|
|
|
@ -2,8 +2,8 @@ package buttondevteam.discordplugin.commands
|
|||
|
||||
import buttondevteam.lib.chat.{Command2, CommandClass}
|
||||
|
||||
@CommandClass(helpText = Array(Array("Help command", //
|
||||
"Shows some info about a command or lists the available commands.")))
|
||||
@CommandClass(helpText = Array("Help command", //
|
||||
"Shows some info about a command or lists the available commands."))
|
||||
class HelpCommand extends ICommand2DC {
|
||||
@Command2.Subcommand
|
||||
def `def`(sender: Command2DCSender, @Command2.TextArg @Command2.OptionalArg args: String): Boolean = {
|
||||
|
|
|
@ -4,13 +4,12 @@ import buttondevteam.discordplugin.{DiscordPlayer, DiscordPlugin}
|
|||
import buttondevteam.lib.chat.{Command2, CommandClass}
|
||||
import buttondevteam.lib.player.ChromaGamerBase
|
||||
import buttondevteam.lib.player.ChromaGamerBase.InfoTarget
|
||||
import discord4j.core.`object`.entity.{Member, Message, User}
|
||||
import discord4j.core.`object`.entity.{Message, User}
|
||||
import reactor.core.scala.publisher.SFlux
|
||||
|
||||
import java.util
|
||||
|
||||
@CommandClass(helpText = Array(Array("User information", //
|
||||
@CommandClass(helpText = Array("User information", //
|
||||
"Shows some information about users, from Discord, from Minecraft or from Reddit if they have these accounts connected.",
|
||||
"If used without args, shows your info.")))
|
||||
"If used without args, shows your info."))
|
||||
class UserinfoCommand extends ICommand2DC {
|
||||
@Command2.Subcommand
|
||||
def `def`(sender: Command2DCSender, @Command2.OptionalArg @Command2.TextArg user: String): Boolean = {
|
||||
|
@ -25,16 +24,11 @@ class UserinfoCommand extends ICommand2DC {
|
|||
else if (user.contains("#")) {
|
||||
val targettag = user.split("#")
|
||||
val targets = getUsers(message, targettag(0))
|
||||
if (targets.size == 0) {
|
||||
if (targets.isEmpty) {
|
||||
channel.createMessage("The user cannot be found (by name): " + user).subscribe
|
||||
return true
|
||||
}
|
||||
for (ptarget <- targets) {
|
||||
if (ptarget.getDiscriminator.equalsIgnoreCase(targettag(1))) {
|
||||
target = ptarget
|
||||
break //todo: break is not supported
|
||||
}
|
||||
}
|
||||
targets.collectFirst(_.getDiscriminator.equalsIgnoreCase(targettag(1)))
|
||||
if (target == null) {
|
||||
channel.createMessage("The user cannot be found (by discriminator): " + user + "(Found " + targets.size + " users with the name.)").subscribe
|
||||
return true
|
||||
|
@ -42,7 +36,7 @@ class UserinfoCommand extends ICommand2DC {
|
|||
}
|
||||
else {
|
||||
val targets = getUsers(message, user)
|
||||
if (targets.size == 0) {
|
||||
if (targets.isEmpty) {
|
||||
channel.createMessage("The user cannot be found on Discord: " + user).subscribe
|
||||
return true
|
||||
}
|
||||
|
@ -50,7 +44,7 @@ class UserinfoCommand extends ICommand2DC {
|
|||
channel.createMessage("Multiple users found with that (nick)name. Please specify the whole tag, like ChromaBot#6338 or use a ping.").subscribe
|
||||
return true
|
||||
}
|
||||
target = targets.get(0)
|
||||
target = targets.head
|
||||
}
|
||||
}
|
||||
if (target == null) {
|
||||
|
@ -65,12 +59,11 @@ class UserinfoCommand extends ICommand2DC {
|
|||
}
|
||||
|
||||
private def getUsers(message: Message, args: String) = {
|
||||
var targets: util.List[User]
|
||||
val guild = message.getGuild.block
|
||||
if (guild == null) { //Private channel
|
||||
targets = DiscordPlugin.dc.getUsers.filter((u) => u.getUsername.equalsIgnoreCase(args)).collectList.block
|
||||
SFlux(DiscordPlugin.dc.getUsers).filter(u => u.getUsername.equalsIgnoreCase(args)).collectSeq().block()
|
||||
}
|
||||
else targets = guild.getMembers.filter((m: Member) => m.getUsername.equalsIgnoreCase(args)).map((m: Member) => m.asInstanceOf[User]).collectList.block
|
||||
targets
|
||||
else
|
||||
SFlux(guild.getMembers).filter(_.getUsername.equalsIgnoreCase(args)).map(_.asInstanceOf[User]).collectSeq().block()
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@ package buttondevteam.discordplugin.commands
|
|||
import buttondevteam.discordplugin.DiscordPlugin
|
||||
import buttondevteam.lib.chat.{Command2, CommandClass}
|
||||
|
||||
@CommandClass(helpText = Array(Array("Version", "Returns the plugin's version")))
|
||||
@CommandClass(helpText = Array("Version", "Returns the plugin's version"))
|
||||
object VersionCommand {
|
||||
def getVersion: Array[String] = {
|
||||
val desc = DiscordPlugin.plugin.getDescription
|
||||
|
@ -11,7 +11,7 @@ object VersionCommand {
|
|||
}
|
||||
}
|
||||
|
||||
@CommandClass(helpText = Array(Array("Version", "Returns the plugin's version")))
|
||||
@CommandClass(helpText = Array("Version", "Returns the plugin's version"))
|
||||
class VersionCommand extends ICommand2DC {
|
||||
@Command2.Subcommand override def `def`(sender: Command2DCSender): Boolean = {
|
||||
sender.sendMessage(VersionCommand.getVersion)
|
||||
|
|
|
@ -9,7 +9,7 @@ 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
|
||||
|
@ -20,29 +20,24 @@ import java.util.stream.Collectors
|
|||
object ExceptionListenerModule {
|
||||
private def SendException(e: Throwable, sourcemessage: String): Unit = {
|
||||
if (instance == null) return
|
||||
try getChannel.flatMap((channel: MessageChannel) => {
|
||||
def foo(channel: MessageChannel) = {
|
||||
var coderRole: Mono[Role] = channel match {
|
||||
case ch: GuildChannel => instance.pingRole(ch.getGuild).get
|
||||
case _ => Mono.empty
|
||||
}
|
||||
coderRole.map((role: Role) => if (TBMCCoreAPI.IsTestServer) new StringBuilder
|
||||
else new StringBuilder(role.getMention).append("\n")).defaultIfEmpty(new StringBuilder).flatMap((sb: StringBuilder) => {
|
||||
def foo(sb: StringBuilder) = {
|
||||
sb.append(sourcemessage).append("\n")
|
||||
sb.append("```").append("\n")
|
||||
var stackTrace = util.Arrays.stream(ExceptionUtils.getStackTrace(e).split("\\n")).filter((s: String) => !s.contains("\tat ") || s.contains("\tat buttondevteam.")).collect(Collectors.joining("\n"))
|
||||
if (sb.length + stackTrace.length >= 1980) stackTrace = stackTrace.substring(0, 1980 - sb.length)
|
||||
sb.append(stackTrace).append("\n")
|
||||
sb.append("```")
|
||||
channel.createMessage(sb.toString)
|
||||
}
|
||||
|
||||
foo(sb)
|
||||
})
|
||||
try getChannel.flatMap(channel => {
|
||||
val coderRole = channel match {
|
||||
case ch: GuildChannel => instance.pingRole(SMono(ch.getGuild)).get
|
||||
case _ => SMono.empty
|
||||
}
|
||||
|
||||
foo(channel)
|
||||
coderRole.map((role: Role) => if (TBMCCoreAPI.IsTestServer) new StringBuilder
|
||||
else new StringBuilder(role.getMention).append("\n"))
|
||||
.defaultIfEmpty(new StringBuilder).flatMap(sb => {
|
||||
sb.append(sourcemessage).append("\n")
|
||||
sb.append("```").append("\n")
|
||||
var stackTrace = util.Arrays.stream(ExceptionUtils.getStackTrace(e).split("\\n"))
|
||||
.filter(s => !s.contains("\tat ") || s.contains("\tat buttondevteam."))
|
||||
.collect(Collectors.joining("\n"))
|
||||
if (sb.length + stackTrace.length >= 1980) stackTrace = stackTrace.substring(0, 1980 - sb.length)
|
||||
sb.append(stackTrace).append("\n")
|
||||
sb.append("```")
|
||||
SMono(channel.createMessage(sb.toString))
|
||||
})
|
||||
}).subscribe
|
||||
catch {
|
||||
case ex: Exception =>
|
||||
|
@ -52,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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,13 +59,12 @@ class ExceptionListenerModule extends Component[DiscordPlugin] with Listener {
|
|||
|
||||
@EventHandler def onException(e: TBMCExceptionEvent): Unit = {
|
||||
if (DiscordPlugin.SafeMode || !ComponentManager.isEnabled(getClass)) return
|
||||
if (lastthrown.stream.anyMatch((ex: Throwable) => util.Arrays.equals(e.getException.getStackTrace, ex.getStackTrace) && (if (e.getException.getMessage == null) ex.getMessage == null
|
||||
else e.getException.getMessage == ex.getMessage)) // e.Exception.Message==ex.Message
|
||||
if (lastthrown.stream.anyMatch(ex => e.getException.getStackTrace.sameElements(ex.getStackTrace)
|
||||
&& (if (e.getException.getMessage == null) ex.getMessage == null else e.getException.getMessage == ex.getMessage))
|
||||
&& lastsourcemsg.contains(e.getSourceMessage)) {
|
||||
return
|
||||
}
|
||||
ExceptionListenerModule
|
||||
.SendException(e.getException, e.getSourceMessage)
|
||||
ExceptionListenerModule.SendException(e.getException, e.getSourceMessage)
|
||||
if (lastthrown.size >= 10) lastthrown.remove(0)
|
||||
if (lastsourcemsg.size >= 10) lastsourcemsg.remove(0)
|
||||
lastthrown.add(e.getException)
|
||||
|
@ -86,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
|
||||
|
|
|
@ -5,16 +5,15 @@ import buttondevteam.discordplugin.{DPUtils, DiscordPlugin}
|
|||
import buttondevteam.lib.TBMCCoreAPI
|
||||
import buttondevteam.lib.architecture.{Component, ConfigData}
|
||||
import com.google.common.collect.Lists
|
||||
import discord4j.common.util.Snowflake
|
||||
import discord4j.core.`object`.entity.channel.{GuildChannel, MessageChannel}
|
||||
import discord4j.core.`object`.entity.{Guild, Member, Message, Role}
|
||||
import discord4j.core.`object`.presence.{Presence, Status}
|
||||
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 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.{SFlux, SMono}
|
||||
|
||||
import java.util
|
||||
import java.util.Calendar
|
||||
|
@ -50,41 +49,47 @@ object FunModule {
|
|||
lastlist = 0
|
||||
}
|
||||
if (msglowercased == "/list" && Bukkit.getOnlinePlayers.size == lastlistp && {
|
||||
ListC += 1;
|
||||
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
|
||||
}
|
||||
lastlistp = Bukkit.getOnlinePlayers.size.toShort //Didn't handle
|
||||
if (!TBMCCoreAPI.IsTestServer && util.Arrays.stream(fm.serverReady).get.anyMatch(msglowercased.contains _)) {
|
||||
if (!TBMCCoreAPI.IsTestServer && fm.serverReady.get.exists(msglowercased.contains)) {
|
||||
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
|
||||
false
|
||||
}
|
||||
|
||||
private var lasttime = 0
|
||||
private var lasttime: Long = 0
|
||||
|
||||
def handleFullHouse(event: PresenceUpdateEvent): Unit = {
|
||||
val fm = ComponentManager.getIfEnabled(classOf[FunModule])
|
||||
if (fm == null) return
|
||||
if (Calendar.getInstance.get(Calendar.DAY_OF_MONTH) % 5 != 0) return
|
||||
if (!Option(event.getOld.orElse(null)).exists(_.getStatus == Status.OFFLINE)
|
||||
|| 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: MessageChannel) => fm.fullHouseDevRole(channel.asInstanceOf[GuildChannel].getGuild).get.filter((role: Role) => event.getOld.map((p: Presence) => p.getStatus == Status.OFFLINE).orElse(false)).filter((role: Role) => !(event.getCurrent.getStatus == Status.OFFLINE)).filterWhen((devrole: Role) => event.getMember.flatMap((m: Member) => m.getRoles.any((r: Role) => r.getId.asLong == devrole.getId.asLong))).filterWhen((devrole: Role) => event.getGuild.flatMapMany((g: Guild) => g.getMembers.filter((m: Member) => m.getRoleIds.stream.anyMatch((s: Snowflake) => s == devrole.getId))).flatMap(Member.getPresence).all((pr: Presence) => !(pr.getStatus == Status.OFFLINE))).filter((devrole: Role) => lasttime + 10 < TimeUnit.NANOSECONDS.toHours(System.nanoTime)).flatMap //This should stay so it checks this last
|
||||
((devrole: Role) => {
|
||||
def foo(devrole: Role) = {
|
||||
.flatMap(channel => fm.fullHouseDevRole(SMono(channel.asInstanceOf[GuildChannel].getGuild)).get
|
||||
.filterWhen(devrole => SMono(event.getMember)
|
||||
.flatMap(m => SFlux(m.getRoles).any(_.getId.asLong == devrole.getId.asLong)))
|
||||
.filterWhen(devrole => SMono(event.getGuild)
|
||||
.flatMapMany(g => SFlux(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((mcs: MessageCreateSpec) => mcs.setContent("Full house!").setEmbed((ecs: EmbedCreateSpec) => ecs.setImage("https://cdn.discordapp.com/attachments/249295547263877121/249687682618359808/poker-hand-full-house-aces-kings-playing-cards-15553791.png")))
|
||||
}
|
||||
|
||||
foo(devrole)
|
||||
})).subscribe
|
||||
SMono(channel.createMessage((mcs: MessageCreateSpec) => mcs.setContent("Full house!")
|
||||
.setEmbed((ecs: EmbedCreateSpec) => ecs.setImage("https://cdn.discordapp.com/attachments/249295547263877121/249687682618359808/poker-hand-full-house-aces-kings-playing-cards-15553791.png"))))
|
||||
})).subscribe
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,14 +114,18 @@ class FunModule extends Component[DiscordPlugin] with Listener {
|
|||
|
||||
override protected def enable(): Unit = registerListener(this)
|
||||
|
||||
override protected def disable(): Unit = FunModule.lastlist = FunModule.lastlistp = FunModule.ListC = 0
|
||||
override protected def disable(): Unit = {
|
||||
FunModule.lastlist = 0
|
||||
FunModule.lastlistp = 0
|
||||
FunModule.ListC = 0
|
||||
}
|
||||
|
||||
@EventHandler def onPlayerJoin(event: PlayerJoinEvent): Unit = FunModule.ListC = 0
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
|
|
@ -12,7 +12,7 @@ import discord4j.core.event.EventDispatcher
|
|||
import discord4j.core.event.domain.PresenceUpdateEvent
|
||||
import discord4j.core.event.domain.message.MessageCreateEvent
|
||||
import discord4j.core.event.domain.role.{RoleCreateEvent, RoleDeleteEvent, RoleUpdateEvent}
|
||||
import reactor.core.scala.publisher.SMono
|
||||
import reactor.core.scala.publisher.{SFlux, SMono}
|
||||
|
||||
object CommonListeners {
|
||||
val timings = new Timings
|
||||
|
@ -56,25 +56,19 @@ object CommonListeners {
|
|||
}
|
||||
|
||||
foo(event)
|
||||
}).onErrorContinue((err: Throwable, obj: Any) => TBMCCoreAPI.SendException("An error occured while handling a message!", err, DiscordPlugin.plugin)).subscribe
|
||||
}).onErrorContinue((err: Throwable, _) => TBMCCoreAPI.SendException("An error occured while handling a message!", err, DiscordPlugin.plugin)).subscribe
|
||||
dispatcher.on(classOf[PresenceUpdateEvent]).subscribe((event: PresenceUpdateEvent) => {
|
||||
def foo(event: PresenceUpdateEvent) = {
|
||||
if (DiscordPlugin.SafeMode) return
|
||||
if (!DiscordPlugin.SafeMode)
|
||||
FunModule.handleFullHouse(event)
|
||||
}
|
||||
|
||||
foo(event)
|
||||
})
|
||||
dispatcher.on(classOf[RoleCreateEvent]).subscribe(GameRoleModule.handleRoleEvent _)
|
||||
dispatcher.on(classOf[RoleDeleteEvent]).subscribe(GameRoleModule.handleRoleEvent _)
|
||||
dispatcher.on(classOf[RoleUpdateEvent]).subscribe(GameRoleModule.handleRoleEvent _)
|
||||
SFlux(dispatcher.on(classOf[RoleCreateEvent])).subscribe(GameRoleModule.handleRoleEvent _)
|
||||
SFlux(dispatcher.on(classOf[RoleDeleteEvent])).subscribe(GameRoleModule.handleRoleEvent _)
|
||||
SFlux(dispatcher.on(classOf[RoleUpdateEvent])).subscribe(GameRoleModule.handleRoleEvent _)
|
||||
}
|
||||
|
||||
private var debug = false
|
||||
var debug = false
|
||||
|
||||
def debug(debug: String): Unit = if (CommonListeners.debug) { //Debug
|
||||
DPUtils.getLogger.info(debug)
|
||||
}
|
||||
|
||||
def debug(): Unit = debug = !debug
|
||||
}
|
|
@ -21,7 +21,7 @@ import java.util.{Objects, Optional}
|
|||
import javax.annotation.Nullable
|
||||
|
||||
@SuppressWarnings(Array("SimplifyOptionalCallChains")) //Java 11
|
||||
@CommandClass(helpText = Array(Array("Channel connect", //
|
||||
@CommandClass(helpText = Array("Channel connect", //
|
||||
"This command allows you to connect a Minecraft channel to a Discord channel (just like how the global chat is connected to #minecraft-chat).",
|
||||
"You need to have access to the MC channel and have manage permissions on the Discord channel.",
|
||||
"You also need to have your Minecraft account connected. In #bot use /connect <mcname>.",
|
||||
|
@ -30,7 +30,7 @@ import javax.annotation.Nullable
|
|||
"To remove a connection use @ChromaBot channelcon remove in the channel.",
|
||||
"Mentioning the bot is needed in this case because the / prefix only works in #bot.",
|
||||
"Invite link: <Unknown>" //
|
||||
)))
|
||||
))
|
||||
class ChannelconCommand(private val module: MinecraftChatModule) extends ICommand2DC {
|
||||
@Command2.Subcommand def remove(sender: Command2DCSender): Boolean = {
|
||||
val message = sender.getMessage
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
package buttondevteam.discordplugin.mcchat
|
||||
|
||||
import buttondevteam.discordplugin.{DPUtils, DiscordPlayer, DiscordPlugin}
|
||||
import buttondevteam.discordplugin.commands.{Command2DCSender, ICommand2DC}
|
||||
import buttondevteam.discordplugin.{DPUtils, DiscordPlayer, DiscordPlugin}
|
||||
import buttondevteam.lib.chat.{Command2, CommandClass}
|
||||
import buttondevteam.lib.player.ChromaGamerBase
|
||||
import discord4j.core.`object`.entity.channel.PrivateChannel
|
||||
|
||||
@CommandClass(helpText = Array(Array(
|
||||
@CommandClass(helpText = Array(
|
||||
"MC Chat",
|
||||
"This command enables or disables the Minecraft chat in private messages.", //
|
||||
"It can be useful if you don't want your messages to be visible, for example when talking in a private channel.",
|
||||
"You can also run all of the ingame commands you have access to using this command, if you have your accounts connected." //
|
||||
)))
|
||||
))
|
||||
class MCChatCommand(private val module: MinecraftChatModule) extends ICommand2DC {
|
||||
@Command2.Subcommand override def `def`(sender: Command2DCSender): Boolean = {
|
||||
if (!(module.allowPrivateChat.get)) {
|
||||
|
|
|
@ -8,15 +8,14 @@ import discord4j.core.`object`.entity.User
|
|||
import discord4j.core.`object`.entity.channel.MessageChannel
|
||||
import lombok.NonNull
|
||||
|
||||
import java.util
|
||||
import java.util.Collections
|
||||
import javax.annotation.Nullable
|
||||
import scala.collection.mutable.ListBuffer
|
||||
|
||||
object MCChatCustom {
|
||||
/**
|
||||
* Used for town or nation chats or anything else
|
||||
*/
|
||||
private[mcchat] val lastmsgCustom = new util.ArrayList[MCChatCustom.CustomLMD]
|
||||
private[mcchat] val lastmsgCustom = new ListBuffer[MCChatCustom.CustomLMD]
|
||||
|
||||
def addCustomChat(channel: MessageChannel, groupid: String, mcchannel: Channel, user: User, dcp: DiscordConnectedPlayer, toggles: Int, brtoggles: Set[TBMCSystemChatEvent.BroadcastTarget]): Boolean = {
|
||||
lastmsgCustom synchronized {
|
||||
|
@ -29,34 +28,32 @@ object MCChatCustom {
|
|||
gid = groupid
|
||||
}
|
||||
val lmd = new MCChatCustom.CustomLMD(channel, user, gid, mcchannel, dcp, toggles, brtoggles)
|
||||
lastmsgCustom.add(lmd)
|
||||
lastmsgCustom += lmd
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
def hasCustomChat(channel: Snowflake): Boolean =
|
||||
lastmsgCustom.stream.anyMatch((lmd: MCChatCustom.CustomLMD) => lmd.channel.getId.asLong == channel.asLong)
|
||||
lastmsgCustom.exists(_.channel.getId.asLong == channel.asLong)
|
||||
|
||||
@Nullable def getCustomChat(channel: Snowflake): CustomLMD =
|
||||
lastmsgCustom.stream.filter((lmd: MCChatCustom.CustomLMD) => lmd.channel.getId.asLong == channel.asLong).findAny.orElse(null)
|
||||
lastmsgCustom.find(_.channel.getId.asLong == channel.asLong).orNull
|
||||
|
||||
def removeCustomChat(channel: Snowflake): Boolean = {
|
||||
lastmsgCustom synchronized MCChatUtils.lastmsgfromd.remove(channel.asLong)
|
||||
lastmsgCustom.removeIf((lmd: MCChatCustom.CustomLMD) => {
|
||||
def foo(lmd: MCChatCustom.CustomLMD): Boolean = {
|
||||
if (lmd.channel.getId.asLong != channel.asLong) return false
|
||||
def removeCustomChat(channel: Snowflake): Unit = {
|
||||
lastmsgCustom synchronized {
|
||||
MCChatUtils.lastmsgfromd.remove(channel.asLong)
|
||||
lastmsgCustom.filterInPlace(lmd => {
|
||||
if (lmd.channel.getId.asLong != channel.asLong) return true
|
||||
lmd.mcchannel match {
|
||||
case room: ChatRoom => room.leaveRoom(lmd.dcp)
|
||||
case _ =>
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
foo(lmd)
|
||||
})
|
||||
false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
def getCustomChats: util.List[CustomLMD] = Collections.unmodifiableList(lastmsgCustom)
|
||||
def getCustomChats: List[CustomLMD] = lastmsgCustom.toList
|
||||
|
||||
class CustomLMD private[mcchat](@NonNull channel: MessageChannel, @NonNull user: User, val groupID: String,
|
||||
@NonNull mcchannel: Channel, val dcp: DiscordConnectedPlayer, var toggles: Int,
|
||||
|
|
|
@ -28,6 +28,7 @@ import java.util.Optional
|
|||
import java.util.concurrent.{LinkedBlockingQueue, TimeoutException}
|
||||
import java.util.function.{Consumer, Function, Predicate}
|
||||
import java.util.stream.Collectors
|
||||
import scala.jdk.OptionConverters.RichOptional
|
||||
|
||||
object MCChatListener {
|
||||
|
||||
|
@ -111,21 +112,21 @@ class MCChatListener(val module: MinecraftChatModule) extends Listener {
|
|||
foo(ecs)
|
||||
}
|
||||
val nanoTime: Long = System.nanoTime
|
||||
val doit: MCChatListener.InterruptibleConsumer[MCChatUtils.LastMsgData] = (lastmsgdata: MCChatUtils.LastMsgData) => {
|
||||
def foo(lastmsgdata: MCChatUtils.LastMsgData): Unit = {
|
||||
if (lastmsgdata.message == null || !(authorPlayer == lastmsgdata.message.getEmbeds.get(0).getAuthor.map(_.getName).orElse(null)) || lastmsgdata.time / 1000000000f < nanoTime / 1000000000f - 120 || !(lastmsgdata.mcchannel.ID == e.getChannel.ID) || lastmsgdata.content.length + e.getMessage.length + 1 > 2048) {
|
||||
lastmsgdata.message = lastmsgdata.channel.createEmbed(embed).block
|
||||
lastmsgdata.time = nanoTime
|
||||
lastmsgdata.mcchannel = e.getChannel
|
||||
lastmsgdata.content = e.getMessage
|
||||
}
|
||||
else {
|
||||
lastmsgdata.content = lastmsgdata.content + "\n" + e.getMessage // The message object doesn't get updated
|
||||
lastmsgdata.message.edit((mes: MessageEditSpec) => mes.setEmbed(embed.andThen((ecs: EmbedCreateSpec) => ecs.setDescription(lastmsgdata.content)))).block
|
||||
}
|
||||
val doit = (lastmsgdata: MCChatUtils.LastMsgData) => {
|
||||
if (lastmsgdata.message == null
|
||||
|| authorPlayer != lastmsgdata.message.getEmbeds.get(0).getAuthor.toScala.map(_.getName).orNull
|
||||
|| lastmsgdata.time / 1000000000f < nanoTime / 1000000000f - 120
|
||||
|| !(lastmsgdata.mcchannel.ID == e.getChannel.ID)
|
||||
|| lastmsgdata.content.length + e.getMessage.length + 1 > 2048) {
|
||||
lastmsgdata.message = lastmsgdata.channel.createEmbed(embed).block
|
||||
lastmsgdata.time = nanoTime
|
||||
lastmsgdata.mcchannel = e.getChannel
|
||||
lastmsgdata.content = e.getMessage
|
||||
}
|
||||
else {
|
||||
lastmsgdata.content = lastmsgdata.content + "\n" + e.getMessage // The message object doesn't get updated
|
||||
lastmsgdata.message.edit((mes: MessageEditSpec) => mes.setEmbed(embed.andThen((ecs: EmbedCreateSpec) => ecs.setDescription(lastmsgdata.content)))).block
|
||||
}
|
||||
|
||||
foo(lastmsgdata)
|
||||
}
|
||||
// Checks if the given channel is different than where the message was sent from
|
||||
// Or if it was from MC
|
||||
|
@ -133,31 +134,29 @@ class MCChatListener(val module: MinecraftChatModule) extends Listener {
|
|||
if (e.getChannel.isGlobal && (e.isFromCommand || isdifferentchannel.test(module.chatChannel.get))) {
|
||||
if (MCChatUtils.lastmsgdata == null)
|
||||
MCChatUtils.lastmsgdata = new MCChatUtils.LastMsgData(module.chatChannelMono.block, null)
|
||||
doit.accept(MCChatUtils.lastmsgdata)
|
||||
doit(MCChatUtils.lastmsgdata)
|
||||
}
|
||||
|
||||
for (data <- MCChatPrivate.lastmsgPerUser) {
|
||||
if ((e.isFromCommand || isdifferentchannel.test(data.channel.getId)) && e.shouldSendTo(MCChatUtils.getSender(data.channel.getId, data.user))) {
|
||||
doit.accept(data)
|
||||
doit(data)
|
||||
}
|
||||
}
|
||||
MCChatCustom.lastmsgCustom synchronized
|
||||
val iterator = MCChatCustom.lastmsgCustom.iterator
|
||||
while ( {
|
||||
iterator.hasNext
|
||||
}) {
|
||||
val lmd = iterator.next
|
||||
if ((e.isFromCommand || isdifferentchannel.test(lmd.channel.getId)) //Test if msg is from Discord
|
||||
&& e.getChannel.ID == lmd.mcchannel.ID //If it's from a command, the command msg has been deleted, so we need to send it
|
||||
&& e.getGroupID == lmd.groupID) { //Check if this is the group we want to test - #58
|
||||
if (e.shouldSendTo(lmd.dcp)) { //Check original user's permissions
|
||||
doit.accept(lmd)
|
||||
MCChatCustom.lastmsgCustom synchronized {
|
||||
MCChatCustom.lastmsgCustom.filterInPlace(lmd => {
|
||||
if ((e.isFromCommand || isdifferentchannel.test(lmd.channel.getId)) //Test if msg is from Discord
|
||||
&& e.getChannel.ID == lmd.mcchannel.ID //If it's from a command, the command msg has been deleted, so we need to send it
|
||||
&& e.getGroupID == lmd.groupID) { //Check if this is the group we want to test - #58
|
||||
if (e.shouldSendTo(lmd.dcp)) { //Check original user's permissions
|
||||
doit(lmd)
|
||||
}
|
||||
else {
|
||||
lmd.channel.createMessage("The user no longer has permission to view the channel, connection removed.").subscribe
|
||||
return false //If the user no longer has permission, remove the connection
|
||||
}
|
||||
}
|
||||
else {
|
||||
iterator.remove() //If the user no longer has permission, remove the connection
|
||||
lmd.channel.createMessage("The user no longer has permission to view the channel, connection removed.").subscribe
|
||||
}
|
||||
}
|
||||
true
|
||||
})
|
||||
}
|
||||
} catch {
|
||||
case ex: InterruptedException =>
|
||||
|
|
|
@ -19,17 +19,20 @@ import org.bukkit.event.Event
|
|||
import org.bukkit.event.player.{AsyncPlayerPreLoginEvent, PlayerJoinEvent, PlayerLoginEvent, PlayerQuitEvent}
|
||||
import org.bukkit.plugin.AuthorNagException
|
||||
import org.reactivestreams.Publisher
|
||||
import reactor.core.publisher.Mono
|
||||
import reactor.core.scala.publisher.SMono
|
||||
|
||||
import java.net.InetAddress
|
||||
import java.util
|
||||
import java.util._
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import java.util.function.Supplier
|
||||
import java.util.logging.Level
|
||||
import java.util.stream.{Collectors, Stream}
|
||||
import java.util.stream.Collectors
|
||||
import javax.annotation.Nullable
|
||||
import scala.collection.concurrent
|
||||
import scala.collection.convert.ImplicitConversions.`map AsJavaMap`
|
||||
import scala.collection.mutable.ListBuffer
|
||||
import scala.jdk.CollectionConverters.CollectionHasAsScala
|
||||
import scala.jdk.javaapi.CollectionConverters.asScala
|
||||
|
||||
object MCChatUtils {
|
||||
|
@ -43,13 +46,13 @@ object MCChatUtils {
|
|||
@Nullable private[mcchat] var lastmsgdata: MCChatUtils.LastMsgData = null
|
||||
private[mcchat] val lastmsgfromd = new LongObjectHashMap[Message] // Last message sent by a Discord user, used for clearing checkmarks
|
||||
private var module: MinecraftChatModule = null
|
||||
private val staticExcludedPlugins = new util.HashMap[Class[_ <: Event], util.HashSet[String]]
|
||||
private val staticExcludedPlugins = Map[Class[_ <: Event], util.HashSet[String]]()
|
||||
|
||||
def updatePlayerList(): Unit = {
|
||||
val mod = getModule
|
||||
if (mod == null || !mod.showPlayerListOnDC.get) return
|
||||
if (lastmsgdata != null) updatePL(lastmsgdata)
|
||||
MCChatCustom.lastmsgCustom.forEach(MCChatUtils.updatePL)
|
||||
MCChatCustom.lastmsgCustom.foreach(MCChatUtils.updatePL)
|
||||
}
|
||||
|
||||
private def notEnabled = (module == null || !module.disabling) && getModule == null //Allow using things while disabling the module
|
||||
|
@ -85,7 +88,8 @@ object MCChatUtils {
|
|||
.filter(_ => C.incrementAndGet > 0) //Always true
|
||||
.map((p) => DPUtils.sanitizeString(p.getDisplayName)).collect(Collectors.joining(", "))
|
||||
s(0) = C + " player" + (if (C.get != 1) "s" else "") + " online"
|
||||
lmd.channel.asInstanceOf[TextChannel].edit((tce: TextChannelEditSpec) => tce.setTopic(String.join("\n----\n", s)).setReason("Player list update")).subscribe //Don't wait
|
||||
lmd.channel.asInstanceOf[TextChannel].edit((tce: TextChannelEditSpec) =>
|
||||
tce.setTopic(String.join("\n----\n", s: _*)).setReason("Player list update")).subscribe //Don't wait
|
||||
}
|
||||
|
||||
private[mcchat] def checkEssentials(p: Player): Boolean = {
|
||||
|
@ -94,12 +98,12 @@ object MCChatUtils {
|
|||
!ess.getUser(p).isHidden
|
||||
}
|
||||
|
||||
def addSender[T <: DiscordSenderBase](senders: ConcurrentHashMap[String, ConcurrentHashMap[Snowflake, T]], user: User, sender: T): T =
|
||||
def addSender[T <: DiscordSenderBase](senders: concurrent.Map[String, ConcurrentHashMap[Snowflake, T]], user: User, sender: T): T =
|
||||
addSender(senders, user.getId.asString, sender)
|
||||
|
||||
def addSender[T <: DiscordSenderBase](senders: ConcurrentHashMap[String, ConcurrentHashMap[Snowflake, T]], did: String, sender: T): T = {
|
||||
var map = senders.get(did)
|
||||
if (map == null) map = new ConcurrentHashMap[Snowflake, T]
|
||||
def addSender[T <: DiscordSenderBase](senders: concurrent.Map[String, ConcurrentHashMap[Snowflake, T]], did: String, sender: T): T = {
|
||||
val origMap = senders.get(did)
|
||||
val map = if (origMap.isEmpty) new ConcurrentHashMap[Snowflake, T] else origMap.get
|
||||
map.put(sender.getChannel.getId, sender)
|
||||
senders.put(did, map)
|
||||
sender
|
||||
|
@ -117,15 +121,12 @@ object MCChatUtils {
|
|||
else null.asInstanceOf
|
||||
}
|
||||
|
||||
def forPublicPrivateChat(action: Mono[MessageChannel] => Mono[_]): Mono[_] = {
|
||||
if (notEnabled) return Mono.empty
|
||||
val list = new util.ArrayList[Mono[_]]
|
||||
list.add(action.apply(module.chatChannelMono))
|
||||
for (data <- MCChatPrivate.lastmsgPerUser) {
|
||||
list.add(action.apply(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))
|
||||
// lastmsgCustom.forEach(cc -> action.accept(cc.channel)); - Only send relevant messages to custom chat
|
||||
Mono.whenDelayError(list)
|
||||
SMono.whenDelayError(list)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -135,14 +136,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
|
||||
val list = new util.ArrayList[Publisher[_]]
|
||||
if (!GeneralEventBroadcasterModule.isHooked || !hookmsg) list.add(forPublicPrivateChat(action))
|
||||
val customLMDFunction = (cc: MCChatCustom.CustomLMD) => action.apply(Mono.just(cc.channel))
|
||||
if (toggle == null) MCChatCustom.lastmsgCustom.stream.map(customLMDFunction).forEach(list.add(_))
|
||||
else MCChatCustom.lastmsgCustom.stream.filter((cc) => (cc.toggles & toggle.flag) ne 0).map(customLMDFunction).forEach(list.add(_))
|
||||
Mono.whenDelayError(list)
|
||||
def forCustomAndAllMCChat(action: SMono[MessageChannel] => SMono[_], @Nullable toggle: ChannelconBroadcast, hookmsg: Boolean): SMono[_] = {
|
||||
if (notEnabled) return SMono.empty
|
||||
val list = new ListBuffer[Publisher[_]]
|
||||
if (!GeneralEventBroadcasterModule.isHooked || !hookmsg) list.append(forPublicPrivateChat(action))
|
||||
val customLMDFunction = (cc: MCChatCustom.CustomLMD) => action(SMono.just(cc.channel))
|
||||
if (toggle == null) MCChatCustom.lastmsgCustom.map(customLMDFunction).foreach(list.append(_))
|
||||
else MCChatCustom.lastmsgCustom.filter((cc) => (cc.toggles & (1 << toggle.id)) ne 0).map(customLMDFunction).foreach(list.append(_))
|
||||
SMono.whenDelayError(list)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -152,18 +153,15 @@ object MCChatUtils {
|
|||
* @param sender The sender 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 sender: CommandSender, @Nullable toggle: ChannelconBroadcast): Mono[_] = {
|
||||
if (notEnabled) return Mono.empty
|
||||
val st = MCChatCustom.lastmsgCustom.stream.filter((clmd) => {
|
||||
def foo(clmd: CustomLMD): Boolean = { //new TBMCChannelConnectFakeEvent(sender, clmd.mcchannel).shouldSendTo(clmd.dcp) - Thought it was this simple hehe - Wait, it *should* be this simple
|
||||
if (toggle != null && ((clmd.toggles & (1 << toggle.id)) eq 0)) return false //If null then allow
|
||||
if (sender == null) return true
|
||||
clmd.groupID.equals(clmd.mcchannel.getGroupID(sender))
|
||||
}
|
||||
|
||||
foo(clmd)
|
||||
}).map((cc) => action.apply(Mono.just(cc.channel))) //TODO: Send error messages on channel connect
|
||||
Mono.whenDelayError(st.iterator) //Can't convert as an iterator or inside the stream, but I can convert it as a stream
|
||||
def forAllowedCustomMCChat(action: SMono[MessageChannel] => SMono[_], @Nullable sender: CommandSender, @Nullable toggle: ChannelconBroadcast): SMono[_] = {
|
||||
if (notEnabled) return SMono.empty
|
||||
val st = MCChatCustom.lastmsgCustom.filter(clmd => { //new TBMCChannelConnectFakeEvent(sender, clmd.mcchannel).shouldSendTo(clmd.dcp) - Thought it was this simple hehe - Wait, it *should* be this simple
|
||||
if (toggle != null && ((clmd.toggles & (1 << toggle.id)) eq 0)) false //If null then allow
|
||||
else if (sender == null) true
|
||||
else clmd.groupID.equals(clmd.mcchannel.getGroupID(sender))
|
||||
}).map(cc => action.apply(SMono.just(cc.channel))) //TODO: Send error messages on channel connect
|
||||
//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
|
||||
SMono.whenDelayError(st)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -174,47 +172,45 @@ 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 sender: CommandSender, @Nullable toggle: ChannelconBroadcast, hookmsg: Boolean): Mono[_] = {
|
||||
if (notEnabled) return Mono.empty
|
||||
def forAllowedCustomAndAllMCChat(action: SMono[MessageChannel] => SMono[_], @Nullable sender: CommandSender, @Nullable toggle: ChannelconBroadcast, hookmsg: Boolean): SMono[_] = {
|
||||
if (notEnabled) return SMono.empty
|
||||
val cc = forAllowedCustomMCChat(action, sender, toggle)
|
||||
if (!GeneralEventBroadcasterModule.isHooked || !hookmsg) return Mono.whenDelayError(forPublicPrivateChat(action), cc)
|
||||
Mono.whenDelayError(cc)
|
||||
if (!GeneralEventBroadcasterModule.isHooked || !hookmsg) return SMono.whenDelayError(Array(forPublicPrivateChat(action), cc))
|
||||
SMono.whenDelayError(Array(cc))
|
||||
}
|
||||
|
||||
def send(message: String): Mono[MessageChannel] => Mono[_] = (ch: Mono[MessageChannel]) => ch.flatMap((mc: MessageChannel) => {
|
||||
def foo(mc: MessageChannel) = {
|
||||
resetLastMessage(mc)
|
||||
mc.createMessage(DPUtils.sanitizeString(message))
|
||||
}
|
||||
|
||||
foo(mc)
|
||||
def send(message: String): SMono[MessageChannel] => SMono[_] = _.flatMap((mc: MessageChannel) => {
|
||||
resetLastMessage(mc)
|
||||
SMono(mc.createMessage(DPUtils.sanitizeString(message)))
|
||||
})
|
||||
|
||||
def forAllowedMCChat(action: Mono[MessageChannel] => Mono[_], event: TBMCSystemChatEvent): Mono[_] = {
|
||||
if (notEnabled) return Mono.empty
|
||||
val list = new util.ArrayList[Mono[_]]
|
||||
if (event.getChannel.isGlobal) list.add(action.apply(module.chatChannelMono))
|
||||
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.add(action.apply(Mono.just(data.channel))) //TODO: Only store ID?}
|
||||
MCChatCustom.lastmsgCustom.stream.filter((clmd) => {
|
||||
def foo(clmd: CustomLMD): Boolean = {
|
||||
clmd.brtoggles.contains(event.getTarget) && event.shouldSendTo(clmd.dcp)
|
||||
}
|
||||
|
||||
foo(clmd)
|
||||
}).map((clmd) => action.apply(Mono.just(clmd.channel))).forEach(list.add(_))
|
||||
Mono.whenDelayError(list)
|
||||
if (event.shouldSendTo(getSender(data.channel.getId, 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))
|
||||
.map(clmd => action(SMono.just(clmd.channel))).forEach(elem => {
|
||||
list.append(elem)
|
||||
()
|
||||
})
|
||||
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) = { //noinspection OptionalGetWithoutIsPresent
|
||||
Stream.of[Supplier[Optional[DiscordSenderBase]]]( // https://stackoverflow.com/a/28833677/2703239
|
||||
() => Optional.ofNullable(getSender(OnlineSenders, channel, author)), // Find first non-null
|
||||
() => Optional.ofNullable(getSender(ConnectedSenders, channel, author)), // This doesn't support the public chat, but it'll always return null for it
|
||||
() => Optional.ofNullable(getSender(UnconnectedSenders, channel, author)), //
|
||||
() => Optional.of(addSender(UnconnectedSenders, author, new DiscordSender(author, DiscordPlugin.dc.getChannelById(channel).block.asInstanceOf[MessageChannel])))).map(_.get).filter(_.isPresent).map(_.get).findFirst.get
|
||||
private[mcchat] def getSender(channel: Snowflake, author: User): DiscordSenderBase = { //noinspection OptionalGetWithoutIsPresent
|
||||
List[() => DiscordSenderBase]( // https://stackoverflow.com/a/28833677/2703239
|
||||
() => getSender[DiscordSenderBase](OnlineSenders, channel, author), // Find first non-null
|
||||
() => getSender[DiscordSenderBase](ConnectedSenders, channel, author), // This doesn't support the public chat, but it'll always return null for it
|
||||
() => getSender[DiscordSenderBase](UnconnectedSenders, channel, author), //
|
||||
() => addSender[DiscordSenderBase](UnconnectedSenders, author,
|
||||
new DiscordSender(author, SMono(DiscordPlugin.dc.getChannelById(channel)).block().asInstanceOf[MessageChannel])))
|
||||
.map(_.apply()).find(sender => sender != null).get
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -226,7 +222,7 @@ object MCChatUtils {
|
|||
def resetLastMessage(channel: Channel): Unit = {
|
||||
if (notEnabled) return
|
||||
if (channel.getId.asLong == module.chatChannel.get.asLong) {
|
||||
if (lastmsgdata == null) lastmsgdata = new MCChatUtils.LastMsgData(module.chatChannelMono.block, null)
|
||||
if (lastmsgdata == null) lastmsgdata = new MCChatUtils.LastMsgData(module.chatChannelMono.block(), null)
|
||||
else lastmsgdata.message = null
|
||||
return
|
||||
} // Don't set the whole object to null, the player and channel information should be preserved
|
||||
|
@ -241,25 +237,23 @@ object MCChatUtils {
|
|||
}
|
||||
|
||||
def addStaticExcludedPlugin(event: Class[_ <: Event], plugin: String): util.HashSet[String] =
|
||||
staticExcludedPlugins.compute(event, (e: Class[_ <: Event], hs: util.HashSet[String]) =>
|
||||
staticExcludedPlugins.compute(event, (_, hs: util.HashSet[String]) =>
|
||||
if (hs == null) Sets.newHashSet(plugin) else if (hs.add(plugin)) hs else hs)
|
||||
|
||||
def callEventExcludingSome(event: Event): Unit = {
|
||||
if (notEnabled) return
|
||||
val second = staticExcludedPlugins.get(event.getClass)
|
||||
val first = module.excludedPlugins.get
|
||||
val both = if (second == null) first
|
||||
val both = if (second.isEmpty) first
|
||||
else util.Arrays.copyOf(first, first.length + second.size)
|
||||
var i = first.length
|
||||
if (second != null) {
|
||||
for (plugin <- second) {
|
||||
both({
|
||||
i += 1;
|
||||
i - 1
|
||||
}) = plugin
|
||||
if (second.nonEmpty) {
|
||||
for (plugin <- second.get.asScala) {
|
||||
both(i) = plugin
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
callEventExcluding(event, false, both)
|
||||
callEventExcluding(event, false, both: _*)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -275,21 +269,18 @@ object MCChatUtils {
|
|||
if (event.isAsynchronous) {
|
||||
if (Thread.holdsLock(Bukkit.getPluginManager)) throw new IllegalStateException(event.getEventName + " cannot be triggered asynchronously from inside synchronized code.")
|
||||
if (Bukkit.getServer.isPrimaryThread) throw new IllegalStateException(event.getEventName + " cannot be triggered asynchronously from primary server thread.")
|
||||
fireEventExcluding(event, only, plugins)
|
||||
fireEventExcluding(event, only, plugins: _*)
|
||||
}
|
||||
else Bukkit.getPluginManager synchronized fireEventExcluding(event, only, plugins)
|
||||
else Bukkit.getPluginManager synchronized fireEventExcluding(event, only, plugins: _*)
|
||||
}
|
||||
|
||||
private def fireEventExcluding(event: Event, only: Boolean, plugins: String*): Unit = {
|
||||
val handlers = event.getHandlers // Code taken from SimplePluginManager in Spigot-API
|
||||
val listeners = handlers.getRegisteredListeners
|
||||
val server = Bukkit.getServer
|
||||
for (registration <- listeners) {
|
||||
if (!registration.getPlugin.isEnabled || util.Arrays.stream(plugins).anyMatch((p: String) => only ^ p.equalsIgnoreCase(registration.getPlugin.getName))) {
|
||||
continue //todo: continue is not supported
|
||||
// Modified to exclude plugins
|
||||
}
|
||||
try registration.callEvent(event)
|
||||
for (registration <- listeners) { // Modified to exclude plugins
|
||||
if (registration.getPlugin.isEnabled
|
||||
&& !plugins.exists(only ^ _.equalsIgnoreCase(registration.getPlugin.getName))) try registration.callEvent(event)
|
||||
catch {
|
||||
case ex: AuthorNagException =>
|
||||
val plugin = registration.getPlugin
|
||||
|
@ -308,12 +299,8 @@ object MCChatUtils {
|
|||
*/
|
||||
def callLoginEvents(dcp: DiscordConnectedPlayer): Unit = {
|
||||
val loginFail = (kickMsg: String) => {
|
||||
def foo(kickMsg: String): Unit = {
|
||||
dcp.sendMessage("Minecraft chat disabled, as the login failed: " + kickMsg)
|
||||
MCChatPrivate.privateMCChat(dcp.getChannel, start = false, dcp.getUser, dcp.getChromaUser)
|
||||
}
|
||||
|
||||
foo(kickMsg)
|
||||
dcp.sendMessage("Minecraft chat disabled, as the login failed: " + kickMsg)
|
||||
MCChatPrivate.privateMCChat(dcp.getChannel, start = false, dcp.getUser, dcp.getChromaUser)
|
||||
} //Probably also happens if the user is banned or so
|
||||
val event = new AsyncPlayerPreLoginEvent(dcp.getName, InetAddress.getLoopbackAddress, dcp.getUniqueId)
|
||||
callEventExcludingSome(event)
|
||||
|
|
|
@ -1,22 +1,23 @@
|
|||
package buttondevteam.discordplugin.mcchat
|
||||
|
||||
import buttondevteam.core.component.channel.Channel
|
||||
import buttondevteam.discordplugin.{ChannelconBroadcast, DPUtils, DiscordConnectedPlayer, DiscordPlugin}
|
||||
import buttondevteam.discordplugin.playerfaker.ServerWatcher
|
||||
import buttondevteam.discordplugin.playerfaker.perm.LPInjector
|
||||
import buttondevteam.discordplugin.util.DPState
|
||||
import buttondevteam.lib.{TBMCCoreAPI, TBMCSystemChatEvent}
|
||||
import buttondevteam.discordplugin.{ChannelconBroadcast, DPUtils, DiscordConnectedPlayer, DiscordPlugin}
|
||||
import buttondevteam.lib.architecture.{Component, ConfigData, ReadOnlyConfigData}
|
||||
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.rest.util.Color
|
||||
import org.bukkit.Bukkit
|
||||
import reactor.core.publisher.Mono
|
||||
import reactor.core.scala.publisher.SMono
|
||||
|
||||
import java.util
|
||||
import java.util.{Objects, UUID}
|
||||
import java.util.stream.Collectors
|
||||
import java.util.{Objects, UUID}
|
||||
|
||||
/**
|
||||
* Provides Minecraft chat connection to Discord. Commands may be used either in a public chat (limited) or in a DM.
|
||||
|
@ -45,7 +46,7 @@ class MinecraftChatModule extends Component[DiscordPlugin] {
|
|||
*/
|
||||
val chatChannel: ReadOnlyConfigData[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
|
||||
|
|
Loading…
Reference in a new issue