diff options
12 files changed, 217 insertions, 44 deletions
diff --git a/src/compat/rei/java/moe/nea/firmament/compat/rei/SkyblockItemIdFocusedStackProvider.kt b/src/compat/rei/java/moe/nea/firmament/compat/rei/SkyblockItemIdFocusedStackProvider.kt index 9ccfab4..7e12fb6 100644 --- a/src/compat/rei/java/moe/nea/firmament/compat/rei/SkyblockItemIdFocusedStackProvider.kt +++ b/src/compat/rei/java/moe/nea/firmament/compat/rei/SkyblockItemIdFocusedStackProvider.kt @@ -13,7 +13,6 @@ import moe.nea.firmament.mixins.accessor.AccessorHandledScreen object SkyblockItemIdFocusedStackProvider : FocusedStackProvider { override fun provide(screen: Screen?, mouse: Point?): CompoundEventResult<EntryStack<*>> { if (screen !is HandledScreen<*>) return CompoundEventResult.pass() - screen as AccessorHandledScreen val focusedSlot = screen.focusedSlot_Firmament ?: return CompoundEventResult.pass() val item = focusedSlot.stack ?: return CompoundEventResult.pass() return CompoundEventResult.interruptTrue(SBItemEntryDefinition.getEntry(item)) diff --git a/src/main/kotlin/features/inventory/SlotLocking.kt b/src/main/kotlin/features/inventory/SlotLocking.kt index 09afe80..fca40c8 100644 --- a/src/main/kotlin/features/inventory/SlotLocking.kt +++ b/src/main/kotlin/features/inventory/SlotLocking.kt @@ -42,6 +42,7 @@ import moe.nea.firmament.util.CommonSoundEffects import moe.nea.firmament.util.MC import moe.nea.firmament.util.SBData import moe.nea.firmament.util.SkyBlockIsland +import moe.nea.firmament.util.accessors.castAccessor import moe.nea.firmament.util.data.Config import moe.nea.firmament.util.data.ManagedConfig import moe.nea.firmament.util.data.ProfileSpecificDataHolder @@ -295,7 +296,7 @@ object SlotLocking { fun onLockUUID(it: HandledScreenKeyPressedEvent) { if (!it.matches(TConfig.lockUUID)) return val inventory = MC.handledScreen ?: return - inventory as AccessorHandledScreen + inventory.castAccessor() val slot = inventory.focusedSlot_Firmament ?: return val stack = slot.item ?: return @@ -330,7 +331,7 @@ object SlotLocking { @Subscribe fun onLockSlotKeyRelease(it: HandledScreenKeyReleasedEvent) { val inventory = MC.handledScreen ?: return - inventory as AccessorHandledScreen + inventory.castAccessor() val slot = inventory.focusedSlot_Firmament val storedSlot = storedLockingSlot ?: return @@ -364,7 +365,7 @@ object SlotLocking { fun onRenderAllBoundSlots(event: HandledScreenForegroundEvent) { val boundSlots = currentWorldData?.boundSlots ?: return fun findByIndex(index: Int) = event.screen.getSlotByIndex(index, true) - val accScreen = event.screen as AccessorHandledScreen + val accScreen = event.screen.castAccessor() val sx = accScreen.x_Firmament val sy = accScreen.y_Firmament val highlitSlots = mutableSetOf<Slot>() @@ -409,14 +410,20 @@ object SlotLocking { @Subscribe fun onRenderCurrentDraggingSlot(event: HandledScreenForegroundEvent) { val draggingSlot = storedLockingSlot ?: return - val accScreen = event.screen as AccessorHandledScreen + val accScreen = event.screen.castAccessor() val hoveredSlot = accScreen.focusedSlot_Firmament ?.takeIf { it.container is Inventory } ?.takeIf { it == draggingSlot || it.isHotbar() != draggingSlot.isHotbar() } val sx = accScreen.x_Firmament val sy = accScreen.y_Firmament val (borderX, borderY) = draggingSlot.lineCenter() - event.context.submitOutline(draggingSlot.x + sx, draggingSlot.y + sy, 16, 16, 0xFF00FF00u.toInt()) // TODO: 1.21.10 + event.context.submitOutline( + draggingSlot.x + sx, + draggingSlot.y + sy, + 16, + 16, + 0xFF00FF00u.toInt() + ) // TODO: 1.21.10 if (hoveredSlot == null) { event.context.drawLine( borderX + sx, borderY + sy, @@ -477,7 +484,7 @@ object SlotLocking { @Subscribe fun onLockSlot(it: HandledScreenKeyPressedEvent) { val inventory = MC.handledScreen ?: return - inventory as AccessorHandledScreen + inventory.castAccessor() val slot = inventory.focusedSlot_Firmament ?: return if (slot.container !is Inventory) return diff --git a/src/main/kotlin/features/inventory/storageoverlay/StorageOverlayCustom.kt b/src/main/kotlin/features/inventory/storageoverlay/StorageOverlayCustom.kt index f291dba..98e8085 100644 --- a/src/main/kotlin/features/inventory/storageoverlay/StorageOverlayCustom.kt +++ b/src/main/kotlin/features/inventory/storageoverlay/StorageOverlayCustom.kt @@ -11,6 +11,7 @@ import net.minecraft.client.input.KeyEvent import net.minecraft.world.entity.player.Inventory import net.minecraft.world.inventory.Slot import moe.nea.firmament.mixins.accessor.AccessorHandledScreen +import moe.nea.firmament.util.accessors.castAccessor import moe.nea.firmament.util.customgui.CustomGui import moe.nea.firmament.util.focusedItemStack @@ -42,7 +43,7 @@ class StorageOverlayCustom( override fun onInit() { overview.init(Minecraft.getInstance(), screen.width, screen.height) overview.init() - screen as AccessorHandledScreen + screen.castAccessor() screen.x_Firmament = overview.measurements.x screen.y_Firmament = overview.measurements.y screen.backgroundWidth_Firmament = overview.measurements.totalWidth @@ -96,7 +97,7 @@ class StorageOverlayCustom( delta, (handler as? StorageBackingHandle.Page)?.storagePageSlot, screen.menu.slots.take(screen.menu.rowCount * 9).drop(9), - Point((screen as AccessorHandledScreen).x_Firmament, screen.y_Firmament) + Point((screen.castAccessor()).x_Firmament, screen.y_Firmament) ) overview.drawScrollBar(drawContext) overview.drawControls(drawContext, mouseX, mouseY) @@ -106,7 +107,7 @@ class StorageOverlayCustom( val index = slot.containerSlot if (index in 0..<36) { val (x, y) = overview.getPlayerInventorySlotPosition(index) - slot.x = x - (screen as AccessorHandledScreen).x_Firmament + slot.x = x - (screen.castAccessor()).x_Firmament slot.y = y - screen.y_Firmament } else { slot.x = -100000 diff --git a/src/main/kotlin/features/items/recipes/ItemList.kt b/src/main/kotlin/features/items/recipes/ItemList.kt new file mode 100644 index 0000000..f8268f4 --- /dev/null +++ b/src/main/kotlin/features/items/recipes/ItemList.kt @@ -0,0 +1,120 @@ +package moe.nea.firmament.features.items.recipes + +import java.util.Optional +import net.minecraft.client.gui.navigation.ScreenRectangle +import net.minecraft.client.gui.screens.Screen +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen +import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.Items +import moe.nea.firmament.annotations.Subscribe +import moe.nea.firmament.api.v1.FirmamentAPI +import moe.nea.firmament.events.HandledScreenForegroundEvent +import moe.nea.firmament.events.ReloadRegistrationEvent +import moe.nea.firmament.repo.RepoManager +import moe.nea.firmament.repo.SBItemStack +import moe.nea.firmament.util.MC +import moe.nea.firmament.util.accessors.castAccessor +import moe.nea.firmament.util.skyblockId + +object ItemList { + // TODO: add a global toggle for this and RecipeRegistry + + fun collectExclusions(screen: Screen): Set<ScreenRectangle> { + val exclusions = mutableSetOf<ScreenRectangle>() + if (screen is AbstractContainerScreen<*>) { + val screenHandler = screen.castAccessor() + exclusions.add( + ScreenRectangle( + screenHandler.x_Firmament, + screenHandler.y_Firmament, + screenHandler.backgroundWidth_Firmament, + screenHandler.backgroundHeight_Firmament + ) + ) + } + FirmamentAPI.getInstance().extensions + .forEach { extension -> + for (rectangle in extension.getExclusionZones(screen)) { + if (exclusions.any { it.encompasses(rectangle) }) + continue + exclusions.add(rectangle) + } + } + + return exclusions + } + + var reachableItems = listOf<SBItemStack>() + var pageOffset = 0 + fun recalculateVisibleItems() { + reachableItems = RepoManager.neuRepo.items + .items.values.map { SBItemStack(it.skyblockId) } + } + + @Subscribe + fun onReload(event: ReloadRegistrationEvent) { + event.repo.registerReloadListener { recalculateVisibleItems() } + } + + fun coordinates(outer: ScreenRectangle, exclusions: Collection<ScreenRectangle>): Sequence<ScreenRectangle> { + val entryWidth = 18 + val columns = outer.width / entryWidth + val rows = outer.height / entryWidth + val lowX = outer.right() - columns * entryWidth + val lowY = outer.top() + return generateSequence(0) { it + 1 } + .map { + val xIndex = it % columns + val yIndex = it / columns + ScreenRectangle( + lowX + xIndex * entryWidth, lowY + yIndex * entryWidth, + entryWidth, entryWidth + ) + } + .take(rows * columns) + .filter { candidate -> exclusions.none { it.intersects(candidate) } } + } + + var lastRenderPositions: List<Pair<ScreenRectangle, SBItemStack>> = listOf() + var lastHoveredItemStack: Pair<ScreenRectangle, SBItemStack>? = null + + fun findStackUnder(mouseX: Int, mouseY: Int): Pair<ScreenRectangle, SBItemStack>? { + val lhis = lastHoveredItemStack + if (lhis != null && lhis.first.containsPoint(mouseX, mouseY)) + return lhis + return lastRenderPositions.firstOrNull { it.first.containsPoint(mouseX, mouseY) } + } + + @Subscribe + fun onRender(event: HandledScreenForegroundEvent) { + lastHoveredItemStack = null + lastRenderPositions = listOf() + val exclusions = collectExclusions(event.screen) + val potentiallyVisible = reachableItems.subList(pageOffset, reachableItems.size) + val screenWidth = event.screen.width + val rightThird = ScreenRectangle( + screenWidth - screenWidth / 3, 0, + screenWidth / 3, event.screen.height + ) + val coords = coordinates(rightThird, exclusions) + + lastRenderPositions = coords.zip(potentiallyVisible.asSequence()).toList() + lastRenderPositions.forEach { (pos, stack) -> + val realStack = stack.asLazyImmutableItemStack() + val toRender = realStack ?: ItemStack(Items.PAINTING) + event.context.renderItem(toRender, pos.left() + 1, pos.top() + 1) + if (pos.containsPoint(event.mouseX, event.mouseY)) { + lastHoveredItemStack = pos to stack + event.context.setTooltipForNextFrame( + MC.font, + if (realStack != null) + ItemSlotWidget.getTooltip(realStack) + else + stack.estimateLore(), + Optional.empty(), + event.mouseX, event.mouseY + ) + } + } + } +} diff --git a/src/main/kotlin/features/items/recipes/ItemSlotWidget.kt b/src/main/kotlin/features/items/recipes/ItemSlotWidget.kt index c47c8ca..b659643 100644 --- a/src/main/kotlin/features/items/recipes/ItemSlotWidget.kt +++ b/src/main/kotlin/features/items/recipes/ItemSlotWidget.kt @@ -71,36 +71,37 @@ class ItemSlotWidget( companion object { val SHORT_NUM_CUTOFF = 1000 var canUseTooltipEvent = true - } - fun getTooltip(itemStack: ItemStack): List<Component> { - val lore = mutableListOf(itemStack.displayNameAccordingToNbt) - lore.addAll(itemStack.loreAccordingToNbt) - if (canUseTooltipEvent) { - try { - ItemTooltipCallback.EVENT.invoker().getTooltip( - itemStack, Item.TooltipContext.EMPTY, - TooltipFlag.NORMAL, lore + fun getTooltip(itemStack: ItemStack): List<Component> { + val lore = mutableListOf(itemStack.displayNameAccordingToNbt) + lore.addAll(itemStack.loreAccordingToNbt) + if (canUseTooltipEvent) { + try { + ItemTooltipCallback.EVENT.invoker().getTooltip( + itemStack, Item.TooltipContext.EMPTY, + TooltipFlag.NORMAL, lore + ) + } catch (ex: Exception) { + canUseTooltipEvent = false + ErrorUtil.softError("Failed to use vanilla tooltips", ex) + } + } else { + ItemTooltipEvent.publish( + ItemTooltipEvent( + itemStack, + Item.TooltipContext.EMPTY, + TooltipFlag.NORMAL, + lore + ) ) - } catch (ex: Exception) { - canUseTooltipEvent = false - ErrorUtil.softError("Failed to use vanilla tooltips", ex) } - } else { - ItemTooltipEvent.publish( - ItemTooltipEvent( - itemStack, - Item.TooltipContext.EMPTY, - TooltipFlag.NORMAL, - lore - ) - ) + if (itemStack.count >= SHORT_NUM_CUTOFF && lore.isNotEmpty()) + lore.add(1, Component.literal("${itemStack.count}x").darkGrey()) + return lore } - if (itemStack.count >= SHORT_NUM_CUTOFF && lore.isNotEmpty()) - lore.add(1, Component.literal("${itemStack.count}x").darkGrey()) - return lore } + override fun tick() { if (SavedKeyBinding.isShiftDown()) return if (content.size <= 1) return diff --git a/src/main/kotlin/features/items/recipes/RecipeWidget.kt b/src/main/kotlin/features/items/recipes/RecipeWidget.kt index b0591b2..f13707c 100644 --- a/src/main/kotlin/features/items/recipes/RecipeWidget.kt +++ b/src/main/kotlin/features/items/recipes/RecipeWidget.kt @@ -27,10 +27,6 @@ abstract class RecipeWidget : GuiEventListener, Renderable, NarratableEntry { this._focused = focused } - override fun getRectangle(): ScreenRectangle { - return rect.asScreenRectangle() - } - override fun isFocused(): Boolean { return this._focused } diff --git a/src/main/kotlin/features/mining/HotmPresets.kt b/src/main/kotlin/features/mining/HotmPresets.kt index 5316211..4930f90 100644 --- a/src/main/kotlin/features/mining/HotmPresets.kt +++ b/src/main/kotlin/features/mining/HotmPresets.kt @@ -24,6 +24,7 @@ import moe.nea.firmament.util.ClipboardUtils import moe.nea.firmament.util.MC import moe.nea.firmament.util.TemplateUtil import moe.nea.firmament.util.TimeMark +import moe.nea.firmament.util.accessors.castAccessor import moe.nea.firmament.util.customgui.CustomGui import moe.nea.firmament.util.customgui.customGui import moe.nea.firmament.util.mc.CommonTextures @@ -124,7 +125,7 @@ object HotmPresets { screen.height / 2 - 100, 300, 200 ) - val screen = screen as AccessorHandledScreen + val screen = screen.castAccessor() screen.x_Firmament = bounds.x screen.y_Firmament = bounds.y screen.backgroundWidth_Firmament = bounds.width @@ -156,7 +157,9 @@ object HotmPresets { } } if (allRows == coveredRows) { - ClipboardUtils.setTextContent(TemplateUtil.encodeTemplate(SHARE_PREFIX, HotmPreset( + ClipboardUtils.setTextContent( + TemplateUtil.encodeTemplate( + SHARE_PREFIX, HotmPreset( unlockedPerks.map { PerkPreset(it) } ))) hasAll = true diff --git a/src/main/kotlin/impl/v1/FirmamentAPIImpl.kt b/src/main/kotlin/impl/v1/FirmamentAPIImpl.kt index d5fc0de..3ca4778 100644 --- a/src/main/kotlin/impl/v1/FirmamentAPIImpl.kt +++ b/src/main/kotlin/impl/v1/FirmamentAPIImpl.kt @@ -1,14 +1,16 @@ package moe.nea.firmament.impl.v1 -import com.mojang.blaze3d.platform.InputConstants import java.util.Collections import java.util.Optional import net.fabricmc.loader.api.FabricLoader import kotlin.jvm.optionals.getOrNull +import net.minecraft.world.item.ItemStack import moe.nea.firmament.Firmament import moe.nea.firmament.api.v1.FirmamentAPI import moe.nea.firmament.api.v1.FirmamentExtension import moe.nea.firmament.api.v1.FirmamentItemWidget +import moe.nea.firmament.features.items.recipes.ItemList +import moe.nea.firmament.repo.ExpensiveItemCacheApi import moe.nea.firmament.util.MC import moe.nea.firmament.util.intoOptional @@ -21,6 +23,7 @@ object FirmamentAPIImpl : FirmamentAPI() { return Collections.unmodifiableList(_extensions) } + @OptIn(ExpensiveItemCacheApi::class) override fun getHoveredItemWidget(): Optional<FirmamentItemWidget> { val mouse = MC.instance.mouseHandler val window = MC.window @@ -30,6 +33,22 @@ object FirmamentAPIImpl : FirmamentAPI() { ?.getChildAt(xpos, ypos) ?.getOrNull() if (widget is FirmamentItemWidget) return widget.intoOptional() + val itemListStack = ItemList.findStackUnder(xpos.toInt(), ypos.toInt()) + if (itemListStack != null) + return object : FirmamentItemWidget { + override fun getPlacement(): FirmamentItemWidget.Placement { + return FirmamentItemWidget.Placement.ITEM_LIST + } + + override fun getItemStack(): ItemStack { + return itemListStack.second.asImmutableItemStack() + } + + override fun getSkyBlockId(): String { + return itemListStack.second.skyblockId.neuItem + } + + }.intoOptional() return Optional.empty() } diff --git a/src/main/kotlin/repo/SBItemStack.kt b/src/main/kotlin/repo/SBItemStack.kt index 80cd5d7..89e53e8 100644 --- a/src/main/kotlin/repo/SBItemStack.kt +++ b/src/main/kotlin/repo/SBItemStack.kt @@ -329,7 +329,9 @@ data class SBItemStack constructor( val reforge = ReforgeStore.modifierLut[reforgeId] ?: return val reforgeStats = reforge.reforgeStats?.get(rarity) ?: mapOf() itemStack.displayNameAccordingToNbt = itemStack.displayNameAccordingToNbt.copy() - .prepend(Component.literal(reforge.reforgeName + " ").withStyle(Rarity.colourMap[rarity] ?: ChatFormatting.WHITE)) + .prepend( + Component.literal(reforge.reforgeName + " ").withStyle(Rarity.colourMap[rarity] ?: ChatFormatting.WHITE) + ) val data = itemStack.extraAttributes.copy() data.putString("modifier", reforgeId.id) itemStack.extraAttributes = data @@ -355,6 +357,7 @@ data class SBItemStack constructor( // TODO: avoid instantiating the item stack here @ExpensiveItemCacheApi val itemType: ItemType? get() = ItemType.fromItemStack(asImmutableItemStack()) + @ExpensiveItemCacheApi val rarity: Rarity? get() = Rarity.fromItem(asImmutableItemStack()) @@ -391,6 +394,13 @@ data class SBItemStack constructor( } + /** + * estimate the lore content without creating an itemstack instance + */ + fun estimateLore(): List<Component> { + return (neuItem?.lore?.map { ItemCache.un189Lore(it) } ?: emptyList()) + extraLore + } + private fun starString(stars: Int): Component { if (stars <= 0) return Component.empty() // TODO: idk master stars diff --git a/src/main/kotlin/util/accessors/GetRectangle.kt b/src/main/kotlin/util/accessors/GetRectangle.kt index 05ecfa9..109de94 100644 --- a/src/main/kotlin/util/accessors/GetRectangle.kt +++ b/src/main/kotlin/util/accessors/GetRectangle.kt @@ -7,7 +7,7 @@ import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen import moe.nea.firmament.mixins.accessor.AccessorHandledScreen fun AbstractContainerScreen<*>.getProperRectangle(): Rectangle { - this as AccessorHandledScreen + this.castAccessor() return Rectangle( getX_Firmament(), getY_Firmament(), diff --git a/src/main/kotlin/util/accessors/castAccessor.kt b/src/main/kotlin/util/accessors/castAccessor.kt new file mode 100644 index 0000000..0ac85a2 --- /dev/null +++ b/src/main/kotlin/util/accessors/castAccessor.kt @@ -0,0 +1,16 @@ +@file:OptIn(ExperimentalContracts::class) + +package moe.nea.firmament.util.accessors + +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.contract +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen +import moe.nea.firmament.mixins.accessor.AccessorHandledScreen + + +inline fun AbstractContainerScreen<*>.castAccessor(): AccessorHandledScreen { + contract { + returns() implies (this@castAccessor is AccessorHandledScreen) + } + return this as AccessorHandledScreen +} diff --git a/src/texturePacks/java/moe/nea/firmament/features/texturepack/CustomScreenLayouts.kt b/src/texturePacks/java/moe/nea/firmament/features/texturepack/CustomScreenLayouts.kt index 10bbeea..e026365 100644 --- a/src/texturePacks/java/moe/nea/firmament/features/texturepack/CustomScreenLayouts.kt +++ b/src/texturePacks/java/moe/nea/firmament/features/texturepack/CustomScreenLayouts.kt @@ -31,6 +31,7 @@ import moe.nea.firmament.mixins.accessor.AccessorHandledScreen import moe.nea.firmament.mixins.accessor.AccessorScreenHandler import moe.nea.firmament.util.ErrorUtil.intoCatch import moe.nea.firmament.util.IdentifierSerializer +import moe.nea.firmament.util.accessors.castAccessor object CustomScreenLayouts : SimplePreparableReloadListener<List<CustomScreenLayouts.CustomScreenLayout>>() { @@ -102,7 +103,7 @@ object CustomScreenLayouts : SimplePreparableReloadListener<List<CustomScreenLay } fun renderGeneric(context: GuiGraphics, screen: AbstractContainerScreen<*>) { - screen as AccessorHandledScreen + screen.castAccessor() val originalX: Int = (screen.width - screen.backgroundWidth_Firmament) / 2 val originalY: Int = (screen.height - screen.backgroundHeight_Firmament) / 2 val modifiedX = originalX + this.x |
