aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/kotlin/features/debug/PowerUserTools.kt1
-rw-r--r--src/main/kotlin/features/debug/SkinPreviews.kt101
-rw-r--r--src/main/kotlin/features/inventory/buttons/InventoryButton.kt3
-rw-r--r--src/main/kotlin/util/TimeMark.kt5
-rw-r--r--translations/en_us.json4
5 files changed, 113 insertions, 1 deletions
diff --git a/src/main/kotlin/features/debug/PowerUserTools.kt b/src/main/kotlin/features/debug/PowerUserTools.kt
index b682813..a549f7e 100644
--- a/src/main/kotlin/features/debug/PowerUserTools.kt
+++ b/src/main/kotlin/features/debug/PowerUserTools.kt
@@ -65,6 +65,7 @@ object PowerUserTools {
val highlightNonOverlayItems by toggle("highlight-non-overlay") { false }
val dontHighlightSemicolonItems by toggle("dont-highlight-semicolon-items") { false }
val showSlotNumbers by keyBindingWithDefaultUnbound("slot-numbers")
+ val autoCopyAnimatedSkins by toggle("copy-animated-skins") { false }
}
var lastCopiedStack: Pair<ItemStack, Text>? = null
diff --git a/src/main/kotlin/features/debug/SkinPreviews.kt b/src/main/kotlin/features/debug/SkinPreviews.kt
new file mode 100644
index 0000000..5c710a4
--- /dev/null
+++ b/src/main/kotlin/features/debug/SkinPreviews.kt
@@ -0,0 +1,101 @@
+package moe.nea.firmament.features.debug
+
+import kotlinx.serialization.json.JsonPrimitive
+import kotlinx.serialization.json.buildJsonObject
+import kotlinx.serialization.json.put
+import kotlin.time.Duration.Companion.seconds
+import net.minecraft.component.DataComponentTypes
+import net.minecraft.component.type.ProfileComponent
+import net.minecraft.entity.EquipmentSlot
+import net.minecraft.entity.LivingEntity
+import net.minecraft.util.math.Vec3d
+import moe.nea.firmament.annotations.Subscribe
+import moe.nea.firmament.events.EntityUpdateEvent
+import moe.nea.firmament.events.IsSlotProtectedEvent
+import moe.nea.firmament.util.ClipboardUtils
+import moe.nea.firmament.util.MC
+import moe.nea.firmament.util.TimeMark
+import moe.nea.firmament.util.extraAttributes
+import moe.nea.firmament.util.json.toJsonArray
+import moe.nea.firmament.util.math.GChainReconciliation.shortenCycle
+import moe.nea.firmament.util.mc.displayNameAccordingToNbt
+import moe.nea.firmament.util.mc.loreAccordingToNbt
+import moe.nea.firmament.util.rawSkyBlockId
+import moe.nea.firmament.util.toTicks
+import moe.nea.firmament.util.tr
+
+
+object SkinPreviews {
+
+ // TODO: add pet support
+ @Subscribe
+ fun onEntityUpdate(event: EntityUpdateEvent) {
+ if (!isRecording) return
+ if (event.entity.pos != pos)
+ return
+ val entity = event.entity as? LivingEntity ?: return
+ val stack = entity.getEquippedStack(EquipmentSlot.HEAD) ?: return
+ val profile = stack.get(DataComponentTypes.PROFILE) ?: return
+ if (!profile.isCompleted) {
+ lastDiscard = TimeMark.now()
+ animation.clear()
+ MC.sendChat(
+ tr(
+ "firmament.dev.skinpreviews.discarding",
+ "Encountered unloaded skin, discarding all previews skin frames."
+ )
+ )
+ return
+ }
+ if (profile == animation.lastOrNull()) return
+ animation.add(profile)
+ val shortened = animation.shortenCycle()
+ if (shortened.size <= (animation.size / 2).coerceAtLeast(1) && lastDiscard.passedTime() > 2.seconds) {
+ val tickEstimation = (lastDiscard.passedTime() / animation.size).toTicks()
+ val skinName = if (skinColor != null) "${skinId}_${skinColor?.uppercase()}" else skinId!!
+ val json =
+ buildJsonObject {
+ put("ticks", tickEstimation)
+ put(
+ "textures",
+ shortened.map {
+ it.gameProfile().id.toString() + ":" + it.properties()["textures"].first().value()
+ }.toJsonArray()
+ )
+ }
+ MC.sendChat(
+ tr(
+ "firmament.dev.skinpreviews.done",
+ "Observed a total of ${animation.size} elements, which could be shortened to a cycle of ${shortened.size}. Copying JSON array. Estimated ticks per frame: $tickEstimation."
+ )
+ )
+ isRecording = false
+ ClipboardUtils.setTextContent(JsonPrimitive(skinName).toString() + ":" + json.toString())
+ }
+ }
+
+ var animation = mutableListOf<ProfileComponent>()
+ var pos = Vec3d(-1.0, 72.0, -101.25)
+ var isRecording = false
+ var skinColor: String? = null
+ var skinId: String? = null
+ var lastDiscard = TimeMark.farPast()
+
+ @Subscribe
+ fun onActivate(event: IsSlotProtectedEvent) {
+ if (!PowerUserTools.TConfig.autoCopyAnimatedSkins) return
+ val lastLine = event.itemStack.loreAccordingToNbt.lastOrNull()?.string
+ if (lastLine != "Right-click to preview!" && lastLine != "Click to preview!") return
+ lastDiscard = TimeMark.now()
+ val stackName = event.itemStack.displayNameAccordingToNbt.string
+ if (stackName == "FIRE SALE!") {
+ skinColor = null
+ skinId = event.itemStack.rawSkyBlockId
+ } else {
+ skinColor = stackName
+ }
+ animation.clear()
+ isRecording = true
+ MC.sendChat(tr("firmament.dev.skinpreviews.start", "Starting to observe items"))
+ }
+}
diff --git a/src/main/kotlin/features/inventory/buttons/InventoryButton.kt b/src/main/kotlin/features/inventory/buttons/InventoryButton.kt
index 0a1121d..e31f4a0 100644
--- a/src/main/kotlin/features/inventory/buttons/InventoryButton.kt
+++ b/src/main/kotlin/features/inventory/buttons/InventoryButton.kt
@@ -10,6 +10,7 @@ import net.minecraft.client.gui.DrawContext
import net.minecraft.command.CommandRegistryAccess
import net.minecraft.command.argument.ItemStackArgumentType
import net.minecraft.item.ItemStack
+import net.minecraft.item.Items
import net.minecraft.resource.featuretoggle.FeatureFlags
import net.minecraft.util.Identifier
import moe.nea.firmament.repo.ExpensiveItemCacheApi
@@ -77,7 +78,7 @@ data class InventoryButton(
}
}
}
- if (itemStack.isBroken)
+ if (itemStack.item == Items.PAINTING)
ErrorUtil.logError("created broken itemstack for inventory button $icon: $itemStack")
return itemStack
}
diff --git a/src/main/kotlin/util/TimeMark.kt b/src/main/kotlin/util/TimeMark.kt
index 4a076ac..112a727 100644
--- a/src/main/kotlin/util/TimeMark.kt
+++ b/src/main/kotlin/util/TimeMark.kt
@@ -2,6 +2,7 @@ package moe.nea.firmament.util
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
+import kotlin.time.DurationUnit
class TimeMark private constructor(private val timeMark: Long) : Comparable<TimeMark> {
fun passedTime() =
@@ -50,3 +51,7 @@ class TimeMark private constructor(private val timeMark: Long) : Comparable<Time
return this.timeMark.compareTo(other.timeMark)
}
}
+
+fun Duration.toTicks(): Long {
+ return toLong(DurationUnit.MILLISECONDS) / 50
+}
diff --git a/translations/en_us.json b/translations/en_us.json
index 97d6553..4f8c408 100644
--- a/translations/en_us.json
+++ b/translations/en_us.json
@@ -277,6 +277,8 @@
"firmament.config.pickaxe-info.show-on-tools.choice.pickaxes_and_drills": "Drills & Pickaxes",
"firmament.config.pickaxe-info.show-on-tools.description": "Show pickaxe ability cooldowns only on some tools. Notabene: Not all tools have support for pickaxe abilities so you might need to swap to your drill to activate the abilities.",
"firmament.config.power-user": "Power Users",
+ "firmament.config.power-user.copy-animated-skins": "Copy animated skins",
+ "firmament.config.power-user.copy-animated-skins.description": "Copy animated skin previews when spawned from Elizabeth.",
"firmament.config.power-user.copy-item-id": "Copy SkyBlock Id",
"firmament.config.power-user.copy-item-id.description": "Press this button to copy the NEU repo SkyBlock id. This is not the raw id, but instead contains some extra transformations for things like runes, pets and enchant books.",
"firmament.config.power-user.copy-item-stack": "Copy ItemStack",
@@ -305,6 +307,8 @@
"firmament.config.power-user.highlight-non-overlay.description": "Highlights items that don't exist in the repo.",
"firmament.config.power-user.show-item-id": "Show SkyBlock Ids",
"firmament.config.power-user.show-item-id.description": "Show the SkyBlock id of items underneath them.",
+ "firmament.config.power-user.slot-numbers": "Show slot numbers",
+ "firmament.config.power-user.slot-numbers.description": "Hold to show slot indices.",
"firmament.config.price-data": "Price Data",
"firmament.config.price-data.avg-lowest-bin-days": "AVG Lowest Bin Days",
"firmament.config.price-data.avg-lowest-bin-days.choice.off": "Off",