Workbench progress

+ More recipe abstraction
+ Bugfixes
+ Red cross when there are not enough ingredients
This commit is contained in:
Emmanuel BENOîT 2016-07-17 14:08:23 +02:00
parent 1c8932193c
commit 218a93ef9f
13 changed files with 325 additions and 134 deletions

Binary file not shown.

Binary file not shown.

View file

@ -20,9 +20,6 @@ public interface I_CraftingRecipeWrapper
public void addInputsToDisplay( IInventory displayInventory ); public void addInputsToDisplay( IInventory displayInventory );
public boolean canCraft( IInventory inventory ); public I_RecipeRequirements getRequirements( );
public void craft( IInventory input , IInventory output , int quantity );
} }

View file

@ -0,0 +1,28 @@
package mmm.core.api.recipes;
import java.util.List;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
public interface I_RecipeRequirements
{
int size( );
int getQuantity( int pos );
List< ItemStack > getItemTypes( int pos );
boolean checkItemStack( int pos , ItemStack stack );
boolean checkInventory( IInventory inventory );
}

View file

@ -0,0 +1,65 @@
package mmm.recipes;
import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import net.minecraft.item.ItemStack;
import net.minecraftforge.oredict.OreDictionary;
class ROreRecipeHelper
{
static RRequirements extractRequirements( final Object[] recipe )
{
final List< ItemStack > combinedInputStacks = new ArrayList<>( );
final IdentityHashMap< List< ItemStack > , Integer > combinedInputOreLists = new IdentityHashMap<>( );
ROreRecipeHelper.extractInputs( recipe , combinedInputStacks , combinedInputOreLists );
final RRequirements reqs = new RRequirements( combinedInputStacks.size( ) + combinedInputOreLists.size( ) );
int i;
for ( i = 0 ; i < combinedInputStacks.size( ) ; i++ ) {
final ItemStack stack = combinedInputStacks.get( i );
reqs.put( i , stack , stack.stackSize );
}
for ( final Map.Entry< List< ItemStack > , Integer > entry : combinedInputOreLists.entrySet( ) ) {
reqs.put( i++ , entry.getKey( ) , entry.getValue( ) );
}
return reqs;
}
private static void extractInputs( final Object[] recipe , final List< ItemStack > combinedInputStacks ,
final IdentityHashMap< List< ItemStack > , Integer > combinedInputOreLists )
{
OUTER: for ( final Object input : recipe ) {
if ( input instanceof ItemStack ) {
final ItemStack invStack = (ItemStack) input;
for ( final ItemStack ciStack : combinedInputStacks ) {
if ( OreDictionary.itemMatches( ciStack , invStack , true ) ) {
ciStack.stackSize ++;
continue OUTER;
}
}
ItemStack ciStack = invStack.copy( );
ciStack.stackSize = 1;
combinedInputStacks.add( ciStack );
} else if ( input instanceof List ) {
@SuppressWarnings( "unchecked" )
final List< ItemStack > oreList = (List< ItemStack >) input;
if ( combinedInputOreLists.containsKey( oreList ) ) {
combinedInputOreLists.put( oreList , combinedInputOreLists.get( oreList ) + 1 );
} else {
combinedInputOreLists.put( oreList , 1 );
}
}
}
}
}

View file

@ -0,0 +1,111 @@
package mmm.recipes;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import mmm.core.api.recipes.I_RecipeRequirements;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraftforge.oredict.OreDictionary;
class RRequirements
implements I_RecipeRequirements
{
private final List< ItemStack >[] itemTypes;
private final int[] quantities;
@SuppressWarnings( "unchecked" )
RRequirements( final int nInputs )
{
this.itemTypes = new List[ nInputs ];
this.quantities = new int[ nInputs ];
}
RRequirements( final ArrayList< ItemStack > inputs )
{
this( inputs.size( ) );
for ( int i = 0 ; i < this.quantities.length ; i++ ) {
final ItemStack input = inputs.get( i );
this.put( i , input , input.stackSize );
}
}
void put( final int pos , final ItemStack stack , final int quantity )
{
this.itemTypes[ pos ] = Arrays.asList( stack );
this.quantities[ pos ] = quantity;
}
void put( final int pos , final List< ItemStack > stacks , final int quantity )
{
assert stacks != null;
this.itemTypes[ pos ] = stacks;
this.quantities[ pos ] = quantity;
}
@Override
public int size( )
{
return this.quantities.length;
}
@Override
public int getQuantity( final int pos )
{
return this.quantities[ pos ];
}
@Override
public List< ItemStack > getItemTypes( final int pos )
{
return this.itemTypes[ pos ];
}
@Override
public boolean checkItemStack( final int pos , final ItemStack stack )
{
if ( stack != null ) {
for ( final ItemStack target : this.getItemTypes( pos ) ) {
if ( OreDictionary.itemMatches( target , stack , false ) ) {
return true;
}
}
}
return false;
}
@Override
public boolean checkInventory( final IInventory inventory )
{
final int nInvItems = inventory.getSizeInventory( );
for ( int i = 0 ; i < this.quantities.length ; i++ ) {
int nLeft = this.quantities[ i ];
for ( int j = 0 ; j < nInvItems && nLeft > 0 ; j++ ) {
final ItemStack invStack = inventory.getStackInSlot( j );
if ( this.checkItemStack( i , invStack ) ) {
nLeft -= invStack.stackSize;
}
}
if ( nLeft > 0 ) {
return false;
}
}
return true;
}
}

View file

@ -4,6 +4,7 @@ package mmm.recipes;
import java.util.List; import java.util.List;
import mmm.core.api.recipes.I_CraftingRecipeWrapper; import mmm.core.api.recipes.I_CraftingRecipeWrapper;
import mmm.core.api.recipes.I_RecipeRequirements;
import net.minecraft.inventory.IInventory; import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraftforge.fml.common.ObfuscationReflectionHelper; import net.minecraftforge.fml.common.ObfuscationReflectionHelper;
@ -18,6 +19,7 @@ public class RShapedOreRecipeWrapper
private final ShapedOreRecipe recipe; private final ShapedOreRecipe recipe;
private final int width; private final int width;
private final int height; private final int height;
private final RRequirements requirements;
public RShapedOreRecipeWrapper( final ShapedOreRecipe recipe ) public RShapedOreRecipeWrapper( final ShapedOreRecipe recipe )
@ -25,6 +27,7 @@ public class RShapedOreRecipeWrapper
this.recipe = recipe; this.recipe = recipe;
this.width = ObfuscationReflectionHelper.getPrivateValue( ShapedOreRecipe.class , this.recipe , "width" ); this.width = ObfuscationReflectionHelper.getPrivateValue( ShapedOreRecipe.class , this.recipe , "width" );
this.height = ObfuscationReflectionHelper.getPrivateValue( ShapedOreRecipe.class , this.recipe , "height" ); this.height = ObfuscationReflectionHelper.getPrivateValue( ShapedOreRecipe.class , this.recipe , "height" );
this.requirements = ROreRecipeHelper.extractRequirements( recipe.getInput( ) );
} }
@ -103,18 +106,9 @@ public class RShapedOreRecipeWrapper
@Override @Override
public boolean canCraft( final IInventory inventory ) public I_RecipeRequirements getRequirements( )
{ {
// TODO Auto-generated method stub return this.requirements;
return false;
}
@Override
public void craft( final IInventory input , final IInventory output , final int quantity )
{
// TODO Auto-generated method stub
} }
} }

View file

@ -1,7 +1,10 @@
package mmm.recipes; package mmm.recipes;
import java.util.ArrayList;
import mmm.core.api.recipes.I_CraftingRecipeWrapper; import mmm.core.api.recipes.I_CraftingRecipeWrapper;
import mmm.core.api.recipes.I_RecipeRequirements;
import net.minecraft.inventory.IInventory; import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.ShapedRecipes; import net.minecraft.item.crafting.ShapedRecipes;
@ -13,11 +16,40 @@ public class RShapedRecipeWrapper
implements I_CraftingRecipeWrapper implements I_CraftingRecipeWrapper
{ {
private final ShapedRecipes recipe; private final ShapedRecipes recipe;
private final RRequirements requirements;
public RShapedRecipeWrapper( final ShapedRecipes recipe ) public RShapedRecipeWrapper( final ShapedRecipes recipe )
{ {
this.recipe = recipe; this.recipe = recipe;
this.requirements = new RRequirements( extractInputs( recipe ) );
}
private static ArrayList< ItemStack > extractInputs( final ShapedRecipes recipe )
{
ArrayList< ItemStack > inputs = new ArrayList<>( );
for ( int i = 0 ; i < recipe.recipeWidth ; i++ ) {
RECIPE: for ( int j = 0 ; j < recipe.recipeHeight ; j++ ) {
ItemStack itemStack = recipe.recipeItems[ i + j * recipe.recipeWidth ];
if ( itemStack == null ) {
continue;
}
for ( int k = 0 ; k < inputs.size( ) ; k++ ) {
ItemStack input = inputs.get( k );
if ( OreDictionary.itemMatches( input , itemStack , true ) ) {
input.stackSize++;
continue RECIPE;
}
}
itemStack = itemStack.copy( );
itemStack.stackSize = 1;
inputs.add( itemStack );
}
}
return inputs;
} }
@ -72,23 +104,17 @@ public class RShapedRecipeWrapper
} else { } else {
stack = stack.copy( ); stack = stack.copy( );
} }
stack.stackSize = 1;
inventory.setInventorySlotContents( index , stack ); inventory.setInventorySlotContents( index , stack );
} }
@Override
public boolean canCraft( final IInventory inventory )
{
// TODO Auto-generated method stub
return false;
}
@Override @Override
public void craft( final IInventory input , final IInventory output , final int quantity ) public I_RecipeRequirements getRequirements( )
{ {
// TODO Auto-generated method stub return this.requirements;
} }
} }

View file

@ -2,10 +2,10 @@ package mmm.recipes;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.List; import java.util.List;
import mmm.core.api.recipes.I_CraftingRecipeWrapper; import mmm.core.api.recipes.I_CraftingRecipeWrapper;
import mmm.core.api.recipes.I_RecipeRequirements;
import net.minecraft.inventory.IInventory; import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraftforge.oredict.OreDictionary; import net.minecraftforge.oredict.OreDictionary;
@ -17,36 +17,13 @@ public class RShapelessOreRecipeWrapper
implements I_CraftingRecipeWrapper implements I_CraftingRecipeWrapper
{ {
private final ShapelessOreRecipe recipe; private final ShapelessOreRecipe recipe;
private final List< ItemStack > combinedInputStacks; private final RRequirements requirements;
private final IdentityHashMap< List< ItemStack > , Integer > combinedInputOreLists;
public RShapelessOreRecipeWrapper( final ShapelessOreRecipe recipe ) public RShapelessOreRecipeWrapper( final ShapelessOreRecipe recipe )
{ {
this.recipe = recipe; this.recipe = recipe;
this.combinedInputStacks = new ArrayList<>( ); this.requirements = ROreRecipeHelper.extractRequirements( recipe.getInput( ).toArray( ) );
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 );
}
}
}
} }
@ -92,47 +69,23 @@ public class RShapelessOreRecipeWrapper
@Override @Override
public void addInputsToDisplay( final IInventory displayInventory ) public void addInputsToDisplay( final IInventory displayInventory )
{ {
int i = 0; for ( int i = 0 ; i < this.requirements.size( ) ; i++ ) {
for ( final ItemStack stack : this.combinedInputStacks ) { ItemStack stack = this.requirements.getItemTypes( i ).get( 0 );
RShapelessOreRecipeWrapper.setSlot( displayInventory , i++ , stack , stack.stackSize ); if ( stack.getMetadata( ) == OreDictionary.WILDCARD_VALUE ) {
} stack = new ItemStack( stack.getItem( ) , 1 , 0 );
for ( final List< ItemStack > oreList : this.combinedInputOreLists.keySet( ) ) { } else {
if ( oreList.isEmpty( ) ) { stack = stack.copy( );
continue;
} }
stack.stackSize = this.requirements.getQuantity( i );
final ItemStack stack = oreList.get( 0 ); displayInventory.setInventorySlotContents( i , stack );
RShapelessOreRecipeWrapper.setSlot( displayInventory , i++ , stack ,
this.combinedInputOreLists.get( oreList ) );
} }
} }
private static void setSlot( final IInventory inventory , final int index , ItemStack stack , final int size )
{
if ( stack.getMetadata( ) == OreDictionary.WILDCARD_VALUE ) {
stack = new ItemStack( stack.getItem( ) , 1 , 0 );
} else {
stack = stack.copy( );
}
stack.stackSize = size;
inventory.setInventorySlotContents( index , stack );
}
@Override @Override
public boolean canCraft( final IInventory inventory ) public I_RecipeRequirements getRequirements( )
{ {
// TODO Auto-generated method stub return this.requirements;
return false;
}
@Override
public void craft( final IInventory input , final IInventory output , final int quantity )
{
// TODO Auto-generated method stub
} }
} }

View file

@ -2,9 +2,9 @@ package mmm.recipes;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import mmm.core.api.recipes.I_CraftingRecipeWrapper; import mmm.core.api.recipes.I_CraftingRecipeWrapper;
import mmm.core.api.recipes.I_RecipeRequirements;
import net.minecraft.inventory.IInventory; import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.ShapelessRecipes; import net.minecraft.item.crafting.ShapelessRecipes;
@ -17,23 +17,29 @@ public class RShapelessRecipeWrapper
{ {
private final ShapelessRecipes recipe; private final ShapelessRecipes recipe;
private final List< ItemStack > combinedInputs; private final RRequirements requirements;
public RShapelessRecipeWrapper( final ShapelessRecipes recipe ) public RShapelessRecipeWrapper( final ShapelessRecipes recipe )
{ {
this.recipe = recipe; this.recipe = recipe;
this.requirements = new RRequirements( RShapelessRecipeWrapper.extractInputs( recipe ) );
}
this.combinedInputs = new ArrayList<>( );
OUTER: for ( final ItemStack invStack : this.recipe.recipeItems ) { private static ArrayList< ItemStack > extractInputs( final ShapelessRecipes recipe )
for ( final ItemStack ciStack : this.combinedInputs ) { {
final ArrayList< ItemStack > combinedInputs = new ArrayList<>( );
OUTER: for ( final ItemStack invStack : recipe.recipeItems ) {
for ( final ItemStack ciStack : combinedInputs ) {
if ( OreDictionary.itemMatches( ciStack , invStack , true ) ) { if ( OreDictionary.itemMatches( ciStack , invStack , true ) ) {
ciStack.stackSize += invStack.stackSize; ciStack.stackSize += invStack.stackSize;
continue OUTER; continue OUTER;
} }
} }
this.combinedInputs.add( invStack.copy( ) ); combinedInputs.add( invStack.copy( ) );
} }
return combinedInputs;
} }
@ -70,58 +76,23 @@ public class RShapelessRecipeWrapper
@Override @Override
public void addInputsToDisplay( final IInventory displayInventory ) public void addInputsToDisplay( final IInventory displayInventory )
{ {
int i = 0; for ( int i = 0 ; i < this.requirements.size( ) ; i++ ) {
for ( ItemStack stack : this.combinedInputs ) { ItemStack stack = this.requirements.getItemTypes( i ).get( 0 );
if ( stack.getMetadata( ) == OreDictionary.WILDCARD_VALUE ) { if ( stack.getMetadata( ) == OreDictionary.WILDCARD_VALUE ) {
stack = new ItemStack( stack.getItem( ) , 1 , 0 ); stack = new ItemStack( stack.getItem( ) , 1 , 0 );
} else { } else {
stack = stack.copy( ); stack = stack.copy( );
} }
RShapelessRecipeWrapper.setSlot( displayInventory , i++ , stack ); stack.stackSize = this.requirements.getQuantity( i );
displayInventory.setInventorySlotContents( i , stack );
} }
} }
private static void setSlot( final IInventory inventory , final int index , ItemStack stack )
{
if ( stack.getMetadata( ) == OreDictionary.WILDCARD_VALUE ) {
stack = new ItemStack( stack.getItem( ) , 1 , 0 );
} else {
stack = stack.copy( );
}
inventory.setInventorySlotContents( index , stack );
}
@Override @Override
public boolean canCraft( final IInventory inventory ) public I_RecipeRequirements getRequirements( )
{ {
final int nInputs = this.combinedInputs.size( ); return this.requirements;
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

@ -8,14 +8,18 @@ import java.util.List;
import mmm.Mmm; import mmm.Mmm;
import mmm.core.CNetwork; import mmm.core.CNetwork;
import mmm.core.api.recipes.I_CraftingRecipeWrapper; import mmm.core.api.recipes.I_CraftingRecipeWrapper;
import mmm.core.api.recipes.I_RecipeRequirements;
import mmm.recipes.RCraftingWrappers; import mmm.recipes.RCraftingWrappers;
import mmm.utils.gui.A_UGContainerScreen; import mmm.utils.gui.A_UGContainerScreen;
import mmm.utils.gui.UGArrowButton; import mmm.utils.gui.UGArrowButton;
import mmm.utils.gui.UGui;
import mmm.utils.gui.UGui.E_Icon;
import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiTextField; import net.minecraft.client.gui.GuiTextField;
import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.resources.I18n; import net.minecraft.client.resources.I18n;
import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly; import net.minecraftforge.fml.relauncher.SideOnly;
@ -87,6 +91,18 @@ public class TBWBGui
this.mc.getTextureManager( ).bindTexture( TBWBGui.BACKGROUND ); this.mc.getTextureManager( ).bindTexture( TBWBGui.BACKGROUND );
this.drawTexturedModalRect( this.guiLeft , this.guiTop , 0 , 0 , this.xSize , this.ySize ); this.drawTexturedModalRect( this.guiLeft , this.guiTop , 0 , 0 , this.xSize , this.ySize );
boolean canCraft;
if ( this.currentRecipe == -1 ) {
canCraft = false;
} else {
TileEntity te = this.container.world.getTileEntity( this.container.position );
I_RecipeRequirements requirements = this.recipes.get( this.currentRecipe ).getRequirements( );
canCraft = te instanceof TBWBTileEntity && requirements.checkInventory( ( (TBWBTileEntity) te ).storage );
}
if ( !canCraft ) {
UGui.drawIcon( this , this.guiLeft + 147 , this.guiTop + 51 , E_Icon.RED_CROSS );
}
GlStateManager.disableBlend( ); GlStateManager.disableBlend( );
this.tfSearch.drawTextBox( ); this.tfSearch.drawTextBox( );
} }

View file

@ -1,12 +1,35 @@
package mmm.utils.gui; package mmm.utils.gui;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Gui;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
public enum UGui { public class UGui
INSTANCE; {
public static enum E_Icon {
RED_CROSS( 26 , 30 , 13 , 13 ),
//
;
public final int x;
public final int y;
public final int width;
public final int height;
private E_Icon( final int x , final int y , final int w , final int h )
{
this.x = x;
this.y = y;
this.width = w;
this.height = h;
}
}
public static final int TAB_TEXTURE_X = 0; public static final int TAB_TEXTURE_X = 0;
public static final int TAB_TEXTURE_Y = 0; public static final int TAB_TEXTURE_Y = 0;
@ -26,4 +49,11 @@ public enum UGui {
public static final ResourceLocation GUI_TEXTURE = new ResourceLocation( "mmm" , "textures/gui/gui-common.png" ); public static final ResourceLocation GUI_TEXTURE = new ResourceLocation( "mmm" , "textures/gui/gui-common.png" );
@SideOnly( Side.CLIENT )
public static void drawIcon( final Gui gui , final int x , final int y , final E_Icon icon )
{
Minecraft.getMinecraft( ).getTextureManager( ).bindTexture( UGui.GUI_TEXTURE );
gui.drawTexturedModalRect( x , y , icon.x , icon.y , icon.width , icon.height );
}
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB