feat: add creation timestamp in lore
This commit is contained in:
@@ -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 }
|
||||
}
|
||||
|
||||
@@ -90,6 +92,14 @@ object TimerInLore {
|
||||
val regex =
|
||||
"(?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
|
||||
@@ -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())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) }
|
||||
|
||||
|
||||
28
src/test/kotlin/util/skyblock/TimestampTest.kt
Normal file
28
src/test/kotlin/util/skyblock/TimestampTest.kt
Normal file
@@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
122
src/test/resources/testdata/items/backpack-in-menu.snbt
vendored
Normal file
122
src/test/resources/testdata/items/backpack-in-menu.snbt
vendored
Normal file
@@ -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"
|
||||
}
|
||||
@@ -173,7 +173,7 @@
|
||||
"firmament.config.jade-integration.blocks.description": "Show custom block descriptions and hardness levels in Jade.",
|
||||
"firmament.config.jade-integration.progress": "Enable Custom Mining Progress",
|
||||
"firmament.config.jade-integration.progress.description": "Show the custom mining progress in Jade, when in a world with mining fatigue.",
|
||||
"firmament.config.lore-timers": "Lore Timers",
|
||||
"firmament.config.lore-timers": "Item Timestamps",
|
||||
"firmament.config.lore-timers.format": "Time Format",
|
||||
"firmament.config.lore-timers.format.choice.american": "§9Ame§cri§fcan",
|
||||
"firmament.config.lore-timers.format.choice.local": "System Time Format",
|
||||
@@ -181,6 +181,8 @@
|
||||
"firmament.config.lore-timers.format.choice.socialist": "European-ish",
|
||||
"firmament.config.lore-timers.format.description": "Choose the time format in which resolved timers are displayed.",
|
||||
"firmament.config.lore-timers.show": "Show Lore Timers",
|
||||
"firmament.config.lore-timers.show-creation": "Show Creation",
|
||||
"firmament.config.lore-timers.show-creation.description": "Shows the creation or craft timestamp of the item. Sometimes this timestamp is retained when upgrading an item, so it isn't necessarily the craft time of this specific item, but rather one of its components.",
|
||||
"firmament.config.lore-timers.show.description": "Shows when a timer in a lore (such as interest, auction duration) would end.",
|
||||
"firmament.config.party-commands": "Party Commands",
|
||||
"firmament.config.party-commands.cooldown": "Cooldown",
|
||||
|
||||
Reference in New Issue
Block a user