From 0aacb6b965852647fde85045882b6aa6cf58c287 Mon Sep 17 00:00:00 2001 From: nea Date: Tue, 25 Jul 2023 17:34:07 +0200 Subject: Add custom texture pack support --- build.gradle.kts | 6 ++- gradle/libs.versions.toml | 2 +- .../moe/nea/firmament/mixins/MixinItemModels.java | 27 +++++++++++++ .../moe/nea/firmament/mixins/MixinModelLoader.java | 44 ++++++++++++++++++++++ .../nea/firmament/events/CustomItemModelEvent.kt | 41 ++++++++++++++++++++ .../moe/nea/firmament/features/FeatureManager.kt | 2 + .../features/texturepack/CustomSkyBlockTextures.kt | 35 +++++++++++++++++ .../resources/assets/firmament/lang/en_us.json | 5 ++- src/main/resources/firmament.accesswidener | 3 +- 9 files changed, 161 insertions(+), 4 deletions(-) create mode 100644 src/main/java/moe/nea/firmament/mixins/MixinItemModels.java create mode 100644 src/main/java/moe/nea/firmament/mixins/MixinModelLoader.java create mode 100644 src/main/kotlin/moe/nea/firmament/events/CustomItemModelEvent.kt create mode 100644 src/main/kotlin/moe/nea/firmament/features/texturepack/CustomSkyBlockTextures.kt diff --git a/build.gradle.kts b/build.gradle.kts index 3690850..4ba4406 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -10,7 +10,7 @@ plugins { id("dev.architectury.loom") version "1.1.336" id("com.github.johnrengelman.shadow") version "7.1.2" id("moe.nea.licenseextractificator") - id("io.github.juuxel.loom-quiltflower") version "1.10.0" + id("io.github.juuxel.loom-vineflower") version "1.11.0" id("io.shcm.shsupercm.fabric.fletchingtable") version "1.5" } @@ -210,3 +210,7 @@ tasks.create("printAllLicenses", LicenseDiscoveryTask::class.java, licensing).ap licensing.addExtraLicenseMatchers() fletchingTable.defaultMixinEnvironment.set("client") + +vineflower { + toolVersion.set("1.9.1") +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fab9d1e..a7d1f84 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -19,7 +19,7 @@ sodium = "mc1.20-0.4.10" freecammod = "1.2.0-mc1.20" ncr = "Fabric-1.20-v2.2.0" mixinextras = "0.2.0-beta.9" -jarvis = "1.1.0" +jarvis = "1.0.0" [libraries] diff --git a/src/main/java/moe/nea/firmament/mixins/MixinItemModels.java b/src/main/java/moe/nea/firmament/mixins/MixinItemModels.java new file mode 100644 index 0000000..2c2cc31 --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/MixinItemModels.java @@ -0,0 +1,27 @@ +package moe.nea.firmament.mixins; + +import moe.nea.firmament.events.CustomItemModelEvent; +import net.minecraft.client.render.item.ItemModels; +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.render.model.BakedModelManager; +import net.minecraft.item.ItemStack; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(ItemModels.class) +public class MixinItemModels { + @Shadow + @Final + private BakedModelManager modelManager; + + @Inject(method = "getModel(Lnet/minecraft/item/ItemStack;)Lnet/minecraft/client/render/model/BakedModel;", at = @At("HEAD"), cancellable = true) + public void onGetModel(ItemStack stack, CallbackInfoReturnable cir) { + var model = CustomItemModelEvent.getModel(stack, modelManager); + if (model != null) + cir.setReturnValue(model); + } +} diff --git a/src/main/java/moe/nea/firmament/mixins/MixinModelLoader.java b/src/main/java/moe/nea/firmament/mixins/MixinModelLoader.java new file mode 100644 index 0000000..8d43083 --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/MixinModelLoader.java @@ -0,0 +1,44 @@ +package moe.nea.firmament.mixins; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.model.ModelLoader; +import net.minecraft.client.render.model.UnbakedModel; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.util.ModelIdentifier; +import net.minecraft.client.util.SpriteIdentifier; +import net.minecraft.resource.Resource; +import net.minecraft.util.Identifier; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.Map; +import java.util.function.BiFunction; + +@Mixin(ModelLoader.class) +public abstract class MixinModelLoader { + + @Shadow + protected abstract void addModel(ModelIdentifier modelId); + + @Shadow + @Final + private Map modelsToBake; + + @Shadow + public abstract UnbakedModel getOrLoadModel(Identifier id); + + @Inject(method = "bake", at = @At("HEAD")) + public void onBake(BiFunction spriteLoader, CallbackInfo ci) { + Map resources = + MinecraftClient.getInstance().getResourceManager().findResources("models/item", it -> "firmskyblock".equals(it.getNamespace()) && it.getPath().endsWith(".json")); + for (Identifier identifier : resources.keySet()) { + ModelIdentifier modelId = new ModelIdentifier("firmskyblock", identifier.getPath().substring("models/item/".length(), identifier.getPath().length() - ".json".length()), "inventory"); + addModel(modelId); + } + modelsToBake.values().forEach(model -> model.setParents(this::getOrLoadModel)); + } +} diff --git a/src/main/kotlin/moe/nea/firmament/events/CustomItemModelEvent.kt b/src/main/kotlin/moe/nea/firmament/events/CustomItemModelEvent.kt new file mode 100644 index 0000000..bc6a05c --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/events/CustomItemModelEvent.kt @@ -0,0 +1,41 @@ +package moe.nea.firmament.events + +import java.util.* +import net.minecraft.client.render.model.BakedModel +import net.minecraft.client.render.model.BakedModelManager +import net.minecraft.client.util.ModelIdentifier +import net.minecraft.item.ItemStack + +data class CustomItemModelEvent( + val itemStack: ItemStack, + var overrideModel: ModelIdentifier? = null, +) : FirmamentEvent() { + companion object : FirmamentEventBus() { + private val cache = IdentityHashMap() + private val sentinelNull = Object() + + fun clearCache() { + cache.clear() + } + + @JvmStatic + fun getModelIdentifier(itemStack: ItemStack?): ModelIdentifier? { + if (itemStack == null) return null + return publish(CustomItemModelEvent(itemStack)).overrideModel + } + + @JvmStatic + fun getModel(itemStack: ItemStack?, thing: BakedModelManager): BakedModel? { + if (itemStack == null) return null + val cachedValue = cache.getOrPut(itemStack) { + val modelId = getModelIdentifier(itemStack) ?: return@getOrPut sentinelNull + val bakedModel = thing.getModel(modelId) + if (bakedModel === thing.missingModel) return@getOrPut sentinelNull + bakedModel + } + if (cachedValue === sentinelNull) + return null + return cachedValue as BakedModel + } + } +} diff --git a/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt b/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt index 86db2f0..96222da 100644 --- a/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt +++ b/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt @@ -29,6 +29,7 @@ import moe.nea.firmament.features.inventory.CraftingOverlay import moe.nea.firmament.features.inventory.SaveCursorPosition import moe.nea.firmament.features.inventory.SlotLocking import moe.nea.firmament.features.inventory.storageoverlay.StorageOverlay +import moe.nea.firmament.features.texturepack.CustomSkyBlockTextures import moe.nea.firmament.features.world.FairySouls import moe.nea.firmament.util.data.DataHolder @@ -58,6 +59,7 @@ object FeatureManager : DataHolder(serializer(), "feature loadFeature(CraftingOverlay) loadFeature(ImagePreview) loadFeature(SaveCursorPosition) + loadFeature(CustomSkyBlockTextures) if (Firmament.DEBUG) { loadFeature(DeveloperFeatures) loadFeature(DebugView) diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomSkyBlockTextures.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomSkyBlockTextures.kt new file mode 100644 index 0000000..0b25e44 --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomSkyBlockTextures.kt @@ -0,0 +1,35 @@ +package moe.nea.firmament.features.texturepack + +import net.minecraft.client.util.ModelIdentifier +import moe.nea.firmament.events.CustomItemModelEvent +import moe.nea.firmament.events.TickEvent +import moe.nea.firmament.features.FirmamentFeature +import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.util.extraAttributes + +object CustomSkyBlockTextures : FirmamentFeature { + override val identifier: String + get() = "custom-skyblock-textures" + + object TConfig : ManagedConfig(identifier) { + val enabled by toggle("enabled") { true } + val cacheDuration by integer("cache-duration", 0, 20) { 1 } + } + + override val config: ManagedConfig + get() = TConfig + + override fun onLoad() { + CustomItemModelEvent.subscribe { + if (!TConfig.enabled) return@subscribe + val extra = it.itemStack.extraAttributes + val id = extra.getString("id") + if (id.isNotBlank()) + it.overrideModel = ModelIdentifier("firmskyblock", id.lowercase(), "inventory") + } + TickEvent.subscribe { + if (it.tickCount % TConfig.cacheDuration == 0) + CustomItemModelEvent.clearCache() + } + } +} diff --git a/src/main/resources/assets/firmament/lang/en_us.json b/src/main/resources/assets/firmament/lang/en_us.json index ca12967..0273ce1 100644 --- a/src/main/resources/assets/firmament/lang/en_us.json +++ b/src/main/resources/assets/firmament/lang/en_us.json @@ -73,5 +73,8 @@ "firmament.config.image-preview.allowed-hosts": "Allowed Image Hosts", "firmament.config.image-preview.percentage": "Image Width (Percentage of screen)", "firmament.config.image-preview.position": "Chat Image Preview", - "firmament.hud.edit": "Edit %s" + "firmament.hud.edit": "Edit %s", + "firmament.config.custom-skyblock-textures": "Custom SkyBlock Item Textures", + "firmament.config.custom-skyblock-textures.cache-duration": "Model Cache Duration", + "firmament.config.custom-skyblock-textures.enabled": "Enable Custom Item Textures" } diff --git a/src/main/resources/firmament.accesswidener b/src/main/resources/firmament.accesswidener index 45e6bb2..8b4f3d7 100644 --- a/src/main/resources/firmament.accesswidener +++ b/src/main/resources/firmament.accesswidener @@ -2,4 +2,5 @@ accessWidener v2 named accessible class net/minecraft/client/render/RenderLayer$MultiPhase accessible class net/minecraft/client/render/RenderLayer$MultiPhaseParameters accessible class net/minecraft/client/font/TextRenderer$Drawer - +accessible class net/minecraft/client/render/model/ModelLoader$BakerImpl +accessible method net/minecraft/client/render/model/ModelLoader$BakerImpl (Lnet/minecraft/client/render/model/ModelLoader;Ljava/util/function/BiFunction;Lnet/minecraft/util/Identifier;)V -- cgit