aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/moe/nea/notenoughupdates/features/world/FairySouls.kt
blob: 9bd1a1fa5406d4a02595978e63790834c177cc5f (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
package moe.nea.notenoughupdates.features.world

import io.github.moulberry.repo.data.Coordinate
import kotlinx.serialization.Serializable
import kotlinx.serialization.serializer
import net.minecraft.util.math.BlockPos
import moe.nea.notenoughupdates.events.ServerChatLineReceivedEvent
import moe.nea.notenoughupdates.events.SkyblockServerUpdateEvent
import moe.nea.notenoughupdates.events.WorldRenderLastEvent
import moe.nea.notenoughupdates.features.NEUFeature
import moe.nea.notenoughupdates.repo.RepoManager
import moe.nea.notenoughupdates.util.MC
import moe.nea.notenoughupdates.util.SBData
import moe.nea.notenoughupdates.util.config.ProfileSpecificConfigHolder
import moe.nea.notenoughupdates.util.render.RenderBlockContext.Companion.renderBlocks
import moe.nea.notenoughupdates.util.unformattedString

val Coordinate.blockPos: BlockPos
    get() = BlockPos(x, y, z)

object FairySouls : NEUFeature,
    ProfileSpecificConfigHolder<FairySouls.Config>(serializer(), "fairy-souls.json", ::Config) {
    @Serializable
    data class Config(
        val foundSouls: MutableMap<String, MutableSet<Int>> = mutableMapOf()
    )

    override val name: String get() = "Fairy Souls"
    override val identifier: String get() = "fairy-souls"

    val playerReach = 5
    val playerReachSquared = playerReach * playerReach

    var currentLocationName: String? = null
    var currentLocationSouls: List<Coordinate> = emptyList()
    var currentMissingSouls: List<Coordinate> = emptyList()

    fun updateMissingSouls() {
        currentMissingSouls = emptyList()
        val c = config ?: return
        val fi = c.foundSouls[currentLocationName] ?: setOf()
        val cms = currentLocationSouls.toMutableList()
        fi.asSequence().sortedDescending().filter { it in cms.indices }.forEach { cms.removeAt(it) }
        currentMissingSouls = cms
    }

    fun updateWorldSouls() {
        currentLocationSouls = emptyList()
        val loc = currentLocationName ?: return
        currentLocationSouls = RepoManager.neuRepo.constants.fairySouls.soulLocations[loc] ?: return
    }

    fun findNearestClickableSoul(): Coordinate? {
        val player = MC.player ?: return null
        val pos = player.pos
        val location = SBData.skyblockLocation ?: return null
        val soulLocations: List<Coordinate> =
            RepoManager.neuRepo.constants.fairySouls.soulLocations[location] ?: return null
        return soulLocations
            .map { it to it.blockPos.getSquaredDistance(pos) }
            .filter { it.second < playerReachSquared }
            .minByOrNull { it.second }
            ?.first
    }

    private fun markNearestSoul() {
        val nearestSoul = findNearestClickableSoul() ?: return
        val c = config ?: return
        val loc = currentLocationName ?: return
        val idx = currentLocationSouls.indexOf(nearestSoul)
        c.foundSouls.computeIfAbsent(loc) { mutableSetOf() }.add(idx)
        markDirty()
        updateMissingSouls()
    }


    override fun onLoad() {
        SkyblockServerUpdateEvent.subscribe {
            currentLocationName = it.newLocraw?.skyblockLocation
            updateWorldSouls()
            updateMissingSouls()
        }
        ServerChatLineReceivedEvent.subscribe {
            when (it.text.unformattedString) {
                "You have already found that Fairy Soul!" -> {
                    markNearestSoul()
                }

                "SOUL! You found a Fairy Soul!" -> {
                    markNearestSoul()
                }
            }
        }
        WorldRenderLastEvent.subscribe {
            renderBlocks(it.camera) {
                color(1F, 1F, 0F, 0.8F)
                currentMissingSouls.forEach {
                    block(it.blockPos)
                }
            }
        }
    }
}