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,16 +31,18 @@ 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) { @Subscribe
it.deleteCommand("warp") fun onCommandEvent(event: CommandEvent) {
it.register("warp") { if (!TConfig.provideWarpTabCompletion) return
event.deleteCommand("warp")
event.register("warp") {
thenArgument("to", string()) { toArg -> thenArgument("to", string()) { toArg ->
suggestsList { suggestsList {
RepoManager.neuRepo.constants?.islands?.warps?.flatMap { listOf(it.warp) + it.aliases } ?: listOf() RepoManager.neuRepo.constants?.islands?.warps?.flatMap { listOf(it.warp) + it.aliases } ?: listOf()
@@ -49,9 +52,7 @@ object AutoCompletions : FirmamentFeature {
if (warpName == "is" && TConfig.replaceWarpIsByWarpIsland) { if (warpName == "is" && TConfig.replaceWarpIsByWarpIsland) {
MC.sendServerCommand("warp island") MC.sendServerCommand("warp island")
} else { } else {
MC.sendServerCommand("warp ${warpName}") 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,10 +97,42 @@ 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
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()
}
@Subscribe
fun onModifyChat(it: ModifyChatEvent) {
if (!TConfig.enableLinks) return
it.replaceWith = it.replaceWith.transformEachRecursively { child -> it.replaceWith = it.replaceWith.transformEachRecursively { child ->
val text = child.string val text = child.string
if ("://" !in text) return@transformEachRecursively child if ("://" !in text) return@transformEachRecursively child
@@ -129,36 +162,4 @@ object ChatLinks : FirmamentFeature {
s s
} }
} }
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()
}
}
} }

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,8 +35,9 @@ 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
fun onCommands(it: CommandEvent) {
it.register("join") { it.register("join") {
thenArgument("what", RestArgumentType) { what -> thenArgument("what", RestArgumentType) { what ->
thenExecute { thenExecute {
@@ -48,7 +50,8 @@ object QuickCommands : FirmamentFeature {
if (joinName == null) { if (joinName == null) {
source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.unknown", what)) source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.unknown", what))
} else { } else {
source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.success", joinName)) source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.success",
joinName))
MC.sendCommand("joininstance $joinName") MC.sendCommand("joininstance $joinName")
} }
} }
@@ -58,7 +61,6 @@ object QuickCommands : FirmamentFeature {
} }
} }
} }
}
fun CommandContext<DefaultSource>.getNameForFloor(w: String): String? { fun CommandContext<DefaultSource>.getNameForFloor(w: String): String? {
val kuudraLevel = removePartialPrefix(w, "kuudratier") ?: removePartialPrefix(w, "tier") val kuudraLevel = removePartialPrefix(w, "kuudratier") ?: removePartialPrefix(w, "tier")
@@ -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,14 +63,17 @@ 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
fun copyInventoryInfo(it: HandledScreenKeyPressedEvent) {
if (it.screen !is AccessorHandledScreen) return
val item = it.screen.focusedItemStack ?: return
if (it.matches(TConfig.copyItemId)) { if (it.matches(TConfig.copyItemId)) {
val sbId = item.skyBlockId val sbId = item.skyBlockId
if (sbId == null) { if (sbId == null) {
lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skyblockid.fail")) lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skyblockid.fail"))
return@subscribe return
} }
ClipboardUtils.setTextContent(sbId.neuItem) ClipboardUtils.setTextContent(sbId.neuItem)
lastCopiedStack = lastCopiedStack =
@@ -114,7 +82,7 @@ object PowerUserTools : FirmamentFeature {
val model = CustomItemModelEvent.getModelIdentifier(item) val model = CustomItemModelEvent.getModelIdentifier(item)
if (model == null) { if (model == null) {
lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.modelid.fail")) lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.modelid.fail"))
return@subscribe return
} }
ClipboardUtils.setTextContent(model.toString()) ClipboardUtils.setTextContent(model.toString())
lastCopiedStack = lastCopiedStack =
@@ -127,17 +95,17 @@ object PowerUserTools : FirmamentFeature {
} else if (it.matches(TConfig.copySkullTexture)) { } else if (it.matches(TConfig.copySkullTexture)) {
if (item.item != Items.PLAYER_HEAD) { if (item.item != Items.PLAYER_HEAD) {
lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skull-id.fail.no-skull")) lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skull-id.fail.no-skull"))
return@subscribe return
} }
val profile = item.get(DataComponentTypes.PROFILE) val profile = item.get(DataComponentTypes.PROFILE)
if (profile == null) { if (profile == null) {
lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skull-id.fail.no-profile")) lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skull-id.fail.no-profile"))
return@subscribe return
} }
val skullTexture = CustomSkyBlockTextures.getSkullTexture(profile) val skullTexture = CustomSkyBlockTextures.getSkullTexture(profile)
if (skullTexture == null) { if (skullTexture == null) {
lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skull-id.fail.no-texture")) lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skull-id.fail.no-texture"))
return@subscribe return
} }
ClipboardUtils.setTextContent(skullTexture.toString()) ClipboardUtils.setTextContent(skullTexture.toString())
lastCopiedStack = lastCopiedStack =
@@ -148,6 +116,45 @@ object PowerUserTools : FirmamentFeature {
println("Copied skull id: $skullTexture") 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,8 +42,8 @@ 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
@@ -51,5 +52,4 @@ object CompatibliltyFeatures : FirmamentFeature {
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,14 +51,9 @@ 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
}
}
HudRenderEvent.subscribe {
if (!TConfig.autoSprintKeyBinding.isBound) return@subscribe
it.context.matrices.push() it.context.matrices.push()
TConfig.autoSprintHud.applyTransformations(it.context.matrices) TConfig.autoSprintHud.applyTransformations(it.context.matrices)
it.context.drawText( it.context.drawText(
@@ -72,6 +68,12 @@ object Fixes : FirmamentFeature {
) )
it.context.matrices.pop() it.context.matrices.pop()
} }
@Subscribe
fun onWorldKeyboard(it: WorldKeyboardEvent) {
if (it.matches(TConfig.autoSprintKeyBinding)) {
TConfig.autoSprint = !TConfig.autoSprint
}
} }
fun shouldPeekChat(): Boolean { fun shouldPeekChat(): Boolean {

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,13 +36,13 @@ 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
@@ -66,5 +67,4 @@ object CraftingOverlay : FirmamentFeature {
) )
} }
} }
}
} }

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) {
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 val stack = it.item
drawItemStackRarity(it.context, it.x, it.y, stack) 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)
}
}
} }

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,66 +97,11 @@ 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 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()
}
}
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 val inv = event.slot.inventory
var anyBlocked = false var anyBlocked = false
for (i in 0 until event.slot.index) { for (i in 0 until event.slot.index) {
@@ -167,10 +113,73 @@ object SlotLocking : FirmamentFeature {
event.protectSilent() event.protectSilent()
} }
} }
@Subscribe
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 @Subscribe
fun function(it: SlotRenderEvents.After) { 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,19 +42,18 @@ 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
fun onRectangles(it: HandledScreenPushREIEvent) {
val bounds = it.screen.getRectangle() val bounds = it.screen.getRectangle()
for (button in getValidButtons()) { for (button in getValidButtons()) {
val buttonBounds = button.getBounds(bounds) val buttonBounds = button.getBounds(bounds)
it.context.matrices.push() it.block(buttonBounds)
it.context.matrices.translate(buttonBounds.minX.toFloat(), buttonBounds.minY.toFloat(), 0F)
button.render(it.context)
it.context.matrices.pop()
} }
lastRectangle = bounds
} }
HandledScreenClickEvent.subscribe {
@Subscribe
fun onClickScreen(it: HandledScreenClickEvent) {
val bounds = it.screen.getRectangle() val bounds = it.screen.getRectangle()
for (button in getValidButtons()) { for (button in getValidButtons()) {
val buttonBounds = button.getBounds(bounds) val buttonBounds = button.getBounds(bounds)
@@ -62,13 +63,18 @@ object InventoryButtons : FirmamentFeature {
} }
} }
} }
HandledScreenPushREIEvent.subscribe {
@Subscribe
fun onRenderForeground(it: HandledScreenForegroundEvent) {
val bounds = it.screen.getRectangle() val bounds = it.screen.getRectangle()
for (button in getValidButtons()) { for (button in getValidButtons()) {
val buttonBounds = button.getBounds(bounds) val buttonBounds = button.getBounds(bounds)
it.block(buttonBounds) 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,8 +41,24 @@ 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) {
rememberContent(currentHandler ?: return)
}
@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()
}
}
@Subscribe
fun onScreenChange(it: ScreenChangeEvent) {
if (lastStorageOverlay != null && it.new != null) { if (lastStorageOverlay != null && it.new != null) {
shouldReturnToStorageOverlay = lastStorageOverlay shouldReturnToStorageOverlay = lastStorageOverlay
shouldReturnToStorageOverlayFrom = it.new shouldReturnToStorageOverlayFrom = it.new
@@ -54,20 +71,6 @@ object StorageOverlay : FirmamentFeature {
} }
} }
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()
}
}
TickEvent.subscribe {
rememberContent(currentHandler ?: return@subscribe)
}
}
private fun rememberContent(handler: StorageBackingHandle) { private fun rememberContent(handler: StorageBackingHandle) {
// TODO: Make all of these functions work on deltas / updates instead of the entire contents // TODO: Make all of these functions work on deltas / updates instead of the entire contents
val data = Data.data?.storageInventories ?: return val data = Data.data?.storageInventories ?: return

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,32 +74,31 @@ 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 { } ?: return
abilityUsePattern.useMatch(it.unformattedString) { defaultAbilityDurations[name] = cooldown
lastUsage[group("name")] = TimeMark.now()
}
abilitySwitchPattern.useMatch(it.unformattedString) {
abilityOverride = group("ability")
} }
} }
DurabilityBarEvent.subscribe {
if (!TConfig.drillFuelBar) return@subscribe @Subscribe
fun onDurabilityBar(it: DurabilityBarEvent) {
if (!TConfig.drillFuelBar) return
val lore = it.item.loreAccordingToNbt val lore = it.item.loreAccordingToNbt
if (lore.lastOrNull()?.unformattedString?.contains("DRILL") != true) return@subscribe if (lore.lastOrNull()?.unformattedString?.contains("DRILL") != true) return
val maxFuel = lore.firstNotNullOfOrNull { val maxFuel = lore.firstNotNullOfOrNull {
fuelPattern.useMatch(it.unformattedString) { fuelPattern.useMatch(it.unformattedString) {
parseShortNumber(group("maxFuel")) parseShortNumber(group("maxFuel"))
} }
} ?: return@subscribe } ?: return
val extra = it.item.extraAttributes val extra = it.item.extraAttributes
if (!extra.contains("drill_fuel")) return@subscribe if (!extra.contains("drill_fuel")) return
val fuel = extra.getInt("drill_fuel") val fuel = extra.getInt("drill_fuel")
val percentage = fuel / maxFuel.toFloat() val percentage = fuel / maxFuel.toFloat()
it.barOverride = DurabilityBarEvent.DurabilityBar( it.barOverride = DurabilityBarEvent.DurabilityBar(
@@ -109,17 +109,22 @@ object PickaxeAbility : FirmamentFeature {
), percentage ), percentage
) )
} }
SlotClickEvent.subscribe {
if (MC.screen?.title?.unformattedString == "Heart of the Mountain") { @Subscribe
val name = it.stack.displayNameAccordingToNbt?.unformattedString ?: return@subscribe fun onChatMessage(it: ProcessChatEvent) {
val cooldown = it.stack.loreAccordingToNbt.firstNotNullOfOrNull { abilityUsePattern.useMatch(it.unformattedString) {
cooldownPattern.useMatch(it.unformattedString) { lastUsage[group("name")] = TimeMark.now()
parseTimePattern(group("cooldown"))
} }
} ?: return@subscribe abilitySwitchPattern.useMatch(it.unformattedString) {
defaultAbilityDurations[name] = cooldown 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,8 +123,8 @@ 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"))
@@ -130,5 +135,4 @@ object PristineProfitTracker : FirmamentFeature {
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,18 +39,19 @@ 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
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) { if (TConfig.cacheDuration < 1 || it.tickCount % TConfig.cacheDuration == 0) {
CustomItemModelEvent.clearCache() CustomItemModelEvent.clearCache()
skullTextureCache.clear() 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>()

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,44 +97,15 @@ 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,
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()
}
}
}
WorldRenderLastEvent.subscribe {
if (!TConfig.displaySouls) return@subscribe
renderInWorld(it) { 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) 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) color(1F, 1F, 0F, 0.8F)
currentMissingSouls.forEach { currentMissingSouls.forEach {
block(it.blockPos) block(it.blockPos)
@@ -150,5 +116,24 @@ object FairySouls : FirmamentFeature {
} }
} }
} }
@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,46 +74,81 @@ 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) {
color(1f, 1f, 0f, 1f) if (!ordered) {
temporaryPlayerWaypointList.forEach { (player, waypoint) -> waypoints.withIndex().forEach {
block(waypoint.pos) color(0f, 0.3f, 0.7f, 0.5f)
} 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()) { } else {
waypoint(waypoint.pos, Text.stringifiedTranslatable("firmament.waypoint.temporary", player)) orderedIndex %= waypoints.size
if (skin != null) { val firstColor = Color.ofRGBA(0, 200, 40, 180)
matrixStack.translate(0F, -20F, 0F) color(firstColor)
// Head front tracer(waypoints[orderedIndex].toCenterPos(), lineWidth = 3f)
texture( waypoints.withIndex().toList()
skin, 16, 16, .wrappingWindow(orderedIndex, 3)
1 / 8f, 1 / 8f, .zip(
2 / 8f, 2 / 8f, listOf(
firstColor,
Color.ofRGBA(180, 200, 40, 150),
Color.ofRGBA(180, 80, 20, 140),
) )
// Head overlay )
texture( .reversed()
skin, 16, 16, .forEach { (waypoint, col) ->
5 / 8f, 1 / 8f, val (index, pos) = waypoint
6 / 8f, 2 / 8f, color(col)
block(pos)
color(1f, 1f, 1f, 1f)
if (TConfig.showIndex)
withFacingThePlayer(pos.toCenterPos()) {
text(Text.literal(index.toString()))
}
}
}
}
}
@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) {
WorldReadyEvent.subscribe {
temporaryPlayerWaypointList.clear()
}
CommandEvent.SubCommand.subscribe { event ->
event.subcommand("waypoint") { event.subcommand("waypoint") {
thenArgument("pos", BlockPosArgumentType.blockPos()) { pos -> thenArgument("pos", BlockPosArgumentType.blockPos()) { pos ->
thenExecute { thenExecute {
@@ -194,74 +230,48 @@ object Waypoints : FirmamentFeature {
} }
} }
} }
WorldRenderLastEvent.subscribe { event ->
if (waypoints.isEmpty()) return@subscribe @Subscribe
fun onRenderTemporaryWaypoints(event: WorldRenderLastEvent) {
temporaryPlayerWaypointList.entries.removeIf { it.value.postedAt.passedTime() > TConfig.tempWaypointDuration }
if (temporaryPlayerWaypointList.isEmpty()) return
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)
if (TConfig.showIndex) temporaryPlayerWaypointList.forEach { (player, waypoint) ->
withFacingThePlayer(it.value.toCenterPos()) { val skin =
text(Text.literal(it.index.toString())) MC.networkHandler?.listedPlayerListEntries?.find { it.profile.name == player }
} ?.skinTextures
} ?.texture
} else { withFacingThePlayer(waypoint.pos.toCenterPos()) {
orderedIndex %= waypoints.size waypoint(waypoint.pos, Text.stringifiedTranslatable("firmament.waypoint.temporary", player))
val firstColor = Color.ofRGBA(0, 200, 40, 180) if (skin != null) {
color(firstColor) matrixStack.translate(0F, -20F, 0F)
tracer(waypoints[orderedIndex].toCenterPos(), lineWidth = 3f) // Head front
waypoints.withIndex().toList() texture(
.wrappingWindow(orderedIndex, 3) skin, 16, 16,
.zip( 1 / 8f, 1 / 8f,
listOf( 2 / 8f, 2 / 8f,
firstColor,
Color.ofRGBA(180, 200, 40, 150),
Color.ofRGBA(180, 80, 20, 140),
) )
) // Head overlay
.reversed() texture(
.forEach { (waypoint, col) -> skin, 16, 16,
val (index, pos) = waypoint 5 / 8f, 1 / 8f,
color(col) 6 / 8f, 2 / 8f,
block(pos)
color(1f, 1f, 1f, 1f)
if (TConfig.showIndex)
withFacingThePlayer(pos.toCenterPos()) {
text(Text.literal(index.toString()))
}
}
}
}
}
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
}
}
}
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()
}
} }
fun <E> List<E>.wrappingWindow(startIndex: Int, windowSize: Int): List<E> { fun <E> List<E>.wrappingWindow(startIndex: Int, windowSize: Int): List<E> {