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"
|
||||
}
|
||||
Reference in New Issue
Block a user