Use Scala version of Reactor & data types
This commit is contained in:
parent
c57ac26b2d
commit
fce6b91b97
18 changed files with 282 additions and 314 deletions
15
pom.xml
15
pom.xml
|
@ -78,21 +78,6 @@
|
|||
</useSystemClassLoader> <!-- https://stackoverflow.com/a/53012553/2703239 -->
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>pre-scala</id>
|
||||
<configuration>
|
||||
<compilerArgs>-proc:only</compilerArgs>
|
||||
</configuration>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>compile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>net.alchim31.maven</groupId>
|
||||
<artifactId>scala-maven-plugin</artifactId>
|
||||
|
|
|
@ -6,10 +6,10 @@ import discord4j.common.util.Snowflake
|
|||
import discord4j.core.`object`.entity.channel.MessageChannel
|
||||
import discord4j.core.`object`.entity.{Guild, Message, Role}
|
||||
import discord4j.core.spec.EmbedCreateSpec
|
||||
import reactor.core.publisher.Mono
|
||||
import reactor.core.scala.publisher.SMono
|
||||
|
||||
import java.util
|
||||
import java.util.{Comparator, Optional}
|
||||
import java.util.Comparator
|
||||
import java.util.logging.Logger
|
||||
import java.util.regex.Pattern
|
||||
import javax.annotation.Nullable
|
||||
|
@ -62,8 +62,8 @@ object DPUtils {
|
|||
return matcher.replaceAll(aFunctionalInterface); //Find nearest URL match and if it's not reaching to the char then escape*/ val sb = new StringBuffer
|
||||
while ( {
|
||||
matcher.find
|
||||
}) matcher.appendReplacement(sb, if (Optional.ofNullable(ts.floor(Array[Int](matcher.start, 0))).map( //Find a URL start <= our start
|
||||
(a: Array[Int]) => a(1)).orElse(-1) < matcher.start //Check if URL end < our start
|
||||
}) matcher.appendReplacement(sb, if (Option(ts.floor(Array[Int](matcher.start, 0))).map( //Find a URL start <= our start
|
||||
(a: Array[Int]) => a(1)).getOrElse(-1) < matcher.start //Check if URL end < our start
|
||||
) "\\\\" + matcher.group else matcher.group)
|
||||
matcher.appendTail(sb)
|
||||
sb.toString
|
||||
|
@ -74,22 +74,22 @@ object DPUtils {
|
|||
DiscordPlugin.plugin.getLogger
|
||||
}
|
||||
|
||||
def channelData(config: IHaveConfig, key: String): ReadOnlyConfigData[Mono[MessageChannel]] =
|
||||
def channelData(config: IHaveConfig, key: String): ReadOnlyConfigData[SMono[MessageChannel]] =
|
||||
config.getReadOnlyDataPrimDef(key, 0L, (id: Any) =>
|
||||
getMessageChannel(key, Snowflake.of(id.asInstanceOf[Long])), (_: Mono[MessageChannel]) => 0L) //We can afford to search for the channel in the cache once (instead of using mainServer)
|
||||
def roleData(config: IHaveConfig, key: String, defName: String): ReadOnlyConfigData[Mono[Role]] =
|
||||
roleData(config, key, defName, Mono.just(DiscordPlugin.mainServer))
|
||||
getMessageChannel(key, Snowflake.of(id.asInstanceOf[Long])), (_: SMono[MessageChannel]) => 0L) //We can afford to search for the channel in the cache once (instead of using mainServer)
|
||||
def roleData(config: IHaveConfig, key: String, defName: String): ReadOnlyConfigData[SMono[Role]] =
|
||||
roleData(config, key, defName, SMono.just(DiscordPlugin.mainServer))
|
||||
|
||||
/**
|
||||
* Needs to be a {@link ConfigData} for checking if it's set
|
||||
*/
|
||||
def roleData(config: IHaveConfig, key: String, defName: String, guild: Mono[Guild]): ReadOnlyConfigData[Mono[Role]] = config.getReadOnlyDataPrimDef(key, defName, (name: Any) => {
|
||||
def foo(name: Any): Mono[Role] = {
|
||||
if (!name.isInstanceOf[String] || name.asInstanceOf[String].isEmpty) return Mono.empty[Role]
|
||||
def roleData(config: IHaveConfig, key: String, defName: String, guild: SMono[Guild]): ReadOnlyConfigData[SMono[Role]] = config.getReadOnlyDataPrimDef(key, defName, (name: Any) => {
|
||||
def foo(name: Any): SMono[Role] = {
|
||||
if (!name.isInstanceOf[String] || name.asInstanceOf[String].isEmpty) return SMono.empty[Role]
|
||||
guild.flatMapMany(_.getRoles).filter((r: Role) => r.getName == name).onErrorResume((e: Throwable) => {
|
||||
def foo(e: Throwable): Mono[Role] = {
|
||||
def foo(e: Throwable): SMono[Role] = {
|
||||
getLogger.warning("Failed to get role data for " + key + "=" + name + " - " + e.getMessage)
|
||||
Mono.empty[Role]
|
||||
SMono.empty[Role]
|
||||
}
|
||||
|
||||
foo(e)
|
||||
|
@ -97,7 +97,7 @@ object DPUtils {
|
|||
}
|
||||
|
||||
foo(name)
|
||||
}, (_: Mono[Role]) => defName)
|
||||
}, (_: SMono[Role]) => defName)
|
||||
|
||||
def snowflakeData(config: IHaveConfig, key: String, defID: Long): ReadOnlyConfigData[Snowflake] =
|
||||
config.getReadOnlyDataPrimDef(key, defID, (id: Any) => Snowflake.of(id.asInstanceOf[Long]), _.asLong)
|
||||
|
@ -137,7 +137,7 @@ object DPUtils {
|
|||
*/
|
||||
def disableIfConfigErrorRes(@Nullable component: Component[DiscordPlugin], config: ConfigData[_], result: Any): Boolean = {
|
||||
//noinspection ConstantConditions
|
||||
if (result == null || (result.isInstanceOf[Mono[_]] && !result.asInstanceOf[Mono[_]].hasElement.block)) {
|
||||
if (result == null || (result.isInstanceOf[SMono[_]] && !result.asInstanceOf[SMono[_]].hasElement.block())) {
|
||||
var path: String = null
|
||||
try {
|
||||
if (component != null) Component.setComponentEnabled(component, false)
|
||||
|
@ -157,26 +157,26 @@ object DPUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Send a response in the form of "@User, message". Use Mono.empty() if you don't have a channel object.
|
||||
* Send a response in the form of "@User, message". Use SMono.empty() if you don't have a channel object.
|
||||
*
|
||||
* @param original The original message to reply to
|
||||
* @param channel The channel to send the message in, defaults to the original
|
||||
* @param message The message to send
|
||||
* @return A mono to send the message
|
||||
*/
|
||||
def reply(original: Message, @Nullable channel: MessageChannel, message: String): Mono[Message] = {
|
||||
val ch = if (channel == null) original.getChannel
|
||||
else Mono.just(channel)
|
||||
def reply(original: Message, @Nullable channel: MessageChannel, message: String): SMono[Message] = {
|
||||
val ch = if (channel == null) SMono(original.getChannel)
|
||||
else SMono.just(channel)
|
||||
reply(original, ch, message)
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #reply(Message, MessageChannel, String)
|
||||
*/
|
||||
def reply(original: Message, ch: Mono[MessageChannel], message: String): Mono[Message] =
|
||||
ch.flatMap(_.createMessage((if (original.getAuthor.isPresent)
|
||||
def reply(original: Message, ch: SMono[MessageChannel], message: String): SMono[Message] =
|
||||
ch.flatMap(channel => SMono(channel.createMessage((if (original.getAuthor.isPresent)
|
||||
original.getAuthor.get.getMention + ", "
|
||||
else "") + message))
|
||||
else "") + message)))
|
||||
|
||||
def nickMention(userId: Snowflake): String = "<@!" + userId.asString + ">"
|
||||
|
||||
|
@ -189,21 +189,21 @@ object DPUtils {
|
|||
* @param id The channel ID
|
||||
* @return A message channel
|
||||
*/
|
||||
def getMessageChannel(key: String, id: Snowflake): Mono[MessageChannel] = {
|
||||
if (id.asLong == 0L) return Mono.empty[MessageChannel]
|
||||
def getMessageChannel(key: String, id: Snowflake): SMono[MessageChannel] = {
|
||||
if (id.asLong == 0L) return SMono.empty[MessageChannel]
|
||||
|
||||
DiscordPlugin.dc.getChannelById(id).onErrorResume(e => {
|
||||
SMono(DiscordPlugin.dc.getChannelById(id)).onErrorResume(e => {
|
||||
def foo(e: Throwable) = {
|
||||
getLogger.warning("Failed to get channel data for " + key + "=" + id + " - " + e.getMessage)
|
||||
Mono.empty
|
||||
SMono.empty
|
||||
}
|
||||
|
||||
foo(e)
|
||||
}).filter(ch => ch.isInstanceOf[MessageChannel]).cast(classOf[MessageChannel])
|
||||
}).filter(ch => ch.isInstanceOf[MessageChannel]).cast[MessageChannel]
|
||||
}
|
||||
|
||||
def getMessageChannel(config: ConfigData[Snowflake]): Mono[MessageChannel] =
|
||||
def getMessageChannel(config: ConfigData[Snowflake]): SMono[MessageChannel] =
|
||||
getMessageChannel(config.getPath, config.get)
|
||||
|
||||
def ignoreError[T](mono: Mono[T]): Mono[T] = mono.onErrorResume((_: Throwable) => Mono.empty)
|
||||
def ignoreError[T](mono: SMono[T]): SMono[T] = mono.onErrorResume((_: Throwable) => SMono.empty)
|
||||
}
|
|
@ -15,8 +15,8 @@ import org.bukkit.inventory.{Inventory, PlayerInventory}
|
|||
import org.bukkit.permissions.{PermissibleBase, Permission, PermissionAttachment, PermissionAttachmentInfo}
|
||||
import org.bukkit.plugin.Plugin
|
||||
import org.mockito.Answers.RETURNS_DEFAULTS
|
||||
import org.mockito.{MockSettings, Mockito}
|
||||
import org.mockito.invocation.InvocationOnMock
|
||||
import org.mockito.{MockSettings, Mockito}
|
||||
|
||||
import java.lang.reflect.Modifier
|
||||
import java.net.InetSocketAddress
|
||||
|
@ -52,7 +52,24 @@ object DiscordConnectedPlayer {
|
|||
}).stubOnly
|
||||
}
|
||||
|
||||
abstract class DiscordConnectedPlayer(user: User, channel: MessageChannel) extends DiscordSenderBase(user, channel) with IMCPlayer[DiscordConnectedPlayer] {
|
||||
/**
|
||||
* @constructor The parameters must match with {@link #create ( User, MessageChannel, UUID, String, MinecraftChatModule)}
|
||||
* @param user May be null.
|
||||
* @param channel May not be null.
|
||||
* @param uniqueId The UUID of the player.
|
||||
* @param name The Minecraft name of the player.
|
||||
* @param module The MinecraftChatModule or null if testing.
|
||||
*/
|
||||
abstract class DiscordConnectedPlayer(user: User, channel: MessageChannel, val uniqueId: UUID, val name: String, val module: MinecraftChatModule) extends DiscordSenderBase(user, channel) with IMCPlayer[DiscordConnectedPlayer] {
|
||||
private var loggedIn = false
|
||||
private var displayName: String = name
|
||||
|
||||
private var location: Location = if (module == null) null else Bukkit.getWorlds.get(0).getSpawnLocation
|
||||
private val basePlayer: OfflinePlayer = if (module == null) null else Bukkit.getOfflinePlayer(uniqueId)
|
||||
private var perm: PermissibleBase = if (module == null) null else new PermissibleBase(basePlayer)
|
||||
private val origPerm: PermissibleBase = perm
|
||||
private val vanillaCmdListener: VCMDWrapper = if (module == null) null else new VCMDWrapper(VCMDWrapper.createListener(this, module))
|
||||
|
||||
override def isPermissionSet(name: String): Boolean = this.origPerm.isPermissionSet(name)
|
||||
|
||||
override def isPermissionSet(perm: Permission): Boolean = this.origPerm.isPermissionSet(perm)
|
||||
|
@ -98,40 +115,11 @@ abstract class DiscordConnectedPlayer(user: User, channel: MessageChannel) exten
|
|||
|
||||
override def getDisplayName: String = this.displayName
|
||||
|
||||
private var vanillaCmdListener: VCMDWrapper = null
|
||||
private var loggedIn = false
|
||||
private var origPerm: PermissibleBase = null
|
||||
private var name: String = null
|
||||
private var basePlayer: OfflinePlayer = null
|
||||
private var perm: PermissibleBase = null
|
||||
private var location: Location = null
|
||||
final private var module: MinecraftChatModule = null
|
||||
final private var uniqueId: UUID = null
|
||||
final private var displayName: String = null
|
||||
|
||||
/**
|
||||
* The parameters must match with {@link #create ( User, MessageChannel, UUID, String, MinecraftChatModule)}
|
||||
*/
|
||||
def this(user: User, channel: MessageChannel, uuid: UUID, mcname: String, module: MinecraftChatModule) {
|
||||
this(user, channel)
|
||||
location = Bukkit.getWorlds.get(0).getSpawnLocation
|
||||
perm = new PermissibleBase(basePlayer = Bukkit.getOfflinePlayer(uuid))
|
||||
origPerm = perm
|
||||
name = mcname
|
||||
this.module = module
|
||||
uniqueId = uuid
|
||||
displayName = mcname
|
||||
vanillaCmdListener = new VCMDWrapper(VCMDWrapper.createListener(this, module))
|
||||
}
|
||||
|
||||
/**
|
||||
* For testing
|
||||
*/
|
||||
def this(user: User, channel: MessageChannel) {
|
||||
this(user, channel)
|
||||
module = null
|
||||
uniqueId = UUID.randomUUID
|
||||
}
|
||||
def this(user: User, channel: MessageChannel) =
|
||||
this(user, channel, UUID.randomUUID(), "Test", null)
|
||||
|
||||
override def setOp(value: Boolean): Unit = { //CraftPlayer-compatible implementation
|
||||
this.origPerm.setOp(value)
|
||||
|
@ -214,7 +202,7 @@ abstract class DiscordConnectedPlayer(user: User, channel: MessageChannel) exten
|
|||
override def getGameMode = GameMode.SPECTATOR
|
||||
|
||||
//noinspection ScalaDeprecation
|
||||
@SuppressWarnings(Array("deprecation")) final private val spigot: Spigot = new Spigot() {
|
||||
@SuppressWarnings(Array("deprecation")) override def spigot: Spigot = new Spigot() {
|
||||
override def getRawAddress: InetSocketAddress = null
|
||||
|
||||
override def playEffect(location: Location, effect: Effect, id: Int, data: Int, offsetX: Float, offsetY: Float, offsetZ: Float, speed: Float, particleCount: Int, radius: Int): Unit = {
|
||||
|
@ -241,11 +229,9 @@ abstract class DiscordConnectedPlayer(user: User, channel: MessageChannel) exten
|
|||
|
||||
override def sendMessage(position: ChatMessageType, component: BaseComponent): Unit =
|
||||
sendMessage(component) //Ignore position
|
||||
override def sendMessage(position: ChatMessageType, components: BaseComponent*) =
|
||||
sendMessage(components)
|
||||
override def sendMessage(position: ChatMessageType, components: BaseComponent*): Unit =
|
||||
sendMessage(components: _*)
|
||||
|
||||
override def isInvulnerable = true
|
||||
}
|
||||
|
||||
override def spigot: Spigot = spigot
|
||||
}
|
|
@ -15,12 +15,12 @@ import buttondevteam.lib.architecture._
|
|||
import buttondevteam.lib.player.ChromaGamerBase
|
||||
import com.google.common.io.Files
|
||||
import discord4j.common.util.Snowflake
|
||||
import discord4j.core.{DiscordClientBuilder, GatewayDiscordClient}
|
||||
import discord4j.core.`object`.entity.{ApplicationInfo, Guild, Role}
|
||||
import discord4j.core.`object`.presence.{Activity, Presence}
|
||||
import discord4j.core.`object`.reaction.ReactionEmoji
|
||||
import discord4j.core.event.domain.guild.GuildCreateEvent
|
||||
import discord4j.core.event.domain.lifecycle.ReadyEvent
|
||||
import discord4j.core.{DiscordClientBuilder, GatewayDiscordClient}
|
||||
import discord4j.gateway.ShardInfo
|
||||
import discord4j.store.jdk.JdkStoreService
|
||||
import org.apache.logging.log4j.LogManager
|
||||
|
@ -29,7 +29,7 @@ import org.bukkit.command.CommandSender
|
|||
import org.bukkit.configuration.file.YamlConfiguration
|
||||
import org.mockito.internal.util.MockUtil
|
||||
import reactor.core.Disposable
|
||||
import reactor.core.publisher.Mono
|
||||
import reactor.core.scala.publisher.SMono
|
||||
|
||||
import java.io.File
|
||||
import java.nio.charset.StandardCharsets
|
||||
|
@ -65,13 +65,16 @@ import java.util.Optional
|
|||
* The main server where the roles and other information is pulled from. It's automatically set to the first server the bot's invited to.
|
||||
*/
|
||||
private def mainServer = getIConfig.getDataPrimDef("mainServer", 0L, (id: Any) => {
|
||||
def foo(id: Any) = { //It attempts to get the default as well
|
||||
if (id.asInstanceOf[Long] == 0L) Optional.empty //Hack?
|
||||
else DiscordPlugin.dc.getGuildById(Snowflake.of(id.asInstanceOf[Long])).onErrorResume((t: Throwable) => Mono.fromRunnable(() => getLogger.warning("Failed to get guild: " + t.getMessage))).blockOptional
|
||||
def foo(id: Any): Option[Guild] = { //It attempts to get the default as well
|
||||
if (id.asInstanceOf[Long] == 0L) Option.empty
|
||||
else SMono.fromPublisher(DiscordPlugin.dc.getGuildById(Snowflake.of(id.asInstanceOf[Long])))
|
||||
.onErrorResume((t: Throwable) => {
|
||||
getLogger.warning("Failed to get guild: " + t.getMessage); SMono.empty
|
||||
}).blockOption()
|
||||
}
|
||||
|
||||
foo(id)
|
||||
}, (g: Optional[Guild]) => (g.map((gg: Guild) => gg.getId.asLong): Optional[Long]).orElse(0L))
|
||||
}, (g: Option[Guild]) => (g.map(_.getId.asLong): Option[Long]).getOrElse(0L))
|
||||
|
||||
/**
|
||||
* The (bot) channel to use for Discord commands like /role.
|
||||
|
@ -81,7 +84,7 @@ import java.util.Optional
|
|||
* The role that allows using mod-only Discord commands.
|
||||
* If empty (''), then it will only allow for the owner.
|
||||
*/
|
||||
var modRole: ReadOnlyConfigData[Mono[Role]] = null
|
||||
var modRole: ReadOnlyConfigData[SMono[Role]] = null
|
||||
/**
|
||||
* The invite link to show by /discord invite. If empty, it defaults to the first invite if the bot has access.
|
||||
*/
|
||||
|
@ -153,7 +156,9 @@ import java.util.Optional
|
|||
}
|
||||
|
||||
private def stopStarting(): Unit = {
|
||||
this synchronized (starting = false)
|
||||
this synchronized {
|
||||
starting = false
|
||||
}
|
||||
notifyAll()
|
||||
}
|
||||
|
||||
|
@ -164,7 +169,7 @@ import java.util.Optional
|
|||
DiscordPlugin.dc.updatePresence(Presence.online(Activity.playing("Minecraft"))).subscribe //Update from the initial presence
|
||||
return
|
||||
}
|
||||
DiscordPlugin.mainServer = mainServer.get.orElse(null) //Shouldn't change afterwards
|
||||
DiscordPlugin.mainServer = mainServer.get.orNull //Shouldn't change afterwards
|
||||
if (DiscordPlugin.mainServer == null) {
|
||||
if (event.size == 0) {
|
||||
getLogger.severe("Main server not found! Invite the bot and do /discord restart")
|
||||
|
@ -174,7 +179,7 @@ import java.util.Optional
|
|||
}
|
||||
DiscordPlugin.mainServer = event.get(0).getGuild
|
||||
getLogger.warning("Main server set to first one: " + DiscordPlugin.mainServer.getName)
|
||||
mainServer.set(Optional.of(DiscordPlugin.mainServer)) //Save in config
|
||||
mainServer.set(Option(DiscordPlugin.mainServer)) //Save in config
|
||||
}
|
||||
DiscordPlugin.SafeMode = false
|
||||
setupConfig()
|
||||
|
|
|
@ -2,28 +2,24 @@ package buttondevteam.discordplugin
|
|||
|
||||
import discord4j.core.`object`.entity.User
|
||||
import discord4j.core.`object`.entity.channel.MessageChannel
|
||||
import org.bukkit.{Bukkit, Server}
|
||||
import org.bukkit.command.CommandSender
|
||||
import org.bukkit.permissions.{PermissibleBase, Permission, PermissionAttachment, PermissionAttachmentInfo}
|
||||
import org.bukkit.plugin.Plugin
|
||||
import reactor.core.publisher.Mono
|
||||
import org.bukkit.{Bukkit, Server}
|
||||
import reactor.core.scala.publisher.SMono
|
||||
|
||||
import java.util
|
||||
|
||||
class DiscordSender(user: User, channel: MessageChannel) extends DiscordSenderBase(user, channel) with CommandSender {
|
||||
class DiscordSender(user: User, channel: MessageChannel, pname: String) extends DiscordSenderBase(user, channel) with CommandSender {
|
||||
private val perm = new PermissibleBase(this)
|
||||
private var name: String = null
|
||||
private val name: String = Option(pname)
|
||||
.orElse(Option(user).map(u => SMono(u.asMember(DiscordPlugin.mainServer.getId))
|
||||
.onErrorResume(_ => SMono.empty).blockOption()
|
||||
.map(u => u.getDisplayName)))
|
||||
.getOrElse("Discord user")
|
||||
|
||||
def this(user: User, channel: MessageChannel) {
|
||||
this(user, channel)
|
||||
val `def` = "Discord user"
|
||||
name = if (user == null) `def`
|
||||
else user.asMember(DiscordPlugin.mainServer.getId).onErrorResume((_: Throwable) => Mono.empty).blockOptional.map(_.getDisplayName).orElse(`def`)
|
||||
}
|
||||
|
||||
def this(user: User, channel: MessageChannel, name: String) {
|
||||
this(user, channel)
|
||||
this.name = name
|
||||
this(user, channel, null)
|
||||
}
|
||||
|
||||
override def isPermissionSet(name: String): Boolean = perm.isPermissionSet(name)
|
||||
|
|
|
@ -90,7 +90,8 @@ import reactor.core.publisher.Flux
|
|||
}
|
||||
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
|
||||
if (lastAnnouncementTime.get ne lastanntime) lastAnnouncementTime.set(lastanntime) // If sending succeeded} catch {
|
||||
if (lastAnnouncementTime.get ne lastanntime) lastAnnouncementTime.set(lastanntime) // If sending succeeded
|
||||
} catch {
|
||||
case e: Exception =>
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
|
|
@ -7,8 +7,7 @@ import buttondevteam.lib.chat.{Command2, CommandClass}
|
|||
object VersionCommand {
|
||||
def getVersion: Array[String] = {
|
||||
val desc = DiscordPlugin.plugin.getDescription
|
||||
Array[String]( //
|
||||
desc.getFullName, desc.getWebsite //)
|
||||
Array[String](desc.getFullName, desc.getWebsite)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package buttondevteam.discordplugin.exceptions
|
||||
|
||||
import buttondevteam.core.ComponentManager
|
||||
import buttondevteam.discordplugin.exceptions.ExceptionListenerModule.SendException
|
||||
import buttondevteam.discordplugin.{DPUtils, DiscordPlugin}
|
||||
import buttondevteam.lib.architecture.Component
|
||||
import buttondevteam.lib.{TBMCCoreAPI, TBMCExceptionEvent}
|
||||
|
@ -12,6 +11,7 @@ import org.bukkit.Bukkit
|
|||
import org.bukkit.event.{EventHandler, Listener}
|
||||
import reactor.core.publisher.Mono
|
||||
|
||||
import java.util
|
||||
import java.util.stream.Collectors
|
||||
|
||||
/**
|
||||
|
@ -65,7 +65,10 @@ 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 && lastsourcemsg.contains(e.getSourceMessage)) { return }
|
||||
else e.getException.getMessage == ex.getMessage)) // e.Exception.Message==ex.Message
|
||||
&& lastsourcemsg.contains(e.getSourceMessage)) {
|
||||
return
|
||||
}
|
||||
ExceptionListenerModule
|
||||
.SendException(e.getException, e.getSourceMessage)
|
||||
if (lastthrown.size >= 10) lastthrown.remove(0)
|
||||
|
|
|
@ -59,7 +59,7 @@ object FunModule {
|
|||
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 && util.Arrays.stream(fm.serverReady).get.anyMatch(msglowercased.contains _)) {
|
||||
var next = 0
|
||||
if (usableServerReadyStrings.size == 0) fm.createUsableServerReadyStrings()
|
||||
next = usableServerReadyStrings.remove(serverReadyRandom.nextInt(usableServerReadyStrings.size))
|
||||
|
|
|
@ -6,7 +6,7 @@ import buttondevteam.lib.TBMCCoreAPI
|
|||
import discord4j.common.util.Snowflake
|
||||
import discord4j.core.`object`.entity.channel.{MessageChannel, PrivateChannel}
|
||||
import discord4j.core.`object`.entity.{Member, Message, Role, User}
|
||||
import reactor.core.publisher.{Flux, Mono}
|
||||
import reactor.core.scala.publisher.{SFlux, SMono}
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
|
@ -18,14 +18,14 @@ object CommandListener {
|
|||
* @param mentionedonly Only run the command if ChromaBot is mentioned at the start of the message
|
||||
* @return Whether it <b>did not run</b> the command
|
||||
*/
|
||||
def runCommand(message: Message, commandChannelID: Snowflake, mentionedonly: Boolean): Mono[Boolean] = {
|
||||
def runCommand(message: Message, commandChannelID: Snowflake, mentionedonly: Boolean): SMono[Boolean] = {
|
||||
val timings = CommonListeners.timings
|
||||
val ret = Mono.just(true)
|
||||
val ret = SMono.just(true)
|
||||
if (message.getContent.isEmpty) return ret //Pin messages and such, let the mcchat listener deal with it
|
||||
val content = message.getContent
|
||||
timings.printElapsed("A")
|
||||
message.getChannel.flatMap((channel: MessageChannel) => {
|
||||
def foo(channel: MessageChannel): Mono[Boolean] = {
|
||||
SMono(message.getChannel).flatMap((channel: MessageChannel) => {
|
||||
def foo(channel: MessageChannel): SMono[Boolean] = {
|
||||
var tmp = ret
|
||||
if (!mentionedonly) { //mentionedonly conditions are in CommonListeners
|
||||
timings.printElapsed("B")
|
||||
|
@ -33,22 +33,24 @@ object CommandListener {
|
|||
return ret
|
||||
}
|
||||
timings.printElapsed("C")
|
||||
tmp = ret.`then`(channel.`type`).thenReturn(true) // Fun (this true is ignored - x)
|
||||
tmp = ret.`then`(SMono(channel.`type`)).`then`(ret) // Fun (this true is ignored - x)
|
||||
}
|
||||
val cmdwithargs = new StringBuilder(content)
|
||||
val gotmention = new AtomicBoolean
|
||||
timings.printElapsed("Before self")
|
||||
tmp.flatMapMany((x: Boolean) => DiscordPlugin.dc.getSelf.flatMap((self: User) => self.asMember(DiscordPlugin.mainServer.getId)).flatMapMany((self: Member) => {
|
||||
def foo(self: Member): Flux[String] = {
|
||||
timings.printElapsed("D")
|
||||
gotmention.set(checkanddeletemention(cmdwithargs, self.getMention, message))
|
||||
gotmention.set(checkanddeletemention(cmdwithargs, self.getNicknameMention, message) || gotmention.get)
|
||||
val mentions = message.getRoleMentions
|
||||
self.getRoles.filterWhen((r: Role) => mentions.any((rr: Role) => rr.getName == r.getName)).map(_.getMention)
|
||||
}
|
||||
tmp.flatMapMany((_: Boolean) => SMono(DiscordPlugin.dc.getSelf)
|
||||
.flatMap((self: User) => SMono(self.asMember(DiscordPlugin.mainServer.getId)))
|
||||
.flatMapMany((self: Member) => {
|
||||
def foo(self: Member) = {
|
||||
timings.printElapsed("D")
|
||||
gotmention.set(checkanddeletemention(cmdwithargs, self.getMention, message))
|
||||
gotmention.set(checkanddeletemention(cmdwithargs, self.getNicknameMention, message) || gotmention.get)
|
||||
val mentions = SFlux(message.getRoleMentions)
|
||||
SFlux(self.getRoles).filterWhen((r: Role) => mentions.any((rr: Role) => rr.getName == r.getName)).map(_.getMention)
|
||||
}
|
||||
|
||||
foo(self)
|
||||
}).map((mentionRole: String) => {
|
||||
foo(self)
|
||||
}).map((mentionRole: String) => {
|
||||
def foo(mentionRole: String): Boolean = {
|
||||
timings.printElapsed("E")
|
||||
gotmention.set(checkanddeletemention(cmdwithargs, mentionRole, message) || gotmention.get) // Delete all mentions
|
||||
|
@ -56,17 +58,20 @@ object CommandListener {
|
|||
}
|
||||
|
||||
foo(mentionRole)
|
||||
}: Boolean)[Mono[Boolean]].switchIfEmpty(Mono.fromSupplier[Boolean](() => !mentionedonly || gotmention.get)))[Mono[Boolean]].filter((b: Boolean) => b).last(false).filter((b: Boolean) => b).doOnNext((b: Boolean) => channel.`type`.subscribe).flatMap((b: Boolean) => {
|
||||
def foo(): Mono[Boolean] = {
|
||||
}).switchIfEmpty(SMono.fromCallable(() => !mentionedonly || gotmention.get))).filter(b => b)
|
||||
.last(Option(false)).filter(b => b)
|
||||
.doOnNext(_ => channel.`type`.subscribe).flatMap(_ => {
|
||||
def foo(): SMono[Boolean] = {
|
||||
val cmdwithargsString = cmdwithargs.toString
|
||||
try {
|
||||
timings.printElapsed("F")
|
||||
if (!DiscordPlugin.plugin.manager.handleCommand(new Command2DCSender(message), cmdwithargsString)) return DPUtils.reply(message, channel, "unknown command. Do " + DiscordPlugin.getPrefix + "help for help.").map((_: Message) => false)
|
||||
if (!DiscordPlugin.plugin.manager.handleCommand(new Command2DCSender(message), cmdwithargsString))
|
||||
return DPUtils.reply(message, channel, "unknown command. Do " + DiscordPlugin.getPrefix + "help for help.").map(_ => false)
|
||||
} catch {
|
||||
case e: Exception =>
|
||||
TBMCCoreAPI.SendException("Failed to process Discord command: " + cmdwithargsString, e, DiscordPlugin.plugin)
|
||||
}
|
||||
Mono.just(false) //If the command succeeded or there was an error, return false
|
||||
SMono.just(false) //If the command succeeded or there was an error, return false
|
||||
}
|
||||
|
||||
foo()
|
||||
|
|
|
@ -13,6 +13,7 @@ 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.publisher.Mono
|
||||
import reactor.core.scala.publisher.SMono
|
||||
|
||||
object CommonListeners {
|
||||
val timings = new Timings
|
||||
|
@ -36,24 +37,24 @@ object CommonListeners {
|
|||
if (!author.isPresent || author.get.isBot) return `def`
|
||||
if (FunModule.executeMemes(event.getMessage)) return `def`
|
||||
val commandChannel = DiscordPlugin.plugin.commandChannel.get
|
||||
event.getMessage.getChannel.map((mch: MessageChannel) => (commandChannel != null && mch.getId.asLong == commandChannel.asLong) //If mentioned, that's higher than chat
|
||||
SMono(event.getMessage.getChannel).map((mch: MessageChannel) => (commandChannel != null && mch.getId.asLong == commandChannel.asLong) //If mentioned, that's higher than chat
|
||||
|| mch.isInstanceOf[PrivateChannel] || event.getMessage.getContent.contains("channelcon")).flatMap(
|
||||
(shouldRun: Boolean) => { //Only 'channelcon' is allowed in other channels
|
||||
def foo(shouldRun: Boolean): Mono[Boolean] = { //Only continue if this doesn't handle the event
|
||||
if (!shouldRun) return Mono.just(true) //The condition is only for the first command execution, not mcchat
|
||||
def foo(shouldRun: Boolean): SMono[Boolean] = { //Only continue if this doesn't handle the event
|
||||
if (!shouldRun) return SMono.just(true) //The condition is only for the first command execution, not mcchat
|
||||
timings.printElapsed("Run command 1")
|
||||
CommandListener.runCommand(event.getMessage, commandChannel, mentionedonly = true) //#bot is handled here
|
||||
}
|
||||
|
||||
foo(shouldRun)
|
||||
}).filterWhen((ch: Any) => {
|
||||
def foo(): Mono[Boolean] = {
|
||||
def foo() = {
|
||||
timings.printElapsed("mcchat")
|
||||
val mcchat = Component.getComponents.get(classOf[MinecraftChatModule])
|
||||
if (mcchat != null && mcchat.isEnabled) { //ComponentManager.isEnabled() searches the component again
|
||||
return mcchat.asInstanceOf[MinecraftChatModule].getListener.handleDiscord(event) //Also runs Discord commands in chat channels
|
||||
}
|
||||
Mono.just(true) //Wasn't handled, continue
|
||||
SMono.just(true) //Wasn't handled, continue
|
||||
}
|
||||
|
||||
foo()
|
||||
|
|
|
@ -1,27 +1,24 @@
|
|||
package buttondevteam.discordplugin.mcchat
|
||||
|
||||
import buttondevteam.core.component.channel.Channel
|
||||
import buttondevteam.core.component.channel.ChatRoom
|
||||
import buttondevteam.core.component.channel.{Channel, ChatRoom}
|
||||
import buttondevteam.discordplugin.ChannelconBroadcast.ChannelconBroadcast
|
||||
import buttondevteam.discordplugin._
|
||||
import buttondevteam.discordplugin.commands.{Command2DCSender, ICommand2DC}
|
||||
import buttondevteam.lib.TBMCSystemChatEvent
|
||||
import buttondevteam.lib.chat.Command2
|
||||
import buttondevteam.lib.chat.CommandClass
|
||||
import buttondevteam.lib.player.TBMCPlayer
|
||||
import buttondevteam.lib.chat.{Command2, CommandClass}
|
||||
import buttondevteam.lib.player.{ChromaGamerBase, TBMCPlayer}
|
||||
import discord4j.core.`object`.entity.Message
|
||||
import discord4j.core.`object`.entity.channel.{GuildChannel, MessageChannel}
|
||||
import discord4j.rest.util.{Permission, PermissionSet}
|
||||
import lombok.RequiredArgsConstructor
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.command.CommandSender
|
||||
import reactor.core.publisher.Mono
|
||||
import reactor.core.scala.publisher.SMono
|
||||
|
||||
import javax.annotation.Nullable
|
||||
import java.lang.reflect.Method
|
||||
import java.util
|
||||
import java.util.{Objects, Optional}
|
||||
import java.util.function.Supplier
|
||||
import java.util.stream.Collectors
|
||||
import java.util.{Objects, Optional}
|
||||
import javax.annotation.Nullable
|
||||
|
||||
@SuppressWarnings(Array("SimplifyOptionalCallChains")) //Java 11
|
||||
@CommandClass(helpText = Array(Array("Channel connect", //
|
||||
|
@ -37,11 +34,11 @@ import java.util.stream.Collectors
|
|||
class ChannelconCommand(private val module: MinecraftChatModule) extends ICommand2DC {
|
||||
@Command2.Subcommand def remove(sender: Command2DCSender): Boolean = {
|
||||
val message = sender.getMessage
|
||||
if (checkPerms(message, null)) true
|
||||
if (checkPerms(message, null)) return true
|
||||
else if (MCChatCustom.removeCustomChat(message.getChannelId))
|
||||
DPUtils.reply(message, Mono.empty, "channel connection removed.").subscribe
|
||||
DPUtils.reply(message, SMono.empty, "channel connection removed.").subscribe
|
||||
else
|
||||
DPUtils.reply(message, Mono.empty, "this channel isn't connected.").subscribe
|
||||
DPUtils.reply(message, SMono.empty, "this channel isn't connected.").subscribe
|
||||
true
|
||||
}
|
||||
|
||||
|
@ -54,31 +51,30 @@ class ChannelconCommand(private val module: MinecraftChatModule) extends IComman
|
|||
if (cc == null) {
|
||||
return respond(sender, "this channel isn't connected.")
|
||||
}
|
||||
val togglesString: Supplier[String] = () => util.Arrays.stream(ChannelconBroadcast.values)
|
||||
.map((t: ChannelconBroadcast) =>
|
||||
t.toString.toLowerCase + ": " + (if ((cc.toggles & t.flag) == 0) "disabled" else "enabled"))
|
||||
.collect(Collectors.joining("\n")) + "\n\n" +
|
||||
val togglesString: Supplier[String] = () => ChannelconBroadcast.values
|
||||
.map(t => t.toString.toLowerCase + ": " + (if ((cc.toggles & (1 << t.id)) == 0) "disabled" else "enabled"))
|
||||
.mkString("\n") + "\n\n" +
|
||||
TBMCSystemChatEvent.BroadcastTarget.stream.map((target: TBMCSystemChatEvent.BroadcastTarget) =>
|
||||
target.getName + ": " + (if (cc.brtoggles.contains(target)) "enabled" else "disabled"))
|
||||
.collect(Collectors.joining("\n"))
|
||||
if (toggle == null) {
|
||||
DPUtils.reply(message, Mono.empty, "toggles:\n" + togglesString.get).subscribe
|
||||
DPUtils.reply(message, SMono.empty, "toggles:\n" + togglesString.get).subscribe
|
||||
return true
|
||||
}
|
||||
val arg: String = toggle.toUpperCase
|
||||
val b: Optional[ChannelconBroadcast] = util.Arrays.stream(ChannelconBroadcast.values).filter((t: ChannelconBroadcast) => t.toString == arg).findAny
|
||||
if (!b.isPresent) {
|
||||
val b = ChannelconBroadcast.values.find((t: ChannelconBroadcast) => t.toString == arg)
|
||||
if (b.isEmpty) {
|
||||
val bt: TBMCSystemChatEvent.BroadcastTarget = TBMCSystemChatEvent.BroadcastTarget.get(arg)
|
||||
if (bt == null) {
|
||||
DPUtils.reply(message, Mono.empty, "cannot find toggle. Toggles:\n" + togglesString.get).subscribe
|
||||
DPUtils.reply(message, SMono.empty, "cannot find toggle. Toggles:\n" + togglesString.get).subscribe
|
||||
return true
|
||||
}
|
||||
val add: Boolean = !(cc.brtoggles.contains(bt))
|
||||
if (add) {
|
||||
cc.brtoggles.add(bt)
|
||||
cc.brtoggles += bt
|
||||
}
|
||||
else {
|
||||
cc.brtoggles.remove(bt)
|
||||
cc.brtoggles -= bt
|
||||
}
|
||||
return respond(sender, "'" + bt.getName + "' " + (if (add) "en" else "dis") + "abled")
|
||||
}
|
||||
|
@ -89,10 +85,10 @@ class ChannelconCommand(private val module: MinecraftChatModule) extends IComman
|
|||
//1 0 | 1
|
||||
//1 1 | 0
|
||||
// XOR
|
||||
cc.toggles ^= b.get.flag
|
||||
DPUtils.reply(message, Mono.empty, "'" + b.get.toString.toLowerCase + "' "
|
||||
+ (if ((cc.toggles & b.get.flag) == 0) "disabled" else "enabled")).subscribe
|
||||
return true
|
||||
cc.toggles ^= (1 << b.get.id)
|
||||
DPUtils.reply(message, SMono.empty, "'" + b.get.toString.toLowerCase + "' "
|
||||
+ (if ((cc.toggles & (1 << b.get.id)) == 0) "disabled" else "enabled")).subscribe
|
||||
true
|
||||
}
|
||||
|
||||
@Command2.Subcommand def `def`(sender: Command2DCSender, channelID: String): Boolean = {
|
||||
|
@ -139,14 +135,14 @@ class ChannelconCommand(private val module: MinecraftChatModule) extends IComman
|
|||
return true;
|
||||
}*/
|
||||
//TODO: "Channel admins" that can connect channels?
|
||||
MCChatCustom.addCustomChat(channel, groupid, chan.get, author, dcp, 0, new util.HashSet[TBMCSystemChatEvent.BroadcastTarget])
|
||||
MCChatCustom.addCustomChat(channel, groupid, chan.get, author, dcp, 0, Set())
|
||||
if (chan.get.isInstanceOf[ChatRoom]) {
|
||||
DPUtils.reply(message, channel, "alright, connection made to the room!").subscribe
|
||||
}
|
||||
else {
|
||||
DPUtils.reply(message, channel, "alright, connection made to group `" + groupid + "`!").subscribe
|
||||
}
|
||||
return true
|
||||
true
|
||||
}
|
||||
|
||||
@SuppressWarnings(Array("ConstantConditions"))
|
||||
|
@ -167,7 +163,7 @@ class ChannelconCommand(private val module: MinecraftChatModule) extends IComman
|
|||
false
|
||||
}
|
||||
|
||||
def getHelpText(method: Method, ann: Command2.Subcommand): Array[String] =
|
||||
override def getHelpText(method: Method, ann: Command2.Subcommand): Array[String] =
|
||||
Array[String](
|
||||
"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).",
|
||||
|
@ -178,6 +174,6 @@ class ChannelconCommand(private val module: MinecraftChatModule) extends IComman
|
|||
"To remove a connection use @ChromaBot channelcon remove in the channel.",
|
||||
"Mentioning the bot is needed in this case because the " + DiscordPlugin.getPrefix + " prefix only works in " + DPUtils.botmention + ".",
|
||||
"Invite link: <https://discordapp.com/oauth2/authorize?client_id="
|
||||
+ DiscordPlugin.dc.getApplicationInfo.map((info) => info.getId.asString).blockOptional.orElse("Unknown")
|
||||
+ SMono(DiscordPlugin.dc.getApplicationInfo).map(info => info.getId.asString).blockOption().getOrElse("Unknown")
|
||||
+ "&scope=bot&permissions=268509264>")
|
||||
}
|
|
@ -18,7 +18,7 @@ object MCChatCustom {
|
|||
*/
|
||||
private[mcchat] val lastmsgCustom = new util.ArrayList[MCChatCustom.CustomLMD]
|
||||
|
||||
def addCustomChat(channel: MessageChannel, groupid: String, mcchannel: Channel, user: User, dcp: DiscordConnectedPlayer, toggles: Int, brtoggles: util.Set[TBMCSystemChatEvent.BroadcastTarget]): Boolean = {
|
||||
def addCustomChat(channel: MessageChannel, groupid: String, mcchannel: Channel, user: User, dcp: DiscordConnectedPlayer, toggles: Int, brtoggles: Set[TBMCSystemChatEvent.BroadcastTarget]): Boolean = {
|
||||
lastmsgCustom synchronized {
|
||||
var gid: String = null
|
||||
mcchannel match {
|
||||
|
@ -58,9 +58,9 @@ object MCChatCustom {
|
|||
|
||||
def getCustomChats: util.List[CustomLMD] = Collections.unmodifiableList(lastmsgCustom)
|
||||
|
||||
class CustomLMD private(@NonNull channel: MessageChannel, @NonNull user: User, val groupID: String,
|
||||
@NonNull val mcchannel: Channel, val dcp: DiscordConnectedPlayer, var toggles: Int,
|
||||
var brtoggles: Set[TBMCSystemChatEvent.BroadcastTarget]) extends MCChatUtils.LastMsgData(channel, user) {
|
||||
class CustomLMD private[mcchat](@NonNull channel: MessageChannel, @NonNull user: User, val groupID: String,
|
||||
@NonNull mcchannel: Channel, val dcp: DiscordConnectedPlayer, var toggles: Int,
|
||||
var brtoggles: Set[TBMCSystemChatEvent.BroadcastTarget]) extends MCChatUtils.LastMsgData(channel, user, mcchannel) {
|
||||
}
|
||||
|
||||
}
|
|
@ -21,6 +21,7 @@ import org.bukkit.entity.Player
|
|||
import org.bukkit.event.{EventHandler, Listener}
|
||||
import org.bukkit.scheduler.BukkitTask
|
||||
import reactor.core.publisher.Mono
|
||||
import reactor.core.scala.publisher.{SFlux, SMono}
|
||||
|
||||
import java.time.Instant
|
||||
import java.util
|
||||
|
@ -244,30 +245,30 @@ class MCChatListener(val module: MinecraftChatModule) extends Listener {
|
|||
private var recthread: Thread = null
|
||||
|
||||
// Discord
|
||||
def handleDiscord(ev: MessageCreateEvent): Mono[Boolean] = {
|
||||
def handleDiscord(ev: MessageCreateEvent): SMono[Boolean] = {
|
||||
val timings: Timings = CommonListeners.timings
|
||||
timings.printElapsed("Chat event")
|
||||
val author: Optional[User] = ev.getMessage.getAuthor
|
||||
val hasCustomChat: Boolean = MCChatCustom.hasCustomChat(ev.getMessage.getChannelId)
|
||||
val prefix: Char = DiscordPlugin.getPrefix
|
||||
return ev.getMessage.getChannel.filter((channel: MessageChannel) => {
|
||||
def foo(channel: MessageChannel) = {
|
||||
timings.printElapsed("Filter 1")
|
||||
return !((ev.getMessage.getChannelId.asLong != module.chatChannel.get.asLong && !((channel.isInstanceOf[PrivateChannel] && author.map((u: User) => MCChatPrivate.isMinecraftChatEnabled(u.getId.asString)).orElse(false))) && !(hasCustomChat))) //Chat isn't enabled on this channel
|
||||
}
|
||||
val author = Option(ev.getMessage.getAuthor.orElse(null))
|
||||
val hasCustomChat = MCChatCustom.hasCustomChat(ev.getMessage.getChannelId)
|
||||
val prefix = DiscordPlugin.getPrefix
|
||||
SMono(ev.getMessage.getChannel).filter(channel => {
|
||||
def hasPrivateChat = channel.isInstanceOf[PrivateChannel] &&
|
||||
author.exists((u: User) => MCChatPrivate.isMinecraftChatEnabled(u.getId.asString))
|
||||
|
||||
foo(channel)
|
||||
}).filter((channel: MessageChannel) => {
|
||||
def foo(channel: MessageChannel) = {
|
||||
timings.printElapsed("Filter 2")
|
||||
return !((channel.isInstanceOf[PrivateChannel] //Only in private chat && ev.getMessage.getContent.length < "/mcchat<>".length && ev.getMessage.getContent.replace(prefix + "", "").equalsIgnoreCase("mcchat")))//Either mcchat or /mcchat
|
||||
//Allow disabling the chat if needed
|
||||
}
|
||||
def hasPublicChat = ev.getMessage.getChannelId.asLong == module.chatChannel.get.asLong
|
||||
|
||||
foo(channel)
|
||||
}).filterWhen((channel: MessageChannel) => CommandListener.runCommand(ev.getMessage, DiscordPlugin.plugin.commandChannel.get, true)).filter //Allow running commands in chat channels
|
||||
((channel: MessageChannel) => {
|
||||
def foo(channel: MessageChannel) = {
|
||||
timings.printElapsed("Filter 1")
|
||||
val chatEnabled = hasPublicChat || hasPrivateChat || hasCustomChat
|
||||
chatEnabled
|
||||
}).filter(channel => {
|
||||
timings.printElapsed("Filter 2")
|
||||
!(channel.isInstanceOf[PrivateChannel] //Only in private chat
|
||||
&& ev.getMessage.getContent.length < "/mcchat<>".length
|
||||
&& ev.getMessage.getContent.replace(prefix + "", "").equalsIgnoreCase("mcchat")) //Either mcchat or /mcchat
|
||||
//Allow disabling the chat if needed
|
||||
}).filterWhen(_ =>
|
||||
CommandListener.runCommand(ev.getMessage, DiscordPlugin.plugin.commandChannel.get, mentionedonly = true)) //Allow running commands in chat channels
|
||||
.filter(channel => {
|
||||
MCChatUtils.resetLastMessage(channel)
|
||||
recevents.add(ev)
|
||||
timings.printElapsed("Message event added")
|
||||
|
@ -275,22 +276,15 @@ class MCChatListener(val module: MinecraftChatModule) extends Listener {
|
|||
return true
|
||||
}
|
||||
recrun = () => {
|
||||
def foo() = { //Don't return in a while loop next time
|
||||
recthread = Thread.currentThread
|
||||
processDiscordToMC()
|
||||
if (DiscordPlugin.plugin.isEnabled && !(stop)) {
|
||||
rectask = Bukkit.getScheduler.runTaskAsynchronously(DiscordPlugin.plugin, recrun) //Continue message processing
|
||||
}
|
||||
recthread = Thread.currentThread
|
||||
processDiscordToMC()
|
||||
if (DiscordPlugin.plugin.isEnabled && !(stop)) {
|
||||
rectask = Bukkit.getScheduler.runTaskAsynchronously(DiscordPlugin.plugin, recrun) //Continue message processing
|
||||
}
|
||||
|
||||
foo()
|
||||
}
|
||||
rectask = Bukkit.getScheduler.runTaskAsynchronously(DiscordPlugin.plugin, recrun) //Start message processing
|
||||
return true
|
||||
}
|
||||
|
||||
foo(channel)
|
||||
}).map((b: MessageChannel) => false).defaultIfEmpty(true)
|
||||
}).map(_ => false).defaultIfEmpty(true)
|
||||
}
|
||||
|
||||
private def processDiscordToMC(): Unit = {
|
||||
|
@ -307,7 +301,7 @@ class MCChatListener(val module: MinecraftChatModule) extends Listener {
|
|||
val dsender: DiscordSenderBase = MCChatUtils.getSender(event.getMessage.getChannelId, sender)
|
||||
val user: DiscordPlayer = dsender.getChromaUser
|
||||
|
||||
for (u <- event.getMessage.getUserMentions.toIterable) { //TODO: Role mentions
|
||||
for (u <- SFlux(event.getMessage.getUserMentions).toIterable()) { //TODO: Role mentions
|
||||
dmessage = dmessage.replace(u.getMention, "@" + u.getUsername) // TODO: IG Formatting
|
||||
val m: Optional[Member] = u.asMember(DiscordPlugin.mainServer.getId).onErrorResume((t: Throwable) => Mono.empty).blockOptional
|
||||
if (m.isPresent) {
|
||||
|
@ -317,7 +311,7 @@ class MCChatListener(val module: MinecraftChatModule) extends Listener {
|
|||
}
|
||||
}
|
||||
|
||||
for (ch <- event.getGuild.flux.flatMap(_.getChannels).toIterable) {
|
||||
for (ch <- SFlux(event.getGuild.flux).flatMap(_.getChannels).toIterable()) {
|
||||
dmessage = dmessage.replace(ch.getMention, "#" + ch.getName)
|
||||
}
|
||||
dmessage = EmojiParser.parseToAliases(dmessage, EmojiParser.FitzpatrickAction.PARSE) //Converts emoji to text- TODO: Add option to disable (resource pack?)
|
||||
|
@ -388,7 +382,7 @@ class MCChatListener(val module: MinecraftChatModule) extends Listener {
|
|||
}
|
||||
react = true
|
||||
}
|
||||
return react
|
||||
react
|
||||
}
|
||||
|
||||
private def handleIngameCommand(event: MessageCreateEvent, dmessage: String, dsender: DiscordSenderBase, user: DiscordPlayer, clmd: MCChatCustom.CustomLMD, isPrivate: Boolean): Boolean = {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package buttondevteam.discordplugin.mcchat
|
||||
|
||||
import buttondevteam.core.ComponentManager
|
||||
import buttondevteam.discordplugin.mcchat.MCChatUtils.LastMsgData
|
||||
import buttondevteam.discordplugin.{DiscordConnectedPlayer, DiscordPlayer, DiscordPlugin, DiscordSenderBase}
|
||||
import buttondevteam.lib.player.TBMCPlayer
|
||||
import discord4j.common.util.Snowflake
|
||||
|
@ -8,52 +9,53 @@ import discord4j.core.`object`.entity.User
|
|||
import discord4j.core.`object`.entity.channel.{MessageChannel, PrivateChannel}
|
||||
import org.bukkit.Bukkit
|
||||
|
||||
import java.util
|
||||
import scala.collection.mutable.ListBuffer
|
||||
|
||||
object MCChatPrivate {
|
||||
/**
|
||||
* Used for messages in PMs (mcchat).
|
||||
*/
|
||||
private[mcchat] val lastmsgPerUser = new util.ArrayList[MCChatUtils.LastMsgData]
|
||||
private[mcchat] var lastmsgPerUser: ListBuffer[LastMsgData] = ListBuffer()
|
||||
|
||||
def privateMCChat(channel: MessageChannel, start: Boolean, user: User, dp: DiscordPlayer): Unit = {
|
||||
MCChatUtils.ConnectedSenders synchronized
|
||||
val mcp = dp.getAs(classOf[TBMCPlayer])
|
||||
if (mcp != null) { // If the accounts aren't connected, can't make a connected sender
|
||||
val p = Bukkit.getPlayer(mcp.getUUID)
|
||||
val op = Bukkit.getOfflinePlayer(mcp.getUUID)
|
||||
val mcm = ComponentManager.getIfEnabled(classOf[MinecraftChatModule])
|
||||
if (start) {
|
||||
val sender = DiscordConnectedPlayer.create(user, channel, mcp.getUUID, op.getName, mcm)
|
||||
MCChatUtils.addSender(MCChatUtils.ConnectedSenders, user, sender)
|
||||
MCChatUtils.LoggedInPlayers.put(mcp.getUUID, sender)
|
||||
if (p == null) { // Player is offline - If the player is online, that takes precedence
|
||||
MCChatUtils.callLoginEvents(sender)
|
||||
MCChatUtils.ConnectedSenders synchronized {
|
||||
val mcp = dp.getAs(classOf[TBMCPlayer])
|
||||
if (mcp != null) { // If the accounts aren't connected, can't make a connected sender
|
||||
val p = Bukkit.getPlayer(mcp.getUUID)
|
||||
val op = Bukkit.getOfflinePlayer(mcp.getUUID)
|
||||
val mcm = ComponentManager.getIfEnabled(classOf[MinecraftChatModule])
|
||||
if (start) {
|
||||
val sender = DiscordConnectedPlayer.create(user, channel, mcp.getUUID, op.getName, mcm)
|
||||
MCChatUtils.addSender(MCChatUtils.ConnectedSenders, user, sender)
|
||||
MCChatUtils.LoggedInPlayers.put(mcp.getUUID, sender)
|
||||
if (p == null) { // Player is offline - If the player is online, that takes precedence
|
||||
MCChatUtils.callLoginEvents(sender)
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
val sender = MCChatUtils.removeSender(MCChatUtils.ConnectedSenders, channel.getId, user)
|
||||
assert(sender != null)
|
||||
Bukkit.getScheduler.runTask(DiscordPlugin.plugin, () => {
|
||||
def foo(): Unit = {
|
||||
if ((p == null || p.isInstanceOf[DiscordSenderBase]) // Player is offline - If the player is online, that takes precedence
|
||||
&& sender.isLoggedIn) { //Don't call the quit event if login failed
|
||||
MCChatUtils.callLogoutEvent(sender, false) //The next line has to run *after* this one, so can't use the needsSync parameter
|
||||
else {
|
||||
val sender = MCChatUtils.removeSender(MCChatUtils.ConnectedSenders, channel.getId, user)
|
||||
assert(sender != null)
|
||||
Bukkit.getScheduler.runTask(DiscordPlugin.plugin, () => {
|
||||
def foo(): Unit = {
|
||||
if ((p == null || p.isInstanceOf[DiscordSenderBase]) // Player is offline - If the player is online, that takes precedence
|
||||
&& sender.isLoggedIn) { //Don't call the quit event if login failed
|
||||
MCChatUtils.callLogoutEvent(sender, false) //The next line has to run *after* this one, so can't use the needsSync parameter
|
||||
}
|
||||
|
||||
MCChatUtils.LoggedInPlayers.remove(sender.getUniqueId)
|
||||
sender.setLoggedIn(false)
|
||||
}
|
||||
|
||||
MCChatUtils.LoggedInPlayers.remove(sender.getUniqueId)
|
||||
sender.setLoggedIn(false)
|
||||
foo()
|
||||
}
|
||||
|
||||
foo()
|
||||
)
|
||||
}
|
||||
)
|
||||
// ---- PermissionsEx warning is normal on logout ----
|
||||
}
|
||||
// ---- PermissionsEx warning is normal on logout ----
|
||||
if (!start) MCChatUtils.lastmsgfromd.remove(channel.getId.asLong)
|
||||
if (start) lastmsgPerUser += new MCChatUtils.LastMsgData(channel, user) // Doesn't support group DMs
|
||||
else lastmsgPerUser.filterInPlace(_.channel.getId.asLong != channel.getId.asLong) //Remove
|
||||
}
|
||||
if (!start) MCChatUtils.lastmsgfromd.remove(channel.getId.asLong)
|
||||
if (start) lastmsgPerUser.add(new MCChatUtils.LastMsgData(channel, user)) // Doesn't support group DMs
|
||||
else lastmsgPerUser.removeIf((lmd: MCChatUtils.LastMsgData) => lmd.channel.getId.asLong == channel.getId.asLong)
|
||||
}
|
||||
|
||||
def isMinecraftChatEnabled(dp: DiscordPlayer): Boolean = isMinecraftChatEnabled(dp.getDiscordID)
|
||||
|
@ -64,11 +66,12 @@ object MCChatPrivate {
|
|||
}
|
||||
|
||||
def logoutAll(): Unit = {
|
||||
MCChatUtils.ConnectedSenders synchronized
|
||||
for (entry <- MCChatUtils.ConnectedSenders.entrySet) {
|
||||
for (valueEntry <- entry.getValue.entrySet) {
|
||||
if (MCChatUtils.getSender(MCChatUtils.OnlineSenders, valueEntry.getKey, valueEntry.getValue.getUser) == null) { //If the player is online then the fake player was already logged out
|
||||
MCChatUtils.callLogoutEvent(valueEntry.getValue, !Bukkit.isPrimaryThread)
|
||||
MCChatUtils.ConnectedSenders synchronized {
|
||||
for (entry <- asScala(MCChatUtils.ConnectedSenders.entrySet)) {
|
||||
for (valueEntry <- entry.getValue.entrySet) {
|
||||
if (MCChatUtils.getSender(MCChatUtils.OnlineSenders, valueEntry.getKey, valueEntry.getValue.getUser) == null) { //If the player is online then the fake player was already logged out
|
||||
MCChatUtils.callLogoutEvent(valueEntry.getValue, !Bukkit.isPrimaryThread)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,15 +30,16 @@ import java.util.function.Supplier
|
|||
import java.util.logging.Level
|
||||
import java.util.stream.{Collectors, Stream}
|
||||
import javax.annotation.Nullable
|
||||
import scala.jdk.javaapi.CollectionConverters.asScala
|
||||
|
||||
object MCChatUtils {
|
||||
/**
|
||||
* May contain P<DiscordID> as key for public chat
|
||||
*/
|
||||
val UnconnectedSenders = new ConcurrentHashMap[String, ConcurrentHashMap[Snowflake, DiscordSender]]
|
||||
val ConnectedSenders = new ConcurrentHashMap[String, ConcurrentHashMap[Snowflake, DiscordConnectedPlayer]]
|
||||
val OnlineSenders = new ConcurrentHashMap[String, ConcurrentHashMap[Snowflake, DiscordPlayerSender]]
|
||||
val LoggedInPlayers = new ConcurrentHashMap[UUID, DiscordConnectedPlayer]
|
||||
val UnconnectedSenders = asScala(new ConcurrentHashMap[String, ConcurrentHashMap[Snowflake, DiscordSender]])
|
||||
val ConnectedSenders = asScala(new ConcurrentHashMap[String, ConcurrentHashMap[Snowflake, DiscordConnectedPlayer]])
|
||||
val OnlineSenders = asScala(new ConcurrentHashMap[String, ConcurrentHashMap[Snowflake, DiscordPlayerSender]])
|
||||
val LoggedInPlayers = asScala(new ConcurrentHashMap[UUID, DiscordConnectedPlayer])
|
||||
@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
|
||||
|
@ -361,10 +362,15 @@ object MCChatUtils {
|
|||
private[mcchat] def callEventSync(event: Event) = Bukkit.getScheduler.runTask(DiscordPlugin.plugin, () => callEventExcludingSome(event))
|
||||
|
||||
class LastMsgData(val channel: MessageChannel, val user: User) {
|
||||
var message: String = null
|
||||
var message: Message = null
|
||||
var time = 0L
|
||||
var content: String = null
|
||||
var mcchannel: component.channel.Channel = null
|
||||
|
||||
protected def this(channel: MessageChannel, user: User, mcchannel: component.channel.Channel) = {
|
||||
this(channel, user)
|
||||
this.mcchannel = mcchannel
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
package buttondevteam.discordplugin.playerfaker;
|
||||
|
||||
import buttondevteam.discordplugin.DiscordSenderBase;
|
||||
import buttondevteam.discordplugin.IMCPlayer;
|
||||
import buttondevteam.discordplugin.mcchat.MinecraftChatModule;
|
||||
import buttondevteam.lib.TBMCCoreAPI;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class VCMDWrapper {
|
||||
@Getter //Needed to mock the player
|
||||
@Nullable
|
||||
private final Object listener;
|
||||
|
||||
/**
|
||||
* This constructor will only send raw vanilla messages to the sender in plain text.
|
||||
*
|
||||
* @param player The Discord sender player (the wrapper)
|
||||
*/
|
||||
public static <T extends DiscordSenderBase & IMCPlayer<T>> Object createListener(T player, MinecraftChatModule module) {
|
||||
return createListener(player, null, module);
|
||||
}
|
||||
|
||||
/**
|
||||
* This constructor will send both raw vanilla messages to the sender in plain text and forward the raw message to the provided player.
|
||||
*
|
||||
* @param player The Discord sender player (the wrapper)
|
||||
* @param bukkitplayer The Bukkit player to send the raw message to
|
||||
* @param module The Minecraft chat module
|
||||
*/
|
||||
public static <T extends DiscordSenderBase & IMCPlayer<T>> Object createListener(T player, Player bukkitplayer, MinecraftChatModule module) {
|
||||
try {
|
||||
Object ret;
|
||||
String mcpackage = Bukkit.getServer().getClass().getPackage().getName();
|
||||
if (mcpackage.contains("1_12"))
|
||||
ret = new VanillaCommandListener<>(player, bukkitplayer);
|
||||
else if (mcpackage.contains("1_14"))
|
||||
ret = new VanillaCommandListener14<>(player, bukkitplayer);
|
||||
else if (mcpackage.contains("1_15") || mcpackage.contains("1_16"))
|
||||
ret = VanillaCommandListener15.create(player, bukkitplayer); //bukkitplayer may be null but that's fine
|
||||
else
|
||||
ret = null;
|
||||
if (ret == null)
|
||||
compatWarning(module);
|
||||
return ret;
|
||||
} catch (NoClassDefFoundError | Exception e) {
|
||||
compatWarning(module);
|
||||
TBMCCoreAPI.SendException("Failed to create vanilla command listener", e, module);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void compatWarning(MinecraftChatModule module) {
|
||||
module.logWarn("Vanilla commands won't be available from Discord due to a compatibility error. Disable vanilla command support to remove this message.");
|
||||
}
|
||||
|
||||
static boolean compatResponse(DiscordSenderBase dsender) {
|
||||
dsender.sendMessage("Vanilla commands are not supported on this Minecraft version.");
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package buttondevteam.discordplugin.playerfaker
|
||||
|
||||
import buttondevteam.discordplugin.{DiscordSenderBase, IMCPlayer}
|
||||
import buttondevteam.discordplugin.mcchat.MinecraftChatModule
|
||||
import buttondevteam.lib.TBMCCoreAPI
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
object VCMDWrapper {
|
||||
/**
|
||||
* This constructor will only send raw vanilla messages to the sender in plain text.
|
||||
*
|
||||
* @param player The Discord sender player (the wrapper)
|
||||
*/
|
||||
def createListener[T <: DiscordSenderBase with IMCPlayer[T]](player: T, module: MinecraftChatModule): AnyRef =
|
||||
createListener(player, null, module)
|
||||
|
||||
/**
|
||||
* This constructor will send both raw vanilla messages to the sender in plain text and forward the raw message to the provided player.
|
||||
*
|
||||
* @param player The Discord sender player (the wrapper)
|
||||
* @param bukkitplayer The Bukkit player to send the raw message to
|
||||
* @param module The Minecraft chat module
|
||||
*/
|
||||
def createListener[T <: DiscordSenderBase with IMCPlayer[T]](player: T, bukkitplayer: Player, module: MinecraftChatModule): AnyRef = try {
|
||||
var ret: AnyRef = null
|
||||
val mcpackage = Bukkit.getServer.getClass.getPackage.getName
|
||||
if (mcpackage.contains("1_12")) ret = new VanillaCommandListener[T](player, bukkitplayer)
|
||||
else if (mcpackage.contains("1_14")) ret = new VanillaCommandListener14[T](player, bukkitplayer)
|
||||
else if (mcpackage.contains("1_15") || mcpackage.contains("1_16")) ret = VanillaCommandListener15.create(player, bukkitplayer) //bukkitplayer may be null but that's fine
|
||||
else ret = null
|
||||
if (ret == null) compatWarning(module)
|
||||
ret
|
||||
} catch {
|
||||
case e@(_: NoClassDefFoundError | _: Exception) =>
|
||||
compatWarning(module)
|
||||
TBMCCoreAPI.SendException("Failed to create vanilla command listener", e, module)
|
||||
null
|
||||
}
|
||||
|
||||
private def compatWarning(module: MinecraftChatModule): Unit =
|
||||
module.logWarn("Vanilla commands won't be available from Discord due to a compatibility error. Disable vanilla command support to remove this message.")
|
||||
|
||||
private[playerfaker] def compatResponse(dsender: DiscordSenderBase) = {
|
||||
dsender.sendMessage("Vanilla commands are not supported on this Minecraft version.")
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
class VCMDWrapper(private val listener: AnyRef) {
|
||||
@javax.annotation.Nullable def getListener: AnyRef = listener
|
||||
|
||||
//Needed to mock the player @Nullable
|
||||
}
|
Loading…
Reference in a new issue