diff options
Diffstat (limited to 'src/main/kotlin')
-rw-r--r-- | src/main/kotlin/events/UseItemEvent.kt | 11 | ||||
-rw-r--r-- | src/main/kotlin/events/registration/ChatEvents.kt | 81 | ||||
-rw-r--r-- | src/main/kotlin/features/mining/PickaxeAbility.kt | 43 | ||||
-rw-r--r-- | src/main/kotlin/gui/CheckboxComponent.kt | 56 | ||||
-rw-r--r-- | src/main/kotlin/gui/config/ChoiceHandler.kt | 47 | ||||
-rw-r--r-- | src/main/kotlin/gui/config/EnumRenderer.kt | 15 | ||||
-rw-r--r-- | src/main/kotlin/gui/config/ManagedConfig.kt | 24 | ||||
-rw-r--r-- | src/main/kotlin/keybindings/FirmamentKeyBindings.kt | 29 | ||||
-rw-r--r-- | src/main/kotlin/util/MC.kt | 6 | ||||
-rw-r--r-- | src/main/kotlin/util/TestUtil.kt | 1 | ||||
-rw-r--r-- | src/main/kotlin/util/json/KJsonOps.kt | 131 | ||||
-rw-r--r-- | src/main/kotlin/util/skyblock/ItemType.kt | 5 |
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 + } } |