mirror of
https://gitlab.com/2009scape/rt4-client.git
synced 2025-12-16 11:30:19 -07:00
Update to use a centralized fetcher
This commit is contained in:
parent
6adc5135bc
commit
03a205f64b
9 changed files with 169 additions and 128 deletions
|
|
@ -0,0 +1,60 @@
|
||||||
|
package KondoKit.network
|
||||||
|
|
||||||
|
import java.io.IOException
|
||||||
|
import java.net.HttpURLConnection
|
||||||
|
import java.net.URL
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lightweight helper for opening GET connections with shared defaults so callers don't repeat header setup.
|
||||||
|
*/
|
||||||
|
object HttpFetcher {
|
||||||
|
const val DEFAULT_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
|
||||||
|
|
||||||
|
private val defaultHeaders = mapOf(
|
||||||
|
"User-Agent" to DEFAULT_USER_AGENT,
|
||||||
|
"Accept" to "*/*"
|
||||||
|
)
|
||||||
|
|
||||||
|
fun openGetConnection(
|
||||||
|
url: String,
|
||||||
|
headers: Map<String, String> = emptyMap(),
|
||||||
|
connectTimeoutMillis: Int? = null,
|
||||||
|
readTimeoutMillis: Int? = null
|
||||||
|
): HttpURLConnection {
|
||||||
|
val connection = URL(url).openConnection() as HttpURLConnection
|
||||||
|
connection.requestMethod = "GET"
|
||||||
|
(defaultHeaders + headers).forEach { (key, value) ->
|
||||||
|
connection.setRequestProperty(key, value)
|
||||||
|
}
|
||||||
|
connectTimeoutMillis?.let { connection.connectTimeout = it }
|
||||||
|
readTimeoutMillis?.let { connection.readTimeout = it }
|
||||||
|
return connection
|
||||||
|
}
|
||||||
|
|
||||||
|
fun fetchString(
|
||||||
|
url: String,
|
||||||
|
headers: Map<String, String> = emptyMap(),
|
||||||
|
connectTimeoutMillis: Int? = null,
|
||||||
|
readTimeoutMillis: Int? = null
|
||||||
|
): String {
|
||||||
|
val connection = openGetConnection(url, headers, connectTimeoutMillis, readTimeoutMillis)
|
||||||
|
val responseCode = connection.responseCode
|
||||||
|
val responseStream = if (responseCode in 200..299) {
|
||||||
|
connection.inputStream
|
||||||
|
} else {
|
||||||
|
connection.errorStream
|
||||||
|
} ?: throw IOException("No response stream available for $url (HTTP $responseCode)")
|
||||||
|
|
||||||
|
val payload = responseStream.bufferedReader().use { it.readText() }
|
||||||
|
if (responseCode !in 200..299) {
|
||||||
|
throw HttpStatusException(url, responseCode, payload)
|
||||||
|
}
|
||||||
|
return payload
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class HttpStatusException(
|
||||||
|
val url: String,
|
||||||
|
val statusCode: Int,
|
||||||
|
val body: String
|
||||||
|
) : IOException("Request to $url failed with HTTP $statusCode")
|
||||||
|
|
@ -10,9 +10,6 @@ object GitLabConfig {
|
||||||
const val GITLAB_PROJECT_PATH = "2009scape/tools/client-plugins" // Using path from DownloadManager
|
const val GITLAB_PROJECT_PATH = "2009scape/tools/client-plugins" // Using path from DownloadManager
|
||||||
const val GITLAB_BRANCH = "master"
|
const val GITLAB_BRANCH = "master"
|
||||||
|
|
||||||
// HTTP headers and client settings
|
|
||||||
const val CHROME_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
|
|
||||||
|
|
||||||
// Debug settings
|
// Debug settings
|
||||||
const val DEBUG = true // Set to false to disable debug logging
|
const val DEBUG = true // Set to false to disable debug logging
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,14 @@
|
||||||
package KondoKit.pluginmanager
|
package KondoKit.pluginmanager
|
||||||
|
|
||||||
import KondoKit.views.ReflectiveEditorView
|
|
||||||
import com.google.gson.Gson
|
|
||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
import java.awt.EventQueue
|
|
||||||
import java.io.BufferedReader
|
import java.io.BufferedReader
|
||||||
import java.io.InputStreamReader
|
import java.io.InputStreamReader
|
||||||
import java.net.HttpURLConnection
|
import java.net.HttpURLConnection
|
||||||
import java.net.URL
|
|
||||||
import java.util.concurrent.*
|
import java.util.concurrent.*
|
||||||
import javax.swing.SwingUtilities
|
import javax.swing.SwingUtilities
|
||||||
|
import KondoKit.network.HttpFetcher
|
||||||
import KondoKit.pluginmanager.GitLabConfig
|
import KondoKit.pluginmanager.GitLabConfig
|
||||||
|
import KondoKit.util.JsonParser
|
||||||
|
|
||||||
object GitLabPluginFetcher {
|
object GitLabPluginFetcher {
|
||||||
|
|
||||||
|
|
@ -33,12 +31,7 @@ object GitLabPluginFetcher {
|
||||||
val apiUrl = GitLabConfig.getRepositoryTreeUrl()
|
val apiUrl = GitLabConfig.getRepositoryTreeUrl()
|
||||||
debugLog("API URL: $apiUrl")
|
debugLog("API URL: $apiUrl")
|
||||||
|
|
||||||
// Create URL connection
|
val connection = HttpFetcher.openGetConnection(apiUrl)
|
||||||
val url = URL(apiUrl)
|
|
||||||
val connection = url.openConnection() as HttpURLConnection
|
|
||||||
connection.requestMethod = "GET"
|
|
||||||
connection.setRequestProperty("User-Agent", GitLabConfig.CHROME_USER_AGENT)
|
|
||||||
debugLog("Set User-Agent header to: ${GitLabConfig.CHROME_USER_AGENT}")
|
|
||||||
|
|
||||||
// Read response
|
// Read response
|
||||||
val responseCode = connection.responseCode
|
val responseCode = connection.responseCode
|
||||||
|
|
@ -51,8 +44,7 @@ object GitLabPluginFetcher {
|
||||||
debugLog("Response preview: ${response.take(200)}...")
|
debugLog("Response preview: ${response.take(200)}...")
|
||||||
|
|
||||||
// Parse JSON response
|
// Parse JSON response
|
||||||
val gson = Gson()
|
val treeItems = JsonParser.fromJson(response, Array<JsonObject>::class.java)
|
||||||
val treeItems = gson.fromJson(response, Array<JsonObject>::class.java)
|
|
||||||
debugLog("Parsed ${treeItems.size} items from JSON")
|
debugLog("Parsed ${treeItems.size} items from JSON")
|
||||||
|
|
||||||
// Filter for directories (trees) with mode "040000"
|
// Filter for directories (trees) with mode "040000"
|
||||||
|
|
@ -119,11 +111,7 @@ object GitLabPluginFetcher {
|
||||||
val pluginUrl = GitLabConfig.getRawFileUrl(pluginFilePath)
|
val pluginUrl = GitLabConfig.getRawFileUrl(pluginFilePath)
|
||||||
debugLog("Fetching plugin.properties from: $pluginUrl")
|
debugLog("Fetching plugin.properties from: $pluginUrl")
|
||||||
|
|
||||||
// Create URL connection
|
val connection = HttpFetcher.openGetConnection(pluginUrl)
|
||||||
val url = URL(pluginUrl)
|
|
||||||
val connection = url.openConnection() as HttpURLConnection
|
|
||||||
connection.requestMethod = "GET"
|
|
||||||
connection.setRequestProperty("User-Agent", GitLabConfig.CHROME_USER_AGENT)
|
|
||||||
|
|
||||||
// Read response
|
// Read response
|
||||||
val responseCode = connection.responseCode
|
val responseCode = connection.responseCode
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import java.util.zip.ZipEntry
|
||||||
import java.util.zip.ZipInputStream
|
import java.util.zip.ZipInputStream
|
||||||
import javax.swing.SwingUtilities
|
import javax.swing.SwingUtilities
|
||||||
import KondoKit.pluginmanager.GitLabConfig
|
import KondoKit.pluginmanager.GitLabConfig
|
||||||
|
import KondoKit.network.HttpFetcher
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages downloading and installing plugins from GitLab with concurrent support
|
* Manages downloading and installing plugins from GitLab with concurrent support
|
||||||
|
|
@ -127,11 +128,12 @@ object PluginDownloadManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create URL connection
|
// Create URL connection
|
||||||
val connection = url.openConnection() as HttpURLConnection
|
val connection = try {
|
||||||
connection.requestMethod = "GET"
|
HttpFetcher.openGetConnection(url.toString())
|
||||||
connection.setRequestProperty("User-Agent", GitLabConfig.CHROME_USER_AGENT)
|
} catch (e: Exception) {
|
||||||
// Add Accept header to avoid 406 errors
|
debugLog("Failed to open connection for plugin: ${plugin.path} with URL: $downloadUrl. Error: ${e.message}")
|
||||||
connection.setRequestProperty("Accept", "*/*")
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
debugLog("Connection opened for plugin: ${plugin.path}")
|
debugLog("Connection opened for plugin: ${plugin.path}")
|
||||||
debugLog("Request headers - User-Agent: ${connection.getRequestProperty("User-Agent")}")
|
debugLog("Request headers - User-Agent: ${connection.getRequestProperty("User-Agent")}")
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
package KondoKit.util
|
||||||
|
|
||||||
|
import KondoKit.network.HttpFetcher
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shared loader for GE price JSON from remote or bundled sources.
|
||||||
|
*/
|
||||||
|
object GEPriceService {
|
||||||
|
private const val REMOTE_GE_URL = "https://cdn.2009scape.org/gedata/latest.json"
|
||||||
|
|
||||||
|
private data class RemoteGEItem(
|
||||||
|
val item_id: String?,
|
||||||
|
val value: String?
|
||||||
|
)
|
||||||
|
|
||||||
|
private data class LocalGEItem(
|
||||||
|
val id: String?,
|
||||||
|
val grand_exchange_price: String?
|
||||||
|
)
|
||||||
|
|
||||||
|
fun loadRemotePrices(): Map<String, String> {
|
||||||
|
return try {
|
||||||
|
val payload = HttpFetcher.fetchString(REMOTE_GE_URL)
|
||||||
|
val items = JsonParser.fromJson<Array<RemoteGEItem>>(payload)
|
||||||
|
items.mapNotNull { item ->
|
||||||
|
val id = item.item_id
|
||||||
|
val value = item.value
|
||||||
|
if (id != null && value != null) id to value else null
|
||||||
|
}.toMap()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
emptyMap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun loadLocalPrices(jsonProvider: () -> String?): Map<String, String> {
|
||||||
|
return try {
|
||||||
|
val json = jsonProvider() ?: return emptyMap()
|
||||||
|
val items = JsonParser.fromJson<Array<LocalGEItem>>(json)
|
||||||
|
items.mapNotNull { item ->
|
||||||
|
val id = item.id
|
||||||
|
val price = item.grand_exchange_price
|
||||||
|
if (id != null && price != null) id to price else null
|
||||||
|
}.toMap()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
emptyMap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
package KondoKit.util
|
||||||
|
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import com.google.gson.reflect.TypeToken
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Centralizes JSON parsing to reuse the same Gson configuration everywhere.
|
||||||
|
*/
|
||||||
|
object JsonParser {
|
||||||
|
val gson: Gson = Gson()
|
||||||
|
|
||||||
|
inline fun <reified T> fromJson(json: String): T {
|
||||||
|
val type = object : TypeToken<T>() {}.type
|
||||||
|
return gson.fromJson(json, type)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> fromJson(json: String, classOfT: Class<T>): T = gson.fromJson(json, classOfT)
|
||||||
|
|
||||||
|
fun toJson(src: Any): String = gson.toJson(src)
|
||||||
|
}
|
||||||
|
|
@ -15,15 +15,13 @@ import KondoKit.plugin.Companion.POPUP_FOREGROUND
|
||||||
import KondoKit.plugin.Companion.secondaryColor
|
import KondoKit.plugin.Companion.secondaryColor
|
||||||
import KondoKit.plugin.Companion.primaryColor
|
import KondoKit.plugin.Companion.primaryColor
|
||||||
import KondoKit.plugin.Companion.TOOLTIP_BACKGROUND
|
import KondoKit.plugin.Companion.TOOLTIP_BACKGROUND
|
||||||
import com.google.gson.Gson
|
import KondoKit.util.JsonParser
|
||||||
import plugin.api.API
|
import plugin.api.API
|
||||||
import rt4.Sprites
|
import rt4.Sprites
|
||||||
import java.awt.*
|
import java.awt.*
|
||||||
import java.io.BufferedReader
|
import KondoKit.network.HttpFetcher
|
||||||
import java.io.InputStreamReader
|
import KondoKit.network.HttpStatusException
|
||||||
import java.net.HttpURLConnection
|
|
||||||
import java.net.SocketTimeoutException
|
import java.net.SocketTimeoutException
|
||||||
import java.net.URL
|
|
||||||
import javax.swing.*
|
import javax.swing.*
|
||||||
import javax.swing.border.MatteBorder
|
import javax.swing.border.MatteBorder
|
||||||
import kotlin.math.floor
|
import kotlin.math.floor
|
||||||
|
|
@ -235,37 +233,24 @@ object HiscoresView : View {
|
||||||
|
|
||||||
Thread {
|
Thread {
|
||||||
try {
|
try {
|
||||||
val url = URL(apiUrl)
|
val response = HttpFetcher.fetchString(
|
||||||
val connection = url.openConnection() as HttpURLConnection
|
url = apiUrl,
|
||||||
connection.requestMethod = "GET"
|
connectTimeoutMillis = 5000,
|
||||||
|
readTimeoutMillis = 5000
|
||||||
// If a request take longer than 5 seconds timeout.
|
)
|
||||||
connection.connectTimeout = 5000
|
|
||||||
connection.readTimeout = 5000
|
|
||||||
|
|
||||||
val responseCode = connection.responseCode
|
|
||||||
if (responseCode == HttpURLConnection.HTTP_OK) {
|
|
||||||
val reader = BufferedReader(InputStreamReader(connection.inputStream))
|
|
||||||
val response = reader.use { it.readText() }
|
|
||||||
reader.close()
|
|
||||||
|
|
||||||
SwingUtilities.invokeLater {
|
SwingUtilities.invokeLater {
|
||||||
updatePlayerDataStandalone(response, username, hiscoresPanel)
|
updatePlayerDataStandalone(response, username, hiscoresPanel)
|
||||||
|
|
||||||
// Example of how to use setText now that the search field is accessible:
|
|
||||||
// customSearchField?.setText(username) // You could set the text to the searched username
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
SwingUtilities.invokeLater {
|
|
||||||
showToast(hiscoresPanel, "Player not found!", JOptionPane.ERROR_MESSAGE)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (e: SocketTimeoutException) {
|
} catch (e: SocketTimeoutException) {
|
||||||
SwingUtilities.invokeLater {
|
SwingUtilities.invokeLater {
|
||||||
showToast(hiscoresPanel, "Request timed out", JOptionPane.ERROR_MESSAGE)
|
showToast(hiscoresPanel, "Request timed out", JOptionPane.ERROR_MESSAGE)
|
||||||
}
|
}
|
||||||
|
} catch (e: HttpStatusException) {
|
||||||
|
SwingUtilities.invokeLater {
|
||||||
|
showToast(hiscoresPanel, "Player not found!", JOptionPane.ERROR_MESSAGE)
|
||||||
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
// Handle other errors
|
|
||||||
SwingUtilities.invokeLater {
|
SwingUtilities.invokeLater {
|
||||||
showToast(hiscoresPanel, "Error fetching data!", JOptionPane.ERROR_MESSAGE)
|
showToast(hiscoresPanel, "Error fetching data!", JOptionPane.ERROR_MESSAGE)
|
||||||
}
|
}
|
||||||
|
|
@ -274,8 +259,7 @@ object HiscoresView : View {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updatePlayerDataStandalone(jsonResponse: String, username: String, hiscoresPanel: JPanel) {
|
private fun updatePlayerDataStandalone(jsonResponse: String, username: String, hiscoresPanel: JPanel) {
|
||||||
val gson = Gson()
|
val hiscoresResponse = JsonParser.fromJson<HiscoresResponse>(jsonResponse)
|
||||||
val hiscoresResponse = gson.fromJson(jsonResponse, HiscoresResponse::class.java)
|
|
||||||
updateHiscoresViewStandalone(hiscoresPanel, hiscoresResponse, username)
|
updateHiscoresViewStandalone(hiscoresPanel, hiscoresResponse, username)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,9 +28,7 @@ import java.awt.Font
|
||||||
import java.awt.event.MouseAdapter
|
import java.awt.event.MouseAdapter
|
||||||
import java.awt.event.MouseEvent
|
import java.awt.event.MouseEvent
|
||||||
import java.awt.image.BufferedImage
|
import java.awt.image.BufferedImage
|
||||||
import java.io.BufferedReader
|
import KondoKit.util.GEPriceService
|
||||||
import java.net.HttpURLConnection
|
|
||||||
import java.net.URL
|
|
||||||
import java.text.DecimalFormat
|
import java.text.DecimalFormat
|
||||||
import javax.swing.*
|
import javax.swing.*
|
||||||
import kotlin.math.ceil
|
import kotlin.math.ceil
|
||||||
|
|
@ -75,58 +73,11 @@ object LootTrackerView : View, OnPostClientTickCallback, OnKillingBlowNPCCallbac
|
||||||
|
|
||||||
fun loadGEPrices(): Map<String, String> {
|
fun loadGEPrices(): Map<String, String> {
|
||||||
return if (useLiveGEPrices) {
|
return if (useLiveGEPrices) {
|
||||||
try {
|
|
||||||
println("LootTracker: Loading Remote GE Prices")
|
println("LootTracker: Loading Remote GE Prices")
|
||||||
val url = URL("https://cdn.2009scape.org/gedata/latest.json")
|
GEPriceService.loadRemotePrices()
|
||||||
val connection = url.openConnection() as HttpURLConnection
|
|
||||||
connection.requestMethod = "GET"
|
|
||||||
connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0")
|
|
||||||
|
|
||||||
val responseCode = connection.responseCode
|
|
||||||
if (responseCode == HttpURLConnection.HTTP_OK) {
|
|
||||||
val inputStream = connection.inputStream
|
|
||||||
val content = inputStream.bufferedReader().use(BufferedReader::readText)
|
|
||||||
|
|
||||||
val items = content.trim().removeSurrounding("[", "]").split("},").map { it.trim() + "}" }
|
|
||||||
val gePrices = mutableMapOf<String, String>()
|
|
||||||
|
|
||||||
for (item in items) {
|
|
||||||
val pairs = item.removeSurrounding("{", "}").split(",")
|
|
||||||
val itemId = pairs.find { it.trim().startsWith("\"item_id\"") }?.split(":")?.get(1)?.trim()?.trim('\"')
|
|
||||||
val value = pairs.find { it.trim().startsWith("\"value\"") }?.split(":")?.get(1)?.trim()?.trim('\"')
|
|
||||||
if (itemId != null && value != null) {
|
|
||||||
gePrices[itemId] = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gePrices
|
|
||||||
} else {
|
} else {
|
||||||
emptyMap()
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
emptyMap()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
println("LootTracker: Loading Local GE Prices")
|
println("LootTracker: Loading Local GE Prices")
|
||||||
Helpers.readResourceText("res/item_configs.json")?.let { json ->
|
GEPriceService.loadLocalPrices { Helpers.readResourceText("res/item_configs.json") }
|
||||||
val items = json.trim().removeSurrounding("[", "]").split("},").map { it.trim() + "}" }
|
|
||||||
val gePrices = mutableMapOf<String, String>()
|
|
||||||
|
|
||||||
for (item in items) {
|
|
||||||
val pairs = item.removeSurrounding("{", "}").split(",")
|
|
||||||
val id = pairs.find { it.trim().startsWith("\"id\"") }?.split(":")?.get(1)?.trim()?.trim('\"')
|
|
||||||
val grandExchangePrice = pairs.find { it.trim().startsWith("\"grand_exchange_price\"") }?.split(":")?.get(1)?.trim()?.trim('\"')
|
|
||||||
if (id != null && grandExchangePrice != null) {
|
|
||||||
gePrices[id] = grandExchangePrice
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gePrices
|
|
||||||
} ?: emptyMap()
|
|
||||||
} catch (e: Exception) {
|
|
||||||
emptyMap()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import KondoKit.plugin.Companion.playerXPMultiplier
|
||||||
import KondoKit.plugin.Companion.primaryColor
|
import KondoKit.plugin.Companion.primaryColor
|
||||||
import KondoKit.plugin.Companion.secondaryColor
|
import KondoKit.plugin.Companion.secondaryColor
|
||||||
import KondoKit.plugin.StateManager.focusedView
|
import KondoKit.plugin.StateManager.focusedView
|
||||||
|
import KondoKit.util.JsonParser
|
||||||
import plugin.api.API
|
import plugin.api.API
|
||||||
import java.awt.*
|
import java.awt.*
|
||||||
import java.awt.image.BufferedImage
|
import java.awt.image.BufferedImage
|
||||||
|
|
@ -43,20 +44,10 @@ object XPTrackerView : View, OnUpdateCallback, OnXPUpdateCallback {
|
||||||
|
|
||||||
val npcHitpointsMap: Map<Int, Int> = try {
|
val npcHitpointsMap: Map<Int, Int> = try {
|
||||||
val json = Helpers.readResourceText("res/npc_hitpoints_map.json") ?: "{}"
|
val json = Helpers.readResourceText("res/npc_hitpoints_map.json") ?: "{}"
|
||||||
val pairs = json.trim().removeSurrounding("{", "}").split(",")
|
val parsed: Map<String, Int> = JsonParser.fromJson(json)
|
||||||
val map = mutableMapOf<Int, Int>()
|
parsed.mapNotNull { (key, value) ->
|
||||||
|
key.toIntOrNull()?.let { it to value }
|
||||||
for (pair in pairs) {
|
}.toMap()
|
||||||
val keyValue = pair.split(":")
|
|
||||||
val id = keyValue[0].trim().trim('\"').toIntOrNull()
|
|
||||||
val hitpoints = keyValue[1].trim()
|
|
||||||
|
|
||||||
if (id != null && hitpoints.isNotEmpty()) {
|
|
||||||
map[id] = hitpoints.toIntOrNull() ?: 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
map
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
println("XPTracker Error parsing NPC HP: ${e.message}")
|
println("XPTracker Error parsing NPC HP: ${e.message}")
|
||||||
emptyMap()
|
emptyMap()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue