Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Model Loading API v1 #3145

Merged
merged 28 commits into from
Jul 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
177b15d
Model Loading API v1
Technici4n Jun 25, 2023
b953a2f
Update module lifecycle
Technici4n Jun 25, 2023
efac33b
Remove test dependencies
Technici4n Jun 25, 2023
91ab1fc
Add events to override and wrap models
embeddedt Jun 26, 2023
d0b83de
A few post-merge tweaks
Technici4n Jun 26, 2023
117198a
Fix model wrapping test and use event phases
Technici4n Jun 26, 2023
8471da4
Context interfaces, ModelResolver class, event renames
Technici4n Jun 28, 2023
5197009
Implementation clean up (#2)
PepperCode1 Jul 1, 2023
833d269
Address PR comments
Technici4n Jul 2, 2023
4a574a3
Add ModelLoader to resolver context and remove allocations
Technici4n Jul 2, 2023
448c35f
identifiers -> ids
Technici4n Jul 3, 2023
bda86cb
Fix nested model loading issues
Technici4n Jul 4, 2023
27fb23d
Fix nested model modifier context, add non-extendable annotations
Technici4n Jul 6, 2023
1070100
Add preparable model loading plugins draft
Technici4n Jul 6, 2023
bb156a6
Add off-thread loading test, remove direct ResourceManager access
Technici4n Jul 6, 2023
e86729a
Add draft of block state resolver
PepperCode1 Jul 9, 2023
b2ff9ed
A bit of cleanup
Technici4n Jul 9, 2023
4a13dd1
Further work on block state resolution
Technici4n Jul 10, 2023
12724f1
Add test for blockstate resolution
Technici4n Jul 10, 2023
1014443
Improve implementation, API, test mod (#3)
PepperCode1 Jul 11, 2023
d72470d
Item model, javadoc, and v0 bridge improvements
Technici4n Jul 12, 2023
d1c33d8
Improve legacy variant provider handling
Technici4n Jul 12, 2023
8651bad
WrapperUnbakedModel -> DelegatingUnbakedModel
Technici4n Jul 12, 2023
087dffc
Tweaks for modern fix
Technici4n Jul 13, 2023
130cd79
Improve documentation
PepperCode1 Jul 15, 2023
aed670e
Address review comments
Technici4n Jul 15, 2023
5e4e6d7
Apply suggestions from code review
Technici4n Jul 15, 2023
65dc088
Update fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabri…
Technici4n Jul 16, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions deprecated/fabric-models-v0/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
archivesBaseName = "fabric-models-v0"
version = getSubprojectVersion(project)

moduleDependencies(project, [
'fabric-api-base',
'fabric-model-loading-api-v1'
])
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,12 @@
import net.minecraft.client.util.ModelIdentifier;
import net.minecraft.util.Identifier;

import net.fabricmc.fabric.impl.client.model.BakedModelManagerHooks;
import net.fabricmc.fabric.api.client.model.loading.v1.FabricBakedModelManager;

/**
* @deprecated Use {@link FabricBakedModelManager#getModel(Identifier)} instead.
*/
@Deprecated
public final class BakedModelManagerHelper {
/**
* An alternative to {@link BakedModelManager#getModel(ModelIdentifier)} that accepts an
Expand All @@ -42,7 +46,7 @@ public final class BakedModelManagerHelper {
*/
@Nullable
public static BakedModel getModel(BakedModelManager manager, Identifier id) {
return ((BakedModelManagerHooks) manager).fabric_getModel(id);
return manager.getModel(id);
}

private BakedModelManagerHelper() { }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@
import net.minecraft.resource.ResourceManager;
import net.minecraft.util.Identifier;

import net.fabricmc.fabric.api.client.model.loading.v1.ModelLoadingPlugin;

/**
* @deprecated Use {@link ModelLoadingPlugin} and related classes instead.
*/
@Deprecated
@FunctionalInterface
public interface ExtraModelProvider {
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,13 @@
import net.minecraft.resource.ResourceManager;
import net.minecraft.util.Identifier;

import net.fabricmc.fabric.api.client.model.loading.v1.ModelLoadingPlugin;
import net.fabricmc.fabric.impl.client.model.ModelLoadingRegistryImpl;

/**
* @deprecated Register a {@link ModelLoadingPlugin} instead.
*/
@Deprecated
public interface ModelLoadingRegistry {
ModelLoadingRegistry INSTANCE = new ModelLoadingRegistryImpl();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,13 @@
import net.minecraft.client.util.ModelIdentifier;
import net.minecraft.util.Identifier;

import net.fabricmc.fabric.api.client.model.loading.v1.ModelLoadingPlugin;

/**
* The model loading context used during model providing.
* @deprecated Use {@link ModelLoadingPlugin} and related classes instead.
*/
@Deprecated
public interface ModelProviderContext {
/**
* Load a model using a {@link Identifier}, {@link ModelIdentifier}, ...
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@

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

import net.fabricmc.fabric.api.client.model.loading.v1.ModelLoadingPlugin;

/**
* @deprecated Use {@link ModelLoadingPlugin} and related classes instead.
*/
@Deprecated
public class ModelProviderException extends Exception {
public ModelProviderException(String s) {
super(s);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import net.minecraft.client.render.model.UnbakedModel;
import net.minecraft.util.Identifier;

import net.fabricmc.fabric.api.client.model.loading.v1.ModelLoadingPlugin;

/**
* Interface for model resource providers.
*
Expand All @@ -40,7 +42,10 @@
*
* <ul><li>Only load files with a mod-suffixed name, such as .architect.obj,
* <li>Only load files from an explicit list of namespaces, registered elsewhere.</ul>
*
* @deprecated Use {@link ModelLoadingPlugin} and related classes instead.
*/
@Deprecated
@FunctionalInterface
public interface ModelResourceProvider {
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import net.minecraft.client.render.model.UnbakedModel;
import net.minecraft.client.util.ModelIdentifier;

import net.fabricmc.fabric.api.client.model.loading.v1.ModelLoadingPlugin;

/**
* Interface for model variant providers.
*
Expand All @@ -37,7 +39,10 @@
*
* <p>Keep in mind that only *one* ModelVariantProvider may respond to a given model
* at any time.
*
* @deprecated Use {@link ModelLoadingPlugin} and related classes instead.
*/
@Deprecated
@FunctionalInterface
public interface ModelVariantProvider {
/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* 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;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.function.Function;

import net.minecraft.client.util.ModelIdentifier;
import net.minecraft.resource.ResourceManager;
import net.minecraft.util.Identifier;

import net.fabricmc.fabric.api.client.model.ExtraModelProvider;
import net.fabricmc.fabric.api.client.model.ModelAppender;
import net.fabricmc.fabric.api.client.model.ModelLoadingRegistry;
import net.fabricmc.fabric.api.client.model.ModelProviderContext;
import net.fabricmc.fabric.api.client.model.ModelProviderException;
import net.fabricmc.fabric.api.client.model.ModelResourceProvider;
import net.fabricmc.fabric.api.client.model.ModelVariantProvider;
import net.fabricmc.fabric.api.client.model.loading.v1.ModelLoadingPlugin;
import net.fabricmc.fabric.api.client.model.loading.v1.PreparableModelLoadingPlugin;
import net.fabricmc.fabric.impl.client.model.loading.ModelLoaderPluginContextImpl;

public class ModelLoadingRegistryImpl implements ModelLoadingRegistry {
private final List<ExtraModelProvider> modelProviders = new ArrayList<>();
private final List<ModelAppender> modelAppenders = new ArrayList<>();
private final List<Function<ResourceManager, ModelResourceProvider>> resourceProviderSuppliers = new ArrayList<>();
private final List<Function<ResourceManager, ModelVariantProvider>> variantProviderSuppliers = new ArrayList<>();

{
// Grabs the resource manager to use it in the main model loading code.
// When using the v1 API, data should be loaded in parallel before model loading starts.
PreparableModelLoadingPlugin.register(
(resourceManager, executor) -> CompletableFuture.completedFuture(resourceManager),
this::onInitializeModelLoader);
}

private void onInitializeModelLoader(ResourceManager resourceManager, ModelLoadingPlugin.Context pluginContext) {
Consumer<Identifier> extraModelConsumer = pluginContext::addModels;
Consumer<ModelIdentifier> extraModelConsumer2 = pluginContext::addModels;
// A bit hacky, but avoids the allocation of a new context wrapper every time.
ModelProviderContext resourceProviderContext = ((ModelLoaderPluginContextImpl) pluginContext).modelGetter::apply;

for (ExtraModelProvider provider : modelProviders) {
provider.provideExtraModels(resourceManager, extraModelConsumer);
}

for (ModelAppender appender : modelAppenders) {
appender.appendAll(resourceManager, extraModelConsumer2);
}

for (Function<ResourceManager, ModelResourceProvider> supplier : resourceProviderSuppliers) {
ModelResourceProvider provider = supplier.apply(resourceManager);

pluginContext.resolveModel().register(resolverContext -> {
try {
return provider.loadModelResource(resolverContext.id(), resourceProviderContext);
} catch (ModelProviderException e) {
throw new RuntimeException(e);
}
});
}

for (Function<ResourceManager, ModelVariantProvider> supplier : variantProviderSuppliers) {
ModelVariantProvider provider = supplier.apply(resourceManager);
((ModelLoaderPluginContextImpl) pluginContext).legacyVariantProviders().register(modelId -> {
try {
return provider.loadModelVariant(modelId, resourceProviderContext);
} catch (ModelProviderException e) {
throw new RuntimeException(e);
}
});
}
}

@Override
public void registerModelProvider(ExtraModelProvider provider) {
modelProviders.add(provider);
}

@Override
public void registerAppender(ModelAppender appender) {
modelAppenders.add(appender);
}

@Override
public void registerResourceProvider(Function<ResourceManager, ModelResourceProvider> providerSupplier) {
resourceProviderSuppliers.add(providerSupplier);
}

@Override
public void registerVariantProvider(Function<ResourceManager, ModelVariantProvider> providerSupplier) {
variantProviderSuppliers.add(providerSupplier);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,11 @@
],
"depends": {
"fabricloader": ">=0.4.0",
"fabric-api-base": "*"
"fabric-api-base": "*",
"fabric-model-loading-api-v1": "*"
},
"description": "Hooks for models and model loading.",
"mixins": [
"fabric-models-v0.mixins.json"
],
"custom": {
"fabric-api:module-lifecycle": "stable"
"fabric-api:module-lifecycle": "deprecated"
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
archivesBaseName = "fabric-models-v0"
archivesBaseName = "fabric-model-loading-api-v1"
version = getSubprojectVersion(project)

moduleDependencies(project, ['fabric-api-base'])

testDependencies(project, [
':fabric-renderer-api-v1',
':fabric-rendering-v1',
':fabric-resource-loader-v0'
])
Original file line number Diff line number Diff line change
@@ -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 org.jetbrains.annotations.ApiStatus;

import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.client.render.model.ModelLoader;
import net.minecraft.client.render.model.UnbakedModel;
import net.minecraft.client.util.ModelIdentifier;
import net.minecraft.util.Identifier;

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

/**
* The context for block state resolution.
*/
@ApiStatus.NonExtendable
interface Context {
/**
* The block for which block state models are being resolved.
*/
Block block();

/**
* Sets the model for a block state.
*
* @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);

/**
* Loads a model using an {@link Identifier} or {@link ModelIdentifier}, or gets it if it was already loaded.
*
* @param id the model identifier
* @return the unbaked model, or a missing model if it is not present
*/
UnbakedModel getOrLoadModel(Identifier id);

/**
* The current model loader instance, which changes between resource reloads.
*
* <p>Do <b>not</b> call {@link ModelLoader#getOrLoadModel} as it does not supported nested model resolution;
* use {@link #getOrLoadModel} from the context instead.
*/
ModelLoader loader();
}
}
Loading