diff --git a/src/main/java/io/github/cottonmc/templates/TemplatesModelProvider.java b/src/main/java/io/github/cottonmc/templates/TemplatesModelProvider.java index d9ca0a3..2bc08c3 100644 --- a/src/main/java/io/github/cottonmc/templates/TemplatesModelProvider.java +++ b/src/main/java/io/github/cottonmc/templates/TemplatesModelProvider.java @@ -1,11 +1,15 @@ package io.github.cottonmc.templates; +import io.github.cottonmc.templates.model.TemplateAppearance; +import io.github.cottonmc.templates.model.TemplateAppearanceManager; import net.fabricmc.fabric.api.client.model.ModelProviderContext; import net.fabricmc.fabric.api.client.model.ModelProviderException; import net.fabricmc.fabric.api.client.model.ModelResourceProvider; import net.fabricmc.fabric.api.client.model.ModelVariantProvider; 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.item.ItemConvertible; import net.minecraft.registry.Registries; import net.minecraft.util.Identifier; @@ -13,6 +17,8 @@ import org.jetbrains.annotations.Nullable; import java.util.HashMap; import java.util.Map; +import java.util.Objects; +import java.util.function.Function; import java.util.function.Supplier; public class TemplatesModelProvider implements ModelResourceProvider, ModelVariantProvider { @@ -20,6 +26,9 @@ public class TemplatesModelProvider implements ModelResourceProvider, ModelVaria private final Map itemAssignments = new HashMap<>(); private final Map cache = new HashMap<>(); + private volatile TemplateAppearanceManager appearanceManager; + + /// model loading @Override public @Nullable UnbakedModel loadModelResource(Identifier resourceId, ModelProviderContext context) throws ModelProviderException { @@ -50,7 +59,38 @@ public class TemplatesModelProvider implements ModelResourceProvider, ModelVaria return customModelId == null ? null : loadModelResource(customModelId, context); } - // "public api" + /// template appearance manager cache, & other cache stuff + + public TemplateAppearanceManager getOrCreateTemplateApperanceManager(Function spriteLookup) { + //This is kind of needlessly fancy using the volatile "double checked locking" pattern. + //I'd like all the template models to use the same TemplateApperanceManager, despite the model + //making process happening concurrently on several threads. + + //Volatile field read: + TemplateAppearanceManager read = appearanceManager; + + if(read == null) { + //Acquire a lock: + synchronized(this) { + //There's a chance another thread just initialized the object and released the lock + //while we were waiting for it, so we do another volatile field read (the "double check"): + read = appearanceManager; + if(read == null) { + //If no-one has initialized it still, I guess we should do it + read = appearanceManager = new TemplateAppearanceManager(spriteLookup); + } + } + } + + return Objects.requireNonNull(read); + } + + public void dumpCache() { + cache.clear(); + appearanceManager = null; + } + + /// "public api" public void addTemplateModel(Identifier id, Supplier modelFactory) { factories.put(id, modelFactory); @@ -67,8 +107,4 @@ public class TemplatesModelProvider implements ModelResourceProvider, ModelVaria public void assignItemModel(Identifier templateModelId, ItemConvertible... itemConvs) { for(ItemConvertible itemConv : itemConvs) assignItemModel(templateModelId, Registries.ITEM.getId(itemConv.asItem())); } - - public void dumpCache() { - cache.clear(); - } } diff --git a/src/main/java/io/github/cottonmc/templates/model/SlopeUnbakedModel.java b/src/main/java/io/github/cottonmc/templates/model/SlopeUnbakedModel.java index b66c7f2..a982b4c 100644 --- a/src/main/java/io/github/cottonmc/templates/model/SlopeUnbakedModel.java +++ b/src/main/java/io/github/cottonmc/templates/model/SlopeUnbakedModel.java @@ -1,5 +1,6 @@ package io.github.cottonmc.templates.model; +import io.github.cottonmc.templates.TemplatesClient; import net.minecraft.block.Blocks; import net.minecraft.client.render.block.BlockModels; import net.minecraft.client.render.model.BakedModel; @@ -27,14 +28,14 @@ public class SlopeUnbakedModel implements UnbakedModel { @Override public BakedModel bake(Baker baker, Function spriteLookup, ModelBakeSettings modelBakeSettings, Identifier identifier) { - //TODO: this is weird, should use my own model instead. - // I should also adjust the item frame/first-person rotations (previously I used SANDSTONE_STAIRS, which has models/block/stairs.json as a parent, - // and that one brings some extra custom rotations along for the ride - BakedModel baseModel = baker.bake(BlockModels.getModelId(Blocks.SANDSTONE.getDefaultState()), modelBakeSettings); - - //TODO: push this up (it's just a cache of data sourced from blockmodels, and can be shared among *all* templates/cached until resource-reload) - TemplateAppearanceManager tam = new TemplateAppearanceManager(spriteLookup); - - return new TemplateBakedModel(baseModel, tam, modelBakeSettings.getRotation(), SlopeBaseMesh.make()); + return new TemplateBakedModel( + //TODO: this is weird, should use my own model instead. + // I should also adjust the item frame/first-person rotations (previously I used SANDSTONE_STAIRS, which has models/block/stairs.json as a parent, + // and that one brings some extra custom rotations along for the ride + baker.bake(BlockModels.getModelId(Blocks.SANDSTONE.getDefaultState()), modelBakeSettings), + TemplatesClient.provider.getOrCreateTemplateApperanceManager(spriteLookup), + modelBakeSettings.getRotation(), + SlopeBaseMesh.make() + ); } }