Item Autocomplete system

This commit is contained in:
SoundLogic committed 2015-06-24 14:46:25 -05:00
1 parent fc4ea7e4fc
commit 176fa1f5b5
6 files changed
+260 -2

No files matched your search

@@ -29,7 +29,8 @@ public final class CorporeaHelper {
private static final List<IInventory> empty = Collections.unmodifiableList(new ArrayList());
private static final WeakHashMap<List<ICorporeaSpark>, List<IInventory>> cachedNetworks = new WeakHashMap();
private static final List<ICorporeaAutoCompleteController> autoCompleteControllers = new ArrayList<ICorporeaAutoCompleteController>();
public static final String[] WILDCARD_STRINGS = new String[] {
"...", "~", "+", "?" , "*"
};
@@ -319,4 +320,21 @@ public final class CorporeaHelper {
public static boolean equalOrContain(String s1, String s2, boolean contain) {
return contain ? s1.contains(s2) : s1.equals(s2);
}
/**
* Registers a ICorporeaAutoCompleteController
*/
public static void registerAutoCompleteController(ICorporeaAutoCompleteController controller) {
autoCompleteControllers.add(controller);
}
/**
* Returns if the auto complete helper should run
*/
public static boolean shouldAutoComplete() {
for(ICorporeaAutoCompleteController controller : autoCompleteControllers)
if(controller.shouldAutoComplete())
return true;
return false;
}
}
@@ -0,0 +1,31 @@
/**
* This class was created by <SoundLogic>. It's distributed as
* part of the Botania Mod. Get the Source Code in github:
* https://github.com/Vazkii/Botania
*
* Botania is Open Source and distributed under the
* Botania License: http://botaniamod.net/license.php
*
* File Created @ [June 8, 2015, 1:04:05 PM (GMT)]
*/
package vazkii.botania.api.corporea;
import java.util.List;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
/**
* An interface for systems which may control if the item auto complete system should be active
*/
public interface ICorporeaAutoCompleteController {
/**
* Return true if auto completion should be enabled.
*/
@SideOnly(Side.CLIENT)
public boolean shouldAutoComplete();
}
@@ -0,0 +1,186 @@
/**
* This class was created by <SoundLogic>. It's distributed as
* part of the Botania Mod. Get the Source Code in github:
* https://github.com/Vazkii/Botania
*
* Botania is Open Source and distributed under the
* Botania License: http://botaniamod.net/license.php
*
* File Created @ [June 8, 2015, 12:55:20 AM (GMT)]
*/
package vazkii.botania.client.core.handler;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiChat;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.GuiTextField;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ChatComponentText;
import org.lwjgl.input.Keyboard;
import vazkii.botania.api.corporea.CorporeaHelper;
import vazkii.botania.common.lib.LibObfuscation;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import cpw.mods.fml.common.gameevent.TickEvent.ClientTickEvent;
import cpw.mods.fml.common.gameevent.TickEvent.Phase;
import cpw.mods.fml.relauncher.ReflectionHelper;
public class CorporeaAutoCompleteHandler {
boolean isAutoCompleted = false;
String originalString = "";
List<CompletionData> completions = new ArrayList<CompletionData>();
int position;
static TreeSet<String> itemNames = new TreeSet<String>(
new Comparator<String>() {
@Override
public int compare(String arg0, String arg1) {
return arg0.compareToIgnoreCase(arg1);
}
});
private boolean tabLastTick = false;
public static void updateItemList() {
itemNames.clear();
Iterator<Item> iterator = Item.itemRegistry.iterator();
ArrayList<ItemStack> curList = new ArrayList<ItemStack>();
while(iterator.hasNext()) {
Item item = iterator.next();
if(item != null && item.getCreativeTab() != null) {
curList.clear();
try {
item.getSubItems(item, (CreativeTabs) null, curList);
for(ItemStack stack : curList)
itemNames.add(stack.getDisplayName().trim());
}
catch (Exception e) {}
}
}
}
@SubscribeEvent
public void onTick(ClientTickEvent event) {
if(event.phase != Phase.END)
return;
GuiScreen screen = Minecraft.getMinecraft().currentScreen;
if(!(screen instanceof GuiChat)) {
isAutoCompleted = false;
return;
}
GuiChat chat = (GuiChat) screen;
if(isAutoCompleted) {
boolean valid = ReflectionHelper.getPrivateValue(GuiChat.class, chat, LibObfuscation.COMPLETE_FLAG);
if(!valid)
isAutoCompleted = false;
}
if(Keyboard.isKeyDown(15)) {
if(tabLastTick)
return;
tabLastTick = true;
} else {
tabLastTick = false;
return;
}
if(!CorporeaHelper.shouldAutoComplete())
return;
GuiTextField inputField = ReflectionHelper.getPrivateValue(GuiChat.class, chat, LibObfuscation.INPUT_FIELD);
if(!isAutoCompleted && GuiScreen.isShiftKeyDown())
buildAutoCompletes(inputField, chat);
if(isAutoCompleted && !completions.isEmpty())
advanceAutoComplete(inputField, chat);
}
private void advanceAutoComplete(GuiTextField inputField, GuiChat chat) {
this.position++;
if(this.position >= completions.size())
this.position -= completions.size();
CompletionData data = completions.get(position);
String str = originalString.substring(0, originalString.length() - data.prefixLength) + data.string;
inputField.setText(str);
}
private void buildAutoCompletes(GuiTextField inputField, GuiChat chat) {
String leftOfCursor;
if(inputField.getCursorPosition() == 0)
leftOfCursor = "";
else
leftOfCursor = inputField.getText().substring(0, inputField.getCursorPosition());
if(leftOfCursor.length() == 0 || leftOfCursor.charAt(0) == '/')
return;
this.completions = getNames(leftOfCursor);
if(completions.isEmpty())
return;
this.position = -1;
ReflectionHelper.setPrivateValue(GuiChat.class, chat, true, LibObfuscation.COMPLETE_FLAG);
StringBuilder stringbuilder = new StringBuilder();
CompletionData data;
for(Iterator<CompletionData> iterator = completions.iterator(); iterator.hasNext(); stringbuilder.append(data.string)) {
data = iterator.next();
if(stringbuilder.length() > 0)
stringbuilder.append(", ");
}
Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessageWithOptionalDeletion(new ChatComponentText(stringbuilder.toString()), 1);
isAutoCompleted = true;
originalString = inputField.getText();
}
private ArrayList<CompletionData> getNames(String prefix) {
TreeSet<CompletionData> result = new TreeSet<CompletionData>();
String[] words = prefix.split(" ");
int i = words.length - 1;
String curPrefix = words[i];
while(i >= 0) {
result.addAll(getNamesStartingWith(curPrefix.toLowerCase()));
i--;
if(i >= 0)
curPrefix = words[i] + " " + curPrefix;
}
return new ArrayList<CompletionData>(result);
}
private List<CompletionData> getNamesStartingWith(String prefix) {
ArrayList<CompletionData> result = new ArrayList<CompletionData>();
int length = prefix.length();
SortedSet<String> after = itemNames.tailSet(prefix);
for(String str : after) {
if(str.toLowerCase().startsWith(prefix))
result.add(new CompletionData(str, length));
else return result;
}
return result;
}
private static class CompletionData implements Comparable<CompletionData> {
private String string;
private int prefixLength;
public CompletionData(String string, int prefixLength) {
this.string = string;
this.prefixLength = prefixLength;
}
@Override
public int compareTo(CompletionData arg0) {
return string.compareTo(arg0.string);
}
}
}
@@ -39,6 +39,7 @@ import vazkii.botania.client.core.handler.BaubleRenderHandler;
import vazkii.botania.client.core.handler.BotaniaPlayerController;
import vazkii.botania.client.core.handler.BoundTileRenderer;
import vazkii.botania.client.core.handler.ClientTickHandler;
import vazkii.botania.client.core.handler.CorporeaAutoCompleteHandler;
import vazkii.botania.client.core.handler.DebugHandler;
import vazkii.botania.client.core.handler.HUDHandler;
import vazkii.botania.client.core.handler.LightningHandler;
@@ -143,6 +144,7 @@ import cpw.mods.fml.client.registry.RenderingRegistry;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.Optional;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
import cpw.mods.fml.relauncher.ReflectionHelper;
public class ClientProxy extends CommonProxy {
@@ -162,6 +164,7 @@ public class ClientProxy extends CommonProxy {
MinecraftForge.EVENT_BUS.register(new BaubleRenderHandler());
MinecraftForge.EVENT_BUS.register(new DebugHandler());
MinecraftForge.EVENT_BUS.register(new SubTileRadiusRenderHandler());
FMLCommonHandler.instance().bus().register(new CorporeaAutoCompleteHandler());
if(ConfigHandler.versionCheckEnabled)
new VersionChecker().init();
@@ -174,6 +177,11 @@ public class ClientProxy extends CommonProxy {
initRenderers();
}
@Override
public void postInit(FMLPostInitializationEvent event) {
super.postInit(event);
CorporeaAutoCompleteHandler.updateItemList();
}
private void initRenderers() {
LibRenderIDs.idAltar = RenderingRegistry.getNextAvailableRenderId();
@@ -20,6 +20,7 @@ import java.util.WeakHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
@@ -32,6 +33,7 @@ import net.minecraftforge.event.ServerChatEvent;
import org.apache.commons.lang3.text.WordUtils;
import vazkii.botania.api.corporea.CorporeaHelper;
import vazkii.botania.api.corporea.ICorporeaAutoCompleteController;
import vazkii.botania.api.corporea.ICorporeaSpark;
import vazkii.botania.common.achievement.ModAchievements;
import vazkii.botania.common.core.helper.MathHelper;
@@ -213,8 +215,12 @@ public class TileCorporeaIndex extends TileCorporeaBase {
}
}
public static final class InputHandler {
public static final class InputHandler implements ICorporeaAutoCompleteController {
public InputHandler() {
CorporeaHelper.registerAutoCompleteController(this);
}
@SubscribeEvent(priority = EventPriority.HIGHEST)
public void onChatMessage(ServerChatEvent event) {
List<TileCorporeaIndex> nearbyIndexes = getNearbyIndexes(event.player);
@@ -270,6 +276,11 @@ public class TileCorporeaIndex extends TileCorporeaBase {
return indexList;
}
@Override
public boolean shouldAutoComplete() {
return !getNearbyIndexes(Minecraft.getMinecraft().thePlayer).isEmpty();
}
}
public static interface IRegexStacker {
@@ -72,5 +72,9 @@ public final class LibObfuscation {
// GuiContainer
public static final String[] THE_SLOT = new String[] { "theSlot", "field_147006_u", "u" };
// GuiChat
public static final String[] INPUT_FIELD = new String[] { "inputField", "field_146415_a", "a" };
public static final String[] COMPLETE_FLAG = new String[] { "field_146414_r", "r" };
}