diff --git a/src/main/java/fr/firstmegagame4/env/driven/assets/client/blockstate/BlockStateManager.java b/src/main/java/fr/firstmegagame4/env/driven/assets/client/blockstate/BlockStateManager.java new file mode 100644 index 0000000..6086c7a --- /dev/null +++ b/src/main/java/fr/firstmegagame4/env/driven/assets/client/blockstate/BlockStateManager.java @@ -0,0 +1,46 @@ +package fr.firstmegagame4.env.driven.assets.client.blockstate; + +import fr.firstmegagame4.env.json.api.EnvJson; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.block.BlockModels; +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.util.ModelIdentifier; +import net.minecraft.util.Identifier; + +import java.util.Map; +import java.util.function.Function; + +public class BlockStateManager { + + public final Map envJsonBlocks = new Object2ObjectOpenHashMap<>(); + + public final Map modelProviders = new Object2ObjectOpenHashMap<>(); + + public EnvJson getStateEnvJson(BlockState state) { + return this.envJsonBlocks.get(state.getBlock()); + } + + public BlockStateModelProvider getProvider(Identifier identifier) { + return this.modelProviders.get(identifier); + } + + public void appendBlock(Block block, EnvJson envJson) { + this.envJsonBlocks.put(block, envJson); + } + + public void provideIdentifiers(Block block, Function, Map> baker) { + if (this.envJsonBlocks.containsKey(block)) { + EnvJson envJson = this.envJsonBlocks.get(block); + envJson.members().forEach(member -> { + BlockStateModelProvider.Builder builder = new BlockStateModelProvider.Builder(); + Map map = new Object2ObjectOpenHashMap<>(); + block.getStateManager().getStates().forEach(state -> map.put(state, BlockModels.getModelId(member.result(), state))); + builder.append(baker.apply(map)); + this.modelProviders.put(member.result(), builder.build()); + }); + } + } +} diff --git a/src/main/java/fr/firstmegagame4/env/driven/assets/client/blockstate/BlockStateModelProvider.java b/src/main/java/fr/firstmegagame4/env/driven/assets/client/blockstate/BlockStateModelProvider.java new file mode 100644 index 0000000..62b6e45 --- /dev/null +++ b/src/main/java/fr/firstmegagame4/env/driven/assets/client/blockstate/BlockStateModelProvider.java @@ -0,0 +1,39 @@ +package fr.firstmegagame4.env.driven.assets.client.blockstate; + +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.minecraft.block.BlockState; +import net.minecraft.client.render.model.BakedModel; + +import java.util.Map; + +public class BlockStateModelProvider { + + private final Map provider = new Object2ObjectOpenHashMap<>(); + + private BlockStateModelProvider() {} + + public BakedModel apply(BlockState state) { + return this.provider.get(state); + } + + public static class Builder { + + private final Map elements = new Object2ObjectOpenHashMap<>(); + + public Builder append(BlockState state, BakedModel model) { + this.elements.put(state, model); + return this; + } + + public Builder append(Map elements) { + this.elements.putAll(elements); + return this; + } + + public BlockStateModelProvider build() { + BlockStateModelProvider provider = new BlockStateModelProvider(); + provider.provider.putAll(this.elements); + return provider; + } + } +} diff --git a/src/main/java/fr/firstmegagame4/env/driven/assets/client/duck/JsonObjectDuckInterface.java b/src/main/java/fr/firstmegagame4/env/driven/assets/client/duck/JsonObjectDuckInterface.java new file mode 100644 index 0000000..13cd051 --- /dev/null +++ b/src/main/java/fr/firstmegagame4/env/driven/assets/client/duck/JsonObjectDuckInterface.java @@ -0,0 +1,12 @@ +package fr.firstmegagame4.env.driven.assets.client.duck; + + +import fr.firstmegagame4.env.json.api.EnvJson; + +// Yeah, it's very awkward, I know +public interface JsonObjectDuckInterface { + + EnvJson env_driven_assets$getEnvJson(); + + void env_driven_assets$setEnvJson(EnvJson envJson); +} diff --git a/src/main/java/fr/firstmegagame4/env/driven/assets/client/duck/ModelLoaderDuckInterface.java b/src/main/java/fr/firstmegagame4/env/driven/assets/client/duck/ModelLoaderDuckInterface.java deleted file mode 100644 index 2e2b70a..0000000 --- a/src/main/java/fr/firstmegagame4/env/driven/assets/client/duck/ModelLoaderDuckInterface.java +++ /dev/null @@ -1,8 +0,0 @@ -package fr.firstmegagame4.env.driven.assets.client.duck; - -import fr.firstmegagame4.env.driven.assets.client.model.ModelManager; - -public interface ModelLoaderDuckInterface { - - ModelManager env_driven_assets$getModelManager(); -} diff --git a/src/main/java/fr/firstmegagame4/env/driven/assets/client/injected/ModelManagerContainer.java b/src/main/java/fr/firstmegagame4/env/driven/assets/client/injected/ManagerContainer.java similarity index 51% rename from src/main/java/fr/firstmegagame4/env/driven/assets/client/injected/ModelManagerContainer.java rename to src/main/java/fr/firstmegagame4/env/driven/assets/client/injected/ManagerContainer.java index dae9bf1..5dc8da2 100644 --- a/src/main/java/fr/firstmegagame4/env/driven/assets/client/injected/ModelManagerContainer.java +++ b/src/main/java/fr/firstmegagame4/env/driven/assets/client/injected/ManagerContainer.java @@ -1,8 +1,13 @@ package fr.firstmegagame4.env.driven.assets.client.injected; +import fr.firstmegagame4.env.driven.assets.client.blockstate.BlockStateManager; import fr.firstmegagame4.env.driven.assets.client.model.ModelManager; -public interface ModelManagerContainer { +public interface ManagerContainer { + + default BlockStateManager getBlockStateManager() { + throw new IllegalStateException(); + } default ModelManager getModelManager() { throw new IllegalStateException(); diff --git a/src/main/java/fr/firstmegagame4/env/driven/assets/client/model/EDABakedModel.java b/src/main/java/fr/firstmegagame4/env/driven/assets/client/model/EDABakedModel.java index 023f938..cfa90a3 100644 --- a/src/main/java/fr/firstmegagame4/env/driven/assets/client/model/EDABakedModel.java +++ b/src/main/java/fr/firstmegagame4/env/driven/assets/client/model/EDABakedModel.java @@ -1,8 +1,9 @@ package fr.firstmegagame4.env.driven.assets.client.model; import fr.firstmegagame4.env.driven.assets.client.EDAEnvJsonVisitors; +import fr.firstmegagame4.env.driven.assets.client.blockstate.BlockStateModelProvider; import fr.firstmegagame4.env.driven.assets.client.duck.BakedModelDuckInterface; -import fr.firstmegagame4.env.driven.assets.client.duck.ModelLoaderDuckInterface; +import fr.firstmegagame4.env.driven.assets.client.injected.ManagerContainer; import fr.firstmegagame4.env.json.api.EnvJson; import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel; import net.fabricmc.fabric.api.renderer.v1.model.WrapperBakedModel; @@ -22,11 +23,11 @@ public class EDABakedModel extends ForwardingBakedModel { - private final ModelManager manager; + private final ManagerContainer container; private final ModelBakeSettings settings; public EDABakedModel(ModelLoader loader, BakedModel wrapped, ModelBakeSettings settings) { - this.manager = ((ModelLoaderDuckInterface) loader).env_driven_assets$getModelManager(); + this.container = loader; this.wrapped = wrapped; this.settings = settings; } @@ -43,10 +44,19 @@ public boolean shouldAllowItemRedirection(ItemStack stack, Supplier rand @Override public void emitBlockQuads(BlockRenderView blockView, BlockState state, BlockPos pos, Supplier randomSupplier, RenderContext context) { + EnvJson envJson = this.container.getBlockStateManager().getStateEnvJson(state); + if (envJson != null) { + Identifier identifier = this.getEnvJson().apply(EDAEnvJsonVisitors.blockVisitor(blockView, pos)); + if (identifier != null) { + BlockStateModelProvider provider = this.container.getBlockStateManager().getProvider(identifier); + provider.apply(state).emitBlockQuads(blockView, state, pos, randomSupplier, context); + return; + } + } if (this.getEnvJson() != null) { Identifier identifier = this.getEnvJson().apply(EDAEnvJsonVisitors.blockVisitor(blockView, pos)); if (identifier != null) { - this.manager.changeModelWithSettings(identifier, this.settings).emitBlockQuads(blockView, state, pos, randomSupplier, context, true); + this.container.getModelManager().changeModelWithSettings(identifier, this.settings).emitBlockQuads(blockView, state, pos, randomSupplier, context, true); return; } } @@ -58,7 +68,7 @@ public void emitItemQuads(ItemStack stack, Supplier randomSupplier, Rend if (this.getEnvJson() != null) { Identifier identifier = this.getEnvJson().apply(EDAEnvJsonVisitors.clientVisitor(MinecraftClient.getInstance())); if (identifier != null) { - this.manager.changeModelWithSettings(identifier, this.settings).emitItemQuads(stack, randomSupplier, context, true); + this.container.getModelManager().changeModelWithSettings(identifier, this.settings).emitItemQuads(stack, randomSupplier, context, true); return; } } diff --git a/src/main/java/fr/firstmegagame4/env/driven/assets/mixin/client/BakedModelManagerMixin.java b/src/main/java/fr/firstmegagame4/env/driven/assets/mixin/client/BakedModelManagerMixin.java index 60d2c81..6cac3c7 100644 --- a/src/main/java/fr/firstmegagame4/env/driven/assets/mixin/client/BakedModelManagerMixin.java +++ b/src/main/java/fr/firstmegagame4/env/driven/assets/mixin/client/BakedModelManagerMixin.java @@ -1,15 +1,18 @@ package fr.firstmegagame4.env.driven.assets.mixin.client; +import com.google.gson.JsonObject; import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import com.llamalad7.mixinextras.sugar.Local; import com.mojang.datafixers.util.Pair; import fr.firstmegagame4.env.driven.assets.client.EDAUtils; -import fr.firstmegagame4.env.driven.assets.client.injected.ModelManagerContainer; +import fr.firstmegagame4.env.driven.assets.client.blockstate.BlockStateManager; +import fr.firstmegagame4.env.driven.assets.client.duck.JsonObjectDuckInterface; import fr.firstmegagame4.env.driven.assets.client.duck.JsonUnbakedModelDuckInterface; -import fr.firstmegagame4.env.driven.assets.client.duck.ModelLoaderDuckInterface; +import fr.firstmegagame4.env.driven.assets.client.injected.ManagerContainer; import fr.firstmegagame4.env.driven.assets.client.model.ModelManager; import fr.firstmegagame4.env.json.api.resource.ExtendedResource; +import fr.firstmegagame4.env.json.api.resource.ExtendedResourceReader; import net.minecraft.client.render.model.BakedModelManager; import net.minecraft.client.render.model.ModelLoader; import net.minecraft.resource.Resource; @@ -21,16 +24,20 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import java.io.IOException; +import java.io.Reader; import java.util.Map; @Mixin(BakedModelManager.class) -public class BakedModelManagerMixin implements ModelManagerContainer { +public class BakedModelManagerMixin implements ManagerContainer { @Unique private ModelLoader modelLoader = null; + // This mixin works, MCDev is just doing weird checks + @SuppressWarnings("UnresolvedMixinReference") @WrapOperation(method = "method_45898", at = @At(value = "INVOKE", target = "Lcom/mojang/datafixers/util/Pair;of(Ljava/lang/Object;Ljava/lang/Object;)Lcom/mojang/datafixers/util/Pair;")) - private static Pair mutateModelValue(F first, S second, Operation> original, @Local Map.Entry entry) { + private static Pair mutateModelValue(F first, S second, Operation> original, @Local(argsOnly = true) Map.Entry entry) { ExtendedResource resource = ExtendedResource.of(entry.getValue()); try { if (resource.getEnvJson() != null) { @@ -45,14 +52,35 @@ private static Pair mutateModelValue(F first, S second, Operation

original) { + JsonObject jsonObject = original.call(reader); + ExtendedResourceReader extended = (ExtendedResourceReader) reader; + // May need some logs here + try { + JsonObjectDuckInterface ducked = (JsonObjectDuckInterface) (Object) jsonObject; + ducked.env_driven_assets$setEnvJson(extended.getExtendedResource().getEnvJson()); + } catch (IOException e) { + throw new RuntimeException(e); + } + return jsonObject; + } + @Inject(method = "upload", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/model/ModelLoader;getBakedModelMap()Ljava/util/Map;")) private void hookModelLoader(BakedModelManager.BakingResult bakingResult, Profiler profiler, CallbackInfo ci) { this.modelLoader = bakingResult.modelLoader(); } + @Override + @SuppressWarnings("AddedMixinMembersNamePattern") + public BlockStateManager getBlockStateManager() { + return this.modelLoader.getBlockStateManager(); + } + @Override @SuppressWarnings("AddedMixinMembersNamePattern") public ModelManager getModelManager() { - return ((ModelLoaderDuckInterface) this.modelLoader).env_driven_assets$getModelManager(); + return this.modelLoader.getModelManager(); } } diff --git a/src/main/java/fr/firstmegagame4/env/driven/assets/mixin/client/JsonObjectMixin.java b/src/main/java/fr/firstmegagame4/env/driven/assets/mixin/client/JsonObjectMixin.java new file mode 100644 index 0000000..0fb5365 --- /dev/null +++ b/src/main/java/fr/firstmegagame4/env/driven/assets/mixin/client/JsonObjectMixin.java @@ -0,0 +1,24 @@ +package fr.firstmegagame4.env.driven.assets.mixin.client; + +import com.google.gson.JsonObject; +import fr.firstmegagame4.env.driven.assets.client.duck.JsonObjectDuckInterface; +import fr.firstmegagame4.env.json.api.EnvJson; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; + +@Mixin(JsonObject.class) +public class JsonObjectMixin implements JsonObjectDuckInterface { + + @Unique + private EnvJson envJson = null; + + @Override + public EnvJson env_driven_assets$getEnvJson() { + return this.envJson; + } + + @Override + public void env_driven_assets$setEnvJson(EnvJson envJson) { + this.envJson = envJson; + } +} diff --git a/src/main/java/fr/firstmegagame4/env/driven/assets/mixin/client/ModelLoaderMixin.java b/src/main/java/fr/firstmegagame4/env/driven/assets/mixin/client/ModelLoaderMixin.java index d7529b5..86ee564 100644 --- a/src/main/java/fr/firstmegagame4/env/driven/assets/mixin/client/ModelLoaderMixin.java +++ b/src/main/java/fr/firstmegagame4/env/driven/assets/mixin/client/ModelLoaderMixin.java @@ -3,15 +3,20 @@ import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import com.llamalad7.mixinextras.sugar.Local; import fr.firstmegagame4.env.driven.assets.client.EDAUtils; +import fr.firstmegagame4.env.driven.assets.client.blockstate.BlockStateManager; +import fr.firstmegagame4.env.driven.assets.client.duck.JsonObjectDuckInterface; import fr.firstmegagame4.env.driven.assets.client.duck.JsonUnbakedModelDuckInterface; -import fr.firstmegagame4.env.driven.assets.client.duck.ModelLoaderDuckInterface; +import fr.firstmegagame4.env.driven.assets.client.injected.ManagerContainer; import fr.firstmegagame4.env.driven.assets.client.model.ModelManager; +import net.minecraft.client.color.block.BlockColors; import net.minecraft.client.render.model.*; import net.minecraft.client.render.model.json.JsonUnbakedModel; import net.minecraft.client.texture.Sprite; import net.minecraft.client.util.ModelIdentifier; import net.minecraft.client.util.SpriteIdentifier; +import net.minecraft.registry.Registries; import net.minecraft.util.Identifier; +import net.minecraft.util.profiler.Profiler; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -21,14 +26,18 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import java.util.List; import java.util.Map; import java.util.function.Function; @Mixin(ModelLoader.class) -public abstract class ModelLoaderMixin implements ModelLoaderDuckInterface { +public abstract class ModelLoaderMixin implements ManagerContainer { @Unique - private final ModelManager manager = new ModelManager(); + private final BlockStateManager blockStateManager = new BlockStateManager(); + + @Unique + private final ModelManager modelManager = new ModelManager(); @Shadow @Final @@ -41,9 +50,15 @@ public abstract class ModelLoaderMixin implements ModelLoaderDuckInterface { @Shadow public abstract UnbakedModel getOrLoadModel(Identifier id); - @Override - public ModelManager env_driven_assets$getModelManager() { - return this.manager; + @Inject(method = "", at = @At("TAIL")) + private void computeStatesIntoManager(BlockColors blockColors, Profiler profiler, Map jsonUnbakedModels, Map> blockStates, CallbackInfo ci) { + Registries.BLOCK.streamEntries().forEach(ref -> { + Identifier stateId = ModelLoader.BLOCK_STATES_FINDER.toResourcePath(ref.registryKey().getValue()); + JsonObjectDuckInterface ducked = (JsonObjectDuckInterface) blockStates.get(stateId); + if (ducked.env_driven_assets$getEnvJson() != null) { + this.blockStateManager.appendBlock(ref.value(), ducked.env_driven_assets$getEnvJson()); + } + }); } @Inject(method = "addModel", at = @At("TAIL")) @@ -55,6 +70,18 @@ private void addEnvJsonModels(ModelIdentifier modelId, CallbackInfo ci, @Local U }); } + @Override + @SuppressWarnings("AddedMixinMembersNamePattern") + public BlockStateManager getBlockStateManager() { + return this.blockStateManager; + } + + @Override + @SuppressWarnings("AddedMixinMembersNamePattern") + public ModelManager getModelManager() { + return this.modelManager; + } + @Unique private void addEnvJsonModel(Identifier identifier) { UnbakedModel unbakedModel = this.getOrLoadModel(identifier); @@ -88,7 +115,7 @@ private JsonUnbakedModel passToItem(JsonUnbakedModel original, @Local UnbakedMod @Inject(method = "bake", at = @At("RETURN")) private void hookToCache(Identifier id, ModelBakeSettings settings, CallbackInfoReturnable cir, @Local ModelLoader.BakedModelCacheKey bakedModelCacheKey) { - ((ModelLoaderDuckInterface) this.field_40571).env_driven_assets$getModelManager().appendModel(bakedModelCacheKey, cir.getReturnValue()); + this.field_40571.getModelManager().appendModel(bakedModelCacheKey, cir.getReturnValue()); } @Inject(method = "bake", at = @At("TAIL")) @@ -97,7 +124,7 @@ private void bakeEnvJsonModels(Identifier id, ModelBakeSettings settings, Callba jum.env_driven_assets$getEnvJson().members().forEach(member -> { UnbakedModel envJsonModel = this.field_40571.getOrLoadModel(member.result()); BakedModel bakedModel = envJsonModel.bake((Baker) this, this.textureGetter, settings, member.result()); - ((ModelLoaderDuckInterface) this.field_40571).env_driven_assets$getModelManager().appendModel( + this.field_40571.getModelManager().appendModel( BakedModelCacheKeyAccessor.env_driven_assets$init(member.result(), settings.getRotation(), settings.isUvLocked()), bakedModel ); diff --git a/src/main/resources/env_driven_assets.mixins.json b/src/main/resources/env_driven_assets.mixins.json index f30e506..89dbe1d 100644 --- a/src/main/resources/env_driven_assets.mixins.json +++ b/src/main/resources/env_driven_assets.mixins.json @@ -5,6 +5,7 @@ "plugin": "fr.firstmegagame4.env.driven.assets.plugin.mixin.client.EDAMixinPlugin", "mixins": [ "client.ChunkedBlockRegionMixin", + "client.JsonObjectMixin", "client.MappedBlockAndTintGetterMixin", "client.WorldSliceAccessor" ], diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 355b465..af4e03d 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -37,7 +37,8 @@ "custom": { "loom:injected_interfaces": { "net/minecraft/class_1087": [ "fr/firstmegagame4/env/driven/assets/client/injected/BakedModelRedirection" ], - "net/minecraft/class_1092": [ "fr/firstmegagame4/env/driven/assets/client/injected/ModelManagerContainer" ] + "net/minecraft/class_1088": [ "fr/firstmegagame4/env/driven/assets/client/injected/ManagerContainer" ], + "net/minecraft/class_1092": [ "fr/firstmegagame4/env/driven/assets/client/injected/ManagerContainer" ] }, "modmenu": { "parent": "env_json"