-
Notifications
You must be signed in to change notification settings - Fork 31
Refactor JEI description, add support for fluids #382
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: master
Are you sure you want to change the base?
Changes from 1 commit
9f94b4c
bebadea
53b5d53
1c47a33
b00942a
f8b7177
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,60 +1,107 @@ | ||
| package com.cleanroommc.groovyscript.compat.mods.jei; | ||
|
|
||
| import java.util.Arrays; | ||
| import java.util.List; | ||
| import java.util.Objects; | ||
| import java.util.stream.Collectors; | ||
| import java.util.stream.Stream; | ||
|
|
||
| import javax.annotation.Nonnull; | ||
| import javax.annotation.Nullable; | ||
|
|
||
| import com.cleanroommc.groovyscript.api.GroovyBlacklist; | ||
| import com.cleanroommc.groovyscript.api.GroovyLog; | ||
| import com.cleanroommc.groovyscript.api.IIngredient; | ||
| import com.cleanroommc.groovyscript.api.documentation.annotations.Example; | ||
| import com.cleanroommc.groovyscript.api.documentation.annotations.MethodDescription; | ||
| import com.cleanroommc.groovyscript.api.documentation.annotations.RegistryDescription; | ||
| import com.cleanroommc.groovyscript.core.mixin.jei.IngredientInfoRecipeAccessor; | ||
| import com.cleanroommc.groovyscript.helper.ingredient.ItemsIngredient; | ||
| import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; | ||
|
|
||
| import mezz.jei.api.IModRegistry; | ||
| import mezz.jei.api.IRecipeRegistry; | ||
| import mezz.jei.api.ingredients.VanillaTypes; | ||
| import mezz.jei.api.recipe.IIngredientType; | ||
| import mezz.jei.api.recipe.VanillaRecipeCategoryUid; | ||
| import mezz.jei.plugins.jei.info.IngredientInfoRecipeCategory; | ||
| import net.minecraft.item.ItemStack; | ||
| import org.apache.commons.lang3.tuple.Pair; | ||
|
|
||
| import java.util.Arrays; | ||
| import java.util.Collections; | ||
| import java.util.List; | ||
| import java.util.stream.Collectors; | ||
| import java.util.stream.Stream; | ||
| import net.minecraftforge.fluids.FluidStack; | ||
|
|
||
| @RegistryDescription(category = RegistryDescription.Category.ENTRIES) | ||
| public class Description extends VirtualizedRegistry<Pair<List<IIngredient>, List<String>>> { | ||
| public class Description extends VirtualizedRegistry<Description.DescriptionEntry<?>> { | ||
|
|
||
| static class DescriptionEntry<T> { | ||
| T representative; | ||
| List<T> ingredients; | ||
| IIngredientType<T> ingredientType; | ||
| String[] descriptionKeys; | ||
|
|
||
| DescriptionEntry(@Nonnull List<T> ingredients, @Nonnull IIngredientType<T> ingredientType, @Nullable List<String> descriptionKeys) { | ||
| if (ingredients.isEmpty()) { | ||
| throw new IllegalArgumentException("JEI Description Entries must not have an empty list of ingredients, got " + ingredients); | ||
| } | ||
| Objects.requireNonNull(ingredientType); | ||
|
|
||
| this.ingredients = ingredients; | ||
| this.ingredientType = ingredientType; | ||
| this.representative = this.ingredients.get(0); | ||
| Objects.requireNonNull(representative); | ||
|
|
||
| this.descriptionKeys = descriptionKeys == null ? new String[0] : descriptionKeys.toArray(new String[0]); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Called by {@link JeiPlugin#register} | ||
| */ | ||
| @SuppressWarnings("unchecked") | ||
| @GroovyBlacklist | ||
| public void applyAdditions(IModRegistry modRegistry) { | ||
| for (Pair<List<IIngredient>, List<String>> entry : this.getScriptedRecipes()) { | ||
| modRegistry.addIngredientInfo( | ||
| entry.getLeft().stream().flatMap(x -> Stream.of(x.getMatchingStacks())).collect(Collectors.toList()), | ||
| // Currently, it is only possible to add VanillaTypes.ITEM. It may be desirable to add the ability to do other types. | ||
| VanillaTypes.ITEM, | ||
| entry.getRight().toArray(new String[0])); | ||
| for (DescriptionEntry<?> entry : this.getScriptedRecipes()) { | ||
| System.out.println("adding entry: " + entry); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. println |
||
| if (entry.representative instanceof ItemStack) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. would suggest ensuring everything is the same
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not possible due to a Java quirk, that I have already outlined in the Discord channel. The JEI API exposes an overloaded function like this: If |
||
| modRegistry.addIngredientInfo((List<ItemStack>) entry.ingredients, (IIngredientType<ItemStack>) entry.ingredientType, entry.descriptionKeys); | ||
| } else if (entry.representative instanceof FluidStack) { | ||
| modRegistry.addIngredientInfo((List<FluidStack>) entry.ingredients, (IIngredientType<FluidStack>) entry.ingredientType, entry.descriptionKeys); | ||
| } else { | ||
| GroovyLog.msg("Got a Description Entry of an invalid type, this is probably a bug in Groovyscript").error().post(); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private boolean compareObjects(Object inEntry, Object inRegistry) { | ||
| if (inEntry instanceof ItemStack ieStack) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. since this happens only in
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The problem is sometimes you need to remove description from an item with a specific NBT, which checking only the ID doesn't. I wanted to keep the old logic in regards to this. Though I don't really like how this turned out, yeah
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See my comment on |
||
| return inRegistry instanceof ItemStack irStack && new ItemsIngredient(ieStack).test(irStack); | ||
| } else if (inEntry instanceof FluidStack ieStack) { | ||
| return inRegistry instanceof FluidStack irStack && ieStack.getFluid().equals(irStack.getFluid()); | ||
| } else { | ||
| GroovyLog.msg("Got a Description Entry of type {} which is not supported, this is probably a bug in Groovyscript", inEntry.getClass().getName()) | ||
| .error() | ||
| .post(); | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Called by {@link JeiPlugin#afterRuntimeAvailable()} | ||
| */ | ||
| @SuppressWarnings("unchecked") | ||
| @GroovyBlacklist | ||
| public void applyRemovals(IRecipeRegistry recipeRegistry) { | ||
| IngredientInfoRecipeCategory category = (IngredientInfoRecipeCategory) recipeRegistry.getRecipeCategory(VanillaRecipeCategoryUid.INFORMATION); | ||
| if (category != null) { | ||
| recipeRegistry.getRecipeWrappers(category).forEach(wrapper -> { | ||
| IngredientInfoRecipeAccessor<?> accessor = (IngredientInfoRecipeAccessor<?>) wrapper; | ||
|
|
||
| // Currently, it is only possible to remove VanillaTypes.ITEM. It may be desirable to add the ability to do other types. | ||
| if (!VanillaTypes.ITEM.equals(accessor.getIngredientType())) return; | ||
|
|
||
| for (Pair<List<IIngredient>, List<String>> entry : this.getBackupRecipes()) { | ||
| if (entry.getKey() | ||
| for (DescriptionEntry<?> entry : this.getBackupRecipes()) { | ||
| System.out.println("removing entry: " + entry); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. println
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 1 am coding ❤️ |
||
| if (!entry.ingredientType.equals(accessor.getIngredientType())) continue; | ||
| if (entry.ingredients | ||
| .stream() | ||
| .anyMatch(x -> accessor.getIngredients().stream().anyMatch(a -> a instanceof ItemStack itemStack && x.test(itemStack)))) { | ||
| .anyMatch(x -> accessor.getIngredients().stream().anyMatch(a -> compareObjects(x, a)))) { | ||
| // the API seems to be broken hence the cast | ||
| entry.descriptionKeys = ((List<String>)wrapper.getDescription()).toArray(new String[0]); | ||
| recipeRegistry.hideRecipe(wrapper, VanillaRecipeCategoryUid.INFORMATION); | ||
| } | ||
| } | ||
|
|
@@ -69,32 +116,58 @@ public void onReload() { | |
| } | ||
|
|
||
| @MethodDescription(type = MethodDescription.Type.ADDITION) | ||
| public void add(List<IIngredient> target, List<String> description) { | ||
| addScripted(Pair.of(target, description)); | ||
| public void add(IIngredient[] target, String... description) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe do
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, we could do that I guess, that would be much better in terms of future flexibility too
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this changed to array? Lists are much nicer in groovy. |
||
| addScripted(new DescriptionEntry<>( | ||
| Stream.of(target).flatMap(x -> Stream.of(x.getMatchingStacks())).collect(Collectors.toList()), | ||
| VanillaTypes.ITEM, | ||
| Arrays.asList(description))); | ||
| } | ||
|
|
||
| @MethodDescription(type = MethodDescription.Type.ADDITION) | ||
| public void add(List<IIngredient> target, String... description) { | ||
| addScripted(Pair.of(target, Arrays.asList(description))); | ||
| public void add(IIngredient[] target, List<String> description) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This too
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. because then we cannot overload based on the input type, as all lists cast down to |
||
| add(target, description.toArray(new String[0])); | ||
| } | ||
|
|
||
| @MethodDescription(type = MethodDescription.Type.ADDITION, example = @Example("item('minecraft:clay'), ['wow', 'this', 'is', 'neat']")) | ||
| public void add(IIngredient target, List<String> description) { | ||
| addScripted(Pair.of(Collections.singletonList(target), description)); | ||
| add(new IIngredient[]{target}, description); | ||
| } | ||
|
|
||
| @MethodDescription(type = MethodDescription.Type.ADDITION, example = @Example("item('minecraft:gold_ingot'), 'groovyscript.recipe.fluid_recipe'")) | ||
| public void add(IIngredient target, String... description) { | ||
| addScripted(Pair.of(Collections.singletonList(target), Arrays.asList(description))); | ||
| add(new IIngredient[]{target}, description); | ||
| } | ||
|
|
||
| @MethodDescription(type = MethodDescription.Type.ADDITION) | ||
| public void add(FluidStack[] target, String... description) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. List > array |
||
| addScripted(new DescriptionEntry<>( | ||
| Arrays.asList(target), | ||
| VanillaTypes.FLUID, | ||
| Arrays.asList(description))); | ||
| } | ||
|
|
||
| @MethodDescription(type = MethodDescription.Type.ADDITION) | ||
| public void add(FluidStack[] target, List<String> description) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. List > array |
||
| add(target, description.toArray(new String[0])); | ||
| } | ||
|
|
||
| @MethodDescription(type = MethodDescription.Type.ADDITION, example = @Example("fluid('lava') * 500, ['very', 'hot', 'fluid']")) | ||
| public void add(FluidStack target, List<String> description) { | ||
| add(new FluidStack[]{target}, description); | ||
| } | ||
|
|
||
| @MethodDescription(type = MethodDescription.Type.ADDITION, example = @Example("fluid('water') * 1000, 'groovyscript.recipe.fluid_recipe'")) | ||
| public void add(FluidStack target, String... description) { | ||
| add(new FluidStack[]{target}, description); | ||
| } | ||
|
|
||
| @MethodDescription(example = @Example(value = "item('thaumcraft:triple_meat_treat')", commented = true)) | ||
| public void remove(List<IIngredient> target) { | ||
| addBackup(Pair.of(target, null)); | ||
| public void remove(IIngredient target) { | ||
| addBackup(new DescriptionEntry<>(Arrays.asList(target.getMatchingStacks()), VanillaTypes.ITEM, null)); | ||
| } | ||
|
|
||
| @MethodDescription | ||
| public void remove(IIngredient... target) { | ||
| addBackup(Pair.of(Arrays.asList(target), null)); | ||
| @MethodDescription(example = @Example(value = "fluid('water')", commented = true)) | ||
| public void remove(FluidStack target) { | ||
| addBackup(new DescriptionEntry<>(Arrays.asList(target), VanillaTypes.FLUID, null)); | ||
| } | ||
| } | ||
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.
think this needs
publicThere 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.
As of right now it's only used within the class, any reason why?
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.
part of the signature,
Description extends VirtualizedRegistry<Description.DescriptionEntry<?>>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.
is this for consistency reasons? it works fine as is, but if its for consistency idm fixing