Skip to content

Commit

Permalink
Reintroduce BeforeBake and AfterBake model modifiers (#4320)
Browse files Browse the repository at this point in the history
  • Loading branch information
PepperCode1 authored Dec 24, 2024
1 parent 99ff640 commit 8ca2ae8
Show file tree
Hide file tree
Showing 9 changed files with 509 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Up @@ -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;
Expand All @@ -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 {
Expand Down Expand Up @@ -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
Expand All @@ -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 {
/**
Expand Down Expand Up @@ -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();
}
Loading

0 comments on commit 8ca2ae8

Please sign in to comment.