aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/moe/nea/firmament/util/WarpUtil.kt
blob: 25cfdb022f25442b6f6ce9c71325cb96240b7f45 (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
/*
 * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
 *
 * SPDX-License-Identifier: GPL-3.0-or-later
 */

package moe.nea.firmament.util

import io.github.moulberry.repo.constants.Islands
import io.github.moulberry.repo.constants.Islands.Warp
import kotlinx.serialization.Serializable
import kotlinx.serialization.serializer
import kotlin.math.sqrt
import kotlin.time.Duration.Companion.seconds
import net.minecraft.text.Text
import net.minecraft.util.math.Position
import moe.nea.firmament.events.ProcessChatEvent
import moe.nea.firmament.repo.RepoManager
import moe.nea.firmament.util.data.ProfileSpecificDataHolder

object WarpUtil {
    val warps: List<Islands.Warp> get() = RepoManager.neuRepo.constants.islands.warps

    @Serializable
    data class Data(
        val excludedWarps: MutableSet<String> = mutableSetOf(),
    )

    object DConfig : ProfileSpecificDataHolder<Data>(serializer(), "warp-util", ::Data)

    private var lastAttemptedWarp = ""
    private var lastWarpAttempt = TimeMark.farPast()
    fun findNearestWarp(locrawMode: String, pos: Position): Islands.Warp? {
        return warps.minByOrNull {
            if (locrawMode != it.mode || (DConfig.data?.excludedWarps?.contains(it.warp) == true)) {
                return@minByOrNull Double.MAX_VALUE
            } else {
                return@minByOrNull squaredDist(pos, it)
            }
        }
    }

    private fun squaredDist(pos: Position, warp: Warp): Double {
        val dx = pos.x - warp.x
        val dy = pos.y - warp.y
        val dz = pos.z - warp.z
        return dx * dx + dy * dy + dz * dz
    }

    fun teleportToNearestWarp(locrawMode: String, pos: Position) {
        val nearestWarp = findNearestWarp(locrawMode, pos) ?: return

        if (locrawMode == SBData.skyblockLocation
            && sqrt(squaredDist(pos, nearestWarp)) > 1.1 * sqrt(squaredDist((MC.player ?: return).pos, nearestWarp))
        ) {
            return
        }
        MC.sendServerCommand("warp ${nearestWarp.warp}")
    }

    init {
        ProcessChatEvent.subscribe {
            if (it.unformattedString == "You haven't unlocked this fast travel destination!"
                && lastWarpAttempt.passedTime() < 2.seconds
            ) {
                DConfig.data?.excludedWarps?.add(lastAttemptedWarp)
                DConfig.markDirty()
                MC.sendChat(Text.translatable("firmament.warp-util.mark-excluded", lastAttemptedWarp))
                lastWarpAttempt = TimeMark.farPast()
            }
            if (it.unformattedString == "You may now fast travel to") {
                DConfig.data?.excludedWarps?.clear()
                DConfig.markDirty()
            }
        }
    }
}