1+ import com.google.gson.JsonObject
2+ import com.lambda.client.LambdaMod
3+ import com.lambda.client.command.CommandManager
4+ import com.lambda.client.event.events.ConnectionEvent
5+ import com.lambda.client.module.Category
6+ import com.lambda.client.plugin.api.PluginModule
7+
8+ import com.lambda.client.event.events.PacketEvent
9+ import com.lambda.client.manager.managers.FriendManager
10+ import com.lambda.client.manager.managers.MessageManager
11+ import com.lambda.client.manager.managers.MessageManager.newMessageModifier
12+ import com.lambda.client.mixin.extension.textComponent
13+ import com.lambda.client.module.modules.chat.ChatTimestamp
14+ import com.lambda.client.util.TickTimer
15+ import com.lambda.client.util.TimeUnit
16+ import com.lambda.client.util.text.MessageDetection
17+ import com.lambda.client.util.text.MessageSendHelper
18+ import com.lambda.client.util.text.MessageSendHelper.sendServerMessage
19+ import com.lambda.client.util.text.format
20+ import com.lambda.client.util.text.formatValue
21+ import com.lambda.client.util.threads.defaultScope
22+ import com.lambda.client.util.threads.safeListener
23+ import com.lambda.commons.utils.ConnectionUtils
24+ import com.lambda.commons.utils.SystemUtils
25+ import com.lambda.event.listener.listener
26+ import kotlinx.coroutines.Dispatchers
27+ import kotlinx.coroutines.launch
28+ import net.minecraft.network.play.server.SPacketChat
29+ import net.minecraft.util.text.TextFormatting
30+ import net.minecraftforge.fml.common.gameevent.TickEvent
31+ import org.apache.commons.io.IOUtils
32+
33+ internal object ChatPlusDiscordNotifs: PluginModule(
34+ name = " DiscordNotifs" ,
35+ category = Category .CHAT ,
36+ description = " Sends your chat to a set Discord channel" ,
37+ pluginMain = ChatPlusPlugin
38+ ) {
39+ private val timeout by setting(" Timeout" , true )
40+ private val timeoutTime by setting(" Seconds" , 10 , 0 .. 120 , 5 , { timeout })
41+ private val time by setting(" Timestamp" , true )
42+ private val importantPings by setting(" Important Pings" , false )
43+ private val connectionChange by setting(" Connection Change" , true , description = " When you get disconnected or reconnected to the server" )
44+ private val all by setting(" All Messages" , false )
45+ private val direct by setting(" DMs" , true , { ! all })
46+ private val queue by setting(" Queue Position" , true , { ! all })
47+ private val restart by setting(" Restart" , true , { ! all }, description = " Server restart notifications" )
48+
49+ val url = setting(" URL" , " unchanged" )
50+ val pingID = setting(" Ping ID" , " unchanged" )
51+ val avatar = setting(" Avatar" , " ${LambdaMod .GITHUB_LINK } /assets/raw/assets/assets/icons/kamiGithub.png" )
52+
53+ private const val username = " ${LambdaMod .NAME } ${LambdaMod .VERSION } "
54+ private val server: String get() = mc.currentServerData?.serverIP ? : " the server"
55+ private val timer = TickTimer (TimeUnit .SECONDS )
56+
57+ /* Listeners to send the messages */
58+ init {
59+ safeListener<PacketEvent .Receive > {
60+ if (it.packet !is SPacketChat ) return @safeListener
61+ val message = (it.packet as SPacketChat ).chatComponent.unformattedText
62+
63+ if (timeout(message) && shouldSend(message)) {
64+ sendMessage(getPingID(message) + getMessageType(message, server) + getTime() + message)
65+ }
66+ }
67+
68+ listener<ConnectionEvent .Connect > {
69+ if (! connectionChange) return @listener
70+ sendMessage(getPingID(" KamiBlueMessageType1" ) + getTime() + getMessageType(" KamiBlueMessageType1" , server))
71+ }
72+
73+ listener<ConnectionEvent .Disconnect > {
74+ if (! connectionChange) return @listener
75+ sendMessage(getPingID(" KamiBlueMessageType2" ) + getTime() + getMessageType(" KamiBlueMessageType2" , server))
76+ }
77+
78+ /* Always on status code */
79+ safeListener<TickEvent .ClientTickEvent > {
80+ if (url.value == " unchanged" ) {
81+ MessageSendHelper .sendErrorMessage(chatName + " You must first set a webhook url with the " +
82+ formatValue(" ${CommandManager .prefix} discordnotifs" ) +
83+ " command" )
84+ disable()
85+ } else if (pingID.value == " unchanged" && importantPings) {
86+ MessageSendHelper .sendErrorMessage(chatName + " For Pings to work, you must set a Discord ID with the " +
87+ formatValue(" ${CommandManager .prefix} discordnotifs" ) +
88+ " command" )
89+ disable()
90+ }
91+ }
92+ }
93+
94+ private fun shouldSend (message : String ): Boolean {
95+ return all
96+ || direct && MessageDetection .Direct .ANY detect message
97+ || restart && MessageDetection .Server .RESTART detect message
98+ || queue && MessageDetection .Server .QUEUE detect message
99+ }
100+
101+ private fun getMessageType (message : String , server : String ): String {
102+ if (direct && MessageDetection .Direct .RECEIVE detect message) return " You got a direct message!\n "
103+ if (direct && MessageDetection .Direct .SENT detect message) return " You sent a direct message!\n "
104+ if (message == " KamiBlueMessageType1" ) return " Connected to $server "
105+ return if (message == " KamiBlueMessageType2" ) " Disconnected from $server " else " "
106+ }
107+
108+ private fun timeout (message : String ) = ! timeout
109+ || restart && MessageDetection .Server .RESTART detect message
110+ || direct && MessageDetection .Direct .ANY detect message
111+ || timer.tick(timeoutTime.toLong())
112+
113+ /* Text formatting and misc methods */
114+ private fun getPingID (message : String ) = if (message == " KamiBlueMessageType1"
115+ || message == " KamiBlueMessageType2"
116+ || direct && MessageDetection .Direct .ANY detect message
117+ || restart && MessageDetection .Server .RESTART detect message
118+ || importantPings && MessageDetection .Server .QUEUE_IMPORTANT detect message) formatPingID()
119+ else " "
120+
121+ private fun formatPingID (): String {
122+ return if (! importantPings) " " else " <@!${pingID.value} >: "
123+ }
124+
125+ private fun getTime () =
126+ if (! time) " "
127+ else ChatTimestamp .time
128+
129+ private fun sendMessage (content : String ) {
130+ defaultScope.launch(Dispatchers .IO ) {
131+ ConnectionUtils .runConnection(
132+ url.value,
133+ { connection ->
134+ val bytes = JsonObject ().run {
135+ addProperty(" username" , username)
136+ addProperty(" content" , content)
137+ addProperty(" avatar_url" , avatar.value)
138+ toString().toByteArray(Charsets .UTF_8 )
139+ }
140+
141+ connection.setRequestProperty(" Content-Type" , " application/json; charset=UTF-8" )
142+ connection.setRequestProperty(" Accept" , " application/json" )
143+ connection.setRequestProperty(" User-Agent" , " " )
144+
145+ connection.requestMethod = " POST"
146+ connection.outputStream.use {
147+ it.write(bytes)
148+ }
149+
150+ val response = connection.inputStream.use {
151+ IOUtils .toString(it, Charsets .UTF_8 )
152+ }
153+
154+ if (response.isNotEmpty()) {
155+ LambdaMod .LOG .info(" Unexpected response from DiscordNotifs http request: $response " )
156+ }
157+ },
158+ {
159+ LambdaMod .LOG .warn(" Error while sending webhook" , it)
160+ },
161+ )
162+ }
163+ }
164+ }
0 commit comments