Recipe wrappers

+ General system for wrapping recipes
+ Wrappers for both shaped and shapeless recipes, include OreDict
replacement things
+ Actual crafting is not supported
This commit is contained in:
Emmanuel BENOîT 2016-07-16 14:09:00 +02:00
parent 6935b01458
commit 8361ecb417
13 changed files with 591 additions and 0 deletions

View file

@ -5,6 +5,7 @@ import mmm.core.CProxyCommon;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.SidedProxy; import net.minecraftforge.fml.common.SidedProxy;
import net.minecraftforge.fml.common.event.FMLInitializationEvent; import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
@ -44,4 +45,11 @@ public class Mmm
Mmm.proxy.init( event ); Mmm.proxy.init( event );
} }
@Mod.EventHandler
public void postInit( FMLPostInitializationEvent event )
{
Mmm.proxy.postInit( event );
}
} }

View file

@ -6,7 +6,9 @@ import mmm.MmmFood;
import mmm.MmmMaterials; import mmm.MmmMaterials;
import mmm.MmmTech; import mmm.MmmTech;
import mmm.MmmWorld; import mmm.MmmWorld;
import mmm.recipes.RCraftingWrappers;
import net.minecraftforge.fml.common.event.FMLInitializationEvent; import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
@ -16,6 +18,7 @@ public class CProxyCommon
public void preInit( final FMLPreInitializationEvent event ) public void preInit( final FMLPreInitializationEvent event )
{ {
RCraftingWrappers.preInit( );
CAccessors.preInit( ); CAccessors.preInit( );
MmmMaterials.preInit( ); MmmMaterials.preInit( );
@ -34,4 +37,10 @@ public class CProxyCommon
MmmDeco.init( ); MmmDeco.init( );
} }
public void postInit( final FMLPostInitializationEvent event )
{
RCraftingWrappers.wrapRecipes( );
}
} }

View file

@ -0,0 +1,26 @@
package mmm.core.api.recipes;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
public interface I_CraftingRecipeWrapper
{
public String getName( );
public ItemStack getOutput( );
public void addInputsToDisplay( IInventory displayInventory );
public boolean canCraft( IInventory inventory );
public void craft( IInventory input , IInventory output , int quantity );
}

View file

@ -0,0 +1,17 @@
package mmm.core.api.recipes;
import java.util.List;
import net.minecraft.item.crafting.IRecipe;
public interface I_CraftingRecipeWrapperFactory
{
public Class< ? extends IRecipe > getRecipeClass( );
public List< I_CraftingRecipeWrapper > createWrappers( IRecipe recipe );
}

View file

@ -0,0 +1,56 @@
package mmm.recipes;
import java.util.ArrayList;
import java.util.HashMap;
import mmm.core.api.recipes.I_CraftingRecipeWrapper;
import mmm.core.api.recipes.I_CraftingRecipeWrapperFactory;
import net.minecraft.item.crafting.CraftingManager;
import net.minecraft.item.crafting.IRecipe;
public class RCraftingWrappers
{
private static final HashMap< Class< ? > , I_CraftingRecipeWrapperFactory > FACTORIES = new HashMap<>( );
private static final ArrayList< I_CraftingRecipeWrapper > RECIPES = new ArrayList<>( );
public static void register( final I_CraftingRecipeWrapperFactory factory )
{
final Class< ? extends IRecipe > rc = factory.getRecipeClass( );
if ( RCraftingWrappers.FACTORIES.containsKey( rc ) ) {
throw new IllegalArgumentException( "duplicate recipe wrapper factory for type " + rc );
}
RCraftingWrappers.FACTORIES.put( rc , factory );
}
public static void wrapRecipes( )
{
if ( !RCraftingWrappers.RECIPES.isEmpty( ) ) {
throw new IllegalStateException( "already initialized" );
}
for ( final IRecipe recipe : CraftingManager.getInstance( ).getRecipeList( ) ) {
final I_CraftingRecipeWrapperFactory factory = RCraftingWrappers.FACTORIES.get( recipe.getClass( ) );
if ( factory == null ) {
System.err.println( "unsupported recipe class " + recipe.getClass( ) );
continue;
}
RCraftingWrappers.RECIPES.addAll( factory.createWrappers( recipe ) );
}
System.err.println( "wrapped " + RCraftingWrappers.RECIPES.size( ) + " recipes" );
}
public static void preInit( )
{
RCraftingWrappers.register( new RShapelessRecipeWrapperFactory( ) );
RCraftingWrappers.register( new RShapelessOreRecipeWrapperFactory( ) );
RCraftingWrappers.register( new RShapedRecipeWrapperFactory( ) );
RCraftingWrappers.register( new RShapedOreRecipeWrapperFactory( ) );
}
}

View file

@ -0,0 +1,83 @@
package mmm.recipes;
import java.util.List;
import mmm.core.api.recipes.I_CraftingRecipeWrapper;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fml.common.ObfuscationReflectionHelper;
import net.minecraftforge.oredict.ShapedOreRecipe;
public class RShapedOreRecipeWrapper
implements I_CraftingRecipeWrapper
{
private final ShapedOreRecipe recipe;
private final int width;
private final int height;
public RShapedOreRecipeWrapper( final ShapedOreRecipe recipe )
{
this.recipe = recipe;
this.width = ObfuscationReflectionHelper.getPrivateValue( ShapedOreRecipe.class , this.recipe , "width" );
this.height = ObfuscationReflectionHelper.getPrivateValue( ShapedOreRecipe.class , this.recipe , "height" );
}
@Override
public String getName( )
{
return this.recipe.getRecipeOutput( ).getUnlocalizedName( );
}
@Override
public ItemStack getOutput( )
{
return this.recipe.getRecipeOutput( );
}
@Override
public void addInputsToDisplay( final IInventory displayInventory )
{
final Object[] input = this.recipe.getInput( );
for ( int i = 0 ; i < this.width ; i++ ) {
for ( int j = 0 ; j < this.height ; j++ ) {
final Object inObj = input[ i + j * this.width ];
if ( inObj instanceof ItemStack ) {
displayInventory.setInventorySlotContents( i + j * 3 , ( (ItemStack) inObj ).copy( ) );
} else if ( inObj instanceof List ) {
@SuppressWarnings( "unchecked" )
final List< ItemStack > oreList = (List< ItemStack >) inObj;
if ( oreList.isEmpty( ) ) {
continue;
}
displayInventory.setInventorySlotContents( i + j * 3 , oreList.get( 0 ).copy( ) );
}
}
}
}
@Override
public boolean canCraft( final IInventory inventory )
{
// TODO Auto-generated method stub
return false;
}
@Override
public void craft( final IInventory input , final IInventory output , final int quantity )
{
// TODO Auto-generated method stub
}
}

View file

@ -0,0 +1,32 @@
package mmm.recipes;
import java.util.Arrays;
import java.util.List;
import mmm.core.api.recipes.I_CraftingRecipeWrapper;
import mmm.core.api.recipes.I_CraftingRecipeWrapperFactory;
import net.minecraft.item.crafting.IRecipe;
import net.minecraftforge.oredict.ShapedOreRecipe;
public class RShapedOreRecipeWrapperFactory
implements I_CraftingRecipeWrapperFactory
{
@Override
public Class< ? extends IRecipe > getRecipeClass( )
{
return ShapedOreRecipe.class;
}
@Override
public List< I_CraftingRecipeWrapper > createWrappers( final IRecipe recipe )
{
final ShapedOreRecipe r = (ShapedOreRecipe) recipe;
return Arrays.asList( new RShapedOreRecipeWrapper( r ) );
}
}

View file

@ -0,0 +1,66 @@
package mmm.recipes;
import mmm.core.api.recipes.I_CraftingRecipeWrapper;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.ShapedRecipes;
public class RShapedRecipeWrapper
implements I_CraftingRecipeWrapper
{
private final ShapedRecipes recipe;
public RShapedRecipeWrapper( final ShapedRecipes recipe )
{
this.recipe = recipe;
}
@Override
public String getName( )
{
return this.recipe.getRecipeOutput( ).getUnlocalizedName( );
}
@Override
public ItemStack getOutput( )
{
return this.recipe.getRecipeOutput( );
}
@Override
public void addInputsToDisplay( final IInventory displayInventory )
{
for ( int i = 0 ; i < this.recipe.recipeWidth ; i++ ) {
for ( int j = 0 ; j < this.recipe.recipeHeight ; j++ ) {
ItemStack itemStack = this.recipe.recipeItems[ i + j * this.recipe.recipeWidth ];
if ( itemStack != null ) {
displayInventory.setInventorySlotContents( i + j * 3 , itemStack.copy( ) );
}
}
}
}
@Override
public boolean canCraft( final IInventory inventory )
{
// TODO Auto-generated method stub
return false;
}
@Override
public void craft( final IInventory input , final IInventory output , final int quantity )
{
// TODO Auto-generated method stub
}
}

View file

@ -0,0 +1,36 @@
package mmm.recipes;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import mmm.core.api.recipes.I_CraftingRecipeWrapper;
import mmm.core.api.recipes.I_CraftingRecipeWrapperFactory;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.item.crafting.ShapedRecipes;
public class RShapedRecipeWrapperFactory
implements I_CraftingRecipeWrapperFactory
{
@Override
public Class< ? extends IRecipe > getRecipeClass( )
{
return ShapedRecipes.class;
}
@Override
public List< I_CraftingRecipeWrapper > createWrappers( IRecipe recipe )
{
ShapedRecipes r = (ShapedRecipes) recipe;
if ( r.recipeHeight > 3 || r.recipeWidth > 3 ) {
return Collections.emptyList( );
}
return Arrays.asList( new RShapedRecipeWrapper( r ) );
}
}

View file

@ -0,0 +1,100 @@
package mmm.recipes;
import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.List;
import mmm.core.api.recipes.I_CraftingRecipeWrapper;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraftforge.oredict.OreDictionary;
import net.minecraftforge.oredict.ShapelessOreRecipe;
public class RShapelessOreRecipeWrapper
implements I_CraftingRecipeWrapper
{
private final ShapelessOreRecipe recipe;
private final List< ItemStack > combinedInputStacks;
private final IdentityHashMap< List< ItemStack > , Integer > combinedInputOreLists;
public RShapelessOreRecipeWrapper( final ShapelessOreRecipe recipe )
{
this.recipe = recipe;
this.combinedInputStacks = new ArrayList<>( );
this.combinedInputOreLists = new IdentityHashMap<>( );
OUTER: for ( final Object input : this.recipe.getInput( ) ) {
if ( input instanceof ItemStack ) {
final ItemStack invStack = (ItemStack) input;
for ( final ItemStack ciStack : this.combinedInputStacks ) {
if ( OreDictionary.itemMatches( ciStack , invStack , true ) ) {
ciStack.stackSize += invStack.stackSize;
continue OUTER;
}
}
this.combinedInputStacks.add( invStack.copy( ) );
} else if ( input instanceof List ) {
@SuppressWarnings( "unchecked" )
final List< ItemStack > oreList = (List< ItemStack >) input;
if ( this.combinedInputOreLists.containsKey( oreList ) ) {
this.combinedInputOreLists.put( oreList , this.combinedInputOreLists.get( oreList ) + 1 );
} else {
this.combinedInputOreLists.put( oreList , 1 );
}
}
}
}
@Override
public String getName( )
{
return this.recipe.getRecipeOutput( ).getUnlocalizedName( );
}
@Override
public ItemStack getOutput( )
{
return this.recipe.getRecipeOutput( );
}
@Override
public void addInputsToDisplay( final IInventory displayInventory )
{
int i = 0;
for ( final ItemStack stack : this.combinedInputStacks ) {
displayInventory.setInventorySlotContents( i++ , stack.copy( ) );
}
for ( final List< ItemStack > oreList : this.combinedInputOreLists.keySet( ) ) {
if ( oreList.isEmpty( ) ) {
continue;
}
final ItemStack stack = oreList.get( 0 ).copy( );
stack.stackSize = this.combinedInputOreLists.get( oreList );
displayInventory.setInventorySlotContents( i++ , stack );
}
}
@Override
public boolean canCraft( final IInventory inventory )
{
// TODO Auto-generated method stub
return false;
}
@Override
public void craft( final IInventory input , final IInventory output , final int quantity )
{
// TODO Auto-generated method stub
}
}

View file

@ -0,0 +1,31 @@
package mmm.recipes;
import java.util.Arrays;
import java.util.List;
import mmm.core.api.recipes.I_CraftingRecipeWrapper;
import mmm.core.api.recipes.I_CraftingRecipeWrapperFactory;
import net.minecraft.item.crafting.IRecipe;
import net.minecraftforge.oredict.ShapelessOreRecipe;
public class RShapelessOreRecipeWrapperFactory
implements I_CraftingRecipeWrapperFactory
{
@Override
public Class< ? extends IRecipe > getRecipeClass( )
{
return ShapelessOreRecipe.class;
}
@Override
public List< I_CraftingRecipeWrapper > createWrappers( final IRecipe recipe )
{
return Arrays.asList( new RShapelessOreRecipeWrapper( (ShapelessOreRecipe) recipe ) );
}
}

View file

@ -0,0 +1,95 @@
package mmm.recipes;
import java.util.ArrayList;
import java.util.List;
import mmm.core.api.recipes.I_CraftingRecipeWrapper;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.ShapelessRecipes;
import net.minecraftforge.oredict.OreDictionary;
public class RShapelessRecipeWrapper
implements I_CraftingRecipeWrapper
{
private final ShapelessRecipes recipe;
private final List< ItemStack > combinedInputs;
public RShapelessRecipeWrapper( final ShapelessRecipes recipe )
{
this.recipe = recipe;
this.combinedInputs = new ArrayList<>( );
OUTER: for ( final ItemStack invStack : this.recipe.recipeItems ) {
for ( final ItemStack ciStack : this.combinedInputs ) {
if ( OreDictionary.itemMatches( ciStack , invStack , true ) ) {
ciStack.stackSize += invStack.stackSize;
continue OUTER;
}
}
this.combinedInputs.add( invStack.copy( ) );
}
}
@Override
public String getName( )
{
return this.recipe.getRecipeOutput( ).getUnlocalizedName( );
}
@Override
public ItemStack getOutput( )
{
return this.recipe.getRecipeOutput( );
}
@Override
public void addInputsToDisplay( final IInventory displayInventory )
{
int i = 0;
for ( final ItemStack stack : this.combinedInputs ) {
displayInventory.setInventorySlotContents( i++ , stack.copy( ) );
}
}
@Override
public boolean canCraft( final IInventory inventory )
{
final int nInputs = this.combinedInputs.size( );
final int nInvItems = inventory.getSizeInventory( );
for ( int i = 0 ; i < nInputs ; i++ ) {
final ItemStack rStack = this.combinedInputs.get( i );
int nLeft = rStack.stackSize;
for ( int j = 0 ; j < nInvItems && nLeft > 0 ; j++ ) {
final ItemStack invStack = inventory.getStackInSlot( j );
if ( OreDictionary.itemMatches( rStack , invStack , false ) ) {
nLeft -= invStack.stackSize;
}
}
if ( nLeft > 0 ) {
return false;
}
}
return true;
}
@Override
public void craft( final IInventory input , final IInventory output , final int quantity )
{
// TODO Auto-generated method stub
}
}

View file

@ -0,0 +1,32 @@
package mmm.recipes;
import mmm.core.api.recipes.I_CraftingRecipeWrapperFactory;
import java.util.Arrays;
import java.util.List;
import mmm.core.api.recipes.I_CraftingRecipeWrapper;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.item.crafting.ShapelessRecipes;
public class RShapelessRecipeWrapperFactory
implements I_CraftingRecipeWrapperFactory
{
@Override
public Class< ShapelessRecipes > getRecipeClass( )
{
return ShapelessRecipes.class;
}
@Override
public List< I_CraftingRecipeWrapper > createWrappers( final IRecipe recipe )
{
return Arrays.asList( new RShapelessRecipeWrapper( (ShapelessRecipes) recipe ) );
}
}