diff options
| author | Linnea Gräf <nea@nea.moe> | 2025-09-17 22:24:09 +0200 |
|---|---|---|
| committer | Linnea Gräf <nea@nea.moe> | 2025-09-17 22:32:13 +0200 |
| commit | 21817efdfe62135704571908b9f72ed3ace4bdf1 (patch) | |
| tree | 3bf6df2ae75f2c3029b2dd0c192244a8b8b98a9a | |
| parent | d65824989ac32c7c5ee5ba2957f3cc76c76546b9 (diff) | |
| download | Firmament-21817efdfe62135704571908b9f72ed3ace4bdf1.tar.gz Firmament-21817efdfe62135704571908b9f72ed3ace4bdf1.tar.bz2 Firmament-21817efdfe62135704571908b9f72ed3ace4bdf1.zip | |
feat: add sign text & background movers
6 files changed, 128 insertions, 7 deletions
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 707add4..a37c54c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -67,7 +67,7 @@ neurepoparser = "1.8.0" hotswap_agent = "1.4.2-SNAPSHOT" # Update from https://github.com/LlamaLad7/MixinExtras/tags -mixinextras = "0.4.1" +mixinextras = "0.5.0" # Update from https://repo.nea.moe/#/releases/moe/nea/jarvis/ jarvis = "2.0.0" diff --git a/src/main/java/moe/nea/firmament/mixins/accessor/AccessorScreenHandler.java b/src/main/java/moe/nea/firmament/mixins/accessor/AccessorScreenHandler.java new file mode 100644 index 0000000..a022d8e --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/accessor/AccessorScreenHandler.java @@ -0,0 +1,12 @@ +package moe.nea.firmament.mixins.accessor; + +import net.minecraft.screen.ScreenHandler; +import net.minecraft.screen.ScreenHandlerType; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(ScreenHandler.class) +public interface AccessorScreenHandler { + @Accessor("type") + ScreenHandlerType<?> getType_firmament(); +} diff --git a/src/main/resources/firmament.mixins.json b/src/main/resources/firmament.mixins.json index d78d124..c3392a6 100644 --- a/src/main/resources/firmament.mixins.json +++ b/src/main/resources/firmament.mixins.json @@ -4,6 +4,9 @@ "package": "moe.nea.firmament.mixins", "compatibilityLevel": "JAVA_21", "refmap": "Firmament-refmap.json", + "mixinextras": { + "minVersion": "0.5.0" + }, "injectors": { "defaultRequire": 1 } 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 69a1c7e..3554372 100644 --- a/src/texturePacks/java/moe/nea/firmament/features/texturepack/CustomScreenLayouts.kt +++ b/src/texturePacks/java/moe/nea/firmament/features/texturepack/CustomScreenLayouts.kt @@ -7,11 +7,15 @@ import net.minecraft.client.font.TextRenderer import net.minecraft.client.gl.RenderPipelines import net.minecraft.client.gui.DrawContext import net.minecraft.client.gui.screen.Screen +import net.minecraft.client.gui.screen.ingame.AbstractSignEditScreen import net.minecraft.client.gui.screen.ingame.HandledScreen +import net.minecraft.client.gui.screen.ingame.HangingSignEditScreen +import net.minecraft.client.gui.screen.ingame.SignEditScreen import net.minecraft.client.render.RenderLayer import net.minecraft.registry.Registries import net.minecraft.resource.ResourceManager import net.minecraft.resource.SinglePreparationResourceReloader +import net.minecraft.screen.ScreenHandler import net.minecraft.screen.slot.Slot import net.minecraft.text.Text import net.minecraft.util.Identifier @@ -24,6 +28,7 @@ import moe.nea.firmament.features.texturepack.CustomScreenLayouts.Alignment.CENT import moe.nea.firmament.features.texturepack.CustomScreenLayouts.Alignment.LEFT import moe.nea.firmament.features.texturepack.CustomScreenLayouts.Alignment.RIGHT 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 @@ -38,7 +43,13 @@ object CustomScreenLayouts : SinglePreparationResourceReloader<List<CustomScreen val containerTitle: TitleReplacer? = null, val repairCostTitle: TitleReplacer? = null, val nameField: ComponentMover? = null, - ) + val signLines: List<ComponentMover>? = null, + ) { + init { + if (signLines != null) + require(signLines.size == 4) + } + } @Serializable data class ComponentMover( @@ -56,11 +67,17 @@ object CustomScreenLayouts : SinglePreparationResourceReloader<List<CustomScreen ) { fun matches(screen: Screen): Boolean { // TODO: does this deserve the restriction to handled screen - val s = screen as? HandledScreen<*>? ?: return false - val typeMatches = screenType == null || s.screenHandler.type.equals(Registries.SCREEN_HANDLER - .get(screenType)); + val type = when (screen) { + is HandledScreen<*> -> (screen.screenHandler as AccessorScreenHandler).type_firmament?.let { + Registries.SCREEN_HANDLER.getId(it) + } - return label.matches(s.title) && typeMatches + is HangingSignEditScreen -> Identifier.of("firmskyblock", "hanging_sign") + is SignEditScreen -> Identifier.of("firmskyblock", "sign") + else -> null + } + val typeMatches = screenType == null || type == screenType; + return label.matches(screen.title) && typeMatches } } @@ -74,6 +91,16 @@ object CustomScreenLayouts : SinglePreparationResourceReloader<List<CustomScreen val width: Int, val height: Int, ) { + fun renderDirect(context: DrawContext) { + context.drawTexture( + RenderPipelines.GUI_TEXTURED, + this.texture, + this.x, this.y, + 0F, 0F, + this.width, this.height, this.width, this.height, + ) + } + fun renderGeneric(context: DrawContext, screen: HandledScreen<*>) { screen as AccessorHandledScreen val originalX: Int = (screen.width - screen.backgroundWidth_Firmament) / 2 @@ -197,10 +224,14 @@ object CustomScreenLayouts : SinglePreparationResourceReloader<List<CustomScreen val DO_NOTHING_TEXT_REPLACER = TitleReplacer() @JvmStatic - fun <T>getMover(selector: (CustomScreenLayout)-> (T?)) = + fun <T> getMover(selector: (CustomScreenLayout) -> (T?)) = activeScreenOverride?.let(selector) @JvmStatic + fun getSignTextMover(index: Int) = + getMover { it.signLines?.get(index) } + + @JvmStatic fun getTextMover(selector: (CustomScreenLayout) -> (TitleReplacer?)) = getMover(selector) ?: DO_NOTHING_TEXT_REPLACER diff --git a/src/texturePacks/java/moe/nea/firmament/mixins/custommodels/screenlayouts/MoveSignElements.java b/src/texturePacks/java/moe/nea/firmament/mixins/custommodels/screenlayouts/MoveSignElements.java new file mode 100644 index 0000000..916a877 --- /dev/null +++ b/src/texturePacks/java/moe/nea/firmament/mixins/custommodels/screenlayouts/MoveSignElements.java @@ -0,0 +1,70 @@ +package moe.nea.firmament.mixins.custommodels.screenlayouts; + +import com.llamalad7.mixinextras.expression.Definition; +import com.llamalad7.mixinextras.expression.Expression; +import com.llamalad7.mixinextras.injector.v2.WrapWithCondition; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.llamalad7.mixinextras.sugar.Local; +import com.llamalad7.mixinextras.sugar.Share; +import moe.nea.firmament.features.texturepack.CustomScreenLayouts; +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.ingame.AbstractSignEditScreen; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(AbstractSignEditScreen.class) +public class MoveSignElements { + @WrapWithCondition( + method = "renderSign", + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/ingame/AbstractSignEditScreen;renderSignBackground(Lnet/minecraft/client/gui/DrawContext;)V")) + private boolean onDrawBackgroundSign(AbstractSignEditScreen instance, DrawContext drawContext) { + final var override = CustomScreenLayouts.getActiveScreenOverride(); + if (override == null || override.getBackground() == null) return true; + override.getBackground().renderDirect(drawContext); + return false; + } + + @WrapOperation(method = "renderSignText", at = { + @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;drawSelection(IIII)V")} + ) + private void onRenderSignTextSelection( + DrawContext instance, int x1, int y1, int x2, int y2, Operation<Void> original, + @Local(index = 9) int messageIndex) { + instance.getMatrices().pushMatrix(); + final var override = CustomScreenLayouts.getSignTextMover(messageIndex); + if (override != null) { + instance.getMatrices().translate(override.getX(), override.getY()); + } + original.call(instance, x1, y1, x2, y2); + instance.getMatrices().popMatrix(); + } + @WrapOperation(method = "renderSignText", at = { + @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;fill(IIIII)V")} + ) + private void onRenderSignTextFill( + DrawContext instance, int x1, int y1, int x2, int y2, int color, Operation<Void> original, @Local(index = 9) int messageIndex) { + instance.getMatrices().pushMatrix(); + final var override = CustomScreenLayouts.getSignTextMover(messageIndex); + if (override != null) { + instance.getMatrices().translate(override.getX(), override.getY()); + } + original.call(instance, x1, y1, x2, y2, color); + instance.getMatrices().popMatrix(); + } + + @WrapOperation(method = "renderSignText", at = { + @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;drawText(Lnet/minecraft/client/font/TextRenderer;Ljava/lang/String;IIIZ)V")}, + expect = 2) + private void onRenderSignTextRendering(DrawContext instance, TextRenderer textRenderer, String text, int x, int y, int color, boolean shadow, Operation<Void> original, @Local(index = 9) int messageIndex) { + instance.getMatrices().pushMatrix(); + final var override = CustomScreenLayouts.getSignTextMover(messageIndex); + if (override != null) { + instance.getMatrices().translate(override.getX(), override.getY()); + } + original.call(instance, textRenderer, text, x, y, color, shadow); + instance.getMatrices().popMatrix(); + } + +} diff --git a/web/src/pages/docs/_texture-pack-format.md b/web/src/pages/docs/_texture-pack-format.md index 26274c2..8cbedbf 100644 --- a/web/src/pages/docs/_texture-pack-format.md +++ b/web/src/pages/docs/_texture-pack-format.md @@ -596,6 +596,8 @@ The `label` property is a regular [string matcher](#string-matcher) and matches The `screenType` property is an optional namespaced identifier that allows matching to a [screen type](https://minecraft.wiki/w/Java_Edition_protocol/Inventory#Types). +Signs can be targeted using `firmskyblock:sign` and `firmskyblock:hanging_sign`. + ### Changing the background ```json @@ -617,6 +619,8 @@ The `screenType` property is an optional namespaced identifier that allows match You need to specify an x and y offset relative to where the regular screen would render. This means you just check where the upper left corner of the UI texture would be in your texture (and turn it into a negative number). You also need to specify a width and height of your texture. This is the width in pixels rendered. If you want a higher or lower resolution texture, you can scale the actual texture up (tho it is expected to meet the same aspect ratio as the one defined here). +Signs do not have a regular origin and are instead anchored from the top-middle of the sign. + ### Moving slots around ```json @@ -691,6 +695,7 @@ Some other components can also be moved. These components might be buttons, text Available options - `nameField`: x, y, width & height are all available to move the field to set the name of the item in an anvil. +- `signLines[]`: x, y, are available to move the text relative to where it would render normally. Must be an array of 4 component movers. ### All together |
