Add basic sack util

[no changelog]
This commit is contained in:
Linnea Gräf
2024-10-01 18:00:43 +02:00
parent beb14d73bd
commit a4eac70118
22 changed files with 350 additions and 177 deletions

View File

@@ -1,13 +1,12 @@
package moe.nea.firmament.mixins; package moe.nea.firmament.mixins;
import com.llamalad7.mixinextras.sugar.Local; import moe.nea.firmament.events.ChestInventoryUpdateEvent;
import moe.nea.firmament.events.PlayerInventoryUpdate; import moe.nea.firmament.events.PlayerInventoryUpdate;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientCommonNetworkHandler; import net.minecraft.client.network.ClientCommonNetworkHandler;
import net.minecraft.client.network.ClientConnectionState; import net.minecraft.client.network.ClientConnectionState;
import net.minecraft.client.network.ClientPlayNetworkHandler; import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.network.ClientConnection; import net.minecraft.network.ClientConnection;
import net.minecraft.network.packet.s2c.play.InventoryS2CPacket; import net.minecraft.network.packet.s2c.play.InventoryS2CPacket;
import net.minecraft.network.packet.s2c.play.ScreenHandlerSlotUpdateS2CPacket; import net.minecraft.network.packet.s2c.play.ScreenHandlerSlotUpdateS2CPacket;
@@ -34,7 +33,9 @@ public abstract class SlotUpdateListener extends ClientCommonNetworkHandler {
|| packet.getSyncId() == 0) { || packet.getSyncId() == 0) {
PlayerInventoryUpdate.Companion.publish(new PlayerInventoryUpdate.Single(packet.getSlot(), packet.getStack())); PlayerInventoryUpdate.Companion.publish(new PlayerInventoryUpdate.Single(packet.getSlot(), packet.getStack()));
} else if (packet.getSyncId() == player.currentScreenHandler.syncId) { } else if (packet.getSyncId() == player.currentScreenHandler.syncId) {
// TODO: dispatch single chest slot ChestInventoryUpdateEvent.Companion.publish(
new ChestInventoryUpdateEvent.Single(packet.getSlot(), packet.getStack())
);
} }
} }
@@ -47,7 +48,9 @@ public abstract class SlotUpdateListener extends ClientCommonNetworkHandler {
if (packet.getSyncId() == 0) { if (packet.getSyncId() == 0) {
PlayerInventoryUpdate.Companion.publish(new PlayerInventoryUpdate.Multi(packet.getContents())); PlayerInventoryUpdate.Companion.publish(new PlayerInventoryUpdate.Multi(packet.getContents()));
} else if (packet.getSyncId() == player.currentScreenHandler.syncId) { } else if (packet.getSyncId() == player.currentScreenHandler.syncId) {
// TODO: dispatch multi chest ChestInventoryUpdateEvent.Companion.publish(
new ChestInventoryUpdateEvent.Multi(packet.getContents())
);
} }
} }
} }

View File

@@ -0,0 +1,14 @@
package moe.nea.firmament.mixins.accessor;
import net.minecraft.client.gui.hud.ChatHud;
import net.minecraft.client.gui.hud.ChatHudLine;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import java.util.List;
@Mixin(ChatHud.class)
public interface AccessorChatHud {
@Accessor("messages")
List<ChatHudLine> getMessages_firmament();
}

View File

@@ -4,7 +4,9 @@ import com.mojang.brigadier.CommandDispatcher
import com.mojang.brigadier.arguments.StringArgumentType.string import com.mojang.brigadier.arguments.StringArgumentType.string
import io.ktor.client.statement.bodyAsText import io.ktor.client.statement.bodyAsText
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource
import net.minecraft.nbt.NbtOps
import net.minecraft.text.Text import net.minecraft.text.Text
import net.minecraft.text.TextCodecs
import moe.nea.firmament.apis.UrsaManager import moe.nea.firmament.apis.UrsaManager
import moe.nea.firmament.events.CommandEvent import moe.nea.firmament.events.CommandEvent
import moe.nea.firmament.events.FirmamentEventBus import moe.nea.firmament.events.FirmamentEventBus
@@ -24,6 +26,7 @@ import moe.nea.firmament.util.MC
import moe.nea.firmament.util.SBData import moe.nea.firmament.util.SBData
import moe.nea.firmament.util.ScreenUtil import moe.nea.firmament.util.ScreenUtil
import moe.nea.firmament.util.SkyblockId import moe.nea.firmament.util.SkyblockId
import moe.nea.firmament.util.accessors.messages
import moe.nea.firmament.util.collections.InstanceList import moe.nea.firmament.util.collections.InstanceList
import moe.nea.firmament.util.collections.WeakCache import moe.nea.firmament.util.collections.WeakCache
@@ -205,6 +208,14 @@ fun firmamentCommand() = literal("firmament") {
} }
} }
} }
thenLiteral("dumpchat") {
thenExecute {
MC.inGameHud.chatHud.messages.forEach {
val nbt = TextCodecs.CODEC.encodeStart(NbtOps.INSTANCE, it.content).orThrow
println(nbt)
}
}
}
thenLiteral("sbdata") { thenLiteral("sbdata") {
thenExecute { thenExecute {
source.sendFeedback(Text.stringifiedTranslatable("firmament.sbinfo.profile", SBData.profileId)) source.sendFeedback(Text.stringifiedTranslatable("firmament.sbinfo.profile", SBData.profileId))

View File

@@ -0,0 +1,11 @@
package moe.nea.firmament.events
import net.minecraft.item.ItemStack
import moe.nea.firmament.util.MC
sealed class ChestInventoryUpdateEvent : FirmamentEvent() {
companion object : FirmamentEventBus<ChestInventoryUpdateEvent>()
data class Single(val slot: Int, val stack: ItemStack) : ChestInventoryUpdateEvent()
data class Multi(val contents: List<ItemStack>) : ChestInventoryUpdateEvent()
val inventory = MC.screen
}

View File

@@ -27,7 +27,7 @@ import moe.nea.firmament.util.MC
import moe.nea.firmament.util.MoulConfigUtils import moe.nea.firmament.util.MoulConfigUtils
import moe.nea.firmament.util.ScreenUtil import moe.nea.firmament.util.ScreenUtil
import moe.nea.firmament.util.SkyblockId import moe.nea.firmament.util.SkyblockId
import moe.nea.firmament.util.item.createSkullItem import moe.nea.firmament.util.mc.createSkullItem
import moe.nea.firmament.util.render.RenderInWorldContext import moe.nea.firmament.util.render.RenderInWorldContext
import moe.nea.firmament.util.setSkyBlockFirmamentUiId import moe.nea.firmament.util.setSkyBlockFirmamentUiId
import moe.nea.firmament.util.skyBlockId import moe.nea.firmament.util.skyBlockId

View File

@@ -13,7 +13,7 @@ import moe.nea.firmament.events.SlotRenderEvents
import moe.nea.firmament.features.FirmamentFeature import moe.nea.firmament.features.FirmamentFeature
import moe.nea.firmament.gui.config.ManagedConfig import moe.nea.firmament.gui.config.ManagedConfig
import moe.nea.firmament.util.MC import moe.nea.firmament.util.MC
import moe.nea.firmament.util.item.loreAccordingToNbt import moe.nea.firmament.util.mc.loreAccordingToNbt
import moe.nea.firmament.util.collections.lastNotNullOfOrNull import moe.nea.firmament.util.collections.lastNotNullOfOrNull
import moe.nea.firmament.util.collections.memoizeIdentity import moe.nea.firmament.util.collections.memoizeIdentity
import moe.nea.firmament.util.unformattedString import moe.nea.firmament.util.unformattedString

View File

@@ -28,8 +28,8 @@ import moe.nea.firmament.util.MC
import moe.nea.firmament.util.SBData import moe.nea.firmament.util.SBData
import moe.nea.firmament.util.SkyBlockIsland import moe.nea.firmament.util.SkyBlockIsland
import moe.nea.firmament.util.data.ProfileSpecificDataHolder import moe.nea.firmament.util.data.ProfileSpecificDataHolder
import moe.nea.firmament.util.item.displayNameAccordingToNbt import moe.nea.firmament.util.mc.displayNameAccordingToNbt
import moe.nea.firmament.util.item.loreAccordingToNbt import moe.nea.firmament.util.mc.loreAccordingToNbt
import moe.nea.firmament.util.json.DashlessUUIDSerializer import moe.nea.firmament.util.json.DashlessUUIDSerializer
import moe.nea.firmament.util.skyblockUUID import moe.nea.firmament.util.skyblockUUID
import moe.nea.firmament.util.unformattedString import moe.nea.firmament.util.unformattedString

View File

@@ -21,8 +21,8 @@ import moe.nea.firmament.util.SHORT_NUMBER_FORMAT
import moe.nea.firmament.util.TIME_PATTERN import moe.nea.firmament.util.TIME_PATTERN
import moe.nea.firmament.util.TimeMark import moe.nea.firmament.util.TimeMark
import moe.nea.firmament.util.extraAttributes import moe.nea.firmament.util.extraAttributes
import moe.nea.firmament.util.item.displayNameAccordingToNbt import moe.nea.firmament.util.mc.displayNameAccordingToNbt
import moe.nea.firmament.util.item.loreAccordingToNbt import moe.nea.firmament.util.mc.loreAccordingToNbt
import moe.nea.firmament.util.parseShortNumber import moe.nea.firmament.util.parseShortNumber
import moe.nea.firmament.util.parseTimePattern import moe.nea.firmament.util.parseTimePattern
import moe.nea.firmament.util.render.RenderCircleProgress import moe.nea.firmament.util.render.RenderCircleProgress

View File

@@ -19,7 +19,7 @@ import moe.nea.firmament.events.TickEvent
import moe.nea.firmament.features.FirmamentFeature import moe.nea.firmament.features.FirmamentFeature
import moe.nea.firmament.gui.config.ManagedConfig import moe.nea.firmament.gui.config.ManagedConfig
import moe.nea.firmament.util.collections.WeakCache import moe.nea.firmament.util.collections.WeakCache
import moe.nea.firmament.util.item.decodeProfileTextureProperty import moe.nea.firmament.util.mc.decodeProfileTextureProperty
import moe.nea.firmament.util.skyBlockId import moe.nea.firmament.util.skyBlockId
object CustomSkyBlockTextures : FirmamentFeature { object CustomSkyBlockTextures : FirmamentFeature {

View File

@@ -5,8 +5,8 @@ import com.google.gson.JsonElement
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.minecraft.nbt.NbtElement import net.minecraft.nbt.NbtElement
import net.minecraft.nbt.NbtString import net.minecraft.nbt.NbtString
import moe.nea.firmament.util.item.displayNameAccordingToNbt import moe.nea.firmament.util.mc.displayNameAccordingToNbt
import moe.nea.firmament.util.item.loreAccordingToNbt import moe.nea.firmament.util.mc.loreAccordingToNbt
data class DisplayNamePredicate(val stringMatcher: StringMatcher) : FirmamentModelPredicate { data class DisplayNamePredicate(val stringMatcher: StringMatcher) : FirmamentModelPredicate {
override fun test(stack: ItemStack): Boolean { override fun test(stack: ItemStack): Boolean {

View File

@@ -3,7 +3,7 @@ package moe.nea.firmament.features.texturepack
import com.google.gson.JsonElement import com.google.gson.JsonElement
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import moe.nea.firmament.util.item.loreAccordingToNbt import moe.nea.firmament.util.mc.loreAccordingToNbt
class LorePredicate(val matcher: StringMatcher) : FirmamentModelPredicate { class LorePredicate(val matcher: StringMatcher) : FirmamentModelPredicate {
object Parser : FirmamentModelPredicateParser { object Parser : FirmamentModelPredicateParser {

View File

@@ -12,8 +12,8 @@ import net.minecraft.item.ItemStack
import net.minecraft.item.Items import net.minecraft.item.Items
import moe.nea.firmament.rei.SBItemStack import moe.nea.firmament.rei.SBItemStack
import moe.nea.firmament.util.SkyblockId import moe.nea.firmament.util.SkyblockId
import moe.nea.firmament.util.item.setEncodedSkullOwner import moe.nea.firmament.util.mc.setEncodedSkullOwner
import moe.nea.firmament.util.item.zeroUUID import moe.nea.firmament.util.mc.zeroUUID
object ModifyEquipment : EntityModifier { object ModifyEquipment : EntityModifier {
val names = mapOf( val names = mapOf(

View File

@@ -28,8 +28,8 @@ import moe.nea.firmament.util.FirmFormatters
import moe.nea.firmament.util.HypixelPetInfo import moe.nea.firmament.util.HypixelPetInfo
import moe.nea.firmament.util.LegacyFormattingCode import moe.nea.firmament.util.LegacyFormattingCode
import moe.nea.firmament.util.SkyblockId import moe.nea.firmament.util.SkyblockId
import moe.nea.firmament.util.appendLore import moe.nea.firmament.util.mc.appendLore
import moe.nea.firmament.util.item.displayNameAccordingToNbt import moe.nea.firmament.util.mc.displayNameAccordingToNbt
import moe.nea.firmament.util.petData import moe.nea.firmament.util.petData
import moe.nea.firmament.util.skyBlockId import moe.nea.firmament.util.skyBlockId
import moe.nea.firmament.util.withColor import moe.nea.firmament.util.withColor

View File

@@ -33,10 +33,10 @@ import moe.nea.firmament.gui.hud.MoulConfigHud
import moe.nea.firmament.util.LegacyTagParser import moe.nea.firmament.util.LegacyTagParser
import moe.nea.firmament.util.MC import moe.nea.firmament.util.MC
import moe.nea.firmament.util.SkyblockId import moe.nea.firmament.util.SkyblockId
import moe.nea.firmament.util.appendLore import moe.nea.firmament.util.mc.appendLore
import moe.nea.firmament.util.item.setCustomName import moe.nea.firmament.util.mc.setCustomName
import moe.nea.firmament.util.item.setSkullOwner import moe.nea.firmament.util.mc.setSkullOwner
import moe.nea.firmament.util.modifyLore import moe.nea.firmament.util.mc.modifyLore
import moe.nea.firmament.util.skyblockId import moe.nea.firmament.util.skyblockId
object ItemCache : IReloadable { object ItemCache : IReloadable {

View File

@@ -0,0 +1,8 @@
package moe.nea.firmament.util.accessors
import net.minecraft.client.gui.hud.ChatHud
import net.minecraft.client.gui.hud.ChatHudLine
import moe.nea.firmament.mixins.accessor.AccessorChatHud
val ChatHud.messages: MutableList<ChatHudLine>
get() = (this as AccessorChatHud).messages_firmament

View File

@@ -0,0 +1,28 @@
package moe.nea.firmament.util.mc
import java.util.Spliterator
import java.util.Spliterators
import net.minecraft.inventory.Inventory
import net.minecraft.item.ItemStack
val Inventory.indices get() = 0 until size()
val Inventory.iterableView
get() = object : Iterable<ItemStack> {
override fun spliterator(): Spliterator<ItemStack> {
return Spliterators.spliterator(iterator(), size().toLong(), 0)
}
override fun iterator(): Iterator<ItemStack> {
return object : Iterator<ItemStack> {
var i = 0
override fun hasNext(): Boolean {
return i < size()
}
override fun next(): ItemStack {
if (!hasNext()) throw NoSuchElementException()
return getStack(i++)
}
}
}
}

View File

@@ -1,13 +1,7 @@
package moe.nea.firmament.util.mc
package moe.nea.firmament.util
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.minecraft.nbt.NbtCompound
import net.minecraft.nbt.NbtList
import net.minecraft.text.Text import net.minecraft.text.Text
import moe.nea.firmament.util.item.loreAccordingToNbt
fun ItemStack.appendLore(args: List<Text>) { fun ItemStack.appendLore(args: List<Text>) {
if (args.isEmpty()) return if (args.isEmpty()) return

View File

@@ -1,6 +1,4 @@
package moe.nea.firmament.util.mc
package moe.nea.firmament.util.item
import net.minecraft.component.DataComponentTypes import net.minecraft.component.DataComponentTypes
import net.minecraft.component.type.LoreComponent import net.minecraft.component.type.LoreComponent

View File

@@ -1,8 +1,6 @@
@file:UseSerializers(DashlessUUIDSerializer::class, InstantAsLongSerializer::class) @file:UseSerializers(DashlessUUIDSerializer::class, InstantAsLongSerializer::class)
package moe.nea.firmament.util.item package moe.nea.firmament.util.mc
import com.mojang.authlib.GameProfile import com.mojang.authlib.GameProfile
import com.mojang.authlib.minecraft.MinecraftProfileTexture import com.mojang.authlib.minecraft.MinecraftProfileTexture

View File

@@ -1,5 +1,3 @@
package moe.nea.firmament.util package moe.nea.firmament.util
import java.util.regex.Matcher import java.util.regex.Matcher
@@ -43,6 +41,8 @@ fun parseTimePattern(text: String): Duration {
} }
fun parseShortNumber(string: String): Double { fun parseShortNumber(string: String): Double {
if (string.startsWith("-")) return -parseShortNumber(string.substring(1))
if (string.startsWith("+")) return parseShortNumber(string.substring(1))
var k = string.replace(",", "") var k = string.replace(",", "")
val scalar = k.last() val scalar = k.last()
var scalarMultiplier = siScalars[scalar] var scalarMultiplier = siScalars[scalar]

View File

@@ -0,0 +1,110 @@
package moe.nea.firmament.util.skyblock
import kotlinx.serialization.Serializable
import kotlinx.serialization.serializer
import net.minecraft.client.gui.screen.ingame.GenericContainerScreen
import net.minecraft.text.HoverEvent
import net.minecraft.text.Text
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.ChestInventoryUpdateEvent
import moe.nea.firmament.events.ProcessChatEvent
import moe.nea.firmament.repo.ItemNameLookup
import moe.nea.firmament.util.SHORT_NUMBER_FORMAT
import moe.nea.firmament.util.SkyblockId
import moe.nea.firmament.util.data.ProfileSpecificDataHolder
import moe.nea.firmament.util.mc.displayNameAccordingToNbt
import moe.nea.firmament.util.mc.iterableView
import moe.nea.firmament.util.mc.loreAccordingToNbt
import moe.nea.firmament.util.parseShortNumber
import moe.nea.firmament.util.skyBlockId
import moe.nea.firmament.util.unformattedString
import moe.nea.firmament.util.useMatch
object SackUtil {
@Serializable
data class SackContents(
// TODO: store the certainty of knowledge for each item.
val contents: MutableMap<SkyblockId, Long> = mutableMapOf(),
// val sackTypes:
)
object Store : ProfileSpecificDataHolder<SackContents>(serializer(), "Sacks", ::SackContents)
val items get() = Store.data?.contents ?: mutableMapOf()
val storedRegex = "^Stored: (?<stored>$SHORT_NUMBER_FORMAT)/(?<max>$SHORT_NUMBER_FORMAT)$".toPattern()
@Subscribe
fun storeDataFromInventory(event: ChestInventoryUpdateEvent) {
val screen = event.inventory as? GenericContainerScreen ?: return
if (!screen.title.unformattedString.endsWith(" Sack")) return
val inv = screen.screenHandler?.inventory ?: return
if (inv.size() < 18) return
val backSlot = inv.getStack(inv.size() - 5)
if (backSlot.displayNameAccordingToNbt.unformattedString != "Go Back") return
if (backSlot.loreAccordingToNbt.map { it.unformattedString } != listOf("To Sack of Sacks")) return
for (itemStack in inv.iterableView) {
// TODO: handle runes and gemstones
val stored = itemStack.loreAccordingToNbt.firstNotNullOfOrNull {
storedRegex.useMatch(it.unformattedString) {
val stored = parseShortNumber(group("stored")).toLong()
val max = parseShortNumber(group("max")).toLong()
stored
}
} ?: continue
val itemId = itemStack.skyBlockId ?: continue
items[itemId] = stored
}
Store.markDirty()
}
@Subscribe
fun updateFromChat(event: ProcessChatEvent) {
if (!event.unformattedString.startsWith("[Sacks]")) return
val update = ChatUpdate()
event.text.siblings.forEach(update::updateFromHoverText)
}
data class SackUpdate(
val itemId: SkyblockId?,
val itemName: String,
val changeAmount: Long,
)
private class ChatUpdate {
val updates = mutableListOf<SackUpdate>()
var foundAdded = false
var foundRemoved = false
fun updateFromCleanText(cleanedText: String) {
cleanedText.split("\n").forEach { line ->
changePattern.useMatch(line) {
val amount = parseShortNumber(group("amount")).toLong()
val itemName = group("itemName")
val itemId = ItemNameLookup.guessItemByName(itemName, false)
updates.add(SackUpdate(itemId, itemName, amount))
}
}
}
fun updateFromHoverText(text: Text) {
text.siblings.forEach(::updateFromHoverText)
val hoverText = text.style.hoverEvent?.getValue(HoverEvent.Action.SHOW_TEXT) ?: return
val cleanedText = hoverText.unformattedString
if (cleanedText.startsWith("Added items:\n")) {
if (!foundAdded) {
updateFromCleanText(cleanedText)
foundAdded = true
}
}
if (cleanedText.startsWith("Removed items:\n")) {
if (!foundRemoved) {
updateFromCleanText(cleanedText)
foundRemoved = true
}
}
}
}
val changePattern = " (?<amount>[+\\-]$SHORT_NUMBER_FORMAT) (?<itemName>[^(]+) \\(.*\\)".toPattern()
}

View File

@@ -1,10 +1,7 @@
package moe.nea.firmament.util package moe.nea.firmament.util
import net.minecraft.text.MutableText import net.minecraft.text.MutableText
import net.minecraft.text.PlainTextContent import net.minecraft.text.PlainTextContent
import net.minecraft.text.Style
import net.minecraft.text.Text import net.minecraft.text.Text
import net.minecraft.text.TranslatableTextContent import net.minecraft.text.TranslatableTextContent
import net.minecraft.util.Formatting import net.minecraft.util.Formatting
@@ -93,6 +90,7 @@ fun CharSequence.removeColorCodes(keepNonColorCodes: Boolean = false): String {
val Text.unformattedString: String val Text.unformattedString: String
get() = string.removeColorCodes() get() = string.removeColorCodes()
fun Text.allSiblings(): List<Text> = listOf(this) + siblings.flatMap { it.allSiblings() }
fun MutableText.withColor(formatting: Formatting) = this.styled { it.withColor(formatting).withItalic(false) } fun MutableText.withColor(formatting: Formatting) = this.styled { it.withColor(formatting).withItalic(false) }