aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/kotlin')
-rw-r--r--src/main/kotlin/events/UseItemEvent.kt11
-rw-r--r--src/main/kotlin/events/registration/ChatEvents.kt81
-rw-r--r--src/main/kotlin/features/mining/PickaxeAbility.kt43
-rw-r--r--src/main/kotlin/gui/CheckboxComponent.kt56
-rw-r--r--src/main/kotlin/gui/config/ChoiceHandler.kt47
-rw-r--r--src/main/kotlin/gui/config/EnumRenderer.kt15
-rw-r--r--src/main/kotlin/gui/config/ManagedConfig.kt24
-rw-r--r--src/main/kotlin/keybindings/FirmamentKeyBindings.kt29
-rw-r--r--src/main/kotlin/util/MC.kt6
-rw-r--r--src/main/kotlin/util/TestUtil.kt1
-rw-r--r--src/main/kotlin/util/json/KJsonOps.kt131
-rw-r--r--src/main/kotlin/util/skyblock/ItemType.kt5
12 files changed, 395 insertions, 54 deletions
diff --git a/src/main/kotlin/events/UseItemEvent.kt b/src/main/kotlin/events/UseItemEvent.kt
new file mode 100644
index 0000000..e294bb1
--- /dev/null
+++ b/src/main/kotlin/events/UseItemEvent.kt
@@ -0,0 +1,11 @@
+package moe.nea.firmament.events
+
+import net.minecraft.entity.player.PlayerEntity
+import net.minecraft.item.ItemStack
+import net.minecraft.util.Hand
+import net.minecraft.world.World
+
+data class UseItemEvent(val playerEntity: PlayerEntity, val world: World, val hand: Hand) : FirmamentEvent.Cancellable() {
+ companion object : FirmamentEventBus<UseItemEvent>()
+ val item: ItemStack = playerEntity.getStackInHand(hand)
+}
diff --git a/src/main/kotlin/events/registration/ChatEvents.kt b/src/main/kotlin/events/registration/ChatEvents.kt
index 4c1c63f..1dcc91a 100644
--- a/src/main/kotlin/events/registration/ChatEvents.kt
+++ b/src/main/kotlin/events/registration/ChatEvents.kt
@@ -1,10 +1,9 @@
-
-
package moe.nea.firmament.events.registration
import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents
import net.fabricmc.fabric.api.event.player.AttackBlockCallback
import net.fabricmc.fabric.api.event.player.UseBlockCallback
+import net.fabricmc.fabric.api.event.player.UseItemCallback
import net.minecraft.text.Text
import net.minecraft.util.ActionResult
import moe.nea.firmament.events.AllowChatEvent
@@ -12,43 +11,53 @@ import moe.nea.firmament.events.AttackBlockEvent
import moe.nea.firmament.events.ModifyChatEvent
import moe.nea.firmament.events.ProcessChatEvent
import moe.nea.firmament.events.UseBlockEvent
+import moe.nea.firmament.events.UseItemEvent
private var lastReceivedMessage: Text? = null
fun registerFirmamentEvents() {
- ClientReceiveMessageEvents.ALLOW_CHAT.register(ClientReceiveMessageEvents.AllowChat { message, signedMessage, sender, params, receptionTimestamp ->
- lastReceivedMessage = message
- !ProcessChatEvent.publish(ProcessChatEvent(message, false)).cancelled
- && !AllowChatEvent.publish(AllowChatEvent(message)).cancelled
- })
- ClientReceiveMessageEvents.ALLOW_GAME.register(ClientReceiveMessageEvents.AllowGame { message, overlay ->
- lastReceivedMessage = message
- overlay || (!ProcessChatEvent.publish(ProcessChatEvent(message, false)).cancelled &&
- !AllowChatEvent.publish(AllowChatEvent(message)).cancelled)
- })
- ClientReceiveMessageEvents.MODIFY_GAME.register(ClientReceiveMessageEvents.ModifyGame { message, overlay ->
- if (overlay) message
- else ModifyChatEvent.publish(ModifyChatEvent(message)).replaceWith
- })
- ClientReceiveMessageEvents.GAME_CANCELED.register(ClientReceiveMessageEvents.GameCanceled { message, overlay ->
- if (!overlay && lastReceivedMessage !== message) {
- ProcessChatEvent.publish(ProcessChatEvent(message, true))
- }
- })
- ClientReceiveMessageEvents.CHAT_CANCELED.register(ClientReceiveMessageEvents.ChatCanceled { message, signedMessage, sender, params, receptionTimestamp ->
- if (lastReceivedMessage !== message) {
- ProcessChatEvent.publish(ProcessChatEvent(message, true))
- }
- })
+ ClientReceiveMessageEvents.ALLOW_CHAT.register(ClientReceiveMessageEvents.AllowChat { message, signedMessage, sender, params, receptionTimestamp ->
+ lastReceivedMessage = message
+ !ProcessChatEvent.publish(ProcessChatEvent(message, false)).cancelled
+ && !AllowChatEvent.publish(AllowChatEvent(message)).cancelled
+ })
+ ClientReceiveMessageEvents.ALLOW_GAME.register(ClientReceiveMessageEvents.AllowGame { message, overlay ->
+ lastReceivedMessage = message
+ overlay || (!ProcessChatEvent.publish(ProcessChatEvent(message, false)).cancelled &&
+ !AllowChatEvent.publish(AllowChatEvent(message)).cancelled)
+ })
+ ClientReceiveMessageEvents.MODIFY_GAME.register(ClientReceiveMessageEvents.ModifyGame { message, overlay ->
+ if (overlay) message
+ else ModifyChatEvent.publish(ModifyChatEvent(message)).replaceWith
+ })
+ ClientReceiveMessageEvents.GAME_CANCELED.register(ClientReceiveMessageEvents.GameCanceled { message, overlay ->
+ if (!overlay && lastReceivedMessage !== message) {
+ ProcessChatEvent.publish(ProcessChatEvent(message, true))
+ }
+ })
+ ClientReceiveMessageEvents.CHAT_CANCELED.register(ClientReceiveMessageEvents.ChatCanceled { message, signedMessage, sender, params, receptionTimestamp ->
+ if (lastReceivedMessage !== message) {
+ ProcessChatEvent.publish(ProcessChatEvent(message, true))
+ }
+ })
- AttackBlockCallback.EVENT.register(AttackBlockCallback { player, world, hand, pos, direction ->
- if (AttackBlockEvent.publish(AttackBlockEvent(player, world, hand, pos, direction)).cancelled)
- ActionResult.CONSUME
- else ActionResult.PASS
- })
- UseBlockCallback.EVENT.register(UseBlockCallback { player, world, hand, hitResult ->
- if (UseBlockEvent.publish(UseBlockEvent(player, world, hand, hitResult)).cancelled)
- ActionResult.CONSUME
- else ActionResult.PASS
- })
+ AttackBlockCallback.EVENT.register(AttackBlockCallback { player, world, hand, pos, direction ->
+ if (AttackBlockEvent.publish(AttackBlockEvent(player, world, hand, pos, direction)).cancelled)
+ ActionResult.CONSUME
+ else ActionResult.PASS
+ })
+ UseBlockCallback.EVENT.register(UseBlockCallback { player, world, hand, hitResult ->
+ if (UseBlockEvent.publish(UseBlockEvent(player, world, hand, hitResult)).cancelled)
+ ActionResult.CONSUME
+ else ActionResult.PASS
+ })
+ UseBlockCallback.EVENT.register(UseBlockCallback { player, world, hand, hitResult ->
+ if (UseItemEvent.publish(UseItemEvent(player, world, hand)).cancelled)
+ ActionResult.CONSUME
+ else ActionResult.PASS
+ })
+ UseItemCallback.EVENT.register(UseItemCallback { playerEntity, world, hand ->
+ if (UseItemEvent.publish(UseItemEvent(playerEntity, world, hand)).cancelled) ActionResult.CONSUME
+ else ActionResult.PASS
+ })
}
diff --git a/src/main/kotlin/features/mining/PickaxeAbility.kt b/src/main/kotlin/features/mining/PickaxeAbility.kt
index 4fcf8a7..2d6c3ee 100644
--- a/src/main/kotlin/features/mining/PickaxeAbility.kt
+++ b/src/main/kotlin/features/mining/PickaxeAbility.kt
@@ -7,11 +7,13 @@ import net.minecraft.item.ItemStack
import net.minecraft.util.DyeColor
import net.minecraft.util.Hand
import net.minecraft.util.Identifier
+import net.minecraft.util.StringIdentifiable
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.HudRenderEvent
import moe.nea.firmament.events.ProcessChatEvent
import moe.nea.firmament.events.ProfileSwitchEvent
import moe.nea.firmament.events.SlotClickEvent
+import moe.nea.firmament.events.UseItemEvent
import moe.nea.firmament.events.WorldReadyEvent
import moe.nea.firmament.features.FirmamentFeature
import moe.nea.firmament.gui.config.ManagedConfig
@@ -27,10 +29,13 @@ import moe.nea.firmament.util.mc.displayNameAccordingToNbt
import moe.nea.firmament.util.mc.loreAccordingToNbt
import moe.nea.firmament.util.parseShortNumber
import moe.nea.firmament.util.parseTimePattern
+import moe.nea.firmament.util.red
import moe.nea.firmament.util.render.RenderCircleProgress
import moe.nea.firmament.util.render.lerp
import moe.nea.firmament.util.skyblock.AbilityUtils
+import moe.nea.firmament.util.skyblock.ItemType
import moe.nea.firmament.util.toShedaniel
+import moe.nea.firmament.util.tr
import moe.nea.firmament.util.unformattedString
import moe.nea.firmament.util.useMatch
@@ -43,6 +48,22 @@ object PickaxeAbility : FirmamentFeature {
val cooldownEnabled by toggle("ability-cooldown") { false }
val cooldownScale by integer("ability-scale", 16, 64) { 16 }
val drillFuelBar by toggle("fuel-bar") { true }
+ val blockOnPrivateIsland by choice(
+ "block-on-dynamic",
+ BlockPickaxeAbility.entries,
+ ) {
+ BlockPickaxeAbility.ONLY_DESTRUCTIVE
+ }
+ }
+
+ enum class BlockPickaxeAbility : StringIdentifiable {
+ NEVER,
+ ALWAYS,
+ ONLY_DESTRUCTIVE;
+
+ override fun asString(): String {
+ return name
+ }
}
var lobbyJoinTime = TimeMark.farPast()
@@ -56,6 +77,8 @@ object PickaxeAbility : FirmamentFeature {
"Maniac Miner" to 59.seconds,
"Vein Seeker" to 60.seconds
)
+ val destructiveAbilities = setOf("Pickobulus")
+ val pickaxeTypes = setOf(ItemType.PICKAXE, ItemType.DRILL, ItemType.GAUNTLET)
override val config: ManagedConfig
get() = TConfig
@@ -74,6 +97,26 @@ object PickaxeAbility : FirmamentFeature {
}
@Subscribe
+ fun onPickaxeRightClick(event: UseItemEvent) {
+ if (TConfig.blockOnPrivateIsland == BlockPickaxeAbility.NEVER) return
+ val itemType = ItemType.fromItemStack(event.item)
+ if (itemType !in pickaxeTypes) return
+ val ability = AbilityUtils.getAbilities(event.item)
+ val shouldBlock = when (TConfig.blockOnPrivateIsland) {
+ BlockPickaxeAbility.NEVER -> false
+ BlockPickaxeAbility.ALWAYS -> ability.any()
+ BlockPickaxeAbility.ONLY_DESTRUCTIVE -> ability.any { it.name in destructiveAbilities }
+ }
+ if (shouldBlock) {
+ MC.sendChat(tr("firmament.pickaxe.blocked",
+ "Firmament blocked a pickaxe ability from being used on a private island.")
+ .red() // TODO: .clickCommand("firm confignavigate ${TConfig.identifier} block-on-dynamic")
+ )
+ event.cancel()
+ }
+ }
+
+ @Subscribe
fun onSlotClick(it: SlotClickEvent) {
if (MC.screen?.title?.unformattedString == "Heart of the Mountain") {
val name = it.stack.displayNameAccordingToNbt.unformattedString
diff --git a/src/main/kotlin/gui/CheckboxComponent.kt b/src/main/kotlin/gui/CheckboxComponent.kt
new file mode 100644
index 0000000..761c086
--- /dev/null
+++ b/src/main/kotlin/gui/CheckboxComponent.kt
@@ -0,0 +1,56 @@
+package moe.nea.firmament.gui
+
+import io.github.notenoughupdates.moulconfig.gui.GuiComponent
+import io.github.notenoughupdates.moulconfig.gui.GuiImmediateContext
+import io.github.notenoughupdates.moulconfig.gui.MouseEvent
+import io.github.notenoughupdates.moulconfig.observer.GetSetter
+import io.github.notenoughupdates.moulconfig.platform.ModernRenderContext
+import net.minecraft.client.render.RenderLayer
+import moe.nea.firmament.Firmament
+
+class CheckboxComponent<T>(
+ val state: GetSetter<T>,
+ val value: T,
+) : GuiComponent() {
+ override fun getWidth(): Int {
+ return 16
+ }
+
+ override fun getHeight(): Int {
+ return 16
+ }
+
+ fun isEnabled(): Boolean {
+ return state.get() == value
+ }
+
+ override fun render(context: GuiImmediateContext) {
+ val ctx = (context.renderContext as ModernRenderContext).drawContext
+ ctx.drawGuiTexture(
+ RenderLayer::getGuiTextured,
+ if (isEnabled()) Firmament.identifier("firmament:widget/checkbox_checked")
+ else Firmament.identifier("firmament:widget/checkbox_unchecked"),
+ 0, 0,
+ 16, 16
+ )
+ }
+
+ var isClicking = false
+
+ override fun mouseEvent(mouseEvent: MouseEvent, context: GuiImmediateContext): Boolean {
+ if (mouseEvent is MouseEvent.Click) {
+ if (isClicking && !mouseEvent.mouseState && mouseEvent.mouseButton == 0) {
+ isClicking = false
+ if (context.isHovered)
+ state.set(value)
+ return true
+ }
+ if (mouseEvent.mouseState && mouseEvent.mouseButton == 0 && context.isHovered) {
+ requestFocus()
+ isClicking = true
+ return true
+ }
+ }
+ return false
+ }
+}
diff --git a/src/main/kotlin/gui/config/ChoiceHandler.kt b/src/main/kotlin/gui/config/ChoiceHandler.kt
new file mode 100644
index 0000000..25e885a
--- /dev/null
+++ b/src/main/kotlin/gui/config/ChoiceHandler.kt
@@ -0,0 +1,47 @@
+package moe.nea.firmament.gui.config
+
+import io.github.notenoughupdates.moulconfig.gui.HorizontalAlign
+import io.github.notenoughupdates.moulconfig.gui.VerticalAlign
+import io.github.notenoughupdates.moulconfig.gui.component.AlignComponent
+import io.github.notenoughupdates.moulconfig.gui.component.RowComponent
+import io.github.notenoughupdates.moulconfig.gui.component.TextComponent
+import kotlinx.serialization.json.JsonElement
+import kotlin.jvm.optionals.getOrNull
+import net.minecraft.util.StringIdentifiable
+import moe.nea.firmament.gui.CheckboxComponent
+import moe.nea.firmament.util.ErrorUtil
+import moe.nea.firmament.util.json.KJsonOps
+
+class ChoiceHandler<E>(
+ val universe: List<E>,
+) : ManagedConfig.OptionHandler<E> where E : Enum<E>, E : StringIdentifiable {
+ val codec = StringIdentifiable.createCodec {
+ @Suppress("UNCHECKED_CAST", "PLATFORM_CLASS_MAPPED_TO_KOTLIN")
+ (universe as java.util.List<*>).toArray(arrayOfNulls<Enum<E>>(0)) as Array<E>
+ }
+ val renderer = EnumRenderer.default<E>()
+
+ override fun toJson(element: E): JsonElement? {
+ return codec.encodeStart(KJsonOps.INSTANCE, element)
+ .promotePartial { ErrorUtil.softError("Failed to encode json element '$element': $it") }.result()
+ .getOrNull()
+ }
+
+ override fun fromJson(element: JsonElement): E {
+ return codec.decode(KJsonOps.INSTANCE, element)
+ .promotePartial { ErrorUtil.softError("Failed to decode json element '$element': $it") }
+ .result()
+ .get()
+ .first
+ }
+
+ override fun emitGuiElements(opt: ManagedOption<E>, guiAppender: GuiAppender) {
+ guiAppender.appendFullRow(TextComponent(opt.labelText.string))
+ for (e in universe) {
+ guiAppender.appendFullRow(RowComponent(
+ AlignComponent(CheckboxComponent(opt, e), { HorizontalAlign.LEFT }, { VerticalAlign.CENTER }),
+ TextComponent(renderer.getName(opt, e).string)
+ ))
+ }
+ }
+}
diff --git a/src/main/kotlin/gui/config/EnumRenderer.kt b/src/main/kotlin/gui/config/EnumRenderer.kt
new file mode 100644
index 0000000..3b80b7e
--- /dev/null
+++ b/src/main/kotlin/gui/config/EnumRenderer.kt
@@ -0,0 +1,15 @@
+package moe.nea.firmament.gui.config
+
+import net.minecraft.text.Text
+
+interface EnumRenderer<E : Any> {
+ fun getName(option: ManagedOption<E>, value: E): Text
+
+ companion object {
+ fun <E : Enum<E>> default() = object : EnumRenderer<E> {
+ override fun getName(option: ManagedOption<E>, value: E): Text {
+ return Text.translatable(option.rawLabelText + ".choice." + value.name.lowercase())
+ }
+ }
+ }
+}
diff --git a/src/main/kotlin/gui/config/ManagedConfig.kt b/src/main/kotlin/gui/config/ManagedConfig.kt
index 8222a46..47a9c92 100644
--- a/src/main/kotlin/gui/config/ManagedConfig.kt
+++ b/src/main/kotlin/gui/config/ManagedConfig.kt
@@ -1,5 +1,6 @@
package moe.nea.firmament.gui.config
+import com.mojang.serialization.Codec
import io.github.notenoughupdates.moulconfig.gui.CloseEventListener
import io.github.notenoughupdates.moulconfig.gui.GuiComponentWrapper
import io.github.notenoughupdates.moulconfig.gui.GuiContext
@@ -20,6 +21,7 @@ import kotlin.io.path.writeText
import kotlin.time.Duration
import net.minecraft.client.gui.screen.Screen
import net.minecraft.text.Text
+import net.minecraft.util.StringIdentifiable
import moe.nea.firmament.Firmament
import moe.nea.firmament.gui.FirmButtonComponent
import moe.nea.firmament.keybindings.SavedKeyBinding
@@ -113,6 +115,28 @@ abstract class ManagedConfig(
return option(propertyName, default, BooleanHandler(this))
}
+ protected fun <E> choice(
+ propertyName: String,
+ universe: List<E>,
+ default: () -> E
+ ): ManagedOption<E> where E : Enum<E>, E : StringIdentifiable {
+ return option(propertyName, default, ChoiceHandler(universe))
+ }
+
+// TODO: wait on https://youtrack.jetbrains.com/issue/KT-73434
+// protected inline fun <reified E> choice(
+// propertyName: String,
+// noinline default: () -> E
+// ): ManagedOption<E> where E : Enum<E>, E : StringIdentifiable {
+// return choice(
+// propertyName,
+// enumEntries<E>().toList(),
+// StringIdentifiable.createCodec { enumValues<E>() },
+// EnumRenderer.default(),
+// default
+// )
+// }
+
protected fun duration(
propertyName: String,
min: Duration,
diff --git a/src/main/kotlin/keybindings/FirmamentKeyBindings.kt b/src/main/kotlin/keybindings/FirmamentKeyBindings.kt
index e2bed8d..59b131a 100644
--- a/src/main/kotlin/keybindings/FirmamentKeyBindings.kt
+++ b/src/main/kotlin/keybindings/FirmamentKeyBindings.kt
@@ -1,26 +1,25 @@
-
-
package moe.nea.firmament.keybindings
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper
import net.minecraft.client.option.KeyBinding
import net.minecraft.client.util.InputUtil
-import moe.nea.firmament.gui.config.KeyBindingHandler
import moe.nea.firmament.gui.config.ManagedOption
+import moe.nea.firmament.util.TestUtil
object FirmamentKeyBindings {
- fun registerKeyBinding(name: String, config: ManagedOption<SavedKeyBinding>) {
- val vanillaKeyBinding = KeyBindingHelper.registerKeyBinding(
- KeyBinding(
- name,
- InputUtil.Type.KEYSYM,
- -1,
- "firmament.key.category"
- )
- )
- keyBindings[vanillaKeyBinding] = config
- }
+ fun registerKeyBinding(name: String, config: ManagedOption<SavedKeyBinding>) {
+ val vanillaKeyBinding = KeyBinding(
+ name,
+ InputUtil.Type.KEYSYM,
+ -1,
+ "firmament.key.category"
+ )
+ if (!TestUtil.isInTest) {
+ KeyBindingHelper.registerKeyBinding(vanillaKeyBinding)
+ }
+ keyBindings[vanillaKeyBinding] = config
+ }
- val keyBindings = mutableMapOf<KeyBinding, ManagedOption<SavedKeyBinding>>()
+ val keyBindings = mutableMapOf<KeyBinding, ManagedOption<SavedKeyBinding>>()
}
diff --git a/src/main/kotlin/util/MC.kt b/src/main/kotlin/util/MC.kt
index a60d5c4..294334a 100644
--- a/src/main/kotlin/util/MC.kt
+++ b/src/main/kotlin/util/MC.kt
@@ -92,12 +92,12 @@ object MC {
inline val inGameHud: InGameHud get() = instance.inGameHud
inline val font get() = instance.textRenderer
inline val soundManager get() = instance.soundManager
- inline val player: ClientPlayerEntity? get() = instance.player
+ inline val player: ClientPlayerEntity? get() = TestUtil.unlessTesting { instance.player }
inline val camera: Entity? get() = instance.cameraEntity
inline val guiAtlasManager get() = instance.guiAtlasManager
- inline val world: ClientWorld? get() = instance.world
+ inline val world: ClientWorld? get() = TestUtil.unlessTesting { instance.world }
inline var screen: Screen?
- get() = instance.currentScreen
+ get() = TestUtil.unlessTesting{ instance.currentScreen }
set(value) = instance.setScreen(value)
val screenName get() = screen?.title?.unformattedString?.trim()
inline val handledScreen: HandledScreen<*>? get() = instance.currentScreen as? HandledScreen<*>
diff --git a/src/main/kotlin/util/TestUtil.kt b/src/main/kotlin/util/TestUtil.kt
index 2d38f35..45e3dde 100644
--- a/src/main/kotlin/util/TestUtil.kt
+++ b/src/main/kotlin/util/TestUtil.kt
@@ -1,6 +1,7 @@
package moe.nea.firmament.util
object TestUtil {
+ inline fun <T> unlessTesting(block: () -> T): T? = if (isInTest) null else block()
val isInTest =
Thread.currentThread().stackTrace.any {
it.className.startsWith("org.junit.") || it.className.startsWith("io.kotest.")
diff --git a/src/main/kotlin/util/json/KJsonOps.kt b/src/main/kotlin/util/json/KJsonOps.kt
new file mode 100644
index 0000000..404ea5e
--- /dev/null
+++ b/src/main/kotlin/util/json/KJsonOps.kt
@@ -0,0 +1,131 @@
+package moe.nea.firmament.util.json
+
+import com.google.gson.internal.LazilyParsedNumber
+import com.mojang.datafixers.util.Pair
+import com.mojang.serialization.DataResult
+import com.mojang.serialization.DynamicOps
+import java.util.stream.Stream
+import kotlinx.serialization.json.JsonArray
+import kotlinx.serialization.json.JsonElement
+import kotlinx.serialization.json.JsonNull
+import kotlinx.serialization.json.JsonObject
+import kotlinx.serialization.json.JsonPrimitive
+import kotlinx.serialization.json.boolean
+import kotlinx.serialization.json.booleanOrNull
+import kotlin.streams.asSequence
+
+class KJsonOps : DynamicOps<JsonElement> {
+ companion object {
+ val INSTANCE = KJsonOps()
+ }
+
+ override fun empty(): JsonElement {
+ return JsonNull
+ }
+
+ override fun createNumeric(num: Number): JsonElement {
+ return JsonPrimitive(num)
+ }
+
+ override fun createString(str: String): JsonElement {
+ return JsonPrimitive(str)
+ }
+
+ override fun remove(input: JsonElement, key: String): JsonElement {
+ if (input is JsonObject) {
+ return JsonObject(input.filter { it.key != key })
+ } else {
+ return input
+ }
+ }
+
+ override fun createList(stream: Stream<JsonElement>): JsonElement {
+ return JsonArray(stream.toList())
+ }
+
+ override fun getStream(input: JsonElement): DataResult<Stream<JsonElement>> {
+ if (input is JsonArray)
+ return DataResult.success(input.stream())
+ return DataResult.error { "Not a json array: $input" }
+ }
+
+ override fun createMap(map: Stream<Pair<JsonElement, JsonElement>>): JsonElement {
+ return JsonObject(map.asSequence()
+ .map { ((it.first as JsonPrimitive).content) to it.second }
+ .toMap())
+ }
+
+ override fun getMapValues(input: JsonElement): DataResult<Stream<Pair<JsonElement, JsonElement>>> {
+ if (input is JsonObject) {
+ return DataResult.success(input.entries.stream().map { Pair.of(createString(it.key), it.value) })
+ }
+ return DataResult.error { "Not a JSON object: $input" }
+ }
+
+ override fun mergeToMap(map: JsonElement, key: JsonElement, value: JsonElement): DataResult<JsonElement> {
+ if (key !is JsonPrimitive || key.isString) {
+ return DataResult.error { "key is not a string: $key" }
+ }
+ val jKey = key.content
+ val extra = mapOf(jKey to value)
+ if (map == empty()) {
+ return DataResult.success(JsonObject(extra))
+ }
+ if (map is JsonObject) {
+ return DataResult.success(JsonObject(map + extra))
+ }
+ return DataResult.error { "mergeToMap called with not a map: $map" }
+ }
+
+ override fun mergeToList(list: JsonElement, value: JsonElement): DataResult<JsonElement> {
+ if (list == empty())
+ return DataResult.success(JsonArray(listOf(value)))
+ if (list is JsonArray) {
+ return DataResult.success(JsonArray(list + value))
+ }
+ return DataResult.error { "mergeToList called with not a list: $list" }
+ }
+
+ override fun getStringValue(input: JsonElement): DataResult<String> {
+ if (input is JsonPrimitive && input.isString) {
+ return DataResult.success(input.content)
+ }
+ return DataResult.error { "Not a string: $input" }
+ }
+
+ override fun getNumberValue(input: JsonElement): DataResult<Number> {
+ if (input is JsonPrimitive && !input.isString && input.booleanOrNull == null)
+ return DataResult.success(LazilyParsedNumber(input.content))
+ return DataResult.error { "not a number: $input" }
+ }
+
+ override fun createBoolean(value: Boolean): JsonElement {
+ return JsonPrimitive(value)
+ }
+
+ override fun getBooleanValue(input: JsonElement): DataResult<Boolean> {
+ if (input is JsonPrimitive) {
+ if (input.booleanOrNull != null)
+ return DataResult.success(input.boolean)
+ return super.getBooleanValue(input)
+ }
+ return DataResult.error { "Not a boolean: $input" }
+ }
+
+ override fun <U : Any?> convertTo(output: DynamicOps<U>, input: JsonElement): U {
+ if (input is JsonObject)
+ return output.createMap(
+ input.entries.stream().map { Pair.of(output.createString(it.key), convertTo(output, it.value)) })
+ if (input is JsonArray)
+ return output.createList(input.stream().map { convertTo(output, it) })
+ if (input is JsonNull)
+ return output.empty()
+ if (input is JsonPrimitive) {
+ if (input.isString)
+ return output.createString(input.content)
+ if (input.booleanOrNull != null)
+ return output.createBoolean(input.boolean)
+ }
+ error("Unknown json value: $input")
+ }
+}
diff --git a/src/main/kotlin/util/skyblock/ItemType.kt b/src/main/kotlin/util/skyblock/ItemType.kt
index b031b69..6ddb077 100644
--- a/src/main/kotlin/util/skyblock/ItemType.kt
+++ b/src/main/kotlin/util/skyblock/ItemType.kt
@@ -32,10 +32,15 @@ value class ItemType private constructor(val name: String) {
val SWORD = ofName("SWORD")
val DRILL = ofName("DRILL")
val PICKAXE = ofName("PICKAXE")
+ val GAUNTLET = ofName("GAUNTLET")
/**
* This one is not really official (it never shows up in game).
*/
val PET = ofName("PET")
}
+
+ override fun toString(): String {
+ return name
+ }
}