From 665bf9b7c743c0f03b3b0c51ffac8b4336b25b07 Mon Sep 17 00:00:00 2001 From: William Gaylord Date: Sun, 17 Mar 2024 10:13:09 -0500 Subject: [PATCH] Fix handling FeatureSet related entities in 1.20.3/4 (#16) * Fix handling FeatureSet related entities. * Add 1.20.4 to build.yml * Turns out jsut need to enable the feature set in the server.properties * Remove the server.properties Lets not enable feature sets since they could change alot of stuff on use. The other fix in the PR still works as it makes it so that the entities don't show up as player type, just as unknow if we can't get them. * Use the same way of getting the entity in all parts of the generator. This should help deal with entities from features, since using the factory directly gets around the feature check. * Would be helpful to call the function correctly... --- .github/workflows/build.yml | 2 +- 1.20.4/build.gradle | 31 ++ 1.20.4/gradle.properties | 8 + .../dev/u9g/minecraftdatagenerator/Main.java | 14 + .../generators/BiomesDataGenerator.java | 317 ++++++++++++++++++ .../BlockCollisionShapesDataGenerator.java | 113 +++++++ .../generators/BlocksDataGenerator.java | 198 +++++++++++ .../generators/DataGenerators.java | 77 +++++ .../generators/EffectsDataGenerator.java | 47 +++ .../generators/EnchantmentsDataGenerator.java | 109 ++++++ .../generators/EntitiesDataGenerator.java | 126 +++++++ .../generators/FoodsDataGenerator.java | 52 +++ .../generators/IDataGenerator.java | 10 + .../generators/InstrumentsDataGenerator.java | 25 ++ .../generators/ItemsDataGenerator.java | 82 +++++ .../generators/LanguageDataGenerator.java | 27 ++ .../generators/MaterialsDataGenerator.java | 200 +++++++++++ .../generators/ParticlesDataGenerator.java | 34 ++ .../generators/RecipeDataGenerator.java | 128 +++++++ .../generators/TintsDataGenerator.java | 163 +++++++++ .../mixin/EULAMixin.java | 15 + .../mixin/EntityTypeAccessor.java | 12 + .../mixin/MiningToolItemAccessor.java | 17 + .../mixin/ReadyMixin.java | 28 ++ .../mixin/TheEndBiomeDataAccessor.java | 29 ++ .../mojangannoyances/BiomeColors.java | 35 ++ .../mojangannoyances/BlockColorProvider.java | 11 + .../mojangannoyances/BlockColors.java | 94 ++++++ .../u9g/minecraftdatagenerator/util/DGU.java | 32 ++ .../util/EmptyRenderBlockView.java | 72 ++++ 1.20.4/src/main/resources/fabric.mod.json | 27 ++ .../minecraft-data-generator.mixins.json | 18 + settings.gradle | 1 + 33 files changed, 2153 insertions(+), 1 deletion(-) create mode 100644 1.20.4/build.gradle create mode 100644 1.20.4/gradle.properties create mode 100644 1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/Main.java create mode 100644 1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/BiomesDataGenerator.java create mode 100644 1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/BlockCollisionShapesDataGenerator.java create mode 100644 1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/BlocksDataGenerator.java create mode 100644 1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/DataGenerators.java create mode 100644 1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/EffectsDataGenerator.java create mode 100644 1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/EnchantmentsDataGenerator.java create mode 100644 1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/EntitiesDataGenerator.java create mode 100644 1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/FoodsDataGenerator.java create mode 100644 1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/IDataGenerator.java create mode 100644 1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/InstrumentsDataGenerator.java create mode 100644 1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/ItemsDataGenerator.java create mode 100644 1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/LanguageDataGenerator.java create mode 100644 1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/MaterialsDataGenerator.java create mode 100644 1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/ParticlesDataGenerator.java create mode 100644 1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/RecipeDataGenerator.java create mode 100644 1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/TintsDataGenerator.java create mode 100644 1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/mixin/EULAMixin.java create mode 100644 1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/mixin/EntityTypeAccessor.java create mode 100644 1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/mixin/MiningToolItemAccessor.java create mode 100644 1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/mixin/ReadyMixin.java create mode 100644 1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/mixin/TheEndBiomeDataAccessor.java create mode 100644 1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/mojangannoyances/BiomeColors.java create mode 100644 1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/mojangannoyances/BlockColorProvider.java create mode 100644 1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/mojangannoyances/BlockColors.java create mode 100644 1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/util/DGU.java create mode 100644 1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/util/EmptyRenderBlockView.java create mode 100644 1.20.4/src/main/resources/fabric.mod.json create mode 100644 1.20.4/src/main/resources/minecraft-data-generator.mixins.json diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7bd6150..c1bb07f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,7 +11,7 @@ jobs: build: strategy: matrix: - version: ["1.7", "1.8.9", "1.9.4", "1.10.2", "1.11.2", "1.12.2", "1.13", "1.14", "1.15", "1.16", "1.17", "1.18", "22w19a", "1.19", "1.19.2", "1.20"] + version: ["1.7", "1.8.9", "1.9.4", "1.10.2", "1.11.2", "1.12.2", "1.13", "1.14", "1.15", "1.16", "1.17", "1.18", "22w19a", "1.19", "1.19.2", "1.20", "1.20.4"] name: Build ${{ matrix.version }} timeout-minutes: 10 diff --git a/1.20.4/build.gradle b/1.20.4/build.gradle new file mode 100644 index 0000000..e85de39 --- /dev/null +++ b/1.20.4/build.gradle @@ -0,0 +1,31 @@ +plugins { + id 'fabric-loom' +} + +dependencies { + // To change the versions see the gradle.properties file + minecraft "com.mojang:minecraft:${project.minecraft_version}" + mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" + modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" + + // Fabric API. This is technically optional, but you probably want it anyway. + modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" +} + +processResources { + filteringCharset "UTF-8" + + filesMatching("fabric.mod.json") { + expand "version": project.version + } +} + +tasks.withType(JavaCompile).configureEach { + it.options.encoding = "UTF-8" +} + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(17)) + } +} diff --git a/1.20.4/gradle.properties b/1.20.4/gradle.properties new file mode 100644 index 0000000..7d228ec --- /dev/null +++ b/1.20.4/gradle.properties @@ -0,0 +1,8 @@ +# Fabric Properties +# check these on https://modmuss50.me/fabric.html +minecraft_version=1.20.4 +yarn_mappings=1.20.4+build.3 +loader_version=0.15.3 +# Dependencies +# check this on https://modmuss50.me/fabric.html +fabric_version=0.92.0+1.20.4 diff --git a/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/Main.java b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/Main.java new file mode 100644 index 0000000..f8d1737 --- /dev/null +++ b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/Main.java @@ -0,0 +1,14 @@ +package dev.u9g.minecraftdatagenerator; + +import net.fabricmc.api.ModInitializer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Main implements ModInitializer { + public static final Logger LOGGER = LoggerFactory.getLogger("mc-data-gen-serv"); + + @Override + public void onInitialize() { + + } +} diff --git a/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/BiomesDataGenerator.java b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/BiomesDataGenerator.java new file mode 100644 index 0000000..bda5f96 --- /dev/null +++ b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/BiomesDataGenerator.java @@ -0,0 +1,317 @@ +package dev.u9g.minecraftdatagenerator.generators; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import dev.u9g.minecraftdatagenerator.mixin.TheEndBiomeDataAccessor; +import dev.u9g.minecraftdatagenerator.util.DGU; +import net.fabricmc.fabric.api.biome.v1.NetherBiomes; +import net.minecraft.registry.DynamicRegistryManager; +import net.minecraft.registry.Registry; +import net.minecraft.registry.RegistryKey; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.util.Identifier; +import net.minecraft.world.biome.Biome; + +import java.util.HashSet; +import java.util.Set; + +public class BiomesDataGenerator implements IDataGenerator { + private static final Set> END_BIOMES = new HashSet<>(); + + static { + END_BIOMES.addAll(TheEndBiomeDataAccessor.END_BIOMES_MAP().keySet()); + END_BIOMES.addAll(TheEndBiomeDataAccessor.END_BARRENS_MAP().keySet()); + END_BIOMES.addAll(TheEndBiomeDataAccessor.END_MIDLANDS_MAP().keySet()); + } + + private static String guessBiomeDimensionFromCategory(Biome biome, String biomeName) { + var key = DGU.getWorld().getRegistryManager().get(RegistryKeys.BIOME).getKey(biome).orElseThrow(); + if (NetherBiomes.canGenerateInNether(key)) { + return "nether"; + } else if (END_BIOMES.contains(key) || biomeName.startsWith("end_")) { + return "end"; + } + return "overworld"; + } + + private static String guessCategoryBasedOnName(String name, String dimension) { + if (dimension.equals("nether")) { + return "nether"; + } else if (dimension.equals("end")) { + return "the_end"; + } + + if (name.contains("end")) { + System.out.println(); + } + + if (name.contains("hills")) { + return "extreme_hills"; + } else if (name.contains("ocean")) { + return "ocean"; + } else if (name.contains("plains")) { + return "plains"; + } else if (name.contains("ice") || name.contains("frozen")) { + return "ice"; + } else if (name.contains("jungle")) { + return "jungle"; + } else if (name.contains("desert")) { + return "desert"; + } else if (name.contains("forest") || name.contains("grove")) { + return "forest"; + } else if (name.contains("taiga")) { + return "taiga"; + } else if (name.contains("swamp")) { + return "swamp"; + } else if (name.contains("river")) { + return "river"; + } else if (name.equals("the_end")) { + return "the_end"; + } else if (name.contains("mushroom")) { + return "mushroom"; + } else if (name.contains("beach") || name.equals("stony_shore")) { + return "beach"; + } else if (name.contains("savanna")) { + return "savanna"; + } else if (name.contains("badlands")) { + return "mesa"; + } else if (name.contains("peaks") || name.equals("snowy_slopes") || name.equals("meadow")) { + return "mountain"; + } else if (name.equals("the_void")) { + return "none"; + } else if (name.contains("cave") || name.equals("deep_dark")) { + return "underground"; + } else { + System.out.println("Unable to find biome category for biome with name: '" + name + "'"); + return "none"; + } + } + + private static int getBiomeColorFor(String biomeName) { + switch (biomeName) { + case "the_void" -> { + return 0; + } + case "plains" -> { + return 9286496; + } + case "sunflower_plains" -> { + return 11918216; + } + case "snowy_plains" -> { + return 16777215; + } + case "ice_spikes" -> { + return 11853020; + } + case "desert" -> { + return 16421912; + } + case "swamp" -> { + return 522674; + } + case "forest" -> { + return 353825; + } + case "flower_forest" -> { + return 2985545; + } + case "birch_forest" -> { + return 3175492; + } + case "dark_forest" -> { + return 4215066; + } + case "old_growth_birch_forest" -> { + return 5807212; + } + case "old_growth_pine_taiga" -> { + return 5858897; + } + case "old_growth_spruce_taiga" -> { + return 8490617; + } + case "taiga" -> { + return 747097; + } + case "snowy_taiga" -> { + return 3233098; + } + case "savanna" -> { + return 12431967; + } + case "savanna_plateau" -> { + return 10984804; + } + case "windswept_hills" -> { + return 6316128; + } + case "windswept_gravelly_hills" -> { + return 8947848; + } + case "windswept_forest" -> { + return 2250012; + } + case "windswept_savanna" -> { + return 15063687; + } + case "jungle" -> { + return 5470985; + } + case "sparse_jungle" -> { + return 6458135; + } + case "bamboo_jungle" -> { + return 7769620; + } + case "badlands" -> { + return 14238997; + } + case "eroded_badlands" -> { + return 16739645; + } + case "wooded_badlands" -> { + return 11573093; + } + case "meadow" -> { + return 9217136; + } + case "grove" -> { + return 14675173; + } + case "snowy_slopes" -> { + return 14348785; + } + case "frozen_peaks" -> { + return 15399931; + } + case "jagged_peaks" -> { + return 14937325; + } + case "stony_peaks" -> { + return 13750737; + } + case "river" -> { + return 255; + } + case "frozen_river" -> { + return 10526975; + } + case "beach" -> { + return 16440917; + } + case "snowy_beach" -> { + return 16445632; + } + case "stony_shore" -> { + return 10658436; + } + case "warm_ocean" -> { + return 172; + } + case "lukewarm_ocean" -> { + return 144; + } + case "deep_lukewarm_ocean" -> { + return 64; + } + case "ocean" -> { + return 112; + } + case "deep_ocean" -> { + return 48; + } + case "cold_ocean" -> { + return 2105456; + } + case "deep_cold_ocean" -> { + return 2105400; + } + case "frozen_ocean" -> { + return 7368918; + } + case "deep_frozen_ocean" -> { + return 4210832; + } + case "mushroom_fields" -> { + return 16711935; + } + case "dripstone_caves" -> { + return 12690831; + } + case "lush_caves" -> { + return 14652980; + } + case "nether_wastes" -> { + return 12532539; + } + case "warped_forest" -> { + return 4821115; + } + case "crimson_forest" -> { + return 14485512; + } + case "soul_sand_valley" -> { + return 6174768; + } + case "basalt_deltas" -> { + return 4208182; + } + case "the_end" -> { + return 8421631; + } + case "end_highlands" -> { + return 12828041; + } + case "end_midlands" -> { + return 15464630; + } + case "small_end_islands" -> { + return 42; + } + case "end_barrens" -> { + return 9474162; + } + } + System.out.println("Don't know the color of biome: '" + biomeName + "'"); + return 0; + } + + public static JsonObject generateBiomeInfo(Registry registry, Biome biome) { + JsonObject biomeDesc = new JsonObject(); + Identifier registryKey = registry.getKey(biome).orElseThrow().getValue(); + String localizationKey = String.format("biome.%s.%s", registryKey.getNamespace(), registryKey.getPath()); + String name = registryKey.getPath(); + biomeDesc.addProperty("id", registry.getRawId(biome)); + biomeDesc.addProperty("name", name); + String dimension = guessBiomeDimensionFromCategory(biome, name); + biomeDesc.addProperty("category", guessCategoryBasedOnName(name, dimension)); + biomeDesc.addProperty("temperature", biome.getTemperature()); + //biomeDesc.addProperty("precipitation", biome.getPrecipitation().getName());// - removed in 1.19.4 + biomeDesc.addProperty("has_precipitation", biome.hasPrecipitation()); + //biomeDesc.addProperty("depth", biome.getDepth()); - Doesn't exist anymore in minecraft source + biomeDesc.addProperty("dimension", dimension); + biomeDesc.addProperty("displayName", DGU.translateText(localizationKey)); + biomeDesc.addProperty("color", getBiomeColorFor(registryKey.getPath())); + //biomeDesc.addProperty("rainfall", biome.getDownfall());// - removed in 1.19.4 + + return biomeDesc; + } + + @Override + public String getDataName() { + return "biomes"; + } + + @Override + public JsonArray generateDataJson() { + JsonArray biomesArray = new JsonArray(); + DynamicRegistryManager registryManager = DGU.getWorld().getRegistryManager(); + Registry biomeRegistry = registryManager.get(RegistryKeys.BIOME); + + biomeRegistry.stream() + .map(biome -> generateBiomeInfo(biomeRegistry, biome)) + .forEach(biomesArray::add); + return biomesArray; + } +} diff --git a/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/BlockCollisionShapesDataGenerator.java b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/BlockCollisionShapesDataGenerator.java new file mode 100644 index 0000000..8b9d0e0 --- /dev/null +++ b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/BlockCollisionShapesDataGenerator.java @@ -0,0 +1,113 @@ +package dev.u9g.minecraftdatagenerator.generators; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import dev.u9g.minecraftdatagenerator.util.DGU; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.registry.Registry; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.shape.VoxelShape; +import net.minecraft.world.EmptyBlockView; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class BlockCollisionShapesDataGenerator implements IDataGenerator { + + @Override + public String getDataName() { + return "blockCollisionShapes"; + } + + @Override + public JsonObject generateDataJson() { + Registry blockRegistry = DGU.getWorld().getRegistryManager().get(RegistryKeys.BLOCK); + BlockShapesCache blockShapesCache = new BlockShapesCache(); + + blockRegistry.forEach(blockShapesCache::processBlock); + + JsonObject resultObject = new JsonObject(); + + resultObject.add("blocks", blockShapesCache.dumpBlockShapeIndices(blockRegistry)); + resultObject.add("shapes", blockShapesCache.dumpShapesObject()); + + return resultObject; + } + + private static class BlockShapesCache { + public final Map uniqueBlockShapes = new HashMap<>(); + public final Map> blockCollisionShapes = new HashMap<>(); + private int lastCollisionShapeId = 0; + + public void processBlock(Block block) { + List blockStates = block.getStateManager().getStates(); + List blockCollisionShapes = new ArrayList<>(); + + for (BlockState blockState : blockStates) { + VoxelShape blockShape = blockState.getCollisionShape(EmptyBlockView.INSTANCE, BlockPos.ORIGIN); + Integer blockShapeIndex = uniqueBlockShapes.get(blockShape); + + if (blockShapeIndex == null) { + blockShapeIndex = lastCollisionShapeId++; + uniqueBlockShapes.put(blockShape, blockShapeIndex); + } + blockCollisionShapes.add(blockShapeIndex); + } + + this.blockCollisionShapes.put(block, blockCollisionShapes); + } + + public JsonObject dumpBlockShapeIndices(Registry blockRegistry) { + JsonObject resultObject = new JsonObject(); + + for (var entry : blockCollisionShapes.entrySet()) { + List blockCollisions = entry.getValue(); + long distinctShapesCount = blockCollisions.stream().distinct().count(); + JsonElement blockCollision; + if (distinctShapesCount == 1L) { + blockCollision = new JsonPrimitive(blockCollisions.get(0)); + } else { + blockCollision = new JsonArray(); + for (int collisionId : blockCollisions) { + ((JsonArray) blockCollision).add(collisionId); + } + } + + Identifier registryKey = blockRegistry.getKey(entry.getKey()).orElseThrow().getValue(); + resultObject.add(registryKey.getPath(), blockCollision); + } + + return resultObject; + } + + public JsonObject dumpShapesObject() { + JsonObject shapesObject = new JsonObject(); + + for (var entry : uniqueBlockShapes.entrySet()) { + JsonArray boxesArray = new JsonArray(); + entry.getKey().forEachBox((x1, y1, z1, x2, y2, z2) -> { + JsonArray oneBoxJsonArray = new JsonArray(); + + oneBoxJsonArray.add(x1); + oneBoxJsonArray.add(y1); + oneBoxJsonArray.add(z1); + + oneBoxJsonArray.add(x2); + oneBoxJsonArray.add(y2); + oneBoxJsonArray.add(z2); + + boxesArray.add(oneBoxJsonArray); + }); + shapesObject.add(Integer.toString(entry.getValue()), boxesArray); + } + return shapesObject; + } + } +} diff --git a/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/BlocksDataGenerator.java b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/BlocksDataGenerator.java new file mode 100644 index 0000000..44e8e29 --- /dev/null +++ b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/BlocksDataGenerator.java @@ -0,0 +1,198 @@ +package dev.u9g.minecraftdatagenerator.generators; + +import com.google.common.base.CaseFormat; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import dev.u9g.minecraftdatagenerator.util.DGU; +import net.minecraft.block.AirBlock; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.loot.context.LootContextParameterSet; +import net.minecraft.loot.context.LootContextParameters; +import net.minecraft.registry.Registry; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.state.property.BooleanProperty; +import net.minecraft.state.property.EnumProperty; +import net.minecraft.state.property.IntProperty; +import net.minecraft.state.property.Property; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.shape.VoxelShape; +import net.minecraft.world.EmptyBlockView; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +public class BlocksDataGenerator implements IDataGenerator { + + private static final Logger logger = LoggerFactory.getLogger(BlocksDataGenerator.class); + + private static List getItemsEffectiveForBlock(BlockState blockState) { + return DGU.getWorld().getRegistryManager().get(RegistryKeys.ITEM).stream() + .filter(item -> item.getDefaultStack().isSuitableFor(blockState)) + .collect(Collectors.toList()); + } + + private static void populateDropsIfPossible(BlockState blockState, Item firstToolItem, List outDrops) { + MinecraftServer minecraftServer = DGU.getCurrentlyRunningServer(); + if (minecraftServer != null) { + //If we have local world context, we can actually evaluate loot tables and determine actual data + ServerWorld serverWorld = minecraftServer.getOverworld(); + LootContextParameterSet.Builder lootContextParameterSet = new LootContextParameterSet.Builder(serverWorld) + .add(LootContextParameters.BLOCK_STATE, blockState) + .add(LootContextParameters.ORIGIN, Vec3d.ZERO) + .add(LootContextParameters.TOOL, firstToolItem.getDefaultStack()); + outDrops.addAll(blockState.getDroppedStacks(lootContextParameterSet)); + } else { + //If we're lacking world context to correctly determine drops, assume that default drop is ItemBlock stack in quantity of 1 + Item itemBlock = blockState.getBlock().asItem(); + if (itemBlock != Items.AIR) { + outDrops.add(itemBlock.getDefaultStack()); + } + } + } + + private static String getPropertyTypeName(Property property) { + //Explicitly handle default minecraft properties + if (property instanceof BooleanProperty) { + return "bool"; + } + if (property instanceof IntProperty) { + return "int"; + } + if (property instanceof EnumProperty) { + return "enum"; + } + + //Use simple class name as fallback, this code will give something like + //example_type for ExampleTypeProperty class name + String rawPropertyName = property.getClass().getSimpleName().replace("Property", ""); + return CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, rawPropertyName); + } + + private static > JsonObject generateStateProperty(Property property) { + JsonObject propertyObject = new JsonObject(); + Collection propertyValues = property.getValues(); + + propertyObject.addProperty("name", property.getName()); + propertyObject.addProperty("type", getPropertyTypeName(property)); + propertyObject.addProperty("num_values", propertyValues.size()); + + //Do not add values for vanilla boolean properties, they are known by default + if (!(property instanceof BooleanProperty)) { + JsonArray propertyValuesArray = new JsonArray(); + for (T propertyValue : propertyValues) { + propertyValuesArray.add(property.name(propertyValue)); + } + propertyObject.add("values", propertyValuesArray); + } + return propertyObject; + } + + private static String findMatchingBlockMaterial(BlockState blockState, List materials) { + List matchingMaterials = materials.stream() + .filter(material -> material.getPredicate().test(blockState)) + .collect(Collectors.toList()); + + if (matchingMaterials.size() > 1) { + var firstMaterial = matchingMaterials.get(0); + var otherMaterials = matchingMaterials.subList(1, matchingMaterials.size()); + + if (!otherMaterials.stream().allMatch(firstMaterial::includesMaterial)) { + logger.error("Block {} matches multiple materials: {}", blockState.getBlock(), matchingMaterials); + } + } + if (matchingMaterials.isEmpty()) { + return "default"; + } + return matchingMaterials.get(0).getMaterialName(); + } + + public static JsonObject generateBlock(Registry blockRegistry, List materials, Block block) { + JsonObject blockDesc = new JsonObject(); + + List blockStates = block.getStateManager().getStates(); + BlockState defaultState = block.getDefaultState(); + Identifier registryKey = blockRegistry.getKey(block).orElseThrow().getValue(); + String localizationKey = block.getTranslationKey(); + List effectiveTools = getItemsEffectiveForBlock(defaultState); + + blockDesc.addProperty("id", blockRegistry.getRawId(block)); + blockDesc.addProperty("name", registryKey.getPath()); + blockDesc.addProperty("displayName", DGU.translateText(localizationKey)); + + blockDesc.addProperty("hardness", block.getHardness()); + blockDesc.addProperty("resistance", block.getBlastResistance()); + blockDesc.addProperty("stackSize", block.asItem().getMaxCount()); + blockDesc.addProperty("diggable", block.getHardness() != -1.0f && !(block instanceof AirBlock)); +// JsonObject effTools = new JsonObject(); +// effectiveTools.forEach(item -> effTools.addProperty( +// String.valueOf(Registry.ITEM.getRawId(item)), // key +// item.getMiningSpeedMultiplier(item.getDefaultStack(), defaultState) // value +// )); +// blockDesc.add("effectiveTools", effTools); + blockDesc.addProperty("material", findMatchingBlockMaterial(defaultState, materials)); + + blockDesc.addProperty("transparent", !defaultState.isOpaque()); + blockDesc.addProperty("emitLight", defaultState.getLuminance()); + blockDesc.addProperty("filterLight", defaultState.getOpacity(EmptyBlockView.INSTANCE, BlockPos.ORIGIN)); + + blockDesc.addProperty("defaultState", Block.getRawIdFromState(defaultState)); + blockDesc.addProperty("minStateId", Block.getRawIdFromState(blockStates.get(0))); + blockDesc.addProperty("maxStateId", Block.getRawIdFromState(blockStates.get(blockStates.size() - 1))); + + JsonArray stateProperties = new JsonArray(); + for (Property property : block.getStateManager().getProperties()) { + stateProperties.add(generateStateProperty(property)); + } + blockDesc.add("states", stateProperties); + + //Only add harvest tools if tool is required for harvesting this block + if (defaultState.isToolRequired()) { + JsonObject effectiveToolsObject = new JsonObject(); + for (Item effectiveItem : effectiveTools) { + effectiveToolsObject.addProperty(Integer.toString(Item.getRawId(effectiveItem)), true); + } + blockDesc.add("harvestTools", effectiveToolsObject); + } + + List actualBlockDrops = new ArrayList<>(); + populateDropsIfPossible(defaultState, effectiveTools.isEmpty() ? Items.AIR : effectiveTools.get(0), actualBlockDrops); + + JsonArray dropsArray = new JsonArray(); + for (ItemStack dropStack : actualBlockDrops) { + dropsArray.add(Item.getRawId(dropStack.getItem())); + } + blockDesc.add("drops", dropsArray); + + VoxelShape blockCollisionShape = defaultState.getCollisionShape(EmptyBlockView.INSTANCE, BlockPos.ORIGIN); + blockDesc.addProperty("boundingBox", blockCollisionShape.isEmpty() ? "empty" : "block"); + + return blockDesc; + } + + @Override + public String getDataName() { + return "blocks"; + } + + @Override + public JsonArray generateDataJson() { + JsonArray resultBlocksArray = new JsonArray(); + Registry blockRegistry = DGU.getWorld().getRegistryManager().get(RegistryKeys.BLOCK); + List availableMaterials = MaterialsDataGenerator.getGlobalMaterialInfo(); + + blockRegistry.forEach(block -> resultBlocksArray.add(generateBlock(blockRegistry, availableMaterials, block))); + return resultBlocksArray; + } +} diff --git a/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/DataGenerators.java b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/DataGenerators.java new file mode 100644 index 0000000..c47684a --- /dev/null +++ b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/DataGenerators.java @@ -0,0 +1,77 @@ +package dev.u9g.minecraftdatagenerator.generators; + +import com.google.gson.JsonElement; +import com.google.gson.internal.Streams; +import com.google.gson.stream.JsonWriter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.io.Writer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.List; + +public class DataGenerators { + + private static final Logger logger = LoggerFactory.getLogger(DataGenerators.class); + private static final List GENERATORS = new ArrayList<>(); + + static { + register(new BiomesDataGenerator()); + register(new BlockCollisionShapesDataGenerator()); + register(new BlocksDataGenerator()); + register(new EffectsDataGenerator()); + register(new EnchantmentsDataGenerator()); + register(new EntitiesDataGenerator()); + register(new FoodsDataGenerator()); + register(new ItemsDataGenerator()); + register(new ParticlesDataGenerator()); + register(new TintsDataGenerator()); + register(new MaterialsDataGenerator()); +// register(new RecipeDataGenerator()); - On hold until mcdata supports multiple materials for a recipe + register(new LanguageDataGenerator()); + register(new InstrumentsDataGenerator()); + } + + public static void register(IDataGenerator generator) { + GENERATORS.add(generator); + } + + public static boolean runDataGenerators(Path outputDirectory) { + try { + Files.createDirectories(outputDirectory); + } catch (IOException exception) { + logger.error("Failed to create data generator output directory at {}", outputDirectory, exception); + return false; + } + + int generatorsFailed = 0; + logger.info("Running minecraft data generators, output at {}", outputDirectory); + + for (IDataGenerator dataGenerator : GENERATORS) { + logger.info("Running generator {}", dataGenerator.getDataName()); + try { + String outputFileName = String.format("%s.json", dataGenerator.getDataName()); + JsonElement outputElement = dataGenerator.generateDataJson(); + Path outputFilePath = outputDirectory.resolve(outputFileName); + + try (Writer writer = Files.newBufferedWriter(outputFilePath, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) { + JsonWriter jsonWriter = new JsonWriter(writer); + jsonWriter.setIndent(" "); + Streams.write(outputElement, jsonWriter); + } + logger.info("Generator: {} -> {}", dataGenerator.getDataName(), outputFileName); + + } catch (Throwable exception) { + logger.error("Failed to run data generator {}", dataGenerator.getDataName(), exception); + generatorsFailed++; + } + } + + logger.info("Finishing running data generators"); + return generatorsFailed == 0; + } +} diff --git a/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/EffectsDataGenerator.java b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/EffectsDataGenerator.java new file mode 100644 index 0000000..3c619c3 --- /dev/null +++ b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/EffectsDataGenerator.java @@ -0,0 +1,47 @@ +package dev.u9g.minecraftdatagenerator.generators; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import dev.u9g.minecraftdatagenerator.util.DGU; +import net.minecraft.entity.effect.StatusEffect; +import net.minecraft.entity.effect.StatusEffects; +import net.minecraft.registry.Registry; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.util.Identifier; +import org.apache.commons.lang3.StringUtils; + +import java.util.Arrays; +import java.util.stream.Collectors; + +public class EffectsDataGenerator implements IDataGenerator { + + public static JsonObject generateEffect(Registry registry, StatusEffect statusEffect) { + JsonObject effectDesc = new JsonObject(); + Identifier registryKey = registry.getKey(statusEffect).orElseThrow().getValue(); + + effectDesc.addProperty("id", registry.getRawId(statusEffect)); + if (statusEffect == StatusEffects.UNLUCK) { + effectDesc.addProperty("name", "BadLuck"); + effectDesc.addProperty("displayName", "Bad Luck"); + } else { + effectDesc.addProperty("name", Arrays.stream(registryKey.getPath().split("_")).map(StringUtils::capitalize).collect(Collectors.joining())); + effectDesc.addProperty("displayName", DGU.translateText(statusEffect.getTranslationKey())); + } + + effectDesc.addProperty("type", statusEffect.isBeneficial() ? "good" : "bad"); + return effectDesc; + } + + @Override + public String getDataName() { + return "effects"; + } + + @Override + public JsonArray generateDataJson() { + JsonArray resultsArray = new JsonArray(); + Registry statusEffectRegistry = DGU.getWorld().getRegistryManager().get(RegistryKeys.STATUS_EFFECT); + statusEffectRegistry.forEach(effect -> resultsArray.add(generateEffect(statusEffectRegistry, effect))); + return resultsArray; + } +} diff --git a/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/EnchantmentsDataGenerator.java b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/EnchantmentsDataGenerator.java new file mode 100644 index 0000000..6bd50d7 --- /dev/null +++ b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/EnchantmentsDataGenerator.java @@ -0,0 +1,109 @@ +package dev.u9g.minecraftdatagenerator.generators; + +import com.google.common.collect.ImmutableMap; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import dev.u9g.minecraftdatagenerator.util.DGU; +import net.minecraft.enchantment.Enchantment; +import net.minecraft.enchantment.EnchantmentTarget; +import net.minecraft.registry.Registry; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.util.Identifier; + +import java.util.List; +import java.util.Locale; +import java.util.stream.Collectors; + +public class EnchantmentsDataGenerator implements IDataGenerator { + + private static final ImmutableMap ENCHANTMENT_TARGET_NAMES = ImmutableMap.builder() + .put(EnchantmentTarget.ARMOR, "armor") + .put(EnchantmentTarget.ARMOR_FEET, "armor_feet") + .put(EnchantmentTarget.ARMOR_LEGS, "armor_legs") + .put(EnchantmentTarget.ARMOR_CHEST, "armor_chest") + .put(EnchantmentTarget.ARMOR_HEAD, "armor_head") + .put(EnchantmentTarget.WEAPON, "weapon") + .put(EnchantmentTarget.DIGGER, "digger") + .put(EnchantmentTarget.FISHING_ROD, "fishing_rod") + .put(EnchantmentTarget.TRIDENT, "trident") + .put(EnchantmentTarget.BREAKABLE, "breakable") + .put(EnchantmentTarget.BOW, "bow") + .put(EnchantmentTarget.WEARABLE, "wearable") + .put(EnchantmentTarget.CROSSBOW, "crossbow") + .put(EnchantmentTarget.VANISHABLE, "vanishable") + .build(); + + public static String getEnchantmentTargetName(EnchantmentTarget target) { + return ENCHANTMENT_TARGET_NAMES.getOrDefault(target, target.name().toLowerCase(Locale.ROOT)); + } + + //Equation enchantment costs follow is a * level + b, so we can easily retrieve a and b by passing zero level + private static JsonObject generateEnchantmentMinPowerCoefficients(Enchantment enchantment) { + int b = enchantment.getMinPower(0); + int a = enchantment.getMinPower(1) - b; + + JsonObject resultObject = new JsonObject(); + resultObject.addProperty("a", a); + resultObject.addProperty("b", b); + return resultObject; + } + + private static JsonObject generateEnchantmentMaxPowerCoefficients(Enchantment enchantment) { + int b = enchantment.getMaxPower(0); + int a = enchantment.getMaxPower(1) - b; + + JsonObject resultObject = new JsonObject(); + resultObject.addProperty("a", a); + resultObject.addProperty("b", b); + return resultObject; + } + + public static JsonObject generateEnchantment(Registry registry, Enchantment enchantment) { + JsonObject enchantmentDesc = new JsonObject(); + Identifier registryKey = registry.getKey(enchantment).orElseThrow().getValue(); + + enchantmentDesc.addProperty("id", registry.getRawId(enchantment)); + enchantmentDesc.addProperty("name", registryKey.getPath()); + enchantmentDesc.addProperty("displayName", DGU.translateText(enchantment.getTranslationKey())); + + enchantmentDesc.addProperty("maxLevel", enchantment.getMaxLevel()); + enchantmentDesc.add("minCost", generateEnchantmentMinPowerCoefficients(enchantment)); + enchantmentDesc.add("maxCost", generateEnchantmentMaxPowerCoefficients(enchantment)); + + enchantmentDesc.addProperty("treasureOnly", enchantment.isTreasure()); + enchantmentDesc.addProperty("curse", enchantment.isCursed()); + + List incompatibleEnchantments = registry.stream() + .filter(other -> !enchantment.canCombine(other)) + .filter(other -> other != enchantment) + .toList(); + + JsonArray excludes = new JsonArray(); + for (Enchantment excludedEnchantment : incompatibleEnchantments) { + Identifier otherKey = registry.getKey(excludedEnchantment).orElseThrow().getValue(); + excludes.add(otherKey.getPath()); + } + enchantmentDesc.add("exclude", excludes); + + enchantmentDesc.addProperty("category", getEnchantmentTargetName(enchantment.target)); + enchantmentDesc.addProperty("weight", enchantment.getRarity().getWeight()); + enchantmentDesc.addProperty("tradeable", enchantment.isAvailableForEnchantedBookOffer()); + enchantmentDesc.addProperty("discoverable", enchantment.isAvailableForRandomSelection()); + + return enchantmentDesc; + } + + @Override + public String getDataName() { + return "enchantments"; + } + + @Override + public JsonArray generateDataJson() { + JsonArray resultsArray = new JsonArray(); + Registry enchantmentRegistry = DGU.getWorld().getRegistryManager().get(RegistryKeys.ENCHANTMENT); + enchantmentRegistry.stream() + .forEach(enchantment -> resultsArray.add(generateEnchantment(enchantmentRegistry, enchantment))); + return resultsArray; + } +} diff --git a/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/EntitiesDataGenerator.java b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/EntitiesDataGenerator.java new file mode 100644 index 0000000..50e3516 --- /dev/null +++ b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/EntitiesDataGenerator.java @@ -0,0 +1,126 @@ +package dev.u9g.minecraftdatagenerator.generators; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import dev.u9g.minecraftdatagenerator.mixin.EntityTypeAccessor; +import dev.u9g.minecraftdatagenerator.util.DGU; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.SpawnReason; +import net.minecraft.entity.mob.AmbientEntity; +import net.minecraft.entity.mob.HostileEntity; +import net.minecraft.entity.mob.MobEntity; +import net.minecraft.entity.mob.WaterCreatureEntity; +import net.minecraft.entity.passive.AnimalEntity; +import net.minecraft.entity.passive.PassiveEntity; +import net.minecraft.entity.projectile.ProjectileEntity; +import net.minecraft.registry.Registry; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.registry.tag.TagKey; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.Identifier; + +public class EntitiesDataGenerator implements IDataGenerator { + + public static JsonObject generateEntity(Registry> entityRegistry, EntityType entityType) { + JsonObject entityDesc = new JsonObject(); + Identifier registryKey = entityRegistry.getKey(entityType).orElseThrow().getValue(); + int entityRawId = entityRegistry.getRawId(entityType); + + entityDesc.addProperty("id", entityRawId); + entityDesc.addProperty("internalId", entityRawId); + entityDesc.addProperty("name", registryKey.getPath()); + + entityDesc.addProperty("displayName", DGU.translateText(entityType.getTranslationKey())); + entityDesc.addProperty("width", entityType.getDimensions().width); + entityDesc.addProperty("height", entityType.getDimensions().height); + + String entityTypeString = "UNKNOWN"; + MinecraftServer minecraftServer = DGU.getCurrentlyRunningServer(); + + if (minecraftServer != null) { + Entity entityObject = ((EntityTypeAccessor) entityType).factory().create(entityType, minecraftServer.getOverworld()); + entityTypeString = entityObject != null ? getEntityTypeForClass(entityObject.getClass()) : "unknown"; + } + if(entityType == EntityType.PLAYER){ + entityTypeString = "player"; + } + + entityDesc.addProperty("type", entityTypeString); + entityDesc.addProperty("category", getCategoryFrom(entityType)); + + return entityDesc; + } + + private static String getCategoryFrom(EntityType entityType) { + if (entityType == EntityType.PLAYER) return "UNKNOWN"; // fail early for player entities + /*public T create(World world) { + return this.factory.create(this, world); + }*/ + Entity entity = ((EntityTypeAccessor) entityType).factory().create(entityType, DGU.getWorld()); + if (entity == null) + throw new Error("Entity was null after trying to create a: " + DGU.translateText(entityType.getTranslationKey())); + entity.discard(); + return switch (entity.getClass().getPackageName()) { + case "net.minecraft.entity.decoration", "net.minecraft.entity.decoration.painting" -> "Immobile"; + case "net.minecraft.entity.boss", "net.minecraft.entity.mob", "net.minecraft.entity.boss.dragon" -> + "Hostile mobs"; + case "net.minecraft.entity.projectile", "net.minecraft.entity.projectile.thrown" -> "Projectiles"; + case "net.minecraft.entity.passive" -> "Passive mobs"; + case "net.minecraft.entity.vehicle" -> "Vehicles"; + case "net.minecraft.entity" -> "UNKNOWN"; + default -> throw new Error("Unexpected entity type: " + entity.getClass().getPackageName()); + }; + } + + //Honestly, both "type" and "category" fields in the schema and examples do not contain any useful information + //Since category is optional, I will just leave it out, and for type I will assume general entity classification + //by the Entity class hierarchy (which has some weirdness too by the way) + private static String getEntityTypeForClass(Class entityClass) { + //Top-level classifications + if (WaterCreatureEntity.class.isAssignableFrom(entityClass)) { + return "water_creature"; + } + if (AnimalEntity.class.isAssignableFrom(entityClass)) { + return "animal"; + } + if (HostileEntity.class.isAssignableFrom(entityClass)) { + return "hostile"; + } + if (AmbientEntity.class.isAssignableFrom(entityClass)) { + return "ambient"; + } + + //Second level classifications. PathAwareEntity is not included because it + //doesn't really make much sense to categorize by it + if (PassiveEntity.class.isAssignableFrom(entityClass)) { + return "passive"; + } + if (MobEntity.class.isAssignableFrom(entityClass)) { + return "mob"; + } + + //Other classifications only include living entities and projectiles. everything else is categorized as other + if (LivingEntity.class.isAssignableFrom(entityClass)) { + return "living"; + } + if (ProjectileEntity.class.isAssignableFrom(entityClass)) { + return "projectile"; + } + return "other"; + } + + @Override + public String getDataName() { + return "entities"; + } + + @Override + public JsonArray generateDataJson() { + JsonArray resultArray = new JsonArray(); + Registry> entityTypeRegistry = DGU.getWorld().getRegistryManager().get(RegistryKeys.ENTITY_TYPE); + entityTypeRegistry.forEach(entity -> resultArray.add(generateEntity(entityTypeRegistry, entity))); + return resultArray; + } +} diff --git a/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/FoodsDataGenerator.java b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/FoodsDataGenerator.java new file mode 100644 index 0000000..a5b164f --- /dev/null +++ b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/FoodsDataGenerator.java @@ -0,0 +1,52 @@ +package dev.u9g.minecraftdatagenerator.generators; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import dev.u9g.minecraftdatagenerator.util.DGU; +import net.minecraft.item.FoodComponent; +import net.minecraft.item.Item; +import net.minecraft.registry.Registry; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.util.Identifier; + +import java.util.Objects; + +public class FoodsDataGenerator implements IDataGenerator { + + public static JsonObject generateFoodDescriptor(Registry registry, Item foodItem) { + JsonObject foodDesc = new JsonObject(); + Identifier registryKey = registry.getKey(foodItem).orElseThrow().getValue(); + + foodDesc.addProperty("id", registry.getRawId(foodItem)); + foodDesc.addProperty("name", registryKey.getPath()); + + foodDesc.addProperty("stackSize", foodItem.getMaxCount()); + foodDesc.addProperty("displayName", DGU.translateText(foodItem.getTranslationKey())); + + FoodComponent foodComponent = Objects.requireNonNull(foodItem.getFoodComponent()); + float foodPoints = foodComponent.getHunger(); + float saturationRatio = foodComponent.getSaturationModifier() * 2.0F; + float saturation = foodPoints * saturationRatio; + + foodDesc.addProperty("foodPoints", foodPoints); + foodDesc.addProperty("saturation", saturation); + + foodDesc.addProperty("effectiveQuality", foodPoints + saturation); + foodDesc.addProperty("saturationRatio", saturationRatio); + return foodDesc; + } + + @Override + public String getDataName() { + return "foods"; + } + + public JsonArray generateDataJson() { + JsonArray resultsArray = new JsonArray(); + Registry itemRegistry = DGU.getWorld().getRegistryManager().get(RegistryKeys.ITEM); + itemRegistry.stream() + .filter(Item::isFood) + .forEach(food -> resultsArray.add(generateFoodDescriptor(itemRegistry, food))); + return resultsArray; + } +} diff --git a/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/IDataGenerator.java b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/IDataGenerator.java new file mode 100644 index 0000000..81fe4e2 --- /dev/null +++ b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/IDataGenerator.java @@ -0,0 +1,10 @@ +package dev.u9g.minecraftdatagenerator.generators; + +import com.google.gson.JsonElement; + +public interface IDataGenerator { + + String getDataName(); + + JsonElement generateDataJson(); +} diff --git a/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/InstrumentsDataGenerator.java b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/InstrumentsDataGenerator.java new file mode 100644 index 0000000..e7b9b54 --- /dev/null +++ b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/InstrumentsDataGenerator.java @@ -0,0 +1,25 @@ +package dev.u9g.minecraftdatagenerator.generators; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import net.minecraft.block.enums.Instrument; + +public class InstrumentsDataGenerator implements IDataGenerator { + @Override + public String getDataName() { + return "instruments"; + } + + @Override + public JsonElement generateDataJson() { + JsonArray array = new JsonArray(); + for (Instrument instrument : Instrument.values()) { + JsonObject object = new JsonObject(); + object.addProperty("id", instrument.ordinal()); + object.addProperty("name", instrument.asString()); + array.add(object); + } + return array; + } +} diff --git a/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/ItemsDataGenerator.java b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/ItemsDataGenerator.java new file mode 100644 index 0000000..5402048 --- /dev/null +++ b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/ItemsDataGenerator.java @@ -0,0 +1,82 @@ +package dev.u9g.minecraftdatagenerator.generators; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import dev.u9g.minecraftdatagenerator.util.DGU; +import net.minecraft.enchantment.EnchantmentTarget; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.registry.Registry; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.util.Identifier; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class ItemsDataGenerator implements IDataGenerator { + + private static List calculateItemsToRepairWith(Registry itemRegistry, Item sourceItem) { + ItemStack sourceItemStack = sourceItem.getDefaultStack(); + return itemRegistry.stream() + .filter(otherItem -> sourceItem.canRepair(sourceItemStack, otherItem.getDefaultStack())) + .collect(Collectors.toList()); + } + + private static List getApplicableEnchantmentTargets(Item sourceItem) { + return Arrays.stream(EnchantmentTarget.values()) + .filter(target -> target.isAcceptableItem(sourceItem)) + .collect(Collectors.toList()); + } + + public static JsonObject generateItem(Registry itemRegistry, Item item) { + JsonObject itemDesc = new JsonObject(); + Identifier registryKey = itemRegistry.getKey(item).orElseThrow().getValue(); + + itemDesc.addProperty("id", itemRegistry.getRawId(item)); + itemDesc.addProperty("name", registryKey.getPath()); + + itemDesc.addProperty("displayName", DGU.translateText(item.getTranslationKey())); + itemDesc.addProperty("stackSize", item.getMaxCount()); + + List enchantmentTargets = getApplicableEnchantmentTargets(item); + + JsonArray enchantCategoriesArray = new JsonArray(); + for (EnchantmentTarget target : enchantmentTargets) { + enchantCategoriesArray.add(EnchantmentsDataGenerator.getEnchantmentTargetName(target)); + } + if (enchantCategoriesArray.size() > 0) { + itemDesc.add("enchantCategories", enchantCategoriesArray); + } + + if (item.isDamageable()) { + List repairWithItems = calculateItemsToRepairWith(itemRegistry, item); + + JsonArray fixedWithArray = new JsonArray(); + for (Item repairWithItem : repairWithItems) { + Identifier repairWithName = itemRegistry.getKey(repairWithItem).orElseThrow().getValue(); + fixedWithArray.add(repairWithName.getPath()); + } + if (fixedWithArray.size() > 0) { + itemDesc.add("repairWith", fixedWithArray); + } + + int maxDurability = item.getMaxDamage(); + itemDesc.addProperty("maxDurability", maxDurability); + } + return itemDesc; + } + + @Override + public String getDataName() { + return "items"; + } + + @Override + public JsonArray generateDataJson() { + JsonArray resultArray = new JsonArray(); + Registry itemRegistry = DGU.getWorld().getRegistryManager().get(RegistryKeys.ITEM); + itemRegistry.stream().forEach(item -> resultArray.add(generateItem(itemRegistry, item))); + return resultArray; + } +} diff --git a/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/LanguageDataGenerator.java b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/LanguageDataGenerator.java new file mode 100644 index 0000000..7a3c6ce --- /dev/null +++ b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/LanguageDataGenerator.java @@ -0,0 +1,27 @@ +package dev.u9g.minecraftdatagenerator.generators; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.Objects; + +public class LanguageDataGenerator implements IDataGenerator { + @Override + public String getDataName() { + return "language"; + } + + @Override + public JsonElement generateDataJson() { + try { + InputStream inputStream = Objects.requireNonNull(this.getClass().getResourceAsStream("/assets/minecraft/lang/en_us.json")); + return new Gson().fromJson(new InputStreamReader(inputStream, StandardCharsets.UTF_8), JsonObject.class); + } catch (Exception ignored) { + } + throw new RuntimeException("Failed to generate language file"); + } +} diff --git a/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/MaterialsDataGenerator.java b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/MaterialsDataGenerator.java new file mode 100644 index 0000000..9a5fac1 --- /dev/null +++ b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/MaterialsDataGenerator.java @@ -0,0 +1,200 @@ +package dev.u9g.minecraftdatagenerator.generators; + +import com.google.common.base.Joiner; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import dev.u9g.minecraftdatagenerator.mixin.MiningToolItemAccessor; +import dev.u9g.minecraftdatagenerator.util.DGU; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.item.Item; +import net.minecraft.item.Items; +import net.minecraft.item.MiningToolItem; +import net.minecraft.item.SwordItem; +import net.minecraft.registry.Registry; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.registry.tag.BlockTags; +import net.minecraft.registry.tag.TagKey; + +import java.util.*; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +//TODO entire idea of linking materials to tool speeds is obsolete and just wrong now, +//TODO but we kinda have to support it to let old code work for computing digging times, +//TODO so for now we will handle materials as "virtual" ones based on which tools can break blocks +public class MaterialsDataGenerator implements IDataGenerator { + + private static final List> COMPOSITE_MATERIALS = ImmutableList.>builder() + .add(ImmutableList.of("plant", makeMaterialNameForTag(BlockTags.AXE_MINEABLE))) + .add(ImmutableList.of("gourd", makeMaterialNameForTag(BlockTags.AXE_MINEABLE))) + .add(ImmutableList.of(makeMaterialNameForTag(BlockTags.LEAVES), makeMaterialNameForTag(BlockTags.HOE_MINEABLE))) + .add(ImmutableList.of(makeMaterialNameForTag(BlockTags.LEAVES), makeMaterialNameForTag(BlockTags.AXE_MINEABLE), makeMaterialNameForTag(BlockTags.HOE_MINEABLE))) + .add(ImmutableList.of("vine_or_glow_lichen", "plant", makeMaterialNameForTag(BlockTags.AXE_MINEABLE) + )).build(); + + private static String makeMaterialNameForTag(TagKey tag) { + return tag.id().getPath(); + } + + private static void createCompositeMaterialInfo(List allMaterials, List combinedMaterials) { + String compositeMaterialName = Joiner.on(';').join(combinedMaterials); + + List mappedMaterials = combinedMaterials.stream() + .map(otherName -> allMaterials.stream() + .filter(other -> other.getMaterialName().equals(otherName)) + .findFirst().orElseThrow(() -> new RuntimeException("Material not found with name " + otherName))) + .collect(Collectors.toList()); + + Predicate compositePredicate = blockState -> + mappedMaterials.stream().allMatch(it -> it.getPredicate().test(blockState)); + + MaterialInfo materialInfo = new MaterialInfo(compositeMaterialName, compositePredicate).includes(mappedMaterials); + allMaterials.add(0, materialInfo); + } + + private static void createCompositeMaterial(Map> allMaterials, List combinedMaterials) { + String compositeMaterialName = Joiner.on(';').join(combinedMaterials); + + Map resultingToolSpeeds = new HashMap<>(); + combinedMaterials.stream() + .map(allMaterials::get) + .forEach(resultingToolSpeeds::putAll); + allMaterials.put(compositeMaterialName, resultingToolSpeeds); + } + + public static List getGlobalMaterialInfo() { + ArrayList resultList = new ArrayList<>(); + + resultList.add(new MaterialInfo("vine_or_glow_lichen", blockState -> blockState.isOf(Blocks.VINE) || blockState.isOf(Blocks.GLOW_LICHEN))); + resultList.add(new MaterialInfo("coweb", blockState -> blockState.isOf(Blocks.COBWEB))); + + resultList.add(new MaterialInfo("leaves", blockState -> blockState.isIn(BlockTags.LEAVES))); + resultList.add(new MaterialInfo("wool", blockState -> blockState.isIn(BlockTags.WOOL))); + + // Block Materials were removed in 1.20 in favor of block tags + resultList.add(new MaterialInfo("gourd", blockState -> blockState.isOf(Blocks.MELON) || blockState.isOf(Blocks.PUMPKIN) || blockState.isOf(Blocks.JACK_O_LANTERN))); + // 'sword_efficient' tag is for all plants, and includes everything from the old PLANT and REPLACEABLE_PLANT materials (see https://minecraft.fandom.com/wiki/Tag#Blocks) + resultList.add(new MaterialInfo("plant", blockState -> blockState.isIn(BlockTags.SWORD_EFFICIENT))); + + HashSet uniqueMaterialNames = new HashSet<>(); + + Registry itemRegistry = DGU.getWorld().getRegistryManager().get(RegistryKeys.ITEM); + itemRegistry.forEach(item -> { + if (item instanceof MiningToolItem toolItem) { + TagKey effectiveBlocks = ((MiningToolItemAccessor) toolItem).getEffectiveBlocks(); + String materialName = makeMaterialNameForTag(effectiveBlocks); + + if (!uniqueMaterialNames.contains(materialName)) { + uniqueMaterialNames.add(materialName); + resultList.add(new MaterialInfo(materialName, blockState -> blockState.isIn(effectiveBlocks))); + } + } + }); + + COMPOSITE_MATERIALS.forEach(values -> createCompositeMaterialInfo(resultList, values)); + return resultList; + } + + @Override + public String getDataName() { + return "materials"; + } + + @Override + public JsonElement generateDataJson() { + Registry itemRegistry = DGU.getWorld().getRegistryManager().get(RegistryKeys.ITEM); + + Map> materialMiningSpeeds = new HashMap<>(); + materialMiningSpeeds.put("default", ImmutableMap.of()); + + //Special materials used for shears and swords special mining speed logic + Map leavesMaterialSpeeds = new HashMap<>(); + Map cowebMaterialSpeeds = new HashMap<>(); + Map plantMaterialSpeeds = new HashMap<>(); + Map gourdMaterialSpeeds = new HashMap<>(); + + materialMiningSpeeds.put(makeMaterialNameForTag(BlockTags.LEAVES), leavesMaterialSpeeds); + materialMiningSpeeds.put("coweb", cowebMaterialSpeeds); + materialMiningSpeeds.put("plant", plantMaterialSpeeds); + materialMiningSpeeds.put("gourd", gourdMaterialSpeeds); + + //Shears need special handling because they do not follow normal rules like tools + leavesMaterialSpeeds.put(Items.SHEARS, 15.0f); + cowebMaterialSpeeds.put(Items.SHEARS, 15.0f); + materialMiningSpeeds.put("vine_or_glow_lichen", ImmutableMap.of(Items.SHEARS, 2.0f)); + materialMiningSpeeds.put("wool", ImmutableMap.of(Items.SHEARS, 5.0f)); + + itemRegistry.forEach(item -> { + //Tools are handled rather easily and do not require anything else + if (item instanceof MiningToolItem toolItem) { + TagKey effectiveBlocks = ((MiningToolItemAccessor) toolItem).getEffectiveBlocks(); + String materialName = makeMaterialNameForTag(effectiveBlocks); + + Map materialSpeeds = materialMiningSpeeds.computeIfAbsent(materialName, k -> new HashMap<>()); + float miningSpeed = ((MiningToolItemAccessor) toolItem).getMiningSpeed(); + materialSpeeds.put(item, miningSpeed); + } + + //Swords require special treatment + if (item instanceof SwordItem) { + cowebMaterialSpeeds.put(item, 15.0f); + plantMaterialSpeeds.put(item, 1.5f); + leavesMaterialSpeeds.put(item, 1.5f); + gourdMaterialSpeeds.put(item, 1.5f); + } + }); + + COMPOSITE_MATERIALS.forEach(values -> createCompositeMaterial(materialMiningSpeeds, values)); + + JsonObject resultObject = new JsonObject(); + + for (var entry : materialMiningSpeeds.entrySet()) { + JsonObject toolSpeedsObject = new JsonObject(); + + for (var toolEntry : entry.getValue().entrySet()) { + int rawItemId = itemRegistry.getRawId(toolEntry.getKey()); + toolSpeedsObject.addProperty(Integer.toString(rawItemId), toolEntry.getValue()); + } + resultObject.add(entry.getKey(), toolSpeedsObject); + } + + return resultObject; + } + + public static class MaterialInfo { + private final String materialName; + private final Predicate predicate; + private final List includedMaterials = new ArrayList<>(); + + public MaterialInfo(String materialName, Predicate predicate) { + this.materialName = materialName; + this.predicate = predicate; + } + + protected MaterialInfo includes(List otherMaterials) { + this.includedMaterials.addAll(otherMaterials); + return this; + } + + public String getMaterialName() { + return materialName; + } + + public Predicate getPredicate() { + return predicate; + } + + public boolean includesMaterial(MaterialInfo materialInfo) { + return includedMaterials.contains(materialInfo); + } + + @Override + public String toString() { + return materialName; + } + } +} diff --git a/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/ParticlesDataGenerator.java b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/ParticlesDataGenerator.java new file mode 100644 index 0000000..e446a50 --- /dev/null +++ b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/ParticlesDataGenerator.java @@ -0,0 +1,34 @@ +package dev.u9g.minecraftdatagenerator.generators; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import dev.u9g.minecraftdatagenerator.util.DGU; +import net.minecraft.particle.ParticleType; +import net.minecraft.registry.Registry; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.util.Identifier; + +public class ParticlesDataGenerator implements IDataGenerator { + + public static JsonObject generateParticleType(Registry> registry, ParticleType particleType) { + JsonObject effectDesc = new JsonObject(); + Identifier registryKey = registry.getKey(particleType).orElseThrow().getValue(); + + effectDesc.addProperty("id", registry.getRawId(particleType)); + effectDesc.addProperty("name", registryKey.getPath()); + return effectDesc; + } + + @Override + public String getDataName() { + return "particles"; + } + + @Override + public JsonArray generateDataJson() { + JsonArray resultsArray = new JsonArray(); + Registry> particleTypeRegistry = DGU.getWorld().getRegistryManager().get(RegistryKeys.PARTICLE_TYPE); + particleTypeRegistry.forEach(particleType -> resultsArray.add(generateParticleType(particleTypeRegistry, particleType))); + return resultsArray; + } +} diff --git a/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/RecipeDataGenerator.java b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/RecipeDataGenerator.java new file mode 100644 index 0000000..ea489d1 --- /dev/null +++ b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/RecipeDataGenerator.java @@ -0,0 +1,128 @@ +package dev.u9g.minecraftdatagenerator.generators; + +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Multimap; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import dev.u9g.minecraftdatagenerator.util.DGU; +import net.minecraft.item.Item; +import net.minecraft.recipe.*; +import net.minecraft.registry.DynamicRegistryManager; +import net.minecraft.registry.RegistryKeys; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public class RecipeDataGenerator implements IDataGenerator { + + private static int getRawIdFor(Item item) { + return DGU.getWorld().getRegistryManager().get(RegistryKeys.ITEM).getRawId(item); + } + + @Override + public String getDataName() { + return "recipes"; + } + + @Override + public JsonElement generateDataJson() { + DynamicRegistryManager registryManager = DGU.getWorld().getRegistryManager(); + JsonObject finalObj = new JsonObject(); + Multimap recipes = ArrayListMultimap.create(); + for (RecipeEntry recipeE : Objects.requireNonNull(DGU.getWorld()).getRecipeManager().values()) { + Recipe recipe = recipeE.value(); + if (recipe instanceof ShapedRecipe sr) { + var ingredients = sr.getIngredients(); + List ingr = new ArrayList<>(); + for (int i = 0; i < 9; i++) { + if (i >= ingredients.size()) { + ingr.add(-1); + continue; + } + var stacks = ingredients.get(i); + var matching = stacks.getMatchingStacks(); + if (matching.length == 0) { + ingr.add(-1); + } else { + ingr.add(getRawIdFor(matching[0].getItem())); + } + } + //Lists.reverse(ingr); + + JsonArray inShape = new JsonArray(); + + + var iter = ingr.iterator(); + for (int y = 0; y < sr.getHeight(); y++) { + var jsonRow = new JsonArray(); + for (int z = 0; z < sr.getWidth(); z++) { + jsonRow.add(iter.next()); + } + inShape.add(jsonRow); + } + + JsonObject finalRecipe = new JsonObject(); + finalRecipe.add("inShape", inShape); + + var resultObject = new JsonObject(); + resultObject.addProperty("id", getRawIdFor(sr.getResult(registryManager).getItem())); + resultObject.addProperty("count", sr.getResult(registryManager).getCount()); + finalRecipe.add("result", resultObject); + + String id = ((Integer) getRawIdFor(sr.getResult(registryManager).getItem())).toString(); + + if (!finalObj.has(id)) { + finalObj.add(id, new JsonArray()); + } + finalObj.get(id).getAsJsonArray().add(finalRecipe); +// var input = new JsonArray(); +// var ingredients = sr.getIngredients().stream().toList(); +// for (int y = 0; y < sr.getHeight(); y++) { +// var arr = new JsonArray(); +// for (int x = 0; x < sr.getWidth(); x++) { +// if ((y*3)+x >= ingredients.size()) { +// arr.add(JsonNull.INSTANCE); +// continue; +// } +// var ingredient = ingredients.get((y*3)+x).getMatchingStacks(); // FIXME: fix when there are more than one matching stack +// if (ingredient.length == 0) { +// arr.add(JsonNull.INSTANCE); +// } else { +// arr.add(getRawIdFor(ingredient[0].getItem())); +// } +// } +// input.add(arr); +// } +// var rootRecipeObject = new JsonObject(); +// rootRecipeObject.add("inShape", input); +// var resultObject = new JsonObject(); +// resultObject.addProperty("id", getRawIdFor(sr.getOutput().getItem())); +// resultObject.addProperty("count", sr.getOutput().getCount()); +// rootRecipeObject.add("result", resultObject); +// recipes.put(getRawIdFor(sr.getOutput().getItem()), rootRecipeObject); + } else if (recipe instanceof ShapelessRecipe sl) { + var ingredients = new JsonArray(); + for (Ingredient ingredient : sl.getIngredients()) { + if (ingredient.isEmpty()) continue; + ingredients.add(getRawIdFor(ingredient.getMatchingStacks()[0].getItem())); + } + var rootRecipeObject = new JsonObject(); + rootRecipeObject.add("ingredients", ingredients); + var resultObject = new JsonObject(); + resultObject.addProperty("id", getRawIdFor(sl.getResult(registryManager).getItem())); + resultObject.addProperty("count", sl.getResult(registryManager).getCount()); + rootRecipeObject.add("result", resultObject); + recipes.put(getRawIdFor(sl.getResult(registryManager).getItem()), rootRecipeObject); + } + } + recipes.forEach((a, b) -> { + if (!finalObj.has(a.toString())) { + finalObj.add(a.toString(), new JsonArray()); + } + finalObj.get(a.toString()).getAsJsonArray().add(b); + }); + return finalObj; + } +} diff --git a/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/TintsDataGenerator.java b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/TintsDataGenerator.java new file mode 100644 index 0000000..1f4f96b --- /dev/null +++ b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/generators/TintsDataGenerator.java @@ -0,0 +1,163 @@ +package dev.u9g.minecraftdatagenerator.generators; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import dev.u9g.minecraftdatagenerator.mojangannoyances.BlockColors; +import dev.u9g.minecraftdatagenerator.util.DGU; +import dev.u9g.minecraftdatagenerator.util.EmptyRenderBlockView; +import net.minecraft.block.Block; +import net.minecraft.block.Blocks; +import net.minecraft.block.RedstoneWireBlock; +import net.minecraft.client.color.world.FoliageColors; +import net.minecraft.registry.DynamicRegistryManager; +import net.minecraft.registry.Registry; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.biome.Biome; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class TintsDataGenerator implements IDataGenerator { + + public static BiomeTintColors generateBiomeTintColors(Registry biomeRegistry) { + BiomeTintColors colors = new BiomeTintColors(); + + biomeRegistry.forEach(biome -> { + int biomeGrassColor = biome.getGrassColorAt(0.0, 0.0); + int biomeFoliageColor = biome.getFoliageColor(); + int biomeWaterColor = biome.getWaterColor(); + + colors.grassColoursMap.computeIfAbsent(biomeGrassColor, k -> new ArrayList<>()).add(biome); + colors.foliageColoursMap.computeIfAbsent(biomeFoliageColor, k -> new ArrayList<>()).add(biome); + colors.waterColourMap.computeIfAbsent(biomeWaterColor, k -> new ArrayList<>()).add(biome); + }); + return colors; + } + + public static Map generateRedstoneTintColors() { + Map resultColors = new HashMap<>(); + + for (int redstoneLevel : RedstoneWireBlock.POWER.getValues()) { + int color = RedstoneWireBlock.getWireColor(redstoneLevel); + resultColors.put(redstoneLevel, color); + } + return resultColors; + } + + private static int getBlockColor(Block block, BlockColors blockColors) { + return blockColors.getColor(block.getDefaultState(), EmptyRenderBlockView.INSTANCE, BlockPos.ORIGIN, 0xFFFFFF); + } + + public static Map generateConstantTintColors() { + Map resultColors = new HashMap<>(); + BlockColors blockColors = BlockColors.create(); + + resultColors.put(Blocks.BIRCH_LEAVES, FoliageColors.getBirchColor()); + resultColors.put(Blocks.SPRUCE_LEAVES, FoliageColors.getSpruceColor()); + + resultColors.put(Blocks.LILY_PAD, getBlockColor(Blocks.LILY_PAD, blockColors)); + resultColors.put(Blocks.ATTACHED_MELON_STEM, getBlockColor(Blocks.ATTACHED_MELON_STEM, blockColors)); + resultColors.put(Blocks.ATTACHED_PUMPKIN_STEM, getBlockColor(Blocks.ATTACHED_PUMPKIN_STEM, blockColors)); + + //not really constant, depend on the block age, but kinda have to be handled since textures are literally white without them + resultColors.put(Blocks.MELON_STEM, getBlockColor(Blocks.MELON_STEM, blockColors)); + resultColors.put(Blocks.PUMPKIN_STEM, getBlockColor(Blocks.PUMPKIN_STEM, blockColors)); + + return resultColors; + } + + private static JsonObject encodeBiomeColorMap(Registry biomeRegistry, Map> colorsMap) { + JsonArray resultColorsArray = new JsonArray(); + for (var entry : colorsMap.entrySet()) { + JsonObject entryObject = new JsonObject(); + + JsonArray keysArray = new JsonArray(); + for (Biome biome : entry.getValue()) { + Identifier registryKey = biomeRegistry.getKey(biome).orElseThrow().getValue(); + keysArray.add(registryKey.getPath()); + } + + entryObject.add("keys", keysArray); + entryObject.addProperty("color", entry.getKey()); + resultColorsArray.add(entryObject); + } + + JsonObject resultObject = new JsonObject(); + resultObject.add("data", resultColorsArray); + return resultObject; + } + + private static JsonObject encodeRedstoneColorMap(Map colorsMap) { + JsonArray resultColorsArray = new JsonArray(); + for (var entry : colorsMap.entrySet()) { + JsonObject entryObject = new JsonObject(); + + JsonArray keysArray = new JsonArray(); + keysArray.add(entry.getKey()); + + entryObject.add("keys", keysArray); + entryObject.addProperty("color", entry.getValue()); + resultColorsArray.add(entryObject); + } + + JsonObject resultObject = new JsonObject(); + resultObject.add("data", resultColorsArray); + return resultObject; + } + + private static JsonObject encodeBlocksColorMap(Registry blockRegistry, Map colorsMap) { + JsonArray resultColorsArray = new JsonArray(); + for (var entry : colorsMap.entrySet()) { + JsonObject entryObject = new JsonObject(); + + JsonArray keysArray = new JsonArray(); + Identifier registryKey = blockRegistry.getKey(entry.getKey()).orElseThrow().getValue(); + keysArray.add(registryKey.getPath()); + + entryObject.add("keys", keysArray); + entryObject.addProperty("color", entry.getValue()); + resultColorsArray.add(entryObject); + } + + JsonObject resultObject = new JsonObject(); + resultObject.add("data", resultColorsArray); + return resultObject; + } + + @Override + public String getDataName() { + return "tints"; + } + + @Override + public JsonObject generateDataJson() { + DynamicRegistryManager registryManager = DGU.getWorld().getRegistryManager(); + Registry biomeRegistry = registryManager.get(RegistryKeys.BIOME); + Registry blockRegistry = registryManager.get(RegistryKeys.BLOCK); + + BiomeTintColors biomeTintColors = generateBiomeTintColors(biomeRegistry); + Map redstoneColors = generateRedstoneTintColors(); + Map constantTintColors = generateConstantTintColors(); + + JsonObject resultObject = new JsonObject(); + + resultObject.add("grass", encodeBiomeColorMap(biomeRegistry, biomeTintColors.grassColoursMap)); + resultObject.add("foliage", encodeBiomeColorMap(biomeRegistry, biomeTintColors.foliageColoursMap)); + resultObject.add("water", encodeBiomeColorMap(biomeRegistry, biomeTintColors.waterColourMap)); + + resultObject.add("redstone", encodeRedstoneColorMap(redstoneColors)); + resultObject.add("constant", encodeBlocksColorMap(blockRegistry, constantTintColors)); + + return resultObject; + } + + public static class BiomeTintColors { + final Map> grassColoursMap = new HashMap<>(); + final Map> foliageColoursMap = new HashMap<>(); + final Map> waterColourMap = new HashMap<>(); + } +} diff --git a/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/mixin/EULAMixin.java b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/mixin/EULAMixin.java new file mode 100644 index 0000000..0d297e7 --- /dev/null +++ b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/mixin/EULAMixin.java @@ -0,0 +1,15 @@ +package dev.u9g.minecraftdatagenerator.mixin; + +import net.minecraft.server.dedicated.EulaReader; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(EulaReader.class) +public class EULAMixin { + @Inject(method = "isEulaAgreedTo()Z", at = @At("TAIL"), cancellable = true) + public void init(CallbackInfoReturnable cir) { + cir.setReturnValue(true); + } +} diff --git a/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/mixin/EntityTypeAccessor.java b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/mixin/EntityTypeAccessor.java new file mode 100644 index 0000000..3e62bf5 --- /dev/null +++ b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/mixin/EntityTypeAccessor.java @@ -0,0 +1,12 @@ +package dev.u9g.minecraftdatagenerator.mixin; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(EntityType.class) +public interface EntityTypeAccessor { + @Accessor("factory") + EntityType.EntityFactory factory(); +} diff --git a/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/mixin/MiningToolItemAccessor.java b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/mixin/MiningToolItemAccessor.java new file mode 100644 index 0000000..49cd5d2 --- /dev/null +++ b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/mixin/MiningToolItemAccessor.java @@ -0,0 +1,17 @@ +package dev.u9g.minecraftdatagenerator.mixin; + +import net.minecraft.block.Block; +import net.minecraft.item.MiningToolItem; +import net.minecraft.registry.tag.TagKey; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(MiningToolItem.class) +public interface MiningToolItemAccessor { + + @Accessor + TagKey getEffectiveBlocks(); + + @Accessor + float getMiningSpeed(); +} diff --git a/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/mixin/ReadyMixin.java b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/mixin/ReadyMixin.java new file mode 100644 index 0000000..9cec9cd --- /dev/null +++ b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/mixin/ReadyMixin.java @@ -0,0 +1,28 @@ +package dev.u9g.minecraftdatagenerator.mixin; + +import dev.u9g.minecraftdatagenerator.Main; +import dev.u9g.minecraftdatagenerator.generators.DataGenerators; +import dev.u9g.minecraftdatagenerator.util.DGU; +import net.minecraft.MinecraftVersion; +import net.minecraft.server.dedicated.MinecraftDedicatedServer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.nio.file.Path; + +@Mixin(MinecraftDedicatedServer.class) +public class ReadyMixin { + + @Inject(method = "setupServer()Z", at = @At("TAIL")) + private void init(CallbackInfoReturnable cir) { + Main.LOGGER.info("Starting data generation!"); + String versionName = MinecraftVersion.CURRENT.getName(); + Path serverRootDirectory = DGU.getCurrentlyRunningServer().getRunDirectory().toPath().toAbsolutePath(); + Path dataDumpDirectory = serverRootDirectory.resolve("minecraft-data").resolve(versionName); + DataGenerators.runDataGenerators(dataDumpDirectory); + Main.LOGGER.info("Done data generation!"); + Runtime.getRuntime().halt(0); + } +} diff --git a/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/mixin/TheEndBiomeDataAccessor.java b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/mixin/TheEndBiomeDataAccessor.java new file mode 100644 index 0000000..dc35e0b --- /dev/null +++ b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/mixin/TheEndBiomeDataAccessor.java @@ -0,0 +1,29 @@ +package dev.u9g.minecraftdatagenerator.mixin; + +import net.fabricmc.fabric.impl.biome.TheEndBiomeData; +import net.fabricmc.fabric.impl.biome.WeightedPicker; +import net.minecraft.registry.RegistryKey; +import net.minecraft.world.biome.Biome; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.Map; + + +@Mixin(TheEndBiomeData.class) +public interface TheEndBiomeDataAccessor { + @Accessor(value = "END_BIOMES_MAP", remap = false) + static Map, WeightedPicker>> END_BIOMES_MAP() { + throw new IllegalStateException("Should never be called."); + } + + @Accessor(value = "END_MIDLANDS_MAP", remap = false) + static Map, WeightedPicker>> END_MIDLANDS_MAP() { + throw new IllegalStateException("Should never be called."); + } + + @Accessor(value = "END_BARRENS_MAP", remap = false) + static Map, WeightedPicker>> END_BARRENS_MAP() { + throw new IllegalStateException("Should never be called."); + } +} diff --git a/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/mojangannoyances/BiomeColors.java b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/mojangannoyances/BiomeColors.java new file mode 100644 index 0000000..d374b11 --- /dev/null +++ b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/mojangannoyances/BiomeColors.java @@ -0,0 +1,35 @@ +package dev.u9g.minecraftdatagenerator.mojangannoyances; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.BlockRenderView; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.biome.ColorResolver; + +@Environment(EnvType.CLIENT) +public class BiomeColors { + public static final ColorResolver GRASS_COLOR = Biome::getGrassColorAt; + public static final ColorResolver FOLIAGE_COLOR = (biome, x, z) -> biome.getFoliageColor(); + public static final ColorResolver WATER_COLOR = (biome, x, z) -> biome.getWaterColor(); + + public BiomeColors() { + } + + private static int getColor(BlockRenderView world, BlockPos pos, ColorResolver resolver) { + return world.getColor(pos, resolver); + } + + public static int getGrassColor(BlockRenderView world, BlockPos pos) { + return getColor(world, pos, GRASS_COLOR); + } + + public static int getFoliageColor(BlockRenderView world, BlockPos pos) { + return getColor(world, pos, FOLIAGE_COLOR); + } + + public static int getWaterColor(BlockRenderView world, BlockPos pos) { + return getColor(world, pos, WATER_COLOR); + } +} + diff --git a/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/mojangannoyances/BlockColorProvider.java b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/mojangannoyances/BlockColorProvider.java new file mode 100644 index 0000000..ac5dc57 --- /dev/null +++ b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/mojangannoyances/BlockColorProvider.java @@ -0,0 +1,11 @@ +package dev.u9g.minecraftdatagenerator.mojangannoyances; + +import net.minecraft.block.BlockState; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.BlockRenderView; +import org.jetbrains.annotations.Nullable; + +public interface BlockColorProvider { + int getColor(BlockState state, @Nullable BlockRenderView world, @Nullable BlockPos pos, int tintIndex); +} + diff --git a/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/mojangannoyances/BlockColors.java b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/mojangannoyances/BlockColors.java new file mode 100644 index 0000000..e48e98a --- /dev/null +++ b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/mojangannoyances/BlockColors.java @@ -0,0 +1,94 @@ +package dev.u9g.minecraftdatagenerator.mojangannoyances; + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Maps; +import dev.u9g.minecraftdatagenerator.util.DGU; +import net.minecraft.block.*; +import net.minecraft.block.enums.DoubleBlockHalf; +import net.minecraft.client.color.world.FoliageColors; +import net.minecraft.client.color.world.GrassColors; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.state.property.Property; +import net.minecraft.util.collection.IdList; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.BlockRenderView; +import net.minecraft.world.World; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; +import java.util.Set; + +public class BlockColors { + private static final int NO_COLOR = -1; + private final IdList providers = new IdList<>(32); + private final Map>> properties = Maps.newHashMap(); + + public BlockColors() { + } + + public static BlockColors create() { + BlockColors blockColors = new BlockColors(); + blockColors.registerColorProvider((state, world, pos, tintIndex) -> world != null && pos != null ? BiomeColors.getGrassColor(world, state.get(TallPlantBlock.HALF) == DoubleBlockHalf.UPPER ? pos.down() : pos) : -1, Blocks.LARGE_FERN, Blocks.TALL_GRASS); + blockColors.registerColorProperty(TallPlantBlock.HALF, Blocks.LARGE_FERN, Blocks.TALL_GRASS); + blockColors.registerColorProvider((state, world, pos, tintIndex) -> world != null && pos != null ? BiomeColors.getGrassColor(world, pos) : GrassColors.getColor(0.5, 1.0), Blocks.GRASS_BLOCK, Blocks.FERN, Blocks.SHORT_GRASS, Blocks.POTTED_FERN); + blockColors.registerColorProvider((state, world, pos, tintIndex) -> FoliageColors.getSpruceColor(), Blocks.SPRUCE_LEAVES); + blockColors.registerColorProvider((state, world, pos, tintIndex) -> FoliageColors.getBirchColor(), Blocks.BIRCH_LEAVES); + blockColors.registerColorProvider((state, world, pos, tintIndex) -> world != null && pos != null ? BiomeColors.getFoliageColor(world, pos) : FoliageColors.getDefaultColor(), Blocks.OAK_LEAVES, Blocks.JUNGLE_LEAVES, Blocks.ACACIA_LEAVES, Blocks.DARK_OAK_LEAVES, Blocks.VINE, Blocks.MANGROVE_LEAVES); + blockColors.registerColorProvider((state, world, pos, tintIndex) -> world != null && pos != null ? BiomeColors.getWaterColor(world, pos) : -1, Blocks.WATER, Blocks.BUBBLE_COLUMN, Blocks.WATER_CAULDRON); + blockColors.registerColorProvider((state, world, pos, tintIndex) -> RedstoneWireBlock.getWireColor(state.get(RedstoneWireBlock.POWER)), Blocks.REDSTONE_WIRE); + blockColors.registerColorProperty(RedstoneWireBlock.POWER, Blocks.REDSTONE_WIRE); + blockColors.registerColorProvider((state, world, pos, tintIndex) -> world != null && pos != null ? BiomeColors.getGrassColor(world, pos) : -1, Blocks.SUGAR_CANE); + blockColors.registerColorProvider((state, world, pos, tintIndex) -> 14731036, Blocks.ATTACHED_MELON_STEM, Blocks.ATTACHED_PUMPKIN_STEM); + blockColors.registerColorProvider((state, world, pos, tintIndex) -> { + int i = state.get(StemBlock.AGE); + int j = i * 32; + int k = 255 - i * 8; + int l = i * 4; + return j << 16 | k << 8 | l; + }, Blocks.MELON_STEM, Blocks.PUMPKIN_STEM); + blockColors.registerColorProperty(StemBlock.AGE, Blocks.MELON_STEM, Blocks.PUMPKIN_STEM); + blockColors.registerColorProvider((state, world, pos, tintIndex) -> world != null && pos != null ? 2129968 : 7455580, Blocks.LILY_PAD); + return blockColors; + } + + public int getParticleColor(BlockState state, World world, BlockPos pos) { + BlockColorProvider blockColorProvider = this.providers.get(DGU.getWorld().getRegistryManager().get(RegistryKeys.BLOCK).getRawId(state.getBlock())); + if (blockColorProvider != null) { + return blockColorProvider.getColor(state, null, null, 0); + } else { + MapColor mapColor = state.getMapColor(world, pos); + return mapColor != null ? mapColor.color : -1; + } + } + + public int getColor(BlockState state, @Nullable BlockRenderView world, @Nullable BlockPos pos, int tintIndex) { + BlockColorProvider blockColorProvider = this.providers.get(DGU.getWorld().getRegistryManager().get(RegistryKeys.BLOCK).getRawId(state.getBlock())); + return blockColorProvider == null ? -1 : blockColorProvider.getColor(state, world, pos, tintIndex); + } + + public void registerColorProvider(BlockColorProvider provider, Block... blocks) { + int var4 = blocks.length; + + for (Block block : blocks) { + this.providers.set(provider, DGU.getWorld().getRegistryManager().get(RegistryKeys.BLOCK).getRawId(block)); + } + + } + + private void registerColorProperties(Set> properties, Block... blocks) { + int var4 = blocks.length; + + for (Block block : blocks) { + this.properties.put(block, properties); + } + + } + + private void registerColorProperty(Property property, Block... blocks) { + this.registerColorProperties(ImmutableSet.of(property), blocks); + } + + public Set> getProperties(Block block) { + return this.properties.getOrDefault(block, ImmutableSet.of()); + } +} diff --git a/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/util/DGU.java b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/util/DGU.java new file mode 100644 index 0000000..32c2fb6 --- /dev/null +++ b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/util/DGU.java @@ -0,0 +1,32 @@ +package dev.u9g.minecraftdatagenerator.util; + +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.Language; +import net.minecraft.world.World; + +public class DGU { + + private static final Language language = Language.getInstance(); + + @SuppressWarnings("deprecation") + private static MinecraftServer getCurrentlyRunningServerDedicated() { + return (MinecraftServer) FabricLoader.getInstance().getGameInstance(); + } + + public static MinecraftServer getCurrentlyRunningServer() { + return getCurrentlyRunningServerDedicated(); + } + + private static String translateTextFallback(String translationKey) { + return language.get(translationKey); + } + + public static String translateText(String translationKey) { + return translateTextFallback(translationKey); + } + + public static World getWorld() { + return getCurrentlyRunningServer().getOverworld(); + } +} diff --git a/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/util/EmptyRenderBlockView.java b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/util/EmptyRenderBlockView.java new file mode 100644 index 0000000..460efd8 --- /dev/null +++ b/1.20.4/src/main/java/dev/u9g/minecraftdatagenerator/util/EmptyRenderBlockView.java @@ -0,0 +1,72 @@ +package dev.u9g.minecraftdatagenerator.util; + +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.fluid.FluidState; +import net.minecraft.fluid.Fluids; +import net.minecraft.registry.Registry; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.world.BlockRenderView; +import net.minecraft.world.LightType; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.biome.BiomeKeys; +import net.minecraft.world.biome.ColorResolver; +import net.minecraft.world.chunk.light.LightingProvider; +import org.jetbrains.annotations.Nullable; + +public enum EmptyRenderBlockView implements BlockRenderView { + INSTANCE; + + @Nullable + public BlockEntity getBlockEntity(BlockPos pos) { + return null; + } + + public BlockState getBlockState(BlockPos pos) { + return Blocks.AIR.getDefaultState(); + } + + public FluidState getFluidState(BlockPos pos) { + return Fluids.EMPTY.getDefaultState(); + } + + public int getBottomY() { + return 0; + } + + public int getHeight() { + return 0; + } + + + @Override + public float getBrightness(Direction direction, boolean shaded) { + return 0.0f; + } + + @Override + public LightingProvider getLightingProvider() { + return null; + } + + @Override + public int getColor(BlockPos pos, ColorResolver colorResolver) { + Registry biomeRegistry = DGU.getWorld().getRegistryManager().get(RegistryKeys.BIOME); + Biome plainsBiome = biomeRegistry.get(BiomeKeys.PLAINS); + + return colorResolver.getColor(plainsBiome, pos.getX(), pos.getY()); + } + + @Override + public int getLightLevel(LightType type, BlockPos pos) { + return type == LightType.SKY ? getMaxLightLevel() : 0; + } + + @Override + public int getBaseLightLevel(BlockPos pos, int ambientDarkness) { + return ambientDarkness; + } +} diff --git a/1.20.4/src/main/resources/fabric.mod.json b/1.20.4/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..c999d2a --- /dev/null +++ b/1.20.4/src/main/resources/fabric.mod.json @@ -0,0 +1,27 @@ +{ + "schemaVersion": 1, + "id": "minecraft-data-generator", + "version": "${version}", + "name": "Minecraft Data Generator", + "description": "", + "authors": [ + "Archengius", + "U9G" + ], + "contact": {}, + "license": "MIT", + "environment": "server", + "entrypoints": { + "main": [ + "dev.u9g.minecraftdatagenerator.Main" + ] + }, + "mixins": [ + "minecraft-data-generator.mixins.json" + ], + "depends": { + "fabricloader": ">=0.14.4", + "fabric": "*", + "minecraft": "*" + } +} diff --git a/1.20.4/src/main/resources/minecraft-data-generator.mixins.json b/1.20.4/src/main/resources/minecraft-data-generator.mixins.json new file mode 100644 index 0000000..f3afe06 --- /dev/null +++ b/1.20.4/src/main/resources/minecraft-data-generator.mixins.json @@ -0,0 +1,18 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "dev.u9g.minecraftdatagenerator.mixin", + "compatibilityLevel": "JAVA_17", + "mixins": [ + "EntityTypeAccessor", + "EULAMixin", + "MiningToolItemAccessor", + "ReadyMixin", + "TheEndBiomeDataAccessor" + ], + "client": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/settings.gradle b/settings.gradle index 9609f9b..ab5a196 100644 --- a/settings.gradle +++ b/settings.gradle @@ -46,4 +46,5 @@ dependencyResolutionManagement { "1.19", "1.19.2", "1.20", + "1.20.4", ].forEach { include it }