diff options
author | Linnea Gräf <nea@nea.moe> | 2025-06-26 19:15:38 +0200 |
---|---|---|
committer | Linnea Gräf <nea@nea.moe> | 2025-06-26 19:15:38 +0200 |
commit | a8f8382682fb70791ac5e5601f1c0c149df8c8eb (patch) | |
tree | 82d8118f615d6b8c9a7332990df255c9e9467d8c /src | |
parent | 1c5d0df368471031f892330de7628ff78a6204ed (diff) | |
download | Firmament-a8f8382682fb70791ac5e5601f1c0c149df8c8eb.tar.gz Firmament-a8f8382682fb70791ac5e5601f1c0c149df8c8eb.tar.bz2 Firmament-a8f8382682fb70791ac5e5601f1c0c149df8c8eb.zip |
feat: add creation timestamp in lore
Diffstat (limited to 'src')
-rw-r--r-- | src/main/kotlin/features/inventory/TimerInLore.kt | 29 | ||||
-rw-r--r-- | src/main/kotlin/util/SkyblockId.kt | 44 | ||||
-rw-r--r-- | src/test/kotlin/util/skyblock/TimestampTest.kt | 28 | ||||
-rw-r--r-- | src/test/resources/testdata/items/backpack-in-menu.snbt | 122 |
4 files changed, 209 insertions, 14 deletions
diff --git a/src/main/kotlin/features/inventory/TimerInLore.kt b/src/main/kotlin/features/inventory/TimerInLore.kt index 8eac77f..cc1df9a 100644 --- a/src/main/kotlin/features/inventory/TimerInLore.kt +++ b/src/main/kotlin/features/inventory/TimerInLore.kt @@ -16,12 +16,14 @@ import moe.nea.firmament.util.SBData import moe.nea.firmament.util.aqua import moe.nea.firmament.util.grey import moe.nea.firmament.util.mc.displayNameAccordingToNbt +import moe.nea.firmament.util.timestamp import moe.nea.firmament.util.tr import moe.nea.firmament.util.unformattedString object TimerInLore { object TConfig : ManagedConfig("lore-timers", Category.INVENTORY) { val showTimers by toggle("show") { true } + val showCreationTimestamp by toggle("show-creation") { true } val timerFormat by choice("format") { TimerFormat.SOCIALIST } } @@ -91,6 +93,14 @@ object TimerInLore { "(?i)(?:(?<years>[0-9]+) ?(y|years?) )?(?:(?<days>[0-9]+) ?(d|days?))? ?(?:(?<hours>[0-9]+) ?(h|hours?))? ?(?:(?<minutes>[0-9]+) ?(m|minutes?))? ?(?:(?<seconds>[0-9]+) ?(s|seconds?))?\\b".toRegex() @Subscribe + fun creationInLore(event: ItemTooltipEvent) { + if (!TConfig.showCreationTimestamp) return + val timestamp = event.stack.timestamp ?: return + val formattedTimestamp = TConfig.timerFormat.formatter.format(ZonedDateTime.ofInstant(timestamp, ZoneId.systemDefault())) + event.lines.add(tr("firmament.lore.creationtimestamp", "Created at: $formattedTimestamp").grey()) + } + + @Subscribe fun modifyLore(event: ItemTooltipEvent) { if (!TConfig.showTimers) return var lastTimer: ZonedDateTime? = null @@ -111,9 +121,13 @@ object TimerInLore { var baseLine = ZonedDateTime.now(SBData.hypixelTimeZone) if (countdownType.isRelative) { if (lastTimer == null) { - event.lines.add(i + 1, - tr("firmament.loretimer.missingrelative", - "Found a relative countdown with no baseline (Firmament)").grey()) + event.lines.add( + i + 1, + tr( + "firmament.loretimer.missingrelative", + "Found a relative countdown with no baseline (Firmament)" + ).grey() + ) continue } baseLine = lastTimer @@ -123,10 +137,11 @@ object TimerInLore { lastTimer = timer val localTimer = timer.withZoneSameInstant(ZoneId.systemDefault()) // TODO: install approximate time stabilization algorithm - event.lines.add(i + 1, - Text.literal("${countdownType.label}: ") - .grey() - .append(Text.literal(TConfig.timerFormat.formatter.format(localTimer)).aqua()) + event.lines.add( + i + 1, + Text.literal("${countdownType.label}: ") + .grey() + .append(Text.literal(TConfig.timerFormat.formatter.format(localTimer)).aqua()) ) } } diff --git a/src/main/kotlin/util/SkyblockId.kt b/src/main/kotlin/util/SkyblockId.kt index af767f8..8ede97e 100644 --- a/src/main/kotlin/util/SkyblockId.kt +++ b/src/main/kotlin/util/SkyblockId.kt @@ -6,6 +6,11 @@ import com.mojang.serialization.Codec import io.github.moulberry.repo.data.NEUIngredient import io.github.moulberry.repo.data.NEUItem import io.github.moulberry.repo.data.Rarity +import java.time.Instant +import java.time.LocalDateTime +import java.time.format.DateTimeFormatterBuilder +import java.time.format.SignStyle +import java.time.temporal.ChronoField import java.util.Optional import java.util.UUID import kotlinx.serialization.Serializable @@ -38,13 +43,14 @@ import moe.nea.firmament.util.json.DashlessUUIDSerializer @Serializable value class SkyblockId(val neuItem: String) : Comparable<SkyblockId> { val identifier - get() = Identifier.of("skyblockitem", - neuItem.lowercase().replace(";", "__") - .replace(":", "___") - .replace(illlegalPathRegex) { - it.value.toCharArray() - .joinToString("") { "__" + it.code.toString(16).padStart(4, '0') } - }) + get() = Identifier.of( + "skyblockitem", + neuItem.lowercase().replace(";", "__") + .replace(":", "___") + .replace(illlegalPathRegex) { + it.value.toCharArray() + .joinToString("") { "__" + it.code.toString(16).padStart(4, '0') } + }) override fun toString(): String { return neuItem @@ -137,6 +143,30 @@ fun ItemStack.modifyExtraAttributes(block: (NbtCompound) -> Unit) { val ItemStack.skyblockUUIDString: String? get() = extraAttributes.getString("uuid").getOrNull()?.takeIf { it.isNotBlank() } +private val timestampFormat = //"10/11/21 3:39 PM" + DateTimeFormatterBuilder().apply { + appendValue(ChronoField.MONTH_OF_YEAR, 2) + appendLiteral("/") + appendValue(ChronoField.DAY_OF_MONTH, 2) + appendLiteral("/") + appendValueReduced(ChronoField.YEAR, 2, 2, 1950) + appendLiteral(" ") + appendValue(ChronoField.HOUR_OF_AMPM, 1, 2, SignStyle.NEVER) + appendLiteral(":") + appendValue(ChronoField.MINUTE_OF_HOUR, 2) + appendLiteral(" ") + appendText(ChronoField.AMPM_OF_DAY) + }.toFormatter() +val ItemStack.timestamp + get() = + extraAttributes.getLong("timestamp").getOrNull()?.let { Instant.ofEpochMilli(it) } + ?: extraAttributes.getString("timestamp").getOrNull()?.let { + ErrorUtil.catch("Could not parse timestamp $it") { + LocalDateTime.from(timestampFormat.parse(it)).atZone(SBData.hypixelTimeZone) + .toInstant() + }.orNull() + } + val ItemStack.skyblockUUID: UUID? get() = skyblockUUIDString?.let { UUID.fromString(it) } diff --git a/src/test/kotlin/util/skyblock/TimestampTest.kt b/src/test/kotlin/util/skyblock/TimestampTest.kt new file mode 100644 index 0000000..b960cb9 --- /dev/null +++ b/src/test/kotlin/util/skyblock/TimestampTest.kt @@ -0,0 +1,28 @@ +package moe.nea.firmament.test.util.skyblock + +import java.time.Instant +import java.time.ZonedDateTime +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test +import moe.nea.firmament.test.testutil.ItemResources +import moe.nea.firmament.util.SBData +import moe.nea.firmament.util.timestamp + +class TimestampTest { + + @Test + fun testLongTimestamp() { + Assertions.assertEquals( + Instant.ofEpochSecond(1658091600), + ItemResources.loadItem("hyperion").timestamp + ) + } + + @Test + fun testStringTimestamp() { + Assertions.assertEquals( + ZonedDateTime.of(2021, 10, 11, 15, 39, 0, 0, SBData.hypixelTimeZone).toInstant(), + ItemResources.loadItem("backpack-in-menu").timestamp + ) + } +} diff --git a/src/test/resources/testdata/items/backpack-in-menu.snbt b/src/test/resources/testdata/items/backpack-in-menu.snbt new file mode 100644 index 0000000..2f22768 --- /dev/null +++ b/src/test/resources/testdata/items/backpack-in-menu.snbt @@ -0,0 +1,122 @@ +{ + components: { + "minecraft:custom_data": { + backpack_color: "BROWN", + originTag: "CRAFTING_GRID_COLLECT", + timestamp: "10/11/21 3:39 PM", + uuid: "3d7c83e8-c619-4603-8cfb-c95ceed90864" + }, + "minecraft:custom_name": { + extra: [ + { + color: "gold", + text: "Backpack Slot 3" + } + ], + italic: 0b, + text: "" + }, + "minecraft:lore": [ + { + extra: [ + { + color: "gold", + text: "Jumbo Backpack" + } + ], + italic: 0b, + text: "" + }, + { + extra: [ + { + color: "gray", + text: "" + }, + { + color: "gray", + text: "This backpack has " + }, + { + color: "green", + text: "45" + }, + { + color: "gray", + text: " slots." + } + ], + italic: 0b, + text: "" + }, + { + extra: [ + " " + ], + italic: 0b, + text: "" + }, + { + extra: [ + { + color: "gray", + text: "" + }, + { + color: "yellow", + text: "Left-click to open!" + } + ], + italic: 0b, + text: "" + }, + { + extra: [ + { + color: "gray", + text: "" + }, + { + color: "yellow", + text: "Right-click to remove!" + } + ], + italic: 0b, + text: "" + } + ], + "minecraft:profile": { + id: [I; + 1252359403, + 1319582828, + -1927151386, + 833492163 + ], + properties: [ + { + name: "textures", + signature: "U/49v6SXIw8bAmqM6T7t1BIR736N3Adpx7MlWncnT8zcFEm97zwRx9/tyaUy/XxBHaPGSL6BbgW2TdBtfb9gf0emCAZyWmnzSTtqDGiWpxnQM8v3+gHS8zD7Xrho0a/hU33xTbQ2knj2iRz8C+FReoJFxCjS++aXq6IqliIb3GhqB5b1egaiG2Q3t+yerl2Xue4nhdYM3wtGsYApC/ClR3TEuBcJv1WUVZM8rEoU29pbVnyMCKineG6mIN7W86SmzcT2SF+zMVyD0/mI7R2hRT2lbXnkMpM6FFscdnlvzjjPB9brtAWY7JGJ63b9C+khnvZUlhlQ/3E/08dFnON31VeabJXOmfrbfAgsF0Hgfs7Io+HzoXSXr/FCxNCCFMWlSwORmG2WCT4VRFzG2SThatPVPGJkuR/tLLOLzXo4RKOMzY5EIwa2XSxRUI4+5z2SZY11ofGic3bZD3wvICs2EZ54Pi508ZOda0qI9w5Q/TazC+jX/I5Nq2TLqLj+uU/+UX8eKXvHdk8QpBynyv9SyHo21jVXpiUgL1AsdzBp9cTZHNJuYtBxgDogr3SyAKPmw3BOzVeUi6qW8k4lgtefLKYteVSh52PjFgvQZUR1GNmFaJ+hlgKz8yONp+wXhw3nyL4dMOd2Z/dVVSywBp0tyHuN5l3PfaInK4s8qSydaW0=", + value: "ewogICJ0aW1lc3RhbXAiIDogMTcxOTUzODgxNTgyNCwKICAicHJvZmlsZUlkIiA6ICJkOWYxNTlhYWYxZjY0NGZlOTEwOTg0NzI2ZDBjMWJjMCIsCiAgInByb2ZpbGVOYW1lIiA6ICJtYW5vbmFtaXNzaW9uRyIsCiAgInNpZ25hdHVyZVJlcXVpcmVkIiA6IHRydWUsCiAgInRleHR1cmVzIiA6IHsKICAgICJTS0lOIiA6IHsKICAgICAgInVybCIgOiAiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS81YWQwYjQwNTIxMjYyYjdhM2Y5OWU2M2JkZGQ0YTNlNTQxOTY1Njc3ZTE0MTRlYWZhMTQyZThiYmE5ZGZlNDgxIiwKICAgICAgIm1ldGFkYXRhIiA6IHsKICAgICAgICAibW9kZWwiIDogInNsaW0iCiAgICAgIH0KICAgIH0KICB9Cn0=" + } + ] + }, + "minecraft:tooltip_display": { + hidden_components: [ + "minecraft:jukebox_playable", + "minecraft:painting/variant", + "minecraft:map_id", + "minecraft:fireworks", + "minecraft:attribute_modifiers", + "minecraft:unbreakable", + "minecraft:written_book_content", + "minecraft:banner_patterns", + "minecraft:trim", + "minecraft:potion_contents", + "minecraft:block_entity_data", + "minecraft:dyed_color" + ] + } + }, + count: 3, + id: "minecraft:player_head" +} |