From fa7108e6e848fa07b7d5f6ab1e2ec64cde42fa0f Mon Sep 17 00:00:00 2001 From: Adrian Siekierka Date: Fri, 28 Dec 2018 22:58:19 +0100 Subject: [PATCH 1/2] Model loading hooks (#39) --- build.gradle | 4 +- .../api/client/model/ModelAppender.java | 27 +++ .../client/model/ModelLoadingRegistry.java | 47 +++++ .../client/model/ModelProviderContext.java | 36 ++++ .../client/model/ModelProviderException.java | 27 +++ .../client/model/ModelResourceProvider.java | 52 +++++ .../client/model/ModelVariantProvider.java | 49 +++++ .../impl/client/model/ModelLoaderHooks.java | 26 +++ .../model/ModelLoadingRegistryImpl.java | 188 ++++++++++++++++++ .../mixin/client/model/MixinModelLoader.java | 106 ++++++++++ src/main/resources/fabric.mod.json | 2 +- .../net.fabricmc.fabric.mixins.client.json | 1 + .../fabricmc/fabric/model/ModelModClient.java | 126 ++++++++++++ 13 files changed, 688 insertions(+), 3 deletions(-) create mode 100644 src/main/java/net/fabricmc/fabric/api/client/model/ModelAppender.java create mode 100644 src/main/java/net/fabricmc/fabric/api/client/model/ModelLoadingRegistry.java create mode 100644 src/main/java/net/fabricmc/fabric/api/client/model/ModelProviderContext.java create mode 100644 src/main/java/net/fabricmc/fabric/api/client/model/ModelProviderException.java create mode 100644 src/main/java/net/fabricmc/fabric/api/client/model/ModelResourceProvider.java create mode 100644 src/main/java/net/fabricmc/fabric/api/client/model/ModelVariantProvider.java create mode 100644 src/main/java/net/fabricmc/fabric/impl/client/model/ModelLoaderHooks.java create mode 100644 src/main/java/net/fabricmc/fabric/impl/client/model/ModelLoadingRegistryImpl.java create mode 100644 src/main/java/net/fabricmc/fabric/mixin/client/model/MixinModelLoader.java create mode 100644 src/test/java/net/fabricmc/fabric/model/ModelModClient.java diff --git a/build.gradle b/build.gradle index 2515605db..2839ee5f0 100644 --- a/build.gradle +++ b/build.gradle @@ -26,7 +26,7 @@ targetCompatibility = 1.8 archivesBaseName = "fabric" -def baseVersion = "0.1.2" +def baseVersion = "0.1.3" def mcVersion = "18w50a" def ENV = System.getenv() @@ -38,7 +38,7 @@ minecraft { dependencies { minecraft "com.mojang:minecraft:$mcVersion" - mappings "net.fabricmc:yarn:$mcVersion.59" + mappings "net.fabricmc:yarn:$mcVersion.64" modCompile "net.fabricmc:fabric-loader:0.3.0.74" } diff --git a/src/main/java/net/fabricmc/fabric/api/client/model/ModelAppender.java b/src/main/java/net/fabricmc/fabric/api/client/model/ModelAppender.java new file mode 100644 index 000000000..224e4aa42 --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/api/client/model/ModelAppender.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016, 2017, 2018 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; + +import net.minecraft.client.util.ModelIdentifier; +import net.minecraft.resource.ResourceManager; + +import java.util.function.Consumer; + +@FunctionalInterface +public interface ModelAppender { + void appendAll(ResourceManager manager, Consumer out); +} diff --git a/src/main/java/net/fabricmc/fabric/api/client/model/ModelLoadingRegistry.java b/src/main/java/net/fabricmc/fabric/api/client/model/ModelLoadingRegistry.java new file mode 100644 index 000000000..81f287928 --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/api/client/model/ModelLoadingRegistry.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2016, 2017, 2018 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; + +import net.fabricmc.fabric.impl.client.model.ModelLoadingRegistryImpl; +import net.minecraft.resource.ResourceManager; + +import java.util.function.Function; + +public interface ModelLoadingRegistry { + ModelLoadingRegistry INSTANCE = ModelLoadingRegistryImpl.INSTANCE; + + /** + * Register a model appender, which can request loading additional models. + * + * @param appender + */ + void registerAppender(ModelAppender appender); + + /** + * Register a ModelResourceProvider supplier. + * + * @param providerSupplier The ModelResourceProvider supplier, instantiated with every ModelLoader. + */ + void registerResourceProvider(Function providerSupplier); + + /** + * Register a ModelVariantProvider supplier. + * + * @param providerSupplier The ModelVariantProvider supplier, instantiated with every ModelLoader. + */ + void registerVariantProvider(Function providerSupplier); +} diff --git a/src/main/java/net/fabricmc/fabric/api/client/model/ModelProviderContext.java b/src/main/java/net/fabricmc/fabric/api/client/model/ModelProviderContext.java new file mode 100644 index 000000000..7e9e79f81 --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/api/client/model/ModelProviderContext.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2016, 2017, 2018 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; + +import net.minecraft.client.render.model.UnbakedModel; +import net.minecraft.client.util.ModelIdentifier; +import net.minecraft.util.Identifier; + +/** + * The model loading context used during model providing. + */ +public interface ModelProviderContext { + /** + * Load a model using a {@link Identifier}, {@link ModelIdentifier}, ... + * + * Please note that the game engine keeps track of circular model loading calls on its own. + * + * @param id The model identifier. + * @return The UnbakedModel. Can return a missing model if it's not present! + */ + UnbakedModel loadModel(Identifier id); +} diff --git a/src/main/java/net/fabricmc/fabric/api/client/model/ModelProviderException.java b/src/main/java/net/fabricmc/fabric/api/client/model/ModelProviderException.java new file mode 100644 index 000000000..b15738614 --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/api/client/model/ModelProviderException.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016, 2017, 2018 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; + +public class ModelProviderException extends Exception { + public ModelProviderException(String s) { + super(s); + } + + public ModelProviderException(String s, Throwable t) { + super(s, t); + } +} diff --git a/src/main/java/net/fabricmc/fabric/api/client/model/ModelResourceProvider.java b/src/main/java/net/fabricmc/fabric/api/client/model/ModelResourceProvider.java new file mode 100644 index 000000000..c2c790ce1 --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/api/client/model/ModelResourceProvider.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2016, 2017, 2018 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; + +import net.minecraft.client.render.model.UnbakedModel; +import net.minecraft.client.util.ModelIdentifier; +import net.minecraft.util.Identifier; + +/** + * Interface for model resource providers. + * + * Model resource providers hook the loading of model *files* from the resource tree; + * that is, in vanilla, it handles going from "minecraft:block/stone" to a + * "assets/minecraft/models/block/stone.json" file. + * + * This is where you want to add your own custom model formats. + * + * As providers are instantiated with a new provider, it is safe + * (and recommended!) to cache information inside a loader. + * + * Keep in mind that only *one* ModelResourceProvider may respond to a given model + * at any time. If you're writing, say, an OBJ loader, this means you could + * easily conflict with another OBJ loader unless you take some precautions, + * for example: + * + * a) Only load files with a mod-suffixed name, such as .architect.obj, + * b) Only load files from an explicit list of namespaces, registered elsewhere. + */ +@FunctionalInterface +public interface ModelResourceProvider { + + /** + * @param resourceId The resource identifier to be loaded. + * @return The loaded UnbakedModel, or null if this ModelResourceProvider doesn't handle a specific Identifier + * (or if there was no error!). + */ + /* @Nullable */ UnbakedModel loadModelResource(Identifier resourceId, ModelProviderContext context) throws ModelProviderException; +} diff --git a/src/main/java/net/fabricmc/fabric/api/client/model/ModelVariantProvider.java b/src/main/java/net/fabricmc/fabric/api/client/model/ModelVariantProvider.java new file mode 100644 index 000000000..eac625d9a --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/api/client/model/ModelVariantProvider.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2016, 2017, 2018 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; + +import net.minecraft.client.render.model.UnbakedModel; +import net.minecraft.client.util.ModelIdentifier; +import net.minecraft.util.Identifier; + +/** + * Interface for model variant providers. + * + * Model variant providers hook the resolution of ModelIdentifiers. In vanilla, this is + * the part where a "minecraft:stone#normal" identifier triggers the loading of a + * "minecraft:models/stone" model ({@link ModelResourceProvider} handles the later step). + * + * The most common use of this is to cooperate with a {@link ModelAppender}, but it can + * also allow you to add your own block- or item-state formats. To trigger the loading + * of another model, use the passed {@link ModelProviderContext}. + * + * As every model loading is instantiated with a new provider, it is safe + * (and recommended!) to cache information. + * + * Keep in mind that only *one* ModelVariantProvider may respond to a given model + * at any time. + */ +@FunctionalInterface +public interface ModelVariantProvider { + + /** + * @param modelId The model identifier, complete with variant. + * @return The loaded UnbakedModel, or null if this ModelVariantProvider doesn't handle a specific Identifier + * (or if there was no error!). + */ + /* @Nullable */ UnbakedModel loadModelVariant(ModelIdentifier modelId, ModelProviderContext context) throws ModelProviderException; +} diff --git a/src/main/java/net/fabricmc/fabric/impl/client/model/ModelLoaderHooks.java b/src/main/java/net/fabricmc/fabric/impl/client/model/ModelLoaderHooks.java new file mode 100644 index 000000000..2c07c8364 --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/impl/client/model/ModelLoaderHooks.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016, 2017, 2018 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 net.minecraft.client.render.model.UnbakedModel; +import net.minecraft.client.util.ModelIdentifier; +import net.minecraft.util.Identifier; + +public interface ModelLoaderHooks { + public void fabric_addModel(ModelIdentifier id); + public UnbakedModel fabric_loadModel(Identifier id); +} diff --git a/src/main/java/net/fabricmc/fabric/impl/client/model/ModelLoadingRegistryImpl.java b/src/main/java/net/fabricmc/fabric/impl/client/model/ModelLoadingRegistryImpl.java new file mode 100644 index 000000000..287d05e6a --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/impl/client/model/ModelLoadingRegistryImpl.java @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2016, 2017, 2018 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 com.google.common.collect.Lists; +import com.sun.istack.internal.Nullable; +import net.fabricmc.fabric.api.client.model.*; +import net.fabricmc.loader.launch.common.FabricLauncherBase; +import net.minecraft.client.render.model.ModelLoader; +import net.minecraft.client.render.model.UnbakedModel; +import net.minecraft.client.util.ModelIdentifier; +import net.minecraft.resource.ResourceManager; +import net.minecraft.util.Identifier; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.*; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class ModelLoadingRegistryImpl implements ModelLoadingRegistry { + private static final boolean DEBUG_MODEL_LOADING = FabricLauncherBase.getLauncher().isDevelopment() + || Boolean.valueOf(System.getProperty("fabric.debugModelLoading", "false")); + + @FunctionalInterface + private static interface CustomModelItf { + UnbakedModel load(T obj) throws ModelProviderException; + } + + public static class LoaderInstance implements ModelProviderContext { + private final Logger logger; + private final ResourceManager manager; + private final List modelVariantProviders; + private final List modelResourceProviders; + private final List modelAppenders; + private ModelLoader loader; + + private LoaderInstance(ModelLoadingRegistryImpl i, ModelLoader loader, ResourceManager manager) { + this.logger = ModelLoadingRegistryImpl.LOGGER; + this.loader = loader; + this.manager = manager; + this.modelVariantProviders = i.variantProviderSuppliers.stream().map((s) -> s.apply(manager)).collect(Collectors.toList()); + this.modelResourceProviders = i.resourceProviderSuppliers.stream().map((s) -> s.apply(manager)).collect(Collectors.toList()); + this.modelAppenders = i.appenders; + } + + @Override + public UnbakedModel loadModel(Identifier id) { + if (loader == null) { + throw new RuntimeException("Called loadModel too late!"); + } + + return ((ModelLoaderHooks) loader).fabric_loadModel(id); + } + + public void onModelPopulation(Consumer addModel) { + for (ModelAppender appender : modelAppenders) { + appender.appendAll(manager, addModel); + } + } + + private UnbakedModel loadCustomModel(CustomModelItf function, Collection loaders, String debugName) { + if (!DEBUG_MODEL_LOADING) { + for (T provider : loaders) { + try { + UnbakedModel model = function.load(provider); + if (model != null) { + return model; + } + } catch (ModelProviderException e) { + logger.error(e); + return null; + } + } + + return null; + } + + UnbakedModel modelLoaded = null; + T providerUsed = null; + List providersApplied = null; + + for (T provider : loaders) { + try { + UnbakedModel model = function.load(provider); + if (model != null) { + if (providersApplied != null) { + providersApplied.add(provider); + } else if (providerUsed != null) { + providersApplied = Lists.newArrayList(providerUsed, provider); + } else { + modelLoaded = model; + providerUsed = provider; + } + } + } catch (ModelProviderException e) { + logger.error(e); + return null; + } + } + + if (providersApplied != null) { + StringBuilder builder = new StringBuilder("Conflict - multiple " + debugName + "s claimed the same unbaked model:"); + for (T loader : providersApplied) { + builder.append("\n\t - ").append(loader.getClass().getName()); + } + logger.error(builder.toString()); + return null; + } else { + return modelLoaded; + } + } + + @Nullable + public UnbakedModel loadModelFromResource(Identifier resourceId) { + return loadCustomModel((r) -> r.loadModelResource(resourceId, this), modelResourceProviders, "resource provider"); + } + + @Nullable + public UnbakedModel loadModelFromVariant(Identifier variantId) { + if (!(variantId instanceof ModelIdentifier)) { + return loadModelFromResource(variantId); + } else { + ModelIdentifier modelId = (ModelIdentifier) variantId; + UnbakedModel model = loadCustomModel((r) -> r.loadModelVariant((ModelIdentifier) variantId, this), modelVariantProviders, "resource provider"); + if (model != null) { + return model; + } + + // Replicating the special-case from ModelLoader as loadModelFromJson is insufficiently patchable + if (Objects.equals(modelId.getVariant(), "inventory")) { + Identifier resourceId = new Identifier(modelId.getNamespace(), "item/" + modelId.getPath()); + model = loadModelFromResource(resourceId); + if (model != null) { + return model; + } + } + + return null; + } + } + + public void finish() { + loader = null; + } + } + + private static final Logger LOGGER = LogManager.getLogger(); + public static final ModelLoadingRegistryImpl INSTANCE = new ModelLoadingRegistryImpl(); + + private final List> variantProviderSuppliers = new ArrayList<>(); + private final List> resourceProviderSuppliers = new ArrayList<>(); + private final List appenders = new ArrayList<>(); + + @Override + public void registerAppender(ModelAppender appender) { + appenders.add(appender); + } + + @Override + public void registerResourceProvider(Function providerSupplier) { + resourceProviderSuppliers.add(providerSupplier); + } + + @Override + public void registerVariantProvider(Function providerSupplier) { + variantProviderSuppliers.add(providerSupplier); + } + + public static LoaderInstance begin(ModelLoader loader, ResourceManager manager) { + return new LoaderInstance(INSTANCE, loader, manager); + } +} diff --git a/src/main/java/net/fabricmc/fabric/mixin/client/model/MixinModelLoader.java b/src/main/java/net/fabricmc/fabric/mixin/client/model/MixinModelLoader.java new file mode 100644 index 000000000..408d26ee0 --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/mixin/client/model/MixinModelLoader.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2016, 2017, 2018 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; + +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import net.fabricmc.fabric.impl.client.model.ModelLoaderHooks; +import net.fabricmc.fabric.impl.client.model.ModelLoadingRegistryImpl; +import net.minecraft.client.render.model.ModelLoader; +import net.minecraft.client.render.model.UnbakedModel; +import net.minecraft.client.util.ModelIdentifier; +import net.minecraft.resource.ResourceManager; +import net.minecraft.util.Identifier; +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.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.Map; +import java.util.Set; + +@Mixin(ModelLoader.class) +public class MixinModelLoader implements ModelLoaderHooks { + // this is the first one + @Shadow + public static ModelIdentifier MISSING; + @Shadow + private ResourceManager resourceContainer; + @Shadow + private Set field_5390; + @Shadow + private Map unbakedModels; + + private ModelLoadingRegistryImpl.LoaderInstance fabric_mlrLoaderInstance; + + @Shadow + private void addModel(ModelIdentifier id) { + + } + + @Shadow + private void putModel(Identifier id, UnbakedModel unbakedModel) { + + } + + @Shadow + private void loadModel(Identifier id) { + + } + + @Inject(at = @At("HEAD"), method = "loadModel", cancellable = true) + private void loadModelHook(Identifier id, CallbackInfo ci) { + UnbakedModel customModel = fabric_mlrLoaderInstance.loadModelFromVariant(id); + if (customModel != null) { + putModel(id, customModel); + ci.cancel(); + } + } + + @Inject(at = @At("HEAD"), method = "addModel") + private void addModelHook(ModelIdentifier id, CallbackInfo info) { + if (id == MISSING) { + //noinspection RedundantCast + ModelLoaderHooks hooks = (ModelLoaderHooks) (Object) this; + + fabric_mlrLoaderInstance = ModelLoadingRegistryImpl.begin((ModelLoader) (Object) this, resourceContainer); + fabric_mlrLoaderInstance.onModelPopulation(hooks::fabric_addModel); + } + } + + @Inject(at = @At("RETURN"), method = "") + private void initFinishedHook(CallbackInfo info) { + //noinspection ConstantConditions + fabric_mlrLoaderInstance.finish(); + } + + @Override + public void fabric_addModel(ModelIdentifier id) { + addModel(id); + } + + @Override + public UnbakedModel fabric_loadModel(Identifier id) { + if (!field_5390.add(id)) { + throw new IllegalStateException("Circular reference while loading " + id); + } + loadModel(id); + field_5390.remove(id); + return unbakedModels.get(id); + } +} diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index b2ad0f055..345e7e971 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -1,7 +1,7 @@ { "id": "fabric", "name": "Fabric API", - "version": "0.1.2", + "version": "0.1.3", "side": "universal", "description": "Core API module providing key hooks and intercompatibility features.", "license": "Apache-2.0", diff --git a/src/main/resources/net.fabricmc.fabric.mixins.client.json b/src/main/resources/net.fabricmc.fabric.mixins.client.json index b4f122565..b95567397 100644 --- a/src/main/resources/net.fabricmc.fabric.mixins.client.json +++ b/src/main/resources/net.fabricmc.fabric.mixins.client.json @@ -7,6 +7,7 @@ "bugfix.MixinBiomeColors", "client.itemgroup.MixinItemGroup", "client.itemgroup.MixinCreativePlayerInventoryGui", + "client.model.MixinModelLoader", "client.render.MixinBlockColorMap", "client.render.MixinBlockEntityRenderManager", "client.render.MixinEntityRenderManager", diff --git a/src/test/java/net/fabricmc/fabric/model/ModelModClient.java b/src/test/java/net/fabricmc/fabric/model/ModelModClient.java new file mode 100644 index 000000000..0746b6c05 --- /dev/null +++ b/src/test/java/net/fabricmc/fabric/model/ModelModClient.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2016, 2017, 2018 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.model; + +import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.fabric.api.client.model.ModelLoadingRegistry; +import net.fabricmc.fabric.events.client.ClientTickEvent; +import net.minecraft.block.BlockState; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.model.*; +import net.minecraft.client.render.model.json.ModelItemPropertyOverrideList; +import net.minecraft.client.render.model.json.ModelTransformation; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.util.ModelIdentifier; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.Direction; + +import java.util.*; +import java.util.function.Function; + +public class ModelModClient implements ClientModInitializer { + private static BakedModel bakedModel; + + @Override + public void onInitializeClient() { + ModelLoadingRegistry.INSTANCE.registerAppender((manager, out) -> { + System.out.println("--- ModelAppender called! ---"); + out.accept(new ModelIdentifier("fabric:model#custom")); + }); + + ModelLoadingRegistry.INSTANCE.registerVariantProvider(manager -> ((modelId, context) -> { + if (modelId.getVariant().equals("custom") && modelId.getNamespace().equals("fabric")) { + System.out.println("--- ModelVariantProvider called! ---"); + return context.loadModel(new Identifier("fabric:custom")); + } else { + return null; + } + })); + + ModelLoadingRegistry.INSTANCE.registerResourceProvider(manager -> ((id, context) -> { + if (id.toString().equals("fabric:custom")) { + return context.loadModel(new Identifier("fabric:custom2")); + } else if (id.toString().equals("fabric:custom2")) { + System.out.println("--- ModelResourceProvider called! ---"); + return new UnbakedModel() { + @Override + public Collection getModelDependencies() { + return Collections.emptyList(); + } + + @Override + public Collection getTextureDependencies(Function var1, Set var2) { + return Collections.emptyList(); + } + + @Override + public BakedModel bake(ModelLoader var1, Function var2, ModelRotationContainer var3) { + System.out.println("--- Model baked! ---"); + + return bakedModel = new BakedModel() { + @Override + public List getQuads(BlockState var1, Direction var2, Random var3) { + return Collections.emptyList(); + } + + @Override + public boolean useAmbientOcclusion() { + return false; + } + + @Override + public boolean hasDepthInGui() { + return false; + } + + @Override + public boolean isBuiltin() { + return false; + } + + @Override + public Sprite getSprite() { + return MinecraftClient.getInstance().getSpriteAtlas().getSprite("missingno"); + } + + @Override + public ModelTransformation getTransformations() { + return ModelTransformation.ORIGIN; + } + + @Override + public ModelItemPropertyOverrideList getItemPropertyOverrides() { + return ModelItemPropertyOverrideList.ORIGIN; + } + }; + } + }; + } else { + return null; + } + })); + + ClientTickEvent.CLIENT.register((client) -> { + if (client.getBakedModelManager().getModel(new ModelIdentifier("fabric:model#custom")) + == bakedModel && bakedModel != null) { + System.out.println("--- MODEL LOADED! ---"); + } else { + System.out.println("--- MODEL NOT LOADED! ---"); + } + }); + } +} From ae4f5b739e464ba48f2fde336ffb02f74267144a Mon Sep 17 00:00:00 2001 From: Adrian Siekierka Date: Fri, 28 Dec 2018 23:00:26 +0100 Subject: [PATCH 2/2] compile fix --- .../fabric/impl/client/model/ModelLoadingRegistryImpl.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/fabricmc/fabric/impl/client/model/ModelLoadingRegistryImpl.java b/src/main/java/net/fabricmc/fabric/impl/client/model/ModelLoadingRegistryImpl.java index 287d05e6a..2bf84f206 100644 --- a/src/main/java/net/fabricmc/fabric/impl/client/model/ModelLoadingRegistryImpl.java +++ b/src/main/java/net/fabricmc/fabric/impl/client/model/ModelLoadingRegistryImpl.java @@ -17,7 +17,6 @@ package net.fabricmc.fabric.impl.client.model; import com.google.common.collect.Lists; -import com.sun.istack.internal.Nullable; import net.fabricmc.fabric.api.client.model.*; import net.fabricmc.loader.launch.common.FabricLauncherBase; import net.minecraft.client.render.model.ModelLoader; @@ -126,12 +125,12 @@ public class ModelLoadingRegistryImpl implements ModelLoadingRegistry { } } - @Nullable + /* @Nullable */ public UnbakedModel loadModelFromResource(Identifier resourceId) { return loadCustomModel((r) -> r.loadModelResource(resourceId, this), modelResourceProviders, "resource provider"); } - @Nullable + /* @Nullable */ public UnbakedModel loadModelFromVariant(Identifier variantId) { if (!(variantId instanceof ModelIdentifier)) { return loadModelFromResource(variantId);