aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/at/hannibal2/skyhanni/data/CropAccessoryData.kt
blob: 48b1c67b15b494433bd00da4b3e25597fb0757c4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package at.hannibal2.skyhanni.data

import at.hannibal2.skyhanni.SkyHanniMod
import at.hannibal2.skyhanni.events.InventoryCloseEvent
import at.hannibal2.skyhanni.events.InventoryOpenEvent
import at.hannibal2.skyhanni.events.ProfileApiDataLoadedEvent
import at.hannibal2.skyhanni.events.ProfileJoinEvent
import at.hannibal2.skyhanni.features.garden.CropAccessory
import at.hannibal2.skyhanni.utils.InventoryUtils
import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName
import at.hannibal2.skyhanni.utils.LorenzUtils
import at.hannibal2.skyhanni.utils.NEUItems
import com.google.gson.JsonElement
import net.minecraft.item.ItemStack
import net.minecraft.nbt.CompressedStreamTools
import net.minecraftforge.client.event.GuiScreenEvent
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import net.minecraftforge.fml.common.gameevent.TickEvent
import java.io.ByteArrayInputStream
import java.util.*

class CropAccessoryData {
    private val accessoryBagNamePattern = "Accessory Bag \\((\\d)/(\\d)\\)".toRegex()
    private var loadedAccessoryThisProfile = false
    private var ticks = 0
    private var accessoryInBag: CropAccessory? = null
    private var accessoryInInventory = CropAccessory.NONE

    private var accessoryBagPageNumber = 0

    // Handle API detection
    @SubscribeEvent
    fun onProfileJoin(event: ProfileJoinEvent) {
        loadedAccessoryThisProfile = false
    }

    @SubscribeEvent
    fun onProfileDataLoad(event: ProfileApiDataLoadedEvent) {
        if (loadedAccessoryThisProfile) return
        val inventoryData = event.profileData["inv_contents"] ?: return
        val accessories = getCropAccessories(event.profileData["talisman_bag"]).also {
            it.addAll(getCropAccessories(inventoryData))
        }
        cropAccessory = accessories.maxOrNull() ?: CropAccessory.NONE
        loadedAccessoryThisProfile = true
    }

    // Handle accessory bag detection
    @SubscribeEvent
    fun onInventoryOpen(event: InventoryOpenEvent) {
        val groups = accessoryBagNamePattern.matchEntire(event.inventoryName)?.groups ?: return
        isLoadingAccessories = true
        accessoryBagPageCount = groups[2]!!.value.toInt()
        accessoryBagPageNumber = groups[1]!!.value.toInt()
    }

    @SubscribeEvent
    fun onInventoryClose(event: InventoryCloseEvent) {
        isLoadingAccessories = false
    }

    @SubscribeEvent
    fun onGuiDraw(event: GuiScreenEvent.DrawScreenEvent) {
        if (!isLoadingAccessories) return
        val items = runCatching {
            InventoryUtils.getItemsInOpenChest()
        }.getOrNull() ?: return
        val bestCropAccessoryPage = bestCropAccessory(items.map { it.stack })
        accessoryPage[accessoryBagPageNumber] = bestCropAccessoryPage
        if (accessoryBagPageCount == accessoryPage.size) {
            accessoryInBag = accessoryPage.values.max().also {
                cropAccessory = maxOf(it, accessoryInInventory)
            }
            loadedAccessoryThisProfile = true
        }
    }

    // Handle inventory detection
    @SubscribeEvent
    fun onTick(event: TickEvent.ClientTickEvent) {
        if (event.phase != TickEvent.Phase.START || ticks++ % 20 != 0) return
        if (!LorenzUtils.inSkyBlock) return
        accessoryInInventory = bestCropAccessory(InventoryUtils.getItemsInOwnInventory())
        if (accessoryInInventory == CropAccessory.NONE) return
        if (accessoryInInventory > (accessoryInBag ?: CropAccessory.NONE)) {
            cropAccessory = accessoryInInventory
        }
    }


    private fun bestCropAccessory(items: Iterable<ItemStack>): CropAccessory {
        return items.mapNotNull { item -> CropAccessory.getByName(item.getInternalName()) }
            .maxOrNull() ?: CropAccessory.NONE
    }

    companion object {
        var accessoryBagPageCount = 0
            private set

        private var accessoryPage = mutableMapOf<Int, CropAccessory>()

        var isLoadingAccessories = false
            private set

        val pagesLoaded get() = accessoryPage.size

        var cropAccessory: CropAccessory?
            get() = SkyHanniMod.feature.hidden.savedCropAccessory
            private set(accessory) {
                SkyHanniMod.feature.hidden.savedCropAccessory = accessory
            }

        // Derived partially from NotEnoughUpdates/NotEnoughUpdates, ProfileViewer.Profile#getInventoryInfo
        private fun getCropAccessories(inventory: JsonElement?): MutableList<CropAccessory> {
            if (inventory == null) return mutableListOf()
            val cropAccessories = mutableListOf<CropAccessory>()
            val data = inventory.asJsonObject["data"]?.asString
            val accessoryBagItems = CompressedStreamTools.readCompressed(
                ByteArrayInputStream(Base64.getDecoder().decode(data))
            ).getTagList("i", 10)
            for (j in 0 until accessoryBagItems.tagCount()) {
                val itemStackTag = accessoryBagItems.getCompoundTagAt(j)
                if (!itemStackTag.hasKey("tag")) continue
                val itemTag = itemStackTag.getCompoundTag("tag")
                val itemName = NEUItems.getInternalNameOrNull(itemTag) ?: continue
                val itemAsCropAccessory = CropAccessory.getByName(itemName) ?: continue
                cropAccessories.add(itemAsCropAccessory)
            }
            return cropAccessories
        }
    }
}