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

Update Model Loading API to 1.21.4 #4243

Merged
merged 7 commits into from
Nov 30, 2024
Merged
Show file tree
Hide file tree
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
8 changes: 6 additions & 2 deletions fabric-model-loading-api-v1/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@ version = getSubprojectVersion(project)
moduleDependencies(project, ['fabric-api-base'])

testDependencies(project, [
':fabric-renderer-api-v1',
':fabric-renderer-indigo',
// ':fabric-renderer-api-v1',
// ':fabric-renderer-indigo',
':fabric-rendering-v1',
':fabric-resource-loader-v0'
])

loom {
accessWidenerPath = file('src/client/resources/fabric-model-loading-api-v1.accesswidener')
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,20 @@

import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.client.render.model.UnbakedModel;
import net.minecraft.client.render.model.GroupableModel;

/**
* Block state resolvers are responsible for mapping each {@link BlockState} of a block to an {@link UnbakedModel}.
* Block state resolvers are responsible for mapping each {@link BlockState} of a block to a {@link GroupableModel}.
* They replace the {@code blockstates/} JSON files. One block can be mapped to only one block state resolver; multiple
* resolvers will not receive the same block.
*
* <p>Block state resolvers can be used to create custom block state formats or dynamically resolve block state models.
*
* <p>Use {@link ModelResolver} instead of this interface if interacting with the block and block states directly is not
* necessary. This includes custom model deserializers and loaders.
* <p>Use {@link ModelModifier.OnLoad} instead of this interface if interacting with the block and block states directly
* is not necessary. This includes custom model deserializers and loaders.
*
* @see ModelResolver
* @see ModelModifier.OnLoad
* @see ModelModifier.OnLoadBlock
*/
@FunctionalInterface
public interface BlockStateResolver {
Expand All @@ -44,9 +44,7 @@ public interface BlockStateResolver {
* This method must be called exactly once for each block state.
*
* <p>Note that if multiple block states share the same unbaked model instance, it will be baked multiple times
* (once per block state that has the model set), which is not efficient. To improve efficiency in this case, the
* model should be delegated to using {@link DelegatingUnbakedModel} to ensure that it is only baked once. The inner
* model can be loaded using {@link ModelResolver} if custom loading logic is necessary.
* (once per block state that has the model set).
*/
void resolveBlockStates(Context context);

Expand All @@ -66,6 +64,6 @@ interface Context {
* @param state the block state for which this model should be used
* @param model the unbaked model for this block state
*/
void setModel(BlockState state, UnbakedModel model);
void setModel(BlockState state, GroupableModel model);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import org.jetbrains.annotations.ApiStatus;

import net.minecraft.block.Block;
import net.minecraft.client.render.model.json.JsonUnbakedModel;
import net.minecraft.resource.ResourceManager;
import net.minecraft.util.Identifier;

Expand Down Expand Up @@ -71,28 +70,14 @@ interface Context {
*/
void registerBlockStateResolver(Block block, BlockStateResolver resolver);

/**
* Event access to register model resolvers.
*/
Event<ModelResolver> resolveModel();

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

/**
* Event access to replace the unbaked model used for baking without replacing the cached model.
*
* <p>This is useful for mods which wish to wrap a model without affecting other models that use it as a parent
* (e.g. wrap a block's model into a non-{@link JsonUnbakedModel} class but still allow the item model to be
* loaded and baked without exceptions).
*/
Event<ModelModifier.BeforeBake> modifyModelBeforeBake();

/**
* Event access to monitor baked model loads and replace the loaded model.
* Event access to monitor unbaked block model loads and replace the loaded model.
*/
Event<ModelModifier.AfterBake> modifyModelAfterBake();
Event<ModelModifier.OnLoadBlock> modifyBlockModelOnLoad();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,14 @@

package net.fabricmc.fabric.api.client.model.loading.v1;

import java.util.function.Function;

import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.UnknownNullability;

import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.Baker;
import net.minecraft.client.render.model.ModelBakeSettings;
import net.minecraft.block.BlockState;
import net.minecraft.client.render.model.GroupableModel;
import net.minecraft.client.render.model.ResolvableModel;
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.util.Identifier;

import net.fabricmc.fabric.api.event.Event;
Expand All @@ -39,9 +34,8 @@
*
* <p>Example use cases:
* <ul>
* <li>Overriding a model for a particular block state - check if the given top-level identifier is not null,
* and then check if it has the appropriate variant for that block state. If so, return your desired model,
* otherwise return the given model.</li>
* <li>Overriding the model for a particular block state - check if the given identifier matches the identifier
* for that block state. If so, return your desired model, otherwise return the given model.</li>
* <li>Wrapping a model to override certain behaviors - simply return a new model instance and delegate calls
* to the original model as needed.</li>
* </ul>
Expand All @@ -50,7 +44,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 or baked</b>, so implementations should be
* <p>These callbacks are invoked for <b>every single model that is loaded</b>, so implementations should be
* as efficient as possible.
*/
public final class ModelModifier {
Expand Down Expand Up @@ -78,159 +72,57 @@ public interface OnLoad {
* This handler is invoked to allow modification of an unbaked model right after it is first loaded and before
* it is cached.
*
* <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.
*
* @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#modifyModelOnLoad
*/
UnbakedModel modifyModelOnLoad(UnbakedModel model, Context context);
@Nullable
UnbakedModel modifyModelOnLoad(@Nullable UnbakedModel model, Context context);

/**
* The context for an on load model modification event.
*/
@ApiStatus.NonExtendable
interface Context {
/**
* Models with a resource ID are loaded directly from JSON or a {@link ModelModifier}.
*
* @return the identifier of the given model as an {@link Identifier}, or null if {@link #topLevelId()} is
* not null
* The identifier of the model that was loaded.
*/
@UnknownNullability("#topLevelId() != null")
Identifier resourceId();

/**
* Models with a top-level ID are loaded from blockstate files, {@link BlockStateResolver}s, or by copying
* a previously loaded model.
*
* @return the identifier of the given model as a {@link ModelIdentifier}, or null if {@link #resourceId()}
* is not null
*/
@UnknownNullability("#resourceId() != null")
ModelIdentifier topLevelId();
Identifier id();
}
}

@FunctionalInterface
public interface BeforeBake {
public interface OnLoadBlock {
/**
* This handler is invoked to allow modification of the unbaked model instance right before it is baked.
* This handler is invoked to allow modification of an unbaked block model right after it is first loaded.
*
* @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 {
/**
* Models with a resource ID are loaded directly from JSON or a {@link ModelModifier}.
*
* @return the identifier of the given model as an {@link Identifier}, or null if {@link #topLevelId()} is
* not null
*/
@UnknownNullability("#topLevelId() != null")
Identifier resourceId();

/**
* Models with a top-level ID are loaded from blockstate files, {@link BlockStateResolver}s, or by copying
* a previously loaded model.
*
* @return the identifier of the given model as a {@link ModelIdentifier}, or null if {@link #resourceId()}
* is not null
*/
@UnknownNullability("#resourceId() != null")
ModelIdentifier topLevelId();

/**
* The function that can be used to retrieve sprites.
*/
Function<SpriteIdentifier, Sprite> textureGetter();

/**
* 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#getModel get unbaked models} and
* {@linkplain Baker#bake bake models}.
*/
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.
*
* <p>Note that the passed baked model may be null and that this handler may return a null baked model, since
* {@link UnbakedModel#bake} and {@link Baker#bake} may also return null baked models. Null baked models are
* automatically mapped to the missing model during model retrieval.
*
* <p>For further information, see the docs of {@link ModelLoadingPlugin.Context#modifyModelAfterBake()}.
*
* @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
* @see ModelLoadingPlugin.Context#modifyBlockModelOnLoad
*/
@Nullable
BakedModel modifyModelAfterBake(@Nullable BakedModel model, Context context);
GroupableModel modifyModelOnLoad(GroupableModel model, Context context);

/**
* The context for an after bake model modification event.
* The context for an on load block model modification event.
*/
@ApiStatus.NonExtendable
interface Context {
/**
* Models with a resource ID are loaded directly from JSON or a {@link ModelModifier}.
*
* @return the identifier of the given model as an {@link Identifier}, or null if {@link #topLevelId()} is
* not null
*/
@UnknownNullability("#topLevelId() != null")
Identifier resourceId();

/**
* Models with a top-level ID are loaded from blockstate files, {@link BlockStateResolver}s, or by copying
* a previously loaded model.
*
* @return the identifier of the given model as a {@link ModelIdentifier}, or null if {@link #resourceId()}
* is not null
*/
@UnknownNullability("#resourceId() != null")
ModelIdentifier topLevelId();

/**
* The unbaked model that is being baked.
*/
UnbakedModel sourceModel();

/**
* The function that can be used to retrieve sprites.
*/
Function<SpriteIdentifier, Sprite> textureGetter();

/**
* The settings this model is being baked with.
* The identifier of the model that was loaded.
*/
ModelBakeSettings settings();
ModelIdentifier id();

/**
* The baker being used to bake this model.
* It can be used to {@linkplain Baker#getModel get unbaked models} and
* {@linkplain Baker#bake bake models}.
* The corresponding block state of the model that was loaded.
*/
Baker baker();
BlockState state();
}
}

Expand Down
Loading