Skip to content

Commit

Permalink
[1.21.4] Reintroduce nested models in composite models (#1802)
Browse files Browse the repository at this point in the history
  • Loading branch information
XFactHD authored Dec 27, 2024
1 parent cddb9c1 commit 069ab04
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.mojang.datafixers.util.Either;
import com.mojang.math.Transformation;
import java.util.ArrayList;
import java.util.Collection;
Expand All @@ -28,6 +30,7 @@
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.client.resources.model.ModelBaker;
import net.minecraft.client.resources.model.ModelState;
import net.minecraft.client.resources.model.UnbakedModel;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.resources.ResourceLocation;
Expand All @@ -47,10 +50,10 @@
* A model composed of several named children.
*/
public class UnbakedCompositeModel extends AbstractUnbakedModel {
private final ImmutableMap<String, ResourceLocation> children;
private final ImmutableMap<String, Either<ResourceLocation, UnbakedModel>> children;
private final ImmutableList<String> itemPasses;

public UnbakedCompositeModel(ImmutableMap<String, ResourceLocation> children, ImmutableList<String> itemPasses, StandardModelParameters parameters) {
public UnbakedCompositeModel(ImmutableMap<String, Either<ResourceLocation, UnbakedModel>> children, ImmutableList<String> itemPasses, StandardModelParameters parameters) {
super(parameters);
this.children = children;
this.itemPasses = itemPasses;
Expand All @@ -72,12 +75,15 @@ public BakedModel bake(TextureSlots slots,

Map<String, Boolean> partVisibility = additionalProperties.getOrDefault(NeoForgeModelProperties.PART_VISIBILITY, Map.of());
var bakedPartsBuilder = ImmutableMap.<String, BakedModel>builder();
ModelState fstate = state;
for (var entry : children.entrySet()) {
var name = entry.getKey();
if (!partVisibility.getOrDefault(name, true))
continue;
var model = entry.getValue();
bakedPartsBuilder.put(name, baker.bake(model, state));
Either<ResourceLocation, UnbakedModel> model = entry.getValue();
bakedPartsBuilder.put(name, model.map(
reference -> baker.bake(reference, fstate),
inline -> UnbakedModel.bakeWithTopModelValues(inline, baker, fstate)));
}
var bakedParts = bakedPartsBuilder.build();

Expand All @@ -94,8 +100,8 @@ public BakedModel bake(TextureSlots slots,

@Override
public void resolveDependencies(Resolver resolver) {
for (ResourceLocation path : children.values()) {
resolver.resolve(path);
for (Either<ResourceLocation, UnbakedModel> child : children.values()) {
child.ifLeft(resolver::resolve).ifRight(model -> model.resolveDependencies(resolver));
}
}

Expand Down Expand Up @@ -312,8 +318,8 @@ private Loader() {}
@Override
public UnbakedCompositeModel read(JsonObject jsonObject, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
List<String> itemPasses = new ArrayList<>();
ImmutableMap.Builder<String, ResourceLocation> childrenBuilder = ImmutableMap.builder();
readChildren(jsonObject, "children", childrenBuilder, itemPasses);
ImmutableMap.Builder<String, Either<ResourceLocation, UnbakedModel>> childrenBuilder = ImmutableMap.builder();
readChildren(jsonObject, "children", childrenBuilder, itemPasses, jsonDeserializationContext);

var children = childrenBuilder.build();
if (children.isEmpty())
Expand All @@ -334,13 +340,22 @@ public UnbakedCompositeModel read(JsonObject jsonObject, JsonDeserializationCont
return new UnbakedCompositeModel(children, ImmutableList.copyOf(itemPasses), parameters);
}

private void readChildren(JsonObject jsonObject, String name, ImmutableMap.Builder<String, ResourceLocation> children, List<String> itemPasses) {
private static void readChildren(
JsonObject jsonObject,
String name,
ImmutableMap.Builder<String, Either<ResourceLocation, UnbakedModel>> children,
List<String> itemPasses,
JsonDeserializationContext context) {
if (!jsonObject.has(name))
return;
var childrenJsonObject = jsonObject.getAsJsonObject(name);
for (Map.Entry<String, JsonElement> entry : childrenJsonObject.entrySet()) {
ResourceLocation location = ResourceLocation.parse(entry.getValue().getAsString());
children.put(entry.getKey(), location);
Either<ResourceLocation, UnbakedModel> child = switch (entry.getValue()) {
case JsonPrimitive reference -> Either.left(ResourceLocation.parse(reference.getAsString()));
case JsonObject inline -> Either.right(context.deserialize(inline, UnbakedModel.class));
default -> throw new IllegalArgumentException("");
};
children.put(entry.getKey(), child);
itemPasses.add(entry.getKey()); // We can do this because GSON preserves ordering during deserialization
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,52 @@
import com.google.common.base.Preconditions;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.mojang.datafixers.util.Either;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import net.minecraft.client.data.models.model.ModelTemplate;
import net.minecraft.client.data.models.model.TextureMapping;
import net.minecraft.resources.ResourceLocation;
import net.neoforged.neoforge.client.model.generators.template.CustomLoaderBuilder;
import net.neoforged.neoforge.internal.versions.neoforge.NeoForgeVersion;

public class CompositeModelBuilder extends CustomLoaderBuilder {
private final Map<String, ResourceLocation> childModels = new LinkedHashMap<>();
private final Map<String, Either<ResourceLocation, InlineChild>> childModels = new LinkedHashMap<>();
private final List<String> itemRenderOrder = new ArrayList<>();

public CompositeModelBuilder() {
super(ResourceLocation.fromNamespaceAndPath(NeoForgeVersion.MOD_ID, "composite"), false);
}

/**
* Add a child model by reference. The child model will be loaded from a separate file at the given location
*
* @param name The part name of the child
* @param model The child model's path relative to the models folder
*/
public CompositeModelBuilder child(String name, ResourceLocation model) {
Preconditions.checkNotNull(name, "name must not be null");
Preconditions.checkNotNull(model, "model must not be null");
childModels.put(name, model);
childModels.put(name, Either.left(model));
itemRenderOrder.add(name);
return this;
}

/**
* Add an inline child model. The child model will be loaded from a nested object in the same JSON file
*
* @param name The part name of the child
* @param template The {@link ModelTemplate} to create the child model from
* @param textures The {@link TextureMapping} this child model uses
*/
public CompositeModelBuilder inlineChild(String name, ModelTemplate template, TextureMapping textures) {
Preconditions.checkNotNull(name, "name must not be null");
Preconditions.checkNotNull(template, "model template must not be null");
Preconditions.checkNotNull(textures, "textures must not be null");
childModels.put(name, Either.right(new InlineChild(template, textures)));
itemRenderOrder.add(name);
return this;
}
Expand Down Expand Up @@ -57,8 +82,10 @@ public JsonObject toJson(JsonObject json) {
json = super.toJson(json);

JsonObject children = new JsonObject();
for (Map.Entry<String, ResourceLocation> entry : childModels.entrySet()) {
children.addProperty(entry.getKey(), entry.getValue().toString());
for (Map.Entry<String, Either<ResourceLocation, InlineChild>> entry : childModels.entrySet()) {
entry.getValue()
.ifLeft(reference -> children.addProperty(entry.getKey(), reference.toString()))
.ifRight(inline -> serializeNestedTemplate(inline.template, inline.textures, inlineJson -> children.add(entry.getKey(), inlineJson)));
}
json.add("children", children);

Expand All @@ -70,4 +97,6 @@ public JsonObject toJson(JsonObject json) {

return json;
}

private record InlineChild(ModelTemplate template, TextureMapping textures) {}
}

0 comments on commit 069ab04

Please sign in to comment.