|
| 1 | +package git.artdeell.forgeinstaller; |
| 2 | + |
| 3 | +import java.awt.AWTEvent; |
| 4 | +import java.awt.Component; |
| 5 | +import java.awt.Container; |
| 6 | +import java.awt.EventQueue; |
| 7 | +import java.awt.Toolkit; |
| 8 | +import java.awt.Window; |
| 9 | +import java.awt.event.AWTEventListener; |
| 10 | +import java.awt.event.WindowEvent; |
| 11 | +import java.lang.instrument.Instrumentation; |
| 12 | +import java.util.ArrayList; |
| 13 | +import java.util.List; |
| 14 | + |
| 15 | +import javax.swing.AbstractButton; |
| 16 | +import javax.swing.JDialog; |
| 17 | +import javax.swing.JOptionPane; |
| 18 | + |
| 19 | +public class Agent implements AWTEventListener { |
| 20 | + private boolean forgeWindowHandled = false; |
| 21 | + private final boolean suppressProfileCreation; |
| 22 | + |
| 23 | + public Agent(boolean ps) { |
| 24 | + this.suppressProfileCreation = ps; |
| 25 | + } |
| 26 | + |
| 27 | + @Override |
| 28 | + public void eventDispatched(AWTEvent event) { |
| 29 | + WindowEvent windowEvent = (WindowEvent) event; |
| 30 | + Window window = windowEvent.getWindow(); |
| 31 | + if(windowEvent.getID() == WindowEvent.WINDOW_OPENED) { |
| 32 | + if(!forgeWindowHandled) { // false at startup, so we will handle the first window as the Forge one |
| 33 | + handleForgeWindow(window); |
| 34 | + forgeWindowHandled = true; |
| 35 | + }else if(window instanceof JDialog) { // expecting a new dialog |
| 36 | + handleDialog(window); |
| 37 | + } |
| 38 | + } |
| 39 | + } |
| 40 | + |
| 41 | + public void handleForgeWindow(Window window) { |
| 42 | + List<Component> components = new ArrayList<>(); |
| 43 | + insertAllComponents(components, window, new MainWindowFilter()); |
| 44 | + AbstractButton okButton = null; |
| 45 | + for(Component component : components) { |
| 46 | + if(component instanceof AbstractButton) { |
| 47 | + AbstractButton abstractButton = (AbstractButton) component; |
| 48 | + switch(abstractButton.getText()) { |
| 49 | + case "OK": |
| 50 | + okButton = abstractButton; // store the button, so we can press it after processing other stuff |
| 51 | + break; |
| 52 | + case "Install client": |
| 53 | + abstractButton.doClick(); // It should be the default, but let's make sure |
| 54 | + } |
| 55 | + |
| 56 | + } |
| 57 | + } |
| 58 | + if(okButton == null) { |
| 59 | + System.out.println("Failed to set all the UI components."); |
| 60 | + System.exit(17); |
| 61 | + }else{ |
| 62 | + ProfileFixer.storeProfile(); |
| 63 | + EventQueue.invokeLater(okButton::doClick); // do that after forge actually builds its window, otherwise we set the path too fast |
| 64 | + } |
| 65 | + } |
| 66 | + |
| 67 | + public void handleDialog(Window window) { |
| 68 | + List<Component> components = new ArrayList<>(); |
| 69 | + insertAllComponents(components, window, new DialogFilter()); // ensure that it's a JOptionPane dialog |
| 70 | + if(components.size() == 1) { |
| 71 | + // another common trait of them - they only have one option pane in them, |
| 72 | + // so we can discard the rest of the dialog structure |
| 73 | + JOptionPane optionPane = (JOptionPane) components.get(0); |
| 74 | + if(optionPane.getMessageType() == JOptionPane.INFORMATION_MESSAGE) { // forge doesn't emit information messages for other reasons yet |
| 75 | + System.out.println("The install was successful!"); |
| 76 | + ProfileFixer.reinsertProfile(suppressProfileCreation); |
| 77 | + System.exit(0); // again, forge doesn't call exit for some reason, so we do that ourselves here |
| 78 | + } |
| 79 | + } |
| 80 | + } |
| 81 | + |
| 82 | + public void insertAllComponents(List<Component> components, Container parent, ComponentFilter filter) { |
| 83 | + int componentCount = parent.getComponentCount(); |
| 84 | + for(int i = 0; i < componentCount; i++) { |
| 85 | + Component component = parent.getComponent(i); |
| 86 | + if(filter.checkComponent(component)) components.add(component); |
| 87 | + if(component instanceof Container) { |
| 88 | + insertAllComponents(components, (Container) component, filter); |
| 89 | + } |
| 90 | + } |
| 91 | + } |
| 92 | + |
| 93 | + public static void premain(String args, Instrumentation inst) { |
| 94 | + Toolkit.getDefaultToolkit() |
| 95 | + .addAWTEventListener(new Agent(!"NPS".equals(args)), // No Profile Suppression |
| 96 | + AWTEvent.WINDOW_EVENT_MASK); |
| 97 | + } |
| 98 | +} |
1 commit comments
kirill609 commentedon Nov 30, 2023
Lpapap