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.FirmamentEventBus
import moe.nea.firmament.features.FirmamentFeature
interface SubscriptionOwner
interface SubscriptionOwner {
val delegateFeature: FirmamentFeature
}
data class Subscription<T : FirmamentEvent>(
val owner: SubscriptionOwner,

View File

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

View File

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

View File

@@ -6,11 +6,11 @@
package moe.nea.firmament.features.chat
import io.ktor.client.request.*
import io.ktor.client.statement.*
import io.ktor.utils.io.jvm.javaio.*
import io.ktor.client.request.get
import io.ktor.client.statement.bodyAsChannel
import io.ktor.utils.io.jvm.javaio.toInputStream
import java.net.URL
import java.util.*
import java.util.Collections
import moe.nea.jarvis.api.Point
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -26,6 +26,7 @@ import net.minecraft.text.Text
import net.minecraft.util.Formatting
import net.minecraft.util.Identifier
import moe.nea.firmament.Firmament
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.ModifyChatEvent
import moe.nea.firmament.events.ScreenRenderPostEvent
import moe.nea.firmament.features.FirmamentFeature
@@ -96,10 +97,42 @@ object ChatLinks : FirmamentFeature {
return (url.substringAfterLast('.').lowercase() in imageExtensions)
}
@Subscribe
@OptIn(ExperimentalCoroutinesApi::class)
override fun onLoad() {
ModifyChatEvent.subscribe {
if (TConfig.enableLinks)
fun onRender(it: ScreenRenderPostEvent) {
if (!TConfig.imageEnabled) return
if (it.screen !is ChatScreen) return
val hoveredComponent =
MC.inGameHud.chatHud.getTextStyleAt(it.mouseX.toDouble(), it.mouseY.toDouble()) ?: return
val hoverEvent = hoveredComponent.hoverEvent ?: return
val value = hoverEvent.getValue(HoverEvent.Action.SHOW_TEXT) ?: return
val url = urlRegex.matchEntire(value.unformattedString)?.groupValues?.get(0) ?: return
if (!isImageUrl(url)) return
val imageFuture = imageCache[url] ?: return
if (!imageFuture.isCompleted) return
val image = imageFuture.getCompleted() ?: return
it.drawContext.matrices.push()
val pos = TConfig.position
pos.applyTransformations(it.drawContext.matrices)
val scale = min(1F, min((9 * 20F) / image.height, (16 * 20F) / image.width))
it.drawContext.matrices.scale(scale, scale, 1F)
it.drawContext.drawTexture(
image.texture,
0,
0,
1F,
1F,
image.width,
image.height,
image.width,
image.height,
)
it.drawContext.matrices.pop()
}
@Subscribe
fun onModifyChat(it: ModifyChatEvent) {
if (!TConfig.enableLinks) return
it.replaceWith = it.replaceWith.transformEachRecursively { child ->
val text = child.string
if ("://" !in text) return@transformEachRecursively child
@@ -129,36 +162,4 @@ object ChatLinks : FirmamentFeature {
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 net.minecraft.text.Text
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.commands.DefaultSource
import moe.nea.firmament.commands.RestArgumentType
import moe.nea.firmament.commands.get
@@ -34,8 +35,9 @@ object QuickCommands : FirmamentFeature {
val kuudraLevelNames = listOf("NORMAL", "HOT", "BURNING", "FIERY", "INFERNAL")
val dungeonLevelNames = listOf("ONE", "TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN")
override fun onLoad() {
CommandEvent.subscribe {
@Subscribe
fun onCommands(it: CommandEvent) {
it.register("join") {
thenArgument("what", RestArgumentType) { what ->
thenExecute {
@@ -48,7 +50,8 @@ object QuickCommands : FirmamentFeature {
if (joinName == null) {
source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.unknown", what))
} 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")
}
}
@@ -58,7 +61,6 @@ object QuickCommands : FirmamentFeature {
}
}
}
}
fun CommandContext<DefaultSource>.getNameForFloor(w: String): String? {
val kuudraLevel = removePartialPrefix(w, "kuudratier") ?: removePartialPrefix(w, "tier")
@@ -70,7 +72,8 @@ object QuickCommands : FirmamentFeature {
)
}
if (l !in kuudraLevelNames.indices) {
source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.unknown-kuudra", kuudraLevel))
source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.unknown-kuudra",
kuudraLevel))
return null
}
return "KUUDRA_${kuudraLevelNames[l]}"
@@ -90,7 +93,8 @@ object QuickCommands : FirmamentFeature {
return "CATACOMBS_ENTRANCE"
}
if (l !in dungeonLevelNames.indices) {
source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.unknown-catacombs", kuudraLevel))
source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.unknown-catacombs",
kuudraLevel))
return null
}
return "${if (masterLevel != null) "MASTER_" else ""}CATACOMBS_FLOOR_${dungeonLevelNames[l]}"

View File

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

View File

@@ -6,9 +6,10 @@
package moe.nea.firmament.features.debug
import net.minecraft.text.Text
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.ModifyChatEvent
import moe.nea.firmament.features.FirmamentFeature
import net.minecraft.text.Text
// In memorian Dulkir
@@ -19,13 +20,12 @@ object MinorTrolling : FirmamentFeature {
val trollers = listOf("nea89o", "lrg89")
val t = "From(?: \\[[^\\]]+])? ([^:]+): (.*)".toRegex()
override fun onLoad() {
ModifyChatEvent.subscribe {
val m = t.matchEntire(it.unformattedString) ?: return@subscribe
@Subscribe
fun onTroll(it: ModifyChatEvent) {
val m = t.matchEntire(it.unformattedString) ?: return
val (_, name, text) = m.groupValues
if (name !in trollers) return@subscribe
if (!text.startsWith("c:")) return@subscribe
if (name !in trollers) return
if (!text.startsWith("c:")) return
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.util.hit.BlockHitResult
import net.minecraft.util.hit.HitResult
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.CustomItemModelEvent
import moe.nea.firmament.events.HandledScreenKeyPressedEvent
import moe.nea.firmament.events.ItemTooltipEvent
@@ -54,42 +55,6 @@ object PowerUserTools : FirmamentFeature {
var lastCopiedStackViewTime = false
override fun onLoad() {
ItemTooltipEvent.subscribe {
if (TConfig.showItemIds) {
val id = it.stack.skyBlockId ?: return@subscribe
it.lines.add(Text.stringifiedTranslatable("firmament.tooltip.skyblockid", id.neuItem))
}
val (item, text) = lastCopiedStack ?: return@subscribe
if (!ItemStack.areEqual(item, it.stack)) {
lastCopiedStack = null
return@subscribe
}
lastCopiedStackViewTime = true
it.lines.add(text)
}
WorldKeyboardEvent.subscribe {
if (it.matches(TConfig.copySkullTexture)) {
val p = MC.camera ?: return@subscribe
val blockHit = p.raycast(20.0, 0.0f, false) ?: return@subscribe
if (blockHit.type != HitResult.Type.BLOCK || blockHit !is BlockHitResult) {
MC.sendChat(Text.translatable("firmament.tooltip.copied.skull.fail"))
return@subscribe
}
val blockAt = p.world.getBlockState(blockHit.blockPos)?.block
val entity = p.world.getBlockEntity(blockHit.blockPos)
if (blockAt !is SkullBlock || entity !is SkullBlockEntity || entity.owner == null) {
MC.sendChat(Text.translatable("firmament.tooltip.copied.skull.fail"))
return@subscribe
}
val id = CustomSkyBlockTextures.getSkullTexture(entity.owner!!)
if (id == null) {
MC.sendChat(Text.translatable("firmament.tooltip.copied.skull.fail"))
} else {
ClipboardUtils.setTextContent(id.toString())
MC.sendChat(Text.stringifiedTranslatable("firmament.tooltip.copied.skull", id.toString()))
}
}
}
TickEvent.subscribe {
if (!lastCopiedStackViewTime)
lastCopiedStack = null
@@ -98,14 +63,17 @@ object PowerUserTools : FirmamentFeature {
ScreenChangeEvent.subscribe {
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)) {
val sbId = item.skyBlockId
if (sbId == null) {
lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skyblockid.fail"))
return@subscribe
return
}
ClipboardUtils.setTextContent(sbId.neuItem)
lastCopiedStack =
@@ -114,7 +82,7 @@ object PowerUserTools : FirmamentFeature {
val model = CustomItemModelEvent.getModelIdentifier(item)
if (model == null) {
lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.modelid.fail"))
return@subscribe
return
}
ClipboardUtils.setTextContent(model.toString())
lastCopiedStack =
@@ -127,17 +95,17 @@ object PowerUserTools : FirmamentFeature {
} else if (it.matches(TConfig.copySkullTexture)) {
if (item.item != Items.PLAYER_HEAD) {
lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skull-id.fail.no-skull"))
return@subscribe
return
}
val profile = item.get(DataComponentTypes.PROFILE)
if (profile == null) {
lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skull-id.fail.no-profile"))
return@subscribe
return
}
val skullTexture = CustomSkyBlockTextures.getSkullTexture(profile)
if (skullTexture == null) {
lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skull-id.fail.no-texture"))
return@subscribe
return
}
ClipboardUtils.setTextContent(skullTexture.toString())
lastCopiedStack =
@@ -148,6 +116,45 @@ object PowerUserTools : FirmamentFeature {
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.sound.SoundEvents
import net.minecraft.util.math.Vec3d
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.ParticleSpawnEvent
import moe.nea.firmament.events.SoundReceiveEvent
import moe.nea.firmament.events.WorldKeyboardEvent
import moe.nea.firmament.events.WorldReadyEvent
import moe.nea.firmament.events.WorldRenderLastEvent
import moe.nea.firmament.events.subscription.SubscriptionOwner
import moe.nea.firmament.features.FirmamentFeature
import moe.nea.firmament.util.SBData
import moe.nea.firmament.util.TimeMark
import moe.nea.firmament.util.WarpUtil
import moe.nea.firmament.util.render.RenderInWorldContext
object AncestralSpadeSolver {
object AncestralSpadeSolver : SubscriptionOwner {
var lastDing = TimeMark.farPast()
private set
private val pitches = mutableListOf<Float>()
@@ -33,6 +36,7 @@ object AncestralSpadeSolver {
fun isEnabled() =
DianaWaypoints.TConfig.ancestralSpadeSolver && SBData.skyblockLocation == "hub"
@Subscribe
fun onKeyBind(event: WorldKeyboardEvent) {
if (!isEnabled()) return
if (!event.matches(DianaWaypoints.TConfig.ancestralSpadeTeleport)) return
@@ -42,6 +46,7 @@ object AncestralSpadeSolver {
lastTeleportAttempt = TimeMark.now()
}
@Subscribe
fun onParticleSpawn(event: ParticleSpawnEvent) {
if (!isEnabled()) return
if (event.particleEffect != ParticleTypes.DRIPPING_LAVA) return
@@ -53,6 +58,7 @@ object AncestralSpadeSolver {
}
}
@Subscribe
fun onPlaySound(event: SoundReceiveEvent) {
if (!isEnabled()) return
if (!SoundEvents.BLOCK_NOTE_BLOCK_HARP.matchesId(event.sound.value().id)) return
@@ -92,6 +98,7 @@ object AncestralSpadeSolver {
nextGuess = event.position.add(lastParticleDirection.multiply(soundDistanceEstimate))
}
@Subscribe
fun onWorldRender(event: WorldRenderLastEvent) {
if (!isEnabled()) return
RenderInWorldContext.renderInWorld(event) {
@@ -108,6 +115,7 @@ object AncestralSpadeSolver {
}
}
@Subscribe
fun onSwapWorld(event: WorldReadyEvent) {
nextGuess = null
particlePositions.clear()
@@ -115,4 +123,7 @@ object AncestralSpadeSolver {
lastDing = TimeMark.farPast()
}
override val delegateFeature: FirmamentFeature
get() = DianaWaypoints
}

View File

@@ -28,23 +28,12 @@ object DianaWaypoints : FirmamentFeature {
}
override fun onLoad() {
ParticleSpawnEvent.subscribe(NearbyBurrowsSolver::onParticles)
WorldReadyEvent.subscribe(NearbyBurrowsSolver::onSwapWorld)
WorldRenderLastEvent.subscribe(NearbyBurrowsSolver::onRender)
UseBlockEvent.subscribe {
NearbyBurrowsSolver.onBlockClick(it.hitResult.blockPos)
}
AttackBlockEvent.subscribe {
NearbyBurrowsSolver.onBlockClick(it.blockPos)
}
ProcessChatEvent.subscribe(NearbyBurrowsSolver::onChatEvent)
WorldKeyboardEvent.subscribe(AncestralSpadeSolver::onKeyBind)
ParticleSpawnEvent.subscribe(AncestralSpadeSolver::onParticleSpawn)
SoundReceiveEvent.subscribe(AncestralSpadeSolver::onPlaySound)
WorldRenderLastEvent.subscribe(AncestralSpadeSolver::onWorldRender)
WorldReadyEvent.subscribe(AncestralSpadeSolver::onSwapWorld)
}
}

View File

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

View File

@@ -10,6 +10,7 @@ import net.fabricmc.loader.api.FabricLoader
import net.superkat.explosiveenhancement.api.ExplosiveApi
import net.minecraft.particle.ParticleTypes
import net.minecraft.util.math.Vec3d
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.ParticleSpawnEvent
import moe.nea.firmament.features.FirmamentFeature
import moe.nea.firmament.gui.config.ManagedConfig
@@ -41,8 +42,8 @@ object CompatibliltyFeatures : FirmamentFeature {
ExplosiveApiWrapperImpl()
} else null
override fun onLoad() {
ParticleSpawnEvent.subscribe {
@Subscribe
fun onExplosion(it: ParticleSpawnEvent) {
if (TConfig.enhancedExplosions &&
it.particleEffect.type == ParticleTypes.EXPLOSION_EMITTER &&
explosiveApiWrapper != null
@@ -51,5 +52,4 @@ object CompatibliltyFeatures : FirmamentFeature {
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.text.Text
import net.minecraft.util.Arm
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.HudRenderEvent
import moe.nea.firmament.events.WorldKeyboardEvent
import moe.nea.firmament.features.FirmamentFeature
@@ -50,14 +51,9 @@ object Fixes : FirmamentFeature {
}
}
override fun onLoad() {
WorldKeyboardEvent.subscribe {
if (it.matches(TConfig.autoSprintKeyBinding)) {
TConfig.autoSprint = !TConfig.autoSprint
}
}
HudRenderEvent.subscribe {
if (!TConfig.autoSprintKeyBinding.isBound) return@subscribe
@Subscribe
fun onRenderHud(it: HudRenderEvent) {
if (!TConfig.autoSprintKeyBinding.isBound) return
it.context.matrices.push()
TConfig.autoSprintHud.applyTransformations(it.context.matrices)
it.context.drawText(
@@ -72,6 +68,12 @@ object Fixes : FirmamentFeature {
)
it.context.matrices.pop()
}
@Subscribe
fun onWorldKeyboard(it: WorldKeyboardEvent) {
if (it.matches(TConfig.autoSprintKeyBinding)) {
TConfig.autoSprint = !TConfig.autoSprint
}
}
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.item.ItemStack
import net.minecraft.util.Formatting
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.SlotRenderEvents
import moe.nea.firmament.features.FirmamentFeature
import moe.nea.firmament.rei.recipes.SBCraftingRecipe
import moe.nea.firmament.rei.FirmamentReiPlugin.Companion.asItemEntry
import moe.nea.firmament.rei.SBItemEntryDefinition
import moe.nea.firmament.rei.recipes.SBCraftingRecipe
import moe.nea.firmament.util.MC
object CraftingOverlay : FirmamentFeature {
@@ -35,13 +36,13 @@ object CraftingOverlay : FirmamentFeature {
override val identifier: String
get() = "crafting-overlay"
override fun onLoad() {
SlotRenderEvents.After.subscribe { event ->
@Subscribe
fun onSlotRender(event: SlotRenderEvents.After) {
val slot = event.slot
val recipe = this.recipe ?: return@subscribe
if (slot.inventory != screen?.screenHandler?.inventory) return@subscribe
val recipe = this.recipe ?: return
if (slot.inventory != screen?.screenHandler?.inventory) return
val recipeIndex = craftingOverlayIndices.indexOf(slot.index)
if (recipeIndex < 0) return@subscribe
if (recipeIndex < 0) return
val expectedItem = recipe.neuRecipe.inputs[recipeIndex]
val actualStack = slot.stack ?: ItemStack.EMPTY!!
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.util.Formatting
import net.minecraft.util.Identifier
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.HotbarItemRenderEvent
import moe.nea.firmament.events.SlotRenderEvents
import moe.nea.firmament.features.FirmamentFeature
@@ -65,16 +66,18 @@ object ItemRarityCosmetics : FirmamentFeature {
)
}
override fun onLoad() {
HotbarItemRenderEvent.subscribe {
if (!TConfig.showItemRarityInHotbar) return@subscribe
@Subscribe
fun onRenderSlot(it: SlotRenderEvents.Before) {
if (!TConfig.showItemRarityBackground) return
val stack = it.slot.stack ?: return
drawItemStackRarity(it.context, it.slot.x, it.slot.y, stack)
}
@Subscribe
fun onRenderHotbarItem(it: HotbarItemRenderEvent) {
if (!TConfig.showItemRarityInHotbar) return
val stack = it.item
drawItemStackRarity(it.context, it.x, it.y, stack)
}
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 fun onLoad() {
}
@Subscribe
fun function(it: ItemTooltipEvent) {
fun onItemTooltip(it: ItemTooltipEvent) {
if (!TConfig.tooltipEnabled && !TConfig.enableKeybinding.isPressed()) {
return
}

View File

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

View File

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

View File

@@ -9,6 +9,7 @@ package moe.nea.firmament.features.inventory.buttons
import me.shedaniel.math.Rectangle
import kotlinx.serialization.Serializable
import kotlinx.serialization.serializer
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.HandledScreenClickEvent
import moe.nea.firmament.events.HandledScreenForegroundEvent
import moe.nea.firmament.events.HandledScreenPushREIEvent
@@ -28,6 +29,7 @@ object InventoryButtons : FirmamentFeature {
openEditor()
}
}
object DConfig : DataHolder<Data>(serializer(), identifier, ::Data)
@Serializable
@@ -40,19 +42,18 @@ object InventoryButtons : FirmamentFeature {
get() = TConfig
fun getValidButtons() = DConfig.data.buttons.asSequence().filter { it.isValid() }
override fun onLoad() {
HandledScreenForegroundEvent.subscribe {
@Subscribe
fun onRectangles(it: HandledScreenPushREIEvent) {
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()
it.block(buttonBounds)
}
lastRectangle = bounds
}
HandledScreenClickEvent.subscribe {
@Subscribe
fun onClickScreen(it: HandledScreenClickEvent) {
val bounds = it.screen.getRectangle()
for (button in getValidButtons()) {
val buttonBounds = button.getBounds(bounds)
@@ -62,13 +63,18 @@ object InventoryButtons : FirmamentFeature {
}
}
}
HandledScreenPushREIEvent.subscribe {
@Subscribe
fun onRenderForeground(it: HandledScreenForegroundEvent) {
val bounds = it.screen.getRectangle()
for (button in getValidButtons()) {
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

View File

@@ -6,9 +6,10 @@
package moe.nea.firmament.features.inventory.storageoverlay
import java.util.*
import java.util.SortedMap
import kotlinx.serialization.serializer
import net.minecraft.client.gui.screen.Screen
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.ScreenChangeEvent
import moe.nea.firmament.events.TickEvent
import moe.nea.firmament.features.FirmamentFeature
@@ -40,8 +41,24 @@ object StorageOverlay : FirmamentFeature {
var shouldReturnToStorageOverlay: Screen? = null
var currentHandler: StorageBackingHandle? = StorageBackingHandle.None
override fun onLoad() {
ScreenChangeEvent.subscribe {
@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) {
shouldReturnToStorageOverlay = lastStorageOverlay
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) {
// TODO: Make all of these functions work on deltas / updates instead of the entire contents
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.Hand
import net.minecraft.util.Identifier
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.HudRenderEvent
import moe.nea.firmament.events.ProcessChatEvent
import moe.nea.firmament.events.SlotClickEvent
@@ -73,32 +74,31 @@ object PickaxeAbility : FirmamentFeature {
return 1.0
}
override fun onLoad() {
HudRenderEvent.subscribe(this::renderHud)
WorldReadyEvent.subscribe {
lastUsage.clear()
lobbyJoinTime = TimeMark.now()
abilityOverride = null
@Subscribe
fun onSlotClick(it: SlotClickEvent) {
if (MC.screen?.title?.unformattedString == "Heart of the Mountain") {
val name = it.stack.displayNameAccordingToNbt?.unformattedString ?: return
val cooldown = it.stack.loreAccordingToNbt.firstNotNullOfOrNull {
cooldownPattern.useMatch(it.unformattedString) {
parseTimePattern(group("cooldown"))
}
ProcessChatEvent.subscribe {
abilityUsePattern.useMatch(it.unformattedString) {
lastUsage[group("name")] = TimeMark.now()
}
abilitySwitchPattern.useMatch(it.unformattedString) {
abilityOverride = group("ability")
} ?: return
defaultAbilityDurations[name] = cooldown
}
}
DurabilityBarEvent.subscribe {
if (!TConfig.drillFuelBar) return@subscribe
@Subscribe
fun onDurabilityBar(it: DurabilityBarEvent) {
if (!TConfig.drillFuelBar) return
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 {
fuelPattern.useMatch(it.unformattedString) {
parseShortNumber(group("maxFuel"))
}
} ?: return@subscribe
} ?: return
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 percentage = fuel / maxFuel.toFloat()
it.barOverride = DurabilityBarEvent.DurabilityBar(
@@ -109,17 +109,22 @@ object PickaxeAbility : FirmamentFeature {
), percentage
)
}
SlotClickEvent.subscribe {
if (MC.screen?.title?.unformattedString == "Heart of the Mountain") {
val name = it.stack.displayNameAccordingToNbt?.unformattedString ?: return@subscribe
val cooldown = it.stack.loreAccordingToNbt.firstNotNullOfOrNull {
cooldownPattern.useMatch(it.unformattedString) {
parseTimePattern(group("cooldown"))
@Subscribe
fun onChatMessage(it: ProcessChatEvent) {
abilityUsePattern.useMatch(it.unformattedString) {
lastUsage[group("name")] = TimeMark.now()
}
} ?: return@subscribe
defaultAbilityDurations[name] = cooldown
abilitySwitchPattern.useMatch(it.unformattedString) {
abilityOverride = group("ability")
}
}
@Subscribe
fun onWorldReady(event: WorldReadyEvent) {
lastUsage.clear()
lobbyJoinTime = TimeMark.now()
abilityOverride = null
}
val abilityUsePattern = Pattern.compile("You used your (?<name>.*) Pickaxe Ability!")
@@ -154,7 +159,8 @@ object PickaxeAbility : FirmamentFeature {
Pattern.compile("You selected (?<ability>.*) as your Pickaxe Ability\\. This ability will apply to all of your pickaxes!")
private fun renderHud(event: HudRenderEvent) {
@Subscribe
fun renderHud(event: HudRenderEvent) {
if (!TConfig.cooldownEnabled) return
var ability = getCooldownFromLore(MC.player?.getStackInHand(Hand.MAIN_HAND) ?: return) ?: return
defaultAbilityDurations[ability.name] = ability.cooldown

View File

@@ -12,6 +12,7 @@ import kotlinx.serialization.Serializable
import kotlinx.serialization.serializer
import kotlin.time.Duration.Companion.seconds
import net.minecraft.text.Text
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.ProcessChatEvent
import moe.nea.firmament.features.FirmamentFeature
import moe.nea.firmament.gui.config.ManagedConfig
@@ -62,7 +63,7 @@ object PristineProfitTracker : FirmamentFeature {
val pristineRegex =
"PRISTINE! You found . Flawed (?<kind>${
GemstoneKind.values().joinToString("|") { it.label }
GemstoneKind.entries.joinToString("|") { it.label }
}) Gemstone x(?<count>[0-9,]+)!".toPattern()
val collectionHistogram = Histogram<Double>(10000, 180.seconds)
@@ -97,9 +98,13 @@ object PristineProfitTracker : FirmamentFeature {
val moneyPerSecond = moneyHistogram.averagePer({ it }, 1.seconds)
if (collectionPerSecond == null || moneyPerSecond == null) return
ProfitHud.collectionCurrent = collectionPerSecond
ProfitHud.collectionText = Text.stringifiedTranslatable("firmament.pristine-profit.collection", formatCurrency(collectionPerSecond * SECONDS_PER_HOUR, 1)).formattedString()
ProfitHud.collectionText = Text.stringifiedTranslatable("firmament.pristine-profit.collection",
formatCurrency(collectionPerSecond * SECONDS_PER_HOUR,
1)).formattedString()
ProfitHud.moneyCurrent = moneyPerSecond
ProfitHud.moneyText = Text.stringifiedTranslatable("firmament.pristine-profit.money", formatCurrency(moneyPerSecond * SECONDS_PER_HOUR, 1)).formattedString()
ProfitHud.moneyText = Text.stringifiedTranslatable("firmament.pristine-profit.money",
formatCurrency(moneyPerSecond * SECONDS_PER_HOUR, 1))
.formattedString()
val data = DConfig.data
if (data != null) {
if (data.maxCollectionPerSecond < collectionPerSecond && collectionHistogram.oldestUpdate()
@@ -118,8 +123,8 @@ object PristineProfitTracker : FirmamentFeature {
}
override fun onLoad() {
ProcessChatEvent.subscribe {
@Subscribe
fun onMessage(it: ProcessChatEvent) {
pristineRegex.useMatch(it.unformattedString) {
val gemstoneKind = GemstoneKind.valueOf(group("kind").uppercase())
val flawedCount = parseIntWithComma(group("count"))
@@ -130,5 +135,4 @@ object PristineProfitTracker : FirmamentFeature {
updateUi()
}
}
}
}

View File

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

View File

@@ -9,15 +9,10 @@ package moe.nea.firmament.features.world
import io.github.moulberry.repo.data.Coordinate
import kotlinx.serialization.Serializable
import kotlinx.serialization.serializer
import net.minecraft.client.render.RenderLayer
import net.minecraft.client.render.RenderLayer.ALWAYS_DEPTH_TEST
import net.minecraft.client.render.RenderLayer.MultiPhaseParameters
import net.minecraft.client.render.RenderPhase
import net.minecraft.client.render.VertexFormat
import net.minecraft.client.render.VertexFormats
import net.minecraft.text.Text
import net.minecraft.util.math.Vec3d
import moe.nea.firmament.events.AllowChatEvent
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.ProcessChatEvent
import moe.nea.firmament.events.SkyblockServerUpdateEvent
import moe.nea.firmament.events.WorldRenderLastEvent
import moe.nea.firmament.features.FirmamentFeature
@@ -102,44 +97,15 @@ object FairySouls : FirmamentFeature {
updateMissingSouls()
}
val NODEPTH: RenderLayer = RenderLayer.of(
"firmamentnodepth",
VertexFormats.POSITION_COLOR_TEXTURE,
VertexFormat.DrawMode.QUADS,
256,
true,
true,
MultiPhaseParameters.builder()
.program(RenderPhase.COLOR_PROGRAM)
.writeMaskState(RenderPhase.COLOR_MASK)
.depthTest(ALWAYS_DEPTH_TEST)
.cull(RenderPhase.DISABLE_CULLING)
.layering(RenderLayer.VIEW_OFFSET_Z_LAYERING)
.target(RenderPhase.MAIN_TARGET)
.build(true)
)
override fun onLoad() {
SkyblockServerUpdateEvent.subscribe {
currentLocationName = it.newLocraw?.skyblockLocation
updateWorldSouls()
updateMissingSouls()
}
AllowChatEvent.subscribe {
when (it.text.unformattedString) {
"You have already found that Fairy Soul!" -> {
markNearestSoul()
}
"SOUL! You found a Fairy Soul!" -> {
markNearestSoul()
}
}
}
WorldRenderLastEvent.subscribe {
if (!TConfig.displaySouls) return@subscribe
@Subscribe
fun onWorldRender(it: WorldRenderLastEvent) {
if (!TConfig.displaySouls) return
renderInWorld(it) {
text(Vec3d(0.0, 0.0, 0.0), Text.literal("Test String") , Text.literal("Short"), Text.literal("just lik"), verticalAlign = RenderInWorldContext.VerticalAlign.BOTTOM)
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)
@@ -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.Vec3d
import moe.nea.firmament.Firmament
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.commands.get
import moe.nea.firmament.commands.thenArgument
import moe.nea.firmament.commands.thenExecute
@@ -73,46 +74,81 @@ object Waypoints : FirmamentFeature {
val b: Int = 0,
)
override fun onLoad() {
WorldRenderLastEvent.subscribe { event ->
temporaryPlayerWaypointList.entries.removeIf { it.value.postedAt.passedTime() > TConfig.tempWaypointDuration }
if (temporaryPlayerWaypointList.isNotEmpty())
@Subscribe
fun onRenderOrderedWaypoints(event: WorldRenderLastEvent) {
if (waypoints.isEmpty()) return
RenderInWorldContext.renderInWorld(event) {
color(1f, 1f, 0f, 1f)
temporaryPlayerWaypointList.forEach { (player, waypoint) ->
block(waypoint.pos)
}
if (!ordered) {
waypoints.withIndex().forEach {
color(0f, 0.3f, 0.7f, 0.5f)
block(it.value)
color(1f, 1f, 1f, 1f)
temporaryPlayerWaypointList.forEach { (player, waypoint) ->
val skin =
MC.networkHandler?.listedPlayerListEntries?.find { it.profile.name == player }
?.skinTextures
?.texture
withFacingThePlayer(waypoint.pos.toCenterPos()) {
waypoint(waypoint.pos, Text.stringifiedTranslatable("firmament.waypoint.temporary", player))
if (skin != null) {
matrixStack.translate(0F, -20F, 0F)
// Head front
texture(
skin, 16, 16,
1 / 8f, 1 / 8f,
2 / 8f, 2 / 8f,
if (TConfig.showIndex)
withFacingThePlayer(it.value.toCenterPos()) {
text(Text.literal(it.index.toString()))
}
}
} else {
orderedIndex %= waypoints.size
val firstColor = Color.ofRGBA(0, 200, 40, 180)
color(firstColor)
tracer(waypoints[orderedIndex].toCenterPos(), lineWidth = 3f)
waypoints.withIndex().toList()
.wrappingWindow(orderedIndex, 3)
.zip(
listOf(
firstColor,
Color.ofRGBA(180, 200, 40, 150),
Color.ofRGBA(180, 80, 20, 140),
)
// Head overlay
texture(
skin, 16, 16,
5 / 8f, 1 / 8f,
6 / 8f, 2 / 8f,
)
.reversed()
.forEach { (waypoint, col) ->
val (index, pos) = waypoint
color(col)
block(pos)
color(1f, 1f, 1f, 1f)
if (TConfig.showIndex)
withFacingThePlayer(pos.toCenterPos()) {
text(Text.literal(index.toString()))
}
}
}
}
}
@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()
)
}
}
}
}
}
WorldReadyEvent.subscribe {
temporaryPlayerWaypointList.clear()
}
CommandEvent.SubCommand.subscribe { event ->
@Subscribe
fun onCommand(event: CommandEvent.SubCommand) {
event.subcommand("waypoint") {
thenArgument("pos", BlockPosArgumentType.blockPos()) { pos ->
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) {
if (!ordered) {
waypoints.withIndex().forEach {
color(0f, 0.3f, 0.7f, 0.5f)
block(it.value)
color(1f, 1f, 0f, 1f)
temporaryPlayerWaypointList.forEach { (player, waypoint) ->
block(waypoint.pos)
}
color(1f, 1f, 1f, 1f)
if (TConfig.showIndex)
withFacingThePlayer(it.value.toCenterPos()) {
text(Text.literal(it.index.toString()))
}
}
} else {
orderedIndex %= waypoints.size
val firstColor = Color.ofRGBA(0, 200, 40, 180)
color(firstColor)
tracer(waypoints[orderedIndex].toCenterPos(), lineWidth = 3f)
waypoints.withIndex().toList()
.wrappingWindow(orderedIndex, 3)
.zip(
listOf(
firstColor,
Color.ofRGBA(180, 200, 40, 150),
Color.ofRGBA(180, 80, 20, 140),
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,
)
)
.reversed()
.forEach { (waypoint, col) ->
val (index, pos) = waypoint
color(col)
block(pos)
color(1f, 1f, 1f, 1f)
if (TConfig.showIndex)
withFacingThePlayer(pos.toCenterPos()) {
text(Text.literal(index.toString()))
}
}
}
}
}
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()
// Head overlay
texture(
skin, 16, 16,
5 / 8f, 1 / 8f,
6 / 8f, 2 / 8f,
)
}
}
}
}
}
@Subscribe
fun onWorldReady(event: WorldReadyEvent) {
temporaryPlayerWaypointList.clear()
}
}
fun <E> List<E>.wrappingWindow(startIndex: Int, windowSize: Int): List<E> {