diff options
Diffstat (limited to 'src/main/kotlin/moe/nea/firmament')
25 files changed, 745 insertions, 698 deletions
diff --git a/src/main/kotlin/moe/nea/firmament/events/subscription/Subscription.kt b/src/main/kotlin/moe/nea/firmament/events/subscription/Subscription.kt index 1e7a6a8..a4542e7 100644 --- a/src/main/kotlin/moe/nea/firmament/events/subscription/Subscription.kt +++ b/src/main/kotlin/moe/nea/firmament/events/subscription/Subscription.kt @@ -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, diff --git a/src/main/kotlin/moe/nea/firmament/features/FirmamentFeature.kt b/src/main/kotlin/moe/nea/firmament/features/FirmamentFeature.kt index 2416fec..4b7ba9e 100644 --- a/src/main/kotlin/moe/nea/firmament/features/FirmamentFeature.kt +++ b/src/main/kotlin/moe/nea/firmament/features/FirmamentFeature.kt @@ -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() {} } diff --git a/src/main/kotlin/moe/nea/firmament/features/chat/AutoCompletions.kt b/src/main/kotlin/moe/nea/firmament/features/chat/AutoCompletions.kt index 9912321..3351970 100644 --- a/src/main/kotlin/moe/nea/firmament/features/chat/AutoCompletions.kt +++ b/src/main/kotlin/moe/nea/firmament/features/chat/AutoCompletions.kt @@ -7,6 +7,7 @@ package moe.nea.firmament.features.chat import com.mojang.brigadier.arguments.StringArgumentType.string +import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.commands.get import moe.nea.firmament.commands.suggestsList import moe.nea.firmament.commands.thenArgument @@ -30,28 +31,28 @@ object AutoCompletions : FirmamentFeature { override val identifier: String get() = "auto-completions" - override fun onLoad() { - MaskCommands.subscribe { - if (TConfig.provideWarpTabCompletion) { - it.mask("warp") - } + @Subscribe + fun onMaskCommands(event: MaskCommands) { + if (TConfig.provideWarpTabCompletion) { + event.mask("warp") } - CommandEvent.subscribe { - if (TConfig.provideWarpTabCompletion) { - it.deleteCommand("warp") - it.register("warp") { - thenArgument("to", string()) { toArg -> - suggestsList { - RepoManager.neuRepo.constants?.islands?.warps?.flatMap { listOf(it.warp) + it.aliases } ?: listOf() - } - thenExecute { - val warpName = get(toArg) - if (warpName == "is" && TConfig.replaceWarpIsByWarpIsland) { - MC.sendServerCommand("warp island") - } else { - MC.sendServerCommand("warp ${warpName}") - } - } + } + + @Subscribe + fun onCommandEvent(event: CommandEvent) { + if (!TConfig.provideWarpTabCompletion) return + event.deleteCommand("warp") + event.register("warp") { + thenArgument("to", string()) { toArg -> + suggestsList { + RepoManager.neuRepo.constants?.islands?.warps?.flatMap { listOf(it.warp) + it.aliases } ?: listOf() + } + thenExecute { + val warpName = get(toArg) + if (warpName == "is" && TConfig.replaceWarpIsByWarpIsland) { + MC.sendServerCommand("warp island") + } else { + MC.sendServerCommand("warp $warpName") } } } diff --git a/src/main/kotlin/moe/nea/firmament/features/chat/ChatLinks.kt b/src/main/kotlin/moe/nea/firmament/features/chat/ChatLinks.kt index 6bb6f6e..717e503 100644 --- a/src/main/kotlin/moe/nea/firmament/features/chat/ChatLinks.kt +++ b/src/main/kotlin/moe/nea/firmament/features/chat/ChatLinks.kt @@ -6,11 +6,11 @@ package moe.nea.firmament.features.chat -import io.ktor.client.request.* -import io.ktor.client.statement.* -import io.ktor.utils.io.jvm.javaio.* +import io.ktor.client.request.get +import io.ktor.client.statement.bodyAsChannel +import io.ktor.utils.io.jvm.javaio.toInputStream import java.net.URL -import java.util.* +import java.util.Collections import moe.nea.jarvis.api.Point import kotlinx.coroutines.Deferred import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -26,6 +26,7 @@ import net.minecraft.text.Text import net.minecraft.util.Formatting import net.minecraft.util.Identifier import moe.nea.firmament.Firmament +import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.events.ModifyChatEvent import moe.nea.firmament.events.ScreenRenderPostEvent import moe.nea.firmament.features.FirmamentFeature @@ -96,69 +97,69 @@ object ChatLinks : FirmamentFeature { return (url.substringAfterLast('.').lowercase() in imageExtensions) } + @Subscribe @OptIn(ExperimentalCoroutinesApi::class) - override fun onLoad() { - ModifyChatEvent.subscribe { - if (TConfig.enableLinks) - it.replaceWith = it.replaceWith.transformEachRecursively { child -> - val text = child.string - if ("://" !in text) return@transformEachRecursively child - val s = Text.empty().setStyle(child.style) - var index = 0 - while (index < text.length) { - val nextMatch = urlRegex.find(text, index) - if (nextMatch == null) { - s.append(Text.literal(text.substring(index, text.length))) - break - } - val range = nextMatch.groups[0]!!.range - val url = nextMatch.groupValues[0] - s.append(Text.literal(text.substring(index, range.first))) - s.append( - Text.literal(url).setStyle( - Style.EMPTY.withUnderline(true).withColor( - Formatting.AQUA - ).withHoverEvent(HoverEvent(HoverEvent.Action.SHOW_TEXT, Text.literal(url))) - .withClickEvent(ClickEvent(ClickEvent.Action.OPEN_URL, url)) - ) - ) - if (isImageUrl(url)) - tryCacheUrl(url) - index = range.last + 1 - } - s - } - } + fun onRender(it: ScreenRenderPostEvent) { + if (!TConfig.imageEnabled) return + if (it.screen !is ChatScreen) return + val hoveredComponent = + MC.inGameHud.chatHud.getTextStyleAt(it.mouseX.toDouble(), it.mouseY.toDouble()) ?: return + val hoverEvent = hoveredComponent.hoverEvent ?: return + val value = hoverEvent.getValue(HoverEvent.Action.SHOW_TEXT) ?: return + val url = urlRegex.matchEntire(value.unformattedString)?.groupValues?.get(0) ?: return + if (!isImageUrl(url)) return + val imageFuture = imageCache[url] ?: return + if (!imageFuture.isCompleted) return + val image = imageFuture.getCompleted() ?: return + it.drawContext.matrices.push() + val pos = TConfig.position + pos.applyTransformations(it.drawContext.matrices) + val scale = min(1F, min((9 * 20F) / image.height, (16 * 20F) / image.width)) + it.drawContext.matrices.scale(scale, scale, 1F) + it.drawContext.drawTexture( + image.texture, + 0, + 0, + 1F, + 1F, + image.width, + image.height, + image.width, + image.height, + ) + it.drawContext.matrices.pop() + } - ScreenRenderPostEvent.subscribe { - if (!TConfig.imageEnabled) return@subscribe - if (it.screen !is ChatScreen) return@subscribe - val hoveredComponent = - MC.inGameHud.chatHud.getTextStyleAt(it.mouseX.toDouble(), it.mouseY.toDouble()) ?: return@subscribe - val hoverEvent = hoveredComponent.hoverEvent ?: return@subscribe - val value = hoverEvent.getValue(HoverEvent.Action.SHOW_TEXT) ?: return@subscribe - val url = urlRegex.matchEntire(value.unformattedString)?.groupValues?.get(0) ?: return@subscribe - if (!isImageUrl(url)) return@subscribe - val imageFuture = imageCache[url] ?: return@subscribe - if (!imageFuture.isCompleted) return@subscribe - val image = imageFuture.getCompleted() ?: return@subscribe - it.drawContext.matrices.push() - val pos = TConfig.position - pos.applyTransformations(it.drawContext.matrices) - val scale = min(1F, min((9 * 20F) / image.height, (16 * 20F) / image.width)) - it.drawContext.matrices.scale(scale, scale, 1F) - it.drawContext.drawTexture( - image.texture, - 0, - 0, - 1F, - 1F, - image.width, - image.height, - image.width, - image.height, - ) - it.drawContext.matrices.pop() + @Subscribe + fun onModifyChat(it: ModifyChatEvent) { + if (!TConfig.enableLinks) return + it.replaceWith = it.replaceWith.transformEachRecursively { child -> + val text = child.string + if ("://" !in text) return@transformEachRecursively child + val s = Text.empty().setStyle(child.style) + var index = 0 + while (index < text.length) { + val nextMatch = urlRegex.find(text, index) + if (nextMatch == null) { + s.append(Text.literal(text.substring(index, text.length))) + break + } + val range = nextMatch.groups[0]!!.range + val url = nextMatch.groupValues[0] + s.append(Text.literal(text.substring(index, range.first))) + s.append( + Text.literal(url).setStyle( + Style.EMPTY.withUnderline(true).withColor( + Formatting.AQUA + ).withHoverEvent(HoverEvent(HoverEvent.Action.SHOW_TEXT, Text.literal(url))) + .withClickEvent(ClickEvent(ClickEvent.Action.OPEN_URL, url)) + ) + ) + if (isImageUrl(url)) + tryCacheUrl(url) + index = range.last + 1 + } + s } } } diff --git a/src/main/kotlin/moe/nea/firmament/features/chat/QuickCommands.kt b/src/main/kotlin/moe/nea/firmament/features/chat/QuickCommands.kt index 47be3c1..97ec6e8 100644 --- a/src/main/kotlin/moe/nea/firmament/features/chat/QuickCommands.kt +++ b/src/main/kotlin/moe/nea/firmament/features/chat/QuickCommands.kt @@ -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,29 +35,30 @@ object QuickCommands : FirmamentFeature { val kuudraLevelNames = listOf("NORMAL", "HOT", "BURNING", "FIERY", "INFERNAL") val dungeonLevelNames = listOf("ONE", "TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN") - override fun onLoad() { - CommandEvent.subscribe { - it.register("join") { - thenArgument("what", RestArgumentType) { what -> - thenExecute { - val what = this[what] - if (!SBData.isOnSkyblock) { - MC.sendCommand("join $what") - return@thenExecute - } - val joinName = getNameForFloor(what.replace(" ", "").lowercase()) - if (joinName == null) { - source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.unknown", what)) - } else { - source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.success", joinName)) - MC.sendCommand("joininstance $joinName") - } - } - } + + @Subscribe + fun onCommands(it: CommandEvent) { + it.register("join") { + thenArgument("what", RestArgumentType) { what -> thenExecute { - source.sendFeedback(Text.translatable("firmament.quick-commands.join.explain")) + val what = this[what] + if (!SBData.isOnSkyblock) { + MC.sendCommand("join $what") + return@thenExecute + } + val joinName = getNameForFloor(what.replace(" ", "").lowercase()) + if (joinName == null) { + source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.unknown", what)) + } else { + source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.success", + joinName)) + MC.sendCommand("joininstance $joinName") + } } } + thenExecute { + source.sendFeedback(Text.translatable("firmament.quick-commands.join.explain")) + } } } @@ -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]}" diff --git a/src/main/kotlin/moe/nea/firmament/features/debug/DeveloperFeatures.kt b/src/main/kotlin/moe/nea/firmament/features/debug/DeveloperFeatures.kt index 6bbbdf0..1d7ce49 100644 --- a/src/main/kotlin/moe/nea/firmament/features/debug/DeveloperFeatures.kt +++ b/src/main/kotlin/moe/nea/firmament/features/debug/DeveloperFeatures.kt @@ -55,9 +55,5 @@ object DeveloperFeatures : FirmamentFeature { } return reloadFuture.thenCompose { client.reloadResources() } } - - - override fun onLoad() { - } } diff --git a/src/main/kotlin/moe/nea/firmament/features/debug/MinorTrolling.kt b/src/main/kotlin/moe/nea/firmament/features/debug/MinorTrolling.kt index 95c77ab..57fd8e2 100644 --- a/src/main/kotlin/moe/nea/firmament/features/debug/MinorTrolling.kt +++ b/src/main/kotlin/moe/nea/firmament/features/debug/MinorTrolling.kt @@ -6,9 +6,10 @@ package moe.nea.firmament.features.debug +import net.minecraft.text.Text +import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.events.ModifyChatEvent import moe.nea.firmament.features.FirmamentFeature -import net.minecraft.text.Text // In memorian Dulkir @@ -19,13 +20,12 @@ object MinorTrolling : FirmamentFeature { val trollers = listOf("nea89o", "lrg89") val t = "From(?: \\[[^\\]]+])? ([^:]+): (.*)".toRegex() - override fun onLoad() { - ModifyChatEvent.subscribe { - val m = t.matchEntire(it.unformattedString) ?: return@subscribe - val (_, name, text) = m.groupValues - if (name !in trollers) return@subscribe - if (!text.startsWith("c:")) return@subscribe - it.replaceWith = Text.literal(text.substring(2).replace("&", "§")) - } + @Subscribe + fun onTroll(it: ModifyChatEvent) { + val m = t.matchEntire(it.unformattedString) ?: return + val (_, name, text) = m.groupValues + if (name !in trollers) return + if (!text.startsWith("c:")) return + it.replaceWith = Text.literal(text.substring(2).replace("&", "§")) } } diff --git a/src/main/kotlin/moe/nea/firmament/features/debug/PowerUserTools.kt b/src/main/kotlin/moe/nea/firmament/features/debug/PowerUserTools.kt index 99ef0d5..d530487 100644 --- a/src/main/kotlin/moe/nea/firmament/features/debug/PowerUserTools.kt +++ b/src/main/kotlin/moe/nea/firmament/features/debug/PowerUserTools.kt @@ -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,56 +63,98 @@ object PowerUserTools : FirmamentFeature { ScreenChangeEvent.subscribe { lastCopiedStack = null } - HandledScreenKeyPressedEvent.subscribe { - if (it.screen !is AccessorHandledScreen) return@subscribe - val item = it.screen.focusedItemStack ?: return@subscribe - if (it.matches(TConfig.copyItemId)) { - val sbId = item.skyBlockId - if (sbId == null) { - lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skyblockid.fail")) - return@subscribe - } - ClipboardUtils.setTextContent(sbId.neuItem) - lastCopiedStack = - Pair(item, Text.stringifiedTranslatable("firmament.tooltip.copied.skyblockid", sbId.neuItem)) - } else if (it.matches(TConfig.copyTexturePackId)) { - val model = CustomItemModelEvent.getModelIdentifier(item) - if (model == null) { - lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.modelid.fail")) - return@subscribe - } - ClipboardUtils.setTextContent(model.toString()) - lastCopiedStack = - Pair(item, Text.stringifiedTranslatable("firmament.tooltip.copied.modelid", model.toString())) - } else if (it.matches(TConfig.copyNbtData)) { - // TODO: copy full nbt - val nbt = item.get(DataComponentTypes.CUSTOM_DATA)?.nbt?.toString() ?: "<empty>" - ClipboardUtils.setTextContent(nbt) - lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.nbt")) - } else if (it.matches(TConfig.copySkullTexture)) { - if (item.item != Items.PLAYER_HEAD) { - lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skull-id.fail.no-skull")) - return@subscribe - } - val profile = item.get(DataComponentTypes.PROFILE) - if (profile == null) { - lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skull-id.fail.no-profile")) - return@subscribe - } - val skullTexture = CustomSkyBlockTextures.getSkullTexture(profile) - if (skullTexture == null) { - lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skull-id.fail.no-texture")) - return@subscribe - } - ClipboardUtils.setTextContent(skullTexture.toString()) - lastCopiedStack = - Pair( - item, - Text.stringifiedTranslatable("firmament.tooltip.copied.skull-id", skullTexture.toString()) - ) - println("Copied skull id: $skullTexture") + } + + @Subscribe + fun copyInventoryInfo(it: HandledScreenKeyPressedEvent) { + if (it.screen !is AccessorHandledScreen) return + val item = it.screen.focusedItemStack ?: return + if (it.matches(TConfig.copyItemId)) { + val sbId = item.skyBlockId + if (sbId == null) { + lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skyblockid.fail")) + return + } + ClipboardUtils.setTextContent(sbId.neuItem) + lastCopiedStack = + Pair(item, Text.stringifiedTranslatable("firmament.tooltip.copied.skyblockid", sbId.neuItem)) + } else if (it.matches(TConfig.copyTexturePackId)) { + val model = CustomItemModelEvent.getModelIdentifier(item) + if (model == null) { + lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.modelid.fail")) + return + } + ClipboardUtils.setTextContent(model.toString()) + lastCopiedStack = + Pair(item, Text.stringifiedTranslatable("firmament.tooltip.copied.modelid", model.toString())) + } else if (it.matches(TConfig.copyNbtData)) { + // TODO: copy full nbt + val nbt = item.get(DataComponentTypes.CUSTOM_DATA)?.nbt?.toString() ?: "<empty>" + ClipboardUtils.setTextContent(nbt) + lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.nbt")) + } else if (it.matches(TConfig.copySkullTexture)) { + if (item.item != Items.PLAYER_HEAD) { + lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skull-id.fail.no-skull")) + return + } + val profile = item.get(DataComponentTypes.PROFILE) + if (profile == null) { + lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skull-id.fail.no-profile")) + return + } + val skullTexture = CustomSkyBlockTextures.getSkullTexture(profile) + if (skullTexture == null) { + lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skull-id.fail.no-texture")) + return } + ClipboardUtils.setTextContent(skullTexture.toString()) + lastCopiedStack = + Pair( + item, + Text.stringifiedTranslatable("firmament.tooltip.copied.skull-id", skullTexture.toString()) + ) + println("Copied skull id: $skullTexture") + } + } + + @Subscribe + fun onCopyWorldInfo(it: WorldKeyboardEvent) { + if (it.matches(TConfig.copySkullTexture)) { + val p = MC.camera ?: return + val blockHit = p.raycast(20.0, 0.0f, false) ?: return + if (blockHit.type != HitResult.Type.BLOCK || blockHit !is BlockHitResult) { + MC.sendChat(Text.translatable("firmament.tooltip.copied.skull.fail")) + return + } + val blockAt = p.world.getBlockState(blockHit.blockPos)?.block + val entity = p.world.getBlockEntity(blockHit.blockPos) + if (blockAt !is SkullBlock || entity !is SkullBlockEntity || entity.owner == null) { + MC.sendChat(Text.translatable("firmament.tooltip.copied.skull.fail")) + return + } + val id = CustomSkyBlockTextures.getSkullTexture(entity.owner!!) + if (id == null) { + MC.sendChat(Text.translatable("firmament.tooltip.copied.skull.fail")) + } else { + ClipboardUtils.setTextContent(id.toString()) + MC.sendChat(Text.stringifiedTranslatable("firmament.tooltip.copied.skull", id.toString())) + } + } + } + + @Subscribe + fun addItemId(it: ItemTooltipEvent) { + if (TConfig.showItemIds) { + val id = it.stack.skyBlockId ?: return + it.lines.add(Text.stringifiedTranslatable("firmament.tooltip.skyblockid", id.neuItem)) + } + val (item, text) = lastCopiedStack ?: return + if (!ItemStack.areEqual(item, it.stack)) { + lastCopiedStack = null + return } + lastCopiedStackViewTime = true + it.lines.add(text) } diff --git a/src/main/kotlin/moe/nea/firmament/features/diana/AncestralSpadeSolver.kt b/src/main/kotlin/moe/nea/firmament/features/diana/AncestralSpadeSolver.kt index b9c83e6..e80ef92 100644 --- a/src/main/kotlin/moe/nea/firmament/features/diana/AncestralSpadeSolver.kt +++ b/src/main/kotlin/moe/nea/firmament/features/diana/AncestralSpadeSolver.kt @@ -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 + } diff --git a/src/main/kotlin/moe/nea/firmament/features/diana/DianaWaypoints.kt b/src/main/kotlin/moe/nea/firmament/features/diana/DianaWaypoints.kt index 9102497..b1f66c1 100644 --- a/src/main/kotlin/moe/nea/firmament/features/diana/DianaWaypoints.kt +++ b/src/main/kotlin/moe/nea/firmament/features/diana/DianaWaypoints.kt @@ -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) } } diff --git a/src/main/kotlin/moe/nea/firmament/features/diana/NearbyBurrowsSolver.kt b/src/main/kotlin/moe/nea/firmament/features/diana/NearbyBurrowsSolver.kt index 1ab7e01..e6aeeae 100644 --- a/src/main/kotlin/moe/nea/firmament/features/diana/NearbyBurrowsSolver.kt +++ b/src/main/kotlin/moe/nea/firmament/features/diana/NearbyBurrowsSolver.kt @@ -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 { diff --git a/src/main/kotlin/moe/nea/firmament/features/fixes/CompatibliltyFeatures.kt b/src/main/kotlin/moe/nea/firmament/features/fixes/CompatibliltyFeatures.kt index d3029d8..041e9f3 100644 --- a/src/main/kotlin/moe/nea/firmament/features/fixes/CompatibliltyFeatures.kt +++ b/src/main/kotlin/moe/nea/firmament/features/fixes/CompatibliltyFeatures.kt @@ -10,6 +10,7 @@ import net.fabricmc.loader.api.FabricLoader import net.superkat.explosiveenhancement.api.ExplosiveApi import net.minecraft.particle.ParticleTypes import net.minecraft.util.math.Vec3d +import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.events.ParticleSpawnEvent import moe.nea.firmament.features.FirmamentFeature import moe.nea.firmament.gui.config.ManagedConfig @@ -41,15 +42,14 @@ object CompatibliltyFeatures : FirmamentFeature { ExplosiveApiWrapperImpl() } else null - override fun onLoad() { - ParticleSpawnEvent.subscribe { - if (TConfig.enhancedExplosions && - it.particleEffect.type == ParticleTypes.EXPLOSION_EMITTER && - explosiveApiWrapper != null - ) { - it.cancel() - explosiveApiWrapper.spawnParticle(it.position, 2F) - } + @Subscribe + fun onExplosion(it: ParticleSpawnEvent) { + if (TConfig.enhancedExplosions && + it.particleEffect.type == ParticleTypes.EXPLOSION_EMITTER && + explosiveApiWrapper != null + ) { + it.cancel() + explosiveApiWrapper.spawnParticle(it.position, 2F) } } } diff --git a/src/main/kotlin/moe/nea/firmament/features/fixes/Fixes.kt b/src/main/kotlin/moe/nea/firmament/features/fixes/Fixes.kt index 200bb74..26cfe6b 100644 --- a/src/main/kotlin/moe/nea/firmament/features/fixes/Fixes.kt +++ b/src/main/kotlin/moe/nea/firmament/features/fixes/Fixes.kt @@ -13,6 +13,7 @@ import net.minecraft.client.option.KeyBinding import net.minecraft.entity.player.PlayerEntity import net.minecraft.text.Text import net.minecraft.util.Arm +import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.events.HudRenderEvent import moe.nea.firmament.events.WorldKeyboardEvent import moe.nea.firmament.features.FirmamentFeature @@ -50,27 +51,28 @@ object Fixes : FirmamentFeature { } } - override fun onLoad() { - WorldKeyboardEvent.subscribe { - if (it.matches(TConfig.autoSprintKeyBinding)) { - TConfig.autoSprint = !TConfig.autoSprint - } - } - HudRenderEvent.subscribe { - if (!TConfig.autoSprintKeyBinding.isBound) return@subscribe - it.context.matrices.push() - TConfig.autoSprintHud.applyTransformations(it.context.matrices) - it.context.drawText( - MC.font, Text.translatable( - if (TConfig.autoSprint) - "firmament.fixes.auto-sprint.on" - else if (MC.player?.isSprinting == true) - "firmament.fixes.auto-sprint.sprinting" - else - "firmament.fixes.auto-sprint.not-sprinting" - ), 0, 0, -1, false - ) - it.context.matrices.pop() + @Subscribe + fun onRenderHud(it: HudRenderEvent) { + if (!TConfig.autoSprintKeyBinding.isBound) return + it.context.matrices.push() + TConfig.autoSprintHud.applyTransformations(it.context.matrices) + it.context.drawText( + MC.font, Text.translatable( + if (TConfig.autoSprint) + "firmament.fixes.auto-sprint.on" + else if (MC.player?.isSprinting == true) + "firmament.fixes.auto-sprint.sprinting" + else + "firmament.fixes.auto-sprint.not-sprinting" + ), 0, 0, -1, false + ) + it.context.matrices.pop() + } + + @Subscribe + fun onWorldKeyboard(it: WorldKeyboardEvent) { + if (it.matches(TConfig.autoSprintKeyBinding)) { + TConfig.autoSprint = !TConfig.autoSprint } } diff --git a/src/main/kotlin/moe/nea/firmament/features/inventory/CraftingOverlay.kt b/src/main/kotlin/moe/nea/firmament/features/inventory/CraftingOverlay.kt index e7f821d..866d1cc 100644 --- a/src/main/kotlin/moe/nea/firmament/features/inventory/CraftingOverlay.kt +++ b/src/main/kotlin/moe/nea/firmament/features/inventory/CraftingOverlay.kt @@ -9,11 +9,12 @@ package moe.nea.firmament.features.inventory import net.minecraft.client.gui.screen.ingame.GenericContainerScreen import net.minecraft.item.ItemStack import net.minecraft.util.Formatting +import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.events.SlotRenderEvents import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.rei.recipes.SBCraftingRecipe import moe.nea.firmament.rei.FirmamentReiPlugin.Companion.asItemEntry import moe.nea.firmament.rei.SBItemEntryDefinition +import moe.nea.firmament.rei.recipes.SBCraftingRecipe import moe.nea.firmament.util.MC object CraftingOverlay : FirmamentFeature { @@ -35,36 +36,35 @@ object CraftingOverlay : FirmamentFeature { override val identifier: String get() = "crafting-overlay" - override fun onLoad() { - SlotRenderEvents.After.subscribe { event -> - val slot = event.slot - val recipe = this.recipe ?: return@subscribe - if (slot.inventory != screen?.screenHandler?.inventory) return@subscribe - val recipeIndex = craftingOverlayIndices.indexOf(slot.index) - if (recipeIndex < 0) return@subscribe - val expectedItem = recipe.neuRecipe.inputs[recipeIndex] - val actualStack = slot.stack ?: ItemStack.EMPTY!! - val actualEntry = SBItemEntryDefinition.getEntry(actualStack).value - if ((actualEntry.skyblockId.neuItem != expectedItem.itemId || actualEntry.stackSize < expectedItem.amount) && expectedItem.amount.toInt() != 0) { - event.context.fill( - event.slot.x, - event.slot.y, - event.slot.x + 16, - event.slot.y + 16, - 0x80FF0000.toInt() - ) - } - if (!slot.hasStack()) { - val itemStack = SBItemEntryDefinition.getEntry(expectedItem).asItemEntry().value - event.context.drawItem(itemStack, event.slot.x, event.slot.y) - event.context.drawItemInSlot( - MC.font, - itemStack, - event.slot.x, - event.slot.y, - "${Formatting.RED}${expectedItem.amount.toInt()}" - ) - } + @Subscribe + fun onSlotRender(event: SlotRenderEvents.After) { + val slot = event.slot + val recipe = this.recipe ?: return + if (slot.inventory != screen?.screenHandler?.inventory) return + val recipeIndex = craftingOverlayIndices.indexOf(slot.index) + if (recipeIndex < 0) return + val expectedItem = recipe.neuRecipe.inputs[recipeIndex] + val actualStack = slot.stack ?: ItemStack.EMPTY!! + val actualEntry = SBItemEntryDefinition.getEntry(actualStack).value + if ((actualEntry.skyblockId.neuItem != expectedItem.itemId || actualEntry.stackSize < expectedItem.amount) && expectedItem.amount.toInt() != 0) { + event.context.fill( + event.slot.x, + event.slot.y, + event.slot.x + 16, + event.slot.y + 16, + 0x80FF0000.toInt() + ) + } + if (!slot.hasStack()) { + val itemStack = SBItemEntryDefinition.getEntry(expectedItem).asItemEntry().value + event.context.drawItem(itemStack, event.slot.x, event.slot.y) + event.context.drawItemInSlot( + MC.font, + itemStack, + event.slot.x, + event.slot.y, + "${Formatting.RED}${expectedItem.amount.toInt()}" + ) } } } diff --git a/src/main/kotlin/moe/nea/firmament/features/inventory/ItemRarityCosmetics.kt b/src/main/kotlin/moe/nea/firmament/features/inventory/ItemRarityCosmetics.kt index ac53546..dde0ddb 100644 --- a/src/main/kotlin/moe/nea/firmament/features/inventory/ItemRarityCosmetics.kt +++ b/src/main/kotlin/moe/nea/firmament/features/inventory/ItemRarityCosmetics.kt @@ -12,6 +12,7 @@ import net.minecraft.client.gui.DrawContext import net.minecraft.item.ItemStack import net.minecraft.util.Formatting import net.minecraft.util.Identifier +import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.events.HotbarItemRenderEvent import moe.nea.firmament.events.SlotRenderEvents import moe.nea.firmament.features.FirmamentFeature @@ -65,16 +66,18 @@ object ItemRarityCosmetics : FirmamentFeature { ) } - override fun onLoad() { - HotbarItemRenderEvent.subscribe { - if (!TConfig.showItemRarityInHotbar) return@subscribe - val stack = it.item - drawItemStackRarity(it.context, it.x, it.y, stack) - } - SlotRenderEvents.Before.subscribe { - if (!TConfig.showItemRarityBackground) return@subscribe - val stack = it.slot.stack ?: return@subscribe - drawItemStackRarity(it.context, it.slot.x, it.slot.y, stack) - } + + @Subscribe + fun onRenderSlot(it: SlotRenderEvents.Before) { + if (!TConfig.showItemRarityBackground) return + val stack = it.slot.stack ?: return + drawItemStackRarity(it.context, it.slot.x, it.slot.y, stack) + } + + @Subscribe + fun onRenderHotbarItem(it: HotbarItemRenderEvent) { + if (!TConfig.showItemRarityInHotbar) return + val stack = it.item + drawItemStackRarity(it.context, it.x, it.y, stack) } } diff --git a/src/main/kotlin/moe/nea/firmament/features/inventory/PriceData.kt b/src/main/kotlin/moe/nea/firmament/features/inventory/PriceData.kt index b511611..fb99c7c 100644 --- a/src/main/kotlin/moe/nea/firmament/features/inventory/PriceData.kt +++ b/src/main/kotlin/moe/nea/firmament/features/inventory/PriceData.kt @@ -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 } diff --git a/src/main/kotlin/moe/nea/firmament/features/inventory/SaveCursorPosition.kt b/src/main/kotlin/moe/nea/firmament/features/inventory/SaveCursorPosition.kt index 2748822..e2d48a9 100644 --- a/src/main/kotlin/moe/nea/firmament/features/inventory/SaveCursorPosition.kt +++ b/src/main/kotlin/moe/nea/firmament/features/inventory/SaveCursorPosition.kt @@ -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 diff --git a/src/main/kotlin/moe/nea/firmament/features/inventory/SlotLocking.kt b/src/main/kotlin/moe/nea/firmament/features/inventory/SlotLocking.kt index aee985c..b0fb57b 100644 --- a/src/main/kotlin/moe/nea/firmament/features/inventory/SlotLocking.kt +++ b/src/main/kotlin/moe/nea/firmament/features/inventory/SlotLocking.kt @@ -10,7 +10,7 @@ package moe.nea.firmament.features.inventory import com.mojang.blaze3d.systems.RenderSystem -import java.util.* +import java.util.UUID import org.lwjgl.glfw.GLFW import kotlinx.serialization.Serializable import kotlinx.serialization.UseSerializers @@ -18,6 +18,7 @@ import kotlinx.serialization.serializer import net.minecraft.client.gui.screen.ingame.HandledScreen import net.minecraft.entity.player.PlayerInventory import net.minecraft.screen.GenericContainerScreenHandler +import net.minecraft.screen.slot.Slot import net.minecraft.screen.slot.SlotActionType import net.minecraft.util.Identifier import moe.nea.firmament.annotations.Subscribe @@ -96,81 +97,89 @@ object SlotLocking : FirmamentFeature { return (lore.lastOrNull() ?: return false).unformattedString == "Click to buyback!" } - override fun onLoad() { - HandledScreenKeyPressedEvent.subscribe { - if (!it.matches(TConfig.lockSlot)) return@subscribe - val inventory = MC.handledScreen ?: return@subscribe - inventory as AccessorHandledScreen - - val slot = inventory.focusedSlot_Firmament ?: return@subscribe - val lockedSlots = lockedSlots ?: return@subscribe - if (slot.inventory is PlayerInventory) { - if (slot.index in lockedSlots) { - lockedSlots.remove(slot.index) - } else { - lockedSlots.add(slot.index) - } - DConfig.markDirty() - CommonSoundEffects.playSuccess() - } + @Subscribe + fun onSalvageProtect(event: IsSlotProtectedEvent) { + if (event.slot == null) return + if (!event.slot.hasStack()) return + if (event.slot.stack.displayNameAccordingToNbt?.unformattedString != "Salvage Items") return + val inv = event.slot.inventory + var anyBlocked = false + for (i in 0 until event.slot.index) { + val stack = inv.getStack(i) + if (IsSlotProtectedEvent.shouldBlockInteraction(null, SlotActionType.THROW, stack)) + anyBlocked = true } - HandledScreenKeyPressedEvent.subscribe { - if (!it.matches(TConfig.lockUUID)) return@subscribe - val inventory = MC.handledScreen ?: return@subscribe - inventory as AccessorHandledScreen - - val slot = inventory.focusedSlot_Firmament ?: return@subscribe - val stack = slot.stack ?: return@subscribe - val uuid = stack.skyblockUUID ?: return@subscribe - val lockedUUIDs = lockedUUIDs ?: return@subscribe - if (uuid in lockedUUIDs) { - lockedUUIDs.remove(uuid) - } else { - lockedUUIDs.add(uuid) - } - DConfig.markDirty() - CommonSoundEffects.playSuccess() + if (anyBlocked) { + event.protectSilent() } - IsSlotProtectedEvent.subscribe { - if (it.slot != null && it.slot.inventory is PlayerInventory && it.slot.index in (lockedSlots ?: setOf())) { - it.protect() - } + } + + @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() } - 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() - } + } + + @Subscribe + fun onProtectSlot(it: IsSlotProtectedEvent) { + if (it.slot != null && it.slot.inventory is PlayerInventory && it.slot.index in (lockedSlots ?: setOf())) { + it.protect() } - IsSlotProtectedEvent.subscribe { event -> - if (event.slot == null) return@subscribe - if (!event.slot.hasStack()) return@subscribe - if (event.slot.stack.displayNameAccordingToNbt?.unformattedString != "Salvage Items") return@subscribe - val inv = event.slot.inventory - var anyBlocked = false - for (i in 0 until event.slot.index) { - val stack = inv.getStack(i) - if (IsSlotProtectedEvent.shouldBlockInteraction(null, SlotActionType.THROW, stack)) - anyBlocked = true - } - if (anyBlocked) { - event.protectSilent() + } + + @Subscribe + 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 function(it: SlotRenderEvents.After) { + 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) { diff --git a/src/main/kotlin/moe/nea/firmament/features/inventory/buttons/InventoryButtons.kt b/src/main/kotlin/moe/nea/firmament/features/inventory/buttons/InventoryButtons.kt index 1fe222d..a6dbb5f 100644 --- a/src/main/kotlin/moe/nea/firmament/features/inventory/buttons/InventoryButtons.kt +++ b/src/main/kotlin/moe/nea/firmament/features/inventory/buttons/InventoryButtons.kt @@ -9,6 +9,7 @@ package moe.nea.firmament.features.inventory.buttons import me.shedaniel.math.Rectangle import kotlinx.serialization.Serializable import kotlinx.serialization.serializer +import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.events.HandledScreenClickEvent import moe.nea.firmament.events.HandledScreenForegroundEvent import moe.nea.firmament.events.HandledScreenPushREIEvent @@ -28,6 +29,7 @@ object InventoryButtons : FirmamentFeature { openEditor() } } + object DConfig : DataHolder<Data>(serializer(), identifier, ::Data) @Serializable @@ -40,35 +42,39 @@ object InventoryButtons : FirmamentFeature { get() = TConfig fun getValidButtons() = DConfig.data.buttons.asSequence().filter { it.isValid() } - override fun onLoad() { - HandledScreenForegroundEvent.subscribe { - val bounds = it.screen.getRectangle() - for (button in getValidButtons()) { - val buttonBounds = button.getBounds(bounds) - it.context.matrices.push() - it.context.matrices.translate(buttonBounds.minX.toFloat(), buttonBounds.minY.toFloat(), 0F) - button.render(it.context) - it.context.matrices.pop() - } - lastRectangle = bounds + + @Subscribe + fun onRectangles(it: HandledScreenPushREIEvent) { + val bounds = it.screen.getRectangle() + for (button in getValidButtons()) { + val buttonBounds = button.getBounds(bounds) + it.block(buttonBounds) } - HandledScreenClickEvent.subscribe { - val bounds = it.screen.getRectangle() - for (button in getValidButtons()) { - val buttonBounds = button.getBounds(bounds) - if (buttonBounds.contains(it.mouseX, it.mouseY)) { - MC.sendCommand(button.command!! /* non null invariant covered by getValidButtons */) - break - } + } + + @Subscribe + fun onClickScreen(it: HandledScreenClickEvent) { + val bounds = it.screen.getRectangle() + for (button in getValidButtons()) { + val buttonBounds = button.getBounds(bounds) + if (buttonBounds.contains(it.mouseX, it.mouseY)) { + MC.sendCommand(button.command!! /* non null invariant covered by getValidButtons */) + break } } - HandledScreenPushREIEvent.subscribe { - val bounds = it.screen.getRectangle() - for (button in getValidButtons()) { - val buttonBounds = button.getBounds(bounds) - it.block(buttonBounds) - } + } + + @Subscribe + fun onRenderForeground(it: HandledScreenForegroundEvent) { + val bounds = it.screen.getRectangle() + for (button in getValidButtons()) { + val buttonBounds = button.getBounds(bounds) + it.context.matrices.push() + it.context.matrices.translate(buttonBounds.minX.toFloat(), buttonBounds.minY.toFloat(), 0F) + button.render(it.context) + it.context.matrices.pop() } + lastRectangle = bounds } var lastRectangle: Rectangle? = null diff --git a/src/main/kotlin/moe/nea/firmament/features/inventory/storageoverlay/StorageOverlay.kt b/src/main/kotlin/moe/nea/firmament/features/inventory/storageoverlay/StorageOverlay.kt index b0ebea6..0426e34 100644 --- a/src/main/kotlin/moe/nea/firmament/features/inventory/storageoverlay/StorageOverlay.kt +++ b/src/main/kotlin/moe/nea/firmament/features/inventory/storageoverlay/StorageOverlay.kt @@ -6,9 +6,10 @@ package moe.nea.firmament.features.inventory.storageoverlay -import java.util.* +import java.util.SortedMap import kotlinx.serialization.serializer import net.minecraft.client.gui.screen.Screen +import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.events.ScreenChangeEvent import moe.nea.firmament.events.TickEvent import moe.nea.firmament.features.FirmamentFeature @@ -40,31 +41,33 @@ object StorageOverlay : FirmamentFeature { var shouldReturnToStorageOverlay: Screen? = null var currentHandler: StorageBackingHandle? = StorageBackingHandle.None - override fun onLoad() { - ScreenChangeEvent.subscribe { - if (lastStorageOverlay != null && it.new != null) { - shouldReturnToStorageOverlay = lastStorageOverlay - shouldReturnToStorageOverlayFrom = it.new - lastStorageOverlay = null - } else if (it.old === shouldReturnToStorageOverlayFrom) { - if (shouldReturnToStorageOverlay != null && it.new == null) - setScreenLater(shouldReturnToStorageOverlay) - shouldReturnToStorageOverlay = null - shouldReturnToStorageOverlayFrom = null - } - } + @Subscribe + fun onTick(event: TickEvent) { + rememberContent(currentHandler ?: return) + } - ScreenChangeEvent.subscribe { event -> - currentHandler = StorageBackingHandle.fromScreen(event.new) - if (event.old is StorageOverlayScreen && !event.old.isClosing) { - event.old.setHandler(currentHandler) - if (currentHandler != null) - // TODO: Consider instead only replacing rendering? might make a lot of stack handling easier - event.cancel() - } + @Subscribe + fun onScreenChangeLegacy(event: ScreenChangeEvent) { + currentHandler = StorageBackingHandle.fromScreen(event.new) + if (event.old is StorageOverlayScreen && !event.old.isClosing) { + event.old.setHandler(currentHandler) + if (currentHandler != null) + // TODO: Consider instead only replacing rendering? might make a lot of stack handling easier + event.cancel() } - TickEvent.subscribe { - rememberContent(currentHandler ?: return@subscribe) + } + + @Subscribe + fun onScreenChange(it: ScreenChangeEvent) { + if (lastStorageOverlay != null && it.new != null) { + shouldReturnToStorageOverlay = lastStorageOverlay + shouldReturnToStorageOverlayFrom = it.new + lastStorageOverlay = null + } else if (it.old === shouldReturnToStorageOverlayFrom) { + if (shouldReturnToStorageOverlay != null && it.new == null) + setScreenLater(shouldReturnToStorageOverlay) + shouldReturnToStorageOverlay = null + shouldReturnToStorageOverlayFrom = null } } diff --git a/src/main/kotlin/moe/nea/firmament/features/mining/PickaxeAbility.kt b/src/main/kotlin/moe/nea/firmament/features/mining/PickaxeAbility.kt index 956ffc3..8e62172 100644 --- a/src/main/kotlin/moe/nea/firmament/features/mining/PickaxeAbility.kt +++ b/src/main/kotlin/moe/nea/firmament/features/mining/PickaxeAbility.kt @@ -13,6 +13,7 @@ import net.minecraft.item.ItemStack import net.minecraft.util.DyeColor import net.minecraft.util.Hand import net.minecraft.util.Identifier +import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.events.HudRenderEvent import moe.nea.firmament.events.ProcessChatEvent import moe.nea.firmament.events.SlotClickEvent @@ -73,53 +74,57 @@ object PickaxeAbility : FirmamentFeature { return 1.0 } - override fun onLoad() { - HudRenderEvent.subscribe(this::renderHud) - WorldReadyEvent.subscribe { - lastUsage.clear() - lobbyJoinTime = TimeMark.now() - abilityOverride = null - } - ProcessChatEvent.subscribe { - abilityUsePattern.useMatch(it.unformattedString) { - lastUsage[group("name")] = TimeMark.now() - } - abilitySwitchPattern.useMatch(it.unformattedString) { - abilityOverride = group("ability") - } - } - DurabilityBarEvent.subscribe { - if (!TConfig.drillFuelBar) return@subscribe - val lore = it.item.loreAccordingToNbt - if (lore.lastOrNull()?.unformattedString?.contains("DRILL") != true) return@subscribe - val maxFuel = lore.firstNotNullOfOrNull { - fuelPattern.useMatch(it.unformattedString) { - parseShortNumber(group("maxFuel")) + @Subscribe + fun onSlotClick(it: SlotClickEvent) { + if (MC.screen?.title?.unformattedString == "Heart of the Mountain") { + val name = it.stack.displayNameAccordingToNbt?.unformattedString ?: return + val cooldown = it.stack.loreAccordingToNbt.firstNotNullOfOrNull { + cooldownPattern.useMatch(it.unformattedString) { + parseTimePattern(group("cooldown")) } - } ?: return@subscribe - val extra = it.item.extraAttributes - if (!extra.contains("drill_fuel")) return@subscribe - val fuel = extra.getInt("drill_fuel") - val percentage = fuel / maxFuel.toFloat() - it.barOverride = DurabilityBarEvent.DurabilityBar( - lerp( - DyeColor.RED.toShedaniel(), - DyeColor.GREEN.toShedaniel(), - percentage - ), percentage - ) + } ?: return + defaultAbilityDurations[name] = cooldown } - SlotClickEvent.subscribe { - if (MC.screen?.title?.unformattedString == "Heart of the Mountain") { - val name = it.stack.displayNameAccordingToNbt?.unformattedString ?: return@subscribe - val cooldown = it.stack.loreAccordingToNbt.firstNotNullOfOrNull { - cooldownPattern.useMatch(it.unformattedString) { - parseTimePattern(group("cooldown")) - } - } ?: return@subscribe - defaultAbilityDurations[name] = cooldown + } + + @Subscribe + fun onDurabilityBar(it: DurabilityBarEvent) { + if (!TConfig.drillFuelBar) return + val lore = it.item.loreAccordingToNbt + if (lore.lastOrNull()?.unformattedString?.contains("DRILL") != true) return + val maxFuel = lore.firstNotNullOfOrNull { + fuelPattern.useMatch(it.unformattedString) { + parseShortNumber(group("maxFuel")) } + } ?: return + val extra = it.item.extraAttributes + if (!extra.contains("drill_fuel")) return + val fuel = extra.getInt("drill_fuel") + val percentage = fuel / maxFuel.toFloat() + it.barOverride = DurabilityBarEvent.DurabilityBar( + lerp( + DyeColor.RED.toShedaniel(), + DyeColor.GREEN.toShedaniel(), + percentage + ), percentage + ) + } + + @Subscribe + fun onChatMessage(it: ProcessChatEvent) { + abilityUsePattern.useMatch(it.unformattedString) { + lastUsage[group("name")] = TimeMark.now() } + abilitySwitchPattern.useMatch(it.unformattedString) { + abilityOverride = group("ability") + } + } + + @Subscribe + fun onWorldReady(event: WorldReadyEvent) { + lastUsage.clear() + lobbyJoinTime = TimeMark.now() + abilityOverride = null } val abilityUsePattern = Pattern.compile("You used your (?<name>.*) Pickaxe Ability!") @@ -154,7 +159,8 @@ object PickaxeAbility : FirmamentFeature { Pattern.compile("You selected (?<ability>.*) as your Pickaxe Ability\\. This ability will apply to all of your pickaxes!") - private fun renderHud(event: HudRenderEvent) { + @Subscribe + fun renderHud(event: HudRenderEvent) { if (!TConfig.cooldownEnabled) return var ability = getCooldownFromLore(MC.player?.getStackInHand(Hand.MAIN_HAND) ?: return) ?: return defaultAbilityDurations[ability.name] = ability.cooldown diff --git a/src/main/kotlin/moe/nea/firmament/features/mining/PristineProfitTracker.kt b/src/main/kotlin/moe/nea/firmament/features/mining/PristineProfitTracker.kt index 89ef264..1597501 100644 --- a/src/main/kotlin/moe/nea/firmament/features/mining/PristineProfitTracker.kt +++ b/src/main/kotlin/moe/nea/firmament/features/mining/PristineProfitTracker.kt @@ -12,6 +12,7 @@ import kotlinx.serialization.Serializable import kotlinx.serialization.serializer import kotlin.time.Duration.Companion.seconds import net.minecraft.text.Text +import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.events.ProcessChatEvent import moe.nea.firmament.features.FirmamentFeature import moe.nea.firmament.gui.config.ManagedConfig @@ -62,7 +63,7 @@ object PristineProfitTracker : FirmamentFeature { val pristineRegex = "PRISTINE! You found . Flawed (?<kind>${ - GemstoneKind.values().joinToString("|") { it.label } + GemstoneKind.entries.joinToString("|") { it.label } }) Gemstone x(?<count>[0-9,]+)!".toPattern() val collectionHistogram = Histogram<Double>(10000, 180.seconds) @@ -97,9 +98,13 @@ object PristineProfitTracker : FirmamentFeature { val moneyPerSecond = moneyHistogram.averagePer({ it }, 1.seconds) if (collectionPerSecond == null || moneyPerSecond == null) return ProfitHud.collectionCurrent = collectionPerSecond - ProfitHud.collectionText = Text.stringifiedTranslatable("firmament.pristine-profit.collection", formatCurrency(collectionPerSecond * SECONDS_PER_HOUR, 1)).formattedString() + ProfitHud.collectionText = Text.stringifiedTranslatable("firmament.pristine-profit.collection", + formatCurrency(collectionPerSecond * SECONDS_PER_HOUR, + 1)).formattedString() ProfitHud.moneyCurrent = moneyPerSecond - ProfitHud.moneyText = Text.stringifiedTranslatable("firmament.pristine-profit.money", formatCurrency(moneyPerSecond * SECONDS_PER_HOUR, 1)).formattedString() + ProfitHud.moneyText = Text.stringifiedTranslatable("firmament.pristine-profit.money", + formatCurrency(moneyPerSecond * SECONDS_PER_HOUR, 1)) + .formattedString() val data = DConfig.data if (data != null) { if (data.maxCollectionPerSecond < collectionPerSecond && collectionHistogram.oldestUpdate() @@ -118,17 +123,16 @@ object PristineProfitTracker : FirmamentFeature { } - override fun onLoad() { - ProcessChatEvent.subscribe { - pristineRegex.useMatch(it.unformattedString) { - val gemstoneKind = GemstoneKind.valueOf(group("kind").uppercase()) - val flawedCount = parseIntWithComma(group("count")) - val moneyAmount = sellingStrategy.getSellPrice(gemstoneKind.flawedId) * flawedCount - moneyHistogram.record(moneyAmount) - val collectionAmount = flawedCount * ROUGHS_PER_FLAWED - collectionHistogram.record(collectionAmount.toDouble()) - updateUi() - } + @Subscribe + fun onMessage(it: ProcessChatEvent) { + pristineRegex.useMatch(it.unformattedString) { + val gemstoneKind = GemstoneKind.valueOf(group("kind").uppercase()) + val flawedCount = parseIntWithComma(group("count")) + val moneyAmount = sellingStrategy.getSellPrice(gemstoneKind.flawedId) * flawedCount + moneyHistogram.record(moneyAmount) + val collectionAmount = flawedCount * ROUGHS_PER_FLAWED + collectionHistogram.record(collectionAmount.toDouble()) + updateUi() } } } diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomSkyBlockTextures.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomSkyBlockTextures.kt index 9c2eafc..e66a24a 100644 --- a/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomSkyBlockTextures.kt +++ b/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomSkyBlockTextures.kt @@ -16,6 +16,7 @@ import net.minecraft.client.render.RenderLayer import net.minecraft.client.util.ModelIdentifier import net.minecraft.component.type.ProfileComponent import net.minecraft.util.Identifier +import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.events.CustomItemModelEvent import moe.nea.firmament.events.TickEvent import moe.nea.firmament.features.FirmamentFeature @@ -38,20 +39,21 @@ object CustomSkyBlockTextures : FirmamentFeature { override val config: ManagedConfig get() = TConfig - override fun onLoad() { - CustomItemModelEvent.subscribe { - if (!TConfig.enabled) return@subscribe - val id = it.itemStack.skyBlockId ?: return@subscribe - it.overrideModel = ModelIdentifier("firmskyblock", id.identifier.path, "inventory") - } - TickEvent.subscribe { - if (TConfig.cacheDuration < 1 || it.tickCount % TConfig.cacheDuration == 0) { - CustomItemModelEvent.clearCache() - skullTextureCache.clear() - } + @Subscribe + fun onTick(it: TickEvent) { + if (TConfig.cacheDuration < 1 || it.tickCount % TConfig.cacheDuration == 0) { + CustomItemModelEvent.clearCache() + skullTextureCache.clear() } } + @Subscribe + fun onCustomModelId(it: CustomItemModelEvent) { + if (!TConfig.enabled) return + val id = it.itemStack.skyBlockId ?: return + it.overrideModel = ModelIdentifier("firmskyblock", id.identifier.path, "inventory") + } + private val skullTextureCache = mutableMapOf<IdentityCharacteristics<ProfileComponent>, Any>() private val sentinelPresentInvalid = Object() diff --git a/src/main/kotlin/moe/nea/firmament/features/world/FairySouls.kt b/src/main/kotlin/moe/nea/firmament/features/world/FairySouls.kt index 462325e..2cce041 100644 --- a/src/main/kotlin/moe/nea/firmament/features/world/FairySouls.kt +++ b/src/main/kotlin/moe/nea/firmament/features/world/FairySouls.kt @@ -9,15 +9,10 @@ package moe.nea.firmament.features.world import io.github.moulberry.repo.data.Coordinate import kotlinx.serialization.Serializable import kotlinx.serialization.serializer -import net.minecraft.client.render.RenderLayer -import net.minecraft.client.render.RenderLayer.ALWAYS_DEPTH_TEST -import net.minecraft.client.render.RenderLayer.MultiPhaseParameters -import net.minecraft.client.render.RenderPhase -import net.minecraft.client.render.VertexFormat -import net.minecraft.client.render.VertexFormats import net.minecraft.text.Text import net.minecraft.util.math.Vec3d -import moe.nea.firmament.events.AllowChatEvent +import moe.nea.firmament.annotations.Subscribe +import moe.nea.firmament.events.ProcessChatEvent import moe.nea.firmament.events.SkyblockServerUpdateEvent import moe.nea.firmament.events.WorldRenderLastEvent import moe.nea.firmament.features.FirmamentFeature @@ -102,53 +97,43 @@ object FairySouls : FirmamentFeature { updateMissingSouls() } - val NODEPTH: RenderLayer = RenderLayer.of( - "firmamentnodepth", - VertexFormats.POSITION_COLOR_TEXTURE, - VertexFormat.DrawMode.QUADS, - 256, - true, - true, - MultiPhaseParameters.builder() - .program(RenderPhase.COLOR_PROGRAM) - .writeMaskState(RenderPhase.COLOR_MASK) - .depthTest(ALWAYS_DEPTH_TEST) - .cull(RenderPhase.DISABLE_CULLING) - .layering(RenderLayer.VIEW_OFFSET_Z_LAYERING) - .target(RenderPhase.MAIN_TARGET) - .build(true) - ) - - override fun onLoad() { - SkyblockServerUpdateEvent.subscribe { - currentLocationName = it.newLocraw?.skyblockLocation - updateWorldSouls() - updateMissingSouls() - } - AllowChatEvent.subscribe { - when (it.text.unformattedString) { - "You have already found that Fairy Soul!" -> { - markNearestSoul() - } - - "SOUL! You found a Fairy Soul!" -> { - markNearestSoul() - } + @Subscribe + fun onWorldRender(it: WorldRenderLastEvent) { + if (!TConfig.displaySouls) return + renderInWorld(it) { + text(Vec3d(0.0, 0.0, 0.0), + Text.literal("Test String"), + Text.literal("Short"), + Text.literal("just lik"), + verticalAlign = RenderInWorldContext.VerticalAlign.BOTTOM) + color(1F, 1F, 0F, 0.8F) + currentMissingSouls.forEach { + block(it.blockPos) + } + color(1f, 0f, 1f, 1f) + currentLocationSouls.forEach { + wireframeCube(it.blockPos) } } - WorldRenderLastEvent.subscribe { - if (!TConfig.displaySouls) return@subscribe - renderInWorld(it) { - text(Vec3d(0.0, 0.0, 0.0), Text.literal("Test String") , Text.literal("Short"), Text.literal("just lik"), verticalAlign = RenderInWorldContext.VerticalAlign.BOTTOM) - color(1F, 1F, 0F, 0.8F) - currentMissingSouls.forEach { - block(it.blockPos) - } - color(1f, 0f, 1f, 1f) - currentLocationSouls.forEach { - wireframeCube(it.blockPos) - } + } + + @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() + } } diff --git a/src/main/kotlin/moe/nea/firmament/features/world/Waypoints.kt b/src/main/kotlin/moe/nea/firmament/features/world/Waypoints.kt index bad82b0..dcb3014 100644 --- a/src/main/kotlin/moe/nea/firmament/features/world/Waypoints.kt +++ b/src/main/kotlin/moe/nea/firmament/features/world/Waypoints.kt @@ -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,195 +74,204 @@ object Waypoints : FirmamentFeature { val b: Int = 0, ) - override fun onLoad() { - WorldRenderLastEvent.subscribe { event -> - temporaryPlayerWaypointList.entries.removeIf { it.value.postedAt.passedTime() > TConfig.tempWaypointDuration } - if (temporaryPlayerWaypointList.isNotEmpty()) - RenderInWorldContext.renderInWorld(event) { - color(1f, 1f, 0f, 1f) - temporaryPlayerWaypointList.forEach { (player, waypoint) -> - block(waypoint.pos) - } + @Subscribe + fun onRenderOrderedWaypoints(event: WorldRenderLastEvent) { + if (waypoints.isEmpty()) return + RenderInWorldContext.renderInWorld(event) { + if (!ordered) { + waypoints.withIndex().forEach { + color(0f, 0.3f, 0.7f, 0.5f) + block(it.value) color(1f, 1f, 1f, 1f) - temporaryPlayerWaypointList.forEach { (player, waypoint) -> - val skin = - MC.networkHandler?.listedPlayerListEntries?.find { it.profile.name == player } - ?.skinTextures - ?.texture - withFacingThePlayer(waypoint.pos.toCenterPos()) { - waypoint(waypoint.pos, Text.stringifiedTranslatable("firmament.waypoint.temporary", player)) - if (skin != null) { - matrixStack.translate(0F, -20F, 0F) - // Head front - texture( - skin, 16, 16, - 1 / 8f, 1 / 8f, - 2 / 8f, 2 / 8f, - ) - // Head overlay - texture( - skin, 16, 16, - 5 / 8f, 1 / 8f, - 6 / 8f, 2 / 8f, - ) - } + if (TConfig.showIndex) + withFacingThePlayer(it.value.toCenterPos()) { + text(Text.literal(it.index.toString())) } - } } + } 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), + ) + ) + .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())) + } + } + } } - WorldReadyEvent.subscribe { - temporaryPlayerWaypointList.clear() + } + + @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 + } } - CommandEvent.SubCommand.subscribe { event -> - event.subcommand("waypoint") { - thenArgument("pos", BlockPosArgumentType.blockPos()) { pos -> - thenExecute { - val position = pos.get(this).toAbsoluteBlockPos(source.asFakeServer()) - waypoints.add(position) - source.sendFeedback( - Text.stringifiedTranslatable( - "firmament.command.waypoint.added", - position.x, - position.y, - position.z - ) + } + + @Subscribe + fun onProcessChat(it: ProcessChatEvent) { + val matcher = temporaryPlayerWaypointMatcher.matcher(it.unformattedString) + if (it.nameHeuristic != null && TConfig.tempWaypointDuration > 0.seconds && matcher.find()) { + temporaryPlayerWaypointList[it.nameHeuristic] = TemporaryWaypoint( + BlockPos( + matcher.group(1).toInt(), + matcher.group(2).toInt(), + matcher.group(3).toInt(), + ), + TimeMark.now() + ) + } + } + + @Subscribe + fun onCommand(event: CommandEvent.SubCommand) { + event.subcommand("waypoint") { + thenArgument("pos", BlockPosArgumentType.blockPos()) { pos -> + thenExecute { + val position = pos.get(this).toAbsoluteBlockPos(source.asFakeServer()) + waypoints.add(position) + source.sendFeedback( + Text.stringifiedTranslatable( + "firmament.command.waypoint.added", + position.x, + position.y, + position.z ) - } + ) } } - event.subcommand("waypoints") { - thenLiteral("clear") { - thenExecute { - waypoints.clear() - source.sendFeedback(Text.translatable("firmament.command.waypoint.clear")) - } - } - thenLiteral("toggleordered") { - thenExecute { - ordered = !ordered - if (ordered) { - val p = MC.player?.pos ?: Vec3d.ZERO - orderedIndex = - waypoints.withIndex().minByOrNull { it.value.getSquaredDistance(p) }?.index ?: 0 - } - source.sendFeedback(Text.translatable("firmament.command.waypoint.ordered.toggle.$ordered")) - } + } + event.subcommand("waypoints") { + thenLiteral("clear") { + thenExecute { + waypoints.clear() + source.sendFeedback(Text.translatable("firmament.command.waypoint.clear")) } - thenLiteral("skip") { - thenExecute { - if (ordered && waypoints.isNotEmpty()) { - orderedIndex = (orderedIndex + 1) % waypoints.size - source.sendFeedback(Text.translatable("firmament.command.waypoint.skip")) - } else { - source.sendError(Text.translatable("firmament.command.waypoint.skip.error")) - } + } + thenLiteral("toggleordered") { + thenExecute { + ordered = !ordered + if (ordered) { + val p = MC.player?.pos ?: Vec3d.ZERO + orderedIndex = + waypoints.withIndex().minByOrNull { it.value.getSquaredDistance(p) }?.index ?: 0 } + source.sendFeedback(Text.translatable("firmament.command.waypoint.ordered.toggle.$ordered")) } - thenLiteral("remove") { - thenArgument("index", IntegerArgumentType.integer(0)) { indexArg -> - thenExecute { - val index = get(indexArg) - if (index in waypoints.indices) { - waypoints.removeAt(index) - source.sendFeedback(Text.stringifiedTranslatable( - "firmament.command.waypoint.remove", - index)) - } else { - source.sendError(Text.stringifiedTranslatable("firmament.command.waypoint.remove.error")) - } - } + } + thenLiteral("skip") { + thenExecute { + if (ordered && waypoints.isNotEmpty()) { + orderedIndex = (orderedIndex + 1) % waypoints.size + source.sendFeedback(Text.translatable("firmament.command.waypoint.skip")) + } else { + source.sendError(Text.translatable("firmament.command.waypoint.skip.error")) } } - thenLiteral("import") { + } + thenLiteral("remove") { + thenArgument("index", IntegerArgumentType.integer(0)) { indexArg -> thenExecute { - val contents = ClipboardUtils.getTextContents() - val data = try { - Firmament.json.decodeFromString<List<ColeWeightWaypoint>>(contents) - } catch (ex: Exception) { - Firmament.logger.error("Could not load waypoints from clipboard", ex) - source.sendError(Text.translatable("firmament.command.waypoint.import.error")) - return@thenExecute + val index = get(indexArg) + if (index in waypoints.indices) { + waypoints.removeAt(index) + source.sendFeedback(Text.stringifiedTranslatable( + "firmament.command.waypoint.remove", + index)) + } else { + source.sendError(Text.stringifiedTranslatable("firmament.command.waypoint.remove.error")) } - waypoints.clear() - data.mapTo(waypoints) { BlockPos(it.x, it.y, it.z) } - source.sendFeedback( - Text.stringifiedTranslatable( - "firmament.command.waypoint.import", - data.size - ) - ) } } } - } - WorldRenderLastEvent.subscribe { event -> - if (waypoints.isEmpty()) return@subscribe - RenderInWorldContext.renderInWorld(event) { - if (!ordered) { - waypoints.withIndex().forEach { - color(0f, 0.3f, 0.7f, 0.5f) - block(it.value) - color(1f, 1f, 1f, 1f) - if (TConfig.showIndex) - withFacingThePlayer(it.value.toCenterPos()) { - text(Text.literal(it.index.toString())) - } + thenLiteral("import") { + thenExecute { + val contents = ClipboardUtils.getTextContents() + val data = try { + Firmament.json.decodeFromString<List<ColeWeightWaypoint>>(contents) + } catch (ex: Exception) { + Firmament.logger.error("Could not load waypoints from clipboard", ex) + source.sendError(Text.translatable("firmament.command.waypoint.import.error")) + return@thenExecute } - } 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), - ) + waypoints.clear() + data.mapTo(waypoints) { BlockPos(it.x, it.y, it.z) } + source.sendFeedback( + Text.stringifiedTranslatable( + "firmament.command.waypoint.import", + data.size ) - .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 - } + } + + @Subscribe + fun onRenderTemporaryWaypoints(event: WorldRenderLastEvent) { + temporaryPlayerWaypointList.entries.removeIf { it.value.postedAt.passedTime() > TConfig.tempWaypointDuration } + if (temporaryPlayerWaypointList.isEmpty()) return + RenderInWorldContext.renderInWorld(event) { + color(1f, 1f, 0f, 1f) + temporaryPlayerWaypointList.forEach { (player, waypoint) -> + block(waypoint.pos) } - } - 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() - ) + color(1f, 1f, 1f, 1f) + temporaryPlayerWaypointList.forEach { (player, waypoint) -> + val skin = + MC.networkHandler?.listedPlayerListEntries?.find { it.profile.name == player } + ?.skinTextures + ?.texture + withFacingThePlayer(waypoint.pos.toCenterPos()) { + waypoint(waypoint.pos, Text.stringifiedTranslatable("firmament.waypoint.temporary", player)) + if (skin != null) { + matrixStack.translate(0F, -20F, 0F) + // Head front + texture( + skin, 16, 16, + 1 / 8f, 1 / 8f, + 2 / 8f, 2 / 8f, + ) + // Head overlay + texture( + skin, 16, 16, + 5 / 8f, 1 / 8f, + 6 / 8f, 2 / 8f, + ) + } + } } } } + + @Subscribe + fun onWorldReady(event: WorldReadyEvent) { + temporaryPlayerWaypointList.clear() + } } fun <E> List<E>.wrappingWindow(startIndex: Int, windowSize: Int): List<E> { |