1818package com.lambda.module.modules.client
1919
2020import com.lambda.Lambda
21- import com.lambda.Lambda.LOG
2221import com.lambda.context.SafeContext
22+ import com.lambda.event.EventFlow
2323import com.lambda.event.events.ConnectionEvent
2424import com.lambda.event.listener.UnsafeListener.Companion.listenUnsafeConcurrently
2525import com.lambda.network.api.v1.models.Party
2626import com.lambda.module.Module
27- import com.lambda.module.modules.client.Network.discordAuth
28- import com.lambda.module.modules.client.Network.isAuthenticated
29- import com.lambda.module.modules.client.Network.rpc
30- import com.lambda.module.modules.client.Network.apiAuth
27+ import com.lambda.module.modules.client.Network.updateToken
3128import com.lambda.module.tag.ModuleTag
3229import com.lambda.network.api.v1.endpoints.createParty
3330import com.lambda.network.api.v1.endpoints.editParty
3431import com.lambda.network.api.v1.endpoints.joinParty
3532import com.lambda.network.api.v1.endpoints.leaveParty
33+ import com.lambda.network.api.v1.endpoints.linkDiscord
3634import com.lambda.threading.runConcurrent
3735import com.lambda.threading.runSafe
3836import com.lambda.util.Communication
3937import com.lambda.util.Communication.toast
38+ import com.lambda.util.Communication.warn
4039import com.lambda.util.Nameable
41- import com.lambda.util.StringUtils.capitalize
40+ import com.lambda.util.extension.dimensionName
4241import dev.cbyrne.kdiscordipc.KDiscordIPC
4342import dev.cbyrne.kdiscordipc.core.event.DiscordEvent
44- import dev.cbyrne.kdiscordipc.core.event.impl.ActivityJoinEvent
45- import dev.cbyrne.kdiscordipc.core.event.impl.ActivityJoinRequestEvent
46- import dev.cbyrne.kdiscordipc.core.event.impl.ErrorEvent
4743import dev.cbyrne.kdiscordipc.core.event.impl.ReadyEvent
44+ import dev.cbyrne.kdiscordipc.core.packet.inbound.impl.AuthenticatePacket
4845import dev.cbyrne.kdiscordipc.data.activity.*
4946import kotlinx.coroutines.delay
5047import net.minecraft.entity.player.PlayerEntity
@@ -64,91 +61,134 @@ object Discord : Module(
6461 private val line1Right by setting(" Line 1 Right" , LineInfo .USERNAME ) { page == Page .General }
6562 private val line2Left by setting(" Line 2 Left" , LineInfo .DIMENSION ) { page == Page .General }
6663 private val line2Right by setting(" Line 2 Right" , LineInfo .FPS ) { page == Page .General }
67- private val confirmCoordinates by setting(" Show Coordinates" , false , description = " Confirm display the player coordinates" ) { page == Page .General }
68- private val confirmServer by setting(" Show Server IP" , false , description = " Confirm display the server IP" ) { page == Page .General }
6964
7065 /* Party settings */
71- private val enableParty by setting(" Enable Party " , true , description = " Allows you to create parties. " ) { page == Page .Party } // ToDo: Change this for create by default instead
66+ private val createByDefault by setting(" Create By Default " , true , description = " Create parties on " ) { page == Page .Party }
7267 private val maxPlayers by setting(" Max Players" , 10 , 2 .. 20 ) { page == Page .Party }.onValueChange { _, _ -> if (player.isPartyOwner) edit() } // ToDo: Avoid spam requests
7368
74- private var startup = System .currentTimeMillis()
75- private val dimensionRegex = Regex (""" \b\w+_\w+\b""" ) // ToDo: Change this when combat is merged
69+ val rpc = KDiscordIPC (Lambda .APP_ID , scope = EventFlow .lambdaScope)
7670
77- private var ready: ReadyEvent ? = null
78- private var currentParty: Party ? = null
71+ private var startup = System .currentTimeMillis()
7972
80- private val isPartyInteractionAllowed : Boolean
81- get() = apiAuth != null && discordAuth != null
73+ var discordAuth : AuthenticatePacket . Data ? = null ; private set
74+ var currentParty : Party ? = null ; private set
8275
8376 val PlayerEntity .isPartyOwner
8477 get() = uuid == currentParty?.leader?.uuid
8578
8679 val PlayerEntity .isInParty
87- get() = currentParty?.players?.any { it.uuid == this . uuid }
80+ get() = currentParty?.players?.any { it.uuid == uuid }
8881
8982 init {
83+ rpc.subscribe()
84+
9085 listenUnsafeConcurrently<ConnectionEvent .Connect .Post > {
9186 // FixMe: We have to wait even though this is the last event until toSafe() != null
9287 // because of timing
9388 delay(3000 )
94- runSafe { connect () }
89+ runSafe { handleLoop () }
9590 }
9691
97- // TODO: Exponential backoff up to 25 seconds to avoid being rate limited by discord
98- onEnable { connect() }
99- onDisable { disconnect() }
92+ onEnable { runConcurrent { startDiscord(); handleLoop() } }
93+ onDisable { stopDiscord() }
10094 }
10195
10296 fun createParty () {
103- if (! isPartyInteractionAllowed ) return
97+ if (discordAuth == null ) return toast( " Can not interact with the api (are you offline?) " )
10498
10599 val (party, error) = createParty(maxPlayers, true )
106100 if (error != null ) toast(" Failed to create a party: ${error.message} " , Communication .LogLevel .WARN )
107101
108102 currentParty = party
109103 }
110104
111- // Join a party using the ID
105+ /* *
106+ * Joins a new party with the invitation ID
107+ */
112108 fun join (id : String ) {
113- if (! isPartyInteractionAllowed ) return
109+ if (discordAuth == null ) return toast( " Can not interact with the api (are you offline?) " )
114110
115111 val (party, error) = joinParty(id)
116112 if (error != null ) toast(" Failed to join the party: ${error.message} " , Communication .LogLevel .WARN )
117113
118114 currentParty = party
119115 }
120116
121- // Edit the current party if you are the owner
122- private fun edit () {
123- if (! isPartyInteractionAllowed) return
117+ /* *
118+ * Triggers a party edit request if you are the owner
119+ */
120+ fun edit () {
121+ if (discordAuth == null ) return toast(" Can not interact with the api (are you offline?)" )
124122
125123 val (party, error) = editParty(maxPlayers)
126124 if (error != null ) toast(" Failed to edit the party: ${error.message} " , Communication .LogLevel .WARN )
127125
128126 currentParty = party
129127 }
130128
131- private fun SafeContext.connect () {
132- // FixMe: Race condition
133- runConcurrent { rpc.connect() } // ToDo: Duplicate rpc connection network and discord
134- runConcurrent { rpc.register() }
135- runConcurrent {
136- while (rpc.connected) {
137- update()
138- delay(delay)
139- }
129+ /* *
130+ * Leaves the current party
131+ */
132+ fun leave () {
133+ if (discordAuth == null || currentParty == null ) return toast(" Can not interact with the api (are you offline?)" )
134+
135+ val (_, error) = leaveParty()
136+ if (error != null ) return toast(" Failed to edit the party: ${error.message} " , Communication .LogLevel .WARN )
137+
138+ currentParty = null
139+ }
140+
141+ private suspend fun startDiscord () {
142+ if (rpc.connected) return
143+
144+ rpc.subscribe()
145+ runConcurrent { rpc.connect() } // TODO: Create a function that will wait until x seconds has passed or if the connection is successful
146+ delay(1000 )
147+
148+ val auth = rpc.applicationManager.authenticate()
149+ val (authResp, error) = linkDiscord(discordToken = auth.accessToken)
150+ if (error != null ) {
151+ warn(error.message.toString())
152+ return toast(" Failed to link the discord account to the minecraft auth" )
140153 }
154+
155+ authResp?.let { updateToken(it) }
156+ discordAuth = auth
157+ }
158+
159+ private fun stopDiscord () {
160+ if (! rpc.connected) return
161+
162+ rpc.disconnect()
141163 }
142164
143- private fun disconnect () {
144- if (rpc.connected) {
145- LOG .info(" Gracefully disconnecting from Discord RPC." )
146- leaveParty()
147- rpc.disconnect()
165+ private fun KDiscordIPC.subscribe () {
166+ // ToDO: Get party on join event
167+ on<ReadyEvent > {
168+ subscribe(DiscordEvent .VoiceChannelSelect )
169+ subscribe(DiscordEvent .VoiceStateCreate )
170+ subscribe(DiscordEvent .VoiceStateUpdate )
171+ subscribe(DiscordEvent .VoiceStateDelete )
172+ subscribe(DiscordEvent .VoiceSettingsUpdate )
173+ subscribe(DiscordEvent .VoiceConnectionStatus )
174+ subscribe(DiscordEvent .SpeakingStart )
175+ subscribe(DiscordEvent .SpeakingStop )
176+ subscribe(DiscordEvent .ActivityJoin )
177+ subscribe(DiscordEvent .ActivityJoinRequest )
178+ subscribe(DiscordEvent .OverlayUpdate )
179+ // subscribe(DiscordEvent.ActivitySpectate) // Unsupported
148180 }
181+ }
149182
150- ready = null
151- currentParty = null
183+ private suspend fun SafeContext.handleLoop () {
184+ if (createByDefault) createParty(maxPlayers)
185+
186+ while (rpc.connected) {
187+ update()
188+ delay(delay)
189+ }
190+
191+ leave()
152192 }
153193
154194 private suspend fun SafeContext.update () {
@@ -161,7 +201,7 @@ object Discord : Module(
161201 largeImage(" lambda" , Lambda .VERSION )
162202 smallImage(" https://mc-heads.net/avatar/${mc.gameProfile.id} /nohelm" , mc.gameProfile.name)
163203
164- if (isAuthenticated && party != null ) {
204+ if (party != null ) {
165205 party(party.id.toString(), party.players.size, party.settings.maxPlayers)
166206 secrets(party.joinSecret)
167207 } else {
@@ -172,33 +212,6 @@ object Discord : Module(
172212 }
173213 }
174214
175- private suspend fun KDiscordIPC.register () {
176- on<ReadyEvent > {
177- ready = this
178-
179- // Party features
180- subscribe(DiscordEvent .ActivityJoinRequest )
181- subscribe(DiscordEvent .ActivityJoin )
182-
183- if (enableParty) createParty()
184- }
185-
186- // Event when someone would like to join your party
187- on<ActivityJoinRequestEvent > {
188- toast(" The user ${data.userId} has invited you" )
189- rpc.activityManager.acceptJoinRequest(data.userId)
190- }
191-
192- // Event when someone joins your party
193- on<ActivityJoinEvent > {
194- LOG .info(" Someone has joined" )
195- }
196-
197- on<ErrorEvent > {
198- LOG .error(" Discord RPC error: ${data.message} " )
199- }
200- }
201-
202215 private enum class Page {
203216 General , Party
204217 }
@@ -215,19 +228,9 @@ object Discord : Module(
215228 USERNAME ({ mc.session.username }),
216229 HEALTH ({ " ${mc.player?.health ? : 0 } HP" }),
217230 HUNGER ({ " ${mc.player?.hungerManager?.foodLevel ? : 0 } Hunger" }),
218- DIMENSION ({
219- mc.world?.registryKey?.value?.path?.replace(dimensionRegex) {
220- it.value.split(" _" ).joinToString(" " ) { it.capitalize() }
221- } ? : " Unknown"
222- }),
223- COORDINATES ({
224- if (confirmCoordinates) " Coords: ${mc.player?.blockPos?.toShortString()} "
225- else " [Redacted]"
226- }),
227- SERVER ({
228- if (confirmServer) mc.currentServerEntry?.address ? : " Not Connected"
229- else " [Redacted]"
230- }),
231+ DIMENSION ({ dimensionName }),
232+ COORDINATES ({ " Coords: ${player.blockPos.toShortString()} " }),
233+ SERVER ({ mc.currentServerEntry?.address ? : " Not Connected" }),
231234 FPS ({ " ${mc.currentFps} FPS" });
232235 }
233236}
0 commit comments