-
-
Notifications
You must be signed in to change notification settings - Fork 216
Make recipe placing from recipe book working with custom ingredients #4241
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: api-14
Are you sure you want to change the base?
Make recipe placing from recipe book working with custom ingredients #4241
Conversation
892d7bb to
d0732c5
Compare
d0732c5 to
9a819eb
Compare
|
This is a lot of Mixins to achieve one goal and is hard to justify to be this invasive. Can we simply this by modifying the second parameter of the |
|
Most of the injections in I used as much vanilla logic as I could, and no custom logic is performed if recipe is regular, so I'm not sure what does "this invasive" mean. |
|
We don't want to duplicate vanilla code in our code base unless we really have to, its too fragile and heavily increases maintenance burden and iteration times, that is a no go. If we can cut this down to few mixins instead of having a dozen, that would be a lot better. |
|
I wouldn't copy these 2 vanilla methods if I could really avoid it, it's just the bare minimum to make it work (as far as I figured out). Vanilla recipe placing logic is heavily bounded to |
|
I'm suggesting that we do the final filtering in |
|
You mean something like this? It does reduce duplicated code to just one simple method |
|
I mean that we literally do all the filtering in just the |
|
Wouldn't it remove like... 3 |
|
I'm expecting us to nuke 90% of this PR with just that change, am I missing something? Do we need to do anything else than just filter the items? |
|
While decomposing all the steps I understood that About everything else: We won't be able to capture items without duplicating if we don't use 3 Because of the
So... I don't understand how you suppose to reduce the PR by this much. |
|
Yes, I fully expect us to throw away the
|
|
2nd and 3rd points done. Didn't exactly understand what you meant in 1st (beacuse I think it's already done). |
src/main/java/org/spongepowered/common/item/recipe/crafting/SpongeStackedItemContents.java
Outdated
Show resolved
Hide resolved
src/main/java/org/spongepowered/common/item/recipe/crafting/SpongeStackedItemContents.java
Outdated
Show resolved
Hide resolved
src/main/java/org/spongepowered/common/item/recipe/crafting/SpongeStackedItemContents.java
Outdated
Show resolved
Hide resolved
src/mixins/java/org/spongepowered/common/mixin/core/recipebook/ServerPlaceRecipeMixin.java
Outdated
Show resolved
Hide resolved
src/mixins/java/org/spongepowered/common/mixin/core/recipebook/ServerPlaceRecipeMixin.java
Outdated
Show resolved
Hide resolved
src/mixins/java/org/spongepowered/common/mixin/core/recipebook/ServerPlaceRecipeMixin.java
Show resolved
Hide resolved
src/mixins/java/org/spongepowered/common/mixin/core/recipebook/ServerPlaceRecipeMixin.java
Outdated
Show resolved
Hide resolved
|
Fixed all the reviewed things |
| ) | ||
| ) | ||
| private ItemStack impl$adjustMatchingSlotFinder(final ItemStack craftInputStack) { | ||
| return this.impl$stackList.isEmpty() ? craftInputStack : this.impl$stackList.poll(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This still needs to account for the non empty craftInputStack. My initial suggestion was to just use it instead when its non empty, but now that I thought about it more, it actually just pulls more wrong items inside the slot. I think we should just bail when !ItemStack.isSameItemSameComponents(craftInputStack, this.impl$stackList.poll()) because theres nothing more we can do.
We should hit here when the players inventory is full and they have more stacks in the crafting input than they can fit in their inventory.
I think the following works as intended:
if (this.impl$stackList.isEmpty()) {
return original.call(...);
} else {
final ItemStack input = his.impl$stackList.poll();
if (!ItemStack.isSameItemSameComponents(craftInputStack, input)) {
return -1:
}
return original.call(..., input);
}There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the condition to fail should be !craftInputStack.isEmpty() && !ItemStack.isSameItemSameComponents(craftInputStack, input), or we won't be able to move items to empty crafting slots
29697b4 to
e62f219
Compare
e62f219 to
17ae6d8
Compare
|
Made tests, found a bug in mixin and a bug in vanilla. |
| pearl); | ||
|
|
||
| return Stream.of( | ||
| RecipePlaceTest.populateTests( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's not cram in this much parameters in to one single method, its quite hard to tell whats going on. I would suggest fluent API.
These tests are going to need to have more identifiable names so you can look at the test output and Ctrl + F the source code.
Something along the lines:
test("big_pearl_recipe", ...)
.success("Matching input", ...)
.fail("Missing pearl", ...)
.fail("Has stone", ...)
.fail("Asked where the bathroom is", ...)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replaced method with a lot of parameters with TestPopulator.
As an identifiable name for Ctrl+F I suggest TestContext#asTestName.
Updated everything else as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks a lot better now! Something I didn't happen to mention explicitly and just implicitly in the code snippet is that ideally you should be able to have dynamic number of successful and failure cases.
Given this is a bit of complex surface area as ingredients and their permutations can be quite large, it would make sense to have this written more flexibly to potentially add more edge cases or programmatically generate them in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something like this? Edge cases could be added via TestPopulator#test, those tests are applied before "match" test and thus can cancel it if needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nothing wrong with the actual TestEntry being fixed, but rather that the inputs like the provided inventories and their expected outputs should be easily definable so you can give any number of inventories that should success or fail.
So more like record TestEntry(boolean shiftClick, int clicks, List<ItemStack> inventory, List<ItemStack> input, List<ItemStack> expectedInputs)
This makes all the partialInventory and badInventory obsolete and they can be defined using the same method. Nothing wrong with providing additional helpers to create those test cases but it makes this a lot more straightforward from consumer stand point and when people are glancing at them and wondering where and why did things go work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't it.. already doable? WIth something like
Ah, right, that's actually totally fine!
Whats actually throwing me off is the fact you have crammed in the badInventory and the partialInventory in the same class, forcing you to define one successive and two failing cases at once. We should just generate one case for single entry. If you can just split them off to their own individual cases, like following the code snipped you just gave me, then that's fine! Feel free to use helper method to generate them.
Its better for tests to be verbose and expressive as they are meant to be easily understood.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved tests for bad layouts (which involved badInventory) to separate TestPopulator.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like theres still some partialInventory and partialInput and badInput leftover in the DefaultedTestPopulator
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just don't understand what you want me to do honestly. I changed it again but at this point I'm not even sure if this is what I had to change
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feel free to ask before you change anything. I understand that this is a bit new to you, and I'm honestly giving you a bit too vague feedback because I'm leaving gaps and just pointing to a direction and expecting some existing knowledge, that's on me.
The general gist of unit tests are that they should be very simple and not overly complex and easy to follow (and setup) and have most (if not all) relevant information on few lines. The general problem is that the shape was overly complex, you had to understand the program flow, had multiple inputs and tests with variety of different situations with different inputs (not very obvious) crammed in together.
It's important that test code is easy to understand so people don't have to spend a whole lot of time just to see what the test is doing. Its common to see these files to be very long and have repetitive copy & paste with just few changes for this exact reason.
So instead of having something like:
test(recipe).inventory(...).input(...).badInventory(...).badInput(...)its more natural to write something like:
test(recipe).inventory(...).input(...).state(success)
test(recipe).inventory(...).input(...).state(success)
test(recipe).inventory(...).input(...).state(fail)
test(recipe).inventory(...).input(...).state(fail)
test(recipe).inventory(...).input(...).state(fail)Now the test cases are obvious and their inputs and their expected outcomes can be read and understood in a single line without having to look around. It's also very easy to understand how to add new tests cases.
That said, yes, the badLayoutTests method is something I prefer. Its direct and obvious and hard to miss.
src/test/java/org/spongepowered/common/recipe/RecipePlaceTest.java
Outdated
Show resolved
Hide resolved
src/test/java/org/spongepowered/common/recipe/RecipePlaceTest.java
Outdated
Show resolved
Hide resolved
src/test/java/org/spongepowered/common/recipe/RecipePlaceTest.java
Outdated
Show resolved
Hide resolved
57c5f6a to
0733598
Compare
5534f54 to
1a94490
Compare
This reverts commit 1a94490.
a5c933e to
25698ea
Compare
e6d8ed9 to
a0bb7ae
Compare
| public Stream<TestContext> populate() { | ||
| return Stream.of(this.base) | ||
| .flatMap(context -> Stream.of( | ||
| context.name("Empty input").input(List.of()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These should be directly asked for by generating the tests with the the appropriate badInventory and badInput.
…Hell228/Sponge into api-14-fix/recipe-book-placer
…Hell228/Sponge into api-14-fix/recipe-book-placer
No description provided.