Minor model system cleanup/documentation (#6089)

This commit is contained in:
Vincent Lee 2019-08-28 23:33:49 -05:00 committed by LexManos
parent 799e864d93
commit bae2ee0420
13 changed files with 76 additions and 240 deletions

View file

@ -1,6 +1,6 @@
--- a/net/minecraft/client/renderer/ItemRenderer.java
+++ b/net/minecraft/client/renderer/ItemRenderer.java
@@ -51,13 +51,14 @@
@@ -51,7 +51,7 @@
public ItemRenderer(TextureManager p_i46552_1_, ModelManager p_i46552_2_, ItemColors p_i46552_3_) {
this.field_175057_n = p_i46552_1_;
@ -9,14 +9,7 @@
for(Item item : Registry.field_212630_s) {
if (!field_195411_c.contains(item)) {
this.field_175059_m.func_199311_a(item, new ModelResourceLocation(Registry.field_212630_s.func_177774_c(item), "inventory"));
}
}
+ net.minecraftforge.client.model.ModelLoader.onRegisterItems(this.field_175059_m);
this.field_184395_f = p_i46552_3_;
}
@@ -75,6 +76,10 @@
@@ -75,6 +75,10 @@
}
private void func_191967_a(IBakedModel p_191967_1_, int p_191967_2_, ItemStack p_191967_3_) {
@ -27,7 +20,7 @@
Tessellator tessellator = Tessellator.func_178181_a();
BufferBuilder bufferbuilder = tessellator.func_178180_c();
bufferbuilder.func_181668_a(7, DefaultVertexFormats.field_176599_b);
@@ -98,7 +103,7 @@
@@ -98,7 +102,7 @@
if (p_180454_2_.func_188618_c()) {
GlStateManager.color4f(1.0F, 1.0F, 1.0F, 1.0F);
GlStateManager.enableRescaleNormal();
@ -36,7 +29,7 @@
} else {
this.func_191961_a(p_180454_2_, p_180454_1_);
if (p_180454_1_.func_77962_s()) {
@@ -164,7 +169,7 @@
@@ -164,7 +168,7 @@
k = k | -16777216;
}
@ -45,7 +38,7 @@
}
}
@@ -225,11 +230,8 @@
@@ -225,11 +229,8 @@
GlStateManager.enableBlend();
GlStateManager.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO);
GlStateManager.pushMatrix();
@ -59,7 +52,7 @@
this.func_180454_a(p_184394_1_, p_184394_2_);
GlStateManager.cullFace(GlStateManager.CullFace.BACK);
@@ -260,7 +262,7 @@
@@ -260,7 +261,7 @@
GlStateManager.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA);
GlStateManager.color4f(1.0F, 1.0F, 1.0F, 1.0F);
this.func_180452_a(p_191962_2_, p_191962_3_, p_191962_4_.func_177556_c());
@ -68,7 +61,7 @@
this.func_180454_a(p_191962_1_, p_191962_4_);
GlStateManager.disableAlphaTest();
GlStateManager.disableRescaleNormal();
@@ -299,6 +301,7 @@
@@ -299,6 +300,7 @@
crashreportcategory.func_189529_a("Item Type", () -> {
return String.valueOf((Object)p_184391_2_.func_77973_b());
});
@ -76,7 +69,7 @@
crashreportcategory.func_189529_a("Item Damage", () -> {
return String.valueOf(p_184391_2_.func_77952_i());
});
@@ -330,9 +333,12 @@
@@ -330,9 +332,12 @@
GlStateManager.enableBlend();
GlStateManager.enableLighting();
GlStateManager.enableDepthTest();
@ -90,7 +83,7 @@
GlStateManager.disableLighting();
GlStateManager.disableDepthTest();
GlStateManager.disableTexture();
@@ -340,11 +346,9 @@
@@ -340,11 +345,9 @@
GlStateManager.disableBlend();
Tessellator tessellator = Tessellator.func_178181_a();
BufferBuilder bufferbuilder = tessellator.func_178180_c();
@ -105,7 +98,7 @@
this.func_181565_a(bufferbuilder, p_180453_3_ + 2, p_180453_4_ + 13, 13, 2, 0, 0, 0, 255);
this.func_181565_a(bufferbuilder, p_180453_3_ + 2, p_180453_4_ + 13, i, 1, j >> 16 & 255, j >> 8 & 255, j & 255, 255);
GlStateManager.enableBlend();
@@ -383,4 +387,9 @@
@@ -383,4 +386,9 @@
public void func_195410_a(IResourceManager p_195410_1_) {
this.field_175059_m.func_178085_b();
}

View file

@ -22,6 +22,9 @@ package net.minecraftforge.client.model;
import net.minecraft.client.renderer.texture.ISprite;
import net.minecraftforge.common.model.IModelState;
/**
* Adapter from {@link IModelState} to the vanilla transform description class {@link ISprite}.
*/
public class BasicState implements ISprite
{
private final IModelState defaultState;

View file

@ -42,14 +42,16 @@ public interface ICustomModelLoader extends ISelectiveResourceReloadListener
}
}
/*
/**
* Checks if given model should be loaded by this loader.
* Reading file contents is inadvisable, if possible decision should be made based on the location alone.
* @param modelLocation The path, either to an actual file or a {@link net.minecraft.client.renderer.model.ModelResourceLocation}.
*/
boolean accepts(ResourceLocation modelLocation);
/*
* loads (or reloads) specified model
/**
* @param modelLocation The model to (re)load, either path to an
* actual file or a {@link net.minecraft.client.renderer.model.ModelResourceLocation}.
*/
IUnbakedModel loadModel(ResourceLocation modelLocation) throws Exception;

View file

@ -36,19 +36,23 @@ import net.minecraftforge.common.model.IModelState;
import net.minecraftforge.common.model.TRSRTransformation;
import net.minecraftforge.common.model.animation.IClip;
/*
* Interface for models that can be baked
* (possibly to different vertex formats and with different state).
/**
* General interface for any model that can be baked, superset of vanilla {@link net.minecraft.client.renderer.model.IUnbakedModel}.
* Models can be baked to different vertex formats and with different state.
*/
@SuppressWarnings("unchecked")
public interface IModel<T extends IModel<T>>
{
/**
* @param spriteGetter Where textures will be looked up when baking
* @param sprite Transforms to apply while baking. Usually will be an instance of {@link IModelState}.
*/
@Nullable
IBakedModel bake(ModelBakery bakery, Function<ResourceLocation, TextureAtlasSprite> spriteGetter, ISprite sprite, VertexFormat format);
/*
/**
* Default state this model will be baked with.
* See IModelState.
* @see IModelState
*/
default IModelState getDefaultState() {
return TRSRTransformation.identity();

View file

@ -50,6 +50,14 @@ import java.util.function.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
/**
* Forge reimplementation of vanilla {@link ItemModelGenerator}, i.e. builtin/generated models,
* with the following changes:
* - Represented as a true {@link IUnbakedModel} so it can be baked as usual instead of using
* special-case logic like vanilla does.
* - Various fixes in the baking logic.
* - Not limited to 4 layers maximum.
*/
public final class ItemLayerModel implements IUnbakedModel
{
public static final ItemLayerModel INSTANCE = new ItemLayerModel(ImmutableList.of());

View file

@ -1,104 +0,0 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.client.model;
import java.util.Map;
import net.minecraftforge.common.model.IModelPart;
import net.minecraftforge.common.model.IModelState;
import net.minecraftforge.common.model.TRSRTransformation;
import com.google.common.base.Objects;
import java.util.Optional;
import com.google.common.collect.ImmutableMap;
/*
* Simple implementation of IModelState via a map and a default value. Provides a full state for each part.
* You probably don't want to use this.
*/
public class MapModelState implements IModelState
{
private final ImmutableMap<Wrapper, IModelState> map;
private final IModelState def;
public MapModelState(Map<Wrapper, IModelState> map)
{
this(map, TRSRTransformation.identity());
}
public MapModelState(Map<Wrapper, IModelState> map, TRSRTransformation def)
{
this(map, (IModelState)def);
}
public MapModelState(Map<Wrapper, IModelState> map, IModelState def)
{
this.map = ImmutableMap.copyOf(map);
this.def = def;
}
@Override
public Optional<TRSRTransformation> apply(Optional<? extends IModelPart> part)
{
if(!part.isPresent() || !map.containsKey(part.get())) return def.apply(part);
return map.get(part.get()).apply(Optional.empty());
}
public IModelState getState(Object obj)
{
Wrapper w = wrap(obj);
if(!map.containsKey(w)) return def;
return map.get(w);
}
public static class Wrapper implements IModelPart
{
private final Object obj;
public Wrapper(Object obj)
{
this.obj = obj;
}
@Override
public int hashCode()
{
return obj.hashCode();
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Wrapper other = (Wrapper)obj;
return Objects.equal(this.obj, other.obj);
}
}
public static Wrapper wrap(Object obj)
{
return new Wrapper(obj);
}
}

View file

@ -125,8 +125,6 @@ public final class ModelLoader extends ModelBakery
private final Map<ModelResourceLocation, IUnbakedModel> stateModels = Maps.newHashMap();
private final Map<ModelResourceLocation, BlockModelDefinition> multipartDefinitions = Maps.newHashMap();
private final Map<BlockModelDefinition, IUnbakedModel> multipartModels = Maps.newHashMap();
// TODO: nothing adds to missingVariants, remove it?
private final Set<ModelResourceLocation> missingVariants = Sets.newHashSet();
private final Map<ResourceLocation, Exception> loadingExceptions = Maps.newHashMap();
private IUnbakedModel missingModel = null;
@ -181,8 +179,6 @@ public final class ModelLoader extends ModelBakery
private final class VanillaModelWrapper implements IUnbakedModel
{
private final FaceBakery faceBakery = new FaceBakery();
private final ResourceLocation location;
private final BlockModel model;
private final boolean uvlock;
@ -643,6 +639,9 @@ public final class ModelLoader extends ModelBakery
}
}
/**
* Adapter from the vanilla json model loader to a custom model loader
*/
protected static enum VanillaLoader implements ICustomModelLoader
{
INSTANCE;
@ -668,7 +667,7 @@ public final class ModelLoader extends ModelBakery
return loader;
}
// NOOP, handled in loader
// NOOP, handled by ModelLoader itself
@Override
public void onResourceManagerReload(IResourceManager resourceManager) {}
@ -685,14 +684,17 @@ public final class ModelLoader extends ModelBakery
{
return loader.getMissingModel();
}
String modelPath = modelLocation.getPath();
String trimmedPath = modelLocation.getPath();
if(modelLocation.getPath().startsWith("models/"))
{
modelPath = modelPath.substring("models/".length());
trimmedPath = trimmedPath.substring("models/".length());
}
ResourceLocation armatureLocation = new ResourceLocation(modelLocation.getNamespace(), "armatures/" + modelPath + ".json");
ResourceLocation armatureLocation = new ResourceLocation(modelLocation.getNamespace(), "armatures/" + trimmedPath + ".json");
ModelBlockAnimation animation = ModelBlockAnimation.loadVanillaAnimation(loader.resourceManager, armatureLocation);
BlockModel model = loader.loadModel(modelLocation);
ResourceLocation trimmedLocation = new ResourceLocation(modelLocation.getNamespace(), trimmedPath);
BlockModel model = loader.loadModel(trimmedLocation);
IUnbakedModel iModel = loader.new VanillaModelWrapper(modelLocation, model, false, animation);
if(loader.missingModel == null && modelLocation.equals(MODEL_MISSING))
{
@ -790,67 +792,10 @@ public final class ModelLoader extends ModelBakery
}
}
}
for(ModelResourceLocation missing : missingVariants)
{
IBakedModel model = modelRegistry.get(missing);
if(model == null || model == missingModel)
{
LOGGER.debug(MODELLOADING, ()-> new ModelLoaderErrorMessage(missing, null));
}
if(model == null)
{
modelRegistry.put(missing, missingModel);
}
}
loadingExceptions.clear();
missingVariants.clear();
isLoading = false;
}
/*
// TODO replace these if necessary, IStateMapper and ItemMeshDefinition are gone
private static final Map<IRegistryDelegate<Block>, IStateMapper> customStateMappers = Maps.newHashMap();
/**
* Adds a custom IBlockState -> model variant logic.
*//*
public static void setCustomStateMapper(Block block, IStateMapper mapper)
{
customStateMappers.put(block.delegate, mapper);
}
/**
* Internal, do not use.
*//*
public static void onRegisterAllBlocks(BlockModelShapes shapes)
{
for (Entry<IRegistryDelegate<Block>, IStateMapper> e : customStateMappers.entrySet())
{
shapes.registerBlockWithStateMapper(e.getKey().get(), e.getValue());
}
}
*/
private static final Map<Pair<IRegistryDelegate<Item>, Integer>, ModelResourceLocation> customModels = com.google.common.collect.Maps.newHashMap();
/**
* Adds a simple mapping from Item + metadata to the model variant.
* Registers the variant with the ModelBakery too.
*//*
public static void setCustomModelResourceLocation(Item item, int metadata, ModelResourceLocation model)
{
customModels.put(Pair.of(item.delegate, metadata), model);
ModelBakery.registerItemVariants(item, model);
}
/**
* Adds generic ItemStack -> model variant logic.
* You still need to manually call ModelBakery.registerItemVariants with all values that meshDefinition can return.
*//*
public static void setCustomMeshDefinition(Item item, ItemMeshDefinition meshDefinition)
{
customMeshDefinitions.put(item.delegate, meshDefinition);
}
/**
* Helper method for registering all itemstacks for given item to map to universal bucket model.
*//*
@ -859,16 +804,6 @@ public final class ModelLoader extends ModelBakery
ModelBakery.registerItemVariants(item, ModelDynBucket.LOCATION);
}
*/
/**
* Internal, do not use.
*/
public static void onRegisterItems(ItemModelMesher mesher)
{
for (Entry<Pair<IRegistryDelegate<Item>, Integer>, ModelResourceLocation> e : customModels.entrySet())
{
mesher.register(e.getKey().getLeft().get(), e.getValue());
}
}
private static enum DefaultTextureGetter implements Function<ResourceLocation, TextureAtlasSprite>
{
@ -896,6 +831,9 @@ public final class ModelLoader extends ModelBakery
return DEFAULT_MODEL_GETTER;
}
/**
* Exposes the blockstate json loader as a custom model loader
*/
protected static enum VariantLoader implements ICustomModelLoader
{
INSTANCE;
@ -918,7 +856,7 @@ public final class ModelLoader extends ModelBakery
}
@Override
public IUnbakedModel loadModel(ResourceLocation modelLocation) throws Exception
public IUnbakedModel loadModel(ResourceLocation modelLocation)
{
return loader.getUnbakedModel(modelLocation);
}

View file

@ -47,7 +47,7 @@ import net.minecraftforge.common.animation.ITimeValue;
import net.minecraftforge.common.model.animation.AnimationStateMachine;
import net.minecraftforge.common.model.animation.IAnimationStateMachine;
/*
/**
* Central hub for custom model loaders.
*/
public class ModelLoaderRegistry
@ -57,8 +57,6 @@ public class ModelLoaderRegistry
private static final Set<ICustomModelLoader> loaders = Sets.newHashSet();
private static final Map<ResourceLocation, IUnbakedModel> cache = Maps.newHashMap();
private static final Deque<ResourceLocation> loadingModels = Queues.newArrayDeque();
private static final Set<ResourceLocation> textures = Sets.newHashSet();
private static final Map<ResourceLocation, ResourceLocation> aliases = Maps.newHashMap();
private static IResourceManager manager;
@ -73,7 +71,7 @@ public class ModelLoaderRegistry
registerLoader(ModelDynBucket.LoaderDynBucket.INSTANCE);
}
/*
/**
* Makes system aware of your loader.
*/
public static void registerLoader(ICustomModelLoader loader)
@ -97,8 +95,12 @@ public class ModelLoaderRegistry
/**
* Primary method to get IModel instances.
* ResourceLocation argument will be passed directly to the custom model loaders,
* ModelResourceLocation argument will be loaded through the blockstate system.
* @param location The path to load, either:
* - Pure {@link ResourceLocation}. "models/" will be prepended to the path, then
* the path is passed to the {@link ICustomModelLoader}s, which may further modify
* the path before asking resource packs for it. For example, the {@link VanillaLoader}
* appends ".json" before looking the model up.
* - {@link ModelResourceLocation}. The blockstate system will load the model, using {@link VariantLoader}.
*/
public static IUnbakedModel getModel(ResourceLocation location) throws Exception
{
@ -117,9 +119,6 @@ public class ModelLoaderRegistry
loadingModels.addLast(location);
try
{
ResourceLocation aliased = aliases.get(location);
if (aliased != null) return getModel(aliased);
ResourceLocation actual = getActualLocation(location);
ICustomModelLoader accepted = null;
for(ICustomModelLoader loader : loaders)
@ -174,7 +173,6 @@ public class ModelLoaderRegistry
{
throw new LoaderException(String.format("Loader %s returned null while loading model %s", accepted, location));
}
textures.addAll(model.getTextures(ModelLoader.defaultModelGetter(), new HashSet<>()));
}
finally
{
@ -237,20 +235,12 @@ public class ModelLoaderRegistry
{
//IModel model = new FancyMissingModel(ExceptionUtils.getStackTrace(cause).replaceAll("\\t", " "));
IUnbakedModel model = new FancyMissingModel(getMissingModel(), location.toString());
textures.addAll(model.getTextures(null, null));
return model;
}
static void addAlias(ResourceLocation from, ResourceLocation to)
{
aliases.put(from, to);
}
public static void clearModelCache(IResourceManager manager)
{
ModelLoaderRegistry.manager = manager;
aliases.clear();
textures.clear();
cache.clear();
// putting the builtin models in
cache.put(new ResourceLocation("minecraft:builtin/generated"), ItemLayerModel.INSTANCE);
@ -258,11 +248,6 @@ public class ModelLoaderRegistry
cache.put(new ResourceLocation("minecraft:item/builtin/generated"), ItemLayerModel.INSTANCE);
}
static Iterable<ResourceLocation> getTextures()
{
return textures;
}
public static class LoaderException extends Exception
{
public LoaderException(String message)

View file

@ -27,6 +27,9 @@ import net.minecraftforge.common.model.TRSRTransformation;
import java.util.Optional;
/**
* An {@link IModelState} that combines the transforms from two child {@link IModelState}.
*/
public class ModelStateComposition implements IModelState, ISprite
{
private final IModelState first;

View file

@ -55,6 +55,9 @@ import com.google.common.collect.ImmutableMap;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
/**
* A model that can be rendered in multiple {@link BlockRenderLayer}.
*/
public final class MultiLayerModel implements IUnbakedModel
{
private static final Logger LOGGER = LogManager.getLogger();

View file

@ -27,7 +27,7 @@ import net.minecraftforge.common.model.TRSRTransformation;
import java.util.Optional;
import com.google.common.collect.ImmutableMap;
/*
/**
* Simple implementation of IModelState via a map and a default value.
*/
public final class SimpleModelState implements IModelState, ISprite

View file

@ -19,9 +19,9 @@
package net.minecraftforge.common.model;
/*
* Represents the part of the model you can refer to, for example: mesh,
/**
* Represents some part of a model you can refer to, for example: mesh,
* skeleton, bone or some separately animated submodel.
* Primary function of this interface is the argument type of IModelState.apply.
* @see IModelState
*/
public interface IModelPart {}

View file

@ -21,16 +21,17 @@ package net.minecraftforge.common.model;
import java.util.Optional;
/*
* Represents the dynamic information associated with the model.
* Common use case is (possibly interpolated) animation frame.
/**
* An {@code IModelState} is a function from model part to a transformation that should be applied
* when that part is baked, thus representing the current "state" of the model and its parts.
*/
public interface IModelState
{
/*
* Returns the transformation that needs to be applied to the specific part of the model.
* Coordinate system is determined by the part type.
* if no part is provided, global model transformation is returned.
/**
* @param part Part of the model we are wanting to transform. An empty optional means
* we want a transform for the entire model.
* @return A transformation to apply to the part, if any. The coordinate system of the transform
* is determined by the part type.
*/
Optional<TRSRTransformation> apply(Optional<? extends IModelPart> part);
}