diff --git a/src/api/java/appeng/api/features/IGrinderRecipeBuilder.java b/src/api/java/appeng/api/features/IGrinderRecipeBuilder.java new file mode 100644 index 00000000..de739d25 --- /dev/null +++ b/src/api/java/appeng/api/features/IGrinderRecipeBuilder.java @@ -0,0 +1,112 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2013 AlgorithmX2 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package appeng.api.features; + + +import javax.annotation.Nonnegative; +import javax.annotation.Nonnull; + +import net.minecraft.item.ItemStack; + + +/** + * Builder for a grinder recipe + * + * @author yueh + * @version rv4 + * @since rv4 + */ +public interface IGrinderRecipeBuilder +{ + + /** + * Creates an grinder recipe with inputs. + * Needs to be invoked. + * + * @param input new input for the recipe + * + * @return currently used builder + */ + @Nonnull + IGrinderRecipeBuilder withInput( @Nonnull ItemStack input ); + + /** + * Creates an grinder recipe with output. + * Needs to be invoked. + * + * @param output new output for the recipe + * + * @return currently used builder + */ + @Nonnull + IGrinderRecipeBuilder withOutput( @Nonnull ItemStack output ); + + /** + * Creates an grinder recipe with the first optional output and its chance. + * + * @param optional new first optional for the recipe + * @param chance chance for the first optional output, must be within 0.0 - 1.0 + * + * @return currently used builder + */ + @Nonnull + IGrinderRecipeBuilder withFirstOptional( @Nonnull ItemStack optional, float chance ); + + /** + * Creates an grinder recipe with the second optional output and its chance. + * + * @param optional new second optional for the recipe + * @param chance chance for the second optional output, must be within 0.0 - 1.0 + * + * @return currently used builder + */ + @Nonnull + IGrinderRecipeBuilder withSecondOptional( @Nonnull ItemStack optional, float chance ); + + /** + * Creates an grinder recipe with the amount of turns as cost. + * Needs to be invoked. + * + * @param turns new turns for the recipe, must be > 0 + * + * @return currently used builder + */ + @Nonnull + IGrinderRecipeBuilder withTurns( @Nonnegative int turns ); + + /** + * Finalizes the process of making the recipe. + * Needs to be invoked to fetch grinder recipe. + * + * @return legal grinder 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 + IGrinderRecipe build(); +} diff --git a/src/api/java/appeng/api/features/IGrinderRegistry.java b/src/api/java/appeng/api/features/IGrinderRegistry.java index 2a5e8d15..585b2695 100644 --- a/src/api/java/appeng/api/features/IGrinderRegistry.java +++ b/src/api/java/appeng/api/features/IGrinderRegistry.java @@ -38,6 +38,14 @@ import net.minecraft.item.ItemStack; public interface IGrinderRegistry { + /** + * Extensible way to create a grinder recipe. + * + * @return builder for grinder recipes + */ + @Nonnull + IGrinderRecipeBuilder builder(); + /** * An immutable list of the currently registered recipes. * @@ -47,44 +55,9 @@ public interface IGrinderRegistry Collection getRecipes(); /** - * Add a new recipe with a single input and output and how many turns it requires. - * - * Will ignore duplicate recipes with the same input item. - * - * @param in The {@link ItemStack} to grind. - * @param out The {@link ItemStack} to output. - * @param turns Amount of turns to turn the input into the output, with turns > 0. + * Add a new recipe to the registry. */ - void addRecipe( @Nonnull ItemStack in, @Nonnull ItemStack out, int turns ); - - /** - * Add a new recipe with an input, output and a single optional output. - * - * Will ignore duplicate recipes with the same input item. - * - * @param in The {@link ItemStack} to grind. - * @param out The {@link ItemStack} to output. - * @param optional The optional {@link ItemStack} to output of a certain chance. - * @param chance Chance to get the optional output within 0.0 - 1.0 - * @param turns Amount of turns to turn the input into the output, with turns > 0. - */ - void addRecipe( @Nonnull ItemStack in, @Nonnull ItemStack out, @Nonnull ItemStack optional, float chance, int turns ); - - /** - * add a new recipe with optional outputs, duplicates will not be added. - * - * Will ignore duplicate recipes with the same input item. - * - * @param in The {@link ItemStack} to grind. - * @param out The {@link ItemStack} to output. - * @param optional The first optional {@link ItemStack} to output of a certain chance. - * @param chance Chance to get the first optional output within 0.0 - 1.0 - * @param optional2 The second optional {@link ItemStack} to output of a certain chance. - * @param chance2 chance to get the second optional output within 0.0 - 1.0 - * @param turns Amount of turns to turn the input into the output, with turns > 0. - * - */ - void addRecipe( @Nonnull ItemStack in, @Nonnull ItemStack out, @Nonnull ItemStack optional, float chance, @Nonnull ItemStack optional2, float chance2, int turns ); + boolean addRecipe( IGrinderRecipe recipe ); /** * Remove the specific from the recipe list. diff --git a/src/api/java/appeng/api/features/IInscriberRegistry.java b/src/api/java/appeng/api/features/IInscriberRegistry.java index 11fdf0b0..6c889df1 100644 --- a/src/api/java/appeng/api/features/IInscriberRegistry.java +++ b/src/api/java/appeng/api/features/IInscriberRegistry.java @@ -36,6 +36,14 @@ import net.minecraft.item.ItemStack; */ public interface IInscriberRegistry { + /** + * Extensible way to create an inscriber recipe. + * + * @return builder for inscriber recipes + */ + @Nonnull + IInscriberRecipeBuilder builder(); + /** * An immutable copy of currently registered recipes. * @@ -65,29 +73,25 @@ public interface IInscriberRegistry @Nonnull Set 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 + * + * @return true, when successfully added * * @throws IllegalArgumentException if null is added */ - void addRecipe( IInscriberRecipe recipe ); + boolean addRecipe( IInscriberRecipe recipe ); /** * Removes all equal recipes from the registry. - * + * * @param toBeRemovedRecipe to be removed recipe, can be null, makes just no sense. + * + * @return true, when successfully removed */ - void removeRecipe( IInscriberRecipe toBeRemovedRecipe ); + boolean removeRecipe( IInscriberRecipe toBeRemovedRecipe ); } diff --git a/src/main/java/appeng/core/api/imc/IMCGrinder.java b/src/main/java/appeng/core/api/imc/IMCGrinder.java index 7503d1a0..0e9a49bf 100644 --- a/src/main/java/appeng/core/api/imc/IMCGrinder.java +++ b/src/main/java/appeng/core/api/imc/IMCGrinder.java @@ -58,6 +58,9 @@ import net.minecraft.nbt.NBTTagCompound; import net.minecraftforge.fml.common.event.FMLInterModComms.IMCMessage; import appeng.api.AEApi; +import appeng.api.features.IGrinderRecipe; +import appeng.api.features.IGrinderRecipeBuilder; +import appeng.api.features.IGrinderRegistry; import appeng.core.api.IIMCProcessor; @@ -97,11 +100,27 @@ public class IMCGrinder implements IIMCProcessor final float chance = msg.getFloat( "chance" ); - AEApi.instance().registries().grinder().addRecipe( in, out, optional, chance, turns ); + final IGrinderRegistry grinderRegistry = AEApi.instance().registries().grinder(); + final IGrinderRecipeBuilder builder = grinderRegistry.builder(); + IGrinderRecipe grinderRecipe = builder.withInput( in ) + .withOutput( out ) + .withFirstOptional( optional, chance ) + .withTurns( turns ) + .build(); + + grinderRegistry.addRecipe( grinderRecipe ); } else { - AEApi.instance().registries().grinder().addRecipe( in, out, turns ); + + final IGrinderRegistry grinderRegistry = AEApi.instance().registries().grinder(); + final IGrinderRecipeBuilder builder = grinderRegistry.builder(); + IGrinderRecipe grinderRecipe = builder.withInput( in ) + .withOutput( out ) + .withTurns( turns ) + .build(); + + grinderRegistry.addRecipe( grinderRecipe ); } } } diff --git a/src/main/java/appeng/core/features/registries/grinder/GrinderRecipeManager.java b/src/main/java/appeng/core/features/registries/grinder/GrinderRecipeManager.java index 801af81b..0cb246d3 100644 --- a/src/main/java/appeng/core/features/registries/grinder/GrinderRecipeManager.java +++ b/src/main/java/appeng/core/features/registries/grinder/GrinderRecipeManager.java @@ -24,6 +24,8 @@ import java.util.Collections; import java.util.Map; import java.util.Map.Entry; +import javax.annotation.Nonnull; + import com.google.common.base.Preconditions; import com.google.common.collect.Maps; @@ -33,7 +35,10 @@ import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import appeng.api.features.IGrinderRecipe; +import appeng.api.features.IGrinderRecipeBuilder; import appeng.api.features.IGrinderRegistry; +import appeng.api.features.IInscriberRecipe; +import appeng.api.features.IInscriberRecipeBuilder; import appeng.core.AEConfig; import appeng.core.AELog; import appeng.recipes.ores.IOreListener; @@ -83,58 +88,20 @@ public final class GrinderRecipeManager implements IGrinderRegistry, IOreListene OreDictionaryHandler.INSTANCE.observe( this ); } + @Override + public boolean addRecipe( IGrinderRecipe recipe ) + { + Preconditions.checkNotNull( recipe, "Cannot add null as recipe." ); + + return this.injectRecipe( recipe ); + } + @Override public Collection getRecipes() { return Collections.unmodifiableCollection( this.recipes.values() ); } - @Override - public void addRecipe( final ItemStack in, final ItemStack out, final int cost ) - { - Preconditions.checkNotNull( in, "Null is not accepted as input itemstack." ); - Preconditions.checkNotNull( out, "Null is not accepted as output itemstack." ); - Preconditions.checkArgument( cost > 0, "Turns must be > 0" ); - - this.log( "Allow Grinding of '%1$s' to '%2$s' for %3$d turn", Platform.getItemDisplayName( in ), Platform.getItemDisplayName( out ), cost ); - - this.injectRecipe( new AppEngGrinderRecipe( this.copy( in ), this.copy( out ), cost ) ); - } - - @Override - public void addRecipe( final ItemStack in, final ItemStack out, final ItemStack optional, final float chance, final int cost ) - { - Preconditions.checkNotNull( in, "Null is not accepted as input itemstack." ); - Preconditions.checkNotNull( out, "Null is not accepted as output itemstack." ); - Preconditions.checkNotNull( optional, "Null is not accepted as optional itemstack." ); - Preconditions.checkArgument( chance >= 0.0 && chance <= 1.0, "chance must be within 0.0 - 1.0." ); - Preconditions.checkArgument( cost > 0, "Turns must be > 0" ); - - this.log( "Allow Grinding of '%1$s' to '%2$s' with optional '%3$s' @ %4$.2f for %5$d", Platform.getItemDisplayName( in ), - Platform.getItemDisplayName( out ), Platform.getItemDisplayName( optional ), chance, cost ); - - this.injectRecipe( new AppEngGrinderRecipe( this.copy( in ), this.copy( out ), this.copy( optional ), chance, cost ) ); - } - - @Override - public void addRecipe( final ItemStack in, final ItemStack out, final ItemStack optional1, final float chance1, final ItemStack optional2, final float chance2, final int cost ) - { - Preconditions.checkNotNull( in, "Null is not accepted as input itemstack." ); - Preconditions.checkNotNull( out, "Null is not accepted as output itemstack." ); - Preconditions.checkNotNull( optional1, "Null is not accepted as optional itemstack." ); - Preconditions.checkArgument( chance1 >= 0.0 && chance1 <= 1.0, "chance must be within 0.0 - 1.0." ); - Preconditions.checkNotNull( optional2, "Null is not accepted as optional2 itemstack." ); - Preconditions.checkArgument( chance2 >= 0.0 && chance2 <= 1.0, "chance2 must be within 0.0 - 1.0." ); - Preconditions.checkArgument( cost > 0, "Turns must be > 0" ); - - this.log( "Allow Grinding of '%1$s' to '%2$s' with optional '%3$s' @ %4$.2f and optional2 '%5$s' @ %6$.2f for %7$d", Platform.getItemDisplayName( in ), - Platform.getItemDisplayName( out ), Platform.getItemDisplayName( optional1 ), chance1, Platform.getItemDisplayName( optional2 ), chance2, - cost ); - - this.injectRecipe( - new AppEngGrinderRecipe( this.copy( in ), this.copy( out ), this.copy( optional1 ), this.copy( optional2 ), chance1, chance2, cost ) ); - } - @Override public boolean removeRecipe( IGrinderRecipe recipe ) { @@ -214,26 +181,19 @@ public final class GrinderRecipeManager implements IGrinderRegistry, IOreListene } } - private void injectRecipe( final AppEngGrinderRecipe appEngGrinderRecipe ) + private boolean injectRecipe( final IGrinderRecipe grinderRecipe ) { - final CacheKey cacheKey = new CacheKey( appEngGrinderRecipe.getInput() ); + final CacheKey cacheKey = new CacheKey( grinderRecipe.getInput() ); if( this.recipes.containsKey( cacheKey ) ) { - this.log( "Tried to add duplicate recipe for '%1$s'", Platform.getItemDisplayName( appEngGrinderRecipe.getInput() ) ); - return; + this.log( "Tried to add duplicate recipe for '%1$s'", Platform.getItemDisplayName( grinderRecipe.getInput() ) ); + return false; } - this.recipes.put( cacheKey, appEngGrinderRecipe ); - } + this.recipes.put( cacheKey, grinderRecipe ); - private ItemStack copy( final ItemStack is ) - { - if( is != null ) - { - return is.copy(); - } - return null; + return true; } private int getDustToOreRatio( final String name ) @@ -259,11 +219,25 @@ public final class GrinderRecipeManager implements IGrinderRegistry, IOreListene { final ItemStack extra = is.copy(); extra.stackSize = ratio - 1; - this.addRecipe( item, is, extra, (float) ( AEConfig.instance().getOreDoublePercentage() / 100.0 ), 8 ); + + final IGrinderRecipeBuilder builder = this.builder(); + IGrinderRecipe grinderRecipe = builder.withInput( item ) + .withOutput( is ) + .withFirstOptional( extra, (float) ( AEConfig.instance().getOreDoublePercentage() / 100.0 ) ) + .withTurns( 8 ) + .build(); + + this.addRecipe( grinderRecipe ); } else { - this.addRecipe( item, is, 8 ); + final IGrinderRecipeBuilder builder = this.builder(); + IGrinderRecipe grinderRecipe = builder.withInput( item ) + .withOutput( is ) + .withTurns( 8 ) + .build(); + + this.addRecipe( grinderRecipe ); } } } @@ -280,7 +254,13 @@ public final class GrinderRecipeManager implements IGrinderRegistry, IOreListene if( this.dusts.containsKey( name ) ) { - this.addRecipe( item, this.dusts.get( name ), 4 ); + final IGrinderRecipeBuilder builder = this.builder(); + IGrinderRecipe grinderRecipe = builder.withInput( item ) + .withOutput( this.dusts.get( name ) ) + .withTurns( 4 ) + .build(); + + this.addRecipe( grinderRecipe ); } } @@ -311,11 +291,25 @@ public final class GrinderRecipeManager implements IGrinderRegistry, IOreListene { final ItemStack extra = is.copy(); extra.stackSize = ratio - 1; - this.addRecipe( d.getKey(), is, extra, (float) ( AEConfig.instance().getOreDoublePercentage() / 100.0 ), 8 ); + + final IGrinderRecipeBuilder builder = this.builder(); + IGrinderRecipe grinderRecipe = builder.withInput( d.getKey() ) + .withOutput( is ) + .withFirstOptional( extra, (float) ( AEConfig.instance().getOreDoublePercentage() / 100.0 ) ) + .withTurns( 8 ) + .build(); + + this.addRecipe( grinderRecipe ); } else { - this.addRecipe( d.getKey(), is, 8 ); + final IGrinderRecipeBuilder builder = this.builder(); + IGrinderRecipe grinderRecipe = builder.withInput( d.getKey() ) + .withOutput( is ) + .withTurns( 8 ) + .build(); + + this.addRecipe( grinderRecipe ); } } } @@ -324,7 +318,13 @@ public final class GrinderRecipeManager implements IGrinderRegistry, IOreListene { if( name.equals( d.getValue() ) ) { - this.addRecipe( d.getKey(), item, 4 ); + final IGrinderRecipeBuilder builder = this.builder(); + IGrinderRecipe grinderRecipe = builder.withInput( d.getKey() ) + .withOutput( item ) + .withTurns( 4 ) + .build(); + + this.addRecipe( grinderRecipe ); } } } @@ -393,4 +393,117 @@ public final class GrinderRecipeManager implements IGrinderRegistry, IOreListene } } + + @Override + public IGrinderRecipeBuilder builder() + { + return new Builder(); + } + + /** + * Internal {@link IInscriberRecipeBuilder} implementation. + * Needs to be adapted to represent a correct {@link IInscriberRecipe} + */ + private static final class Builder implements IGrinderRecipeBuilder + { + + private ItemStack in; + private ItemStack out; + + private float optionalChance; + private ItemStack optionalOutput; + + private float optionalChance2; + private ItemStack optionalOutput2; + + private int turns; + + @Override + public IGrinderRecipeBuilder withInput( ItemStack input ) + { + this.in = this.copy( input ); + + return this; + } + + @Override + public IGrinderRecipeBuilder withOutput( ItemStack output ) + { + this.out = this.copy( output ); + + return this; + } + + @Override + public IGrinderRecipeBuilder withFirstOptional( ItemStack optional, float chance ) + { + this.optionalOutput = this.copy( optional ); + this.optionalChance = chance; + + return this; + } + + @Override + public IGrinderRecipeBuilder withSecondOptional( ItemStack optional, float chance ) + { + this.optionalOutput2 = this.copy( optional ); + this.optionalChance2 = chance; + + return this; + } + + @Override + public IGrinderRecipeBuilder withTurns( int turns ) + { + this.turns = turns; + + return this; + } + + @Nonnull + @Override + public IGrinderRecipe build() + { + if( this.in == null ) + { + throw new IllegalStateException( "Null is not accepted as input itemstack." ); + } + + if( this.out == null ) + { + throw new IllegalStateException( "Null is not accepted as output itemstack." ); + } + + if( this.optionalOutput != null && ( this.optionalChance < 0.0 && this.optionalChance > 1.0 ) ) + { + throw new IllegalStateException( "Chance for the first optional must be within 0.0 - 1.0." ); + } + + if( this.optionalOutput == null && this.optionalOutput2 != null ) + { + throw new IllegalStateException( "Second optional can only be used when the first is also present." ); + } + + if( this.optionalOutput2 != null && ( this.optionalChance2 < 0.0 && this.optionalChance2 > 1.0 ) ) + { + throw new IllegalStateException( "Chance for the second optional must be within 0.0 - 1.0." ); + } + + if( this.turns <= 0 ) + { + throw new IllegalStateException( "Turns must be > 0" ); + } + + return new AppEngGrinderRecipe( this.in, this.out, this.optionalOutput, this.optionalOutput2, this.optionalChance, this.optionalChance2, this.turns ); + } + + private ItemStack copy( final ItemStack is ) + { + if( is != null ) + { + return is.copy(); + } + return null; + } + } } diff --git a/src/main/java/appeng/core/features/registries/inscriber/InscriberRegistry.java b/src/main/java/appeng/core/features/registries/inscriber/InscriberRegistry.java index dade498f..70374bc3 100644 --- a/src/main/java/appeng/core/features/registries/inscriber/InscriberRegistry.java +++ b/src/main/java/appeng/core/features/registries/inscriber/InscriberRegistry.java @@ -84,32 +84,42 @@ public final class InscriberRegistry implements IInscriberRegistry } @Override - public void addRecipe( final IInscriberRecipe recipe ) + public boolean addRecipe( final IInscriberRecipe recipe ) { if( recipe == null ) { throw new IllegalArgumentException( "Tried to add an invalid (null) inscriber recipe to the registry." ); } - this.recipes.add( recipe ); + if( this.recipes.add( recipe ) ) + { + recipe.getTopOptional().ifPresent( optionals::add ); + recipe.getBottomOptional().ifPresent( optionals::add ); - recipe.getTopOptional().ifPresent( optionals::add ); - recipe.getBottomOptional().ifPresent( optionals::add ); + this.inputs.addAll( recipe.getInputs() ); - this.inputs.addAll( recipe.getInputs() ); + return true; + } + + return false; } @Override - public void removeRecipe( final IInscriberRecipe toBeRemovedRecipe ) + public boolean removeRecipe( final IInscriberRecipe toBeRemovedRecipe ) { + boolean changed = false; + for( final Iterator iterator = this.recipes.iterator(); iterator.hasNext(); ) { final IInscriberRecipe recipe = iterator.next(); if( recipe.equals( toBeRemovedRecipe ) ) { + changed = true; iterator.remove(); } } + + return changed; } /** diff --git a/src/main/java/appeng/recipes/handlers/Grind.java b/src/main/java/appeng/recipes/handlers/Grind.java index 5bfab1e3..a64754bf 100644 --- a/src/main/java/appeng/recipes/handlers/Grind.java +++ b/src/main/java/appeng/recipes/handlers/Grind.java @@ -27,6 +27,9 @@ import appeng.api.AEApi; import appeng.api.exceptions.MissingIngredientError; import appeng.api.exceptions.RecipeError; import appeng.api.exceptions.RegistrationError; +import appeng.api.features.IGrinderRecipe; +import appeng.api.features.IGrinderRecipeBuilder; +import appeng.api.features.IGrinderRegistry; import appeng.api.recipes.ICraftHandler; import appeng.api.recipes.IIngredient; import appeng.recipes.RecipeHandler; @@ -60,7 +63,14 @@ public class Grind implements ICraftHandler, IWebsiteSerializer { for( final ItemStack is : this.pro_input.getItemStackSet() ) { - AEApi.instance().registries().grinder().addRecipe( is, this.pro_output[0].getItemStack(), 8 ); + final IGrinderRegistry grinderRegistry = AEApi.instance().registries().grinder(); + final IGrinderRecipeBuilder builder = grinderRegistry.builder(); + IGrinderRecipe grinderRecipe = builder.withInput( is ) + .withOutput( this.pro_output[0].getItemStack() ) + .withTurns( 8 ) + .build(); + + grinderRegistry.addRecipe( grinderRecipe ); } }