aboutsummaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
authorLinnea Gräf <nea@nea.moe>2025-11-24 23:42:00 +0100
committerLinnea Gräf <nea@nea.moe>2025-11-24 23:42:00 +0100
commit6dd14e7225ff60361fe9f87020c424c0eb89a68b (patch)
tree6977d5a71850924becc71b1ac53f1865a1c8330a /src/main
parent3f33928c8fefe4816af9d538fa3fce48d5e76f7c (diff)
downloadFirmament-6dd14e7225ff60361fe9f87020c424c0eb89a68b.tar.gz
Firmament-6dd14e7225ff60361fe9f87020c424c0eb89a68b.tar.bz2
Firmament-6dd14e7225ff60361fe9f87020c424c0eb89a68b.zip
feat: firmament api
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/moe/nea/firmament/init/HandledScreenRiser.java42
-rw-r--r--src/main/java/moe/nea/firmament/mixins/MixinHandledScreen.java18
-rw-r--r--src/main/java/moe/nea/firmament/mixins/ScreenInputEvents.java34
-rw-r--r--src/main/kotlin/Firmament.kt2
-rw-r--r--src/main/kotlin/events/HandledScreenKeyPressedEvent.kt5
-rw-r--r--src/main/kotlin/features/debug/PowerUserTools.kt3
-rw-r--r--src/main/kotlin/features/inventory/WardrobeKeybinds.kt2
-rw-r--r--src/main/kotlin/features/inventory/buttons/InventoryButtons.kt7
-rw-r--r--src/main/kotlin/features/items/recipes/ItemSlotWidget.kt17
-rw-r--r--src/main/kotlin/features/items/recipes/RecipeRegistry.kt21
-rw-r--r--src/main/kotlin/features/items/recipes/RecipeWidget.kt4
-rw-r--r--src/main/kotlin/impl/v1/FirmamentAPIImpl.kt48
-rw-r--r--src/main/kotlin/util/HoveredItemStack.kt21
13 files changed, 182 insertions, 42 deletions
diff --git a/src/main/java/moe/nea/firmament/init/HandledScreenRiser.java b/src/main/java/moe/nea/firmament/init/HandledScreenRiser.java
index 881990c..98be517 100644
--- a/src/main/java/moe/nea/firmament/init/HandledScreenRiser.java
+++ b/src/main/java/moe/nea/firmament/init/HandledScreenRiser.java
@@ -2,11 +2,13 @@
package moe.nea.firmament.init;
import me.shedaniel.mm.api.ClassTinkerers;
+import net.minecraft.client.gui.components.events.AbstractContainerEventHandler;
import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.client.input.CharacterEvent;
import net.minecraft.client.input.KeyEvent;
+import net.minecraft.client.input.MouseButtonEvent;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.ClassNode;
@@ -27,6 +29,8 @@ public class HandledScreenRiser extends RiserUtils {
Intermediary.InterClass KeyInput = Intermediary.<KeyEvent>intermediaryClass();
Intermediary.InterClass CharInput = Intermediary.<CharacterEvent>intermediaryClass();
Intermediary.InterClass HandledScreen = Intermediary.<AbstractContainerScreen>intermediaryClass();
+ Intermediary.InterClass AbstractContainerEventHandler = Intermediary.<AbstractContainerEventHandler>intermediaryClass();
+ Intermediary.InterClass MouseButtonEvent = Intermediary.<MouseButtonEvent>intermediaryClass();
Intermediary.InterMethod mouseScrolled = Intermediary.intermediaryMethod(
GuiEventListener::mouseScrolled,
Intermediary.ofClass(boolean.class),
@@ -35,6 +39,14 @@ public class HandledScreenRiser extends RiserUtils {
Intermediary.ofClass(double.class),
Intermediary.ofClass(double.class)
);
+ Intermediary.InterMethod mouseClickedScreen = Intermediary.intermediaryMethod(
+ //onMouseClicked$firmament
+ GuiEventListener::mouseClicked,
+ Intermediary.ofClass(boolean.class),
+ MouseButtonEvent,
+ Intermediary.ofClass(boolean.class)
+ );
+ ;
Intermediary.InterMethod keyReleased = Intermediary.intermediaryMethod(
GuiEventListener::keyReleased,
Intermediary.ofClass(boolean.class),
@@ -47,12 +59,12 @@ public class HandledScreenRiser extends RiserUtils {
);
-
@Override
public void addTinkerers() {
addTransformation(HandledScreen, this::addMouseScroll, true);
addTransformation(HandledScreen, this::addKeyReleased, true);
addTransformation(HandledScreen, this::addCharTyped, true);
+ addTransformation(Screen, this::addMouseClicked, true);
}
/**
@@ -86,7 +98,7 @@ public class HandledScreenRiser extends RiserUtils {
void addKeyReleased(ClassNode classNode) {
addSuperInjector(
- classNode, keyReleased.mapped(), keyReleased.mappedDesc(), "keyReleased_firmament",
+ classNode, keyReleased.mapped(), keyReleased.mappedDesc(), HandledScreen, Screen, "keyReleased_firmament",
insns -> {
// ALOAD 0, load this
insns.add(new VarInsnNode(Opcodes.ALOAD, 0));
@@ -95,9 +107,25 @@ public class HandledScreenRiser extends RiserUtils {
});
}
+ void addMouseClicked(ClassNode classNode) {
+ addSuperInjector(
+ classNode, mouseClickedScreen.mapped(), mouseClickedScreen.mappedDesc(),
+ Screen, AbstractContainerEventHandler, "onMouseClicked$firmament",
+ insns -> {
+ // load this
+ insns.add(new VarInsnNode(Opcodes.ALOAD, 0));
+ // load mouse event
+ insns.add(new VarInsnNode(Opcodes.ALOAD, 1));
+ // load doubled
+ insns.add(new VarInsnNode(Opcodes.ILOAD, 2));
+ }
+ );
+ }
+
void addCharTyped(ClassNode classNode) {
addSuperInjector(
- classNode, charTyped.mapped(), charTyped.mappedDesc(), "charTyped_firmament",
+ classNode, charTyped.mapped(), charTyped.mappedDesc(),
+ HandledScreen, Screen, "charTyped_firmament",
insns -> {
// ALOAD 0, load this
insns.add(new VarInsnNode(Opcodes.ALOAD, 0));
@@ -110,6 +138,8 @@ public class HandledScreenRiser extends RiserUtils {
ClassNode classNode,
String name,
Type desc,
+ Intermediary.InterClass currentClass,
+ Intermediary.InterClass parentClass,
String firmamentName,
Consumer<InsnList> loadArgs
) {
@@ -125,7 +155,7 @@ public class HandledScreenRiser extends RiserUtils {
var insns = keyReleasedNode.instructions;
loadArgs.accept(insns);
// INVOKESPECIAL call super method
- insns.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, Screen.mapped().getInternalName(),
+ insns.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, parentClass.mapped().getInternalName(),
name, desc.getDescriptor()));
// IRETURN return int on stack (booleans are int at runtime)
insns.add(new InsnNode(Opcodes.IRETURN));
@@ -134,7 +164,7 @@ public class HandledScreenRiser extends RiserUtils {
insertTrueHandler(keyReleasedNode, loadArgs, insns -> {
// INVOKEVIRTUAL call custom handler
insns.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL,
- HandledScreen.mapped().getInternalName(),
+ currentClass.mapped().getInternalName(),
firmamentName,
desc.getDescriptor()));
});
@@ -143,7 +173,7 @@ public class HandledScreenRiser extends RiserUtils {
void addMouseScroll(ClassNode classNode) {
addSuperInjector(
- classNode, mouseScrolled.mapped(), mouseScrolled.mappedDesc(), "mouseScrolled_firmament",
+ classNode, mouseScrolled.mapped(), mouseScrolled.mappedDesc(), HandledScreen, Screen, "mouseScrolled_firmament",
insns -> {
// ALOAD 0, load this
insns.add(new VarInsnNode(Opcodes.ALOAD, 0));
diff --git a/src/main/java/moe/nea/firmament/mixins/MixinHandledScreen.java b/src/main/java/moe/nea/firmament/mixins/MixinHandledScreen.java
index bd2b594..c7555fb 100644
--- a/src/main/java/moe/nea/firmament/mixins/MixinHandledScreen.java
+++ b/src/main/java/moe/nea/firmament/mixins/MixinHandledScreen.java
@@ -49,24 +49,6 @@ public abstract class MixinHandledScreen<T extends AbstractContainerMenu> {
this.playerInventory = inventory;
}
- @Inject(method = "keyPressed", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/Screen;keyPressed(Lnet/minecraft/client/input/KeyEvent;)Z", shift = At.Shift.BEFORE), cancellable = true)
- public void onKeyPressed(KeyEvent input, CallbackInfoReturnable<Boolean> cir) {
- if (HandledScreenKeyPressedEvent.Companion.publish(new HandledScreenKeyPressedEvent(
- (AbstractContainerScreen<?>) (Object) this,
- GenericInputAction.of(input),
- InputModifiers.of(input))).getCancelled()) {
- cir.setReturnValue(true);
- }
- }
-
- @Inject(method = "mouseClicked", at = @At("HEAD"), cancellable = true)
- public void onMouseClicked(MouseButtonEvent click, boolean doubled, CallbackInfoReturnable<Boolean> cir) {
- if (HandledScreenKeyPressedEvent.Companion.publish(new HandledScreenKeyPressedEvent((AbstractContainerScreen<?>) (Object) this,
- GenericInputAction.mouse(click), InputModifiers.current())).getCancelled()) {
- cir.setReturnValue(true);
- }
- }
-
@Inject(method = "mouseReleased", at = @At("HEAD"), cancellable = true)
private void onMouseReleased(MouseButtonEvent click, CallbackInfoReturnable<Boolean> cir) {
var self = (AbstractContainerScreen<?>) (Object) this;
diff --git a/src/main/java/moe/nea/firmament/mixins/ScreenInputEvents.java b/src/main/java/moe/nea/firmament/mixins/ScreenInputEvents.java
new file mode 100644
index 0000000..edc8fd6
--- /dev/null
+++ b/src/main/java/moe/nea/firmament/mixins/ScreenInputEvents.java
@@ -0,0 +1,34 @@
+package moe.nea.firmament.mixins;
+
+import moe.nea.firmament.events.HandledScreenKeyPressedEvent;
+import moe.nea.firmament.keybindings.GenericInputAction;
+import moe.nea.firmament.keybindings.InputModifiers;
+import net.minecraft.client.gui.screens.Screen;
+import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
+import net.minecraft.client.input.KeyEvent;
+import net.minecraft.client.input.MouseButtonEvent;
+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.CallbackInfoReturnable;
+
+@Mixin(Screen.class)
+public class ScreenInputEvents {
+ @Inject(method = "keyPressed", at = @At("HEAD"), cancellable = true)
+ public void onKeyPressed(KeyEvent input, CallbackInfoReturnable<Boolean> cir) {
+ if (HandledScreenKeyPressedEvent.Companion.publish(new HandledScreenKeyPressedEvent(
+ (Screen) (Object) this,
+ GenericInputAction.of(input),
+ InputModifiers.of(input))).getCancelled()) {
+ cir.setReturnValue(true);
+ }
+ }
+
+ public boolean onMouseClicked$firmament(MouseButtonEvent click, boolean doubled) {
+ return HandledScreenKeyPressedEvent.Companion.publish(
+ new HandledScreenKeyPressedEvent((Screen) (Object) this,
+ GenericInputAction.mouse(click), InputModifiers.current())).getCancelled();
+ }
+
+
+}
diff --git a/src/main/kotlin/Firmament.kt b/src/main/kotlin/Firmament.kt
index 72f386d..68789f1 100644
--- a/src/main/kotlin/Firmament.kt
+++ b/src/main/kotlin/Firmament.kt
@@ -39,6 +39,7 @@ import moe.nea.firmament.events.TickEvent
import moe.nea.firmament.events.registration.registerFirmamentEvents
import moe.nea.firmament.features.FeatureManager
import moe.nea.firmament.gui.config.storage.FirmamentConfigLoader
+import moe.nea.firmament.impl.v1.FirmamentAPIImpl
import moe.nea.firmament.repo.HypixelStaticData
import moe.nea.firmament.repo.RepoManager
import moe.nea.firmament.util.MC
@@ -123,6 +124,7 @@ object Firmament {
globalJob.cancel()
})
registerFirmamentEvents()
+ FirmamentAPIImpl.loadExtensions()
ItemTooltipCallback.EVENT.register { stack, context, type, lines ->
ItemTooltipEvent.publish(ItemTooltipEvent(stack, context, type, lines))
}
diff --git a/src/main/kotlin/events/HandledScreenKeyPressedEvent.kt b/src/main/kotlin/events/HandledScreenKeyPressedEvent.kt
index b9e23a2..5a5f1e9 100644
--- a/src/main/kotlin/events/HandledScreenKeyPressedEvent.kt
+++ b/src/main/kotlin/events/HandledScreenKeyPressedEvent.kt
@@ -1,19 +1,20 @@
package moe.nea.firmament.events
import org.lwjgl.glfw.GLFW
+import net.minecraft.client.gui.screens.Screen
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen
import moe.nea.firmament.keybindings.GenericInputAction
import moe.nea.firmament.keybindings.InputModifiers
import moe.nea.firmament.keybindings.SavedKeyBinding
sealed interface HandledScreenInputEvent {
- val screen: AbstractContainerScreen<*>
+ val screen: Screen
val input: GenericInputAction
val modifiers: InputModifiers
}
data class HandledScreenKeyPressedEvent(
- override val screen: AbstractContainerScreen<*>,
+ override val screen: Screen,
override val input: GenericInputAction,
override val modifiers: InputModifiers,
// TODO: val isRepeat: Boolean,
diff --git a/src/main/kotlin/features/debug/PowerUserTools.kt b/src/main/kotlin/features/debug/PowerUserTools.kt
index 1a14f73..145ea35 100644
--- a/src/main/kotlin/features/debug/PowerUserTools.kt
+++ b/src/main/kotlin/features/debug/PowerUserTools.kt
@@ -13,6 +13,7 @@ import net.minecraft.world.item.Items
import net.minecraft.nbt.ListTag
import net.minecraft.nbt.NbtOps
import net.minecraft.advancements.critereon.NbtPredicate
+import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.ComponentSerialization
import net.minecraft.resources.ResourceLocation
@@ -202,7 +203,7 @@ object PowerUserTools {
.orThrow
ClipboardUtils.setTextContent(nbt.toPrettyString())
lastCopiedStack = Pair(item, Component.translatableEscape("firmament.tooltip.copied.stack"))
- } else if (it.matches(TConfig.copyTitle)) {
+ } else if (it.matches(TConfig.copyTitle) && it.screen is AbstractContainerScreen<*>) {
val allTitles = ListTag()
val inventoryNames =
it.screen.menu.slots
diff --git a/src/main/kotlin/features/inventory/WardrobeKeybinds.kt b/src/main/kotlin/features/inventory/WardrobeKeybinds.kt
index b3d4bfd..8d4760b 100644
--- a/src/main/kotlin/features/inventory/WardrobeKeybinds.kt
+++ b/src/main/kotlin/features/inventory/WardrobeKeybinds.kt
@@ -1,6 +1,7 @@
package moe.nea.firmament.features.inventory
import org.lwjgl.glfw.GLFW
+import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen
import net.minecraft.world.item.Items
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.HandledScreenKeyPressedEvent
@@ -29,6 +30,7 @@ object WardrobeKeybinds {
@Subscribe
fun switchSlot(event: HandledScreenKeyPressedEvent) {
if (MC.player == null || MC.world == null || MC.interactionManager == null) return
+ if (event.screen !is AbstractContainerScreen<*>) return
val regex = Regex("Wardrobe \\([12]/2\\)")
if (!regex.matches(event.screen.title.string)) return
diff --git a/src/main/kotlin/features/inventory/buttons/InventoryButtons.kt b/src/main/kotlin/features/inventory/buttons/InventoryButtons.kt
index fa376bc..eaa6138 100644
--- a/src/main/kotlin/features/inventory/buttons/InventoryButtons.kt
+++ b/src/main/kotlin/features/inventory/buttons/InventoryButtons.kt
@@ -11,6 +11,7 @@ import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.HandledScreenClickEvent
import moe.nea.firmament.events.HandledScreenForegroundEvent
import moe.nea.firmament.events.HandledScreenPushREIEvent
+import moe.nea.firmament.impl.v1.FirmamentAPIImpl
import moe.nea.firmament.util.MC
import moe.nea.firmament.util.ScreenUtil
import moe.nea.firmament.util.TimeMark
@@ -40,9 +41,11 @@ object InventoryButtons {
)
fun getValidButtons(screen: AbstractContainerScreen<*>): Sequence<InventoryButton> {
- return DConfig.data.buttons.asSequence().filter { button ->
- button.isValid() && (!TConfig.onlyInv || screen is InventoryScreen)
+ if (TConfig.onlyInv && screen !is InventoryScreen) return emptySequence()
+ if (FirmamentAPIImpl.extensions.any { it.shouldHideInventoryButtons(screen) }) {
+ return emptySequence()
}
+ return DConfig.data.buttons.asSequence().filter(InventoryButton::isValid)
}
diff --git a/src/main/kotlin/features/items/recipes/ItemSlotWidget.kt b/src/main/kotlin/features/items/recipes/ItemSlotWidget.kt
index b9832b7..c47c8ca 100644
--- a/src/main/kotlin/features/items/recipes/ItemSlotWidget.kt
+++ b/src/main/kotlin/features/items/recipes/ItemSlotWidget.kt
@@ -10,6 +10,7 @@ import net.minecraft.network.chat.Component
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.TooltipFlag
+import moe.nea.firmament.api.v1.FirmamentItemWidget
import moe.nea.firmament.events.ItemTooltipEvent
import moe.nea.firmament.keybindings.SavedKeyBinding
import moe.nea.firmament.repo.ExpensiveItemCacheApi
@@ -27,7 +28,8 @@ class ItemSlotWidget(
var content: List<SBItemStack>,
val slotKind: RecipeLayouter.SlotKind
) : RecipeWidget(),
- RecipeLayouter.CyclingItemSlot {
+ RecipeLayouter.CyclingItemSlot,
+ FirmamentItemWidget {
override var position = point
override val size get() = Dimension(16, 16)
val itemRect get() = Rectangle(position, Dimension(16, 16))
@@ -122,4 +124,17 @@ class ItemSlotWidget(
// SAFE: content was just assigned to a non-empty list
index = index.coerceIn(content.indices)
}
+
+ override fun getPlacement(): FirmamentItemWidget.Placement {
+ return FirmamentItemWidget.Placement.RECIPE_SCREEN
+ }
+
+ @OptIn(ExpensiveItemCacheApi::class)
+ override fun getItemStack(): ItemStack {
+ return current().asImmutableItemStack()
+ }
+
+ override fun getSkyBlockId(): String {
+ return current().skyblockId.neuItem
+ }
}
diff --git a/src/main/kotlin/features/items/recipes/RecipeRegistry.kt b/src/main/kotlin/features/items/recipes/RecipeRegistry.kt
index cbe1558..c2df46f 100644
--- a/src/main/kotlin/features/items/recipes/RecipeRegistry.kt
+++ b/src/main/kotlin/features/items/recipes/RecipeRegistry.kt
@@ -3,7 +3,6 @@ package moe.nea.firmament.features.items.recipes
import com.mojang.blaze3d.platform.InputConstants
import io.github.moulberry.repo.IReloadable
import io.github.moulberry.repo.NEURepository
-import net.fabricmc.fabric.mixin.client.gametest.input.InputUtilMixin
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.HandledScreenKeyPressedEvent
import moe.nea.firmament.events.ReloadRegistrationEvent
@@ -29,13 +28,19 @@ object RecipeRegistry {
@Subscribe
- fun onDebugRecipe(event: HandledScreenKeyPressedEvent) {
- if (event.matches(SavedKeyBinding.keyWithoutMods(InputConstants.KEY_R))) {
- val stack = event.screen.focusedItemStack ?: return
- val recipes = getRecipesFor(SBItemStack(stack))
- if (recipes.isEmpty()) return
- MC.screen = RecipeScreen(recipes.toList())
- }
+ fun showUsages(event: HandledScreenKeyPressedEvent) {
+ val provider =
+ if (event.matches(SavedKeyBinding.keyWithoutMods(InputConstants.KEY_R))) {
+ ::getRecipesFor
+ } else if (event.matches(SavedKeyBinding.keyWithoutMods(InputConstants.KEY_U))) {
+ ::getUsagesFor
+ } else {
+ return
+ }
+ val stack = event.screen.focusedItemStack ?: return
+ val recipes = provider(SBItemStack(stack))
+ if (recipes.isEmpty()) return
+ MC.screen = RecipeScreen(recipes.toList())
}
diff --git a/src/main/kotlin/features/items/recipes/RecipeWidget.kt b/src/main/kotlin/features/items/recipes/RecipeWidget.kt
index 5884129..b0591b2 100644
--- a/src/main/kotlin/features/items/recipes/RecipeWidget.kt
+++ b/src/main/kotlin/features/items/recipes/RecipeWidget.kt
@@ -34,4 +34,8 @@ abstract class RecipeWidget : GuiEventListener, Renderable, NarratableEntry {
override fun isFocused(): Boolean {
return this._focused
}
+
+ override fun isMouseOver(mouseX: Double, mouseY: Double): Boolean {
+ return rect.contains(mouseX, mouseY)
+ }
}
diff --git a/src/main/kotlin/impl/v1/FirmamentAPIImpl.kt b/src/main/kotlin/impl/v1/FirmamentAPIImpl.kt
new file mode 100644
index 0000000..d5fc0de
--- /dev/null
+++ b/src/main/kotlin/impl/v1/FirmamentAPIImpl.kt
@@ -0,0 +1,48 @@
+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 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.util.MC
+import moe.nea.firmament.util.intoOptional
+
+object FirmamentAPIImpl : FirmamentAPI() {
+ @JvmField
+ val INSTANCE: FirmamentAPI = FirmamentAPIImpl
+
+ private val _extensions = mutableListOf<FirmamentExtension>()
+ override fun getExtensions(): List<FirmamentExtension> {
+ return Collections.unmodifiableList(_extensions)
+ }
+
+ override fun getHoveredItemWidget(): Optional<FirmamentItemWidget> {
+ val mouse = MC.instance.mouseHandler
+ val window = MC.window
+ val xpos = mouse.getScaledXPos(window)
+ val ypos = mouse.getScaledYPos(window)
+ val widget = MC.screen
+ ?.getChildAt(xpos, ypos)
+ ?.getOrNull()
+ if (widget is FirmamentItemWidget) return widget.intoOptional()
+ return Optional.empty()
+ }
+
+ fun loadExtensions() {
+ for (container in FabricLoader.getInstance()
+ .getEntrypointContainers("firmament:v1", FirmamentExtension::class.java)) {
+ Firmament.logger.info("Loading extension ${container.entrypoint} from ${container.provider.metadata.name}")
+ loadExtension(container.entrypoint)
+ }
+ extensions.forEach { it.onLoad() }
+ }
+
+ fun loadExtension(entrypoint: FirmamentExtension) {
+ _extensions.add(entrypoint)
+ }
+}
diff --git a/src/main/kotlin/util/HoveredItemStack.kt b/src/main/kotlin/util/HoveredItemStack.kt
index c8d33fd..91202dd 100644
--- a/src/main/kotlin/util/HoveredItemStack.kt
+++ b/src/main/kotlin/util/HoveredItemStack.kt
@@ -1,13 +1,16 @@
package moe.nea.firmament.util
import com.google.auto.service.AutoService
+import kotlin.jvm.optionals.getOrNull
+import net.minecraft.client.gui.screens.Screen
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen
import net.minecraft.world.item.ItemStack
+import moe.nea.firmament.api.v1.FirmamentAPI
import moe.nea.firmament.mixins.accessor.AccessorHandledScreen
import moe.nea.firmament.util.compatloader.CompatLoader
interface HoveredItemStackProvider : Comparable<HoveredItemStackProvider> {
- fun provideHoveredItemStack(screen: AbstractContainerScreen<*>): ItemStack?
+ fun provideHoveredItemStack(screen: Screen): ItemStack?
override fun compareTo(other: HoveredItemStackProvider): Int {
return compareValues(this.prio, other.prio)
}
@@ -22,8 +25,8 @@ interface HoveredItemStackProvider : Comparable<HoveredItemStackProvider> {
@AutoService(HoveredItemStackProvider::class)
class VanillaScreenProvider : HoveredItemStackProvider {
- override fun provideHoveredItemStack(screen: AbstractContainerScreen<*>): ItemStack? {
- screen as AccessorHandledScreen
+ override fun provideHoveredItemStack(screen: Screen): ItemStack? {
+ if (screen !is AccessorHandledScreen) return null
val vanillaSlot = screen.focusedSlot_Firmament?.item
return vanillaSlot
}
@@ -32,7 +35,17 @@ class VanillaScreenProvider : HoveredItemStackProvider {
get() = -1
}
-val AbstractContainerScreen<*>.focusedItemStack: ItemStack?
+@AutoService(HoveredItemStackProvider::class)
+class FirmamentStackScreenProvider : HoveredItemStackProvider {
+ override fun provideHoveredItemStack(screen: Screen): ItemStack? {
+ return FirmamentAPI.getInstance()
+ .hoveredItemWidget
+ .getOrNull()
+ ?.itemStack
+ }
+}
+
+val Screen.focusedItemStack: ItemStack?
get() =
HoveredItemStackProvider.sorted
.firstNotNullOfOrNull { it.provideHoveredItemStack(this)?.takeIf { !it.isEmpty } }