Closes #1054: Adds an Inscriber API for Developers

This commit is contained in:
thatsIch 2015-04-05 20:16:02 +02:00
parent 1bb8de3570
commit 06bca227d0
19 changed files with 904 additions and 187 deletions

View file

@ -0,0 +1,65 @@
package appeng.api.features;
import java.util.List;
import javax.annotation.Nonnull;
import net.minecraft.item.ItemStack;
import com.google.common.base.Optional;
/**
* Registration Records for {@link IInscriberRegistry}
*
* You have to pay attention though, that recipes are not mirrored,
* where the top and bottom slots are switching places.
*
* This is applied on runtime.
*
* @author thatsIch
* @version rv2
* @since rv2
*/
public interface IInscriberRecipe
{
/**
* the current inputs
*
* @return inputs the inscriber will accept
*/
@Nonnull
List<ItemStack> getInputs();
/**
* gets the current output
*
* @return output that the recipe will produce
*/
@Nonnull
ItemStack getOutput();
/**
* gets the top optional
*
* @return item which is used top
*/
@Nonnull
Optional<ItemStack> getTopOptional();
/**
* gets the bottom optional
*
* @return item which is used bottom
*/
@Nonnull
Optional<ItemStack> getBottomOptional();
/**
* type of inscriber process
*
* @return type of process the inscriber is doing
*/
@Nonnull
InscriberProcessType getProcessType();
}

View file

@ -0,0 +1,88 @@
package appeng.api.features;
import java.util.Collection;
import javax.annotation.Nonnull;
import net.minecraft.item.ItemStack;
/**
* Builder for an inscriber recipe
*
* @author thatsIch
* @version rv2
* @since rv2
*/
public interface IInscriberRecipeBuilder
{
/**
* Creates an inscriber recipe with inputs.
* Needs to be invoked.
*
* @param inputs new inputs for the recipe
*
* @return currently used builder
*/
@Nonnull
IInscriberRecipeBuilder withInputs( @Nonnull Collection<ItemStack> inputs );
/**
* Creates an inscriber recipe with output.
* Needs to be invoked.
*
* @param output new output for the recipe
*
* @return currently used builder
*/
@Nonnull
IInscriberRecipeBuilder withOutput( @Nonnull ItemStack output );
/**
* Creates an inscriber recipe with top.
* Either this or bot needs to be invoked.
*
* @param topOptional new top for the recipe
*
* @return currently used builder
*/
@Nonnull
IInscriberRecipeBuilder withTopOptional( @Nonnull ItemStack topOptional );
/**
* Creates an inscriber recipe with bot.
* Either this or top needs to be invoked.
*
* @param bottomOptional new bot for the recipe
*
* @return currently used builder
*/
@Nonnull
IInscriberRecipeBuilder withBottomOptional( @Nonnull ItemStack bottomOptional );
/**
* Creates an inscriber recipe with type.
* Needs to be invoked.
*
* @param type new type for the recipe
*
* @return currently used builder
*/
@Nonnull
IInscriberRecipeBuilder withProcessType( @Nonnull InscriberProcessType type );
/**
* Finalizes the process of making the recipe.
* Needs to be invoked to fetch inscriber recipe.
*
* @return legal inscriber recipe
*
* @throws IllegalStateException when input is not defined
* @throws IllegalStateException when input has no size
* @throws IllegalStateException when output is not defined
* @throws IllegalStateException when both optionals are not defined
* @throws IllegalStateException when process type is not defined
*/
@Nonnull
IInscriberRecipe build();
}

View file

@ -0,0 +1,69 @@
package appeng.api.features;
import java.util.List;
import java.util.Set;
import javax.annotation.Nonnull;
import net.minecraft.item.ItemStack;
/**
* Lets you manipulate Inscriber Recipes, by adding or editing existing ones.
*
* @author thatsIch
* @version rv2
* @since rv2
*/
public interface IInscriberRegistry
{
/**
* Current list of registered recipes, you can modify this if you want too.
* Will never contain a null recipe
*
* @return currentlyRegisteredRecipes
*/
@Nonnull
List<IInscriberRecipe> getRecipes();
/**
* Optional items which are used in the top or bottom slot
*
* @return set of all optional items
*/
@Nonnull
Set<ItemStack> getOptionals();
/**
* Get all registered items which are valid inputs
*
* @return set of all input items
*/
@Nonnull
Set<ItemStack> getInputs();
/**
* Extensible way to create an inscriber recipe
*
* @return builder for inscriber recipes
*/
@Nonnull
IInscriberRecipeBuilder builder();
/**
* add a new recipe the easy way, duplicates will not be added.
* Added recipes will be automatically added to the optionals and inputs.
*
* @param recipe new recipe
*
* @throws IllegalArgumentException if null is added
*/
void addRecipe( IInscriberRecipe recipe );
/**
* Removes a recipe from the registry
*
* @param toBeRemovedRecipe to be removed recipe, can be null, makes just no sense
*/
void removeRecipe( IInscriberRecipe toBeRemovedRecipe );
}

View file

@ -30,6 +30,12 @@ import appeng.api.storage.ICellRegistry;
import appeng.api.storage.IExternalStorageRegistry;
/**
* @author AlgorithmX2
* @author thatsIch
* @version rv2
* @since rv0
*/
public interface IRegistryContainer
{
@ -69,6 +75,11 @@ public interface IRegistryContainer
*/
IGrinderRegistry grinder();
/**
* Manage inscriber recipes via API
*/
IInscriberRegistry inscriber();
/**
* get access to the locatable registry
*/

View file

@ -0,0 +1,15 @@
package appeng.api.features;
public enum InscriberProcessType
{
/**
* uses the optionals as catalyst
*/
Inscribe,
/**
* spends the optionals
*/
Press
}

View file

@ -36,18 +36,24 @@ import net.minecraft.world.IBlockAccess;
import net.minecraftforge.client.IItemRenderer.ItemRenderType;
import net.minecraftforge.common.util.ForgeDirection;
import appeng.api.features.IInscriberRecipe;
import appeng.api.util.IOrientable;
import appeng.block.AEBaseBlock;
import appeng.block.misc.BlockInscriber;
import appeng.client.render.BaseBlockRender;
import appeng.client.texture.ExtraBlockTextures;
import appeng.core.AELog;
import appeng.recipes.handlers.Inscribe.InscriberRecipe;
import appeng.tile.AEBaseTile;
import appeng.tile.misc.TileInscriber;
import appeng.util.Platform;
/**
* @author AlgorithmX2
* @author thatsIch
* @version rv2
* @since rv0
*/
public class RenderBlockInscriber extends BaseBlockRender
{
@ -225,9 +231,9 @@ public class RenderBlockInscriber extends BaseBlockRender
if( is == null )
{
InscriberRecipe ir = inv.getTask();
IInscriberRecipe ir = inv.getTask();
if( ir != null )
is = ir.output.copy();
is = ir.getOutput().copy();
}
this.renderItem( is, 0.0f, block, tile, tess, x, y, z, f, renderer );

View file

@ -25,16 +25,21 @@ import net.minecraft.item.ItemStack;
import appeng.api.AEApi;
import appeng.api.definitions.IItemDefinition;
import appeng.api.features.IInscriberRecipe;
import appeng.container.guisync.GuiSync;
import appeng.container.interfaces.IProgressProvider;
import appeng.container.slot.SlotOutput;
import appeng.container.slot.SlotRestrictedInput;
import appeng.recipes.handlers.Inscribe;
import appeng.recipes.handlers.Inscribe.InscriberRecipe;
import appeng.tile.misc.TileInscriber;
import appeng.util.Platform;
/**
* @author AlgorithmX2
* @author thatsIch
* @version rv2
* @since rv0
*/
public class ContainerInscriber extends ContainerUpgradeable implements IProgressProvider
{
@ -105,32 +110,32 @@ public class ContainerInscriber extends ContainerUpgradeable implements IProgres
@Override
public boolean isValidForSlot( Slot s, ItemStack is )
{
ItemStack PlateA = this.ti.getStackInSlot( 0 );
ItemStack PlateB = this.ti.getStackInSlot( 1 );
ItemStack top = this.ti.getStackInSlot( 0 );
ItemStack bot = this.ti.getStackInSlot( 1 );
if( s == this.middle )
{
for( ItemStack i : Inscribe.PLATES )
for( ItemStack optional : AEApi.instance().registries().inscriber().getOptionals() )
{
if( Platform.isSameItemPrecise( i, is ) )
if( Platform.isSameItemPrecise( optional, is ) )
return false;
}
boolean matches = false;
boolean found = false;
for( InscriberRecipe i : Inscribe.RECIPES )
for( IInscriberRecipe recipe : AEApi.instance().registries().inscriber().getRecipes() )
{
boolean matchA = ( PlateA == null && i.plateA == null ) || ( Platform.isSameItemPrecise( PlateA, i.plateA ) ) && // and...
( PlateB == null && i.plateB == null ) | ( Platform.isSameItemPrecise( PlateB, i.plateB ) );
boolean matchA = ( top == null && !recipe.getTopOptional().isPresent() ) || ( Platform.isSameItemPrecise( top, recipe.getTopOptional().orNull() ) ) && // and...
( bot == null && !recipe.getBottomOptional().isPresent() ) | ( Platform.isSameItemPrecise( bot, recipe.getBottomOptional().orNull() ) );
boolean matchB = ( PlateB == null && i.plateA == null ) || ( Platform.isSameItemPrecise( PlateB, i.plateA ) ) && // and...
( PlateA == null && i.plateB == null ) | ( Platform.isSameItemPrecise( PlateA, i.plateB ) );
boolean matchB = ( bot == null && !recipe.getTopOptional().isPresent() ) || ( Platform.isSameItemPrecise( bot, recipe.getTopOptional().orNull() ) ) && // and...
( top == null && !recipe.getBottomOptional().isPresent() ) | ( Platform.isSameItemPrecise( top, recipe.getBottomOptional().orNull() ) );
if( matchA || matchB )
{
matches = true;
for( ItemStack option : i.imprintable )
for( ItemStack option : recipe.getInputs() )
{
if( Platform.isSameItemPrecise( is, option ) )
found = true;
@ -142,7 +147,7 @@ public class ContainerInscriber extends ContainerUpgradeable implements IProgres
return false;
}
if( ( s == this.top && PlateB != null ) || ( s == this.bottom && PlateA != null ) )
if( ( s == this.top && bot != null ) || ( s == this.bottom && top != null ) )
{
boolean isValid = false;
ItemStack otherSlot = null;
@ -159,15 +164,15 @@ public class ContainerInscriber extends ContainerUpgradeable implements IProgres
}
// everything else
for( InscriberRecipe i : Inscribe.RECIPES )
for( IInscriberRecipe recipe : AEApi.instance().registries().inscriber().getRecipes() )
{
if( Platform.isSameItemPrecise( i.plateA, otherSlot ) )
if( Platform.isSameItemPrecise( recipe.getTopOptional().orNull(), otherSlot ) )
{
isValid = Platform.isSameItemPrecise( is, i.plateB );
isValid = Platform.isSameItemPrecise( is, recipe.getBottomOptional().orNull() );
}
else if( Platform.isSameItemPrecise( i.plateB, otherSlot ) )
else if( Platform.isSameItemPrecise( recipe.getBottomOptional().orNull(), otherSlot ) )
{
isValid = Platform.isSameItemPrecise( is, i.plateA );
isValid = Platform.isSameItemPrecise( is, recipe.getTopOptional().orNull() );
}
if( isValid )

View file

@ -42,10 +42,15 @@ import appeng.api.implementations.items.IUpgradeModule;
import appeng.api.networking.crafting.ICraftingPatternDetails;
import appeng.api.storage.ICellWorkbenchItem;
import appeng.items.misc.ItemEncodedPattern;
import appeng.recipes.handlers.Inscribe;
import appeng.util.Platform;
/**
* @author AlgorithmX2
* @author thatsIch
* @version rv2
* @since rv0
*/
public class SlotRestrictedInput extends AppEngSlot
{
@ -144,8 +149,8 @@ public class SlotRestrictedInput extends AppEngSlot
return true;
}
for( ItemStack is : Inscribe.PLATES )
if( Platform.isSameItemPrecise( is, i ) )
for( ItemStack optional : AEApi.instance().registries().inscriber().getOptionals() )
if( Platform.isSameItemPrecise( optional, i ) )
return true;
return false;

View file

@ -0,0 +1,170 @@
package appeng.core.features.registries;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.annotation.Nonnull;
import net.minecraft.item.ItemStack;
import appeng.api.features.IInscriberRecipe;
import appeng.api.features.IInscriberRecipeBuilder;
import appeng.api.features.IInscriberRegistry;
import appeng.api.features.InscriberProcessType;
import appeng.core.features.registries.entries.InscriberRecipe;
/**
* @author thatsIch
* @version rv2
* @since rv2
*/
public final class InscriberRegistry implements IInscriberRegistry
{
private final List<IInscriberRecipe> recipes;
private final Set<ItemStack> optionals;
private final Set<ItemStack> inputs;
public InscriberRegistry()
{
this.inputs = new HashSet<ItemStack>();
this.optionals = new HashSet<ItemStack>();
this.recipes = new ArrayList<IInscriberRecipe>();
}
@Nonnull
@Override
public List<IInscriberRecipe> getRecipes()
{
return this.recipes;
}
@Nonnull
@Override
public Set<ItemStack> getOptionals()
{
return this.optionals;
}
@Nonnull
@Override
public Set<ItemStack> getInputs()
{
return this.inputs;
}
@Nonnull
@Override
public IInscriberRecipeBuilder builder()
{
return new Builder();
}
@Override
public void addRecipe( IInscriberRecipe recipe )
{
if( recipe == null )
throw new IllegalArgumentException( "Tried to add an invalid (null) inscriber recipe to the registry." );
this.recipes.add( recipe );
this.optionals.addAll( recipe.getTopOptional().asSet() );
this.optionals.addAll( recipe.getBottomOptional().asSet() );
this.inputs.addAll( recipe.getInputs() );
}
@Override
public void removeRecipe( IInscriberRecipe toBeRemovedRecipe )
{
for( final Iterator<IInscriberRecipe> iterator = this.recipes.iterator(); iterator.hasNext(); )
{
final IInscriberRecipe recipe = iterator.next();
if( recipe.equals( toBeRemovedRecipe ) )
{
iterator.remove();
}
}
}
/**
* Internal {@link IInscriberRecipeBuilder} implementation.
* Needs to be adapted to represent a correct {@link IInscriberRecipe}
*/
private static final class Builder implements IInscriberRecipeBuilder
{
private List<ItemStack> inputs;
private ItemStack output;
private ItemStack topOptional;
private ItemStack bottomOptional;
private InscriberProcessType type;
@Nonnull
@Override
public Builder withInputs( @Nonnull Collection<ItemStack> inputs )
{
this.inputs = new ArrayList<ItemStack>( inputs.size() );
this.inputs.addAll( inputs );
return this;
}
@Nonnull
@Override
public Builder withOutput( @Nonnull ItemStack output )
{
this.output = output;
return this;
}
@Nonnull
@Override
public Builder withTopOptional( @Nonnull ItemStack topOptional )
{
this.topOptional = topOptional;
return this;
}
@Nonnull
@Override
public Builder withBottomOptional( @Nonnull ItemStack bottomOptional )
{
this.bottomOptional = bottomOptional;
return this;
}
@Nonnull
@Override
public Builder withProcessType( @Nonnull InscriberProcessType type )
{
this.type = type;
return this;
}
@Nonnull
@Override
public IInscriberRecipe build()
{
if( this.inputs == null )
throw new IllegalStateException( "Input must be defined." );
if( this.inputs.size() == 0 )
throw new IllegalStateException( "Input must have a size." );
if( this.output == null )
throw new IllegalStateException( "Output must be defined." );
if ( this.topOptional == null && this.bottomOptional == null )
throw new IllegalStateException( "One optional must be defined." );
if ( this.type == null )
throw new IllegalStateException( "Process type must be defined." );
return new InscriberRecipe( this.inputs, this.output, this.topOptional, this.bottomOptional, this.type );
}
}
}

View file

@ -20,6 +20,7 @@ package appeng.core.features.registries;
import appeng.api.features.IGrinderRegistry;
import appeng.api.features.IInscriberRegistry;
import appeng.api.features.ILocatableRegistry;
import appeng.api.features.IMatterCannonAmmoRegistry;
import appeng.api.features.IP2PTunnelRegistry;
@ -35,74 +36,88 @@ import appeng.api.storage.ICellRegistry;
import appeng.api.storage.IExternalStorageRegistry;
/**
* represents all registries
*
* @author AlgorithmX2
* @author thatsIch
* @version rv2
* @since rv0
*/
public class RegistryContainer implements IRegistryContainer
{
private final GrinderRecipeManager GrinderRecipes = new GrinderRecipeManager();
private final ExternalStorageRegistry ExternalStorageHandlers = new ExternalStorageRegistry();
private final CellRegistry CellRegistry = new CellRegistry();
private final LocatableRegistry LocatableRegistry = new LocatableRegistry();
private final SpecialComparisonRegistry SpecialComparisonRegistry = new SpecialComparisonRegistry();
private final WirelessRegistry WirelessRegistry = new WirelessRegistry();
private final GridCacheRegistry GridCacheRegistry = new GridCacheRegistry();
private final P2PTunnelRegistry P2PRegistry = new P2PTunnelRegistry();
private final MovableTileRegistry MovableReg = new MovableTileRegistry();
private final MatterCannonAmmoRegistry matterCannonReg = new MatterCannonAmmoRegistry();
private final PlayerRegistry playerRegistry = new PlayerRegistry();
private final IGrinderRegistry grinder = new GrinderRecipeManager();
private final IInscriberRegistry inscriber = new InscriberRegistry();
private final IExternalStorageRegistry storage = new ExternalStorageRegistry();
private final ICellRegistry cell = new CellRegistry();
private final ILocatableRegistry locatable = new LocatableRegistry();
private final ISpecialComparisonRegistry comparison = new SpecialComparisonRegistry();
private final IWirelessTermRegistry wireless = new WirelessRegistry();
private final IGridCacheRegistry gridCache = new GridCacheRegistry();
private final IP2PTunnelRegistry p2ptunnel = new P2PTunnelRegistry();
private final IMovableRegistry movable = new MovableTileRegistry();
private final IMatterCannonAmmoRegistry matterCannonReg = new MatterCannonAmmoRegistry();
private final IPlayerRegistry playerRegistry = new PlayerRegistry();
private final IRecipeHandlerRegistry recipeReg = new RecipeHandlerRegistry();
@Override
public IMovableRegistry movable()
{
return this.MovableReg;
return this.movable;
}
@Override
public IGridCacheRegistry gridCache()
{
return this.GridCacheRegistry;
return this.gridCache;
}
@Override
public IExternalStorageRegistry externalStorage()
{
return this.ExternalStorageHandlers;
return this.storage;
}
@Override
public ISpecialComparisonRegistry specialComparison()
{
return this.SpecialComparisonRegistry;
return this.comparison;
}
@Override
public IWirelessTermRegistry wireless()
{
return this.WirelessRegistry;
return this.wireless;
}
@Override
public ICellRegistry cell()
{
return this.CellRegistry;
return this.cell;
}
@Override
public IGrinderRegistry grinder()
{
return this.GrinderRecipes;
return this.grinder;
}
@Override
public IInscriberRegistry inscriber()
{
return this.inscriber;
}
@Override
public ILocatableRegistry locatable()
{
return this.LocatableRegistry;
return this.locatable;
}
@Override
public IP2PTunnelRegistry p2pTunnel()
{
return this.P2PRegistry;
return this.p2ptunnel;
}
@Override

View file

@ -0,0 +1,26 @@
package appeng.core.features.registries.entries;
import java.util.Collection;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import net.minecraft.item.ItemStack;
import appeng.api.features.InscriberProcessType;
/**
* inscribe recipes do not use up the provided optional upon craft
*
* @author thatsIch
* @version rv2
* @since rv2
*/
public class InscriberInscribeRecipe extends InscriberRecipe
{
public InscriberInscribeRecipe( @Nonnull Collection<ItemStack> inputs, @Nonnull ItemStack output, @Nullable ItemStack top, @Nullable ItemStack bot )
{
super( inputs, output, top, bot, InscriberProcessType.Inscribe );
}
}

View file

@ -0,0 +1,120 @@
package appeng.core.features.registries.entries;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import net.minecraft.item.ItemStack;
import com.google.common.base.Optional;
import appeng.api.features.IInscriberRecipe;
import appeng.api.features.InscriberProcessType;
/**
* Basic inscriber recipe
*
* @author thatsIch
* @version rv2
* @since rv2
*/
public class InscriberRecipe implements IInscriberRecipe
{
@Nonnull
private final List<ItemStack> inputs;
@Nonnull
private final ItemStack output;
@Nonnull
private final Optional<ItemStack> maybeTop;
@Nonnull
private final Optional<ItemStack> maybeBot;
@Nonnull
private final InscriberProcessType type;
public InscriberRecipe( @Nonnull Collection<ItemStack> inputs, @Nonnull ItemStack output, @Nullable ItemStack top, @Nullable ItemStack bot, @Nonnull InscriberProcessType type )
{
this.inputs = new ArrayList<ItemStack>( inputs.size() );
this.inputs.addAll( inputs );
this.output = output;
this.maybeTop = Optional.fromNullable( top );
this.maybeBot = Optional.fromNullable( bot );
this.type = type;
}
@Nonnull
@Override
public final List<ItemStack> getInputs()
{
return this.inputs;
}
@Nonnull
@Override
public final ItemStack getOutput()
{
return this.output;
}
@Nonnull
@Override
public final Optional<ItemStack> getTopOptional()
{
return this.maybeTop;
}
@Nonnull
@Override
public final Optional<ItemStack> getBottomOptional()
{
return this.maybeBot;
}
@Nonnull
@Override
public final InscriberProcessType getProcessType()
{
return this.type;
}
@Override
public boolean equals( Object o )
{
if( this == o )
return true;
if( !(o instanceof IInscriberRecipe) )
return false;
IInscriberRecipe that = (IInscriberRecipe) o;
if( !this.inputs.equals( that.getInputs() ) )
return false;
if( !this.output.equals( that.getOutput() ) )
return false;
if( !this.maybeTop.equals( that.getTopOptional() ) )
return false;
if( !this.maybeBot.equals( that.getBottomOptional()) )
return false;
return this.type == that.getProcessType();
}
@Override
public int hashCode()
{
int result = this.inputs.hashCode();
result = 31 * result + this.output.hashCode();
result = 31 * result + this.maybeTop.hashCode();
result = 31 * result + this.maybeBot.hashCode();
result = 31 * result + this.type.hashCode();
return result;
}
}

View file

@ -36,15 +36,21 @@ import codechicken.nei.api.IOverlayHandler;
import codechicken.nei.api.IRecipeOverlayRenderer;
import codechicken.nei.recipe.TemplateRecipeHandler;
import appeng.api.AEApi;
import appeng.api.features.IInscriberRecipe;
import appeng.client.gui.implementations.GuiInscriber;
import appeng.core.localization.GuiText;
import appeng.recipes.handlers.Inscribe;
import appeng.recipes.handlers.Inscribe.InscriberRecipe;
import static codechicken.lib.gui.GuiDraw.changeTexture;
import static codechicken.lib.gui.GuiDraw.drawTexturedModalRect;
/**
* @author AlgorithmX2
* @author thatsIch
* @version rv2
* @since rv0
*/
public class NEIInscriberRecipeHandler extends TemplateRecipeHandler
{
@ -59,7 +65,7 @@ public class NEIInscriberRecipeHandler extends TemplateRecipeHandler
{
if( ( outputId.equals( "inscriber" ) ) && ( this.getClass() == NEIInscriberRecipeHandler.class ) )
{
for( InscriberRecipe recipe : Inscribe.RECIPES )
for( IInscriberRecipe recipe : AEApi.instance().registries().inscriber().getRecipes() )
{
CachedInscriberRecipe cachedRecipe = new CachedInscriberRecipe( recipe );
cachedRecipe.computeVisuals();
@ -75,9 +81,9 @@ public class NEIInscriberRecipeHandler extends TemplateRecipeHandler
@Override
public void loadCraftingRecipes( ItemStack result )
{
for( InscriberRecipe recipe : Inscribe.RECIPES )
for( IInscriberRecipe recipe : AEApi.instance().registries().inscriber().getRecipes() )
{
if( NEIServerUtils.areStacksSameTypeCrafting( recipe.output, result ) )
if( NEIServerUtils.areStacksSameTypeCrafting( recipe.getOutput(), result ) )
{
CachedInscriberRecipe cachedRecipe = new CachedInscriberRecipe( recipe );
cachedRecipe.computeVisuals();
@ -89,7 +95,7 @@ public class NEIInscriberRecipeHandler extends TemplateRecipeHandler
@Override
public void loadUsageRecipes( ItemStack ingredient )
{
for( InscriberRecipe recipe : Inscribe.RECIPES )
for( IInscriberRecipe recipe : AEApi.instance().registries().inscriber().getRecipes() )
{
CachedInscriberRecipe cachedRecipe = new CachedInscriberRecipe( recipe );
@ -162,19 +168,22 @@ public class NEIInscriberRecipeHandler extends TemplateRecipeHandler
public final ArrayList<PositionedStack> ingredients;
public final PositionedStack result;
public CachedInscriberRecipe( InscriberRecipe recipe )
public CachedInscriberRecipe( IInscriberRecipe recipe )
{
this.result = new PositionedStack( recipe.output, 108, 29 );
this.result = new PositionedStack( recipe.getOutput(), 108, 29 );
this.ingredients = new ArrayList<PositionedStack>();
if( recipe.plateA != null )
this.ingredients.add( new PositionedStack( recipe.plateA, 40, 5 ) );
for( ItemStack top : recipe.getTopOptional().asSet() )
{
this.ingredients.add( new PositionedStack( top, 40, 5 ) );
}
if( recipe.imprintable != null )
this.ingredients.add( new PositionedStack( recipe.imprintable, 40 + 18, 28 ) );
this.ingredients.add( new PositionedStack( recipe.getInputs(), 40 + 18, 28 ) );
if( recipe.plateB != null )
this.ingredients.add( new PositionedStack( recipe.plateB, 40, 51 ) );
for( ItemStack bot : recipe.getBottomOptional().asSet() )
{
this.ingredients.add( new PositionedStack( bot, 40, 51 ) );
}
}
@Override

View file

@ -30,6 +30,8 @@ import java.util.Map.Entry;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import javax.annotation.Nonnull;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
@ -63,6 +65,12 @@ import appeng.recipes.handlers.IWebsiteSerializer;
import appeng.recipes.handlers.OreRegistration;
/**
* @author AlgorithmX2
* @author thatsIch
* @version rv2
* @since rv0
*/
public class RecipeHandler implements IRecipeHandler
{
@ -84,21 +92,18 @@ public class RecipeHandler implements IRecipeHandler
this.data.Handlers.add( ch );
}
public String getName( IIngredient i )
public String getName( @Nonnull IIngredient i )
{
try
{
for( ItemStack is : i.getItemStackSet() )
{
try
{
return this.getName( is );
}
catch( RecipeError ignored )
{
}
return this.getName( is );
}
}
catch( RecipeError ignored )
{
}
catch( Throwable t )
{
t.printStackTrace();

View file

@ -19,113 +19,48 @@
package appeng.recipes.handlers;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import net.minecraft.item.ItemStack;
import appeng.api.AEApi;
import appeng.api.exceptions.MissingIngredientError;
import appeng.api.exceptions.RecipeError;
import appeng.api.exceptions.RegistrationError;
import appeng.api.recipes.ICraftHandler;
import appeng.api.recipes.IIngredient;
import appeng.recipes.RecipeHandler;
import appeng.util.Platform;
import appeng.api.features.IInscriberRecipe;
import appeng.api.features.InscriberProcessType;
import appeng.core.features.registries.entries.InscriberRecipe;
public class Inscribe implements ICraftHandler, IWebsiteSerializer
/**
* recipe translation for inscribe process
*
* @author AlgorithmX2
* @author thatsIch
* @version rv2
* @since rv0
*/
public final class Inscribe extends InscriberProcess
{
public static final HashSet<ItemStack> PLATES = new HashSet<ItemStack>();
public static final HashSet<ItemStack> INPUTS = new HashSet<ItemStack>();
public static final LinkedList<InscriberRecipe> RECIPES = new LinkedList<InscriberRecipe>();
public boolean usePlates = false;
IIngredient imprintable;
IIngredient plateA;
IIngredient plateB;
IIngredient output;
@Override
public void setup( List<List<IIngredient>> input, List<List<IIngredient>> output ) throws RecipeError
{
if( output.size() == 1 && output.get( 0 ).size() == 1 )
{
if( input.size() == 1 && input.get( 0 ).size() > 1 )
{
this.imprintable = input.get( 0 ).get( 0 );
this.plateA = input.get( 0 ).get( 1 );
if( input.get( 0 ).size() > 2 )
this.plateB = input.get( 0 ).get( 2 );
this.output = output.get( 0 ).get( 0 );
}
else
throw new RecipeError( "Inscriber recipes cannot have rows, and must have more then one input." );
}
else
throw new RecipeError( "Inscriber recipes must produce a single output." );
}
@Override
public void register() throws RegistrationError, MissingIngredientError
{
if( this.imprintable != null )
Collections.addAll( INPUTS, this.imprintable.getItemStackSet() );
if ( this.getImprintable() == null )
return;
if ( this.getOutput() == null )
return;
if( this.plateA != null )
Collections.addAll( PLATES, this.plateA.getItemStackSet() );
final ItemStack[] realInput = this.getImprintable().getItemStackSet();
final List<ItemStack> inputs = new ArrayList<ItemStack>( realInput.length );
Collections.addAll( inputs, realInput );
final ItemStack top = (this.getTopOptional() == null) ? null : this.getTopOptional().getItemStack();
final ItemStack bot = (this.getBotOptional() == null) ? null : this.getBotOptional().getItemStack();
final ItemStack output = this.getOutput().getItemStack();
final InscriberProcessType type = InscriberProcessType.Inscribe;
if( this.plateB != null )
Collections.addAll( PLATES, this.plateB.getItemStackSet() );
IInscriberRecipe recipe = new InscriberRecipe( inputs, output, top, bot, type );
InscriberRecipe ir = new InscriberRecipe( this.imprintable.getItemStackSet(), this.plateA == null ? null : this.plateA.getItemStack(), this.plateB == null ? null : this.plateB.getItemStack(), this.output.getItemStack(), this.usePlates );
RECIPES.add( ir );
}
@Override
public String getPattern( RecipeHandler h )
{
String o = "inscriber " + this.output.getQty() + '\n';
o += h.getName( this.output ) + '\n';
if( this.plateA != null )
o += h.getName( this.plateA ) + '\n';
o += h.getName( this.imprintable );
if( this.plateB != null )
o += '\n' + h.getName( this.plateB );
return o;
}
@Override
public boolean canCraft( ItemStack reqOutput ) throws RegistrationError, MissingIngredientError
{
return Platform.isSameItemPrecise( this.output.getItemStack(), reqOutput );
}
public static class InscriberRecipe
{
public final boolean usePlates;
public final ItemStack plateA;
public final ItemStack[] imprintable;
public final ItemStack plateB;
public final ItemStack output;
public InscriberRecipe( ItemStack[] imprintable, ItemStack plateA, ItemStack plateB, ItemStack out, boolean usePlates )
{
this.imprintable = imprintable;
this.usePlates = usePlates;
this.plateA = plateA;
this.plateB = plateB;
this.output = out;
}
AEApi.instance().registries().inscriber().addRecipe( recipe );
}
}

View file

@ -0,0 +1,115 @@
package appeng.recipes.handlers;
import java.util.List;
import javax.annotation.Nullable;
import net.minecraft.item.ItemStack;
import appeng.api.exceptions.MissingIngredientError;
import appeng.api.exceptions.RecipeError;
import appeng.api.exceptions.RegistrationError;
import appeng.api.recipes.ICraftHandler;
import appeng.api.recipes.IIngredient;
import appeng.recipes.RecipeHandler;
import appeng.util.Platform;
/**
* basic inscriber process for recipes
*
* @author AlgorithmX2
* @author thatsIch
* @version rv2
* @since rv0
*/
public abstract class InscriberProcess implements ICraftHandler, IWebsiteSerializer
{
@Nullable
private IIngredient imprintable;
@Nullable
private IIngredient topOptional;
@Nullable
private IIngredient botOptional;
@Nullable
private IIngredient output;
@Override
public void setup( List<List<IIngredient>> input, List<List<IIngredient>> output ) throws RecipeError
{
if( output.size() == 1 && output.get( 0 ).size() == 1 )
{
if( input.size() == 1 && input.get( 0 ).size() > 1 )
{
this.imprintable = input.get( 0 ).get( 0 );
this.topOptional = input.get( 0 ).get( 1 );
if( input.get( 0 ).size() > 2 )
this.botOptional = input.get( 0 ).get( 2 );
this.output = output.get( 0 ).get( 0 );
}
else
throw new RecipeError( "Inscriber recipes cannot have rows, and must have more then one input." );
}
else
throw new RecipeError( "Inscriber recipes must produce a single output." );
}
@Override
public boolean canCraft( ItemStack reqOutput ) throws RegistrationError, MissingIngredientError
{
return this.output != null && Platform.isSameItemPrecise( this.output.getItemStack(), reqOutput );
}
@Override
public String getPattern( RecipeHandler handler )
{
String pattern = "inscriber ";
if ( this.output != null )
{
pattern += this.output.getQty() + '\n';
pattern += handler.getName( this.output ) + '\n';
}
if( this.topOptional != null )
pattern += handler.getName( this.topOptional ) + '\n';
if ( this.imprintable != null )
pattern += handler.getName( this.imprintable );
if( this.botOptional != null )
pattern += '\n' + handler.getName( this.botOptional );
return pattern;
}
@Nullable
protected IIngredient getImprintable()
{
return this.imprintable;
}
@Nullable
protected IIngredient getTopOptional()
{
return this.topOptional;
}
@Nullable
protected IIngredient getBotOptional()
{
return this.botOptional;
}
@Nullable
protected IIngredient getOutput()
{
return this.output;
}
}

View file

@ -19,11 +19,48 @@
package appeng.recipes.handlers;
public class Press extends Inscribe
{
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public Press()
import net.minecraft.item.ItemStack;
import appeng.api.AEApi;
import appeng.api.exceptions.MissingIngredientError;
import appeng.api.exceptions.RegistrationError;
import appeng.api.features.IInscriberRecipe;
import appeng.api.features.InscriberProcessType;
import appeng.core.features.registries.entries.InscriberRecipe;
/**
* recipe translation for pressing in the inscriber
*
* @author AlgorithmX2
* @author thatsIch
* @version rv2
* @since rv0
*/
public final class Press extends InscriberProcess
{
@Override
public void register() throws RegistrationError, MissingIngredientError
{
this.usePlates = true;
if ( this.getImprintable() == null )
return;
if ( this.getOutput() == null )
return;
final ItemStack[] realInput = this.getImprintable().getItemStackSet();
final List<ItemStack> inputs = new ArrayList<ItemStack>( realInput.length );
Collections.addAll( inputs, realInput );
final ItemStack top = ( this.getTopOptional() == null ) ? null : this.getTopOptional().getItemStack();
final ItemStack bot = ( this.getBotOptional() == null ) ? null : this.getBotOptional().getItemStack();
final ItemStack output = this.getOutput().getItemStack();
final InscriberProcessType type = InscriberProcessType.Press;
IInscriberRecipe recipe = new InscriberRecipe( inputs, output, top, bot, type );
AEApi.instance().registries().inscriber().addRecipe( recipe );
}
}

View file

@ -22,6 +22,8 @@ package appeng.tile.misc;
import java.io.IOException;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import javax.annotation.Nullable;
import io.netty.buffer.ByteBuf;
@ -31,12 +33,16 @@ import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.World;
import net.minecraftforge.common.util.ForgeDirection;
import com.google.common.collect.Lists;
import appeng.api.AEApi;
import appeng.api.config.Actionable;
import appeng.api.config.PowerMultiplier;
import appeng.api.config.Upgrades;
import appeng.api.definitions.IComparableDefinition;
import appeng.api.definitions.ITileDefinition;
import appeng.api.features.IInscriberRecipe;
import appeng.api.features.InscriberProcessType;
import appeng.api.implementations.IUpgradeableHost;
import appeng.api.networking.IGridNode;
import appeng.api.networking.energy.IEnergyGrid;
@ -46,13 +52,12 @@ import appeng.api.networking.ticking.TickRateModulation;
import appeng.api.networking.ticking.TickingRequest;
import appeng.api.util.AECableType;
import appeng.api.util.IConfigManager;
import appeng.core.features.registries.entries.InscriberRecipe;
import appeng.core.settings.TickRates;
import appeng.helpers.Reflected;
import appeng.me.GridAccessException;
import appeng.parts.automation.DefinitionUpgradeInventory;
import appeng.parts.automation.UpgradeInventory;
import appeng.recipes.handlers.Inscribe;
import appeng.recipes.handlers.Inscribe.InscriberRecipe;
import appeng.tile.TileEvent;
import appeng.tile.events.TileEventType;
import appeng.tile.grid.AENetworkPowerTile;
@ -66,6 +71,12 @@ import appeng.util.inv.WrapperInventoryRange;
import appeng.util.item.AEItemStack;
/**
* @author AlgorithmX2
* @author thatsIch
* @version rv2
* @since rv0
*/
public class TileInscriber extends AENetworkPowerTile implements IGridTickable, IUpgradeableHost, IConfigManagerHost
{
@ -220,8 +231,8 @@ public class TileInscriber extends AENetworkPowerTile implements IGridTickable,
return true;
}
for( ItemStack s : Inscribe.PLATES )
if( Platform.isSameItemPrecise( s, itemstack ) )
for( ItemStack optionals : AEApi.instance().registries().inscriber().getOptionals() )
if( Platform.isSameItemPrecise( optionals, itemstack ) )
return true;
}
@ -286,7 +297,8 @@ public class TileInscriber extends AENetworkPowerTile implements IGridTickable,
return this.smash;
}
public InscriberRecipe getTask()
@Nullable
public IInscriberRecipe getTask()
{
ItemStack plateA = this.getStackInSlot( 0 );
ItemStack plateB = this.getStackInSlot( 1 );
@ -337,25 +349,28 @@ public class TileInscriber extends AENetworkPowerTile implements IGridTickable,
else
display.removeTag( "Name" );
return new InscriberRecipe( new ItemStack[] { startingItem }, plateA, plateB, renamedItem, false );
final List<ItemStack> inputs = Lists.newArrayList( startingItem );
final InscriberProcessType type = InscriberProcessType.Inscribe;
return new InscriberRecipe( inputs, renamedItem, plateA, plateB, type );
}
}
for( InscriberRecipe i : Inscribe.RECIPES )
for( IInscriberRecipe recipe : AEApi.instance().registries().inscriber().getRecipes() )
{
boolean matchA = ( plateA == null && i.plateA == null ) || ( Platform.isSameItemPrecise( plateA, i.plateA ) ) && // and...
( plateB == null && i.plateB == null ) | ( Platform.isSameItemPrecise( plateB, i.plateB ) );
boolean matchA = ( plateA == null && !recipe.getTopOptional().isPresent() ) || ( Platform.isSameItemPrecise( plateA, recipe.getTopOptional().orNull() ) ) && // and...
( plateB == null && !recipe.getBottomOptional().isPresent() ) | ( Platform.isSameItemPrecise( plateB, recipe.getBottomOptional().orNull() ) );
boolean matchB = ( plateB == null && i.plateA == null ) || ( Platform.isSameItemPrecise( plateB, i.plateA ) ) && // and...
( plateA == null && i.plateB == null ) | ( Platform.isSameItemPrecise( plateA, i.plateB ) );
boolean matchB = ( plateB == null && !recipe.getTopOptional().isPresent() ) || ( Platform.isSameItemPrecise( plateB, recipe.getTopOptional().orNull() ) ) && // and...
( plateA == null && !recipe.getBottomOptional().isPresent() ) | ( Platform.isSameItemPrecise( plateA, recipe.getBottomOptional().orNull() ) );
if( matchA || matchB )
{
for( ItemStack option : i.imprintable )
for( ItemStack option : recipe.getInputs() )
{
if( Platform.isSameItemPrecise( option, this.getStackInSlot( 2 ) ) )
return i;
return recipe;
}
}
}
@ -367,21 +382,19 @@ public class TileInscriber extends AENetworkPowerTile implements IGridTickable,
{
if( this.smash )
{
this.finalStep++;
if( this.finalStep == 8 )
{
InscriberRecipe out = this.getTask();
final IInscriberRecipe out = this.getTask();
if( out != null )
{
ItemStack is = out.output.copy();
final ItemStack outputCopy = out.getOutput().copy();
InventoryAdaptor ad = InventoryAdaptor.getAdaptor( new WrapperInventoryRange( this.inv, 3, 1, true ), ForgeDirection.UNKNOWN );
if( ad.addItems( is ) == null )
if( ad.addItems( outputCopy ) == null )
{
this.processingTime = 0;
if( out.usePlates )
if( out.getProcessType() == InscriberProcessType.Press )
{
this.setInventorySlotContents( 0, null );
this.setInventorySlotContents( 1, null );
@ -437,12 +450,12 @@ public class TileInscriber extends AENetworkPowerTile implements IGridTickable,
if( this.processingTime > this.maxProcessingTime )
{
this.processingTime = this.maxProcessingTime;
InscriberRecipe out = this.getTask();
IInscriberRecipe out = this.getTask();
if( out != null )
{
ItemStack is = out.output.copy();
ItemStack outputCopy = out.getOutput().copy();
InventoryAdaptor ad = InventoryAdaptor.getAdaptor( new WrapperInventoryRange( this.inv, 3, 1, true ), ForgeDirection.UNKNOWN );
if( ad.simulateAdd( is ) == null )
if( ad.simulateAdd( outputCopy ) == null )
{
this.smash = true;
this.finalStep = 0;

View file

@ -32,6 +32,8 @@ import java.util.Random;
import java.util.Set;
import java.util.WeakHashMap;
import javax.annotation.Nullable;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.Tessellator;
@ -140,6 +142,12 @@ import appeng.util.item.OreReference;
import appeng.util.prioitylist.IPartitionList;
/**
* @author AlgorithmX2
* @author thatsIch
* @version rv2
* @since rv0
*/
public class Platform
{
@ -1119,7 +1127,7 @@ public class Platform
return StatCollector.translateToLocal( string );
}
public static boolean isSameItemPrecise( ItemStack is, ItemStack filter )
public static boolean isSameItemPrecise( @Nullable ItemStack is, @Nullable ItemStack filter )
{
return isSameItem( is, filter ) && sameStackStags( is, filter );
}
@ -1707,7 +1715,7 @@ public class Platform
return false;
}
public static boolean isSameItem( ItemStack left, ItemStack right )
public static boolean isSameItem( @Nullable ItemStack left, @Nullable ItemStack right )
{
return left != null && right != null && left.isItemEqual( right );
}