aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt2
-rw-r--r--src/main/java/at/hannibal2/skyhanni/events/TabCompletionEvent.kt37
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/commands/PartyCommands.kt2
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/commands/tabcomplete/TabComplete.kt12
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/commands/tabcomplete/WarpTabComplete.kt11
-rw-r--r--src/main/java/at/hannibal2/skyhanni/mixins/init/BeforeForLoopInjectionPoint.java59
-rw-r--r--src/main/java/at/hannibal2/skyhanni/mixins/init/SkyhanniMixinPlugin.java3
-rw-r--r--src/main/java/at/hannibal2/skyhanni/mixins/transformers/MixinGuiChat.java62
8 files changed, 135 insertions, 53 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt
index e46db663d..33d7cdbe9 100644
--- a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt
+++ b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt
@@ -101,6 +101,7 @@ import at.hannibal2.skyhanni.features.commands.WarpIsCommand
import at.hannibal2.skyhanni.features.commands.WikiManager
import at.hannibal2.skyhanni.features.commands.tabcomplete.GetFromSacksTabComplete
import at.hannibal2.skyhanni.features.commands.tabcomplete.PlayerTabComplete
+import at.hannibal2.skyhanni.features.commands.tabcomplete.TabComplete
import at.hannibal2.skyhanni.features.commands.tabcomplete.WarpTabComplete
import at.hannibal2.skyhanni.features.cosmetics.ArrowTrail
import at.hannibal2.skyhanni.features.cosmetics.CosmeticFollowingLine
@@ -530,6 +531,7 @@ class SkyHanniMod {
loadModule(FixedRateTimerManager())
loadModule(ChromaManager)
loadModule(ContributorManager)
+ loadModule(TabComplete)
// APIs
loadModule(BazaarApi())
diff --git a/src/main/java/at/hannibal2/skyhanni/events/TabCompletionEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/TabCompletionEvent.kt
new file mode 100644
index 000000000..f3ec47b02
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/events/TabCompletionEvent.kt
@@ -0,0 +1,37 @@
+package at.hannibal2.skyhanni.events
+
+class TabCompletionEvent(
+ val leftOfCursor: String,
+ val fullText: String,
+ val originalCompletions: List<String>,
+) : LorenzEvent() {
+ val lastWord = leftOfCursor.substringAfterLast(' ')
+ val additionalSuggestions = mutableSetOf<String>()
+ val suppressedSuggestions = mutableSetOf<String>()
+
+ fun addSuggestion(suggestion: String) {
+ if (suggestion.startsWith(lastWord, ignoreCase = true))
+ additionalSuggestions.add(suggestion)
+ }
+
+ fun addSuggestions(suggestions: Iterable<String>) {
+ suggestions.forEach(this::addSuggestion)
+ }
+
+ fun excludeAllDefault() {
+ suppressedSuggestions.addAll(originalCompletions)
+ }
+
+ val command = if (leftOfCursor.startsWith("/"))
+ leftOfCursor.substring(1).substringBefore(" ").lowercase()
+ else ""
+
+ fun isCommand(commandName: String): Boolean {
+ return commandName.equals(command, ignoreCase = true)
+ }
+
+ fun intoSuggestionArray(): Array<String>? {
+ if (additionalSuggestions.isEmpty() && suppressedSuggestions.isEmpty()) return null
+ return (originalCompletions - suppressedSuggestions + additionalSuggestions).toTypedArray()
+ }
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/features/commands/PartyCommands.kt b/src/main/java/at/hannibal2/skyhanni/features/commands/PartyCommands.kt
index 5196b08db..b323bb73d 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/commands/PartyCommands.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/commands/PartyCommands.kt
@@ -90,7 +90,7 @@ object PartyCommands {
if (command == "p" || command == "party") {
val friends = if (config.tabComplete.friends) {
- FriendAPI.getAllFriends().filter { it.bestFriend || config.tabComplete.onlyBestFriends }.map { it.name }
+ FriendAPI.getAllFriends().filter { it.bestFriend || !config.tabComplete.onlyBestFriends }.map { it.name }
} else {
emptyList<String>()
}
diff --git a/src/main/java/at/hannibal2/skyhanni/features/commands/tabcomplete/TabComplete.kt b/src/main/java/at/hannibal2/skyhanni/features/commands/tabcomplete/TabComplete.kt
index a835efd38..49bde5993 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/commands/tabcomplete/TabComplete.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/commands/tabcomplete/TabComplete.kt
@@ -1,29 +1,29 @@
package at.hannibal2.skyhanni.features.commands.tabcomplete
+import at.hannibal2.skyhanni.events.TabCompletionEvent
import at.hannibal2.skyhanni.features.commands.PartyCommands
import at.hannibal2.skyhanni.features.commands.ViewRecipeCommand
import at.hannibal2.skyhanni.features.misc.CollectionTracker
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
object TabComplete {
- @JvmStatic
- fun handleTabComplete(leftOfCursor: String, originalArray: Array<String>): Array<String>? {
- val splits = leftOfCursor.split(" ")
+ @SubscribeEvent
+ fun handleTabComplete(event: TabCompletionEvent) {
+ val splits = event.leftOfCursor.split(" ")
if (splits.size > 1) {
var command = splits.first().lowercase()
if (command.startsWith("/")) {
command = command.substring(1)
customTabComplete(command)?.let {
- return buildResponse(splits, it).toSet().toTypedArray()
+ event.addSuggestions(it)
}
}
}
- return null
}
private fun customTabComplete(command: String): List<String>? {
GetFromSacksTabComplete.handleTabComplete(command)?.let { return it }
- WarpTabComplete.handleTabComplete(command)?.let { return it }
PlayerTabComplete.handleTabComplete(command)?.let { return it }
CollectionTracker.handleTabComplete(command)?.let { return it }
PartyCommands.customTabComplete(command)?.let { return it }
diff --git a/src/main/java/at/hannibal2/skyhanni/features/commands/tabcomplete/WarpTabComplete.kt b/src/main/java/at/hannibal2/skyhanni/features/commands/tabcomplete/WarpTabComplete.kt
index 4651040b8..4520aee09 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/commands/tabcomplete/WarpTabComplete.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/commands/tabcomplete/WarpTabComplete.kt
@@ -3,6 +3,7 @@ package at.hannibal2.skyhanni.features.commands.tabcomplete
import at.hannibal2.skyhanni.SkyHanniMod
import at.hannibal2.skyhanni.data.jsonobjects.repo.WarpsJson
import at.hannibal2.skyhanni.events.RepositoryReloadEvent
+import at.hannibal2.skyhanni.events.TabCompletionEvent
import at.hannibal2.skyhanni.utils.LorenzUtils
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
@@ -17,11 +18,11 @@ object WarpTabComplete {
warps = data.warpCommands
}
- fun handleTabComplete(command: String): List<String>? {
- if (!isEnabled()) return null
- if (command != "warp") return null
-
- return warps
+ @SubscribeEvent
+ fun onTabComplete(event: TabCompletionEvent) {
+ if (event.isCommand("warp")) {
+ event.addSuggestions(warps)
+ }
}
fun isEnabled() = LorenzUtils.inSkyBlock && config.warps
diff --git a/src/main/java/at/hannibal2/skyhanni/mixins/init/BeforeForLoopInjectionPoint.java b/src/main/java/at/hannibal2/skyhanni/mixins/init/BeforeForLoopInjectionPoint.java
new file mode 100644
index 000000000..5316a8258
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/mixins/init/BeforeForLoopInjectionPoint.java
@@ -0,0 +1,59 @@
+package at.hannibal2.skyhanni.mixins.init;
+
+import org.spongepowered.asm.lib.Opcodes;
+import org.spongepowered.asm.lib.tree.AbstractInsnNode;
+import org.spongepowered.asm.lib.tree.InsnList;
+import org.spongepowered.asm.lib.tree.VarInsnNode;
+import org.spongepowered.asm.mixin.injection.InjectionPoint;
+import org.spongepowered.asm.mixin.injection.struct.InjectionPointData;
+
+import java.util.Collection;
+
+/**
+ * Inject just before a for loop which iterates over a local variable containing an array.
+ *
+ * <pre>{@code
+ * String [] s = new String[10];
+ *
+ * // <-- Injection point here
+ * for (String e : s) {
+ *
+ * }
+ * }
+ * </pre>
+ * Does not work for more complex instructions which call functions or do other operations inside of the for loop header.
+ * Does not work for {@link java.util.Iterator iterators}.
+ *
+ * <p>Set the lvIndex arg to specify which lvIndex to search for when selecting the loop.</p>
+ *
+ *
+ * <pre>{@code
+ * @Inject(method = "...", at = @At(value = "SKYHANNI_FORLOOP_LOCAL_VAR", args = "lvIndex=1"))
+ * }</pre>
+ */
+@InjectionPoint.AtCode("SKYHANNI_FORLOOP_LOCAL_VAR")
+public class BeforeForLoopInjectionPoint extends InjectionPoint {
+ private final int lvIndex;
+
+ public BeforeForLoopInjectionPoint(InjectionPointData data) {
+ lvIndex = data.get("lvIndex", -1);
+ }
+
+ @Override
+ public boolean find(String s, InsnList insnList, Collection<AbstractInsnNode> collection) {
+ for (AbstractInsnNode p = insnList.getFirst(); p != null; p = p.getNext()) {
+ if (p.getOpcode() != Opcodes.ARRAYLENGTH) {
+ continue;
+ }
+ AbstractInsnNode loadLoopVar = p.getPrevious();
+ if (loadLoopVar == null || loadLoopVar.getOpcode() != Opcodes.ALOAD) continue;
+ AbstractInsnNode storeLoopVar = loadLoopVar.getPrevious();
+ if (storeLoopVar == null || storeLoopVar.getOpcode() != Opcodes.ASTORE) continue;
+ AbstractInsnNode loadLoopArg = storeLoopVar.getPrevious();
+ if (loadLoopArg == null || loadLoopArg.getOpcode() != Opcodes.ALOAD) continue;
+ if (lvIndex != -1 && ((VarInsnNode) loadLoopArg).var != lvIndex) continue;
+ collection.add(loadLoopArg);
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/mixins/init/SkyhanniMixinPlugin.java b/src/main/java/at/hannibal2/skyhanni/mixins/init/SkyhanniMixinPlugin.java
index 1f1b0e1fe..9dd4cc6f8 100644
--- a/src/main/java/at/hannibal2/skyhanni/mixins/init/SkyhanniMixinPlugin.java
+++ b/src/main/java/at/hannibal2/skyhanni/mixins/init/SkyhanniMixinPlugin.java
@@ -3,6 +3,7 @@ package at.hannibal2.skyhanni.mixins.init;
import org.spongepowered.asm.lib.tree.ClassNode;
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
+import org.spongepowered.asm.mixin.injection.InjectionPoint;
import java.io.IOException;
import java.net.MalformedURLException;
@@ -21,7 +22,7 @@ import java.util.zip.ZipInputStream;
public class SkyhanniMixinPlugin implements IMixinConfigPlugin {
@Override
public void onLoad(String mixinPackage) {
-
+ InjectionPoint.register(BeforeForLoopInjectionPoint.class);
}
@Override
diff --git a/src/main/java/at/hannibal2/skyhanni/mixins/transformers/MixinGuiChat.java b/src/main/java/at/hannibal2/skyhanni/mixins/transformers/MixinGuiChat.java
index 97ef80364..ff744b7d0 100644
--- a/src/main/java/at/hannibal2/skyhanni/mixins/transformers/MixinGuiChat.java
+++ b/src/main/java/at/hannibal2/skyhanni/mixins/transformers/MixinGuiChat.java
@@ -1,24 +1,22 @@
package at.hannibal2.skyhanni.mixins.transformers;
import at.hannibal2.skyhanni.events.ChatHoverEvent;
-import at.hannibal2.skyhanni.features.commands.tabcomplete.TabComplete;
+import at.hannibal2.skyhanni.events.TabCompletionEvent;
import at.hannibal2.skyhanni.mixins.hooks.GuiChatHook;
-import com.google.common.collect.Lists;
import net.minecraft.client.gui.GuiChat;
import net.minecraft.client.gui.GuiTextField;
import net.minecraft.util.ChatComponentText;
-import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.IChatComponent;
-import org.apache.commons.lang3.StringUtils;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyArg;
+import org.spongepowered.asm.mixin.injection.ModifyVariable;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
-import java.util.List;
+import java.util.Arrays;
@Mixin(GuiChat.class)
public class MixinGuiChat {
@@ -26,41 +24,25 @@ public class MixinGuiChat {
@Shadow
protected GuiTextField inputField;
- @Shadow
- private boolean waitingOnAutocomplete;
-
- @Shadow
- private boolean playerNamesFound;
-
- @Shadow
- private List<String> foundPlayerNames = Lists.newArrayList();
-
- @Inject(method = "onAutocompleteResponse", at = @At(value = "HEAD"), cancellable = true)
- private void renderItemOverlayPost(String[] originalArray, CallbackInfo ci) {
-
- if (this.waitingOnAutocomplete) {
- String[] result = TabComplete.handleTabComplete(this.inputField.getText(), originalArray);
- if (result == null) return;
- ci.cancel();
-
- this.playerNamesFound = false;
- this.foundPlayerNames.clear();
- for (String s : result) {
- if (!s.isEmpty()) {
- this.foundPlayerNames.add(s);
- }
- }
-
- String s1 = this.inputField.getText().substring(this.inputField.func_146197_a(-1, this.inputField.getCursorPosition(), false));
- String s2 = StringUtils.getCommonPrefix(result);
- s2 = EnumChatFormatting.getTextWithoutFormattingCodes(s2);
- if (!s2.isEmpty() && !s1.equalsIgnoreCase(s2)) {
- this.inputField.deleteFromCursor(this.inputField.func_146197_a(-1, this.inputField.getCursorPosition(), false) - this.inputField.getCursorPosition());
- this.inputField.writeText(s2);
- } else if (!this.foundPlayerNames.isEmpty()) {
- this.playerNamesFound = true;
- }
- }
+ @ModifyVariable(
+ method = "onAutocompleteResponse",
+ at = @At(
+ value = "SKYHANNI_FORLOOP_LOCAL_VAR",
+ shift = At.Shift.BEFORE,
+ args = "lvIndex=1"
+ ),
+ index = 1,
+ argsOnly = true
+ )
+ private String[] renderItemOverlayPost(String[] originalArray) {
+ String inputFieldText = this.inputField.getText();
+ String beforeCursor = inputFieldText.substring(0, this.inputField.getCursorPosition());
+ TabCompletionEvent tabCompletionEvent = new TabCompletionEvent(beforeCursor, inputFieldText, Arrays.asList(originalArray));
+ tabCompletionEvent.postAndCatch();
+ String[] newSuggestions = tabCompletionEvent.intoSuggestionArray();
+ if (newSuggestions == null)
+ newSuggestions = originalArray;
+ return newSuggestions;
}
@Inject(method = "drawScreen", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/GuiChat;handleComponentHover(Lnet/minecraft/util/IChatComponent;II)V"), locals = LocalCapture.CAPTURE_FAILHARD)