summaryrefslogtreecommitdiff
path: root/src/main/java/at/hannibal2/skyhanni/utils
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/at/hannibal2/skyhanni/utils')
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/APIUtil.kt27
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/ChatUtils.kt203
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/ClipboardUtils.kt3
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/CollectionUtils.kt115
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/ColorUtils.kt7
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/CombatUtils.kt1
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/ConditionalUtils.kt33
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/ConfigUtils.kt2
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/DelayedRun.kt3
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/EntityOutlineRenderer.kt3
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/EntityUtils.kt4
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/GuiRenderUtils.kt8
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/IdentityCharacteristics.kt1
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/InventoryUtils.kt4
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/ItemBlink.kt3
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/ItemStackTypeAdapter.kt4
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/ItemUtils.kt4
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/KSerializable.kt6
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/KeyboardManager.kt1
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/LorenzColor.kt1
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/LorenzDebug.kt4
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/LorenzLogger.kt2
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/LorenzUtils.kt435
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/LorenzVec.kt1
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/MinecraftConsoleFilter.kt5
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/MinecraftDispatcher.kt3
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/MultiFilter.kt2
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/NBTTypeAdapter.kt3
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/NEUInternalName.kt3
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/NEUItems.kt3
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/NumberUtil.kt7
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/OSUtils.kt2
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/ParkourHelper.kt6
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/RecalculatingValue.kt3
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/ReflectionUtils.kt62
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/RenderUtils.kt28
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/Season.kt4
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/SimpleTimeMark.kt1
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/SkyBlockItemModifierUtils.kt9
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/SoundUtils.kt3
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/StringUtils.kt1
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/TabListData.kt20
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/TimeMark.kt4
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/TimeUtils.kt9
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/Timer.kt3
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/UtilsPatterns.kt4
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/renderables/RenderLineTooltips.kt4
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt2
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/repopatterns/RepoPattern.kt3
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/repopatterns/RepoPatternGroup.kt1
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/repopatterns/RepoPatternGui.kt6
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/repopatterns/RepoPatternImpl.kt2
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/repopatterns/RepoPatternManager.kt4
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/shader/ShaderHelper.kt2
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/shader/ShaderManager.kt2
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/shader/Uniform.kt5
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/tracker/ItemTrackerData.kt1
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/tracker/SkyHanniItemTracker.kt15
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/tracker/SkyHanniTracker.kt10
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/tracker/TrackerData.kt1
60 files changed, 605 insertions, 513 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/APIUtil.kt b/src/main/java/at/hannibal2/skyhanni/utils/APIUtil.kt
index 2fd634d26..0f561fdff 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/APIUtil.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/APIUtil.kt
@@ -22,8 +22,8 @@ import java.io.FileInputStream
import java.io.InputStreamReader
import java.nio.charset.StandardCharsets
-
object APIUtil {
+
private val parser = JsonParser()
private var showApiErrors = false
@@ -49,7 +49,7 @@ object APIUtil {
fun getJSONResponseAsElement(
urlString: String,
silentError: Boolean = false,
- apiName: String = "Hypixel API"
+ apiName: String = "Hypixel API",
): JsonElement {
val client = builder.build()
try {
@@ -63,16 +63,15 @@ object APIUtil {
if (e.message?.contains("Use JsonReader.setLenient(true)") == true) {
println("MalformedJsonException: Use JsonReader.setLenient(true)")
println(" - getJSONResponse: '$urlString'")
- LorenzUtils.debug("MalformedJsonException: Use JsonReader.setLenient(true)")
+ ChatUtils.debug("MalformedJsonException: Use JsonReader.setLenient(true)")
} else if (retSrc.contains("<center><h1>502 Bad Gateway</h1></center>")) {
if (showApiErrors && apiName == "Hypixel API") {
- LorenzUtils.clickableChat(
+ ChatUtils.clickableChat(
"Problems with detecting the Hypixel API. §eClick here to hide this message for now.",
"shtogglehypixelapierrors"
)
}
e.printStackTrace()
-
} else {
ErrorManager.logErrorWithData(
e, "$apiName error for url: '$urlString'",
@@ -118,7 +117,7 @@ object APIUtil {
val message = "POST request to '$urlString' returned status ${status.statusCode}"
println(message)
- LorenzUtils.error("SkyHanni ran into an error. Status: ${status.statusCode}")
+ ChatUtils.error("SkyHanni ran into an error. Status: ${status.statusCode}")
return ApiResponse(false, message, JsonObject())
}
} catch (throwable: Throwable) {
@@ -126,7 +125,7 @@ object APIUtil {
throw throwable
} else {
throwable.printStackTrace()
- LorenzUtils.error("SkyHanni ran into an ${throwable::class.simpleName ?: "error"} whilst sending a resource. See logs for more details.")
+ ChatUtils.error("SkyHanni ran into an ${throwable::class.simpleName ?: "error"} whilst sending a resource. See logs for more details.")
}
return ApiResponse(false, throwable.message, JsonObject())
} finally {
@@ -139,15 +138,21 @@ object APIUtil {
return parser.parse(retSrc) as JsonObject
}
- fun postJSONIsSuccessful(urlString: String, body: String, silentError: Boolean = false): Boolean {
- val response = postJSON(urlString, body, silentError)
+ fun postJSONIsSuccessful(url: String, body: String, silentError: Boolean = false): Boolean {
+ val response = postJSON(url, body, silentError)
if (response.success) {
return true
}
println(response.message)
- LorenzUtils.error(response.message ?: "An error occurred during the API request")
+ ErrorManager.logErrorStateWithData(
+ "An error occurred during the API request",
+ "unsuccessful API response",
+ "url" to url,
+ "body" to body,
+ "response" to response,
+ )
return false
}
@@ -158,6 +163,6 @@ object APIUtil {
fun toggleApiErrorMessages() {
showApiErrors = !showApiErrors
- LorenzUtils.chat("Hypixel API error messages " + if (showApiErrors) "§chidden" else "§ashown")
+ ChatUtils.chat("Hypixel API error messages " + if (showApiErrors) "§chidden" else "§ashown")
}
}
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/ChatUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/ChatUtils.kt
new file mode 100644
index 000000000..34f42e629
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/utils/ChatUtils.kt
@@ -0,0 +1,203 @@
+package at.hannibal2.skyhanni.utils
+
+import at.hannibal2.skyhanni.SkyHanniMod
+import at.hannibal2.skyhanni.events.LorenzTickEvent
+import at.hannibal2.skyhanni.utils.StringUtils.removeColor
+import net.minecraft.client.Minecraft
+import net.minecraft.event.ClickEvent
+import net.minecraft.event.HoverEvent
+import net.minecraft.util.ChatComponentText
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+import java.util.LinkedList
+import java.util.Queue
+import kotlin.time.Duration.Companion.milliseconds
+
+object ChatUtils {
+
+ // TODO log based on chat category (error, warning, debug, user error, normal)
+ private val log = LorenzLogger("chat/mod_sent")
+ var lastButtonClicked = 0L
+
+ private const val DEBUG_PREFIX = "[SkyHanni Debug] §7"
+ private const val USER_ERROR_PREFIX = "§c[SkyHanni] "
+ private val ERROR_PREFIX by lazy { "§c[SkyHanni-${SkyHanniMod.version}] " }
+ private const val CHAT_PREFIX = "[SkyHanni] "
+
+ /**
+ * Sends a debug message to the chat and the console.
+ * This is only sent if the debug feature is enabled.
+ *
+ * @param message The message to be sent
+ *
+ * @see DEBUG_PREFIX
+ */
+ fun debug(message: String) {
+ if (SkyHanniMod.feature.dev.debug.enabled && internalChat(DEBUG_PREFIX + message)) {
+ LorenzUtils.consoleLog("[Debug] $message")
+ }
+ }
+
+ /**
+ * Sends a message to the user that they did something incorrectly.
+ * We should tell them what to do instead as well.
+ *
+ * @param message The message to be sent
+ *
+ * @see USER_ERROR_PREFIX
+ */
+ fun userError(message: String) {
+ internalChat(USER_ERROR_PREFIX + message)
+ }
+
+ /**
+ * Sends a message to the user that an error occurred caused by something in the code.
+ * This should be used for errors that are not caused by the user.
+ *
+ * Why deprecate this? Even if this message is descriptive for the user and the developer,
+ * we don't want inconsitencies in errors, and we would need to search
+ * for the code line where this error gets printed any way.
+ * so it's better to use the stack trace still.
+ *
+ * @param message The message to be sent
+ * @param prefix Whether to prefix the message with the error prefix, default true
+ *
+ * @see ERROR_PREFIX
+ */
+ @Deprecated(
+ "Do not send the user a non clickable non stacktrace containing error message.",
+ ReplaceWith("ErrorManager.logErrorStateWithData")
+ )
+ fun error(message: String) {
+ println("error: '$message'")
+ internalChat(ERROR_PREFIX + message)
+ }
+
+ /**
+ * Sends a message to the user
+ * @param message The message to be sent
+ * @param prefix Whether to prefix the message with the chat prefix, default true
+ * @param prefixColor Color that the prefix should be, default yellow (§e)
+ *
+ * @see CHAT_PREFIX
+ */
+ fun chat(message: String, prefix: Boolean = true, prefixColor: String = "§e") {
+ if (prefix) {
+ internalChat(prefixColor + CHAT_PREFIX + message)
+ } else {
+ internalChat(message)
+ }
+ }
+
+ private fun internalChat(message: String): Boolean {
+ log.log(message)
+ val minecraft = Minecraft.getMinecraft()
+ if (minecraft == null) {
+ LorenzUtils.consoleLog(message.removeColor())
+ return false
+ }
+
+ val thePlayer = minecraft.thePlayer
+ if (thePlayer == null) {
+ LorenzUtils.consoleLog(message.removeColor())
+ return false
+ }
+
+ thePlayer.addChatMessage(ChatComponentText(message))
+ return true
+ }
+
+ /**
+ * Sends a message to the user that they can click and run a command
+ * @param message The message to be sent
+ * @param command The command to be executed when the message is clicked
+ * @param prefix Whether to prefix the message with the chat prefix, default true
+ * @param prefixColor Color that the prefix should be, default yellow (§e)
+ *
+ * @see CHAT_PREFIX
+ */
+ fun clickableChat(message: String, command: String, prefix: Boolean = true, prefixColor: String = "§e") {
+ val msgPrefix = if (prefix) prefixColor + CHAT_PREFIX else ""
+ val text = ChatComponentText(msgPrefix + message)
+ val fullCommand = "/" + command.removePrefix("/")
+ text.chatStyle.chatClickEvent = ClickEvent(ClickEvent.Action.RUN_COMMAND, fullCommand)
+ text.chatStyle.chatHoverEvent =
+ HoverEvent(HoverEvent.Action.SHOW_TEXT, ChatComponentText("§eExecute $fullCommand"))
+ Minecraft.getMinecraft().thePlayer.addChatMessage(text)
+ }
+
+ /**
+ * Sends a message to the user that they can click and run a command
+ * @param message The message to be sent
+ * @param hover The message to be shown when the message is hovered
+ * @param command The command to be executed when the message is clicked
+ * @param prefix Whether to prefix the message with the chat prefix, default true
+ * @param prefixColor Color that the prefix should be, default yellow (§e)
+ *
+ * @see CHAT_PREFIX
+ */
+ fun hoverableChat(
+ message: String,
+ hover: List<String>,
+ command: String? = null,
+ prefix: Boolean = true,
+ prefixColor: String = "§e",
+ ) {
+ val msgPrefix = if (prefix) prefixColor + CHAT_PREFIX else ""
+ val text = ChatComponentText(msgPrefix + message)
+ text.chatStyle.chatHoverEvent =
+ HoverEvent(HoverEvent.Action.SHOW_TEXT, ChatComponentText(hover.joinToString("\n")))
+
+ command?.let {
+ text.chatStyle.chatClickEvent = ClickEvent(ClickEvent.Action.RUN_COMMAND, "/${it.removePrefix("/")}")
+ }
+
+ Minecraft.getMinecraft().thePlayer.addChatMessage(text)
+ }
+
+ /**
+ * Sends a message to the user that they can click and run a command
+ * @param message The message to be sent
+ * @param url The url to be opened
+ * @param autoOpen Automatically opens the url as well as sending the clickable link message
+ * @param hover The message to be shown when the message is hovered
+ * @param prefix Whether to prefix the message with the chat prefix, default true
+ * @param prefixColor Color that the prefix should be, default yellow (§e)
+ *
+ * @see CHAT_PREFIX
+ */
+ fun clickableLinkChat(
+ message: String,
+ url: String,
+ hover: String = "§eOpen $url",
+ autoOpen: Boolean = false,
+ prefix: Boolean = true,
+ prefixColor: String = "§e"
+ ) {
+ val msgPrefix = if (prefix) prefixColor + CHAT_PREFIX else ""
+ val text = ChatComponentText(msgPrefix + message)
+ text.chatStyle.chatClickEvent = ClickEvent(ClickEvent.Action.OPEN_URL, url)
+ text.chatStyle.chatHoverEvent = HoverEvent(HoverEvent.Action.SHOW_TEXT, ChatComponentText("$prefixColor$hover"))
+ Minecraft.getMinecraft().thePlayer.addChatMessage(text)
+ if (autoOpen) OSUtils.openBrowser(url)
+ }
+
+ private var lastMessageSent = SimpleTimeMark.farPast()
+ private val sendQueue: Queue<String> = LinkedList()
+
+ @SubscribeEvent
+ fun sendQueuedChatMessages(event: LorenzTickEvent) {
+ val player = Minecraft.getMinecraft().thePlayer
+ if (player == null) {
+ sendQueue.clear()
+ return
+ }
+ if (lastMessageSent.passedSince() > 300.milliseconds) {
+ player.sendChatMessage(sendQueue.poll() ?: return)
+ lastMessageSent = SimpleTimeMark.now()
+ }
+ }
+
+ fun sendMessageToServer(message: String) {
+ sendQueue.add(message)
+ }
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/ClipboardUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/ClipboardUtils.kt
index 31008d9b4..b1d8eb68b 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/ClipboardUtils.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/ClipboardUtils.kt
@@ -14,6 +14,7 @@ import java.awt.datatransfer.UnsupportedFlavorException
import kotlin.time.Duration.Companion.milliseconds
object ClipboardUtils {
+
private var dispatcher = Dispatchers.IO
private var lastClipboardAccessTime = SimpleTimeMark.farPast()
@@ -71,4 +72,4 @@ object ClipboardUtils {
}
}
}
-} \ No newline at end of file
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/CollectionUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/CollectionUtils.kt
new file mode 100644
index 000000000..b93f17fa4
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/utils/CollectionUtils.kt
@@ -0,0 +1,115 @@
+package at.hannibal2.skyhanni.utils
+
+import java.util.Collections
+import java.util.WeakHashMap
+import java.util.concurrent.ConcurrentLinkedQueue
+
+object CollectionUtils {
+
+ fun <E> ConcurrentLinkedQueue<E>.drainTo(list: MutableCollection<E>) {
+ while (true)
+ list.add(this.poll() ?: break)
+ }
+
+ // Let garbage collector handle the removal of entries in this list
+ fun <T> weakReferenceList(): MutableSet<T> = Collections.newSetFromMap(WeakHashMap<T, Boolean>())
+
+ fun <T> MutableCollection<T>.filterToMutable(predicate: (T) -> Boolean) = filterTo(mutableListOf(), predicate)
+
+ fun <T> List<T>.indexOfFirst(vararg args: T) = args.map { indexOf(it) }.firstOrNull { it != -1 }
+
+ infix fun <K, V> MutableMap<K, V>.put(pairs: Pair<K, V>) {
+ this[pairs.first] = pairs.second
+ }
+
+ // Taken and modified from Skytils
+ @JvmStatic
+ fun <T> T.equalsOneOf(vararg other: T): Boolean {
+ for (obj in other) {
+ if (this == obj) return true
+ }
+ return false
+ }
+
+ fun <E> List<E>.getOrNull(index: Int): E? {
+ return if (index in indices) {
+ get(index)
+ } else null
+ }
+
+ fun <T : Any> T?.toSingletonListOrEmpty(): List<T> {
+ if (this == null) return emptyList()
+ return listOf(this)
+ }
+
+ fun <K> MutableMap<K, Int>.addOrPut(key: K, number: Int): Int =
+ this.merge(key, number, Int::plus)!! // Never returns null since "plus" can't return null
+
+ fun <K> MutableMap<K, Long>.addOrPut(key: K, number: Long): Long =
+ this.merge(key, number, Long::plus)!! // Never returns null since "plus" can't return null
+
+ fun <K> MutableMap<K, Double>.addOrPut(key: K, number: Double): Double =
+ this.merge(key, number, Double::plus)!! // Never returns null since "plus" can't return null
+
+ fun <K, N : Number> Map<K, N>.sumAllValues(): Double {
+ if (values.isEmpty()) return 0.0
+
+ return when (values.first()) {
+ is Double -> values.sumOf { it.toDouble() }
+ is Float -> values.sumOf { it.toDouble() }
+ is Long -> values.sumOf { it.toLong() }.toDouble()
+ else -> values.sumOf { it.toInt() }.toDouble()
+ }
+ }
+
+ fun List<String>.nextAfter(after: String, skip: Int = 1) = nextAfter({ it == after }, skip)
+
+ fun List<String>.nextAfter(after: (String) -> Boolean, skip: Int = 1): String? {
+ var missing = -1
+ for (line in this) {
+ if (after(line)) {
+ missing = skip - 1
+ continue
+ }
+ if (missing == 0) {
+ return line
+ }
+ if (missing != -1) {
+ missing--
+ }
+ }
+ return null
+ }
+
+ fun <K, V> Map<K, V>.editCopy(function: MutableMap<K, V>.() -> Unit) =
+ toMutableMap().also { function(it) }.toMap()
+
+ fun <T> List<T>.editCopy(function: MutableList<T>.() -> Unit) =
+ toMutableList().also { function(it) }.toList()
+
+ fun <K, V> Map<K, V>.moveEntryToTop(matcher: (Map.Entry<K, V>) -> Boolean): Map<K, V> {
+ val entry = entries.find(matcher)
+ if (entry != null) {
+ val newMap = linkedMapOf(entry.key to entry.value)
+ newMap.putAll(this)
+ return newMap
+ }
+ return this
+ }
+
+ fun <E> MutableList<List<E>>.addAsSingletonList(text: E) {
+ add(Collections.singletonList(text))
+ }
+
+ fun <K, V : Comparable<V>> List<Pair<K, V>>.sorted(): List<Pair<K, V>> {
+ return sortedBy { (_, value) -> value }
+ }
+
+ fun <K, V : Comparable<V>> Map<K, V>.sorted(): Map<K, V> {
+ return toList().sorted().toMap()
+ }
+
+ fun <K, V : Comparable<V>> Map<K, V>.sortedDesc(): Map<K, V> {
+ return toList().sorted().reversed().toMap()
+ }
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/ColorUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/ColorUtils.kt
index 076afc0c4..8eab43636 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/ColorUtils.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/ColorUtils.kt
@@ -1,6 +1,11 @@
package at.hannibal2.skyhanni.utils
+import java.awt.Color
+
object ColorUtils {
+
+ /** transfer string colors from the config to java.awt.Color */
+ fun String.toChromaColor() = Color(SpecialColour.specialToChromaRGB(this), true)
fun getRed(colour: Int) = colour shr 16 and 0xFF
fun getGreen(colour: Int) = colour shr 8 and 0xFF
@@ -8,4 +13,4 @@ object ColorUtils {
fun getBlue(colour: Int) = colour and 0xFF
fun getAlpha(colour: Int) = colour shr 24 and 0xFF
-} \ No newline at end o