Add data generation. (#4399)

Recipe and other Data Generators
This commit is contained in:
Eutro
2020-06-02 22:13:49 +01:00
committed by GitHub
parent 1056629545
commit 58afa6539f
139 changed files with 2702 additions and 962 deletions
@@ -0,0 +1,26 @@
package appeng.forge.data.providers;
import appeng.api.definitions.IBlocks;
import appeng.api.definitions.IItems;
import appeng.api.definitions.IMaterials;
import appeng.core.Api;
import appeng.core.AppEng;
import com.google.gson.JsonElement;
import net.minecraft.data.IDataProvider;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.storage.loot.LootParameterSet;
import net.minecraft.world.storage.loot.LootParameterSets;
import net.minecraft.world.storage.loot.LootTable;
import net.minecraft.world.storage.loot.LootTableManager;
import javax.annotation.Nonnull;
import java.nio.file.Path;
public interface IAE2DataProvider extends IDataProvider
{
IBlocks BLOCKS = Api.INSTANCE.definitions().blocks();
IItems ITEMS = Api.INSTANCE.definitions().items();
IMaterials MATERIALS = Api.INSTANCE.definitions().materials();
}
@@ -0,0 +1,97 @@
package appeng.forge.data.providers.loot;
import appeng.core.AppEng;
import appeng.forge.data.providers.IAE2DataProvider;
import com.google.common.collect.ImmutableMap;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import net.minecraft.block.Block;
import net.minecraft.data.DirectoryCache;
import net.minecraft.data.IDataProvider;
import net.minecraft.data.loot.BlockLootTables;
import net.minecraft.item.Items;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.storage.loot.*;
import net.minecraft.world.storage.loot.conditions.SurvivesExplosion;
import net.minecraftforge.fml.event.lifecycle.GatherDataEvent;
import net.minecraftforge.registries.ForgeRegistries;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Map;
import java.util.function.Function;
public class BlockDropProvider extends BlockLootTables implements IAE2DataProvider
{
private Map<Block, Function<Block, LootTable.Builder>> overrides = ImmutableMap.<Block, Function<Block, LootTable.Builder>>builder()
.put( BLOCKS.matrixFrame().block(), $ -> LootTable.builder() )
.put( BLOCKS.quartzOre().block(), b -> droppingItemWithFortune( b, Items.QUARTZ ) ) // FIXME replace with the material reference
.put( BLOCKS.quartzOreCharged().block(), b -> droppingItemWithFortune( b, Items.LAPIS_LAZULI ) ) // FIXME replace with the material reference
.build();
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
private final Path outputFolder;
public BlockDropProvider( GatherDataEvent dataEvent )
{
outputFolder = dataEvent.getGenerator().getOutputFolder();
}
@Override
public void act( @Nonnull DirectoryCache cache ) throws IOException
{
for( Map.Entry<ResourceLocation, Block> entry : ForgeRegistries.BLOCKS.getEntries() )
{
LootTable.Builder builder;
if( entry.getKey().getNamespace().equals( AppEng.MOD_ID ) )
{
builder = overrides.getOrDefault( entry.getValue(), this::defaultBuilder )
.apply( entry.getValue() );
IDataProvider.save( GSON, cache, toJson( builder ), getPath( outputFolder, entry.getKey() ) );
}
}
}
private LootTable.Builder defaultBuilder( Block block )
{
LootEntry.Builder<?> entry = ItemLootEntry.builder( block );
LootPool.Builder pool = LootPool.builder()
.name( "main" )
.rolls( ConstantRange.of( 1 ) )
.addEntry( entry )
.acceptCondition( SurvivesExplosion.builder() );
return LootTable.builder()
.addLootPool( pool );
}
private Path getPath( Path root, ResourceLocation id )
{
return root.resolve( "data/" + id.getNamespace() + "/loot_tables/blocks/" + id.getPath() + ".json" );
}
public JsonElement toJson( LootTable.Builder builder )
{
return LootTableManager.toJson( finishBuilding( builder ) );
}
@Nonnull
public LootTable finishBuilding( LootTable.Builder builder )
{
return builder.setParameterSet( LootParameterSets.BLOCK ).build();
}
@Nonnull
@Override
public String getName()
{
return AppEng.MOD_NAME + " Block Drops";
}
}
@@ -0,0 +1,137 @@
package appeng.forge.data.providers.recipes;
import appeng.api.definitions.IItemDefinition;
import appeng.core.AppEng;
import appeng.forge.data.providers.IAE2DataProvider;
import appeng.recipes.conditions.FeaturesEnabled;
import com.google.common.collect.ImmutableMap;
import it.unimi.dsi.fastutil.chars.Char2ObjectArrayMap;
import it.unimi.dsi.fastutil.chars.Char2ObjectMap;
import it.unimi.dsi.fastutil.chars.CharOpenHashSet;
import it.unimi.dsi.fastutil.chars.CharSet;
import net.minecraft.data.DataGenerator;
import net.minecraft.data.IFinishedRecipe;
import net.minecraft.data.RecipeProvider;
import net.minecraft.data.ShapedRecipeBuilder;
import net.minecraft.item.Item;
import net.minecraft.tags.Tag;
import net.minecraftforge.common.Tags;
import net.minecraftforge.common.crafting.ConditionalRecipe;
import javax.annotation.Nonnull;
import java.util.Map;
import java.util.function.Consumer;
public class QuartzToolRecipes extends RecipeProvider implements IAE2DataProvider
{
private Map<net.minecraft.tags.Tag<Item>, IItemDefinition[]> items = ImmutableMap.of(
Tags.Items.GEMS_QUARTZ,
new IItemDefinition[] {
ITEMS.netherQuartzAxe(),
ITEMS.netherQuartzHoe(),
ITEMS.netherQuartzShovel(),
ITEMS.netherQuartzPick(),
ITEMS.netherQuartzSword(),
ITEMS.netherQuartzWrench(),
ITEMS.netherQuartzKnife()
}
// FIXME certus quartz
);
private String[][] patterns = {
{
"XX ",
"X/ ",
" / "
},
{
"XX ",
" / ",
" / "
},
{
" X ",
" / ",
" / "
},
{
"XXX",
" / ",
" / "
},
{
" X ",
" X ",
" / "
},
{
"X X",
" X ",
"X X"
},
{
" /",
"I/ ",
"XX "
}
};
private Char2ObjectMap<Tag<Item>> keys = new Char2ObjectArrayMap<>(
new char[] { 'I', '/' },
new Tag[] { Tags.Items.INGOTS_IRON, Tags.Items.RODS_WOODEN }
);
public QuartzToolRecipes( DataGenerator generatorIn )
{
super( generatorIn );
}
@Override
protected void registerRecipes( @Nonnull Consumer<IFinishedRecipe> consumer )
{
for( Map.Entry<Tag<Item>, IItemDefinition[]> entry : items.entrySet() )
{
Tag<Item> tag = entry.getKey();
IItemDefinition[] tools = entry.getValue();
for( int i = 0; i < tools.length; i++ )
{
CharSet keySet = new CharOpenHashSet( new char[] { 'X', ' ' } );
ShapedRecipeBuilder shapedBuilder = ShapedRecipeBuilder.shapedRecipe( tools[i].item() );
for( String s : patterns[i] )
{
shapedBuilder.patternLine( s );
for( int j = 0; j < s.length(); j++ )
{
char c = s.charAt( j );
if( !keySet.contains( c ) )
{
keySet.add( c );
shapedBuilder.key( c, keys.get( c ) );
}
}
}
shapedBuilder.key( 'X', tag )
.addCriterion( "has_" + tag.getId(), hasItem( tag ) );
ConditionalRecipe.builder()
.addCondition( new FeaturesEnabled( tools[i].features() ) )
.addRecipe( shapedBuilder::build )
.build( consumer, AppEng.MOD_ID, "tools/" + tools[i].identifier() );
}
}
}
@Override public String getName()
{
return AppEng.MOD_NAME + " Quartz Tools";
}
}
@@ -0,0 +1,117 @@
package appeng.forge.data.providers.recipes;
import appeng.api.definitions.IBlockDefinition;
import appeng.core.AppEng;
import appeng.forge.data.providers.IAE2DataProvider;
import appeng.recipes.conditions.FeaturesEnabled;
import com.google.common.collect.Sets;
import net.minecraft.block.Block;
import net.minecraft.data.*;
import net.minecraft.item.crafting.Ingredient;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.common.crafting.ConditionalRecipe;
import javax.annotation.Nonnull;
import java.nio.file.Path;
import java.util.function.Consumer;
public class SlabStairRecipes extends RecipeProvider implements IAE2DataProvider
{
IBlockDefinition[][] blocks = {
{ BLOCKS.skyStoneBlock(), BLOCKS.skyStoneSlab(), BLOCKS.skyStoneStairs() },
{ BLOCKS.smoothSkyStoneBlock(), BLOCKS.smoothSkyStoneSlab(), BLOCKS.smoothSkyStoneStairs() },
{ BLOCKS.skyStoneBrick(), BLOCKS.skyStoneBrickSlab(), BLOCKS.skyStoneBrickStairs() },
{ BLOCKS.skyStoneSmallBrick(), BLOCKS.skyStoneSmallBrickSlab(), BLOCKS.skyStoneSmallBrickStairs() },
{ BLOCKS.fluixBlock(), BLOCKS.fluixSlab(), BLOCKS.fluixStairs() },
{ BLOCKS.quartzBlock(), BLOCKS.quartzSlab(), BLOCKS.quartzStairs() },
{ BLOCKS.chiseledQuartzBlock(), BLOCKS.chiseledQuartzSlab(), BLOCKS.chiseledQuartzStairs() },
{ BLOCKS.quartzPillar(), BLOCKS.quartzPillarSlab(), BLOCKS.quartzPillarStairs() },
};
public SlabStairRecipes( DataGenerator generatorIn )
{
super( generatorIn );
}
@Override
public void registerRecipes( @Nonnull Consumer<IFinishedRecipe> consumer )
{
for( IBlockDefinition[] block : blocks )
{
slabRecipe( consumer, block[0], block[1] );
stairRecipe( consumer, block[0], block[2] );
}
}
private void slabRecipe( Consumer<IFinishedRecipe> consumer, IBlockDefinition block, IBlockDefinition slabs )
{
Block inputBlock = block.block();
Block outputBlock = slabs.block();
FeaturesEnabled condition = new FeaturesEnabled( Sets.union( block.features(), slabs.features() ) );
ConditionalRecipe.builder()
.addCondition( condition )
.addRecipe(
ShapedRecipeBuilder.shapedRecipe( slabs.block(), 6 )
.patternLine( "###" )
.key( '#', inputBlock )
.addCriterion( criterionName( block ), hasItem( inputBlock ) )
::build
)
.build( consumer, AppEng.MOD_ID, "slabs/" + block.identifier() );
ConditionalRecipe.builder()
.addCondition( condition )
.addRecipe(
c -> SingleItemRecipeBuilder.stonecuttingRecipe( Ingredient.fromItems( inputBlock ), outputBlock, 2 )
.addCriterion( criterionName( block ), hasItem( inputBlock ) )
.build( c, new ResourceLocation( AppEng.MOD_ID, slabs.identifier() ) )
)
.build( consumer, AppEng.MOD_ID, "slabs/block_cutter/" + block.identifier() );
}
private void stairRecipe( Consumer<IFinishedRecipe> consumer, IBlockDefinition block, IBlockDefinition stairs )
{
Block inputBlock = block.block();
Block outputBlock = stairs.block();
FeaturesEnabled condition = new FeaturesEnabled( Sets.union( block.features(), stairs.features() ) );
ConditionalRecipe.builder()
.addCondition( condition )
.addRecipe(
ShapedRecipeBuilder.shapedRecipe( outputBlock, 4 )
.patternLine( "# " )
.patternLine( "## " )
.patternLine( "###" )
.key( '#', inputBlock )
.addCriterion( criterionName( block ), hasItem( inputBlock ) )
::build
)
.build( consumer, AppEng.MOD_ID, "stairs/" + block.identifier() );
ConditionalRecipe.builder()
.addCondition( condition )
.addRecipe(
c -> SingleItemRecipeBuilder.stonecuttingRecipe( Ingredient.fromItems( inputBlock ), outputBlock )
.addCriterion( criterionName( block ), hasItem( inputBlock ) )
.build( c, new ResourceLocation( AppEng.MOD_ID, stairs.identifier() ) )
)
.build( consumer, AppEng.MOD_ID, "stairs/block_cutter/" + block.identifier() );
}
private String criterionName( IBlockDefinition block )
{
return String.format( "has_%s", block.identifier() );
}
@Override public String getName()
{
return AppEng.MOD_NAME + " Slabs and Stairs";
}
}
@@ -0,0 +1,92 @@
package appeng.forge.data.providers.recipes;
import appeng.core.AppEng;
import appeng.forge.data.providers.IAE2DataProvider;
import com.google.gson.JsonObject;
import net.minecraft.data.DataGenerator;
import net.minecraft.data.IFinishedRecipe;
import net.minecraft.data.RecipeProvider;
import net.minecraft.item.crafting.IRecipeSerializer;
import net.minecraft.util.ResourceLocation;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Objects;
import java.util.function.Consumer;
public class SpecialRecipes extends RecipeProvider implements IAE2DataProvider
{
public SpecialRecipes( DataGenerator generatorIn )
{
super( generatorIn );
}
@Override
protected void registerRecipes( @Nonnull Consumer<IFinishedRecipe> consumer )
{
// ConditionalRecipe.builder() FIXME this works, but NPEs at runtime
// .addCondition( new FeaturesEnabled( AEFeature.ENABLE_DISASSEMBLY_CRAFTING ) )
// .addRecipe( new FinishedRecipe( DisassembleRecipe.SERIALIZER ) )
// .build( consumer, AppEng.MOD_ID, "special/disassemble" );
// ConditionalRecipe.builder() FIXME re-implement facades
// .addCondition( new FeaturesEnabled( AEFeature.ENABLE_FACADE_CRAFTING ) )
// .addRecipe( new FinishedRecipe( FacadeRecipe.SERIALIZER ) )
// .build( consumer, AppEng.MOD_ID, "special/facade" );
}
private static class FinishedRecipe implements IFinishedRecipe
{
private final IRecipeSerializer<?> serializer;
public FinishedRecipe( IRecipeSerializer<?> serializer )
{
this.serializer = serializer;
}
@Override public void serialize( @Nonnull JsonObject json )
{
}
@Nonnull
@Override
public ResourceLocation getID()
{
return Objects.requireNonNull( serializer.getRegistryName() );
}
@Nonnull
@Override
public IRecipeSerializer<?> getSerializer()
{
return serializer;
}
@Nullable
@Override
public JsonObject getAdvancementJson()
{
return null;
}
@Nullable
@Override
public ResourceLocation getAdvancementID()
{
return null;
}
}
@Nonnull
@Override
public String getName()
{
return AppEng.MOD_NAME + " Special Crafting Recipes";
}
}