From 6206975f10b20f3b91611e865b0153625572bf1a Mon Sep 17 00:00:00 2001 From: PepperCode1 <44146161+PepperCode1@users.noreply.github.com> Date: Sun, 22 Dec 2024 14:44:03 -0800 Subject: [PATCH] Reintroduce BeforeBake and AfterBake model modifiers --- .../model/loading/v1/ModelLoadingPlugin.java | 26 +++ .../model/loading/v1/ModelModifier.java | 158 +++++++++++++++++- .../client/model/loading/ModelBakerHooks.java | 24 +++ .../loading/ModelLoadingEventDispatcher.java | 157 ++++++++++++++++- .../ModelLoadingPluginContextImpl.java | 64 +++++++ .../loading/ModelBakerBakerImplMixin.java | 55 ++++++ .../client/model/loading/ModelBakerMixin.java | 25 ++- .../fabric-model-loading-api-v1.mixins.json | 1 + .../model/loading/ModelTestModClient.java | 11 +- 9 files changed, 509 insertions(+), 12 deletions(-) create mode 100644 fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/ModelBakerHooks.java create mode 100644 fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/ModelBakerBakerImplMixin.java diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/ModelLoadingPlugin.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/ModelLoadingPlugin.java index 30bc4ea274..a9138c92e2 100644 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/ModelLoadingPlugin.java +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/ModelLoadingPlugin.java @@ -82,12 +82,38 @@ interface Context { /** * Event access to monitor unbaked model loads and replace the loaded model. + * + *

Replacements done by listeners of this callback do affect child models (that is, models whose + * parent hierarchy contains the replaced model), unlike {@link #modifyModelBeforeBake}. */ Event modifyModelOnLoad(); + /** + * Event access to replace the unbaked model used for baking without replacing the cached model. + * + *

Replacements done by listeners of this callback do not affect child models (that is, models whose + * parent hierarchy contains the replaced model), unlike {@link #modifyModelOnLoad}. + */ + Event modifyModelBeforeBake(); + + /** + * Event access to replace the baked model. + */ + Event modifyModelAfterBake(); + /** * Event access to monitor unbaked block model loads and replace the loaded model. */ Event modifyBlockModelOnLoad(); + + /** + * Event access to replace the unbaked block model used for baking. + */ + Event modifyBlockModelBeforeBake(); + + /** + * Event access to replace the baked block model. + */ + Event modifyBlockModelAfterBake(); } } diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/ModelModifier.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/ModelModifier.java index fdfc4f018e..95ad0a4645 100644 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/ModelModifier.java +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/ModelModifier.java @@ -20,7 +20,10 @@ import org.jetbrains.annotations.Nullable; import net.minecraft.block.BlockState; +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.render.model.Baker; import net.minecraft.client.render.model.GroupableModel; +import net.minecraft.client.render.model.ModelBakeSettings; import net.minecraft.client.render.model.ResolvableModel; import net.minecraft.client.render.model.UnbakedModel; import net.minecraft.client.util.ModelIdentifier; @@ -44,7 +47,7 @@ * and separate phases are provided for mods that wrap their own models and mods that need to wrap models of other mods * or wrap models arbitrarily. * - *

These callbacks are invoked for every single model that is loaded, so implementations should be + *

These callbacks are invoked for every single model that is loaded or baked, so implementations should be * as efficient as possible. */ public final class ModelModifier { @@ -75,7 +78,11 @@ public interface OnLoad { *

If the given model is {@code null}, its corresponding identifier was requested during * {@linkplain ResolvableModel#resolve resolution} but the model was not loaded normally; i.e. through a JSON * file, possibly because that file did not exist. If a non-{@code null} model is returned in this case, - * resolution will continue without warnings or errors. + * resolution will continue without warnings or errors. This callback can return a {@code null} model, which + * has the same meaning as described earlier, so it is unlikely that an implementor should need to return + * {@code null} unless directly returning the given model. + * + *

For further information, see the docs of {@link ModelLoadingPlugin.Context#modifyModelOnLoad()}. * * @param model the current unbaked model instance * @param context context with additional information about the model/loader @@ -97,6 +104,86 @@ interface Context { } } + @FunctionalInterface + public interface BeforeBake { + /** + * This handler is invoked to allow modification of the unbaked model instance right before it is baked. + * + *

For further information, see the docs of {@link ModelLoadingPlugin.Context#modifyModelBeforeBake()}. + * + * @param model the current unbaked model instance + * @param context context with additional information about the model/loader + * @return the model that should be used in this scenario. If no changes are needed, just return {@code model} as-is. + * @see ModelLoadingPlugin.Context#modifyModelBeforeBake + */ + UnbakedModel modifyModelBeforeBake(UnbakedModel model, Context context); + + /** + * The context for a before bake model modification event. + */ + @ApiStatus.NonExtendable + interface Context { + /** + * The identifier of the model being baked. + */ + Identifier id(); + + /** + * The settings this model is being baked with. + */ + ModelBakeSettings settings(); + + /** + * The baker being used to bake this model. It can be used to {@linkplain Baker#bake bake models} and + * {@linkplain Baker#getSpriteGetter get sprites}. Note that baking a model which was not previously + * {@linkplain ResolvableModel.Resolver#resolve resolved} will log a warning and return the missing model. + */ + Baker baker(); + } + } + + @FunctionalInterface + public interface AfterBake { + /** + * This handler is invoked to allow modification of the baked model instance right after it is baked and before + * it is cached. + * + * @param model the current baked model instance + * @param context context with additional information about the model/loader + * @return the model that should be used in this scenario. If no changes are needed, just return {@code model} as-is. + * @see ModelLoadingPlugin.Context#modifyModelAfterBake + */ + BakedModel modifyModelAfterBake(BakedModel model, Context context); + + /** + * The context for an after bake model modification event. + */ + @ApiStatus.NonExtendable + interface Context { + /** + * The identifier of the model being baked. + */ + Identifier id(); + + /** + * The unbaked model that is being baked. + */ + UnbakedModel sourceModel(); + + /** + * The settings this model is being baked with. + */ + ModelBakeSettings settings(); + + /** + * The baker being used to bake this model. It can be used to {@linkplain Baker#bake bake models} and + * {@linkplain Baker#getSpriteGetter get sprites}. Note that baking a model which was not previously + * {@linkplain ResolvableModel.Resolver#resolve resolved} will log a warning and return the missing model. + */ + Baker baker(); + } + } + @FunctionalInterface public interface OnLoadBlock { /** @@ -126,5 +213,72 @@ interface Context { } } + @FunctionalInterface + public interface BeforeBakeBlock { + /** + * This handler is invoked to allow modification of the unbaked block model instance right before it is baked. + * + * @param model the current unbaked model instance + * @param context context with additional information about the model/loader + * @return the model that should be used in this scenario. If no changes are needed, just return {@code model} as-is. + * @see ModelLoadingPlugin.Context#modifyBlockModelBeforeBake + */ + GroupableModel modifyModelBeforeBake(GroupableModel model, Context context); + + /** + * The context for a before bake block model modification event. + */ + @ApiStatus.NonExtendable + interface Context { + /** + * The identifier of the model being baked. + */ + ModelIdentifier id(); + + /** + * The baker being used to bake this model. It can be used to {@linkplain Baker#bake bake models} and + * {@linkplain Baker#getSpriteGetter get sprites}. Note that baking a model which was not previously + * {@linkplain ResolvableModel.Resolver#resolve resolved} will log a warning and return the missing model. + */ + Baker baker(); + } + } + + @FunctionalInterface + public interface AfterBakeBlock { + /** + * This handler is invoked to allow modification of the baked block model instance right after it is baked. + * + * @param model the current baked model instance + * @param context context with additional information about the model/loader + * @return the model that should be used in this scenario. If no changes are needed, just return {@code model} as-is. + * @see ModelLoadingPlugin.Context#modifyBlockModelAfterBake + */ + BakedModel modifyModelAfterBake(BakedModel model, Context context); + + /** + * The context for an after bake block model modification event. + */ + @ApiStatus.NonExtendable + interface Context { + /** + * The identifier of the model being baked. + */ + ModelIdentifier id(); + + /** + * The unbaked model that is being baked. + */ + GroupableModel sourceModel(); + + /** + * The baker being used to bake this model. It can be used to {@linkplain Baker#bake bake models} and + * {@linkplain Baker#getSpriteGetter get sprites}. Note that baking a model which was not previously + * {@linkplain ResolvableModel.Resolver#resolve resolved} will log a warning and return the missing model. + */ + Baker baker(); + } + } + private ModelModifier() { } } diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/ModelBakerHooks.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/ModelBakerHooks.java new file mode 100644 index 0000000000..c6a245e6eb --- /dev/null +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/ModelBakerHooks.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.impl.client.model.loading; + +import org.jetbrains.annotations.Nullable; + +public interface ModelBakerHooks { + @Nullable + ModelLoadingEventDispatcher fabric_getDispatcher(); +} diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/ModelLoadingEventDispatcher.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/ModelLoadingEventDispatcher.java index f6a75e21dc..ad9be411c4 100644 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/ModelLoadingEventDispatcher.java +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/ModelLoadingEventDispatcher.java @@ -25,6 +25,7 @@ import java.util.function.Consumer; import com.google.common.collect.ImmutableList; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; import it.unimi.dsi.fastutil.objects.Reference2ReferenceMap; import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; import org.jetbrains.annotations.Nullable; @@ -34,8 +35,11 @@ import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.client.render.block.BlockModels; +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.render.model.Baker; import net.minecraft.client.render.model.BlockStatesLoader; import net.minecraft.client.render.model.GroupableModel; +import net.minecraft.client.render.model.ModelBakeSettings; import net.minecraft.client.render.model.UnbakedModel; import net.minecraft.client.util.ModelIdentifier; import net.minecraft.registry.Registries; @@ -55,7 +59,12 @@ public class ModelLoadingEventDispatcher { private final BlockStateResolverContext blockStateResolverContext = new BlockStateResolverContext(); private final OnLoadModifierContext onLoadModifierContext = new OnLoadModifierContext(); + private final ObjectArrayList beforeBakeModifierContextStack = new ObjectArrayList<>(); + private final ObjectArrayList afterBakeModifierContextStack = new ObjectArrayList<>(); + private final OnLoadBlockModifierContext onLoadBlockModifierContext = new OnLoadBlockModifierContext(); + private final BeforeBakeBlockModifierContext beforeBakeBlockModifierContext = new BeforeBakeBlockModifierContext(); + private final AfterBakeBlockModifierContext afterBakeBlockModifierContext = new AfterBakeBlockModifierContext(); public ModelLoadingEventDispatcher(List plugins) { this.pluginContext = new ModelLoadingPluginContextImpl(); @@ -79,6 +88,34 @@ public UnbakedModel modifyModelOnLoad(@Nullable UnbakedModel model, Identifier i return pluginContext.modifyModelOnLoad().invoker().modifyModelOnLoad(model, onLoadModifierContext); } + public UnbakedModel modifyModelBeforeBake(UnbakedModel model, Identifier id, ModelBakeSettings settings, Baker baker) { + if (beforeBakeModifierContextStack.isEmpty()) { + beforeBakeModifierContextStack.add(new BeforeBakeModifierContext()); + } + + BeforeBakeModifierContext context = beforeBakeModifierContextStack.pop(); + context.prepare(id, settings, baker); + + model = pluginContext.modifyModelBeforeBake().invoker().modifyModelBeforeBake(model, context); + + beforeBakeModifierContextStack.push(context); + return model; + } + + public BakedModel modifyModelAfterBake(BakedModel model, Identifier id, UnbakedModel sourceModel, ModelBakeSettings settings, Baker baker) { + if (afterBakeModifierContextStack.isEmpty()) { + afterBakeModifierContextStack.add(new AfterBakeModifierContext()); + } + + AfterBakeModifierContext context = afterBakeModifierContextStack.pop(); + context.prepare(id, sourceModel, settings, baker); + + model = pluginContext.modifyModelAfterBake().invoker().modifyModelAfterBake(model, context); + + afterBakeModifierContextStack.push(context); + return model; + } + public BlockStatesLoader.BlockStateDefinition modifyBlockModelsOnLoad(BlockStatesLoader.BlockStateDefinition models) { Map map = models.models(); @@ -162,6 +199,16 @@ private GroupableModel modifyBlockModelOnLoad(GroupableModel model, ModelIdentif return pluginContext.modifyBlockModelOnLoad().invoker().modifyModelOnLoad(model, onLoadBlockModifierContext); } + public GroupableModel modifyBlockModelBeforeBake(GroupableModel model, ModelIdentifier id, Baker baker) { + beforeBakeBlockModifierContext.prepare(id, baker); + return pluginContext.modifyBlockModelBeforeBake().invoker().modifyModelBeforeBake(model, beforeBakeBlockModifierContext); + } + + public BakedModel modifyBlockModelAfterBake(BakedModel model, ModelIdentifier id, GroupableModel sourceModel, Baker baker) { + afterBakeBlockModifierContext.prepare(id, sourceModel, baker); + return pluginContext.modifyBlockModelAfterBake().invoker().modifyModelAfterBake(model, afterBakeBlockModifierContext); + } + private static class BlockStateResolverContext implements BlockStateResolver.Context { private Block block; private final Reference2ReferenceMap models = new Reference2ReferenceOpenHashMap<>(); @@ -178,7 +225,7 @@ public Block block() { @Override public void setModel(BlockState state, GroupableModel model) { - Objects.requireNonNull(model, "state cannot be null"); + Objects.requireNonNull(state, "state cannot be null"); Objects.requireNonNull(model, "model cannot be null"); if (!state.isOf(block)) { @@ -204,6 +251,67 @@ public Identifier id() { } } + private static class BeforeBakeModifierContext implements ModelModifier.BeforeBake.Context { + private Identifier id; + private ModelBakeSettings settings; + private Baker baker; + + private void prepare(Identifier id, ModelBakeSettings settings, Baker baker) { + this.id = id; + this.settings = settings; + this.baker = baker; + } + + @Override + public Identifier id() { + return id; + } + + @Override + public ModelBakeSettings settings() { + return settings; + } + + @Override + public Baker baker() { + return baker; + } + } + + private static class AfterBakeModifierContext implements ModelModifier.AfterBake.Context { + private Identifier id; + private UnbakedModel sourceModel; + private ModelBakeSettings settings; + private Baker baker; + + private void prepare(Identifier id, UnbakedModel sourceModel, ModelBakeSettings settings, Baker baker) { + this.id = id; + this.sourceModel = sourceModel; + this.settings = settings; + this.baker = baker; + } + + @Override + public Identifier id() { + return id; + } + + @Override + public UnbakedModel sourceModel() { + return sourceModel; + } + + @Override + public ModelBakeSettings settings() { + return settings; + } + + @Override + public Baker baker() { + return baker; + } + } + private static class OnLoadBlockModifierContext implements ModelModifier.OnLoadBlock.Context { private ModelIdentifier id; private BlockState state; @@ -223,4 +331,51 @@ public BlockState state() { return state; } } + + private static class BeforeBakeBlockModifierContext implements ModelModifier.BeforeBakeBlock.Context { + private ModelIdentifier id; + private Baker baker; + + private void prepare(ModelIdentifier id, Baker baker) { + this.id = id; + this.baker = baker; + } + + @Override + public ModelIdentifier id() { + return id; + } + + @Override + public Baker baker() { + return baker; + } + } + + private static class AfterBakeBlockModifierContext implements ModelModifier.AfterBakeBlock.Context { + private ModelIdentifier id; + private GroupableModel sourceModel; + private Baker baker; + + private void prepare(ModelIdentifier id, GroupableModel sourceModel, Baker baker) { + this.id = id; + this.sourceModel = sourceModel; + this.baker = baker; + } + + @Override + public ModelIdentifier id() { + return id; + } + + @Override + public GroupableModel sourceModel() { + return sourceModel; + } + + @Override + public Baker baker() { + return baker; + } + } } diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/ModelLoadingPluginContextImpl.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/ModelLoadingPluginContextImpl.java index 41c2d8ad7a..c0a605f888 100644 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/ModelLoadingPluginContextImpl.java +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/ModelLoadingPluginContextImpl.java @@ -57,6 +57,28 @@ public class ModelLoadingPluginContextImpl implements ModelLoadingPlugin.Context return model; }, MODEL_MODIFIER_PHASES); + private final Event beforeBakeModifiers = EventFactory.createWithPhases(ModelModifier.BeforeBake.class, modifiers -> (model, context) -> { + for (ModelModifier.BeforeBake modifier : modifiers) { + try { + model = modifier.modifyModelBeforeBake(model, context); + } catch (Exception exception) { + LOGGER.error("Failed to modify unbaked model before bake", exception); + } + } + + return model; + }, MODEL_MODIFIER_PHASES); + private final Event afterBakeModifiers = EventFactory.createWithPhases(ModelModifier.AfterBake.class, modifiers -> (model, context) -> { + for (ModelModifier.AfterBake modifier : modifiers) { + try { + model = modifier.modifyModelAfterBake(model, context); + } catch (Exception exception) { + LOGGER.error("Failed to modify baked model after bake", exception); + } + } + + return model; + }, MODEL_MODIFIER_PHASES); private final Event onLoadBlockModifiers = EventFactory.createWithPhases(ModelModifier.OnLoadBlock.class, modifiers -> (model, context) -> { for (ModelModifier.OnLoadBlock modifier : modifiers) { try { @@ -68,6 +90,28 @@ public class ModelLoadingPluginContextImpl implements ModelLoadingPlugin.Context return model; }, MODEL_MODIFIER_PHASES); + private final Event beforeBakeBlockModifiers = EventFactory.createWithPhases(ModelModifier.BeforeBakeBlock.class, modifiers -> (model, context) -> { + for (ModelModifier.BeforeBakeBlock modifier : modifiers) { + try { + model = modifier.modifyModelBeforeBake(model, context); + } catch (Exception exception) { + LOGGER.error("Failed to modify unbaked block model before bake", exception); + } + } + + return model; + }, MODEL_MODIFIER_PHASES); + private final Event afterBakeBlockModifiers = EventFactory.createWithPhases(ModelModifier.AfterBakeBlock.class, modifiers -> (model, context) -> { + for (ModelModifier.AfterBakeBlock modifier : modifiers) { + try { + model = modifier.modifyModelAfterBake(model, context); + } catch (Exception exception) { + LOGGER.error("Failed to modify baked block model after bake", exception); + } + } + + return model; + }, MODEL_MODIFIER_PHASES); @Override public void addModels(Identifier... ids) { @@ -102,8 +146,28 @@ public Event modifyModelOnLoad() { return onLoadModifiers; } + @Override + public Event modifyModelBeforeBake() { + return beforeBakeModifiers; + } + + @Override + public Event modifyModelAfterBake() { + return afterBakeModifiers; + } + @Override public Event modifyBlockModelOnLoad() { return onLoadBlockModifiers; } + + @Override + public Event modifyBlockModelBeforeBake() { + return beforeBakeBlockModifiers; + } + + @Override + public Event modifyBlockModelAfterBake() { + return afterBakeBlockModifiers; + } } diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/ModelBakerBakerImplMixin.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/ModelBakerBakerImplMixin.java new file mode 100644 index 0000000000..fb3b6629f4 --- /dev/null +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/ModelBakerBakerImplMixin.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.mixin.client.model.loading; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +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.Coerce; + +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.render.model.Baker; +import net.minecraft.client.render.model.ModelBakeSettings; +import net.minecraft.client.render.model.ModelBaker; +import net.minecraft.client.render.model.UnbakedModel; +import net.minecraft.util.Identifier; + +import net.fabricmc.fabric.impl.client.model.loading.ModelBakerHooks; +import net.fabricmc.fabric.impl.client.model.loading.ModelLoadingEventDispatcher; + +@Mixin(ModelBaker.BakerImpl.class) +abstract class ModelBakerBakerImplMixin { + @Shadow + @Final + private ModelBaker field_40571; + + @WrapOperation(method = "bake(Lnet/minecraft/util/Identifier;Lnet/minecraft/client/render/model/ModelBakeSettings;)Lnet/minecraft/client/render/model/BakedModel;", at = @At(value = "INVOKE", target = "net/minecraft/client/render/model/UnbakedModel.bake(Lnet/minecraft/client/render/model/UnbakedModel;Lnet/minecraft/client/render/model/Baker;Lnet/minecraft/client/render/model/ModelBakeSettings;)Lnet/minecraft/client/render/model/BakedModel;")) + private BakedModel wrapModelBake(UnbakedModel unbakedModel, @Coerce Baker baker, ModelBakeSettings settings, Operation operation, Identifier id) { + ModelLoadingEventDispatcher dispatcher = ((ModelBakerHooks) this.field_40571).fabric_getDispatcher(); + + if (dispatcher == null) { + return operation.call(unbakedModel, baker, settings); + } + + unbakedModel = dispatcher.modifyModelBeforeBake(unbakedModel, id, settings, baker); + BakedModel model = operation.call(unbakedModel, baker, settings); + return dispatcher.modifyModelAfterBake(model, id, unbakedModel, settings, baker); + } +} diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/ModelBakerMixin.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/ModelBakerMixin.java index e89d086d3c..cd0e04a491 100644 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/ModelBakerMixin.java +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/ModelBakerMixin.java @@ -19,6 +19,8 @@ import java.util.HashMap; import java.util.Map; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.spongepowered.asm.mixin.Final; @@ -31,15 +33,19 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.render.model.Baker; +import net.minecraft.client.render.model.GroupableModel; import net.minecraft.client.render.model.ModelBaker; import net.minecraft.client.render.model.ModelRotation; +import net.minecraft.client.util.ModelIdentifier; import net.minecraft.util.Identifier; import net.fabricmc.fabric.impl.client.model.loading.BakedModelsHooks; +import net.fabricmc.fabric.impl.client.model.loading.ModelBakerHooks; import net.fabricmc.fabric.impl.client.model.loading.ModelLoadingEventDispatcher; @Mixin(ModelBaker.class) -abstract class ModelBakerMixin { +abstract class ModelBakerMixin implements ModelBakerHooks { @Shadow @Final static Logger LOGGER; @@ -53,6 +59,17 @@ private void onReturnInit(CallbackInfo ci) { fabric_eventDispatcher = ModelLoadingEventDispatcher.CURRENT.get(); } + @WrapOperation(method = "method_65737", at = @At(value = "INVOKE", target = "net/minecraft/client/render/model/GroupableModel.bake(Lnet/minecraft/client/render/model/Baker;)Lnet/minecraft/client/render/model/BakedModel;")) + private BakedModel wrapBlockModelBake(GroupableModel unbakedModel, Baker baker, Operation operation, ModelBaker.ErrorCollectingSpriteGetter spriteGetter, Map map, ModelIdentifier id) { + if (fabric_eventDispatcher == null) { + return operation.call(unbakedModel, baker); + } + + unbakedModel = fabric_eventDispatcher.modifyBlockModelBeforeBake(unbakedModel, id, baker); + BakedModel model = operation.call(unbakedModel, baker); + return fabric_eventDispatcher.modifyBlockModelAfterBake(model, id, unbakedModel, baker); + } + @Inject(method = "bake", at = @At("RETURN")) private void onReturnBake(ModelBaker.ErrorCollectingSpriteGetter spriteGetter, CallbackInfoReturnable cir) { if (fabric_eventDispatcher == null) { @@ -71,4 +88,10 @@ private void onReturnBake(ModelBaker.ErrorCollectingSpriteGetter spriteGetter, C }); ((BakedModelsHooks) (Object) models).fabric_setExtraModels(extraModels); } + + @Override + @Nullable + public ModelLoadingEventDispatcher fabric_getDispatcher() { + return fabric_eventDispatcher; + } } diff --git a/fabric-model-loading-api-v1/src/client/resources/fabric-model-loading-api-v1.mixins.json b/fabric-model-loading-api-v1/src/client/resources/fabric-model-loading-api-v1.mixins.json index f299bdb408..d6e3c40f08 100644 --- a/fabric-model-loading-api-v1/src/client/resources/fabric-model-loading-api-v1.mixins.json +++ b/fabric-model-loading-api-v1/src/client/resources/fabric-model-loading-api-v1.mixins.json @@ -5,6 +5,7 @@ "client": [ "BakedModelManagerMixin", "ModelBakerBakedModelsMixin", + "ModelBakerBakerImplMixin", "ModelBakerMixin", "ReferencedModelsCollectorMixin", "WrapperBakedModelMixin" diff --git a/fabric-model-loading-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/model/loading/ModelTestModClient.java b/fabric-model-loading-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/model/loading/ModelTestModClient.java index 6456b82f63..e18336e124 100644 --- a/fabric-model-loading-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/model/loading/ModelTestModClient.java +++ b/fabric-model-loading-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/model/loading/ModelTestModClient.java @@ -58,8 +58,8 @@ public class ModelTestModClient implements ClientModInitializer { public static final String ID = "fabric-model-loading-api-v1-testmod"; public static final Identifier HALF_RED_SAND_MODEL_ID = id("half_red_sand"); - public static final Identifier GOLD_BLOCK_MODEL_ID = Identifier.ofVanilla("block/gold_block"); public static final Identifier BROWN_GLAZED_TERRACOTTA_MODEL_ID = Identifier.ofVanilla("block/brown_glazed_terracotta"); + public static final Identifier GOLD_BLOCK_MODEL_ID = Identifier.ofVanilla("block/gold_block"); @Override public void onInitializeClient() { @@ -114,14 +114,9 @@ public BakedModel bake(ModelTextures textures, Baker baker, ModelBakeSettings se }); // Remove bottom face of gold blocks - pluginContext.modifyModelOnLoad().register(ModelModifier.WRAP_PHASE, (model, context) -> { + pluginContext.modifyModelAfterBake().register(ModelModifier.WRAP_PHASE, (model, context) -> { if (context.id().equals(GOLD_BLOCK_MODEL_ID)) { - return new WrapperUnbakedModel(model) { - @Override - public BakedModel bake(ModelTextures textures, Baker baker, ModelBakeSettings settings, boolean ambientOcclusion, boolean isSideLit, ModelTransformation transformation) { - return new DownQuadRemovingModel(super.bake(textures, baker, settings, ambientOcclusion, isSideLit, transformation)); - } - }; + return new DownQuadRemovingModel(model); } return model;