Tailrec announcer method, fix some compile issues

This commit is contained in:
Norbi Peti 2021-03-06 01:27:21 +01:00
parent d416eef144
commit 7296ebd2f8
No known key found for this signature in database
GPG key ID: DBA4C4549A927E56
18 changed files with 272 additions and 292 deletions

View file

@ -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")

View file

@ -44,7 +44,8 @@ abstract class DiscordSenderBase protected(var user: User, var channel: MessageC
return
}
val sendmsg = DPUtils.sanitizeString(message)
this synchronized msgtosend += "\n" + sendmsg
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"
@ -55,10 +56,11 @@ abstract class DiscordSenderBase protected(var user: User, var channel: MessageC
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: _*))
}

View file

@ -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
if (reddituserclass != null) {
val user = ChromaGamerBase.getUser(author, reddituserclass)
val id = user.getConnectedID(classOf[DiscordPlayer])
if (id != null) author = "<@" + id + ">"
} while ( {
false
})
}
}
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()
}
}

View file

@ -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")
}

View file

@ -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

View file

@ -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
}

View file

@ -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 = {

View file

@ -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()
}
}

View file

@ -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)

View file

@ -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
try getChannel.flatMap(channel => {
val coderRole = channel match {
case ch: GuildChannel => instance.pingRole(SMono(ch.getGuild)).get
case _ => SMono.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) = {
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: String) => !s.contains("\tat ") || s.contains("\tat buttondevteam.")).collect(Collectors.joining("\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("```")
channel.createMessage(sb.toString)
}
foo(sb)
SMono(channel.createMessage(sb.toString))
})
}
foo(channel)
}).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

View file

@ -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,40 +49,46 @@ 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
}
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)
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.

View file

@ -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
}

View file

@ -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

View file

@ -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)) {

View file

@ -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,

View file

@ -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,9 +112,12 @@ 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) {
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
@ -124,40 +128,35 @@ class MCChatListener(val module: MinecraftChatModule) extends Listener {
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
val isdifferentchannel: Predicate[Snowflake] = (id: Snowflake) => !((e.getSender.isInstanceOf[DiscordSenderBase])) || (e.getSender.asInstanceOf[DiscordSenderBase]).getChannel.getId.asLong != id.asLong
if (e.getChannel.isGlobal && (e.isFromCommand || isdifferentchannel.test(module.chatChannel.get))) {
if (MCChatUtils.lastmsgdata == null)
MCChatUtils.lastmsgdata = new MCChatUtils.LastMsgData(module.chatChannelMono.block, null)
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
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.accept(lmd)
doit(lmd)
}
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
return false //If the user no longer has permission, remove the connection
}
}
true
})
}
} catch {
case ex: InterruptedException =>

View file

@ -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) = {
def send(message: String): SMono[MessageChannel] => SMono[_] = _.flatMap((mc: MessageChannel) => {
resetLastMessage(mc)
mc.createMessage(DPUtils.sanitizeString(message))
}
foo(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)
} //Probably also happens if the user is banned or so
val event = new AsyncPlayerPreLoginEvent(dcp.getName, InetAddress.getLoopbackAddress, dcp.getUniqueId)
callEventExcludingSome(event)

View file

@ -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