aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/util/WarpUtil.kt
blob: 6783fa1119947ee25e12cf09cb891679fa19821b (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
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.annotations.Subscribe
import moe.nea.firmament.commands.thenExecute
import moe.nea.firmament.events.CommandEvent
import moe.nea.firmament.events.ProcessChatEvent
import moe.nea.firmament.repo.RepoManager
import moe.nea.firmament.util.data.Config
import moe.nea.firmament.util.data.ProfileSpecificDataHolder

object WarpUtil {
	val warps: Sequence<Islands.Warp>
		get() = RepoManager.neuRepo.constants.islands.warps
			.asSequence()
			.filter { it.warp !in ignoredWarps }

	val ignoredWarps = setOf("carnival", "")

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

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

	private var lastAttemptedWarp = ""
	private var lastWarpAttempt = TimeMark.farPast()
	fun findNearestWarp(island: SkyBlockIsland, pos: Position): Islands.Warp? {
		return warps.asSequence().filter { it.mode == island.locrawMode }.minByOrNull {
			if (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(island: SkyBlockIsland, pos: Position) {
		val nearestWarp = findNearestWarp(island, pos)
		if (nearestWarp == null) {
			MC.sendChat(Text.translatable("firmament.warp-util.no-warp-found", island.userFriendlyName))
			return
		}
		if (island == SBData.skyblockLocation
			&& sqrt(squaredDist(pos, nearestWarp)) > 1.1 * sqrt(squaredDist((MC.player ?: return).pos, nearestWarp))
		) {
			MC.sendChat(Text.translatable("firmament.warp-util.already-close", nearestWarp.warp))
			return
		}
		MC.sendChat(Text.translatable("firmament.warp-util.attempting-to-warp", nearestWarp.warp))
		lastWarpAttempt = TimeMark.now()
		lastAttemptedWarp = nearestWarp.warp
		MC.sendCommand("warp ${nearestWarp.warp}")
	}

	@Subscribe
	fun clearUnlockedWarpsCommand(event: CommandEvent.SubCommand) {
		event.subcommand("clearwarps") {
			thenExecute {
				DConfig.data?.excludedWarps?.clear()
				DConfig.markDirty()
				source.sendFeedback(Text.translatable("firmament.warp-util.clear-excluded"))
			}
		}
	}

	init {
		ProcessChatEvent.subscribe("WarpUtil:processChat") {
			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.stringifiedTranslatable("firmament.warp-util.mark-excluded", lastAttemptedWarp))
				lastWarpAttempt = TimeMark.farPast()
			}
			if (it.unformattedString.startsWith("You may now fast travel to")) {
				DConfig.data?.excludedWarps?.clear()
				DConfig.markDirty()
			}
		}
	}
}