aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/kotlin/util/ErrorUtil.kt7
-rw-r--r--src/texturePacks/java/moe/nea/firmament/features/texturepack/CustomScreenLayouts.kt142
-rw-r--r--src/texturePacks/java/moe/nea/firmament/features/texturepack/CustomSkyBlockTextures.kt1
-rw-r--r--src/texturePacks/java/moe/nea/firmament/features/texturepack/CustomTextColors.kt14
-rw-r--r--src/texturePacks/java/moe/nea/firmament/mixins/custommodels/screenlayouts/ReplaceFurnaceBackgrounds.java32
-rw-r--r--src/texturePacks/java/moe/nea/firmament/mixins/custommodels/screenlayouts/ReplaceGenericBackgrounds.java29
-rw-r--r--src/texturePacks/java/moe/nea/firmament/mixins/custommodels/screenlayouts/ReplacePlayerBackgrounds.java34
7 files changed, 258 insertions, 1 deletions
diff --git a/src/main/kotlin/util/ErrorUtil.kt b/src/main/kotlin/util/ErrorUtil.kt
index 2f0acd6..f12bb12 100644
--- a/src/main/kotlin/util/ErrorUtil.kt
+++ b/src/main/kotlin/util/ErrorUtil.kt
@@ -37,6 +37,13 @@ object ErrorUtil {
else Firmament.logger.error(message)
}
+ fun <T> Result<T>.intoCatch(message: String): Catch<T> {
+ return this.map { Catch.succeed(it) }.getOrElse {
+ softError(message, it)
+ Catch.fail(it)
+ }
+ }
+
class Catch<T> private constructor(val value: T?, val exc: Throwable?) {
fun orNull(): T? = value
diff --git a/src/texturePacks/java/moe/nea/firmament/features/texturepack/CustomScreenLayouts.kt b/src/texturePacks/java/moe/nea/firmament/features/texturepack/CustomScreenLayouts.kt
new file mode 100644
index 0000000..ec696ec
--- /dev/null
+++ b/src/texturePacks/java/moe/nea/firmament/features/texturepack/CustomScreenLayouts.kt
@@ -0,0 +1,142 @@
+package moe.nea.firmament.features.texturepack
+
+import kotlinx.serialization.Serializable
+import net.minecraft.client.gui.DrawContext
+import net.minecraft.client.gui.screen.Screen
+import net.minecraft.client.gui.screen.ingame.HandledScreen
+import net.minecraft.client.render.RenderLayer
+import net.minecraft.resource.ResourceManager
+import net.minecraft.resource.SinglePreparationResourceReloader
+import net.minecraft.screen.slot.Slot
+import net.minecraft.util.Identifier
+import net.minecraft.util.profiler.Profiler
+import moe.nea.firmament.Firmament
+import moe.nea.firmament.annotations.Subscribe
+import moe.nea.firmament.events.FinalizeResourceManagerEvent
+import moe.nea.firmament.events.ScreenChangeEvent
+import moe.nea.firmament.mixins.accessor.AccessorHandledScreen
+import moe.nea.firmament.util.ErrorUtil.intoCatch
+import moe.nea.firmament.util.IdentifierSerializer
+
+object CustomScreenLayouts : SinglePreparationResourceReloader<List<CustomScreenLayouts.CustomScreenLayout>>() {
+
+ @Serializable
+ data class CustomScreenLayout(
+ val predicates: Preds,
+ val background: BackgroundReplacer? = null,
+ val slots: List<SlotReplacer> = listOf(),
+ )
+
+ @Serializable
+ data class Preds(
+ val label: StringMatcher,
+ ) {
+ fun matches(screen: Screen): Boolean {
+ // TODO: does this deserve the restriction to handled screen
+ val s = screen as? HandledScreen<*>? ?: return false
+ return label.matches(s.title)
+ }
+ }
+
+ @Serializable
+ data class BackgroundReplacer(
+ @Serializable(with = IdentifierSerializer::class)
+ val texture: Identifier,
+ // TODO: allow selectively still rendering some components (recipe button, trade backgrounds, furnace flame progress, arrows)
+ val x: Int,
+ val y: Int,
+ val width: Int,
+ val height: Int,
+ ) {
+ fun renderGeneric(context: DrawContext, screen: HandledScreen<*>) {
+ screen as AccessorHandledScreen
+ val originalX: Int = (screen.width - screen.backgroundWidth_Firmament) / 2
+ val originalY: Int = (screen.height - screen.backgroundHeight_Firmament) / 2
+ val modifiedX = originalX + this.x
+ val modifiedY = originalY + this.y
+ val textureWidth = this.width
+ val textureHeight = this.height
+ context.drawTexture(
+ RenderLayer::getGuiTextured,
+ this.texture,
+ modifiedX,
+ modifiedY,
+ 0.0f,
+ 0.0f,
+ textureWidth,
+ textureHeight,
+ textureWidth,
+ textureHeight
+ )
+
+ }
+ }
+
+ @Serializable
+ data class SlotReplacer(
+ // TODO: override getRecipeBookButtonPos as well
+ // TODO: is this index or id (i always forget which one is duplicated per inventory)
+ val index: Int,
+ val x: Int,
+ val y: Int,
+ ) {
+ fun move(slots: List<Slot>) {
+ val slot = slots.getOrNull(index) ?: return
+ slot.x = x
+ slot.y = y
+ }
+ }
+
+
+ @Subscribe
+ fun onStart(event: FinalizeResourceManagerEvent) {
+ event.resourceManager.registerReloader(CustomScreenLayouts)
+ }
+
+ override fun prepare(
+ manager: ResourceManager,
+ profiler: Profiler
+ ): List<CustomScreenLayout> {
+ val allScreenLayouts = manager.findResources(
+ "overrides/screen_layout",
+ { it.path.endsWith(".json") && it.namespace == "firmskyblock" })
+ val allParsedLayouts = allScreenLayouts.mapNotNull { (path, stream) ->
+ Firmament.tryDecodeJsonFromStream<CustomScreenLayout>(stream.inputStream)
+ .intoCatch("Could not read custom screen layout from $path").orNull()
+ }
+ return allParsedLayouts
+ }
+
+ var customScreenLayouts = listOf<CustomScreenLayout>()
+
+ override fun apply(
+ prepared: List<CustomScreenLayout>,
+ manager: ResourceManager?,
+ profiler: Profiler?
+ ) {
+ this.customScreenLayouts = prepared
+ }
+
+ @get:JvmStatic
+ var activeScreenOverride = null as CustomScreenLayout?
+
+ @Subscribe
+ fun onScreenOpen(event: ScreenChangeEvent) {
+ if (!CustomSkyBlockTextures.TConfig.allowLayoutChanges) {
+ activeScreenOverride = null
+ return
+ }
+ activeScreenOverride = event.new?.let { screen ->
+ customScreenLayouts.find { it.predicates.matches(screen) }
+ }
+
+ val screen = event.new as? HandledScreen<*> ?: return
+ val handler = screen.screenHandler
+ activeScreenOverride?.let { override ->
+ override.slots.forEach { slotReplacer ->
+ slotReplacer.move(handler.slots)
+ }
+ }
+ }
+
+}
diff --git a/src/texturePacks/java/moe/nea/firmament/features/texturepack/CustomSkyBlockTextures.kt b/src/texturePacks/java/moe/nea/firmament/features/texturepack/CustomSkyBlockTextures.kt
index cf2a232..18949ff 100644
--- a/src/texturePacks/java/moe/nea/firmament/features/texturepack/CustomSkyBlockTextures.kt
+++ b/src/texturePacks/java/moe/nea/firmament/features/texturepack/CustomSkyBlockTextures.kt
@@ -36,6 +36,7 @@ object CustomSkyBlockTextures : FirmamentFeature {
val enableLegacyMinecraftCompat by toggle("legacy-minecraft-path-support") { true }
val enableLegacyCIT by toggle("legacy-cit") { true }
val allowRecoloringUiText by toggle("recolor-text") { true }
+ val allowLayoutChanges by toggle("screen-layouts") { true }
}
override val config: ManagedConfig
diff --git a/src/texturePacks/java/moe/nea/firmament/features/texturepack/CustomTextColors.kt b/src/texturePacks/java/moe/nea/firmament/features/texturepack/CustomTextColors.kt
index 4ca1796..1fcee48 100644
--- a/src/texturePacks/java/moe/nea/firmament/features/texturepack/CustomTextColors.kt
+++ b/src/texturePacks/java/moe/nea/firmament/features/texturepack/CustomTextColors.kt
@@ -2,6 +2,7 @@ package moe.nea.firmament.features.texturepack
import java.util.Optional
import kotlinx.serialization.Serializable
+import kotlinx.serialization.Transient
import kotlin.jvm.optionals.getOrNull
import net.minecraft.resource.ResourceManager
import net.minecraft.resource.SinglePreparationResourceReloader
@@ -18,12 +19,23 @@ object CustomTextColors : SinglePreparationResourceReloader<CustomTextColors.Tex
data class TextOverrides(
val defaultColor: Int,
val overrides: List<TextOverride> = listOf()
- )
+ ) {
+ /**
+ * Stub custom text color to allow always returning a text override
+ */
+ @Transient
+ val baseOverride = TextOverride(
+ StringMatcher.Equals("", false),
+ defaultColor,
+ false
+ )
+ }
@Serializable
data class TextOverride(
val predicate: StringMatcher,
val override: Int,
+ val hidden: Boolean = false,
)
@Subscribe
diff --git a/src/texturePacks/java/moe/nea/firmament/mixins/custommodels/screenlayouts/ReplaceFurnaceBackgrounds.java b/src/texturePacks/java/moe/nea/firmament/mixins/custommodels/screenlayouts/ReplaceFurnaceBackgrounds.java
new file mode 100644
index 0000000..2252a96
--- /dev/null
+++ b/src/texturePacks/java/moe/nea/firmament/mixins/custommodels/screenlayouts/ReplaceFurnaceBackgrounds.java
@@ -0,0 +1,32 @@
+package moe.nea.firmament.mixins.custommodels.screenlayouts;
+
+import com.llamalad7.mixinextras.injector.v2.WrapWithCondition;
+import moe.nea.firmament.features.texturepack.CustomScreenLayouts;
+import net.minecraft.client.gui.DrawContext;
+import net.minecraft.client.gui.screen.ingame.AbstractFurnaceScreen;
+import net.minecraft.client.gui.screen.ingame.RecipeBookScreen;
+import net.minecraft.client.gui.screen.recipebook.RecipeBookWidget;
+import net.minecraft.client.render.RenderLayer;
+import net.minecraft.entity.player.PlayerInventory;
+import net.minecraft.screen.AbstractFurnaceScreenHandler;
+import net.minecraft.text.Text;
+import net.minecraft.util.Identifier;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+
+import java.util.function.Function;
+
+@Mixin(AbstractFurnaceScreen.class)
+public abstract class ReplaceFurnaceBackgrounds<T extends AbstractFurnaceScreenHandler> extends RecipeBookScreen<T> {
+ public ReplaceFurnaceBackgrounds(T handler, RecipeBookWidget<?> recipeBook, PlayerInventory inventory, Text title) {
+ super(handler, recipeBook, inventory, title);
+ }
+
+ @WrapWithCondition(method = "drawBackground", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;drawTexture(Ljava/util/function/Function;Lnet/minecraft/util/Identifier;IIFFIIII)V"), allow = 1)
+ private boolean onDrawBackground(DrawContext instance, Function<Identifier, RenderLayer> renderLayers, Identifier sprite, int x, int y, float u, float v, int width, int height, int textureWidth, int textureHeight) {
+ final var override = CustomScreenLayouts.getActiveScreenOverride();
+ if (override == null || override.getBackground() == null) return true;
+ override.getBackground().renderGeneric(instance, this);
+ return false;
+ }
+}
diff --git a/src/texturePacks/java/moe/nea/firmament/mixins/custommodels/screenlayouts/ReplaceGenericBackgrounds.java b/src/texturePacks/java/moe/nea/firmament/mixins/custommodels/screenlayouts/ReplaceGenericBackgrounds.java
new file mode 100644
index 0000000..d33de91
--- /dev/null
+++ b/src/texturePacks/java/moe/nea/firmament/mixins/custommodels/screenlayouts/ReplaceGenericBackgrounds.java
@@ -0,0 +1,29 @@
+package moe.nea.firmament.mixins.custommodels.screenlayouts;
+
+
+import moe.nea.firmament.features.texturepack.CustomScreenLayouts;
+import net.minecraft.client.gui.DrawContext;
+import net.minecraft.client.gui.screen.ingame.*;
+import net.minecraft.entity.player.PlayerInventory;
+import net.minecraft.screen.ScreenHandler;
+import net.minecraft.text.Text;
+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({CraftingScreen.class, CrafterScreen.class, Generic3x3ContainerScreen.class, GenericContainerScreen.class, HopperScreen.class, ShulkerBoxScreen.class,})
+public abstract class ReplaceGenericBackgrounds extends HandledScreen<ScreenHandler> {
+ // TODO: split out screens with special background components like flames, arrows, etc. (maybe arrows deserve generic handling tho)
+ public ReplaceGenericBackgrounds(ScreenHandler handler, PlayerInventory inventory, Text title) {
+ super(handler, inventory, title);
+ }
+
+ @Inject(method = "drawBackground", at = @At("HEAD"), cancellable = true)
+ private void replaceDrawBackground(DrawContext context, float deltaTicks, int mouseX, int mouseY, CallbackInfo ci) {
+ final var override = CustomScreenLayouts.getActiveScreenOverride();
+ if (override == null || override.getBackground() == null) return;
+ override.getBackground().renderGeneric(context, this);
+ ci.cancel();
+ }
+}
diff --git a/src/texturePacks/java/moe/nea/firmament/mixins/custommodels/screenlayouts/ReplacePlayerBackgrounds.java b/src/texturePacks/java/moe/nea/firmament/mixins/custommodels/screenlayouts/ReplacePlayerBackgrounds.java
new file mode 100644
index 0000000..a20dc61
--- /dev/null
+++ b/src/texturePacks/java/moe/nea/firmament/mixins/custommodels/screenlayouts/ReplacePlayerBackgrounds.java
@@ -0,0 +1,34 @@
+package moe.nea.firmament.mixins.custommodels.screenlayouts;
+
+
+import com.llamalad7.mixinextras.injector.v2.WrapWithCondition;
+import moe.nea.firmament.features.texturepack.CustomScreenLayouts;
+import net.minecraft.client.gui.DrawContext;
+import net.minecraft.client.gui.screen.ingame.InventoryScreen;
+import net.minecraft.client.gui.screen.ingame.RecipeBookScreen;
+import net.minecraft.client.gui.screen.recipebook.RecipeBookWidget;
+import net.minecraft.client.render.RenderLayer;
+import net.minecraft.entity.player.PlayerInventory;
+import net.minecraft.screen.PlayerScreenHandler;
+import net.minecraft.text.Text;
+import net.minecraft.util.Identifier;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+
+import java.util.function.Function;
+
+@Mixin(InventoryScreen.class)
+public abstract class ReplacePlayerBackgrounds extends RecipeBookScreen<PlayerScreenHandler> {
+ public ReplacePlayerBackgrounds(PlayerScreenHandler handler, RecipeBookWidget<?> recipeBook, PlayerInventory inventory, Text title) {
+ super(handler, recipeBook, inventory, title);
+ }
+
+ @WrapWithCondition(method = "drawBackground", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;drawTexture(Ljava/util/function/Function;Lnet/minecraft/util/Identifier;IIFFIIII)V"))
+ private boolean onDrawBackground(DrawContext instance, Function<Identifier, RenderLayer> renderLayers, Identifier sprite, int x, int y, float u, float v, int width, int height, int textureWidth, int textureHeight) {
+ final var override = CustomScreenLayouts.getActiveScreenOverride();
+ if (override == null || override.getBackground() == null) return true;
+ override.getBackground().renderGeneric(instance, this);
+ return false;
+ }
+ // TODO: allow moving the player
+}