From 35102b47a19490658a9826bf5a86693428e3ba45 Mon Sep 17 00:00:00 2001 From: SubAt0mic Date: Thu, 28 Aug 2025 14:28:39 -0400 Subject: [PATCH 1/8] odin websocket + melody progress gui --- build.gradle.kts | 3 + src/main/kotlin/me/odinmain/OdinMain.kt | 6 + .../me/odinmain/commands/impl/DevCommand.kt | 17 +++ .../me/odinmain/commands/impl/SoopyCommand.kt | 17 +-- .../features/impl/floor7/p3/MelodyMessage.kt | 133 +++++++++++++++++- .../impl/floor7/p3/termGUI/CustomTermGui.kt | 2 + .../features/impl/render/ClickGUIModule.kt | 23 ++- .../me/odinmain/utils/network/SslUtils.kt | 36 +++++ .../utils/network/WebSocketConnection.kt | 61 ++++++++ .../me/odinmain/utils/network/WebUtils.kt | 104 ++++++++++++++ .../odinmain/utils/skyblock/LocationUtils.kt | 14 ++ src/main/resources/odincacerts.jks | Bin 0 -> 169578 bytes 12 files changed, 390 insertions(+), 26 deletions(-) create mode 100644 src/main/kotlin/me/odinmain/utils/network/SslUtils.kt create mode 100644 src/main/kotlin/me/odinmain/utils/network/WebSocketConnection.kt create mode 100644 src/main/kotlin/me/odinmain/utils/network/WebUtils.kt create mode 100644 src/main/resources/odincacerts.jks diff --git a/build.gradle.kts b/build.gradle.kts index f92735998..0e105b817 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -40,6 +40,9 @@ allprojects { implementation(kotlin("reflect")) implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0-RC") + implementation("com.squareup.okhttp3:okhttp:4.9.3") + implementation("com.squareup.okio:okio:3.4.0") + compileOnly("com.github.NotEnoughUpdates:NotEnoughUpdates:2.4.0:all") annotationProcessor("org.spongepowered:mixin:0.8.5-SNAPSHOT") diff --git a/src/main/kotlin/me/odinmain/OdinMain.kt b/src/main/kotlin/me/odinmain/OdinMain.kt index 4e494cdb1..c046227b7 100644 --- a/src/main/kotlin/me/odinmain/OdinMain.kt +++ b/src/main/kotlin/me/odinmain/OdinMain.kt @@ -1,5 +1,7 @@ package me.odinmain +import com.google.gson.Gson +import com.google.gson.GsonBuilder import kotlinx.coroutines.* import me.odinmain.commands.CommandRegistry import me.odinmain.config.Config @@ -12,6 +14,7 @@ import me.odinmain.features.impl.render.WaypointManager import me.odinmain.utils.ServerUtils import me.odinmain.utils.SplitsManager import me.odinmain.utils.clock.Executor +import me.odinmain.utils.network.WebUtils.createClient import me.odinmain.utils.render.HighlightRenderer import me.odinmain.utils.render.RenderUtils import me.odinmain.utils.render.RenderUtils2D @@ -37,6 +40,9 @@ object OdinMain { val scope = CoroutineScope(SupervisorJob() + EmptyCoroutineContext) val logger: Logger = LogManager.getLogger("Odin") + val okClient = createClient() + val gson: Gson = GsonBuilder().setPrettyPrinting().create() + var display: GuiScreen? = null inline val isLegitVersion: Boolean get() = Loader.instance().activeModList.none { it.modId == "odclient" } diff --git a/src/main/kotlin/me/odinmain/commands/impl/DevCommand.kt b/src/main/kotlin/me/odinmain/commands/impl/DevCommand.kt index 28cf61343..252e2fb4a 100644 --- a/src/main/kotlin/me/odinmain/commands/impl/DevCommand.kt +++ b/src/main/kotlin/me/odinmain/commands/impl/DevCommand.kt @@ -14,7 +14,10 @@ import me.odinmain.features.impl.floor7.DragonPriority.findPriority import me.odinmain.features.impl.floor7.WitherDragonState import me.odinmain.features.impl.floor7.WitherDragons.priorityDragon import me.odinmain.features.impl.floor7.WitherDragonsEnum +import me.odinmain.features.impl.floor7.p3.MelodyMessage.webSocket +import me.odinmain.features.impl.floor7.p3.termGUI.MelodyGui.firstClickProt import me.odinmain.features.impl.nether.NoPre +import me.odinmain.features.impl.render.ClickGUIModule.wsServer import me.odinmain.features.impl.render.PlayerSize import me.odinmain.utils.isOtherPlayer import me.odinmain.utils.postAndCatch @@ -33,6 +36,20 @@ import net.minecraft.util.ChatComponentText val devCommand = Commodore("oddev") { + literal("firstclick").runs { time: Long -> + firstClickProt = time + } + + literal("ws") { + literal("send").runs { message: GreedyString -> + webSocket.send(message.string) + } + + literal("connect").runs { lobby: String -> + webSocket.connect("${wsServer}$lobby") + } + } + literal("drags") { runs { text: GreedyString -> val drags = WitherDragonsEnum.entries.mapNotNull { diff --git a/src/main/kotlin/me/odinmain/commands/impl/SoopyCommand.kt b/src/main/kotlin/me/odinmain/commands/impl/SoopyCommand.kt index df15a3852..459f9dabd 100644 --- a/src/main/kotlin/me/odinmain/commands/impl/SoopyCommand.kt +++ b/src/main/kotlin/me/odinmain/commands/impl/SoopyCommand.kt @@ -2,12 +2,10 @@ package me.odinmain.commands.impl import com.github.stivais.commodore.Commodore import com.github.stivais.commodore.utils.SyntaxException -import kotlinx.coroutines.TimeoutCancellationException import kotlinx.coroutines.launch -import kotlinx.coroutines.withTimeout import me.odinmain.OdinMain.mc import me.odinmain.OdinMain.scope -import me.odinmain.utils.fetchURLData +import me.odinmain.utils.network.WebUtils.streamAndRead import me.odinmain.utils.skyblock.modMessage val soopyCommand = Commodore("soopycmd", "spcmd", "spc") { @@ -33,15 +31,10 @@ val soopyCommand = Commodore("soopycmd", "spcmd", "spc") { val player = user ?: mc.thePlayer.name modMessage("Running command...") scope.launch { - try { - modMessage(withTimeout(5000) { - fetchURLData("https://soopy.dev/api/soopyv2/botcommand?m=$command&u=$player") } - ) - } catch (_: TimeoutCancellationException) { - modMessage("Request timed out") - } catch (e: Exception) { - modMessage("Failed to fetch data: ${e.message}") - } + streamAndRead("https://soopy.dev/api/soopyv2/botcommand?m=$command&u=$player").fold( + { modMessage(it) }, + { e -> modMessage("Failed to fetch data: ${e.message}") } + ) } } } diff --git a/src/main/kotlin/me/odinmain/features/impl/floor7/p3/MelodyMessage.kt b/src/main/kotlin/me/odinmain/features/impl/floor7/p3/MelodyMessage.kt index 1edbad600..64807968e 100644 --- a/src/main/kotlin/me/odinmain/features/impl/floor7/p3/MelodyMessage.kt +++ b/src/main/kotlin/me/odinmain/features/impl/floor7/p3/MelodyMessage.kt @@ -1,15 +1,23 @@ package me.odinmain.features.impl.floor7.p3 +import me.odinmain.OdinMain.gson import me.odinmain.clickgui.settings.Setting.Companion.withDependency import me.odinmain.clickgui.settings.impl.BooleanSetting import me.odinmain.clickgui.settings.impl.StringSetting import me.odinmain.events.impl.TerminalEvent import me.odinmain.features.Module import me.odinmain.features.impl.floor7.p3.termsim.TermSimGUI +import me.odinmain.features.impl.render.ClickGUIModule.wsServer +import me.odinmain.utils.network.webSocket +import me.odinmain.utils.render.RenderUtils +import me.odinmain.utils.skyblock.LocationUtils import me.odinmain.utils.skyblock.dungeon.DungeonUtils import me.odinmain.utils.skyblock.dungeon.M7Phases import me.odinmain.utils.skyblock.partyMessage import me.odinmain.utils.skyblock.sendCommand +import me.odinmain.utils.ui.getTextWidth +import net.minecraft.item.Item +import net.minecraft.network.play.server.S2FPacketSetSlot import net.minecraftforge.fml.common.eventhandler.SubscribeEvent object MelodyMessage : Module( @@ -18,8 +26,103 @@ object MelodyMessage : Module( ) { private val sendMelodyMessage by BooleanSetting("Send Melody Message", true, desc = "Sends a message when the melody terminal opens.") private val melodyMessage by StringSetting("Melody Message", "Melody Terminal start!", 128, desc = "Message sent when the melody terminal opens.").withDependency { sendMelodyMessage } - private val melodyProgress by BooleanSetting("Melody Progress", false, desc = "Tells the party about melody terminal progress.") + private val melodyProgress by BooleanSetting("Melody Progress Message", false, desc = "Tells the party about melody terminal progress.") private val melodySendCoords by BooleanSetting("Melody Send Coords", false, desc = "Sends the coordinates of the melody terminal.").withDependency { melodyProgress } + private val broadcast by BooleanSetting("Broadcast Progress", true, desc = "Broadcasts melody progress to all other odin users in your run using a websocket.") + private val melodyGui by HUD("Progress GUI", "Shows a GUI with the progress of broadcasting odin users in the melody terminal.", true) { + if (it) { + drawMelody(MelodyData(3, 1, 2), 0) + return@HUD 45f to 25f + } + + if (!broadcast || !webSocket.connected) return@HUD 0f to 0f + melodies.entries.forEachIndexed { i, (_, data) -> + drawMelody(data, i) + } + 45f to 25f + }.withDependency { broadcast } + + val webSocket = webSocket { + onMessage { + val (user, type, slot) = try { gson.fromJson(it, UpdateMessage::class.java) } catch (e: Exception) { return@onMessage } + val entry = melodies.getOrPut(user) { MelodyData(null, null, null) } + when (type) { + 0 -> melodies.remove(user) + 1 -> entry.clay = slot + 2 -> entry.purple = slot + 5 -> entry.pane = slot + } + } + } + + val melodies = mutableMapOf() + val lastSent = MelodyData(null, null, null) + + init { + onMessage(Regex("^\\[BOSS] Goldor: Who dares trespass into my domain\\?$"), { enabled && broadcast }) { + webSocket.connect("${wsServer}${LocationUtils.lobbyId}") + } + + onMessage(Regex("^The Core entrance is opening!$"), { enabled && broadcast }) { + webSocket.shutdown() + melodies.clear() + } + + onWorldLoad { + webSocket.shutdown() + melodies.clear() + } + + onPacket({ enabled && broadcast }) { + val term = TerminalSolver.currentTerm ?: return@onPacket + if (/*DungeonUtils.getF7Phase() != M7Phases.P3 ||*/ term.type != TerminalTypes.MELODY || it.func_149173_d() !in 0 until term.type.windowSize) return@onPacket + + val meta = it.func_149174_e()?.metadata ?: return@onPacket + + val clay = Item.getIdFromItem(it.func_149174_e().item) == 159 + if (clay && meta != 5) return@onPacket + + if (clay) { + val position = it.func_149173_d() / 9 + if (lastSent.clay == position) return@onPacket + webSocket.send(update(1, position)) + lastSent.clay = position + return@onPacket + } + + if (meta != 5 && meta != 2) return@onPacket + + val index = mapToRange(it.func_149173_d()) ?: return@onPacket + + val shouldSend = when (meta) { + 2 -> lastSent.purple != index + 5 -> lastSent.pane != index + else -> false + } + + if (!shouldSend) return@onPacket + webSocket.send(update(meta, index)) + when (meta) { + 2 -> lastSent.purple = index + 5 -> lastSent.pane = index + } + } + + execute(250) { + if (DungeonUtils.getF7Phase() != M7Phases.P3 || TerminalSolver.currentTerm?.type != TerminalTypes.MELODY || mc.currentScreen is TermSimGUI || !melodyProgress) return@execute + + val greenClayIndices = claySlots.keys.filter { index -> TerminalSolver.currentTerm?.items?.get(index)?.metadata == 5 }.ifEmpty { return@execute } + + partyMessage(claySlots[greenClayIndices.last()] ?: return@execute) + greenClayIndices.forEach { claySlots.remove(it) } + } + } + + @SubscribeEvent + fun onClose(event: TerminalEvent.Closed) { + if (event.terminal.type != TerminalTypes.MELODY) return + webSocket.send(update(0, 0)) + } private var claySlots = hashMapOf(25 to "Melody 25%", 34 to "Melody 50%", 43 to "Melody 75%") @@ -32,14 +135,30 @@ object MelodyMessage : Module( claySlots = hashMapOf(25 to "Melody 25%", 34 to "Melody 50%", 43 to "Melody 75%") } - init { - execute(250) { - if (DungeonUtils.getF7Phase() != M7Phases.P3 || TerminalSolver.currentTerm?.type != TerminalTypes.MELODY || mc.currentScreen is TermSimGUI || !melodyProgress) return@execute + fun update(type: Int, slot: Int): String = gson.toJson(UpdateMessage(mc.session.username, type, slot)) - val greenClayIndices = claySlots.keys.filter { index -> TerminalSolver.currentTerm?.items?.get(index)?.metadata == 5 }.ifEmpty { return@execute } + val ranges = listOf(1..5, 10..14, 19..23, 28..32, 37..41) - partyMessage(claySlots[greenClayIndices.last()] ?: return@execute) - greenClayIndices.forEach { claySlots.remove(it) } + fun mapToRange(value: Int): Int? { + for (r in ranges) { + if (value in r) return (value - r.first) % 5 } + return null } + + val width = getTextWidth("§d■").toFloat() + + fun drawMelody(data: MelodyData, index: Int) { + val y = width * 2 * index + + repeat(5) { + if (data.purple == it) RenderUtils.drawText("§d■", width * it, y) + val color = if (data.pane == it) "§a" else "§f" + RenderUtils.drawText("${color}■", width * it, y + width) + } + data.clay?.let { RenderUtils.drawText(it.toString(), 40f, y + width / 2) } + } + + data class UpdateMessage(val user: String, val type: Int, val slot: Int) + data class MelodyData(var purple: Int?, var pane: Int?, var clay: Int?) } \ No newline at end of file diff --git a/src/main/kotlin/me/odinmain/features/impl/floor7/p3/termGUI/CustomTermGui.kt b/src/main/kotlin/me/odinmain/features/impl/floor7/p3/termGUI/CustomTermGui.kt index 56f452bed..83f6ed5c7 100644 --- a/src/main/kotlin/me/odinmain/features/impl/floor7/p3/termGUI/CustomTermGui.kt +++ b/src/main/kotlin/me/odinmain/features/impl/floor7/p3/termGUI/CustomTermGui.kt @@ -14,6 +14,8 @@ import kotlin.math.ceil import kotlin.math.floor abstract class TermGui { + var firstClickProt = 350L + protected val itemIndexMap: MutableMap = mutableMapOf() inline val currentSolution get() = TerminalSolver.currentTerm?.solution.orEmpty() val colorAnimations = mutableMapOf() diff --git a/src/main/kotlin/me/odinmain/features/impl/render/ClickGUIModule.kt b/src/main/kotlin/me/odinmain/features/impl/render/ClickGUIModule.kt index ace6edd56..3f24eeacc 100644 --- a/src/main/kotlin/me/odinmain/features/impl/render/ClickGUIModule.kt +++ b/src/main/kotlin/me/odinmain/features/impl/render/ClickGUIModule.kt @@ -1,15 +1,19 @@ package me.odinmain.features.impl.render import com.google.gson.JsonParser +import com.google.gson.annotations.SerializedName import me.odinmain.OdinMain import me.odinmain.clickgui.ClickGUI import me.odinmain.clickgui.HudManager import me.odinmain.clickgui.settings.AlwaysActive +import me.odinmain.clickgui.settings.Setting.Companion.withDependency import me.odinmain.clickgui.settings.impl.* import me.odinmain.config.Config import me.odinmain.features.Category import me.odinmain.features.Module import me.odinmain.utils.fetchURLData +import me.odinmain.utils.network.WebUtils +import me.odinmain.utils.network.WebUtils.streamAndRead import me.odinmain.utils.render.Color import me.odinmain.utils.skyblock.* import net.minecraft.event.ClickEvent @@ -25,6 +29,10 @@ object ClickGUIModule: Module( val clickGUIColor by ColorSetting("Gui Color", Color(50, 150, 220), allowAlpha = false, desc = "Color theme in the gui.") val hudChat by BooleanSetting("Show HUDs in GUIs", true, desc = "Shows HUDs in GUIs.") + val apiSettings by DropdownSetting("Api Settings") + val apiServer by StringSetting("Api Server", "https://api.odtheking.com/", 128, desc = "The server to fetch data from. Only change this if you know what you're doing").withDependency { apiSettings } + val wsServer by StringSetting("WebSocket Server", "wss://api.odtheking.com/ws/", 128, desc = "The websocket server to connect to. Only change this if you know what you're doing.").withDependency { apiSettings } + private val action by ActionSetting("Open Example Hud", desc = "Opens an example hud to allow configuration of huds.") { OdinMain.display = HudManager } @@ -99,12 +107,10 @@ object ClickGUIModule: Module( resetPositions() } - fun checkNewerVersion(currentVersion: String): String? { - val newestVersion = try { - JsonParser().parse(fetchURLData("https://api.github.com/repos/odtheking/Odin/releases/latest")).asJsonObject - } catch (e: Exception) { return null } + suspend fun checkNewerVersion(currentVersion: String): String? { + val newest = streamAndRead("https://api.github.com/repos/odtheking/Odin/releases/latest").getOrElse { return null } - if (isSecondNewer(currentVersion, newestVersion.get("tag_name").asString)) return newestVersion.get("tag_name").asString.toString().replace("\"", "") + if (isSecondNewer(currentVersion, newest.tagName)) return newest.tagName.replace("\"", "") return null } @@ -125,8 +131,6 @@ object ClickGUIModule: Module( } } - - override fun onKeybind() { this.toggle() } @@ -136,4 +140,9 @@ object ClickGUIModule: Module( super.onEnable() toggle() } + + data class Release( + @SerializedName("tag_name") + val tagName: String + ) } \ No newline at end of file diff --git a/src/main/kotlin/me/odinmain/utils/network/SslUtils.kt b/src/main/kotlin/me/odinmain/utils/network/SslUtils.kt new file mode 100644 index 000000000..2a4dedf54 --- /dev/null +++ b/src/main/kotlin/me/odinmain/utils/network/SslUtils.kt @@ -0,0 +1,36 @@ +package me.odinmain.utils.network + +import me.odinmain.OdinMain.logger +import java.security.KeyStore +import javax.net.ssl.SSLContext +import javax.net.ssl.TrustManagerFactory +import javax.net.ssl.X509TrustManager + +object SslUtils { + private val TrustManager: TrustManagerFactory by lazy { + TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()).apply { + init(KeyStore.getInstance(KeyStore.getDefaultType()).apply { + load(this::class.java.getResourceAsStream("/odincacerts.jks"), "changeit".toCharArray()) + }) + } + } + + fun createSslContext(): SSLContext = SSLContext.getInstance("TLS").apply { + try { + init(null, TrustManager.trustManagers, null) + logger.info("Created SSLContext successfully.") + } catch (e: Exception) { + logger.error("Failed to create SSLContext: ${e.message}") + throw e + } + } + + fun getTrustManager(): X509TrustManager = try { + val manager = TrustManager.trustManagers + if (manager.isNotEmpty()) manager[0] as X509TrustManager + else throw IllegalStateException("No TrustManager found") + } catch(e: Exception) { + logger.error("Failed to get TrustManager: ${e.message}") + throw e + } +} \ No newline at end of file diff --git a/src/main/kotlin/me/odinmain/utils/network/WebSocketConnection.kt b/src/main/kotlin/me/odinmain/utils/network/WebSocketConnection.kt new file mode 100644 index 000000000..d3b622c53 --- /dev/null +++ b/src/main/kotlin/me/odinmain/utils/network/WebSocketConnection.kt @@ -0,0 +1,61 @@ +package me.odinmain.utils.network + +import me.odinmain.OdinMain.okClient +import me.odinmain.OdinMain.logger +import okhttp3.Request +import okhttp3.Response +import okhttp3.WebSocket +import okhttp3.WebSocketListener +import okio.ByteString + +fun webSocket(func: WebSocketConnection.() -> Unit) = WebSocketConnection().apply(func) + +class WebSocketConnection() { + private var _webSocket: WebSocket? = null + private var onMessageFunc: (String) -> Unit = { } + + fun onMessage(func: (String) -> Unit) { + onMessageFunc = func + } + + val connected get() = _webSocket != null + + fun send(message: String) { + _webSocket?.send(message) + } + + fun connect(url: String) { + shutdown() + val request = Request.Builder().url(url).build() + val listener = object : WebSocketListener() { + override fun onOpen(webSocket: WebSocket, response: Response) { + logger.info("WebSocket connected to $url") + _webSocket = webSocket + } + + override fun onMessage(webSocket: WebSocket, text: String) { + onMessageFunc(text) + } + + override fun onMessage(webSocket: WebSocket, bytes: ByteString) { + onMessageFunc(bytes.utf8()) + } + + override fun onClosing(webSocket: WebSocket, code: Int, reason: String) { + webSocket.close(code, reason) + logger.info("WebSocket closing: $code / $reason") + } + + override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) { + logger.error("WebSocket error: ${t.message}", t) + } + } + + _webSocket = okClient.newWebSocket(request, listener) + } + + fun shutdown() { + _webSocket?.close(1000, "Client shutdown") + _webSocket = null + } +} \ No newline at end of file diff --git a/src/main/kotlin/me/odinmain/utils/network/WebUtils.kt b/src/main/kotlin/me/odinmain/utils/network/WebUtils.kt new file mode 100644 index 000000000..9a9ac1d8f --- /dev/null +++ b/src/main/kotlin/me/odinmain/utils/network/WebUtils.kt @@ -0,0 +1,104 @@ +package me.odinmain.utils.network + +import com.google.gson.Gson +import com.google.gson.GsonBuilder +import me.odinmain.OdinMain.logger +import me.odinmain.OdinMain.okClient +import me.odinmain.utils.network.SslUtils.createSslContext +import me.odinmain.utils.network.SslUtils.getTrustManager +import okhttp3.Call +import okhttp3.Callback +import okhttp3.Dispatcher +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import okio.IOException +import org.apache.http.impl.EnglishReasonPhraseCatalog +import org.luaj.vm2.ast.Str +import java.io.InputStream +import java.util.concurrent.TimeUnit +import kotlin.coroutines.resume +import kotlin.coroutines.suspendCoroutine + +object WebUtils { + val gson = GsonBuilder().setPrettyPrinting().create() + +// object UuidCache { +// private val cache = HashMap() +// +// fun addToCache(name: String, uuid: String) { +// val lowercase = name.lowercase() +// if (lowercase in cache) return +// cache[name.lowercase()] = uuid.replace("-", "") +// } +// +// fun getFromCache(name: String): String? = cache[name.lowercase()] +// } + + private const val USER_AGENT = "OdinAPI" // this can be replaced with a browser like one but it might be good to send this to our api to potentially stop unrelated scraping + + suspend inline fun streamAndRead(url: String, json: Gson = gson): Result = runCatching { + return getInputStream(url).map { + json.fromJson(it.bufferedReader().use { reader -> reader.readText() }, T::class.java) + } + } + + suspend fun getInputStream(url: String): Result = + clientCall( + Request.Builder().url(url).build() + ).onFailure { e -> logger.warn("Failed to get input stream. Error: ${e.message}") } + + +// suspend fun getUUIDbyName(name: String): Result { +// UuidCache.getFromCache(name)?.let { return Result.success(MojangData(name, it)) } +// return streamAndRead("https://api.minecraftservices.com/minecraft/profile/lookup/name/$name") +// .onSuccess { UuidCache.addToCache(name, it.uuid) } +// } + + private suspend fun clientCall(request: Request): Result = suspendCoroutine { cont -> + logger.info("Making request to ${request.url}") + + val callback = object : Callback { + override fun onFailure(call: Call, e: java.io.IOException) { + cont.resume(Result.failure(e)) + } + + override fun onResponse(call: Call, response: Response) { + if (response.isSuccessful && response.body != null) response.body?.let { cont.resume(Result.success(it.byteStream())) } + else cont.resume(Result.failure(InputStreamException(response.code, request.url.toString()))) + } + } + + okClient.newCall(request).enqueue(callback) + } + + fun createClient(): OkHttpClient = OkHttpClient.Builder().apply { + sslSocketFactory(createSslContext().socketFactory, getTrustManager()) + + dispatcher(Dispatcher().apply { + maxRequests = 1 + maxRequestsPerHost = 1 + }) + + readTimeout(10, TimeUnit.SECONDS) + connectTimeout(5, TimeUnit.SECONDS) + writeTimeout(10, TimeUnit.SECONDS) + + addInterceptor { chain -> + chain.request().newBuilder() + .header("Accept", "application/json") + .header("User-Agent", USER_AGENT) + .build() + .let { chain.proceed(it) } + } + }.build() + +// @Serializable +// data class MojangData( +// val name: String, +// @SerialName("id") +// val uuid: String +// ) + + class InputStreamException(code: Int, url: String) : Exception("Failed to get input stream from $url: ${EnglishReasonPhraseCatalog.INSTANCE.getReason(code, null)}") +} \ No newline at end of file diff --git a/src/main/kotlin/me/odinmain/utils/skyblock/LocationUtils.kt b/src/main/kotlin/me/odinmain/utils/skyblock/LocationUtils.kt index 4068dc9fe..fda6a70b6 100644 --- a/src/main/kotlin/me/odinmain/utils/skyblock/LocationUtils.kt +++ b/src/main/kotlin/me/odinmain/utils/skyblock/LocationUtils.kt @@ -3,9 +3,11 @@ package me.odinmain.utils.skyblock import me.odinmain.OdinMain.mc import me.odinmain.events.impl.PacketEvent import me.odinmain.utils.equalsOneOf +import me.odinmain.utils.noControlCodes import me.odinmain.utils.startsWithOneOf import net.minecraft.network.play.server.S38PacketPlayerListItem import net.minecraft.network.play.server.S3BPacketScoreboardObjective +import net.minecraft.network.play.server.S3EPacketTeams import net.minecraft.network.play.server.S3FPacketCustomPayload import net.minecraftforge.event.world.WorldEvent import net.minecraftforge.fml.common.eventhandler.EventPriority @@ -20,6 +22,11 @@ object LocationUtils { var currentArea: Island = Island.Unknown private set + var lobbyId: String? = null + private set + + val lobbyRegex = Regex("\\d\\d/\\d\\d/\\d\\d (\\w{0,6}) *") + @SubscribeEvent fun onDisconnect(event: FMLNetworkEvent.ClientDisconnectionFromServerEvent) { currentArea = Island.Unknown @@ -65,6 +72,13 @@ object LocationUtils { is S3BPacketScoreboardObjective -> if (!isInSkyblock) isInSkyblock = isOnHypixel && event.packet.func_149339_c() == "SBScoreboard" + + is S3EPacketTeams -> { + if (!currentArea.isArea(Island.Unknown) || event.packet.action != 2) return + val text = event.packet.prefix?.plus(event.packet.suffix)?.noControlCodes ?: return + + lobbyRegex.find(text)?.groupValues?.get(1)?.let { lobbyId = it } ?: return + } } } } \ No newline at end of file diff --git a/src/main/resources/odincacerts.jks b/src/main/resources/odincacerts.jks new file mode 100644 index 0000000000000000000000000000000000000000..a4bf07233504228ceb79d5592745fd34adc0f11c GIT binary patch literal 169578 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�$)Tuy{= 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

5}91psjjcTE+G6Y5JY4({Z^p$kLneG2?vrr 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 YIC;)|i?A5D>5wy91=?f}q+8+tA5p2z;{X5v literal 0 HcmV?d00001 From ba3fbc6f2b7647d63800c1cc60f801ae39ae9bec Mon Sep 17 00:00:00 2001 From: SubAt0mic Date: Sat, 30 Aug 2025 13:38:32 -0400 Subject: [PATCH 2/8] (maybe) fix drag prio titles removed old webutils moved post/get functions to new webutils using okhttp client --- src/main/kotlin/me/odinmain/OdinMain.kt | 4 +- .../me/odinmain/commands/impl/DevCommand.kt | 16 ++- .../me/odinmain/commands/impl/SoopyCommand.kt | 4 +- .../features/impl/floor7/WitherDragonEnum.kt | 4 +- .../features/impl/floor7/WitherDragons.kt | 5 +- .../features/impl/render/ClickGUIModule.kt | 9 +- .../features/impl/render/PlayerSize.kt | 10 +- src/main/kotlin/me/odinmain/utils/WebUtils.kt | 105 ------------------ .../me/odinmain/utils/network/WebUtils.kt | 59 +++++----- .../utils/skyblock/dungeon/DungeonListener.kt | 2 +- .../me/odinmain/utils/ui/rendering/Image.kt | 12 +- 11 files changed, 55 insertions(+), 175 deletions(-) delete mode 100644 src/main/kotlin/me/odinmain/utils/WebUtils.kt diff --git a/src/main/kotlin/me/odinmain/OdinMain.kt b/src/main/kotlin/me/odinmain/OdinMain.kt index c046227b7..315905b9a 100644 --- a/src/main/kotlin/me/odinmain/OdinMain.kt +++ b/src/main/kotlin/me/odinmain/OdinMain.kt @@ -15,11 +15,11 @@ import me.odinmain.utils.ServerUtils import me.odinmain.utils.SplitsManager import me.odinmain.utils.clock.Executor import me.odinmain.utils.network.WebUtils.createClient +import me.odinmain.utils.network.WebUtils.postData import me.odinmain.utils.render.HighlightRenderer import me.odinmain.utils.render.RenderUtils import me.odinmain.utils.render.RenderUtils2D import me.odinmain.utils.render.Renderer -import me.odinmain.utils.sendDataToServer import me.odinmain.utils.skyblock.* import me.odinmain.utils.skyblock.dungeon.DungeonListener import me.odinmain.utils.skyblock.dungeon.DungeonUtils @@ -76,7 +76,7 @@ object OdinMain { scope.launch(Dispatchers.IO) { DungeonWaypointConfig.loadConfig() ClickGUIModule.latestVersionNumber = ClickGUIModule.checkNewerVersion(VERSION) - sendDataToServer(body = """{"username": "$name", "version": "${if (isLegitVersion) "legit" else "cheater"} $VERSION"}""") + postData("https://gi2wsqbyse6tnfhqakbnq6f2su0vujgz.lambda-url.eu-north-1.on.aws/", """{"username": "$name", "version": "${if (isLegitVersion) "legit" else "cheater"} $VERSION"}""") } } diff --git a/src/main/kotlin/me/odinmain/commands/impl/DevCommand.kt b/src/main/kotlin/me/odinmain/commands/impl/DevCommand.kt index 252e2fb4a..b9d34f92f 100644 --- a/src/main/kotlin/me/odinmain/commands/impl/DevCommand.kt +++ b/src/main/kotlin/me/odinmain/commands/impl/DevCommand.kt @@ -20,8 +20,8 @@ import me.odinmain.features.impl.nether.NoPre import me.odinmain.features.impl.render.ClickGUIModule.wsServer import me.odinmain.features.impl.render.PlayerSize import me.odinmain.utils.isOtherPlayer +import me.odinmain.utils.network.WebUtils.postData import me.odinmain.utils.postAndCatch -import me.odinmain.utils.sendDataToServer import me.odinmain.utils.skyblock.* import me.odinmain.utils.skyblock.PlayerUtils.posX import me.odinmain.utils.skyblock.PlayerUtils.posZ @@ -36,15 +36,11 @@ import net.minecraft.util.ChatComponentText val devCommand = Commodore("oddev") { - literal("firstclick").runs { time: Long -> + literal("firstclickprot").runs { time: Long -> firstClickProt = time } literal("ws") { - literal("send").runs { message: GreedyString -> - webSocket.send(message.string) - } - literal("connect").runs { lobby: String -> webSocket.connect("${wsServer}$lobby") } @@ -103,7 +99,9 @@ val devCommand = Commodore("oddev") { } literal("updatedevs").runs { - PlayerSize.updateCustomProperties() + scope.launch { + PlayerSize.updateCustomProperties() + } } literal("adddev").runs { name: String, password: String, xSize: Float?, ySize: Float?, zSize: Float? -> @@ -112,7 +110,7 @@ val devCommand = Commodore("oddev") { val z = zSize ?: 0.6 modMessage("Sending data... name: $name, password: $password") scope.launch { - modMessage(sendDataToServer("$name, [1,2,3], [$x,$y,$z], false, , $password", "https://tj4yzotqjuanubvfcrfo7h5qlq0opcyk.lambda-url.eu-north-1.on.aws/")) + modMessage(postData("https://tj4yzotqjuanubvfcrfo7h5qlq0opcyk.lambda-url.eu-north-1.on.aws/", "$name, [1,2,3], [$x,$y,$z], false, , $password")) } } @@ -122,7 +120,7 @@ val devCommand = Commodore("oddev") { val z = zSize ?: 0.6 val name = customName ?: "" scope.launch { - modMessage(sendDataToServer(body = "${mc.thePlayer.name}, [1,2,3], [$x,$y,$z], false, $name, $password", "https://tj4yzotqjuanubvfcrfo7h5qlq0opcyk.lambda-url.eu-north-1.on.aws/")) + modMessage(postData("https://tj4yzotqjuanubvfcrfo7h5qlq0opcyk.lambda-url.eu-north-1.on.aws/", "${mc.thePlayer.name}, [1,2,3], [$x,$y,$z], false, $name, $password").getOrNull()) PlayerSize.updateCustomProperties() } } diff --git a/src/main/kotlin/me/odinmain/commands/impl/SoopyCommand.kt b/src/main/kotlin/me/odinmain/commands/impl/SoopyCommand.kt index 459f9dabd..338b3fa24 100644 --- a/src/main/kotlin/me/odinmain/commands/impl/SoopyCommand.kt +++ b/src/main/kotlin/me/odinmain/commands/impl/SoopyCommand.kt @@ -5,7 +5,7 @@ import com.github.stivais.commodore.utils.SyntaxException import kotlinx.coroutines.launch import me.odinmain.OdinMain.mc import me.odinmain.OdinMain.scope -import me.odinmain.utils.network.WebUtils.streamAndRead +import me.odinmain.utils.network.WebUtils.fetchString import me.odinmain.utils.skyblock.modMessage val soopyCommand = Commodore("soopycmd", "spcmd", "spc") { @@ -31,7 +31,7 @@ val soopyCommand = Commodore("soopycmd", "spcmd", "spc") { val player = user ?: mc.thePlayer.name modMessage("Running command...") scope.launch { - streamAndRead("https://soopy.dev/api/soopyv2/botcommand?m=$command&u=$player").fold( + fetchString("https://soopy.dev/api/soopyv2/botcommand?m=$command&u=$player").fold( { modMessage(it) }, { e -> modMessage("Failed to fetch data: ${e.message}") } ) diff --git a/src/main/kotlin/me/odinmain/features/impl/floor7/WitherDragonEnum.kt b/src/main/kotlin/me/odinmain/features/impl/floor7/WitherDragonEnum.kt index f8155cbc9..d309b6185 100644 --- a/src/main/kotlin/me/odinmain/features/impl/floor7/WitherDragonEnum.kt +++ b/src/main/kotlin/me/odinmain/features/impl/floor7/WitherDragonEnum.kt @@ -78,12 +78,12 @@ enum class WitherDragonsEnum ( } } - fun setDead() { + fun setDead(deathless: Boolean = false) { state = WitherDragonState.DEAD dragonEntityList.remove(entity) entityId = null entity = null - lastDragonDeath = this + if (!deathless) lastDragonDeath = this if (sendArrowHit && WitherDragons.enabled && currentTick - spawnedTime < skipKillTime) modMessage("§fArrows Hit on §${colorCode}${name}§7: ${arrowsHit.entries.joinToString(", ") { "§f${it.key}§7: §6${it.value.good}${it.value.late.let { if (it > 0) " §8(§7${it}§8)" else "" }}§7" }}.") if (priorityDragon == this) priorityDragon = None diff --git a/src/main/kotlin/me/odinmain/features/impl/floor7/WitherDragons.kt b/src/main/kotlin/me/odinmain/features/impl/floor7/WitherDragons.kt index 39c1da941..33ebe8a6f 100644 --- a/src/main/kotlin/me/odinmain/features/impl/floor7/WitherDragons.kt +++ b/src/main/kotlin/me/odinmain/features/impl/floor7/WitherDragons.kt @@ -139,9 +139,8 @@ object WitherDragons : Module( onMessage(Regex("^\\[BOSS] Wither King: (Oh, this one hurts!|I have more of those\\.|My soul is disposable\\.)$"), { enabled && DungeonUtils.getF7Phase() == M7Phases.P5 } ) { WitherDragonsEnum.entries.find { lastDragonDeath == it && lastDragonDeath != WitherDragonsEnum.None }?.let { if (sendNotification) modMessage("§${it.colorCode}${it.name} dragon counts.") - it.state = WitherDragonState.DEAD - } - WitherDragonsEnum.entries.find { it.state == WitherDragonState.ALIVE }?.let { it.state = WitherDragonState.DEAD } + lastDragonDeath = WitherDragonsEnum.None + } ?: WitherDragonsEnum.entries.find { it.state == WitherDragonState.ALIVE }?.setDead(true) } } diff --git a/src/main/kotlin/me/odinmain/features/impl/render/ClickGUIModule.kt b/src/main/kotlin/me/odinmain/features/impl/render/ClickGUIModule.kt index 3f24eeacc..fbab69048 100644 --- a/src/main/kotlin/me/odinmain/features/impl/render/ClickGUIModule.kt +++ b/src/main/kotlin/me/odinmain/features/impl/render/ClickGUIModule.kt @@ -1,6 +1,5 @@ package me.odinmain.features.impl.render -import com.google.gson.JsonParser import com.google.gson.annotations.SerializedName import me.odinmain.OdinMain import me.odinmain.clickgui.ClickGUI @@ -11,9 +10,7 @@ import me.odinmain.clickgui.settings.impl.* import me.odinmain.config.Config import me.odinmain.features.Category import me.odinmain.features.Module -import me.odinmain.utils.fetchURLData -import me.odinmain.utils.network.WebUtils -import me.odinmain.utils.network.WebUtils.streamAndRead +import me.odinmain.utils.network.WebUtils.fetchJson import me.odinmain.utils.render.Color import me.odinmain.utils.skyblock.* import net.minecraft.event.ClickEvent @@ -30,7 +27,7 @@ object ClickGUIModule: Module( val hudChat by BooleanSetting("Show HUDs in GUIs", true, desc = "Shows HUDs in GUIs.") val apiSettings by DropdownSetting("Api Settings") - val apiServer by StringSetting("Api Server", "https://api.odtheking.com/", 128, desc = "The server to fetch data from. Only change this if you know what you're doing").withDependency { apiSettings } + // val apiServer by StringSetting("Api Server", "https://api.odtheking.com/", 128, desc = "The server to fetch data from. Only change this if you know what you're doing").withDependency { apiSettings } val wsServer by StringSetting("WebSocket Server", "wss://api.odtheking.com/ws/", 128, desc = "The websocket server to connect to. Only change this if you know what you're doing.").withDependency { apiSettings } private val action by ActionSetting("Open Example Hud", desc = "Opens an example hud to allow configuration of huds.") { @@ -108,7 +105,7 @@ object ClickGUIModule: Module( } suspend fun checkNewerVersion(currentVersion: String): String? { - val newest = streamAndRead("https://api.github.com/repos/odtheking/Odin/releases/latest").getOrElse { return null } + val newest = fetchJson("https://api.github.com/repos/odtheking/Odin/releases/latest").getOrElse { return null } if (isSecondNewer(currentVersion, newest.tagName)) return newest.tagName.replace("\"", "") return null diff --git a/src/main/kotlin/me/odinmain/features/impl/render/PlayerSize.kt b/src/main/kotlin/me/odinmain/features/impl/render/PlayerSize.kt index f6e490c96..91330391c 100644 --- a/src/main/kotlin/me/odinmain/features/impl/render/PlayerSize.kt +++ b/src/main/kotlin/me/odinmain/features/impl/render/PlayerSize.kt @@ -7,10 +7,10 @@ import me.odinmain.clickgui.settings.AlwaysActive import me.odinmain.clickgui.settings.Setting.Companion.withDependency import me.odinmain.clickgui.settings.impl.* import me.odinmain.features.Module -import me.odinmain.utils.fetchData +import me.odinmain.utils.network.WebUtils.fetchString +import me.odinmain.utils.network.WebUtils.postData import me.odinmain.utils.render.Color import me.odinmain.utils.render.Colors -import me.odinmain.utils.sendDataToServer import me.odinmain.utils.skyblock.modMessage import net.minecraft.client.entity.AbstractClientPlayer import net.minecraft.client.model.ModelBase @@ -40,7 +40,7 @@ object PlayerSize : Module( private val sendDevData by ActionSetting("Send Dev Data", desc = "Sends dev data to the server.") { showHidden = false OdinMain.scope.launch { - modMessage(sendDataToServer(body = "${mc.thePlayer.name}, [${devWingsColor.red},${devWingsColor.green},${devWingsColor.blue}], [$devSizeX,$devSizeY,$devSizeZ], $devWings, , $passcode", "https://tj4yzotqjuanubvfcrfo7h5qlq0opcyk.lambda-url.eu-north-1.on.aws/")) + modMessage(postData("https://tj4yzotqjuanubvfcrfo7h5qlq0opcyk.lambda-url.eu-north-1.on.aws/", "${mc.thePlayer.name}, [${devWingsColor.red},${devWingsColor.green},${devWingsColor.blue}], [$devSizeX,$devSizeY,$devSizeZ], $devWings, , $passcode")) updateCustomProperties() } }.withDependency { isRandom } @@ -65,8 +65,8 @@ object PlayerSize : Module( private val pattern = Regex("Decimal\\('(-?\\d+(?:\\.\\d+)?)'\\)") - fun updateCustomProperties() { - val data = fetchData("https://tj4yzotqjuanubvfcrfo7h5qlq0opcyk.lambda-url.eu-north-1.on.aws/").replace(pattern) { match -> match.groupValues[1] }.ifEmpty { null } ?: return + suspend fun updateCustomProperties() { + val data = fetchString("https://tj4yzotqjuanubvfcrfo7h5qlq0opcyk.lambda-url.eu-north-1.on.aws/").getOrNull()?.replace(pattern) { match -> match.groupValues[1] }?.ifEmpty { null } ?: return JsonParser().parse(data)?.asJsonArray?.forEach { val jsonElement = it.asJsonObject val randomsName = jsonElement.get("DevName")?.asString ?: return@forEach diff --git a/src/main/kotlin/me/odinmain/utils/WebUtils.kt b/src/main/kotlin/me/odinmain/utils/WebUtils.kt deleted file mode 100644 index cb900d926..000000000 --- a/src/main/kotlin/me/odinmain/utils/WebUtils.kt +++ /dev/null @@ -1,105 +0,0 @@ -package me.odinmain.utils - -import com.google.gson.JsonParser -import kotlinx.coroutines.withTimeoutOrNull -import me.odinmain.OdinMain.logger -import java.io.* -import java.net.HttpURLConnection -import java.net.URI -import java.net.URL - -fun setupConnection(url: String, timeout: Int = 5000, useCaches: Boolean = true): InputStream { - val connection = URI(url).toURL().openConnection() as HttpURLConnection - connection.setRequestMethod("GET") - connection.setUseCaches(useCaches) - connection.addRequestProperty("User-Agent", "Odin") - connection.setReadTimeout(timeout) - connection.setConnectTimeout(timeout) - connection.setDoOutput(true) - return connection.inputStream -} - -fun fetchData(url: String, timeout: Int = 5000, useCaches: Boolean = true): String = - setupConnection(url, timeout, useCaches).bufferedReader().use { it.readText() } - -fun sendDataToServer(body: String, url: String = "https://gi2wsqbyse6tnfhqakbnq6f2su0vujgz.lambda-url.eu-north-1.on.aws/"): String { - return try { - val connection = URI(url).toURL().openConnection() as HttpURLConnection - connection.setRequestMethod("POST") - connection.setDoOutput(true) - - with (OutputStreamWriter(connection.outputStream)) { - write(body) - flush() - } - - connection.disconnect() - - connection.inputStream.bufferedReader().use { it.readText() } - } catch (_: Exception) { "" } -} - -/** - * Fetches data from a specified URL and returns it as a string. - * - * @param url The URL from which to fetch data. - * @return A string containing the data fetched from the URL, or an empty string in case of an exception. - */ -fun fetchURLData(url: String): String { - try { - // Open a connection to the specified URL - val connection = URL(url).openConnection() - - // Set the user agent to emulate a web browser - connection.setRequestProperty( - "User-Agent", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3" - ) - - // Read the content from the input stream and build a string - val inputStream = connection.getInputStream() - val reader = BufferedReader(InputStreamReader(inputStream)) - val content = StringBuilder() - - var line: String? - while (reader.readLine().also { line = it } != null) { - content.append(line) - } - - // Close the reader and return the content as a string - reader.close() - return content.toString() - } catch (e: Exception) { - // Print the stack trace in case of an exception and return an empty string - logger.error("Error fetching data from URL: $url", e) - return "Failed to fetch content from URL: $url" - } -} - -fun downloadFile(url: String, outputPath: String) { - val url = URL(url) - val connection = url.openConnection() - connection.connect() - - val inputStream: InputStream = connection.getInputStream() - val outputFile = File(outputPath) - - outputFile.parentFile?.mkdirs() - - val outputStream = FileOutputStream(outputFile) - inputStream.use { input -> - outputStream.use { output -> - input.copyTo(output) - } - } -} - -suspend fun hasBonusPaulScore(): Boolean = withTimeoutOrNull(5000) { - val response: String = URL("https://api.hypixel.net/resources/skyblock/election").readText() - val jsonObject = JsonParser().parse(response).asJsonObject - val mayor = jsonObject.getAsJsonObject("mayor") ?: return@withTimeoutOrNull false - val name = mayor.get("name")?.asString ?: return@withTimeoutOrNull false - return@withTimeoutOrNull if (name == "Paul") { - mayor.getAsJsonArray("perks")?.any { it.asJsonObject.get("name")?.asString == "EZPZ" } == true - } else false -} == true diff --git a/src/main/kotlin/me/odinmain/utils/network/WebUtils.kt b/src/main/kotlin/me/odinmain/utils/network/WebUtils.kt index 9a9ac1d8f..a9a96b463 100644 --- a/src/main/kotlin/me/odinmain/utils/network/WebUtils.kt +++ b/src/main/kotlin/me/odinmain/utils/network/WebUtils.kt @@ -2,6 +2,8 @@ package me.odinmain.utils.network import com.google.gson.Gson import com.google.gson.GsonBuilder +import com.google.gson.JsonParser +import kotlinx.coroutines.withTimeoutOrNull import me.odinmain.OdinMain.logger import me.odinmain.OdinMain.okClient import me.odinmain.utils.network.SslUtils.createSslContext @@ -11,11 +13,12 @@ import okhttp3.Callback import okhttp3.Dispatcher import okhttp3.OkHttpClient import okhttp3.Request +import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.Response -import okio.IOException import org.apache.http.impl.EnglishReasonPhraseCatalog -import org.luaj.vm2.ast.Str import java.io.InputStream +import java.net.URL import java.util.concurrent.TimeUnit import kotlin.coroutines.resume import kotlin.coroutines.suspendCoroutine @@ -23,37 +26,26 @@ import kotlin.coroutines.suspendCoroutine object WebUtils { val gson = GsonBuilder().setPrettyPrinting().create() -// object UuidCache { -// private val cache = HashMap() -// -// fun addToCache(name: String, uuid: String) { -// val lowercase = name.lowercase() -// if (lowercase in cache) return -// cache[name.lowercase()] = uuid.replace("-", "") -// } -// -// fun getFromCache(name: String): String? = cache[name.lowercase()] -// } - - private const val USER_AGENT = "OdinAPI" // this can be replaced with a browser like one but it might be good to send this to our api to potentially stop unrelated scraping - - suspend inline fun streamAndRead(url: String, json: Gson = gson): Result = runCatching { + private const val USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3" + + suspend inline fun fetchJson(url: String, json: Gson = gson): Result = runCatching { return getInputStream(url).map { json.fromJson(it.bufferedReader().use { reader -> reader.readText() }, T::class.java) } } - suspend fun getInputStream(url: String): Result = - clientCall( - Request.Builder().url(url).build() - ).onFailure { e -> logger.warn("Failed to get input stream. Error: ${e.message}") } + suspend inline fun fetchString(url: String): Result = runCatching { + return getInputStream(url).map { it.bufferedReader().use { reader -> reader.readText() } } + } + suspend fun getInputStream(url: String): Result = + clientCall(Request.Builder().url(url).build()) + .onFailure { e -> logger.warn("Failed to get input stream. Error: ${e.message}") } -// suspend fun getUUIDbyName(name: String): Result { -// UuidCache.getFromCache(name)?.let { return Result.success(MojangData(name, it)) } -// return streamAndRead("https://api.minecraftservices.com/minecraft/profile/lookup/name/$name") -// .onSuccess { UuidCache.addToCache(name, it.uuid) } -// } + suspend fun postData(url: String, body: String): Result = + clientCall(Request.Builder().url(url).post(body.toRequestBody()).build()) + .map { it.bufferedReader().use { reader -> reader.readText() } } + .onFailure { e -> logger.warn("Failed to post data. Error: ${e.message}") } private suspend fun clientCall(request: Request): Result = suspendCoroutine { cont -> logger.info("Making request to ${request.url}") @@ -93,12 +85,15 @@ object WebUtils { } }.build() -// @Serializable -// data class MojangData( -// val name: String, -// @SerialName("id") -// val uuid: String -// ) + suspend fun hasBonusPaulScore(): Boolean = withTimeoutOrNull(5000) { + val response: String = fetchString("https://api.hypixel.net/resources/skyblock/election").getOrElse { return@withTimeoutOrNull false } + val jsonObject = JsonParser().parse(response).asJsonObject + val mayor = jsonObject.getAsJsonObject("mayor") ?: return@withTimeoutOrNull false + val name = mayor.get("name")?.asString ?: return@withTimeoutOrNull false + return@withTimeoutOrNull if (name == "Paul") { + mayor.getAsJsonArray("perks")?.any { it.asJsonObject.get("name")?.asString == "EZPZ" } == true + } else false + } == true class InputStreamException(code: Int, url: String) : Exception("Failed to get input stream from $url: ${EnglishReasonPhraseCatalog.INSTANCE.getReason(code, null)}") } \ No newline at end of file diff --git a/src/main/kotlin/me/odinmain/utils/skyblock/dungeon/DungeonListener.kt b/src/main/kotlin/me/odinmain/utils/skyblock/dungeon/DungeonListener.kt index 15489d1a9..904542c1c 100644 --- a/src/main/kotlin/me/odinmain/utils/skyblock/dungeon/DungeonListener.kt +++ b/src/main/kotlin/me/odinmain/utils/skyblock/dungeon/DungeonListener.kt @@ -11,7 +11,7 @@ import me.odinmain.features.impl.dungeon.LeapMenu.odinSorting import me.odinmain.features.impl.dungeon.MapInfo.shownTitle import me.odinmain.features.impl.dungeon.Mimic import me.odinmain.utils.equalsOneOf -import me.odinmain.utils.hasBonusPaulScore +import me.odinmain.utils.network.WebUtils.hasBonusPaulScore import me.odinmain.utils.noControlCodes import me.odinmain.utils.romanToInt import me.odinmain.utils.skyblock.PlayerUtils.posX diff --git a/src/main/kotlin/me/odinmain/utils/ui/rendering/Image.kt b/src/main/kotlin/me/odinmain/utils/ui/rendering/Image.kt index 2c93d88ea..dcc852cb2 100644 --- a/src/main/kotlin/me/odinmain/utils/ui/rendering/Image.kt +++ b/src/main/kotlin/me/odinmain/utils/ui/rendering/Image.kt @@ -1,6 +1,7 @@ package me.odinmain.utils.ui.rendering -import me.odinmain.utils.setupConnection +import kotlinx.coroutines.runBlocking +import me.odinmain.utils.network.WebUtils.getInputStream import java.io.File import java.io.FileNotFoundException import java.io.InputStream @@ -10,17 +11,12 @@ import java.nio.file.Files class Image( val identifier: String, - var isSVG: Boolean = false, + val isSVG: Boolean = identifier.endsWith(".svg", true), var stream: InputStream = getStream(identifier), private var buffer: ByteBuffer? = null ) { - constructor(inputStream: InputStream, identifier: String) : this(identifier, false, inputStream) { stream = inputStream } - init { - isSVG = identifier.endsWith(".svg", true) - } - fun buffer(): ByteBuffer { if (buffer == null) { val bytes = stream.readBytes() @@ -44,7 +40,7 @@ class Image( private fun getStream(path: String): InputStream { val trimmedPath = path.trim() - return if (trimmedPath.startsWith("http")) setupConnection(trimmedPath) + return if (trimmedPath.startsWith("http")) runBlocking { getInputStream(trimmedPath).getOrThrow() } // this is really weird but the old one behaved the same... else { val file = File(trimmedPath) if (file.exists() && file.isFile) Files.newInputStream(file.toPath()) From 898a06405c231902dfd4616e0a6d786f072aae97 Mon Sep 17 00:00:00 2001 From: SubAt0mic Date: Sat, 30 Aug 2025 13:44:59 -0400 Subject: [PATCH 3/8] oopsies! --- src/main/kotlin/me/odinmain/commands/impl/DevCommand.kt | 2 +- src/main/kotlin/me/odinmain/features/impl/render/PlayerSize.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/me/odinmain/commands/impl/DevCommand.kt b/src/main/kotlin/me/odinmain/commands/impl/DevCommand.kt index b9d34f92f..e42cec0cf 100644 --- a/src/main/kotlin/me/odinmain/commands/impl/DevCommand.kt +++ b/src/main/kotlin/me/odinmain/commands/impl/DevCommand.kt @@ -110,7 +110,7 @@ val devCommand = Commodore("oddev") { val z = zSize ?: 0.6 modMessage("Sending data... name: $name, password: $password") scope.launch { - modMessage(postData("https://tj4yzotqjuanubvfcrfo7h5qlq0opcyk.lambda-url.eu-north-1.on.aws/", "$name, [1,2,3], [$x,$y,$z], false, , $password")) + modMessage(postData("https://tj4yzotqjuanubvfcrfo7h5qlq0opcyk.lambda-url.eu-north-1.on.aws/", "$name, [1,2,3], [$x,$y,$z], false, , $password").getOrNull()) } } diff --git a/src/main/kotlin/me/odinmain/features/impl/render/PlayerSize.kt b/src/main/kotlin/me/odinmain/features/impl/render/PlayerSize.kt index 91330391c..44ccd839c 100644 --- a/src/main/kotlin/me/odinmain/features/impl/render/PlayerSize.kt +++ b/src/main/kotlin/me/odinmain/features/impl/render/PlayerSize.kt @@ -40,7 +40,7 @@ object PlayerSize : Module( private val sendDevData by ActionSetting("Send Dev Data", desc = "Sends dev data to the server.") { showHidden = false OdinMain.scope.launch { - modMessage(postData("https://tj4yzotqjuanubvfcrfo7h5qlq0opcyk.lambda-url.eu-north-1.on.aws/", "${mc.thePlayer.name}, [${devWingsColor.red},${devWingsColor.green},${devWingsColor.blue}], [$devSizeX,$devSizeY,$devSizeZ], $devWings, , $passcode")) + modMessage(postData("https://tj4yzotqjuanubvfcrfo7h5qlq0opcyk.lambda-url.eu-north-1.on.aws/", "${mc.thePlayer.name}, [${devWingsColor.red},${devWingsColor.green},${devWingsColor.blue}], [$devSizeX,$devSizeY,$devSizeZ], $devWings, , $passcode").getOrNull()) updateCustomProperties() } }.withDependency { isRandom } From 8e599f1506ba9f95dd814e6fd4a836c90eabad68 Mon Sep 17 00:00:00 2001 From: SubAt0mic Date: Sat, 30 Aug 2025 15:04:43 -0400 Subject: [PATCH 4/8] show own melody progress option --- .../me/odinmain/features/impl/floor7/p3/MelodyMessage.kt | 6 +++++- src/main/kotlin/me/odinmain/utils/network/WebUtils.kt | 8 ++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/kotlin/me/odinmain/features/impl/floor7/p3/MelodyMessage.kt b/src/main/kotlin/me/odinmain/features/impl/floor7/p3/MelodyMessage.kt index 64807968e..c36a93bf7 100644 --- a/src/main/kotlin/me/odinmain/features/impl/floor7/p3/MelodyMessage.kt +++ b/src/main/kotlin/me/odinmain/features/impl/floor7/p3/MelodyMessage.kt @@ -36,12 +36,16 @@ object MelodyMessage : Module( } if (!broadcast || !webSocket.connected) return@HUD 0f to 0f - melodies.entries.forEachIndexed { i, (_, data) -> + melodies.entries.forEachIndexed { i, (name, data) -> + if (!showOwn && name == mc.session.username) return@forEachIndexed drawMelody(data, i) } 45f to 25f }.withDependency { broadcast } + // explicit boolean because showOwn is broken or something + private val showOwn: Boolean by BooleanSetting("Show Own", false, desc = "Shows your own melody progress in the GUI.").withDependency { melodyGui.enabled && broadcast } + val webSocket = webSocket { onMessage { val (user, type, slot) = try { gson.fromJson(it, UpdateMessage::class.java) } catch (e: Exception) { return@onMessage } diff --git a/src/main/kotlin/me/odinmain/utils/network/WebUtils.kt b/src/main/kotlin/me/odinmain/utils/network/WebUtils.kt index a9a96b463..eaae566fc 100644 --- a/src/main/kotlin/me/odinmain/utils/network/WebUtils.kt +++ b/src/main/kotlin/me/odinmain/utils/network/WebUtils.kt @@ -29,14 +29,10 @@ object WebUtils { private const val USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3" suspend inline fun fetchJson(url: String, json: Gson = gson): Result = runCatching { - return getInputStream(url).map { - json.fromJson(it.bufferedReader().use { reader -> reader.readText() }, T::class.java) - } + json.fromJson(fetchString(url).getOrElse { return Result.failure(it) }, T::class.java) } - suspend inline fun fetchString(url: String): Result = runCatching { - return getInputStream(url).map { it.bufferedReader().use { reader -> reader.readText() } } - } + suspend inline fun fetchString(url: String): Result = getInputStream(url).map { it.bufferedReader().use { reader -> reader.readText() } } suspend fun getInputStream(url: String): Result = clientCall(Request.Builder().url(url).build()) From 79e5e4d6d5169ed4dacd92219f81e487849bf633 Mon Sep 17 00:00:00 2001 From: SubAt0mic Date: Sun, 31 Aug 2025 22:37:57 -0400 Subject: [PATCH 5/8] fixed concurrentmodification exception --- .../me/odinmain/features/impl/floor7/p3/MelodyMessage.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/me/odinmain/features/impl/floor7/p3/MelodyMessage.kt b/src/main/kotlin/me/odinmain/features/impl/floor7/p3/MelodyMessage.kt index c36a93bf7..7baa41e5b 100644 --- a/src/main/kotlin/me/odinmain/features/impl/floor7/p3/MelodyMessage.kt +++ b/src/main/kotlin/me/odinmain/features/impl/floor7/p3/MelodyMessage.kt @@ -19,6 +19,7 @@ import me.odinmain.utils.ui.getTextWidth import net.minecraft.item.Item import net.minecraft.network.play.server.S2FPacketSetSlot import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import java.util.concurrent.ConcurrentHashMap object MelodyMessage : Module( name = "Melody Message", @@ -59,7 +60,7 @@ object MelodyMessage : Module( } } - val melodies = mutableMapOf() + val melodies = ConcurrentHashMap() val lastSent = MelodyData(null, null, null) init { From c7b1760cb32ae630baf5ebc60d70054c5dfc03ac Mon Sep 17 00:00:00 2001 From: SubAt0mic Date: Tue, 2 Sep 2025 12:48:54 -0400 Subject: [PATCH 6/8] dev player stuff from new endpoint probably --- .../odinmain/features/impl/dungeon/Mimic.kt | 2 +- .../features/impl/render/PlayerSize.kt | 43 +++++++++---------- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/src/main/kotlin/me/odinmain/features/impl/dungeon/Mimic.kt b/src/main/kotlin/me/odinmain/features/impl/dungeon/Mimic.kt index b0bd3829a..94a6d1eff 100644 --- a/src/main/kotlin/me/odinmain/features/impl/dungeon/Mimic.kt +++ b/src/main/kotlin/me/odinmain/features/impl/dungeon/Mimic.kt @@ -30,7 +30,7 @@ object Mimic : Module( private val color by ColorSetting("Color", Colors.MINECRAFT_RED.withAlpha(0.5f), allowAlpha = true, desc = "The color of the box.").withDependency { mimicBox } private val lineWidth by NumberSetting("Line Width", 2f, 0.1f, 10f, 0.1f, desc = "The width of the box's lines.").withDependency { mimicBox } - private val princeMessageToggle by BooleanSetting("Toggle Prince Message", false, desc = "Toggles the prince killed message.") + private val princeMessageToggle by BooleanSetting("Toggle Prince Message", true, desc = "Toggles the prince killed message.") val princeMessage by StringSetting("Prince Message", "Prince Killed!", 128, desc = "Message sent when prince is detected as killed.").withDependency { princeMessageToggle } private val princeReset by ActionSetting("Prince Killed", desc = "Sends Prince killed message in party chat.") { princeKilled() } diff --git a/src/main/kotlin/me/odinmain/features/impl/render/PlayerSize.kt b/src/main/kotlin/me/odinmain/features/impl/render/PlayerSize.kt index 44ccd839c..04c3ad553 100644 --- a/src/main/kotlin/me/odinmain/features/impl/render/PlayerSize.kt +++ b/src/main/kotlin/me/odinmain/features/impl/render/PlayerSize.kt @@ -1,15 +1,14 @@ package me.odinmain.features.impl.render -import com.google.gson.JsonParser +import com.google.gson.annotations.SerializedName import kotlinx.coroutines.launch import me.odinmain.OdinMain import me.odinmain.clickgui.settings.AlwaysActive import me.odinmain.clickgui.settings.Setting.Companion.withDependency import me.odinmain.clickgui.settings.impl.* import me.odinmain.features.Module -import me.odinmain.utils.network.WebUtils.fetchString +import me.odinmain.utils.network.WebUtils.fetchJson import me.odinmain.utils.network.WebUtils.postData -import me.odinmain.utils.render.Color import me.odinmain.utils.render.Colors import me.odinmain.utils.skyblock.modMessage import net.minecraft.client.entity.AbstractClientPlayer @@ -48,7 +47,14 @@ object PlayerSize : Module( private var randoms: HashMap = HashMap() val isRandom get() = randoms.containsKey(mc.session?.username) - data class RandomPlayer(val scale: Triple, val wings: Boolean = false, val wingsColor: Color = Colors.WHITE, val customName: String, val isDev: Boolean) + data class RandomPlayer( + @SerializedName("CustomName") val customName: String?, + @SerializedName("DevName") val name: String, + @SerializedName("IsDev") val isDev: Boolean?, + @SerializedName("WingsColor") val wingsColor: Array, + @SerializedName("Size") val scale: Array, + @SerializedName("Wings") val wings: Boolean + ) @JvmStatic fun preRenderCallbackScaleHook(entityLivingBaseIn: AbstractClientPlayer) { @@ -59,23 +65,14 @@ object PlayerSize : Module( if (!randoms.containsKey(entityLivingBaseIn.name)) return if (!devSize && entityLivingBaseIn.name == mc.thePlayer.name) return val random = randoms[entityLivingBaseIn.name] ?: return - if (random.scale.second < 0) GlStateManager.translate(0f, random.scale.second * 2, 0f) - GlStateManager.scale(random.scale.first, random.scale.second, random.scale.third) + if (random.scale[1] < 0) GlStateManager.translate(0f, random.scale[1] * 2, 0f) + GlStateManager.scale(random.scale[0], random.scale[1], random.scale[2]) } - private val pattern = Regex("Decimal\\('(-?\\d+(?:\\.\\d+)?)'\\)") - suspend fun updateCustomProperties() { - val data = fetchString("https://tj4yzotqjuanubvfcrfo7h5qlq0opcyk.lambda-url.eu-north-1.on.aws/").getOrNull()?.replace(pattern) { match -> match.groupValues[1] }?.ifEmpty { null } ?: return - JsonParser().parse(data)?.asJsonArray?.forEach { - val jsonElement = it.asJsonObject - val randomsName = jsonElement.get("DevName")?.asString ?: return@forEach - val size = jsonElement.get("Size")?.asJsonArray?.let { sizeArray -> Triple(sizeArray[0].asFloat, sizeArray[1].asFloat, sizeArray[2].asFloat) } ?: return@forEach - val wings = jsonElement.get("Wings")?.asBoolean == true - val wingsColor = jsonElement.get("WingsColor")?.asJsonArray?.let { colorArray -> Color(colorArray[0].asInt, colorArray[1].asInt, colorArray[2].asInt) } ?: Colors.WHITE - val customName = jsonElement.get("CustomName")?.asString?.replace("COLOR", "§") ?: "" - val isDev = jsonElement.get("IsDev")?.asBoolean ?: false - randoms[randomsName] = RandomPlayer(size, wings, Color(wingsColor.red, wingsColor.green, wingsColor.blue), customName, isDev) + val data = fetchJson>("https://api.odtheking.com/devs/").getOrNull() ?: return + for (player in data) { + randoms[player.name] = player } } @@ -97,8 +94,8 @@ object PlayerSize : Module( fun replaceText(text: String?): String? { var replacedText = text for (random in randoms) { - if (random.value.customName.isBlank()) continue - replacedText = randoms[random.key]?.let { replacedText?.replace(random.key, it.customName) } + if (random.value.customName?.isBlank() == false) + replacedText = randoms[random.key]?.let { replacedText?.replace(random.key, it.customName.toString()) } } return replacedText @@ -136,11 +133,11 @@ object PlayerSize : Module( val x = player.lastTickPosX + (player.posX - player.lastTickPosX) * partialTicks val y = player.lastTickPosY + (player.posY - player.lastTickPosY) * partialTicks val z = player.lastTickPosZ + (player.posZ - player.lastTickPosZ) * partialTicks - if (random.scale.second < 0) GlStateManager.translate(0f, random.scale.second * -2, 0f) + if (random.scale[1] < 0) GlStateManager.translate(0f, random.scale[1] * -2, 0f) GlStateManager.translate(-mc.renderManager.viewerPosX + x, -mc.renderManager.viewerPosY + y, -mc.renderManager.viewerPosZ + z) GlStateManager.scale(-0.2, -0.2, 0.2) - GlStateManager.scale(random.scale.first, random.scale.second, random.scale.third) + GlStateManager.scale(random.scale[0], random.scale[1], random.scale[2]) GlStateManager.rotate(180 + rotation, 0f, 1f, 0f) GlStateManager.translate(0.0, -(1.25 / 0.2f), 0.0) GlStateManager.translate(0.0, 0.0, 0.25) @@ -150,7 +147,7 @@ object PlayerSize : Module( GlStateManager.translate(0.0, 1.0, -0.5) } - GlStateManager.color(random.wingsColor.red.toFloat()/255, random.wingsColor.green.toFloat()/255, random.wingsColor.blue.toFloat()/255, 1f) + GlStateManager.color(random.wingsColor[0].toFloat()/255, random.wingsColor[1].toFloat()/255, random.wingsColor[2].toFloat()/255, 1f) mc.textureManager.bindTexture(dragonWingTextureLocation) for (j in 0..1) { From 6633ba1e8333cc87924c9851ee1646c7c45a348b Mon Sep 17 00:00:00 2001 From: SubAt0mic Date: Fri, 5 Sep 2025 14:27:42 -0400 Subject: [PATCH 7/8] various (untested) fixes --- .../me/odinmain/commands/impl/DevCommand.kt | 9 ++++++--- .../me/odinmain/features/impl/dungeon/Mimic.kt | 4 ++-- .../features/impl/floor7/p3/MelodyMessage.kt | 18 ++++-------------- .../features/impl/floor7/p3/TerminalSolver.kt | 2 ++ .../impl/floor7/p3/termGUI/CustomTermGui.kt | 5 ++--- .../features/impl/render/PlayerSize.kt | 4 +++- .../me/odinmain/utils/network/WebUtils.kt | 13 +++++-------- 7 files changed, 24 insertions(+), 31 deletions(-) diff --git a/src/main/kotlin/me/odinmain/commands/impl/DevCommand.kt b/src/main/kotlin/me/odinmain/commands/impl/DevCommand.kt index e42cec0cf..fe5a48599 100644 --- a/src/main/kotlin/me/odinmain/commands/impl/DevCommand.kt +++ b/src/main/kotlin/me/odinmain/commands/impl/DevCommand.kt @@ -6,6 +6,7 @@ import kotlinx.coroutines.launch import me.odinmain.OdinMain.VERSION import me.odinmain.OdinMain.mc import me.odinmain.OdinMain.scope +import me.odinmain.config.Config import me.odinmain.events.impl.PacketEvent import me.odinmain.features.ModuleManager.generateFeatureList import me.odinmain.features.impl.dungeon.MapInfo @@ -15,10 +16,11 @@ import me.odinmain.features.impl.floor7.WitherDragonState import me.odinmain.features.impl.floor7.WitherDragons.priorityDragon import me.odinmain.features.impl.floor7.WitherDragonsEnum import me.odinmain.features.impl.floor7.p3.MelodyMessage.webSocket -import me.odinmain.features.impl.floor7.p3.termGUI.MelodyGui.firstClickProt +import me.odinmain.features.impl.floor7.p3.TerminalSolver.firstClickProt import me.odinmain.features.impl.nether.NoPre import me.odinmain.features.impl.render.ClickGUIModule.wsServer import me.odinmain.features.impl.render.PlayerSize +import me.odinmain.features.impl.render.PlayerSize.DEV_SERVER import me.odinmain.utils.isOtherPlayer import me.odinmain.utils.network.WebUtils.postData import me.odinmain.utils.postAndCatch @@ -38,6 +40,7 @@ val devCommand = Commodore("oddev") { literal("firstclickprot").runs { time: Long -> firstClickProt = time + Config.save() } literal("ws") { @@ -110,7 +113,7 @@ val devCommand = Commodore("oddev") { val z = zSize ?: 0.6 modMessage("Sending data... name: $name, password: $password") scope.launch { - modMessage(postData("https://tj4yzotqjuanubvfcrfo7h5qlq0opcyk.lambda-url.eu-north-1.on.aws/", "$name, [1,2,3], [$x,$y,$z], false, , $password").getOrNull()) + modMessage(postData(DEV_SERVER, "$name, [1,2,3], [$x,$y,$z], false, , $password").getOrNull()) } } @@ -120,7 +123,7 @@ val devCommand = Commodore("oddev") { val z = zSize ?: 0.6 val name = customName ?: "" scope.launch { - modMessage(postData("https://tj4yzotqjuanubvfcrfo7h5qlq0opcyk.lambda-url.eu-north-1.on.aws/", "${mc.thePlayer.name}, [1,2,3], [$x,$y,$z], false, $name, $password").getOrNull()) + modMessage(postData(DEV_SERVER, "${mc.thePlayer.name}, [1,2,3], [$x,$y,$z], false, $name, $password").getOrNull()) PlayerSize.updateCustomProperties() } } diff --git a/src/main/kotlin/me/odinmain/features/impl/dungeon/Mimic.kt b/src/main/kotlin/me/odinmain/features/impl/dungeon/Mimic.kt index 94a6d1eff..d0cdc085b 100644 --- a/src/main/kotlin/me/odinmain/features/impl/dungeon/Mimic.kt +++ b/src/main/kotlin/me/odinmain/features/impl/dungeon/Mimic.kt @@ -30,8 +30,8 @@ object Mimic : Module( private val color by ColorSetting("Color", Colors.MINECRAFT_RED.withAlpha(0.5f), allowAlpha = true, desc = "The color of the box.").withDependency { mimicBox } private val lineWidth by NumberSetting("Line Width", 2f, 0.1f, 10f, 0.1f, desc = "The width of the box's lines.").withDependency { mimicBox } - private val princeMessageToggle by BooleanSetting("Toggle Prince Message", true, desc = "Toggles the prince killed message.") - val princeMessage by StringSetting("Prince Message", "Prince Killed!", 128, desc = "Message sent when prince is detected as killed.").withDependency { princeMessageToggle } + private val princeMessageToggle by BooleanSetting("Prince Message", true, desc = "Toggles the prince killed message.") + val princeMessage by StringSetting("Prince Message Text", "Prince Killed!", 128, desc = "Message sent when prince is detected as killed.").withDependency { princeMessageToggle } private val princeReset by ActionSetting("Prince Killed", desc = "Sends Prince killed message in party chat.") { princeKilled() } private const val MIMIC_TEXTURE = "ewogICJ0aW1lc3RhbXAiIDogMTY3Mjc2NTM1NTU0MCwKICAicHJvZmlsZUlkIiA6ICJhNWVmNzE3YWI0MjA0MTQ4ODlhOTI5ZDA5OTA0MzcwMyIsCiAgInByb2ZpbGVOYW1lIiA6ICJXaW5zdHJlYWtlcnoiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTE5YzEyNTQzYmM3NzkyNjA1ZWY2OGUxZjg3NDlhZThmMmEzODFkOTA4NWQ0ZDRiNzgwYmExMjgyZDM1OTdhMCIsCiAgICAgICJtZXRhZGF0YSIgOiB7CiAgICAgICAgIm1vZGVsIiA6ICJzbGltIgogICAgICB9CiAgICB9CiAgfQp9" diff --git a/src/main/kotlin/me/odinmain/features/impl/floor7/p3/MelodyMessage.kt b/src/main/kotlin/me/odinmain/features/impl/floor7/p3/MelodyMessage.kt index 7baa41e5b..67f7f53d4 100644 --- a/src/main/kotlin/me/odinmain/features/impl/floor7/p3/MelodyMessage.kt +++ b/src/main/kotlin/me/odinmain/features/impl/floor7/p3/MelodyMessage.kt @@ -27,7 +27,7 @@ object MelodyMessage : Module( ) { private val sendMelodyMessage by BooleanSetting("Send Melody Message", true, desc = "Sends a message when the melody terminal opens.") private val melodyMessage by StringSetting("Melody Message", "Melody Terminal start!", 128, desc = "Message sent when the melody terminal opens.").withDependency { sendMelodyMessage } - private val melodyProgress by BooleanSetting("Melody Progress Message", false, desc = "Tells the party about melody terminal progress.") + private val melodyProgress by BooleanSetting("Melody Progress", false, desc = "Tells the party about melody terminal progress.") private val melodySendCoords by BooleanSetting("Melody Send Coords", false, desc = "Sends the coordinates of the melody terminal.").withDependency { melodyProgress } private val broadcast by BooleanSetting("Broadcast Progress", true, desc = "Broadcasts melody progress to all other odin users in your run using a websocket.") private val melodyGui by HUD("Progress GUI", "Shows a GUI with the progress of broadcasting odin users in the melody terminal.", true) { @@ -80,7 +80,7 @@ object MelodyMessage : Module( onPacket({ enabled && broadcast }) { val term = TerminalSolver.currentTerm ?: return@onPacket - if (/*DungeonUtils.getF7Phase() != M7Phases.P3 ||*/ term.type != TerminalTypes.MELODY || it.func_149173_d() !in 0 until term.type.windowSize) return@onPacket + if (DungeonUtils.getF7Phase() != M7Phases.P3 || term.type != TerminalTypes.MELODY || it.func_149173_d() !in 0 until term.type.windowSize || mc.currentScreen is TermSimGUI) return@onPacket val meta = it.func_149174_e()?.metadata ?: return@onPacket @@ -92,6 +92,7 @@ object MelodyMessage : Module( if (lastSent.clay == position) return@onPacket webSocket.send(update(1, position)) lastSent.clay = position + if (melodyProgress) clayProgress[position]?.let { partyMessage(it) } return@onPacket } @@ -112,15 +113,6 @@ object MelodyMessage : Module( 5 -> lastSent.pane = index } } - - execute(250) { - if (DungeonUtils.getF7Phase() != M7Phases.P3 || TerminalSolver.currentTerm?.type != TerminalTypes.MELODY || mc.currentScreen is TermSimGUI || !melodyProgress) return@execute - - val greenClayIndices = claySlots.keys.filter { index -> TerminalSolver.currentTerm?.items?.get(index)?.metadata == 5 }.ifEmpty { return@execute } - - partyMessage(claySlots[greenClayIndices.last()] ?: return@execute) - greenClayIndices.forEach { claySlots.remove(it) } - } } @SubscribeEvent @@ -129,15 +121,13 @@ object MelodyMessage : Module( webSocket.send(update(0, 0)) } - private var claySlots = hashMapOf(25 to "Melody 25%", 34 to "Melody 50%", 43 to "Melody 75%") + private val clayProgress = hashMapOf(1 to "Melody 25%", 2 to "Melody 50%", 3 to "Melody 75%") @SubscribeEvent fun onTermLoad(event: TerminalEvent.Opened) { if (DungeonUtils.getF7Phase() != M7Phases.P3 || event.terminal.type != TerminalTypes.MELODY || mc.currentScreen is TermSimGUI) return if (sendMelodyMessage) partyMessage(melodyMessage) if (melodySendCoords) sendCommand("od sendcoords", true) - - claySlots = hashMapOf(25 to "Melody 25%", 34 to "Melody 50%", 43 to "Melody 75%") } fun update(type: Int, slot: Int): String = gson.toJson(UpdateMessage(mc.session.username, type, slot)) diff --git a/src/main/kotlin/me/odinmain/features/impl/floor7/p3/TerminalSolver.kt b/src/main/kotlin/me/odinmain/features/impl/floor7/p3/TerminalSolver.kt index 5fe8b6c5e..1a0ef2afc 100644 --- a/src/main/kotlin/me/odinmain/features/impl/floor7/p3/TerminalSolver.kt +++ b/src/main/kotlin/me/odinmain/features/impl/floor7/p3/TerminalSolver.kt @@ -88,6 +88,8 @@ object TerminalSolver : Module( val melodyRowColor by ColorSetting("Melody Row", Colors.MINECRAFT_RED, true, desc = "Color of the row indicator for melody.").withDependency { showColors && !cancelMelodySolver } val melodyPointerColor by ColorSetting("Melody Pointer", Colors.MINECRAFT_GREEN, true, desc = "Color of the location for pressing for melody.").withDependency { showColors && !cancelMelodySolver } + var firstClickProt by NumberSetting("First Click Protection", 350L, 0, 500, 10, unit = "ms", desc = "The amount of time before you can click in a terminal.").hide() + var currentTerm: TerminalHandler? = null private set var lastTermOpened: TerminalHandler? = null diff --git a/src/main/kotlin/me/odinmain/features/impl/floor7/p3/termGUI/CustomTermGui.kt b/src/main/kotlin/me/odinmain/features/impl/floor7/p3/termGUI/CustomTermGui.kt index 83f6ed5c7..ebbf49f00 100644 --- a/src/main/kotlin/me/odinmain/features/impl/floor7/p3/termGUI/CustomTermGui.kt +++ b/src/main/kotlin/me/odinmain/features/impl/floor7/p3/termGUI/CustomTermGui.kt @@ -3,6 +3,7 @@ package me.odinmain.features.impl.floor7.p3.termGUI import me.odinmain.OdinMain.mc import me.odinmain.events.impl.GuiEvent import me.odinmain.features.impl.floor7.p3.TerminalSolver +import me.odinmain.features.impl.floor7.p3.TerminalSolver.firstClickProt import me.odinmain.features.impl.floor7.p3.TerminalSolver.hideClicked import me.odinmain.utils.postAndCatch import me.odinmain.utils.render.Color @@ -14,8 +15,6 @@ import kotlin.math.ceil import kotlin.math.floor abstract class TermGui { - var firstClickProt = 350L - protected val itemIndexMap: MutableMap = mutableMapOf() inline val currentSolution get() = TerminalSolver.currentTerm?.solution.orEmpty() val colorAnimations = mutableMapOf() @@ -53,7 +52,7 @@ abstract class TermGui { fun mouseClicked(button: Int) { getHoveredItem()?.let { slot -> TerminalSolver.currentTerm?.let { - if (System.currentTimeMillis() - it.timeOpened >= 350 && !GuiEvent.CustomTermGuiClick(slot, button).postAndCatch() && it.canClick(slot, button)) { + if (System.currentTimeMillis() - it.timeOpened >= firstClickProt && !GuiEvent.CustomTermGuiClick(slot, button).postAndCatch() && it.canClick(slot, button)) { it.click(slot, if (button == 0) ClickType.Middle else ClickType.Right, hideClicked && !it.isClicked) if (TerminalSolver.customAnimations) colorAnimations[slot]?.start() } diff --git a/src/main/kotlin/me/odinmain/features/impl/render/PlayerSize.kt b/src/main/kotlin/me/odinmain/features/impl/render/PlayerSize.kt index 04c3ad553..0376c41f2 100644 --- a/src/main/kotlin/me/odinmain/features/impl/render/PlayerSize.kt +++ b/src/main/kotlin/me/odinmain/features/impl/render/PlayerSize.kt @@ -36,10 +36,12 @@ object PlayerSize : Module( private var showHidden by DropdownSetting("Show Hidden", false).withDependency { isRandom } private val passcode by StringSetting("Passcode", "odin", desc = "Passcode for dev features.").withDependency { showHidden && isRandom } + const val DEV_SERVER = "https://api.odtheking.com/devs/" + private val sendDevData by ActionSetting("Send Dev Data", desc = "Sends dev data to the server.") { showHidden = false OdinMain.scope.launch { - modMessage(postData("https://tj4yzotqjuanubvfcrfo7h5qlq0opcyk.lambda-url.eu-north-1.on.aws/", "${mc.thePlayer.name}, [${devWingsColor.red},${devWingsColor.green},${devWingsColor.blue}], [$devSizeX,$devSizeY,$devSizeZ], $devWings, , $passcode").getOrNull()) + modMessage(postData(DEV_SERVER, "${mc.thePlayer.name}, [${devWingsColor.red},${devWingsColor.green},${devWingsColor.blue}], [$devSizeX,$devSizeY,$devSizeZ], $devWings, , $passcode").getOrNull()) updateCustomProperties() } }.withDependency { isRandom } diff --git a/src/main/kotlin/me/odinmain/utils/network/WebUtils.kt b/src/main/kotlin/me/odinmain/utils/network/WebUtils.kt index eaae566fc..d5b08b4d2 100644 --- a/src/main/kotlin/me/odinmain/utils/network/WebUtils.kt +++ b/src/main/kotlin/me/odinmain/utils/network/WebUtils.kt @@ -2,7 +2,7 @@ package me.odinmain.utils.network import com.google.gson.Gson import com.google.gson.GsonBuilder -import com.google.gson.JsonParser +import com.google.gson.JsonObject import kotlinx.coroutines.withTimeoutOrNull import me.odinmain.OdinMain.logger import me.odinmain.OdinMain.okClient @@ -13,12 +13,10 @@ import okhttp3.Callback import okhttp3.Dispatcher import okhttp3.OkHttpClient import okhttp3.Request -import okhttp3.RequestBody import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.Response import org.apache.http.impl.EnglishReasonPhraseCatalog import java.io.InputStream -import java.net.URL import java.util.concurrent.TimeUnit import kotlin.coroutines.resume import kotlin.coroutines.suspendCoroutine @@ -64,8 +62,8 @@ object WebUtils { sslSocketFactory(createSslContext().socketFactory, getTrustManager()) dispatcher(Dispatcher().apply { - maxRequests = 1 - maxRequestsPerHost = 1 + maxRequests = 10 + maxRequestsPerHost = 5 }) readTimeout(10, TimeUnit.SECONDS) @@ -82,9 +80,8 @@ object WebUtils { }.build() suspend fun hasBonusPaulScore(): Boolean = withTimeoutOrNull(5000) { - val response: String = fetchString("https://api.hypixel.net/resources/skyblock/election").getOrElse { return@withTimeoutOrNull false } - val jsonObject = JsonParser().parse(response).asJsonObject - val mayor = jsonObject.getAsJsonObject("mayor") ?: return@withTimeoutOrNull false + val response = fetchJson("https://api.hypixel.net/resources/skyblock/election").getOrElse { return@withTimeoutOrNull false } + val mayor = response.getAsJsonObject("mayor") ?: return@withTimeoutOrNull false val name = mayor.get("name")?.asString ?: return@withTimeoutOrNull false return@withTimeoutOrNull if (name == "Paul") { mayor.getAsJsonArray("perks")?.any { it.asJsonObject.get("name")?.asString == "EZPZ" } == true From 213e9578b8f1f0bd8e2db149f9449dca1f571a77 Mon Sep 17 00:00:00 2001 From: odtheking Date: Wed, 8 Oct 2025 12:33:21 +0300 Subject: [PATCH 8/8] Refactor DevCommand and PlayerSize for improved data handling and structure --- src/main/kotlin/me/odinmain/OdinMain.kt | 2 +- .../me/odinmain/commands/impl/DevCommand.kt | 23 +++++---------- .../features/impl/floor7/p3/MelodyMessage.kt | 8 ++--- .../features/impl/render/PlayerSize.kt | 29 ++++++++++++++----- .../me/odinmain/utils/network/WebUtils.kt | 19 +++++------- 5 files changed, 41 insertions(+), 40 deletions(-) diff --git a/src/main/kotlin/me/odinmain/OdinMain.kt b/src/main/kotlin/me/odinmain/OdinMain.kt index 315905b9a..398891158 100644 --- a/src/main/kotlin/me/odinmain/OdinMain.kt +++ b/src/main/kotlin/me/odinmain/OdinMain.kt @@ -76,7 +76,7 @@ object OdinMain { scope.launch(Dispatchers.IO) { DungeonWaypointConfig.loadConfig() ClickGUIModule.latestVersionNumber = ClickGUIModule.checkNewerVersion(VERSION) - postData("https://gi2wsqbyse6tnfhqakbnq6f2su0vujgz.lambda-url.eu-north-1.on.aws/", """{"username": "$name", "version": "${if (isLegitVersion) "legit" else "cheater"} $VERSION"}""") + postData("https://api.odtheking.com/tele/", """{"username": "$name", "version": "${if (isLegitVersion) "legit" else "cheater"} $VERSION"}""") } } diff --git a/src/main/kotlin/me/odinmain/commands/impl/DevCommand.kt b/src/main/kotlin/me/odinmain/commands/impl/DevCommand.kt index fe5a48599..b93b71b58 100644 --- a/src/main/kotlin/me/odinmain/commands/impl/DevCommand.kt +++ b/src/main/kotlin/me/odinmain/commands/impl/DevCommand.kt @@ -21,9 +21,11 @@ import me.odinmain.features.impl.nether.NoPre import me.odinmain.features.impl.render.ClickGUIModule.wsServer import me.odinmain.features.impl.render.PlayerSize import me.odinmain.features.impl.render.PlayerSize.DEV_SERVER +import me.odinmain.features.impl.render.PlayerSize.buildDevBody import me.odinmain.utils.isOtherPlayer import me.odinmain.utils.network.WebUtils.postData import me.odinmain.utils.postAndCatch +import me.odinmain.utils.render.Colors import me.odinmain.utils.skyblock.* import me.odinmain.utils.skyblock.PlayerUtils.posX import me.odinmain.utils.skyblock.PlayerUtils.posZ @@ -108,23 +110,12 @@ val devCommand = Commodore("oddev") { } literal("adddev").runs { name: String, password: String, xSize: Float?, ySize: Float?, zSize: Float? -> - val x = xSize ?: 0.6 - val y = ySize ?: 0.6 - val z = zSize ?: 0.6 - modMessage("Sending data... name: $name, password: $password") + val x = xSize ?: 0.6f + val y = ySize ?: 0.6f + val z = zSize ?: 0.6f + modMessage("Sending data... name: $name, x: $x, y: $y, z: $z") scope.launch { - modMessage(postData(DEV_SERVER, "$name, [1,2,3], [$x,$y,$z], false, , $password").getOrNull()) - } - } - - literal("customSize").runs { password: String, xSize: Float?, ySize: Float?, zSize: Float?, customName: String? -> - val x = xSize ?: 0.6 - val y = ySize ?: 0.6 - val z = zSize ?: 0.6 - val name = customName ?: "" - scope.launch { - modMessage(postData(DEV_SERVER, "${mc.thePlayer.name}, [1,2,3], [$x,$y,$z], false, $name, $password").getOrNull()) - PlayerSize.updateCustomProperties() + modMessage(postData(DEV_SERVER, buildDevBody(name, Colors.WHITE, x, y, z, false, " ", password)).getOrNull()) } } diff --git a/src/main/kotlin/me/odinmain/features/impl/floor7/p3/MelodyMessage.kt b/src/main/kotlin/me/odinmain/features/impl/floor7/p3/MelodyMessage.kt index 67f7f53d4..098b7978c 100644 --- a/src/main/kotlin/me/odinmain/features/impl/floor7/p3/MelodyMessage.kt +++ b/src/main/kotlin/me/odinmain/features/impl/floor7/p3/MelodyMessage.kt @@ -49,7 +49,7 @@ object MelodyMessage : Module( val webSocket = webSocket { onMessage { - val (user, type, slot) = try { gson.fromJson(it, UpdateMessage::class.java) } catch (e: Exception) { return@onMessage } + val (user, type, slot) = try { gson.fromJson(it, UpdateMessage::class.java) } catch (_: Exception) { return@onMessage } val entry = melodies.getOrPut(user) { MelodyData(null, null, null) } when (type) { 0 -> melodies.remove(user) @@ -60,8 +60,8 @@ object MelodyMessage : Module( } } - val melodies = ConcurrentHashMap() - val lastSent = MelodyData(null, null, null) + private val melodies = ConcurrentHashMap() + private val lastSent = MelodyData(null, null, null) init { onMessage(Regex("^\\[BOSS] Goldor: Who dares trespass into my domain\\?$"), { enabled && broadcast }) { @@ -141,7 +141,7 @@ object MelodyMessage : Module( return null } - val width = getTextWidth("§d■").toFloat() + private val width = getTextWidth("§d■").toFloat() fun drawMelody(data: MelodyData, index: Int) { val y = width * 2 * index diff --git a/src/main/kotlin/me/odinmain/features/impl/render/PlayerSize.kt b/src/main/kotlin/me/odinmain/features/impl/render/PlayerSize.kt index 6b43af5d9..c34e8448b 100644 --- a/src/main/kotlin/me/odinmain/features/impl/render/PlayerSize.kt +++ b/src/main/kotlin/me/odinmain/features/impl/render/PlayerSize.kt @@ -9,6 +9,7 @@ import me.odinmain.clickgui.settings.impl.* import me.odinmain.features.Module import me.odinmain.utils.network.WebUtils.fetchJson import me.odinmain.utils.network.WebUtils.postData +import me.odinmain.utils.render.Color import me.odinmain.utils.render.Colors import me.odinmain.utils.skyblock.modMessage import net.minecraft.client.entity.AbstractClientPlayer @@ -41,7 +42,13 @@ object PlayerSize : Module( private val sendDevData by ActionSetting("Send Dev Data", desc = "Sends dev data to the server.") { showHidden = false OdinMain.scope.launch { - modMessage(postData(DEV_SERVER, "${mc.thePlayer.name}, [${devWingsColor.red},${devWingsColor.green},${devWingsColor.blue}], [$devSizeX,$devSizeY,$devSizeZ], $devWings, , $passcode").getOrNull()) + val body = buildDevBody( + mc.thePlayer?.name ?: return@launch, + devWingsColor, devSizeX, devSizeY, + devSizeZ, devWings, " ", passcode + ) + + modMessage(postData(DEV_SERVER, body).getOrNull()) updateCustomProperties() } }.withDependency { isRandom } @@ -72,10 +79,19 @@ object PlayerSize : Module( } suspend fun updateCustomProperties() { - val data = fetchJson>("https://api.odtheking.com/devs/").getOrNull() ?: return - for (player in data) { - randoms[player.name] = player - } + val response = fetchJson>("https://api.odtheking.com/devs/").getOrNull() ?: return + randoms.putAll(response.associateBy { it.name }) + } + + fun buildDevBody(devName: String, wingsColor: Color, sizeX: Float, sizeY: Float, sizeZ: Float, wings: Boolean, customName: String, password: String): String { + return """ { + "devName": "$devName", + "wingsColor": [${wingsColor.red}, ${wingsColor.green}, ${wingsColor.blue}], + "size": [$sizeX, $sizeY, $sizeZ], + "wings": $wings, + "customName": "$customName", + "password": "$password" + } """.trimIndent() } init { @@ -96,8 +112,7 @@ object PlayerSize : Module( fun replaceText(text: String?): String? { var replacedText = text for ((key, value) in randoms.toMap()) { - if (value.customName.isBlank()) continue - replacedText = value.customName.let { replacedText?.replace(key, it) } + if (value.customName?.isBlank() == false) replacedText = value.customName.let { replacedText?.replace(key, it) } } return replacedText diff --git a/src/main/kotlin/me/odinmain/utils/network/WebUtils.kt b/src/main/kotlin/me/odinmain/utils/network/WebUtils.kt index d5b08b4d2..0684055bd 100644 --- a/src/main/kotlin/me/odinmain/utils/network/WebUtils.kt +++ b/src/main/kotlin/me/odinmain/utils/network/WebUtils.kt @@ -1,30 +1,25 @@ package me.odinmain.utils.network import com.google.gson.Gson -import com.google.gson.GsonBuilder import com.google.gson.JsonObject +import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.withTimeoutOrNull +import me.odinmain.OdinMain.gson import me.odinmain.OdinMain.logger import me.odinmain.OdinMain.okClient import me.odinmain.utils.network.SslUtils.createSslContext import me.odinmain.utils.network.SslUtils.getTrustManager -import okhttp3.Call -import okhttp3.Callback -import okhttp3.Dispatcher -import okhttp3.OkHttpClient -import okhttp3.Request +import okhttp3.* +import okhttp3.MediaType.Companion.toMediaType import okhttp3.RequestBody.Companion.toRequestBody -import okhttp3.Response import org.apache.http.impl.EnglishReasonPhraseCatalog import java.io.InputStream import java.util.concurrent.TimeUnit import kotlin.coroutines.resume -import kotlin.coroutines.suspendCoroutine object WebUtils { - val gson = GsonBuilder().setPrettyPrinting().create() - private const val USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3" + private val JSON = "application/json; charset=utf-8".toMediaType() suspend inline fun fetchJson(url: String, json: Gson = gson): Result = runCatching { json.fromJson(fetchString(url).getOrElse { return Result.failure(it) }, T::class.java) @@ -37,11 +32,11 @@ object WebUtils { .onFailure { e -> logger.warn("Failed to get input stream. Error: ${e.message}") } suspend fun postData(url: String, body: String): Result = - clientCall(Request.Builder().url(url).post(body.toRequestBody()).build()) + clientCall(Request.Builder().url(url).post(body.toRequestBody(JSON)).build()) .map { it.bufferedReader().use { reader -> reader.readText() } } .onFailure { e -> logger.warn("Failed to post data. Error: ${e.message}") } - private suspend fun clientCall(request: Request): Result = suspendCoroutine { cont -> + private suspend fun clientCall(request: Request): Result = suspendCancellableCoroutine { cont -> logger.info("Making request to ${request.url}") val callback = object : Callback {