aboutsummaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
authornea <nea@nea.moe>2023-07-25 17:34:07 +0200
committernea <nea@nea.moe>2023-07-25 17:34:07 +0200
commit0aacb6b965852647fde85045882b6aa6cf58c287 (patch)
tree4be786b2a3765ffac8f9d50fc1d311a6b11c8d69 /src/main
parent1a07394887e546a3381cc7548b9be287671d243d (diff)
downloadfirmament-0aacb6b965852647fde85045882b6aa6cf58c287.tar.gz
firmament-0aacb6b965852647fde85045882b6aa6cf58c287.tar.bz2
firmament-0aacb6b965852647fde85045882b6aa6cf58c287.zip
Add custom texture pack support
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/moe/nea/firmament/mixins/MixinItemModels.java27
-rw-r--r--src/main/java/moe/nea/firmament/mixins/MixinModelLoader.java44
-rw-r--r--src/main/kotlin/moe/nea/firmament/events/CustomItemModelEvent.kt41
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt2
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/texturepack/CustomSkyBlockTextures.kt35
-rw-r--r--src/main/resources/assets/firmament/lang/en_us.json5
-rw-r--r--src/main/resources/firmament.accesswidener3
7 files changed, 155 insertions, 2 deletions
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<BakedModel> 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<Identifier, UnbakedModel> modelsToBake;
+
+ @Shadow
+ public abstract UnbakedModel getOrLoadModel(Identifier id);
+
+ @Inject(method = "bake", at = @At("HEAD"))
+ public void onBake(BiFunction<Identifier, SpriteIdentifier, Sprite> spriteLoader, CallbackInfo ci) {
+ Map<Identifier, Resource> 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<CustomItemModelEvent>() {
+ private val cache = IdentityHashMap<ItemStack?, Any>()
+ 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<FeatureManager.Config>(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 <init> (Lnet/minecraft/client/render/model/ModelLoader;Ljava/util/function/BiFunction;Lnet/minecraft/util/Identifier;)V