From 236902d814e0402f06c49f44b828fb595f32a963 Mon Sep 17 00:00:00 2001 From: PepperCode1 <44146161+PepperCode1@users.noreply.github.com> Date: Wed, 21 Aug 2024 08:05:05 -0700 Subject: [PATCH] Finish porting Model Loading, FRAPI, and Indigo (#4043) --- .../model/loading/v1/BlockStateResolver.java | 15 -- .../loading/v1/DelegatingUnbakedModel.java | 17 +- .../model/loading/v1/ModelLoadingPlugin.java | 2 +- .../model/loading/v1/ModelModifier.java | 24 --- .../model/loading/v1/ModelResolver.java | 14 -- .../v1/PreparableModelLoadingPlugin.java | 2 +- .../model/loading/ModelLoaderHooks.java | 10 -- .../loading/ModelLoadingEventDispatcher.java | 170 ++++++------------ .../ModelLoadingPluginContextImpl.java | 8 +- .../loading/ModelLoadingPluginManager.java | 9 +- .../model/loading/BakedModelManagerMixin.java | 79 ++++++-- .../model/loading/BlockStatesLoaderMixin.java | 56 ------ .../model/loading/ModelLoaderMixin.java | 147 ++------------- .../model/loading/class_10097Mixin.java | 95 ++++++++++ .../fabric-model-loading-api-v1.mixins.json | 6 +- .../loading/BakedModelFeatureRenderer.java | 18 +- .../model/loading/ModelTestModClient.java | 15 +- .../model/loading/NestedModelLoadingTest.java | 110 ------------ .../testmodClient/resources/fabric.mod.json | 1 - .../api/renderer/v1/mesh/MutableQuadView.java | 28 ++- .../api/renderer/v1/mesh/QuadEmitter.java | 10 +- .../fabric/api/renderer/v1/mesh/QuadView.java | 19 +- .../impl/renderer/VanillaModelEncoder.java | 2 +- .../fabric/test/renderer/FrameBlock.java | 29 +-- .../renderer/client/FrameUnbakedModel.java | 13 -- .../client/OctagonalColumnUnbakedModel.java | 13 -- .../renderer/client/PillarUnbakedModel.java | 14 -- .../client/RiverstoneUnbakedModel.java | 17 +- .../indigo/renderer/IndigoRenderer.java | 1 - .../indigo/renderer/aocalc/AoCalculator.java | 39 +++- .../renderer/aocalc/VanillaAoHelper.java | 13 +- .../renderer/mesh/MutableQuadViewImpl.java | 11 +- .../renderer/render/BlockRenderInfo.java | 4 +- .../renderer/render/ItemRenderContext.java | 2 +- .../renderer/BlockModelRendererMixin.java | 6 - .../indigo/renderer/ItemRendererMixin.java | 8 +- settings.gradle | 6 +- 37 files changed, 380 insertions(+), 653 deletions(-) delete mode 100644 fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/BlockStatesLoaderMixin.java create mode 100644 fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/class_10097Mixin.java delete mode 100644 fabric-model-loading-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/model/loading/NestedModelLoadingTest.java 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 4f350e43d2..4712101bf1 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,9 +20,7 @@ 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.util.Identifier; /** * Block state resolvers are responsible for mapping each {@link BlockState} of a block to an {@link UnbakedModel}. @@ -69,18 +67,5 @@ interface Context { * @param model the unbaked model for this block state */ void setModel(BlockState state, UnbakedModel model); - - /** - * Loads a model using an {@link Identifier}, 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. - */ - ModelLoader loader(); } } 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 index 900a28066a..4e2c80937b 100644 --- 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 @@ -16,8 +16,6 @@ package net.fabricmc.fabric.api.client.model.loading.v1; -import java.util.Collection; -import java.util.List; import java.util.function.Function; import org.jetbrains.annotations.Nullable; @@ -37,7 +35,6 @@ */ public final class DelegatingUnbakedModel implements UnbakedModel { private final Identifier delegate; - private final List dependencies; /** * Constructs a new delegating model. @@ -46,23 +43,11 @@ public final class DelegatingUnbakedModel implements UnbakedModel { */ public DelegatingUnbakedModel(Identifier delegate) { this.delegate = delegate; - this.dependencies = List.of(delegate); - } - - /*@Override - public Collection getModelDependencies() { - return dependencies; } - @Override - public void setParents(Function modelLoader) { - modelLoader.apply(delegate).setParents(modelLoader); - }*/ - - // TODO 24w44a @Override public void method_62326(class_10103 arg, class_10102 arg2) { - + arg.method_62642(delegate); } @Override 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 5d15c84286..ace79da597 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 @@ -47,7 +47,7 @@ static void register(ModelLoadingPlugin plugin) { * Called towards the beginning of the model loading process, every time resource are (re)loaded. * Use the context object to extend model loading as desired. */ - void onInitializeModelLoader(Context pluginContext); + void initialize(Context pluginContext); @ApiStatus.NonExtendable interface Context { 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 0d8596b6db..d3340dc7b5 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 @@ -25,7 +25,6 @@ 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.ModelLoader; import net.minecraft.client.render.model.UnbakedModel; import net.minecraft.client.texture.Sprite; import net.minecraft.client.util.ModelIdentifier; @@ -109,19 +108,6 @@ interface Context { */ @UnknownNullability("#resourceId() != null") ModelIdentifier topLevelId(); - - /** - * Loads a model using an {@link Identifier}, 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. - */ - ModelLoader loader(); } } @@ -177,11 +163,6 @@ interface Context { * {@linkplain Baker#bake load baked models}. */ Baker baker(); - - /** - * The current model loader instance, which changes between resource reloads. - */ - ModelLoader loader(); } } @@ -250,11 +231,6 @@ interface Context { * {@linkplain Baker#bake load baked models}. */ Baker baker(); - - /** - * The current model loader instance, which changes between resource reloads. - */ - ModelLoader loader(); } } 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 index 7f0843e2ca..9ee85033ff 100644 --- 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 @@ -19,7 +19,6 @@ import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; -import net.minecraft.client.render.model.ModelLoader; import net.minecraft.client.render.model.UnbakedModel; import net.minecraft.util.Identifier; @@ -61,18 +60,5 @@ interface Context { * The identifier of the model to be loaded. */ Identifier id(); - - /** - * Loads a model using an {@link Identifier}, 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. - */ - ModelLoader loader(); } } diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/PreparableModelLoadingPlugin.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/PreparableModelLoadingPlugin.java index b900cffc51..b0a3eb526a 100644 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/PreparableModelLoadingPlugin.java +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/PreparableModelLoadingPlugin.java @@ -48,7 +48,7 @@ static void register(DataLoader loader, PreparableModelLoadingPlugin p * @param data The data loaded by the {@link DataLoader}. * @param pluginContext The context that can be used to extend model loading. */ - void onInitializeModelLoader(T data, ModelLoadingPlugin.Context pluginContext); + void initialize(T data, ModelLoadingPlugin.Context pluginContext); @FunctionalInterface interface DataLoader { 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 index 4349886994..4a4a0b7476 100644 --- 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 @@ -16,16 +16,6 @@ package net.fabricmc.fabric.impl.client.model.loading; -import net.minecraft.client.render.model.UnbakedModel; -import net.minecraft.client.util.ModelIdentifier; -import net.minecraft.util.Identifier; - public interface ModelLoaderHooks { ModelLoadingEventDispatcher fabric_getDispatcher(); - - UnbakedModel fabric_getMissingModel(); - - UnbakedModel fabric_getOrLoadModel(Identifier id); - - void fabric_add(ModelIdentifier id, UnbakedModel model); } 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 7d6a3dcc5e..34daf56bf8 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 @@ -16,8 +16,12 @@ package net.fabricmc.fabric.impl.client.model.loading; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; +import java.util.Optional; +import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Function; @@ -35,13 +39,14 @@ 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.ModelLoader; 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.state.StateManager; +import net.minecraft.registry.Registries; +import net.minecraft.registry.RegistryKey; import net.minecraft.util.Identifier; import net.fabricmc.fabric.api.client.model.loading.v1.BlockStateResolver; @@ -51,24 +56,23 @@ public class ModelLoadingEventDispatcher { private static final Logger LOGGER = LoggerFactory.getLogger(ModelLoadingEventDispatcher.class); + public static final ThreadLocal CURRENT = new ThreadLocal<>(); - private final ModelLoader loader; private final ModelLoadingPluginContextImpl pluginContext; - private final ObjectArrayList modelResolverContextStack = new ObjectArrayList<>(); + private final ModelResolverContext modelResolverContext = new ModelResolverContext(); private final BlockStateResolverContext blockStateResolverContext = new BlockStateResolverContext(); - private final ObjectArrayList onLoadModifierContextStack = new ObjectArrayList<>(); + private final OnLoadModifierContext onLoadModifierContext = new OnLoadModifierContext(); private final ObjectArrayList beforeBakeModifierContextStack = new ObjectArrayList<>(); private final ObjectArrayList afterBakeModifierContextStack = new ObjectArrayList<>(); - public ModelLoadingEventDispatcher(ModelLoader loader, List plugins) { - this.loader = loader; + public ModelLoadingEventDispatcher(List plugins) { this.pluginContext = new ModelLoadingPluginContextImpl(); for (ModelLoadingPlugin plugin : plugins) { try { - plugin.onInitializeModelLoader(pluginContext); + plugin.initialize(pluginContext); } catch (Exception exception) { LOGGER.error("Failed to initialize model loading plugin", exception); } @@ -81,18 +85,30 @@ public void addExtraModels(Consumer extraModelConsumer) { } } - public boolean loadBlockStateModels(Identifier id, StateManager stateManager) { - BlockStateResolver resolver = pluginContext.blockStateResolvers.get(id); + public BlockStatesLoader.class_10095 loadBlockStateModels() { + Map map = new HashMap<>(); - if (resolver != null) { - resolveBlockStates(resolver, stateManager.getOwner(), id); - return true; - } else { - return false; - } + pluginContext.blockStateResolvers.forEach((block, resolver) -> { + Optional> optionalKey = Registries.BLOCK.getKey(block); + + if (optionalKey.isEmpty()) { + return; + } + + Identifier blockId = optionalKey.get().getValue(); + + BiConsumer output = (state, model) -> { + ModelIdentifier modelId = BlockModels.getModelId(blockId, state); + map.put(modelId, new BlockStatesLoader.BlockModel(state, model)); + }; + + resolveBlockStates(resolver, block, output); + }); + + return new BlockStatesLoader.class_10095(map); } - private void resolveBlockStates(BlockStateResolver resolver, Block block, Identifier blockId) { + private void resolveBlockStates(BlockStateResolver resolver, Block block, BiConsumer output) { BlockStateResolverContext context = blockStateResolverContext; context.prepare(block); @@ -100,7 +116,6 @@ private void resolveBlockStates(BlockStateResolver resolver, Block block, Identi ImmutableList allStates = block.getStateManager().getStates(); boolean thrown = false; - // Call resolver try { resolver.resolveBlockStates(context); } catch (Exception e) { @@ -108,34 +123,21 @@ private void resolveBlockStates(BlockStateResolver resolver, Block block, Identi thrown = true; } - // Copy models over to the loader - if (thrown) { - UnbakedModel missingModel = ((ModelLoaderHooks) loader).fabric_getMissingModel(); - - for (BlockState state : allStates) { - ModelIdentifier modelId = BlockModels.getModelId(blockId, state); - ((ModelLoaderHooks) loader).fabric_add(modelId, missingModel); - } - } else if (resolvedModels.size() == allStates.size()) { - // If there are as many resolved models as total states, all states have - // been resolved and models do not need to be null-checked. - resolvedModels.forEach((state, model) -> { - ModelIdentifier modelId = BlockModels.getModelId(blockId, state); - ((ModelLoaderHooks) loader).fabric_add(modelId, model); - }); - } else { - UnbakedModel missingModel = ((ModelLoaderHooks) loader).fabric_getMissingModel(); - - for (BlockState state : allStates) { - ModelIdentifier modelId = BlockModels.getModelId(blockId, state); - @Nullable - UnbakedModel 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); - ((ModelLoaderHooks) loader).fabric_add(modelId, missingModel); - } else { - ((ModelLoaderHooks) loader).fabric_add(modelId, model); + if (!thrown) { + if (resolvedModels.size() == allStates.size()) { + // If there are as many resolved models as total states, all states have + // been resolved and models do not need to be null-checked. + resolvedModels.forEach(output); + } else { + for (BlockState state : allStates) { + @Nullable + UnbakedModel 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); + } else { + output.accept(state, model); + } } } } @@ -145,31 +147,13 @@ private void resolveBlockStates(BlockStateResolver resolver, Block block, Identi @Nullable public UnbakedModel resolveModel(Identifier id) { - if (modelResolverContextStack.isEmpty()) { - modelResolverContextStack.add(new ModelResolverContext()); - } - - ModelResolverContext context = modelResolverContextStack.pop(); - context.prepare(id); - - UnbakedModel model = pluginContext.resolveModel().invoker().resolveModel(context); - - modelResolverContextStack.push(context); - return model; + modelResolverContext.prepare(id); + return pluginContext.resolveModel().invoker().resolveModel(modelResolverContext); } public UnbakedModel modifyModelOnLoad(UnbakedModel model, @UnknownNullability Identifier resourceId, @UnknownNullability ModelIdentifier topLevelId) { - if (onLoadModifierContextStack.isEmpty()) { - onLoadModifierContextStack.add(new OnLoadModifierContext()); - } - - OnLoadModifierContext context = onLoadModifierContextStack.pop(); - context.prepare(resourceId, topLevelId); - - model = pluginContext.modifyModelOnLoad().invoker().modifyModelOnLoad(model, context); - - onLoadModifierContextStack.push(context); - return model; + 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) { @@ -201,7 +185,7 @@ public BakedModel modifyModelAfterBake(@Nullable BakedModel model, @UnknownNulla return model; } - private class ModelResolverContext implements ModelResolver.Context { + private static class ModelResolverContext implements ModelResolver.Context { private Identifier id; private void prepare(Identifier id) { @@ -212,19 +196,9 @@ private void prepare(Identifier id) { public Identifier id() { return id; } - - @Override - public UnbakedModel getOrLoadModel(Identifier id) { - return ((ModelLoaderHooks) loader).fabric_getOrLoadModel(id); - } - - @Override - public ModelLoader loader() { - return loader; - } } - private class BlockStateResolverContext implements BlockStateResolver.Context { + private static class BlockStateResolverContext implements BlockStateResolver.Context { private Block block; private final Reference2ReferenceMap models = new Reference2ReferenceOpenHashMap<>(); @@ -251,19 +225,9 @@ public void setModel(BlockState state, UnbakedModel model) { throw new IllegalStateException("Duplicate model for state " + state + " on block " + block); } } - - @Override - public UnbakedModel getOrLoadModel(Identifier id) { - return ((ModelLoaderHooks) loader).fabric_getOrLoadModel(id); - } - - @Override - public ModelLoader loader() { - return loader; - } } - private class OnLoadModifierContext implements ModelModifier.OnLoad.Context { + private static class OnLoadModifierContext implements ModelModifier.OnLoad.Context { @UnknownNullability private Identifier resourceId; @UnknownNullability @@ -285,19 +249,9 @@ public Identifier resourceId() { public ModelIdentifier topLevelId() { return topLevelId; } - - @Override - public UnbakedModel getOrLoadModel(Identifier id) { - return ((ModelLoaderHooks) loader).fabric_getOrLoadModel(id); - } - - @Override - public ModelLoader loader() { - return loader; - } } - private class BeforeBakeModifierContext implements ModelModifier.BeforeBake.Context { + private static class BeforeBakeModifierContext implements ModelModifier.BeforeBake.Context { @UnknownNullability private Identifier resourceId; @UnknownNullability @@ -340,14 +294,9 @@ public ModelBakeSettings settings() { public Baker baker() { return baker; } - - @Override - public ModelLoader loader() { - return loader; - } } - private class AfterBakeModifierContext implements ModelModifier.AfterBake.Context { + private static class AfterBakeModifierContext implements ModelModifier.AfterBake.Context { @UnknownNullability private Identifier resourceId; @UnknownNullability @@ -397,10 +346,5 @@ public ModelBakeSettings settings() { public Baker baker() { return baker; } - - @Override - public ModelLoader loader() { - return loader; - } } } 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 3231be50b8..bd7c7211bd 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 @@ -17,7 +17,7 @@ package net.fabricmc.fabric.impl.client.model.loading; import java.util.Collection; -import java.util.HashMap; +import java.util.IdentityHashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Objects; @@ -44,7 +44,7 @@ public class ModelLoadingPluginContextImpl implements ModelLoadingPlugin.Context private static final Logger LOGGER = LoggerFactory.getLogger(ModelLoadingPluginContextImpl.class); final Set extraModels = new LinkedHashSet<>(); - final Map blockStateResolvers = new HashMap<>(); + final Map blockStateResolvers = new IdentityHashMap<>(); private final Event modelResolvers = EventFactory.createArrayBacked(ModelResolver.class, resolvers -> context -> { for (ModelResolver resolver : resolvers) { @@ -124,9 +124,7 @@ public void registerBlockStateResolver(Block block, BlockStateResolver resolver) throw new IllegalArgumentException("Received unregistered block"); } - Identifier blockId = optionalKey.get().getValue(); - - if (blockStateResolvers.put(blockId, resolver) != null) { + if (blockStateResolvers.put(block, resolver) != null) { throw new IllegalArgumentException("Duplicate block state resolver for " + block); } } diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/ModelLoadingPluginManager.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/ModelLoadingPluginManager.java index 8ccbee0264..21f43bd2a4 100644 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/ModelLoadingPluginManager.java +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/ModelLoadingPluginManager.java @@ -47,11 +47,6 @@ public static void registerPlugin(PreparableModelLoadingPlugin.DataLoader PREPARABLE_PLUGINS.add(new PreparablePluginHolder<>(loader, plugin)); } - /** - * The current exception behavior as of 1.20 is as follows. - * If getting a {@link CompletableFuture}s throws then the whole client will crash. - * If a {@link CompletableFuture} completes exceptionally then the resource reload will fail. - */ public static CompletableFuture> preparePlugins(ResourceManager resourceManager, Executor executor) { List> futures = new ArrayList<>(); @@ -63,12 +58,12 @@ public static CompletableFuture> preparePlugins(Resourc futures.add(preparePlugin(holder, resourceManager, executor)); } - return Util.combine(futures); + return Util.combineSafe(futures); } private static CompletableFuture preparePlugin(PreparablePluginHolder holder, ResourceManager resourceManager, Executor executor) { CompletableFuture dataFuture = holder.loader.load(resourceManager, executor); - return dataFuture.thenApply(data -> pluginContext -> holder.plugin.onInitializeModelLoader(data, pluginContext)); + return dataFuture.thenApply(data -> pluginContext -> holder.plugin.initialize(data, pluginContext)); } private ModelLoadingPluginManager() { } 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 24e1b33c85..2d91f07822 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,17 +16,24 @@ package net.fabricmc.fabric.mixin.client.model.loading; -import java.util.List; +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 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.CallbackInfoReturnable; import net.minecraft.class_10097; import net.minecraft.client.render.model.BakedModel; @@ -41,12 +48,15 @@ import net.minecraft.util.profiler.Profiler; import net.fabricmc.fabric.api.client.model.loading.v1.FabricBakedModelManager; -import net.fabricmc.fabric.api.client.model.loading.v1.ModelLoadingPlugin; import net.fabricmc.fabric.impl.client.model.loading.ModelLoadingConstants; +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 { + @Unique + private volatile CompletableFuture eventDispatcherFuture; + @Shadow private Map models; @@ -55,33 +65,64 @@ public BakedModel getModel(Identifier id) { return models.get(ModelLoadingConstants.toResourceModelId(id)); } + @Inject(method = "reload", at = @At("HEAD")) + private void onHeadReload(ResourceReloader.Synchronizer synchronizer, ResourceManager manager, Profiler prepareProfiler, Profiler applyProfiler, Executor prepareExecutor, Executor applyExecutor, CallbackInfoReturnable> cir) { + eventDispatcherFuture = ModelLoadingPluginManager.preparePlugins(manager, prepareExecutor).thenApplyAsync(ModelLoadingEventDispatcher::new); + } + + @ModifyReturnValue(method = "reload", at = @At("RETURN")) + private CompletableFuture resetEventDispatcherFuture(CompletableFuture future) { + return future.thenApplyAsync(v -> { + eventDispatcherFuture = null; + return v; + }); + } + + @ModifyExpressionValue(method = "reload", at = @At(value = "INVOKE", target = "net/minecraft/client/render/model/BakedModelManager.reloadBlockStates(Lnet/minecraft/client/render/model/BlockStatesLoader;Lnet/minecraft/resource/ResourceManager;Ljava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture;")) + private CompletableFuture hookBlockStateModelLoading(CompletableFuture modelsFuture) { + CompletableFuture resolvedModelsFuture = eventDispatcherFuture.thenApplyAsync(ModelLoadingEventDispatcher::loadBlockStateModels); + return modelsFuture.thenCombine(resolvedModelsFuture, (models, resolvedModels) -> { + Map map = models.models(); + + if (!(map instanceof HashMap)) { + map = new HashMap<>(map); + models = new BlockStatesLoader.class_10095(map); + } + + map.putAll(resolvedModels.models()); + return models; + }); + } + @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 - ), - allow = 1) - private CompletableFuture loadModelPluginData( + )) + private CompletableFuture hookModelDiscovery( CompletableFuture self, CompletionStage> otherFuture, BiFunction, class_10097> function, - Executor executor, - // reload args - ResourceReloader.Synchronizer synchronizer, - ResourceManager manager, - Profiler prepareProfiler, - Profiler applyProfiler, - Executor prepareExecutor, - Executor applyExecutor) { - CompletableFuture> pluginsFuture = ModelLoadingPluginManager.preparePlugins(manager, prepareExecutor); + Executor executor) { CompletableFuture>> pairFuture = self.thenCombine(otherFuture, Pair::new); - return pairFuture.thenCombineAsync(pluginsFuture, (pair, plugins) -> { - ModelLoadingPluginManager.CURRENT_PLUGINS.set(plugins); - class_10097 modelLoader = function.apply(pair.getLeft(), pair.getRight()); - ModelLoadingPluginManager.CURRENT_PLUGINS.remove(); - return modelLoader; + return pairFuture.thenCombineAsync(eventDispatcherFuture, (pair, eventDispatcher) -> { + ModelLoadingEventDispatcher.CURRENT.set(eventDispatcher); + class_10097 class_10097 = function.apply(pair.getLeft(), pair.getRight()); + ModelLoadingEventDispatcher.CURRENT.remove(); + return class_10097; }, 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) + private Function hookModelBaking(Function function) { + return v -> { + ModelLoadingEventDispatcher.CURRENT.set(eventDispatcherFuture.join()); + Object bakingResult = function.apply(v); + ModelLoadingEventDispatcher.CURRENT.remove(); + return bakingResult; + }; + } } diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/BlockStatesLoaderMixin.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/BlockStatesLoaderMixin.java deleted file mode 100644 index fe9290f29b..0000000000 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/BlockStatesLoaderMixin.java +++ /dev/null @@ -1,56 +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 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.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.client.render.model.BlockStatesLoader; -import net.minecraft.state.StateManager; -import net.minecraft.util.Identifier; - -import net.fabricmc.fabric.impl.client.model.loading.BlockStatesLoaderHooks; - -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -import java.util.List; - -@Mixin(BlockStatesLoader.class) -abstract class BlockStatesLoaderMixin implements BlockStatesLoaderHooks { - @Unique - @Nullable - private LoadingOverride loadingOverride; - - // TODO 24w33a - Mappings - @Inject(method = "method_62627", at = @At("HEAD"), cancellable = true) - private void onHeadLoadBlockStates(Identifier id, StateManager stateManager, List list, CallbackInfoReturnable cir) { - if (loadingOverride != null && loadingOverride.loadBlockStates(id, stateManager)) { - cir.cancel(); - } - } - - @Override - public void fabric_setLoadingOverride(LoadingOverride override) { - loadingOverride = override; - } -} 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 index aee4dbff54..22d7f84f9b 100644 --- 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 @@ -16,162 +16,54 @@ package net.fabricmc.fabric.mixin.client.model.loading; -import java.util.Map; -import java.util.Set; import java.util.function.Function; -import java.util.stream.Collectors; import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; -import com.llamalad7.mixinextras.sugar.Local; -import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet; -import org.spongepowered.asm.mixin.Final; +import org.jetbrains.annotations.Nullable; 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.Coerce; import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.ModifyVariable; -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.color.block.BlockColors; +import net.minecraft.class_10096; 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.ModelLoader; import net.minecraft.client.render.model.UnbakedModel; -import net.minecraft.client.render.model.json.JsonUnbakedModel; 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.minecraft.util.profiler.Profiler; import net.fabricmc.fabric.impl.client.model.loading.BakerImplHooks; -import net.fabricmc.fabric.impl.client.model.loading.BlockStatesLoaderHooks; 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; -import net.fabricmc.fabric.impl.client.model.loading.ModelLoadingPluginManager; @Mixin(ModelLoader.class) abstract class ModelLoaderMixin implements ModelLoaderHooks { - @Final - @Shadow - private Set modelsToLoad; - @Final - @Shadow - private Map unbakedModels; - @Shadow - @Final - private Map modelsToBake; - @Shadow - @Final - private UnbakedModel missingModel; - @Unique + @Nullable private ModelLoadingEventDispatcher fabric_eventDispatcher; - @Unique - private final ObjectLinkedOpenHashSet modelLoadingStack = new ObjectLinkedOpenHashSet<>(); - - @Shadow - abstract UnbakedModel getOrLoadModel(Identifier id); - - @Shadow - abstract void add(ModelIdentifier id, UnbakedModel unbakedModel); - - @Shadow - abstract JsonUnbakedModel loadModelFromJson(Identifier id); - - @Inject(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/model/BlockStatesLoader;load()V")) - private void afterMissingModelInit(BlockColors blockColors, Profiler profiler, Map jsonUnbakedModels, Map> blockStates, CallbackInfo info, @Local BlockStatesLoader blockStatesLoader) { - // Sanity check - if (missingModel == null || !modelsToBake.containsKey(ModelLoader.MISSING_MODEL_ID)) { - throw new AssertionError("Missing model not initialized. This is likely a Fabric API porting bug."); - } - - // Add the missing model to the cache since vanilla doesn't. Mods may load/bake the missing model directly. - unbakedModels.put(ModelLoader.MISSING_ID, missingModel); - profiler.swap("fabric_plugins_init"); - - fabric_eventDispatcher = new ModelLoadingEventDispatcher((ModelLoader) (Object) this, ModelLoadingPluginManager.CURRENT_PLUGINS.get()); - fabric_eventDispatcher.addExtraModels(this::addExtraModel); - ((BlockStatesLoaderHooks) blockStatesLoader).fabric_setLoadingOverride(fabric_eventDispatcher::loadBlockStateModels); - } - - @Unique - private void addExtraModel(Identifier id) { - ModelIdentifier modelId = ModelLoadingConstants.toResourceModelId(id); - UnbakedModel unbakedModel = getOrLoadModel(id); - add(modelId, unbakedModel); - } - - @Inject(method = "getOrLoadModel", at = @At("HEAD"), cancellable = true) - private void allowRecursiveLoading(Identifier id, CallbackInfoReturnable cir) { - // If the stack is empty, this is the top-level call, so proceed as normal. - if (!modelLoadingStack.isEmpty()) { - if (unbakedModels.containsKey(id)) { - cir.setReturnValue(unbakedModels.get(id)); - } else if (modelLoadingStack.contains(id)) { - throw new IllegalStateException("Circular reference while loading model '" + id + "' (" + modelLoadingStack.stream().map(i -> i + "->").collect(Collectors.joining()) + id + ")"); - } else { - UnbakedModel model = loadModel(id); - unbakedModels.put(id, model); - // These will be loaded at the top-level call. - modelsToLoad.addAll(model.getModelDependencies()); - cir.setReturnValue(model); - } - } - } - - // This is the call that needs to be redirected to support ModelResolvers, but it returns a JsonUnbakedModel. - // Redirect it to always return null and handle the logic in a ModifyVariable right after the call. - @Redirect(method = "getOrLoadModel", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/model/ModelLoader;loadModelFromJson(Lnet/minecraft/util/Identifier;)Lnet/minecraft/client/render/model/json/JsonUnbakedModel;")) - private JsonUnbakedModel cancelLoadModelFromJson(ModelLoader self, Identifier id) { - return null; - } - - @ModifyVariable(method = "getOrLoadModel", at = @At(value = "INVOKE_ASSIGN", target = "Lnet/minecraft/client/render/model/ModelLoader;loadModelFromJson(Lnet/minecraft/util/Identifier;)Lnet/minecraft/client/render/model/json/JsonUnbakedModel;")) - private UnbakedModel doLoadModel(UnbakedModel model, @Local(ordinal = 1) Identifier id) { - return loadModel(id); - } - @Unique - private UnbakedModel loadModel(Identifier id) { - modelLoadingStack.add(id); - - try { - UnbakedModel model = fabric_eventDispatcher.resolveModel(id); - - if (model == null) { - model = loadModelFromJson(id); - } - - return fabric_eventDispatcher.modifyModelOnLoad(model, id, null); - } finally { - modelLoadingStack.removeLast(); - } - } - - @ModifyVariable(method = "add", at = @At("HEAD"), argsOnly = true) - private UnbakedModel onAdd(UnbakedModel model, ModelIdentifier id) { - if (ModelLoadingConstants.isResourceModelId(id)) { - return model; - } - - return fabric_eventDispatcher.modifyModelOnLoad(model, null, id); + @Inject(method = "", at = @At("RETURN")) + private void onReturnInit(CallbackInfo ci) { + fabric_eventDispatcher = ModelLoadingEventDispatcher.CURRENT.get(); } @WrapOperation(method = "method_61072(Lnet/minecraft/client/render/model/ModelLoader$SpriteGetter;Lnet/minecraft/client/util/ModelIdentifier;Lnet/minecraft/client/render/model/UnbakedModel;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/model/ModelLoader$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, ModelLoader.SpriteGetter spriteGetter, ModelIdentifier id) { - if (ModelLoadingConstants.isResourceModelId(id) || id.equals(ModelLoader.MISSING_MODEL_ID)) { + if (fabric_eventDispatcher == null) { + return operation.call(baker, unbakedModel, settings); + } + + if (ModelLoadingConstants.isResourceModelId(id) || id.equals(class_10096.field_53661)) { // 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 modelsToBake but it should be the same as the one in unbakedModels. + // 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); } @@ -185,19 +77,4 @@ private BakedModel wrapSingleOuterBake(@Coerce Baker baker, UnbakedModel unbaked public ModelLoadingEventDispatcher fabric_getDispatcher() { return fabric_eventDispatcher; } - - @Override - public UnbakedModel fabric_getMissingModel() { - return missingModel; - } - - @Override - public UnbakedModel fabric_getOrLoadModel(Identifier id) { - return getOrLoadModel(id); - } - - @Override - public void fabric_add(ModelIdentifier id, UnbakedModel model) { - add(id, model); - } } diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/class_10097Mixin.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/class_10097Mixin.java new file mode 100644 index 0000000000..6bbf6e5d37 --- /dev/null +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/class_10097Mixin.java @@ -0,0 +1,95 @@ +/* + * 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 org.jetbrains.annotations.Nullable; +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.ModifyVariable; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.class_10097; +import net.minecraft.client.render.model.BlockStatesLoader; +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(class_10097.class) +abstract class class_10097Mixin { + @Unique + @Nullable + private ModelLoadingEventDispatcher fabric_eventDispatcher; + + @Shadow + abstract UnbakedModel method_62638(Identifier identifier); + + @Shadow + abstract void method_62635(ModelIdentifier modelIdentifier, UnbakedModel unbakedModel); + + @Inject(method = "", at = @At("RETURN")) + private void onReturnInit(CallbackInfo ci) { + fabric_eventDispatcher = ModelLoadingEventDispatcher.CURRENT.get(); + } + + @Inject(method = "method_62632", at = @At("RETURN")) + private void onAddStandardModels(BlockStatesLoader.class_10095 blockStateModels, CallbackInfo ci) { + if (fabric_eventDispatcher == null) { + return; + } + + fabric_eventDispatcher.addExtraModels(id -> { + ModelIdentifier modelId = ModelLoadingConstants.toResourceModelId(id); + UnbakedModel unbakedModel = method_62638(id); + method_62635(modelId, unbakedModel); + }); + } + + @ModifyVariable(method = "method_62640", at = @At(value = "STORE", ordinal = 0), ordinal = 0) + @Nullable + private UnbakedModel onLoadResourceModel(@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 = "method_62635", 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); + } +} 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 8da1ac215f..047df397bf 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,9 @@ "compatibilityLevel": "JAVA_21", "client": [ "BakedModelManagerMixin", - "BlockStatesLoaderMixin", - "ModelLoaderMixin", - "ModelLoaderBakerImplMixin" + "class_10097Mixin", + "ModelLoaderBakerImplMixin", + "ModelLoaderMixin" ], "injectors": { "defaultRequire": 1 diff --git a/fabric-model-loading-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/model/loading/BakedModelFeatureRenderer.java b/fabric-model-loading-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/model/loading/BakedModelFeatureRenderer.java index 5da7b30d20..aaa3e5d7b6 100644 --- a/fabric-model-loading-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/model/loading/BakedModelFeatureRenderer.java +++ b/fabric-model-loading-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/model/loading/BakedModelFeatureRenderer.java @@ -18,8 +18,6 @@ import java.util.function.Supplier; -import net.minecraft.client.render.entity.state.EntityRenderState; - import org.joml.AxisAngle4f; import org.joml.Quaternionf; @@ -31,29 +29,27 @@ import net.minecraft.client.render.entity.feature.FeatureRenderer; import net.minecraft.client.render.entity.feature.FeatureRendererContext; import net.minecraft.client.render.entity.model.EntityModel; +import net.minecraft.client.render.entity.state.LivingEntityRenderState; import net.minecraft.client.render.model.BakedModel; import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.entity.LivingEntity; +import net.minecraft.util.math.MathHelper; -public class BakedModelFeatureRenderer> extends FeatureRenderer { +public class BakedModelFeatureRenderer> extends FeatureRenderer { private final Supplier modelSupplier; - public BakedModelFeatureRenderer(FeatureRendererContext context, Supplier modelSupplier) { + public BakedModelFeatureRenderer(FeatureRendererContext context, Supplier modelSupplier) { super(context); this.modelSupplier = modelSupplier; } @Override - public void render(MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, T state, float limbAngle, float limbDistance) { + public void render(MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, S state, float limbAngle, float limbDistance) { BakedModel model = modelSupplier.get(); VertexConsumer vertices = vertexConsumers.getBuffer(TexturedRenderLayers.getEntityCutout()); matrices.push(); - //matrices.multiply(Vector3f.POSITIVE_Y.getDegreesQuaternion(headYaw)); - //matrices.multiply(Vector3f.POSITIVE_X.getDegreesQuaternion(headPitch)); - // TODO 24w33a Is limbAngle the same as animationProgress? Probably not - matrices.multiply(new Quaternionf(new AxisAngle4f(limbAngle * 0.07F, 0, 1, 0))); + matrices.multiply(new Quaternionf(new AxisAngle4f(state.age * 0.07F - state.bodyYaw * MathHelper.RADIANS_PER_DEGREE, 0, 1, 0))); matrices.scale(-0.75F, -0.75F, 0.75F); - float aboveHead = (float) (Math.sin(limbAngle * 0.08F)) * 0.5F + 0.5F; + float aboveHead = (float) (Math.sin(state.age * 0.08F)) * 0.5F + 0.5F; matrices.translate(-0.5F, 0.75F + aboveHead, -0.5F); MinecraftClient.getInstance().getBlockRenderManager().getModelRenderer().render(matrices.peek(), vertices, null, model, 1, 1, 1, light, OverlayTexture.DEFAULT_UV); matrices.pop(); 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 dac0381a81..d088f5d9c2 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 @@ -26,7 +26,6 @@ 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.ModelLoader; import net.minecraft.client.render.model.UnbakedModel; import net.minecraft.client.util.ModelIdentifier; import net.minecraft.resource.ResourceType; @@ -69,6 +68,7 @@ public void emitBlockQuads(BlockRenderView blockView, BlockState state, BlockPos 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(); @@ -79,17 +79,19 @@ public void onInitializeClient() { return model; }); + // 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 context.getOrLoadModel(class_10096.field_53660); + return new DelegatingUnbakedModel(class_10096.field_53660); } 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) -> { @@ -109,14 +111,15 @@ public void onInitializeClient() { // 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"); - - UnbakedModel stage0Model = new DelegatingUnbakedModel(wheatStage0Id); + 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), stage0Model); + context.setModel(state.with(CropBlock.AGE, age), wheatStage0Model); } - context.setModel(state.with(CropBlock.AGE, 7), context.getOrLoadModel(Identifier.ofVanilla("block/wheat_stage7"))); + context.setModel(state.with(CropBlock.AGE, 7), wheatStage7Model); }); }); diff --git a/fabric-model-loading-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/model/loading/NestedModelLoadingTest.java b/fabric-model-loading-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/model/loading/NestedModelLoadingTest.java deleted file mode 100644 index 7a4782fbae..0000000000 --- a/fabric-model-loading-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/model/loading/NestedModelLoadingTest.java +++ /dev/null @@ -1,110 +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.test.model.loading; - -import static net.fabricmc.fabric.test.model.loading.ModelTestModClient.id; - -import com.mojang.logging.LogUtils; - -import net.minecraft.class_10096; - -import org.slf4j.Logger; - -import net.minecraft.client.render.model.ModelLoader; -import net.minecraft.client.render.model.UnbakedModel; -import net.minecraft.util.Identifier; - -import net.fabricmc.api.ClientModInitializer; -import net.fabricmc.fabric.api.client.model.loading.v1.ModelLoadingPlugin; - -/** - * Tests that deep model resolution resolve each model a single time, depth-first. - */ -public class NestedModelLoadingTest implements ClientModInitializer { - private static final Logger LOGGER = LogUtils.getLogger(); - - private static final Identifier BASE_MODEL = id("nested_base"); - private static final Identifier NESTED_MODEL_1 = id("nested_1"); - private static final Identifier NESTED_MODEL_2 = id("nested_2"); - private static final Identifier NESTED_MODEL_3 = id("nested_3"); - private static final Identifier NESTED_MODEL_4 = id("nested_4"); - private static final Identifier NESTED_MODEL_5 = id("nested_5"); - private static final Identifier TARGET_MODEL = Identifier.ofVanilla("block/stone"); - - @Override - public void onInitializeClient() { - ModelLoadingPlugin.register(pluginContext -> { - pluginContext.addModels(BASE_MODEL); - - pluginContext.resolveModel().register(context -> { - Identifier id = context.id(); - UnbakedModel ret = null; - - if (id.equals(BASE_MODEL)) { - LOGGER.info("Nested model 1 started loading"); - ret = context.getOrLoadModel(NESTED_MODEL_1); - LOGGER.info("Nested model 1 finished loading"); - } else if (id.equals(NESTED_MODEL_1)) { - LOGGER.info(" Nested model 2 started loading"); - ret = context.getOrLoadModel(NESTED_MODEL_2); - LOGGER.info(" Nested model 2 finished loading"); - } else if (id.equals(NESTED_MODEL_2)) { - LOGGER.info(" Nested model 3 started loading"); - ret = context.getOrLoadModel(NESTED_MODEL_3); - LOGGER.info(" Nested model 3 finished loading"); - } else if (id.equals(NESTED_MODEL_3)) { - // Will be overridden by the model modifier below anyway. - LOGGER.info(" Returning dummy model for nested model 3"); - ret = context.getOrLoadModel(class_10096.field_53660); - } else if (id.equals(NESTED_MODEL_4)) { - // Will be overridden by the model modifier below anyway. - LOGGER.info(" Returning dummy model for nested model 4"); - ret = context.getOrLoadModel(class_10096.field_53660); - } else if (id.equals(NESTED_MODEL_5)) { - LOGGER.info(" Target model started loading"); - ret = context.getOrLoadModel(TARGET_MODEL); - LOGGER.info(" Target model finished loading"); - } - - return ret; - }); - - pluginContext.modifyModelOnLoad().register((model, context) -> { - UnbakedModel ret = model; - Identifier id = context.resourceId(); - - if (id != null) { - if (id.equals(NESTED_MODEL_3)) { - LOGGER.info(" Nested model 4 started loading"); - ret = context.getOrLoadModel(NESTED_MODEL_4); - LOGGER.info(" Nested model 4 finished loading"); - - if (!id.equals(context.resourceId())) { - throw new AssertionError("Context object should not have changed."); - } - } else if (id.equals(NESTED_MODEL_4)) { - LOGGER.info(" Nested model 5 started loading"); - ret = context.getOrLoadModel(NESTED_MODEL_5); - LOGGER.info(" Nested model 5 finished loading"); - } - } - - return ret; - }); - }); - } -} diff --git a/fabric-model-loading-api-v1/src/testmodClient/resources/fabric.mod.json b/fabric-model-loading-api-v1/src/testmodClient/resources/fabric.mod.json index 97eea29e4d..3291587c74 100644 --- a/fabric-model-loading-api-v1/src/testmodClient/resources/fabric.mod.json +++ b/fabric-model-loading-api-v1/src/testmodClient/resources/fabric.mod.json @@ -12,7 +12,6 @@ "entrypoints": { "client": [ "net.fabricmc.fabric.test.model.loading.ModelTestModClient", - "net.fabricmc.fabric.test.model.loading.NestedModelLoadingTest", "net.fabricmc.fabric.test.model.loading.PreparablePluginTest" ] } diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/renderer/v1/mesh/MutableQuadView.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/renderer/v1/mesh/MutableQuadView.java index fa40d07693..cf946622a3 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/renderer/v1/mesh/MutableQuadView.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/renderer/v1/mesh/MutableQuadView.java @@ -16,6 +16,7 @@ package net.fabricmc.fabric.api.renderer.v1.mesh; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; import org.joml.Vector2f; import org.joml.Vector2fc; @@ -292,14 +293,39 @@ default MutableQuadView normal(int vertexIndex, Vector3fc normal) { /** * Enables bulk vertex data transfer using the standard Minecraft quad format. * + *

The material applied to this quad view might be slightly different from the {@code material} parameter regarding diffuse shading. + * If either the baked quad {@link BakedQuad#hasShade() does not have shade} or the material {@link MaterialFinder#disableDiffuse(boolean) does not have shade}, + * diffuse shading will be disabled for this quad view. + * This is reflected in the quad view's {@link #material()}, but the {@code material} parameter is unchanged (it is immutable anyway). + * + *

The {@linkplain BakedQuad#getLightEmission() baked quad's light emission} will be applied to the lightmap values from the vertex data + * after copying. + * *

Calling this method does not emit the quad. + */ + default MutableQuadView fromVanilla(BakedQuad quad, RenderMaterial material, @Nullable Direction cullFace) { + return fromVanilla(quad, material, cullFace, true); + } + + // TODO: If this is unmarked as experimental, update the javadoc of the other overloads. + /** + * Enables bulk vertex data transfer using the standard Minecraft quad format. * *

The material applied to this quad view might be slightly different from the {@code material} parameter regarding diffuse shading. * If either the baked quad {@link BakedQuad#hasShade() does not have shade} or the material {@link MaterialFinder#disableDiffuse(boolean) does not have shade}, * diffuse shading will be disabled for this quad view. * This is reflected in the quad view's {@link #material()}, but the {@code material} parameter is unchanged (it is immutable anyway). + * + *

If {@code applyLightEmission} is {@code true}, the {@linkplain BakedQuad#getLightEmission() baked quad's light emission} will be applied + * to the lightmap values from the vertex data after copying. Otherwise, the light emission will be ignored. + * + *

Calling this method does not emit the quad. + * + * @apiNote This method is marked as experimental because future snapshots may change the item renderer to also respect quad light emission, + * in which case this method will be removed. See MC-275296. */ - MutableQuadView fromVanilla(BakedQuad quad, RenderMaterial material, @Nullable Direction cullFace); + @ApiStatus.Experimental + MutableQuadView fromVanilla(BakedQuad quad, RenderMaterial material, @Nullable Direction cullFace, boolean applyLightEmission); /** * @deprecated Use {@link #color(int, int)} instead. diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/renderer/v1/mesh/QuadEmitter.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/renderer/v1/mesh/QuadEmitter.java index 1616d8def8..c3632e442c 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/renderer/v1/mesh/QuadEmitter.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/renderer/v1/mesh/QuadEmitter.java @@ -16,6 +16,7 @@ package net.fabricmc.fabric.api.renderer.v1.mesh; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; import org.joml.Vector2f; import org.joml.Vector2fc; @@ -138,7 +139,14 @@ default QuadEmitter normal(int vertexIndex, Vector3fc normal) { QuadEmitter fromVanilla(int[] quadData, int startIndex); @Override - QuadEmitter fromVanilla(BakedQuad quad, RenderMaterial material, @Nullable Direction cullFace); + default QuadEmitter fromVanilla(BakedQuad quad, RenderMaterial material, @Nullable Direction cullFace) { + MutableQuadView.super.fromVanilla(quad, material, cullFace); + return this; + } + + @ApiStatus.Experimental + @Override + QuadEmitter fromVanilla(BakedQuad quad, RenderMaterial material, @Nullable Direction cullFace, boolean applyLightEmission); /** * Tolerance for determining if the depth parameter to {@link #square(Direction, float, float, float, float, float)} diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/renderer/v1/mesh/QuadView.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/renderer/v1/mesh/QuadView.java index 707098d762..2a49b9b2d9 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/renderer/v1/mesh/QuadView.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/renderer/v1/mesh/QuadView.java @@ -21,6 +21,7 @@ import org.joml.Vector2f; import org.joml.Vector3f; +import net.minecraft.client.render.LightmapTextureManager; import net.minecraft.client.render.VertexFormats; import net.minecraft.client.render.model.BakedQuad; import net.minecraft.client.texture.Sprite; @@ -200,7 +201,23 @@ default BakedQuad toBakedQuad(Sprite sprite) { // Mimic material properties to the largest possible extent int outputColorIndex = material().disableColorIndex() ? -1 : colorIndex(); boolean outputShade = !material().disableDiffuse(); - return new BakedQuad(vertexData, outputColorIndex, lightFace(), sprite, outputShade, 0 /* TODO 24w33a */); + // The output light emission is equal to the minimum of all four sky light values and all four block light values. + int outputLightEmission = 15; + + for (int i = 0; i < 4; i++) { + int lightmap = lightmap(i); + + if (lightmap == 0) { + outputLightEmission = 0; + break; + } + + int blockLight = LightmapTextureManager.getBlockLightCoordinates(lightmap); + int skyLight = LightmapTextureManager.getSkyLightCoordinates(lightmap); + outputLightEmission = Math.min(outputLightEmission, Math.min(blockLight, skyLight)); + } + + return new BakedQuad(vertexData, outputColorIndex, lightFace(), sprite, outputShade, outputLightEmission); } /** diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/renderer/VanillaModelEncoder.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/renderer/VanillaModelEncoder.java index 73cf272002..b76ebd5dc0 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/renderer/VanillaModelEncoder.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/renderer/VanillaModelEncoder.java @@ -78,7 +78,7 @@ public static void emitItemQuads(BakedModel model, @Nullable BlockState state, S for (int j = 0; j < count; j++) { final BakedQuad q = quads.get(j); - emitter.fromVanilla(q, STANDARD_MATERIAL, cullFace); + emitter.fromVanilla(q, STANDARD_MATERIAL, cullFace, false); emitter.emit(); } } diff --git a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/FrameBlock.java b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/FrameBlock.java index 7004b5f8d4..ed4d09160b 100644 --- a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/FrameBlock.java +++ b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/FrameBlock.java @@ -16,8 +16,6 @@ package net.fabricmc.fabric.test.renderer; -import net.minecraft.util.ActionResult; - import org.jetbrains.annotations.Nullable; import net.minecraft.block.Block; @@ -27,6 +25,7 @@ import net.minecraft.block.entity.BlockEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; +import net.minecraft.util.ActionResult; import net.minecraft.util.Hand; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; @@ -46,8 +45,6 @@ public FrameBlock(Settings settings) { @Override public ActionResult onUseWithItem(ItemStack stack, BlockState blockState, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult blockHitResult) { if (world.getBlockEntity(pos) instanceof FrameBlockEntity frame) { - Block handBlock = Block.getBlockFromItem(stack.getItem()); - @Nullable Block currentBlock = frame.getBlock(); @@ -59,26 +56,31 @@ public ActionResult onUseWithItem(ItemStack stack, BlockState blockState, World frame.setBlock(null); } - if (world.isClient) - return ActionResult.SUCCESS; + return ActionResult.SUCCESS; + } else { + return ActionResult.PASS; } - - return ActionResult.PASS_TO_DEFAULT_BLOCK_ACTION; } + Block handBlock = Block.getBlockFromItem(stack.getItem()); + // getBlockFromItem will return air if we do not have a block item in hand if (handBlock == Blocks.AIR) { - return ActionResult.FAIL; + return ActionResult.PASS; } // Do not allow blocks that may have a block entity if (handBlock instanceof BlockEntityProvider) { - return ActionResult.FAIL; + return ActionResult.PASS; } - stack.decrement(1); + if (currentBlock == handBlock) { + return ActionResult.PASS; + } if (!world.isClient()) { + stack.decrementUnlessCreative(1, player); + if (currentBlock != null) { player.getInventory().offerOrDrop(new ItemStack(currentBlock)); } @@ -86,11 +88,10 @@ public ActionResult onUseWithItem(ItemStack stack, BlockState blockState, World frame.setBlock(handBlock); } - if (world.isClient()) - return ActionResult.SUCCESS; + return ActionResult.SUCCESS; } - return ActionResult.FAIL; + return ActionResult.PASS_TO_DEFAULT_BLOCK_ACTION; } @Nullable diff --git a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/FrameUnbakedModel.java b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/FrameUnbakedModel.java index 1a5406a6aa..8f595f0db1 100644 --- a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/FrameUnbakedModel.java +++ b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/FrameUnbakedModel.java @@ -16,8 +16,6 @@ package net.fabricmc.fabric.test.renderer.client; -import java.util.Collection; -import java.util.Collections; import java.util.function.Function; import org.jetbrains.annotations.Nullable; @@ -41,19 +39,8 @@ public class FrameUnbakedModel implements UnbakedModel { private static final SpriteIdentifier OBSIDIAN_SPRITE_ID = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier.ofVanilla("block/obsidian")); - // TODO 24w33a - /*@Override - public Collection getModelDependencies() { - return Collections.emptySet(); - } - - @Override - public void setParents(Function modelLoader) { - }*/ - @Override public void method_62326(class_10103 arg, class_10102 arg2) { - } /* diff --git a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/OctagonalColumnUnbakedModel.java b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/OctagonalColumnUnbakedModel.java index e42dc0a7ad..478dc6b293 100644 --- a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/OctagonalColumnUnbakedModel.java +++ b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/OctagonalColumnUnbakedModel.java @@ -16,8 +16,6 @@ package net.fabricmc.fabric.test.renderer.client; -import java.util.Collection; -import java.util.Collections; import java.util.function.Function; import org.jetbrains.annotations.Nullable; @@ -56,19 +54,8 @@ public OctagonalColumnUnbakedModel(ShadeMode shadeMode) { this.shadeMode = shadeMode; } - // TODO 24w33a - /*@Override - public Collection getModelDependencies() { - return Collections.emptySet(); - } - - @Override - public void setParents(Function modelLoader) { - }*/ - @Override public void method_62326(class_10103 arg, class_10102 arg2) { - } @Override diff --git a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/PillarUnbakedModel.java b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/PillarUnbakedModel.java index 5d7d54c942..a76a17c78b 100644 --- a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/PillarUnbakedModel.java +++ b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/PillarUnbakedModel.java @@ -16,8 +16,6 @@ package net.fabricmc.fabric.test.renderer.client; -import java.util.Collection; -import java.util.Collections; import java.util.List; import java.util.function.Function; import java.util.stream.Stream; @@ -31,7 +29,6 @@ import net.minecraft.client.texture.Sprite; import net.minecraft.client.util.SpriteIdentifier; import net.minecraft.screen.PlayerScreenHandler; -import net.minecraft.util.Identifier; import net.fabricmc.fabric.test.renderer.RendererTest; @@ -40,19 +37,8 @@ public class PillarUnbakedModel implements UnbakedModel { .map(suffix -> new SpriteIdentifier(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE, RendererTest.id("block/pillar_" + suffix))) .toList(); - // TODO 24w33a - /*@Override - public Collection getModelDependencies() { - return Collections.emptySet(); - } - - @Override - public void setParents(Function modelLoader) { - }*/ - @Override public void method_62326(class_10103 arg, class_10102 arg2) { - } @Nullable diff --git a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/RiverstoneUnbakedModel.java b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/RiverstoneUnbakedModel.java index 91a72e8f7c..ba2290f356 100644 --- a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/RiverstoneUnbakedModel.java +++ b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/RiverstoneUnbakedModel.java @@ -16,8 +16,6 @@ package net.fabricmc.fabric.test.renderer.client; -import java.util.Collection; -import java.util.Collections; import java.util.function.Function; import org.jetbrains.annotations.Nullable; @@ -34,21 +32,10 @@ public class RiverstoneUnbakedModel implements UnbakedModel { private static final Identifier STONE_MODEL_ID = Identifier.ofVanilla("block/stone"); private static final Identifier GOLD_BLOCK_MODEL_ID = Identifier.ofVanilla("block/gold_block"); - // TODO 24w33a - /*@Override - public Collection getModelDependencies() { - return Collections.emptySet(); - } - - @Override - public void setParents(Function modelLoader) { - modelLoader.apply(STONE_MODEL_ID).setParents(modelLoader); - modelLoader.apply(GOLD_BLOCK_MODEL_ID).setParents(modelLoader); - }*/ - @Override public void method_62326(class_10103 arg, class_10102 arg2) { - + arg.method_62642(STONE_MODEL_ID); + arg.method_62642(GOLD_BLOCK_MODEL_ID); } @Nullable diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/IndigoRenderer.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/IndigoRenderer.java index c4033ec788..d1eb246bcd 100644 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/IndigoRenderer.java +++ b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/IndigoRenderer.java @@ -25,7 +25,6 @@ import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial; import net.fabricmc.fabric.api.renderer.v1.mesh.MeshBuilder; import net.fabricmc.fabric.impl.client.indigo.renderer.material.MaterialFinderImpl; -import net.fabricmc.fabric.impl.client.indigo.renderer.material.RenderMaterialImpl; import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.MeshBuilderImpl; /** diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/aocalc/AoCalculator.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/aocalc/AoCalculator.java index 401bf8f676..a662227ee7 100644 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/aocalc/AoCalculator.java +++ b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/aocalc/AoCalculator.java @@ -36,6 +36,7 @@ import net.minecraft.client.render.LightmapTextureManager; import net.minecraft.client.render.WorldRenderer; import net.minecraft.client.render.block.BlockModelRenderer; +import net.minecraft.client.render.model.BakedQuad; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.util.math.MathHelper; @@ -147,17 +148,18 @@ private void calcVanilla(QuadViewImpl quad) { // Because this instance is effectively thread-local, we preserve instances // to avoid making a new allocation each call. private final float[] vanillaAoData = new float[Direction.values().length * 2]; - private final BitSet vanillaAoControlBits = new BitSet(3); + private final BitSet vanillaAoFlags = new BitSet(3); private final int[] vertexData = new int[EncodingFormat.QUAD_STRIDE]; + private final DummyBakedQuad dummyBakedQuad = new DummyBakedQuad(); private void calcVanilla(QuadViewImpl quad, float[] aoDest, int[] lightDest) { - vanillaAoControlBits.clear(); + vanillaAoFlags.clear(); final Direction lightFace = quad.lightFace(); quad.toVanilla(vertexData, 0); + dummyBakedQuad.prepare(quad.lightFace(), quad.hasShade()); - VanillaAoHelper.updateShape(blockInfo.blockView, blockInfo.blockState, blockInfo.blockPos, vertexData, lightFace, vanillaAoData, vanillaAoControlBits); - // TODO 24w33a - //vanillaCalc.apply(blockInfo.blockView, blockInfo.blockState, blockInfo.blockPos, lightFace, vanillaAoData, vanillaAoControlBits, quad.hasShade()); + VanillaAoHelper.getQuadDimensions(blockInfo.blockView, blockInfo.blockState, blockInfo.blockPos, vertexData, lightFace, vanillaAoData, vanillaAoFlags); + vanillaCalc.apply(blockInfo.blockView, blockInfo.blockState, blockInfo.blockPos, vanillaAoData, vanillaAoFlags, dummyBakedQuad); System.arraycopy(vanillaCalc.brightness, 0, aoDest, 0, 4); System.arraycopy(vanillaCalc.light, 0, lightDest, 0, 4); @@ -582,4 +584,31 @@ private static int nonZeroMin(int a, int b) { if (b == 0) return a; return Math.min(a, b); } + + // This quad is passed to the vanilla AO calc. It only calls getFace, isEmissive, getLightEmission, and hasShade. + // Since Indigo already applies vanilla's light emission value in MutableQuadView#fromVanilla, this quad should not + // provide its own light emission. + private static class DummyBakedQuad extends BakedQuad { + private Direction lightFace; + private boolean shade; + + DummyBakedQuad() { + super(new int[32], -1, Direction.UP, null, true, 0); + } + + public void prepare(Direction lightFace, boolean shade) { + this.lightFace = lightFace; + this.shade = shade; + } + + @Override + public Direction getFace() { + return lightFace; + } + + @Override + public boolean hasShade() { + return shade; + } + } } diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/aocalc/VanillaAoHelper.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/aocalc/VanillaAoHelper.java index 840df16d96..88d47d74ad 100644 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/aocalc/VanillaAoHelper.java +++ b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/aocalc/VanillaAoHelper.java @@ -19,21 +19,18 @@ import java.util.BitSet; import net.minecraft.block.BlockState; +import net.minecraft.client.MinecraftClient; import net.minecraft.client.render.block.BlockModelRenderer; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.world.BlockRenderView; -public class VanillaAoHelper { +public final class VanillaAoHelper { // Renderer method we call isn't declared as static, but uses no // instance data and is called from multiple threads in vanilla also. - private static BlockModelRenderer blockRenderer; + private static BlockModelRenderer BLOCK_RENDERER = MinecraftClient.getInstance().getBlockRenderManager().getModelRenderer(); - public static void initialize(BlockModelRenderer instance) { - blockRenderer = instance; - } - - public static void updateShape(BlockRenderView blockRenderView, BlockState blockState, BlockPos pos, int[] vertexData, Direction face, float[] aoData, BitSet controlBits) { - blockRenderer.getQuadDimensions(blockRenderView, blockState, pos, vertexData, face, aoData, controlBits); + public static void getQuadDimensions(BlockRenderView blockRenderView, BlockState blockState, BlockPos pos, int[] vertexData, Direction face, float[] aoData, BitSet controlBits) { + BLOCK_RENDERER.getQuadDimensions(blockRenderView, blockState, pos, vertexData, face, aoData, controlBits); } } diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/mesh/MutableQuadViewImpl.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/mesh/MutableQuadViewImpl.java index 09cfbd5dd3..64a24e2d41 100644 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/mesh/MutableQuadViewImpl.java +++ b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/mesh/MutableQuadViewImpl.java @@ -30,6 +30,7 @@ import org.jetbrains.annotations.Nullable; +import net.minecraft.client.render.LightmapTextureManager; import net.minecraft.client.render.model.BakedQuad; import net.minecraft.client.texture.Sprite; import net.minecraft.util.math.Direction; @@ -194,7 +195,7 @@ public final MutableQuadViewImpl fromVanilla(int[] quadData, int startIndex) { } @Override - public final MutableQuadViewImpl fromVanilla(BakedQuad quad, RenderMaterial material, @Nullable Direction cullFace) { + public final MutableQuadViewImpl fromVanilla(BakedQuad quad, RenderMaterial material, @Nullable Direction cullFace, boolean applyLightEmission) { fromVanilla(quad.getVertexData(), 0); data[baseIndex + HEADER_BITS] = EncodingFormat.cullFace(0, cullFace); nominalFace(quad.getFace()); @@ -204,6 +205,14 @@ public final MutableQuadViewImpl fromVanilla(BakedQuad quad, RenderMaterial mate material = RenderMaterialImpl.setDisableDiffuse((RenderMaterialImpl) material, true); } + if (applyLightEmission && quad.isEmissive()) { + int lightEmission = quad.getLightEmission(); + + for (int i = 0; i < 4; i++) { + lightmap(i, LightmapTextureManager.applyEmission(lightmap(i), lightEmission)); + } + } + material(material); tag(0); return this; diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/BlockRenderInfo.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/BlockRenderInfo.java index 8c49c69f01..a78e7d755c 100644 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/BlockRenderInfo.java +++ b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/BlockRenderInfo.java @@ -111,9 +111,7 @@ boolean shouldDrawFace(@Nullable Direction face) { if ((cullCompletionFlags & mask) == 0) { cullCompletionFlags |= mask; - // TODO 24w33a - Double check this - //if (Block.shouldDrawSide(blockState, blockView, blockPos, face, searchPos.set(blockPos, face))) { - if (Block.shouldDrawSide(blockState, blockState, face)) { + if (Block.shouldDrawSide(blockState, blockView.getBlockState(searchPos.set(blockPos, face)), face)) { cullResultFlags |= mask; return true; } else { diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/ItemRenderContext.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/ItemRenderContext.java index 0fd0892e58..bc38e6d50d 100644 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/ItemRenderContext.java +++ b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/ItemRenderContext.java @@ -120,7 +120,7 @@ public BakedModelConsumer bakedModelConsumer() { return vanillaModelConsumer; } - public void renderModel(ItemStack itemStack, ModelTransformationMode transformMode, boolean invert, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int lightmap, int overlay, BakedModel model) { + public void renderModel(ItemStack itemStack, ModelTransformationMode transformMode, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int lightmap, int overlay, BakedModel model) { this.itemStack = itemStack; this.transformMode = transformMode; this.matrixStack = matrixStack; diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/BlockModelRendererMixin.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/BlockModelRendererMixin.java index 69f7bb6ebd..f643cb8324 100644 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/BlockModelRendererMixin.java +++ b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/BlockModelRendererMixin.java @@ -31,7 +31,6 @@ import net.minecraft.util.math.random.Random; import net.minecraft.world.BlockRenderView; -import net.fabricmc.fabric.impl.client.indigo.renderer.aocalc.VanillaAoHelper; import net.fabricmc.fabric.impl.client.indigo.renderer.render.BlockRenderContext; @Mixin(BlockModelRenderer.class) @@ -47,9 +46,4 @@ private void hookRender(BlockRenderView blockView, BakedModel model, BlockState ci.cancel(); } } - - @Inject(at = @At("RETURN"), method = "*") - private void onInit(CallbackInfo ci) { - VanillaAoHelper.initialize((BlockModelRenderer) (Object) this); - } } diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/ItemRendererMixin.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/ItemRendererMixin.java index 1bc2e8d381..ff981d906c 100644 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/ItemRendererMixin.java +++ b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/ItemRendererMixin.java @@ -43,12 +43,10 @@ public abstract class ItemRendererMixin { @Unique private final ThreadLocal fabric_contexts = ThreadLocal.withInitial(() -> new ItemRenderContext(colors)); - // FIXME: Method is unmapped in Yarn - @Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/model/BakedModel;isBuiltin()Z"), method = "method_62476", cancellable = true) - public void hook_renderItem(ItemStack stack, ModelTransformationMode transformMode, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int light, int overlay, BakedModel model, boolean invert, CallbackInfo ci) { + @Inject(method = "method_62476", at = @At(value = "HEAD"), cancellable = true) + public void hook_renderItem(ItemStack stack, ModelTransformationMode transformMode, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int light, int overlay, BakedModel model, boolean notInHand, CallbackInfo ci) { if (!model.isVanillaAdapter()) { - fabric_contexts.get().renderModel(stack, transformMode, invert, matrixStack, vertexConsumerProvider, light, overlay, model); - matrixStack.pop(); + fabric_contexts.get().renderModel(stack, transformMode, matrixStack, vertexConsumerProvider, light, overlay, model); ci.cancel(); } } diff --git a/settings.gradle b/settings.gradle index 36a96f62ca..87019d51b1 100644 --- a/settings.gradle +++ b/settings.gradle @@ -38,14 +38,14 @@ 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' include 'fabric-recipe-api-v1' include 'fabric-registry-sync-v0' -//include 'fabric-renderer-api-v1' -//include 'fabric-renderer-indigo' +include 'fabric-renderer-api-v1' +include 'fabric-renderer-indigo' include 'fabric-rendering-fluids-v1' include 'fabric-rendering-v1' include 'fabric-resource-conditions-api-v1'