Improved IGrinderRegistry

Added a builder for grinder recipes similar to IInscriberRegistry.
Replaced different add methods with this builder.
IIinscriberRegistry#addRecipe and removeRecipe now return true on success.
This commit is contained in:
yueh 2017-01-31 22:54:54 +01:00
parent c720584e49
commit 6d289248bd
7 changed files with 363 additions and 122 deletions

View File

@ -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();
}

View File

@ -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<IGrinderRecipe> 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.

View File

@ -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<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
*
* @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 );
}

View File

@ -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 );
}
}
}

View File

@ -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<IGrinderRecipe> 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;
}
}
}

View File

@ -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<IInscriberRecipe> iterator = this.recipes.iterator(); iterator.hasNext(); )
{
final IInscriberRecipe recipe = iterator.next();
if( recipe.equals( toBeRemovedRecipe ) )
{
changed = true;
iterator.remove();
}
}
return changed;
}
/**

View File

@ -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 );
}
}