Skip to content

Commit

Permalink
Making grp chatting system
Browse files Browse the repository at this point in the history
  • Loading branch information
ririf4 committed Feb 4, 2025
1 parent 7bbd7e6 commit 80fabf8
Show file tree
Hide file tree
Showing 15 changed files with 758 additions and 140 deletions.
13 changes: 2 additions & 11 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,16 @@ dependencies {

modApi("org.yaml:snakeyaml:2.3")
modApi("net.kyori:adventure-text-serializer-gson:4.17.0")
modApi("net.ririfa:langman:1.2.1-beta.1")
modApi("net.ririfa:langman:1.2.2-SNAPSHOT")
modCompileOnly("org.apache.logging.log4j:log4j-api:+")
modCompileOnly("org.apache.logging.log4j:log4j-core:+")

// TODO: Is loom provide this?
includeInJar("net.dv8tion:JDA:5.2.1") {
exclude("net.java.dev.jna", "jna")
}
includeInJar("org.yaml:snakeyaml:2.0")
includeInJar("net.kyori:adventure-text-serializer-gson:4.17.0")
includeInJar("com.github.ben-manes.caffeine:caffeine:3.1.8")
includeInJar("net.ririfa:langman:1.2.1-beta.3")
}

val targetJavaVersion = 21
Expand Down Expand Up @@ -83,14 +82,6 @@ tasks.named<ProcessResources>("processResources") {
}
}

tasks.named("remapSourcesJar") {
dependsOn(tasks.named("jar"))
}

tasks.named("remapJar") {
dependsOn(tasks.named("sourcesJar"))
}

tasks.withType<Jar> {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import net.minecraft.advancement.*;
import net.minecraft.server.network.ServerPlayerEntity;
import net.ririfa.fabricord.discord.DiscordBotManager;
import net.ririfa.fabricord.discord.DiscordEmbed;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.asm.mixin.Mixin;
Expand All @@ -20,6 +21,8 @@ public abstract class PlayerAdvancementTrackerMixin {

@Inject(method = "grantCriterion", at = @At("RETURN"))
public void onAdvancementGranted(AdvancementEntry advancementEntry, String string, @NotNull CallbackInfoReturnable<Boolean> cir) {
if (!DiscordBotManager.botIsInitialized) return;

if (cir.getReturnValue()) {
Advancement advancement = advancementEntry.value();
Optional<AdvancementDisplay> display = advancement.comp_1913();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import net.ririfa.fabricord.discord.DiscordBotManager;
import net.ririfa.fabricord.discord.DiscordEmbed;
import org.jetbrains.annotations.Contract;
import org.spongepowered.asm.mixin.Mixin;
Expand All @@ -16,6 +17,8 @@ public abstract class ServerPlayerEntityMixin {
@Contract(pure = true)
@Inject(method = "onDeath", at = @At("RETURN"))
public void onPlayerDeath(DamageSource source, CallbackInfo ci) {
if (!DiscordBotManager.botIsInitialized) return;

ServerPlayerEntity player = (ServerPlayerEntity) (Object) this;
Text message = player.getDamageTracker().getDeathMessage();

Expand Down
95 changes: 72 additions & 23 deletions src/main/kotlin/net/ririfa/fabricord/Fabricord.kt
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
package net.ririfa.fabricord

import com.mojang.brigadier.arguments.StringArgumentType.greedyString
import net.fabricmc.api.DedicatedServerModInitializer
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents
import net.fabricmc.fabric.api.message.v1.ServerMessageEvents
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents
import net.fabricmc.loader.api.FabricLoader
import net.minecraft.server.command.CommandManager.argument
import net.minecraft.server.command.CommandManager.literal
import net.minecraft.text.Text
import net.ririfa.langman.LangMan
import net.ririfa.fabricord.discord.DiscordBotManager
import net.ririfa.fabricord.discord.DiscordEmbed
import net.ririfa.fabricord.discord.DiscordPlayerEventHandler
import net.ririfa.fabricord.discord.DiscordPlayerEventHandler.handleMCMessage
import net.ririfa.fabricord.translation.FabricordMessageKey
import net.ririfa.fabricord.translation.FabricordMessageProvider
Expand All @@ -27,13 +32,9 @@ import org.slf4j.LoggerFactory
import org.yaml.snakeyaml.Yaml
import java.io.File
import java.io.IOException
import java.nio.file.FileSystems
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
import java.util.concurrent.Executors
import java.util.concurrent.ScheduledExecutorService
import java.util.concurrent.TimeUnit
import java.nio.file.*
import java.util.UUID
import java.util.concurrent.*
import kotlin.io.path.notExists

class Fabricord : DedicatedServerModInitializer {
Expand All @@ -45,15 +46,19 @@ class Fabricord : DedicatedServerModInitializer {

private val loader: FabricLoader = FabricLoader.getInstance()
val executorService: ScheduledExecutorService = Executors.newSingleThreadScheduledExecutor()
internal lateinit var ca: ConsoleTrackerAppender

private val serverDir: Path = loader.gameDir.toRealPath()
private val modDir: Path = serverDir.resolve(MOD_ID)
private val configFile: Path = modDir.resolve("config.yml")
private val langDir: File = serverDir.resolve("lang").toFile()
private val langDir: File = modDir.resolve("lang").toFile()
private val availableLang = listOf("en", "ja")

val grpFile: Path = modDir.resolve("groups.json")

private val yaml = Yaml()
private var initializeIsDone = false
private val localChatToggled = mutableMapOf<UUID, Boolean>()

//region Configurations
// Required
Expand Down Expand Up @@ -82,6 +87,7 @@ class Fabricord : DedicatedServerModInitializer {
lateinit var langMan: LangMan<FabricordMessageProvider, Text>

override fun onInitializeServer() {
instance = this
if (!langDir.exists()) {
langDir.mkdirs()
}
Expand All @@ -95,7 +101,12 @@ class Fabricord : DedicatedServerModInitializer {

langMan.init(InitType.YAML, langDir, availableLang)

langMan.messages.forEach { (key, value) ->
logger.info("Loaded message: $key: $value")
}

logger.info(langMan.getSysMessage(FabricordMessageKey.System.Initializing))
DiscordPlayerEventHandler.init()
checkRequiredFilesAndDirectories()
loadConfig()

Expand All @@ -111,27 +122,26 @@ class Fabricord : DedicatedServerModInitializer {

initializeIsDone = true
logger.info(langMan.getSysMessage(FabricordMessageKey.System.Initialized))

instance = this
}

private fun registerEvents() {
val appender = ConsoleTrackerAppender("FabricordConsoleTracker")
ca = ConsoleTrackerAppender("FabricordConsoleTracker")
val rootLogger = LogManager.getRootLogger() as org.apache.logging.log4j.core.Logger
rootLogger.addAppender(appender)
rootLogger.addAppender(ca)
ServerMessageEvents.CHAT_MESSAGE.register(ServerMessageEvents.ChatMessage { message, sender, _ ->
executorService.submit {
val content = message.content.string
handleMCMessage(sender, content)
}
val uuid = sender.uuid
if (uuid in localChatToggled) return@ChatMessage

val content = message.content.string
handleMCMessage(sender, content)
})

ServerPlayConnectionEvents.JOIN.register(ServerPlayConnectionEvents.Join { handler, _, _ ->
val player = handler.player

if (!DiscordBotManager.botIsInitialized) {
player.networkHandler.disconnect(
player.adapt().getMessage(FabricordMessageKey.System.BotNotInitialized)
player.adapt().getMessage(FabricordMessageKey.System.Discord.BotNotInitialized)
)
return@Join
}
Expand All @@ -152,9 +162,8 @@ class Fabricord : DedicatedServerModInitializer {
executorService.submit {
try {
DiscordBotManager.init(server)
DiscordBotManager.startBot()
} catch (e: Exception) {
logger.error(langMan.getSysMessage(FabricordMessageKey.System.FailedToStartBot), e)
logger.error(langMan.getSysMessage(FabricordMessageKey.System.Discord.FailedToStartBot), e)
server.stop(false)
}
}
Expand All @@ -167,11 +176,43 @@ class Fabricord : DedicatedServerModInitializer {
if (!executorService.awaitTermination(5, TimeUnit.SECONDS)) {
executorService.shutdownNow()
}

rootLogger.removeAppender(ca)
ca.stop()
} catch (e: Exception) {
logger.error(langMan.getSysMessage(FabricordMessageKey.System.FailedToStopBot), e)
logger.error(langMan.getSysMessage(FabricordMessageKey.System.Discord.FailedToStopBot), e)
}
}

CommandRegistrationCallback.EVENT.register { dispatcher, registryAccess, environment ->
dispatcher.register(
literal("lc")
.executes { context ->
val player = context.source.player ?: return@executes 0
val uuid = player.uuid
val current = localChatToggled.getOrDefault(uuid, false)
val newState = !current
localChatToggled[uuid] = newState
player.sendMessage(
player.adapt().getMessage(FabricordMessageKey.System.SwitchedLocalChatState, newState),
false
)
return@executes 1
}
.then(
argument("message", greedyString())
.executes { context ->
val player = context.source.player ?: return@executes 0
val message = context.getArgument("message", String::class.java)
val textToSend = Text.literal("${player.name.string}: $message")
player.server.playerManager.broadcast(textToSend, false)
return@executes 1
}
)
)


}
}

internal class ConsoleTrackerAppender(name: String) : AbstractAppender(name, null, PatternLayout.createDefaultLayout(), false, emptyArray()) {
Expand All @@ -190,20 +231,28 @@ class Fabricord : DedicatedServerModInitializer {
}

val formattedMessage = when (level) {
Level.INFO, Level.WARN -> """
```"$safeMessage"```
""".trimIndent()
Level.INFO, Level.WARN ->

//
"""
```
$safeMessage
```
""".trimIndent()
//

Level.ERROR -> {
val errorMessage = safeMessage
.lineSequence()
.joinToString("\n") { "- $it" }

//
"""
```diff
$errorMessage
```
""".trimIndent()
//
}

else -> return
Expand Down
50 changes: 36 additions & 14 deletions src/main/kotlin/net/ririfa/fabricord/discord/DiscordBotManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,27 +28,32 @@ import java.util.concurrent.TimeUnit
import javax.security.auth.login.LoginException

object DiscordBotManager : ListenerAdapter() {
@JvmField
var jda: JDA? = null
@JvmField
var webHook: Webhook? = null
@JvmField
var botIsInitialized: Boolean = false
private val logQueue = ConcurrentLinkedQueue<String>()
private val logScheduler = Executors.newSingleThreadScheduledExecutor()
private val lm = Fabricord.instance.langMan
lateinit var lm: LangMan<FabricordMessageProvider, Text>

private val intents = GatewayIntent.MESSAGE_CONTENT
internal var server: MinecraftServer? = null

init {
logScheduler.scheduleAtFixedRate({
flushLogQueue()
}, 0, 1500, TimeUnit.MILLISECONDS)
}, 0, 1750, TimeUnit.MILLISECONDS)
}

fun init(s: MinecraftServer) {
server = s
lm = Fabricord.instance.langMan
startBot()
}

fun startBot() {
private fun startBot() {
executorService.submit {
val onlineStatus = getOnlineStatus()
val activity = getBotActivity()
Expand All @@ -70,7 +75,7 @@ object DiscordBotManager : ListenerAdapter() {
jda?.updateCommands()

botIsInitialized = true
Fabricord.logger.info(lm.getSysMessage(FabricordMessageKey.System.Discord.BotNowOnline))
Fabricord.logger.info(lm.getSysMessage(FabricordMessageKey.System.Discord.BotNowOnline, jda?.selfUser?.name ?: "Bot"))
Fabricord.serverStartMessage?.let { sendToDiscord(it) }

if (Fabricord.messageStyle == "modern") {
Expand Down Expand Up @@ -130,23 +135,40 @@ object DiscordBotManager : ListenerAdapter() {

private val discordListener = object : ListenerAdapter() {
override fun onMessageReceived(event: MessageReceivedEvent) {
val server = server ?: return Fabricord.logger.error("MinecraftServer is not initialized. Cannot process Discord message.")

executorService.submit {
val mentionedPlayers = findMentionedPlayers(event.message.contentRaw, server.playerManager.playerList)
if (mentionedPlayers.isNotEmpty()) {
DiscordMessageHandler.handleMentionedDiscordMessage(event, server, mentionedPlayers, false)
} else {
DiscordMessageHandler.handleDiscordMessage(event, server)
val server = server ?: return Fabricord.logger.error(
// MinecraftServerNotInitialized + CantProcessMessage
lm.getSysMessage(FabricordMessageKey.System.Discord.MinecraftServerNotInitialized,
lm.getSysMessage(FabricordMessageKey.System.Discord.CantProcessMessage)))

if (event.channel == Fabricord.logChannelID?.let { jda?.getTextChannelById(it) }) {
executorService.submit {
val mentionedPlayers = findMentionedPlayers(event.message.contentRaw, server.playerManager.playerList)
if (mentionedPlayers.isNotEmpty()) {
DiscordMessageHandler.handleMentionedDiscordMessage(event, server, mentionedPlayers, false)
} else {
DiscordMessageHandler.handleDiscordMessage(event, server)
}
}
} else if (event.channel == consoleLogChannelID?.let { jda?.getTextChannelById(it) }) {
if (!event.author.isBot) {
val command = event.message.contentRaw
server.execute {
server.commandManager.executeWithPrefix(server.commandSource, command)
}
}
}
}
}

private fun handlePlayerListCommand(event: SlashCommandInteractionEvent) {
val discordUserLang = event.userLocale.locale

val server = server ?: run {
Fabricord.logger.error("MinecraftServer is not initialized. Cannot process /playerlist command.")
event.reply("Sorry, I can't get the player list right now.")
Fabricord.logger.error(
// MinecraftServerNotInitialized + CantProcessCommand
lm.getSysMessage(FabricordMessageKey.System.Discord.MinecraftServerNotInitialized,
lm.getSysMessage(FabricordMessageKey.System.Discord.CantProcessCommand)))
event.reply(lm.getSysMessageByLangCode(FabricordMessageKey.System.Discord.CantGetPlayerList, discordUserLang))
.setEphemeral(true)
.queue {
executorService.schedule({
Expand Down
Loading

0 comments on commit 80fabf8

Please sign in to comment.