diff options
17 files changed, 548 insertions, 6 deletions
diff --git a/src/main/java/moe/nea/firmament/mixins/EntityDespawnPatch.java b/src/main/java/moe/nea/firmament/mixins/EntityDespawnPatch.java new file mode 100644 index 0000000..1c095da --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/EntityDespawnPatch.java @@ -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)); + } +} diff --git a/src/main/java/moe/nea/firmament/mixins/EntityInteractEventPatch.java b/src/main/java/moe/nea/firmament/mixins/EntityInteractEventPatch.java new file mode 100644 index 0000000..4c2e92f --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/EntityInteractEventPatch.java @@ -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)); + } + +} diff --git a/src/main/java/moe/nea/firmament/mixins/HudRenderEvents.java b/src/main/java/moe/nea/firmament/mixins/HudRenderEventsPatch.java index 111ab33..6618e95 100644 --- a/src/main/java/moe/nea/firmament/mixins/HudRenderEvents.java +++ b/src/main/java/moe/nea/firmament/mixins/HudRenderEventsPatch.java @@ -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)); } diff --git a/src/main/kotlin/moe/nea/firmament/commands/rome.kt b/src/main/kotlin/moe/nea/firmament/commands/rome.kt index 74391a6..dc46f1f 100644 --- a/src/main/kotlin/moe/nea/firmament/commands/rome.kt +++ b/src/main/kotlin/moe/nea/firmament/commands/rome.kt @@ -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)) diff --git a/src/main/kotlin/moe/nea/firmament/events/EntityDespawnEvent.kt b/src/main/kotlin/moe/nea/firmament/events/EntityDespawnEvent.kt new file mode 100644 index 0000000..c744729 --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/events/EntityDespawnEvent.kt @@ -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>() +} diff --git a/src/main/kotlin/moe/nea/firmament/events/EntityInteractionEvent.kt b/src/main/kotlin/moe/nea/firmament/events/EntityInteractionEvent.kt new file mode 100644 index 0000000..fe16868 --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/events/EntityInteractionEvent.kt @@ -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, + } +} diff --git a/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt b/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt index 4c1fde8..f2b2d25 100644 --- a/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt +++ b/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt @@ -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) 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 d530487..17e8253 100644 --- a/src/main/kotlin/moe/nea/firmament/features/debug/PowerUserTools.kt +++ b/src/main/kotlin/moe/nea/firmament/features/debug/PowerUserTools.kt @@ -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 diff --git a/src/main/kotlin/moe/nea/firmament/features/events/anniversity/AnniversaryFeatures.kt b/src/main/kotlin/moe/nea/firmament/features/events/anniversity/AnniversaryFeatures.kt new file mode 100644 index 0000000..5735e76 --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/features/events/anniversity/AnniversaryFeatures.kt @@ -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()) + + } + +} diff --git a/src/main/kotlin/moe/nea/firmament/gui/BarComponent.kt b/src/main/kotlin/moe/nea/firmament/gui/BarComponent.kt index a1eb23c..91b5735 100644 --- a/src/main/kotlin/moe/nea/firmament/gui/BarComponent.kt +++ b/src/main/kotlin/moe/nea/firmament/gui/BarComponent.kt @@ -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( diff --git a/src/main/kotlin/moe/nea/firmament/gui/hud/MoulConfigHud.kt b/src/main/kotlin/moe/nea/firmament/gui/hud/MoulConfigHud.kt index ec884bb..afc8740 100644 --- a/src/main/kotlin/moe/nea/firmament/gui/hud/MoulConfigHud.kt +++ b/src/main/kotlin/moe/nea/firmament/gui/hud/MoulConfigHud.kt @@ -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) diff --git a/src/main/kotlin/moe/nea/firmament/repo/ItemNameLookup.kt b/src/main/kotlin/moe/nea/firmament/repo/ItemNameLookup.kt new file mode 100644 index 0000000..4bdf616 --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/repo/ItemNameLookup.kt @@ -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 + } + +} diff --git a/src/main/kotlin/moe/nea/firmament/repo/RepoManager.kt b/src/main/kotlin/moe/nea/firmament/repo/RepoManager.kt index a1e73b1..db17e6a 100644 --- a/src/main/kotlin/moe/nea/firmament/repo/RepoManager.kt +++ b/src/main/kotlin/moe/nea/firmament/repo/RepoManager.kt @@ -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()) { diff --git a/src/main/kotlin/moe/nea/firmament/util/MoulConfigUtils.kt b/src/main/kotlin/moe/nea/firmament/util/MoulConfigUtils.kt index 0b56c7c..4d3221f 100644 --- a/src/main/kotlin/moe/nea/firmament/util/MoulConfigUtils.kt +++ b/src/main/kotlin/moe/nea/firmament/util/MoulConfigUtils.kt @@ -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("#")) { diff --git a/src/main/resources/assets/firmament/gui/anniversary_pig.xml b/src/main/resources/assets/firmament/gui/anniversary_pig.xml new file mode 100644 index 0000000..eb83aa5 --- /dev/null +++ b/src/main/resources/assets/firmament/gui/anniversary_pig.xml @@ -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> diff --git a/src/main/resources/assets/firmament/gui/pristine_profit.xml b/src/main/resources/assets/firmament/gui/pristine_profit.xml index 2d69abb..5f9ea43 100644 --- a/src/main/resources/assets/firmament/gui/pristine_profit.xml +++ b/src/main/resources/assets/firmament/gui/pristine_profit.xml @@ -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> diff --git a/src/main/resources/assets/firmament/lang/en_us.json b/src/main/resources/assets/firmament/lang/en_us.json index 089a223..c25e5d7 100644 --- a/src/main/resources/assets/firmament/lang/en_us.json +++ b/src/main/resources/assets/firmament/lang/en_us.json @@ -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", |