diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperConfig.java index 6003c5a1e9..dd0737f414 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperConfig.java @@ -137,6 +137,18 @@ public interface MenuEntrySwapperConfig extends Config return true; } + @ConfigItem( + position = -2, + keyName = "objectLeftClickCustomization", + name = "Customizable left-click", + description = "Allows customization of left-clicks on objects", + section = objectSection + ) + default boolean objectLeftClickCustomization() + { + return true; + } + @ConfigItem( keyName = "swapAdmire", name = "Admire", diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperPlugin.java index beb52d9397..856d5798d1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperPlugin.java @@ -29,7 +29,9 @@ package net.runelite.client.plugins.menuentryswapper; import com.google.common.annotations.VisibleForTesting; import static com.google.common.base.Predicates.alwaysTrue; import static com.google.common.base.Predicates.equalTo; +import com.google.common.base.Strings; import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.LinkedHashMultimap; import com.google.common.collect.Multimap; @@ -42,6 +44,8 @@ import java.util.Set; import java.util.function.Predicate; import java.util.function.Supplier; import javax.inject.Inject; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.ChatMessageType; import net.runelite.api.Client; import net.runelite.api.GameState; import net.runelite.api.ItemComposition; @@ -49,13 +53,18 @@ import net.runelite.api.KeyCode; import net.runelite.api.MenuAction; import net.runelite.api.MenuEntry; import net.runelite.api.NPC; +import net.runelite.api.ObjectComposition; import net.runelite.api.events.ClientTick; import net.runelite.api.events.MenuEntryAdded; import net.runelite.api.events.MenuOpened; +import net.runelite.api.events.MenuOptionClicked; import net.runelite.api.events.PostItemComposition; import net.runelite.api.widgets.WidgetID; import net.runelite.api.widgets.WidgetInfo; import net.runelite.client.callback.ClientThread; +import net.runelite.client.chat.ChatMessageBuilder; +import net.runelite.client.chat.ChatMessageManager; +import net.runelite.client.chat.QueuedMessage; import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.events.ConfigChanged; @@ -79,6 +88,7 @@ import net.runelite.client.util.Text; tags = {"npcs", "inventory", "items", "objects"}, enabledByDefault = false ) +@Slf4j public class MenuEntrySwapperPlugin extends Plugin { private static final String CONFIGURE = "Configure"; @@ -89,6 +99,7 @@ public class MenuEntrySwapperPlugin extends Plugin private static final String SHIFTCLICK_CONFIG_GROUP = "shiftclick"; private static final String ITEM_KEY_PREFIX = "item_"; + private static final String OBJECT_KEY_PREFIX = "object_"; // Shift click private static final WidgetMenuOption FIXED_INVENTORY_TAB_CONFIGURE_SC = new WidgetMenuOption(CONFIGURE, @@ -139,6 +150,14 @@ public class MenuEntrySwapperPlugin extends Plugin MenuAction.NPC_FIFTH_OPTION, MenuAction.EXAMINE_NPC); + private static final List OBJECT_MENU_TYPES = ImmutableList.of( + MenuAction.GAME_OBJECT_FIRST_OPTION, + MenuAction.GAME_OBJECT_SECOND_OPTION, + MenuAction.GAME_OBJECT_THIRD_OPTION, + MenuAction.GAME_OBJECT_FOURTH_OPTION + // GAME_OBJECT_FIFTH_OPTION gets sorted underneath Walk here after we swap, so it doesn't work + ); + private static final Set ESSENCE_MINE_NPCS = ImmutableSet.of( "aubury", "sedridor", @@ -172,6 +191,9 @@ public class MenuEntrySwapperPlugin extends Plugin @Inject private ItemManager itemManager; + @Inject + private ChatMessageManager chatMessageManager; + private boolean configuringShiftClick = false; private boolean configuringLeftClick = false; @@ -655,6 +677,48 @@ public class MenuEntrySwapperPlugin extends Plugin } } + @Subscribe + public void onMenuOptionClicked(MenuOptionClicked menuOptionClicked) + { + final MenuAction menuAction = menuOptionClicked.getMenuAction(); + if (shiftModifier() && OBJECT_MENU_TYPES.contains(menuAction) && config.objectLeftClickCustomization()) + { + // Get multiloc id + int objectId = menuOptionClicked.getId(); + ObjectComposition objectDefinition = client.getObjectDefinition(objectId); + if (objectDefinition.getImpostorIds() != null) + { + objectDefinition = objectDefinition.getImpostor(); + objectId = objectDefinition.getId(); + } + + final int actionIdx = OBJECT_MENU_TYPES.indexOf(menuAction); + String message = new ChatMessageBuilder() + .append("The default left click option for '").append(objectDefinition.getName()).append("' ") + .append("has been set to '").append(objectDefinition.getActions()[actionIdx]).append("'.") + .build(); + + chatMessageManager.queue(QueuedMessage.builder() + .type(ChatMessageType.CONSOLE) + .runeLiteFormattedMessage(message) + .build()); + + menuOptionClicked.consume(); + + log.debug("Set object swap for {} to {}", objectId, menuAction); + + final MenuAction defaultAction = defaultAction(objectDefinition); + if (defaultAction != menuAction) + { + setObjectSwapConfig(objectId, OBJECT_MENU_TYPES.indexOf(menuAction)); + } + else + { + unsetObjectSwapConfig(objectId); + } + } + } + private void bankModeSwap(MenuAction entryType, int entryIdentifier) { MenuEntry[] menuEntries = client.getMenuEntries(); @@ -736,6 +800,29 @@ public class MenuEntrySwapperPlugin extends Plugin } } + if (OBJECT_MENU_TYPES.contains(menuAction)) + { + // Get multiloc id + int objectId = eventId; + ObjectComposition objectComposition = client.getObjectDefinition(objectId); + if (objectComposition.getImpostorIds() != null) + { + objectComposition = objectComposition.getImpostor(); + objectId = objectComposition.getId(); + } + + Integer customOption = getObjectSwapConfig(objectId); + if (customOption != null) + { + MenuAction swapAction = OBJECT_MENU_TYPES.get(customOption); + if (swapAction == menuAction) + { + swap(optionIndexes, menuEntries, index, menuEntries.length - 1); + return; + } + } + } + // Built-in swaps Collection swaps = this.swaps.get(option); for (Swap swap : swaps) @@ -954,4 +1041,39 @@ public class MenuEntrySwapperPlugin extends Plugin configuringLeftClick = target.equals(LEFT_CLICK_MENU_TARGET); rebuildCustomizationMenus(); } + + private Integer getObjectSwapConfig(int objectId) + { + String config = configManager.getConfiguration(MenuEntrySwapperConfig.GROUP, OBJECT_KEY_PREFIX + objectId); + if (config == null || config.isEmpty()) + { + return null; + } + + return Integer.parseInt(config); + } + + private void setObjectSwapConfig(int objectId, int index) + { + configManager.setConfiguration(MenuEntrySwapperConfig.GROUP, OBJECT_KEY_PREFIX + objectId, index); + } + + private void unsetObjectSwapConfig(int objectId) + { + configManager.unsetConfiguration(MenuEntrySwapperConfig.GROUP, OBJECT_KEY_PREFIX + objectId); + } + + private static MenuAction defaultAction(ObjectComposition objectComposition) + { + String[] actions = objectComposition.getActions(); + for (int i = 0; i < actions.length; ++i) + { + if (!Strings.isNullOrEmpty(actions[i])) + { + assert i < OBJECT_MENU_TYPES.size(); + return OBJECT_MENU_TYPES.get(i); + } + } + return null; + } } diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperPluginTest.java index 4fa03023a1..f051cfaa2d 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperPluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperPluginTest.java @@ -34,8 +34,10 @@ import net.runelite.api.GameState; import net.runelite.api.KeyCode; import net.runelite.api.MenuAction; import net.runelite.api.MenuEntry; +import net.runelite.api.ObjectComposition; import net.runelite.api.events.ClientTick; import net.runelite.api.events.MenuEntryAdded; +import net.runelite.client.chat.ChatMessageManager; import net.runelite.client.config.ConfigManager; import net.runelite.client.game.ItemManager; import net.runelite.client.menus.TestMenuEntry; @@ -45,10 +47,12 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import org.mockito.Mock; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -70,6 +74,10 @@ public class MenuEntrySwapperPluginTest @Bind ItemManager itemManager; + @Mock + @Bind + ChatMessageManager chatMessageManager; + @Mock @Bind MenuEntrySwapperConfig config; @@ -85,6 +93,7 @@ public class MenuEntrySwapperPluginTest Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this); when(client.getGameState()).thenReturn(GameState.LOGGED_IN); + when(client.getObjectDefinition(anyInt())).thenReturn(mock(ObjectComposition.class)); when(client.getMenuEntries()).thenAnswer((Answer) invocationOnMock -> {