Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[1.21.4] Reintroduce nested models in composite models #1802

Merged
merged 1 commit into from
Dec 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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) {}
}
Loading