-
Notifications
You must be signed in to change notification settings - Fork 204
Update to MUI 3.0.6 and generify recipe transfers from JEI #2900
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 all commits
d6cdaad
93917c3
0107888
b8d6a3a
5ad8370
930935b
f9a10b5
79403b7
80cdbb1
633ae5a
9243635
4363e27
f6943c1
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,15 +1,35 @@ | ||
| package gregtech.api.mui; | ||
|
|
||
| import gregtech.api.GTValues; | ||
| import gregtech.client.ClientProxy; | ||
| import gregtech.integration.jei.JustEnoughItemsModule; | ||
|
|
||
| import net.minecraftforge.fml.relauncher.Side; | ||
| import net.minecraftforge.fml.relauncher.SideOnly; | ||
|
|
||
| import com.cleanroommc.modularui.integration.recipeviewer.RecipeViewerRecipeTransferHandler; | ||
| import com.cleanroommc.modularui.screen.ModularPanel; | ||
| import com.cleanroommc.modularui.screen.ModularScreen; | ||
| import com.cleanroommc.modularui.value.sync.SyncHandler; | ||
| import com.cleanroommc.modularui.widget.Widget; | ||
| import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap; | ||
| import it.unimi.dsi.fastutil.ints.Int2ObjectMap; | ||
| import it.unimi.dsi.fastutil.ints.IntComparators; | ||
| import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; | ||
| import mezz.jei.api.gui.IRecipeLayout; | ||
| import mezz.jei.api.recipe.transfer.IRecipeTransferError; | ||
| import org.jetbrains.annotations.NotNull; | ||
|
|
||
| import java.util.Map; | ||
|
|
||
| @SuppressWarnings("UnstableApiUsage") | ||
| @SideOnly(Side.CLIENT) | ||
| public class GregTechGuiScreen extends ModularScreen { | ||
| public class GregTechGuiScreen extends ModularScreen implements RecipeViewerRecipeTransferHandler { | ||
|
|
||
| // Stores lists of higher priority recipe receivers to the left of the tree | ||
| @SideOnly(Side.CLIENT) | ||
| private static final Int2ObjectMap<Map<String, IRecipeTransferReceiver>> registeredRecipeTransferReceivers = new Int2ObjectAVLTreeMap<>( | ||
| IntComparators.OPPOSITE_COMPARATOR); | ||
|
Comment on lines
+31
to
+32
Contributor
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. i feel like there could be a better way of doing this instead of a nested map, perhaps a combining the string key and priority in an inner class or a |
||
|
|
||
| public GregTechGuiScreen(ModularPanel mainPanel) { | ||
| this(mainPanel, GTGuiTheme.STANDARD); | ||
|
|
@@ -27,4 +47,86 @@ public GregTechGuiScreen(String owner, ModularPanel mainPanel, String themeId) { | |
| super(owner, mainPanel); | ||
| useTheme(themeId); | ||
| } | ||
|
|
||
| @Override | ||
| public void onClose() { | ||
| // Only clear all registered recipe receivers when the UI is truly closing, ie not just opening JEI over it. | ||
| if (ClientProxy.isGUIClosingPermanently) { | ||
| // Clear all registered recipe receivers on UI close, just in case. | ||
| registeredRecipeTransferReceivers.clear(); | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| public IRecipeTransferError transferRecipe(IRecipeLayout recipeLayout, boolean maxTransfer, boolean simulate) { | ||
| // Receivers are sorted high to low on registration | ||
| for (Map<String, IRecipeTransferReceiver> subMap : registeredRecipeTransferReceivers.values()) { | ||
| for (IRecipeTransferReceiver receiver : subMap.values()) { | ||
| IRecipeTransferError result = receiver.receiveRecipe(recipeLayout, maxTransfer, simulate); | ||
| if (result != null && result.getType() == IRecipeTransferError.Type.INTERNAL) continue; | ||
| return result; | ||
| } | ||
| } | ||
|
|
||
| // No valid transfer handler was found | ||
| return JustEnoughItemsModule.transferHelper.createInternalError(); | ||
| } | ||
|
|
||
| /** | ||
| * Register an {@link IRecipeTransferReceiver} to this screen. <br/> | ||
| * Recipe transfer handlers registered through this method will have a priority of {@code 0}. <br/> | ||
| * <b>Important:</b> ensure that you remove this handler with {@link #removeRecipeTransferHandler(String)} when it's | ||
| * disposed of! <br/> | ||
| * Remove it by calling {@link #removeRecipeTransferHandler(String)} from {@link Widget#dispose()} for widgets and | ||
| * {@link SyncHandler#dispose()} for sync handlers. | ||
| * | ||
| * @throws IllegalArgumentException if a receiver with the given key already exists. | ||
| */ | ||
| @SideOnly(Side.CLIENT) | ||
| public static void registerRecipeTransferHandler(@NotNull String key, | ||
| @NotNull IRecipeTransferReceiver transferReceiver) { | ||
| registerRecipeTransferHandler(key, transferReceiver, 0); | ||
| } | ||
|
|
||
| /** | ||
| * Register an {@link IRecipeTransferReceiver} to this screen with a certain priority. Higher numbers will be tried | ||
| * first. <br/> | ||
| * <b>Important:</b> ensure that you remove this handler with {@link #removeRecipeTransferHandler(String)} when it's | ||
| * disposed of! <br/> | ||
| * Remove it by calling {@link #removeRecipeTransferHandler(String)} from {@link Widget#dispose()} for widgets and | ||
| * {@link SyncHandler#dispose()} for sync handlers. | ||
| * | ||
| * @throws IllegalArgumentException if a receiver with the given key already exists. | ||
| */ | ||
| @SideOnly(Side.CLIENT) | ||
| public static void registerRecipeTransferHandler(@NotNull String key, | ||
| @NotNull IRecipeTransferReceiver transferReceiver, | ||
| int priority) { | ||
| for (Map<String, IRecipeTransferReceiver> subMap : registeredRecipeTransferReceivers.values()) { | ||
| if (subMap.containsKey(key)) { | ||
| throw new IllegalArgumentException( | ||
| "Tried to register a recipe transfer receiver to a key that's already used!"); | ||
| } | ||
| } | ||
|
Comment on lines
+105
to
+110
Contributor
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. perhaps we could have a set of names to check against faster instead of iterating the all the maps in priority? |
||
|
|
||
| registeredRecipeTransferReceivers.computeIfAbsent(priority, $ -> new Object2ObjectOpenHashMap<>()) | ||
| .put(key, transferReceiver); | ||
| } | ||
|
|
||
| /** | ||
| * Remove a registered {@link IRecipeTransferReceiver} from this screen. | ||
| * | ||
| * @throws IllegalArgumentException if no receiver exists with the given key. | ||
| */ | ||
| @SideOnly(Side.CLIENT) | ||
| public static void removeRecipeTransferHandler(@NotNull String key) { | ||
| for (Map<String, IRecipeTransferReceiver> subMap : registeredRecipeTransferReceivers.values()) { | ||
| if (subMap.containsKey(key)) { | ||
| subMap.remove(key); | ||
| return; | ||
| } | ||
| } | ||
|
|
||
| throw new IllegalArgumentException("Tried to remove a recipe transfer receiver by a key that didn't exist!"); | ||
| } | ||
| } | ||
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| package gregtech.api.mui; | ||
|
|
||
| import gregtech.api.mui.sync.RecipeTransferSyncHandler; | ||
| import gregtech.integration.jei.JustEnoughItemsModule; | ||
|
|
||
| import net.minecraftforge.fml.relauncher.Side; | ||
| import net.minecraftforge.fml.relauncher.SideOnly; | ||
|
|
||
| import com.cleanroommc.modularui.value.sync.SyncHandler; | ||
| import com.cleanroommc.modularui.widget.Widget; | ||
| import mezz.jei.api.gui.IRecipeLayout; | ||
| import mezz.jei.api.recipe.transfer.IRecipeTransferError; | ||
| import mezz.jei.api.recipe.transfer.IRecipeTransferHandlerHelper; | ||
| import org.jetbrains.annotations.NotNull; | ||
| import org.jetbrains.annotations.Nullable; | ||
|
|
||
| import java.util.Collection; | ||
|
|
||
| /** | ||
| * An interface for receiving a recipe from a recipe viewer to anything on the panel, such as a {@link Widget} or | ||
| * {@link SyncHandler}. <br/> | ||
| * Register it via {@link GregTechGuiScreen#registerRecipeTransferHandler(String, IRecipeTransferReceiver)} or | ||
| * {@link GregTechGuiScreen#registerRecipeTransferHandler(String, IRecipeTransferReceiver, int)} if you want to | ||
| * prioritize checking a certain handler first. <br/> | ||
| * If you're implementing this on a {@link SyncHandler}, it's recommended to extend {@link RecipeTransferSyncHandler} | ||
| * instead as registering and unregistering from {@link GregTechGuiScreen} is done for you. | ||
| */ | ||
| public interface IRecipeTransferReceiver { | ||
|
|
||
| /** | ||
| * Attempt or simulate transferring a recipe from a recipe viewer like JEI or HEI. <br/> | ||
| * A factory for default {@link IRecipeTransferError}s is available at {@link JustEnoughItemsModule#transferHelper}. | ||
| * There are three default options for errors: <br/> | ||
| * - {@link IRecipeTransferHandlerHelper#createInternalError()}: mark the recipe as invalid for transferring by | ||
| * graying out the + button. <br/> | ||
| * - {@link IRecipeTransferHandlerHelper#createUserErrorWithTooltip(String)}: the same as above, but also display a | ||
| * message when hovering over the + button. <br/> | ||
| * - {@link IRecipeTransferHandlerHelper#createUserErrorForSlots(String, Collection)}: the same as above, but | ||
| * additionally highlight certain slots in the recipe to, for example, mark missing ingredients. <b>Important: will | ||
| * throw {@link IllegalArgumentException} if the supplied {@link Collection} is empty!</b> | ||
| * | ||
| * @param recipeLayout the recipe layout that contains the recipe category, and the item and fluid stacks. | ||
| * @param maxTransfer if the receiver should try to move as many ingredients as possible to the crafting slots, ie | ||
| * shift clicking a recipe into a crafting table. | ||
| * @param simulate if this recipe should only simulate being transferred | ||
| * @return {@code null} if the transfer should succeed or an {@link IRecipeTransferError} if not. If there are | ||
| * multiple registered recipe transfer receivers on the same panel, returning an error with type | ||
| * {@link IRecipeTransferError.Type#INTERNAL} will skip this and attempt the next one. | ||
| */ | ||
| @Nullable | ||
| @SideOnly(Side.CLIENT) | ||
| IRecipeTransferError receiveRecipe(@NotNull IRecipeLayout recipeLayout, boolean maxTransfer, boolean simulate); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| package gregtech.api.mui.sync; | ||
|
|
||
| import gregtech.api.mui.GregTechGuiScreen; | ||
| import gregtech.api.mui.IRecipeTransferReceiver; | ||
|
|
||
| import com.cleanroommc.modularui.value.sync.PanelSyncManager; | ||
| import com.cleanroommc.modularui.value.sync.SyncHandler; | ||
| import org.jetbrains.annotations.ApiStatus; | ||
| import org.jetbrains.annotations.MustBeInvokedByOverriders; | ||
|
|
||
| /** | ||
| * A base class for to handle implementing {@link IRecipeTransferReceiver} on a {@link SyncHandler}s to automatically | ||
| * register and unregister it from the map of valid handlers in {@link GregTechGuiScreen}. | ||
| */ | ||
| public abstract class RecipeTransferSyncHandler extends SyncHandler implements IRecipeTransferReceiver { | ||
|
|
||
| @ApiStatus.OverrideOnly | ||
| @MustBeInvokedByOverriders | ||
| @Override | ||
| public void init(String key, PanelSyncManager syncManager) { | ||
| super.init(key, syncManager); | ||
| if (syncManager.isClient()) { | ||
| GregTechGuiScreen.registerRecipeTransferHandler(getKey(), this, getTransferHandlerPriority()); | ||
| } | ||
| } | ||
|
|
||
| protected int getTransferHandlerPriority() { | ||
| return 0; | ||
| } | ||
|
|
||
| @ApiStatus.OverrideOnly | ||
| @MustBeInvokedByOverriders | ||
| @Override | ||
| public void dispose() { | ||
| if (getSyncManager().isClient()) { | ||
| GregTechGuiScreen.removeRecipeTransferHandler(getKey()); | ||
| } | ||
| super.dispose(); | ||
| } | ||
| } |
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.
The class is already annotated side only client, do we need to annotate this field as well?