Add /firm npcs command

This commit is contained in:
Linnea Gräf
2024-08-07 21:34:16 +02:00
parent 9b277bd897
commit b4f9ca21ef
21 changed files with 538 additions and 32 deletions

View File

@@ -23,7 +23,7 @@ notenoughanimations = "WaI2x21x"
devauth = "1.2.0"
ktor = "2.3.0"
neurepoparser = "1.4.0"
neurepoparser = "1.5.0"
hotswap_agent = "1.4.2-SNAPSHOT"
mixinextras = "0.3.5"
jarvis = "1.1.3"

View File

@@ -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++))

View File

@@ -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>()
}

View File

@@ -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)
}

View File

@@ -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))
}
}
}
}

View File

@@ -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)
}
}

View File

@@ -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()
}
}
}

View File

@@ -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)
}
}
}
}

View File

@@ -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()

View File

@@ -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)
}
}

View File

@@ -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
)
}
}

View File

@@ -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()
}
}

View File

@@ -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)

View File

@@ -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) {

View File

@@ -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> {

View File

@@ -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))
) {

View File

@@ -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)

View File

@@ -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)
}
}

View File

@@ -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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 B