package net.minecraftforge.client.model.generators; import java.util.Arrays; import java.util.List; import java.util.function.Function; import java.util.stream.IntStream; import javax.annotation.Nullable; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ObjectArrays; import com.google.gson.JsonObject; import net.minecraft.client.renderer.model.ModelRotation; import net.minecraftforge.client.model.generators.MultiPartBlockStateBuilder.PartBuilder; import net.minecraftforge.client.model.generators.VariantBlockStateBuilder.PartialBlockstate; /** * Represents a model with blockstate configurations, e.g. rotation, uvlock, and * random weight. *
* Can be manually constructed, created by static factory such as
* {@link #allYRotations(ModelFile, int, boolean)}, or created by builder via
* {@link #builder()}.
*/
public final class ConfiguredModel {
/**
* The default random weight of configured models, used by convenience
* overloads.
*/
public static final int DEFAULT_WEIGHT = 1;
public final ModelFile model;
public final int rotationX;
public final int rotationY;
public final boolean uvLock;
public final int weight;
private static IntStream validRotations() {
return IntStream.range(0, 4).map(i -> i * 90);
}
public static ConfiguredModel[] allYRotations(ModelFile model, int x, boolean uvlock) {
return allYRotations(model, x, uvlock, DEFAULT_WEIGHT);
}
public static ConfiguredModel[] allYRotations(ModelFile model, int x, boolean uvlock, int weight) {
return validRotations()
.mapToObj(y -> new ConfiguredModel(model, x, y, uvlock, weight))
.toArray(ConfiguredModel[]::new);
}
public static ConfiguredModel[] allRotations(ModelFile model, boolean uvlock) {
return allRotations(model, uvlock, DEFAULT_WEIGHT);
}
public static ConfiguredModel[] allRotations(ModelFile model, boolean uvlock, int weight) {
return validRotations()
.mapToObj(x -> allYRotations(model, x, uvlock, weight))
.flatMap(Arrays::stream)
.toArray(ConfiguredModel[]::new);
}
/**
* Construct a new {@link ConfiguredModel}.
*
* @param model the underlying model
* @param rotationX x-rotation to apply to the model
* @param rotationY y-rotation to apply to the model
* @param uvLock if uvlock should be enabled
* @param weight the random weight of the model
*
* @throws NullPointerException if {@code model} is {@code null}
* @throws IllegalArgumentException if x and/or y rotation are not valid (see
* {@link ModelRotation})
* @throws IllegalArgumentException if weight is less than or equal to zero
*/
public ConfiguredModel(ModelFile model, int rotationX, int rotationY, boolean uvLock, int weight) {
Preconditions.checkNotNull(model);
this.model = model;
checkRotation(rotationX, rotationY);
this.rotationX = rotationX;
this.rotationY = rotationY;
this.uvLock = uvLock;
checkWeight(weight);
this.weight = weight;
}
/**
* Construct a new {@link ConfiguredModel} with the {@link #DEFAULT_WEIGHT
* default random weight}.
*
* @param model the underlying model
* @param rotationX x-rotation to apply to the model
* @param rotationY y-rotation to apply to the model
* @param uvLock if uvlock should be enabled
*
* @throws NullPointerException if {@code model} is {@code null}
* @throws IllegalArgumentException if x and/or y rotation are not valid (see
* {@link ModelRotation})
*/
public ConfiguredModel(ModelFile model, int rotationX, int rotationY, boolean uvLock) {
this(model, rotationX, rotationY, uvLock, DEFAULT_WEIGHT);
}
/**
* Construct a new {@link ConfiguredModel} with the default rotation (0, 0),
* uvlock (false), and {@link #DEFAULT_WEIGHT default random weight}.
*
* @throws NullPointerException if {@code model} is {@code null}
*/
public ConfiguredModel(ModelFile model) {
this(model, 0, 0, false);
}
static void checkRotation(int rotationX, int rotationY) {
Preconditions.checkArgument(ModelRotation.getModelRotation(rotationX, rotationY) != null, "Invalid model rotation x=%d, y=%d", rotationX, rotationY);
}
static void checkWeight(int weight) {
Preconditions.checkArgument(weight >= 1, "Model weight must be greater than or equal to 1. Found: %d", weight);
}
JsonObject toJSON(boolean includeWeight) {
JsonObject modelJson = new JsonObject();
modelJson.addProperty("model", model.getLocation().toString());
if (rotationX != 0)
modelJson.addProperty("x", rotationX);
if (rotationY != 0)
modelJson.addProperty("y", rotationY);
if (uvLock)
modelJson.addProperty("uvlock", uvLock);
if (includeWeight && weight != DEFAULT_WEIGHT)
modelJson.addProperty("weight", weight);
return modelJson;
}
/**
* Create a new unowned {@link Builder}.
*
* @return the builder
* @see Builder
*/
public static Builder> builder() {
return new Builder<>();
}
static Builder
* Multiple models can be configured at once through the use of
* {@link #nextModel()}.
*
* @param
* Known callbacks include:
*
*
*
* @return the owning builder object
* @throws NullPointerException if there is no owning builder (and thus no callback)
*/
public T addModel() {
Preconditions.checkNotNull(callback, "Cannot use addModel() without an owning builder present");
return callback.apply(build());
}
/**
* Complete the current model and return a new builder instance with the same
* callback, and storing all previously built models.
*
* @return a new builder for configuring the next model
*/
public Builder