diff --git a/libraries/datagen/README.md b/libraries/datagen/README.md new file mode 100644 index 00000000..bd0dc95d --- /dev/null +++ b/libraries/datagen/README.md @@ -0,0 +1,66 @@ +# Data Generator API + +The Data Generator API is a library that provides a simple and intuitive way to generate data files for Minecraft mods. +It allows mod developers to easily create block models, item models, and other data files without having to manually write JSON files. + +## Registering Data Generators +### Entrypoint + +The Data Generator API provides an entrypoint that allows mod developers to register their data generators. +This entrypoint is used to register the data generators that will be used to generate the data files for the mod. + +An example is shown below. + +`fabric.mod.json` +```json +{ + ... + "entrypoints": { + ... + "datagen": [ + "com.example.ExampleDataGenerator" + ], + ... + }, + ... +} +``` + +```java +package com.example; + +import net.ornithemc.osl.datagen.api.DataGeneratorInitializer; + +public class ExampleDataGenerator implements DataGeneratorInitializer { + @Override + public void onDatagenInit(ModDataGenerator dataGenerator) { + PackGenerator pack = dataGenerator.createPack(); + pack.addProvider(ExampleModelProvider::new); + } +} +``` + +### Mod Data Providers + +Mod data providers are used to provide data to the pack generator. +There are a few builtin providers, such as the model provider, and language provider. + +An example for the model provider is shown below. + +```java +package com.example; + +public class ExampleModelProvider extends ModModelProvider { + public ExampleModelProvider(PackGenerator generator, ModContainer mod) { + super(generator, mod); + } + + public void generateModels(ModelGenerator generator) { + BlockModelTemplates templates = generator.blockTemplates(); + templates.simpleBlock(Blocks.OAK_PLANKS, block("oak_planks")); + } +} +``` + +Vanilla DataProviders can also be extended to provide data such as tags. +In the extended constructor, replace DataGenerator with PackGenerator and upcast it back to DataGenerator. diff --git a/libraries/datagen/build.gradle b/libraries/datagen/build.gradle new file mode 100644 index 00000000..99b09f4a --- /dev/null +++ b/libraries/datagen/build.gradle @@ -0,0 +1,6 @@ +setUpLibrary(project) + +dependencies { + implementation 'com.google.code.gson:gson:2.8.0' + implementation 'com.google.guava:guava:17.0' +} \ No newline at end of file diff --git a/libraries/datagen/datagen-mc18w43a-mc1.14.4/build.gradle b/libraries/datagen/datagen-mc18w43a-mc1.14.4/build.gradle new file mode 100644 index 00000000..0a350fdb --- /dev/null +++ b/libraries/datagen/datagen-mc18w43a-mc1.14.4/build.gradle @@ -0,0 +1 @@ +setUpModule(project) diff --git a/libraries/datagen/datagen-mc18w43a-mc1.14.4/gradle.properties b/libraries/datagen/datagen-mc18w43a-mc1.14.4/gradle.properties new file mode 100644 index 00000000..038ff5db --- /dev/null +++ b/libraries/datagen/datagen-mc18w43a-mc1.14.4/gradle.properties @@ -0,0 +1,5 @@ +#min_mc_version = 1.13-pre6 +min_mc_version = 18w43a +max_mc_version = 1.14.4 + +minecraft_version = 1.14.4 diff --git a/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/api/model/ModelBuilder.java b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/api/model/ModelBuilder.java new file mode 100644 index 00000000..07a9c1c8 --- /dev/null +++ b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/api/model/ModelBuilder.java @@ -0,0 +1,75 @@ +package net.ornithemc.osl.datagen.api.model; + +import com.google.gson.JsonObject; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; + +import java.util.HashMap; +import java.util.Map; + +/** + * Represents a block or item model. + */ +public class ModelBuilder { + private NamespacedIdentifier parent; + private Map textures = new HashMap<>(); + + /** + * Creates a new model builder. + * + * @return the model builder + */ + public static ModelBuilder create() { + return new ModelBuilder(); + } + + /** + * Creates a new model builder with the given parent. + * + * @param parent the parent model + * @return the model builder + */ + public static ModelBuilder create(NamespacedIdentifier parent) { + return new ModelBuilder().parent(parent); + } + + /** + * Sets the parent model. + * + * @param parent the parent model + * @return the model builder + */ + public ModelBuilder parent(NamespacedIdentifier parent) { + this.parent = parent; + return this; + } + + /** + * Sets the texture path for the given name. + * + * @param name the name of the texture + * @param texture the texture path + * @return the model builder + */ + public ModelBuilder texture(String name, NamespacedIdentifier texture) { + this.textures.put(name, texture); + return this; + } + + public JsonObject build() { + JsonObject model = new JsonObject(); + + if (parent != null) { + model.addProperty("parent", parent.toString()); + } + + if (!textures.isEmpty()) { + JsonObject texturesJson = new JsonObject(); + for (Map.Entry entry : textures.entrySet()) { + texturesJson.addProperty(entry.getKey(), entry.getValue().toString()); + } + model.add("textures", texturesJson); + } + + return model; + } +} diff --git a/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/api/model/ModelGenerator.java b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/api/model/ModelGenerator.java new file mode 100644 index 00000000..8e4effe0 --- /dev/null +++ b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/api/model/ModelGenerator.java @@ -0,0 +1,63 @@ +package net.ornithemc.osl.datagen.api.model; + +import net.minecraft.block.Block; +import net.minecraft.item.ItemLike; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.datagen.api.model.block.BlockModelDefinitionBuilder; +import net.ornithemc.osl.datagen.api.model.block.BlockModelTemplates; + +/** + * Provides methods for generating model resources. + */ +public interface ModelGenerator { + /** + * Generates a blockstate file for the given block. + * + * @param block the block to generate the blockstate for + * @param builder the builder to use for generating the blockstate + */ + void blockstate(Block block, BlockModelDefinitionBuilder builder); + + /** + * Generates an item model file for the given item or block item. + * + * @param item the item to generate the item model for + * @param builder the builder to use for generating the item model + */ + void itemModel(ItemLike item, ModelBuilder builder); + + /** + * Generates a block model file for the given identifier. + * + * @param identifier the identifier to generate the block model for + * @param builder the builder to use for generating the block model + * @return the generated block model identifier + */ + NamespacedIdentifier blockModel(NamespacedIdentifier identifier, ModelBuilder builder); + + /** + * Generates a block model file for the given block. + * + * @param block the block to generate the block model for + * @param builder the builder to use for generating the block model + * @return the generated block model identifier + */ + NamespacedIdentifier blockModel(Block block, ModelBuilder builder); + + /** + * Generates a block model file for the given block with the given suffix. + * + * @param block the block to generate the block model for + * @param suffix the suffix to append to the block model identifier + * @param builder the builder to use for generating the block model + * @return the generated block model identifier + */ + NamespacedIdentifier blockModel(Block block, String suffix, ModelBuilder builder); + + /** + * Returns the block model templates. + * + * @return the block model templates + */ + BlockModelTemplates blockTemplates(); +} diff --git a/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/api/model/block/BlockModelDefinitionBuilder.java b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/api/model/block/BlockModelDefinitionBuilder.java new file mode 100644 index 00000000..ba42477c --- /dev/null +++ b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/api/model/block/BlockModelDefinitionBuilder.java @@ -0,0 +1,228 @@ +package net.ornithemc.osl.datagen.api.model.block; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import net.minecraft.block.state.BlockState; +import net.minecraft.client.render.block.BlockModelShaper; +import net.minecraft.state.property.Property; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; + +import java.util.*; + +/** + * Builder for blockstate model definitions. + */ +public class BlockModelDefinitionBuilder { + private final Map variants = new HashMap<>(); + private final List selectors = new ArrayList<>(); + + private BlockModelDefinitionBuilder() { + } + + /** + * Creates a new block model definition builder. + * + * @return the new block model definition builder + */ + public static BlockModelDefinitionBuilder create() { + return new BlockModelDefinitionBuilder(); + } + + /** + * Creates a new block model definition builder with a default variant. + * + * @param modelLocation the model location + * @return the new block model definition builder + */ + public static BlockModelDefinitionBuilder createSimple(NamespacedIdentifier modelLocation) { + return new BlockModelDefinitionBuilder().variant("", VariantsBuilder.of(modelLocation)); + } + + /** + * Adds a variant to the block model definition. + * + * @param state the block state predicate + * @param variants the variants builder + * @return this builder + */ + public BlockModelDefinitionBuilder variant(BlockState state, VariantsBuilder variants) { + this.variants.put(BlockModelShaper.propertiesToString(state.values()), variants); + return this; + } + + /** + * Adds a variant to the block model definition. + * + * @param state the block state predicate + * @param modelLocation the model location + * @return this builder + */ + public BlockModelDefinitionBuilder variant(BlockState state, NamespacedIdentifier modelLocation) { + this.variants.put(BlockModelShaper.propertiesToString(state.values()), VariantsBuilder.of(modelLocation)); + return this; + } + + /** + * Adds a variant to the block model definition. + * + * @param predicateBuilder the blockstate predicate builder + * @param variants the variants builder + * @return this builder + */ + public BlockModelDefinitionBuilder variant(PredicateBuilder predicateBuilder, VariantsBuilder variants) { + this.variants.put(predicateBuilder.build(), variants); + return this; + } + + /** + * Adds a variant to the block model definition. + * + * @param predicateBuilder the blockstate predicate builder + * @param modelLocation the model location + * @return this builder + */ + public BlockModelDefinitionBuilder variant(PredicateBuilder predicateBuilder, NamespacedIdentifier modelLocation) { + this.variants.put(predicateBuilder.build(), VariantsBuilder.of(modelLocation)); + return this; + } + + /** + * Adds a variant to the block model definition. + * + * @param variantName the variant name + * @param variants the variants builder + * @return this builder + */ + private BlockModelDefinitionBuilder variant(String variantName, VariantsBuilder variants) { + this.variants.put(variantName, variants); + return this; + } + + /** + * Adds a selector to the block model definition. + * + * @param variants the variants builder + * @return this builder + */ + public BlockModelDefinitionBuilder selector(VariantsBuilder variants) { + this.selectors.add(new SelectorBuilder(null, variants)); + return this; + } + + /** + * Adds a selector to the block model definition. + * + * @param modelLocation the model location + * @return this builder + */ + public BlockModelDefinitionBuilder selector(NamespacedIdentifier modelLocation) { + this.selectors.add(new SelectorBuilder(null, VariantsBuilder.of(modelLocation))); + return this; + } + + /** + * Adds a selector to the block model definition. + * + * @param conditions the conditions builder + * @param variants the variants builder + * @return this builder + */ + public BlockModelDefinitionBuilder selector(ConditionsBuilder conditions, VariantsBuilder variants) { + this.selectors.add(new SelectorBuilder(conditions, variants)); + return this; + } + + /** + * Adds a selector to the block model definition. + * + * @param conditions the conditions builder + * @param modelLocation the model location + * @return this builder + */ + public BlockModelDefinitionBuilder selector(ConditionsBuilder conditions, NamespacedIdentifier modelLocation) { + this.selectors.add(new SelectorBuilder(conditions, VariantsBuilder.of(modelLocation))); + return this; + } + + public JsonObject build() { + JsonObject json = new JsonObject(); + + if (!variants.isEmpty()) { + JsonObject variantsJson = new JsonObject(); + + for (Map.Entry entry : variants.entrySet()) { + variantsJson.add(entry.getKey(), entry.getValue().build()); + } + + json.add("variants", variantsJson); + } + + if (!selectors.isEmpty()) { + JsonArray multiPart = new JsonArray(); + + for (SelectorBuilder entry : selectors) { + multiPart.add(entry.build()); + } + + json.add("multipart", multiPart); + } + + if (json.keySet().isEmpty()) { + throw new IllegalStateException("Block state model definition is empty"); + } + + return json; + } + + static class SelectorBuilder { + private final ConditionsBuilder conditions; + private final VariantsBuilder variants; + + SelectorBuilder(ConditionsBuilder conditions, VariantsBuilder variants) { + this.conditions = conditions; + this.variants = variants; + } + + private JsonObject build() { + JsonObject json = new JsonObject(); + + if (conditions != null) json.add("when", conditions.build()); + json.add("apply", variants.build()); + + return json; + } + } + + /** + * Creates a predicate builder with the specified property and value. + * + * @param property the property + * @param value the value + * @return the predicate builder + * @param the property type + */ + public static > PredicateBuilder predicate(Property property, T value) { + return new PredicateBuilder().set(property, value); + } + + public static class PredicateBuilder { + private final Map, Comparable> predicates = new HashMap<>(); + + /** + * Sets the specified property and value. + * + * @param property the property + * @param value the value + * @return this builder + * @param the property type + */ + public > PredicateBuilder set(Property property, T value) { + predicates.put(property, value); + return this; + } + + private String build() { + return BlockModelShaper.propertiesToString(predicates); + } + } +} diff --git a/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/api/model/block/BlockModelTemplates.java b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/api/model/block/BlockModelTemplates.java new file mode 100644 index 00000000..cd337c42 --- /dev/null +++ b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/api/model/block/BlockModelTemplates.java @@ -0,0 +1,603 @@ +package net.ornithemc.osl.datagen.api.model.block; + +import net.minecraft.block.Block; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.NamespacedIdentifiers; +import net.ornithemc.osl.datagen.api.model.ModelBuilder; + +/** + * A collection of block model and definition templates. + */ +public interface BlockModelTemplates { + /** + * Creates a simple block model, definition, and item model with the given texture. + * + * @param block the block + * @param texture the texture + */ + BlockModelTemplates simpleBlock(Block block, NamespacedIdentifier texture); + + /** + * Creates a simple block model, definition, without an item model with the given texture. + * + * @param block the block + * @param texture the texture + */ + BlockModelTemplates simpleBlockWithoutItem(Block block, NamespacedIdentifier texture); + + /** + * Creates a slab block model, definition, and item model with the given textures. + * + * @param block the block + * @param doubleModelLocation the double slab model location + * @param sideTexture the side texture + * @param topTexture the top texture + * @param bottomTexture the bottom texture + */ + BlockModelTemplates slab(Block block, NamespacedIdentifier doubleModelLocation, NamespacedIdentifier sideTexture, NamespacedIdentifier topTexture, NamespacedIdentifier bottomTexture); + + /** + * Creates a slab block model, definition, and item model with the given texture. + * + * @param block the block + * @param doubleModelLocation the double slab model location + * @param texture the texture + */ + BlockModelTemplates simpleSlab(Block block, NamespacedIdentifier doubleModelLocation, NamespacedIdentifier texture); + + /** + * Creates a stairs block model, definition, and item model with the given textures. + * + * @param block the block + * @param sideTexture the side texture + * @param topTexture the top texture + * @param bottomTexture the bottom texture + */ + BlockModelTemplates stairs(Block block, NamespacedIdentifier sideTexture, NamespacedIdentifier topTexture, NamespacedIdentifier bottomTexture); + + /** + * Creates a stairs block model, definition, and item model with the given texture. + * + * @param block the block + * @param texture the texture + */ + BlockModelTemplates simpleStairs(Block block, NamespacedIdentifier texture); + + /** + * Creates a wall block model, definition, and item model with the given texture. + * + * @param block the block + * @param texture the texture + * @return the model builder + */ + BlockModelTemplates wall(Block block, NamespacedIdentifier texture); + + /** + * Creates a fence block model, definition, and item model with the given texture. + * + * @param block the block + * @param texture the texture + * @return the model builder + */ + BlockModelTemplates fence(Block block, NamespacedIdentifier texture); + + /** + * Creates a button block model, definition, and item model with the given texture. + * + * @param block the block + * @param texture the texture + * @return the model builder + */ + BlockModelTemplates button(Block block, NamespacedIdentifier texture); + + /** + * Creates a door block model, definition, and item model with the given textures. + * + * @param block the block + * @param inventoryTexture the inventory texture + * @param topTexture the top texture + * @param bottomTexture the bottom texture + * @return the model builder + */ + BlockModelTemplates door(Block block, NamespacedIdentifier inventoryTexture, NamespacedIdentifier topTexture, NamespacedIdentifier bottomTexture); + + /** + * Creates a fence gate block model, definition, and item model with the given texture. + * + * @param block the block + * @param texture the texture + * @return the model builder + */ + BlockModelTemplates fenceGate(Block block, NamespacedIdentifier texture); + + /** + * Creates a leaves block model, definition, and item model with the given texture. + * + * @param block the block + * @param texture the texture + * @return the model builder + */ + BlockModelTemplates leaves(Block block, NamespacedIdentifier texture); + + /** + * Creates a pressure plate block model, definition, and item model with the given texture. + * + * @param block the block + * @param texture the texture + * @return the model builder + */ + BlockModelTemplates pressurePlate(Block block, NamespacedIdentifier texture); + + /** + * Creates a trapdoor block model, definition, and item model with the given texture. + * + * @param block the block + * @param texture the texture + * @return the model builder + */ + BlockModelTemplates trapdoor(Block block, NamespacedIdentifier texture); + + /** + * Creates a cube block model with the given textures. + * + * @param downTexture the bottom texture + * @param upTexture the top texture + * @param northTexture the north texture + * @param southTexture the south texture + * @param westTexture the west texture + * @param eastTexture the east texture + * @return the model builder + */ + static ModelBuilder cube( + NamespacedIdentifier downTexture, + NamespacedIdentifier upTexture, + NamespacedIdentifier northTexture, + NamespacedIdentifier southTexture, + NamespacedIdentifier westTexture, + NamespacedIdentifier eastTexture + ) { + return ModelBuilder.create(NamespacedIdentifiers.from("block/cube")) + .texture("down", downTexture) + .texture("up", upTexture) + .texture("north", northTexture) + .texture("south", southTexture) + .texture("west", westTexture) + .texture("east", eastTexture); + } + + /** + * Creates a cube block model with the given texture for all sides. + * + * @param texture the texture + * @return the model builder + */ + static ModelBuilder cubeAll(NamespacedIdentifier texture) { + return ModelBuilder.create(NamespacedIdentifiers.from("block/cube_all")).texture("all", texture); + } + + /** + * Creates a cube block model with the given textures. + * + * @param sideTexture the side texture + * @param topTexture the top texture + * @param bottomTexture the bottom texture + * @return the model builder + */ + static ModelBuilder cubeBottomTop(NamespacedIdentifier sideTexture, NamespacedIdentifier topTexture, NamespacedIdentifier bottomTexture) { + return ModelBuilder.create(NamespacedIdentifiers.from("block/cube_bottom_top")) + .texture("side", sideTexture) + .texture("bottom", bottomTexture) + .texture("top", topTexture); + } + + /** + * Creates a cube block model with the given textures for the sides and a different texture for the ends. + * + * @param sideTexture the side texture + * @param endTexture the end texture + * @return the model builder + */ + static ModelBuilder cubeColumn(NamespacedIdentifier sideTexture, NamespacedIdentifier endTexture) { + return ModelBuilder.create(NamespacedIdentifiers.from("block/cube_column")) + .texture("side", sideTexture) + .texture("end", endTexture); + } + + /** + * Creates a cube block model with the given textures for the sides and different textures for the ends. + * + * @param downTexture the bottom texture + * @param upTexture the top texture + * @param northTexture the north texture + * @param southTexture the south texture + * @param westTexture the west texture + * @param eastTexture the east texture + * @return the model builder + */ + static ModelBuilder cubeDirectional( + NamespacedIdentifier downTexture, + NamespacedIdentifier upTexture, + NamespacedIdentifier northTexture, + NamespacedIdentifier southTexture, + NamespacedIdentifier westTexture, + NamespacedIdentifier eastTexture + ) { + return ModelBuilder.create(NamespacedIdentifiers.from("block/cube_directional")) + .texture("down", downTexture) + .texture("up", upTexture) + .texture("north", northTexture) + .texture("south", southTexture) + .texture("west", westTexture) + .texture("east", eastTexture); + } + + /** + * Creates a cube block model with the given texture for all sides mirrored. + * + * @param downTexture the bottom texture + * @param upTexture the top texture + * @param northTexture the north texture + * @param southTexture the south texture + * @param westTexture the west texture + * @param eastTexture the east texture + * @return the model builder + */ + static ModelBuilder cubeMirrored( + NamespacedIdentifier downTexture, + NamespacedIdentifier upTexture, + NamespacedIdentifier northTexture, + NamespacedIdentifier southTexture, + NamespacedIdentifier westTexture, + NamespacedIdentifier eastTexture + ) { + return ModelBuilder.create(NamespacedIdentifiers.from("block/cube_mirrored")) + .texture("down", downTexture) + .texture("up", upTexture) + .texture("north", northTexture) + .texture("south", southTexture) + .texture("west", westTexture) + .texture("east", eastTexture); + } + + /** + * Creates a cube block model with the given texture for all sides mirrored. + * + * @param texture the texture + * @return the model builder + */ + static ModelBuilder cubeAllMirrored(NamespacedIdentifier texture) { + return ModelBuilder.create(NamespacedIdentifiers.from("block/cube_all_mirrored")).texture("all", texture); + } + + /** + * Creates a cube block model with the given texture for the sides and a different texture for the top. + * + * @param sideTexture the side texture + * @param topTexture the top texture + * @return the model builder + */ + static ModelBuilder cubeTop(NamespacedIdentifier sideTexture, NamespacedIdentifier topTexture) { + return ModelBuilder.create(NamespacedIdentifiers.from("block/cube_top")) + .texture("side", sideTexture) + .texture("top", topTexture); + } + + /** + * Creates a bottom slab block model with the given textures. + * + * @param sideTexture the side texture + * @param topTexture the top texture + * @param bottomTexture the bottom texture + * @return the model builder + */ + static ModelBuilder slabBottom(NamespacedIdentifier sideTexture, NamespacedIdentifier topTexture, NamespacedIdentifier bottomTexture) { + return ModelBuilder.create(NamespacedIdentifiers.from("block/slab")) + .texture("side", sideTexture) + .texture("top", topTexture) + .texture("bottom", bottomTexture); + } + + /** + * Creates a top slab block model with the given textures. + * + * @param sideTexture the side texture + * @param topTexture the top texture + * @param bottomTexture the bottom texture + * @return the model builder + */ + static ModelBuilder slabTop(NamespacedIdentifier sideTexture, NamespacedIdentifier topTexture, NamespacedIdentifier bottomTexture) { + return ModelBuilder.create(NamespacedIdentifiers.from("block/slab_top")) + .texture("side", sideTexture) + .texture("top", topTexture) + .texture("bottom", bottomTexture); + } + + /** + * Creates a cross-like block model with the given texture. + * + * @param texture the texture + * @return the model builder + */ + static ModelBuilder cross(NamespacedIdentifier texture) { + return ModelBuilder.create(NamespacedIdentifiers.from("block/cross")).texture("cross", texture); + } + + /** + * Creates a stairs block model with the given textures. + * + * @param sideTexture the side texture + * @param topTexture the top texture + * @param bottomTexture the bottom texture + * @return the model builder + */ + static ModelBuilder stairs(NamespacedIdentifier sideTexture, NamespacedIdentifier topTexture, NamespacedIdentifier bottomTexture) { + return ModelBuilder.create(NamespacedIdentifiers.from("block/stairs")) + .texture("side", sideTexture) + .texture("top", topTexture) + .texture("bottom", bottomTexture); + } + + /** + * Creates an inner stairs block model with the given textures. + * + * @param sideTexture the side texture + * @param topTexture the top texture + * @param bottomTexture the bottom texture + * @return the model builder + */ + static ModelBuilder stairsInner(NamespacedIdentifier sideTexture, NamespacedIdentifier topTexture, NamespacedIdentifier bottomTexture) { + return ModelBuilder.create(NamespacedIdentifiers.from("block/inner_stairs")) + .texture("side", sideTexture) + .texture("top", topTexture) + .texture("bottom", bottomTexture); + } + + /** + * Creates an outer stairs block model with the given textures. + * + * @param sideTexture the side texture + * @param topTexture the top texture + * @param bottomTexture the bottom texture + * @return the model builder + */ + static ModelBuilder stairsOuter(NamespacedIdentifier sideTexture, NamespacedIdentifier topTexture, NamespacedIdentifier bottomTexture) { + return ModelBuilder.create(NamespacedIdentifiers.from("block/outer_stairs")) + .texture("side", sideTexture) + .texture("top", topTexture) + .texture("bottom", bottomTexture); + } + + /** + * Creates a wall inventory block model with the given texture. + * + * @param texture the texture + * @return the model builder + */ + static ModelBuilder wallInventory(NamespacedIdentifier texture) { + return ModelBuilder.create(NamespacedIdentifiers.from("block/wall_inventory")).texture("wall", texture); + } + + /** + * Creates a wall post block model with the given texture. + * + * @param texture the texture + * @return the model builder + */ + static ModelBuilder wallPost(NamespacedIdentifier texture) { + return ModelBuilder.create(NamespacedIdentifiers.from("block/template_wall_post")).texture("wall", texture); + } + + /** + * Creates a wall side block model with the given texture. + * + * @param texture the texture + * @return the model builder + */ + static ModelBuilder wallSide(NamespacedIdentifier texture) { + return ModelBuilder.create(NamespacedIdentifiers.from("block/template_wall_side")).texture("wall", texture); + } + + /** + * Creates a fence inventory block model with the given texture. + * + * @param texture the texture + * @return the model builder + */ + static ModelBuilder fenceInventory(NamespacedIdentifier texture) { + return ModelBuilder.create(NamespacedIdentifiers.from("block/fence_inventory")).texture("texture", texture); + } + + /** + * Creates a fence post, block model with the given texture. + * + * @param texture the texture + * @return the model builder + */ + static ModelBuilder fencePost(NamespacedIdentifier texture) { + return ModelBuilder.create(NamespacedIdentifiers.from("block/fence_post")).texture("texture", texture); + } + + /** + * Creates a fence side block model with the given texture. + * + * @param texture the texture + * @return the model builder + */ + static ModelBuilder fenceSide(NamespacedIdentifier texture) { + return ModelBuilder.create(NamespacedIdentifiers.from("block/fence_side")).texture("texture", texture); + } + + /** + * Creates a button block model with the given texture. + * + * @param texture the texture + * @return the model builder + */ + static ModelBuilder button(NamespacedIdentifier texture) { + return ModelBuilder.create(NamespacedIdentifiers.from("block/button")).texture("texture", texture); + } + + /** + * Creates a button inventory block model with the given texture. + * + * @param texture the texture + * @return the model builder + */ + static ModelBuilder buttonInventory(NamespacedIdentifier texture) { + return ModelBuilder.create(NamespacedIdentifiers.from("block/button_inventory")).texture("texture", texture); + } + + /** + * Creates a button pressed, block model with the given texture. + * + * @param texture the texture + * @return the model builder + */ + static ModelBuilder buttonPressed(NamespacedIdentifier texture) { + return ModelBuilder.create(NamespacedIdentifiers.from("block/button_pressed")).texture("texture", texture); + } + + /** + * Creates a door bottom block model with the given top and bottom textures. + * + * @param topTexture the top texture + * @param bottomTexture the bottom texture + * @return the model builder + */ + static ModelBuilder doorBottom(NamespacedIdentifier topTexture, NamespacedIdentifier bottomTexture) { + return ModelBuilder.create(NamespacedIdentifiers.from("block/door_bottom")).texture("top", topTexture).texture("bottom", bottomTexture); + } + + /** + * Creates a door bottom block model with the given top and bottom textures, with the hinge on the right. + * + * @param topTexture the top texture + * @param bottomTexture the bottom texture + * @return the model builder + */ + static ModelBuilder doorBottomHinge(NamespacedIdentifier topTexture, NamespacedIdentifier bottomTexture) { + return ModelBuilder.create(NamespacedIdentifiers.from("block/door_bottom_rh")).texture("top", topTexture).texture("bottom", bottomTexture); + } + + /** + * Creates a door top block model with the given top and bottom textures. + * + * @param topTexture the top texture + * @param bottomTexture the bottom texture + * @return the model builder + */ + static ModelBuilder doorTop(NamespacedIdentifier topTexture, NamespacedIdentifier bottomTexture) { + return ModelBuilder.create(NamespacedIdentifiers.from("block/door_top")).texture("top", topTexture).texture("bottom", bottomTexture); + } + + /** + * Creates a door top block model with the given top and bottom textures, with the hinge on the right. + * + * @param topTexture the top texture + * @param bottomTexture the bottom texture + * @return the model builder + */ + static ModelBuilder doorTopHinge(NamespacedIdentifier topTexture, NamespacedIdentifier bottomTexture) { + return ModelBuilder.create(NamespacedIdentifiers.from("block/door_top_rh")).texture("top", topTexture).texture("bottom", bottomTexture); + } + + /** + * Creates a fence gate block model with the given texture. + * + * @param texture the texture + * @return the model builder + */ + static ModelBuilder fenceGate(NamespacedIdentifier texture) { + return ModelBuilder.create(NamespacedIdentifiers.from("block/template_fence_gate")).texture("texture", texture); + } + + /** + * Creates a fence gate block model with the given texture, with the gate open. + * + * @param texture the texture + * @return the model builder + */ + static ModelBuilder fenceGateOpen(NamespacedIdentifier texture) { + return ModelBuilder.create(NamespacedIdentifiers.from("block/template_fence_gate_open")).texture("texture", texture); + } + + /** + * Creates a fence gate block model with the given texture, with the gate open and on a wall. + * + * @param texture the texture + * @return the model builder + */ + static ModelBuilder fenceGateWall(NamespacedIdentifier texture) { + return ModelBuilder.create(NamespacedIdentifiers.from("block/template_fence_gate_wall")).texture("texture", texture); + } + + /** + * Creates a fence gate block model with the given texture, with the gate open and on a wall. + * + * @param texture the texture + * @return the model builder + */ + static ModelBuilder fenceGateWallOpen(NamespacedIdentifier texture) { + return ModelBuilder.create(NamespacedIdentifiers.from("block/template_fence_gate_wall_open")).texture("texture", texture); + } + + /** + * Creates a leaves block model with the given texture. + * + * @param texture the texture + * @return the model builder + */ + static ModelBuilder leaves(NamespacedIdentifier texture) { + return ModelBuilder.create(NamespacedIdentifiers.from("block/leaves")).texture("all", texture); + } + + /** + * Creates a pressure plate block model with the given texture, with the plate up. + * + * @param texture the texture + * @return the model builder + */ + static ModelBuilder pressurePlateUp(NamespacedIdentifier texture) { + return ModelBuilder.create(NamespacedIdentifiers.from("block/pressure_plate_up")).texture("texture", texture); + } + + /** + * Creates a pressure plate block model with the given texture, with the plate down. + * + * @param texture the texture + * @return the model builder + */ + static ModelBuilder pressurePlateDown(NamespacedIdentifier texture) { + return ModelBuilder.create(NamespacedIdentifiers.from("block/pressure_plate_down")).texture("texture", texture); + } + + /** + * Creates a closed trapdoor block model with the given texture, with the trapdoor at the bottom. + * + * @param texture the texture + * @return the model builder + */ + static ModelBuilder trapdoorBottom(NamespacedIdentifier texture) { + return ModelBuilder.create(NamespacedIdentifiers.from("block/template_orientable_trapdoor_bottom")).texture("texture", texture); + } + + /** + * Creates a trapdoor block model with the given texture, with the trapdoor open. + * + * @param texture the texture + * @return the model builder + */ + static ModelBuilder trapdoorOpen(NamespacedIdentifier texture) { + return ModelBuilder.create(NamespacedIdentifiers.from("block/template_orientable_trapdoor_open")).texture("texture", texture); + } + + /** + * Creates a closed trapdoor block model with the given texture, with the trapdoor at the top. + * + * @param texture the texture + * @return the model builder + */ + static ModelBuilder trapdoorTop(NamespacedIdentifier texture) { + return ModelBuilder.create(NamespacedIdentifiers.from("block/template_orientable_trapdoor_top")).texture("texture", texture); + } +} diff --git a/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/api/model/block/ConditionsBuilder.java b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/api/model/block/ConditionsBuilder.java new file mode 100644 index 00000000..825d1435 --- /dev/null +++ b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/api/model/block/ConditionsBuilder.java @@ -0,0 +1,173 @@ +package net.ornithemc.osl.datagen.api.model.block; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import net.minecraft.state.property.Property; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * Represents block model definition selector conditions. + */ +public interface ConditionsBuilder { + JsonObject build(); + + /** + * Creates an inverted property predicate with the specified property and values. + * + * @param property the property + * @param mainMatch the main match value + * @param extraPossibleMatch the extra possible match values + * @param the type of the property + * @return the property builder + */ + @SafeVarargs + static > PropertyPredicate propertyInverted(Property property, @NotNull T mainMatch, T... extraPossibleMatch) { + List valueList = new ArrayList<>(); + valueList.add(mainMatch); + valueList.addAll(Arrays.asList(extraPossibleMatch)); + return new PropertyPredicate<>(false, property, valueList); + } + + /** + * Creates a property predicate with the specified property and values. + * + * @param property the property + * @param mainMatch the main match value + * @param extraPossibleMatch the extra possible match values + * @param the type of the property + * @return the property builder + */ + @SafeVarargs + static > PropertyPredicate property(Property property, @NotNull T mainMatch, T... extraPossibleMatch) { + List valueList = new ArrayList<>(); + valueList.add(mainMatch); + valueList.addAll(Arrays.asList(extraPossibleMatch)); + return new PropertyPredicate<>(false, property, valueList); + } + + /** + * Creates a simple conditions builder with the specified properties. + * + * @param properties the properties + * @return the conditions builder + */ + static ConditionsBuilder properties(PropertyPredicate...properties) { + if (properties.length == 0) { + throw new IllegalArgumentException("Must provide at least one property"); + } + + return new PropertyConditionBuilder(properties); + } + + /** + * Creates a "or" conditions builder with the specified conditions. + * + * @param conditions the conditions + * @return the conditions builder + */ + static ConditionsBuilder or(ConditionsBuilder...conditions) { + if (conditions.length == 0) { + throw new IllegalArgumentException("Must provide at least one condition"); + } + + return new OrConditonBuilder(conditions); + } + + /** + * Creates a "and" conditions builder with the specified conditions. + * + * @param conditions the conditions + * @return the conditions builder + */ + static ConditionsBuilder and(ConditionsBuilder...conditions) { + if (conditions.length == 0) { + throw new IllegalArgumentException("Must provide at least one condition"); + } + + return new AndConditonBuilder(conditions); + } + + class PropertyPredicate> { + private final boolean inverted; + private final Property property; + private final List values; + + private PropertyPredicate(boolean inverted, Property property, List values) { + this.inverted = inverted; + this.property = property; + this.values = values; + } + + private void write(JsonObject object) { + object.addProperty(property.getName(), (inverted ? "!" : "") + values.stream().map(property::getName).collect(Collectors.joining("|"))); + } + } + + class PropertyConditionBuilder implements ConditionsBuilder { + private final PropertyPredicate[] properties; + + private PropertyConditionBuilder(PropertyPredicate[] properties) { + this.properties = properties; + } + + @Override + public JsonObject build() { + JsonObject object = new JsonObject(); + + for (PropertyPredicate propertyPredicate : properties) { + propertyPredicate.write(object); + } + + return object; + } + } + + class AndConditonBuilder implements ConditionsBuilder { + private final ConditionsBuilder[] conditions; + + private AndConditonBuilder(ConditionsBuilder[] conditions) { + this.conditions = conditions; + } + + @Override + public JsonObject build() { + JsonArray array = new JsonArray(); + + for (ConditionsBuilder condition : conditions) { + array.add(condition.build()); + } + + JsonObject object = new JsonObject(); + object.add("AND", array); + + return object; + } + } + + class OrConditonBuilder implements ConditionsBuilder { + private final ConditionsBuilder[] conditions; + + private OrConditonBuilder(ConditionsBuilder[] conditions) { + this.conditions = conditions; + } + + @Override + public JsonObject build() { + JsonArray array = new JsonArray(); + + for (ConditionsBuilder condition : conditions) { + array.add(condition.build()); + } + + JsonObject object = new JsonObject(); + object.add("OR", array); + + return object; + } + } +} diff --git a/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/api/model/block/VariantsBuilder.java b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/api/model/block/VariantsBuilder.java new file mode 100644 index 00000000..a0709a76 --- /dev/null +++ b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/api/model/block/VariantsBuilder.java @@ -0,0 +1,153 @@ +package net.ornithemc.osl.datagen.api.model.block; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import net.minecraft.client.resource.model.ModelRotation; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; + +/** + * Represents block model definition variants. + */ +public interface VariantsBuilder { + JsonElement build(); + + /** + * Creates a variant builder with the specified model location. + * + * @param modelLocation the model location + * @return the variant builder + */ + static VariantBuilder of(NamespacedIdentifier modelLocation) { + return new VariantBuilder(modelLocation); + } + + /** + * Creates a multi-variant builder with the specified variants. + * + * @param variants the variants + * @return the multi-variant builder + */ + static VariantsBuilder multi(VariantBuilder... variants) { + if (variants.length == 0) { + throw new IllegalArgumentException("Must provide at least one variant"); + } + + return new MultiBuilder(variants); + } + + class VariantBuilder implements VariantsBuilder { + private final NamespacedIdentifier modelLocation; + private int x = 0; + private int y = 0; + private boolean lockedUV = false; + private int weight = 1; + + private VariantBuilder(NamespacedIdentifier modelLocation) { + this.modelLocation = modelLocation; + } + + /** + * Sets the x rotation of the model. + * + * @param x the x rotation + * @return the variant builder + */ + public VariantBuilder x(int x) { + ModelRotation rotation = ModelRotation.by(x, y); + + if (rotation == null) { + throw new IllegalArgumentException("Invalid x rotation " + x); + } + + this.x = x; + return this; + } + + /** + * Sets the y rotation of the model. + * + * @param y the y rotation + * @return the variant builder + */ + public VariantBuilder y(int y) { + ModelRotation rotation = ModelRotation.by(x, y); + + if (rotation == null) { + throw new IllegalArgumentException("Invalid y rotation " + y); + } + + this.y = y; + return this; + } + + /** + * Sets whether the UV coordinates of the model should be locked. + * + * @param lockUV whether the UV coordinates should be locked + * @return the variant builder + */ + public VariantBuilder lockedUV(boolean lockUV) { + this.lockedUV = lockUV; + return this; + } + + /** + * Sets the weight of the variant. + * + * @param weight the weight + * @return the variant builder + */ + public VariantBuilder weight(int weight) { + if (weight <= 0) { + throw new IllegalArgumentException("Weight must be greater than 0"); + } + + this.weight = weight; + return this; + } + + public JsonElement build() { + JsonObject json = new JsonObject(); + json.addProperty("model", modelLocation.toString()); + + // Defaulted properties + if (x != 0) { + json.addProperty("x", x); + } + + if (y != 0) { + json.addProperty("y", y); + } + + if (lockedUV) { + json.addProperty("uvlock", true); + } + + if (weight > 1) { + json.addProperty("weight", weight); + } + + return json; + } + } + + class MultiBuilder implements VariantsBuilder { + private final VariantBuilder[] variants; + + private MultiBuilder(VariantBuilder... variants) { + this.variants = variants; + } + + @Override + public JsonElement build() { + JsonArray json = new JsonArray(); + + for (VariantBuilder variant : variants) { + json.add(variant.build()); + } + + return json; + } + } +} diff --git a/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/api/model/item/ItemModelTemplates.java b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/api/model/item/ItemModelTemplates.java new file mode 100644 index 00000000..05919f02 --- /dev/null +++ b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/api/model/item/ItemModelTemplates.java @@ -0,0 +1,31 @@ +package net.ornithemc.osl.datagen.api.model.item; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.NamespacedIdentifiers; +import net.ornithemc.osl.datagen.api.model.ModelBuilder; + +/** + * A collection of item model templates. + */ +public final class ItemModelTemplates { + /** + * Creates a basic item model with the given texture. + * + * @param texture the texture + * @return the model builder + */ + public static ModelBuilder basic(NamespacedIdentifier texture) { + return ModelBuilder.create(NamespacedIdentifiers.from("item/generated")).texture("layer0", texture); + } + + /** + * Creates a basic item model with the given textures. + * + * @param firstLayer the first texture + * @param secondLayer the second texture + * @return the model builder + */ + public static ModelBuilder basic(NamespacedIdentifier firstLayer, NamespacedIdentifier secondLayer) { + return ModelBuilder.create(NamespacedIdentifiers.from("item/generated")).texture("layer0", firstLayer).texture("layer1", secondLayer); + } +} diff --git a/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/api/provider/ModAdvancementProvider.java b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/api/provider/ModAdvancementProvider.java new file mode 100644 index 00000000..c45298d8 --- /dev/null +++ b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/api/provider/ModAdvancementProvider.java @@ -0,0 +1,50 @@ +package net.ornithemc.osl.datagen.api.provider; + +import com.google.gson.JsonElement; +import net.fabricmc.loader.api.ModContainer; +import net.minecraft.advancement.Advancement; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.datagen.api.PackGenerator; +import net.ornithemc.osl.resource.loader.api.resource.ResourcePath; +import net.ornithemc.osl.resource.loader.api.resource.ResourceType; + +import java.nio.file.Path; +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +/** + * A PackProvider for generating advancements. + */ +public abstract class ModAdvancementProvider extends GsonDataProvider { + protected ModAdvancementProvider(PackGenerator generator, ModContainer mod) { + super(generator, mod); + } + + @Override + protected final void generate(BiConsumer consumer) { + Consumer advancementConsumer = advancement -> { + consumer.accept(advancement.getId(), advancement.builder().toJson()); + }; + + generateAdvancements(advancementConsumer); + } + + /** + * Generates advancements. + *

+ * Use {@link Advancement#builder()} to create advancements before passing them to the consumer. + * + * @param consumer the consumer to accept the advancements + */ + public abstract void generateAdvancements(Consumer consumer); + + @Override + protected Path getPath(NamespacedIdentifier id) { + return generator.getOutputPath().resolve(ResourcePath.nameOf(ResourceType.SERVER_DATA, id.prefixed("advancements/").suffixed(".json"))); + } + + @Override + public String getProviderName() { + return "Advancements"; + } +} diff --git a/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/api/provider/ModLanguageProvider.java b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/api/provider/ModLanguageProvider.java new file mode 100644 index 00000000..cde0ae74 --- /dev/null +++ b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/api/provider/ModLanguageProvider.java @@ -0,0 +1,131 @@ +package net.ornithemc.osl.datagen.api.provider; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import net.fabricmc.loader.api.ModContainer; +import net.minecraft.block.Block; +import net.minecraft.entity.EntityType; +import net.minecraft.item.Item; +import net.minecraft.resource.Identifier; +import net.minecraft.world.biome.Biome; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.datagen.api.PackGenerator; +import net.ornithemc.osl.resource.loader.api.resource.ResourcePath; +import net.ornithemc.osl.resource.loader.api.resource.ResourceType; + +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; +import java.util.function.BiConsumer; + +/** + * A provider for language files generated by a ModDataGenerator. + */ +public abstract class ModLanguageProvider extends GsonDataProvider { + private final String languageCode; + + /** + * Constructs a {@code ModLanguageProvider} with the specified generator, mod, and language code. + * + * @param generator the pack generator responsible for creating and registering resources + * @param mod the mod container providing metadata and context for the mod + * @param languageCode the language code to use for the language file + */ + protected ModLanguageProvider(PackGenerator generator, ModContainer mod, String languageCode) { + super(generator, mod); + this.languageCode = languageCode; + } + + /** + * Constructs a {@code ModLanguageProvider} with the specified generator and mod, + * using "en_us" as the default language code. + * + * @param generator the pack generator responsible for creating and registering resources + * @param mod the mod container providing metadata and context for the mod + */ + protected ModLanguageProvider(PackGenerator generator, ModContainer mod) { + this(generator, mod, "en_us"); + } + + @Override + protected final void generate(BiConsumer consumer) { + Map translations = new HashMap<>(); + + generateTranslations(translations::put); + + JsonObject jsonObject = new JsonObject(); + translations.forEach(jsonObject::addProperty); + + consumer.accept(new Identifier(mod.getMetadata().getId(), this.languageCode), jsonObject); + } + + /** + * Generates translations for the language file. + * + * @param builder the translation builder to use for adding translations + */ + protected abstract void generateTranslations(TranslationBuilder builder); + + @Override + protected Path getPath(NamespacedIdentifier id) { + return this.generator.getOutputPath().resolve(ResourcePath.nameOf(ResourceType.CLIENT_ASSETS, id.prefixed("lang").suffixed(".json"))); + } + + @Override + public String getProviderName() { + return String.format("Language (%s)", this.languageCode); + } + + /** + * A builder for language translations. + */ + public interface TranslationBuilder { + /** + * Adds a translation for the specified key and value. + * + * @param key the translation key + * @param value the translation value + */ + void add(String key, String value); + + /** + * Adds a translation for the specified block and value. + * + * @param block the block to add a translation for + * @param value the translation value + */ + default void add(Block block, String value) { + this.add(block.getTranslationKey(), value); + } + + /** + * Adds a translation for the specified item and value. + * + * @param item the item to add a translation for + * @param value the translation value + */ + default void add(Item item, String value) { + this.add(item.getTranslationKey(), value); + } + + /** + * Adds a translation for the specified entity type and value. + * + * @param entityType the entity type to add a translation for + * @param value the translation value + */ + default void add(EntityType entityType, String value) { + this.add(entityType.getTranslationKey(), value); + } + + /** + * Adds a translation for the specified biome and value. + * + * @param biome the biome to add a translation for + * @param value the translation value + */ + default void add(Biome biome, String value) { + this.add(biome.getTranslationKey(), value); + } + } +} diff --git a/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/api/provider/ModLootTablesProvider.java b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/api/provider/ModLootTablesProvider.java new file mode 100644 index 00000000..bb506639 --- /dev/null +++ b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/api/provider/ModLootTablesProvider.java @@ -0,0 +1,44 @@ +package net.ornithemc.osl.datagen.api.provider; + +import com.google.gson.JsonElement; +import net.fabricmc.loader.api.ModContainer; +import net.minecraft.world.gen.loot.LootTable; +import net.minecraft.world.gen.loot.LootTables; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.datagen.api.PackGenerator; +import net.ornithemc.osl.resource.loader.api.resource.ResourcePath; +import net.ornithemc.osl.resource.loader.api.resource.ResourceType; + +import java.nio.file.Path; +import java.util.function.BiConsumer; + +/** + * A PackProvider to generate loot tables. + */ +public abstract class ModLootTablesProvider extends GsonDataProvider { + protected ModLootTablesProvider(PackGenerator generator, ModContainer mod) { + super(generator, mod); + } + + @Override + protected final void generate(BiConsumer consumer) { + generateLootTables((id, lootTable) -> consumer.accept(id, LootTables.m_19064268(lootTable.m_74891066()).getAsJsonObject())); + } + + /** + * Generates loot tables. + * + * @param consumer the consumer to accept the loot tables + */ + public abstract void generateLootTables(BiConsumer consumer); + + @Override + protected Path getPath(NamespacedIdentifier id) { + return generator.getOutputPath().resolve(ResourcePath.nameOf(ResourceType.SERVER_DATA, id.prefixed("loot_tables/").suffixed(".json"))); + } + + @Override + public String getProviderName() { + return "LootTables"; + } +} diff --git a/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/api/provider/ModModelProvider.java b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/api/provider/ModModelProvider.java new file mode 100644 index 00000000..df5a7bbe --- /dev/null +++ b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/api/provider/ModModelProvider.java @@ -0,0 +1,86 @@ +package net.ornithemc.osl.datagen.api.provider; + +import com.google.gson.JsonElement; +import net.fabricmc.loader.api.ModContainer; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.NamespacedIdentifiers; +import net.ornithemc.osl.datagen.api.PackGenerator; +import net.ornithemc.osl.datagen.api.model.ModelGenerator; +import net.ornithemc.osl.datagen.impl.model.ModelGeneratorImpl; +import net.ornithemc.osl.resource.loader.api.resource.ResourcePath; +import net.ornithemc.osl.resource.loader.api.resource.ResourceType; + +import java.nio.file.Path; +import java.util.function.BiConsumer; + +/** + * A PackProvider to generate block and item models. + */ +public abstract class ModModelProvider extends GsonDataProvider { + protected ModModelProvider(PackGenerator generator, ModContainer mod) { + super(generator, mod); + } + + @Override + protected final void generate(BiConsumer consumer) { + ModelGenerator modelGenerator = new ModelGeneratorImpl(consumer); + generateModels(modelGenerator); + } + + /** + * Generates block and item models. + * + * @param generator the generator to register the models + */ + public abstract void generateModels(ModelGenerator generator); + + /** + * Prefixes the given identifier with "block/". + * + * @param id the identifier to prefix + * @return the prefixed identifier + */ + public NamespacedIdentifier block(NamespacedIdentifier id) { + return id.suffixed("block/"); + } + + /** + * Prefixes the given path with "block/". + * + * @param path the path to prefix + * @return the prefixed path as a NamespacedIdentifier + */ + public NamespacedIdentifier block(String path) { + return block(NamespacedIdentifiers.parse(path)); + } + + /** + * Prefixes the given identifier with "item/". + * + * @param id the identifier to prefix + * @return the prefixed identifier + */ + public NamespacedIdentifier item(NamespacedIdentifier id) { + return id.suffixed("item/"); + } + + /** + * Prefixes the given path with "item/". + * + * @param path the path to prefix + * @return the prefixed path as a NamespacedIdentifier + */ + public NamespacedIdentifier item(String path) { + return item(NamespacedIdentifiers.parse(path)); + } + + @Override + protected Path getPath(NamespacedIdentifier id) { + return generator.getOutputPath().resolve(ResourcePath.nameOf(ResourceType.CLIENT_ASSETS, id.suffixed(".json"))); + } + + @Override + public String getProviderName() { + return "Models"; + } +} diff --git a/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/api/provider/ModRecipesProvider.java b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/api/provider/ModRecipesProvider.java new file mode 100644 index 00000000..2bf01df9 --- /dev/null +++ b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/api/provider/ModRecipesProvider.java @@ -0,0 +1,52 @@ +package net.ornithemc.osl.datagen.api.provider; + +import com.google.common.collect.Sets; +import com.google.gson.JsonObject; +import net.fabricmc.loader.api.ModContainer; +import net.minecraft.data.DataGenerator; +import net.minecraft.data.HashCache; +import net.minecraft.data.recipe.RecipesProvider; +import net.minecraft.resource.Identifier; +import net.minecraft.unmapped.C_23159014; +import net.ornithemc.osl.datagen.api.PackGenerator; +import net.ornithemc.osl.datagen.impl.access.RecipeBuilderAccess; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Set; +import java.util.function.Consumer; + +/** + * A PackProvider for generating recipes. + */ +public abstract class ModRecipesProvider extends RecipesProvider { + public ModRecipesProvider(PackGenerator generator) { + super((DataGenerator) generator); + } + + @Override + public final void run(HashCache cache) { + Path path = this.generator.getOutput(); + Set set = Sets.newHashSet(); + this.generateRecipes((c_23159014) -> { + if (!set.add(c_23159014.m_80989661())) { + throw new IllegalStateException("Duplicate recipe " + c_23159014.m_80989661()); + } else { + this.save(cache, ((RecipeBuilderAccess) c_23159014).getRecipe(), path.resolve("data/" + c_23159014.m_80989661().getNamespace() + "/recipes/" + c_23159014.m_80989661().getPath() + ".json")); + JsonObject jsonObject = c_23159014.m_38911806(); + if (jsonObject != null) { + this.saveAdvancement(cache, jsonObject, path.resolve("data/" + c_23159014.m_80989661().getNamespace() + "/advancements/" + c_23159014.m_66233363().getPath() + ".json")); + } + + } + }); + } + + /** + * Generates recipes. + * @see RecipesProvider#buildShapelessRecipes(Consumer) for usage examples. + * + * @param consumer the consumer to accept the recipes + */ + protected abstract void generateRecipes(Consumer consumer); +} diff --git a/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/DataGeneratorInit.java b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/DataGeneratorInit.java new file mode 100644 index 00000000..44b8d54d --- /dev/null +++ b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/DataGeneratorInit.java @@ -0,0 +1,50 @@ +package net.ornithemc.osl.datagen.impl; + +import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.api.entrypoint.EntrypointContainer; +import net.minecraft.Bootstrap; +import net.ornithemc.osl.datagen.api.DataGeneratorInitializer; +import net.ornithemc.osl.entrypoints.api.ModInitializer; +import net.ornithemc.osl.registries.api.RegistryEvents; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +public class DataGeneratorInit implements ModInitializer { + @Override + public void init() { + if (!DataGenHelperImpl.ENABLED) return; + + RegistryEvents.REGISTRIES_FROZEN.register(() -> { + Bootstrap.init(); + + Path basePath = DataGenHelperImpl.getOutputDir(); + + List> entrypoints = FabricLoader.getInstance() + .getEntrypointContainers(DataGeneratorInitializer.KEY, DataGeneratorInitializer.class); + + List generators = new ArrayList<>(); + + for (EntrypointContainer entrypoint : entrypoints) { + final String modId = entrypoint.getProvider().getMetadata().getId(); + + if (DataGenHelperImpl.MOD_ID_FILTER != null && !modId.equals(DataGenHelperImpl.MOD_ID_FILTER)) { + continue; + } + + ModDataGeneratorImpl generator = new ModDataGeneratorImpl(basePath, entrypoint.getProvider()); + generators.add(generator); + + DataGeneratorInitializer initializer = entrypoint.getEntrypoint(); + initializer.onDatagenInit(generator); + } + + for (ModDataGeneratorImpl generator : generators) { + generator.run(); + } + + System.exit(0); + }); + } +} diff --git a/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/ModDataGeneratorImpl.java b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/ModDataGeneratorImpl.java new file mode 100644 index 00000000..0a67499f --- /dev/null +++ b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/ModDataGeneratorImpl.java @@ -0,0 +1,54 @@ +package net.ornithemc.osl.datagen.impl; + +import net.fabricmc.loader.api.ModContainer; +import net.minecraft.data.DataGenerator; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.datagen.api.ModDataGenerator; +import net.ornithemc.osl.datagen.api.PackGenerator; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class ModDataGeneratorImpl implements ModDataGenerator { + private final Path basePath; + private final ModContainer modContainer; + private final List generators; + + public ModDataGeneratorImpl(Path basePath, ModContainer modContainer) { + this.basePath = basePath; + this.modContainer = modContainer; + generators = new ArrayList<>(); + } + + @Override + public PackGenerator createPack() { + DataGenerator generator = new PackDataGeneratorImpl(basePath, Collections.emptySet(), modContainer.getMetadata().getDescription(), modContainer); + generators.add(generator); + return generator; + } + + @Override + public PackGenerator createBundledResourcePack(NamespacedIdentifier id) { + DataGenerator generator = new PackDataGeneratorImpl(basePath.resolve(id.prefixed("resourcepacks/").identifier()), Collections.emptySet(), id.toString(), modContainer); + generators.add(generator); + return generator; + } + + @Override + public ModContainer getMod() { + return modContainer; + } + + public void run() { + for (DataGenerator generator : generators) { + try { + generator.run(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } +} diff --git a/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/ModDataProviderExtensionImpl.java b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/ModDataProviderExtensionImpl.java new file mode 100644 index 00000000..7fddef4d --- /dev/null +++ b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/ModDataProviderExtensionImpl.java @@ -0,0 +1,14 @@ +package net.ornithemc.osl.datagen.impl; + +import net.ornithemc.osl.datagen.api.PackCache; +import net.ornithemc.osl.datagen.api.provider.ModDataProvider; + +public interface ModDataProviderExtensionImpl extends ModDataProvider { + @Override + default void provide(PackCache cache) {} + + @Override + default String getProviderName() { + return ""; + } +} diff --git a/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/PackDataGeneratorImpl.java b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/PackDataGeneratorImpl.java new file mode 100644 index 00000000..d959a2ef --- /dev/null +++ b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/PackDataGeneratorImpl.java @@ -0,0 +1,46 @@ +package net.ornithemc.osl.datagen.impl; + +import net.fabricmc.loader.api.ModContainer; +import net.minecraft.data.DataGenerator; +import net.minecraft.data.DataProvider; +import net.ornithemc.osl.datagen.api.PackGenerator; +import net.ornithemc.osl.datagen.api.provider.ModDataProvider; +import net.ornithemc.osl.datagen.impl.provider.MCMetaProvider; +import net.ornithemc.osl.datagen.impl.wrapper.PackProviderWrapper; + +import java.nio.file.Path; +import java.util.Collection; +import java.util.function.BiFunction; +import java.util.function.Function; + +public class PackDataGeneratorImpl extends DataGenerator { + private final ModContainer mod; + + public PackDataGeneratorImpl(Path output, Collection inputs, String description, ModContainer mod) { + super(output, inputs); + this.mod = mod; + this.addProvider((p, m) -> new MCMetaProvider(p, description)); + } + + @Override + public void addProvider(ComplexProviderFactory providerFunction) { + ModDataProvider provider = providerFunction.create(this, this.mod); + + if (provider instanceof DataProvider) { + addProvider((DataProvider) provider); + } else { + addProvider(new PackProviderWrapper(provider)); + } + } + + @Override + public void addProvider(SimpleProviderFactory providerFunction) { + ModDataProvider provider = providerFunction.create(this); + + if (provider instanceof DataProvider) { + addProvider((DataProvider) provider); + } else { + addProvider(new PackProviderWrapper(provider)); + } + } +} diff --git a/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/access/RecipeBuilderAccess.java b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/access/RecipeBuilderAccess.java new file mode 100644 index 00000000..b7d6fa28 --- /dev/null +++ b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/access/RecipeBuilderAccess.java @@ -0,0 +1,7 @@ +package net.ornithemc.osl.datagen.impl.access; + +import com.google.gson.JsonObject; + +public interface RecipeBuilderAccess { + JsonObject getRecipe(); +} diff --git a/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/mixin/C_23159014NewMixin.java b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/mixin/C_23159014NewMixin.java new file mode 100644 index 00000000..188c1ab6 --- /dev/null +++ b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/mixin/C_23159014NewMixin.java @@ -0,0 +1,21 @@ +package net.ornithemc.osl.datagen.impl.mixin; + +import com.google.gson.JsonObject; +import net.minecraft.unmapped.C_23159014; +import net.ornithemc.conditionalmixin.annotations.Conditional; +import net.ornithemc.conditionalmixin.annotations.Version; +import net.ornithemc.osl.datagen.impl.access.RecipeBuilderAccess; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Conditional(minecraftVersion = @Version(">=19w03a")) +@Mixin(C_23159014.class) +public interface C_23159014NewMixin extends RecipeBuilderAccess { + @Shadow + JsonObject m_77277228(); + + @Override + default JsonObject getRecipe() { + return this.m_77277228(); + } +} diff --git a/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/mixin/C_23159014OldMixin.java b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/mixin/C_23159014OldMixin.java new file mode 100644 index 00000000..34937238 --- /dev/null +++ b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/mixin/C_23159014OldMixin.java @@ -0,0 +1,21 @@ +package net.ornithemc.osl.datagen.impl.mixin; + +import com.google.gson.JsonObject; +import net.minecraft.unmapped.C_23159014; +import net.ornithemc.conditionalmixin.annotations.Conditional; +import net.ornithemc.conditionalmixin.annotations.Version; +import net.ornithemc.osl.datagen.impl.access.RecipeBuilderAccess; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Conditional(minecraftVersion = @Version("<19w03a")) +@Mixin(C_23159014.class) +public interface C_23159014OldMixin extends RecipeBuilderAccess { + @Shadow + JsonObject m_13901626(); + + @Override + default JsonObject getRecipe() { + return this.m_13901626(); + } +} diff --git a/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/mixin/DataGeneratorMixin.java b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/mixin/DataGeneratorMixin.java new file mode 100644 index 00000000..1ddec854 --- /dev/null +++ b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/mixin/DataGeneratorMixin.java @@ -0,0 +1,19 @@ +package net.ornithemc.osl.datagen.impl.mixin; + +import net.minecraft.data.DataGenerator; +import net.ornithemc.osl.datagen.api.PackGenerator; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import java.nio.file.Path; + +@Mixin(DataGenerator.class) +public abstract class DataGeneratorMixin implements PackGenerator { + @Shadow + public abstract Path getOutput(); + + @Override + public Path getOutputPath() { + return this.getOutput(); + } +} diff --git a/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/mixin/DataProviderMixin.java b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/mixin/DataProviderMixin.java new file mode 100644 index 00000000..53404586 --- /dev/null +++ b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/mixin/DataProviderMixin.java @@ -0,0 +1,17 @@ +package net.ornithemc.osl.datagen.impl.mixin; + +import net.minecraft.data.DataProvider; +import net.ornithemc.osl.datagen.impl.ModDataProviderExtensionImpl; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(DataProvider.class) +public interface DataProviderMixin extends ModDataProviderExtensionImpl { + @Shadow + String getName(); + + @Override + default String getProviderName() { + return this.getName(); + } +} diff --git a/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/mixin/HashCacheMixin.java b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/mixin/HashCacheMixin.java new file mode 100644 index 00000000..2626db15 --- /dev/null +++ b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/mixin/HashCacheMixin.java @@ -0,0 +1,51 @@ +package net.ornithemc.osl.datagen.impl.mixin; + +import net.minecraft.data.HashCache; +import net.ornithemc.osl.datagen.api.PackCache; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Objects; + +@Mixin(HashCache.class) +public abstract class HashCacheMixin implements PackCache { + @Shadow + @Nullable + public abstract String get(Path path); + + @Shadow + public abstract void put(Path path, String hash); + + @Override + public void checkAndWrite(Path path, byte[] data) throws IOException { + String hash = SHA1.hashBytes(data).toString(); + + if (!Objects.equals(this.get(path), hash) || !Files.exists(path)) { + Files.createDirectories(path.getParent()); + + Files.write(path, data); + } + + this.put(path, hash); + } + + @Override + public void checkAndWrite(Path path, String data) throws IOException { + String hash = SHA1.hashUnencodedChars(data).toString(); + + if (!Objects.equals(this.get(path), hash) || !Files.exists(path)) { + Files.createDirectories(path.getParent()); + + try (BufferedWriter bufferedWriter = Files.newBufferedWriter(path)) { + bufferedWriter.write(data); + } + } + + this.put(path, hash); + } +} diff --git a/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/model/BlockModelTemplatesImpl.java b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/model/BlockModelTemplatesImpl.java new file mode 100644 index 00000000..c328777f --- /dev/null +++ b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/model/BlockModelTemplatesImpl.java @@ -0,0 +1,1093 @@ +package net.ornithemc.osl.datagen.impl.model; + +import net.minecraft.block.*; +import net.minecraft.block.state.property.*; +import net.minecraft.util.math.Direction; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.datagen.api.model.ModelBuilder; +import net.ornithemc.osl.datagen.api.model.ModelGenerator; +import net.ornithemc.osl.datagen.api.model.block.BlockModelDefinitionBuilder; +import net.ornithemc.osl.datagen.api.model.block.BlockModelTemplates; +import net.ornithemc.osl.datagen.api.model.block.ConditionsBuilder; +import net.ornithemc.osl.datagen.api.model.block.VariantsBuilder; +import net.ornithemc.osl.datagen.api.model.item.ItemModelTemplates; + +public class BlockModelTemplatesImpl implements BlockModelTemplates { + private final ModelGenerator modelGenerator; + + public BlockModelTemplatesImpl(ModelGenerator modelGenerator) { + this.modelGenerator = modelGenerator; + } + + @Override + public BlockModelTemplates simpleBlock(Block block, NamespacedIdentifier texture) { + NamespacedIdentifier blockModelId = modelGenerator.blockModel(block, BlockModelTemplates.cubeAll(texture)); + modelGenerator.itemModel(block, ModelBuilder.create(blockModelId)); + modelGenerator.blockstate(block, BlockModelDefinitionBuilder.createSimple(blockModelId)); + + return this; + } + + @Override + public BlockModelTemplates simpleBlockWithoutItem(Block block, NamespacedIdentifier texture) { + NamespacedIdentifier blockModelId = modelGenerator.blockModel(block, BlockModelTemplates.cubeAll(texture)); + modelGenerator.blockstate(block, BlockModelDefinitionBuilder.createSimple(blockModelId)); + + return this; + } + + @Override + public BlockModelTemplates slab(Block block, NamespacedIdentifier doubleModelLocation, NamespacedIdentifier sideTexture, NamespacedIdentifier topTexture, NamespacedIdentifier bottomTexture) { + NamespacedIdentifier bottomId = modelGenerator.blockModel(block, BlockModelTemplates.slabBottom(sideTexture, topTexture, bottomTexture)); + NamespacedIdentifier topId = modelGenerator.blockModel(block, "_top", BlockModelTemplates.slabTop(sideTexture, topTexture, bottomTexture)); + modelGenerator.itemModel(block, ModelBuilder.create(bottomId)); + modelGenerator.blockstate( + block, + BlockModelDefinitionBuilder.create() + .variant(BlockModelDefinitionBuilder.predicate(SlabBlock.HALF, SlabType.BOTTOM), bottomId) + .variant(BlockModelDefinitionBuilder.predicate(SlabBlock.HALF, SlabType.TOP), topId) + .variant(BlockModelDefinitionBuilder.predicate(SlabBlock.HALF, SlabType.DOUBLE), doubleModelLocation) + ); + + return this; + } + + @Override + public BlockModelTemplates simpleSlab(Block block, NamespacedIdentifier doubleModelLocation, NamespacedIdentifier texture) { + return slab(block, doubleModelLocation, texture, texture, texture); + } + + @Override + public BlockModelTemplates stairs(Block block, NamespacedIdentifier sideTexture, NamespacedIdentifier topTexture, NamespacedIdentifier bottomTexture) { + NamespacedIdentifier baseId = modelGenerator.blockModel(block, BlockModelTemplates.stairs(sideTexture, topTexture, bottomTexture)); + NamespacedIdentifier innerId = modelGenerator.blockModel(block, "_inner", BlockModelTemplates.stairsInner(sideTexture, topTexture, bottomTexture)); + NamespacedIdentifier outerId = modelGenerator.blockModel(block, "_outer", BlockModelTemplates.stairsOuter(sideTexture, topTexture, bottomTexture)); + modelGenerator.itemModel(block, ModelBuilder.create(baseId)); + + modelGenerator.blockstate( + block, + BlockModelDefinitionBuilder.create() + // Straight Bottom + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.EAST) + .set(StairsBlock.HALF, StairHalf.BOTTOM) + .set(StairsBlock.SHAPE, StairShape.STRAIGHT), + VariantsBuilder.of(baseId) + ) + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.WEST) + .set(StairsBlock.HALF, StairHalf.BOTTOM) + .set(StairsBlock.SHAPE, StairShape.STRAIGHT), + VariantsBuilder.of(baseId).y(180).lockedUV(true) + ) + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.SOUTH) + .set(StairsBlock.HALF, StairHalf.BOTTOM) + .set(StairsBlock.SHAPE, StairShape.STRAIGHT), + VariantsBuilder.of(baseId).y(90).lockedUV(true) + ) + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.NORTH) + .set(StairsBlock.HALF, StairHalf.BOTTOM) + .set(StairsBlock.SHAPE, StairShape.STRAIGHT), + VariantsBuilder.of(baseId).y(270).lockedUV(true) + ) + // Outer Right Bottom + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.EAST) + .set(StairsBlock.HALF, StairHalf.BOTTOM) + .set(StairsBlock.SHAPE, StairShape.OUTER_RIGHT), + VariantsBuilder.of(outerId) + ) + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.WEST) + .set(StairsBlock.HALF, StairHalf.BOTTOM) + .set(StairsBlock.SHAPE, StairShape.OUTER_RIGHT), + VariantsBuilder.of(outerId).y(180).lockedUV(true) + ) + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.SOUTH) + .set(StairsBlock.HALF, StairHalf.BOTTOM) + .set(StairsBlock.SHAPE, StairShape.OUTER_RIGHT), + VariantsBuilder.of(outerId).y(90).lockedUV(true) + ) + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.NORTH) + .set(StairsBlock.HALF, StairHalf.BOTTOM) + .set(StairsBlock.SHAPE, StairShape.OUTER_RIGHT), + VariantsBuilder.of(outerId).y(270).lockedUV(true) + ) + // Outer Left Bottom + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.EAST) + .set(StairsBlock.HALF, StairHalf.BOTTOM) + .set(StairsBlock.SHAPE, StairShape.OUTER_LEFT), + VariantsBuilder.of(outerId).y(270).lockedUV(true) + ) + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.WEST) + .set(StairsBlock.HALF, StairHalf.BOTTOM) + .set(StairsBlock.SHAPE, StairShape.OUTER_LEFT), + VariantsBuilder.of(outerId).y(90).lockedUV(true) + ) + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.SOUTH) + .set(StairsBlock.HALF, StairHalf.BOTTOM) + .set(StairsBlock.SHAPE, StairShape.OUTER_LEFT), + VariantsBuilder.of(outerId) + ) + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.NORTH) + .set(StairsBlock.HALF, StairHalf.BOTTOM) + .set(StairsBlock.SHAPE, StairShape.OUTER_LEFT), + VariantsBuilder.of(outerId).y(180).lockedUV(true) + ) + // Inner Right Bottom + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.EAST) + .set(StairsBlock.HALF, StairHalf.BOTTOM) + .set(StairsBlock.SHAPE, StairShape.INNER_RIGHT), + VariantsBuilder.of(innerId) + ) + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.WEST) + .set(StairsBlock.HALF, StairHalf.BOTTOM) + .set(StairsBlock.SHAPE, StairShape.INNER_RIGHT), + VariantsBuilder.of(innerId).y(180).lockedUV(true) + ) + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.SOUTH) + .set(StairsBlock.HALF, StairHalf.BOTTOM) + .set(StairsBlock.SHAPE, StairShape.INNER_RIGHT), + VariantsBuilder.of(innerId).y(90).lockedUV(true) + ) + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.NORTH) + .set(StairsBlock.HALF, StairHalf.BOTTOM) + .set(StairsBlock.SHAPE, StairShape.INNER_RIGHT), + VariantsBuilder.of(innerId).y(270).lockedUV(true) + ) + // Inner Left Bottom + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.EAST) + .set(StairsBlock.HALF, StairHalf.BOTTOM) + .set(StairsBlock.SHAPE, StairShape.INNER_LEFT), + VariantsBuilder.of(innerId).y(270).lockedUV(true) + ) + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.WEST) + .set(StairsBlock.HALF, StairHalf.BOTTOM) + .set(StairsBlock.SHAPE, StairShape.INNER_LEFT), + VariantsBuilder.of(innerId).y(90).lockedUV(true) + ) + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.SOUTH) + .set(StairsBlock.HALF, StairHalf.BOTTOM) + .set(StairsBlock.SHAPE, StairShape.INNER_LEFT), + VariantsBuilder.of(innerId) + ) + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.NORTH) + .set(StairsBlock.HALF, StairHalf.BOTTOM) + .set(StairsBlock.SHAPE, StairShape.INNER_LEFT), + VariantsBuilder.of(innerId).y(180).lockedUV(true) + ) + + // Straight Top + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.EAST) + .set(StairsBlock.HALF, StairHalf.TOP) + .set(StairsBlock.SHAPE, StairShape.STRAIGHT), + VariantsBuilder.of(baseId).x(180).lockedUV(true) + ) + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.WEST) + .set(StairsBlock.HALF, StairHalf.TOP) + .set(StairsBlock.SHAPE, StairShape.STRAIGHT), + VariantsBuilder.of(baseId).x(180).y(180).lockedUV(true) + ) + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.SOUTH) + .set(StairsBlock.HALF, StairHalf.TOP) + .set(StairsBlock.SHAPE, StairShape.STRAIGHT), + VariantsBuilder.of(baseId).x(180).y(90).lockedUV(true) + ) + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.NORTH) + .set(StairsBlock.HALF, StairHalf.TOP) + .set(StairsBlock.SHAPE, StairShape.STRAIGHT), + VariantsBuilder.of(baseId).x(180).y(270).lockedUV(true) + ) + // Outer Right Top + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.EAST) + .set(StairsBlock.HALF, StairHalf.TOP) + .set(StairsBlock.SHAPE, StairShape.OUTER_RIGHT), + VariantsBuilder.of(outerId).x(180).lockedUV(true) + ) + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.WEST) + .set(StairsBlock.HALF, StairHalf.TOP) + .set(StairsBlock.SHAPE, StairShape.OUTER_RIGHT), + VariantsBuilder.of(outerId).x(180).y(180).lockedUV(true) + ) + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.SOUTH) + .set(StairsBlock.HALF, StairHalf.TOP) + .set(StairsBlock.SHAPE, StairShape.OUTER_RIGHT), + VariantsBuilder.of(outerId).x(180).y(90).lockedUV(true) + ) + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.NORTH) + .set(StairsBlock.HALF, StairHalf.TOP) + .set(StairsBlock.SHAPE, StairShape.OUTER_RIGHT), + VariantsBuilder.of(outerId).x(180).y(270).lockedUV(true) + ) + // Outer Left Top + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.EAST) + .set(StairsBlock.HALF, StairHalf.TOP) + .set(StairsBlock.SHAPE, StairShape.OUTER_LEFT), + VariantsBuilder.of(outerId).x(180).y(270).lockedUV(true) + ) + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.WEST) + .set(StairsBlock.HALF, StairHalf.TOP) + .set(StairsBlock.SHAPE, StairShape.OUTER_LEFT), + VariantsBuilder.of(outerId).x(180).y(90).lockedUV(true) + ) + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.SOUTH) + .set(StairsBlock.HALF, StairHalf.TOP) + .set(StairsBlock.SHAPE, StairShape.OUTER_LEFT), + VariantsBuilder.of(outerId).x(180).lockedUV(true) + ) + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.NORTH) + .set(StairsBlock.HALF, StairHalf.TOP) + .set(StairsBlock.SHAPE, StairShape.OUTER_LEFT), + VariantsBuilder.of(outerId).x(180).y(180).lockedUV(true) + ) + // Inner Right Top + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.EAST) + .set(StairsBlock.HALF, StairHalf.TOP) + .set(StairsBlock.SHAPE, StairShape.INNER_RIGHT), + VariantsBuilder.of(innerId).x(180).lockedUV(true) + ) + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.WEST) + .set(StairsBlock.HALF, StairHalf.TOP) + .set(StairsBlock.SHAPE, StairShape.INNER_RIGHT), + VariantsBuilder.of(innerId).x(180).y(180).lockedUV(true) + ) + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.SOUTH) + .set(StairsBlock.HALF, StairHalf.TOP) + .set(StairsBlock.SHAPE, StairShape.INNER_RIGHT), + VariantsBuilder.of(innerId).x(180).y(90).lockedUV(true) + ) + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.NORTH) + .set(StairsBlock.HALF, StairHalf.TOP) + .set(StairsBlock.SHAPE, StairShape.INNER_RIGHT), + VariantsBuilder.of(innerId).x(180).y(270).lockedUV(true) + ) + // Inner Left Top + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.EAST) + .set(StairsBlock.HALF, StairHalf.TOP) + .set(StairsBlock.SHAPE, StairShape.INNER_LEFT), + VariantsBuilder.of(innerId).x(180).y(270).lockedUV(true) + ) + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.WEST) + .set(StairsBlock.HALF, StairHalf.TOP) + .set(StairsBlock.SHAPE, StairShape.INNER_LEFT), + VariantsBuilder.of(innerId).x(180).y(90).lockedUV(true) + ) + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.SOUTH) + .set(StairsBlock.HALF, StairHalf.TOP) + .set(StairsBlock.SHAPE, StairShape.INNER_LEFT), + VariantsBuilder.of(innerId).x(180).lockedUV(true) + ) + .variant( + BlockModelDefinitionBuilder.predicate(StairsBlock.FACING, Direction.NORTH) + .set(StairsBlock.HALF, StairHalf.TOP) + .set(StairsBlock.SHAPE, StairShape.INNER_LEFT), + VariantsBuilder.of(innerId).x(180).y(180).lockedUV(true) + ) + ); + + return this; + } + + @Override + public BlockModelTemplates simpleStairs(Block block, NamespacedIdentifier texture) { + return stairs(block, texture, texture, texture); + } + + @Override + public BlockModelTemplates wall(Block block, NamespacedIdentifier texture) { + NamespacedIdentifier inventoryId = modelGenerator.blockModel(block, "_inventory", BlockModelTemplates.wallInventory(texture)); + NamespacedIdentifier postId = modelGenerator.blockModel(block, "_post", BlockModelTemplates.wallPost(texture)); + NamespacedIdentifier sideId = modelGenerator.blockModel(block, "_side", BlockModelTemplates.wallSide(texture)); + modelGenerator.itemModel(block, ModelBuilder.create(inventoryId)); + + modelGenerator.blockstate( + block, + BlockModelDefinitionBuilder.create() + .selector( + ConditionsBuilder.properties( + ConditionsBuilder.property(WallBlock.UP, true) + ), + VariantsBuilder.of(postId) + ) + .selector( + ConditionsBuilder.properties( + ConditionsBuilder.property(WallBlock.NORTH, true) + ), + VariantsBuilder.of(sideId).lockedUV(true) + ) + .selector( + ConditionsBuilder.properties( + ConditionsBuilder.property(WallBlock.EAST, true) + ), + VariantsBuilder.of(sideId).lockedUV(true).y(90) + ) + .selector( + ConditionsBuilder.properties( + ConditionsBuilder.property(WallBlock.SOUTH, true) + ), + VariantsBuilder.of(sideId).lockedUV(true).y(180) + ) + .selector( + ConditionsBuilder.properties( + ConditionsBuilder.property(WallBlock.WEST, true) + ), + VariantsBuilder.of(sideId).lockedUV(true).y(270) + ) + ); + + return this; + } + + @Override + public BlockModelTemplates fence(Block block, NamespacedIdentifier texture) { + NamespacedIdentifier inventoryId = modelGenerator.blockModel(block, "_inventory", BlockModelTemplates.fenceInventory(texture)); + NamespacedIdentifier postId = modelGenerator.blockModel(block, "_post", BlockModelTemplates.fencePost(texture)); + NamespacedIdentifier sideId = modelGenerator.blockModel(block, "_side", BlockModelTemplates.fenceSide(texture)); + modelGenerator.itemModel(block, ModelBuilder.create(inventoryId)); + + modelGenerator.blockstate( + block, + BlockModelDefinitionBuilder.create() + .selector(postId) + .selector( + ConditionsBuilder.properties( + ConditionsBuilder.property(FenceBlock.NORTH, true) + ), + VariantsBuilder.of(sideId).lockedUV(true) + ) + .selector( + ConditionsBuilder.properties( + ConditionsBuilder.property(FenceBlock.EAST, true) + ), + VariantsBuilder.of(sideId).lockedUV(true).y(90) + ) + .selector( + ConditionsBuilder.properties( + ConditionsBuilder.property(FenceBlock.SOUTH, true) + ), + VariantsBuilder.of(sideId).lockedUV(true).y(180) + ) + .selector( + ConditionsBuilder.properties( + ConditionsBuilder.property(FenceBlock.WEST, true) + ), + VariantsBuilder.of(sideId).lockedUV(true).y(270) + ) + ); + + return this; + } + + @Override + public BlockModelTemplates button(Block block, NamespacedIdentifier texture) { + NamespacedIdentifier inventoryId = modelGenerator.blockModel(block, "_inventory", BlockModelTemplates.buttonInventory(texture)); + NamespacedIdentifier baseId = modelGenerator.blockModel(block, BlockModelTemplates.button(texture)); + NamespacedIdentifier pressedId = modelGenerator.blockModel(block, "_pressed", BlockModelTemplates.buttonPressed(texture)); + modelGenerator.itemModel(block, ModelBuilder.create(inventoryId)); + + modelGenerator.blockstate( + block, + BlockModelDefinitionBuilder.create() + // Floor not powered + .variant( + BlockModelDefinitionBuilder.predicate(ButtonBlock.FACE, AttachFace.FLOOR) + .set(ButtonBlock.FACING, Direction.EAST) + .set(ButtonBlock.POWERED, false), + VariantsBuilder.of(baseId).y(90) + ) + .variant( + BlockModelDefinitionBuilder.predicate(ButtonBlock.FACE, AttachFace.FLOOR) + .set(ButtonBlock.FACING, Direction.WEST) + .set(ButtonBlock.POWERED, false), + VariantsBuilder.of(baseId).y(270) + ) + .variant( + BlockModelDefinitionBuilder.predicate(ButtonBlock.FACE, AttachFace.FLOOR) + .set(ButtonBlock.FACING, Direction.SOUTH) + .set(ButtonBlock.POWERED, false), + VariantsBuilder.of(baseId).y(180) + ) + .variant( + BlockModelDefinitionBuilder.predicate(ButtonBlock.FACE, AttachFace.FLOOR) + .set(ButtonBlock.FACING, Direction.NORTH) + .set(ButtonBlock.POWERED, false), + VariantsBuilder.of(baseId) + ) + // Wall not powered + .variant( + BlockModelDefinitionBuilder.predicate(ButtonBlock.FACE, AttachFace.WALL) + .set(ButtonBlock.FACING, Direction.EAST) + .set(ButtonBlock.POWERED, false), + VariantsBuilder.of(baseId).lockedUV(true).x(90).y(90) + ) + .variant( + BlockModelDefinitionBuilder.predicate(ButtonBlock.FACE, AttachFace.WALL) + .set(ButtonBlock.FACING, Direction.WEST) + .set(ButtonBlock.POWERED, false), + VariantsBuilder.of(baseId).lockedUV(true).x(90).y(270) + ) + .variant( + BlockModelDefinitionBuilder.predicate(ButtonBlock.FACE, AttachFace.WALL) + .set(ButtonBlock.FACING, Direction.SOUTH) + .set(ButtonBlock.POWERED, false), + VariantsBuilder.of(baseId).lockedUV(true).x(90).y(180) + ) + .variant( + BlockModelDefinitionBuilder.predicate(ButtonBlock.FACE, AttachFace.WALL) + .set(ButtonBlock.FACING, Direction.NORTH) + .set(ButtonBlock.POWERED, false), + VariantsBuilder.of(baseId).lockedUV(true).x(90) + ) + // Ceiling not powered + .variant( + BlockModelDefinitionBuilder.predicate(ButtonBlock.FACE, AttachFace.CEILING) + .set(ButtonBlock.FACING, Direction.EAST) + .set(ButtonBlock.POWERED, false), + VariantsBuilder.of(baseId).x(180).y(270) + ) + .variant( + BlockModelDefinitionBuilder.predicate(ButtonBlock.FACE, AttachFace.CEILING) + .set(ButtonBlock.FACING, Direction.WEST) + .set(ButtonBlock.POWERED, false), + VariantsBuilder.of(baseId).x(180).y(90) + ) + .variant( + BlockModelDefinitionBuilder.predicate(ButtonBlock.FACE, AttachFace.CEILING) + .set(ButtonBlock.FACING, Direction.SOUTH) + .set(ButtonBlock.POWERED, false), + VariantsBuilder.of(baseId).x(180) + ) + .variant( + BlockModelDefinitionBuilder.predicate(ButtonBlock.FACE, AttachFace.CEILING) + .set(ButtonBlock.FACING, Direction.NORTH) + .set(ButtonBlock.POWERED, false), + VariantsBuilder.of(baseId).x(180).y(180) + ) + + // Floor powered + .variant( + BlockModelDefinitionBuilder.predicate(ButtonBlock.FACE, AttachFace.FLOOR) + .set(ButtonBlock.FACING, Direction.EAST) + .set(ButtonBlock.POWERED, true), + VariantsBuilder.of(pressedId).y(90) + ) + .variant( + BlockModelDefinitionBuilder.predicate(ButtonBlock.FACE, AttachFace.FLOOR) + .set(ButtonBlock.FACING, Direction.WEST) + .set(ButtonBlock.POWERED, true), + VariantsBuilder.of(pressedId).y(270) + ) + .variant( + BlockModelDefinitionBuilder.predicate(ButtonBlock.FACE, AttachFace.FLOOR) + .set(ButtonBlock.FACING, Direction.SOUTH) + .set(ButtonBlock.POWERED, true), + VariantsBuilder.of(pressedId).y(180) + ) + .variant( + BlockModelDefinitionBuilder.predicate(ButtonBlock.FACE, AttachFace.FLOOR) + .set(ButtonBlock.FACING, Direction.NORTH) + .set(ButtonBlock.POWERED, true), + VariantsBuilder.of(pressedId) + ) + // Wall powered + .variant( + BlockModelDefinitionBuilder.predicate(ButtonBlock.FACE, AttachFace.WALL) + .set(ButtonBlock.FACING, Direction.EAST) + .set(ButtonBlock.POWERED, true), + VariantsBuilder.of(pressedId).lockedUV(true).x(90).y(90) + ) + .variant( + BlockModelDefinitionBuilder.predicate(ButtonBlock.FACE, AttachFace.WALL) + .set(ButtonBlock.FACING, Direction.WEST) + .set(ButtonBlock.POWERED, true), + VariantsBuilder.of(pressedId).lockedUV(true).x(90).y(270) + ) + .variant( + BlockModelDefinitionBuilder.predicate(ButtonBlock.FACE, AttachFace.WALL) + .set(ButtonBlock.FACING, Direction.SOUTH) + .set(ButtonBlock.POWERED, true), + VariantsBuilder.of(pressedId).lockedUV(true).x(90).y(180) + ) + .variant( + BlockModelDefinitionBuilder.predicate(ButtonBlock.FACE, AttachFace.WALL) + .set(ButtonBlock.FACING, Direction.NORTH) + .set(ButtonBlock.POWERED, true), + VariantsBuilder.of(pressedId).lockedUV(true).x(90) + ) + // Ceiling powered + .variant( + BlockModelDefinitionBuilder.predicate(ButtonBlock.FACE, AttachFace.CEILING) + .set(ButtonBlock.FACING, Direction.EAST) + .set(ButtonBlock.POWERED, true), + VariantsBuilder.of(pressedId).x(180).y(270) + ) + .variant( + BlockModelDefinitionBuilder.predicate(ButtonBlock.FACE, AttachFace.CEILING) + .set(ButtonBlock.FACING, Direction.WEST) + .set(ButtonBlock.POWERED, true), + VariantsBuilder.of(pressedId).x(180).y(90) + ) + .variant( + BlockModelDefinitionBuilder.predicate(ButtonBlock.FACE, AttachFace.CEILING) + .set(ButtonBlock.FACING, Direction.SOUTH) + .set(ButtonBlock.POWERED, true), + VariantsBuilder.of(pressedId).x(180) + ) + .variant( + BlockModelDefinitionBuilder.predicate(ButtonBlock.FACE, AttachFace.CEILING) + .set(ButtonBlock.FACING, Direction.NORTH) + .set(ButtonBlock.POWERED, true), + VariantsBuilder.of(pressedId).x(180).y(180) + ) + ); + + return this; + } + + @Override + public BlockModelTemplates door(Block block, NamespacedIdentifier inventoryTexture, NamespacedIdentifier topTexture, NamespacedIdentifier bottomTexture) { + NamespacedIdentifier bottomId = modelGenerator.blockModel(block, "_bottom", BlockModelTemplates.doorBottom(topTexture, bottomTexture)); + NamespacedIdentifier bottomHingeId = modelGenerator.blockModel(block, "_bottom_hinge", BlockModelTemplates.doorBottomHinge(topTexture, bottomTexture)); + NamespacedIdentifier topId = modelGenerator.blockModel(block, "_top", BlockModelTemplates.doorTop(topTexture, bottomTexture)); + NamespacedIdentifier topHingeId = modelGenerator.blockModel(block, "_top_hinge", BlockModelTemplates.doorTopHinge(topTexture, bottomTexture)); + modelGenerator.itemModel(block, ItemModelTemplates.basic(inventoryTexture)); + + modelGenerator.blockstate( + block, + BlockModelDefinitionBuilder.create() + // Closed lower left + .variant( + BlockModelDefinitionBuilder.predicate(DoorBlock.FACING, Direction.EAST) + .set(DoorBlock.HALF, Half.LOWER) + .set(DoorBlock.HINGE, DoorHinge.LEFT) + .set(DoorBlock.OPEN, false), + VariantsBuilder.of(bottomId) + ) + .variant( + BlockModelDefinitionBuilder.predicate(DoorBlock.FACING, Direction.SOUTH) + .set(DoorBlock.HALF, Half.LOWER) + .set(DoorBlock.HINGE, DoorHinge.LEFT) + .set(DoorBlock.OPEN, false), + VariantsBuilder.of(bottomId).y(90) + ) + .variant( + BlockModelDefinitionBuilder.predicate(DoorBlock.FACING, Direction.WEST) + .set(DoorBlock.HALF, Half.LOWER) + .set(DoorBlock.HINGE, DoorHinge.LEFT) + .set(DoorBlock.OPEN, false), + VariantsBuilder.of(bottomId).y(180) + ) + .variant( + BlockModelDefinitionBuilder.predicate(DoorBlock.FACING, Direction.NORTH) + .set(DoorBlock.HALF, Half.LOWER) + .set(DoorBlock.HINGE, DoorHinge.LEFT) + .set(DoorBlock.OPEN, false), + VariantsBuilder.of(bottomId).y(270) + ) + // Closed lower right + .variant( + BlockModelDefinitionBuilder.predicate(DoorBlock.FACING, Direction.EAST) + .set(DoorBlock.HALF, Half.LOWER) + .set(DoorBlock.HINGE, DoorHinge.RIGHT) + .set(DoorBlock.OPEN, false), + VariantsBuilder.of(bottomHingeId) + ) + .variant( + BlockModelDefinitionBuilder.predicate(DoorBlock.FACING, Direction.SOUTH) + .set(DoorBlock.HALF, Half.LOWER) + .set(DoorBlock.HINGE, DoorHinge.RIGHT) + .set(DoorBlock.OPEN, false), + VariantsBuilder.of(bottomHingeId).y(90) + ) + .variant( + BlockModelDefinitionBuilder.predicate(DoorBlock.FACING, Direction.WEST) + .set(DoorBlock.HALF, Half.LOWER) + .set(DoorBlock.HINGE, DoorHinge.RIGHT) + .set(DoorBlock.OPEN, false), + VariantsBuilder.of(bottomHingeId).y(180) + ) + .variant( + BlockModelDefinitionBuilder.predicate(DoorBlock.FACING, Direction.NORTH) + .set(DoorBlock.HALF, Half.LOWER) + .set(DoorBlock.HINGE, DoorHinge.RIGHT) + .set(DoorBlock.OPEN, false), + VariantsBuilder.of(bottomHingeId).y(270) + ) + // Opened lower left + .variant( + BlockModelDefinitionBuilder.predicate(DoorBlock.FACING, Direction.EAST) + .set(DoorBlock.HALF, Half.LOWER) + .set(DoorBlock.HINGE, DoorHinge.LEFT) + .set(DoorBlock.OPEN, true), + VariantsBuilder.of(bottomHingeId).y(90) + ) + .variant( + BlockModelDefinitionBuilder.predicate(DoorBlock.FACING, Direction.SOUTH) + .set(DoorBlock.HALF, Half.LOWER) + .set(DoorBlock.HINGE, DoorHinge.LEFT) + .set(DoorBlock.OPEN, true), + VariantsBuilder.of(bottomHingeId).y(180) + ) + .variant( + BlockModelDefinitionBuilder.predicate(DoorBlock.FACING, Direction.WEST) + .set(DoorBlock.HALF, Half.LOWER) + .set(DoorBlock.HINGE, DoorHinge.LEFT) + .set(DoorBlock.OPEN, true), + VariantsBuilder.of(bottomHingeId).y(270) + ) + .variant( + BlockModelDefinitionBuilder.predicate(DoorBlock.FACING, Direction.NORTH) + .set(DoorBlock.HALF, Half.LOWER) + .set(DoorBlock.HINGE, DoorHinge.LEFT) + .set(DoorBlock.OPEN, true), + VariantsBuilder.of(bottomHingeId) + ) + // Opened lower right + .variant( + BlockModelDefinitionBuilder.predicate(DoorBlock.FACING, Direction.EAST) + .set(DoorBlock.HALF, Half.LOWER) + .set(DoorBlock.HINGE, DoorHinge.RIGHT) + .set(DoorBlock.OPEN, true), + VariantsBuilder.of(bottomId).y(270) + ) + .variant( + BlockModelDefinitionBuilder.predicate(DoorBlock.FACING, Direction.SOUTH) + .set(DoorBlock.HALF, Half.LOWER) + .set(DoorBlock.HINGE, DoorHinge.RIGHT) + .set(DoorBlock.OPEN, true), + VariantsBuilder.of(bottomId) + ) + .variant( + BlockModelDefinitionBuilder.predicate(DoorBlock.FACING, Direction.WEST) + .set(DoorBlock.HALF, Half.LOWER) + .set(DoorBlock.HINGE, DoorHinge.RIGHT) + .set(DoorBlock.OPEN, true), + VariantsBuilder.of(bottomId).y(90) + ) + .variant( + BlockModelDefinitionBuilder.predicate(DoorBlock.FACING, Direction.NORTH) + .set(DoorBlock.HALF, Half.LOWER) + .set(DoorBlock.HINGE, DoorHinge.RIGHT) + .set(DoorBlock.OPEN, true), + VariantsBuilder.of(bottomId).y(180) + ) + + // Closed top left + .variant( + BlockModelDefinitionBuilder.predicate(DoorBlock.FACING, Direction.EAST) + .set(DoorBlock.HALF, Half.UPPER) + .set(DoorBlock.HINGE, DoorHinge.LEFT) + .set(DoorBlock.OPEN, false), + VariantsBuilder.of(topId) + ) + .variant( + BlockModelDefinitionBuilder.predicate(DoorBlock.FACING, Direction.SOUTH) + .set(DoorBlock.HALF, Half.UPPER) + .set(DoorBlock.HINGE, DoorHinge.LEFT) + .set(DoorBlock.OPEN, false), + VariantsBuilder.of(topId).y(90) + ) + .variant( + BlockModelDefinitionBuilder.predicate(DoorBlock.FACING, Direction.WEST) + .set(DoorBlock.HALF, Half.UPPER) + .set(DoorBlock.HINGE, DoorHinge.LEFT) + .set(DoorBlock.OPEN, false), + VariantsBuilder.of(topId).y(180) + ) + .variant( + BlockModelDefinitionBuilder.predicate(DoorBlock.FACING, Direction.NORTH) + .set(DoorBlock.HALF, Half.UPPER) + .set(DoorBlock.HINGE, DoorHinge.LEFT) + .set(DoorBlock.OPEN, false), + VariantsBuilder.of(topId).y(270) + ) + // Closed top right + .variant( + BlockModelDefinitionBuilder.predicate(DoorBlock.FACING, Direction.EAST) + .set(DoorBlock.HALF, Half.UPPER) + .set(DoorBlock.HINGE, DoorHinge.RIGHT) + .set(DoorBlock.OPEN, false), + VariantsBuilder.of(topHingeId) + ) + .variant( + BlockModelDefinitionBuilder.predicate(DoorBlock.FACING, Direction.SOUTH) + .set(DoorBlock.HALF, Half.UPPER) + .set(DoorBlock.HINGE, DoorHinge.RIGHT) + .set(DoorBlock.OPEN, false), + VariantsBuilder.of(topHingeId).y(90) + ) + .variant( + BlockModelDefinitionBuilder.predicate(DoorBlock.FACING, Direction.WEST) + .set(DoorBlock.HALF, Half.UPPER) + .set(DoorBlock.HINGE, DoorHinge.RIGHT) + .set(DoorBlock.OPEN, false), + VariantsBuilder.of(topHingeId).y(180) + ) + .variant( + BlockModelDefinitionBuilder.predicate(DoorBlock.FACING, Direction.NORTH) + .set(DoorBlock.HALF, Half.UPPER) + .set(DoorBlock.HINGE, DoorHinge.RIGHT) + .set(DoorBlock.OPEN, false), + VariantsBuilder.of(topHingeId).y(270) + ) + // Opened top left + .variant( + BlockModelDefinitionBuilder.predicate(DoorBlock.FACING, Direction.EAST) + .set(DoorBlock.HALF, Half.UPPER) + .set(DoorBlock.HINGE, DoorHinge.LEFT) + .set(DoorBlock.OPEN, true), + VariantsBuilder.of(topHingeId).y(90) + ) + .variant( + BlockModelDefinitionBuilder.predicate(DoorBlock.FACING, Direction.SOUTH) + .set(DoorBlock.HALF, Half.UPPER) + .set(DoorBlock.HINGE, DoorHinge.LEFT) + .set(DoorBlock.OPEN, true), + VariantsBuilder.of(topHingeId).y(180) + ) + .variant( + BlockModelDefinitionBuilder.predicate(DoorBlock.FACING, Direction.WEST) + .set(DoorBlock.HALF, Half.UPPER) + .set(DoorBlock.HINGE, DoorHinge.LEFT) + .set(DoorBlock.OPEN, true), + VariantsBuilder.of(topHingeId).y(270) + ) + .variant( + BlockModelDefinitionBuilder.predicate(DoorBlock.FACING, Direction.NORTH) + .set(DoorBlock.HALF, Half.UPPER) + .set(DoorBlock.HINGE, DoorHinge.LEFT) + .set(DoorBlock.OPEN, true), + VariantsBuilder.of(topHingeId) + ) + // Opened top right + .variant( + BlockModelDefinitionBuilder.predicate(DoorBlock.FACING, Direction.EAST) + .set(DoorBlock.HALF, Half.UPPER) + .set(DoorBlock.HINGE, DoorHinge.RIGHT) + .set(DoorBlock.OPEN, true), + VariantsBuilder.of(topId).y(270) + ) + .variant( + BlockModelDefinitionBuilder.predicate(DoorBlock.FACING, Direction.SOUTH) + .set(DoorBlock.HALF, Half.UPPER) + .set(DoorBlock.HINGE, DoorHinge.RIGHT) + .set(DoorBlock.OPEN, true), + VariantsBuilder.of(topId) + ) + .variant( + BlockModelDefinitionBuilder.predicate(DoorBlock.FACING, Direction.WEST) + .set(DoorBlock.HALF, Half.UPPER) + .set(DoorBlock.HINGE, DoorHinge.RIGHT) + .set(DoorBlock.OPEN, true), + VariantsBuilder.of(topId).y(90) + ) + .variant( + BlockModelDefinitionBuilder.predicate(DoorBlock.FACING, Direction.NORTH) + .set(DoorBlock.HALF, Half.UPPER) + .set(DoorBlock.HINGE, DoorHinge.RIGHT) + .set(DoorBlock.OPEN, true), + VariantsBuilder.of(topId).y(180) + ) + ); + + return this; + } + + @Override + public BlockModelTemplates fenceGate(Block block, NamespacedIdentifier texture) { + NamespacedIdentifier baseId = modelGenerator.blockModel(block, BlockModelTemplates.fenceGate(texture)); + NamespacedIdentifier openedId = modelGenerator.blockModel(block, "_open", BlockModelTemplates.fenceGateOpen(texture)); + NamespacedIdentifier wallId = modelGenerator.blockModel(block, "_wall", BlockModelTemplates.fenceGateWall(texture)); + NamespacedIdentifier wallOpenedId = modelGenerator.blockModel(block, "_wall_open", BlockModelTemplates.fenceGateWallOpen(texture)); + modelGenerator.itemModel(block, ModelBuilder.create(baseId)); + + modelGenerator.blockstate( + block, + BlockModelDefinitionBuilder.create() + // Closed not in wall + .variant( + BlockModelDefinitionBuilder.predicate(FenceGateBlock.FACING, Direction.SOUTH) + .set(FenceGateBlock.IN_WALL, false) + .set(FenceGateBlock.OPEN, false), + VariantsBuilder.of(baseId).lockedUV(true) + ) + .variant( + BlockModelDefinitionBuilder.predicate(FenceGateBlock.FACING, Direction.WEST) + .set(FenceGateBlock.IN_WALL, false) + .set(FenceGateBlock.OPEN, false), + VariantsBuilder.of(baseId).lockedUV(true).y(90) + ) + .variant( + BlockModelDefinitionBuilder.predicate(FenceGateBlock.FACING, Direction.NORTH) + .set(FenceGateBlock.IN_WALL, false) + .set(FenceGateBlock.OPEN, false), + VariantsBuilder.of(baseId).lockedUV(true).y(180) + ) + .variant( + BlockModelDefinitionBuilder.predicate(FenceGateBlock.FACING, Direction.EAST) + .set(FenceGateBlock.IN_WALL, false) + .set(FenceGateBlock.OPEN, false), + VariantsBuilder.of(baseId).lockedUV(true).y(270) + ) + // Opened not in wall + .variant( + BlockModelDefinitionBuilder.predicate(FenceGateBlock.FACING, Direction.SOUTH) + .set(FenceGateBlock.IN_WALL, false) + .set(FenceGateBlock.OPEN, true), + VariantsBuilder.of(openedId).lockedUV(true) + ) + .variant( + BlockModelDefinitionBuilder.predicate(FenceGateBlock.FACING, Direction.WEST) + .set(FenceGateBlock.IN_WALL, false) + .set(FenceGateBlock.OPEN, true), + VariantsBuilder.of(openedId).lockedUV(true).y(90) + ) + .variant( + BlockModelDefinitionBuilder.predicate(FenceGateBlock.FACING, Direction.NORTH) + .set(FenceGateBlock.IN_WALL, false) + .set(FenceGateBlock.OPEN, true), + VariantsBuilder.of(openedId).lockedUV(true).y(180) + ) + .variant( + BlockModelDefinitionBuilder.predicate(FenceGateBlock.FACING, Direction.EAST) + .set(FenceGateBlock.IN_WALL, false) + .set(FenceGateBlock.OPEN, true), + VariantsBuilder.of(openedId).lockedUV(true).y(270) + ) + // Closed in wall + .variant( + BlockModelDefinitionBuilder.predicate(FenceGateBlock.FACING, Direction.SOUTH) + .set(FenceGateBlock.IN_WALL, true) + .set(FenceGateBlock.OPEN, false), + VariantsBuilder.of(wallId).lockedUV(true) + ) + .variant( + BlockModelDefinitionBuilder.predicate(FenceGateBlock.FACING, Direction.WEST) + .set(FenceGateBlock.IN_WALL, true) + .set(FenceGateBlock.OPEN, false), + VariantsBuilder.of(wallId).lockedUV(true).y(90) + ) + .variant( + BlockModelDefinitionBuilder.predicate(FenceGateBlock.FACING, Direction.NORTH) + .set(FenceGateBlock.IN_WALL, true) + .set(FenceGateBlock.OPEN, false), + VariantsBuilder.of(wallId).lockedUV(true).y(180) + ) + .variant( + BlockModelDefinitionBuilder.predicate(FenceGateBlock.FACING, Direction.EAST) + .set(FenceGateBlock.IN_WALL, true) + .set(FenceGateBlock.OPEN, false), + VariantsBuilder.of(wallId).lockedUV(true).y(270) + ) + // Opened in wall + .variant( + BlockModelDefinitionBuilder.predicate(FenceGateBlock.FACING, Direction.SOUTH) + .set(FenceGateBlock.IN_WALL, true) + .set(FenceGateBlock.OPEN, true), + VariantsBuilder.of(wallOpenedId).lockedUV(true) + ) + .variant( + BlockModelDefinitionBuilder.predicate(FenceGateBlock.FACING, Direction.WEST) + .set(FenceGateBlock.IN_WALL, true) + .set(FenceGateBlock.OPEN, true), + VariantsBuilder.of(wallOpenedId).lockedUV(true).y(90) + ) + .variant( + BlockModelDefinitionBuilder.predicate(FenceGateBlock.FACING, Direction.NORTH) + .set(FenceGateBlock.IN_WALL, true) + .set(FenceGateBlock.OPEN, true), + VariantsBuilder.of(wallOpenedId).lockedUV(true).y(180) + ) + .variant( + BlockModelDefinitionBuilder.predicate(FenceGateBlock.FACING, Direction.EAST) + .set(FenceGateBlock.IN_WALL, true) + .set(FenceGateBlock.OPEN, true), + VariantsBuilder.of(wallOpenedId).lockedUV(true).y(270) + ) + ); + + return this; + } + + @Override + public BlockModelTemplates leaves(Block block, NamespacedIdentifier texture) { + NamespacedIdentifier modelId = modelGenerator.blockModel(block, BlockModelTemplates.leaves(texture)); + modelGenerator.itemModel(block, ModelBuilder.create(modelId)); + modelGenerator.blockstate(block, BlockModelDefinitionBuilder.createSimple(modelId)); + + return this; + } + + @Override + public BlockModelTemplates pressurePlate(Block block, NamespacedIdentifier texture) { + NamespacedIdentifier baseId = modelGenerator.blockModel(block, BlockModelTemplates.pressurePlateUp(texture)); + NamespacedIdentifier downId = modelGenerator.blockModel(block, "_down", BlockModelTemplates.pressurePlateDown(texture)); + modelGenerator.itemModel(block, ModelBuilder.create(baseId)); + + modelGenerator.blockstate( + block, + BlockModelDefinitionBuilder.create() + .variant( + BlockModelDefinitionBuilder.predicate(PressurePlateBlock.POWERED, false), + VariantsBuilder.of(baseId) + ) + .variant( + BlockModelDefinitionBuilder.predicate(PressurePlateBlock.POWERED, true), + VariantsBuilder.of(downId) + ) + ); + + return this; + } + + @Override + public BlockModelTemplates trapdoor(Block block, NamespacedIdentifier texture) { + NamespacedIdentifier bottomId = modelGenerator.blockModel(block, "_bottom", BlockModelTemplates.trapdoorBottom(texture)); + NamespacedIdentifier topId = modelGenerator.blockModel(block, "_top", BlockModelTemplates.trapdoorTop(texture)); + NamespacedIdentifier openedId = modelGenerator.blockModel(block, "_open", BlockModelTemplates.trapdoorOpen(texture)); + modelGenerator.itemModel(block, ModelBuilder.create(bottomId)); + + modelGenerator.blockstate( + block, + BlockModelDefinitionBuilder.create() + // Closed bottom + .variant( + BlockModelDefinitionBuilder.predicate(TrapdoorBlock.FACING, Direction.NORTH) + .set(TrapdoorBlock.HALF, StairHalf.BOTTOM) + .set(TrapdoorBlock.OPEN, false), + VariantsBuilder.of(bottomId) + ) + .variant( + BlockModelDefinitionBuilder.predicate(TrapdoorBlock.FACING, Direction.SOUTH) + .set(TrapdoorBlock.HALF, StairHalf.BOTTOM) + .set(TrapdoorBlock.OPEN, false), + VariantsBuilder.of(bottomId).y(180) + ) + .variant( + BlockModelDefinitionBuilder.predicate(TrapdoorBlock.FACING, Direction.EAST) + .set(TrapdoorBlock.HALF, StairHalf.BOTTOM) + .set(TrapdoorBlock.OPEN, false), + VariantsBuilder.of(bottomId).y(90) + ) + .variant( + BlockModelDefinitionBuilder.predicate(TrapdoorBlock.FACING, Direction.WEST) + .set(TrapdoorBlock.HALF, StairHalf.BOTTOM) + .set(TrapdoorBlock.OPEN, false), + VariantsBuilder.of(bottomId).y(270) + ) + // Closed top + .variant( + BlockModelDefinitionBuilder.predicate(TrapdoorBlock.FACING, Direction.NORTH) + .set(TrapdoorBlock.HALF, StairHalf.TOP) + .set(TrapdoorBlock.OPEN, false), + VariantsBuilder.of(topId) + ) + .variant( + BlockModelDefinitionBuilder.predicate(TrapdoorBlock.FACING, Direction.SOUTH) + .set(TrapdoorBlock.HALF, StairHalf.TOP) + .set(TrapdoorBlock.OPEN, false), + VariantsBuilder.of(topId).y(180) + ) + .variant( + BlockModelDefinitionBuilder.predicate(TrapdoorBlock.FACING, Direction.EAST) + .set(TrapdoorBlock.HALF, StairHalf.TOP) + .set(TrapdoorBlock.OPEN, false), + VariantsBuilder.of(topId).y(90) + ) + .variant( + BlockModelDefinitionBuilder.predicate(TrapdoorBlock.FACING, Direction.WEST) + .set(TrapdoorBlock.HALF, StairHalf.TOP) + .set(TrapdoorBlock.OPEN, false), + VariantsBuilder.of(topId).y(270) + ) + + // Opened bottom + .variant( + BlockModelDefinitionBuilder.predicate(TrapdoorBlock.FACING, Direction.NORTH) + .set(TrapdoorBlock.HALF, StairHalf.BOTTOM) + .set(TrapdoorBlock.OPEN, true), + VariantsBuilder.of(openedId) + ) + .variant( + BlockModelDefinitionBuilder.predicate(TrapdoorBlock.FACING, Direction.SOUTH) + .set(TrapdoorBlock.HALF, StairHalf.BOTTOM) + .set(TrapdoorBlock.OPEN, true), + VariantsBuilder.of(openedId).y(180) + ) + .variant( + BlockModelDefinitionBuilder.predicate(TrapdoorBlock.FACING, Direction.EAST) + .set(TrapdoorBlock.HALF, StairHalf.BOTTOM) + .set(TrapdoorBlock.OPEN, true), + VariantsBuilder.of(openedId).y(90) + ) + .variant( + BlockModelDefinitionBuilder.predicate(TrapdoorBlock.FACING, Direction.WEST) + .set(TrapdoorBlock.HALF, StairHalf.BOTTOM) + .set(TrapdoorBlock.OPEN, true), + VariantsBuilder.of(openedId).y(270) + ) + // Opened top + .variant( + BlockModelDefinitionBuilder.predicate(TrapdoorBlock.FACING, Direction.NORTH) + .set(TrapdoorBlock.HALF, StairHalf.TOP) + .set(TrapdoorBlock.OPEN, true), + VariantsBuilder.of(openedId).x(180).y(180) + ) + .variant( + BlockModelDefinitionBuilder.predicate(TrapdoorBlock.FACING, Direction.SOUTH) + .set(TrapdoorBlock.HALF, StairHalf.TOP) + .set(TrapdoorBlock.OPEN, true), + VariantsBuilder.of(openedId).x(180).y(0) + ) + .variant( + BlockModelDefinitionBuilder.predicate(TrapdoorBlock.FACING, Direction.EAST) + .set(TrapdoorBlock.HALF, StairHalf.TOP) + .set(TrapdoorBlock.OPEN, true), + VariantsBuilder.of(openedId).x(180).y(270) + ) + .variant( + BlockModelDefinitionBuilder.predicate(TrapdoorBlock.FACING, Direction.WEST) + .set(TrapdoorBlock.HALF, StairHalf.TOP) + .set(TrapdoorBlock.OPEN, true), + VariantsBuilder.of(openedId).x(180).y(90) + ) + ); + + return this; + } +} diff --git a/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/model/ModelGeneratorImpl.java b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/model/ModelGeneratorImpl.java new file mode 100644 index 00000000..cbc9eea7 --- /dev/null +++ b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/model/ModelGeneratorImpl.java @@ -0,0 +1,59 @@ +package net.ornithemc.osl.datagen.impl.model; + +import com.google.gson.JsonElement; +import net.minecraft.block.Block; +import net.minecraft.item.ItemLike; +import net.ornithemc.osl.blocks.api.BlockRegistry; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.datagen.api.model.ModelBuilder; +import net.ornithemc.osl.datagen.api.model.ModelGenerator; +import net.ornithemc.osl.datagen.api.model.block.BlockModelDefinitionBuilder; +import net.ornithemc.osl.datagen.api.model.block.BlockModelTemplates; +import net.ornithemc.osl.items.api.ItemRegistry; + +import java.util.function.BiConsumer; + +public class ModelGeneratorImpl implements ModelGenerator { + private final BiConsumer writer; + private final BlockModelTemplates templates; + + public ModelGeneratorImpl(BiConsumer writer) { + this.writer = writer; + this.templates = new BlockModelTemplatesImpl(this); + } + + @Override + public void blockstate(Block block, BlockModelDefinitionBuilder builder) { + NamespacedIdentifier blockId = BlockRegistry.getIdentifier(block); + writer.accept(blockId.prefixed("blockstates/"), builder.build()); + } + + @Override + public void itemModel(ItemLike item, ModelBuilder builder) { + NamespacedIdentifier itemId = ItemRegistry.getIdentifier(item.asItem()); + writer.accept(itemId.prefixed("models/item/"), builder.build()); + } + + @Override + public NamespacedIdentifier blockModel(NamespacedIdentifier identifier, ModelBuilder builder) { + writer.accept(identifier.prefixed("models/block/"), builder.build()); + return identifier.prefixed("block/"); + } + + @Override + public NamespacedIdentifier blockModel(Block block, ModelBuilder builder) { + NamespacedIdentifier blockId = BlockRegistry.getIdentifier(block); + return blockModel(blockId, builder); + } + + @Override + public NamespacedIdentifier blockModel(Block block, String suffix, ModelBuilder builder) { + NamespacedIdentifier blockId = BlockRegistry.getIdentifier(block); + return blockModel(blockId.suffixed(suffix), builder); + } + + @Override + public BlockModelTemplates blockTemplates() { + return templates; + } +} diff --git a/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/wrapper/PackProviderWrapper.java b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/wrapper/PackProviderWrapper.java new file mode 100644 index 00000000..980140bc --- /dev/null +++ b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/datagen/impl/wrapper/PackProviderWrapper.java @@ -0,0 +1,25 @@ +package net.ornithemc.osl.datagen.impl.wrapper; + +import net.minecraft.data.DataProvider; +import net.minecraft.data.HashCache; +import net.ornithemc.osl.datagen.api.provider.ModDataProvider; + +import java.io.IOException; + +public class PackProviderWrapper implements DataProvider { + private final ModDataProvider delegate; + + public PackProviderWrapper(ModDataProvider delegate) { + this.delegate = delegate; + } + + @Override + public void run(HashCache cache) throws IOException { + delegate.provide(cache); + } + + @Override + public String getName() { + return delegate.getProviderName(); + } +} diff --git a/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/resources/fabric.mod.json b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/resources/fabric.mod.json new file mode 100644 index 00000000..c8529f68 --- /dev/null +++ b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/resources/fabric.mod.json @@ -0,0 +1,42 @@ +{ + "schemaVersion": 1, + "id": "osl-datagen", + "version": "0.1.0-alpha.1+mc18w43a-mc1.14.4", + "environment": "*", + "entrypoints": { + "init": [ + "net.ornithemc.osl.datagen.impl.DataGeneratorInit" + ] + }, + "mixins": [ + "osl.datagen.mixins.json" + ], + "accessWidener": "osl.datagen.classtweaker", + "depends": { + "fabricloader": "\u003e\u003d0.18.0", + "minecraft": "\u003e\u003d1.14-alpha.18.43.a \u003c\u003d1.14.4", + "osl-core": "\u003e\u003d0.11.0", + "osl-entrypoints": "\u003e\u003d0.5.0", + "osl-lifecycle-events": "\u003e\u003d0.6.0", + "osl-executors": "\u003e\u003d0.1.0", + "osl-text-components": "\u003e\u003d0.1.0-", + "osl-networking": "\u003e\u003d0.10.0", + "osl-networking-impl": "\u003e\u003d0.2.0", + "osl-registries": "\u003e\u003d0.2.0", + "osl-resource-loader": "\u003e\u003d0.8.0", + "osl-blockstates": "\u003e\u003d0.1.0", + "osl-blocks": "\u003e\u003d0.3.0", + "osl-items": "\u003e\u003d0.2.0" + }, + "name": "OSL Data Generator", + "description": "Data Generator api.", + "authors": [ + "OrnitheMC" + ], + "contact": { + "homepage": "https://ornithemc.net/", + "issues": "https://github.com/OrnitheMC/ornithe-standard-libraries/issues", + "sources": "https://github.com/OrnitheMC/ornithe-standard-libraries" + }, + "license": "Apache-2.0" +} \ No newline at end of file diff --git a/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/resources/osl.datagen.classtweaker b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/resources/osl.datagen.classtweaker new file mode 100644 index 00000000..72cd6dda --- /dev/null +++ b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/resources/osl.datagen.classtweaker @@ -0,0 +1,14 @@ +classTweaker v1 named + +transitive-accessible method net/minecraft/data/recipe/RecipesProvider m_22877789 (Lnet/minecraft/block/Block;)Lnet/minecraft/advancement/criterion/EnterBlockTrigger$Instance; +transitive-accessible method net/minecraft/data/recipe/RecipesProvider m_87855158 (Lnet/minecraft/advancement/criterion/NumberPredicate$Ints;Lnet/minecraft/item/ItemLike;)Lnet/minecraft/advancement/criterion/InventoryChangedTrigger$Instance; +transitive-accessible method net/minecraft/data/recipe/RecipesProvider m_04657628 (Lnet/minecraft/item/ItemLike;)Lnet/minecraft/advancement/criterion/InventoryChangedTrigger$Instance; +transitive-accessible method net/minecraft/data/recipe/RecipesProvider m_53363402 (Lnet/minecraft/tag/Tag;)Lnet/minecraft/advancement/criterion/InventoryChangedTrigger$Instance; +transitive-accessible field net/minecraft/data/recipe/RecipesProvider generator Lnet/minecraft/data/DataGenerator; + +transitive-inject-interface net/minecraft/data/DataGenerator net/ornithemc/osl/datagen/api/PackGenerator +transitive-inject-interface net/minecraft/data/DataProvider net/ornithemc/osl/datagen/impl/ModDataProviderExtensionImpl +transitive-inject-interface net/minecraft/data/HashCache net/ornithemc/osl/datagen/api/PackCache + +accessible method net/minecraft/data/recipe/RecipesProvider save (Lnet/minecraft/data/HashCache;Lcom/google/gson/JsonObject;Ljava/nio/file/Path;)V +accessible method net/minecraft/data/recipe/RecipesProvider saveAdvancement (Lnet/minecraft/data/HashCache;Lcom/google/gson/JsonObject;Ljava/nio/file/Path;)V diff --git a/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/resources/osl.datagen.mixins.json b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/resources/osl.datagen.mixins.json new file mode 100644 index 00000000..0019af49 --- /dev/null +++ b/libraries/datagen/datagen-mc18w43a-mc1.14.4/src/main/resources/osl.datagen.mixins.json @@ -0,0 +1,21 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "net.ornithemc.osl.datagen.impl.mixin", + "compatibilityLevel": "JAVA_8", + "plugin": "net.ornithemc.conditionalmixin.mixin.ConditionalMixinPlugin", + "mixins": [ + "C_23159014NewMixin", + "C_23159014OldMixin", + "DataGeneratorMixin", + "DataProviderMixin", + "HashCacheMixin" + ], + "client": [ + ], + "server": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/libraries/datagen/gradle.properties b/libraries/datagen/gradle.properties new file mode 100644 index 00000000..2c6f8a50 --- /dev/null +++ b/libraries/datagen/gradle.properties @@ -0,0 +1,7 @@ +library_id = datagen +library_name = Data Generator +library_description = Data Generator api. +library_version = 0.1.0-alpha.1 + +entrypoint_init = net.ornithemc.osl.datagen.impl.DataGeneratorInit +osl_dependencies = core:0.8.0,entrypoints:0.5.0,registries:0.1.0,resource-loader:0.8.0,blocks:0.2.0,items:0.2.0 diff --git a/libraries/datagen/src/main/java/net/ornithemc/osl/datagen/api/DataGeneratorInitializer.java b/libraries/datagen/src/main/java/net/ornithemc/osl/datagen/api/DataGeneratorInitializer.java new file mode 100644 index 00000000..015beade --- /dev/null +++ b/libraries/datagen/src/main/java/net/ornithemc/osl/datagen/api/DataGeneratorInitializer.java @@ -0,0 +1,10 @@ +package net.ornithemc.osl.datagen.api; + +/** + * An initializer for data generators. + */ +public interface DataGeneratorInitializer { + String KEY = "datagen"; + + void onDatagenInit(ModDataGenerator dataGenerator); +} diff --git a/libraries/datagen/src/main/java/net/ornithemc/osl/datagen/api/ModDataGenerator.java b/libraries/datagen/src/main/java/net/ornithemc/osl/datagen/api/ModDataGenerator.java new file mode 100644 index 00000000..4cccc9f6 --- /dev/null +++ b/libraries/datagen/src/main/java/net/ornithemc/osl/datagen/api/ModDataGenerator.java @@ -0,0 +1,22 @@ +package net.ornithemc.osl.datagen.api; + +import net.fabricmc.loader.api.ModContainer; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; + +/** + * A data generator for a mod. + */ +public interface ModDataGenerator { + /** + * Creates a pack generator for the mod. + */ + PackGenerator createPack(); + /** + * Creates a bundled resource pack generator for the mod. + */ + PackGenerator createBundledResourcePack(NamespacedIdentifier id); + /** + * Returns the mod container assigned to this ModDataGenerator. + */ + ModContainer getMod(); +} diff --git a/libraries/datagen/src/main/java/net/ornithemc/osl/datagen/api/PackCache.java b/libraries/datagen/src/main/java/net/ornithemc/osl/datagen/api/PackCache.java new file mode 100644 index 00000000..680865a3 --- /dev/null +++ b/libraries/datagen/src/main/java/net/ornithemc/osl/datagen/api/PackCache.java @@ -0,0 +1,30 @@ +package net.ornithemc.osl.datagen.api; + +import com.google.common.hash.HashFunction; +import com.google.common.hash.Hashing; + +import java.io.IOException; +import java.nio.file.Path; + +/** + * A cache for pack resources generated by a ModDataGenerator. + */ +public interface PackCache { + HashFunction SHA1 = Hashing.sha1(); + + /** + * Checks if the data for the given path has changed and writes it to the cache if it has. + * @param path the path to check + * @param data the data to write + * @throws IOException if an I/O error occurs + */ + void checkAndWrite(Path path, byte[] data) throws IOException; + + /** + * Checks if the data for the given path has changed and writes it to the cache if it has. + * @param path the path to check + * @param data the data to write + * @throws IOException if an I/O error occurs + */ + void checkAndWrite(Path path, String data) throws IOException; +} diff --git a/libraries/datagen/src/main/java/net/ornithemc/osl/datagen/api/PackGenerator.java b/libraries/datagen/src/main/java/net/ornithemc/osl/datagen/api/PackGenerator.java new file mode 100644 index 00000000..b8632d6b --- /dev/null +++ b/libraries/datagen/src/main/java/net/ornithemc/osl/datagen/api/PackGenerator.java @@ -0,0 +1,36 @@ +package net.ornithemc.osl.datagen.api; + +import net.fabricmc.loader.api.ModContainer; +import net.ornithemc.osl.datagen.api.provider.ModDataProvider; + +import java.nio.file.Path; +import java.util.function.BiFunction; +import java.util.function.Function; + +/** + * A generator for a pack of resources. + */ +public interface PackGenerator { + /** + * Adds a provider to the pack. + */ + void addProvider(ComplexProviderFactory provider); + /** + * Adds a provider to the pack. + */ + void addProvider(SimpleProviderFactory provider); + /** + * Returns the output path for the pack. + */ + Path getOutputPath(); + + @FunctionalInterface + interface SimpleProviderFactory { + ModDataProvider create(PackGenerator generator); + } + + @FunctionalInterface + interface ComplexProviderFactory { + ModDataProvider create(PackGenerator generator, ModContainer container); + } +} diff --git a/libraries/datagen/src/main/java/net/ornithemc/osl/datagen/api/provider/GsonDataProvider.java b/libraries/datagen/src/main/java/net/ornithemc/osl/datagen/api/provider/GsonDataProvider.java new file mode 100644 index 00000000..6cbd51df --- /dev/null +++ b/libraries/datagen/src/main/java/net/ornithemc/osl/datagen/api/provider/GsonDataProvider.java @@ -0,0 +1,57 @@ +package net.ornithemc.osl.datagen.api.provider; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import net.fabricmc.loader.api.ModContainer; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.datagen.api.PackGenerator; +import net.ornithemc.osl.datagen.api.PackCache; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.function.BiConsumer; + +/** + * A provider for pack resources generated by a ModDataGenerator that generates JSON files using GSON. + */ +public abstract class GsonDataProvider implements ModDataProvider { + private static final Logger LOGGER = LogManager.getLogger(); + private static final Gson GSON = (new GsonBuilder()).setPrettyPrinting().create(); + public final PackGenerator generator; + public final ModContainer mod; + + protected GsonDataProvider(PackGenerator generator, ModContainer mod) { + this.generator = generator; + this.mod = mod; + } + + @Override + public void provide(PackCache cache) { + generate((id, json) -> { + Path path = getPath(id); + + try { + String string = GSON.toJson(json); + cache.checkAndWrite(path, string); + } catch (IOException iOException) { + LOGGER.error("Couldn't save data to {}", path, iOException); + } + }); + } + + /** + * Generates pack resources using the given consumer. + * @param consumer the consumer to generate pack resources with + */ + protected abstract void generate(BiConsumer consumer); + + /** + * Gets the resource path for the given identifier. + * @param id the identifier + * @return the resource path for the given identifier + */ + protected abstract Path getPath(NamespacedIdentifier id); +} diff --git a/libraries/datagen/src/main/java/net/ornithemc/osl/datagen/api/provider/ModDataProvider.java b/libraries/datagen/src/main/java/net/ornithemc/osl/datagen/api/provider/ModDataProvider.java new file mode 100644 index 00000000..ba6d4309 --- /dev/null +++ b/libraries/datagen/src/main/java/net/ornithemc/osl/datagen/api/provider/ModDataProvider.java @@ -0,0 +1,23 @@ +package net.ornithemc.osl.datagen.api.provider; + +import net.ornithemc.osl.datagen.api.PackCache; + +import java.io.IOException; + +/** + * A provider for pack resources generated by a ModDataGenerator. + */ +public interface ModDataProvider { + /** + * Gets the name of this provider. + * @return the name of this provider + */ + String getProviderName(); + + /** + * Provides pack resources to the given cache. + * @param cache the cache to provide pack resources to + * @throws IOException if an I/O error occurs + */ + void provide(PackCache cache) throws IOException; +} diff --git a/libraries/datagen/src/main/java/net/ornithemc/osl/datagen/impl/DataGenHelperImpl.java b/libraries/datagen/src/main/java/net/ornithemc/osl/datagen/impl/DataGenHelperImpl.java new file mode 100644 index 00000000..f6162ee2 --- /dev/null +++ b/libraries/datagen/src/main/java/net/ornithemc/osl/datagen/impl/DataGenHelperImpl.java @@ -0,0 +1,31 @@ +package net.ornithemc.osl.datagen.impl; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Objects; + +public class DataGenHelperImpl { + /** + * When enabled the startup will be hijacked to run the data generators and then quit. + */ + public static final boolean ENABLED = System.getProperty("fabric-api.datagen") != null; + + /** + * Sets the output directory for the generated data. + */ + private static final String OUTPUT_DIR = System.getProperty("fabric-api.datagen.output-dir"); + + /** + * When enabled providers can enable extra validation, such as ensuring all registry entries have data generated for them. + */ + public static final boolean STRICT_VALIDATION = System.getProperty("fabric-api.datagen.strict-validation") != null; + + /** + * Filter to a specific mod ID with this property, useful if dependencies also have data generators. + */ + public static final String MOD_ID_FILTER = System.getProperty("fabric-api.datagen.modid"); + + public static Path getOutputDir() { + return Paths.get(Objects.requireNonNull(OUTPUT_DIR, "No output dir provided with the 'fabric-api.datagen.output-dir' property")); + } +} diff --git a/libraries/datagen/src/main/java/net/ornithemc/osl/datagen/impl/provider/MCMetaProvider.java b/libraries/datagen/src/main/java/net/ornithemc/osl/datagen/impl/provider/MCMetaProvider.java new file mode 100644 index 00000000..20756ea8 --- /dev/null +++ b/libraries/datagen/src/main/java/net/ornithemc/osl/datagen/impl/provider/MCMetaProvider.java @@ -0,0 +1,42 @@ +package net.ornithemc.osl.datagen.impl.provider; + +import net.ornithemc.osl.datagen.api.PackCache; +import net.ornithemc.osl.datagen.api.PackGenerator; +import net.ornithemc.osl.datagen.api.provider.ModDataProvider; +import net.ornithemc.osl.resource.loader.api.resource.pack.ResourcePackMetadata; +import net.ornithemc.osl.resource.loader.impl.resource.pack.ResourcePacks; +import net.ornithemc.osl.resource.loader.impl.resource.pack.SimpleResourcePackMetadata; +import net.ornithemc.osl.text.api.TextComponents; + +import java.io.IOException; +import java.nio.file.Path; + +public class MCMetaProvider implements ModDataProvider { + private final PackGenerator generator; + private final String description; + + public MCMetaProvider(PackGenerator generator, String description) { + this.generator = generator; + this.description = description; + } + + private Path getPath() { + return this.generator.getOutputPath().resolve("pack.mcmeta"); + } + + @Override + public String getProviderName() { + return "MCMeta"; + } + + @Override + public void provide(PackCache cache) throws IOException { + ResourcePackMetadata metadata = new SimpleResourcePackMetadata(ResourcePacks.getSupportedFormat(), TextComponents.literal(this.description)); + + Path path = getPath(); + + String json = SimpleResourcePackMetadata.SERIALIZER.serialize(metadata).toString(); + + cache.checkAndWrite(path, json); + } +} diff --git a/libraries/registries/src/main/java/net/ornithemc/osl/registries/api/RegistryEvents.java b/libraries/registries/src/main/java/net/ornithemc/osl/registries/api/RegistryEvents.java index 9d829188..f416acad 100644 --- a/libraries/registries/src/main/java/net/ornithemc/osl/registries/api/RegistryEvents.java +++ b/libraries/registries/src/main/java/net/ornithemc/osl/registries/api/RegistryEvents.java @@ -28,4 +28,6 @@ public final class RegistryEvents { */ public static final Event BOOTSTRAP_REGISTRIES = Event.runnable(); + public static final Event REGISTRIES_FROZEN = Event.runnable(); + } diff --git a/libraries/registries/src/main/java/net/ornithemc/osl/registries/impl/registry/RegistriesImpl.java b/libraries/registries/src/main/java/net/ornithemc/osl/registries/impl/registry/RegistriesImpl.java index 2b823195..b89a33fd 100644 --- a/libraries/registries/src/main/java/net/ornithemc/osl/registries/impl/registry/RegistriesImpl.java +++ b/libraries/registries/src/main/java/net/ornithemc/osl/registries/impl/registry/RegistriesImpl.java @@ -91,6 +91,8 @@ public static void init() { validate(); LOGGER.info("Bootstrapped {} registries.", BOOTSTRAPS.size()); + + RegistryEvents.REGISTRIES_FROZEN.invoker().run(); } private static void bootstrap() { diff --git a/settings.gradle b/settings.gradle index 33bc9646..392dd4ec 100644 --- a/settings.gradle +++ b/settings.gradle @@ -191,3 +191,6 @@ include ':libraries:resource-loader:resource-loader-mc19w07a-mc1.14.4' include ':libraries:text-components' include ':libraries:text-components:text-components-mca1.0.1_01-mc1.6.4' include ':libraries:text-components:text-components-mc13w36a-mc1.14.4' + +include ':libraries:datagen' +include ':libraries:datagen:datagen-mc18w43a-mc1.14.4'