Fix up most of the remaining event handlers
[no changelog]
This commit is contained in:
@@ -8,8 +8,11 @@ package moe.nea.firmament.events.subscription
|
||||
|
||||
import moe.nea.firmament.events.FirmamentEvent
|
||||
import moe.nea.firmament.events.FirmamentEventBus
|
||||
import moe.nea.firmament.features.FirmamentFeature
|
||||
|
||||
interface SubscriptionOwner
|
||||
interface SubscriptionOwner {
|
||||
val delegateFeature: FirmamentFeature
|
||||
}
|
||||
|
||||
data class Subscription<T : FirmamentEvent>(
|
||||
val owner: SubscriptionOwner,
|
||||
|
||||
@@ -19,7 +19,9 @@ interface FirmamentFeature : SubscriptionOwner {
|
||||
set(value) {
|
||||
FeatureManager.setEnabled(identifier, value)
|
||||
}
|
||||
override val delegateFeature: FirmamentFeature
|
||||
get() = this
|
||||
val config: ManagedConfig? get() = null
|
||||
fun onLoad()
|
||||
fun onLoad() {}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
package moe.nea.firmament.features.chat
|
||||
|
||||
import com.mojang.brigadier.arguments.StringArgumentType.string
|
||||
import moe.nea.firmament.annotations.Subscribe
|
||||
import moe.nea.firmament.commands.get
|
||||
import moe.nea.firmament.commands.suggestsList
|
||||
import moe.nea.firmament.commands.thenArgument
|
||||
@@ -30,28 +31,28 @@ object AutoCompletions : FirmamentFeature {
|
||||
override val identifier: String
|
||||
get() = "auto-completions"
|
||||
|
||||
override fun onLoad() {
|
||||
MaskCommands.subscribe {
|
||||
if (TConfig.provideWarpTabCompletion) {
|
||||
it.mask("warp")
|
||||
}
|
||||
@Subscribe
|
||||
fun onMaskCommands(event: MaskCommands) {
|
||||
if (TConfig.provideWarpTabCompletion) {
|
||||
event.mask("warp")
|
||||
}
|
||||
CommandEvent.subscribe {
|
||||
if (TConfig.provideWarpTabCompletion) {
|
||||
it.deleteCommand("warp")
|
||||
it.register("warp") {
|
||||
thenArgument("to", string()) { toArg ->
|
||||
suggestsList {
|
||||
RepoManager.neuRepo.constants?.islands?.warps?.flatMap { listOf(it.warp) + it.aliases } ?: listOf()
|
||||
}
|
||||
thenExecute {
|
||||
val warpName = get(toArg)
|
||||
if (warpName == "is" && TConfig.replaceWarpIsByWarpIsland) {
|
||||
MC.sendServerCommand("warp island")
|
||||
} else {
|
||||
MC.sendServerCommand("warp ${warpName}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onCommandEvent(event: CommandEvent) {
|
||||
if (!TConfig.provideWarpTabCompletion) return
|
||||
event.deleteCommand("warp")
|
||||
event.register("warp") {
|
||||
thenArgument("to", string()) { toArg ->
|
||||
suggestsList {
|
||||
RepoManager.neuRepo.constants?.islands?.warps?.flatMap { listOf(it.warp) + it.aliases } ?: listOf()
|
||||
}
|
||||
thenExecute {
|
||||
val warpName = get(toArg)
|
||||
if (warpName == "is" && TConfig.replaceWarpIsByWarpIsland) {
|
||||
MC.sendServerCommand("warp island")
|
||||
} else {
|
||||
MC.sendServerCommand("warp $warpName")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
|
||||
package moe.nea.firmament.features.chat
|
||||
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.statement.*
|
||||
import io.ktor.utils.io.jvm.javaio.*
|
||||
import io.ktor.client.request.get
|
||||
import io.ktor.client.statement.bodyAsChannel
|
||||
import io.ktor.utils.io.jvm.javaio.toInputStream
|
||||
import java.net.URL
|
||||
import java.util.*
|
||||
import java.util.Collections
|
||||
import moe.nea.jarvis.api.Point
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
@@ -26,6 +26,7 @@ import net.minecraft.text.Text
|
||||
import net.minecraft.util.Formatting
|
||||
import net.minecraft.util.Identifier
|
||||
import moe.nea.firmament.Firmament
|
||||
import moe.nea.firmament.annotations.Subscribe
|
||||
import moe.nea.firmament.events.ModifyChatEvent
|
||||
import moe.nea.firmament.events.ScreenRenderPostEvent
|
||||
import moe.nea.firmament.features.FirmamentFeature
|
||||
@@ -96,69 +97,69 @@ object ChatLinks : FirmamentFeature {
|
||||
return (url.substringAfterLast('.').lowercase() in imageExtensions)
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
override fun onLoad() {
|
||||
ModifyChatEvent.subscribe {
|
||||
if (TConfig.enableLinks)
|
||||
it.replaceWith = it.replaceWith.transformEachRecursively { child ->
|
||||
val text = child.string
|
||||
if ("://" !in text) return@transformEachRecursively child
|
||||
val s = Text.empty().setStyle(child.style)
|
||||
var index = 0
|
||||
while (index < text.length) {
|
||||
val nextMatch = urlRegex.find(text, index)
|
||||
if (nextMatch == null) {
|
||||
s.append(Text.literal(text.substring(index, text.length)))
|
||||
break
|
||||
}
|
||||
val range = nextMatch.groups[0]!!.range
|
||||
val url = nextMatch.groupValues[0]
|
||||
s.append(Text.literal(text.substring(index, range.first)))
|
||||
s.append(
|
||||
Text.literal(url).setStyle(
|
||||
Style.EMPTY.withUnderline(true).withColor(
|
||||
Formatting.AQUA
|
||||
).withHoverEvent(HoverEvent(HoverEvent.Action.SHOW_TEXT, Text.literal(url)))
|
||||
.withClickEvent(ClickEvent(ClickEvent.Action.OPEN_URL, url))
|
||||
)
|
||||
)
|
||||
if (isImageUrl(url))
|
||||
tryCacheUrl(url)
|
||||
index = range.last + 1
|
||||
}
|
||||
s
|
||||
}
|
||||
}
|
||||
fun onRender(it: ScreenRenderPostEvent) {
|
||||
if (!TConfig.imageEnabled) return
|
||||
if (it.screen !is ChatScreen) return
|
||||
val hoveredComponent =
|
||||
MC.inGameHud.chatHud.getTextStyleAt(it.mouseX.toDouble(), it.mouseY.toDouble()) ?: return
|
||||
val hoverEvent = hoveredComponent.hoverEvent ?: return
|
||||
val value = hoverEvent.getValue(HoverEvent.Action.SHOW_TEXT) ?: return
|
||||
val url = urlRegex.matchEntire(value.unformattedString)?.groupValues?.get(0) ?: return
|
||||
if (!isImageUrl(url)) return
|
||||
val imageFuture = imageCache[url] ?: return
|
||||
if (!imageFuture.isCompleted) return
|
||||
val image = imageFuture.getCompleted() ?: return
|
||||
it.drawContext.matrices.push()
|
||||
val pos = TConfig.position
|
||||
pos.applyTransformations(it.drawContext.matrices)
|
||||
val scale = min(1F, min((9 * 20F) / image.height, (16 * 20F) / image.width))
|
||||
it.drawContext.matrices.scale(scale, scale, 1F)
|
||||
it.drawContext.drawTexture(
|
||||
image.texture,
|
||||
0,
|
||||
0,
|
||||
1F,
|
||||
1F,
|
||||
image.width,
|
||||
image.height,
|
||||
image.width,
|
||||
image.height,
|
||||
)
|
||||
it.drawContext.matrices.pop()
|
||||
}
|
||||
|
||||
ScreenRenderPostEvent.subscribe {
|
||||
if (!TConfig.imageEnabled) return@subscribe
|
||||
if (it.screen !is ChatScreen) return@subscribe
|
||||
val hoveredComponent =
|
||||
MC.inGameHud.chatHud.getTextStyleAt(it.mouseX.toDouble(), it.mouseY.toDouble()) ?: return@subscribe
|
||||
val hoverEvent = hoveredComponent.hoverEvent ?: return@subscribe
|
||||
val value = hoverEvent.getValue(HoverEvent.Action.SHOW_TEXT) ?: return@subscribe
|
||||
val url = urlRegex.matchEntire(value.unformattedString)?.groupValues?.get(0) ?: return@subscribe
|
||||
if (!isImageUrl(url)) return@subscribe
|
||||
val imageFuture = imageCache[url] ?: return@subscribe
|
||||
if (!imageFuture.isCompleted) return@subscribe
|
||||
val image = imageFuture.getCompleted() ?: return@subscribe
|
||||
it.drawContext.matrices.push()
|
||||
val pos = TConfig.position
|
||||
pos.applyTransformations(it.drawContext.matrices)
|
||||
val scale = min(1F, min((9 * 20F) / image.height, (16 * 20F) / image.width))
|
||||
it.drawContext.matrices.scale(scale, scale, 1F)
|
||||
it.drawContext.drawTexture(
|
||||
image.texture,
|
||||
0,
|
||||
0,
|
||||
1F,
|
||||
1F,
|
||||
image.width,
|
||||
image.height,
|
||||
image.width,
|
||||
image.height,
|
||||
)
|
||||
it.drawContext.matrices.pop()
|
||||
@Subscribe
|
||||
fun onModifyChat(it: ModifyChatEvent) {
|
||||
if (!TConfig.enableLinks) return
|
||||
it.replaceWith = it.replaceWith.transformEachRecursively { child ->
|
||||
val text = child.string
|
||||
if ("://" !in text) return@transformEachRecursively child
|
||||
val s = Text.empty().setStyle(child.style)
|
||||
var index = 0
|
||||
while (index < text.length) {
|
||||
val nextMatch = urlRegex.find(text, index)
|
||||
if (nextMatch == null) {
|
||||
s.append(Text.literal(text.substring(index, text.length)))
|
||||
break
|
||||
}
|
||||
val range = nextMatch.groups[0]!!.range
|
||||
val url = nextMatch.groupValues[0]
|
||||
s.append(Text.literal(text.substring(index, range.first)))
|
||||
s.append(
|
||||
Text.literal(url).setStyle(
|
||||
Style.EMPTY.withUnderline(true).withColor(
|
||||
Formatting.AQUA
|
||||
).withHoverEvent(HoverEvent(HoverEvent.Action.SHOW_TEXT, Text.literal(url)))
|
||||
.withClickEvent(ClickEvent(ClickEvent.Action.OPEN_URL, url))
|
||||
)
|
||||
)
|
||||
if (isImageUrl(url))
|
||||
tryCacheUrl(url)
|
||||
index = range.last + 1
|
||||
}
|
||||
s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ package moe.nea.firmament.features.chat
|
||||
|
||||
import com.mojang.brigadier.context.CommandContext
|
||||
import net.minecraft.text.Text
|
||||
import moe.nea.firmament.annotations.Subscribe
|
||||
import moe.nea.firmament.commands.DefaultSource
|
||||
import moe.nea.firmament.commands.RestArgumentType
|
||||
import moe.nea.firmament.commands.get
|
||||
@@ -34,28 +35,29 @@ object QuickCommands : FirmamentFeature {
|
||||
|
||||
val kuudraLevelNames = listOf("NORMAL", "HOT", "BURNING", "FIERY", "INFERNAL")
|
||||
val dungeonLevelNames = listOf("ONE", "TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN")
|
||||
override fun onLoad() {
|
||||
CommandEvent.subscribe {
|
||||
it.register("join") {
|
||||
thenArgument("what", RestArgumentType) { what ->
|
||||
thenExecute {
|
||||
val what = this[what]
|
||||
if (!SBData.isOnSkyblock) {
|
||||
MC.sendCommand("join $what")
|
||||
return@thenExecute
|
||||
}
|
||||
val joinName = getNameForFloor(what.replace(" ", "").lowercase())
|
||||
if (joinName == null) {
|
||||
source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.unknown", what))
|
||||
} else {
|
||||
source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.success", joinName))
|
||||
MC.sendCommand("joininstance $joinName")
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onCommands(it: CommandEvent) {
|
||||
it.register("join") {
|
||||
thenArgument("what", RestArgumentType) { what ->
|
||||
thenExecute {
|
||||
val what = this[what]
|
||||
if (!SBData.isOnSkyblock) {
|
||||
MC.sendCommand("join $what")
|
||||
return@thenExecute
|
||||
}
|
||||
val joinName = getNameForFloor(what.replace(" ", "").lowercase())
|
||||
if (joinName == null) {
|
||||
source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.unknown", what))
|
||||
} else {
|
||||
source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.success",
|
||||
joinName))
|
||||
MC.sendCommand("joininstance $joinName")
|
||||
}
|
||||
}
|
||||
thenExecute {
|
||||
source.sendFeedback(Text.translatable("firmament.quick-commands.join.explain"))
|
||||
}
|
||||
}
|
||||
thenExecute {
|
||||
source.sendFeedback(Text.translatable("firmament.quick-commands.join.explain"))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -70,7 +72,8 @@ object QuickCommands : FirmamentFeature {
|
||||
)
|
||||
}
|
||||
if (l !in kuudraLevelNames.indices) {
|
||||
source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.unknown-kuudra", kuudraLevel))
|
||||
source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.unknown-kuudra",
|
||||
kuudraLevel))
|
||||
return null
|
||||
}
|
||||
return "KUUDRA_${kuudraLevelNames[l]}"
|
||||
@@ -90,7 +93,8 @@ object QuickCommands : FirmamentFeature {
|
||||
return "CATACOMBS_ENTRANCE"
|
||||
}
|
||||
if (l !in dungeonLevelNames.indices) {
|
||||
source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.unknown-catacombs", kuudraLevel))
|
||||
source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.unknown-catacombs",
|
||||
kuudraLevel))
|
||||
return null
|
||||
}
|
||||
return "${if (masterLevel != null) "MASTER_" else ""}CATACOMBS_FLOOR_${dungeonLevelNames[l]}"
|
||||
|
||||
@@ -55,9 +55,5 @@ object DeveloperFeatures : FirmamentFeature {
|
||||
}
|
||||
return reloadFuture.thenCompose { client.reloadResources() }
|
||||
}
|
||||
|
||||
|
||||
override fun onLoad() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,9 +6,10 @@
|
||||
|
||||
package moe.nea.firmament.features.debug
|
||||
|
||||
import net.minecraft.text.Text
|
||||
import moe.nea.firmament.annotations.Subscribe
|
||||
import moe.nea.firmament.events.ModifyChatEvent
|
||||
import moe.nea.firmament.features.FirmamentFeature
|
||||
import net.minecraft.text.Text
|
||||
|
||||
|
||||
// In memorian Dulkir
|
||||
@@ -19,13 +20,12 @@ object MinorTrolling : FirmamentFeature {
|
||||
val trollers = listOf("nea89o", "lrg89")
|
||||
val t = "From(?: \\[[^\\]]+])? ([^:]+): (.*)".toRegex()
|
||||
|
||||
override fun onLoad() {
|
||||
ModifyChatEvent.subscribe {
|
||||
val m = t.matchEntire(it.unformattedString) ?: return@subscribe
|
||||
val (_, name, text) = m.groupValues
|
||||
if (name !in trollers) return@subscribe
|
||||
if (!text.startsWith("c:")) return@subscribe
|
||||
it.replaceWith = Text.literal(text.substring(2).replace("&", "§"))
|
||||
}
|
||||
@Subscribe
|
||||
fun onTroll(it: ModifyChatEvent) {
|
||||
val m = t.matchEntire(it.unformattedString) ?: return
|
||||
val (_, name, text) = m.groupValues
|
||||
if (name !in trollers) return
|
||||
if (!text.startsWith("c:")) return
|
||||
it.replaceWith = Text.literal(text.substring(2).replace("&", "§"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import net.minecraft.item.Items
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.hit.BlockHitResult
|
||||
import net.minecraft.util.hit.HitResult
|
||||
import moe.nea.firmament.annotations.Subscribe
|
||||
import moe.nea.firmament.events.CustomItemModelEvent
|
||||
import moe.nea.firmament.events.HandledScreenKeyPressedEvent
|
||||
import moe.nea.firmament.events.ItemTooltipEvent
|
||||
@@ -54,42 +55,6 @@ object PowerUserTools : FirmamentFeature {
|
||||
var lastCopiedStackViewTime = false
|
||||
|
||||
override fun onLoad() {
|
||||
ItemTooltipEvent.subscribe {
|
||||
if (TConfig.showItemIds) {
|
||||
val id = it.stack.skyBlockId ?: return@subscribe
|
||||
it.lines.add(Text.stringifiedTranslatable("firmament.tooltip.skyblockid", id.neuItem))
|
||||
}
|
||||
val (item, text) = lastCopiedStack ?: return@subscribe
|
||||
if (!ItemStack.areEqual(item, it.stack)) {
|
||||
lastCopiedStack = null
|
||||
return@subscribe
|
||||
}
|
||||
lastCopiedStackViewTime = true
|
||||
it.lines.add(text)
|
||||
}
|
||||
WorldKeyboardEvent.subscribe {
|
||||
if (it.matches(TConfig.copySkullTexture)) {
|
||||
val p = MC.camera ?: return@subscribe
|
||||
val blockHit = p.raycast(20.0, 0.0f, false) ?: return@subscribe
|
||||
if (blockHit.type != HitResult.Type.BLOCK || blockHit !is BlockHitResult) {
|
||||
MC.sendChat(Text.translatable("firmament.tooltip.copied.skull.fail"))
|
||||
return@subscribe
|
||||
}
|
||||
val blockAt = p.world.getBlockState(blockHit.blockPos)?.block
|
||||
val entity = p.world.getBlockEntity(blockHit.blockPos)
|
||||
if (blockAt !is SkullBlock || entity !is SkullBlockEntity || entity.owner == null) {
|
||||
MC.sendChat(Text.translatable("firmament.tooltip.copied.skull.fail"))
|
||||
return@subscribe
|
||||
}
|
||||
val id = CustomSkyBlockTextures.getSkullTexture(entity.owner!!)
|
||||
if (id == null) {
|
||||
MC.sendChat(Text.translatable("firmament.tooltip.copied.skull.fail"))
|
||||
} else {
|
||||
ClipboardUtils.setTextContent(id.toString())
|
||||
MC.sendChat(Text.stringifiedTranslatable("firmament.tooltip.copied.skull", id.toString()))
|
||||
}
|
||||
}
|
||||
}
|
||||
TickEvent.subscribe {
|
||||
if (!lastCopiedStackViewTime)
|
||||
lastCopiedStack = null
|
||||
@@ -98,57 +63,99 @@ object PowerUserTools : FirmamentFeature {
|
||||
ScreenChangeEvent.subscribe {
|
||||
lastCopiedStack = null
|
||||
}
|
||||
HandledScreenKeyPressedEvent.subscribe {
|
||||
if (it.screen !is AccessorHandledScreen) return@subscribe
|
||||
val item = it.screen.focusedItemStack ?: return@subscribe
|
||||
if (it.matches(TConfig.copyItemId)) {
|
||||
val sbId = item.skyBlockId
|
||||
if (sbId == null) {
|
||||
lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skyblockid.fail"))
|
||||
return@subscribe
|
||||
}
|
||||
ClipboardUtils.setTextContent(sbId.neuItem)
|
||||
lastCopiedStack =
|
||||
Pair(item, Text.stringifiedTranslatable("firmament.tooltip.copied.skyblockid", sbId.neuItem))
|
||||
} else if (it.matches(TConfig.copyTexturePackId)) {
|
||||
val model = CustomItemModelEvent.getModelIdentifier(item)
|
||||
if (model == null) {
|
||||
lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.modelid.fail"))
|
||||
return@subscribe
|
||||
}
|
||||
ClipboardUtils.setTextContent(model.toString())
|
||||
lastCopiedStack =
|
||||
Pair(item, Text.stringifiedTranslatable("firmament.tooltip.copied.modelid", model.toString()))
|
||||
} else if (it.matches(TConfig.copyNbtData)) {
|
||||
// TODO: copy full nbt
|
||||
val nbt = item.get(DataComponentTypes.CUSTOM_DATA)?.nbt?.toString() ?: "<empty>"
|
||||
ClipboardUtils.setTextContent(nbt)
|
||||
lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.nbt"))
|
||||
} else if (it.matches(TConfig.copySkullTexture)) {
|
||||
if (item.item != Items.PLAYER_HEAD) {
|
||||
lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skull-id.fail.no-skull"))
|
||||
return@subscribe
|
||||
}
|
||||
val profile = item.get(DataComponentTypes.PROFILE)
|
||||
if (profile == null) {
|
||||
lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skull-id.fail.no-profile"))
|
||||
return@subscribe
|
||||
}
|
||||
val skullTexture = CustomSkyBlockTextures.getSkullTexture(profile)
|
||||
if (skullTexture == null) {
|
||||
lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skull-id.fail.no-texture"))
|
||||
return@subscribe
|
||||
}
|
||||
ClipboardUtils.setTextContent(skullTexture.toString())
|
||||
lastCopiedStack =
|
||||
Pair(
|
||||
item,
|
||||
Text.stringifiedTranslatable("firmament.tooltip.copied.skull-id", skullTexture.toString())
|
||||
)
|
||||
println("Copied skull id: $skullTexture")
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun copyInventoryInfo(it: HandledScreenKeyPressedEvent) {
|
||||
if (it.screen !is AccessorHandledScreen) return
|
||||
val item = it.screen.focusedItemStack ?: return
|
||||
if (it.matches(TConfig.copyItemId)) {
|
||||
val sbId = item.skyBlockId
|
||||
if (sbId == null) {
|
||||
lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skyblockid.fail"))
|
||||
return
|
||||
}
|
||||
ClipboardUtils.setTextContent(sbId.neuItem)
|
||||
lastCopiedStack =
|
||||
Pair(item, Text.stringifiedTranslatable("firmament.tooltip.copied.skyblockid", sbId.neuItem))
|
||||
} else if (it.matches(TConfig.copyTexturePackId)) {
|
||||
val model = CustomItemModelEvent.getModelIdentifier(item)
|
||||
if (model == null) {
|
||||
lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.modelid.fail"))
|
||||
return
|
||||
}
|
||||
ClipboardUtils.setTextContent(model.toString())
|
||||
lastCopiedStack =
|
||||
Pair(item, Text.stringifiedTranslatable("firmament.tooltip.copied.modelid", model.toString()))
|
||||
} else if (it.matches(TConfig.copyNbtData)) {
|
||||
// TODO: copy full nbt
|
||||
val nbt = item.get(DataComponentTypes.CUSTOM_DATA)?.nbt?.toString() ?: "<empty>"
|
||||
ClipboardUtils.setTextContent(nbt)
|
||||
lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.nbt"))
|
||||
} else if (it.matches(TConfig.copySkullTexture)) {
|
||||
if (item.item != Items.PLAYER_HEAD) {
|
||||
lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skull-id.fail.no-skull"))
|
||||
return
|
||||
}
|
||||
val profile = item.get(DataComponentTypes.PROFILE)
|
||||
if (profile == null) {
|
||||
lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skull-id.fail.no-profile"))
|
||||
return
|
||||
}
|
||||
val skullTexture = CustomSkyBlockTextures.getSkullTexture(profile)
|
||||
if (skullTexture == null) {
|
||||
lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skull-id.fail.no-texture"))
|
||||
return
|
||||
}
|
||||
ClipboardUtils.setTextContent(skullTexture.toString())
|
||||
lastCopiedStack =
|
||||
Pair(
|
||||
item,
|
||||
Text.stringifiedTranslatable("firmament.tooltip.copied.skull-id", skullTexture.toString())
|
||||
)
|
||||
println("Copied skull id: $skullTexture")
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onCopyWorldInfo(it: WorldKeyboardEvent) {
|
||||
if (it.matches(TConfig.copySkullTexture)) {
|
||||
val p = MC.camera ?: return
|
||||
val blockHit = p.raycast(20.0, 0.0f, false) ?: return
|
||||
if (blockHit.type != HitResult.Type.BLOCK || blockHit !is BlockHitResult) {
|
||||
MC.sendChat(Text.translatable("firmament.tooltip.copied.skull.fail"))
|
||||
return
|
||||
}
|
||||
val blockAt = p.world.getBlockState(blockHit.blockPos)?.block
|
||||
val entity = p.world.getBlockEntity(blockHit.blockPos)
|
||||
if (blockAt !is SkullBlock || entity !is SkullBlockEntity || entity.owner == null) {
|
||||
MC.sendChat(Text.translatable("firmament.tooltip.copied.skull.fail"))
|
||||
return
|
||||
}
|
||||
val id = CustomSkyBlockTextures.getSkullTexture(entity.owner!!)
|
||||
if (id == null) {
|
||||
MC.sendChat(Text.translatable("firmament.tooltip.copied.skull.fail"))
|
||||
} else {
|
||||
ClipboardUtils.setTextContent(id.toString())
|
||||
MC.sendChat(Text.stringifiedTranslatable("firmament.tooltip.copied.skull", id.toString()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun addItemId(it: ItemTooltipEvent) {
|
||||
if (TConfig.showItemIds) {
|
||||
val id = it.stack.skyBlockId ?: return
|
||||
it.lines.add(Text.stringifiedTranslatable("firmament.tooltip.skyblockid", id.neuItem))
|
||||
}
|
||||
val (item, text) = lastCopiedStack ?: return
|
||||
if (!ItemStack.areEqual(item, it.stack)) {
|
||||
lastCopiedStack = null
|
||||
return
|
||||
}
|
||||
lastCopiedStackViewTime = true
|
||||
it.lines.add(text)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -10,17 +10,20 @@ import kotlin.time.Duration.Companion.seconds
|
||||
import net.minecraft.particle.ParticleTypes
|
||||
import net.minecraft.sound.SoundEvents
|
||||
import net.minecraft.util.math.Vec3d
|
||||
import moe.nea.firmament.annotations.Subscribe
|
||||
import moe.nea.firmament.events.ParticleSpawnEvent
|
||||
import moe.nea.firmament.events.SoundReceiveEvent
|
||||
import moe.nea.firmament.events.WorldKeyboardEvent
|
||||
import moe.nea.firmament.events.WorldReadyEvent
|
||||
import moe.nea.firmament.events.WorldRenderLastEvent
|
||||
import moe.nea.firmament.events.subscription.SubscriptionOwner
|
||||
import moe.nea.firmament.features.FirmamentFeature
|
||||
import moe.nea.firmament.util.SBData
|
||||
import moe.nea.firmament.util.TimeMark
|
||||
import moe.nea.firmament.util.WarpUtil
|
||||
import moe.nea.firmament.util.render.RenderInWorldContext
|
||||
|
||||
object AncestralSpadeSolver {
|
||||
object AncestralSpadeSolver : SubscriptionOwner {
|
||||
var lastDing = TimeMark.farPast()
|
||||
private set
|
||||
private val pitches = mutableListOf<Float>()
|
||||
@@ -33,6 +36,7 @@ object AncestralSpadeSolver {
|
||||
fun isEnabled() =
|
||||
DianaWaypoints.TConfig.ancestralSpadeSolver && SBData.skyblockLocation == "hub"
|
||||
|
||||
@Subscribe
|
||||
fun onKeyBind(event: WorldKeyboardEvent) {
|
||||
if (!isEnabled()) return
|
||||
if (!event.matches(DianaWaypoints.TConfig.ancestralSpadeTeleport)) return
|
||||
@@ -42,6 +46,7 @@ object AncestralSpadeSolver {
|
||||
lastTeleportAttempt = TimeMark.now()
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onParticleSpawn(event: ParticleSpawnEvent) {
|
||||
if (!isEnabled()) return
|
||||
if (event.particleEffect != ParticleTypes.DRIPPING_LAVA) return
|
||||
@@ -53,6 +58,7 @@ object AncestralSpadeSolver {
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onPlaySound(event: SoundReceiveEvent) {
|
||||
if (!isEnabled()) return
|
||||
if (!SoundEvents.BLOCK_NOTE_BLOCK_HARP.matchesId(event.sound.value().id)) return
|
||||
@@ -92,6 +98,7 @@ object AncestralSpadeSolver {
|
||||
nextGuess = event.position.add(lastParticleDirection.multiply(soundDistanceEstimate))
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onWorldRender(event: WorldRenderLastEvent) {
|
||||
if (!isEnabled()) return
|
||||
RenderInWorldContext.renderInWorld(event) {
|
||||
@@ -108,6 +115,7 @@ object AncestralSpadeSolver {
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onSwapWorld(event: WorldReadyEvent) {
|
||||
nextGuess = null
|
||||
particlePositions.clear()
|
||||
@@ -115,4 +123,7 @@ object AncestralSpadeSolver {
|
||||
lastDing = TimeMark.farPast()
|
||||
}
|
||||
|
||||
override val delegateFeature: FirmamentFeature
|
||||
get() = DianaWaypoints
|
||||
|
||||
}
|
||||
|
||||
@@ -28,23 +28,12 @@ object DianaWaypoints : FirmamentFeature {
|
||||
}
|
||||
|
||||
override fun onLoad() {
|
||||
ParticleSpawnEvent.subscribe(NearbyBurrowsSolver::onParticles)
|
||||
WorldReadyEvent.subscribe(NearbyBurrowsSolver::onSwapWorld)
|
||||
WorldRenderLastEvent.subscribe(NearbyBurrowsSolver::onRender)
|
||||
UseBlockEvent.subscribe {
|
||||
NearbyBurrowsSolver.onBlockClick(it.hitResult.blockPos)
|
||||
}
|
||||
AttackBlockEvent.subscribe {
|
||||
NearbyBurrowsSolver.onBlockClick(it.blockPos)
|
||||
}
|
||||
ProcessChatEvent.subscribe(NearbyBurrowsSolver::onChatEvent)
|
||||
|
||||
|
||||
WorldKeyboardEvent.subscribe(AncestralSpadeSolver::onKeyBind)
|
||||
ParticleSpawnEvent.subscribe(AncestralSpadeSolver::onParticleSpawn)
|
||||
SoundReceiveEvent.subscribe(AncestralSpadeSolver::onPlaySound)
|
||||
WorldRenderLastEvent.subscribe(AncestralSpadeSolver::onWorldRender)
|
||||
WorldReadyEvent.subscribe(AncestralSpadeSolver::onSwapWorld)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,15 +11,18 @@ import net.minecraft.particle.ParticleTypes
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.util.math.MathHelper
|
||||
import net.minecraft.util.math.Position
|
||||
import moe.nea.firmament.annotations.Subscribe
|
||||
import moe.nea.firmament.events.ParticleSpawnEvent
|
||||
import moe.nea.firmament.events.ProcessChatEvent
|
||||
import moe.nea.firmament.events.WorldReadyEvent
|
||||
import moe.nea.firmament.events.WorldRenderLastEvent
|
||||
import moe.nea.firmament.events.subscription.SubscriptionOwner
|
||||
import moe.nea.firmament.features.FirmamentFeature
|
||||
import moe.nea.firmament.util.TimeMark
|
||||
import moe.nea.firmament.util.mutableMapWithMaxSize
|
||||
import moe.nea.firmament.util.render.RenderInWorldContext.Companion.renderInWorld
|
||||
|
||||
object NearbyBurrowsSolver {
|
||||
object NearbyBurrowsSolver : SubscriptionOwner {
|
||||
|
||||
|
||||
private val recentlyDugBurrows: MutableMap<BlockPos, TimeMark> = mutableMapWithMaxSize(20)
|
||||
@@ -32,6 +35,7 @@ object NearbyBurrowsSolver {
|
||||
|
||||
val burrows = mutableMapOf<BlockPos, BurrowType>()
|
||||
|
||||
@Subscribe
|
||||
fun onChatEvent(event: ProcessChatEvent) {
|
||||
val lastClickedBurrow = lastBlockClick ?: return
|
||||
if (event.unformattedString.startsWith("You dug out a Griffin Burrow!") ||
|
||||
@@ -62,6 +66,7 @@ object NearbyBurrowsSolver {
|
||||
recentEnchantParticles[blockPos] = TimeMark.now()
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onParticles(event: ParticleSpawnEvent) {
|
||||
if (!DianaWaypoints.TConfig.nearbyWaypoints) return
|
||||
|
||||
@@ -106,6 +111,7 @@ object NearbyBurrowsSolver {
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onRender(event: WorldRenderLastEvent) {
|
||||
if (!DianaWaypoints.TConfig.nearbyWaypoints) return
|
||||
renderInWorld(event) {
|
||||
@@ -120,6 +126,7 @@ object NearbyBurrowsSolver {
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onSwapWorld(worldReadyEvent: WorldReadyEvent) {
|
||||
burrows.clear()
|
||||
recentEnchantParticles.clear()
|
||||
@@ -132,6 +139,9 @@ object NearbyBurrowsSolver {
|
||||
burrows.remove(blockPos)
|
||||
lastBlockClick = blockPos
|
||||
}
|
||||
|
||||
override val delegateFeature: FirmamentFeature
|
||||
get() = DianaWaypoints
|
||||
}
|
||||
|
||||
fun Position.toBlockPos(): BlockPos {
|
||||
|
||||
@@ -10,6 +10,7 @@ import net.fabricmc.loader.api.FabricLoader
|
||||
import net.superkat.explosiveenhancement.api.ExplosiveApi
|
||||
import net.minecraft.particle.ParticleTypes
|
||||
import net.minecraft.util.math.Vec3d
|
||||
import moe.nea.firmament.annotations.Subscribe
|
||||
import moe.nea.firmament.events.ParticleSpawnEvent
|
||||
import moe.nea.firmament.features.FirmamentFeature
|
||||
import moe.nea.firmament.gui.config.ManagedConfig
|
||||
@@ -41,15 +42,14 @@ object CompatibliltyFeatures : FirmamentFeature {
|
||||
ExplosiveApiWrapperImpl()
|
||||
} else null
|
||||
|
||||
override fun onLoad() {
|
||||
ParticleSpawnEvent.subscribe {
|
||||
if (TConfig.enhancedExplosions &&
|
||||
it.particleEffect.type == ParticleTypes.EXPLOSION_EMITTER &&
|
||||
explosiveApiWrapper != null
|
||||
) {
|
||||
it.cancel()
|
||||
explosiveApiWrapper.spawnParticle(it.position, 2F)
|
||||
}
|
||||
@Subscribe
|
||||
fun onExplosion(it: ParticleSpawnEvent) {
|
||||
if (TConfig.enhancedExplosions &&
|
||||
it.particleEffect.type == ParticleTypes.EXPLOSION_EMITTER &&
|
||||
explosiveApiWrapper != null
|
||||
) {
|
||||
it.cancel()
|
||||
explosiveApiWrapper.spawnParticle(it.position, 2F)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import net.minecraft.client.option.KeyBinding
|
||||
import net.minecraft.entity.player.PlayerEntity
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Arm
|
||||
import moe.nea.firmament.annotations.Subscribe
|
||||
import moe.nea.firmament.events.HudRenderEvent
|
||||
import moe.nea.firmament.events.WorldKeyboardEvent
|
||||
import moe.nea.firmament.features.FirmamentFeature
|
||||
@@ -50,27 +51,28 @@ object Fixes : FirmamentFeature {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onLoad() {
|
||||
WorldKeyboardEvent.subscribe {
|
||||
if (it.matches(TConfig.autoSprintKeyBinding)) {
|
||||
TConfig.autoSprint = !TConfig.autoSprint
|
||||
}
|
||||
}
|
||||
HudRenderEvent.subscribe {
|
||||
if (!TConfig.autoSprintKeyBinding.isBound) return@subscribe
|
||||
it.context.matrices.push()
|
||||
TConfig.autoSprintHud.applyTransformations(it.context.matrices)
|
||||
it.context.drawText(
|
||||
MC.font, Text.translatable(
|
||||
if (TConfig.autoSprint)
|
||||
"firmament.fixes.auto-sprint.on"
|
||||
else if (MC.player?.isSprinting == true)
|
||||
"firmament.fixes.auto-sprint.sprinting"
|
||||
else
|
||||
"firmament.fixes.auto-sprint.not-sprinting"
|
||||
), 0, 0, -1, false
|
||||
)
|
||||
it.context.matrices.pop()
|
||||
@Subscribe
|
||||
fun onRenderHud(it: HudRenderEvent) {
|
||||
if (!TConfig.autoSprintKeyBinding.isBound) return
|
||||
it.context.matrices.push()
|
||||
TConfig.autoSprintHud.applyTransformations(it.context.matrices)
|
||||
it.context.drawText(
|
||||
MC.font, Text.translatable(
|
||||
if (TConfig.autoSprint)
|
||||
"firmament.fixes.auto-sprint.on"
|
||||
else if (MC.player?.isSprinting == true)
|
||||
"firmament.fixes.auto-sprint.sprinting"
|
||||
else
|
||||
"firmament.fixes.auto-sprint.not-sprinting"
|
||||
), 0, 0, -1, false
|
||||
)
|
||||
it.context.matrices.pop()
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onWorldKeyboard(it: WorldKeyboardEvent) {
|
||||
if (it.matches(TConfig.autoSprintKeyBinding)) {
|
||||
TConfig.autoSprint = !TConfig.autoSprint
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,11 +9,12 @@ package moe.nea.firmament.features.inventory
|
||||
import net.minecraft.client.gui.screen.ingame.GenericContainerScreen
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.util.Formatting
|
||||
import moe.nea.firmament.annotations.Subscribe
|
||||
import moe.nea.firmament.events.SlotRenderEvents
|
||||
import moe.nea.firmament.features.FirmamentFeature
|
||||
import moe.nea.firmament.rei.recipes.SBCraftingRecipe
|
||||
import moe.nea.firmament.rei.FirmamentReiPlugin.Companion.asItemEntry
|
||||
import moe.nea.firmament.rei.SBItemEntryDefinition
|
||||
import moe.nea.firmament.rei.recipes.SBCraftingRecipe
|
||||
import moe.nea.firmament.util.MC
|
||||
|
||||
object CraftingOverlay : FirmamentFeature {
|
||||
@@ -35,36 +36,35 @@ object CraftingOverlay : FirmamentFeature {
|
||||
override val identifier: String
|
||||
get() = "crafting-overlay"
|
||||
|
||||
override fun onLoad() {
|
||||
SlotRenderEvents.After.subscribe { event ->
|
||||
val slot = event.slot
|
||||
val recipe = this.recipe ?: return@subscribe
|
||||
if (slot.inventory != screen?.screenHandler?.inventory) return@subscribe
|
||||
val recipeIndex = craftingOverlayIndices.indexOf(slot.index)
|
||||
if (recipeIndex < 0) return@subscribe
|
||||
val expectedItem = recipe.neuRecipe.inputs[recipeIndex]
|
||||
val actualStack = slot.stack ?: ItemStack.EMPTY!!
|
||||
val actualEntry = SBItemEntryDefinition.getEntry(actualStack).value
|
||||
if ((actualEntry.skyblockId.neuItem != expectedItem.itemId || actualEntry.stackSize < expectedItem.amount) && expectedItem.amount.toInt() != 0) {
|
||||
event.context.fill(
|
||||
event.slot.x,
|
||||
event.slot.y,
|
||||
event.slot.x + 16,
|
||||
event.slot.y + 16,
|
||||
0x80FF0000.toInt()
|
||||
)
|
||||
}
|
||||
if (!slot.hasStack()) {
|
||||
val itemStack = SBItemEntryDefinition.getEntry(expectedItem).asItemEntry().value
|
||||
event.context.drawItem(itemStack, event.slot.x, event.slot.y)
|
||||
event.context.drawItemInSlot(
|
||||
MC.font,
|
||||
itemStack,
|
||||
event.slot.x,
|
||||
event.slot.y,
|
||||
"${Formatting.RED}${expectedItem.amount.toInt()}"
|
||||
)
|
||||
}
|
||||
@Subscribe
|
||||
fun onSlotRender(event: SlotRenderEvents.After) {
|
||||
val slot = event.slot
|
||||
val recipe = this.recipe ?: return
|
||||
if (slot.inventory != screen?.screenHandler?.inventory) return
|
||||
val recipeIndex = craftingOverlayIndices.indexOf(slot.index)
|
||||
if (recipeIndex < 0) return
|
||||
val expectedItem = recipe.neuRecipe.inputs[recipeIndex]
|
||||
val actualStack = slot.stack ?: ItemStack.EMPTY!!
|
||||
val actualEntry = SBItemEntryDefinition.getEntry(actualStack).value
|
||||
if ((actualEntry.skyblockId.neuItem != expectedItem.itemId || actualEntry.stackSize < expectedItem.amount) && expectedItem.amount.toInt() != 0) {
|
||||
event.context.fill(
|
||||
event.slot.x,
|
||||
event.slot.y,
|
||||
event.slot.x + 16,
|
||||
event.slot.y + 16,
|
||||
0x80FF0000.toInt()
|
||||
)
|
||||
}
|
||||
if (!slot.hasStack()) {
|
||||
val itemStack = SBItemEntryDefinition.getEntry(expectedItem).asItemEntry().value
|
||||
event.context.drawItem(itemStack, event.slot.x, event.slot.y)
|
||||
event.context.drawItemInSlot(
|
||||
MC.font,
|
||||
itemStack,
|
||||
event.slot.x,
|
||||
event.slot.y,
|
||||
"${Formatting.RED}${expectedItem.amount.toInt()}"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import net.minecraft.client.gui.DrawContext
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.util.Formatting
|
||||
import net.minecraft.util.Identifier
|
||||
import moe.nea.firmament.annotations.Subscribe
|
||||
import moe.nea.firmament.events.HotbarItemRenderEvent
|
||||
import moe.nea.firmament.events.SlotRenderEvents
|
||||
import moe.nea.firmament.features.FirmamentFeature
|
||||
@@ -65,16 +66,18 @@ object ItemRarityCosmetics : FirmamentFeature {
|
||||
)
|
||||
}
|
||||
|
||||
override fun onLoad() {
|
||||
HotbarItemRenderEvent.subscribe {
|
||||
if (!TConfig.showItemRarityInHotbar) return@subscribe
|
||||
val stack = it.item
|
||||
drawItemStackRarity(it.context, it.x, it.y, stack)
|
||||
}
|
||||
SlotRenderEvents.Before.subscribe {
|
||||
if (!TConfig.showItemRarityBackground) return@subscribe
|
||||
val stack = it.slot.stack ?: return@subscribe
|
||||
drawItemStackRarity(it.context, it.slot.x, it.slot.y, stack)
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onRenderSlot(it: SlotRenderEvents.Before) {
|
||||
if (!TConfig.showItemRarityBackground) return
|
||||
val stack = it.slot.stack ?: return
|
||||
drawItemStackRarity(it.context, it.slot.x, it.slot.y, stack)
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onRenderHotbarItem(it: HotbarItemRenderEvent) {
|
||||
if (!TConfig.showItemRarityInHotbar) return
|
||||
val stack = it.item
|
||||
drawItemStackRarity(it.context, it.x, it.y, stack)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,11 +27,8 @@ object PriceData : FirmamentFeature {
|
||||
|
||||
override val config get() = TConfig
|
||||
|
||||
override fun onLoad() {
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun function(it: ItemTooltipEvent) {
|
||||
fun onItemTooltip(it: ItemTooltipEvent) {
|
||||
if (!TConfig.tooltipEnabled && !TConfig.enableKeybinding.isPressed()) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -27,10 +27,6 @@ object SaveCursorPosition : FirmamentFeature {
|
||||
override val config: TConfig
|
||||
get() = TConfig
|
||||
|
||||
override fun onLoad() {
|
||||
|
||||
}
|
||||
|
||||
var savedPositionedP1: Pair<Double, Double>? = null
|
||||
var savedPosition: SavedPosition? = null
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
package moe.nea.firmament.features.inventory
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem
|
||||
import java.util.*
|
||||
import java.util.UUID
|
||||
import org.lwjgl.glfw.GLFW
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.UseSerializers
|
||||
@@ -18,6 +18,7 @@ import kotlinx.serialization.serializer
|
||||
import net.minecraft.client.gui.screen.ingame.HandledScreen
|
||||
import net.minecraft.entity.player.PlayerInventory
|
||||
import net.minecraft.screen.GenericContainerScreenHandler
|
||||
import net.minecraft.screen.slot.Slot
|
||||
import net.minecraft.screen.slot.SlotActionType
|
||||
import net.minecraft.util.Identifier
|
||||
import moe.nea.firmament.annotations.Subscribe
|
||||
@@ -96,81 +97,89 @@ object SlotLocking : FirmamentFeature {
|
||||
return (lore.lastOrNull() ?: return false).unformattedString == "Click to buyback!"
|
||||
}
|
||||
|
||||
override fun onLoad() {
|
||||
HandledScreenKeyPressedEvent.subscribe {
|
||||
if (!it.matches(TConfig.lockSlot)) return@subscribe
|
||||
val inventory = MC.handledScreen ?: return@subscribe
|
||||
inventory as AccessorHandledScreen
|
||||
|
||||
val slot = inventory.focusedSlot_Firmament ?: return@subscribe
|
||||
val lockedSlots = lockedSlots ?: return@subscribe
|
||||
if (slot.inventory is PlayerInventory) {
|
||||
if (slot.index in lockedSlots) {
|
||||
lockedSlots.remove(slot.index)
|
||||
} else {
|
||||
lockedSlots.add(slot.index)
|
||||
}
|
||||
DConfig.markDirty()
|
||||
CommonSoundEffects.playSuccess()
|
||||
}
|
||||
@Subscribe
|
||||
fun onSalvageProtect(event: IsSlotProtectedEvent) {
|
||||
if (event.slot == null) return
|
||||
if (!event.slot.hasStack()) return
|
||||
if (event.slot.stack.displayNameAccordingToNbt?.unformattedString != "Salvage Items") return
|
||||
val inv = event.slot.inventory
|
||||
var anyBlocked = false
|
||||
for (i in 0 until event.slot.index) {
|
||||
val stack = inv.getStack(i)
|
||||
if (IsSlotProtectedEvent.shouldBlockInteraction(null, SlotActionType.THROW, stack))
|
||||
anyBlocked = true
|
||||
}
|
||||
HandledScreenKeyPressedEvent.subscribe {
|
||||
if (!it.matches(TConfig.lockUUID)) return@subscribe
|
||||
val inventory = MC.handledScreen ?: return@subscribe
|
||||
inventory as AccessorHandledScreen
|
||||
|
||||
val slot = inventory.focusedSlot_Firmament ?: return@subscribe
|
||||
val stack = slot.stack ?: return@subscribe
|
||||
val uuid = stack.skyblockUUID ?: return@subscribe
|
||||
val lockedUUIDs = lockedUUIDs ?: return@subscribe
|
||||
if (uuid in lockedUUIDs) {
|
||||
lockedUUIDs.remove(uuid)
|
||||
} else {
|
||||
lockedUUIDs.add(uuid)
|
||||
}
|
||||
DConfig.markDirty()
|
||||
CommonSoundEffects.playSuccess()
|
||||
}
|
||||
IsSlotProtectedEvent.subscribe {
|
||||
if (it.slot != null && it.slot.inventory is PlayerInventory && it.slot.index in (lockedSlots ?: setOf())) {
|
||||
it.protect()
|
||||
}
|
||||
}
|
||||
IsSlotProtectedEvent.subscribe { event ->
|
||||
val doesNotDeleteItem = event.actionType == SlotActionType.SWAP
|
||||
|| event.actionType == SlotActionType.PICKUP
|
||||
|| event.actionType == SlotActionType.QUICK_MOVE
|
||||
|| event.actionType == SlotActionType.QUICK_CRAFT
|
||||
|| event.actionType == SlotActionType.CLONE
|
||||
|| event.actionType == SlotActionType.PICKUP_ALL
|
||||
val isSellOrTradeScreen =
|
||||
isNpcShop(MC.handledScreen) || isTradeScreen(MC.handledScreen) || isSalvageScreen(MC.handledScreen)
|
||||
if (!isSellOrTradeScreen && doesNotDeleteItem) return@subscribe
|
||||
val stack = event.itemStack ?: return@subscribe
|
||||
val uuid = stack.skyblockUUID ?: return@subscribe
|
||||
if (uuid in (lockedUUIDs ?: return@subscribe)) {
|
||||
event.protect()
|
||||
}
|
||||
}
|
||||
IsSlotProtectedEvent.subscribe { event ->
|
||||
if (event.slot == null) return@subscribe
|
||||
if (!event.slot.hasStack()) return@subscribe
|
||||
if (event.slot.stack.displayNameAccordingToNbt?.unformattedString != "Salvage Items") return@subscribe
|
||||
val inv = event.slot.inventory
|
||||
var anyBlocked = false
|
||||
for (i in 0 until event.slot.index) {
|
||||
val stack = inv.getStack(i)
|
||||
if (IsSlotProtectedEvent.shouldBlockInteraction(null, SlotActionType.THROW, stack))
|
||||
anyBlocked = true
|
||||
}
|
||||
if (anyBlocked) {
|
||||
event.protectSilent()
|
||||
}
|
||||
if (anyBlocked) {
|
||||
event.protectSilent()
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun function(it: SlotRenderEvents.After) {
|
||||
fun onProtectUuidItems(event: IsSlotProtectedEvent) {
|
||||
val doesNotDeleteItem = event.actionType == SlotActionType.SWAP
|
||||
|| event.actionType == SlotActionType.PICKUP
|
||||
|| event.actionType == SlotActionType.QUICK_MOVE
|
||||
|| event.actionType == SlotActionType.QUICK_CRAFT
|
||||
|| event.actionType == SlotActionType.CLONE
|
||||
|| event.actionType == SlotActionType.PICKUP_ALL
|
||||
val isSellOrTradeScreen =
|
||||
isNpcShop(MC.handledScreen) || isTradeScreen(MC.handledScreen) || isSalvageScreen(MC.handledScreen)
|
||||
if (!isSellOrTradeScreen && doesNotDeleteItem) return
|
||||
val stack = event.itemStack ?: return
|
||||
val uuid = stack.skyblockUUID ?: return
|
||||
if (uuid in (lockedUUIDs ?: return)) {
|
||||
event.protect()
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onProtectSlot(it: IsSlotProtectedEvent) {
|
||||
if (it.slot != null && it.slot.inventory is PlayerInventory && it.slot.index in (lockedSlots ?: setOf())) {
|
||||
it.protect()
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onLockUUID(it: HandledScreenKeyPressedEvent) {
|
||||
if (!it.matches(TConfig.lockUUID)) return
|
||||
val inventory = MC.handledScreen ?: return
|
||||
inventory as AccessorHandledScreen
|
||||
|
||||
val slot = inventory.focusedSlot_Firmament ?: return
|
||||
val stack = slot.stack ?: return
|
||||
val uuid = stack.skyblockUUID ?: return
|
||||
val lockedUUIDs = lockedUUIDs ?: return
|
||||
if (uuid in lockedUUIDs) {
|
||||
lockedUUIDs.remove(uuid)
|
||||
} else {
|
||||
lockedUUIDs.add(uuid)
|
||||
}
|
||||
DConfig.markDirty()
|
||||
CommonSoundEffects.playSuccess()
|
||||
it.cancel()
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onLockSlot(it: HandledScreenKeyPressedEvent) {
|
||||
if (!it.matches(TConfig.lockSlot)) return
|
||||
val inventory = MC.handledScreen ?: return
|
||||
inventory as AccessorHandledScreen
|
||||
|
||||
val slot = inventory.focusedSlot_Firmament ?: return
|
||||
val lockedSlots = lockedSlots ?: return
|
||||
if (slot.inventory is PlayerInventory) {
|
||||
if (slot.index in lockedSlots) {
|
||||
lockedSlots.remove(slot.index)
|
||||
} else {
|
||||
lockedSlots.add(slot.index)
|
||||
}
|
||||
DConfig.markDirty()
|
||||
CommonSoundEffects.playSuccess()
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onRenderSlotOverlay(it: SlotRenderEvents.After) {
|
||||
val isSlotLocked = it.slot.inventory is PlayerInventory && it.slot.index in (lockedSlots ?: setOf())
|
||||
val isUUIDLocked = (it.slot.stack?.skyblockUUID) in (lockedUUIDs ?: setOf())
|
||||
if (isSlotLocked || isUUIDLocked) {
|
||||
|
||||
@@ -9,6 +9,7 @@ package moe.nea.firmament.features.inventory.buttons
|
||||
import me.shedaniel.math.Rectangle
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.serializer
|
||||
import moe.nea.firmament.annotations.Subscribe
|
||||
import moe.nea.firmament.events.HandledScreenClickEvent
|
||||
import moe.nea.firmament.events.HandledScreenForegroundEvent
|
||||
import moe.nea.firmament.events.HandledScreenPushREIEvent
|
||||
@@ -28,6 +29,7 @@ object InventoryButtons : FirmamentFeature {
|
||||
openEditor()
|
||||
}
|
||||
}
|
||||
|
||||
object DConfig : DataHolder<Data>(serializer(), identifier, ::Data)
|
||||
|
||||
@Serializable
|
||||
@@ -40,35 +42,39 @@ object InventoryButtons : FirmamentFeature {
|
||||
get() = TConfig
|
||||
|
||||
fun getValidButtons() = DConfig.data.buttons.asSequence().filter { it.isValid() }
|
||||
override fun onLoad() {
|
||||
HandledScreenForegroundEvent.subscribe {
|
||||
val bounds = it.screen.getRectangle()
|
||||
for (button in getValidButtons()) {
|
||||
val buttonBounds = button.getBounds(bounds)
|
||||
it.context.matrices.push()
|
||||
it.context.matrices.translate(buttonBounds.minX.toFloat(), buttonBounds.minY.toFloat(), 0F)
|
||||
button.render(it.context)
|
||||
it.context.matrices.pop()
|
||||
}
|
||||
lastRectangle = bounds
|
||||
|
||||
@Subscribe
|
||||
fun onRectangles(it: HandledScreenPushREIEvent) {
|
||||
val bounds = it.screen.getRectangle()
|
||||
for (button in getValidButtons()) {
|
||||
val buttonBounds = button.getBounds(bounds)
|
||||
it.block(buttonBounds)
|
||||
}
|
||||
HandledScreenClickEvent.subscribe {
|
||||
val bounds = it.screen.getRectangle()
|
||||
for (button in getValidButtons()) {
|
||||
val buttonBounds = button.getBounds(bounds)
|
||||
if (buttonBounds.contains(it.mouseX, it.mouseY)) {
|
||||
MC.sendCommand(button.command!! /* non null invariant covered by getValidButtons */)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onClickScreen(it: HandledScreenClickEvent) {
|
||||
val bounds = it.screen.getRectangle()
|
||||
for (button in getValidButtons()) {
|
||||
val buttonBounds = button.getBounds(bounds)
|
||||
if (buttonBounds.contains(it.mouseX, it.mouseY)) {
|
||||
MC.sendCommand(button.command!! /* non null invariant covered by getValidButtons */)
|
||||
break
|
||||
}
|
||||
}
|
||||
HandledScreenPushREIEvent.subscribe {
|
||||
val bounds = it.screen.getRectangle()
|
||||
for (button in getValidButtons()) {
|
||||
val buttonBounds = button.getBounds(bounds)
|
||||
it.block(buttonBounds)
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onRenderForeground(it: HandledScreenForegroundEvent) {
|
||||
val bounds = it.screen.getRectangle()
|
||||
for (button in getValidButtons()) {
|
||||
val buttonBounds = button.getBounds(bounds)
|
||||
it.context.matrices.push()
|
||||
it.context.matrices.translate(buttonBounds.minX.toFloat(), buttonBounds.minY.toFloat(), 0F)
|
||||
button.render(it.context)
|
||||
it.context.matrices.pop()
|
||||
}
|
||||
lastRectangle = bounds
|
||||
}
|
||||
|
||||
var lastRectangle: Rectangle? = null
|
||||
|
||||
@@ -6,9 +6,10 @@
|
||||
|
||||
package moe.nea.firmament.features.inventory.storageoverlay
|
||||
|
||||
import java.util.*
|
||||
import java.util.SortedMap
|
||||
import kotlinx.serialization.serializer
|
||||
import net.minecraft.client.gui.screen.Screen
|
||||
import moe.nea.firmament.annotations.Subscribe
|
||||
import moe.nea.firmament.events.ScreenChangeEvent
|
||||
import moe.nea.firmament.events.TickEvent
|
||||
import moe.nea.firmament.features.FirmamentFeature
|
||||
@@ -40,31 +41,33 @@ object StorageOverlay : FirmamentFeature {
|
||||
var shouldReturnToStorageOverlay: Screen? = null
|
||||
var currentHandler: StorageBackingHandle? = StorageBackingHandle.None
|
||||
|
||||
override fun onLoad() {
|
||||
ScreenChangeEvent.subscribe {
|
||||
if (lastStorageOverlay != null && it.new != null) {
|
||||
shouldReturnToStorageOverlay = lastStorageOverlay
|
||||
shouldReturnToStorageOverlayFrom = it.new
|
||||
lastStorageOverlay = null
|
||||
} else if (it.old === shouldReturnToStorageOverlayFrom) {
|
||||
if (shouldReturnToStorageOverlay != null && it.new == null)
|
||||
setScreenLater(shouldReturnToStorageOverlay)
|
||||
shouldReturnToStorageOverlay = null
|
||||
shouldReturnToStorageOverlayFrom = null
|
||||
}
|
||||
}
|
||||
@Subscribe
|
||||
fun onTick(event: TickEvent) {
|
||||
rememberContent(currentHandler ?: return)
|
||||
}
|
||||
|
||||
ScreenChangeEvent.subscribe { event ->
|
||||
currentHandler = StorageBackingHandle.fromScreen(event.new)
|
||||
if (event.old is StorageOverlayScreen && !event.old.isClosing) {
|
||||
event.old.setHandler(currentHandler)
|
||||
if (currentHandler != null)
|
||||
// TODO: Consider instead only replacing rendering? might make a lot of stack handling easier
|
||||
event.cancel()
|
||||
}
|
||||
@Subscribe
|
||||
fun onScreenChangeLegacy(event: ScreenChangeEvent) {
|
||||
currentHandler = StorageBackingHandle.fromScreen(event.new)
|
||||
if (event.old is StorageOverlayScreen && !event.old.isClosing) {
|
||||
event.old.setHandler(currentHandler)
|
||||
if (currentHandler != null)
|
||||
// TODO: Consider instead only replacing rendering? might make a lot of stack handling easier
|
||||
event.cancel()
|
||||
}
|
||||
TickEvent.subscribe {
|
||||
rememberContent(currentHandler ?: return@subscribe)
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onScreenChange(it: ScreenChangeEvent) {
|
||||
if (lastStorageOverlay != null && it.new != null) {
|
||||
shouldReturnToStorageOverlay = lastStorageOverlay
|
||||
shouldReturnToStorageOverlayFrom = it.new
|
||||
lastStorageOverlay = null
|
||||
} else if (it.old === shouldReturnToStorageOverlayFrom) {
|
||||
if (shouldReturnToStorageOverlay != null && it.new == null)
|
||||
setScreenLater(shouldReturnToStorageOverlay)
|
||||
shouldReturnToStorageOverlay = null
|
||||
shouldReturnToStorageOverlayFrom = null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import net.minecraft.item.ItemStack
|
||||
import net.minecraft.util.DyeColor
|
||||
import net.minecraft.util.Hand
|
||||
import net.minecraft.util.Identifier
|
||||
import moe.nea.firmament.annotations.Subscribe
|
||||
import moe.nea.firmament.events.HudRenderEvent
|
||||
import moe.nea.firmament.events.ProcessChatEvent
|
||||
import moe.nea.firmament.events.SlotClickEvent
|
||||
@@ -73,53 +74,57 @@ object PickaxeAbility : FirmamentFeature {
|
||||
return 1.0
|
||||
}
|
||||
|
||||
override fun onLoad() {
|
||||
HudRenderEvent.subscribe(this::renderHud)
|
||||
WorldReadyEvent.subscribe {
|
||||
lastUsage.clear()
|
||||
lobbyJoinTime = TimeMark.now()
|
||||
abilityOverride = null
|
||||
}
|
||||
ProcessChatEvent.subscribe {
|
||||
abilityUsePattern.useMatch(it.unformattedString) {
|
||||
lastUsage[group("name")] = TimeMark.now()
|
||||
}
|
||||
abilitySwitchPattern.useMatch(it.unformattedString) {
|
||||
abilityOverride = group("ability")
|
||||
}
|
||||
}
|
||||
DurabilityBarEvent.subscribe {
|
||||
if (!TConfig.drillFuelBar) return@subscribe
|
||||
val lore = it.item.loreAccordingToNbt
|
||||
if (lore.lastOrNull()?.unformattedString?.contains("DRILL") != true) return@subscribe
|
||||
val maxFuel = lore.firstNotNullOfOrNull {
|
||||
fuelPattern.useMatch(it.unformattedString) {
|
||||
parseShortNumber(group("maxFuel"))
|
||||
@Subscribe
|
||||
fun onSlotClick(it: SlotClickEvent) {
|
||||
if (MC.screen?.title?.unformattedString == "Heart of the Mountain") {
|
||||
val name = it.stack.displayNameAccordingToNbt?.unformattedString ?: return
|
||||
val cooldown = it.stack.loreAccordingToNbt.firstNotNullOfOrNull {
|
||||
cooldownPattern.useMatch(it.unformattedString) {
|
||||
parseTimePattern(group("cooldown"))
|
||||
}
|
||||
} ?: return@subscribe
|
||||
val extra = it.item.extraAttributes
|
||||
if (!extra.contains("drill_fuel")) return@subscribe
|
||||
val fuel = extra.getInt("drill_fuel")
|
||||
val percentage = fuel / maxFuel.toFloat()
|
||||
it.barOverride = DurabilityBarEvent.DurabilityBar(
|
||||
lerp(
|
||||
DyeColor.RED.toShedaniel(),
|
||||
DyeColor.GREEN.toShedaniel(),
|
||||
percentage
|
||||
), percentage
|
||||
)
|
||||
} ?: return
|
||||
defaultAbilityDurations[name] = cooldown
|
||||
}
|
||||
SlotClickEvent.subscribe {
|
||||
if (MC.screen?.title?.unformattedString == "Heart of the Mountain") {
|
||||
val name = it.stack.displayNameAccordingToNbt?.unformattedString ?: return@subscribe
|
||||
val cooldown = it.stack.loreAccordingToNbt.firstNotNullOfOrNull {
|
||||
cooldownPattern.useMatch(it.unformattedString) {
|
||||
parseTimePattern(group("cooldown"))
|
||||
}
|
||||
} ?: return@subscribe
|
||||
defaultAbilityDurations[name] = cooldown
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onDurabilityBar(it: DurabilityBarEvent) {
|
||||
if (!TConfig.drillFuelBar) return
|
||||
val lore = it.item.loreAccordingToNbt
|
||||
if (lore.lastOrNull()?.unformattedString?.contains("DRILL") != true) return
|
||||
val maxFuel = lore.firstNotNullOfOrNull {
|
||||
fuelPattern.useMatch(it.unformattedString) {
|
||||
parseShortNumber(group("maxFuel"))
|
||||
}
|
||||
} ?: return
|
||||
val extra = it.item.extraAttributes
|
||||
if (!extra.contains("drill_fuel")) return
|
||||
val fuel = extra.getInt("drill_fuel")
|
||||
val percentage = fuel / maxFuel.toFloat()
|
||||
it.barOverride = DurabilityBarEvent.DurabilityBar(
|
||||
lerp(
|
||||
DyeColor.RED.toShedaniel(),
|
||||
DyeColor.GREEN.toShedaniel(),
|
||||
percentage
|
||||
), percentage
|
||||
)
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onChatMessage(it: ProcessChatEvent) {
|
||||
abilityUsePattern.useMatch(it.unformattedString) {
|
||||
lastUsage[group("name")] = TimeMark.now()
|
||||
}
|
||||
abilitySwitchPattern.useMatch(it.unformattedString) {
|
||||
abilityOverride = group("ability")
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onWorldReady(event: WorldReadyEvent) {
|
||||
lastUsage.clear()
|
||||
lobbyJoinTime = TimeMark.now()
|
||||
abilityOverride = null
|
||||
}
|
||||
|
||||
val abilityUsePattern = Pattern.compile("You used your (?<name>.*) Pickaxe Ability!")
|
||||
@@ -154,7 +159,8 @@ object PickaxeAbility : FirmamentFeature {
|
||||
Pattern.compile("You selected (?<ability>.*) as your Pickaxe Ability\\. This ability will apply to all of your pickaxes!")
|
||||
|
||||
|
||||
private fun renderHud(event: HudRenderEvent) {
|
||||
@Subscribe
|
||||
fun renderHud(event: HudRenderEvent) {
|
||||
if (!TConfig.cooldownEnabled) return
|
||||
var ability = getCooldownFromLore(MC.player?.getStackInHand(Hand.MAIN_HAND) ?: return) ?: return
|
||||
defaultAbilityDurations[ability.name] = ability.cooldown
|
||||
|
||||
@@ -12,6 +12,7 @@ import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.serializer
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
import net.minecraft.text.Text
|
||||
import moe.nea.firmament.annotations.Subscribe
|
||||
import moe.nea.firmament.events.ProcessChatEvent
|
||||
import moe.nea.firmament.features.FirmamentFeature
|
||||
import moe.nea.firmament.gui.config.ManagedConfig
|
||||
@@ -62,7 +63,7 @@ object PristineProfitTracker : FirmamentFeature {
|
||||
|
||||
val pristineRegex =
|
||||
"PRISTINE! You found . Flawed (?<kind>${
|
||||
GemstoneKind.values().joinToString("|") { it.label }
|
||||
GemstoneKind.entries.joinToString("|") { it.label }
|
||||
}) Gemstone x(?<count>[0-9,]+)!".toPattern()
|
||||
|
||||
val collectionHistogram = Histogram<Double>(10000, 180.seconds)
|
||||
@@ -97,9 +98,13 @@ object PristineProfitTracker : FirmamentFeature {
|
||||
val moneyPerSecond = moneyHistogram.averagePer({ it }, 1.seconds)
|
||||
if (collectionPerSecond == null || moneyPerSecond == null) return
|
||||
ProfitHud.collectionCurrent = collectionPerSecond
|
||||
ProfitHud.collectionText = Text.stringifiedTranslatable("firmament.pristine-profit.collection", formatCurrency(collectionPerSecond * SECONDS_PER_HOUR, 1)).formattedString()
|
||||
ProfitHud.collectionText = Text.stringifiedTranslatable("firmament.pristine-profit.collection",
|
||||
formatCurrency(collectionPerSecond * SECONDS_PER_HOUR,
|
||||
1)).formattedString()
|
||||
ProfitHud.moneyCurrent = moneyPerSecond
|
||||
ProfitHud.moneyText = Text.stringifiedTranslatable("firmament.pristine-profit.money", formatCurrency(moneyPerSecond * SECONDS_PER_HOUR, 1)).formattedString()
|
||||
ProfitHud.moneyText = Text.stringifiedTranslatable("firmament.pristine-profit.money",
|
||||
formatCurrency(moneyPerSecond * SECONDS_PER_HOUR, 1))
|
||||
.formattedString()
|
||||
val data = DConfig.data
|
||||
if (data != null) {
|
||||
if (data.maxCollectionPerSecond < collectionPerSecond && collectionHistogram.oldestUpdate()
|
||||
@@ -118,17 +123,16 @@ object PristineProfitTracker : FirmamentFeature {
|
||||
}
|
||||
|
||||
|
||||
override fun onLoad() {
|
||||
ProcessChatEvent.subscribe {
|
||||
pristineRegex.useMatch(it.unformattedString) {
|
||||
val gemstoneKind = GemstoneKind.valueOf(group("kind").uppercase())
|
||||
val flawedCount = parseIntWithComma(group("count"))
|
||||
val moneyAmount = sellingStrategy.getSellPrice(gemstoneKind.flawedId) * flawedCount
|
||||
moneyHistogram.record(moneyAmount)
|
||||
val collectionAmount = flawedCount * ROUGHS_PER_FLAWED
|
||||
collectionHistogram.record(collectionAmount.toDouble())
|
||||
updateUi()
|
||||
}
|
||||
@Subscribe
|
||||
fun onMessage(it: ProcessChatEvent) {
|
||||
pristineRegex.useMatch(it.unformattedString) {
|
||||
val gemstoneKind = GemstoneKind.valueOf(group("kind").uppercase())
|
||||
val flawedCount = parseIntWithComma(group("count"))
|
||||
val moneyAmount = sellingStrategy.getSellPrice(gemstoneKind.flawedId) * flawedCount
|
||||
moneyHistogram.record(moneyAmount)
|
||||
val collectionAmount = flawedCount * ROUGHS_PER_FLAWED
|
||||
collectionHistogram.record(collectionAmount.toDouble())
|
||||
updateUi()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import net.minecraft.client.render.RenderLayer
|
||||
import net.minecraft.client.util.ModelIdentifier
|
||||
import net.minecraft.component.type.ProfileComponent
|
||||
import net.minecraft.util.Identifier
|
||||
import moe.nea.firmament.annotations.Subscribe
|
||||
import moe.nea.firmament.events.CustomItemModelEvent
|
||||
import moe.nea.firmament.events.TickEvent
|
||||
import moe.nea.firmament.features.FirmamentFeature
|
||||
@@ -38,20 +39,21 @@ object CustomSkyBlockTextures : FirmamentFeature {
|
||||
override val config: ManagedConfig
|
||||
get() = TConfig
|
||||
|
||||
override fun onLoad() {
|
||||
CustomItemModelEvent.subscribe {
|
||||
if (!TConfig.enabled) return@subscribe
|
||||
val id = it.itemStack.skyBlockId ?: return@subscribe
|
||||
it.overrideModel = ModelIdentifier("firmskyblock", id.identifier.path, "inventory")
|
||||
}
|
||||
TickEvent.subscribe {
|
||||
if (TConfig.cacheDuration < 1 || it.tickCount % TConfig.cacheDuration == 0) {
|
||||
CustomItemModelEvent.clearCache()
|
||||
skullTextureCache.clear()
|
||||
}
|
||||
@Subscribe
|
||||
fun onTick(it: TickEvent) {
|
||||
if (TConfig.cacheDuration < 1 || it.tickCount % TConfig.cacheDuration == 0) {
|
||||
CustomItemModelEvent.clearCache()
|
||||
skullTextureCache.clear()
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onCustomModelId(it: CustomItemModelEvent) {
|
||||
if (!TConfig.enabled) return
|
||||
val id = it.itemStack.skyBlockId ?: return
|
||||
it.overrideModel = ModelIdentifier("firmskyblock", id.identifier.path, "inventory")
|
||||
}
|
||||
|
||||
private val skullTextureCache = mutableMapOf<IdentityCharacteristics<ProfileComponent>, Any>()
|
||||
private val sentinelPresentInvalid = Object()
|
||||
|
||||
|
||||
@@ -9,15 +9,10 @@ package moe.nea.firmament.features.world
|
||||
import io.github.moulberry.repo.data.Coordinate
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.serializer
|
||||
import net.minecraft.client.render.RenderLayer
|
||||
import net.minecraft.client.render.RenderLayer.ALWAYS_DEPTH_TEST
|
||||
import net.minecraft.client.render.RenderLayer.MultiPhaseParameters
|
||||
import net.minecraft.client.render.RenderPhase
|
||||
import net.minecraft.client.render.VertexFormat
|
||||
import net.minecraft.client.render.VertexFormats
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.math.Vec3d
|
||||
import moe.nea.firmament.events.AllowChatEvent
|
||||
import moe.nea.firmament.annotations.Subscribe
|
||||
import moe.nea.firmament.events.ProcessChatEvent
|
||||
import moe.nea.firmament.events.SkyblockServerUpdateEvent
|
||||
import moe.nea.firmament.events.WorldRenderLastEvent
|
||||
import moe.nea.firmament.features.FirmamentFeature
|
||||
@@ -102,53 +97,43 @@ object FairySouls : FirmamentFeature {
|
||||
updateMissingSouls()
|
||||
}
|
||||
|
||||
val NODEPTH: RenderLayer = RenderLayer.of(
|
||||
"firmamentnodepth",
|
||||
VertexFormats.POSITION_COLOR_TEXTURE,
|
||||
VertexFormat.DrawMode.QUADS,
|
||||
256,
|
||||
true,
|
||||
true,
|
||||
MultiPhaseParameters.builder()
|
||||
.program(RenderPhase.COLOR_PROGRAM)
|
||||
.writeMaskState(RenderPhase.COLOR_MASK)
|
||||
.depthTest(ALWAYS_DEPTH_TEST)
|
||||
.cull(RenderPhase.DISABLE_CULLING)
|
||||
.layering(RenderLayer.VIEW_OFFSET_Z_LAYERING)
|
||||
.target(RenderPhase.MAIN_TARGET)
|
||||
.build(true)
|
||||
)
|
||||
|
||||
override fun onLoad() {
|
||||
SkyblockServerUpdateEvent.subscribe {
|
||||
currentLocationName = it.newLocraw?.skyblockLocation
|
||||
updateWorldSouls()
|
||||
updateMissingSouls()
|
||||
}
|
||||
AllowChatEvent.subscribe {
|
||||
when (it.text.unformattedString) {
|
||||
"You have already found that Fairy Soul!" -> {
|
||||
markNearestSoul()
|
||||
}
|
||||
|
||||
"SOUL! You found a Fairy Soul!" -> {
|
||||
markNearestSoul()
|
||||
}
|
||||
@Subscribe
|
||||
fun onWorldRender(it: WorldRenderLastEvent) {
|
||||
if (!TConfig.displaySouls) return
|
||||
renderInWorld(it) {
|
||||
text(Vec3d(0.0, 0.0, 0.0),
|
||||
Text.literal("Test String"),
|
||||
Text.literal("Short"),
|
||||
Text.literal("just lik"),
|
||||
verticalAlign = RenderInWorldContext.VerticalAlign.BOTTOM)
|
||||
color(1F, 1F, 0F, 0.8F)
|
||||
currentMissingSouls.forEach {
|
||||
block(it.blockPos)
|
||||
}
|
||||
}
|
||||
WorldRenderLastEvent.subscribe {
|
||||
if (!TConfig.displaySouls) return@subscribe
|
||||
renderInWorld(it) {
|
||||
text(Vec3d(0.0, 0.0, 0.0), Text.literal("Test String") , Text.literal("Short"), Text.literal("just lik"), verticalAlign = RenderInWorldContext.VerticalAlign.BOTTOM)
|
||||
color(1F, 1F, 0F, 0.8F)
|
||||
currentMissingSouls.forEach {
|
||||
block(it.blockPos)
|
||||
}
|
||||
color(1f, 0f, 1f, 1f)
|
||||
currentLocationSouls.forEach {
|
||||
wireframeCube(it.blockPos)
|
||||
}
|
||||
color(1f, 0f, 1f, 1f)
|
||||
currentLocationSouls.forEach {
|
||||
wireframeCube(it.blockPos)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onProcessChat(it: ProcessChatEvent) {
|
||||
when (it.text.unformattedString) {
|
||||
"You have already found that Fairy Soul!" -> {
|
||||
markNearestSoul()
|
||||
}
|
||||
|
||||
"SOUL! You found a Fairy Soul!" -> {
|
||||
markNearestSoul()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onLocationChange(it: SkyblockServerUpdateEvent) {
|
||||
currentLocationName = it.newLocraw?.skyblockLocation
|
||||
updateWorldSouls()
|
||||
updateMissingSouls()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import net.minecraft.text.Text
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.util.math.Vec3d
|
||||
import moe.nea.firmament.Firmament
|
||||
import moe.nea.firmament.annotations.Subscribe
|
||||
import moe.nea.firmament.commands.get
|
||||
import moe.nea.firmament.commands.thenArgument
|
||||
import moe.nea.firmament.commands.thenExecute
|
||||
@@ -73,194 +74,203 @@ object Waypoints : FirmamentFeature {
|
||||
val b: Int = 0,
|
||||
)
|
||||
|
||||
override fun onLoad() {
|
||||
WorldRenderLastEvent.subscribe { event ->
|
||||
temporaryPlayerWaypointList.entries.removeIf { it.value.postedAt.passedTime() > TConfig.tempWaypointDuration }
|
||||
if (temporaryPlayerWaypointList.isNotEmpty())
|
||||
RenderInWorldContext.renderInWorld(event) {
|
||||
color(1f, 1f, 0f, 1f)
|
||||
temporaryPlayerWaypointList.forEach { (player, waypoint) ->
|
||||
block(waypoint.pos)
|
||||
}
|
||||
@Subscribe
|
||||
fun onRenderOrderedWaypoints(event: WorldRenderLastEvent) {
|
||||
if (waypoints.isEmpty()) return
|
||||
RenderInWorldContext.renderInWorld(event) {
|
||||
if (!ordered) {
|
||||
waypoints.withIndex().forEach {
|
||||
color(0f, 0.3f, 0.7f, 0.5f)
|
||||
block(it.value)
|
||||
color(1f, 1f, 1f, 1f)
|
||||
temporaryPlayerWaypointList.forEach { (player, waypoint) ->
|
||||
val skin =
|
||||
MC.networkHandler?.listedPlayerListEntries?.find { it.profile.name == player }
|
||||
?.skinTextures
|
||||
?.texture
|
||||
withFacingThePlayer(waypoint.pos.toCenterPos()) {
|
||||
waypoint(waypoint.pos, Text.stringifiedTranslatable("firmament.waypoint.temporary", player))
|
||||
if (skin != null) {
|
||||
matrixStack.translate(0F, -20F, 0F)
|
||||
// Head front
|
||||
texture(
|
||||
skin, 16, 16,
|
||||
1 / 8f, 1 / 8f,
|
||||
2 / 8f, 2 / 8f,
|
||||
)
|
||||
// Head overlay
|
||||
texture(
|
||||
skin, 16, 16,
|
||||
5 / 8f, 1 / 8f,
|
||||
6 / 8f, 2 / 8f,
|
||||
)
|
||||
}
|
||||
if (TConfig.showIndex)
|
||||
withFacingThePlayer(it.value.toCenterPos()) {
|
||||
text(Text.literal(it.index.toString()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
WorldReadyEvent.subscribe {
|
||||
temporaryPlayerWaypointList.clear()
|
||||
}
|
||||
CommandEvent.SubCommand.subscribe { event ->
|
||||
event.subcommand("waypoint") {
|
||||
thenArgument("pos", BlockPosArgumentType.blockPos()) { pos ->
|
||||
thenExecute {
|
||||
val position = pos.get(this).toAbsoluteBlockPos(source.asFakeServer())
|
||||
waypoints.add(position)
|
||||
source.sendFeedback(
|
||||
Text.stringifiedTranslatable(
|
||||
"firmament.command.waypoint.added",
|
||||
position.x,
|
||||
position.y,
|
||||
position.z
|
||||
)
|
||||
} else {
|
||||
orderedIndex %= waypoints.size
|
||||
val firstColor = Color.ofRGBA(0, 200, 40, 180)
|
||||
color(firstColor)
|
||||
tracer(waypoints[orderedIndex].toCenterPos(), lineWidth = 3f)
|
||||
waypoints.withIndex().toList()
|
||||
.wrappingWindow(orderedIndex, 3)
|
||||
.zip(
|
||||
listOf(
|
||||
firstColor,
|
||||
Color.ofRGBA(180, 200, 40, 150),
|
||||
Color.ofRGBA(180, 80, 20, 140),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
event.subcommand("waypoints") {
|
||||
thenLiteral("clear") {
|
||||
thenExecute {
|
||||
waypoints.clear()
|
||||
source.sendFeedback(Text.translatable("firmament.command.waypoint.clear"))
|
||||
}
|
||||
}
|
||||
thenLiteral("toggleordered") {
|
||||
thenExecute {
|
||||
ordered = !ordered
|
||||
if (ordered) {
|
||||
val p = MC.player?.pos ?: Vec3d.ZERO
|
||||
orderedIndex =
|
||||
waypoints.withIndex().minByOrNull { it.value.getSquaredDistance(p) }?.index ?: 0
|
||||
}
|
||||
source.sendFeedback(Text.translatable("firmament.command.waypoint.ordered.toggle.$ordered"))
|
||||
}
|
||||
}
|
||||
thenLiteral("skip") {
|
||||
thenExecute {
|
||||
if (ordered && waypoints.isNotEmpty()) {
|
||||
orderedIndex = (orderedIndex + 1) % waypoints.size
|
||||
source.sendFeedback(Text.translatable("firmament.command.waypoint.skip"))
|
||||
} else {
|
||||
source.sendError(Text.translatable("firmament.command.waypoint.skip.error"))
|
||||
}
|
||||
}
|
||||
}
|
||||
thenLiteral("remove") {
|
||||
thenArgument("index", IntegerArgumentType.integer(0)) { indexArg ->
|
||||
thenExecute {
|
||||
val index = get(indexArg)
|
||||
if (index in waypoints.indices) {
|
||||
waypoints.removeAt(index)
|
||||
source.sendFeedback(Text.stringifiedTranslatable(
|
||||
"firmament.command.waypoint.remove",
|
||||
index))
|
||||
} else {
|
||||
source.sendError(Text.stringifiedTranslatable("firmament.command.waypoint.remove.error"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
thenLiteral("import") {
|
||||
thenExecute {
|
||||
val contents = ClipboardUtils.getTextContents()
|
||||
val data = try {
|
||||
Firmament.json.decodeFromString<List<ColeWeightWaypoint>>(contents)
|
||||
} catch (ex: Exception) {
|
||||
Firmament.logger.error("Could not load waypoints from clipboard", ex)
|
||||
source.sendError(Text.translatable("firmament.command.waypoint.import.error"))
|
||||
return@thenExecute
|
||||
}
|
||||
waypoints.clear()
|
||||
data.mapTo(waypoints) { BlockPos(it.x, it.y, it.z) }
|
||||
source.sendFeedback(
|
||||
Text.stringifiedTranslatable(
|
||||
"firmament.command.waypoint.import",
|
||||
data.size
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
WorldRenderLastEvent.subscribe { event ->
|
||||
if (waypoints.isEmpty()) return@subscribe
|
||||
RenderInWorldContext.renderInWorld(event) {
|
||||
if (!ordered) {
|
||||
waypoints.withIndex().forEach {
|
||||
color(0f, 0.3f, 0.7f, 0.5f)
|
||||
block(it.value)
|
||||
)
|
||||
.reversed()
|
||||
.forEach { (waypoint, col) ->
|
||||
val (index, pos) = waypoint
|
||||
color(col)
|
||||
block(pos)
|
||||
color(1f, 1f, 1f, 1f)
|
||||
if (TConfig.showIndex)
|
||||
withFacingThePlayer(it.value.toCenterPos()) {
|
||||
text(Text.literal(it.index.toString()))
|
||||
withFacingThePlayer(pos.toCenterPos()) {
|
||||
text(Text.literal(index.toString()))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
orderedIndex %= waypoints.size
|
||||
val firstColor = Color.ofRGBA(0, 200, 40, 180)
|
||||
color(firstColor)
|
||||
tracer(waypoints[orderedIndex].toCenterPos(), lineWidth = 3f)
|
||||
waypoints.withIndex().toList()
|
||||
.wrappingWindow(orderedIndex, 3)
|
||||
.zip(
|
||||
listOf(
|
||||
firstColor,
|
||||
Color.ofRGBA(180, 200, 40, 150),
|
||||
Color.ofRGBA(180, 80, 20, 140),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onTick(event: TickEvent) {
|
||||
if (waypoints.isEmpty() || !ordered) return
|
||||
orderedIndex %= waypoints.size
|
||||
val p = MC.player?.pos ?: return
|
||||
if (TConfig.skipToNearest) {
|
||||
orderedIndex =
|
||||
(waypoints.withIndex().minBy { it.value.getSquaredDistance(p) }.index + 1) % waypoints.size
|
||||
} else {
|
||||
if (waypoints[orderedIndex].isWithinDistance(p, 3.0)) {
|
||||
orderedIndex = (orderedIndex + 1) % waypoints.size
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onProcessChat(it: ProcessChatEvent) {
|
||||
val matcher = temporaryPlayerWaypointMatcher.matcher(it.unformattedString)
|
||||
if (it.nameHeuristic != null && TConfig.tempWaypointDuration > 0.seconds && matcher.find()) {
|
||||
temporaryPlayerWaypointList[it.nameHeuristic] = TemporaryWaypoint(
|
||||
BlockPos(
|
||||
matcher.group(1).toInt(),
|
||||
matcher.group(2).toInt(),
|
||||
matcher.group(3).toInt(),
|
||||
),
|
||||
TimeMark.now()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onCommand(event: CommandEvent.SubCommand) {
|
||||
event.subcommand("waypoint") {
|
||||
thenArgument("pos", BlockPosArgumentType.blockPos()) { pos ->
|
||||
thenExecute {
|
||||
val position = pos.get(this).toAbsoluteBlockPos(source.asFakeServer())
|
||||
waypoints.add(position)
|
||||
source.sendFeedback(
|
||||
Text.stringifiedTranslatable(
|
||||
"firmament.command.waypoint.added",
|
||||
position.x,
|
||||
position.y,
|
||||
position.z
|
||||
)
|
||||
.reversed()
|
||||
.forEach { (waypoint, col) ->
|
||||
val (index, pos) = waypoint
|
||||
color(col)
|
||||
block(pos)
|
||||
color(1f, 1f, 1f, 1f)
|
||||
if (TConfig.showIndex)
|
||||
withFacingThePlayer(pos.toCenterPos()) {
|
||||
text(Text.literal(index.toString()))
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
event.subcommand("waypoints") {
|
||||
thenLiteral("clear") {
|
||||
thenExecute {
|
||||
waypoints.clear()
|
||||
source.sendFeedback(Text.translatable("firmament.command.waypoint.clear"))
|
||||
}
|
||||
}
|
||||
thenLiteral("toggleordered") {
|
||||
thenExecute {
|
||||
ordered = !ordered
|
||||
if (ordered) {
|
||||
val p = MC.player?.pos ?: Vec3d.ZERO
|
||||
orderedIndex =
|
||||
waypoints.withIndex().minByOrNull { it.value.getSquaredDistance(p) }?.index ?: 0
|
||||
}
|
||||
source.sendFeedback(Text.translatable("firmament.command.waypoint.ordered.toggle.$ordered"))
|
||||
}
|
||||
}
|
||||
thenLiteral("skip") {
|
||||
thenExecute {
|
||||
if (ordered && waypoints.isNotEmpty()) {
|
||||
orderedIndex = (orderedIndex + 1) % waypoints.size
|
||||
source.sendFeedback(Text.translatable("firmament.command.waypoint.skip"))
|
||||
} else {
|
||||
source.sendError(Text.translatable("firmament.command.waypoint.skip.error"))
|
||||
}
|
||||
}
|
||||
}
|
||||
thenLiteral("remove") {
|
||||
thenArgument("index", IntegerArgumentType.integer(0)) { indexArg ->
|
||||
thenExecute {
|
||||
val index = get(indexArg)
|
||||
if (index in waypoints.indices) {
|
||||
waypoints.removeAt(index)
|
||||
source.sendFeedback(Text.stringifiedTranslatable(
|
||||
"firmament.command.waypoint.remove",
|
||||
index))
|
||||
} else {
|
||||
source.sendError(Text.stringifiedTranslatable("firmament.command.waypoint.remove.error"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
thenLiteral("import") {
|
||||
thenExecute {
|
||||
val contents = ClipboardUtils.getTextContents()
|
||||
val data = try {
|
||||
Firmament.json.decodeFromString<List<ColeWeightWaypoint>>(contents)
|
||||
} catch (ex: Exception) {
|
||||
Firmament.logger.error("Could not load waypoints from clipboard", ex)
|
||||
source.sendError(Text.translatable("firmament.command.waypoint.import.error"))
|
||||
return@thenExecute
|
||||
}
|
||||
waypoints.clear()
|
||||
data.mapTo(waypoints) { BlockPos(it.x, it.y, it.z) }
|
||||
source.sendFeedback(
|
||||
Text.stringifiedTranslatable(
|
||||
"firmament.command.waypoint.import",
|
||||
data.size
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
TickEvent.subscribe {
|
||||
if (waypoints.isEmpty() || !ordered) return@subscribe
|
||||
orderedIndex %= waypoints.size
|
||||
val p = MC.player?.pos ?: return@subscribe
|
||||
if (TConfig.skipToNearest) {
|
||||
orderedIndex =
|
||||
(waypoints.withIndex().minBy { it.value.getSquaredDistance(p) }.index + 1) % waypoints.size
|
||||
} else {
|
||||
if (waypoints[orderedIndex].isWithinDistance(p, 3.0)) {
|
||||
orderedIndex = (orderedIndex + 1) % waypoints.size
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onRenderTemporaryWaypoints(event: WorldRenderLastEvent) {
|
||||
temporaryPlayerWaypointList.entries.removeIf { it.value.postedAt.passedTime() > TConfig.tempWaypointDuration }
|
||||
if (temporaryPlayerWaypointList.isEmpty()) return
|
||||
RenderInWorldContext.renderInWorld(event) {
|
||||
color(1f, 1f, 0f, 1f)
|
||||
temporaryPlayerWaypointList.forEach { (player, waypoint) ->
|
||||
block(waypoint.pos)
|
||||
}
|
||||
color(1f, 1f, 1f, 1f)
|
||||
temporaryPlayerWaypointList.forEach { (player, waypoint) ->
|
||||
val skin =
|
||||
MC.networkHandler?.listedPlayerListEntries?.find { it.profile.name == player }
|
||||
?.skinTextures
|
||||
?.texture
|
||||
withFacingThePlayer(waypoint.pos.toCenterPos()) {
|
||||
waypoint(waypoint.pos, Text.stringifiedTranslatable("firmament.waypoint.temporary", player))
|
||||
if (skin != null) {
|
||||
matrixStack.translate(0F, -20F, 0F)
|
||||
// Head front
|
||||
texture(
|
||||
skin, 16, 16,
|
||||
1 / 8f, 1 / 8f,
|
||||
2 / 8f, 2 / 8f,
|
||||
)
|
||||
// Head overlay
|
||||
texture(
|
||||
skin, 16, 16,
|
||||
5 / 8f, 1 / 8f,
|
||||
6 / 8f, 2 / 8f,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ProcessChatEvent.subscribe {
|
||||
val matcher = temporaryPlayerWaypointMatcher.matcher(it.unformattedString)
|
||||
if (it.nameHeuristic != null && TConfig.tempWaypointDuration > 0.seconds && matcher.find()) {
|
||||
temporaryPlayerWaypointList[it.nameHeuristic] = TemporaryWaypoint(
|
||||
BlockPos(
|
||||
matcher.group(1).toInt(),
|
||||
matcher.group(2).toInt(),
|
||||
matcher.group(3).toInt(),
|
||||
),
|
||||
TimeMark.now()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onWorldReady(event: WorldReadyEvent) {
|
||||
temporaryPlayerWaypointList.clear()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user