Skip to content

Generalize recipes and implement them#1119

Closed
Limeth wants to merge 1 commit intoSpongePowered:bleedingfrom
Limeth:feature/recipe-ii
Closed

Generalize recipes and implement them#1119
Limeth wants to merge 1 commit intoSpongePowered:bleedingfrom
Limeth:feature/recipe-ii

Conversation

@Limeth
Copy link
Copy Markdown

@Limeth Limeth commented Jan 3, 2017

SpongeAPI|SpongeCommon|SpongeForge

This is a WIP continuation of kashike's PR, with his consent.
It aims to generalize how recipes are registered and handled. Instead of checking the equality of the ingredients, it works by testing ingredient predicates. It also aims to let the user implement the recipe interfaces by themselves, making it, for example, possible to transfer NBT data from the ingredients to the result.
In this PR, ItemStackSnapshots are used extensively. This is to prevent the user from modifying the original ItemStack. I could instead provide an ItemStack#copy, but that doesn't make it visually obvious the original item won't change.

Crafting recipes

All recipes stored in CraftingManager must implement both IRecipe and CraftingRecipe.

Vanilla, mods:
delegation to native

  • IRecipe -- MixinIRecipe implements CraftingRecipe
  • ShapedRecipes -- MixinShapedRecipes implements ShapedCraftingRecipe
  • ShapelessRecipes -- MixinShapelessRecipes implements ShapelessCraftingRecipe

Sponge:
delegation to sponge by overriding both native & sponge

  • CraftingRecipe -- wrap in SpongeCustomCraftingRecipe? Is it possible to mix-in IRecipe? Feedback needed.
  • ShapedCraftingRecipe -- extends ShapedRecipes
  • ShapelessCraftingRecipe -- extends ShapelessRecipes

/**
* Delegates all NMS methods to the abstract methods
*/
public abstract class AbstractSpongeShapedCraftingRecipe extends ShapedRecipes implements ShapedCraftingRecipe {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nope.

Mix ShapedCraftingRecipe into ShapedRecipes. Otherwise, mod recipes won't be API recipes (and neither will Mojang ones...)

private final ShapedCraftingRecipe delegate;

public DelegateShapedCraftingRecipe(ShapedCraftingRecipe delegate) {
Preconditions.checkNotNull(delegate, "The delegate must not be null");
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This method is usually statically imported:
`checkNotNull(delegate, "delegate");

return false;
}

if (recipeNMS.getMetadata() != 32767 && recipeNMS.getMetadata() != inventoryNMS.getMetadata())
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What is 32767 for a magic number here?
Either create a constant with a meaningful name or add a comment.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I don't unfortunately know what exactly it is.

@Limeth Limeth force-pushed the feature/recipe-ii branch from ade6f80 to c3a0c37 Compare January 8, 2017 16:58
.map(itemStack -> itemStack.getItem() == ItemTypes.NONE)
.orElse(true);

if (!empty)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Missing brackets.

finalAisleX + "; " + finalAisleY + "] is not present. There should be" +
" one for each symbol in the aisle!"));

if (!ingredientPredicate.test(itemStack.createSnapshot()))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Missing brackets.

Preconditions.checkNotNull(mainItem);

this.mainItem = mainItem;
this.remainingItems = remainingItems == null ? ImmutableList.of() : ImmutableList.copyOf(remainingItems);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Mark the parameter @Nullable if it is to be null.


@Override
public ItemStackSnapshot getMainItem() {
return mainItem;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this.


@Override
public List<ItemStackSnapshot> getRemainingItems() {
return remainingItems;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this.


@Override
public int getHeight() {
return recipeHeight;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this.


@Override
public Optional<Predicate<ItemStackSnapshot>> getIngredientPredicate(int x, int y) {
return Optional.ofNullable(ingredients.get(x, y));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this.

checkState(!this.aisle.isEmpty(), "aisle must be set before setting aisle symbols");

if (ingredient != null) {
ingredientMap.put(symbol, ingredient);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this.


@Final
@Shadow
protected int recipeWidth;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

squash it onto one line:
@Final @Shadow protected int recipeWidth

private net.minecraft.item.ItemStack[] recipeItems;

public Optional<Predicate<ItemStackSnapshot>> sponge$getIngredientPredicate(int x, int y) {
if(x < 0 || x >= recipeWidth || y < 0 || y >= recipeHeight)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Missing brackets; space if (

@Limeth
Copy link
Copy Markdown
Author

Limeth commented Jan 9, 2017

I am currently kind of stuck. I can't quite figure out how to fix this mixin error I'm getting. I thought that maybe I had the hierarchy wrong and tried making MixinShapedRecipes implement MixinIRecipe, but that creates another error.

As a side question, does anyone know if there is an easy way to achieve this?

@Maxqia
Copy link
Copy Markdown
Contributor

Maxqia commented Jan 12, 2017

^ and that sir, is why you don't copy names from classes you're trying to mixin :P

@ST-DDT
Copy link
Copy Markdown
Member

ST-DDT commented Jan 13, 2017

@Limeth You asked for help? How can I help you?

@Limeth
Copy link
Copy Markdown
Author

Limeth commented Jan 13, 2017

I think I may have figured out the conversion between native and Sponge inventories, yay. See the latest commit.

@Limeth
Copy link
Copy Markdown
Author

Limeth commented Jan 13, 2017

@ST-DDT Thanks for the response! The errors seem to have magically disappeared when I switched machines and I think I've just made breakthrough step in the implementation of this PR, so I don't need help for now. I'm sure I'll get stuck again very soon, though! :D

@Limeth
Copy link
Copy Markdown
Author

Limeth commented Jan 14, 2017

Crafting recipes are working now. \o/

Copy link
Copy Markdown
Member

@gabizou gabizou left a comment

Choose a reason for hiding this comment

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

Minor style changes.

public abstract Slot getSlot(int slotId);

@Shadow
public ItemStack slotClick(int slotId, int dragType, ClickType clickTypeIn, EntityPlayer player) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If the method is public, you can mark it as abstract and avoid the actual method body.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Also, we prefer that the @Shadow annotations are on the same line as the method (unlike @Override).

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I would, but then I wouldn't be able to call it from here.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Ah yes, good point.

})
public abstract class MixinContainerCrafting extends MixinContainer {

private final Container this$ = (Container) (Object) this;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Just inline this field, this otherwise is ugly.


@SuppressWarnings("unchecked")
private List<CraftingRecipe> spongeRecipes() {
return (List<CraftingRecipe>) (List<?>) recipes;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why is there a level of indirection? It doesn't make sense unless there's something I'm missing.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You have getRecipes which is an override, and this spongeRecipes, which is something else? You can safely just eliminate this method entirely.

boolean matches(InventoryCrafting inv, net.minecraft.world.World worldIn);

@Shadow
net.minecraft.item.ItemStack getCraftingResult(InventoryCrafting inv);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Same line, and preferably keep these without spaces at the top of the mixin.

import java.util.stream.Collectors;

@Mixin(IRecipe.class)
public interface MixinIRecipe extends CraftingRecipe {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What you may want to do is annotate the class with @Implements(iface = @Interface(CraftingRecipe.class), prefix = "", unique = true)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I had it like that before, but ended up making the interface extend CraftingRecipe directly. Why should I put it back?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

the unique bits, it ensures that the methods won't overlap vanilla methods, but you can have both extending and @Implements. Right, @Mumfrey?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

[22:18:47] [main/ERROR] [mixin]: mixins.common.core.json:item.recipe.crafting.MixinIRecipe: Prefix  for iface Lorg/spongepowered/api/item/recipe/crafting/CraftingRecipe; is not valid

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

@gabizou ^ that's what is printed to the console when I use @Implements, I guess I should remove it?

@Override
public RecipeRegistry getRecipeRegistry() {
public SmeltingRecipeRegistry getSmeltingRecipeRegistry() {
throw new UnsupportedOperationException(); // TODO
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Does this PR not implement the smelting recipe registry?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Not yet. I can either start implementing the smelting recipe registry in this PR, or make another one when this is one is merged.


@Nonnull
public static Optional<ItemStack> getContainerItem(@Nonnull ItemStack itemStack) {
Preconditions.checkNotNull(itemStack, "The itemStack must not be null");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

methods from Preconditions should be statically imported.

@@ -36,7 +36,7 @@
// TODO
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This class was a stub. you should either implement it or remove if not needed

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Somehow forgot to remove it.


@Override
public ItemStackSnapshot getExemplaryResult() {
return recipe.getExemplaryResult();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Field accesses should be qualified with this. consistently throughout the codebase

Protip: most IDEs can do this automatically

net.minecraft.item.ItemStack inventoryNMS = ItemStackUtil.fromSnapshotToNative(inventoryStack);

if (!recipeNMS.isEmpty() || !inventoryNMS.isEmpty())
{
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

incorrect formatting, should have brace on previous line
(I know this is copied from vanilla code but formatting should be consistent with sponge's code)

@Limeth
Copy link
Copy Markdown
Author

Limeth commented Jan 16, 2017

Smelting recipes are now working too. \o/

@gabizou gabizou added version: 1.11 (u) API: 6 (unsupported since Jan 1st 2018) system: inventory status: wip Work in progress labels Jan 17, 2017
Copy link
Copy Markdown
Member

@gabizou gabizou left a comment

Choose a reason for hiding this comment

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

Code cleanup. Lots of mixed coding style, not sure if it's because it's from multiple authors or different IDE setups, but needs to match the current coding standards.


// Crafting

@Nonnull
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is already included in the package level annotations for parameters, methods, and fields. Don't clutter it up in the implementation.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

It's giving me warnings when it's not there. ¯_(ツ)_/¯

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You have to tell your IDE what the NonnullByDefault annotation is, look it up for your ide.

checkNotNull(itemStack, "The itemStack must not be null");

net.minecraft.item.ItemStack nmsStack = ItemStackUtil.toNative(itemStack);
Item nmsItem = nmsStack.getItem();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Could probably do some short circuit to ItemStack.isValid() which was added in 1.11.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I can't seem to find that method.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Sorry, isEmpty().

}

@Override
@Nonnull
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

No, more clutter.

import java.util.function.Supplier;

public abstract class AbstractSpongeCraftingRecipe implements CraftingRecipe, IRecipe {
@Override
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Spacing here, group static methods together versus mixed in with instance methods. Or, you can mark the groups with comments.

return matches(this::isValid, inv, worldIn);
}

public static boolean matches(BiFunction<GridInventory, World, Boolean> isValid, InventoryCrafting inv, net.minecraft.world.World worldIn) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do recipes require World instances? I'd imagine that we'd only ever want to deal with WorldServer instances (not client based worlds).

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Yes, see CraftingManager#getRemainingItems(InventoryCrafting, World).


@Override
@Nonnull
public Optional<Predicate<ItemStackSnapshot>> getIngredientPredicate(int x, int y) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why is this even an Optional? Sounds like bad use to be honest. If anything, it can just be any or none predicate.

private final List<SmeltingRecipe> recipes = Lists.newArrayList();

/**
* @author Limeth
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Need more than this. Needs a date, needs some @reason explanation.

*/
@Overwrite
public void addSmeltingRecipe(ItemStack input, ItemStack stack, float experience)
{
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The coding style is awkward here.

Predicate<ItemStackSnapshot> ingredientPredicate = new MatchSmeltingVanillaItemStack(exemplaryIngredient);

this.recipes.add(new SpongeSmeltingRecipe(exemplaryResult,
exemplaryIngredient, ingredientPredicate, experience));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why the awkward line break?

import org.spongepowered.api.event.cause.entity.damage.DamageType;
import org.spongepowered.api.event.cause.entity.damage.source.*;
import org.spongepowered.api.event.cause.entity.spawn.*;
import org.spongepowered.api.event.cause.entity.damage.source.BlockDamageSource;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Don't touch star imports from things that you're not touching.


@Override
public int getRecipeSize() {
return getRecipeSize(this::getSize);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

?????

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Consistency with other static methods in this class; see usage in SpongeShapedCraftingRecipe.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

wat? I'm still very confused as to why this is necessary? seems like a massive hack/anti-pattern.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

SpongeShapedCraftingRecipe must extend ShapedRecipes, but cannot extend two classes at the same time, so methods in AbstractSpongeCraftingRecipe are declared statically and are called from within SpongeShapedCraftingRecipe.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Move them to an interface?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

or just duplicate the implementations, anything but this.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The pattern is just IoC but that simple fact is being occluded by the actual method of implementation. I had the same problem with Adapter but solved it in a slightly clearer way of abstracting the logic away to an inner class Adapter.Logic and then any Trait mixins call back against the static methods therein.

Honestly for consistency a similar approach should be used here. Instead of static methods in a base class, wrap the static methods in a Logic or Operations class and call back against it. The mixins should also probably be Trait in this case to denote their usage.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I can't quite figure out what you mean by the Trait and can't quite picture how the end result would look, would you please link me the code you wrote?

/**
* @author Limeth
*/
@Overwrite
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All these overwrites make me twitchy. You should atleast maintain the old functionality of the class (ie. still put things into the maps) or you're going to break mods.

@Limeth
Copy link
Copy Markdown
Author

Limeth commented Jan 18, 2017

@Deamon5550 I've rewritten the MixinFurnaceRecipes class to make it mod-friendly.

*/
@Overwrite
public float getSmeltingExperience(ItemStack stack) {
@Inject(method = "getSmeltingExperience", at = @At("RETURN"))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Shouldn't this be also set to cancellable?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It's using setReturnValue so yes, it needs to be cancellable or it will throw an exception if that code path is followed.

}

public static MatchCraftingVanillaItemStack never() {
return new MatchCraftingVanillaItemStack();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

IMO it would be better if you just return/use a simple predicate -> false here.
You could even cache the instance, if it is needed at all. (See the other comment)

@Override
public Predicate<ItemStackSnapshot> getIngredientPredicate(int x, int y) {
if (x < 0 || x >= recipeWidth || y < 0 || y >= recipeHeight) {
return MatchCraftingVanillaItemStack.never();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I would rather throw an IndexOutOfBoundsException here.

* @return Whether the stacks match according to the vanilla Minecraft
* behavior
*/
public static boolean matchesVanillaItemStack(ItemStackSnapshot recipeStack, ItemStackSnapshot inventoryStack) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggestion: We should probably expose this somewhere in the API. (Maybe in the CraftingRecipeRegistry or ISS?)
Either as method or as static field storing a Function<ISS,Predicate<ISS>>.

That way we allow some default matching combined with .and(someCostumConditions).

What do you think about it? Or shall we do that later?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

The behavior is specific to crafting recipes, smelting recipes use a different method, so I think it's a good idea to expose it in the CraftingRecipeRegistry and do the same for smelting recipes.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm not fond of just a "catch all" matching for ItemStacks since there can be various "this is allowed" matches, including things where it just matches the ItemType, ItemType and quantity, ItemType and NBT, all of the above, etc.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

What do you propose?

@Limeth Limeth changed the title [WIP] Generalize recipes and implement them Generalize recipes and implement them Jan 19, 2017
@Limeth
Copy link
Copy Markdown
Author

Limeth commented Jan 25, 2017

Some feedback would be welcome.

Copy link
Copy Markdown
Contributor

@kashike kashike left a comment

Choose a reason for hiding this comment

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

Please reformat to follow our codestyle. You are missing this. everywhere, braces missing/on wrong lines, etc.
Additionally, be sure to checkNotNull parameters to give a nicer NullPointerException message.

Iterator<IInventory> inventories = fabric.allInventories().iterator();
InventoryCrafting inventoryCrafting = (InventoryCrafting) inventories.next();

if(inventories.hasNext())
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

if (
missing braces

ItemStack nativeIngredient = ItemStackUtil.fromSnapshotToNative(ingredient);

for (Map.Entry<ItemStack, ItemStack> entry : this.smeltingList.entrySet())
{
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Wrong formatting.


@Override
public int getWidth() {
return recipeWidth;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this.


@Override
public int getHeight() {
return recipeHeight;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this.

@Override
@Nonnull
public List<Predicate<ItemStackSnapshot>> getIngredientPredicates() {
return recipeItems.stream()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this.

public MatchSmeltingVanillaItemStack(ItemStackSnapshot itemStackSnapshot) {
checkNotNull(itemStackSnapshot, "The itemStackSnapshot must not be null");

this.itemStackSnapshot = itemStackSnapshot;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this.itemStackSnapshot = checkNotNull(itemStackSnapshot, "The itemStackSnapshot must not be null");


@Override
public int getSize() {
return ingredients.size();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this.


@Override
public List<ItemStackSnapshot> getRemainingItems(GridInventory grid) {
return StreamSupport.stream(grid.<Slot>slots().spliterator(), false)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

checkNotNull(grid, "grid")


@Override
public ItemStackSnapshot getExemplaryResult() {
return exemplaryResult;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this.


@Override
public List<Predicate<ItemStackSnapshot>> getIngredientPredicates() {
return ingredients;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this.

@Limeth Limeth force-pushed the feature/recipe-ii branch from 2d6e838 to e4544b3 Compare January 25, 2017 15:31
@Limeth
Copy link
Copy Markdown
Author

Limeth commented Jan 25, 2017

Changes made as suggested, waiting for more feedback.

@Limeth
Copy link
Copy Markdown
Author

Limeth commented Feb 6, 2017

This PR is not dead! I am determined to get it merged. :D

@Aaron1011
Copy link
Copy Markdown
Contributor

@Limeth: Can you rebase this against bleeding?

@Limeth Limeth force-pushed the feature/recipe-ii branch 2 times, most recently from ee4c52c to 9e86bcb Compare February 7, 2017 21:00
@Limeth
Copy link
Copy Markdown
Author

Limeth commented Feb 7, 2017

Rebased against bleeding.

@Aaron1011
Copy link
Copy Markdown
Contributor

@Limeth: There still appear to be merge conflicts

@Limeth Limeth force-pushed the feature/recipe-ii branch from 9e86bcb to f5d4cec Compare February 8, 2017 14:33
@Limeth
Copy link
Copy Markdown
Author

Limeth commented Feb 8, 2017

Conflicting commits appeared within that hour. Rebased again, should be fine now.

@Limeth
Copy link
Copy Markdown
Author

Limeth commented Feb 13, 2017

@bloodmc @gabizou @Zidane Thoughts?

Copy link
Copy Markdown
Member

@gabizou gabizou left a comment

Choose a reason for hiding this comment

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

Multiple changes needed, mostly style, but there's too much noise at the moment.

ItemStack containerStack = ItemStackUtil.fromNative(nmsContainerStack);

return Optional.of(containerStack);
} else {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Useless else statement.

checkNotNull(world, "world");

return Sponge.getRegistry().getCraftingRecipeRegistry()
.findMatchingRecipe(this.craftingGrid, world);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Awkwardly separated line.

@Override
protected void init(SlotProvider<IInventory, ItemStack> slots) {
super.init(slots, false);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I like to separate variable assignments and method calls with a space.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

That's fine, but you shouldn't do this here because you haven't changed anything else in this class.

* @return Whether the stacks match according to the vanilla Minecraft
* behavior
*/
public static boolean matchesVanillaItemStack(ItemStackSnapshot recipeStack, ItemStackSnapshot inventoryStack) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm not fond of just a "catch all" matching for ItemStacks since there can be various "this is allowed" matches, including things where it just matches the ItemType, ItemType and quantity, ItemType and NBT, all of the above, etc.

@Override
public ShapedCraftingRecipe.Builder where(char symbol, Predicate<ItemStackSnapshot> ingredient) throws IllegalArgumentException {
checkState(!this.aisle.isEmpty(), "aisle must be set before setting aisle symbols");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You have a lot of extra new lines that just add empty space, and it's getting distracting/excessive. Condense where possible.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Should I just remove all empty lines? How can I tell which ones you want preserved? Removing this one in particular goes against my skin, because not separating a code block with a new line looks confusing. I'd like to point out that imo I've spent too much time fixing code style by reading the reviews, as most of them have been about it. It's quite annoying having to wait for the reviews and finding out it's just another one about code style. It would be much easier for me if I had a clear understandable guide on what code style you prefer.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Thanks @ziceptor, I must've missed that. The question stays, though: Which empty lines are distracting? Which should I keep/remove?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm commenting where I'm finding useless new lines for you to get an idea.


checkState(width > 0, "The aisle cannot be empty.");

do {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is a very weird loop. I'm confused as to why it can't just be a for-loop with the iterator...

byIncreasingTheSlotIndex:
for (int x = 0; x < grid.getColumns(); x++) {
ItemStackSnapshot itemStackSnapshot = grid.getSlot(x, y)
.flatMap(Slot::peek).map(ItemStack::createSnapshot)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Don't have multiple calls on the same line for chaining in this case. split up between two separate lines.


if (ingredient.test(itemStackSnapshot)) {
iterator.remove();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

More useless empty lines.

continue;
}

Iterator<Predicate<ItemStackSnapshot>> iterator = ingredients.iterator();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This logic is lacking comments to see what is actually going on (Yes, it's valid checking, but how is it valid checking?)


NonNullList<ItemStack> result = NonNullList.withSize(inv.getSizeInventory(), ItemStack.EMPTY);

for(int i = 0; i < spongeResult.size(); i++) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You need a space after for


for (IRecipe irecipe : this.recipes) {
if (irecipe.matches(nativeInventory, (net.minecraft.world.World) world))
{
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should be on the previous line

Copy link
Copy Markdown
Member

@gabizou gabizou left a comment

Choose a reason for hiding this comment

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

Commented for some clarification of changes requested.

return RecipeUtil.findMatchingRecipe(this.inventory, this.craftingLens.getCraftingGrid(), this.craftingLens.getOutputSlot());
public Optional<CraftingRecipe> getRecipe(World world) {
checkNotNull(world, "world");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This line is a distracting useless line, adding an extra whitespace where it's not really necessary or used.

public static GridInventory toSpongeInventory(InventoryCrafting inv) {
DefaultInventoryFabric fabric = new DefaultInventoryFabric(inv);
GridInventoryLensImpl lens = new GridInventoryLensImpl(0, inv.getWidth(), inv.getHeight(), inv.getWidth(), SlotLensImpl::new);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This line is unnecessary extra, there's no real reason for it to be honest.

if (inventories.hasNext()) {
throw new IllegalStateException("Another inventory found: " + inventories.next());
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This line can be removed.

Fabric<IInventory> fabric = ((GridInventoryAdapter) inv).getInventory();
Iterator<IInventory> inventories = fabric.allInventories().iterator();
InventoryCrafting inventoryCrafting = (InventoryCrafting) inventories.next();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This line is "ok" since you have some logic going on in the next few lines.

public static ItemStack getCraftingResult(Function<GridInventory, ItemStackSnapshot> getResult, InventoryCrafting inv) {
ItemStackSnapshot result = getResult.apply(toSpongeInventory(inv));

Preconditions.checkNotNull(result, "The Sponge implementation returned a `null` result.");
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You can static import the checkNotNull method (We do so throughout the implementation)

int gridY = gapY + (gapY >= offsetY ? getHeight() : 0);
boolean empty = grid.getSlot(gridX, gridY)
.flatMap(Slot::peek)
.map(itemStack -> itemStack.getItem() == ItemTypes.NONE)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Does this need to check for isEmpty() itemstacks?

if (aisle != null) {
Collections.addAll(this.aisle, aisle);
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Useless empty line.

@Override
public ShapedCraftingRecipe.Builder where(char symbol, Predicate<ItemStackSnapshot> ingredient) throws IllegalArgumentException {
checkState(!this.aisle.isEmpty(), "aisle must be set before setting aisle symbols");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm commenting where I'm finding useless new lines for you to get an idea.

@Override
public ShapedCraftingRecipe.Builder result(ItemStackSnapshot result) {
Preconditions.checkNotNull(result, "result");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Useless empty line.

Preconditions.checkNotNull(result, "result");

this.result = result;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Useless empty line.

@Faithcaio Faithcaio mentioned this pull request Jun 15, 2017
@kashike
Copy link
Copy Markdown
Contributor

kashike commented Jun 15, 2017

Superseded by #1395

@kashike kashike closed this Jun 15, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status: wip Work in progress system: inventory version: 1.11 (u) API: 6 (unsupported since Jan 1st 2018)

Projects

None yet

Development

Successfully merging this pull request may close these issues.