aboutsummaryrefslogtreecommitdiff
path: root/mod/src/main/kotlin/moe/nea/ledger/ItemIdProvider.kt
diff options
context:
space:
mode:
Diffstat (limited to 'mod/src/main/kotlin/moe/nea/ledger/ItemIdProvider.kt')
-rw-r--r--mod/src/main/kotlin/moe/nea/ledger/ItemIdProvider.kt188
1 files changed, 188 insertions, 0 deletions
diff --git a/mod/src/main/kotlin/moe/nea/ledger/ItemIdProvider.kt b/mod/src/main/kotlin/moe/nea/ledger/ItemIdProvider.kt
new file mode 100644
index 0000000..ff2c691
--- /dev/null
+++ b/mod/src/main/kotlin/moe/nea/ledger/ItemIdProvider.kt
@@ -0,0 +1,188 @@
+package moe.nea.ledger
+
+import moe.nea.ledger.events.BeforeGuiAction
+import moe.nea.ledger.events.ExtraSupplyIdEvent
+import moe.nea.ledger.events.RegistrationFinishedEvent
+import moe.nea.ledger.events.SupplyDebugInfo
+import moe.nea.ledger.gen.ItemIds
+import moe.nea.ledger.modules.ExternalDataProvider
+import net.minecraft.client.Minecraft
+import net.minecraft.item.ItemStack
+import net.minecraft.nbt.NBTTagCompound
+import net.minecraftforge.client.event.GuiScreenEvent
+import net.minecraftforge.common.MinecraftForge
+import net.minecraftforge.fml.common.eventhandler.EventPriority
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+import org.lwjgl.input.Mouse
+
+class ItemIdProvider {
+
+ @SubscribeEvent
+ fun onMouseInput(event: GuiScreenEvent.MouseInputEvent.Pre) {
+ if (Mouse.getEventButton() == -1) return
+ BeforeGuiAction(event.gui).post()
+ }
+
+ @SubscribeEvent
+ fun onKeyInput(event: GuiScreenEvent.KeyboardInputEvent.Pre) {
+ BeforeGuiAction(event.gui).post()
+ }
+
+ private val knownNames = mutableMapOf<String, ItemId>()
+
+ fun createLookupTagFromDisplayName(itemName: String): String {
+ return itemName.unformattedString().trim().lowercase()
+ }
+
+ fun saveKnownItem(itemName: String, itemId: ItemId) {
+ knownNames[createLookupTagFromDisplayName(itemName)] = itemId
+ }
+
+ @SubscribeEvent
+ fun onDataLoaded(event: ExternalDataProvider.DataLoaded) {
+ event.provider.itemNames.forEach { (itemId, itemName) ->
+ saveKnownItem(itemName, ItemId(itemId))
+ }
+ }
+
+ @SubscribeEvent
+ fun onRegistrationFinished(event: RegistrationFinishedEvent) {
+ MinecraftForge.EVENT_BUS.post(ExtraSupplyIdEvent(::saveKnownItem))
+ }
+
+ @SubscribeEvent(priority = EventPriority.HIGH)
+ fun savePlayerInventoryIds(event: BeforeGuiAction) {
+ val player = Minecraft.getMinecraft().thePlayer ?: return
+ val inventory = player.inventory ?: return
+ inventory.mainInventory?.forEach { saveFromSlot(it) }
+ inventory.armorInventory?.forEach { saveFromSlot(it) }
+ }
+
+ @SubscribeEvent
+ fun onDebugData(event: SupplyDebugInfo) {
+ event.record("knownItemNames", knownNames.size)
+ }
+
+ fun saveFromSlot(stack: ItemStack?, preprocessName: (String) -> String = { it }) {
+ if (stack == null) return
+ val nbt = stack.tagCompound ?: NBTTagCompound()
+ val display = nbt.getCompoundTag("display")
+ var name = display.getString("Name").unformattedString()
+ name = preprocessName(name)
+ name = name.trim()
+ val id = stack.getInternalId()
+ if (id != null && name.isNotBlank()) {
+ saveKnownItem(name, id)
+ }
+ }
+
+ @SubscribeEvent(priority = EventPriority.HIGH)
+ fun saveChestInventoryIds(event: BeforeGuiAction) {
+ val slots = event.chestSlots ?: return
+ val chestName = slots.lowerChestInventory.name.unformattedString()
+ val isOrderMenu = chestName == "Your Bazaar Orders" || chestName == "Co-op Bazaar Orders"
+ val preprocessor: (String) -> String = if (isOrderMenu) {
+ { it.removePrefix("BUY ").removePrefix("SELL ") }
+ } else {
+ { it }
+ }
+ slots.inventorySlots.forEach {
+ saveFromSlot(it?.stack, preprocessor)
+ }
+ }
+
+ // TODO: make use of colour
+ fun findForName(name: String, fallbackToGenerated: Boolean = true): ItemId? {
+ var id = knownNames[createLookupTagFromDisplayName(name)]
+ if (id == null && fallbackToGenerated) {
+ id = generateName(name)
+ }
+ return id
+ }
+
+ fun generateName(name: String): ItemId {
+ return ItemId(name.uppercase().replace(" ", "_"))
+ }
+
+ private val coinRegex = "(?<amount>$SHORT_NUMBER_PATTERN) Coins?".toPattern()
+ private val stackedItemRegex = "(?<name>.*) x(?<count>$SHORT_NUMBER_PATTERN)".toPattern()
+ private val reverseStackedItemRegex = "(?<count>$SHORT_NUMBER_PATTERN)x (?<name>.*)".toPattern()
+ private val essenceRegex = "(?<essence>.*) Essence x(?<count>$SHORT_NUMBER_PATTERN)".toPattern()
+ private val numberedItemRegex = "(?<count>$SHORT_NUMBER_PATTERN) (?<what>.*)".toPattern()
+
+ fun findCostItemsFromSpan(lore: List<String>): List<Pair<ItemId, Double>> {
+ return lore.iterator().asSequence()
+ .dropWhile { it.unformattedString() != "Cost" }.drop(1)
+ .takeWhile { it != "" }
+ .map { findStackableItemByName(it) ?: Pair(ItemId.NIL, 1.0) }
+ .toList()
+ }
+
+ private val etherialRewardPattern = "\\+(?<amount>${SHORT_NUMBER_PATTERN})x? (?<what>.*)".toPattern()
+
+ fun findStackableItemByName(name: String, fallbackToGenerated: Boolean = false): Pair<ItemId, Double>? {
+ val properName = name.unformattedString().trim()
+ if (properName == "FREE" || properName == "This Chest is Free!") {
+ return Pair(ItemId.COINS, 0.0)
+ }
+ coinRegex.useMatcher(properName) {
+ return Pair(ItemId.COINS, parseShortNumber(group("amount")))
+ }
+ etherialRewardPattern.useMatcher(properName) {
+ val id = when (val id = group("what")) {
+ "Copper" -> ItemIds.SKYBLOCK_COPPER
+ "Bits" -> ItemIds.SKYBLOCK_BIT
+ "Garden Experience" -> ItemId.GARDEN
+ "Farming XP" -> ItemId.FARMING
+ "Gold Essence" -> ItemIds.ESSENCE_GOLD
+ "Gemstone Powder" -> ItemId.GEMSTONE_POWDER
+ "Mithril Powder" -> ItemId.MITHRIL_POWDER
+ "Pelts" -> ItemIds.SKYBLOCK_PELT
+ "Fine Flour" -> ItemIds.FINE_FLOUR
+ else -> {
+ id.ifDropLast(" Experience") {
+ ItemId.skill(generateName(it).string)
+ } ?: id.ifDropLast(" XP") {
+ ItemId.skill(generateName(it).string)
+ } ?: id.ifDropLast(" Powder") {
+ ItemId("SKYBLOCK_POWDER_${generateName(it).string}")
+ } ?: id.ifDropLast(" Essence") {
+ ItemId("ESSENCE_${generateName(it).string}")
+ } ?: generateName(id)
+ }
+ }
+ return Pair(id, parseShortNumber(group("amount")))
+ }
+ essenceRegex.useMatcher(properName) {
+ return Pair(ItemId("ESSENCE_${group("essence").uppercase()}"),
+ parseShortNumber(group("count")))
+ }
+ stackedItemRegex.useMatcher(properName) {
+ val item = findForName(group("name"), fallbackToGenerated)
+ if (item != null) {
+ val count = parseShortNumber(group("count"))
+ return Pair(item, count)
+ }
+ }
+ reverseStackedItemRegex.useMatcher(properName) {
+ val item = findForName(group("name"), fallbackToGenerated)
+ if (item != null) {
+ val count = parseShortNumber(group("count"))
+ return Pair(item, count)
+ }
+ }
+ numberedItemRegex.useMatcher(properName) {
+ val item = findForName(group("what"), fallbackToGenerated)
+ if (item != null) {
+ val count = parseShortNumber(group("count"))
+ return Pair(item, count)
+ }
+ }
+
+ return findForName(properName, fallbackToGenerated)?.let { Pair(it, 1.0) }
+ }
+
+ fun getKnownItemIds(): Collection<ItemId> {
+ return knownNames.values
+ }
+} \ No newline at end of file