diff options
| author | Linnea Gräf <nea@nea.moe> | 2024-08-28 19:04:24 +0200 |
|---|---|---|
| committer | Linnea Gräf <nea@nea.moe> | 2024-08-28 19:04:24 +0200 |
| commit | d2f240ff0ca0d27f417f837e706c781a98c31311 (patch) | |
| tree | 0db7aff6cc14deaf36eed83889d59fd6b3a6f599 /src/main/kotlin/util | |
| parent | a6906308163aa3b2d18fa1dc1aa71ac9bbcc83ab (diff) | |
| download | Firmament-d2f240ff0ca0d27f417f837e706c781a98c31311.tar.gz Firmament-d2f240ff0ca0d27f417f837e706c781a98c31311.tar.bz2 Firmament-d2f240ff0ca0d27f417f837e706c781a98c31311.zip | |
Refactor source layout
Introduce compat source sets and move all kotlin sources to the main directory
[no changelog]
Diffstat (limited to 'src/main/kotlin/util')
62 files changed, 3138 insertions, 0 deletions
diff --git a/src/main/kotlin/util/Base64Util.kt b/src/main/kotlin/util/Base64Util.kt new file mode 100644 index 0000000..44bcdfd --- /dev/null +++ b/src/main/kotlin/util/Base64Util.kt @@ -0,0 +1,10 @@ + +package moe.nea.firmament.util + +object Base64Util { + fun String.padToValidBase64(): String { + val align = this.length % 4 + if (align == 0) return this + return this + "=".repeat(4 - align) + } +} diff --git a/src/main/kotlin/util/BazaarPriceStrategy.kt b/src/main/kotlin/util/BazaarPriceStrategy.kt new file mode 100644 index 0000000..002eedb --- /dev/null +++ b/src/main/kotlin/util/BazaarPriceStrategy.kt @@ -0,0 +1,19 @@ + +package moe.nea.firmament.util + +import moe.nea.firmament.repo.HypixelStaticData + +enum class BazaarPriceStrategy { + BUY_ORDER, + SELL_ORDER, + NPC_SELL; + + fun getSellPrice(skyblockId: SkyblockId): Double { + val bazaarEntry = HypixelStaticData.bazaarData[skyblockId] ?: return 0.0 + return when (this) { + BUY_ORDER -> bazaarEntry.quickStatus.sellPrice + SELL_ORDER -> bazaarEntry.quickStatus.buyPrice + NPC_SELL -> TODO() + } + } +} diff --git a/src/main/kotlin/util/ClipboardUtils.kt b/src/main/kotlin/util/ClipboardUtils.kt new file mode 100644 index 0000000..7b9b836 --- /dev/null +++ b/src/main/kotlin/util/ClipboardUtils.kt @@ -0,0 +1,24 @@ + + +package moe.nea.firmament.util + +import moe.nea.firmament.Firmament + +object ClipboardUtils { + fun setTextContent(string: String) { + try { + MC.keyboard.clipboard = string.ifEmpty { " " } + } catch (e: Exception) { + Firmament.logger.error("Could not write clipboard", e) + } + } + + fun getTextContents(): String { + try { + return MC.keyboard.clipboard ?: "" + } catch (e: Exception) { + Firmament.logger.error("Could not read clipboard", e) + return "" + } + } +} diff --git a/src/main/kotlin/util/CommonSoundEffects.kt b/src/main/kotlin/util/CommonSoundEffects.kt new file mode 100644 index 0000000..a97a2cb --- /dev/null +++ b/src/main/kotlin/util/CommonSoundEffects.kt @@ -0,0 +1,26 @@ + + +package moe.nea.firmament.util + +import net.minecraft.client.sound.PositionedSoundInstance +import net.minecraft.sound.SoundEvent +import net.minecraft.util.Identifier + +// TODO: Replace these with custom sound events that just re use the vanilla ogg s +object CommonSoundEffects { + fun playSound(identifier: Identifier) { + MC.soundManager.play(PositionedSoundInstance.master(SoundEvent.of(identifier), 1F)) + } + + fun playFailure() { + playSound(Identifier.of("minecraft", "block.anvil.place")) + } + + fun playSuccess() { + playDing() + } + + fun playDing() { + playSound(Identifier.of("minecraft", "entity.arrow.hit_player")) + } +} diff --git a/src/main/kotlin/util/DurabilityBarEvent.kt b/src/main/kotlin/util/DurabilityBarEvent.kt new file mode 100644 index 0000000..993462c --- /dev/null +++ b/src/main/kotlin/util/DurabilityBarEvent.kt @@ -0,0 +1,20 @@ + +package moe.nea.firmament.util + +import me.shedaniel.math.Color +import net.minecraft.item.ItemStack +import moe.nea.firmament.events.FirmamentEvent +import moe.nea.firmament.events.FirmamentEventBus + +data class DurabilityBarEvent( + val item: ItemStack, +) : FirmamentEvent() { + data class DurabilityBar( + val color: Color, + val percentage: Float, + ) + + var barOverride: DurabilityBar? = null + + companion object : FirmamentEventBus<DurabilityBarEvent>() +} diff --git a/src/main/kotlin/util/ErrorBoundary.kt b/src/main/kotlin/util/ErrorBoundary.kt new file mode 100644 index 0000000..fbc5b37 --- /dev/null +++ b/src/main/kotlin/util/ErrorBoundary.kt @@ -0,0 +1,10 @@ + + +package moe.nea.firmament.util + + +fun <T> errorBoundary(block: () -> T): T? { + // TODO: implement a proper error boundary here to avoid crashing minecraft code + return block() +} + diff --git a/src/main/kotlin/util/FirmFormatters.kt b/src/main/kotlin/util/FirmFormatters.kt new file mode 100644 index 0000000..c3bdd16 --- /dev/null +++ b/src/main/kotlin/util/FirmFormatters.kt @@ -0,0 +1,59 @@ + + +package moe.nea.firmament.util + +import com.google.common.math.IntMath.pow +import kotlin.math.absoluteValue +import kotlin.time.Duration + +object FirmFormatters { + fun formatCommas(int: Int, segments: Int = 3): String = formatCommas(int.toLong(), segments) + fun formatCommas(long: Long, segments: Int = 3): String { + val α = long / 1000 + if (α != 0L) { + return formatCommas(α, segments) + "," + (long - α * 1000).toString().padStart(3, '0') + } + return long.toString() + } + + fun formatCommas(float: Float, fractionalDigits: Int): String = formatCommas(float.toDouble(), fractionalDigits) + fun formatCommas(double: Double, fractionalDigits: Int): String { + val long = double.toLong() + val δ = (double - long).absoluteValue + val μ = pow(10, fractionalDigits) + val digits = (μ * δ).toInt().toString().padStart(fractionalDigits, '0').trimEnd('0') + return formatCommas(long) + (if (digits.isEmpty()) "" else ".$digits") + } + + fun formatDistance(distance: Double): String { + if (distance < 10) + return "%.1fm".format(distance) + return "%dm".format(distance.toInt()) + } + + fun formatTimespan(duration: Duration, millis: Boolean = false): String { + if (duration.isInfinite()) { + return if (duration.isPositive()) "∞" + else "-∞" + } + val sb = StringBuilder() + if (duration.isNegative()) sb.append("-") + duration.toComponents { days, hours, minutes, seconds, nanoseconds -> + if (days > 0) { + sb.append(days).append("d") + } + if (hours > 0) { + sb.append(hours).append("h") + } + if (minutes > 0) { + sb.append(minutes).append("m") + } + sb.append(seconds).append("s") + if (millis) { + sb.append(nanoseconds / 1_000_000).append("ms") + } + } + return sb.toString() + } + +} diff --git a/src/main/kotlin/util/FragmentGuiScreen.kt b/src/main/kotlin/util/FragmentGuiScreen.kt new file mode 100644 index 0000000..5e13d51 --- /dev/null +++ b/src/main/kotlin/util/FragmentGuiScreen.kt @@ -0,0 +1,93 @@ + + +package moe.nea.firmament.util + +import io.github.notenoughupdates.moulconfig.gui.GuiContext +import me.shedaniel.math.Dimension +import me.shedaniel.math.Point +import me.shedaniel.math.Rectangle +import net.minecraft.client.gui.DrawContext +import net.minecraft.client.gui.screen.Screen +import net.minecraft.text.Text + +abstract class FragmentGuiScreen( + val dismissOnOutOfBounds: Boolean = true +) : Screen(Text.literal("")) { + var popup: MoulConfigFragment? = null + + fun createPopup(context: GuiContext, position: Point) { + popup = MoulConfigFragment(context, position) { popup = null } + } + + override fun render(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) { + super.render(context, mouseX, mouseY, delta) + context.matrices.push() + context.matrices.translate(0f, 0f, 1000f) + popup?.render(context, mouseX, mouseY, delta) + context.matrices.pop() + } + + private inline fun ifPopup(ifYes: (MoulConfigFragment) -> Unit): Boolean { + val p = popup ?: return false + ifYes(p) + return true + } + + override fun keyPressed(keyCode: Int, scanCode: Int, modifiers: Int): Boolean { + return ifPopup { + it.keyPressed(keyCode, scanCode, modifiers) + } + } + + override fun keyReleased(keyCode: Int, scanCode: Int, modifiers: Int): Boolean { + return ifPopup { + it.keyReleased(keyCode, scanCode, modifiers) + } + } + + override fun mouseMoved(mouseX: Double, mouseY: Double) { + ifPopup { it.mouseMoved(mouseX, mouseY) } + } + + override fun mouseReleased(mouseX: Double, mouseY: Double, button: Int): Boolean { + return ifPopup { + it.mouseReleased(mouseX, mouseY, button) + } + } + + override fun mouseDragged(mouseX: Double, mouseY: Double, button: Int, deltaX: Double, deltaY: Double): Boolean { + return ifPopup { + it.mouseDragged(mouseX, mouseY, button, deltaX, deltaY) + } + } + + override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean { + return ifPopup { + if (!Rectangle( + it.position, + Dimension(it.context.root.width, it.context.root.height) + ).contains(Point(mouseX, mouseY)) + && dismissOnOutOfBounds + ) { + popup = null + } else { + it.mouseClicked(mouseX, mouseY, button) + } + }|| super.mouseClicked(mouseX, mouseY, button) + } + + override fun charTyped(chr: Char, modifiers: Int): Boolean { + return ifPopup { it.charTyped(chr, modifiers) } + } + + override fun mouseScrolled( + mouseX: Double, + mouseY: Double, + horizontalAmount: Double, + verticalAmount: Double + ): Boolean { + return ifPopup { + it.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount) + } + } +} diff --git a/src/main/kotlin/util/GetRectangle.kt b/src/main/kotlin/util/GetRectangle.kt new file mode 100644 index 0000000..ec64f31 --- /dev/null +++ b/src/main/kotlin/util/GetRectangle.kt @@ -0,0 +1,17 @@ + + +package moe.nea.firmament.util + +import me.shedaniel.math.Rectangle +import moe.nea.firmament.mixins.accessor.AccessorHandledScreen +import net.minecraft.client.gui.screen.ingame.HandledScreen + +fun HandledScreen<*>.getRectangle(): Rectangle { + this as AccessorHandledScreen + return Rectangle( + getX_Firmament(), + getY_Firmament(), + getBackgroundWidth_Firmament(), + getBackgroundHeight_Firmament() + ) +} diff --git a/src/main/kotlin/util/HoveredItemStack.kt b/src/main/kotlin/util/HoveredItemStack.kt new file mode 100644 index 0000000..47a59d0 --- /dev/null +++ b/src/main/kotlin/util/HoveredItemStack.kt @@ -0,0 +1,31 @@ + + +package moe.nea.firmament.util + +import me.shedaniel.math.impl.PointHelper +import me.shedaniel.rei.api.client.REIRuntime +import me.shedaniel.rei.api.client.gui.widgets.Slot +import me.shedaniel.rei.api.client.registry.screen.ScreenRegistry +import net.minecraft.client.gui.Element +import net.minecraft.client.gui.ParentElement +import net.minecraft.client.gui.screen.ingame.HandledScreen +import net.minecraft.item.ItemStack +import moe.nea.firmament.mixins.accessor.AccessorHandledScreen + + +val HandledScreen<*>.focusedItemStack: ItemStack? + get() { + this as AccessorHandledScreen + val vanillaSlot = this.focusedSlot_Firmament?.stack + if (vanillaSlot != null) return vanillaSlot + val focusedSlot = ScreenRegistry.getInstance().getFocusedStack(this, PointHelper.ofMouse()) + if (focusedSlot != null) return focusedSlot.cheatsAs().value + var baseElement: Element? = REIRuntime.getInstance().overlay.orElse(null) + val mx = PointHelper.getMouseFloatingX() + val my = PointHelper.getMouseFloatingY() + while (true) { + if (baseElement is Slot) return baseElement.currentEntry.cheatsAs().value + if (baseElement !is ParentElement) return null + baseElement = baseElement.hoveredElement(mx, my).orElse(null) + } + } diff --git a/src/main/kotlin/util/IdentifierSerializer.kt b/src/main/kotlin/util/IdentifierSerializer.kt new file mode 100644 index 0000000..65c5b1c --- /dev/null +++ b/src/main/kotlin/util/IdentifierSerializer.kt @@ -0,0 +1,25 @@ + +package moe.nea.firmament.util + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.builtins.serializer +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import net.minecraft.util.Identifier + +object IdentifierSerializer : KSerializer<Identifier> { + val delegateSerializer = String.serializer() + override val descriptor: SerialDescriptor + get() = PrimitiveSerialDescriptor("Identifier", PrimitiveKind.STRING) + + override fun deserialize(decoder: Decoder): Identifier { + return Identifier.of(decoder.decodeSerializableValue(delegateSerializer)) + } + + override fun serialize(encoder: Encoder, value: Identifier) { + encoder.encodeSerializableValue(delegateSerializer, value.toString()) + } +} diff --git a/src/main/kotlin/util/IdentityCharacteristics.kt b/src/main/kotlin/util/IdentityCharacteristics.kt new file mode 100644 index 0000000..f6054c4 --- /dev/null +++ b/src/main/kotlin/util/IdentityCharacteristics.kt @@ -0,0 +1,15 @@ + + +package moe.nea.firmament.util + +class IdentityCharacteristics<T>(val value: T) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is IdentityCharacteristics<*>) return false + return value === other.value + } + + override fun hashCode(): Int { + return System.identityHashCode(value) + } +} diff --git a/src/main/kotlin/util/ItemUtil.kt b/src/main/kotlin/util/ItemUtil.kt new file mode 100644 index 0000000..40d6198 --- /dev/null +++ b/src/main/kotlin/util/ItemUtil.kt @@ -0,0 +1,26 @@ + + +package moe.nea.firmament.util + +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NbtCompound +import net.minecraft.nbt.NbtList +import net.minecraft.text.Text +import moe.nea.firmament.util.item.loreAccordingToNbt + + +fun ItemStack.appendLore(args: List<Text>) { + if (args.isEmpty()) return + modifyLore { + val loreList = loreAccordingToNbt.toMutableList() + for (arg in args) { + loreList.add(arg) + } + loreList + } +} + +fun ItemStack.modifyLore(update: (List<Text>) -> List<Text>) { + val loreList = loreAccordingToNbt + loreAccordingToNbt = update(loreList) +} diff --git a/src/main/kotlin/util/LegacyFormattingCode.kt b/src/main/kotlin/util/LegacyFormattingCode.kt new file mode 100644 index 0000000..44bacfc --- /dev/null +++ b/src/main/kotlin/util/LegacyFormattingCode.kt @@ -0,0 +1,35 @@ + + +package moe.nea.firmament.util + +import net.minecraft.util.Formatting + +enum class LegacyFormattingCode(val label: String, val char: Char, val index: Int) { + BLACK("BLACK", '0', 0), + DARK_BLUE("DARK_BLUE", '1', 1), + DARK_GREEN("DARK_GREEN", '2', 2), + DARK_AQUA("DARK_AQUA", '3', 3), + DARK_RED("DARK_RED", '4', 4), + DARK_PURPLE("DARK_PURPLE", '5', 5), + GOLD("GOLD", '6', 6), + GRAY("GRAY", '7', 7), + DARK_GRAY("DARK_GRAY", '8', 8), + BLUE("BLUE", '9', 9), + GREEN("GREEN", 'a', 10), + AQUA("AQUA", 'b', 11), + RED("RED", 'c', 12), + LIGHT_PURPLE("LIGHT_PURPLE", 'd', 13), + YELLOW("YELLOW", 'e', 14), + WHITE("WHITE", 'f', 15), + OBFUSCATED("OBFUSCATED", 'k', -1), + BOLD("BOLD", 'l', -1), + STRIKETHROUGH("STRIKETHROUGH", 'm', -1), + UNDERLINE("UNDERLINE", 'n', -1), + ITALIC("ITALIC", 'o', -1), + RESET("RESET", 'r', -1); + + val modern = Formatting.byCode(char)!! + + val formattingCode = "§$char" + +} diff --git a/src/main/kotlin/util/LegacyTagParser.kt b/src/main/kotlin/util/LegacyTagParser.kt new file mode 100644 index 0000000..4e08da1 --- /dev/null +++ b/src/main/kotlin/util/LegacyTagParser.kt @@ -0,0 +1,245 @@ + + +package moe.nea.firmament.util + +import java.util.* +import net.minecraft.nbt.AbstractNbtNumber +import net.minecraft.nbt.NbtByte +import net.minecraft.nbt.NbtCompound +import net.minecraft.nbt.NbtDouble +import net.minecraft.nbt.NbtElement +import net.minecraft.nbt.NbtFloat +import net.minecraft.nbt.NbtInt +import net.minecraft.nbt.NbtList +import net.minecraft.nbt.NbtLong +import net.minecraft.nbt.NbtShort +import net.minecraft.nbt.NbtString + +class LegacyTagParser private constructor(string: String) { + data class TagParsingException(val baseString: String, val offset: Int, val mes0: String) : + Exception("$mes0 at $offset in `$baseString`.") + + class StringRacer(val backing: String) { + var idx = 0 + val stack = Stack<Int>() + + fun pushState() { + stack.push(idx) + } + + fun popState() { + idx = stack.pop() + } + + fun discardState() { + stack.pop() + } + + fun peek(count: Int): String { + return backing.substring(minOf(idx, backing.length), minOf(idx + cou |
