Attempted to update to latest API, lots of errors (9 remains)
- Removed Reactor Scala extensions in an attempt to get this thing to compile but it doesn't seem to help - Removed heavily version-dependent stuff
This commit is contained in:
parent
8d63394b55
commit
f909eb4779
40 changed files with 274 additions and 1405 deletions
12
build.sbt
12
build.sbt
|
@ -12,25 +12,23 @@ scalaVersion := "3.1.0"
|
|||
|
||||
resolvers += "spigot-repo" at "https://hub.spigotmc.org/nexus/content/repositories/snapshots/"
|
||||
resolvers += "jitpack.io" at "https://jitpack.io"
|
||||
resolvers += "paper-repo" at "https://papermc.io/repo/repository/maven-public/"
|
||||
resolvers += Resolver.mavenLocal
|
||||
|
||||
// assembly / assemblyOption := (assembly / assemblyOption).value.copy(includeScala = false)
|
||||
|
||||
libraryDependencies ++= Seq(
|
||||
"org.spigotmc" % "spigot-api" % "1.12.2-R0.1-SNAPSHOT" % Provided,
|
||||
"org.spigotmc" % "spigot" % "1.12.2-R0.1-SNAPSHOT" % Provided,
|
||||
"org.spigotmc." % "spigot" % "1.14.4-R0.1-SNAPSHOT" % Provided,
|
||||
"com.destroystokyo.paper" % "paper" % "1.16.3-R0.1-SNAPSHOT" % Provided,
|
||||
"org.spigotmc" % "spigot" % "1.19.4-R0.1-SNAPSHOT" % Provided,
|
||||
"io.papermc.paper" % "paper-api" % "1.19.4-R0.1-SNAPSHOT" % Provided,
|
||||
|
||||
"com.discord4j" % "discord4j-core" % "3.2.2",
|
||||
"org.slf4j" % "slf4j-jdk14" % "1.7.36",
|
||||
"com.vdurmont" % "emoji-java" % "5.1.1",
|
||||
"org.mockito" % "mockito-core" % "4.6.1",
|
||||
"io.projectreactor" % "reactor-scala-extensions_2.13" % "0.8.0",
|
||||
// https://mvnrepository.com/artifact/org.immutables/value
|
||||
"org.immutables" % "value" % "2.9.0" % "provided",
|
||||
|
||||
"com.github.TBMCPlugins.ChromaCore" % "Chroma-Core" % "v1.0.0" % Provided,
|
||||
"com.github.TBMCPlugins.ChromaCore" % "Chroma-Core" % "v2.0.0-SNAPSHOT" % Provided,
|
||||
"net.ess3" % "EssentialsX" % "2.17.1" % Provided,
|
||||
"net.luckperms" % "api" % "5.4" % Provided,
|
||||
)
|
||||
|
@ -141,3 +139,5 @@ saveConfigComments := {
|
|||
}
|
||||
|
||||
Compile / resourceGenerators += saveConfigComments
|
||||
//scalacOptions ++= Seq("-release", "17", "--verbose")
|
||||
scalacOptions ++= Seq("-release", "17")
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
lombok.var.flagUsage = ALLOW
|
|
@ -1,2 +1,2 @@
|
|||
sbt.version=1.5.8
|
||||
sbt.version=1.8.2
|
||||
scala.version=3.0.0
|
|
@ -3,4 +3,4 @@
|
|||
|
||||
resolvers += Resolver.mavenLocal
|
||||
|
||||
libraryDependencies += "org.spigotmc" % "spigot-api" % "1.12.2-R0.1-SNAPSHOT"
|
||||
libraryDependencies += "org.spigotmc" % "spigot-api" % "1.19.4-R0.1-SNAPSHOT"
|
||||
|
|
|
@ -4,7 +4,7 @@ import buttondevteam.discordplugin.ChannelconBroadcast.ChannelconBroadcast
|
|||
import buttondevteam.discordplugin.mcchat.MCChatUtils
|
||||
import discord4j.core.`object`.entity.Message
|
||||
import discord4j.core.`object`.entity.channel.MessageChannel
|
||||
import reactor.core.scala.publisher.SMono
|
||||
import reactor.core.publisher.Mono
|
||||
|
||||
import javax.annotation.Nullable
|
||||
|
||||
|
@ -20,7 +20,7 @@ object ChromaBot {
|
|||
*
|
||||
* @param message The message to send, duh (use [[MessageChannel.createMessage]])
|
||||
*/
|
||||
def sendMessage(message: SMono[MessageChannel] => SMono[Message]): Unit =
|
||||
def sendMessage(message: Mono[MessageChannel] => Mono[Message]): Unit =
|
||||
MCChatUtils.forPublicPrivateChat(message).subscribe()
|
||||
|
||||
/**
|
||||
|
@ -29,7 +29,7 @@ object ChromaBot {
|
|||
* @param message The message to send, duh
|
||||
* @param toggle The toggle type for channelcon
|
||||
*/
|
||||
def sendMessageCustomAsWell(message: SMono[MessageChannel] => SMono[Message], @Nullable toggle: ChannelconBroadcast): Unit =
|
||||
def sendMessageCustomAsWell(message: Mono[MessageChannel] => Mono[Message], @Nullable toggle: ChannelconBroadcast): Unit =
|
||||
MCChatUtils.forCustomAndAllMCChat(message.apply, toggle, hookmsg = false).subscribe()
|
||||
|
||||
def updatePlayerList(): Unit =
|
||||
|
|
|
@ -3,11 +3,11 @@ package buttondevteam.discordplugin
|
|||
import buttondevteam.lib.TBMCCoreAPI
|
||||
import buttondevteam.lib.architecture.{Component, ConfigData, IHaveConfig, ReadOnlyConfigData}
|
||||
import discord4j.common.util.Snowflake
|
||||
import discord4j.core.`object`.entity.channel.MessageChannel
|
||||
import discord4j.core.`object`.entity.channel.{Channel, MessageChannel}
|
||||
import discord4j.core.`object`.entity.{Guild, Message, Role}
|
||||
import discord4j.core.spec.EmbedCreateSpec
|
||||
import discord4j.core.spec.legacy.{LegacyEmbedCreateSpec, LegacySpec}
|
||||
import reactor.core.publisher.{Flux, Mono}
|
||||
import reactor.core.scala.publisher.{SFlux, SMono}
|
||||
|
||||
import java.util
|
||||
import java.util.Comparator
|
||||
|
@ -19,8 +19,8 @@ object DPUtils {
|
|||
private val URL_PATTERN = Pattern.compile("https?://\\S*")
|
||||
private val FORMAT_PATTERN = Pattern.compile("[*_~]")
|
||||
|
||||
def embedWithHead(ecs: LegacyEmbedCreateSpec, displayname: String, playername: String, profileUrl: String): LegacyEmbedCreateSpec =
|
||||
ecs.setAuthor(displayname, profileUrl, "https://minotar.net/avatar/" + playername + "/32.png")
|
||||
def embedWithHead(ecs: EmbedCreateSpec.Builder, displayname: String, playername: String, profileUrl: String): EmbedCreateSpec.Builder =
|
||||
ecs.author(displayname, profileUrl, s"https://minotar.net/avatar/$playername/32.png")
|
||||
|
||||
/**
|
||||
* Removes §[char] colour codes from strings & escapes them for Discord <br>
|
||||
|
@ -68,34 +68,26 @@ object DPUtils {
|
|||
else DiscordPlugin.plugin.getLogger
|
||||
}
|
||||
|
||||
def channelData(config: IHaveConfig, key: String): ReadOnlyConfigData[SMono[MessageChannel]] =
|
||||
config.getReadOnlyDataPrimDef(key, 0L, (id: Any) =>
|
||||
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 channelData(config: IHaveConfig, key: String): ConfigData[Mono[MessageChannel]] =
|
||||
config.getData(key, id => getMessageChannel(key, Snowflake.of(id.asInstanceOf[Long])),
|
||||
(_: Mono[MessageChannel]) => 0L, 0L, true) //We can afford to search for the channel in the cache once (instead of using mainServer)
|
||||
|
||||
def roleData(config: IHaveConfig, key: String, defName: String): ReadOnlyConfigData[SMono[Role]] =
|
||||
roleData(config, key, defName, SMono.just(DiscordPlugin.mainServer))
|
||||
def roleData(config: IHaveConfig, key: String, defName: String): ConfigData[Mono[Role]] =
|
||||
roleData(config, key, defName, Mono.just(DiscordPlugin.mainServer))
|
||||
|
||||
/**
|
||||
* Needs to be a [[ConfigData]] for checking if it's set
|
||||
*/
|
||||
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): SMono[Role] = {
|
||||
def roleData(config: IHaveConfig, key: String, defName: String, guild: Mono[Guild]): ConfigData[Mono[Role]] = config.getData(key, name => {
|
||||
if (!name.isInstanceOf[String] || name.asInstanceOf[String].isEmpty) Mono.empty[Role]
|
||||
else guild.flatMapMany(_.getRoles).filter(_.getName == name).onErrorResume(e => {
|
||||
getLogger.warning("Failed to get role data for " + key + "=" + name + " - " + e.getMessage)
|
||||
SMono.empty[Role]
|
||||
}
|
||||
|
||||
foo(e)
|
||||
Mono.empty[Role]
|
||||
}).next
|
||||
}
|
||||
}, _ => defName, defName, true)
|
||||
|
||||
foo(name)
|
||||
}, (_: 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)
|
||||
def snowflakeData(config: IHaveConfig, key: String, defID: Long): ConfigData[Snowflake] =
|
||||
config.getData(key, id => Snowflake.of(id.asInstanceOf[Long]), _.asLong, defID, true)
|
||||
|
||||
/**
|
||||
* Mentions the <b>bot channel</b>. Useful for help texts.
|
||||
|
@ -132,7 +124,7 @@ object DPUtils {
|
|||
*/
|
||||
def disableIfConfigErrorRes(@Nullable component: Component[DiscordPlugin], config: ConfigData[_], result: Any): Boolean = {
|
||||
//noinspection ConstantConditions
|
||||
if (result == null || (result.isInstanceOf[SMono[_]] && !result.asInstanceOf[SMono[_]].hasElement.block())) {
|
||||
if (result == null || (result.isInstanceOf[Mono[_]] && !result.asInstanceOf[Mono[_]].hasElement.block())) {
|
||||
var path: String = null
|
||||
try {
|
||||
if (component != null) Component.setComponentEnabled(component, false)
|
||||
|
@ -152,26 +144,26 @@ object DPUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Send a response in the form of "@User, message". Use SMono.empty() if you don't have a channel object.
|
||||
* Send a response in the form of "@User, message". Use Mono.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): SMono[Message] = {
|
||||
val ch = if (channel == null) SMono(original.getChannel)
|
||||
else SMono.just(channel)
|
||||
def reply(original: Message, @Nullable channel: MessageChannel, message: String): Mono[Message] = {
|
||||
val ch = if (channel == null) original.getChannel
|
||||
else Mono.just(channel)
|
||||
reply(original, ch, message)
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #reply(Message, MessageChannel, String)
|
||||
*/
|
||||
def reply(original: Message, ch: SMono[MessageChannel], message: String): SMono[Message] =
|
||||
ch.flatMap(channel => SMono(channel.createMessage((if (original.getAuthor.isPresent)
|
||||
def reply(original: Message, ch: Mono[MessageChannel], message: String): Mono[Message] =
|
||||
ch.flatMap(channel => channel.createMessage((if (original.getAuthor.isPresent)
|
||||
original.getAuthor.get.getMention + ", "
|
||||
else "") + message)))
|
||||
else "") + message))
|
||||
|
||||
def nickMention(userId: Snowflake): String = "<@!" + userId.asString + ">"
|
||||
|
||||
|
@ -184,31 +176,19 @@ object DPUtils {
|
|||
* @param id The channel ID
|
||||
* @return A message channel
|
||||
*/
|
||||
def getMessageChannel(key: String, id: Snowflake): SMono[MessageChannel] = {
|
||||
if (id.asLong == 0L) return SMono.empty[MessageChannel]
|
||||
def getMessageChannel(key: String, id: Snowflake): Mono[MessageChannel] = {
|
||||
if (id.asLong == 0L) return Mono.empty[MessageChannel]
|
||||
|
||||
SMono(DiscordPlugin.dc.getChannelById(id)).onErrorResume(e => {
|
||||
def foo(e: Throwable) = {
|
||||
getLogger.warning("Failed to get channel data for " + key + "=" + id + " - " + e.getMessage)
|
||||
SMono.empty
|
||||
DiscordPlugin.dc.getChannelById(id).onErrorResume(e => {
|
||||
getLogger.warning(s"Failed to get channel data for $key=$id - ${e.getMessage}")
|
||||
Mono.empty[Channel]
|
||||
}).filter(ch => ch.isInstanceOf[MessageChannel]).cast(classOf[MessageChannel]])
|
||||
}
|
||||
|
||||
foo(e)
|
||||
}).filter(ch => ch.isInstanceOf[MessageChannel]).cast[MessageChannel]
|
||||
}
|
||||
|
||||
def getMessageChannel(config: ConfigData[Snowflake]): SMono[MessageChannel] =
|
||||
def getMessageChannel(config: ConfigData[Snowflake]): Mono[MessageChannel] =
|
||||
getMessageChannel(config.getPath, config.get)
|
||||
|
||||
def ignoreError[T](mono: SMono[T]): SMono[T] = mono.onErrorResume((_: Throwable) => SMono.empty)
|
||||
|
||||
implicit class MonoExtensions[T](mono: Mono[T]) {
|
||||
def ^^(): SMono[T] = SMono(mono)
|
||||
}
|
||||
|
||||
implicit class FluxExtensions[T](flux: Flux[T]) {
|
||||
def ^^(): SFlux[T] = SFlux(flux)
|
||||
}
|
||||
def ignoreError[T](mono: Mono[T]): Mono[T] = mono.onErrorResume((_: Throwable) => Mono.empty)
|
||||
|
||||
implicit class SpecExtensions[T <: LegacySpec[_]](spec: T) {
|
||||
def ^^(): Unit = ()
|
||||
|
|
|
@ -32,12 +32,12 @@ import org.bukkit.command.CommandSender
|
|||
import org.bukkit.configuration.file.YamlConfiguration
|
||||
import org.mockito.internal.util.MockUtil
|
||||
import reactor.core.Disposable
|
||||
import reactor.core.scala.publisher.SMono
|
||||
import reactor.core.scala.publisher.scalaOption2JavaOptional
|
||||
import reactor.core.publisher.Mono
|
||||
|
||||
import java.io.File
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.util.Optional
|
||||
import scala.jdk.OptionConverters.*
|
||||
|
||||
@ButtonPlugin.ConfigOpts(disableConfigGen = true) object DiscordPlugin {
|
||||
private[discordplugin] var dc: GatewayDiscordClient = null
|
||||
|
@ -68,28 +68,24 @@ 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): Option[Guild] = { //It attempts to get the default as well
|
||||
private def mainServer = getIConfig.getData("mainServer", id => { //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: Option[Guild]) => (g.map(_.getId.asLong): Option[Long]).getOrElse(0L))
|
||||
else DiscordPlugin.dc.getGuildById(Snowflake.of(id.asInstanceOf[Long]))
|
||||
.onErrorResume(t => {
|
||||
getLogger.warning("Failed to get guild: " + t.getMessage)
|
||||
Mono.empty
|
||||
}).blockOptional().toScala
|
||||
}, g => g.map(_.getId.asLong).getOrElse(0L), 0L, true)
|
||||
|
||||
/**
|
||||
* The (bot) channel to use for Discord commands like /role.
|
||||
*/
|
||||
var commandChannel: ReadOnlyConfigData[Snowflake] = DPUtils.snowflakeData(getIConfig, "commandChannel", 0L)
|
||||
var commandChannel: ConfigData[Snowflake] = DPUtils.snowflakeData(getIConfig, "commandChannel", 0L)
|
||||
/**
|
||||
* The role that allows using mod-only Discord commands.
|
||||
* If empty (''), then it will only allow for the owner.
|
||||
*/
|
||||
var modRole: ReadOnlyConfigData[SMono[Role]] = null
|
||||
var modRole: ConfigData[Mono[Role]] = null
|
||||
/**
|
||||
* The invite link to show by /discord invite. If empty, it defaults to the first invite if the bot has access.
|
||||
*/
|
||||
|
@ -189,11 +185,10 @@ import java.util.Optional
|
|||
CommonListeners.register(DiscordPlugin.dc.getEventDispatcher)
|
||||
TBMCCoreAPI.RegisterEventsForExceptions(new MCListener, this)
|
||||
TBMCCoreAPI.RegisterUserClass(classOf[DiscordPlayer], () => new DiscordPlayer)
|
||||
ChromaGamerBase.addConverter((sender: CommandSender) => sender match {
|
||||
case dsender: DiscordSenderBase => Some(dsender.getChromaUser)
|
||||
case _ => None
|
||||
})
|
||||
IHaveConfig.pregenConfig(this, null)
|
||||
ChromaGamerBase.addConverter {
|
||||
case dsender: DiscordSenderBase => Some(dsender.getChromaUser).toJava
|
||||
case _ => None.toJava
|
||||
}
|
||||
ChromaBot.enabled = true //Initialize ChromaBot
|
||||
Component.registerComponent(this, new GeneralEventBroadcasterModule)
|
||||
Component.registerComponent(this, new MinecraftChatModule)
|
||||
|
|
|
@ -7,7 +7,7 @@ import buttondevteam.lib.architecture.{Component, ComponentMetadata}
|
|||
import buttondevteam.lib.player.ChromaGamerBase
|
||||
import com.google.gson.JsonParser
|
||||
import discord4j.core.`object`.entity.channel.MessageChannel
|
||||
import reactor.core.scala.publisher.SMono
|
||||
import reactor.core.publisher.Mono
|
||||
|
||||
import scala.annotation.tailrec
|
||||
import scala.collection.mutable
|
||||
|
@ -86,8 +86,8 @@ import scala.collection.mutable
|
|||
}
|
||||
}
|
||||
|
||||
def sendMsg(ch: SMono[MessageChannel], msg: String) =
|
||||
ch.asJava().flatMap(c => c.createMessage(msg)).flatMap(_.pin).subscribe()
|
||||
def sendMsg(ch: Mono[MessageChannel], msg: String) =
|
||||
ch.flatMap(c => c.createMessage(msg)).flatMap(_.pin).subscribe()
|
||||
|
||||
if (msgsb.nonEmpty) sendMsg(channel.get(), msgsb.toString())
|
||||
if (modmsgsb.nonEmpty) sendMsg(modChannel.get(), modmsgsb.toString())
|
||||
|
|
|
@ -16,9 +16,7 @@ import buttondevteam.lib.architecture.{Component, ComponentMetadata}
|
|||
|
||||
@ComponentMetadata(enabledByDefault = false) class GeneralEventBroadcasterModule extends Component[DiscordPlugin] {
|
||||
override protected def enable(): Unit = try {
|
||||
PlayerListWatcher.hookUpDown(true, this)
|
||||
log("Finished hooking into the player list")
|
||||
GeneralEventBroadcasterModule.hooked = true
|
||||
// TODO: Removed for now
|
||||
} catch {
|
||||
case e: Exception =>
|
||||
TBMCCoreAPI.SendException("Error while hacking the player list! Disable this module if you're on an incompatible version.", e, this)
|
||||
|
@ -28,9 +26,6 @@ import buttondevteam.lib.architecture.{Component, ComponentMetadata}
|
|||
|
||||
override protected def disable(): Unit = try {
|
||||
if (!GeneralEventBroadcasterModule.hooked) return ()
|
||||
if (PlayerListWatcher.hookUpDown(false, this)) log("Finished unhooking the player list!")
|
||||
else log("Didn't have the player list hooked.")
|
||||
GeneralEventBroadcasterModule.hooked = false
|
||||
} catch {
|
||||
case e: Exception =>
|
||||
TBMCCoreAPI.SendException("Error while hacking the player list!", e, this)
|
||||
|
|
|
@ -1,168 +0,0 @@
|
|||
package buttondevteam.discordplugin.broadcaster
|
||||
|
||||
import buttondevteam.discordplugin.mcchat.MCChatUtils
|
||||
import buttondevteam.discordplugin.mcchat.playerfaker.DelegatingMockMaker
|
||||
import buttondevteam.lib.TBMCCoreAPI
|
||||
import org.bukkit.Bukkit
|
||||
import org.mockito.Mockito
|
||||
import org.mockito.internal.creation.bytebuddy.SubclassByteBuddyMockMaker
|
||||
import org.mockito.invocation.InvocationOnMock
|
||||
import org.mockito.stubbing.Answer
|
||||
|
||||
import java.lang.invoke.{MethodHandle, MethodHandles}
|
||||
import java.lang.reflect.{Constructor, Method, Modifier}
|
||||
import java.util.UUID
|
||||
|
||||
object PlayerListWatcher {
|
||||
private var plist: AnyRef = null
|
||||
private var mock: AnyRef = null
|
||||
private var fHandle: MethodHandle = null //Handle for PlayerList.f(EntityPlayer) - Only needed for 1.16
|
||||
@throws[Exception]
|
||||
private[broadcaster] def hookUpDown(up: Boolean, module: GeneralEventBroadcasterModule): Boolean = {
|
||||
val csc = Bukkit.getServer.getClass
|
||||
val conf = csc.getDeclaredField("console")
|
||||
conf.setAccessible(true)
|
||||
val server = conf.get(Bukkit.getServer)
|
||||
val nms = server.getClass.getPackage.getName
|
||||
val dplc = Class.forName(nms + ".DedicatedPlayerList")
|
||||
val currentPL = server.getClass.getMethod("getPlayerList").invoke(server)
|
||||
if (up) {
|
||||
if (currentPL eq mock) {
|
||||
module.logWarn("Player list already mocked!")
|
||||
return false
|
||||
}
|
||||
DelegatingMockMaker.getInstance.setMockMaker(new SubclassByteBuddyMockMaker)
|
||||
val icbcl = Class.forName(nms + ".IChatBaseComponent")
|
||||
var sendMessageTemp: Method = null
|
||||
try sendMessageTemp = server.getClass.getMethod("sendMessage", icbcl, classOf[UUID])
|
||||
catch {
|
||||
case e: NoSuchMethodException =>
|
||||
sendMessageTemp = server.getClass.getMethod("sendMessage", icbcl)
|
||||
}
|
||||
val sendMessageMethod = sendMessageTemp
|
||||
val cmtcl = Class.forName(nms + ".ChatMessageType")
|
||||
val systemType = cmtcl.getDeclaredField("SYSTEM").get(null)
|
||||
val chatType = cmtcl.getDeclaredField("CHAT").get(null)
|
||||
val obc = csc.getPackage.getName
|
||||
val ccmcl = Class.forName(obc + ".util.CraftChatMessage")
|
||||
val fixComponent = ccmcl.getMethod("fixComponent", icbcl)
|
||||
val ppoc = Class.forName(nms + ".PacketPlayOutChat")
|
||||
var ppocCTemp: Constructor[_] = null
|
||||
try ppocCTemp = ppoc.getConstructor(icbcl, cmtcl, classOf[UUID])
|
||||
catch {
|
||||
case _: Exception =>
|
||||
ppocCTemp = ppoc.getConstructor(icbcl, cmtcl)
|
||||
}
|
||||
val ppocC = ppocCTemp
|
||||
val sendAllMethod = dplc.getMethod("sendAll", Class.forName(nms + ".Packet"))
|
||||
var tpt: Method = null
|
||||
try tpt = icbcl.getMethod("toPlainText")
|
||||
catch {
|
||||
case _: NoSuchMethodException =>
|
||||
tpt = icbcl.getMethod("getString")
|
||||
}
|
||||
val toPlainText = tpt
|
||||
val sysb = Class.forName(nms + ".SystemUtils").getField("b")
|
||||
//Find the original method without overrides
|
||||
var lookupConstructor: Constructor[MethodHandles.Lookup] = null
|
||||
if (nms.contains("1_16")) {
|
||||
lookupConstructor = classOf[MethodHandles.Lookup].getDeclaredConstructor(classOf[Class[_]])
|
||||
lookupConstructor.setAccessible(true) //Create lookup with a given class instead of caller
|
||||
}
|
||||
else lookupConstructor = null
|
||||
mock = Mockito.mock(dplc, Mockito.withSettings.defaultAnswer(new Answer[AnyRef]() { // Cannot call super constructor
|
||||
@throws[Throwable]
|
||||
override def answer(invocation: InvocationOnMock): AnyRef = {
|
||||
val method = invocation.getMethod
|
||||
if (!(method.getName == "sendMessage")) {
|
||||
if (method.getName == "sendAll") {
|
||||
sendAll(invocation.getArgument(0))
|
||||
return null
|
||||
}
|
||||
//In 1.16 it passes a reference to the player list to advancement data for each player
|
||||
if (nms.contains("1_16") && method.getName == "f" && method.getParameterCount > 0 && method.getParameterTypes()(0).getSimpleName == "EntityPlayer") {
|
||||
method.setAccessible(true)
|
||||
if (fHandle == null) {
|
||||
assert(lookupConstructor != null)
|
||||
val lookup = lookupConstructor.newInstance(mock.getClass)
|
||||
fHandle = lookup.unreflectSpecial(method, mock.getClass) //Special: super.method()
|
||||
}
|
||||
return fHandle.invoke(mock, invocation.getArgument(0)) //Invoke with our instance, so it passes that to advancement data, we have the fields as well
|
||||
}
|
||||
return method.invoke(plist, invocation.getArguments)
|
||||
}
|
||||
val args = invocation.getArguments
|
||||
val params = method.getParameterTypes
|
||||
if (params.isEmpty) {
|
||||
TBMCCoreAPI.SendException("Found a strange method", new Exception("Found a sendMessage() method without arguments."), module)
|
||||
return null
|
||||
}
|
||||
if (params(0).getSimpleName == "IChatBaseComponent[]") for (arg <- args(0).asInstanceOf[Array[AnyRef]]) {
|
||||
sendMessage(arg, system = true)
|
||||
}
|
||||
else if (params(0).getSimpleName == "IChatBaseComponent") if (params.length > 1 && params(1).getSimpleName.equalsIgnoreCase("boolean")) sendMessage(args(0), args(1).asInstanceOf[Boolean])
|
||||
else sendMessage(args(0), system = true)
|
||||
else TBMCCoreAPI.SendException("Found a method with interesting params", new Exception("Found a sendMessage(" + params(0).getSimpleName + ") method"), module)
|
||||
null
|
||||
}
|
||||
|
||||
private
|
||||
|
||||
def sendMessage(chatComponent: Any, system: Boolean) = try { //Converted to use reflection
|
||||
if (sendMessageMethod.getParameterCount == 2) sendMessageMethod.invoke(server, chatComponent, sysb.get(null))
|
||||
else sendMessageMethod.invoke(server, chatComponent)
|
||||
val chatmessagetype = if (system) systemType
|
||||
else chatType
|
||||
// CraftBukkit start - we run this through our processor first so we can get web links etc
|
||||
val comp = fixComponent.invoke(null, chatComponent)
|
||||
val packet = if (ppocC.getParameterCount == 3) ppocC.newInstance(comp, chatmessagetype, sysb.get(null))
|
||||
else ppocC.newInstance(comp, chatmessagetype)
|
||||
this.sendAll(packet)
|
||||
} catch {
|
||||
case e: Exception =>
|
||||
TBMCCoreAPI.SendException("An error occurred while passing a vanilla message through the player list", e, module)
|
||||
}
|
||||
|
||||
private
|
||||
|
||||
def sendAll(packet: Any) = try { // Some messages get sent by directly constructing a packet
|
||||
sendAllMethod.invoke(plist, packet)
|
||||
if (packet.getClass eq ppoc) {
|
||||
val msgf = ppoc.getDeclaredField("a")
|
||||
msgf.setAccessible(true)
|
||||
MCChatUtils.forPublicPrivateChat(MCChatUtils.send(toPlainText.invoke(msgf.get(packet)).asInstanceOf[String])).subscribe()
|
||||
}
|
||||
} catch {
|
||||
case e: Exception =>
|
||||
TBMCCoreAPI.SendException("Failed to broadcast message sent to all players - hacking failed.", e, module)
|
||||
}
|
||||
}).stubOnly).asInstanceOf
|
||||
plist = currentPL
|
||||
var plc = dplc
|
||||
while ( {
|
||||
plc != null
|
||||
}) { //Set all fields
|
||||
for (f <- plc.getDeclaredFields) {
|
||||
f.setAccessible(true)
|
||||
val modf = f.getClass.getDeclaredField("modifiers")
|
||||
modf.setAccessible(true)
|
||||
modf.set(f, f.getModifiers & ~Modifier.FINAL)
|
||||
f.set(mock, f.get(plist))
|
||||
}
|
||||
plc = plc.getSuperclass
|
||||
}
|
||||
}
|
||||
try server.getClass.getMethod("a", dplc).invoke(server, if (up) mock
|
||||
else plist)
|
||||
catch {
|
||||
case e: NoSuchMethodException =>
|
||||
server.getClass.getMethod("a", Class.forName(server.getClass.getPackage.getName + ".PlayerList")).invoke(server, if (up) mock
|
||||
else plist)
|
||||
}
|
||||
val pllf = csc.getDeclaredField("playerList")
|
||||
pllf.setAccessible(true)
|
||||
pllf.set(Bukkit.getServer, if (up) mock
|
||||
else plist)
|
||||
true
|
||||
}
|
||||
}
|
|
@ -8,13 +8,13 @@ import discord4j.discordjson.json.{ApplicationCommandOptionData, ApplicationComm
|
|||
|
||||
import java.lang.reflect.Method
|
||||
|
||||
class Command2DC extends Command2[ICommand2DC, Command2DCSender] {
|
||||
class Command2DC extends Command2[ICommand2DC, Command2DCSender]('/', false) {
|
||||
override def registerCommand(command: ICommand2DC): Unit = {
|
||||
registerCommand(command, DiscordPlugin.dc.getApplicationInfo.block().getId.asLong())
|
||||
}
|
||||
|
||||
def registerCommand(command: ICommand2DC, appId: Long, guildId: Option[Long] = None): Unit = {
|
||||
super.registerCommand(command, DiscordPlugin.getPrefix) //Needs to be configurable for the helps
|
||||
super.registerCommand(command) //Needs to be configurable for the helps
|
||||
val greetCmdRequest = ApplicationCommandRequest.builder()
|
||||
.name(command.getCommandPath) //TODO: Main path
|
||||
.description("Connect your Minecraft account.") //TODO: Description
|
||||
|
|
|
@ -7,10 +7,10 @@ import discord4j.core.`object`.entity.{Member, Message, User}
|
|||
import discord4j.core.event.domain.interaction.ChatInputInteractionEvent
|
||||
|
||||
import java.util.Optional
|
||||
import reactor.core.scala.publisher.javaOptional2ScalaOption;
|
||||
import scala.jdk.OptionConverters._
|
||||
|
||||
class Command2DCSender(val event: ChatInputInteractionEvent) extends Command2Sender {
|
||||
val authorAsMember: Option[Member] = event.getInteraction.getMember
|
||||
val authorAsMember: Option[Member] = event.getInteraction.getMember.toScala
|
||||
val author: User = event.getInteraction.getUser
|
||||
override def sendMessage(message: String): Unit = {
|
||||
if (message.isEmpty) return ()
|
||||
|
@ -20,5 +20,5 @@ class Command2DCSender(val event: ChatInputInteractionEvent) extends Command2Sen
|
|||
|
||||
override def sendMessage(message: Array[String]): Unit = sendMessage(String.join("\n", message: _*))
|
||||
|
||||
override def getName: String = authorAsMember.flatMap(_.getNickname).getOrElse(author.getUsername)
|
||||
override def getName: String = authorAsMember.flatMap(_.getNickname.toScala).getOrElse(author.getUsername)
|
||||
}
|
|
@ -5,22 +5,23 @@ 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.scala.publisher.SMono
|
||||
import reactor.core.publisher.Mono
|
||||
import scala.jdk.OptionConverters._
|
||||
|
||||
@CommandClass(helpText = Array("Switches debug mode."))
|
||||
class DebugCommand extends ICommand2DC {
|
||||
@Command2.Subcommand
|
||||
override def `def`(sender: Command2DCSender): Boolean = {
|
||||
SMono.justOrEmpty(sender.authorAsMember)
|
||||
Mono.justOrEmpty(sender.authorAsMember.orNull)
|
||||
.switchIfEmpty(Option(sender.author) //Support DMs
|
||||
.map((u: User) => SMono(u.asMember(DiscordPlugin.mainServer.getId))).getOrElse(SMono.empty))
|
||||
.map((u: User) => u.asMember(DiscordPlugin.mainServer.getId)).toJava.orElse(Mono.empty[Member]))
|
||||
.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 == m.getId.asLong)))
|
||||
.onErrorResume(_ => SMono.just(false)) //Role not found
|
||||
.switchIfEmpty(Mono.fromCallable(() => DiscordPlugin.mainServer.getOwnerId.asLong == m.getId.asLong)))
|
||||
.onErrorResume(_ => Mono.just(false)) //Role not found
|
||||
.subscribe(success => {
|
||||
if (success) {
|
||||
CommonListeners.debug = !CommonListeners.debug;
|
||||
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.")
|
||||
|
|
|
@ -6,11 +6,11 @@ import buttondevteam.lib.chat.{Command2, CommandClass}
|
|||
"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 = {
|
||||
if (args == null || args.isEmpty) sender.sendMessage(getManager.getCommandsText)
|
||||
def `def`(sender: Command2DCSender, @Command2.TextArg @Command2.OptionalArg command: String): Boolean = {
|
||||
if (command == null || command.isEmpty) sender.sendMessage(getManager.getCommandsText)
|
||||
else {
|
||||
val ht = getManager.getHelpText(args)
|
||||
if (ht == null) sender.sendMessage("Command not found: " + args)
|
||||
val ht = getManager.getCommandNode(command).getData.getHelpText(sender)
|
||||
if (ht == null) sender.sendMessage("Command not found: " + command)
|
||||
else sender.sendMessage(ht)
|
||||
}
|
||||
true
|
||||
|
|
|
@ -6,7 +6,6 @@ import buttondevteam.lib.chat.{Command2, CommandClass}
|
|||
import buttondevteam.lib.player.ChromaGamerBase
|
||||
import buttondevteam.lib.player.ChromaGamerBase.InfoTarget
|
||||
import discord4j.core.`object`.entity.{Message, User}
|
||||
import reactor.core.scala.publisher.SFlux
|
||||
|
||||
import scala.jdk.CollectionConverters.ListHasAsScala
|
||||
|
||||
|
@ -34,9 +33,9 @@ class UserinfoCommand extends ICommand2DC {
|
|||
private def getUsers(message: Message, args: String) = {
|
||||
val guild = message.getGuild.block
|
||||
if (guild == null) { //Private channel
|
||||
SFlux(DiscordPlugin.dc.getUsers).filter(u => u.getUsername.equalsIgnoreCase(args)).collectSeq().block()
|
||||
DiscordPlugin.dc.getUsers.filter(u => u.getUsername.equalsIgnoreCase(args)).collectList().block()
|
||||
}
|
||||
else
|
||||
SFlux(guild.getMembers).filter(_.getUsername.equalsIgnoreCase(args)).map(_.asInstanceOf[User]).collectSeq().block()
|
||||
guild.getMembers.filter(_.getUsername.equalsIgnoreCase(args)).map(_.asInstanceOf[User]).collectList().block()
|
||||
}
|
||||
}
|
|
@ -5,7 +5,6 @@ import buttondevteam.discordplugin.DiscordPlugin
|
|||
import buttondevteam.lib.TBMCDebugMessageEvent
|
||||
import discord4j.core.`object`.entity.channel.MessageChannel
|
||||
import org.bukkit.event.{EventHandler, Listener}
|
||||
import reactor.core.scala.publisher.SMono
|
||||
|
||||
object DebugMessageListener {
|
||||
private def SendMessage(message: String): Unit = {
|
||||
|
@ -17,7 +16,7 @@ object DebugMessageListener {
|
|||
sb.append("```").append("\n")
|
||||
sb.append(if (message.length > 2000) message.substring(0, 2000) else message).append("\n")
|
||||
sb.append("```")
|
||||
mc.flatMap((ch: MessageChannel) => SMono(ch.createMessage(sb.toString))).subscribe()
|
||||
mc.flatMap((ch: MessageChannel) => ch.createMessage(sb.toString)).subscribe()
|
||||
} catch {
|
||||
case ex: Exception =>
|
||||
ex.printStackTrace()
|
||||
|
|
|
@ -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.scala.publisher.SMono
|
||||
import reactor.core.publisher.Mono
|
||||
|
||||
import java.util
|
||||
import java.util.stream.Collectors
|
||||
|
@ -22,8 +22,8 @@ object ExceptionListenerModule {
|
|||
if (instance == null) return ()
|
||||
try getChannel.flatMap(channel => {
|
||||
val coderRole = channel match {
|
||||
case ch: GuildChannel => instance.pingRole(SMono(ch.getGuild)).get
|
||||
case _ => SMono.empty
|
||||
case ch: GuildChannel => instance.pingRole(ch.getGuild).get
|
||||
case _ => Mono.empty
|
||||
}
|
||||
coderRole.map((role: Role) => if (TBMCCoreAPI.IsTestServer) new StringBuilder
|
||||
else new StringBuilder(role.getMention).append("\n"))
|
||||
|
@ -36,7 +36,7 @@ object ExceptionListenerModule {
|
|||
if (sb.length + stackTrace.length >= 1980) stackTrace = stackTrace.substring(0, 1980 - sb.length)
|
||||
sb.append(stackTrace).append("\n")
|
||||
sb.append("```")
|
||||
SMono(channel.createMessage(sb.toString))
|
||||
channel.createMessage(sb.toString)
|
||||
})
|
||||
}).subscribe()
|
||||
catch {
|
||||
|
@ -47,9 +47,9 @@ object ExceptionListenerModule {
|
|||
|
||||
private var instance: ExceptionListenerModule = null
|
||||
|
||||
def getChannel: SMono[MessageChannel] = {
|
||||
def getChannel: Mono[MessageChannel] = {
|
||||
if (instance != null) return instance.channel.get
|
||||
SMono.empty
|
||||
Mono.empty
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,7 @@ class ExceptionListenerModule extends Component[DiscordPlugin] with Listener {
|
|||
if (lastsourcemsg.size >= 10) lastsourcemsg.remove(0)
|
||||
lastthrown.add(e.getException)
|
||||
lastsourcemsg.add(e.getSourceMessage)
|
||||
e.setHandled()
|
||||
e.setHandled(true)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -80,7 +80,7 @@ class ExceptionListenerModule extends Component[DiscordPlugin] with Listener {
|
|||
/**
|
||||
* The role to ping if an error occurs. Set to empty ('') to disable.
|
||||
*/
|
||||
private def pingRole(guild: SMono[Guild]) = DPUtils.roleData(getConfig, "pingRole", "Coder", guild)
|
||||
private def pingRole(guild: Mono[Guild]) = DPUtils.roleData(getConfig, "pingRole", "Coder", guild)
|
||||
|
||||
override protected def enable(): Unit = {
|
||||
if (DPUtils.disableIfConfigError(this, channel)) return ()
|
||||
|
|
|
@ -13,7 +13,7 @@ import discord4j.core.spec.legacy.{LegacyEmbedCreateSpec, LegacyMessageCreateSpe
|
|||
import org.bukkit.Bukkit
|
||||
import org.bukkit.event.player.PlayerJoinEvent
|
||||
import org.bukkit.event.{EventHandler, Listener}
|
||||
import reactor.core.scala.publisher.{SFlux, SMono}
|
||||
import reactor.core.publisher.Mono
|
||||
|
||||
import java.util
|
||||
import java.util.Calendar
|
||||
|
@ -52,7 +52,7 @@ object FunModule {
|
|||
ListC += 1
|
||||
ListC - 1
|
||||
} > 2) { // Lowered already
|
||||
DPUtils.reply(message, SMono.empty, "stop it. You know the answer.").subscribe()
|
||||
DPUtils.reply(message, Mono.empty, "stop it. You know the answer.").subscribe()
|
||||
lastlist = 0
|
||||
lastlistp = Bukkit.getOnlinePlayers.size.toShort
|
||||
return true //Handled
|
||||
|
@ -62,7 +62,7 @@ object FunModule {
|
|||
var next = 0
|
||||
if (usableServerReadyStrings.size == 0) fm.createUsableServerReadyStrings()
|
||||
next = usableServerReadyStrings.remove(serverReadyRandom.nextInt(usableServerReadyStrings.size))
|
||||
DPUtils.reply(message, SMono.empty, fm.serverReadyAnswers.get.get(next)).subscribe()
|
||||
DPUtils.reply(message, Mono.empty, fm.serverReadyAnswers.get.get(next)).subscribe()
|
||||
return false //Still process it as a command/mcchat if needed
|
||||
}
|
||||
false
|
||||
|
@ -78,17 +78,17 @@ object FunModule {
|
|||
|| event.getCurrent.getStatus == Status.OFFLINE)
|
||||
return () //If it's not an offline -> online change
|
||||
fm.fullHouseChannel.get.filter((ch: MessageChannel) => ch.isInstanceOf[GuildChannel])
|
||||
.flatMap(channel => fm.fullHouseDevRole(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(channel => fm.fullHouseDevRole(channel.asInstanceOf[GuildChannel].getGuild).get
|
||||
.filterWhen(devrole => event.getMember
|
||||
.flatMap(m => m.getRoles.any(_.getId.asLong == devrole.getId.asLong)))
|
||||
.filterWhen(devrole => event.getGuild
|
||||
.flatMapMany(g => g.getMembers.filter(_.getRoleIds.stream.anyMatch(_ == devrole.getId)))
|
||||
.flatMap(_.getPresence).all(_.getStatus != Status.OFFLINE))
|
||||
.filter(_ => lasttime + 10 < TimeUnit.NANOSECONDS.toHours(System.nanoTime)) //This should stay so it checks this last
|
||||
.flatMap(_ => {
|
||||
lasttime = TimeUnit.NANOSECONDS.toHours(System.nanoTime)
|
||||
SMono(channel.createMessage(_.setContent("Full house!")
|
||||
.setEmbed((ecs: LegacyEmbedCreateSpec) => ecs.setImage("https://cdn.discordapp.com/attachments/249295547263877121/249687682618359808/poker-hand-full-house-aces-kings-playing-cards-15553791.png"))))
|
||||
channel.createMessage(_.setContent("Full house!")
|
||||
.setEmbed((ecs: LegacyEmbedCreateSpec) => ecs.setImage("https://cdn.discordapp.com/attachments/249295547263877121/249687682618359808/poker-hand-full-house-aces-kings-playing-cards-15553791.png")))
|
||||
})).subscribe()
|
||||
}
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ class FunModule extends Component[DiscordPlugin] with Listener {
|
|||
* Questions that the bot will choose a random answer to give to.
|
||||
*/
|
||||
final private val serverReady: ConfigData[Array[String]] =
|
||||
getConfig.getData("serverReady", () => Array[String](
|
||||
getConfig.getData("serverReady", Array[String](
|
||||
"when will the server be open", "when will the server be ready",
|
||||
"when will the server be done", "when will the server be complete",
|
||||
"when will the server be finished", "when's the server ready",
|
||||
|
@ -107,7 +107,7 @@ class FunModule extends Component[DiscordPlugin] with Listener {
|
|||
* Answers for a recognized question. Selected randomly.
|
||||
*/
|
||||
final private val serverReadyAnswers: ConfigData[util.ArrayList[String]] =
|
||||
getConfig.getData("serverReadyAnswers", () => Lists.newArrayList(FunModule.serverReadyStrings: _*))
|
||||
getConfig.getData("serverReadyAnswers", Lists.newArrayList(FunModule.serverReadyStrings: _*))
|
||||
|
||||
private def createUsableServerReadyStrings(): Unit =
|
||||
IntStream.range(0, serverReadyAnswers.get.size).forEach((i: Int) => FunModule.usableServerReadyStrings.add(i.toShort))
|
||||
|
@ -125,7 +125,7 @@ class FunModule extends Component[DiscordPlugin] with Listener {
|
|||
/**
|
||||
* If all of the people who have this role are online, the bot will post a full house.
|
||||
*/
|
||||
private def fullHouseDevRole(guild: SMono[Guild]) = DPUtils.roleData(getConfig, "fullHouseDevRole", "Developer", guild)
|
||||
private def fullHouseDevRole(guild: Mono[Guild]) = DPUtils.roleData(getConfig, "fullHouseDevRole", "Developer", guild)
|
||||
|
||||
/**
|
||||
* The channel to post the full house to.
|
||||
|
|
|
@ -17,36 +17,35 @@ import discord4j.core.event.domain.message.MessageCreateEvent
|
|||
import discord4j.core.event.domain.role.{RoleCreateEvent, RoleDeleteEvent, RoleUpdateEvent}
|
||||
import reactor.core.Disposable
|
||||
import reactor.core.publisher.Mono
|
||||
import reactor.core.scala.publisher.{SFlux, SMono}
|
||||
|
||||
object CommonListeners {
|
||||
val timings = new Timings
|
||||
|
||||
def register(dispatcher: EventDispatcher): Unit = {
|
||||
dispatcher.on(classOf[MessageCreateEvent]).flatMap((event: MessageCreateEvent) => {
|
||||
SMono.just(event.getMessage).filter(_ => !DiscordPlugin.SafeMode)
|
||||
Mono.just(event.getMessage).filter(_ => !DiscordPlugin.SafeMode)
|
||||
.filter(message => message.getAuthor.filter(!_.isBot).isPresent)
|
||||
.filter(message => !FunModule.executeMemes(message))
|
||||
.filterWhen(message => {
|
||||
Option(Component.getComponents.get(classOf[MinecraftChatModule])).filter(_.isEnabled)
|
||||
.map(_.asInstanceOf[MinecraftChatModule].getListener.handleDiscord(event))
|
||||
.getOrElse(SMono.just(true)) //Wasn't handled, continue
|
||||
.map(_.asInstanceOf[MinecraftChatModule].getListener.handleDiscord(event).asInstanceOf[Mono[java.lang.Boolean]])
|
||||
.getOrElse(Mono.just(true)) //Wasn't handled, continue
|
||||
})
|
||||
}).onErrorContinue((err, _) => TBMCCoreAPI.SendException("An error occured while handling a message!", err, DiscordPlugin.plugin)).subscribe()
|
||||
dispatcher.on(classOf[PresenceUpdateEvent]).subscribe((event: PresenceUpdateEvent) => {
|
||||
if (!DiscordPlugin.SafeMode)
|
||||
FunModule.handleFullHouse(event)
|
||||
})
|
||||
SFlux(dispatcher.on(classOf[RoleCreateEvent])).subscribe(GameRoleModule.handleRoleEvent)
|
||||
SFlux(dispatcher.on(classOf[RoleDeleteEvent])).subscribe(GameRoleModule.handleRoleEvent)
|
||||
SFlux(dispatcher.on(classOf[RoleUpdateEvent])).subscribe(GameRoleModule.handleRoleEvent)
|
||||
SFlux(dispatcher.on(classOf[ChatInputInteractionEvent], event => {
|
||||
dispatcher.on(classOf[RoleCreateEvent]).subscribe(GameRoleModule.handleRoleEvent)
|
||||
dispatcher.on(classOf[RoleDeleteEvent]).subscribe(GameRoleModule.handleRoleEvent)
|
||||
dispatcher.on(classOf[RoleUpdateEvent]).subscribe(GameRoleModule.handleRoleEvent)
|
||||
dispatcher.on(classOf[ChatInputInteractionEvent], event => {
|
||||
if(event.getCommandName() equals "connect") {
|
||||
val asd = Mono.just(new ConnectCommand().`def`(new Command2DCSender(event), event.getOption("name").get.getValue.get.asString))
|
||||
asd
|
||||
} else
|
||||
Mono.empty()
|
||||
})).subscribe()
|
||||
}).subscribe()
|
||||
}
|
||||
|
||||
var debug = false
|
||||
|
|
|
@ -11,7 +11,7 @@ import discord4j.common.util.Snowflake
|
|||
import org.bukkit.event.player.PlayerJoinEvent
|
||||
import org.bukkit.event.{EventHandler, Listener}
|
||||
import reactor.core.publisher.Mono
|
||||
import reactor.core.scala.publisher.javaOptional2ScalaOption
|
||||
import scala.jdk.OptionConverters._
|
||||
|
||||
class MCListener extends Listener {
|
||||
@EventHandler def onPlayerJoin(e: PlayerJoinEvent): Unit =
|
||||
|
@ -25,18 +25,18 @@ class MCListener extends Listener {
|
|||
@EventHandler def onGetInfo(e: TBMCPlayerGetInfoEvent): Unit = {
|
||||
Option(DiscordPlugin.SafeMode).filterNot(identity).flatMap(_ => Option(e.getPlayer.getAs(classOf[DiscordPlayer])))
|
||||
.flatMap(dp => Option(dp.getDiscordID)).filter(_.nonEmpty)
|
||||
.map(Snowflake.of).flatMap(id => DiscordPlugin.dc.getUserById(id).onErrorResume(_ => Mono.empty).blockOptional())
|
||||
.map(Snowflake.of).flatMap(id => DiscordPlugin.dc.getUserById(id).onErrorResume(_ => Mono.empty).blockOptional().toScala)
|
||||
.map(user => {
|
||||
e.addInfo("Discord tag: " + user.getUsername + "#" + user.getDiscriminator)
|
||||
user
|
||||
})
|
||||
.flatMap(user => user.asMember(DiscordPlugin.mainServer.getId).onErrorResume(t => Mono.empty).blockOptional())
|
||||
.flatMap(member => member.getPresence.blockOptional())
|
||||
.flatMap(user => user.asMember(DiscordPlugin.mainServer.getId).onErrorResume(t => Mono.empty).blockOptional().toScala)
|
||||
.flatMap(member => member.getPresence.blockOptional().toScala)
|
||||
.map(pr => {
|
||||
e.addInfo(pr.getStatus.toString)
|
||||
pr
|
||||
})
|
||||
.flatMap(_.getActivity).foreach(activity => e.addInfo(s"${activity.getType}: ${activity.getName}"))
|
||||
.flatMap(_.getActivity.toScala).foreach(activity => e.addInfo(s"${activity.getType}: ${activity.getName}"))
|
||||
}
|
||||
|
||||
/*@EventHandler
|
||||
|
|
|
@ -6,13 +6,14 @@ import buttondevteam.discordplugin.ChannelconBroadcast.ChannelconBroadcast
|
|||
import buttondevteam.discordplugin.commands.{Command2DCSender, ICommand2DC}
|
||||
import buttondevteam.discordplugin.mcchat.sender.{DiscordConnectedPlayer, DiscordPlayer}
|
||||
import buttondevteam.lib.TBMCSystemChatEvent
|
||||
import buttondevteam.lib.architecture.config.IConfigData
|
||||
import buttondevteam.lib.chat.{Command2, CommandClass}
|
||||
import buttondevteam.lib.player.{ChromaGamerBase, TBMCPlayer}
|
||||
import discord4j.core.`object`.entity.Message
|
||||
import discord4j.core.`object`.entity.channel.{GuildChannel, MessageChannel}
|
||||
import discord4j.rest.util.{Permission, PermissionSet}
|
||||
import org.bukkit.Bukkit
|
||||
import reactor.core.scala.publisher.SMono
|
||||
import reactor.core.publisher.Mono
|
||||
|
||||
import java.lang.reflect.Method
|
||||
import java.util
|
||||
|
@ -37,9 +38,9 @@ class ChannelconCommand(private val module: MinecraftChatModule) extends IComman
|
|||
val message: Message = null // TODO
|
||||
if (checkPerms(message, null)) return true
|
||||
else if (MCChatCustom.removeCustomChat(message.getChannelId))
|
||||
DPUtils.reply(message, SMono.empty, "channel connection removed.").subscribe()
|
||||
DPUtils.reply(message, Mono.empty, "channel connection removed.").subscribe()
|
||||
else
|
||||
DPUtils.reply(message, SMono.empty, "this channel isn't connected.").subscribe()
|
||||
DPUtils.reply(message, Mono.empty, "this channel isn't connected.").subscribe()
|
||||
true
|
||||
}
|
||||
|
||||
|
@ -59,7 +60,7 @@ class ChannelconCommand(private val module: MinecraftChatModule) extends IComman
|
|||
target.getName + ": " + (if (cc.brtoggles.contains(target)) "enabled" else "disabled"))
|
||||
.collect(Collectors.joining("\n"))
|
||||
if (toggle == null) {
|
||||
DPUtils.reply(message, SMono.empty, "toggles:\n" + togglesString.get).subscribe()
|
||||
DPUtils.reply(message, Mono.empty, "toggles:\n" + togglesString.get).subscribe()
|
||||
return true
|
||||
}
|
||||
val arg: String = toggle.toUpperCase
|
||||
|
@ -67,7 +68,7 @@ class ChannelconCommand(private val module: MinecraftChatModule) extends IComman
|
|||
if (b.isEmpty) {
|
||||
val bt: TBMCSystemChatEvent.BroadcastTarget = TBMCSystemChatEvent.BroadcastTarget.get(arg)
|
||||
if (bt == null) {
|
||||
DPUtils.reply(message, SMono.empty, "cannot find toggle. Toggles:\n" + togglesString.get).subscribe()
|
||||
DPUtils.reply(message, Mono.empty, "cannot find toggle. Toggles:\n" + togglesString.get).subscribe()
|
||||
return true
|
||||
}
|
||||
val add: Boolean = !(cc.brtoggles.contains(bt))
|
||||
|
@ -87,7 +88,7 @@ class ChannelconCommand(private val module: MinecraftChatModule) extends IComman
|
|||
//1 1 | 0
|
||||
// XOR
|
||||
cc.toggles ^= (1 << b.get.id)
|
||||
DPUtils.reply(message, SMono.empty, "'" + b.get.toString.toLowerCase + "' "
|
||||
DPUtils.reply(message, Mono.empty, "'" + b.get.toString.toLowerCase + "' "
|
||||
+ (if ((cc.toggles & (1 << b.get.id)) == 0) "disabled" else "enabled")).subscribe()
|
||||
true
|
||||
}
|
||||
|
@ -105,8 +106,9 @@ class ChannelconCommand(private val module: MinecraftChatModule) extends IComman
|
|||
if (MCChatCustom.hasCustomChat(message.getChannelId)) {
|
||||
return respond(sender, "this channel is already connected to a Minecraft channel. Use `@ChromaBot channelcon remove` to remove it.")
|
||||
}
|
||||
val chan: Optional[Channel] = Channel.getChannels.filter((ch: Channel) => ch.ID.equalsIgnoreCase(channelID) || (util.Arrays.stream(ch.IDs.get).anyMatch((cid: String) => cid.equalsIgnoreCase(channelID)))).findAny
|
||||
if (!(chan.isPresent)) { //TODO: Red embed that disappears over time (kinda like the highlight messages in OW)
|
||||
val chan: Optional[Channel] = Channel.getChannels.filter(ch => ch.getIdentifier.equalsIgnoreCase(channelID)
|
||||
|| util.Arrays.stream(ch.extraIdentifiers.get).anyMatch(cid => cid.equalsIgnoreCase(channelID))).findAny
|
||||
if (!chan.isPresent) { //TODO: Red embed that disappears over time (kinda like the highlight messages in OW)
|
||||
DPUtils.reply(message, channel, "MC channel with ID '" + channelID + "' not found! The ID is the command for it without the /.").subscribe()
|
||||
return true
|
||||
}
|
||||
|
@ -120,7 +122,7 @@ class ChannelconCommand(private val module: MinecraftChatModule) extends IComman
|
|||
DPUtils.reply(message, channel, "you need to connect your Minecraft account. On the main server in " + DPUtils.botmention + " do " + DiscordPlugin.getPrefix + "connect <MCname>").subscribe()
|
||||
return true
|
||||
}
|
||||
val dcp: DiscordConnectedPlayer = DiscordConnectedPlayer.create(message.getAuthor.get, channel, chp.getUUID, Bukkit.getOfflinePlayer(chp.getUUID).getName, module)
|
||||
val dcp: DiscordConnectedPlayer = DiscordConnectedPlayer.create(message.getAuthor.get, channel, chp.getUniqueId, Bukkit.getOfflinePlayer(chp.getUniqueId).getName, module)
|
||||
//Using a fake player with no login/logout, should be fine for this event
|
||||
val groupid: String = chan.get.getGroupID(dcp)
|
||||
if (groupid == null && !((chan.get.isInstanceOf[ChatRoom]))) { //ChatRooms don't allow it unless the user joins, which happens later
|
||||
|
@ -175,6 +177,6 @@ class ChannelconCommand(private val module: MinecraftChatModule) extends IComman
|
|||
"To remove a connection use @ChromaBot channelcon remove in the channel.",
|
||||
"Mentioning the bot is needed in this case because the " + DiscordPlugin.getPrefix + " prefix only works in " + DPUtils.botmention + ".",
|
||||
"Invite link: <https://discordapp.com/oauth2/authorize?client_id="
|
||||
+ SMono(DiscordPlugin.dc.getApplicationInfo).map(info => info.getId.asString).blockOption().getOrElse("Unknown")
|
||||
+ DiscordPlugin.dc.getApplicationInfo.map(info => info.getId.asString).blockOptional().orElse("Unknown")
|
||||
+ "&scope=bot&permissions=268509264>")
|
||||
}
|
|
@ -3,7 +3,6 @@ package buttondevteam.discordplugin.mcchat
|
|||
import buttondevteam.core.ComponentManager
|
||||
import buttondevteam.discordplugin.*
|
||||
import buttondevteam.discordplugin.DPUtils.SpecExtensions
|
||||
import buttondevteam.discordplugin.mcchat.playerfaker.{VanillaCommandListener, VanillaCommandListener14, VanillaCommandListener15}
|
||||
import buttondevteam.discordplugin.mcchat.sender.{DiscordPlayer, DiscordSender, DiscordSenderBase}
|
||||
import buttondevteam.lib.*
|
||||
import buttondevteam.lib.chat.{ChatMessage, TBMCChatAPI}
|
||||
|
@ -13,6 +12,7 @@ import discord4j.common.util.Snowflake
|
|||
import discord4j.core.`object`.entity.channel.{MessageChannel, PrivateChannel}
|
||||
import discord4j.core.`object`.entity.{Member, Message, User}
|
||||
import discord4j.core.event.domain.message.MessageCreateEvent
|
||||
import discord4j.core.spec.EmbedCreateSpec
|
||||
import discord4j.core.spec.legacy.{LegacyEmbedCreateSpec, LegacyMessageEditSpec}
|
||||
import discord4j.rest.util.Color
|
||||
import org.bukkit.Bukkit
|
||||
|
@ -20,14 +20,13 @@ 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
|
||||
import java.util.concurrent.{LinkedBlockingQueue, TimeoutException}
|
||||
import java.util.function.{Consumer, Predicate}
|
||||
import java.util.function.{Consumer, Predicate, Supplier}
|
||||
import java.util.stream.Collectors
|
||||
import scala.jdk.CollectionConverters.{ListHasAsScala, SetHasAsScala}
|
||||
import scala.jdk.CollectionConverters.{IterableHasAsScala, ListHasAsScala, SetHasAsScala}
|
||||
import scala.jdk.OptionConverters.RichOptional
|
||||
|
||||
object MCChatListener {
|
||||
|
@ -87,45 +86,42 @@ class MCChatListener(val module: MinecraftChatModule) extends Listener {
|
|||
val se: util.AbstractMap.SimpleEntry[TBMCChatEvent, Instant] = sendevents.take // Wait until an element is available
|
||||
e = se.getKey
|
||||
time = se.getValue
|
||||
val authorPlayer: String = "[" + DPUtils.sanitizeStringNoEscape(e.getChannel.DisplayName.get) + "] " + //
|
||||
val authorPlayer: String = "[" + DPUtils.sanitizeStringNoEscape(e.getChannel.displayName.get) + "] " + //
|
||||
(if ("Minecraft" == e.getOrigin) "" else "[" + e.getOrigin.charAt(0) + "]") +
|
||||
DPUtils.sanitizeStringNoEscape(ChromaUtils.getDisplayName(e.getSender))
|
||||
val color: chat.Color = e.getChannel.Color.get
|
||||
val embed: Consumer[LegacyEmbedCreateSpec] = (ecs: LegacyEmbedCreateSpec) => {
|
||||
def foo(ecs: LegacyEmbedCreateSpec) = {
|
||||
ecs.setDescription(e.getMessage).setColor(Color.of(color.getRed, color.getGreen, color.getBlue))
|
||||
val color: chat.Color = e.getChannel.color.get
|
||||
val embed = () => {
|
||||
val ecs = EmbedCreateSpec.builder()
|
||||
ecs.description(e.getMessage).color(Color.of(color.getRed, color.getGreen, color.getBlue))
|
||||
val url: String = module.profileURL.get
|
||||
e.getSender match {
|
||||
case player: Player =>
|
||||
DPUtils.embedWithHead(ecs, authorPlayer, e.getSender.getName,
|
||||
if (url.nonEmpty) url + "?type=minecraft&id=" + player.getUniqueId else null)
|
||||
case dsender: DiscordSenderBase =>
|
||||
ecs.setAuthor(authorPlayer,
|
||||
ecs.author(authorPlayer,
|
||||
if (url.nonEmpty) url + "?type=discord&id=" + dsender.getUser.getId.asString else null,
|
||||
dsender.getUser.getAvatarUrl)
|
||||
case _ =>
|
||||
DPUtils.embedWithHead(ecs, authorPlayer, e.getSender.getName, null)
|
||||
}
|
||||
ecs.setTimestamp(time)
|
||||
}
|
||||
|
||||
foo(ecs)
|
||||
ecs.timestamp(time)
|
||||
}
|
||||
val nanoTime: Long = System.nanoTime
|
||||
val doit = (lastmsgdata: MCChatUtils.LastMsgData) => {
|
||||
if (lastmsgdata.message == null
|
||||
|| authorPlayer != lastmsgdata.message.getEmbeds.get(0).getAuthor.toScala.flatMap(_.getName.toScala).orNull
|
||||
|| lastmsgdata.time / 1000000000f < nanoTime / 1000000000f - 120
|
||||
|| !(lastmsgdata.mcchannel.ID == e.getChannel.ID)
|
||||
|| !(lastmsgdata.mcchannel.getIdentifier == e.getChannel.getIdentifier)
|
||||
|| lastmsgdata.content.length + e.getMessage.length + 1 > 2048) {
|
||||
lastmsgdata.message = lastmsgdata.channel.createEmbed(embed).block
|
||||
lastmsgdata.message = lastmsgdata.channel.createMessage(embed().build()).block
|
||||
lastmsgdata.time = nanoTime
|
||||
lastmsgdata.mcchannel = e.getChannel
|
||||
lastmsgdata.content = e.getMessage
|
||||
}
|
||||
else {
|
||||
lastmsgdata.content = lastmsgdata.content + "\n" + e.getMessage // The message object doesn't get updated
|
||||
lastmsgdata.message.edit((mes: LegacyMessageEditSpec) => mes.setEmbed(embed.andThen((ecs: LegacyEmbedCreateSpec) => ecs.setDescription(lastmsgdata.content))).^^()).block
|
||||
lastmsgdata.message.edit().withEmbeds(embed().description(lastmsgdata.content).build()).block
|
||||
}
|
||||
}
|
||||
// Checks if the given channel is different than where the message was sent from
|
||||
|
@ -145,7 +141,7 @@ class MCChatListener(val module: MinecraftChatModule) extends Listener {
|
|||
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.getChannel.getIdentifier == lmd.mcchannel.getIdentifier //If it's from a command, the command msg has been deleted, so we need to send it
|
||||
&& e.getGroupID() == lmd.groupID) { //Check if this is the group we want to test - #58
|
||||
if (e.shouldSendTo(lmd.dcp)) { //Check original user's permissions
|
||||
doit(lmd)
|
||||
|
@ -244,11 +240,11 @@ class MCChatListener(val module: MinecraftChatModule) extends Listener {
|
|||
private var recthread: Thread = null
|
||||
|
||||
// Discord
|
||||
def handleDiscord(ev: MessageCreateEvent): SMono[Boolean] = {
|
||||
def handleDiscord(ev: MessageCreateEvent): Mono[Boolean] = {
|
||||
val author = Option(ev.getMessage.getAuthor.orElse(null))
|
||||
val hasCustomChat = MCChatCustom.hasCustomChat(ev.getMessage.getChannelId)
|
||||
val prefix = DiscordPlugin.getPrefix
|
||||
SMono(ev.getMessage.getChannel)
|
||||
ev.getMessage.getChannel
|
||||
.filter(channel => isChatEnabled(channel, author, hasCustomChat))
|
||||
.filter(channel => !isRunningMCChatCommand(channel, ev.getMessage.getContent, prefix))
|
||||
.filter(channel => {
|
||||
|
@ -313,7 +309,7 @@ class MCChatListener(val module: MinecraftChatModule) extends Listener {
|
|||
replaceUserMentions()
|
||||
|
||||
def replaceChannelMentions(): Unit = {
|
||||
for (ch <- SFlux(event.getGuild.flux).flatMap(_.getChannels).toIterable()) {
|
||||
for (ch <- event.getGuild.flux.flatMap(_.getChannels).toIterable().asScala) {
|
||||
dmessage = dmessage.replace(ch.getMention, "#" + ch.getName)
|
||||
}
|
||||
}
|
||||
|
@ -385,9 +381,9 @@ class MCChatListener(val module: MinecraftChatModule) extends Listener {
|
|||
else {
|
||||
val cmb = ChatMessage.builder(dsender, user, dmessage + getAttachmentText).fromCommand(false)
|
||||
if (clmd != null)
|
||||
TBMCChatAPI.SendChatMessage(cmb.permCheck(clmd.dcp).build, clmd.mcchannel)
|
||||
TBMCChatAPI.sendChatMessage(cmb.permCheck(clmd.dcp).build, clmd.mcchannel)
|
||||
else
|
||||
TBMCChatAPI.SendChatMessage(cmb.build)
|
||||
TBMCChatAPI.sendChatMessage(cmb.build)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
@ -440,13 +436,7 @@ class MCChatListener(val module: MinecraftChatModule) extends Listener {
|
|||
val mcpackage = Bukkit.getServer.getClass.getPackage.getName
|
||||
if (!module.enableVanillaCommands.get)
|
||||
Bukkit.dispatchCommand(dsender, cmd)
|
||||
else if (mcpackage.contains("1_12"))
|
||||
VanillaCommandListener.runBukkitOrVanillaCommand(dsender, cmd)
|
||||
else if (mcpackage.contains("1_14"))
|
||||
VanillaCommandListener14.runBukkitOrVanillaCommand(dsender, cmd)
|
||||
else if (mcpackage.contains("1_15") || mcpackage.contains("1_16"))
|
||||
VanillaCommandListener15.runBukkitOrVanillaCommand(dsender, cmd)
|
||||
else
|
||||
else // TODO: Vanilla command handling
|
||||
Bukkit.dispatchCommand(dsender, cmd)
|
||||
} catch {
|
||||
case e: NoClassDefFoundError =>
|
||||
|
|
|
@ -22,13 +22,13 @@ object MCChatPrivate {
|
|||
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 p = Bukkit.getPlayer(mcp.getUniqueId)
|
||||
val op = Bukkit.getOfflinePlayer(mcp.getUniqueId)
|
||||
val mcm = ComponentManager.getIfEnabled(classOf[MinecraftChatModule])
|
||||
if (start) {
|
||||
val sender = DiscordConnectedPlayer.create(user, channel, mcp.getUUID, op.getName, mcm)
|
||||
val sender = DiscordConnectedPlayer.create(user, channel, mcp.getUniqueId, op.getName, mcm)
|
||||
MCChatUtils.addSender(MCChatUtils.ConnectedSenders, user, sender)
|
||||
MCChatUtils.LoggedInPlayers.put(mcp.getUUID, sender)
|
||||
MCChatUtils.LoggedInPlayers.put(mcp.getUniqueId, sender)
|
||||
if (p == null) { // Player is offline - If the player is online, that takes precedence
|
||||
MCChatUtils.callLoginEvents(sender)
|
||||
}
|
||||
|
|
|
@ -20,8 +20,7 @@ import org.bukkit.entity.Player
|
|||
import org.bukkit.event.Event
|
||||
import org.bukkit.event.player.{AsyncPlayerPreLoginEvent, PlayerJoinEvent, PlayerLoginEvent, PlayerQuitEvent}
|
||||
import org.bukkit.plugin.AuthorNagException
|
||||
import reactor.core.publisher.{Flux as JFlux, Mono as JMono}
|
||||
import reactor.core.scala.publisher.SMono
|
||||
import reactor.core.publisher.{Flux, Mono}
|
||||
|
||||
import java.net.InetAddress
|
||||
import java.util
|
||||
|
@ -36,6 +35,7 @@ import scala.collection.convert.ImplicitConversions.`map AsJavaMap`
|
|||
import scala.collection.mutable.ListBuffer
|
||||
import scala.jdk.CollectionConverters.{CollectionHasAsScala, SeqHasAsJava}
|
||||
import scala.jdk.javaapi.CollectionConverters.asScala
|
||||
import scala.jdk.javaapi.OptionConverters._
|
||||
|
||||
object MCChatUtils {
|
||||
/**
|
||||
|
@ -93,8 +93,7 @@ object MCChatUtils {
|
|||
.filter(_ => C.incrementAndGet > 0) //Always true
|
||||
.map((p) => DPUtils.sanitizeString(p.getDisplayName)).collect(Collectors.joining(", "))
|
||||
s(0) = s"$C player${if (C.get != 1) "s" else ""} online"
|
||||
lmd.channel.asInstanceOf[TextChannel].edit((tce: LegacyTextChannelEditSpec) =>
|
||||
tce.setTopic(String.join("\n----\n", s: _*)).setReason("Player list update").^^()).subscribe //Don't wait
|
||||
lmd.channel.asInstanceOf[TextChannel].edit().withTopic(String.join("\n----\n", s: _*)).withReason("Player list update").subscribe() //Don't wait
|
||||
}
|
||||
|
||||
private[mcchat] def checkEssentials(p: Player): Boolean = {
|
||||
|
@ -126,11 +125,11 @@ object MCChatUtils {
|
|||
else null.asInstanceOf
|
||||
}
|
||||
|
||||
def forPublicPrivateChat(action: SMono[MessageChannel] => SMono[_]): SMono[_] = {
|
||||
if (notEnabled) return SMono.empty
|
||||
val list = MCChatPrivate.lastmsgPerUser.map(data => action(SMono.just(data.channel)))
|
||||
def forPublicPrivateChat(action: Mono[MessageChannel] => Mono[_]): Mono[_] = {
|
||||
if (notEnabled) return Mono.empty
|
||||
val list = MCChatPrivate.lastmsgPerUser.map(data => action(Mono.just(data.channel)))
|
||||
.prepend(action(module.chatChannelMono))
|
||||
SMono(JMono.whenDelayError(list.asJava))
|
||||
Mono.whenDelayError(list.asJava)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -140,14 +139,14 @@ object MCChatUtils {
|
|||
* @param toggle The toggle to check
|
||||
* @param hookmsg Whether the message is also sent from the hook
|
||||
*/
|
||||
def forCustomAndAllMCChat(action: SMono[MessageChannel] => SMono[_], @Nullable toggle: ChannelconBroadcast, hookmsg: Boolean): SMono[_] = {
|
||||
if (notEnabled) return SMono.empty
|
||||
def forCustomAndAllMCChat(action: Mono[MessageChannel] => Mono[_], @Nullable toggle: ChannelconBroadcast, hookmsg: Boolean): Mono[_] = {
|
||||
if (notEnabled) return Mono.empty
|
||||
val list = List(if (!GeneralEventBroadcasterModule.isHooked || !hookmsg)
|
||||
forPublicPrivateChat(action) else SMono.empty) ++
|
||||
forPublicPrivateChat(action) else Mono.empty) ++
|
||||
(if (toggle == null) MCChatCustom.lastmsgCustom
|
||||
else MCChatCustom.lastmsgCustom.filter(cc => (cc.toggles & (1 << toggle.id)) != 0))
|
||||
.map(_.channel).map(SMono.just).map(action)
|
||||
SMono(JMono.whenDelayError(list.asJava))
|
||||
.map(_.channel).map(Mono.just).map(action)
|
||||
Mono.whenDelayError(list.asJava)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -157,15 +156,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: SMono[MessageChannel] => SMono[_], @Nullable sender: CommandSender, @Nullable toggle: ChannelconBroadcast): SMono[_] = {
|
||||
if (notEnabled) return SMono.empty
|
||||
def forAllowedCustomMCChat(action: Mono[MessageChannel] => Mono[_], @Nullable sender: CommandSender, @Nullable toggle: ChannelconBroadcast): Mono[_] = {
|
||||
if (notEnabled) return Mono.empty
|
||||
val st = MCChatCustom.lastmsgCustom.filter(clmd => { //new TBMCChannelConnectFakeEvent(sender, clmd.mcchannel).shouldSendTo(clmd.dcp) - Thought it was this simple hehe - Wait, it *should* be this simple
|
||||
if (toggle != null && ((clmd.toggles & (1 << toggle.id)) == 0)) false //If null then allow
|
||||
else if (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
|
||||
}).map(cc => action.apply(Mono.just(cc.channel))) //TODO: Send error messages on channel connect
|
||||
//Mono.whenDelayError((() => st.iterator).asInstanceOf[java.lang.Iterable[Mono[_]]]) //Can't convert as an iterator or inside the stream, but I can convert it as a stream
|
||||
SMono.whenDelayError(st)
|
||||
Mono.whenDelayError(st.asJava)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -176,32 +175,32 @@ 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: SMono[MessageChannel] => SMono[_], @Nullable sender: CommandSender, @Nullable toggle: ChannelconBroadcast, hookmsg: Boolean): SMono[_] = {
|
||||
if (notEnabled) return SMono.empty
|
||||
def forAllowedCustomAndAllMCChat(action: Mono[MessageChannel] => Mono[_], @Nullable sender: CommandSender, @Nullable toggle: ChannelconBroadcast, hookmsg: Boolean): Mono[_] = {
|
||||
if (notEnabled) return Mono.empty
|
||||
val cc = forAllowedCustomMCChat(action, sender, toggle)
|
||||
if (!GeneralEventBroadcasterModule.isHooked || !hookmsg) return SMono.whenDelayError(Array(forPublicPrivateChat(action), cc))
|
||||
SMono.whenDelayError(Array(cc))
|
||||
if (!GeneralEventBroadcasterModule.isHooked || !hookmsg) return Mono.whenDelayError(forPublicPrivateChat(action), cc)
|
||||
Mono.whenDelayError(cc)
|
||||
}
|
||||
|
||||
def send(message: String): SMono[MessageChannel] => SMono[_] = _.flatMap((mc: MessageChannel) => {
|
||||
def send(message: String): Mono[MessageChannel] => Mono[_] = _.flatMap((mc: MessageChannel) => {
|
||||
resetLastMessage(mc)
|
||||
SMono(mc.createMessage(DPUtils.sanitizeString(message)))
|
||||
mc.createMessage(DPUtils.sanitizeString(message))
|
||||
})
|
||||
|
||||
def forAllowedMCChat(action: SMono[MessageChannel] => SMono[_], event: TBMCSystemChatEvent): SMono[_] = {
|
||||
if (notEnabled) return SMono.empty
|
||||
val list = new ListBuffer[SMono[_]]
|
||||
def forAllowedMCChat(action: Mono[MessageChannel] => Mono[_], event: TBMCSystemChatEvent): Mono[_] = {
|
||||
if (notEnabled) return Mono.empty
|
||||
val list = new ListBuffer[Mono[_]]
|
||||
if (event.getChannel.isGlobal) list.append(action(module.chatChannelMono))
|
||||
for (data <- MCChatPrivate.lastmsgPerUser)
|
||||
if (event.shouldSendTo(getSender(data.channel.getId, data.user)))
|
||||
list.append(action(SMono.just(data.channel))) //TODO: Only store ID?
|
||||
list.append(action(Mono.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 => {
|
||||
.map(clmd => action(Mono.just(clmd.channel))).foreach(elem => {
|
||||
list.append(elem)
|
||||
()
|
||||
})
|
||||
SMono.whenDelayError(list)
|
||||
Mono.whenDelayError(list.asJava)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -212,7 +211,7 @@ object MCChatUtils {
|
|||
.orElse(Option(getSender(ConnectedSenders, channel, author))) // This doesn't support the public chat, but it'll always return null for it
|
||||
.orElse(Option(getSender(UnconnectedSenders, channel, author))) //
|
||||
.orElse(Option(addSender(UnconnectedSenders, author,
|
||||
new DiscordSender(author, SMono(DiscordPlugin.dc.getChannelById(channel)).block().asInstanceOf[MessageChannel]))))
|
||||
new DiscordSender(author, DiscordPlugin.dc.getChannelById(channel).block().asInstanceOf[MessageChannel]))))
|
||||
.get
|
||||
}
|
||||
|
||||
|
@ -322,7 +321,7 @@ object MCChatUtils {
|
|||
callEventExcludingSome(new PlayerJoinEvent(dcp, ""))
|
||||
dcp.setLoggedIn(true)
|
||||
if (module != null) {
|
||||
if (module.serverWatcher != null) module.serverWatcher.fakePlayers.add(dcp)
|
||||
// TODO: ServerWatcher
|
||||
module.log(dcp.getName + " (" + dcp.getUniqueId + ") logged in from Discord")
|
||||
}
|
||||
}
|
||||
|
@ -345,7 +344,7 @@ object MCChatUtils {
|
|||
dcp.setLoggedIn(false)
|
||||
if (module != null) {
|
||||
module.log(dcp.getName + " (" + dcp.getUniqueId + ") logged out from Discord")
|
||||
if (module.serverWatcher != null) module.serverWatcher.fakePlayers.remove(dcp)
|
||||
// TODO: ServerWatcher
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ import org.bukkit.event.player.*
|
|||
import org.bukkit.event.player.PlayerLoginEvent.Result
|
||||
import org.bukkit.event.server.{BroadcastMessageEvent, TabCompleteEvent}
|
||||
import org.bukkit.event.{EventHandler, EventPriority, Listener}
|
||||
import reactor.core.scala.publisher.{SFlux, SMono}
|
||||
import reactor.core.publisher.{Flux, Mono}
|
||||
|
||||
class MCListener(val module: MinecraftChatModule) extends Listener {
|
||||
final private val muteRole = DPUtils.roleData(module.getConfig, "muteRole", "Muted")
|
||||
|
@ -35,11 +35,11 @@ class MCListener(val module: MinecraftChatModule) extends Listener {
|
|||
val p = e.getPlayer
|
||||
val dp = TBMCPlayerBase.getPlayer(p.getUniqueId, classOf[TBMCPlayer]).getAs(classOf[DiscordPlayer])
|
||||
if (dp != null)
|
||||
DiscordPlugin.dc.getUserById(Snowflake.of(dp.getDiscordID)).^^().flatMap(user =>
|
||||
user.getPrivateChannel.^^().flatMap(chan => module.chatChannelMono.flatMap(cc => {
|
||||
DiscordPlugin.dc.getUserById(Snowflake.of(dp.getDiscordID)).flatMap(user =>
|
||||
user.getPrivateChannel.flatMap(chan => module.chatChannelMono.flatMap(cc => {
|
||||
MCChatUtils.addSender(MCChatUtils.OnlineSenders, dp.getDiscordID, DiscordPlayerSender.create(user, chan, p, module))
|
||||
MCChatUtils.addSender(MCChatUtils.OnlineSenders, dp.getDiscordID, DiscordPlayerSender.create(user, cc, p, module)) //Stored per-channel
|
||||
SMono.empty
|
||||
Mono.empty
|
||||
}))).subscribe()
|
||||
val message = e.getJoinMessage
|
||||
sendJoinLeaveMessage(message, e.getPlayer)
|
||||
|
@ -87,18 +87,17 @@ class MCListener(val module: MinecraftChatModule) extends Listener {
|
|||
if (!source.isPlayer) return ()
|
||||
val p = TBMCPlayerBase.getPlayer(source.getPlayer.getUniqueId, classOf[TBMCPlayer]).getAs(classOf[DiscordPlayer])
|
||||
if (p == null) return ()
|
||||
DPUtils.ignoreError(SMono(DiscordPlugin.dc.getUserById(Snowflake.of(p.getDiscordID)))
|
||||
.flatMap(user => SMono(user.asMember(DiscordPlugin.mainServer.getId)))
|
||||
DPUtils.ignoreError(DiscordPlugin.dc.getUserById(Snowflake.of(p.getDiscordID))
|
||||
.flatMap(user => user.asMember(DiscordPlugin.mainServer.getId))
|
||||
.flatMap(user => role.flatMap((r: Role) => {
|
||||
def foo(r: Role): SMono[_] = {
|
||||
def foo(r: Role): Mono[_] = {
|
||||
if (e.getValue) user.addRole(r.getId)
|
||||
else user.removeRole(r.getId)
|
||||
val modlog = module.modlogChannel.get
|
||||
val msg = (if (e.getValue) "M"
|
||||
else "Unm") + "uted user: " + user.getUsername + "#" + user.getDiscriminator
|
||||
val msg = s"${(if (e.getValue) "M" else "Unm")}uted user: ${user.getUsername}#${user.getDiscriminator}"
|
||||
module.log(msg)
|
||||
if (modlog != null) return modlog.flatMap((ch: MessageChannel) => SMono(ch.createMessage(msg)))
|
||||
SMono.empty
|
||||
if (modlog != null) return modlog.flatMap((ch: MessageChannel) => ch.createMessage(msg))
|
||||
Mono.empty
|
||||
}
|
||||
|
||||
foo(r)
|
||||
|
@ -119,7 +118,7 @@ class MCListener(val module: MinecraftChatModule) extends Listener {
|
|||
case _ => event.getSender.getName
|
||||
}
|
||||
//Channel channel = ChromaGamerBase.getFromSender(event.getSender()).channel().get(); - TODO
|
||||
DiscordPlugin.mainServer.getEmojis.^^().filter(e => "YEEHAW" == e.getName).take(1).singleOrEmpty
|
||||
DiscordPlugin.mainServer.getEmojis.filter(e => "YEEHAW" == e.getName).take(1).singleOrEmpty
|
||||
.map(Option.apply).defaultIfEmpty(Option.empty)
|
||||
.flatMap(yeehaw => MCChatUtils.forPublicPrivateChat(MCChatUtils.send(name +
|
||||
yeehaw.map(guildEmoji => " <:YEEHAW:" + guildEmoji.getId.asString + ">s").getOrElse(" YEEHAWs")))).subscribe()
|
||||
|
@ -132,7 +131,7 @@ class MCListener(val module: MinecraftChatModule) extends Listener {
|
|||
val t = event.getBuffer.substring(i + 1) //0 if not found
|
||||
if (!t.startsWith("@")) return ()
|
||||
val token = t.substring(1)
|
||||
val x = DiscordPlugin.mainServer.getMembers.^^().flatMap(m => SFlux.just(m.getUsername, m.getNickname.orElse("")))
|
||||
val x = DiscordPlugin.mainServer.getMembers.flatMap(m => Flux.just(m.getUsername, m.getNickname.orElse("")))
|
||||
.filter(_.startsWith(token)).map("@" + _).doOnNext(event.getCompletions.add(_)).blockLast()
|
||||
}
|
||||
|
||||
|
|
|
@ -2,8 +2,6 @@ package buttondevteam.discordplugin.mcchat
|
|||
|
||||
import buttondevteam.core.component.channel.Channel
|
||||
import buttondevteam.discordplugin.DPUtils.{MonoExtensions, SpecExtensions}
|
||||
import buttondevteam.discordplugin.mcchat.playerfaker.ServerWatcher
|
||||
import buttondevteam.discordplugin.mcchat.playerfaker.perm.LPInjector
|
||||
import buttondevteam.discordplugin.mcchat.sender.DiscordConnectedPlayer
|
||||
import buttondevteam.discordplugin.util.DPState
|
||||
import buttondevteam.discordplugin.{ChannelconBroadcast, DPUtils, DiscordPlugin}
|
||||
|
@ -14,7 +12,7 @@ import discord4j.common.util.Snowflake
|
|||
import discord4j.core.`object`.entity.channel.MessageChannel
|
||||
import discord4j.rest.util.Color
|
||||
import org.bukkit.Bukkit
|
||||
import reactor.core.scala.publisher.SMono
|
||||
import reactor.core.publisher.Mono
|
||||
|
||||
import java.util
|
||||
import java.util.stream.Collectors
|
||||
|
@ -33,27 +31,27 @@ class MinecraftChatModule extends Component[DiscordPlugin] {
|
|||
def getListener: MCChatListener = this.listener
|
||||
|
||||
private var listener: MCChatListener = null
|
||||
private[mcchat] var serverWatcher: ServerWatcher = null
|
||||
private var lpInjector: LPInjector = null
|
||||
private[mcchat] var serverWatcher = null
|
||||
private var lpInjector = null
|
||||
private[mcchat] var disabling = false
|
||||
|
||||
/**
|
||||
* A list of commands that can be used in public chats - Warning: Some plugins will treat players as OPs, always test before allowing a command!
|
||||
*/
|
||||
val whitelistedCommands: ConfigData[util.ArrayList[String]] = getConfig.getData("whitelistedCommands",
|
||||
() => Lists.newArrayList("list", "u", "shrug", "tableflip", "unflip", "mwiki", "yeehaw", "lenny", "rp", "plugins"))
|
||||
Lists.newArrayList("list", "u", "shrug", "tableflip", "unflip", "mwiki", "yeehaw", "lenny", "rp", "plugins"))
|
||||
|
||||
/**
|
||||
* The channel to use as the public Minecraft chat - everything public gets broadcasted here
|
||||
*/
|
||||
val chatChannel: ReadOnlyConfigData[Snowflake] = DPUtils.snowflakeData(getConfig, "chatChannel", 0L)
|
||||
val chatChannel: ConfigData[Snowflake] = DPUtils.snowflakeData(getConfig, "chatChannel", 0L)
|
||||
|
||||
def chatChannelMono: SMono[MessageChannel] = DPUtils.getMessageChannel(chatChannel.getPath, chatChannel.get)
|
||||
def chatChannelMono: Mono[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
|
||||
*/
|
||||
val modlogChannel: ReadOnlyConfigData[SMono[MessageChannel]] = DPUtils.channelData(getConfig, "modlogChannel")
|
||||
val modlogChannel: ConfigData[Mono[MessageChannel]] = DPUtils.channelData(getConfig, "modlogChannel")
|
||||
/**
|
||||
* The plugins to exclude from fake player events used for the 'mcchat' command - some plugins may crash, add them here
|
||||
*/
|
||||
|
@ -117,7 +115,7 @@ class MinecraftChatModule extends Component[DiscordPlugin] {
|
|||
val chconkeys = chcons.getKeys(false)
|
||||
for (chconkey <- chconkeys.asScala) {
|
||||
val chcon = chcons.getConfigurationSection(chconkey)
|
||||
val mcch = Channel.getChannels.filter((ch: Channel) => ch.ID == chcon.getString("mcchid")).findAny
|
||||
val mcch = Channel.getChannels.filter((ch: Channel) => ch.getIdentifier == chcon.getString("mcchid")).findAny
|
||||
val ch = DiscordPlugin.dc.getChannelById(Snowflake.of(chcon.getLong("chid"))).block
|
||||
val did = chcon.getLong("did")
|
||||
val user = DiscordPlugin.dc.getUserById(Snowflake.of(did)).block
|
||||
|
@ -135,18 +133,9 @@ class MinecraftChatModule extends Component[DiscordPlugin] {
|
|||
}
|
||||
}
|
||||
}
|
||||
try if (lpInjector == null) lpInjector = new LPInjector //new LPInjector(DiscordPlugin.plugin)
|
||||
catch {
|
||||
case e: Exception =>
|
||||
TBMCCoreAPI.SendException("Failed to init LuckPerms injector", e, this)
|
||||
case e: NoClassDefFoundError =>
|
||||
log("No LuckPerms, not injecting")
|
||||
//e.printStackTrace();
|
||||
}
|
||||
// TODO: LPInjector
|
||||
if (addFakePlayersToBukkit.get) try {
|
||||
serverWatcher = new ServerWatcher
|
||||
serverWatcher.enableDisable(true)
|
||||
log("Finished hooking into the server")
|
||||
// TODO: Fake players
|
||||
} catch {
|
||||
case e: Exception =>
|
||||
TBMCCoreAPI.SendException("Failed to hack the server (object)! Disable addFakePlayersToBukkit in the config.", e, this)
|
||||
|
@ -189,8 +178,7 @@ class MinecraftChatModule extends Component[DiscordPlugin] {
|
|||
serverUp.set(false) //Disable even if just the component is disabled because that way it won't falsely report crashes
|
||||
try //If it's not enabled it won't do anything
|
||||
if (serverWatcher != null) {
|
||||
serverWatcher.enableDisable(false)
|
||||
log("Finished unhooking the server")
|
||||
// TODO: ServerWatcher
|
||||
}
|
||||
catch {
|
||||
case e: Exception =>
|
||||
|
@ -200,7 +188,7 @@ class MinecraftChatModule extends Component[DiscordPlugin] {
|
|||
val chconsc = getConfig.getConfig.createSection("chcons")
|
||||
for (chcon <- chcons) {
|
||||
val chconc = chconsc.createSection(chcon.channel.getId.asString)
|
||||
chconc.set("mcchid", chcon.mcchannel.ID)
|
||||
chconc.set("mcchid", chcon.mcchannel.getIdentifier)
|
||||
chconc.set("chid", chcon.channel.getId.asLong)
|
||||
chconc.set("did", chcon.user.getId.asLong)
|
||||
chconc.set("mcuid", chcon.dcp.getUniqueId.toString)
|
||||
|
@ -222,13 +210,13 @@ class MinecraftChatModule extends Component[DiscordPlugin] {
|
|||
*/
|
||||
private def sendStateMessage(color: Color, message: String) =
|
||||
MCChatUtils.forCustomAndAllMCChat(_.flatMap(
|
||||
_.createEmbed(_.setColor(color).setTitle(message).^^()).^^()
|
||||
.onErrorResume(_ => SMono.empty)
|
||||
_.createEmbed(_.setColor(color).setTitle(message))
|
||||
.onErrorResume(_ => Mono.empty)
|
||||
), ChannelconBroadcast.RESTART, hookmsg = false).block()
|
||||
|
||||
private def sendStateMessage(color: Color, message: String, extra: String) =
|
||||
MCChatUtils.forCustomAndAllMCChat(_.flatMap(
|
||||
_.createEmbed(_.setColor(color).setTitle(message).setDescription(extra).^^()).^^()
|
||||
.onErrorResume(_ => SMono.empty)
|
||||
_.createEmbed(_.setColor(color).setTitle(message).setDescription(extra))
|
||||
.onErrorResume(_ => Mono.empty)
|
||||
), ChannelconBroadcast.RESTART, hookmsg = false).block()
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
package buttondevteam.discordplugin.mcchat.playerfaker
|
||||
|
||||
import org.mockito.MockedConstruction
|
||||
import org.mockito.internal.creation.bytebuddy.SubclassByteBuddyMockMaker
|
||||
import org.mockito.invocation.MockHandler
|
||||
import org.mockito.mock.MockCreationSettings
|
||||
import org.mockito.plugins.MockMaker
|
||||
|
||||
import java.util.Optional
|
||||
|
||||
object DelegatingMockMaker {
|
||||
def getInstance: DelegatingMockMaker = DelegatingMockMaker.instance
|
||||
|
||||
private var instance: DelegatingMockMaker = null
|
||||
}
|
||||
|
||||
class DelegatingMockMaker() extends MockMaker {
|
||||
DelegatingMockMaker.instance = this
|
||||
|
||||
override def createMock[T](settings: MockCreationSettings[T], handler: MockHandler[_]): T =
|
||||
this.mockMaker.createMock(settings, handler)
|
||||
|
||||
override def createSpy[T](settings: MockCreationSettings[T], handler: MockHandler[_], instance: T): Optional[T] =
|
||||
this.mockMaker.createSpy(settings, handler, instance)
|
||||
|
||||
override def getHandler(mock: Any): MockHandler[_] =
|
||||
this.mockMaker.getHandler(mock)
|
||||
|
||||
override def resetMock(mock: Any, newHandler: MockHandler[_], settings: MockCreationSettings[_]): Unit = {
|
||||
this.mockMaker.resetMock(mock, newHandler, settings)
|
||||
}
|
||||
|
||||
override def isTypeMockable(`type`: Class[_]): MockMaker.TypeMockability =
|
||||
this.mockMaker.isTypeMockable(`type`)
|
||||
|
||||
override def createStaticMock[T](`type`: Class[T], settings: MockCreationSettings[T], handler: MockHandler[_]): MockMaker.StaticMockControl[T] =
|
||||
this.mockMaker.createStaticMock(`type`, settings, handler)
|
||||
|
||||
override def createConstructionMock[T](`type`: Class[T], settingsFactory: java.util.function.Function[MockedConstruction.Context,
|
||||
MockCreationSettings[T]], handlerFactory: java.util.function.Function[MockedConstruction.Context,
|
||||
MockHandler[T]], mockInitializer: MockedConstruction.MockInitializer[T]): MockMaker.ConstructionMockControl[T] =
|
||||
this.mockMaker.createConstructionMock[T](`type`, settingsFactory, handlerFactory, mockInitializer)
|
||||
|
||||
def setMockMaker(mockMaker: MockMaker): Unit = {
|
||||
this.mockMaker = mockMaker
|
||||
}
|
||||
|
||||
def getMockMaker: MockMaker = this.mockMaker
|
||||
|
||||
private var mockMaker: MockMaker = new SubclassByteBuddyMockMaker
|
||||
}
|
|
@ -1,218 +0,0 @@
|
|||
package buttondevteam.discordplugin.mcchat.playerfaker;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.HumanEntity;
|
||||
import org.bukkit.event.inventory.InventoryType;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.InventoryHolder;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class DiscordInventory implements Inventory {
|
||||
private ItemStack[] items = new ItemStack[27];
|
||||
private List<ItemStack> itemStacks = Arrays.asList(items);
|
||||
|
||||
public int maxStackSize;
|
||||
private static ItemStack emptyStack = new ItemStack(Material.AIR, 0);
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return items.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxStackSize() {
|
||||
return maxStackSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxStackSize(int maxStackSize) {
|
||||
this.maxStackSize = maxStackSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Discord inventory";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItem(int index) {
|
||||
if (index >= items.length)
|
||||
return emptyStack;
|
||||
else
|
||||
return items[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setItem(int index, ItemStack item) {
|
||||
if (index < items.length)
|
||||
items[index] = item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashMap<Integer, ItemStack> addItem(ItemStack... items) throws IllegalArgumentException {
|
||||
return IntStream.range(0, items.length).collect(HashMap::new, (map, i) -> map.put(i, items[i]), HashMap::putAll); //Pretend that we can't add anything
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashMap<Integer, ItemStack> removeItem(ItemStack... items) throws IllegalArgumentException {
|
||||
return IntStream.range(0, items.length).collect(HashMap::new, (map, i) -> map.put(i, items[i]), HashMap::putAll); //Pretend that we can't add anything
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack[] getContents() {
|
||||
return items;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContents(ItemStack[] items) throws IllegalArgumentException {
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack[] getStorageContents() {
|
||||
return items;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStorageContents(ItemStack[] items) throws IllegalArgumentException {
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public boolean contains(int materialId) {
|
||||
return itemStacks.stream().anyMatch(is -> is.getType().getId() == materialId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Material material) throws IllegalArgumentException {
|
||||
return itemStacks.stream().anyMatch(is -> is.getType() == material);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(ItemStack item) {
|
||||
return itemStacks.stream().anyMatch(is -> is.getType() == item.getType() && is.getAmount() == item.getAmount());
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public boolean contains(int materialId, int amount) {
|
||||
return itemStacks.stream().anyMatch(is -> is.getType().getId() == materialId && is.getAmount() == amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Material material, int amount) throws IllegalArgumentException {
|
||||
return itemStacks.stream().anyMatch(is -> is.getType() == material && is.getAmount() == amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(ItemStack item, int amount) { //Not correct implementation but whatever
|
||||
return itemStacks.stream().anyMatch(is -> is.getType() == item.getType() && is.getAmount() == amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAtLeast(ItemStack item, int amount) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public HashMap<Integer, ? extends ItemStack> all(int materialId) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashMap<Integer, ? extends ItemStack> all(Material material) throws IllegalArgumentException {
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashMap<Integer, ? extends ItemStack> all(ItemStack item) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public int first(int materialId) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int first(Material material) throws IllegalArgumentException {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int first(ItemStack item) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int firstEmpty() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public void remove(int materialId) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(Material material) throws IllegalArgumentException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(ItemStack item) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear(int index) {
|
||||
if (index < items.length)
|
||||
items[index] = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
Arrays.fill(items, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<HumanEntity> getViewers() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "Discord inventory";
|
||||
}
|
||||
|
||||
@Override
|
||||
public InventoryType getType() {
|
||||
return InventoryType.CHEST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InventoryHolder getHolder() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("NullableProblems")
|
||||
@Override
|
||||
public ListIterator<ItemStack> iterator() {
|
||||
return itemStacks.listIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListIterator<ItemStack> iterator(int index) {
|
||||
return itemStacks.listIterator(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getLocation() {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -1,94 +0,0 @@
|
|||
package buttondevteam.discordplugin.mcchat.playerfaker
|
||||
|
||||
import buttondevteam.discordplugin.mcchat.MCChatUtils
|
||||
import buttondevteam.discordplugin.mcchat.sender.DiscordConnectedPlayer
|
||||
import com.destroystokyo.paper.profile.CraftPlayerProfile
|
||||
import net.bytebuddy.implementation.bind.annotation.IgnoreForBinding
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.{Bukkit, Server}
|
||||
import org.mockito.Mockito
|
||||
import org.mockito.internal.creation.bytebuddy.InlineByteBuddyMockMaker
|
||||
import org.mockito.invocation.InvocationOnMock
|
||||
|
||||
import java.lang.reflect.Modifier
|
||||
import java.util
|
||||
import java.util.*
|
||||
|
||||
object ServerWatcher {
|
||||
|
||||
class AppendListView[T](private val originalList: java.util.List[T], private val additionalList: java.util.List[T]) extends java.util.AbstractSequentialList[T] {
|
||||
|
||||
override def listIterator(i: Int): util.ListIterator[T] = {
|
||||
val os = originalList.size
|
||||
if (i < os) originalList.listIterator(i)
|
||||
else additionalList.listIterator(i - os)
|
||||
}
|
||||
|
||||
override def size: Int = originalList.size + additionalList.size
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ServerWatcher {
|
||||
final val fakePlayers = new util.ArrayList[Player]
|
||||
private var origServer: Server = null
|
||||
|
||||
@IgnoreForBinding
|
||||
@throws[Exception]
|
||||
def enableDisable(enable: Boolean): Unit = {
|
||||
val serverField = classOf[Bukkit].getDeclaredField("server")
|
||||
serverField.setAccessible(true)
|
||||
if (enable) {
|
||||
val serverClass = Bukkit.getServer.getClass
|
||||
val originalServer = serverField.get(null)
|
||||
DelegatingMockMaker.getInstance.setMockMaker(new InlineByteBuddyMockMaker)
|
||||
val settings = Mockito.withSettings.stubOnly.defaultAnswer((invocation: InvocationOnMock) => {
|
||||
def foo(invocation: InvocationOnMock): AnyRef = {
|
||||
val method = invocation.getMethod
|
||||
val pc = method.getParameterCount
|
||||
var player = Option.empty[DiscordConnectedPlayer]
|
||||
method.getName match {
|
||||
case "getPlayer" =>
|
||||
if (pc == 1 && (method.getParameterTypes()(0) == classOf[UUID]))
|
||||
player = MCChatUtils.LoggedInPlayers.get(invocation.getArgument[UUID](0))
|
||||
case "getPlayerExact" =>
|
||||
if (pc == 1) {
|
||||
val argument = invocation.getArgument(0)
|
||||
player = MCChatUtils.LoggedInPlayers.values.find(_.getName.equalsIgnoreCase(argument))
|
||||
}
|
||||
|
||||
/*case "getOnlinePlayers":
|
||||
if (playerList == null) {
|
||||
@SuppressWarnings("unchecked") var list = (List<Player>) method.invoke(origServer, invocation.getArguments());
|
||||
playerList = new AppendListView<>(list, fakePlayers);
|
||||
} - Your scientists were so preoccupied with whether or not they could, they didn’t stop to think if they should.
|
||||
return playerList;*/
|
||||
case "createProfile" => //Paper's method, casts the player to a CraftPlayer
|
||||
if (pc == 2) {
|
||||
val uuid = invocation.getArgument(0)
|
||||
val name = invocation.getArgument(1)
|
||||
player = if (uuid != null) MCChatUtils.LoggedInPlayers.get(uuid) else Option.empty
|
||||
if (player.isEmpty && name != null)
|
||||
player = MCChatUtils.LoggedInPlayers.values.find(_.getName.equalsIgnoreCase(name))
|
||||
if (player.nonEmpty)
|
||||
return new CraftPlayerProfile(player.get.getUniqueId, player.get.getName)
|
||||
}
|
||||
}
|
||||
if (player.nonEmpty) return player.get
|
||||
method.invoke(origServer, invocation.getArguments)
|
||||
}
|
||||
|
||||
foo(invocation)
|
||||
})
|
||||
//var mock = mockMaker.createMock(settings, MockHandlerFactory.createMockHandler(settings));
|
||||
//thread.setContextClassLoader(cl);
|
||||
val mock = Mockito.mock(serverClass, settings)
|
||||
for (field <- serverClass.getFields) { //Copy public fields, private fields aren't accessible directly anyways
|
||||
if (!Modifier.isFinal(field.getModifiers) && !Modifier.isStatic(field.getModifiers)) field.set(mock, field.get(originalServer))
|
||||
}
|
||||
serverField.set(null, mock)
|
||||
origServer = originalServer.asInstanceOf[Server]
|
||||
}
|
||||
else if (origServer != null) serverField.set(null, origServer)
|
||||
}
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
package buttondevteam.discordplugin.mcchat.playerfaker
|
||||
|
||||
import buttondevteam.discordplugin.mcchat.MinecraftChatModule
|
||||
import buttondevteam.discordplugin.mcchat.sender.{DiscordSenderBase, IMCPlayer}
|
||||
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
|
||||
}
|
|
@ -1,84 +0,0 @@
|
|||
package buttondevteam.discordplugin.mcchat.playerfaker
|
||||
|
||||
import buttondevteam.discordplugin.mcchat.sender.{DiscordSenderBase, IMCPlayer}
|
||||
import net.minecraft.server.v1_12_R1.*
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.craftbukkit.v1_12_R1.command.VanillaCommandWrapper
|
||||
import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer
|
||||
import org.bukkit.craftbukkit.v1_12_R1.{CraftServer, CraftWorld}
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
import java.util
|
||||
|
||||
object VanillaCommandListener {
|
||||
def runBukkitOrVanillaCommand(dsender: DiscordSenderBase, cmdstr: String): Boolean = {
|
||||
val cmd = Bukkit.getServer.asInstanceOf[CraftServer].getCommandMap.getCommand(cmdstr.split(" ")(0).toLowerCase)
|
||||
if (!dsender.isInstanceOf[Player] || !cmd.isInstanceOf[VanillaCommandWrapper])
|
||||
return Bukkit.dispatchCommand(dsender, cmdstr) // Unconnected users are treated well in vanilla cmds
|
||||
if (!dsender.isInstanceOf[IMCPlayer[_]])
|
||||
throw new ClassCastException("dsender needs to implement IMCPlayer to use vanilla commands as it implements Player.")
|
||||
val sender = dsender.asInstanceOf[IMCPlayer[_]]
|
||||
val vcmd = cmd.asInstanceOf[VanillaCommandWrapper]
|
||||
if (!vcmd.testPermission(sender)) return true
|
||||
val icommandlistener = sender.getVanillaCmdListener.getListener.asInstanceOf[ICommandListener]
|
||||
if (icommandlistener == null) return VCMDWrapper.compatResponse(dsender)
|
||||
var args = cmdstr.split(" ")
|
||||
args = util.Arrays.copyOfRange(args, 1, args.length)
|
||||
try vcmd.dispatchVanillaCommand(sender, icommandlistener, args)
|
||||
catch {
|
||||
case commandexception: CommandException =>
|
||||
// Taken from CommandHandler
|
||||
val chatmessage = new ChatMessage(commandexception.getMessage, commandexception.getArgs)
|
||||
chatmessage.getChatModifier.setColor(EnumChatFormat.RED)
|
||||
icommandlistener.sendMessage(chatmessage)
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
class VanillaCommandListener[T <: DiscordSenderBase with IMCPlayer[T]] extends ICommandListener {
|
||||
def getPlayer: T = this.player
|
||||
|
||||
private var player: T = null.asInstanceOf
|
||||
private var bukkitplayer: Player = null
|
||||
|
||||
/**
|
||||
* This constructor will only send raw vanilla messages to the sender in plain text.
|
||||
*
|
||||
* @param player The Discord sender player (the wrapper)
|
||||
*/
|
||||
def this(player: T) = {
|
||||
this()
|
||||
this.player = player
|
||||
this.bukkitplayer = null
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
def this(player: T, bukkitplayer: Player) = {
|
||||
this()
|
||||
this.player = player
|
||||
this.bukkitplayer = bukkitplayer
|
||||
if (bukkitplayer != null && !bukkitplayer.isInstanceOf[CraftPlayer])
|
||||
throw new ClassCastException("bukkitplayer must be a Bukkit player!")
|
||||
}
|
||||
|
||||
override def C_(): MinecraftServer = Bukkit.getServer.asInstanceOf[CraftServer].getServer
|
||||
|
||||
override def a(oplevel: Int, cmd: String): Boolean = { //return oplevel <= 2; // Value from CommandBlockListenerAbstract, found what it is in EntityPlayer - Wait, that'd always allow OP commands
|
||||
oplevel == 0 || player.isOp
|
||||
}
|
||||
|
||||
override def getName: String = player.getName
|
||||
|
||||
override def getWorld: World = player.getWorld.asInstanceOf[CraftWorld].getHandle
|
||||
|
||||
override def sendMessage(arg0: IChatBaseComponent): Unit = {
|
||||
player.sendMessage(arg0.toPlainText)
|
||||
if (bukkitplayer != null) bukkitplayer.asInstanceOf[CraftPlayer].getHandle.sendMessage(arg0)
|
||||
}
|
||||
}
|
|
@ -1,84 +0,0 @@
|
|||
package buttondevteam.discordplugin.mcchat.playerfaker
|
||||
|
||||
import buttondevteam.discordplugin.mcchat.sender.{DiscordSenderBase, IMCPlayer}
|
||||
import net.minecraft.server.v1_14_R1.*
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.command.CommandSender
|
||||
import org.bukkit.craftbukkit.v1_14_R1.command.{ProxiedNativeCommandSender, VanillaCommandWrapper}
|
||||
import org.bukkit.craftbukkit.v1_14_R1.entity.CraftPlayer
|
||||
import org.bukkit.craftbukkit.v1_14_R1.{CraftServer, CraftWorld}
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
import java.util
|
||||
|
||||
object VanillaCommandListener14 {
|
||||
def runBukkitOrVanillaCommand(dsender: DiscordSenderBase, cmdstr: String): Boolean = {
|
||||
val cmd = Bukkit.getServer.asInstanceOf[CraftServer].getCommandMap.getCommand(cmdstr.split(" ")(0).toLowerCase)
|
||||
if (!dsender.isInstanceOf[Player] || !cmd.isInstanceOf[VanillaCommandWrapper])
|
||||
return Bukkit.dispatchCommand(dsender, cmdstr) // Unconnected users are treated well in vanilla cmds
|
||||
if (!dsender.isInstanceOf[IMCPlayer[_]])
|
||||
throw new ClassCastException("dsender needs to implement IMCPlayer to use vanilla commands as it implements Player.")
|
||||
val sender = dsender.asInstanceOf[IMCPlayer[_]] // Don't use val on recursive interfaces :P
|
||||
val vcmd = cmd.asInstanceOf[VanillaCommandWrapper]
|
||||
if (!vcmd.testPermission(sender)) return true
|
||||
val world = Bukkit.getWorlds.get(0).asInstanceOf[CraftWorld].getHandle
|
||||
val icommandlistener = sender.getVanillaCmdListener.getListener.asInstanceOf[ICommandListener]
|
||||
if (icommandlistener == null) return VCMDWrapper.compatResponse(dsender)
|
||||
val wrapper = new CommandListenerWrapper(icommandlistener, new Vec3D(0, 0, 0), new Vec2F(0, 0), world, 0, sender.getName, new ChatComponentText(sender.getName), world.getMinecraftServer, null)
|
||||
val pncs = new ProxiedNativeCommandSender(wrapper, sender, sender)
|
||||
var args = cmdstr.split(" ")
|
||||
args = util.Arrays.copyOfRange(args, 1, args.length)
|
||||
try return vcmd.execute(pncs, cmd.getLabel, args)
|
||||
catch {
|
||||
case commandexception: CommandException =>
|
||||
// Taken from CommandHandler
|
||||
val chatmessage = new ChatMessage(commandexception.getMessage, commandexception.a)
|
||||
chatmessage.getChatModifier.setColor(EnumChatFormat.RED)
|
||||
icommandlistener.sendMessage(chatmessage)
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
class VanillaCommandListener14[T <: DiscordSenderBase with IMCPlayer[T]] extends ICommandListener {
|
||||
def getPlayer: T = this.player
|
||||
|
||||
private var player: T = null.asInstanceOf
|
||||
private var bukkitplayer: Player = null
|
||||
|
||||
/**
|
||||
* This constructor will only send raw vanilla messages to the sender in plain text.
|
||||
*
|
||||
* @param player The Discord sender player (the wrapper)
|
||||
*/
|
||||
def this(player: T) = {
|
||||
this()
|
||||
this.player = player
|
||||
this.bukkitplayer = null
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
def this(player: T, bukkitplayer: Player) = {
|
||||
this()
|
||||
this.player = player
|
||||
this.bukkitplayer = bukkitplayer
|
||||
if (bukkitplayer != null && !bukkitplayer.isInstanceOf[CraftPlayer]) throw new ClassCastException("bukkitplayer must be a Bukkit player!")
|
||||
}
|
||||
|
||||
override def sendMessage(arg0: IChatBaseComponent): scala.Unit = {
|
||||
player.sendMessage(arg0.getString)
|
||||
if (bukkitplayer != null) bukkitplayer.asInstanceOf[CraftPlayer].getHandle.sendMessage(arg0)
|
||||
}
|
||||
|
||||
override def shouldSendSuccess = true
|
||||
|
||||
override def shouldSendFailure = true
|
||||
|
||||
override def shouldBroadcastCommands = true //Broadcast to in-game admins
|
||||
override def getBukkitSender(commandListenerWrapper: CommandListenerWrapper): CommandSender = player
|
||||
}
|
|
@ -1,123 +0,0 @@
|
|||
package buttondevteam.discordplugin.mcchat.playerfaker
|
||||
|
||||
import buttondevteam.discordplugin.mcchat.sender.{DiscordSenderBase, IMCPlayer}
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.command.{CommandSender, SimpleCommandMap}
|
||||
import org.bukkit.entity.Player
|
||||
import org.mockito.{Answers, Mockito}
|
||||
|
||||
import java.lang.reflect.Modifier
|
||||
import java.util
|
||||
|
||||
/**
|
||||
* Same as {@link VanillaCommandListener14} but with reflection
|
||||
*/
|
||||
object VanillaCommandListener15 {
|
||||
private var vcwcl: Class[_] = null
|
||||
private var nms: String = null
|
||||
|
||||
/**
|
||||
* This method will only send raw vanilla messages to the sender in plain text.
|
||||
*
|
||||
* @param player The Discord sender player (the wrapper)
|
||||
*/
|
||||
@throws[Exception]
|
||||
def create[T <: DiscordSenderBase with IMCPlayer[T]](player: T): VanillaCommandListener15[T] = create(player, null)
|
||||
|
||||
/**
|
||||
* This method 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
|
||||
*/
|
||||
@SuppressWarnings(Array("unchecked"))
|
||||
@throws[Exception]
|
||||
def create[T <: DiscordSenderBase with IMCPlayer[T]](player: T, bukkitplayer: Player): VanillaCommandListener15[T] = {
|
||||
if (vcwcl == null) {
|
||||
val pkg = Bukkit.getServer.getClass.getPackage.getName
|
||||
vcwcl = Class.forName(pkg + ".command.VanillaCommandWrapper")
|
||||
}
|
||||
if (nms == null) {
|
||||
val server = Bukkit.getServer
|
||||
nms = server.getClass.getMethod("getServer").invoke(server).getClass.getPackage.getName //org.mockito.codegen
|
||||
}
|
||||
val iclcl = Class.forName(nms + ".ICommandListener")
|
||||
Mockito.mock(classOf[VanillaCommandListener15[T]],
|
||||
Mockito.withSettings.stubOnly.useConstructor(player, bukkitplayer)
|
||||
.extraInterfaces(iclcl).defaultAnswer(invocation => {
|
||||
if (invocation.getMethod.getName == "sendMessage") {
|
||||
val icbc = invocation.getArgument(0)
|
||||
player.sendMessage(icbc.getClass.getMethod("getString").invoke(icbc).asInstanceOf[String])
|
||||
if (bukkitplayer != null) {
|
||||
val handle = bukkitplayer.getClass.getMethod("getHandle").invoke(bukkitplayer)
|
||||
handle.getClass.getMethod("sendMessage", icbc.getClass).invoke(handle, icbc)
|
||||
}
|
||||
null
|
||||
}
|
||||
else if (!Modifier.isAbstract(invocation.getMethod.getModifiers)) invocation.callRealMethod
|
||||
else if (invocation.getMethod.getReturnType eq classOf[Boolean]) true //shouldSend... shouldBroadcast...
|
||||
else if (invocation.getMethod.getReturnType eq classOf[CommandSender]) player
|
||||
else Answers.RETURNS_DEFAULTS.answer(invocation)
|
||||
}))
|
||||
}
|
||||
|
||||
@throws[Exception]
|
||||
def runBukkitOrVanillaCommand(dsender: DiscordSenderBase, cmdstr: String): Boolean = {
|
||||
val server = Bukkit.getServer
|
||||
val cmap = server.getClass.getMethod("getCommandMap").invoke(server).asInstanceOf[SimpleCommandMap]
|
||||
val cmd = cmap.getCommand(cmdstr.split(" ")(0).toLowerCase)
|
||||
if (!dsender.isInstanceOf[Player] || cmd == null || !vcwcl.isAssignableFrom(cmd.getClass))
|
||||
return Bukkit.dispatchCommand(dsender, cmdstr) // Unconnected users are treated well in vanilla cmds
|
||||
if (!dsender.isInstanceOf[IMCPlayer[_]])
|
||||
throw new ClassCastException("dsender needs to implement IMCPlayer to use vanilla commands as it implements Player.")
|
||||
val sender = dsender.asInstanceOf[IMCPlayer[_]] // Don't use val on recursive interfaces :P
|
||||
if (!vcwcl.getMethod("testPermission", classOf[CommandSender]).invoke(cmd, sender).asInstanceOf[Boolean])
|
||||
return true
|
||||
val cworld = Bukkit.getWorlds.get(0)
|
||||
val world = cworld.getClass.getMethod("getHandle").invoke(cworld)
|
||||
val icommandlistener = sender.getVanillaCmdListener.getListener
|
||||
if (icommandlistener == null) return VCMDWrapper.compatResponse(dsender)
|
||||
val clwcl = Class.forName(nms + ".CommandListenerWrapper")
|
||||
val v3dcl = Class.forName(nms + ".Vec3D")
|
||||
val v2fcl = Class.forName(nms + ".Vec2F")
|
||||
val icbcl = Class.forName(nms + ".IChatBaseComponent")
|
||||
val mcscl = Class.forName(nms + ".MinecraftServer")
|
||||
val ecl = Class.forName(nms + ".Entity")
|
||||
val cctcl = Class.forName(nms + ".ChatComponentText")
|
||||
val iclcl = Class.forName(nms + ".ICommandListener")
|
||||
val wrapper = clwcl.getConstructor(iclcl, v3dcl, v2fcl, world.getClass, classOf[Int], classOf[String], icbcl, mcscl, ecl)
|
||||
.newInstance(icommandlistener, v3dcl.getConstructor(classOf[Double], classOf[Double], classOf[Double])
|
||||
.newInstance(0, 0, 0), v2fcl.getConstructor(classOf[Float], classOf[Float])
|
||||
.newInstance(0, 0), world, 0, sender.getName, cctcl.getConstructor(classOf[String])
|
||||
.newInstance(sender.getName), world.getClass.getMethod("getMinecraftServer").invoke(world), null)
|
||||
/*val wrapper = new CommandListenerWrapper(icommandlistener, new Vec3D(0, 0, 0),
|
||||
new Vec2F(0, 0), world, 0, sender.getName(),
|
||||
new ChatComponentText(sender.getName()), world.getMinecraftServer(), null);*/
|
||||
val pncscl = Class.forName(vcwcl.getPackage.getName + ".ProxiedNativeCommandSender")
|
||||
val pncs = pncscl.getConstructor(clwcl, classOf[CommandSender], classOf[CommandSender])
|
||||
.newInstance(wrapper, sender, sender)
|
||||
var args = cmdstr.split(" ")
|
||||
args = util.Arrays.copyOfRange(args, 1, args.length)
|
||||
try return cmd.execute(pncs.asInstanceOf[CommandSender], cmd.getLabel, args)
|
||||
catch {
|
||||
case commandexception: Exception =>
|
||||
if (!(commandexception.getClass.getSimpleName == "CommandException")) throw commandexception
|
||||
// Taken from CommandHandler
|
||||
val cmcl = Class.forName(nms + ".ChatMessage")
|
||||
val chatmessage = cmcl.getConstructor(classOf[String], classOf[Array[AnyRef]])
|
||||
.newInstance(commandexception.getMessage, Array[AnyRef](commandexception.getClass.getMethod("a").invoke(commandexception)))
|
||||
val modifier = cmcl.getMethod("getChatModifier").invoke(chatmessage)
|
||||
val ecfcl = Class.forName(nms + ".EnumChatFormat")
|
||||
modifier.getClass.getMethod("setColor", ecfcl).invoke(modifier, ecfcl.getField("RED").get(null))
|
||||
icommandlistener.getClass.getMethod("sendMessage", icbcl).invoke(icommandlistener, chatmessage)
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
class VanillaCommandListener15[T <: DiscordSenderBase with IMCPlayer[T]] protected(var player: T, val bukkitplayer: Player) {
|
||||
if (bukkitplayer != null && !bukkitplayer.getClass.getSimpleName.endsWith("CraftPlayer"))
|
||||
throw new ClassCastException("bukkitplayer must be a Bukkit player!")
|
||||
|
||||
def getPlayer: T = this.player
|
||||
}
|
|
@ -1,207 +0,0 @@
|
|||
package buttondevteam.discordplugin.mcchat.playerfaker.perm;
|
||||
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
public final class LPInjector implements Listener { //Disable login event for LuckPerms
|
||||
/*private final LPBukkitPlugin plugin;
|
||||
private final BukkitConnectionListener connectionListener;
|
||||
private final Set<UUID> deniedLogin;
|
||||
private final Field detectedCraftBukkitOfflineMode;
|
||||
private final Method printCraftBukkitOfflineModeError;
|
||||
private final Field PERMISSIBLE_BASE_ATTACHMENTS_FIELD;
|
||||
private final Method convertAndAddAttachments;
|
||||
private final Method getActive;
|
||||
private final Method setOldPermissible;
|
||||
private final Method getOldPermissible;
|
||||
|
||||
public LPInjector(DiscordPlugin dp) throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException {
|
||||
LPBukkitBootstrap bs = (LPBukkitBootstrap) Bukkit.getPluginManager().getPlugin("LuckPerms");
|
||||
Field field = LPBukkitBootstrap.class.getDeclaredField("plugin");
|
||||
field.setAccessible(true);
|
||||
plugin = (LPBukkitPlugin) field.get(bs);
|
||||
MCChatUtils.addStaticExcludedPlugin(PlayerLoginEvent.class, "LuckPerms");
|
||||
MCChatUtils.addStaticExcludedPlugin(PlayerQuitEvent.class, "LuckPerms");
|
||||
|
||||
field = LPBukkitPlugin.class.getDeclaredField("connectionListener");
|
||||
field.setAccessible(true);
|
||||
connectionListener = (BukkitConnectionListener) field.get(plugin);
|
||||
field = connectionListener.getClass().getDeclaredField("deniedLogin");
|
||||
field.setAccessible(true);
|
||||
//noinspection unchecked
|
||||
deniedLogin = (Set<UUID>) field.get(connectionListener);
|
||||
field = connectionListener.getClass().getDeclaredField("detectedCraftBukkitOfflineMode");
|
||||
field.setAccessible(true);
|
||||
detectedCraftBukkitOfflineMode = field;
|
||||
printCraftBukkitOfflineModeError = connectionListener.getClass().getDeclaredMethod("printCraftBukkitOfflineModeError");
|
||||
printCraftBukkitOfflineModeError.setAccessible(true);
|
||||
|
||||
//PERMISSIBLE_FIELD = DiscordFakePlayer.class.getDeclaredField("perm");
|
||||
//PERMISSIBLE_FIELD.setAccessible(true); //Hacking my own plugin, while we're at it
|
||||
PERMISSIBLE_BASE_ATTACHMENTS_FIELD = PermissibleBase.class.getDeclaredField("attachments");
|
||||
PERMISSIBLE_BASE_ATTACHMENTS_FIELD.setAccessible(true);
|
||||
|
||||
convertAndAddAttachments = LuckPermsPermissible.class.getDeclaredMethod("convertAndAddAttachments", Collection.class);
|
||||
convertAndAddAttachments.setAccessible(true);
|
||||
getActive = LuckPermsPermissible.class.getDeclaredMethod("getActive");
|
||||
getActive.setAccessible(true);
|
||||
setOldPermissible = LuckPermsPermissible.class.getDeclaredMethod("setOldPermissible", PermissibleBase.class);
|
||||
setOldPermissible.setAccessible(true);
|
||||
getOldPermissible = LuckPermsPermissible.class.getDeclaredMethod("getOldPermissible");
|
||||
getOldPermissible.setAccessible(true);
|
||||
|
||||
TBMCCoreAPI.RegisterEventsForExceptions(this, dp);
|
||||
}
|
||||
|
||||
|
||||
//Code copied from LuckPerms - me.lucko.luckperms.bukkit.listeners.BukkitConnectionListener
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onPlayerLogin(PlayerLoginEvent e) {*/
|
||||
/* Called when the player starts logging into the server.
|
||||
At this point, the users data should be present and loaded. */
|
||||
|
||||
/*if (!(e.getPlayer() instanceof DiscordConnectedPlayer))
|
||||
return; //Normal players must be handled by the plugin
|
||||
|
||||
final DiscordConnectedPlayer player = (DiscordConnectedPlayer) e.getPlayer();
|
||||
|
||||
if (plugin.getConfiguration().get(ConfigKeys.DEBUG_LOGINS)) {
|
||||
plugin.getLogger().info("Processing login for " + player.getUniqueId() + " - " + player.getName());
|
||||
}
|
||||
|
||||
final User user = plugin.getUserManager().getIfLoaded(player.getUniqueId());
|
||||
|
||||
/* User instance is null for whatever reason. Could be that it was unloaded between asyncpre and now. */
|
||||
/*if (user == null) {
|
||||
deniedLogin.add(player.getUniqueId());
|
||||
|
||||
if (!plugin.getConnectionListener().getUniqueConnections().contains(player.getUniqueId())) {
|
||||
|
||||
plugin.getLogger().warn("User " + player.getUniqueId() + " - " + player.getName() +
|
||||
" doesn't have data pre-loaded, they have never been processed during pre-login in this session." +
|
||||
" - denying login.");
|
||||
|
||||
try {
|
||||
if ((Boolean) detectedCraftBukkitOfflineMode.get(connectionListener)) {
|
||||
printCraftBukkitOfflineModeError.invoke(connectionListener);
|
||||
|
||||
Component reason = TranslationManager.render(Message.LOADING_STATE_ERROR_CB_OFFLINE_MODE.build(), player.getLocale());
|
||||
e.disallow(PlayerLoginEvent.Result.KICK_OTHER, LegacyComponentSerializer.legacySection().serialize(reason));
|
||||
return;
|
||||
}
|
||||
} catch (IllegalAccessException | InvocationTargetException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
} else {
|
||||
plugin.getLogger().warn("User " + player.getUniqueId() + " - " + player.getName() +
|
||||
" doesn't currently have data pre-loaded, but they have been processed before in this session." +
|
||||
" - denying login.");
|
||||
}
|
||||
|
||||
Component reason = TranslationManager.render(Message.LOADING_STATE_ERROR.build(), player.getLocale());
|
||||
e.disallow(PlayerLoginEvent.Result.KICK_OTHER, LegacyComponentSerializer.legacySection().serialize(reason));
|
||||
return;
|
||||
}
|
||||
|
||||
// User instance is there, now we can inject our custom Permissible into the player.
|
||||
// Care should be taken at this stage to ensure that async tasks which manipulate bukkit data check that the player is still online.
|
||||
try {
|
||||
// get the existing PermissibleBase held by the player
|
||||
PermissibleBase oldPermissible = player.getPerm();
|
||||
|
||||
// Make a new permissible for the user
|
||||
LuckPermsPermissible lpPermissible = new LuckPermsPermissible(player, user, this.plugin);
|
||||
|
||||
// Inject into the player
|
||||
inject(player, lpPermissible, oldPermissible);
|
||||
|
||||
} catch (Throwable t) {
|
||||
plugin.getLogger().warn("Exception thrown when setting up permissions for " +
|
||||
player.getUniqueId() + " - " + player.getName() + " - denying login.");
|
||||
t.printStackTrace();
|
||||
|
||||
Component reason = TranslationManager.render(Message.LOADING_SETUP_ERROR.build(), player.getLocale());
|
||||
e.disallow(PlayerLoginEvent.Result.KICK_OTHER, LegacyComponentSerializer.legacySection().serialize(reason));
|
||||
return;
|
||||
}
|
||||
|
||||
this.plugin.getContextManager().signalContextUpdate(player);
|
||||
}
|
||||
|
||||
// Wait until the last priority to unload, so plugins can still perform permission checks on this event
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerQuit(PlayerQuitEvent e) {
|
||||
if (!(e.getPlayer() instanceof DiscordConnectedPlayer))
|
||||
return;
|
||||
|
||||
final DiscordConnectedPlayer player = (DiscordConnectedPlayer) e.getPlayer();
|
||||
|
||||
connectionListener.handleDisconnect(player.getUniqueId());
|
||||
|
||||
// perform unhooking from bukkit objects 1 tick later.
|
||||
// this allows plugins listening after us on MONITOR to still have intact permissions data
|
||||
this.plugin.getBootstrap().getServer().getScheduler().runTaskLater(this.plugin.getBootstrap(), () -> {
|
||||
// Remove the custom permissible
|
||||
try {
|
||||
uninject(player);
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
// Handle auto op
|
||||
if (this.plugin.getConfiguration().get(ConfigKeys.AUTO_OP)) {
|
||||
player.setOp(false);
|
||||
}
|
||||
|
||||
// remove their contexts cache
|
||||
this.plugin.getContextManager().onPlayerQuit(player);
|
||||
}, 1L);
|
||||
}
|
||||
|
||||
//me.lucko.luckperms.bukkit.inject.permissible.PermissibleInjector
|
||||
private void inject(DiscordConnectedPlayer player, LuckPermsPermissible newPermissible, PermissibleBase oldPermissible) throws IllegalAccessException, InvocationTargetException {
|
||||
|
||||
// seems we have already injected into this player.
|
||||
if (oldPermissible instanceof LuckPermsPermissible) {
|
||||
throw new IllegalStateException("LPPermissible already injected into player " + player.toString());
|
||||
}
|
||||
|
||||
// Move attachments over from the old permissible
|
||||
|
||||
//noinspection unchecked
|
||||
List<PermissionAttachment> attachments = (List<PermissionAttachment>) PERMISSIBLE_BASE_ATTACHMENTS_FIELD.get(oldPermissible);
|
||||
|
||||
convertAndAddAttachments.invoke(newPermissible, attachments);
|
||||
attachments.clear();
|
||||
oldPermissible.clearPermissions();
|
||||
|
||||
// Setup the new permissible
|
||||
((AtomicBoolean) getActive.invoke(newPermissible)).set(true);
|
||||
setOldPermissible.invoke(newPermissible, oldPermissible);
|
||||
|
||||
// inject the new instance
|
||||
player.setPerm(newPermissible);
|
||||
}
|
||||
|
||||
private void uninject(DiscordConnectedPlayer player) throws Exception {
|
||||
|
||||
// gets the players current permissible.
|
||||
PermissibleBase permissible = player.getPerm();
|
||||
|
||||
// only uninject if the permissible was a luckperms one.
|
||||
if (permissible instanceof LuckPermsPermissible) {
|
||||
LuckPermsPermissible lpPermissible = ((LuckPermsPermissible) permissible);
|
||||
|
||||
// clear all permissions
|
||||
lpPermissible.clearPermissions();
|
||||
|
||||
// set to inactive
|
||||
((AtomicBoolean) getActive.invoke(lpPermissible)).set(false);
|
||||
|
||||
// handle the replacement permissible.
|
||||
// just inject a dummy class. this is used when we know the player is about to quit the server.
|
||||
player.setPerm(DummyPermissibleBase.INSTANCE);
|
||||
|
||||
}
|
||||
}*/
|
||||
}
|
|
@ -1,12 +1,12 @@
|
|||
package buttondevteam.discordplugin.mcchat.sender
|
||||
|
||||
import buttondevteam.discordplugin.mcchat.MinecraftChatModule
|
||||
import buttondevteam.discordplugin.mcchat.playerfaker.{DiscordInventory, VCMDWrapper}
|
||||
import discord4j.core.`object`.entity.User
|
||||
import discord4j.core.`object`.entity.channel.MessageChannel
|
||||
import org.bukkit.*
|
||||
import org.bukkit.attribute.{Attribute, AttributeInstance, AttributeModifier}
|
||||
import org.bukkit.entity.{Entity, Player}
|
||||
import org.bukkit.event.inventory.InventoryType
|
||||
import org.bukkit.event.player.{AsyncPlayerChatEvent, PlayerTeleportEvent}
|
||||
import org.bukkit.inventory.{Inventory, PlayerInventory}
|
||||
import org.bukkit.permissions.{PermissibleBase, Permission, PermissionAttachment, PermissionAttachmentInfo}
|
||||
|
@ -31,10 +31,6 @@ object DiscordConnectedPlayer {
|
|||
try {
|
||||
if (!Modifier.isAbstract(invocation.getMethod.getModifiers))
|
||||
invocation.callRealMethod
|
||||
else if (classOf[PlayerInventory].isAssignableFrom(invocation.getMethod.getReturnType))
|
||||
Mockito.mock(classOf[DiscordInventory], Mockito.withSettings.extraInterfaces(classOf[PlayerInventory]))
|
||||
else if (classOf[Inventory].isAssignableFrom(invocation.getMethod.getReturnType))
|
||||
new DiscordInventory
|
||||
else
|
||||
RETURNS_DEFAULTS.answer(invocation)
|
||||
} catch {
|
||||
|
@ -64,7 +60,8 @@ abstract class DiscordConnectedPlayer(user: User, channel: MessageChannel, val u
|
|||
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))
|
||||
private val vanillaCmdListener = null // TODO
|
||||
private val inventory: PlayerInventory = if (module == null) null else Bukkit.createInventory(this, InventoryType.PLAYER).asInstanceOf
|
||||
|
||||
override def isPermissionSet(name: String): Boolean = this.origPerm.isPermissionSet(name)
|
||||
|
||||
|
@ -97,7 +94,7 @@ abstract class DiscordConnectedPlayer(user: User, channel: MessageChannel, val u
|
|||
|
||||
override def setDisplayName(displayName: String): Unit = this.displayName = displayName
|
||||
|
||||
override def getVanillaCmdListener: VCMDWrapper = this.vanillaCmdListener
|
||||
override def getVanillaCmdListener = this.vanillaCmdListener
|
||||
|
||||
def isLoggedIn: Boolean = this.loggedIn
|
||||
|
||||
|
@ -197,6 +194,8 @@ abstract class DiscordConnectedPlayer(user: User, channel: MessageChannel, val u
|
|||
|
||||
override def getGameMode = GameMode.SPECTATOR
|
||||
|
||||
override def getInventory: PlayerInventory = inventory
|
||||
|
||||
//noinspection ScalaDeprecation
|
||||
/*@SuppressWarnings(Array("deprecation")) override def spigot: super.Spigot = new super.Spigot() {
|
||||
override def getRawAddress: InetSocketAddress = null
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package buttondevteam.discordplugin.mcchat.sender
|
||||
|
||||
import buttondevteam.discordplugin.mcchat.MinecraftChatModule
|
||||
import buttondevteam.discordplugin.mcchat.playerfaker.VCMDWrapper
|
||||
import discord4j.core.`object`.entity.User
|
||||
import discord4j.core.`object`.entity.channel.MessageChannel
|
||||
import org.bukkit.entity.Player
|
||||
|
@ -25,9 +24,8 @@ object DiscordPlayerSender {
|
|||
}
|
||||
|
||||
abstract class DiscordPlayerSender(user: User, channel: MessageChannel, var player: Player, val module: Nothing) extends DiscordSenderBase(user, channel) with IMCPlayer[DiscordPlayerSender] {
|
||||
val vanillaCmdListener = new VCMDWrapper(VCMDWrapper.createListener(this, player, module))
|
||||
|
||||
override def getVanillaCmdListener: VCMDWrapper = this.vanillaCmdListener
|
||||
override def getVanillaCmdListener = null
|
||||
|
||||
override def sendMessage(message: String): Unit = {
|
||||
player.sendMessage(message)
|
||||
|
@ -35,7 +33,7 @@ abstract class DiscordPlayerSender(user: User, channel: MessageChannel, var play
|
|||
}
|
||||
|
||||
override def sendMessage(messages: Array[String]): Unit = {
|
||||
player.sendMessage(messages)
|
||||
player.sendMessage(messages*)
|
||||
super.sendMessage(messages)
|
||||
}
|
||||
}
|
|
@ -7,15 +7,16 @@ import org.bukkit.command.CommandSender
|
|||
import org.bukkit.permissions.{PermissibleBase, Permission, PermissionAttachment, PermissionAttachmentInfo}
|
||||
import org.bukkit.plugin.Plugin
|
||||
import org.bukkit.{Bukkit, Server}
|
||||
import reactor.core.scala.publisher.SMono
|
||||
import reactor.core.publisher.Mono
|
||||
import scala.jdk.OptionConverters._
|
||||
|
||||
import java.util
|
||||
|
||||
class DiscordSender(user: User, channel: MessageChannel, pname: String) extends DiscordSenderBase(user, channel) with CommandSender {
|
||||
private val perm = new PermissibleBase(this)
|
||||
private val name: String = Option(pname)
|
||||
.orElse(Option(user).flatMap(u => SMono(u.asMember(DiscordPlugin.mainServer.getId))
|
||||
.onErrorResume(_ => SMono.empty).blockOption()
|
||||
.orElse(Option(user).flatMap(u => u.asMember(DiscordPlugin.mainServer.getId)
|
||||
.onErrorResume(_ => Mono.empty).blockOptional().toScala
|
||||
.map(u => u.getDisplayName)))
|
||||
.getOrElse("Discord user")
|
||||
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
package buttondevteam.discordplugin.mcchat.sender
|
||||
|
||||
import buttondevteam.discordplugin.mcchat.playerfaker.VCMDWrapper
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
trait IMCPlayer[T] extends Player {
|
||||
def getVanillaCmdListener: VCMDWrapper
|
||||
def getVanillaCmdListener: Null // TODO
|
||||
}
|
|
@ -5,6 +5,7 @@ import buttondevteam.discordplugin.mcchat.sender.{DiscordPlayer, DiscordSenderBa
|
|||
import buttondevteam.discordplugin.mcchat.{MCChatUtils, MinecraftChatModule}
|
||||
import buttondevteam.discordplugin.util.DPState
|
||||
import buttondevteam.discordplugin.{DPUtils, DiscordPlugin}
|
||||
import buttondevteam.lib.chat.commands.MCCommandSettings
|
||||
import buttondevteam.lib.chat.{Command2, CommandClass, ICommand2MC}
|
||||
import buttondevteam.lib.player.{ChromaGamerBase, TBMCPlayer, TBMCPlayerBase}
|
||||
import discord4j.core.`object`.ExtendedInvite
|
||||
|
@ -19,7 +20,8 @@ import java.lang.reflect.Method
|
|||
"Discord",
|
||||
"This command allows performing Discord-related actions."
|
||||
)) class DiscordMCCommand extends ICommand2MC {
|
||||
@Command2.Subcommand def accept(player: Player): Boolean = {
|
||||
@Command2.Subcommand
|
||||
def accept(player: Player): Boolean = {
|
||||
if (checkSafeMode(player)) return true
|
||||
val did = ConnectCommand.WaitingToConnect.get(player.getName)
|
||||
if (did == null) {
|
||||
|
@ -35,7 +37,8 @@ import java.lang.reflect.Method
|
|||
true
|
||||
}
|
||||
|
||||
@Command2.Subcommand def decline(player: Player): Boolean = {
|
||||
@Command2.Subcommand
|
||||
def decline(player: Player): Boolean = {
|
||||
if (checkSafeMode(player)) return true
|
||||
val did = ConnectCommand.WaitingToConnect.remove(player.getName)
|
||||
if (did == null) {
|
||||
|
@ -46,17 +49,21 @@ import java.lang.reflect.Method
|
|||
true
|
||||
}
|
||||
|
||||
@Command2.Subcommand(permGroup = Command2.Subcommand.MOD_GROUP, helpText = Array(
|
||||
@Command2.Subcommand(helpText = Array(
|
||||
"Reload Discord plugin",
|
||||
"Reloads the config. To apply some changes, you may need to also run /discord restart."
|
||||
)) def reload(sender: CommandSender): Unit =
|
||||
))
|
||||
@MCCommandSettings(permGroup = MCCommandSettings.MOD_GROUP)
|
||||
def reload(sender: CommandSender): Unit =
|
||||
if (DiscordPlugin.plugin.tryReloadConfig) sender.sendMessage("§bConfig reloaded.")
|
||||
else sender.sendMessage("§cFailed to reload config.")
|
||||
|
||||
@Command2.Subcommand(permGroup = Command2.Subcommand.MOD_GROUP, helpText = Array(
|
||||
@Command2.Subcommand(helpText = Array(
|
||||
"Restart the plugin", //
|
||||
"This command disables and then enables the plugin." //
|
||||
)) def restart(sender: CommandSender): Unit = {
|
||||
))
|
||||
@MCCommandSettings(permGroup = MCCommandSettings.MOD_GROUP)
|
||||
def restart(sender: CommandSender): Unit = {
|
||||
val task: Runnable = () => {
|
||||
def foo(): Unit = {
|
||||
if (!DiscordPlugin.plugin.tryReloadConfig) {
|
||||
|
@ -87,14 +94,16 @@ import java.lang.reflect.Method
|
|||
|
||||
@Command2.Subcommand(helpText = Array(
|
||||
"Version command",
|
||||
"Prints the plugin version")) def version(sender: CommandSender): Unit = {
|
||||
sender.sendMessage(VersionCommand.getVersion)
|
||||
"Prints the plugin version"))
|
||||
def version(sender: CommandSender): Unit = {
|
||||
sender.sendMessage(VersionCommand.getVersion*)
|
||||
}
|
||||
|
||||
@Command2.Subcommand(helpText = Array(
|
||||
"Invite",
|
||||
"Shows an invite link to the server"
|
||||
)) def invite(sender: CommandSender): Unit = {
|
||||
))
|
||||
def invite(sender: CommandSender): Unit = {
|
||||
if (checkSafeMode(sender)) {
|
||||
return ()
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package buttondevteam.discordplugin.role
|
||||
|
||||
import buttondevteam.core.ComponentManager
|
||||
import buttondevteam.discordplugin.DPUtils.{FluxExtensions, MonoExtensions}
|
||||
import buttondevteam.discordplugin.{DPUtils, DiscordPlugin}
|
||||
import buttondevteam.lib.architecture.{Component, ComponentMetadata}
|
||||
import discord4j.core.`object`.entity.Role
|
||||
|
@ -9,7 +8,7 @@ import discord4j.core.`object`.entity.channel.MessageChannel
|
|||
import discord4j.core.event.domain.role.{RoleCreateEvent, RoleDeleteEvent, RoleEvent, RoleUpdateEvent}
|
||||
import discord4j.rest.util.Color
|
||||
import org.bukkit.Bukkit
|
||||
import reactor.core.scala.publisher.SMono
|
||||
import reactor.core.publisher.Mono
|
||||
|
||||
import java.util.Collections
|
||||
import scala.jdk.CollectionConverters.SeqHasAsJava
|
||||
|
@ -30,14 +29,14 @@ import scala.jdk.CollectionConverters.SeqHasAsJava
|
|||
val role = roleCreateEvent.getRole
|
||||
if (!notMainServer(role)) {
|
||||
grm.isGameRole(role).flatMap(b => {
|
||||
if (!b) SMono.empty //Deleted or not a game role
|
||||
if (!b) Mono.empty //Deleted or not a game role
|
||||
else {
|
||||
GameRoles.add(role.getName)
|
||||
if (logChannel != null)
|
||||
logChannel.flatMap(_.createMessage("Added " + role.getName + " as game role." +
|
||||
" If you don't want this, change the role's color from the game role color.").^^())
|
||||
" If you don't want this, change the role's color from the game role color."))
|
||||
else
|
||||
SMono.empty
|
||||
Mono.empty
|
||||
}
|
||||
}).subscribe()
|
||||
()
|
||||
|
@ -48,7 +47,7 @@ import scala.jdk.CollectionConverters.SeqHasAsJava
|
|||
if (role == null) return ()
|
||||
if (notMainServer(role)) return ()
|
||||
if (GameRoles.remove(role.getName) && logChannel != null)
|
||||
logChannel.flatMap(_.createMessage("Removed " + role.getName + " as a game role.").^^()).subscribe()
|
||||
logChannel.flatMap(_.createMessage("Removed " + role.getName + " as a game role.")).subscribe()
|
||||
case roleUpdateEvent: RoleUpdateEvent =>
|
||||
if (!roleUpdateEvent.getOld.isPresent) {
|
||||
grm.logWarn("Old role not stored, cannot update game role!")
|
||||
|
@ -60,21 +59,21 @@ import scala.jdk.CollectionConverters.SeqHasAsJava
|
|||
grm.isGameRole(cr).flatMap(isGameRole => {
|
||||
if (!isGameRole)
|
||||
if (GameRoles.remove(or.getName) && logChannel != null)
|
||||
logChannel.flatMap(_.createMessage("Removed " + or.getName + " as a game role because its color changed.").^^())
|
||||
logChannel.flatMap(_.createMessage("Removed " + or.getName + " as a game role because its color changed."))
|
||||
else
|
||||
SMono.empty
|
||||
Mono.empty
|
||||
else if (GameRoles.contains(or.getName) && or.getName == cr.getName)
|
||||
SMono.empty
|
||||
Mono.empty
|
||||
else {
|
||||
val removed = GameRoles.remove(or.getName) //Regardless of whether it was a game role
|
||||
GameRoles.add(cr.getName) //Add it because it has no color
|
||||
if (logChannel != null)
|
||||
if (removed)
|
||||
logChannel.flatMap((ch: MessageChannel) => ch.createMessage("Changed game role from " + or.getName + " to " + cr.getName + ".").^^())
|
||||
logChannel.flatMap((ch: MessageChannel) => ch.createMessage("Changed game role from " + or.getName + " to " + cr.getName + "."))
|
||||
else
|
||||
logChannel.flatMap((ch: MessageChannel) => ch.createMessage("Added " + cr.getName + " as game role because it has the color of one.").^^())
|
||||
logChannel.flatMap((ch: MessageChannel) => ch.createMessage("Added " + cr.getName + " as game role because it has the color of one."))
|
||||
else
|
||||
SMono.empty
|
||||
Mono.empty
|
||||
}
|
||||
}).subscribe()
|
||||
case _ =>
|
||||
|
@ -88,7 +87,7 @@ import scala.jdk.CollectionConverters.SeqHasAsJava
|
|||
|
||||
override protected def enable(): Unit = {
|
||||
getPlugin.manager.registerCommand(command)
|
||||
GameRoles = DiscordPlugin.mainServer.getRoles.^^().filterWhen(this.isGameRole).map(_.getName).collectSeq().block().asJava
|
||||
GameRoles = DiscordPlugin.mainServer.getRoles.filterWhen(this.isGameRole).map(_.getName).collectList().block()
|
||||
}
|
||||
|
||||
override protected def disable(): Unit = getPlugin.manager.unregisterCommand(command)
|
||||
|
@ -101,14 +100,16 @@ import scala.jdk.CollectionConverters.SeqHasAsJava
|
|||
* The role color that is used by game roles.
|
||||
* Defaults to the second to last in the upper row - #95a5a6.
|
||||
*/
|
||||
final private val roleColor = getConfig.getConfig[Color]("roleColor").`def`(Color.of(149, 165, 166)).getter((rgb: Any) => Color.of(Integer.parseInt(rgb.asInstanceOf[String].substring(1), 16))).setter((color: Color) => String.format("#%08x", color.getRGB)).buildReadOnly
|
||||
final private val roleColor = getConfig.getData("roleColor", Color.of(149, 165, 166),
|
||||
rgb => Color.of(Integer.parseInt(rgb.asInstanceOf[String].substring(1), 16)),
|
||||
color => String.format("#%08x", color.getRGB), true)
|
||||
|
||||
private def isGameRole(r: Role): SMono[Boolean] = {
|
||||
if (r.getGuildId.asLong != DiscordPlugin.mainServer.getId.asLong) return SMono.just(false) //Only allow on the main server
|
||||
private def isGameRole(r: Role): Mono[java.lang.Boolean] = {
|
||||
if (r.getGuildId.asLong != DiscordPlugin.mainServer.getId.asLong) return Mono.just(false) //Only allow on the main server
|
||||
val rc = roleColor.get
|
||||
if (r.getColor equals rc)
|
||||
DiscordPlugin.dc.getSelf.flatMap(u => u.asMember(DiscordPlugin.mainServer.getId)).^^()
|
||||
.flatMap(_.hasHigherRoles(Collections.singleton(r.getId)).^^().asInstanceOf).defaultIfEmpty(false) //Below one of our roles
|
||||
else SMono.just(false)
|
||||
DiscordPlugin.dc.getSelf.flatMap(u => u.asMember(DiscordPlugin.mainServer.getId))
|
||||
.flatMap(_.hasHigherRoles(Collections.singleton(r.getId))).defaultIfEmpty(false) //Below one of our roles
|
||||
else Mono.just(false)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue