aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinnea Gräf <nea@nea.moe>2025-09-17 22:24:09 +0200
committerLinnea Gräf <nea@nea.moe>2025-09-17 22:32:13 +0200
commit21817efdfe62135704571908b9f72ed3ace4bdf1 (patch)
tree3bf6df2ae75f2c3029b2dd0c192244a8b8b98a9a
parentd65824989ac32c7c5ee5ba2957f3cc76c76546b9 (diff)
downloadFirmament-21817efdfe62135704571908b9f72ed3ace4bdf1.tar.gz
Firmament-21817efdfe62135704571908b9f72ed3ace4bdf1.tar.bz2
Firmament-21817efdfe62135704571908b9f72ed3ace4bdf1.zip
feat: add sign text & background movers
-rw-r--r--gradle/libs.versions.toml2
-rw-r--r--src/main/java/moe/nea/firmament/mixins/accessor/AccessorScreenHandler.java12
-rw-r--r--src/main/resources/firmament.mixins.json3
-rw-r--r--src/texturePacks/java/moe/nea/firmament/features/texturepack/CustomScreenLayouts.kt43
-rw-r--r--src/texturePacks/java/moe/nea/firmament/mixins/custommodels/screenlayouts/MoveSignElements.java70
-rw-r--r--web/src/pages/docs/_texture-pack-format.md5
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