Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reintroduce BeforeBake* and AfterBake* model modifiers #4320

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -82,12 +82,38 @@ interface Context {

/**
* Event access to monitor unbaked model loads and replace the loaded model.
*
* <p>Replacements done by listeners of this callback <b>do</b> affect child models (that is, models whose
* parent hierarchy contains the replaced model), unlike {@link #modifyModelBeforeBake}.
*/
Event<ModelModifier.OnLoad> modifyModelOnLoad();

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

/**
* Event access to replace the baked model.
*/
Event<ModelModifier.AfterBake> modifyModelAfterBake();

/**
* Event access to monitor unbaked block model loads and replace the loaded model.
*/
Event<ModelModifier.OnLoadBlock> modifyBlockModelOnLoad();

/**
* Event access to replace the unbaked block model used for baking.
*/
Event<ModelModifier.BeforeBakeBlock> modifyBlockModelBeforeBake();

/**
* Event access to replace the baked block model.
*/
Event<ModelModifier.AfterBakeBlock> modifyBlockModelAfterBake();
}
}
Original file line number Diff line number Diff line change
@@ -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.
*
* <p>These callbacks are invoked for <b>every single model that is loaded</b>, so implementations should be
* <p>These callbacks are invoked for <b>every single model that is loaded or baked</b>, so implementations should be
* as efficient as possible.
*/
public final class ModelModifier {
@@ -75,7 +78,11 @@ public interface OnLoad {
* <p>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.
*
* <p>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.
*
* <p>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() { }
}
Original file line number Diff line number Diff line change
@@ -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();
}
Original file line number Diff line number Diff line change
@@ -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<BeforeBakeModifierContext> beforeBakeModifierContextStack = new ObjectArrayList<>();
private final ObjectArrayList<AfterBakeModifierContext> afterBakeModifierContextStack = new ObjectArrayList<>();

private final OnLoadBlockModifierContext onLoadBlockModifierContext = new OnLoadBlockModifierContext();
private final BeforeBakeBlockModifierContext beforeBakeBlockModifierContext = new BeforeBakeBlockModifierContext();
private final AfterBakeBlockModifierContext afterBakeBlockModifierContext = new AfterBakeBlockModifierContext();

public ModelLoadingEventDispatcher(List<ModelLoadingPlugin> 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<ModelIdentifier, BlockStatesLoader.BlockModel> 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<BlockState, GroupableModel> 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;
}
}
}
Original file line number Diff line number Diff line change
@@ -57,6 +57,28 @@ public class ModelLoadingPluginContextImpl implements ModelLoadingPlugin.Context

return model;
}, MODEL_MODIFIER_PHASES);
private final Event<ModelModifier.BeforeBake> 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<ModelModifier.AfterBake> 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<ModelModifier.OnLoadBlock> 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<ModelModifier.BeforeBakeBlock> 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<ModelModifier.AfterBakeBlock> 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<ModelModifier.OnLoad> modifyModelOnLoad() {
return onLoadModifiers;
}

@Override
public Event<ModelModifier.BeforeBake> modifyModelBeforeBake() {
return beforeBakeModifiers;
}

@Override
public Event<ModelModifier.AfterBake> modifyModelAfterBake() {
return afterBakeModifiers;
}

@Override
public Event<ModelModifier.OnLoadBlock> modifyBlockModelOnLoad() {
return onLoadBlockModifiers;
}

@Override
public Event<ModelModifier.BeforeBakeBlock> modifyBlockModelBeforeBake() {
return beforeBakeBlockModifiers;
}

@Override
public Event<ModelModifier.AfterBakeBlock> modifyBlockModelAfterBake() {
return afterBakeBlockModifiers;
}
}
Original file line number Diff line number Diff line change
@@ -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<BakedModel> 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);
}
}
Original file line number Diff line number Diff line change
@@ -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<BakedModel> operation, ModelBaker.ErrorCollectingSpriteGetter spriteGetter, Map<ModelIdentifier, BakedModel> 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<ModelBaker.BakedModels> 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;
}
}
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@
"client": [
"BakedModelManagerMixin",
"ModelBakerBakedModelsMixin",
"ModelBakerBakerImplMixin",
"ModelBakerMixin",
"ReferencedModelsCollectorMixin",
"WrapperBakedModelMixin"
Original file line number Diff line number Diff line change
@@ -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;