diff options
author | Linnea Gräf <nea@nea.moe> | 2024-08-07 21:34:16 +0200 |
---|---|---|
committer | Linnea Gräf <nea@nea.moe> | 2024-08-07 21:34:16 +0200 |
commit | b4f9ca21ef801bb3e39c53ae21bb6bf4398c94e9 (patch) | |
tree | 1f7928e5587b6d4d7ca071949f0a70bf81282c14 /src | |
parent | 9b277bd897490d13ee4549a086e8d1b5f4cd0e10 (diff) | |
download | Firmament-b4f9ca21ef801bb3e39c53ae21bb6bf4398c94e9.tar.gz Firmament-b4f9ca21ef801bb3e39c53ae21bb6bf4398c94e9.tar.bz2 Firmament-b4f9ca21ef801bb3e39c53ae21bb6bf4398c94e9.zip |
Add /firm npcs command
Diffstat (limited to 'src')
20 files changed, 537 insertions, 31 deletions
diff --git a/src/main/kotlin/moe/nea/firmament/Firmament.kt b/src/main/kotlin/moe/nea/firmament/Firmament.kt index e2b904f..a0693f0 100644 --- a/src/main/kotlin/moe/nea/firmament/Firmament.kt +++ b/src/main/kotlin/moe/nea/firmament/Firmament.kt @@ -112,6 +112,7 @@ object Firmament { @JvmStatic fun onClientInitialize() { + FeatureManager.subscribeEvents() var tick = 0 ClientTickEvents.END_CLIENT_TICK.register(ClientTickEvents.EndTick { instance -> TickEvent.publish(TickEvent(tick++)) diff --git a/src/main/kotlin/moe/nea/firmament/events/ReloadRegistrationEvent.kt b/src/main/kotlin/moe/nea/firmament/events/ReloadRegistrationEvent.kt new file mode 100644 index 0000000..4c3083e --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/events/ReloadRegistrationEvent.kt @@ -0,0 +1,7 @@ +package moe.nea.firmament.events + +import io.github.moulberry.repo.NEURepository + +data class ReloadRegistrationEvent(val repo: NEURepository) : FirmamentEvent() { + companion object : FirmamentEventBus<ReloadRegistrationEvent>() +} diff --git a/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt b/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt index d127381..c69d7b2 100644 --- a/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt +++ b/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt @@ -87,13 +87,12 @@ object FeatureManager : DataHolder<FeatureManager.Config>(serializer(), "feature loadFeature(DebugView) } allFeatures.forEach { it.config } - subscribeEvents() FeaturesInitializedEvent.publish(FeaturesInitializedEvent(allFeatures.toList())) hasAutoloaded = true } } - private fun subscribeEvents() { + fun subscribeEvents() { AllSubscriptions.provideSubscriptions { subscribeSingleEvent(it) } diff --git a/src/main/kotlin/moe/nea/firmament/features/world/NPCWaypoints.kt b/src/main/kotlin/moe/nea/firmament/features/world/NPCWaypoints.kt new file mode 100644 index 0000000..592b8fa --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/features/world/NPCWaypoints.kt @@ -0,0 +1,40 @@ +package moe.nea.firmament.features.world + +import moe.nea.firmament.annotations.Subscribe +import moe.nea.firmament.commands.thenExecute +import moe.nea.firmament.events.CommandEvent +import moe.nea.firmament.events.ReloadRegistrationEvent +import moe.nea.firmament.util.MoulConfigUtils +import moe.nea.firmament.util.ScreenUtil + +object NPCWaypoints { + + var allNpcWaypoints = listOf<NavigableWaypoint>() + + @Subscribe + fun onRepoReloadRegistration(event: ReloadRegistrationEvent) { + event.repo.registerReloadListener { + allNpcWaypoints = it.items.items.values + .asSequence() + .filter { !it.island.isNullOrBlank() } + .map { + NavigableWaypoint.NPCWaypoint(it) + } + .toList() + } + } + + @Subscribe + fun onOpenGui(event: CommandEvent.SubCommand) { + event.subcommand("npcs") { + thenExecute { + ScreenUtil.setScreenLater(MoulConfigUtils.loadScreen( + "npc_waypoints", + NpcWaypointGui(allNpcWaypoints), + null)) + } + } + } + + +} diff --git a/src/main/kotlin/moe/nea/firmament/features/world/NavigableWaypoint.kt b/src/main/kotlin/moe/nea/firmament/features/world/NavigableWaypoint.kt new file mode 100644 index 0000000..28a517f --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/features/world/NavigableWaypoint.kt @@ -0,0 +1,22 @@ +package moe.nea.firmament.features.world + +import io.github.moulberry.repo.data.NEUItem +import net.minecraft.util.math.BlockPos +import moe.nea.firmament.util.SkyBlockIsland + +abstract class NavigableWaypoint { + abstract val name: String + abstract val position: BlockPos + abstract val island: SkyBlockIsland + + data class NPCWaypoint( + val item: NEUItem, + ) : NavigableWaypoint() { + override val name: String + get() = item.displayName + override val position: BlockPos + get() = BlockPos(item.x, item.y, item.z) + override val island: SkyBlockIsland + get() = SkyBlockIsland.forMode(item.island) + } +} diff --git a/src/main/kotlin/moe/nea/firmament/features/world/NavigationHelper.kt b/src/main/kotlin/moe/nea/firmament/features/world/NavigationHelper.kt new file mode 100644 index 0000000..acdfb86 --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/features/world/NavigationHelper.kt @@ -0,0 +1,121 @@ +package moe.nea.firmament.features.world + +import io.github.moulberry.repo.constants.Islands +import net.minecraft.text.Text +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.Position +import net.minecraft.util.math.Vec3i +import moe.nea.firmament.annotations.Subscribe +import moe.nea.firmament.events.SkyblockServerUpdateEvent +import moe.nea.firmament.events.TickEvent +import moe.nea.firmament.events.WorldRenderLastEvent +import moe.nea.firmament.repo.RepoManager +import moe.nea.firmament.util.MC +import moe.nea.firmament.util.SBData +import moe.nea.firmament.util.SkyBlockIsland +import moe.nea.firmament.util.WarpUtil +import moe.nea.firmament.util.render.RenderInWorldContext + +object NavigationHelper { + var targetWaypoint: NavigableWaypoint? = null + set(value) { + field = value + recalculateRoute() + } + + var nextTeleporter: Islands.Teleporter? = null + private set + + val Islands.Teleporter.toIsland get() = SkyBlockIsland.forMode(this.getTo()) + val Islands.Teleporter.fromIsland get() = SkyBlockIsland.forMode(this.getFrom()) + val Islands.Teleporter.blockPos get() = BlockPos(x.toInt(), y.toInt(), z.toInt()) + + @Subscribe + fun onWorldSwitch(event: SkyblockServerUpdateEvent) { + recalculateRoute() + } + + fun recalculateRoute() { + val tp = targetWaypoint + val currentIsland = SBData.skyblockLocation + if (tp == null || currentIsland == null) { + nextTeleporter = null + return + } + val route = findRoute(currentIsland, tp.island, mutableSetOf()) + nextTeleporter = route?.get(0) + } + + private fun findRoute( + fromIsland: SkyBlockIsland, + targetIsland: SkyBlockIsland, + visitedIslands: MutableSet<SkyBlockIsland> + ): MutableList<Islands.Teleporter>? { + var shortestChain: MutableList<Islands.Teleporter>? = null + for (it in RepoManager.neuRepo.constants.islands.teleporters) { + if (it.toIsland in visitedIslands) continue + if (it.fromIsland != fromIsland) continue + if (it.toIsland == targetIsland) return mutableListOf(it) + visitedIslands.add(fromIsland) + val nextRoute = findRoute(it.toIsland, targetIsland, visitedIslands) ?: continue + nextRoute.add(0, it) + if (shortestChain == null || shortestChain.size > nextRoute.size) { + shortestChain = nextRoute + } + visitedIslands.remove(fromIsland) + } + return shortestChain + } + + + @Subscribe + fun onMovement(event: TickEvent) { // TODO: add a movement tick event maybe? + val tp = targetWaypoint ?: return + val p = MC.player ?: return + if (p.squaredDistanceTo(tp.position.toCenterPos()) < 5 * 5) { + targetWaypoint = null + } + } + + @Subscribe + fun drawWaypoint(event: WorldRenderLastEvent) { + val tp = targetWaypoint ?: return + val nt = nextTeleporter + RenderInWorldContext.renderInWorld(event) { + if (nt != null) { + waypoint(nt.blockPos, + Text.literal("Teleporter to " + nt.toIsland.userFriendlyName), + Text.literal("(towards " + tp.name + "§f)")) + } else if (tp.island == SBData.skyblockLocation) { + waypoint(tp.position, + Text.literal(tp.name)) + } + } + } + + fun tryWarpNear() { + val tp = targetWaypoint + if (tp == null) { + MC.sendChat(Text.literal("Could not find a waypoint to warp you to. Select one first.")) + return + } + WarpUtil.teleportToNearestWarp(tp.island, tp.position.asPositionView()) + } + +} + +fun Vec3i.asPositionView(): Position { + return object : Position { + override fun getX(): Double { + return this@asPositionView.x.toDouble() + } + + override fun getY(): Double { + return this@asPositionView.y.toDouble() + } + + override fun getZ(): Double { + return this@asPositionView.z.toDouble() + } + } +} diff --git a/src/main/kotlin/moe/nea/firmament/features/world/NpcWaypointGui.kt b/src/main/kotlin/moe/nea/firmament/features/world/NpcWaypointGui.kt new file mode 100644 index 0000000..6146e50 --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/features/world/NpcWaypointGui.kt @@ -0,0 +1,68 @@ +package moe.nea.firmament.features.world + +import io.github.notenoughupdates.moulconfig.observer.ObservableList +import io.github.notenoughupdates.moulconfig.xml.Bind +import moe.nea.firmament.features.events.anniversity.AnniversaryFeatures.atOnce +import moe.nea.firmament.keybindings.SavedKeyBinding + +class NpcWaypointGui( + val allWaypoints: List<NavigableWaypoint>, +) { + + data class NavigableWaypointW(val waypoint: NavigableWaypoint) { + @Bind + fun name() = waypoint.name + + @Bind + fun isSelected() = NavigationHelper.targetWaypoint == waypoint + + @Bind + fun click() { + if (SavedKeyBinding.isShiftDown()) { + NavigationHelper.targetWaypoint = waypoint + NavigationHelper.tryWarpNear() + } else if (isSelected()) { + NavigationHelper.targetWaypoint = null + } else { + NavigationHelper.targetWaypoint = waypoint + } + } + } + + @JvmField + @field:Bind + var search: String = "" + var lastSearch: String? = null + + @Bind("results") + fun results(): ObservableList<NavigableWaypointW> { + return results + } + + @Bind + fun tick() { + if (search != lastSearch) { + updateSearch() + lastSearch = search + } + } + + val results: ObservableList<NavigableWaypointW> = ObservableList(mutableListOf()) + + fun updateSearch() { + val split = search.split(" +".toRegex()) + results.atOnce { + results.clear() + allWaypoints.filter { waypoint -> + if (search.isBlank()) { + true + } else { + split.all { waypoint.name.contains(it, ignoreCase = true) } + } + }.mapTo(results) { + NavigableWaypointW(it) + } + } + } + +} diff --git a/src/main/kotlin/moe/nea/firmament/gui/FirmButtonComponent.kt b/src/main/kotlin/moe/nea/firmament/gui/FirmButtonComponent.kt index d1e223e..09025af 100644 --- a/src/main/kotlin/moe/nea/firmament/gui/FirmButtonComponent.kt +++ b/src/main/kotlin/moe/nea/firmament/gui/FirmButtonComponent.kt @@ -18,8 +18,9 @@ import io.github.notenoughupdates.moulconfig.observer.GetSetter open class FirmButtonComponent( child: GuiComponent, val isEnabled: GetSetter<Boolean> = GetSetter.constant(true), + val noBackground: Boolean = false, val action: Runnable, -) : PanelComponent(child) { +) : PanelComponent(child, if (noBackground) 0 else 2, DefaultBackgroundRenderer.TRANSPARENT) { /* TODO: make use of vanillas built in nine slicer */ val hoveredBg = @@ -44,7 +45,6 @@ open class FirmButtonComponent( .cornerUv(5 / 200F, 5 / 20F) .mode(NinePatch.Mode.STRETCHING) .build() - var isClicking = false override fun mouseEvent(mouseEvent: MouseEvent, context: GuiImmediateContext): Boolean { if (!isEnabled.get()) return false @@ -54,12 +54,14 @@ open class FirmButtonComponent( if (context.isHovered) { action.run() } + blur() return true } } if (!context.isHovered) return false if (mouseEvent !is MouseEvent.Click) return false if (mouseEvent.mouseState && mouseEvent.mouseButton == 0) { + requestFocus() isClicking = true return true } @@ -73,10 +75,11 @@ open class FirmButtonComponent( override fun render(context: GuiImmediateContext) { context.renderContext.pushMatrix() - context.renderContext.drawNinePatch( - getBackground(context), - 0f, 0f, context.width, context.height - ) + if (!noBackground) + context.renderContext.drawNinePatch( + getBackground(context), + 0f, 0f, context.width, context.height + ) context.renderContext.translate(insets.toFloat(), insets.toFloat(), 0f) element.render(getChildContext(context)) context.renderContext.popMatrix() diff --git a/src/main/kotlin/moe/nea/firmament/gui/FirmHoverComponent.kt b/src/main/kotlin/moe/nea/firmament/gui/FirmHoverComponent.kt new file mode 100644 index 0000000..b1792ce --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/gui/FirmHoverComponent.kt @@ -0,0 +1,59 @@ +package moe.nea.firmament.gui + +import io.github.notenoughupdates.moulconfig.gui.GuiComponent +import io.github.notenoughupdates.moulconfig.gui.GuiImmediateContext +import io.github.notenoughupdates.moulconfig.gui.KeyboardEvent +import io.github.notenoughupdates.moulconfig.gui.MouseEvent +import java.util.function.BiFunction +import java.util.function.Supplier +import kotlin.time.Duration +import moe.nea.firmament.util.TimeMark + +class FirmHoverComponent( + val child: GuiComponent, + val hoverLines: Supplier<List<String>>, + val hoverDelay: Duration, +) : GuiComponent() { + override fun getWidth(): Int { + return child.width + } + + override fun getHeight(): Int { + return child.height + } + + override fun <T : Any?> foldChildren( + initial: T, + visitor: BiFunction<GuiComponent, T, T> + ): T { + return visitor.apply(child, initial) + } + + override fun render(context: GuiImmediateContext) { + if (context.isHovered && (permaHover || lastMouseMove.passedTime() > hoverDelay)) { + context.renderContext.scheduleDrawTooltip(hoverLines.get()) + permaHover = true + } else { + permaHover = false + } + if (!context.isHovered) { + lastMouseMove = TimeMark.now() + } + child.render(context) + + } + + var permaHover = false + var lastMouseMove = TimeMark.farPast() + + override fun mouseEvent(mouseEvent: MouseEvent, context: GuiImmediateContext): Boolean { + if (mouseEvent is MouseEvent.Move) { + lastMouseMove = TimeMark.now() + } + return child.mouseEvent(mouseEvent, context) + } + + override fun keyboardEvent(event: KeyboardEvent, context: GuiImmediateContext): Boolean { + return child.keyboardEvent(event, context) + } +} diff --git a/src/main/kotlin/moe/nea/firmament/gui/ImageComponent.kt b/src/main/kotlin/moe/nea/firmament/gui/ImageComponent.kt new file mode 100644 index 0000000..bba7dee --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/gui/ImageComponent.kt @@ -0,0 +1,33 @@ +package moe.nea.firmament.gui + +import io.github.notenoughupdates.moulconfig.common.MyResourceLocation +import io.github.notenoughupdates.moulconfig.gui.GuiComponent +import io.github.notenoughupdates.moulconfig.gui.GuiImmediateContext +import java.util.function.Supplier + +class ImageComponent( + private val width: Int, + private val height: Int, + val resourceLocation: Supplier<MyResourceLocation>, + val u1: Float, + val u2: Float, + val v1: Float, + val v2: Float, +) : GuiComponent() { + override fun getWidth(): Int { + return width + } + + override fun getHeight(): Int { + return height + } + + override fun render(context: GuiImmediateContext) { + context.renderContext.bindTexture(resourceLocation.get()) + context.renderContext.drawTexturedRect( + 0f, 0f, + context.width.toFloat(), context.height.toFloat(), + u1, v1, u2, v2 + ) + } +} diff --git a/src/main/kotlin/moe/nea/firmament/gui/TickComponent.kt b/src/main/kotlin/moe/nea/firmament/gui/TickComponent.kt new file mode 100644 index 0000000..d1879b1 --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/gui/TickComponent.kt @@ -0,0 +1,18 @@ +package moe.nea.firmament.gui + +import io.github.notenoughupdates.moulconfig.gui.GuiComponent +import io.github.notenoughupdates.moulconfig.gui.GuiImmediateContext + +class TickComponent(val onTick: Runnable) : GuiComponent() { + override fun getWidth(): Int { + return 0 + } + + override fun getHeight(): Int { + return 0 + } + + override fun render(context: GuiImmediateContext) { + onTick.run() + } +} diff --git a/src/main/kotlin/moe/nea/firmament/keybindings/SavedKeyBinding.kt b/src/main/kotlin/moe/nea/firmament/keybindings/SavedKeyBinding.kt index f07cd29..4056e66 100644 --- a/src/main/kotlin/moe/nea/firmament/keybindings/SavedKeyBinding.kt +++ b/src/main/kotlin/moe/nea/firmament/keybindings/SavedKeyBinding.kt @@ -47,8 +47,7 @@ data class SavedKeyBinding( || InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_RIGHT_SUPER) } else InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_LEFT_CONTROL) || InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_RIGHT_CONTROL) - val shift = InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_LEFT_SHIFT) - || InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_RIGHT_SHIFT) + val shift = isShiftDown() val alt = InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_LEFT_ALT) || InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_RIGHT_ALT) var mods = 0 @@ -57,6 +56,11 @@ data class SavedKeyBinding( if (alt) mods = mods or GLFW.GLFW_MOD_ALT return mods } + + private val h get() = MC.window.handle + fun isShiftDown() = InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_LEFT_SHIFT) + || InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_RIGHT_SHIFT) + } fun isPressed(atLeast: Boolean = false): Boolean { @@ -69,8 +73,7 @@ data class SavedKeyBinding( || InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_RIGHT_SUPER) } else InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_LEFT_CONTROL) || InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_RIGHT_CONTROL) - val shift = InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_LEFT_SHIFT) - || InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_RIGHT_SHIFT) + val shift = isShiftDown() val alt = InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_LEFT_ALT) || InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_RIGHT_ALT) if (atLeast) diff --git a/src/main/kotlin/moe/nea/firmament/repo/RepoManager.kt b/src/main/kotlin/moe/nea/firmament/repo/RepoManager.kt index 179b720..e7a1e9e 100644 --- a/src/main/kotlin/moe/nea/firmament/repo/RepoManager.kt +++ b/src/main/kotlin/moe/nea/firmament/repo/RepoManager.kt @@ -7,7 +7,6 @@ package moe.nea.firmament.repo -import io.github.moulberry.repo.NEURecipeCache import io.github.moulberry.repo.NEURepository import io.github.moulberry.repo.NEURepositoryException import io.github.moulberry.repo.data.NEUItem @@ -20,6 +19,7 @@ import net.minecraft.network.packet.s2c.play.SynchronizeRecipesS2CPacket import net.minecraft.text.Text import moe.nea.firmament.Firmament import moe.nea.firmament.Firmament.logger +import moe.nea.firmament.events.ReloadRegistrationEvent import moe.nea.firmament.gui.config.ManagedConfig import moe.nea.firmament.rei.PetData import moe.nea.firmament.util.MinecraftDispatcher @@ -57,6 +57,7 @@ object RepoManager { registerReloadListener(ItemCache) registerReloadListener(ExpLadders) registerReloadListener(ItemNameLookup) + ReloadRegistrationEvent.publish(ReloadRegistrationEvent(this)) registerReloadListener { Firmament.coroutineScope.launch(MinecraftDispatcher) { if (!trySendClientboundUpdateRecipesPacket()) { @@ -69,9 +70,10 @@ object RepoManager { val essenceRecipeProvider = EssenceRecipeProvider() val recipeCache = BetterRepoRecipeCache(essenceRecipeProvider) + init { - neuRepo.registerReloadListener(essenceRecipeProvider) - neuRepo.registerReloadListener(recipeCache) + neuRepo.registerReloadListener(essenceRecipeProvider) + neuRepo.registerReloadListener(recipeCache) } fun getAllRecipes() = neuRepo.items.items.values.asSequence().flatMap { it.recipes } @@ -110,7 +112,9 @@ object RepoManager { fun reload() { try { - ItemCache.ReloadProgressHud.reportProgress("Reloading from Disk", 0, -1) // TODO: replace with a proper boundy bar + ItemCache.ReloadProgressHud.reportProgress("Reloading from Disk", + 0, + -1) // TODO: replace with a proper boundy bar ItemCache.ReloadProgressHud.isEnabled = true neuRepo.reload() } catch (exc: NEURepositoryException) { diff --git a/src/main/kotlin/moe/nea/firmament/util/MoulConfigUtils.kt b/src/main/kotlin/moe/nea/firmament/util/MoulConfigUtils.kt index 2884dc5..b99c1fc 100644 --- a/src/main/kotlin/moe/nea/firmament/util/MoulConfigUtils.kt +++ b/src/main/kotlin/moe/nea/firmament/util/MoulConfigUtils.kt @@ -18,13 +18,19 @@ import io.github.notenoughupdates.moulconfig.xml.XMLGuiLoader import io.github.notenoughupdates.moulconfig.xml.XMLUniverse import io.github.notenoughupdates.moulconfig.xml.XSDGenerator import java.io.File +import java.util.function.Supplier import javax.xml.namespace.QName import me.shedaniel.math.Color import org.w3c.dom.Element +import kotlin.time.Duration +import kotlin.time.Duration.Companion.seconds import net.minecraft.client.gui.screen.Screen import moe.nea.firmament.gui.BarComponent import moe.nea.firmament.gui.FirmButtonComponent +import moe.nea.firmament.gui.FirmHoverComponent import moe.nea.firmament.gui.FixedComponent +import moe.nea.firmament.gui.ImageComponent +import moe.nea.firmament.gui.TickComponent object MoulConfigUtils { val firmUrl = "http://firmament.nea.moe/moulconfig" @@ -69,6 +75,31 @@ object MoulConfigUtils { return mapOf("progress" to true, "total" to true, "emptyColor" to true, "fillColor" to true) } }) + uni.registerLoader(object : XMLGuiLoader.Basic<FirmHoverComponent> { + override fun createInstance(context: XMLContext<*>, element: Element): FirmHoverComponent { + return FirmHoverComponent( + context.getChildFragment(element), + context.getPropertyFromAttribute(element, QName("lines"), List::class.java) as Supplier<List<String>>, + context.getPropertyFromAttribute(element, QName("delay"), Duration::class.java, 0.6.seconds), + ) + } + + override fun getName(): QName { + return QName(firmUrl, "Hover") + } + + override fun getChildCount(): ChildCount { + return ChildCount.ONE + } + + override fun getAttributeNames(): Map<String, Boolean> { + return mapOf( + "lines" to true, + "delay" to false, + ) + } + + }) uni.registerLoader(object : XMLGuiLoader.Basic<FirmButtonComponent> { override fun getName(): QName { return QName(firmUrl, "Button") @@ -79,6 +110,7 @@ object MoulConfigUtils { context.getChildFragment(element), context.getPropertyFromAttribute(element, QName("enabled"), Boolean::class.java) ?: GetSetter.constant(true), + context.getPropertyFromAttribute(element, QName("noBackground"), Boolean::class.java, false), context.getMethodFromAttribute(element, QName("onClick")), ) } @@ -88,7 +120,56 @@ object MoulConfigUtils { } override fun getAttributeNames(): Map<String, Boolean> { - return mapOf("onClick" to true, "enabled" to false) + return mapOf("onClick" to true, "enabled" to false, "noBackground" to false) + } + }) + uni.registerLoader(object : XMLGuiLoader.Basic<ImageComponent> { + override fun createInstance(context: XMLContext<*>, element: Element): ImageComponent { + return ImageComponent( + context.getPropertyFromAttribute(element, QName("width"), Int::class.java)!!.get(), + context.getPropertyFromAttribute(element, QName("height"), Int::class.java)!!.get(), + context.getPropertyFromAttribute(element, QName("resource"), MyResourceLocation::class.java)!!, + context.getPropertyFromAttribute(element, QName("u1"), Float::class.java, 0f), + context.getPropertyFromAttribute(element, QName("u2"), Float::class.java, 1f), + context.getPropertyFromAttribute(element, QName("v1"), Float::class.java, 0f), + context.getPropertyFromAttribute(element, QName("v2"), Float::class.java, 1f), + ) + } + + override fun getName(): QName { + return QName(firmUrl, "Image") + } + + override fun getChildCount(): ChildCount { + return ChildCount.NONE + } + + override fun getAttributeNames(): Map<String, Boolean> { + return mapOf( + "width" to true, "height" to true, + "resource" to true, + "u1" to false, + "u2" to false, + "v1" to false, + "v2" to false, + ) + } + }) + uni.registerLoader(object : XMLGuiLoader.Basic<TickComponent> { + override fun createInstance(context: XMLContext<*>, element: Element): TickComponent { + return TickComponent(context.getMethodFromAttribute(element, QName("tick"))) + } + + override fun getName(): QName { + return QName(firmUrl, "Tick") + } + + override fun getChildCount(): ChildCount { + return ChildCount.NONE + } + + override fun getAttributeNames(): Map<String, Boolean> { + return mapOf("tick" to true) } }) uni.registerLoader(object : XMLGuiLoader.Basic<FixedComponent> { diff --git a/src/main/kotlin/moe/nea/firmament/util/WarpUtil.kt b/src/main/kotlin/moe/nea/firmament/util/WarpUtil.kt index 7a20346..ca8bac6 100644 --- a/src/main/kotlin/moe/nea/firmament/util/WarpUtil.kt +++ b/src/main/kotlin/moe/nea/firmament/util/WarpUtil.kt @@ -31,8 +31,8 @@ object WarpUtil { private var lastAttemptedWarp = "" private var lastWarpAttempt = TimeMark.farPast() fun findNearestWarp(island: SkyBlockIsland, pos: Position): Islands.Warp? { - return warps.minByOrNull { - if (island.locrawMode != it.mode || (DConfig.data?.excludedWarps?.contains(it.warp) == true)) { + return warps.asSequence().filter { it.mode == island.locrawMode }.minByOrNull { + if (DConfig.data?.excludedWarps?.contains(it.warp) == true) { return@minByOrNull Double.MAX_VALUE } else { return@minByOrNull squaredDist(pos, it) @@ -48,8 +48,11 @@ object WarpUtil { } fun teleportToNearestWarp(island: SkyBlockIsland, pos: Position) { - val nearestWarp = findNearestWarp(island, pos) ?: return - + val nearestWarp = findNearestWarp(island, pos) + if (nearestWarp == null) { + MC.sendChat(Text.literal("Could not find an unlocked warp in ${island.userFriendlyName}")) + return + } if (island == SBData.skyblockLocation && sqrt(squaredDist(pos, nearestWarp)) > 1.1 * sqrt(squaredDist((MC.player ?: return).pos, nearestWarp)) ) { diff --git a/src/main/kotlin/moe/nea/firmament/util/render/FacingThePlayerContext.kt b/src/main/kotlin/moe/nea/firmament/util/render/FacingThePlayerContext.kt index 01a7083..79d6e6f 100644 --- a/src/main/kotlin/moe/nea/firmament/util/render/FacingThePlayerContext.kt +++ b/src/main/kotlin/moe/nea/firmament/util/render/FacingThePlayerContext.kt @@ -37,7 +37,8 @@ class FacingThePlayerContext(val worldContext: RenderInWorldContext) { fun text( vararg texts: Text, - verticalAlign: RenderInWorldContext.VerticalAlign = RenderInWorldContext.VerticalAlign.CENTER + verticalAlign: RenderInWorldContext.VerticalAlign = RenderInWorldContext.VerticalAlign.CENTER, + background: Int = 0x70808080, ) { assertTrueOr(texts.isNotEmpty()) { return@text } for ((index, text) in texts.withIndex()) { @@ -47,14 +48,14 @@ class FacingThePlayerContext(val worldContext: RenderInWorldContext) { val vertexConsumer: VertexConsumer = worldContext.vertexConsumers.getBuffer(RenderLayer.getTextBackgroundSeeThrough()) val matrix4f = worldContext.matrixStack.peek().positionMatrix - vertexConsumer.vertex(matrix4f, -1.0f, -1.0f, 0.0f).color(0x70808080) + vertexConsumer.vertex(matrix4f, -1.0f, -1.0f, 0.0f).color(background) .light(LightmapTextureManager.MAX_BLOCK_LIGHT_COORDINATE).next() - vertexConsumer.vertex(matrix4f, -1.0f, MC.font.fontHeight.toFloat(), 0.0f).color(0x70808080) + vertexConsumer.vertex(matrix4f, -1.0f, MC.font.fontHeight.toFloat(), 0.0f).color(background) .light(LightmapTextureManager.MAX_BLOCK_LIGHT_COORDINATE).next() vertexConsumer.vertex(matrix4f, width.toFloat(), MC.font.fontHeight.toFloat(), 0.0f) - .color(0x70808080) + .color(background) .light(LightmapTextureManager.MAX_BLOCK_LIGHT_COORDINATE).next() - vertexConsumer.vertex(matrix4f, width.toFloat(), -1.0f, 0.0f).color(0x70808080) + vertexConsumer.vertex(matrix4f, width.toFloat(), -1.0f, 0.0f).color(background) .light(LightmapTextureManager.MAX_BLOCK_LIGHT_COORDINATE).next() worldContext.matrixStack.translate(0F, 0F, 0.01F) diff --git a/src/main/kotlin/moe/nea/firmament/util/render/RenderInWorldContext.kt b/src/main/kotlin/moe/nea/firmament/util/render/RenderInWorldContext.kt index 3b6e262..0620425 100644 --- a/src/main/kotlin/moe/nea/firmament/util/render/RenderInWorldContext.kt +++ b/src/main/kotlin/moe/nea/firmament/util/render/RenderInWorldContext.kt @@ -83,11 +83,12 @@ class RenderInWorldContext private constructor( } } - fun waypoint(position: BlockPos, label: Text) { + fun waypoint(position: BlockPos, vararg label: Text) { text( position.toCenterPos(), - label, - Text.literal("§e${FirmFormatters.formatDistance(MC.player?.pos?.distanceTo(position.toCenterPos()) ?: 42069.0)}") + *label, + Text.literal("§e${FirmFormatters.formatDistance(MC.player?.pos?.distanceTo(position.toCenterPos()) ?: 42069.0)}"), + background = 0xAA202020.toInt() ) } @@ -123,9 +124,9 @@ class RenderInWorldContext private constructor( } } - fun text(position: Vec3d, vararg texts: Text, verticalAlign: VerticalAlign = VerticalAlign.CENTER) { + fun text(position: Vec3d, vararg texts: Text, verticalAlign: VerticalAlign = VerticalAlign.CENTER, background: Int = 0x70808080) { withFacingThePlayer(position) { - text(*texts, verticalAlign = verticalAlign) + text(*texts, verticalAlign = verticalAlign, background = background) } } diff --git a/src/main/resources/assets/firmament/gui/npc_waypoints.xml b/src/main/resources/assets/firmament/gui/npc_waypoints.xml new file mode 100644 index 0000000..a71e899 --- /dev/null +++ b/src/main/resources/assets/firmament/gui/npc_waypoints.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8" ?> + +<!-- +SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe> + +SPDX-License-Identifier: GPL-3.0-or-later +--> + +<Root xmlns="http://notenoughupdates.org/moulconfig" xmlns:firm="http://firmament.nea.moe/moulconfig"> + <Center> + <Panel background="VANILLA" insets="5"> + <Column> + <Center> + <TextField value="@search" width="200"/> + </Center> + <firm:Tick tick="@tick"/> + <Spacer height="5"/> + <Panel background="TRANSPARENT" insets="4"> + <ScrollPanel width="200" height="300"> + <Array data="@results"> + <Row> + <Text text="@name" width="180"/> + <firm:Hover lines="Click to set this waypoint as your destination;Shift-Click to warp to the nearest warp point and set this as your destination"> + <firm:Button onClick="@click" noBackground="true"> + <When condition="@isSelected"> + <firm:Image resource="firmament:textures/gui/waypoint_selected.png" + width="16" + height="16"/> + <firm:Image resource="firmament:textures/gui/waypoint_unselected.png" + width="16" + height="16"/> + </When> + </firm:Button> + </firm:Hover> + </Row> + </Array> + </ScrollPanel> + </Panel> + </Column> + </Panel> + </Center> +</Root> diff --git a/src/main/resources/assets/firmament/textures/gui/waypoint_selected.png b/src/main/resources/assets/firmament/textures/gui/waypoint_selected.png Binary files differnew file mode 100644 index 0000000..80108ad --- /dev/null +++ b/src/main/resources/assets/firmament/textures/gui/waypoint_selected.png diff --git a/src/main/resources/assets/firmament/textures/gui/waypoint_unselected.png b/src/main/resources/assets/firmament/textures/gui/waypoint_unselected.png Binary files differnew file mode 100644 index 0000000..3c47e75 --- /dev/null +++ b/src/main/resources/assets/firmament/textures/gui/waypoint_unselected.png |