diff --git a/fabric-model-loading-api-v1/build.gradle b/fabric-model-loading-api-v1/build.gradle index 3d2819264b..74504e6057 100644 --- a/fabric-model-loading-api-v1/build.gradle +++ b/fabric-model-loading-api-v1/build.gradle @@ -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') +} diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/BlockStateResolver.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/BlockStateResolver.java index 4712101bf1..f8623a2660 100644 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/BlockStateResolver.java +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/BlockStateResolver.java @@ -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. * *

Block state resolvers can be used to create custom block state formats or dynamically resolve block state models. * - *

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. + *

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 { @@ -44,9 +44,7 @@ public interface BlockStateResolver { * This method must be called exactly once for each block state. * *

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); @@ -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); } } diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/DelegatingUnbakedModel.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/DelegatingUnbakedModel.java deleted file mode 100644 index a4fa129848..0000000000 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/DelegatingUnbakedModel.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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.api.client.model.loading.v1; - -import java.util.function.Function; - -import org.jetbrains.annotations.Nullable; - -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.UnbakedModel; -import net.minecraft.client.texture.Sprite; -import net.minecraft.client.util.SpriteIdentifier; -import net.minecraft.util.Identifier; - -/** - * An unbaked model that returns another {@link BakedModel} at {@linkplain #bake bake time}. - * This allows multiple {@link UnbakedModel}s to share the same {@link BakedModel} instance - * and prevents baking the same model multiple times. - */ -public final class DelegatingUnbakedModel implements UnbakedModel { - private final Identifier delegate; - - /** - * Constructs a new delegating model. - * - * @param delegate The identifier of the underlying baked model. - */ - public DelegatingUnbakedModel(Identifier delegate) { - this.delegate = delegate; - } - - @Override - public void resolve(Resolver resolver) { - resolver.resolve(delegate); - } - - @Override - @Nullable - public BakedModel bake(Baker baker, Function textureGetter, ModelBakeSettings rotationContainer) { - return baker.bake(delegate, rotationContainer); - } -} 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 ace79da597..615c69712c 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 @@ -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; @@ -71,28 +70,14 @@ interface Context { */ void registerBlockStateResolver(Block block, BlockStateResolver resolver); - /** - * Event access to register model resolvers. - */ - Event resolveModel(); - /** * Event access to monitor unbaked model loads and replace the loaded model. */ Event modifyModelOnLoad(); /** - * Event access to replace the unbaked model used for baking without replacing the cached model. - * - *

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 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 modifyModelAfterBake(); + Event modifyBlockModelOnLoad(); } } 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 9a86ec61d5..fdfc4f018e 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 @@ -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; @@ -39,9 +34,8 @@ * *

Example use cases: *

@@ -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. * - *

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

These callbacks are invoked for every single model that is loaded, so implementations should be * as efficient as possible. */ public final class ModelModifier { @@ -78,12 +72,18 @@ 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. * + *

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. @@ -91,146 +91,38 @@ public interface OnLoad { @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 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. - * - *

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. - * - *

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 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(); } } diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/ModelResolver.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/ModelResolver.java deleted file mode 100644 index 9ee85033ff..0000000000 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/ModelResolver.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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.api.client.model.loading.v1; - -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.Nullable; - -import net.minecraft.client.render.model.UnbakedModel; -import net.minecraft.util.Identifier; - -/** - * Model resolvers are able to provide a custom model for specific {@link Identifier}s. - * In vanilla, these {@link Identifier}s are converted to file paths and used to load - * a model from JSON. Since model resolvers override this process, they can be used to - * create custom model formats. - * - *

Only one resolver may provide a custom model for a certain {@link Identifier}. - * Thus, resolvers that load models using a custom format could conflict. To avoid - * conflicts, such resolvers may want to only load files with a mod-suffixed name - * or only load files that have been explicitly defined elsewhere. - * - *

If it is necessary to load and bake an arbitrary model that is not referenced - * normally, a model resolver can be used in conjunction with - * {@link ModelLoadingPlugin.Context#addModels} to directly load and bake custom model - * instances. - * - *

Model resolvers are invoked for every single model that will be loaded, - * so implementations should be as efficient as possible. - * - * @see ModelLoadingPlugin.Context#addModels - */ -@FunctionalInterface -public interface ModelResolver { - /** - * @return the resolved {@link UnbakedModel}, or {@code null} if this resolver does not handle the current {@link Identifier} - */ - @Nullable - UnbakedModel resolveModel(Context context); - - /** - * The context for model resolution. - */ - @ApiStatus.NonExtendable - interface Context { - /** - * The identifier of the model to be loaded. - */ - Identifier id(); - } -} diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/UnwrappableBakedModel.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/UnwrappableBakedModel.java new file mode 100644 index 0000000000..80a402643b --- /dev/null +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/UnwrappableBakedModel.java @@ -0,0 +1,90 @@ +/* + * 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.api.client.model.loading.v1; + +import java.util.function.Predicate; + +import org.jetbrains.annotations.Nullable; + +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.render.model.WrapperBakedModel; + +/** + * An interface to be implemented by models that wrap and replace another model, such as {@link WrapperBakedModel}. + * This allows mods to access the wrapped model without having to know the exact type of the wrapper model. + * + *

If you need to access data stored in one of your {@link BakedModel} subclasses, + * and you would normally access the model by its identifier and then cast it: + * call {@link #unwrap(BakedModel, Predicate)} on the model first, in case another + * mod is wrapping your model to alter its rendering. + */ +public interface UnwrappableBakedModel { + /** + * Return the wrapped model, if there is one at the moment, or {@code null} otherwise. + * + *

If there are multiple layers of wrapping, this method does not necessarily return the innermost model. + */ + @Nullable + BakedModel getWrappedModel(); + + /** + * Iteratively unwrap the given model until the given condition returns true or all models in the hierarchy have + * been tested. If no model passes the condition, null is returned. + * + *

A good use of this method is to safely cast a model to an expected type, by passing + * {@code model -> model instanceof MyCustomBakedModel} as the condition. + */ + @Nullable + static BakedModel unwrap(BakedModel model, Predicate condition) { + while (!condition.test(model)) { + if (model instanceof UnwrappableBakedModel wrapper) { + BakedModel wrapped = wrapper.getWrappedModel(); + + if (wrapped == null) { + return null; + } else if (wrapped == model) { + throw new IllegalArgumentException("Model " + model + " is wrapping itself!"); + } else { + model = wrapped; + } + } else { + return null; + } + } + + return model; + } + + /** + * Fully unwrap a model, i.e. return the innermost model. + */ + static BakedModel unwrap(BakedModel model) { + while (model instanceof UnwrappableBakedModel wrapper) { + BakedModel wrapped = wrapper.getWrappedModel(); + + if (wrapped == null) { + return model; + } else if (wrapped == model) { + throw new IllegalArgumentException("Model " + model + " is wrapping itself!"); + } else { + model = wrapped; + } + } + + return model; + } +} diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/WrapperGroupableModel.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/WrapperGroupableModel.java new file mode 100644 index 0000000000..8a65c11a67 --- /dev/null +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/WrapperGroupableModel.java @@ -0,0 +1,52 @@ +/* + * 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.api.client.model.loading.v1; + +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; + +/** + * A simple implementation of {@link GroupableModel} that delegates all method calls to the {@link #wrapped} field. + * Implementations must set the {@link #wrapped} field somehow. + */ +public abstract class WrapperGroupableModel implements GroupableModel { + protected GroupableModel wrapped; + + protected WrapperGroupableModel() { + } + + protected WrapperGroupableModel(GroupableModel wrapped) { + this.wrapped = wrapped; + } + + @Override + public void resolve(Resolver resolver) { + wrapped.resolve(resolver); + } + + @Override + public BakedModel bake(Baker baker) { + return wrapped.bake(baker); + } + + @Override + public Object getEqualityGroup(BlockState state) { + return wrapped.getEqualityGroup(state); + } +} diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/WrapperUnbakedModel.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/WrapperUnbakedModel.java new file mode 100644 index 0000000000..7a4f382a2e --- /dev/null +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/WrapperUnbakedModel.java @@ -0,0 +1,80 @@ +/* + * 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.api.client.model.loading.v1; + +import org.jetbrains.annotations.Nullable; + +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.ModelTextures; +import net.minecraft.client.render.model.UnbakedModel; +import net.minecraft.client.render.model.json.ModelTransformation; + +/** + * A simple implementation of {@link UnbakedModel} that delegates all method calls to the {@link #wrapped} field. + * Implementations must set the {@link #wrapped} field somehow. + */ +public abstract class WrapperUnbakedModel implements UnbakedModel { + protected UnbakedModel wrapped; + + protected WrapperUnbakedModel() { + } + + protected WrapperUnbakedModel(UnbakedModel wrapped) { + this.wrapped = wrapped; + } + + @Override + public void resolve(Resolver resolver) { + wrapped.resolve(resolver); + } + + @Override + public BakedModel bake(ModelTextures textures, Baker baker, ModelBakeSettings settings, boolean ambientOcclusion, boolean isSideLit, ModelTransformation transformation) { + return wrapped.bake(textures, baker, settings, ambientOcclusion, isSideLit, transformation); + } + + @Override + @Nullable + public Boolean getAmbientOcclusion() { + return wrapped.getAmbientOcclusion(); + } + + @Override + @Nullable + public GuiLight getGuiLight() { + return wrapped.getGuiLight(); + } + + @Override + @Nullable + public ModelTransformation getTransformation() { + return wrapped.getTransformation(); + } + + @Override + public ModelTextures.Textures getTextures() { + return wrapped.getTextures(); + } + + @Override + @Nullable + public UnbakedModel getParent() { + return wrapped.getParent(); + } +} diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/BlockStateResolverHolder.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/BakedModelsHooks.java similarity index 70% rename from fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/BlockStateResolverHolder.java rename to fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/BakedModelsHooks.java index 3b70bc224c..94f202ec1d 100644 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/BlockStateResolverHolder.java +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/BakedModelsHooks.java @@ -16,10 +16,16 @@ package net.fabricmc.fabric.impl.client.model.loading; -import net.minecraft.block.Block; +import java.util.Map; + +import org.jetbrains.annotations.Nullable; + +import net.minecraft.client.render.model.BakedModel; import net.minecraft.util.Identifier; -import net.fabricmc.fabric.api.client.model.loading.v1.BlockStateResolver; +public interface BakedModelsHooks { + @Nullable + Map fabric_getExtraModels(); -record BlockStateResolverHolder(BlockStateResolver resolver, Block block, Identifier blockId) { + void fabric_setExtraModels(@Nullable Map extraModels); } diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/BakerImplHooks.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/BakerImplHooks.java deleted file mode 100644 index 8d088dee1d..0000000000 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/BakerImplHooks.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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 java.util.function.Function; - -import net.minecraft.client.texture.Sprite; -import net.minecraft.client.util.SpriteIdentifier; - -public interface BakerImplHooks { - Function fabric_getTextureGetter(); -} diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/ModelLoaderHooks.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/ModelLoaderHooks.java deleted file mode 100644 index 4a4a0b7476..0000000000 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/ModelLoaderHooks.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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; - -public interface ModelLoaderHooks { - ModelLoadingEventDispatcher fabric_getDispatcher(); -} diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/ModelLoadingConstants.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/ModelLoadingConstants.java deleted file mode 100644 index 7d27e12e0f..0000000000 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/ModelLoadingConstants.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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 net.minecraft.client.util.ModelIdentifier; -import net.minecraft.util.Identifier; - -public final class ModelLoadingConstants { - /** - * This variant is used to convert user-provided Identifiers for extra models to ModelIdentifiers, since top-level - * models that will be baked must have a ModelIdentifier. Models corresponding to the Identifiers will go through - * ModelModifier.OnLoad, but models corresponding to the ModelIdentifiers will not. - * - *

This variant must be non-empty, must not contain "=", and must not be equal to "inventory" or "missingno". - */ - public static final String RESOURCE_SPECIAL_VARIANT = "fabric_resource"; - - private ModelLoadingConstants() { - } - - public static ModelIdentifier toResourceModelId(Identifier id) { - return new ModelIdentifier(id, RESOURCE_SPECIAL_VARIANT); - } - - public static boolean isResourceModelId(ModelIdentifier id) { - return id.variant().equals(RESOURCE_SPECIAL_VARIANT); - } -} 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 b80ad7263a..f6a75e21dc 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 @@ -23,28 +23,21 @@ import java.util.Optional; import java.util.function.BiConsumer; import java.util.function.Consumer; -import java.util.function.Function; 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; -import org.jetbrains.annotations.UnknownNullability; import org.slf4j.Logger; import org.slf4j.LoggerFactory; 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.ModelBakeSettings; +import net.minecraft.client.render.model.GroupableModel; 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.registry.Registries; import net.minecraft.registry.RegistryKey; import net.minecraft.util.Identifier; @@ -52,7 +45,6 @@ import net.fabricmc.fabric.api.client.model.loading.v1.BlockStateResolver; import net.fabricmc.fabric.api.client.model.loading.v1.ModelLoadingPlugin; import net.fabricmc.fabric.api.client.model.loading.v1.ModelModifier; -import net.fabricmc.fabric.api.client.model.loading.v1.ModelResolver; public class ModelLoadingEventDispatcher { private static final Logger LOGGER = LoggerFactory.getLogger(ModelLoadingEventDispatcher.class); @@ -60,12 +52,10 @@ public class ModelLoadingEventDispatcher { private final ModelLoadingPluginContextImpl pluginContext; - private final ModelResolverContext modelResolverContext = new ModelResolverContext(); 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(); public ModelLoadingEventDispatcher(List plugins) { this.pluginContext = new ModelLoadingPluginContextImpl(); @@ -79,15 +69,41 @@ public ModelLoadingEventDispatcher(List plugins) { } } - public void addExtraModels(Consumer extraModelConsumer) { - for (Identifier id : pluginContext.extraModels) { - extraModelConsumer.accept(id); - } + public void forEachExtraModel(Consumer extraModelConsumer) { + pluginContext.extraModels.forEach(extraModelConsumer); + } + + @Nullable + public UnbakedModel modifyModelOnLoad(@Nullable UnbakedModel model, Identifier id) { + onLoadModifierContext.prepare(id); + return pluginContext.modifyModelOnLoad().invoker().modifyModelOnLoad(model, onLoadModifierContext); } - public BlockStatesLoader.BlockStateDefinition loadBlockStateModels() { - Map map = new HashMap<>(); + public BlockStatesLoader.BlockStateDefinition modifyBlockModelsOnLoad(BlockStatesLoader.BlockStateDefinition models) { + Map map = models.models(); + + if (!(map instanceof HashMap)) { + map = new HashMap<>(map); + models = new BlockStatesLoader.BlockStateDefinition(map); + } + + putResolvedBlockStates(map); + + map.replaceAll((id, blockModel) -> { + GroupableModel original = blockModel.model(); + GroupableModel modified = modifyBlockModelOnLoad(original, id, blockModel.state()); + + if (original != modified) { + return new BlockStatesLoader.BlockModel(blockModel.state(), modified); + } + return blockModel; + }); + + return models; + } + + private void putResolvedBlockStates(Map map) { pluginContext.blockStateResolvers.forEach((block, resolver) -> { Optional> optionalKey = Registries.BLOCK.getKey(block); @@ -97,22 +113,18 @@ public BlockStatesLoader.BlockStateDefinition loadBlockStateModels() { Identifier blockId = optionalKey.get().getValue(); - BiConsumer output = (state, model) -> { + resolveBlockStates(resolver, block, (state, model) -> { ModelIdentifier modelId = BlockModels.getModelId(blockId, state); map.put(modelId, new BlockStatesLoader.BlockModel(state, model)); - }; - - resolveBlockStates(resolver, block, output); + }); }); - - return new BlockStatesLoader.BlockStateDefinition(map); } - private void resolveBlockStates(BlockStateResolver resolver, Block block, BiConsumer output) { + private void resolveBlockStates(BlockStateResolver resolver, Block block, BiConsumer output) { BlockStateResolverContext context = blockStateResolverContext; context.prepare(block); - Reference2ReferenceMap resolvedModels = context.models; + Reference2ReferenceMap resolvedModels = context.models; ImmutableList allStates = block.getStateManager().getStates(); boolean thrown = false; @@ -131,7 +143,7 @@ private void resolveBlockStates(BlockStateResolver resolver, Block block, BiCons } else { for (BlockState state : allStates) { @Nullable - UnbakedModel model = resolvedModels.get(state); + GroupableModel model = resolvedModels.get(state); if (model == null) { LOGGER.error("Block state resolver did not provide a model for state {} in block {}. Using missing model.", state, block); @@ -145,62 +157,14 @@ private void resolveBlockStates(BlockStateResolver resolver, Block block, BiCons resolvedModels.clear(); } - @Nullable - public UnbakedModel resolveModel(Identifier id) { - modelResolverContext.prepare(id); - return pluginContext.resolveModel().invoker().resolveModel(modelResolverContext); - } - - public UnbakedModel modifyModelOnLoad(UnbakedModel model, @UnknownNullability Identifier resourceId, @UnknownNullability ModelIdentifier topLevelId) { - onLoadModifierContext.prepare(resourceId, topLevelId); - return pluginContext.modifyModelOnLoad().invoker().modifyModelOnLoad(model, onLoadModifierContext); - } - - public UnbakedModel modifyModelBeforeBake(UnbakedModel model, @UnknownNullability Identifier resourceId, @UnknownNullability ModelIdentifier topLevelId, Function textureGetter, ModelBakeSettings settings, Baker baker) { - if (beforeBakeModifierContextStack.isEmpty()) { - beforeBakeModifierContextStack.add(new BeforeBakeModifierContext()); - } - - BeforeBakeModifierContext context = beforeBakeModifierContextStack.pop(); - context.prepare(resourceId, topLevelId, textureGetter, settings, baker); - - model = pluginContext.modifyModelBeforeBake().invoker().modifyModelBeforeBake(model, context); - - beforeBakeModifierContextStack.push(context); - return model; - } - - @Nullable - public BakedModel modifyModelAfterBake(@Nullable BakedModel model, @UnknownNullability Identifier resourceId, @UnknownNullability ModelIdentifier topLevelId, UnbakedModel sourceModel, Function textureGetter, ModelBakeSettings settings, Baker baker) { - if (afterBakeModifierContextStack.isEmpty()) { - afterBakeModifierContextStack.add(new AfterBakeModifierContext()); - } - - AfterBakeModifierContext context = afterBakeModifierContextStack.pop(); - context.prepare(resourceId, topLevelId, sourceModel, textureGetter, settings, baker); - - model = pluginContext.modifyModelAfterBake().invoker().modifyModelAfterBake(model, context); - - afterBakeModifierContextStack.push(context); - return model; - } - - private static class ModelResolverContext implements ModelResolver.Context { - private Identifier id; - - private void prepare(Identifier id) { - this.id = id; - } - - @Override - public Identifier id() { - return id; - } + private GroupableModel modifyBlockModelOnLoad(GroupableModel model, ModelIdentifier id, BlockState state) { + onLoadBlockModifierContext.prepare(id, state); + return pluginContext.modifyBlockModelOnLoad().invoker().modifyModelOnLoad(model, onLoadBlockModifierContext); } private static class BlockStateResolverContext implements BlockStateResolver.Context { private Block block; - private final Reference2ReferenceMap models = new Reference2ReferenceOpenHashMap<>(); + private final Reference2ReferenceMap models = new Reference2ReferenceOpenHashMap<>(); private void prepare(Block block) { this.block = block; @@ -213,7 +177,7 @@ public Block block() { } @Override - public void setModel(BlockState state, UnbakedModel model) { + public void setModel(BlockState state, GroupableModel model) { Objects.requireNonNull(model, "state cannot be null"); Objects.requireNonNull(model, "model cannot be null"); @@ -228,123 +192,35 @@ public void setModel(BlockState state, UnbakedModel model) { } private static class OnLoadModifierContext implements ModelModifier.OnLoad.Context { - @UnknownNullability - private Identifier resourceId; - @UnknownNullability - private ModelIdentifier topLevelId; - - private void prepare(@UnknownNullability Identifier resourceId, @UnknownNullability ModelIdentifier topLevelId) { - this.resourceId = resourceId; - this.topLevelId = topLevelId; - } - - @Override - @UnknownNullability("#topLevelId() != null") - public Identifier resourceId() { - return resourceId; - } - - @Override - @UnknownNullability("#resourceId() != null") - public ModelIdentifier topLevelId() { - return topLevelId; - } - } - - private static class BeforeBakeModifierContext implements ModelModifier.BeforeBake.Context { - @UnknownNullability - private Identifier resourceId; - @UnknownNullability - private ModelIdentifier topLevelId; - private Function textureGetter; - private ModelBakeSettings settings; - private Baker baker; - - private void prepare(@UnknownNullability Identifier resourceId, @UnknownNullability ModelIdentifier topLevelId, Function textureGetter, ModelBakeSettings settings, Baker baker) { - this.resourceId = resourceId; - this.topLevelId = topLevelId; - this.textureGetter = textureGetter; - this.settings = settings; - this.baker = baker; - } - - @Override - @UnknownNullability("#topLevelId() != null") - public Identifier resourceId() { - return resourceId; - } - - @Override - @UnknownNullability("#resourceId() != null") - public ModelIdentifier topLevelId() { - return topLevelId; - } - - @Override - public Function textureGetter() { - return textureGetter; - } + private Identifier id; - @Override - public ModelBakeSettings settings() { - return settings; + private void prepare(Identifier id) { + this.id = id; } @Override - public Baker baker() { - return baker; + public Identifier id() { + return id; } } - private static class AfterBakeModifierContext implements ModelModifier.AfterBake.Context { - @UnknownNullability - private Identifier resourceId; - @UnknownNullability - private ModelIdentifier topLevelId; - private UnbakedModel sourceModel; - private Function textureGetter; - private ModelBakeSettings settings; - private Baker baker; - - private void prepare(@UnknownNullability Identifier resourceId, @UnknownNullability ModelIdentifier topLevelId, UnbakedModel sourceModel, Function textureGetter, ModelBakeSettings settings, Baker baker) { - this.resourceId = resourceId; - this.topLevelId = topLevelId; - this.sourceModel = sourceModel; - this.textureGetter = textureGetter; - this.settings = settings; - this.baker = baker; - } + private static class OnLoadBlockModifierContext implements ModelModifier.OnLoadBlock.Context { + private ModelIdentifier id; + private BlockState state; - @Override - @UnknownNullability("#topLevelId() != null") - public Identifier resourceId() { - return resourceId; - } - - @Override - @UnknownNullability("#resourceId() != null") - public ModelIdentifier topLevelId() { - return topLevelId; - } - - @Override - public UnbakedModel sourceModel() { - return sourceModel; - } - - @Override - public Function textureGetter() { - return textureGetter; + private void prepare(ModelIdentifier id, BlockState state) { + this.id = id; + this.state = state; } @Override - public ModelBakeSettings settings() { - return settings; + public ModelIdentifier id() { + return id; } @Override - public Baker baker() { - return baker; + public BlockState state() { + return state; } } } 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 bd7c7211bd..41c2d8ad7a 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 @@ -28,7 +28,6 @@ import org.slf4j.LoggerFactory; import net.minecraft.block.Block; -import net.minecraft.client.render.model.UnbakedModel; import net.minecraft.registry.Registries; import net.minecraft.registry.RegistryKey; import net.minecraft.util.Identifier; @@ -36,7 +35,6 @@ import net.fabricmc.fabric.api.client.model.loading.v1.BlockStateResolver; import net.fabricmc.fabric.api.client.model.loading.v1.ModelLoadingPlugin; import net.fabricmc.fabric.api.client.model.loading.v1.ModelModifier; -import net.fabricmc.fabric.api.client.model.loading.v1.ModelResolver; import net.fabricmc.fabric.api.event.Event; import net.fabricmc.fabric.api.event.EventFactory; @@ -46,22 +44,6 @@ public class ModelLoadingPluginContextImpl implements ModelLoadingPlugin.Context final Set extraModels = new LinkedHashSet<>(); final Map blockStateResolvers = new IdentityHashMap<>(); - private final Event modelResolvers = EventFactory.createArrayBacked(ModelResolver.class, resolvers -> context -> { - for (ModelResolver resolver : resolvers) { - try { - UnbakedModel model = resolver.resolveModel(context); - - if (model != null) { - return model; - } - } catch (Exception exception) { - LOGGER.error("Failed to resolve model", exception); - } - } - - return null; - }); - private static final Identifier[] MODEL_MODIFIER_PHASES = new Identifier[] { ModelModifier.OVERRIDE_PHASE, ModelModifier.DEFAULT_PHASE, ModelModifier.WRAP_PHASE, ModelModifier.WRAP_LAST_PHASE }; private final Event onLoadModifiers = EventFactory.createWithPhases(ModelModifier.OnLoad.class, modifiers -> (model, context) -> { @@ -75,32 +57,18 @@ 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) { + private final Event onLoadBlockModifiers = EventFactory.createWithPhases(ModelModifier.OnLoadBlock.class, modifiers -> (model, context) -> { + for (ModelModifier.OnLoadBlock 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); + model = modifier.modifyModelOnLoad(model, context); } catch (Exception exception) { - LOGGER.error("Failed to modify baked model after bake", exception); + LOGGER.error("Failed to modify unbaked block model on load", exception); } } return model; }, MODEL_MODIFIER_PHASES); - public ModelLoadingPluginContextImpl() { - } - @Override public void addModels(Identifier... ids) { for (Identifier id : ids) { @@ -129,23 +97,13 @@ public void registerBlockStateResolver(Block block, BlockStateResolver resolver) } } - @Override - public Event resolveModel() { - return modelResolvers; - } - @Override public Event modifyModelOnLoad() { return onLoadModifiers; } @Override - public Event modifyModelBeforeBake() { - return beforeBakeModifiers; - } - - @Override - public Event modifyModelAfterBake() { - return afterBakeModifiers; + public Event modifyBlockModelOnLoad() { + return onLoadBlockModifiers; } } diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/BakedModelManagerMixin.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/BakedModelManagerMixin.java index b1cb3ac0c7..cc46cd6ad7 100644 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/BakedModelManagerMixin.java +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/BakedModelManagerMixin.java @@ -16,52 +16,60 @@ package net.fabricmc.fabric.mixin.client.model.loading; -import java.util.HashMap; import java.util.Map; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; import java.util.concurrent.Executor; -import java.util.function.BiFunction; import java.util.function.Function; import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import com.llamalad7.mixinextras.injector.ModifyReturnValue; +import com.llamalad7.mixinextras.sugar.Local; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.ModifyArg; -import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import net.minecraft.client.render.model.BakedModel; import net.minecraft.client.render.model.BakedModelManager; import net.minecraft.client.render.model.BlockStatesLoader; +import net.minecraft.client.render.model.ModelBaker; import net.minecraft.client.render.model.ReferencedModelsCollector; -import net.minecraft.client.render.model.UnbakedModel; -import net.minecraft.client.util.ModelIdentifier; import net.minecraft.resource.ResourceManager; import net.minecraft.resource.ResourceReloader; import net.minecraft.util.Identifier; -import net.minecraft.util.Pair; import net.fabricmc.fabric.api.client.model.loading.v1.FabricBakedModelManager; -import net.fabricmc.fabric.impl.client.model.loading.ModelLoadingConstants; +import net.fabricmc.fabric.impl.client.model.loading.BakedModelsHooks; import net.fabricmc.fabric.impl.client.model.loading.ModelLoadingEventDispatcher; import net.fabricmc.fabric.impl.client.model.loading.ModelLoadingPluginManager; @Mixin(BakedModelManager.class) abstract class BakedModelManagerMixin implements FabricBakedModelManager { + @Shadow + @Final + private BakedModel missingBlockModel; + @Unique + @Nullable private volatile CompletableFuture eventDispatcherFuture; - @Shadow - private Map models; + @Unique + @Nullable + private Map extraModels; @Override public BakedModel getModel(Identifier id) { - return models.get(ModelLoadingConstants.toResourceModelId(id)); + if (extraModels == null) { + return missingBlockModel; + } + + return extraModels.getOrDefault(id, missingBlockModel); } @Inject(method = "reload", at = @At("HEAD")) @@ -77,51 +85,45 @@ private CompletableFuture resetEventDispatcherFuture(CompletableFuture hookBlockStateModelLoading(CompletableFuture modelsFuture) { - CompletableFuture resolvedModelsFuture = eventDispatcherFuture.thenApplyAsync(ModelLoadingEventDispatcher::loadBlockStateModels); - return modelsFuture.thenCombine(resolvedModelsFuture, (models, resolvedModels) -> { - Map map = models.models(); + @ModifyExpressionValue(method = "reload", at = @At(value = "INVOKE", target = "net/minecraft/client/render/model/BlockStatesLoader.load(Lnet/minecraft/client/render/model/UnbakedModel;Lnet/minecraft/resource/ResourceManager;Ljava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture;")) + private CompletableFuture hookBlockStateModels(CompletableFuture modelsFuture) { + return modelsFuture.thenCombine(eventDispatcherFuture, (models, eventDispatcher) -> eventDispatcher.modifyBlockModelsOnLoad(models)); + } - if (!(map instanceof HashMap)) { - map = new HashMap<>(map); - models = new BlockStatesLoader.BlockStateDefinition(map); - } + @ModifyArg(method = "reload", at = @At(value = "INVOKE", target = "java/util/concurrent/CompletableFuture.thenApplyAsync(Ljava/util/function/Function;Ljava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture;", ordinal = 1), index = 0) + private Function hookModelDiscovery(Function function) { + return v -> { + CompletableFuture future = eventDispatcherFuture; - map.putAll(resolvedModels.models()); - return models; - }); - } + if (future == null) { + return function.apply(v); + } - @Redirect( - method = "reload", - at = @At( - value = "INVOKE", - target = "java/util/concurrent/CompletableFuture.thenCombineAsync(Ljava/util/concurrent/CompletionStage;Ljava/util/function/BiFunction;Ljava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture;", - ordinal = 0, - remap = false - )) - private CompletableFuture hookModelDiscovery( - CompletableFuture self, - CompletionStage> otherFuture, - BiFunction, ReferencedModelsCollector> function, - Executor executor) { - CompletableFuture>> pairFuture = self.thenCombine(otherFuture, Pair::new); - return pairFuture.thenCombineAsync(eventDispatcherFuture, (pair, eventDispatcher) -> { - ModelLoadingEventDispatcher.CURRENT.set(eventDispatcher); - ReferencedModelsCollector referencedModelsCollector = function.apply(pair.getLeft(), pair.getRight()); + ModelLoadingEventDispatcher.CURRENT.set(future.join()); + ReferencedModelsCollector referencedModelsCollector = function.apply(v); ModelLoadingEventDispatcher.CURRENT.remove(); return referencedModelsCollector; - }, executor); + }; } - @ModifyArg(method = "reload", at = @At(value = "INVOKE", target = "java/util/concurrent/CompletableFuture.thenApplyAsync (Ljava/util/function/Function;Ljava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture;", ordinal = 1), index = 0) + @ModifyArg(method = "reload", at = @At(value = "INVOKE", target = "java/util/concurrent/CompletableFuture.thenApplyAsync(Ljava/util/function/Function;Ljava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture;", ordinal = 3), index = 0) private Function hookModelBaking(Function function) { return v -> { - ModelLoadingEventDispatcher.CURRENT.set(eventDispatcherFuture.join()); + CompletableFuture future = eventDispatcherFuture; + + if (future == null) { + return function.apply(v); + } + + ModelLoadingEventDispatcher.CURRENT.set(future.join()); Object bakingResult = function.apply(v); ModelLoadingEventDispatcher.CURRENT.remove(); return bakingResult; }; } + + @Inject(method = "upload", at = @At(value = "INVOKE_STRING", target = "net/minecraft/util/profiler/Profiler.swap(Ljava/lang/String;)V", args = "ldc=cache")) + private void onUpload(CallbackInfo ci, @Local ModelBaker.BakedModels bakedModels) { + extraModels = ((BakedModelsHooks) (Object) bakedModels).fabric_getExtraModels(); + } } diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/ModelBakerBakedModelsMixin.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/ModelBakerBakedModelsMixin.java new file mode 100644 index 0000000000..9cbc3b6cbc --- /dev/null +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/ModelBakerBakedModelsMixin.java @@ -0,0 +1,47 @@ +/* + * 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 java.util.Map; + +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; + +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.render.model.ModelBaker; +import net.minecraft.util.Identifier; + +import net.fabricmc.fabric.impl.client.model.loading.BakedModelsHooks; + +@Mixin(ModelBaker.BakedModels.class) +abstract class ModelBakerBakedModelsMixin implements BakedModelsHooks { + @Unique + @Nullable + private Map extraModels; + + @Override + @Nullable + public Map fabric_getExtraModels() { + return extraModels; + } + + @Override + public void fabric_setExtraModels(@Nullable Map extraModels) { + this.extraModels = extraModels; + } +} 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 new file mode 100644 index 0000000000..e89d086d3c --- /dev/null +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/ModelBakerMixin.java @@ -0,0 +1,74 @@ +/* + * 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 java.util.HashMap; +import java.util.Map; + +import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.render.model.ModelBaker; +import net.minecraft.client.render.model.ModelRotation; +import net.minecraft.util.Identifier; + +import net.fabricmc.fabric.impl.client.model.loading.BakedModelsHooks; +import net.fabricmc.fabric.impl.client.model.loading.ModelLoadingEventDispatcher; + +@Mixin(ModelBaker.class) +abstract class ModelBakerMixin { + @Shadow + @Final + static Logger LOGGER; + + @Unique + @Nullable + private ModelLoadingEventDispatcher fabric_eventDispatcher; + + @Inject(method = "", at = @At("RETURN")) + private void onReturnInit(CallbackInfo ci) { + fabric_eventDispatcher = ModelLoadingEventDispatcher.CURRENT.get(); + } + + @Inject(method = "bake", at = @At("RETURN")) + private void onReturnBake(ModelBaker.ErrorCollectingSpriteGetter spriteGetter, CallbackInfoReturnable cir) { + if (fabric_eventDispatcher == null) { + return; + } + + ModelBaker.BakedModels models = cir.getReturnValue(); + Map extraModels = new HashMap<>(); + fabric_eventDispatcher.forEachExtraModel(id -> { + try { + BakedModel model = ((ModelBaker) (Object) this).new BakerImpl(spriteGetter, id::toString).bake(id, ModelRotation.X0_Y0); + extraModels.put(id, model); + } catch (Exception e) { + LOGGER.warn("Unable to bake extra model: '{}': {}", id, e); + } + }); + ((BakedModelsHooks) (Object) models).fabric_setExtraModels(extraModels); + } +} diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/ModelLoaderBakerImplMixin.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/ModelLoaderBakerImplMixin.java deleted file mode 100644 index 2750e1d207..0000000000 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/ModelLoaderBakerImplMixin.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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 java.util.function.Function; - -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.client.texture.Sprite; -import net.minecraft.client.util.SpriteIdentifier; -import net.minecraft.util.Identifier; - -import net.fabricmc.fabric.impl.client.model.loading.BakerImplHooks; -import net.fabricmc.fabric.impl.client.model.loading.ModelLoaderHooks; -import net.fabricmc.fabric.impl.client.model.loading.ModelLoadingEventDispatcher; - -@Mixin(targets = "net/minecraft/client/render/model/ModelBaker$BakerImpl") -abstract class ModelLoaderBakerImplMixin implements BakerImplHooks { - @Shadow - @Final - private ModelBaker field_40571; - @Shadow - @Final - private Function textureGetter; - - @WrapOperation(method = "bake(Lnet/minecraft/util/Identifier;Lnet/minecraft/client/render/model/ModelBakeSettings;)Lnet/minecraft/client/render/model/BakedModel;", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/model/ModelBaker$BakerImpl;bake(Lnet/minecraft/client/render/model/UnbakedModel;Lnet/minecraft/client/render/model/ModelBakeSettings;)Lnet/minecraft/client/render/model/BakedModel;")) - private BakedModel wrapInnerBake(@Coerce Baker self, UnbakedModel unbakedModel, ModelBakeSettings settings, Operation operation, Identifier id) { - ModelLoadingEventDispatcher dispatcher = ((ModelLoaderHooks) this.field_40571).fabric_getDispatcher(); - unbakedModel = dispatcher.modifyModelBeforeBake(unbakedModel, id, null, textureGetter, settings, self); - BakedModel model = operation.call(self, unbakedModel, settings); - return dispatcher.modifyModelAfterBake(model, id, null, unbakedModel, textureGetter, settings, self); - } - - @Override - public Function fabric_getTextureGetter() { - return textureGetter; - } -} diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/ModelLoaderMixin.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/ModelLoaderMixin.java deleted file mode 100644 index 769125a2d9..0000000000 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/ModelLoaderMixin.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * 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 java.util.function.Function; - -import com.llamalad7.mixinextras.injector.wrapoperation.Operation; -import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; -import org.jetbrains.annotations.Nullable; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Coerce; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import net.minecraft.client.render.model.BakedModel; -import net.minecraft.client.render.model.Baker; -import net.minecraft.client.render.model.MissingModel; -import net.minecraft.client.render.model.ModelBakeSettings; -import net.minecraft.client.render.model.ModelBaker; -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.fabricmc.fabric.impl.client.model.loading.BakerImplHooks; -import net.fabricmc.fabric.impl.client.model.loading.ModelLoaderHooks; -import net.fabricmc.fabric.impl.client.model.loading.ModelLoadingConstants; -import net.fabricmc.fabric.impl.client.model.loading.ModelLoadingEventDispatcher; - -@Mixin(ModelBaker.class) -abstract class ModelLoaderMixin implements ModelLoaderHooks { - @Unique - @Nullable - private ModelLoadingEventDispatcher fabric_eventDispatcher; - - @Inject(method = "", at = @At("RETURN")) - private void onReturnInit(CallbackInfo ci) { - fabric_eventDispatcher = ModelLoadingEventDispatcher.CURRENT.get(); - } - - @WrapOperation(method = "method_61072", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/model/ModelBaker$BakerImpl;bake(Lnet/minecraft/client/render/model/UnbakedModel;Lnet/minecraft/client/render/model/ModelBakeSettings;)Lnet/minecraft/client/render/model/BakedModel;")) - private BakedModel wrapSingleOuterBake(@Coerce Baker baker, UnbakedModel unbakedModel, ModelBakeSettings settings, Operation operation, ModelBaker.SpriteGetter spriteGetter, ModelIdentifier id) { - if (fabric_eventDispatcher == null) { - return operation.call(baker, unbakedModel, settings); - } - - if (ModelLoadingConstants.isResourceModelId(id) || id.equals(MissingModel.MODEL_ID)) { - // Call the baker instead of the operation to ensure the baked model is cached and doesn't end up going - // through events twice. - // This ignores the UnbakedModel in field_53662 (top-level model map) but it should be the same as the one in field_53663 (resource model map). - return baker.bake(id.id(), settings); - } - - Function textureGetter = ((BakerImplHooks) baker).fabric_getTextureGetter(); - unbakedModel = fabric_eventDispatcher.modifyModelBeforeBake(unbakedModel, null, id, textureGetter, settings, baker); - BakedModel model = operation.call(baker, unbakedModel, settings); - return fabric_eventDispatcher.modifyModelAfterBake(model, null, id, unbakedModel, textureGetter, settings, baker); - } - - @Override - public ModelLoadingEventDispatcher fabric_getDispatcher() { - return fabric_eventDispatcher; - } -} diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/ReferencedModelsCollectorMixin.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/ReferencedModelsCollectorMixin.java index ac0ea35e8a..ea1b67105a 100644 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/ReferencedModelsCollectorMixin.java +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/ReferencedModelsCollectorMixin.java @@ -25,13 +25,10 @@ import org.spongepowered.asm.mixin.injection.ModifyVariable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import net.minecraft.client.render.model.BlockStatesLoader; import net.minecraft.client.render.model.ReferencedModelsCollector; import net.minecraft.client.render.model.UnbakedModel; -import net.minecraft.client.util.ModelIdentifier; import net.minecraft.util.Identifier; -import net.fabricmc.fabric.impl.client.model.loading.ModelLoadingConstants; import net.fabricmc.fabric.impl.client.model.loading.ModelLoadingEventDispatcher; @Mixin(ReferencedModelsCollector.class) @@ -41,55 +38,24 @@ abstract class ReferencedModelsCollectorMixin { private ModelLoadingEventDispatcher fabric_eventDispatcher; @Shadow - abstract UnbakedModel computeResolvedModel(Identifier identifier); - - @Shadow - abstract void addTopLevelModel(ModelIdentifier modelIdentifier, UnbakedModel unbakedModel); + abstract UnbakedModel computeResolvedModel(Identifier id); @Inject(method = "", at = @At("RETURN")) private void onReturnInit(CallbackInfo ci) { fabric_eventDispatcher = ModelLoadingEventDispatcher.CURRENT.get(); - } - @Inject(method = "addBlockStates", at = @At("RETURN")) - private void onAddStandardModels(BlockStatesLoader.BlockStateDefinition blockStateModels, CallbackInfo ci) { - if (fabric_eventDispatcher == null) { - return; + if (fabric_eventDispatcher != null) { + fabric_eventDispatcher.forEachExtraModel(this::computeResolvedModel); } - - fabric_eventDispatcher.addExtraModels(id -> { - ModelIdentifier modelId = ModelLoadingConstants.toResourceModelId(id); - UnbakedModel unbakedModel = computeResolvedModel(id); - addTopLevelModel(modelId, unbakedModel); - }); } @ModifyVariable(method = "getModel", at = @At(value = "STORE", ordinal = 0), ordinal = 0) @Nullable - private UnbakedModel onLoadResourceModel(@Nullable UnbakedModel model, Identifier id) { + private UnbakedModel onLoadModel(@Nullable UnbakedModel model, Identifier id) { if (fabric_eventDispatcher == null) { return model; } - UnbakedModel resolvedModel = fabric_eventDispatcher.resolveModel(id); - - if (resolvedModel != null) { - model = resolvedModel; - } - - return fabric_eventDispatcher.modifyModelOnLoad(model, id, null); - } - - @ModifyVariable(method = "addTopLevelModel", at = @At("HEAD"), argsOnly = true) - private UnbakedModel onAddTopLevelModel(UnbakedModel model, ModelIdentifier modelId) { - if (fabric_eventDispatcher == null) { - return model; - } - - if (ModelLoadingConstants.isResourceModelId(modelId)) { - return model; - } - - return fabric_eventDispatcher.modifyModelOnLoad(model, null, modelId); + return fabric_eventDispatcher.modifyModelOnLoad(model, id); } } diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/BlockStatesLoaderHooks.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/WrapperBakedModelMixin.java similarity index 51% rename from fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/BlockStatesLoaderHooks.java rename to fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/WrapperBakedModelMixin.java index eda9103233..6fd7417a1d 100644 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/BlockStatesLoaderHooks.java +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/WrapperBakedModelMixin.java @@ -14,17 +14,25 @@ * limitations under the License. */ -package net.fabricmc.fabric.impl.client.model.loading; +package net.fabricmc.fabric.mixin.client.model.loading; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.state.StateManager; -import net.minecraft.util.Identifier; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; -public interface BlockStatesLoaderHooks { - void fabric_setLoadingOverride(LoadingOverride override); +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.render.model.WrapperBakedModel; - interface LoadingOverride { - boolean loadBlockStates(Identifier id, StateManager stateManager); +import net.fabricmc.fabric.api.client.model.loading.v1.UnwrappableBakedModel; + +@Mixin(WrapperBakedModel.class) +abstract class WrapperBakedModelMixin implements UnwrappableBakedModel { + @Shadow + @Final + protected BakedModel wrapped; + + @Override + public BakedModel getWrappedModel() { + return wrapped; } } diff --git a/fabric-model-loading-api-v1/src/client/resources/fabric-model-loading-api-v1.accesswidener b/fabric-model-loading-api-v1/src/client/resources/fabric-model-loading-api-v1.accesswidener new file mode 100644 index 0000000000..12de3c5c2e --- /dev/null +++ b/fabric-model-loading-api-v1/src/client/resources/fabric-model-loading-api-v1.accesswidener @@ -0,0 +1,3 @@ +accessWidener v2 named +accessible class net/minecraft/client/render/model/ModelBaker$BakerImpl +accessible method net/minecraft/client/render/model/ModelBaker$BakerImpl (Lnet/minecraft/client/render/model/ModelBaker;Lnet/minecraft/client/render/model/ModelBaker$ErrorCollectingSpriteGetter;Lnet/minecraft/client/model/ModelNameSupplier;)V 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 7edc34fafb..f299bdb408 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 @@ -4,9 +4,10 @@ "compatibilityLevel": "JAVA_21", "client": [ "BakedModelManagerMixin", + "ModelBakerBakedModelsMixin", + "ModelBakerMixin", "ReferencedModelsCollectorMixin", - "ModelLoaderBakerImplMixin", - "ModelLoaderMixin" + "WrapperBakedModelMixin" ], "injectors": { "defaultRequire": 1 diff --git a/fabric-model-loading-api-v1/src/client/resources/fabric.mod.json b/fabric-model-loading-api-v1/src/client/resources/fabric.mod.json index 7327b98d33..34681e8f3f 100644 --- a/fabric-model-loading-api-v1/src/client/resources/fabric.mod.json +++ b/fabric-model-loading-api-v1/src/client/resources/fabric.mod.json @@ -26,10 +26,12 @@ "config": "fabric-model-loading-api-v1.mixins.json" } ], + "accessWidener": "fabric-model-loading-api-v1.accesswidener", "custom": { "fabric-api:module-lifecycle": "stable", "loom:injected_interfaces": { - "net/minecraft/class_1092": [ "net/fabricmc/fabric/api/client/model/loading/v1/FabricBakedModelManager" ] + "net/minecraft/class_1092": [ "net/fabricmc/fabric/api/client/model/loading/v1/FabricBakedModelManager" ], + "net/minecraft/class_10200": [ "net/fabricmc/fabric/api/client/model/loading/v1/UnwrappableBakedModel" ] } } } 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 a02e119d5f..52e79ab289 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 @@ -16,32 +16,31 @@ package net.fabricmc.fabric.test.model.loading; -import java.util.function.Supplier; +import java.util.List; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.block.CropBlock; import net.minecraft.block.HorizontalConnectingBlock; -import net.minecraft.client.render.block.BlockModels; import net.minecraft.client.render.entity.PlayerEntityRenderer; 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.MissingModel; -import net.minecraft.client.render.model.UnbakedModel; -import net.minecraft.client.util.ModelIdentifier; +import net.minecraft.client.render.model.ModelBakeSettings; +import net.minecraft.client.render.model.ModelTextures; +import net.minecraft.client.render.model.json.ModelTransformation; +import net.minecraft.client.render.model.json.ModelVariant; +import net.minecraft.client.render.model.json.WeightedUnbakedModel; import net.minecraft.resource.ResourceType; import net.minecraft.util.Identifier; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.random.Random; -import net.minecraft.world.BlockRenderView; +import net.minecraft.util.math.AffineTransformation; import net.fabricmc.api.ClientModInitializer; -import net.fabricmc.fabric.api.client.model.loading.v1.DelegatingUnbakedModel; import net.fabricmc.fabric.api.client.model.loading.v1.ModelLoadingPlugin; import net.fabricmc.fabric.api.client.model.loading.v1.ModelModifier; +import net.fabricmc.fabric.api.client.model.loading.v1.WrapperUnbakedModel; import net.fabricmc.fabric.api.client.rendering.v1.LivingEntityFeatureRendererRegistrationCallback; -import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel; -import net.fabricmc.fabric.api.renderer.v1.render.RenderContext; import net.fabricmc.fabric.api.resource.ResourceManagerHelper; public class ModelTestModClient implements ClientModInitializer { @@ -51,76 +50,85 @@ public class ModelTestModClient implements ClientModInitializer { 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"); - static class DownQuadRemovingModel extends ForwardingBakedModel { - DownQuadRemovingModel(BakedModel model) { - wrapped = model; - } - - @Override - public void emitBlockQuads(BlockRenderView blockView, BlockState state, BlockPos pos, Supplier randomSupplier, RenderContext context) { - context.pushTransform(q -> q.cullFace() != Direction.DOWN); - super.emitBlockQuads(blockView, state, pos, randomSupplier, context); - context.popTransform(); - } - } + //static class DownQuadRemovingModel extends ForwardingBakedModel { + // DownQuadRemovingModel(BakedModel model) { + // wrapped = model; + // } + // + // @Override + // public void emitBlockQuads(BlockRenderView blockView, BlockState state, BlockPos pos, Supplier randomSupplier, RenderContext context) { + // context.pushTransform(q -> q.cullFace() != Direction.DOWN); + // super.emitBlockQuads(blockView, state, pos, randomSupplier, context); + // context.popTransform(); + // } + //} @Override public void onInitializeClient() { ModelLoadingPlugin.register(pluginContext -> { pluginContext.addModels(HALF_RED_SAND_MODEL_ID); - // remove bottom face of gold blocks - pluginContext.modifyModelAfterBake().register(ModelModifier.WRAP_PHASE, (model, context) -> { - Identifier id = context.resourceId(); + // Make wheat stages 1->6 use the same model as stage 0. This can be done with resource packs, this is just a test. + pluginContext.registerBlockStateResolver(Blocks.WHEAT, context -> { + BlockState state = context.block().getDefaultState(); + + Identifier wheatStage0Id = Identifier.ofVanilla("block/wheat_stage0"); + Identifier wheatStage7Id = Identifier.ofVanilla("block/wheat_stage7"); + GroupableModel wheatStage0Model = simpleGroupableModel(wheatStage0Id); + GroupableModel wheatStage7Model = simpleGroupableModel(wheatStage7Id); - if (id != null && id.equals(GOLD_BLOCK_MODEL_ID)) { - return new DownQuadRemovingModel(model); + for (int age = 0; age <= 6; age++) { + context.setModel(state.with(CropBlock.AGE, age), wheatStage0Model); } - return model; + context.setModel(state.with(CropBlock.AGE, 7), wheatStage7Model); }); - // make fences with west: true and everything else false appear to be a missing model visually - ModelIdentifier fenceId = BlockModels.getModelId(Blocks.OAK_FENCE.getDefaultState().with(HorizontalConnectingBlock.WEST, true)); - pluginContext.modifyModelOnLoad().register(ModelModifier.OVERRIDE_PHASE, (model, context) -> { - ModelIdentifier id = context.topLevelId(); - - if (id != null && id.equals(fenceId)) { - return new DelegatingUnbakedModel(MissingModel.ID); + // Replace the brown glazed terracotta model with a missing model without affecting child models. + // Since 1.21.4, the item model is not a child model, so it is also affected. + pluginContext.modifyModelOnLoad().register(ModelModifier.WRAP_PHASE, (model, context) -> { + if (context.id().equals(BROWN_GLAZED_TERRACOTTA_MODEL_ID)) { + return new WrapperUnbakedModel(model) { + @Override + public void resolve(Resolver resolver) { + super.resolve(resolver); + resolver.resolve(MissingModel.ID); + } + + @Override + public BakedModel bake(ModelTextures textures, Baker baker, ModelBakeSettings settings, boolean ambientOcclusion, boolean isSideLit, ModelTransformation transformation) { + return baker.bake(MissingModel.ID, settings); + } + }; } return model; }); - // make brown glazed terracotta appear to be a missing model visually, but without affecting the item, by using pre-bake - // using load here would make the item also appear missing - pluginContext.modifyModelBeforeBake().register(ModelModifier.OVERRIDE_PHASE, (model, context) -> { - Identifier id = context.resourceId(); - - if (id != null && id.equals(BROWN_GLAZED_TERRACOTTA_MODEL_ID)) { - return MissingModel.create(); + // Make oak fences with west: true and everything else false appear to be a missing model visually. + BlockState westOakFence = Blocks.OAK_FENCE.getDefaultState().with(HorizontalConnectingBlock.WEST, true); + pluginContext.modifyBlockModelOnLoad().register(ModelModifier.OVERRIDE_PHASE, (model, context) -> { + if (context.state() == westOakFence) { + return simpleGroupableModel(MissingModel.ID); } return model; }); - // Make wheat stages 1->6 use the same model as stage 0. This can be done with resource packs, this is just a test. - pluginContext.registerBlockStateResolver(Blocks.WHEAT, context -> { - BlockState state = context.block().getDefaultState(); - - // All the block state models are top-level... - // Use a delegating unbaked model to make sure the identical models only get baked a single time. - Identifier wheatStage0Id = Identifier.ofVanilla("block/wheat_stage0"); - Identifier wheatStage7Id = Identifier.ofVanilla("block/wheat_stage7"); - UnbakedModel wheatStage0Model = new DelegatingUnbakedModel(wheatStage0Id); - UnbakedModel wheatStage7Model = new DelegatingUnbakedModel(wheatStage7Id); - - for (int age = 0; age <= 6; age++) { - context.setModel(state.with(CropBlock.AGE, age), wheatStage0Model); - } - - context.setModel(state.with(CropBlock.AGE, 7), wheatStage7Model); - }); + // TODO 1.21.4: reintroduce test once FRAPI+Indigo are ported + // remove bottom face of gold blocks + //pluginContext.modifyModelOnLoad().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 model; + //}); }); ResourceManagerHelper.get(ResourceType.CLIENT_RESOURCES).registerReloadListener(SpecificModelReloadListener.INSTANCE); @@ -135,4 +143,8 @@ public void onInitializeClient() { public static Identifier id(String path) { return Identifier.of(ID, path); } + + private static GroupableModel simpleGroupableModel(Identifier model) { + return new WeightedUnbakedModel(List.of(new ModelVariant(model, AffineTransformation.identity(), false, 1))); + } } diff --git a/fabric-model-loading-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/model/loading/PreparablePluginTest.java b/fabric-model-loading-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/model/loading/PreparablePluginTest.java index f2af763a6a..be5f9a4db8 100644 --- a/fabric-model-loading-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/model/loading/PreparablePluginTest.java +++ b/fabric-model-loading-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/model/loading/PreparablePluginTest.java @@ -55,15 +55,11 @@ public class PreparablePluginTest implements ClientModInitializer { public void onInitializeClient() { PreparableModelLoadingPlugin.register(PreparablePluginTest::loadModelReplacements, (replacementModels, pluginContext) -> { pluginContext.modifyModelOnLoad().register((model, ctx) -> { - Identifier id = ctx.resourceId(); + @Nullable + UnbakedModel replacementModel = replacementModels.get(ctx.id()); - if (id != null) { - @Nullable - UnbakedModel replacementModel = replacementModels.get(id); - - if (replacementModel != null) { - return replacementModel; - } + if (replacementModel != null) { + return replacementModel; } return model; diff --git a/fabric-model-loading-api-v1/src/testmodClient/resources/assets/fabric-model-loading-api-v1-testmod/models/half_red_sand.json b/fabric-model-loading-api-v1/src/testmodClient/resources/assets/fabric-model-loading-api-v1-testmod/models/half_red_sand.json index ea15269ffe..4d79f0ef30 100644 --- a/fabric-model-loading-api-v1/src/testmodClient/resources/assets/fabric-model-loading-api-v1-testmod/models/half_red_sand.json +++ b/fabric-model-loading-api-v1/src/testmodClient/resources/assets/fabric-model-loading-api-v1-testmod/models/half_red_sand.json @@ -1,7 +1,8 @@ { "textures": { "sand": "minecraft:block/sand", - "red_sand": "minecraft:block/red_sand" + "red_sand": "minecraft:block/red_sand", + "particle": "#sand" }, "elements": [ { diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/BuiltinItemRenderer.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/BuiltinItemRenderer.java deleted file mode 100644 index 2ea0bea1ff..0000000000 --- a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/BuiltinItemRenderer.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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.api.client.rendering.v1; - -import net.minecraft.client.render.VertexConsumerProvider; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; - -/** - * Builtin item renderers render items with custom code. - * They allow using non-model rendering, such as BERs, for items. - * - *

An item with a builtin renderer must have a model extending {@code minecraft:builtin/entity}. - * The renderers are registered with {@link BuiltinItemRendererRegistry#register(Item, BuiltinItemRenderer)}. - * - * @deprecated Please use {@link BuiltinItemRendererRegistry.DynamicItemRenderer} instead. - */ -@Deprecated -@FunctionalInterface -public interface BuiltinItemRenderer { - /** - * Renders an item stack. - * - * @param stack the rendered item stack - * @param matrices the matrix stack - * @param vertexConsumers the vertex consumer provider - * @param light the color light multiplier at the rendering position - * @param overlay the overlay UV passed to {@link net.minecraft.client.render.VertexConsumer#overlay(int)} - */ - void render(ItemStack stack, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay); -} diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/BuiltinItemRendererRegistry.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/BuiltinItemRendererRegistry.java deleted file mode 100644 index 7500996bfe..0000000000 --- a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/api/client/rendering/v1/BuiltinItemRendererRegistry.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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.api.client.rendering.v1; - -import org.jetbrains.annotations.Nullable; - -import net.minecraft.client.render.VertexConsumerProvider; -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.item.Item; -import net.minecraft.item.ItemConvertible; -import net.minecraft.item.ItemStack; -import net.minecraft.item.ModelTransformationMode; - -import net.fabricmc.fabric.impl.client.rendering.BuiltinItemRendererRegistryImpl; - -/** - * This registry holds {@linkplain DynamicItemRenderer builtin item renderers} for items. - */ -// TODO 1.21.4, class_10444/class_10515 -public interface BuiltinItemRendererRegistry { - /** - * The singleton instance of the renderer registry. - * Use this instance to call the methods in this interface. - */ - BuiltinItemRendererRegistry INSTANCE = new BuiltinItemRendererRegistryImpl(); - - /** - * Registers the renderer for the item. - * - *

Note that the item's JSON model must also extend {@code minecraft:builtin/entity}. - * - * @param item the item - * @param renderer the renderer - * @throws IllegalArgumentException if the item already has a registered renderer - * @throws NullPointerException if either the item or the renderer is null - * @deprecated Please use {@link BuiltinItemRendererRegistry#register(ItemConvertible, DynamicItemRenderer)} instead. - */ - @Deprecated - void register(Item item, BuiltinItemRenderer renderer); - - /** - * Registers the renderer for the item. - * - *

Note that the item's JSON model must also extend {@code minecraft:builtin/entity}. - * - * @param item the item - * @param renderer the renderer - * @throws IllegalArgumentException if the item already has a registered renderer - * @throws NullPointerException if either the item or the renderer is null - * @deprecated Please use {@link BuiltinItemRendererRegistry#register(ItemConvertible, DynamicItemRenderer)} instead. - */ - @Deprecated - void register(ItemConvertible item, BuiltinItemRenderer renderer); - - /** - * Registers the renderer for the item. - * - *

Note that the item's JSON model must also extend {@code minecraft:builtin/entity}. - * - * @param item the item - * @param renderer the renderer - * @throws IllegalArgumentException if the item already has a registered renderer - * @throws NullPointerException if either the item or the renderer is null - */ - void register(ItemConvertible item, DynamicItemRenderer renderer); - - /** - * Returns the renderer for the item, or {@code null} if the item has no renderer. - */ - @Nullable - DynamicItemRenderer get(ItemConvertible item); - - /** - * Dynamic item renderers render items with custom code. - * They allow using non-model rendering, such as BERs, for items. - * - *

An item with a dynamic renderer must have a model extending {@code minecraft:builtin/entity}. - * The renderers are registered with {@link BuiltinItemRendererRegistry#register(ItemConvertible, DynamicItemRenderer)}. - */ - @FunctionalInterface - interface DynamicItemRenderer { - /** - * Renders an item stack. - * - * @param stack the rendered item stack - * @param mode the model transformation mode - * @param matrices the matrix stack - * @param vertexConsumers the vertex consumer provider - * @param light packed lightmap coordinates - * @param overlay the overlay UV passed to {@link net.minecraft.client.render.VertexConsumer#overlay(int)} - */ - void render(ItemStack stack, ModelTransformationMode mode, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay); - } -} diff --git a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/impl/client/rendering/BuiltinItemRendererRegistryImpl.java b/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/impl/client/rendering/BuiltinItemRendererRegistryImpl.java deleted file mode 100644 index 8fe0e5239e..0000000000 --- a/fabric-rendering-v1/src/client/java/net/fabricmc/fabric/impl/client/rendering/BuiltinItemRendererRegistryImpl.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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.rendering; - -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; - -import org.jetbrains.annotations.Nullable; - -import net.minecraft.item.Item; -import net.minecraft.item.ItemConvertible; -import net.minecraft.registry.Registries; - -import net.fabricmc.fabric.api.client.rendering.v1.BuiltinItemRenderer; -import net.fabricmc.fabric.api.client.rendering.v1.BuiltinItemRendererRegistry; - -public final class BuiltinItemRendererRegistryImpl implements BuiltinItemRendererRegistry { - private static final Map RENDERERS = new HashMap<>(); - - public BuiltinItemRendererRegistryImpl() { - } - - @Override - public void register(Item item, BuiltinItemRenderer renderer) { - Objects.requireNonNull(renderer, "renderer is null"); - this.register(item, (stack, mode, matrices, vertexConsumers, light, overlay) -> renderer.render(stack, matrices, vertexConsumers, light, overlay)); - } - - @Override - public void register(ItemConvertible item, BuiltinItemRenderer renderer) { - Objects.requireNonNull(item, "item is null"); - register(item.asItem(), renderer); - } - - @Override - public void register(ItemConvertible item, DynamicItemRenderer renderer) { - Objects.requireNonNull(item, "item is null"); - Objects.requireNonNull(item.asItem(), "item is null"); - Objects.requireNonNull(renderer, "renderer is null"); - - if (RENDERERS.putIfAbsent(item.asItem(), renderer) != null) { - throw new IllegalArgumentException("Item " + Registries.ITEM.getId(item.asItem()) + " already has a builtin renderer!"); - } - } - - @Override - @Nullable - public DynamicItemRenderer get(ItemConvertible item) { - Objects.requireNonNull(item.asItem(), "item is null"); - - return RENDERERS.get(item.asItem()); - } -} diff --git a/settings.gradle b/settings.gradle index 99249ed590..b135db168c 100644 --- a/settings.gradle +++ b/settings.gradle @@ -48,7 +48,7 @@ include 'fabric-key-binding-api-v1' include 'fabric-lifecycle-events-v1' include 'fabric-loot-api-v3' include 'fabric-message-api-v1' -//include 'fabric-model-loading-api-v1' +include 'fabric-model-loading-api-v1' include 'fabric-networking-api-v1' include 'fabric-object-builder-api-v1' include 'fabric-particles-v1'