Fix up most of the remaining event handlers

[no changelog]
This commit is contained in:
Linnea Gräf
2024-05-07 21:11:09 +02:00
parent 8f3cc34740
commit 93e6e0ab16
25 changed files with 760 additions and 713 deletions

View File

@@ -8,8 +8,11 @@ package moe.nea.firmament.events.subscription
import moe.nea.firmament.events.FirmamentEvent import moe.nea.firmament.events.FirmamentEvent
import moe.nea.firmament.events.FirmamentEventBus import moe.nea.firmament.events.FirmamentEventBus
import moe.nea.firmament.features.FirmamentFeature
interface SubscriptionOwner interface SubscriptionOwner {
val delegateFeature: FirmamentFeature
}
data class Subscription<T : FirmamentEvent>( data class Subscription<T : FirmamentEvent>(
val owner: SubscriptionOwner, val owner: SubscriptionOwner,

View File

@@ -19,7 +19,9 @@ interface FirmamentFeature : SubscriptionOwner {
set(value) { set(value) {
FeatureManager.setEnabled(identifier, value) FeatureManager.setEnabled(identifier, value)
} }
override val delegateFeature: FirmamentFeature
get() = this
val config: ManagedConfig? get() = null val config: ManagedConfig? get() = null
fun onLoad() fun onLoad() {}
} }

View File

@@ -7,6 +7,7 @@
package moe.nea.firmament.features.chat package moe.nea.firmament.features.chat
import com.mojang.brigadier.arguments.StringArgumentType.string import com.mojang.brigadier.arguments.StringArgumentType.string
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.commands.get import moe.nea.firmament.commands.get
import moe.nea.firmament.commands.suggestsList import moe.nea.firmament.commands.suggestsList
import moe.nea.firmament.commands.thenArgument import moe.nea.firmament.commands.thenArgument
@@ -30,28 +31,28 @@ object AutoCompletions : FirmamentFeature {
override val identifier: String override val identifier: String
get() = "auto-completions" get() = "auto-completions"
override fun onLoad() { @Subscribe
MaskCommands.subscribe { fun onMaskCommands(event: MaskCommands) {
if (TConfig.provideWarpTabCompletion) { if (TConfig.provideWarpTabCompletion) {
it.mask("warp") event.mask("warp")
}
} }
CommandEvent.subscribe { }
if (TConfig.provideWarpTabCompletion) {
it.deleteCommand("warp") @Subscribe
it.register("warp") { fun onCommandEvent(event: CommandEvent) {
thenArgument("to", string()) { toArg -> if (!TConfig.provideWarpTabCompletion) return
suggestsList { event.deleteCommand("warp")
RepoManager.neuRepo.constants?.islands?.warps?.flatMap { listOf(it.warp) + it.aliases } ?: listOf() event.register("warp") {
} thenArgument("to", string()) { toArg ->
thenExecute { suggestsList {
val warpName = get(toArg) RepoManager.neuRepo.constants?.islands?.warps?.flatMap { listOf(it.warp) + it.aliases } ?: listOf()
if (warpName == "is" && TConfig.replaceWarpIsByWarpIsland) { }
MC.sendServerCommand("warp island") thenExecute {
} else { val warpName = get(toArg)
MC.sendServerCommand("warp ${warpName}") if (warpName == "is" && TConfig.replaceWarpIsByWarpIsland) {
} MC.sendServerCommand("warp island")
} } else {
MC.sendServerCommand("warp $warpName")
} }
} }
} }

View File

@@ -6,11 +6,11 @@
package moe.nea.firmament.features.chat package moe.nea.firmament.features.chat
import io.ktor.client.request.* import io.ktor.client.request.get
import io.ktor.client.statement.* import io.ktor.client.statement.bodyAsChannel
import io.ktor.utils.io.jvm.javaio.* import io.ktor.utils.io.jvm.javaio.toInputStream
import java.net.URL import java.net.URL
import java.util.* import java.util.Collections
import moe.nea.jarvis.api.Point import moe.nea.jarvis.api.Point
import kotlinx.coroutines.Deferred import kotlinx.coroutines.Deferred
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -26,6 +26,7 @@ import net.minecraft.text.Text
import net.minecraft.util.Formatting import net.minecraft.util.Formatting
import net.minecraft.util.Identifier import net.minecraft.util.Identifier
import moe.nea.firmament.Firmament import moe.nea.firmament.Firmament
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.ModifyChatEvent import moe.nea.firmament.events.ModifyChatEvent
import moe.nea.firmament.events.ScreenRenderPostEvent import moe.nea.firmament.events.ScreenRenderPostEvent
import moe.nea.firmament.features.FirmamentFeature import moe.nea.firmament.features.FirmamentFeature
@@ -96,69 +97,69 @@ object ChatLinks : FirmamentFeature {
return (url.substringAfterLast('.').lowercase() in imageExtensions) return (url.substringAfterLast('.').lowercase() in imageExtensions)
} }
@Subscribe
@OptIn(ExperimentalCoroutinesApi::class) @OptIn(ExperimentalCoroutinesApi::class)
override fun onLoad() { fun onRender(it: ScreenRenderPostEvent) {
ModifyChatEvent.subscribe { if (!TConfig.imageEnabled) return
if (TConfig.enableLinks) if (it.screen !is ChatScreen) return
it.replaceWith = it.replaceWith.transformEachRecursively { child -> val hoveredComponent =
val text = child.string MC.inGameHud.chatHud.getTextStyleAt(it.mouseX.toDouble(), it.mouseY.toDouble()) ?: return
if ("://" !in text) return@transformEachRecursively child val hoverEvent = hoveredComponent.hoverEvent ?: return
val s = Text.empty().setStyle(child.style) val value = hoverEvent.getValue(HoverEvent.Action.SHOW_TEXT) ?: return
var index = 0 val url = urlRegex.matchEntire(value.unformattedString)?.groupValues?.get(0) ?: return
while (index < text.length) { if (!isImageUrl(url)) return
val nextMatch = urlRegex.find(text, index) val imageFuture = imageCache[url] ?: return
if (nextMatch == null) { if (!imageFuture.isCompleted) return
s.append(Text.literal(text.substring(index, text.length))) val image = imageFuture.getCompleted() ?: return
break it.drawContext.matrices.push()
} val pos = TConfig.position
val range = nextMatch.groups[0]!!.range pos.applyTransformations(it.drawContext.matrices)
val url = nextMatch.groupValues[0] val scale = min(1F, min((9 * 20F) / image.height, (16 * 20F) / image.width))
s.append(Text.literal(text.substring(index, range.first))) it.drawContext.matrices.scale(scale, scale, 1F)
s.append( it.drawContext.drawTexture(
Text.literal(url).setStyle( image.texture,
Style.EMPTY.withUnderline(true).withColor( 0,
Formatting.AQUA 0,
).withHoverEvent(HoverEvent(HoverEvent.Action.SHOW_TEXT, Text.literal(url))) 1F,
.withClickEvent(ClickEvent(ClickEvent.Action.OPEN_URL, url)) 1F,
) image.width,
) image.height,
if (isImageUrl(url)) image.width,
tryCacheUrl(url) image.height,
index = range.last + 1 )
} it.drawContext.matrices.pop()
s }
}
}
ScreenRenderPostEvent.subscribe { @Subscribe
if (!TConfig.imageEnabled) return@subscribe fun onModifyChat(it: ModifyChatEvent) {
if (it.screen !is ChatScreen) return@subscribe if (!TConfig.enableLinks) return
val hoveredComponent = it.replaceWith = it.replaceWith.transformEachRecursively { child ->
MC.inGameHud.chatHud.getTextStyleAt(it.mouseX.toDouble(), it.mouseY.toDouble()) ?: return@subscribe val text = child.string
val hoverEvent = hoveredComponent.hoverEvent ?: return@subscribe if ("://" !in text) return@transformEachRecursively child
val value = hoverEvent.getValue(HoverEvent.Action.SHOW_TEXT) ?: return@subscribe val s = Text.empty().setStyle(child.style)
val url = urlRegex.matchEntire(value.unformattedString)?.groupValues?.get(0) ?: return@subscribe var index = 0
if (!isImageUrl(url)) return@subscribe while (index < text.length) {
val imageFuture = imageCache[url] ?: return@subscribe val nextMatch = urlRegex.find(text, index)
if (!imageFuture.isCompleted) return@subscribe if (nextMatch == null) {
val image = imageFuture.getCompleted() ?: return@subscribe s.append(Text.literal(text.substring(index, text.length)))
it.drawContext.matrices.push() break
val pos = TConfig.position }
pos.applyTransformations(it.drawContext.matrices) val range = nextMatch.groups[0]!!.range
val scale = min(1F, min((9 * 20F) / image.height, (16 * 20F) / image.width)) val url = nextMatch.groupValues[0]
it.drawContext.matrices.scale(scale, scale, 1F) s.append(Text.literal(text.substring(index, range.first)))
it.drawContext.drawTexture( s.append(
image.texture, Text.literal(url).setStyle(
0, Style.EMPTY.withUnderline(true).withColor(
0, Formatting.AQUA
1F, ).withHoverEvent(HoverEvent(HoverEvent.Action.SHOW_TEXT, Text.literal(url)))
1F, .withClickEvent(ClickEvent(ClickEvent.Action.OPEN_URL, url))
image.width, )
image.height, )
image.width, if (isImageUrl(url))
image.height, tryCacheUrl(url)
) index = range.last + 1
it.drawContext.matrices.pop() }
s
} }
} }
} }

View File

@@ -8,6 +8,7 @@ package moe.nea.firmament.features.chat
import com.mojang.brigadier.context.CommandContext import com.mojang.brigadier.context.CommandContext
import net.minecraft.text.Text import net.minecraft.text.Text
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.commands.DefaultSource import moe.nea.firmament.commands.DefaultSource
import moe.nea.firmament.commands.RestArgumentType import moe.nea.firmament.commands.RestArgumentType
import moe.nea.firmament.commands.get import moe.nea.firmament.commands.get
@@ -34,28 +35,29 @@ object QuickCommands : FirmamentFeature {
val kuudraLevelNames = listOf("NORMAL", "HOT", "BURNING", "FIERY", "INFERNAL") val kuudraLevelNames = listOf("NORMAL", "HOT", "BURNING", "FIERY", "INFERNAL")
val dungeonLevelNames = listOf("ONE", "TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN") val dungeonLevelNames = listOf("ONE", "TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN")
override fun onLoad() {
CommandEvent.subscribe { @Subscribe
it.register("join") { fun onCommands(it: CommandEvent) {
thenArgument("what", RestArgumentType) { what -> it.register("join") {
thenExecute { thenArgument("what", RestArgumentType) { what ->
val what = this[what] thenExecute {
if (!SBData.isOnSkyblock) { val what = this[what]
MC.sendCommand("join $what") if (!SBData.isOnSkyblock) {
return@thenExecute MC.sendCommand("join $what")
} return@thenExecute
val joinName = getNameForFloor(what.replace(" ", "").lowercase()) }
if (joinName == null) { val joinName = getNameForFloor(what.replace(" ", "").lowercase())
source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.unknown", what)) if (joinName == null) {
} else { source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.unknown", what))
source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.success", joinName)) } else {
MC.sendCommand("joininstance $joinName") 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) { 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 null
} }
return "KUUDRA_${kuudraLevelNames[l]}" return "KUUDRA_${kuudraLevelNames[l]}"
@@ -90,7 +93,8 @@ object QuickCommands : FirmamentFeature {
return "CATACOMBS_ENTRANCE" return "CATACOMBS_ENTRANCE"
} }
if (l !in dungeonLevelNames.indices) { 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 null
} }
return "${if (masterLevel != null) "MASTER_" else ""}CATACOMBS_FLOOR_${dungeonLevelNames[l]}" return "${if (masterLevel != null) "MASTER_" else ""}CATACOMBS_FLOOR_${dungeonLevelNames[l]}"

View File

@@ -55,9 +55,5 @@ object DeveloperFeatures : FirmamentFeature {
} }
return reloadFuture.thenCompose { client.reloadResources() } return reloadFuture.thenCompose { client.reloadResources() }
} }
override fun onLoad() {
}
} }

View File

@@ -6,9 +6,10 @@
package moe.nea.firmament.features.debug 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.events.ModifyChatEvent
import moe.nea.firmament.features.FirmamentFeature import moe.nea.firmament.features.FirmamentFeature
import net.minecraft.text.Text
// In memorian Dulkir // In memorian Dulkir
@@ -19,13 +20,12 @@ object MinorTrolling : FirmamentFeature {
val trollers = listOf("nea89o", "lrg89") val trollers = listOf("nea89o", "lrg89")
val t = "From(?: \\[[^\\]]+])? ([^:]+): (.*)".toRegex() val t = "From(?: \\[[^\\]]+])? ([^:]+): (.*)".toRegex()
override fun onLoad() { @Subscribe
ModifyChatEvent.subscribe { fun onTroll(it: ModifyChatEvent) {
val m = t.matchEntire(it.unformattedString) ?: return@subscribe val m = t.matchEntire(it.unformattedString) ?: return
val (_, name, text) = m.groupValues val (_, name, text) = m.groupValues
if (name !in trollers) return@subscribe if (name !in trollers) return
if (!text.startsWith("c:")) return@subscribe if (!text.startsWith("c:")) return
it.replaceWith = Text.literal(text.substring(2).replace("&", "§")) it.replaceWith = Text.literal(text.substring(2).replace("&", "§"))
}
} }
} }

View File

@@ -15,6 +15,7 @@ import net.minecraft.item.Items
import net.minecraft.text.Text import net.minecraft.text.Text
import net.minecraft.util.hit.BlockHitResult import net.minecraft.util.hit.BlockHitResult
import net.minecraft.util.hit.HitResult import net.minecraft.util.hit.HitResult
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.CustomItemModelEvent import moe.nea.firmament.events.CustomItemModelEvent
import moe.nea.firmament.events.HandledScreenKeyPressedEvent import moe.nea.firmament.events.HandledScreenKeyPressedEvent
import moe.nea.firmament.events.ItemTooltipEvent import moe.nea.firmament.events.ItemTooltipEvent
@@ -54,42 +55,6 @@ object PowerUserTools : FirmamentFeature {
var lastCopiedStackViewTime = false var lastCopiedStackViewTime = false
override fun onLoad() { 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 { TickEvent.subscribe {
if (!lastCopiedStackViewTime) if (!lastCopiedStackViewTime)
lastCopiedStack = null lastCopiedStack = null
@@ -98,57 +63,99 @@ object PowerUserTools : FirmamentFeature {
ScreenChangeEvent.subscribe { ScreenChangeEvent.subscribe {
lastCopiedStack = null lastCopiedStack = null
} }
HandledScreenKeyPressedEvent.subscribe { }
if (it.screen !is AccessorHandledScreen) return@subscribe
val item = it.screen.focusedItemStack ?: return@subscribe @Subscribe
if (it.matches(TConfig.copyItemId)) { fun copyInventoryInfo(it: HandledScreenKeyPressedEvent) {
val sbId = item.skyBlockId if (it.screen !is AccessorHandledScreen) return
if (sbId == null) { val item = it.screen.focusedItemStack ?: return
lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skyblockid.fail")) if (it.matches(TConfig.copyItemId)) {
return@subscribe val sbId = item.skyBlockId
} if (sbId == null) {
ClipboardUtils.setTextContent(sbId.neuItem) lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skyblockid.fail"))
lastCopiedStack = return
Pair(item, Text.stringifiedTranslatable("firmament.tooltip.copied.skyblockid", sbId.neuItem)) }
} else if (it.matches(TConfig.copyTexturePackId)) { ClipboardUtils.setTextContent(sbId.neuItem)
val model = CustomItemModelEvent.getModelIdentifier(item) lastCopiedStack =
if (model == null) { Pair(item, Text.stringifiedTranslatable("firmament.tooltip.copied.skyblockid", sbId.neuItem))
lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.modelid.fail")) } else if (it.matches(TConfig.copyTexturePackId)) {
return@subscribe val model = CustomItemModelEvent.getModelIdentifier(item)
} if (model == null) {
ClipboardUtils.setTextContent(model.toString()) lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.modelid.fail"))
lastCopiedStack = return
Pair(item, Text.stringifiedTranslatable("firmament.tooltip.copied.modelid", model.toString())) }
} else if (it.matches(TConfig.copyNbtData)) { ClipboardUtils.setTextContent(model.toString())
// TODO: copy full nbt lastCopiedStack =
val nbt = item.get(DataComponentTypes.CUSTOM_DATA)?.nbt?.toString() ?: "<empty>" Pair(item, Text.stringifiedTranslatable("firmament.tooltip.copied.modelid", model.toString()))
ClipboardUtils.setTextContent(nbt) } else if (it.matches(TConfig.copyNbtData)) {
lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.nbt")) // TODO: copy full nbt
} else if (it.matches(TConfig.copySkullTexture)) { val nbt = item.get(DataComponentTypes.CUSTOM_DATA)?.nbt?.toString() ?: "<empty>"
if (item.item != Items.PLAYER_HEAD) { ClipboardUtils.setTextContent(nbt)
lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skull-id.fail.no-skull")) lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.nbt"))
return@subscribe } else if (it.matches(TConfig.copySkullTexture)) {
} if (item.item != Items.PLAYER_HEAD) {
val profile = item.get(DataComponentTypes.PROFILE) lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skull-id.fail.no-skull"))
if (profile == null) { return
lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skull-id.fail.no-profile")) }
return@subscribe val profile = item.get(DataComponentTypes.PROFILE)
} if (profile == null) {
val skullTexture = CustomSkyBlockTextures.getSkullTexture(profile) lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skull-id.fail.no-profile"))
if (skullTexture == null) { return
lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skull-id.fail.no-texture")) }
return@subscribe val skullTexture = CustomSkyBlockTextures.getSkullTexture(profile)
} if (skullTexture == null) {
ClipboardUtils.setTextContent(skullTexture.toString()) lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skull-id.fail.no-texture"))
lastCopiedStack = return
Pair( }
item, ClipboardUtils.setTextContent(skullTexture.toString())
Text.stringifiedTranslatable("firmament.tooltip.copied.skull-id", skullTexture.toString()) lastCopiedStack =
) Pair(
println("Copied skull id: $skullTexture") 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)
}
} }

View File

@@ -10,17 +10,20 @@ import kotlin.time.Duration.Companion.seconds
import net.minecraft.particle.ParticleTypes import net.minecraft.particle.ParticleTypes
import net.minecraft.sound.SoundEvents import net.minecraft.sound.SoundEvents
import net.minecraft.util.math.Vec3d import net.minecraft.util.math.Vec3d
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.ParticleSpawnEvent import moe.nea.firmament.events.ParticleSpawnEvent
import moe.nea.firmament.events.SoundReceiveEvent import moe.nea.firmament.events.SoundReceiveEvent
import moe.nea.firmament.events.WorldKeyboardEvent import moe.nea.firmament.events.WorldKeyboardEvent
import moe.nea.firmament.events.WorldReadyEvent import moe.nea.firmament.events.WorldReadyEvent
import moe.nea.firmament.events.WorldRenderLastEvent 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.SBData
import moe.nea.firmament.util.TimeMark import moe.nea.firmament.util.TimeMark
import moe.nea.firmament.util.WarpUtil import moe.nea.firmament.util.WarpUtil
import moe.nea.firmament.util.render.RenderInWorldContext import moe.nea.firmament.util.render.RenderInWorldContext
object AncestralSpadeSolver { object AncestralSpadeSolver : SubscriptionOwner {
var lastDing = TimeMark.farPast() var lastDing = TimeMark.farPast()
private set private set
private val pitches = mutableListOf<Float>() private val pitches = mutableListOf<Float>()
@@ -33,6 +36,7 @@ object AncestralSpadeSolver {
fun isEnabled() = fun isEnabled() =
DianaWaypoints.TConfig.ancestralSpadeSolver && SBData.skyblockLocation == "hub" DianaWaypoints.TConfig.ancestralSpadeSolver && SBData.skyblockLocation == "hub"
@Subscribe
fun onKeyBind(event: WorldKeyboardEvent) { fun onKeyBind(event: WorldKeyboardEvent) {
if (!isEnabled()) return if (!isEnabled()) return
if (!event.matches(DianaWaypoints.TConfig.ancestralSpadeTeleport)) return if (!event.matches(DianaWaypoints.TConfig.ancestralSpadeTeleport)) return
@@ -42,6 +46,7 @@ object AncestralSpadeSolver {
lastTeleportAttempt = TimeMark.now() lastTeleportAttempt = TimeMark.now()
} }
@Subscribe
fun onParticleSpawn(event: ParticleSpawnEvent) { fun onParticleSpawn(event: ParticleSpawnEvent) {
if (!isEnabled()) return if (!isEnabled()) return
if (event.particleEffect != ParticleTypes.DRIPPING_LAVA) return if (event.particleEffect != ParticleTypes.DRIPPING_LAVA) return
@@ -53,6 +58,7 @@ object AncestralSpadeSolver {
} }
} }
@Subscribe
fun onPlaySound(event: SoundReceiveEvent) { fun onPlaySound(event: SoundReceiveEvent) {
if (!isEnabled()) return if (!isEnabled()) return
if (!SoundEvents.BLOCK_NOTE_BLOCK_HARP.matchesId(event.sound.value().id)) 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)) nextGuess = event.position.add(lastParticleDirection.multiply(soundDistanceEstimate))
} }
@Subscribe
fun onWorldRender(event: WorldRenderLastEvent) { fun onWorldRender(event: WorldRenderLastEvent) {
if (!isEnabled()) return if (!isEnabled()) return
RenderInWorldContext.renderInWorld(event) { RenderInWorldContext.renderInWorld(event) {
@@ -108,6 +115,7 @@ object AncestralSpadeSolver {
} }
} }
@Subscribe
fun onSwapWorld(event: WorldReadyEvent) { fun onSwapWorld(event: WorldReadyEvent) {
nextGuess = null nextGuess = null
particlePositions.clear() particlePositions.clear()
@@ -115,4 +123,7 @@ object AncestralSpadeSolver {
lastDing = TimeMark.farPast() lastDing = TimeMark.farPast()
} }
override val delegateFeature: FirmamentFeature
get() = DianaWaypoints
} }

View File

@@ -28,23 +28,12 @@ object DianaWaypoints : FirmamentFeature {
} }
override fun onLoad() { override fun onLoad() {
ParticleSpawnEvent.subscribe(NearbyBurrowsSolver::onParticles)
WorldReadyEvent.subscribe(NearbyBurrowsSolver::onSwapWorld)
WorldRenderLastEvent.subscribe(NearbyBurrowsSolver::onRender)
UseBlockEvent.subscribe { UseBlockEvent.subscribe {
NearbyBurrowsSolver.onBlockClick(it.hitResult.blockPos) NearbyBurrowsSolver.onBlockClick(it.hitResult.blockPos)
} }
AttackBlockEvent.subscribe { AttackBlockEvent.subscribe {
NearbyBurrowsSolver.onBlockClick(it.blockPos) 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)
} }
} }

View File

@@ -11,15 +11,18 @@ import net.minecraft.particle.ParticleTypes
import net.minecraft.util.math.BlockPos import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.MathHelper import net.minecraft.util.math.MathHelper
import net.minecraft.util.math.Position import net.minecraft.util.math.Position
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.ParticleSpawnEvent import moe.nea.firmament.events.ParticleSpawnEvent
import moe.nea.firmament.events.ProcessChatEvent import moe.nea.firmament.events.ProcessChatEvent
import moe.nea.firmament.events.WorldReadyEvent import moe.nea.firmament.events.WorldReadyEvent
import moe.nea.firmament.events.WorldRenderLastEvent 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.TimeMark
import moe.nea.firmament.util.mutableMapWithMaxSize import moe.nea.firmament.util.mutableMapWithMaxSize
import moe.nea.firmament.util.render.RenderInWorldContext.Companion.renderInWorld import moe.nea.firmament.util.render.RenderInWorldContext.Companion.renderInWorld
object NearbyBurrowsSolver { object NearbyBurrowsSolver : SubscriptionOwner {
private val recentlyDugBurrows: MutableMap<BlockPos, TimeMark> = mutableMapWithMaxSize(20) private val recentlyDugBurrows: MutableMap<BlockPos, TimeMark> = mutableMapWithMaxSize(20)
@@ -32,6 +35,7 @@ object NearbyBurrowsSolver {
val burrows = mutableMapOf<BlockPos, BurrowType>() val burrows = mutableMapOf<BlockPos, BurrowType>()
@Subscribe
fun onChatEvent(event: ProcessChatEvent) { fun onChatEvent(event: ProcessChatEvent) {
val lastClickedBurrow = lastBlockClick ?: return val lastClickedBurrow = lastBlockClick ?: return
if (event.unformattedString.startsWith("You dug out a Griffin Burrow!") || if (event.unformattedString.startsWith("You dug out a Griffin Burrow!") ||
@@ -62,6 +66,7 @@ object NearbyBurrowsSolver {
recentEnchantParticles[blockPos] = TimeMark.now() recentEnchantParticles[blockPos] = TimeMark.now()
} }
@Subscribe
fun onParticles(event: ParticleSpawnEvent) { fun onParticles(event: ParticleSpawnEvent) {
if (!DianaWaypoints.TConfig.nearbyWaypoints) return if (!DianaWaypoints.TConfig.nearbyWaypoints) return
@@ -106,6 +111,7 @@ object NearbyBurrowsSolver {
} }
} }
@Subscribe
fun onRender(event: WorldRenderLastEvent) { fun onRender(event: WorldRenderLastEvent) {
if (!DianaWaypoints.TConfig.nearbyWaypoints) return if (!DianaWaypoints.TConfig.nearbyWaypoints) return
renderInWorld(event) { renderInWorld(event) {
@@ -120,6 +126,7 @@ object NearbyBurrowsSolver {
} }
} }
@Subscribe
fun onSwapWorld(worldReadyEvent: WorldReadyEvent) { fun onSwapWorld(worldReadyEvent: WorldReadyEvent) {
burrows.clear() burrows.clear()
recentEnchantParticles.clear() recentEnchantParticles.clear()
@@ -132,6 +139,9 @@ object NearbyBurrowsSolver {
burrows.remove(blockPos) burrows.remove(blockPos)
lastBlockClick = blockPos lastBlockClick = blockPos
} }
override val delegateFeature: FirmamentFeature
get() = DianaWaypoints
} }
fun Position.toBlockPos(): BlockPos { fun Position.toBlockPos(): BlockPos {

View File

@@ -10,6 +10,7 @@ import net.fabricmc.loader.api.FabricLoader
import net.superkat.explosiveenhancement.api.ExplosiveApi import net.superkat.explosiveenhancement.api.ExplosiveApi
import net.minecraft.particle.ParticleTypes import net.minecraft.particle.ParticleTypes
import net.minecraft.util.math.Vec3d import net.minecraft.util.math.Vec3d
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.ParticleSpawnEvent import moe.nea.firmament.events.ParticleSpawnEvent
import moe.nea.firmament.features.FirmamentFeature import moe.nea.firmament.features.FirmamentFeature
import moe.nea.firmament.gui.config.ManagedConfig import moe.nea.firmament.gui.config.ManagedConfig
@@ -41,15 +42,14 @@ object CompatibliltyFeatures : FirmamentFeature {
ExplosiveApiWrapperImpl() ExplosiveApiWrapperImpl()
} else null } else null
override fun onLoad() { @Subscribe
ParticleSpawnEvent.subscribe { fun onExplosion(it: ParticleSpawnEvent) {
if (TConfig.enhancedExplosions && if (TConfig.enhancedExplosions &&
it.particleEffect.type == ParticleTypes.EXPLOSION_EMITTER && it.particleEffect.type == ParticleTypes.EXPLOSION_EMITTER &&
explosiveApiWrapper != null explosiveApiWrapper != null
) { ) {
it.cancel() it.cancel()
explosiveApiWrapper.spawnParticle(it.position, 2F) explosiveApiWrapper.spawnParticle(it.position, 2F)
}
} }
} }
} }

View File

@@ -13,6 +13,7 @@ import net.minecraft.client.option.KeyBinding
import net.minecraft.entity.player.PlayerEntity import net.minecraft.entity.player.PlayerEntity
import net.minecraft.text.Text import net.minecraft.text.Text
import net.minecraft.util.Arm import net.minecraft.util.Arm
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.HudRenderEvent import moe.nea.firmament.events.HudRenderEvent
import moe.nea.firmament.events.WorldKeyboardEvent import moe.nea.firmament.events.WorldKeyboardEvent
import moe.nea.firmament.features.FirmamentFeature import moe.nea.firmament.features.FirmamentFeature
@@ -50,27 +51,28 @@ object Fixes : FirmamentFeature {
} }
} }
override fun onLoad() { @Subscribe
WorldKeyboardEvent.subscribe { fun onRenderHud(it: HudRenderEvent) {
if (it.matches(TConfig.autoSprintKeyBinding)) { if (!TConfig.autoSprintKeyBinding.isBound) return
TConfig.autoSprint = !TConfig.autoSprint it.context.matrices.push()
} TConfig.autoSprintHud.applyTransformations(it.context.matrices)
} it.context.drawText(
HudRenderEvent.subscribe { MC.font, Text.translatable(
if (!TConfig.autoSprintKeyBinding.isBound) return@subscribe if (TConfig.autoSprint)
it.context.matrices.push() "firmament.fixes.auto-sprint.on"
TConfig.autoSprintHud.applyTransformations(it.context.matrices) else if (MC.player?.isSprinting == true)
it.context.drawText( "firmament.fixes.auto-sprint.sprinting"
MC.font, Text.translatable( else
if (TConfig.autoSprint) "firmament.fixes.auto-sprint.not-sprinting"
"firmament.fixes.auto-sprint.on" ), 0, 0, -1, false
else if (MC.player?.isSprinting == true) )
"firmament.fixes.auto-sprint.sprinting" it.context.matrices.pop()
else }
"firmament.fixes.auto-sprint.not-sprinting"
), 0, 0, -1, false @Subscribe
) fun onWorldKeyboard(it: WorldKeyboardEvent) {
it.context.matrices.pop() if (it.matches(TConfig.autoSprintKeyBinding)) {
TConfig.autoSprint = !TConfig.autoSprint
} }
} }

View File

@@ -9,11 +9,12 @@ package moe.nea.firmament.features.inventory
import net.minecraft.client.gui.screen.ingame.GenericContainerScreen import net.minecraft.client.gui.screen.ingame.GenericContainerScreen
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.minecraft.util.Formatting import net.minecraft.util.Formatting
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.SlotRenderEvents import moe.nea.firmament.events.SlotRenderEvents
import moe.nea.firmament.features.FirmamentFeature 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.FirmamentReiPlugin.Companion.asItemEntry
import moe.nea.firmament.rei.SBItemEntryDefinition import moe.nea.firmament.rei.SBItemEntryDefinition
import moe.nea.firmament.rei.recipes.SBCraftingRecipe
import moe.nea.firmament.util.MC import moe.nea.firmament.util.MC
object CraftingOverlay : FirmamentFeature { object CraftingOverlay : FirmamentFeature {
@@ -35,36 +36,35 @@ object CraftingOverlay : FirmamentFeature {
override val identifier: String override val identifier: String
get() = "crafting-overlay" get() = "crafting-overlay"
override fun onLoad() { @Subscribe
SlotRenderEvents.After.subscribe { event -> fun onSlotRender(event: SlotRenderEvents.After) {
val slot = event.slot val slot = event.slot
val recipe = this.recipe ?: return@subscribe val recipe = this.recipe ?: return
if (slot.inventory != screen?.screenHandler?.inventory) return@subscribe if (slot.inventory != screen?.screenHandler?.inventory) return
val recipeIndex = craftingOverlayIndices.indexOf(slot.index) val recipeIndex = craftingOverlayIndices.indexOf(slot.index)
if (recipeIndex < 0) return@subscribe if (recipeIndex < 0) return
val expectedItem = recipe.neuRecipe.inputs[recipeIndex] val expectedItem = recipe.neuRecipe.inputs[recipeIndex]
val actualStack = slot.stack ?: ItemStack.EMPTY!! val actualStack = slot.stack ?: ItemStack.EMPTY!!
val actualEntry = SBItemEntryDefinition.getEntry(actualStack).value val actualEntry = SBItemEntryDefinition.getEntry(actualStack).value
if ((actualEntry.skyblockId.neuItem != expectedItem.itemId || actualEntry.stackSize < expectedItem.amount) && expectedItem.amount.toInt() != 0) { if ((actualEntry.skyblockId.neuItem != expectedItem.itemId || actualEntry.stackSize < expectedItem.amount) && expectedItem.amount.toInt() != 0) {
event.context.fill( event.context.fill(
event.slot.x, event.slot.x,
event.slot.y, event.slot.y,
event.slot.x + 16, event.slot.x + 16,
event.slot.y + 16, event.slot.y + 16,
0x80FF0000.toInt() 0x80FF0000.toInt()
) )
} }
if (!slot.hasStack()) { if (!slot.hasStack()) {
val itemStack = SBItemEntryDefinition.getEntry(expectedItem).asItemEntry().value val itemStack = SBItemEntryDefinition.getEntry(expectedItem).asItemEntry().value
event.context.drawItem(itemStack, event.slot.x, event.slot.y) event.context.drawItem(itemStack, event.slot.x, event.slot.y)
event.context.drawItemInSlot( event.context.drawItemInSlot(
MC.font, MC.font,
itemStack, itemStack,
event.slot.x, event.slot.x,
event.slot.y, event.slot.y,
"${Formatting.RED}${expectedItem.amount.toInt()}" "${Formatting.RED}${expectedItem.amount.toInt()}"
) )
}
} }
} }
} }

View File

@@ -12,6 +12,7 @@ import net.minecraft.client.gui.DrawContext
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.minecraft.util.Formatting import net.minecraft.util.Formatting
import net.minecraft.util.Identifier import net.minecraft.util.Identifier
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.HotbarItemRenderEvent import moe.nea.firmament.events.HotbarItemRenderEvent
import moe.nea.firmament.events.SlotRenderEvents import moe.nea.firmament.events.SlotRenderEvents
import moe.nea.firmament.features.FirmamentFeature import moe.nea.firmament.features.FirmamentFeature
@@ -65,16 +66,18 @@ object ItemRarityCosmetics : FirmamentFeature {
) )
} }
override fun onLoad() {
HotbarItemRenderEvent.subscribe { @Subscribe
if (!TConfig.showItemRarityInHotbar) return@subscribe fun onRenderSlot(it: SlotRenderEvents.Before) {
val stack = it.item if (!TConfig.showItemRarityBackground) return
drawItemStackRarity(it.context, it.x, it.y, stack) val stack = it.slot.stack ?: return
} drawItemStackRarity(it.context, it.slot.x, it.slot.y, stack)
SlotRenderEvents.Before.subscribe { }
if (!TConfig.showItemRarityBackground) return@subscribe
val stack = it.slot.stack ?: return@subscribe @Subscribe
drawItemStackRarity(it.context, it.slot.x, it.slot.y, stack) fun onRenderHotbarItem(it: HotbarItemRenderEvent) {
} if (!TConfig.showItemRarityInHotbar) return
val stack = it.item
drawItemStackRarity(it.context, it.x, it.y, stack)
} }
} }

View File

@@ -27,11 +27,8 @@ object PriceData : FirmamentFeature {
override val config get() = TConfig override val config get() = TConfig
override fun onLoad() {
}
@Subscribe @Subscribe
fun function(it: ItemTooltipEvent) { fun onItemTooltip(it: ItemTooltipEvent) {
if (!TConfig.tooltipEnabled && !TConfig.enableKeybinding.isPressed()) { if (!TConfig.tooltipEnabled && !TConfig.enableKeybinding.isPressed()) {
return return
} }

View File

@@ -27,10 +27,6 @@ object SaveCursorPosition : FirmamentFeature {
override val config: TConfig override val config: TConfig
get() = TConfig get() = TConfig
override fun onLoad() {
}
var savedPositionedP1: Pair<Double, Double>? = null var savedPositionedP1: Pair<Double, Double>? = null
var savedPosition: SavedPosition? = null var savedPosition: SavedPosition? = null

View File

@@ -10,7 +10,7 @@
package moe.nea.firmament.features.inventory package moe.nea.firmament.features.inventory
import com.mojang.blaze3d.systems.RenderSystem import com.mojang.blaze3d.systems.RenderSystem
import java.util.* import java.util.UUID
import org.lwjgl.glfw.GLFW import org.lwjgl.glfw.GLFW
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers import kotlinx.serialization.UseSerializers
@@ -18,6 +18,7 @@ import kotlinx.serialization.serializer
import net.minecraft.client.gui.screen.ingame.HandledScreen import net.minecraft.client.gui.screen.ingame.HandledScreen
import net.minecraft.entity.player.PlayerInventory import net.minecraft.entity.player.PlayerInventory
import net.minecraft.screen.GenericContainerScreenHandler import net.minecraft.screen.GenericContainerScreenHandler
import net.minecraft.screen.slot.Slot
import net.minecraft.screen.slot.SlotActionType import net.minecraft.screen.slot.SlotActionType
import net.minecraft.util.Identifier import net.minecraft.util.Identifier
import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.annotations.Subscribe
@@ -96,81 +97,89 @@ object SlotLocking : FirmamentFeature {
return (lore.lastOrNull() ?: return false).unformattedString == "Click to buyback!" return (lore.lastOrNull() ?: return false).unformattedString == "Click to buyback!"
} }
override fun onLoad() { @Subscribe
HandledScreenKeyPressedEvent.subscribe { fun onSalvageProtect(event: IsSlotProtectedEvent) {
if (!it.matches(TConfig.lockSlot)) return@subscribe if (event.slot == null) return
val inventory = MC.handledScreen ?: return@subscribe if (!event.slot.hasStack()) return
inventory as AccessorHandledScreen if (event.slot.stack.displayNameAccordingToNbt?.unformattedString != "Salvage Items") return
val inv = event.slot.inventory
val slot = inventory.focusedSlot_Firmament ?: return@subscribe var anyBlocked = false
val lockedSlots = lockedSlots ?: return@subscribe for (i in 0 until event.slot.index) {
if (slot.inventory is PlayerInventory) { val stack = inv.getStack(i)
if (slot.index in lockedSlots) { if (IsSlotProtectedEvent.shouldBlockInteraction(null, SlotActionType.THROW, stack))
lockedSlots.remove(slot.index) anyBlocked = true
} else {
lockedSlots.add(slot.index)
}
DConfig.markDirty()
CommonSoundEffects.playSuccess()
}
} }
HandledScreenKeyPressedEvent.subscribe { if (anyBlocked) {
if (!it.matches(TConfig.lockUUID)) return@subscribe event.protectSilent()
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()
}
} }
} }
@Subscribe @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 isSlotLocked = it.slot.inventory is PlayerInventory && it.slot.index in (lockedSlots ?: setOf())
val isUUIDLocked = (it.slot.stack?.skyblockUUID) in (lockedUUIDs ?: setOf()) val isUUIDLocked = (it.slot.stack?.skyblockUUID) in (lockedUUIDs ?: setOf())
if (isSlotLocked || isUUIDLocked) { if (isSlotLocked || isUUIDLocked) {

View File

@@ -9,6 +9,7 @@ package moe.nea.firmament.features.inventory.buttons
import me.shedaniel.math.Rectangle import me.shedaniel.math.Rectangle
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.serializer import kotlinx.serialization.serializer
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.HandledScreenClickEvent import moe.nea.firmament.events.HandledScreenClickEvent
import moe.nea.firmament.events.HandledScreenForegroundEvent import moe.nea.firmament.events.HandledScreenForegroundEvent
import moe.nea.firmament.events.HandledScreenPushREIEvent import moe.nea.firmament.events.HandledScreenPushREIEvent
@@ -28,6 +29,7 @@ object InventoryButtons : FirmamentFeature {
openEditor() openEditor()
} }
} }
object DConfig : DataHolder<Data>(serializer(), identifier, ::Data) object DConfig : DataHolder<Data>(serializer(), identifier, ::Data)
@Serializable @Serializable
@@ -40,35 +42,39 @@ object InventoryButtons : FirmamentFeature {
get() = TConfig get() = TConfig
fun getValidButtons() = DConfig.data.buttons.asSequence().filter { it.isValid() } fun getValidButtons() = DConfig.data.buttons.asSequence().filter { it.isValid() }
override fun onLoad() {
HandledScreenForegroundEvent.subscribe { @Subscribe
val bounds = it.screen.getRectangle() fun onRectangles(it: HandledScreenPushREIEvent) {
for (button in getValidButtons()) { val bounds = it.screen.getRectangle()
val buttonBounds = button.getBounds(bounds) for (button in getValidButtons()) {
it.context.matrices.push() val buttonBounds = button.getBounds(bounds)
it.context.matrices.translate(buttonBounds.minX.toFloat(), buttonBounds.minY.toFloat(), 0F) it.block(buttonBounds)
button.render(it.context)
it.context.matrices.pop()
}
lastRectangle = bounds
} }
HandledScreenClickEvent.subscribe { }
val bounds = it.screen.getRectangle()
for (button in getValidButtons()) { @Subscribe
val buttonBounds = button.getBounds(bounds) fun onClickScreen(it: HandledScreenClickEvent) {
if (buttonBounds.contains(it.mouseX, it.mouseY)) { val bounds = it.screen.getRectangle()
MC.sendCommand(button.command!! /* non null invariant covered by getValidButtons */) for (button in getValidButtons()) {
break 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()) { @Subscribe
val buttonBounds = button.getBounds(bounds) fun onRenderForeground(it: HandledScreenForegroundEvent) {
it.block(buttonBounds) 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 var lastRectangle: Rectangle? = null

View File

@@ -6,9 +6,10 @@
package moe.nea.firmament.features.inventory.storageoverlay package moe.nea.firmament.features.inventory.storageoverlay
import java.util.* import java.util.SortedMap
import kotlinx.serialization.serializer import kotlinx.serialization.serializer
import net.minecraft.client.gui.screen.Screen import net.minecraft.client.gui.screen.Screen
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.ScreenChangeEvent import moe.nea.firmament.events.ScreenChangeEvent
import moe.nea.firmament.events.TickEvent import moe.nea.firmament.events.TickEvent
import moe.nea.firmament.features.FirmamentFeature import moe.nea.firmament.features.FirmamentFeature
@@ -40,31 +41,33 @@ object StorageOverlay : FirmamentFeature {
var shouldReturnToStorageOverlay: Screen? = null var shouldReturnToStorageOverlay: Screen? = null
var currentHandler: StorageBackingHandle? = StorageBackingHandle.None var currentHandler: StorageBackingHandle? = StorageBackingHandle.None
override fun onLoad() { @Subscribe
ScreenChangeEvent.subscribe { fun onTick(event: TickEvent) {
if (lastStorageOverlay != null && it.new != null) { rememberContent(currentHandler ?: return)
shouldReturnToStorageOverlay = lastStorageOverlay }
shouldReturnToStorageOverlayFrom = it.new
lastStorageOverlay = null
} else if (it.old === shouldReturnToStorageOverlayFrom) {
if (shouldReturnToStorageOverlay != null && it.new == null)
setScreenLater(shouldReturnToStorageOverlay)
shouldReturnToStorageOverlay = null
shouldReturnToStorageOverlayFrom = null
}
}
ScreenChangeEvent.subscribe { event -> @Subscribe
currentHandler = StorageBackingHandle.fromScreen(event.new) fun onScreenChangeLegacy(event: ScreenChangeEvent) {
if (event.old is StorageOverlayScreen && !event.old.isClosing) { currentHandler = StorageBackingHandle.fromScreen(event.new)
event.old.setHandler(currentHandler) if (event.old is StorageOverlayScreen && !event.old.isClosing) {
if (currentHandler != null) event.old.setHandler(currentHandler)
// TODO: Consider instead only replacing rendering? might make a lot of stack handling easier if (currentHandler != null)
event.cancel() // 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
} }
} }

View File

@@ -13,6 +13,7 @@ import net.minecraft.item.ItemStack
import net.minecraft.util.DyeColor import net.minecraft.util.DyeColor
import net.minecraft.util.Hand import net.minecraft.util.Hand
import net.minecraft.util.Identifier import net.minecraft.util.Identifier
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.HudRenderEvent import moe.nea.firmament.events.HudRenderEvent
import moe.nea.firmament.events.ProcessChatEvent import moe.nea.firmament.events.ProcessChatEvent
import moe.nea.firmament.events.SlotClickEvent import moe.nea.firmament.events.SlotClickEvent
@@ -73,53 +74,57 @@ object PickaxeAbility : FirmamentFeature {
return 1.0 return 1.0
} }
override fun onLoad() { @Subscribe
HudRenderEvent.subscribe(this::renderHud) fun onSlotClick(it: SlotClickEvent) {
WorldReadyEvent.subscribe { if (MC.screen?.title?.unformattedString == "Heart of the Mountain") {
lastUsage.clear() val name = it.stack.displayNameAccordingToNbt?.unformattedString ?: return
lobbyJoinTime = TimeMark.now() val cooldown = it.stack.loreAccordingToNbt.firstNotNullOfOrNull {
abilityOverride = null cooldownPattern.useMatch(it.unformattedString) {
} parseTimePattern(group("cooldown"))
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"))
} }
} ?: return@subscribe } ?: return
val extra = it.item.extraAttributes defaultAbilityDurations[name] = cooldown
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
)
} }
SlotClickEvent.subscribe { }
if (MC.screen?.title?.unformattedString == "Heart of the Mountain") {
val name = it.stack.displayNameAccordingToNbt?.unformattedString ?: return@subscribe @Subscribe
val cooldown = it.stack.loreAccordingToNbt.firstNotNullOfOrNull { fun onDurabilityBar(it: DurabilityBarEvent) {
cooldownPattern.useMatch(it.unformattedString) { if (!TConfig.drillFuelBar) return
parseTimePattern(group("cooldown")) val lore = it.item.loreAccordingToNbt
} if (lore.lastOrNull()?.unformattedString?.contains("DRILL") != true) return
} ?: return@subscribe val maxFuel = lore.firstNotNullOfOrNull {
defaultAbilityDurations[name] = cooldown 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!") 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!") 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 if (!TConfig.cooldownEnabled) return
var ability = getCooldownFromLore(MC.player?.getStackInHand(Hand.MAIN_HAND) ?: return) ?: return var ability = getCooldownFromLore(MC.player?.getStackInHand(Hand.MAIN_HAND) ?: return) ?: return
defaultAbilityDurations[ability.name] = ability.cooldown defaultAbilityDurations[ability.name] = ability.cooldown

View File

@@ -12,6 +12,7 @@ import kotlinx.serialization.Serializable
import kotlinx.serialization.serializer import kotlinx.serialization.serializer
import kotlin.time.Duration.Companion.seconds import kotlin.time.Duration.Companion.seconds
import net.minecraft.text.Text import net.minecraft.text.Text
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.ProcessChatEvent import moe.nea.firmament.events.ProcessChatEvent
import moe.nea.firmament.features.FirmamentFeature import moe.nea.firmament.features.FirmamentFeature
import moe.nea.firmament.gui.config.ManagedConfig import moe.nea.firmament.gui.config.ManagedConfig
@@ -62,7 +63,7 @@ object PristineProfitTracker : FirmamentFeature {
val pristineRegex = val pristineRegex =
"PRISTINE! You found . Flawed (?<kind>${ "PRISTINE! You found . Flawed (?<kind>${
GemstoneKind.values().joinToString("|") { it.label } GemstoneKind.entries.joinToString("|") { it.label }
}) Gemstone x(?<count>[0-9,]+)!".toPattern() }) Gemstone x(?<count>[0-9,]+)!".toPattern()
val collectionHistogram = Histogram<Double>(10000, 180.seconds) val collectionHistogram = Histogram<Double>(10000, 180.seconds)
@@ -97,9 +98,13 @@ object PristineProfitTracker : FirmamentFeature {
val moneyPerSecond = moneyHistogram.averagePer({ it }, 1.seconds) val moneyPerSecond = moneyHistogram.averagePer({ it }, 1.seconds)
if (collectionPerSecond == null || moneyPerSecond == null) return if (collectionPerSecond == null || moneyPerSecond == null) return
ProfitHud.collectionCurrent = collectionPerSecond 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.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 val data = DConfig.data
if (data != null) { if (data != null) {
if (data.maxCollectionPerSecond < collectionPerSecond && collectionHistogram.oldestUpdate() if (data.maxCollectionPerSecond < collectionPerSecond && collectionHistogram.oldestUpdate()
@@ -118,17 +123,16 @@ object PristineProfitTracker : FirmamentFeature {
} }
override fun onLoad() { @Subscribe
ProcessChatEvent.subscribe { fun onMessage(it: ProcessChatEvent) {
pristineRegex.useMatch(it.unformattedString) { pristineRegex.useMatch(it.unformattedString) {
val gemstoneKind = GemstoneKind.valueOf(group("kind").uppercase()) val gemstoneKind = GemstoneKind.valueOf(group("kind").uppercase())
val flawedCount = parseIntWithComma(group("count")) val flawedCount = parseIntWithComma(group("count"))
val moneyAmount = sellingStrategy.getSellPrice(gemstoneKind.flawedId) * flawedCount val moneyAmount = sellingStrategy.getSellPrice(gemstoneKind.flawedId) * flawedCount
moneyHistogram.record(moneyAmount) moneyHistogram.record(moneyAmount)
val collectionAmount = flawedCount * ROUGHS_PER_FLAWED val collectionAmount = flawedCount * ROUGHS_PER_FLAWED
collectionHistogram.record(collectionAmount.toDouble()) collectionHistogram.record(collectionAmount.toDouble())
updateUi() updateUi()
}
} }
} }
} }

View File

@@ -16,6 +16,7 @@ import net.minecraft.client.render.RenderLayer
import net.minecraft.client.util.ModelIdentifier import net.minecraft.client.util.ModelIdentifier
import net.minecraft.component.type.ProfileComponent import net.minecraft.component.type.ProfileComponent
import net.minecraft.util.Identifier import net.minecraft.util.Identifier
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.CustomItemModelEvent import moe.nea.firmament.events.CustomItemModelEvent
import moe.nea.firmament.events.TickEvent import moe.nea.firmament.events.TickEvent
import moe.nea.firmament.features.FirmamentFeature import moe.nea.firmament.features.FirmamentFeature
@@ -38,20 +39,21 @@ object CustomSkyBlockTextures : FirmamentFeature {
override val config: ManagedConfig override val config: ManagedConfig
get() = TConfig get() = TConfig
override fun onLoad() { @Subscribe
CustomItemModelEvent.subscribe { fun onTick(it: TickEvent) {
if (!TConfig.enabled) return@subscribe if (TConfig.cacheDuration < 1 || it.tickCount % TConfig.cacheDuration == 0) {
val id = it.itemStack.skyBlockId ?: return@subscribe CustomItemModelEvent.clearCache()
it.overrideModel = ModelIdentifier("firmskyblock", id.identifier.path, "inventory") skullTextureCache.clear()
}
TickEvent.subscribe {
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 skullTextureCache = mutableMapOf<IdentityCharacteristics<ProfileComponent>, Any>()
private val sentinelPresentInvalid = Object() private val sentinelPresentInvalid = Object()

View File

@@ -9,15 +9,10 @@ package moe.nea.firmament.features.world
import io.github.moulberry.repo.data.Coordinate import io.github.moulberry.repo.data.Coordinate
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.serializer 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.text.Text
import net.minecraft.util.math.Vec3d 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.SkyblockServerUpdateEvent
import moe.nea.firmament.events.WorldRenderLastEvent import moe.nea.firmament.events.WorldRenderLastEvent
import moe.nea.firmament.features.FirmamentFeature import moe.nea.firmament.features.FirmamentFeature
@@ -102,53 +97,43 @@ object FairySouls : FirmamentFeature {
updateMissingSouls() updateMissingSouls()
} }
val NODEPTH: RenderLayer = RenderLayer.of( @Subscribe
"firmamentnodepth", fun onWorldRender(it: WorldRenderLastEvent) {
VertexFormats.POSITION_COLOR_TEXTURE, if (!TConfig.displaySouls) return
VertexFormat.DrawMode.QUADS, renderInWorld(it) {
256, text(Vec3d(0.0, 0.0, 0.0),
true, Text.literal("Test String"),
true, Text.literal("Short"),
MultiPhaseParameters.builder() Text.literal("just lik"),
.program(RenderPhase.COLOR_PROGRAM) verticalAlign = RenderInWorldContext.VerticalAlign.BOTTOM)
.writeMaskState(RenderPhase.COLOR_MASK) color(1F, 1F, 0F, 0.8F)
.depthTest(ALWAYS_DEPTH_TEST) currentMissingSouls.forEach {
.cull(RenderPhase.DISABLE_CULLING) block(it.blockPos)
.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()
}
} }
} color(1f, 0f, 1f, 1f)
WorldRenderLastEvent.subscribe { currentLocationSouls.forEach {
if (!TConfig.displaySouls) return@subscribe wireframeCube(it.blockPos)
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)
}
} }
} }
} }
@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()
}
} }

View File

@@ -22,6 +22,7 @@ import net.minecraft.text.Text
import net.minecraft.util.math.BlockPos import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Vec3d import net.minecraft.util.math.Vec3d
import moe.nea.firmament.Firmament import moe.nea.firmament.Firmament
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.commands.get import moe.nea.firmament.commands.get
import moe.nea.firmament.commands.thenArgument import moe.nea.firmament.commands.thenArgument
import moe.nea.firmament.commands.thenExecute import moe.nea.firmament.commands.thenExecute
@@ -73,194 +74,203 @@ object Waypoints : FirmamentFeature {
val b: Int = 0, val b: Int = 0,
) )
override fun onLoad() { @Subscribe
WorldRenderLastEvent.subscribe { event -> fun onRenderOrderedWaypoints(event: WorldRenderLastEvent) {
temporaryPlayerWaypointList.entries.removeIf { it.value.postedAt.passedTime() > TConfig.tempWaypointDuration } if (waypoints.isEmpty()) return
if (temporaryPlayerWaypointList.isNotEmpty()) RenderInWorldContext.renderInWorld(event) {
RenderInWorldContext.renderInWorld(event) { if (!ordered) {
color(1f, 1f, 0f, 1f) waypoints.withIndex().forEach {
temporaryPlayerWaypointList.forEach { (player, waypoint) -> color(0f, 0.3f, 0.7f, 0.5f)
block(waypoint.pos) block(it.value)
}
color(1f, 1f, 1f, 1f) color(1f, 1f, 1f, 1f)
temporaryPlayerWaypointList.forEach { (player, waypoint) -> if (TConfig.showIndex)
val skin = withFacingThePlayer(it.value.toCenterPos()) {
MC.networkHandler?.listedPlayerListEntries?.find { it.profile.name == player } text(Text.literal(it.index.toString()))
?.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,
)
}
} }
}
} }
} } else {
WorldReadyEvent.subscribe { orderedIndex %= waypoints.size
temporaryPlayerWaypointList.clear() val firstColor = Color.ofRGBA(0, 200, 40, 180)
} color(firstColor)
CommandEvent.SubCommand.subscribe { event -> tracer(waypoints[orderedIndex].toCenterPos(), lineWidth = 3f)
event.subcommand("waypoint") { waypoints.withIndex().toList()
thenArgument("pos", BlockPosArgumentType.blockPos()) { pos -> .wrappingWindow(orderedIndex, 3)
thenExecute { .zip(
val position = pos.get(this).toAbsoluteBlockPos(source.asFakeServer()) listOf(
waypoints.add(position) firstColor,
source.sendFeedback( Color.ofRGBA(180, 200, 40, 150),
Text.stringifiedTranslatable( Color.ofRGBA(180, 80, 20, 140),
"firmament.command.waypoint.added",
position.x,
position.y,
position.z
)
) )
} )
} .reversed()
} .forEach { (waypoint, col) ->
event.subcommand("waypoints") { val (index, pos) = waypoint
thenLiteral("clear") { color(col)
thenExecute { block(pos)
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)
color(1f, 1f, 1f, 1f) color(1f, 1f, 1f, 1f)
if (TConfig.showIndex) if (TConfig.showIndex)
withFacingThePlayer(it.value.toCenterPos()) { withFacingThePlayer(pos.toCenterPos()) {
text(Text.literal(it.index.toString())) 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) @Subscribe
waypoints.withIndex().toList() fun onTick(event: TickEvent) {
.wrappingWindow(orderedIndex, 3) if (waypoints.isEmpty() || !ordered) return
.zip( orderedIndex %= waypoints.size
listOf( val p = MC.player?.pos ?: return
firstColor, if (TConfig.skipToNearest) {
Color.ofRGBA(180, 200, 40, 150), orderedIndex =
Color.ofRGBA(180, 80, 20, 140), (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) event.subcommand("waypoints") {
color(1f, 1f, 1f, 1f) thenLiteral("clear") {
if (TConfig.showIndex) thenExecute {
withFacingThePlayer(pos.toCenterPos()) { waypoints.clear()
text(Text.literal(index.toString())) 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 @Subscribe
val p = MC.player?.pos ?: return@subscribe fun onRenderTemporaryWaypoints(event: WorldRenderLastEvent) {
if (TConfig.skipToNearest) { temporaryPlayerWaypointList.entries.removeIf { it.value.postedAt.passedTime() > TConfig.tempWaypointDuration }
orderedIndex = if (temporaryPlayerWaypointList.isEmpty()) return
(waypoints.withIndex().minBy { it.value.getSquaredDistance(p) }.index + 1) % waypoints.size RenderInWorldContext.renderInWorld(event) {
} else { color(1f, 1f, 0f, 1f)
if (waypoints[orderedIndex].isWithinDistance(p, 3.0)) { temporaryPlayerWaypointList.forEach { (player, waypoint) ->
orderedIndex = (orderedIndex + 1) % waypoints.size 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()) { @Subscribe
temporaryPlayerWaypointList[it.nameHeuristic] = TemporaryWaypoint( fun onWorldReady(event: WorldReadyEvent) {
BlockPos( temporaryPlayerWaypointList.clear()
matcher.group(1).toInt(),
matcher.group(2).toInt(),
matcher.group(3).toInt(),
),
TimeMark.now()
)
}
}
} }
} }