package electroblob.wizardry.client.gui; import electroblob.wizardry.Wizardry; import electroblob.wizardry.client.DrawingUtils; import electroblob.wizardry.registry.WizardryTabs; import electroblob.wizardry.spell.Spell; import net.minecraft.client.gui.GuiTextField; import net.minecraft.client.gui.inventory.GuiContainerCreative; import net.minecraft.client.resources.I18n; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.util.text.Style; import net.minecraft.util.text.TextFormatting; import net.minecraftforge.client.event.GuiScreenEvent; import net.minecraftforge.fml.common.Mod.EventBusSubscriber; import net.minecraftforge.fml.common.ObfuscationReflectionHelper; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.TickEvent.ClientTickEvent; import net.minecraftforge.fml.common.gameevent.TickEvent.Phase; import net.minecraftforge.fml.relauncher.Side; import java.lang.reflect.Field; import java.util.Locale; @EventBusSubscriber(Side.CLIENT) public class CustomCreativeSearchHandler { private static final int SEARCH_TOOLTIP_HOVER_TIME = 20; private static final Style TOOLTIP_SYNTAX = new Style().setColor(TextFormatting.YELLOW); private static final Style TOOLTIP_BODY = new Style().setColor(TextFormatting.WHITE); /** Reflected into {@code GuiContainerCreative#searchField} */ private static final Field searchField; private static GuiTextField currentSearchField = null; private static int searchBarHoverTime; static { searchField = ObfuscationReflectionHelper.findField(GuiContainerCreative.class, "field_147062_A"); } @SubscribeEvent public static void onInitGuiEvent(GuiScreenEvent.InitGuiEvent.Post event){ // Reduces reflection as much as possible - searchField is created on GUI init and never reassigned so we need // not (and should not!) use reflection to retrieve it every time a key is typed if(event.getGui() instanceof GuiContainerCreative){ try{ currentSearchField = (GuiTextField)searchField.get(event.getGui()); }catch(IllegalAccessException e){ e.printStackTrace(); } } } @SubscribeEvent public static void onKeyboardInputEvent(GuiScreenEvent.KeyboardInputEvent.Post event){ // Custom creative tab search behaviour if(event.getGui() instanceof GuiContainerCreative){ GuiContainerCreative gui = (GuiContainerCreative)event.getGui(); CreativeTabs tab = CreativeTabs.CREATIVE_TAB_ARRAY[gui.getSelectedTabIndex()]; if(tab == WizardryTabs.SPELLS){ GuiContainerCreative.ContainerCreative container = (GuiContainerCreative.ContainerCreative)gui.inventorySlots; container.itemList.clear(); // Required or duplicates will appear! String searchText = currentSearchField.getText().toLowerCase(Locale.ROOT); tab.displayAllRelevantItems(container.itemList); if(!searchText.isEmpty()){ container.itemList.removeIf(s -> !Spell.byMetadata(s.getMetadata()).matches(searchText)); container.scrollTo(0); // Seems to refresh the GUI somehow so it displays correctly } } } } @SubscribeEvent public static void onClientTickEvent(ClientTickEvent event){ if(event.phase == Phase.END && searchBarHoverTime > 0 && searchBarHoverTime < SEARCH_TOOLTIP_HOVER_TIME){ searchBarHoverTime++; } } @SubscribeEvent public static void onDrawScreenPostEvent(GuiScreenEvent.DrawScreenEvent.Post event){ if(event.getGui() instanceof GuiContainerCreative && currentSearchField != null){ GuiContainerCreative gui = (GuiContainerCreative)event.getGui(); CreativeTabs tab = CreativeTabs.CREATIVE_TAB_ARRAY[gui.getSelectedTabIndex()]; if(tab == WizardryTabs.SPELLS && DrawingUtils.isPointInRegion(currentSearchField.x, currentSearchField.y, currentSearchField.width, currentSearchField.height, event.getMouseX(), event.getMouseY())){ if(searchBarHoverTime == 0){ searchBarHoverTime++; }else if(searchBarHoverTime == SEARCH_TOOLTIP_HOVER_TIME){ event.getGui().drawHoveringText(I18n.format("container." + Wizardry.MODID + ":arcane_workbench.search_tooltip", TOOLTIP_SYNTAX.getFormattingCode(), TOOLTIP_BODY.getFormattingCode()), event.getMouseX(), event.getMouseY()); } } }else{ searchBarHoverTime = 0; } } }