Skip to content

Refactor recipes#1098

Closed
kashike wants to merge 9 commits intoSpongePowered:bleedingfrom
kashike:feature/recipe
Closed

Refactor recipes#1098
kashike wants to merge 9 commits intoSpongePowered:bleedingfrom
kashike:feature/recipe

Conversation

@kashike
Copy link
Contributor

@kashike kashike commented Feb 24, 2016

API | Common
Adds #1027
Resolves #1028


This PR changes ShapedCraftingRecipe (previously ShapedRecipe) from using an x and y int-based system to an aisle-based system, with char being used to get/set ingredients.

Example usage:
sugar

/*
 * 1 x 1
 *
 * ---------
 * | REEDS |
 * ---------
 */
// Re-create the sugar recipe
ShapedCraftingRecipe.builder()
    .aisle(
        "#"
    )
    .where('#', ItemStack.builder().itemType(ItemTypes.REEDS).build())
    .result(ItemStack.builder().itemType(ItemTypes.SUGAR).build())
    .build();

lever

/*
 * 2 x 1
 *
 * ---------------
 * |    STICK    |
 * ---------------
 * | COBBLESTONE |
 * ---------------
 */
// Re-create the lever recipe
ShapedCraftingRecipe.builder()
    .aisle(
        "X",
        "#"
    )
    .where('X', ItemStack.builder().itemType(ItemTypes.STICK).build())
    .where('#', ItemStack.builder().itemType(ItemTypes.COBBLESTONE).build())
    .result(ItemStack.builder().itemType(ItemTypes.LEVER).build())
    .build();

ladders

/*
 * 3 x 3
 *
 * -------------------------
 * | STICK |       | STICK |
 * -------------------------
 * | STICK | STICK | STICK |
 * -------------------------
 * | STICK |       | STICK |
 * -------------------------
 */
// Re-create the ladder recipe
ShapedCraftingRecipe.builder()
    .aisle(
        "# #",
        "###",
        "# #"
    )
    .where('#', ItemStack.builder().itemType(ItemTypes.STICK).build())
    .result(ItemStack.builder().itemType(ItemTypes.LADDER).quantity(3).build())
    .build();

bedrock

/*
 * 3 x 3
 *
 * ---------------------
 * | BED |  BED  | BED |
 * ---------------------
 * | BED | STONE | BED |
 * ---------------------
 * | BED |  BED  | BED |
 * ---------------------
 */
ShapedCraftingRecipe.builder()
    .aisle(
        "BBB",
        "BRB",
        "BBB"
    )
    .where('B', ItemStack.builder().itemType(ItemTypes.BED).build())
    .where('R', ItemStack.builder().itemType(ItemTypes.STONE).build())
    .result(ItemStack.builder().itemType(ItemTypes.BEDROCK).build())
    .build();

@JBYoshi
Copy link
Member

JBYoshi commented Feb 24, 2016

Bed + stone (rock) = bedrock

😃

@kashike
Copy link
Contributor Author

kashike commented Feb 24, 2016

@JBYoshi You caught me. 😆

@Mumfrey
Copy link
Member

Mumfrey commented Feb 24, 2016

This is a really nice idea.

* @return The resultant item type
*/
List<ItemType> getResultTypes();
ItemType getResultType();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why remove the list?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I can tell, recipes may only return a single ItemStack as a result, so a single ItemType makes sense - correct me if wrong.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recipes can have more than one output, this was established a long time ago
#242 (comment)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Mumfrey
Copy link
Member

Mumfrey commented Feb 24, 2016

Just out of curiosity, where did the term 'aisle' come from?

@ST-DDT
Copy link
Member

ST-DDT commented Feb 24, 2016

How would you handle data stuff?
Requires blue or red color and returns blue or red wool?

@kashike
Copy link
Contributor Author

kashike commented Feb 24, 2016

@Mumfrey I wrote this and stuck it in a branch around the same time I made #1028 - I think I stole the name from FactoryBlockPattern, though

@ST-DDT That's part of the ItemStack.

@ST-DDT
Copy link
Member

ST-DDT commented Feb 24, 2016

@kashike So I have to create 16 recipies to create 1 item with 16 different data states?
What happens if I have two colors? 16x16 color => 256 recipies?

@simon816
Copy link
Contributor

These two API issues have been around for a long time, maybe you could see if you're able to fix them too? #463 #599 (just a thought)

@kinggoesgaming
Copy link
Contributor

@ST-DDT I was hyped about this till you mentioned this

@kashike
Copy link
Contributor Author

kashike commented Feb 24, 2016

@ST-DDT That is what vanilla itself does, yes.

@kashike
Copy link
Contributor Author

kashike commented Feb 24, 2016

Since mods can create their own class off of IRecipe, I don't see a way to ensuring all recipes go through this - @Mumfrey?

@simon816
Copy link
Contributor

@kashike This is just for ShapedRecipes, there are other types of recipe too. That's what the more generic Recipe class represents (IRecipe). Also note this issue: #599

* @return fluent interface
*/
Builder addResult(ItemStack result);
Builder result(ItemStack result);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be varargs

@Mumfrey
Copy link
Member

Mumfrey commented Feb 24, 2016

Since mods can create their own class off of IRecipe, I don't see a way to ensuring all recipes go through this - @Mumfrey?

This is why the work I'm currently doing on Mixin is so important. Yes it will allow us to address stuff like this.

* @return The ingredient
*/
Optional<ItemStack> getIngredient(Vector2i pos);
Optional<ItemStack> getIngredient(char symbol);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure on the usefulness of this method because it requires knowledge of how the recipe was created in the builder. I think an (x, y) coord would be better suited here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm yeah might as well I guess

@simon816
Copy link
Contributor

@Mumfrey in a mock-up implementation I did a long time ago (simon816/SpongeCommon@0184019) I was able to get around the problem by capturing the IRecipe instance when it gets registered and then attach a wrapping Sponge Recipe instance over it. (This was way before we used java 8)

* Gets the aisle.
*
* @return The aisle
*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that a copy? The Javadocs should mention this.

@Zidane
Copy link
Member

Zidane commented Feb 24, 2016

@simon816

Yeah we aren't doing wrapping. This is solvable with changes coming to Mixin where we can mix into implementors of IRecipe.

@felixoi
Copy link

felixoi commented Feb 24, 2016

What's about an option to only assign an ItemType to a char? That would fix @ST-DDT 's problem

@kashike
Copy link
Contributor Author

kashike commented Feb 24, 2016

@Feeliiix Would you like something like...

Builder where(char symbol, @Nullable ItemStack ingredient) throws IllegalArgumentException;

Builder where(char symbol, @Nullable ItemType ingredient) throws IllegalArgumentException;

?

@felixoi
Copy link

felixoi commented Feb 24, 2016

Yes, exactly.

@gabizou
Copy link
Member

gabizou commented Feb 24, 2016

It's very well possible that the where can take an ItemStackSnapshot, granted it'd be transitive to mod using ItemStack instances since there's damage values to consider, but for our sakes, it could very well match more than based on the damage value, but also the tag compound and any other custom data from plugins required.

@kashike
Copy link
Contributor Author

kashike commented Feb 24, 2016

We could accept ItemStack, ItemStackSnapshot, and ItemType?

@Zidane
Copy link
Member

Zidane commented Feb 24, 2016

+1 to ItemStackSnapshot.

@gabizou gabizou changed the title [WIP] Refactor recipes Refactor recipes Aug 3, 2016

public interface FurnaceRecipe extends Recipe {

float getExperience(GridInventory grid);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why GridInventory?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...and not something more targeted to an actual Furnace?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And it should return a doube. Missing javadoc.

@me4502
Copy link
Contributor

me4502 commented Oct 2, 2016

As a suggestion, should we have a 'CustomRecipe' or whatever, that accepts a predicate or function?

Basically that would allow plugins to create recipes similar to the fancy ones like armour dying.

@Deamon5550 Deamon5550 modified the milestones: Revision 6.0, Revision 5.0 Oct 18, 2016
*
* @param grid An ItemGrid as input
* @param grid A grid inventory as input
* @return A list of ItemStacks or {@link Optional#empty()} if the given
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or {@link Optional#empty()} to or an empty list

boolean remove(CraftingRecipe recipe);

/**
* Gets a {@link Collection} of all recipes this registry is aware of.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this immutable?

* Sets the aisle pattern for the shaped recipe.
*
* @param aisle A string array of ingredients
* @return fluent interface
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Case

*/
int getHeight();

interface Builder extends ResettableBuilder<ShapedCraftingRecipe, Builder> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doc

* @param result The resultant stacks
* @return fluent interface
*/
Builder results(Collection<ItemStack> result);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not accept Iterable?

/**
* A ShapedCraftingRecipe is a Recipe that has shape and fits into a grid.
*/
public interface ShapedCraftingRecipe extends CraftingRecipe {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Return a guava table of item stacks?

@liach
Copy link
Contributor

liach commented Dec 6, 2016

@kashike Status?

@Limeth
Copy link
Contributor

Limeth commented Dec 30, 2016

Can I offer my help here? I'd like to get recipes merged.

@Limeth
Copy link
Contributor

Limeth commented Dec 30, 2016

I like the idea of using Predicates to check the item stacks.

@kashike
Copy link
Contributor Author

kashike commented Dec 30, 2016

@Limeth I've gone ahead and added you to my forks. Feel free to make new commits, just don't modify the existing ones. 👍

* @return The builder
*/
Builder addResult(ItemStack result);
Builder results(ItemStack... results);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be default implemented.

* @param ingredients The ingredients
* @return The builder
*/
Builder ingredients(ItemStack... ingredients);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be default implemented.

* @param result The resultant stacks
* @return The builder
*/
Builder results(ItemStack... result);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be default implemented.


public interface FurnaceRecipe extends Recipe {

float getExperience(GridInventory grid);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And it should return a doube. Missing javadoc.

* @return The builder
*/
ShapelessRecipe build();
Builder results(Collection<ItemStack> result);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you use a Collection here and for the ShapedRecipe an Iterable?

@gabizou
Copy link
Member

gabizou commented Jan 10, 2017

@kashike I'm getting confused as to why there are now three PR's attempting to refactor recipes.

From what I can see, there's #1098 (this one), #1449 (Limeth's continuation of this one), and #1419 (Maxqia's refactor).

Normally, we should only have at most two PR's, but as it stands, there's some issues with all of them (this one being not updated). I'd like to get these PR's organized and some cleanup of reviews/comments from @SpongePowered/developers.

@Maxqia
Copy link
Contributor

Maxqia commented Jan 10, 2017

:P mine just kinda enveloped this one in response to Limeth's PR, My PR contains a lot of this PR's code...

@kashike
Copy link
Contributor Author

kashike commented Jan 11, 2017

@gabizou I gave this PR to @Limeth since they wanted to work on it and get recipes done. I didn't realise until now that a new PR was opened. I suggest @Maxqia and @Limeth work together to turn their two PRs into one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.