Introduce custom loader additions to the model data generators. (#7450)
Currently implemented loaders: * OBJ * Composite * Multi-layer * Item layers (vanilla item/generated but with fullbright texture support) * Bucket * Separate Perspective
This commit is contained in:
parent
cf3e9d1e0c
commit
fed7beab89
18 changed files with 660 additions and 20 deletions
|
@ -353,8 +353,10 @@ project(':forge') {
|
|||
'--mod', 'global_loot_test',
|
||||
'--mod', 'scaffolding_test',
|
||||
'--mod', 'custom_tag_types_test',
|
||||
'--mod', 'new_model_loader_test',
|
||||
'--output', rootProject.file('src/generated_test/resources/'),
|
||||
'--existing', sourceSets.main.resources.srcDirs[0]
|
||||
'--existing', sourceSets.main.resources.srcDirs[0],
|
||||
'--existing', sourceSets.test.resources.srcDirs[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,6 +63,10 @@ bf2e445b48b024354a69138b20a4a4a8aa5d15d1 assets/minecraft/blockstates/oak_trapdo
|
|||
9c4cc92efb78811e8d70a383a1a89eb75b69db04 assets/minecraft/blockstates/stone.json
|
||||
570fdd86046df75a073b759ff7aaf4c4caf43115 assets/minecraft/blockstates/torch.json
|
||||
a012d6d92bab1c91913bd0f2dc0492a0fce916f2 assets/minecraft/blockstates/wall_torch.json
|
||||
e615d11ed9a452bca5d8b242e733a43ba2df19a3 assets/new_model_loader_test/blockstates/obj_block.json
|
||||
bab7cd04569c8aa63320772acdc3c91a5ceda14a assets/new_model_loader_test/models/block/obj_block.json
|
||||
9fa44308a52fbc384d5befee4e117531642299fb assets/new_model_loader_test/models/item/item_layers.json
|
||||
70c8c81f3a157e4d698f213d5c1a13c13eaa5157 assets/new_model_loader_test/models/item/separate_perspective.json
|
||||
273e0ed992d227f09f1c83bc22d066fb68d03c84 assets/piston_event_test/blockstates/shiftonmove.json
|
||||
d2c8e860521c5e738ed0798337f5728d610825ff assets/piston_event_test/models/block/shiftonmove.json
|
||||
f51f026a75e27a0a53a76771d553c0e3385a2966 assets/piston_event_test/models/item/shiftonmove.json
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"variants": {
|
||||
"": {
|
||||
"model": "new_model_loader_test:block/obj_block"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"textures": {
|
||||
"qr": "minecraft:block/oak_planks",
|
||||
"particle": "#qr"
|
||||
},
|
||||
"loader": "forge:obj",
|
||||
"model": "new_model_loader_test:models/item/sugar_glider.obj",
|
||||
"flip-v": true
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"parent": "forge:item/default",
|
||||
"textures": {
|
||||
"layer0": "minecraft:item/coal",
|
||||
"layer1": "minecraft:item/stick"
|
||||
},
|
||||
"loader": "forge:item-layers",
|
||||
"fullbright_layers": [
|
||||
1
|
||||
]
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"parent": "forge:item/default",
|
||||
"loader": "forge:separate-perspective",
|
||||
"base": {
|
||||
"parent": "minecraft:item/coal"
|
||||
},
|
||||
"perspectives": {
|
||||
"gui": {
|
||||
"parent": "minecraft:item/snowball"
|
||||
},
|
||||
"first_person_left_hand": {
|
||||
"parent": "minecraft:item/bone"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
package net.minecraftforge.client.model;
|
||||
|
||||
import com.google.common.collect.ImmutableBiMap;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
|
@ -164,7 +165,7 @@ public class SeparatePerspectiveModel implements IModelGeometry<SeparatePerspect
|
|||
{
|
||||
public static final Loader INSTANCE = new Loader();
|
||||
|
||||
private static final ImmutableMap<String, ItemCameraTransforms.TransformType> PERSPECTIVES = ImmutableMap.<String, ItemCameraTransforms.TransformType>builder()
|
||||
public static final ImmutableBiMap<String, ItemCameraTransforms.TransformType> PERSPECTIVES = ImmutableBiMap.<String, ItemCameraTransforms.TransformType>builder()
|
||||
.put("none", ItemCameraTransforms.TransformType.NONE)
|
||||
.put("third_person_left_hand", ItemCameraTransforms.TransformType.THIRD_PERSON_LEFT_HAND)
|
||||
.put("third_person_right_hand", ItemCameraTransforms.TransformType.THIRD_PERSON_RIGHT_HAND)
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
package net.minecraftforge.client.model.generators;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.gson.JsonObject;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.common.data.ExistingFileHelper;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class CustomLoaderBuilder<T extends ModelBuilder<T>>
|
||||
{
|
||||
protected final ResourceLocation loaderId;
|
||||
protected final T parent;
|
||||
protected final ExistingFileHelper existingFileHelper;
|
||||
protected final Map<String, Boolean> visibility = new LinkedHashMap<>();
|
||||
|
||||
protected CustomLoaderBuilder(ResourceLocation loaderId, T parent, ExistingFileHelper existingFileHelper)
|
||||
{
|
||||
this.loaderId = loaderId;
|
||||
this.parent = parent;
|
||||
this.existingFileHelper = existingFileHelper;
|
||||
}
|
||||
|
||||
public CustomLoaderBuilder<T> visibility(String partName, boolean show)
|
||||
{
|
||||
Preconditions.checkNotNull(partName, "partName must not be null");
|
||||
this.visibility.put(partName, show);
|
||||
return this;
|
||||
}
|
||||
|
||||
public T end()
|
||||
{
|
||||
return parent;
|
||||
}
|
||||
|
||||
public JsonObject toJson(JsonObject json)
|
||||
{
|
||||
json.addProperty("loader", loaderId.toString());
|
||||
|
||||
if (visibility.size() > 0)
|
||||
{
|
||||
JsonObject visibilityObj = new JsonObject();
|
||||
|
||||
for(Map.Entry<String, Boolean> entry : visibility.entrySet())
|
||||
{
|
||||
visibilityObj.addProperty(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
json.add("visibility", visibilityObj);
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
}
|
|
@ -19,13 +19,10 @@
|
|||
|
||||
package net.minecraftforge.client.model.generators;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
@ -75,6 +72,8 @@ public class ModelBuilder<T extends ModelBuilder<T>> extends ModelFile {
|
|||
|
||||
protected final List<ElementBuilder> elements = new ArrayList<>();
|
||||
|
||||
protected CustomLoaderBuilder customLoader = null;
|
||||
|
||||
protected ModelBuilder(ResourceLocation outputLocation, ExistingFileHelper existingFileHelper) {
|
||||
super(outputLocation);
|
||||
this.existingFileHelper = existingFileHelper;
|
||||
|
@ -178,6 +177,7 @@ public class ModelBuilder<T extends ModelBuilder<T>> extends ModelFile {
|
|||
}
|
||||
|
||||
public ElementBuilder element() {
|
||||
Preconditions.checkState(customLoader == null, "Cannot use elements and custom loaders at the same time");
|
||||
ElementBuilder ret = new ElementBuilder();
|
||||
elements.add(ret);
|
||||
return ret;
|
||||
|
@ -191,13 +191,29 @@ public class ModelBuilder<T extends ModelBuilder<T>> extends ModelFile {
|
|||
* @throws IndexOutOfBoundsException if {@code} index is out of bounds
|
||||
*/
|
||||
public ElementBuilder element(int index) {
|
||||
Preconditions.checkState(customLoader == null, "Cannot use elements and custom loaders at the same time");
|
||||
Preconditions.checkElementIndex(index, elements.size(), "Element index");
|
||||
return elements.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use a custom loader instead of the vanilla elements.
|
||||
* @param customLoaderFactory
|
||||
* @return the custom loader builder
|
||||
*/
|
||||
public <L extends CustomLoaderBuilder<T>> L customLoader(BiFunction<T, ExistingFileHelper, L> customLoaderFactory)
|
||||
{
|
||||
Preconditions.checkState(elements.size() == 0, "Cannot use elements and custom loaders at the same time");
|
||||
Preconditions.checkNotNull(customLoaderFactory, "customLoaderFactory must not be null");
|
||||
L customLoader = customLoaderFactory.apply(self(), existingFileHelper);
|
||||
this.customLoader = customLoader;
|
||||
return customLoader;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public JsonObject toJson() {
|
||||
JsonObject root = new JsonObject();
|
||||
|
||||
if (this.parent != null) {
|
||||
root.addProperty("parent", this.parent.getLocation().toString());
|
||||
}
|
||||
|
@ -290,6 +306,9 @@ public class ModelBuilder<T extends ModelBuilder<T>> extends ModelFile {
|
|||
root.add("elements", elements);
|
||||
}
|
||||
|
||||
if (customLoader != null)
|
||||
return customLoader.toJson(root);
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ import com.google.gson.GsonBuilder;
|
|||
import net.minecraft.data.DataGenerator;
|
||||
import net.minecraft.data.DirectoryCache;
|
||||
import net.minecraft.data.IDataProvider;
|
||||
import net.minecraft.resources.IResource;
|
||||
import net.minecraft.resources.ResourcePackType;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.common.data.ExistingFileHelper;
|
||||
|
@ -51,12 +52,39 @@ public abstract class ModelProvider<T extends ModelBuilder<T>> implements IDataP
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(ResourceLocation loc, ResourcePackType type, String pathSuffix, String pathPrefix) {
|
||||
if (generatedModels.containsKey(loc)) {
|
||||
return true;
|
||||
public boolean exists(ResourceLocation loc, ResourcePackType type, String pathSuffix, String pathPrefix)
|
||||
{
|
||||
if (pathPrefix.equals("models") && pathSuffix.equals(".json"))
|
||||
{
|
||||
if (generatedModels.containsKey(loc))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return delegate.exists(loc, type, pathSuffix, pathPrefix);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(ResourceLocation loc, ResourcePackType type) {
|
||||
if (loc.getPath().startsWith("models/") && loc.getPath().endsWith(".json"))
|
||||
{
|
||||
ResourceLocation modelLoc = new ResourceLocation(
|
||||
loc.getNamespace(),
|
||||
loc.getPath().substring("models/".length(), loc.getPath().length() - ".json".length())
|
||||
);
|
||||
if (generatedModels.containsKey(modelLoc))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return delegate.exists(loc, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IResource getResource(ResourceLocation loc, ResourcePackType type) throws IOException
|
||||
{
|
||||
return delegate.getResource(loc, type);
|
||||
}
|
||||
}
|
||||
|
||||
public static final String BLOCK_FOLDER = "block";
|
||||
|
@ -357,6 +385,14 @@ public abstract class ModelProvider<T extends ModelBuilder<T>> implements IDataP
|
|||
return singleTexture(name, BLOCK_FOLDER + "/carpet", "wool", wool);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a model builder that's not directly saved to disk. Meant for use in custom model loaders.
|
||||
*/
|
||||
public T nested()
|
||||
{
|
||||
return factory.apply(new ResourceLocation("dummy:dummy"));
|
||||
}
|
||||
|
||||
public ModelFile.ExistingModelFile getExistingFile(ResourceLocation path) {
|
||||
ModelFile.ExistingModelFile ret = new ModelFile.ExistingModelFile(extendWithFolder(path), existingFileHelper);
|
||||
ret.assertExistence();
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
package net.minecraftforge.client.model.generators.loaders;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.gson.JsonObject;
|
||||
import net.minecraft.fluid.Fluid;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.client.model.generators.CustomLoaderBuilder;
|
||||
import net.minecraftforge.client.model.generators.ModelBuilder;
|
||||
import net.minecraftforge.common.data.ExistingFileHelper;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class CompositeModelBuilder<T extends ModelBuilder<T>> extends CustomLoaderBuilder<T>
|
||||
{
|
||||
public static <T extends ModelBuilder<T>> CompositeModelBuilder<T> begin(T parent, ExistingFileHelper existingFileHelper)
|
||||
{
|
||||
return new CompositeModelBuilder<>(parent, existingFileHelper);
|
||||
}
|
||||
|
||||
private final Map<String, T> childModels = new LinkedHashMap<>();
|
||||
|
||||
protected CompositeModelBuilder(T parent, ExistingFileHelper existingFileHelper)
|
||||
{
|
||||
super(new ResourceLocation("forge:composite"), parent, existingFileHelper);
|
||||
}
|
||||
|
||||
public CompositeModelBuilder<T> submodel(String name, T modelBuilder)
|
||||
{
|
||||
Preconditions.checkNotNull(name, "name must not be null");
|
||||
Preconditions.checkNotNull(modelBuilder, "modelBuilder must not be null");
|
||||
childModels.put(name, modelBuilder);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonObject toJson(JsonObject json)
|
||||
{
|
||||
json = super.toJson(json);
|
||||
|
||||
JsonObject parts = new JsonObject();
|
||||
for(Map.Entry<String, T> entry : childModels.entrySet())
|
||||
{
|
||||
parts.add(entry.getKey(), entry.getValue().toJson());
|
||||
}
|
||||
json.add("parts", parts);
|
||||
|
||||
return json;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
package net.minecraftforge.client.model.generators.loaders;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.gson.JsonObject;
|
||||
import net.minecraft.fluid.Fluid;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.client.model.generators.CustomLoaderBuilder;
|
||||
import net.minecraftforge.client.model.generators.ModelBuilder;
|
||||
import net.minecraftforge.common.data.ExistingFileHelper;
|
||||
|
||||
public class DynamicBucketModelBuilder<T extends ModelBuilder<T>> extends CustomLoaderBuilder<T>
|
||||
{
|
||||
public static <T extends ModelBuilder<T>> DynamicBucketModelBuilder<T> begin(T parent, ExistingFileHelper existingFileHelper)
|
||||
{
|
||||
return new DynamicBucketModelBuilder<>(parent, existingFileHelper);
|
||||
}
|
||||
|
||||
private ResourceLocation fluid;
|
||||
private Boolean flipGas;
|
||||
private Boolean applyTint;
|
||||
private Boolean coverIsMask;
|
||||
private Boolean applyFluidLuminosity;
|
||||
|
||||
protected DynamicBucketModelBuilder(T parent, ExistingFileHelper existingFileHelper)
|
||||
{
|
||||
super(new ResourceLocation("forge:bucket"), parent, existingFileHelper);
|
||||
}
|
||||
|
||||
public DynamicBucketModelBuilder<T> fluid(Fluid fluid)
|
||||
{
|
||||
Preconditions.checkNotNull(fluid, "fluid must not be null");
|
||||
this.fluid = fluid.getRegistryName();
|
||||
return this;
|
||||
}
|
||||
|
||||
public DynamicBucketModelBuilder<T> flipGas(boolean flip)
|
||||
{
|
||||
this.flipGas = flip;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DynamicBucketModelBuilder<T> applyTint(boolean tint)
|
||||
{
|
||||
this.applyTint = tint;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DynamicBucketModelBuilder<T> coverIsMask(boolean coverIsMask)
|
||||
{
|
||||
this.coverIsMask = coverIsMask;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DynamicBucketModelBuilder<T> applyFluidLuminosity(boolean applyFluidLuminosity)
|
||||
{
|
||||
this.applyFluidLuminosity = applyFluidLuminosity;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonObject toJson(JsonObject json)
|
||||
{
|
||||
json = super.toJson(json);
|
||||
|
||||
Preconditions.checkNotNull(fluid, "fluid must not be null");
|
||||
|
||||
json.addProperty("fluid", fluid.toString());
|
||||
|
||||
if (flipGas != null)
|
||||
json.addProperty("flipGas", flipGas);
|
||||
|
||||
if (applyTint != null)
|
||||
json.addProperty("applyTint", applyTint);
|
||||
|
||||
if (coverIsMask != null)
|
||||
json.addProperty("coverIsMask", coverIsMask);
|
||||
|
||||
if (applyFluidLuminosity != null)
|
||||
json.addProperty("applyFluidLuminosity", applyFluidLuminosity);
|
||||
|
||||
return json;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package net.minecraftforge.client.model.generators.loaders;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.client.model.generators.CustomLoaderBuilder;
|
||||
import net.minecraftforge.client.model.generators.ModelBuilder;
|
||||
import net.minecraftforge.common.data.ExistingFileHelper;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class ItemLayersModelBuilder<T extends ModelBuilder<T>> extends CustomLoaderBuilder<T>
|
||||
{
|
||||
public static <T extends ModelBuilder<T>> ItemLayersModelBuilder<T> begin(T parent, ExistingFileHelper existingFileHelper)
|
||||
{
|
||||
return new ItemLayersModelBuilder<>(parent, existingFileHelper);
|
||||
}
|
||||
|
||||
private final Set<Integer> fullbright = new LinkedHashSet<>();
|
||||
|
||||
protected ItemLayersModelBuilder(T parent, ExistingFileHelper existingFileHelper)
|
||||
{
|
||||
super(new ResourceLocation("forge:item-layers"), parent, existingFileHelper);
|
||||
}
|
||||
|
||||
public ItemLayersModelBuilder<T> fullbright(int layer)
|
||||
{
|
||||
Preconditions.checkArgument(layer >= 0, "layer must be >= 0");
|
||||
fullbright.add(layer);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonObject toJson(JsonObject json)
|
||||
{
|
||||
json = super.toJson(json);
|
||||
|
||||
JsonArray parts = new JsonArray();
|
||||
for(int entry : fullbright)
|
||||
{
|
||||
parts.add(entry);
|
||||
}
|
||||
json.add("fullbright_layers", parts);
|
||||
|
||||
return json;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package net.minecraftforge.client.model.generators.loaders;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.gson.JsonObject;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.client.model.MultiLayerModel;
|
||||
import net.minecraftforge.client.model.generators.CustomLoaderBuilder;
|
||||
import net.minecraftforge.client.model.generators.ModelBuilder;
|
||||
import net.minecraftforge.common.data.ExistingFileHelper;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class MultiLayerModelBuilder<T extends ModelBuilder<T>> extends CustomLoaderBuilder<T>
|
||||
{
|
||||
public static <T extends ModelBuilder<T>> MultiLayerModelBuilder<T> begin(T parent, ExistingFileHelper existingFileHelper)
|
||||
{
|
||||
return new MultiLayerModelBuilder<>(parent, existingFileHelper);
|
||||
}
|
||||
|
||||
private final Map<String, T> childModels = new LinkedHashMap<>();
|
||||
|
||||
protected MultiLayerModelBuilder(T parent, ExistingFileHelper existingFileHelper)
|
||||
{
|
||||
super(new ResourceLocation("forge:multi-layer"), parent, existingFileHelper);
|
||||
}
|
||||
|
||||
public MultiLayerModelBuilder<T> submodel(RenderType layer, T modelBuilder)
|
||||
{
|
||||
Preconditions.checkNotNull(layer, "layer must not be null");
|
||||
Preconditions.checkArgument(MultiLayerModel.Loader.BLOCK_LAYERS.containsValue(layer), "layer must be supported by MultiLayerModel");
|
||||
Preconditions.checkNotNull(modelBuilder, "modelBuilder must not be null");
|
||||
childModels.put(MultiLayerModel.Loader.BLOCK_LAYERS.inverse().get(layer), modelBuilder);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonObject toJson(JsonObject json)
|
||||
{
|
||||
json = super.toJson(json);
|
||||
|
||||
JsonObject parts = new JsonObject();
|
||||
for(Map.Entry<String, T> entry : childModels.entrySet())
|
||||
{
|
||||
parts.add(entry.getKey(), entry.getValue().toJson());
|
||||
}
|
||||
json.add("layers", parts);
|
||||
|
||||
return json;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
package net.minecraftforge.client.model.generators.loaders;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.gson.JsonObject;
|
||||
import net.minecraft.resources.ResourcePackType;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.client.model.generators.CustomLoaderBuilder;
|
||||
import net.minecraftforge.client.model.generators.ModelBuilder;
|
||||
import net.minecraftforge.common.data.ExistingFileHelper;
|
||||
|
||||
public class OBJLoaderBuilder<T extends ModelBuilder<T>> extends CustomLoaderBuilder<T>
|
||||
{
|
||||
public static <T extends ModelBuilder<T>> OBJLoaderBuilder<T> begin(T parent, ExistingFileHelper existingFileHelper)
|
||||
{
|
||||
return new OBJLoaderBuilder<>(parent, existingFileHelper);
|
||||
}
|
||||
|
||||
private ResourceLocation modelLocation;
|
||||
private Boolean detectCullableFaces;
|
||||
private Boolean diffuseLighting;
|
||||
private Boolean flipV;
|
||||
private Boolean ambientToFullbright;
|
||||
private ResourceLocation materialLibraryOverrideLocation;
|
||||
|
||||
protected OBJLoaderBuilder(T parent, ExistingFileHelper existingFileHelper)
|
||||
{
|
||||
super(new ResourceLocation("forge:obj"), parent, existingFileHelper);
|
||||
}
|
||||
|
||||
public OBJLoaderBuilder<T> modelLocation(ResourceLocation modelLocation)
|
||||
{
|
||||
Preconditions.checkNotNull(modelLocation, "modelLocation must not be null");
|
||||
Preconditions.checkArgument(existingFileHelper.exists(modelLocation, ResourcePackType.CLIENT_RESOURCES),
|
||||
"OBJ Model %s does not exist in any known resource pack", modelLocation);
|
||||
this.modelLocation = modelLocation;
|
||||
return this;
|
||||
}
|
||||
|
||||
public OBJLoaderBuilder<T> detectCullableFaces(boolean detectCullableFaces)
|
||||
{
|
||||
this.detectCullableFaces = detectCullableFaces;
|
||||
return this;
|
||||
}
|
||||
|
||||
public OBJLoaderBuilder<T> diffuseLighting(boolean diffuseLighting)
|
||||
{
|
||||
this.diffuseLighting = diffuseLighting;
|
||||
return this;
|
||||
}
|
||||
|
||||
public OBJLoaderBuilder<T> flipV(boolean flipV)
|
||||
{
|
||||
this.flipV = flipV;
|
||||
return this;
|
||||
}
|
||||
|
||||
public OBJLoaderBuilder<T> ambientToFullbright(boolean ambientToFullbright)
|
||||
{
|
||||
this.ambientToFullbright = ambientToFullbright;
|
||||
return this;
|
||||
}
|
||||
|
||||
public OBJLoaderBuilder<T> overrideMaterialLibrary(ResourceLocation materialLibraryOverrideLocation)
|
||||
{
|
||||
Preconditions.checkNotNull(materialLibraryOverrideLocation, "materialLibraryOverrideLocation must not be null");
|
||||
Preconditions.checkArgument(existingFileHelper.exists(materialLibraryOverrideLocation, ResourcePackType.CLIENT_RESOURCES),
|
||||
"OBJ Model %s does not exist in any known resource pack", materialLibraryOverrideLocation);
|
||||
this.materialLibraryOverrideLocation = materialLibraryOverrideLocation;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonObject toJson(JsonObject json)
|
||||
{
|
||||
json = super.toJson(json);
|
||||
|
||||
Preconditions.checkNotNull(modelLocation, "modelLocation must not be null");
|
||||
|
||||
json.addProperty("model", modelLocation.toString());
|
||||
|
||||
if (detectCullableFaces != null)
|
||||
json.addProperty("detectCullableFaces", detectCullableFaces);
|
||||
|
||||
if (diffuseLighting != null)
|
||||
json.addProperty("diffuseLighting", diffuseLighting);
|
||||
|
||||
if (flipV != null)
|
||||
json.addProperty("flip-v", flipV);
|
||||
|
||||
if (ambientToFullbright != null)
|
||||
json.addProperty("ambientToFullbright", ambientToFullbright);
|
||||
|
||||
if (materialLibraryOverrideLocation != null)
|
||||
json.addProperty("materialLibraryOverrideLocation", materialLibraryOverrideLocation.toString());
|
||||
|
||||
return json;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package net.minecraftforge.client.model.generators.loaders;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.gson.JsonObject;
|
||||
import net.minecraft.client.renderer.model.ItemCameraTransforms;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.client.model.MultiLayerModel;
|
||||
import net.minecraftforge.client.model.SeparatePerspectiveModel;
|
||||
import net.minecraftforge.client.model.generators.CustomLoaderBuilder;
|
||||
import net.minecraftforge.client.model.generators.ModelBuilder;
|
||||
import net.minecraftforge.common.data.ExistingFileHelper;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class SeparatePerspectiveModelBuilder<T extends ModelBuilder<T>> extends CustomLoaderBuilder<T>
|
||||
{
|
||||
public static <T extends ModelBuilder<T>> SeparatePerspectiveModelBuilder<T> begin(T parent, ExistingFileHelper existingFileHelper)
|
||||
{
|
||||
return new SeparatePerspectiveModelBuilder<>(parent, existingFileHelper);
|
||||
}
|
||||
|
||||
private T base;
|
||||
private final Map<String, T> childModels = new LinkedHashMap<>();
|
||||
|
||||
protected SeparatePerspectiveModelBuilder(T parent, ExistingFileHelper existingFileHelper)
|
||||
{
|
||||
super(new ResourceLocation("forge:separate-perspective"), parent, existingFileHelper);
|
||||
}
|
||||
|
||||
public SeparatePerspectiveModelBuilder<T> base(T modelBuilder)
|
||||
{
|
||||
Preconditions.checkNotNull(modelBuilder, "modelBuilder must not be null");
|
||||
base = modelBuilder;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SeparatePerspectiveModelBuilder<T> perspective(ItemCameraTransforms.TransformType perspective, T modelBuilder)
|
||||
{
|
||||
Preconditions.checkNotNull(perspective, "layer must not be null");
|
||||
Preconditions.checkArgument(SeparatePerspectiveModel.Loader.PERSPECTIVES.containsValue(perspective), "perspective is not included in SeparatePerspectiveModel. New mc version?");
|
||||
Preconditions.checkNotNull(modelBuilder, "modelBuilder must not be null");
|
||||
childModels.put(SeparatePerspectiveModel.Loader.PERSPECTIVES.inverse().get(perspective), modelBuilder);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonObject toJson(JsonObject json)
|
||||
{
|
||||
json = super.toJson(json);
|
||||
|
||||
if (base != null)
|
||||
{
|
||||
json.add("base", base.toJson());
|
||||
}
|
||||
|
||||
JsonObject parts = new JsonObject();
|
||||
for(Map.Entry<String, T> entry : childModels.entrySet())
|
||||
{
|
||||
parts.add(entry.getKey(), entry.getValue().toJson());
|
||||
}
|
||||
json.add("perspectives", parts);
|
||||
|
||||
return json;
|
||||
}
|
||||
}
|
|
@ -70,6 +70,22 @@ public class ExistingFileHelper {
|
|||
return new ResourceLocation(base.getNamespace(), prefix + "/" + base.getPath() + suffix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given resource exists in the known resource packs.
|
||||
*
|
||||
* @param loc the base location of the resource, e.g.
|
||||
* {@code "minecraft:block/stone"}
|
||||
* @param type the type of resources to check
|
||||
* @return {@code true} if the resource exists in any pack, {@code false}
|
||||
* otherwise
|
||||
*/
|
||||
public boolean exists(ResourceLocation loc, ResourcePackType type) {
|
||||
if (!enable) {
|
||||
return true;
|
||||
}
|
||||
return getManager(type).hasResource(loc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given resource exists in the known resource packs.
|
||||
*
|
||||
|
@ -83,15 +99,17 @@ public class ExistingFileHelper {
|
|||
* otherwise
|
||||
*/
|
||||
public boolean exists(ResourceLocation loc, ResourcePackType type, String pathSuffix, String pathPrefix) {
|
||||
if (!enable) {
|
||||
return true;
|
||||
}
|
||||
return getManager(type).hasResource(getLocation(loc, pathSuffix, pathPrefix));
|
||||
return exists(getLocation(loc, pathSuffix, pathPrefix), type);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public IResource getResource(ResourceLocation loc, ResourcePackType type, String pathSuffix, String pathPrefix) throws IOException {
|
||||
return getManager(type).getResource(getLocation(loc, pathSuffix, pathPrefix));
|
||||
return getResource(getLocation(loc, pathSuffix, pathPrefix), type);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public IResource getResource(ResourceLocation loc, ResourcePackType type) throws IOException {
|
||||
return getManager(type).getResource(loc);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -26,13 +26,11 @@ import com.mojang.datafixers.util.Pair;
|
|||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.client.renderer.model.IModelTransform;
|
||||
import net.minecraft.client.renderer.model.IUnbakedModel;
|
||||
import net.minecraft.client.renderer.model.ModelBakery;
|
||||
import net.minecraft.client.renderer.model.RenderMaterial;
|
||||
import net.minecraft.client.renderer.model.*;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormatElement;
|
||||
import net.minecraft.data.DataGenerator;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.inventory.EquipmentSlotType;
|
||||
import net.minecraft.item.*;
|
||||
|
@ -50,12 +48,18 @@ import net.minecraftforge.client.model.IModelBuilder;
|
|||
import net.minecraftforge.client.model.IModelConfiguration;
|
||||
import net.minecraftforge.client.model.IModelLoader;
|
||||
import net.minecraftforge.client.model.ModelLoaderRegistry;
|
||||
import net.minecraftforge.client.model.generators.BlockStateProvider;
|
||||
import net.minecraftforge.client.model.generators.ItemModelProvider;
|
||||
import net.minecraftforge.client.model.generators.loaders.ItemLayersModelBuilder;
|
||||
import net.minecraftforge.client.model.generators.loaders.OBJLoaderBuilder;
|
||||
import net.minecraftforge.client.model.generators.loaders.SeparatePerspectiveModelBuilder;
|
||||
import net.minecraftforge.client.model.geometry.ISimpleModelGeometry;
|
||||
import net.minecraftforge.client.model.pipeline.BakedQuadBuilder;
|
||||
import net.minecraftforge.common.data.ExistingFileHelper;
|
||||
import net.minecraftforge.eventbus.api.IEventBus;
|
||||
import net.minecraftforge.fml.RegistryObject;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
|
||||
import net.minecraftforge.fml.event.lifecycle.GatherDataEvent;
|
||||
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
|
||||
import net.minecraftforge.registries.DeferredRegister;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
|
@ -136,6 +140,7 @@ public class NewModelLoaderTest
|
|||
ITEMS.register(modEventBus);
|
||||
|
||||
modEventBus.addListener(this::modelRegistry);
|
||||
modEventBus.addListener(this::datagen);
|
||||
}
|
||||
|
||||
public void modelRegistry(ModelRegistryEvent event)
|
||||
|
@ -209,4 +214,64 @@ public class NewModelLoaderTest
|
|||
return Collections.singleton(owner.resolveTexture("particle"));
|
||||
}
|
||||
}
|
||||
|
||||
private void datagen(GatherDataEvent event)
|
||||
{
|
||||
DataGenerator gen = event.getGenerator();
|
||||
|
||||
if (event.includeClient())
|
||||
{
|
||||
// Let blockstate provider see generated item models by passing its existing file helper
|
||||
ItemModelProvider itemModels = new ItemModels(gen, event.getExistingFileHelper());
|
||||
gen.addProvider(itemModels);
|
||||
gen.addProvider(new BlockStates(gen, itemModels.existingFileHelper));
|
||||
}
|
||||
}
|
||||
|
||||
public static class ItemModels extends ItemModelProvider
|
||||
{
|
||||
public ItemModels(DataGenerator generator, ExistingFileHelper existingFileHelper)
|
||||
{
|
||||
super(generator, MODID, existingFileHelper);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerModels()
|
||||
{
|
||||
withExistingParent(NewModelLoaderTest.item_layers.getId().getPath(), "forge:item/default")
|
||||
.texture("layer0", "minecraft:item/coal")
|
||||
.texture("layer1", "minecraft:item/stick")
|
||||
.customLoader(ItemLayersModelBuilder::begin)
|
||||
.fullbright(1)
|
||||
.end();
|
||||
withExistingParent(NewModelLoaderTest.separate_perspective.getId().getPath(), "forge:item/default")
|
||||
.customLoader(SeparatePerspectiveModelBuilder::begin)
|
||||
.base(nested().parent(getExistingFile(mcLoc("minecraft:item/coal"))))
|
||||
.perspective(ItemCameraTransforms.TransformType.GUI, nested().parent(getExistingFile(mcLoc("minecraft:item/snowball"))))
|
||||
.perspective(ItemCameraTransforms.TransformType.FIRST_PERSON_LEFT_HAND, nested().parent(getExistingFile(mcLoc("minecraft:item/bone"))))
|
||||
.end();
|
||||
}
|
||||
}
|
||||
|
||||
public static class BlockStates extends BlockStateProvider
|
||||
{
|
||||
public BlockStates(DataGenerator gen, ExistingFileHelper exFileHelper)
|
||||
{
|
||||
super(gen, MODID, exFileHelper);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerStatesAndModels()
|
||||
{
|
||||
simpleBlock(NewModelLoaderTest.obj_block.get(), models()
|
||||
.getBuilder(NewModelLoaderTest.obj_block.getId().getPath())
|
||||
.customLoader(OBJLoaderBuilder::begin)
|
||||
.modelLocation(new ResourceLocation("new_model_loader_test:models/item/sugar_glider.obj"))
|
||||
.flipV(true)
|
||||
.end()
|
||||
.texture("qr", "minecraft:block/oak_planks")
|
||||
.texture("particle", "#qr")
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue