Add shiny pig tracker
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package moe.nea.firmament.mixins;
|
||||
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import moe.nea.firmament.events.EntityDespawnEvent;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.entity.Entity;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(ClientWorld.class)
|
||||
public class EntityDespawnPatch {
|
||||
@Inject(method = "removeEntity", at = @At(value = "TAIL"))
|
||||
private void onRemoved(int entityId, Entity.RemovalReason removalReason, CallbackInfo ci, @Local @Nullable Entity entity) {
|
||||
EntityDespawnEvent.Companion.publish(new EntityDespawnEvent(entity, entityId, removalReason));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package moe.nea.firmament.mixins;
|
||||
|
||||
import moe.nea.firmament.events.EntityInteractionEvent;
|
||||
import net.minecraft.client.network.ClientPlayerInteractionManager;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.hit.EntityHitResult;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(ClientPlayerInteractionManager.class)
|
||||
public class EntityInteractEventPatch {
|
||||
@Inject(method = "attackEntity", at = @At("HEAD"))
|
||||
private void onAttack(PlayerEntity player, Entity target, CallbackInfo ci) {
|
||||
EntityInteractionEvent.Companion.publish(new EntityInteractionEvent(EntityInteractionEvent.InteractionKind.ATTACK, target, Hand.MAIN_HAND));
|
||||
}
|
||||
|
||||
@Inject(method = "interactEntity", at = @At("HEAD"))
|
||||
private void onInteract(PlayerEntity player, Entity entity, Hand hand, CallbackInfoReturnable<ActionResult> cir) {
|
||||
EntityInteractionEvent.Companion.publish(new EntityInteractionEvent(EntityInteractionEvent.InteractionKind.INTERACT, entity, hand));
|
||||
}
|
||||
|
||||
@Inject(method = "interactEntityAtLocation", at = @At("HEAD"))
|
||||
private void onInteractAtLocation(PlayerEntity player, Entity entity, EntityHitResult hitResult, Hand hand, CallbackInfoReturnable<ActionResult> cir) {
|
||||
EntityInteractionEvent.Companion.publish(new EntityInteractionEvent(EntityInteractionEvent.InteractionKind.INTERACT_AT_LOCATION, entity, hand));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,8 +19,8 @@ import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(InGameHud.class)
|
||||
public class HudRenderEvents {
|
||||
@Inject(method = "renderSleepOverlay", at = @At(value = "TAIL"))
|
||||
public class HudRenderEventsPatch {
|
||||
@Inject(method = "renderSleepOverlay", at = @At(value = "HEAD"))
|
||||
public void renderCallBack(DrawContext context, float tickDelta, CallbackInfo ci) {
|
||||
HudRenderEvent.Companion.publish(new HudRenderEvent(context, tickDelta));
|
||||
}
|
||||
@@ -9,7 +9,7 @@ package moe.nea.firmament.commands
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher
|
||||
import com.mojang.brigadier.arguments.StringArgumentType.string
|
||||
import io.ktor.client.statement.*
|
||||
import io.ktor.client.statement.bodyAsText
|
||||
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource
|
||||
import net.minecraft.text.Text
|
||||
import moe.nea.firmament.apis.UrsaManager
|
||||
@@ -195,6 +195,13 @@ fun firmamentCommand() = literal("firmament") {
|
||||
FairySouls.TConfig.showConfigEditor()
|
||||
}
|
||||
}
|
||||
thenLiteral("simulate") {
|
||||
thenArgument("message", RestArgumentType) { message ->
|
||||
thenExecute {
|
||||
MC.instance.messageHandler.onGameMessage(Text.literal(get(message)), false)
|
||||
}
|
||||
}
|
||||
}
|
||||
thenLiteral("sbdata") {
|
||||
thenExecute {
|
||||
source.sendFeedback(Text.stringifiedTranslatable("firmament.sbinfo.profile", SBData.profileId))
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package moe.nea.firmament.events
|
||||
|
||||
import net.minecraft.entity.Entity
|
||||
|
||||
data class EntityDespawnEvent(
|
||||
val entity: Entity?, val entityId: Int,
|
||||
val reason: Entity.RemovalReason,
|
||||
) : FirmamentEvent() {
|
||||
companion object: FirmamentEventBus<EntityDespawnEvent>()
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package moe.nea.firmament.events
|
||||
|
||||
import net.minecraft.entity.Entity
|
||||
import net.minecraft.util.Hand
|
||||
|
||||
data class EntityInteractionEvent(
|
||||
val kind: InteractionKind,
|
||||
val entity: Entity,
|
||||
val hand: Hand,
|
||||
) : FirmamentEvent() {
|
||||
companion object : FirmamentEventBus<EntityInteractionEvent>()
|
||||
enum class InteractionKind {
|
||||
/**
|
||||
* Is sent when left-clicking an entity
|
||||
*/
|
||||
ATTACK,
|
||||
|
||||
/**
|
||||
* Is a fallback when [INTERACT_AT_LOCATION] fails
|
||||
*/
|
||||
INTERACT,
|
||||
|
||||
/**
|
||||
* Is tried first on right click
|
||||
*/
|
||||
INTERACT_AT_LOCATION,
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ import moe.nea.firmament.features.debug.DeveloperFeatures
|
||||
import moe.nea.firmament.features.debug.MinorTrolling
|
||||
import moe.nea.firmament.features.debug.PowerUserTools
|
||||
import moe.nea.firmament.features.diana.DianaWaypoints
|
||||
import moe.nea.firmament.features.events.anniversity.AnniversaryFeatures
|
||||
import moe.nea.firmament.features.fixes.CompatibliltyFeatures
|
||||
import moe.nea.firmament.features.fixes.Fixes
|
||||
import moe.nea.firmament.features.inventory.CraftingOverlay
|
||||
@@ -70,6 +71,7 @@ object FeatureManager : DataHolder<FeatureManager.Config>(serializer(), "feature
|
||||
loadFeature(ChatLinks)
|
||||
loadFeature(InventoryButtons)
|
||||
loadFeature(CompatibliltyFeatures)
|
||||
loadFeature(AnniversaryFeatures)
|
||||
loadFeature(QuickCommands)
|
||||
loadFeature(SaveCursorPosition)
|
||||
loadFeature(CustomSkyBlockTextures)
|
||||
|
||||
@@ -10,12 +10,16 @@ package moe.nea.firmament.features.debug
|
||||
import net.minecraft.block.SkullBlock
|
||||
import net.minecraft.block.entity.SkullBlockEntity
|
||||
import net.minecraft.component.DataComponentTypes
|
||||
import net.minecraft.entity.Entity
|
||||
import net.minecraft.entity.LivingEntity
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.item.Items
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.hit.BlockHitResult
|
||||
import net.minecraft.util.hit.EntityHitResult
|
||||
import net.minecraft.util.hit.HitResult
|
||||
import moe.nea.firmament.annotations.Subscribe
|
||||
import moe.nea.firmament.events.CommandEvent
|
||||
import moe.nea.firmament.events.CustomItemModelEvent
|
||||
import moe.nea.firmament.events.HandledScreenKeyPressedEvent
|
||||
import moe.nea.firmament.events.ItemTooltipEvent
|
||||
@@ -41,6 +45,7 @@ object PowerUserTools : FirmamentFeature {
|
||||
val copyTexturePackId by keyBindingWithDefaultUnbound("copy-texture-pack-id")
|
||||
val copyNbtData by keyBindingWithDefaultUnbound("copy-nbt-data")
|
||||
val copySkullTexture by keyBindingWithDefaultUnbound("copy-skull-texture")
|
||||
val copyEntityData by keyBindingWithDefaultUnbound("entity-data")
|
||||
}
|
||||
|
||||
override val config
|
||||
@@ -65,6 +70,37 @@ object PowerUserTools : FirmamentFeature {
|
||||
}
|
||||
}
|
||||
|
||||
fun debugFormat(itemStack: ItemStack): Text {
|
||||
return Text.literal(itemStack.skyBlockId?.toString() ?: itemStack.toString())
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onEntityInfo(event: WorldKeyboardEvent) {
|
||||
if (!event.matches(TConfig.copyEntityData)) return
|
||||
val target = (MC.instance.crosshairTarget as? EntityHitResult)?.entity
|
||||
if (target == null) {
|
||||
MC.sendChat(Text.translatable("firmament.poweruser.entity.fail"))
|
||||
return
|
||||
}
|
||||
showEntity(target)
|
||||
}
|
||||
|
||||
fun showEntity(target: Entity) {
|
||||
MC.sendChat(Text.translatable("firmament.poweruser.entity.type", target.type))
|
||||
MC.sendChat(Text.translatable("firmament.poweruser.entity.name", target.name))
|
||||
if (target is LivingEntity) {
|
||||
MC.sendChat(Text.translatable("firmament.poweruser.entity.armor"))
|
||||
for (armorItem in target.armorItems) {
|
||||
MC.sendChat(Text.translatable("firmament.poweruser.entity.armor.item", debugFormat(armorItem)))
|
||||
}
|
||||
}
|
||||
MC.sendChat(Text.stringifiedTranslatable("firmament.poweruser.entity.passengers", target.passengerList.size))
|
||||
target.passengerList.forEach {
|
||||
showEntity(target)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Subscribe
|
||||
fun copyInventoryInfo(it: HandledScreenKeyPressedEvent) {
|
||||
if (it.screen !is AccessorHandledScreen) return
|
||||
|
||||
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package moe.nea.firmament.features.events.anniversity
|
||||
|
||||
import io.github.notenoughupdates.moulconfig.observer.ObservableList
|
||||
import io.github.notenoughupdates.moulconfig.xml.Bind
|
||||
import moe.nea.jarvis.api.Point
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
import net.minecraft.entity.passive.PigEntity
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import moe.nea.firmament.annotations.Subscribe
|
||||
import moe.nea.firmament.events.EntityInteractionEvent
|
||||
import moe.nea.firmament.events.ProcessChatEvent
|
||||
import moe.nea.firmament.events.TickEvent
|
||||
import moe.nea.firmament.events.WorldReadyEvent
|
||||
import moe.nea.firmament.features.FirmamentFeature
|
||||
import moe.nea.firmament.gui.config.ManagedConfig
|
||||
import moe.nea.firmament.gui.hud.MoulConfigHud
|
||||
import moe.nea.firmament.rei.SBItemEntryDefinition
|
||||
import moe.nea.firmament.repo.ItemNameLookup
|
||||
import moe.nea.firmament.util.MC
|
||||
import moe.nea.firmament.util.SHORT_NUMBER_FORMAT
|
||||
import moe.nea.firmament.util.SkyblockId
|
||||
import moe.nea.firmament.util.TimeMark
|
||||
import moe.nea.firmament.util.parseShortNumber
|
||||
import moe.nea.firmament.util.useMatch
|
||||
|
||||
object AnniversaryFeatures : FirmamentFeature {
|
||||
override val identifier: String
|
||||
get() = "anniversary"
|
||||
|
||||
object TConfig : ManagedConfig(identifier) {
|
||||
val enableShinyPigTracker by toggle("shiny-pigs") {true}
|
||||
val trackPigCooldown by position("pig-hud", 200, 300) { Point(0.1, 0.2) }
|
||||
}
|
||||
|
||||
override val config: ManagedConfig?
|
||||
get() = TConfig
|
||||
|
||||
data class ClickedPig(
|
||||
val clickedAt: TimeMark,
|
||||
val startLocation: BlockPos,
|
||||
val pigEntity: PigEntity
|
||||
) {
|
||||
@Bind("timeLeft")
|
||||
fun getTimeLeft(): Double = 1 - clickedAt.passedTime() / pigDuration
|
||||
}
|
||||
|
||||
val clickedPigs = ObservableList<ClickedPig>(mutableListOf())
|
||||
var lastClickedPig: PigEntity? = null
|
||||
|
||||
val pigDuration = 90.seconds
|
||||
|
||||
@Subscribe
|
||||
fun onTick(event: TickEvent) {
|
||||
clickedPigs.removeIf { it.clickedAt.passedTime() > pigDuration }
|
||||
}
|
||||
|
||||
val pattern = "SHINY! You extracted (?<reward>.*) from the piglet's orb!".toPattern()
|
||||
|
||||
@Subscribe
|
||||
fun onChat(event: ProcessChatEvent) {
|
||||
if(!TConfig.enableShinyPigTracker)return
|
||||
if (event.unformattedString == "Oink! Bring the pig back to the Shiny Orb!") {
|
||||
val pig = lastClickedPig ?: return
|
||||
// TODO: store proper location based on the orb location, maybe
|
||||
val startLocation = pig.blockPos ?: return
|
||||
clickedPigs.add(ClickedPig(TimeMark.now(), startLocation, pig))
|
||||
lastClickedPig = null
|
||||
}
|
||||
if (event.unformattedString == "SHINY! The orb is charged! Click on it for loot!") {
|
||||
val player = MC.player ?: return
|
||||
val lowest =
|
||||
clickedPigs.minByOrNull { it.startLocation.getSquaredDistance(player.pos) } ?: return
|
||||
clickedPigs.remove(lowest)
|
||||
}
|
||||
pattern.useMatch(event.unformattedString) {
|
||||
val reward = group("reward")
|
||||
val parsedReward = parseReward(reward)
|
||||
addReward(parsedReward)
|
||||
PigCooldown.rewards.atOnce {
|
||||
PigCooldown.rewards.clear()
|
||||
rewards.mapTo(PigCooldown.rewards) { PigCooldown.DisplayReward(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun addReward(reward: Reward) {
|
||||
val it = rewards.listIterator()
|
||||
while (it.hasNext()) {
|
||||
val merged = reward.mergeWith(it.next()) ?: continue
|
||||
it.set(merged)
|
||||
return
|
||||
}
|
||||
rewards.add(reward)
|
||||
}
|
||||
|
||||
val rewards = mutableListOf<Reward>()
|
||||
|
||||
fun <T> ObservableList<T>.atOnce(block: () -> Unit) {
|
||||
val oldObserver = observer
|
||||
observer = null
|
||||
block()
|
||||
observer = oldObserver
|
||||
update()
|
||||
}
|
||||
|
||||
sealed interface Reward {
|
||||
fun mergeWith(other: Reward): Reward?
|
||||
data class EXP(val amount: Double, val skill: String) : Reward {
|
||||
override fun mergeWith(other: Reward): Reward? {
|
||||
if (other is EXP && other.skill == skill)
|
||||
return EXP(amount + other.amount, skill)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
data class Coins(val amount: Double) : Reward {
|
||||
override fun mergeWith(other: Reward): Reward? {
|
||||
if (other is Coins)
|
||||
return Coins(other.amount + amount)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
data class Items(val amount: Int, val item: SkyblockId) : Reward {
|
||||
override fun mergeWith(other: Reward): Reward? {
|
||||
if (other is Items && other.item == item)
|
||||
return Items(amount + other.amount, item)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
data class Unknown(val text: String) : Reward {
|
||||
override fun mergeWith(other: Reward): Reward? {
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val expReward = "\\+(?<exp>$SHORT_NUMBER_FORMAT) (?<kind>[^ ]+) XP".toPattern()
|
||||
val coinReward = "\\+(?<amount>$SHORT_NUMBER_FORMAT) coins".toPattern()
|
||||
val itemReward = "(?:(?<amount>[0-9]+)x )?(?<name>.*)".toPattern()
|
||||
fun parseReward(string: String): Reward {
|
||||
expReward.useMatch<Unit>(string) {
|
||||
val exp = parseShortNumber(group("exp"))
|
||||
val kind = group("kind")
|
||||
return Reward.EXP(exp, kind)
|
||||
}
|
||||
coinReward.useMatch<Unit>(string) {
|
||||
val coins = parseShortNumber(group("amount"))
|
||||
return Reward.Coins(coins)
|
||||
}
|
||||
itemReward.useMatch(string) {
|
||||
val amount = group("amount")?.toIntOrNull() ?: 1
|
||||
val name = group("name")
|
||||
val item = ItemNameLookup.guessItemByName(name, false) ?: return@useMatch
|
||||
return Reward.Items(amount, item)
|
||||
}
|
||||
return Reward.Unknown(string)
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onWorldClear(event: WorldReadyEvent) {
|
||||
lastClickedPig = null
|
||||
clickedPigs.clear()
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onEntityClick(event: EntityInteractionEvent) {
|
||||
if (event.entity is PigEntity) {
|
||||
lastClickedPig = event.entity
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun init(event: WorldReadyEvent) {
|
||||
PigCooldown.forceInit()
|
||||
}
|
||||
|
||||
object PigCooldown : MoulConfigHud("anniversary_pig", TConfig.trackPigCooldown) {
|
||||
override fun shouldRender(): Boolean {
|
||||
return clickedPigs.isNotEmpty() && TConfig.enableShinyPigTracker
|
||||
}
|
||||
|
||||
@Bind("pigs")
|
||||
fun getPigs() = clickedPigs
|
||||
|
||||
class DisplayReward(val backedBy: Reward) {
|
||||
@Bind
|
||||
fun count(): String {
|
||||
return when (backedBy) {
|
||||
is Reward.Coins -> backedBy.amount
|
||||
is Reward.EXP -> backedBy.amount
|
||||
is Reward.Items -> backedBy.amount
|
||||
is Reward.Unknown -> 0
|
||||
}.toString()
|
||||
}
|
||||
|
||||
val itemStack = if (backedBy is Reward.Items) {
|
||||
SBItemEntryDefinition.getEntry(backedBy.item, backedBy.amount)
|
||||
} else {
|
||||
SBItemEntryDefinition.getEntry(SkyblockId.NULL)
|
||||
}
|
||||
|
||||
@Bind
|
||||
fun name(): String {
|
||||
return when (backedBy) {
|
||||
is Reward.Coins -> "Coins"
|
||||
is Reward.EXP -> backedBy.skill
|
||||
is Reward.Items -> itemStack.value.asItemStack().name.string
|
||||
is Reward.Unknown -> backedBy.text
|
||||
}
|
||||
}
|
||||
|
||||
@Bind
|
||||
fun isKnown() = backedBy !is Reward.Unknown
|
||||
}
|
||||
|
||||
@get:Bind("rewards")
|
||||
val rewards = ObservableList<DisplayReward>(mutableListOf())
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -58,7 +58,7 @@ class BarComponent(
|
||||
ScreenDrawing.texturedRect(context, x, y, 4, 8, texture, emptyColor.color)
|
||||
return
|
||||
}
|
||||
val increasePerPixel = (sectionEnd - sectionStart / 4)
|
||||
val increasePerPixel = (sectionEnd - sectionStart) / width
|
||||
var valueAtPixel = sectionStart
|
||||
for (i in (0 until width)) {
|
||||
ScreenDrawing.texturedRect(
|
||||
|
||||
@@ -30,11 +30,16 @@ abstract class MoulConfigHud(
|
||||
|
||||
private var fragment: GuiContext? = null
|
||||
|
||||
fun forceInit() {
|
||||
|
||||
}
|
||||
|
||||
open fun shouldRender(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
init {
|
||||
require(name.matches("^[a-z_/]+$".toRegex()))
|
||||
HudRenderEvent.subscribe {
|
||||
if (!shouldRender()) return@subscribe
|
||||
val renderContext = componentWrapper.createContext(it.context)
|
||||
|
||||
103
src/main/kotlin/moe/nea/firmament/repo/ItemNameLookup.kt
Normal file
103
src/main/kotlin/moe/nea/firmament/repo/ItemNameLookup.kt
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package moe.nea.firmament.repo
|
||||
|
||||
import io.github.moulberry.repo.IReloadable
|
||||
import io.github.moulberry.repo.NEURepository
|
||||
import io.github.moulberry.repo.data.NEUItem
|
||||
import java.util.NavigableMap
|
||||
import java.util.TreeMap
|
||||
import moe.nea.firmament.util.SkyblockId
|
||||
import moe.nea.firmament.util.removeColorCodes
|
||||
import moe.nea.firmament.util.skyblockId
|
||||
|
||||
object ItemNameLookup : IReloadable {
|
||||
|
||||
fun getItemNameChunks(name: String): Set<String> {
|
||||
return name.removeColorCodes().split(" ").filterTo(mutableSetOf()) { it.isNotBlank() }
|
||||
}
|
||||
|
||||
var nameMap: NavigableMap<String, out Set<SkyblockId>> = TreeMap()
|
||||
|
||||
override fun reload(repository: NEURepository) {
|
||||
val nameMap = TreeMap<String, MutableSet<SkyblockId>>()
|
||||
repository.items.items.values.forEach { item ->
|
||||
getAllNamesForItem(item).forEach { name ->
|
||||
val chunks = getItemNameChunks(name)
|
||||
chunks.forEach { chunk ->
|
||||
val set = nameMap.getOrPut(chunk, ::mutableSetOf)
|
||||
set.add(item.skyblockId)
|
||||
}
|
||||
}
|
||||
}
|
||||
this.nameMap = nameMap
|
||||
}
|
||||
|
||||
fun getAllNamesForItem(item: NEUItem): Set<String> {
|
||||
val names = mutableSetOf<String>()
|
||||
names.add(item.displayName)
|
||||
if (item.displayName.contains("Enchanted Book")) {
|
||||
val enchantName = item.lore.firstOrNull()
|
||||
if (enchantName != null) {
|
||||
names.add(enchantName)
|
||||
}
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
fun findItemCandidatesByName(name: String): MutableSet<SkyblockId> {
|
||||
val candidates = mutableSetOf<SkyblockId>()
|
||||
for (chunk in getItemNameChunks(name)) {
|
||||
val set = nameMap[chunk] ?: emptySet()
|
||||
candidates.addAll(set)
|
||||
}
|
||||
return candidates
|
||||
}
|
||||
|
||||
|
||||
fun guessItemByName(
|
||||
/**
|
||||
* The display name of the item. Color codes will be ignored.
|
||||
*/
|
||||
name: String,
|
||||
/**
|
||||
* Whether the [name] may contain other text, such as reforges, master stars and such.
|
||||
*/
|
||||
mayBeMangled: Boolean
|
||||
): SkyblockId? {
|
||||
val cleanName = name.removeColorCodes()
|
||||
return findBestItemFromCandidates(
|
||||
findItemCandidatesByName(cleanName),
|
||||
cleanName,
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
fun findBestItemFromCandidates(
|
||||
candidates: Iterable<SkyblockId>,
|
||||
name: String, mayBeMangled: Boolean
|
||||
): SkyblockId? {
|
||||
val expectedClean = name.removeColorCodes()
|
||||
var bestMatch: SkyblockId? = null
|
||||
var bestMatchLength = -1
|
||||
for (candidate in candidates) {
|
||||
val item = RepoManager.getNEUItem(candidate) ?: continue
|
||||
for (name in getAllNamesForItem(item)) {
|
||||
val actualClean = name.removeColorCodes()
|
||||
val matches = if (mayBeMangled) expectedClean == actualClean
|
||||
else expectedClean.contains(actualClean)
|
||||
if (!matches) continue
|
||||
if (actualClean.length > bestMatchLength) {
|
||||
bestMatch = candidate
|
||||
bestMatchLength = actualClean.length
|
||||
}
|
||||
}
|
||||
}
|
||||
return bestMatch
|
||||
}
|
||||
|
||||
}
|
||||
@@ -63,6 +63,7 @@ object RepoManager {
|
||||
val neuRepo: NEURepository = NEURepository.of(RepoDownloadManager.repoSavedLocation).apply {
|
||||
registerReloadListener(ItemCache)
|
||||
registerReloadListener(ExpLadders)
|
||||
registerReloadListener(ItemNameLookup)
|
||||
registerReloadListener {
|
||||
Firmament.coroutineScope.launch(MinecraftDispatcher) {
|
||||
if (!trySendClientboundUpdateRecipesPacket()) {
|
||||
|
||||
@@ -18,7 +18,7 @@ import org.w3c.dom.Element
|
||||
import moe.nea.firmament.gui.BarComponent
|
||||
|
||||
object MoulConfigUtils {
|
||||
val firmUrl = "http://nea.moe/Firmament"
|
||||
val firmUrl = "http://firmament.nea.moe/moulconfig"
|
||||
val universe = XMLUniverse.getDefaultUniverse().also { uni ->
|
||||
uni.registerMapper(java.awt.Color::class.java) {
|
||||
if (it.startsWith("#")) {
|
||||
|
||||
35
src/main/resources/assets/firmament/gui/anniversary_pig.xml
Normal file
35
src/main/resources/assets/firmament/gui/anniversary_pig.xml
Normal file
@@ -0,0 +1,35 @@
|
||||
<?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:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://notenoughupdates.org/moulconfig https://raw.githubusercontent.com/NotEnoughUpdates/MoulConfig/master/MoulConfig.xsd"
|
||||
xmlns:firm="http://firmament.nea.moe/moulconfig"
|
||||
>
|
||||
<Column>
|
||||
<Array data="@pigs">
|
||||
<Row>
|
||||
<Text text="Pig: "/>
|
||||
<firm:Bar progress="@timeLeft" total="1" fillColor="#ffb6c1" emptyColor="#db7093"/>
|
||||
</Row>
|
||||
</Array>
|
||||
<Text text="Profits:"/>
|
||||
<Array data="@rewards">
|
||||
<When condition="@isKnown">
|
||||
<Row>
|
||||
<Text text="@count"/>
|
||||
<Text text="x "/>
|
||||
<Text text="@name"/>
|
||||
</Row>
|
||||
<Row>
|
||||
<Text text="Unknown reward: "/>
|
||||
<Text text="@name"/>
|
||||
</Row>
|
||||
</When>
|
||||
</Array>
|
||||
</Column>
|
||||
</Root>
|
||||
@@ -7,7 +7,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
-->
|
||||
|
||||
<Root xmlns="http://notenoughupdates.org/moulconfig" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:firm="http://nea.moe/Firmament"
|
||||
xmlns:firm="http://firmament.nea.moe/moulconfig"
|
||||
xsi:schemaLocation="http://notenoughupdates.org/moulconfig https://raw.githubusercontent.com/NotEnoughUpdates/MoulConfig/master/MoulConfig.xsd">
|
||||
<Column>
|
||||
<Row>
|
||||
|
||||
@@ -13,6 +13,15 @@
|
||||
"firmament.command.waypoint.remove.error": "Could not find waypoint with that index to delete.",
|
||||
"firmament.command.waypoint.skip.error": "Could not skip a waypoint. Are you in ordered waypoint mode with waypoints loaded?",
|
||||
"firmament.command.waypoint.skip": "Skipped 1 waypoint",
|
||||
"firmament.poweruser.entity.fail": "No entity found under cursor",
|
||||
"firmament.poweruser.entity.type": "Entity Type: %s",
|
||||
"firmament.poweruser.entity.name": "Entity Name: %s",
|
||||
"firmament.poweruser.entity.armor": "Entity Armor:",
|
||||
"firmament.poweruser.entity.armor.item": " - %s",
|
||||
"firmament.poweruser.entity.passengers": "%s Passengers",
|
||||
"firmament.config.anniversary": "Anniversary Features",
|
||||
"firmament.config.anniversary.shiny-pigs": "Shiny Pigs Tracker",
|
||||
"firmament.config.anniversary.pig-hud": "Pig Tracker Hud",
|
||||
"firmament.pristine-profit.collection": "Collection: %s/h",
|
||||
"firmament.pristine-profit.money": "Money: %s/h",
|
||||
"firmament.toggle.true": "On",
|
||||
@@ -156,6 +165,7 @@
|
||||
"firmament.modapi.event": "Received mod API event: %s",
|
||||
"firmament.config.power-user.copy-texture-pack-id": "Copy Texture Pack Id",
|
||||
"firmament.config.power-user.copy-skull-texture": "Copy Placed Skull Id",
|
||||
"firmament.config.power-user.entity-data": "Show Entity Data",
|
||||
"firmament.config.power-user.copy-nbt-data": "Copy NBT data",
|
||||
"firmament.config.power-user": "Power Users",
|
||||
"firmament.tooltip.skyblockid": "SkyBlock Id: %s",
|
||||
|
||||
Reference in New Issue
Block a user