From 444fd73bb2e80dc1e426f10d5c274d0235f8988c Mon Sep 17 00:00:00 2001 From: Radek Davidek Date: Fri, 19 Dec 2025 22:58:50 +0100 Subject: [PATCH] transfer fixes --- pgo-automat-settings.properties | 2 +- .../com/pokemongo/PokemonGoAutomation.java | 50 +++++++- src/main/java/com/pokemongo/PokemonGoGUI.java | 77 ++++++++++--- .../java/com/pokemongo/PositionPicker.java | 23 ++-- src/main/java/com/pokemongo/WindowFinder.java | 109 ++++++++++++------ 5 files changed, 192 insertions(+), 69 deletions(-) diff --git a/pgo-automat-settings.properties b/pgo-automat-settings.properties index 451f7cc..3731639 100644 --- a/pgo-automat-settings.properties +++ b/pgo-automat-settings.properties @@ -1,5 +1,5 @@ #Pokmon GO Automatizace - Nastaven -#Fri Dec 19 21:53:30 CET 2025 +#Fri Dec 19 22:55:32 CET 2025 autoklik.count=500 window.width=807 transfer.delay=0 diff --git a/src/main/java/com/pokemongo/PokemonGoAutomation.java b/src/main/java/com/pokemongo/PokemonGoAutomation.java index 6983551..0c58000 100644 --- a/src/main/java/com/pokemongo/PokemonGoAutomation.java +++ b/src/main/java/com/pokemongo/PokemonGoAutomation.java @@ -4,7 +4,9 @@ import java.awt.AWTException; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.Insets; +import java.awt.MouseInfo; import java.awt.Point; +import java.awt.PointerInfo; import java.awt.Rectangle; import java.awt.Robot; import java.awt.Toolkit; @@ -32,6 +34,7 @@ public class PokemonGoAutomation { private static final int DELAY_BETWEEN_CLICKS = 100; // ms private static final int DELAY_AFTER_ACTION = 100; // ms private int transferredPokemonCount = 0; // Počet transfernutých pokémonů + private Point initialMousePosition = null; // Pozice kurzoru před začátkem automatizace public PokemonGoAutomation() throws AWTException { this.robot = new Robot(); @@ -524,6 +527,13 @@ public class PokemonGoAutomation { System.out.println("Spouštím Transfer automatizaci - Počet pokémonů: " + totalPokemonCount + ", Čekání: " + delaySeconds + "s"); + // Uložit aktuální pozici kurzoru + PointerInfo pointerInfo = MouseInfo.getPointerInfo(); + initialMousePosition = pointerInfo != null ? pointerInfo.getLocation() : null; + if (initialMousePosition != null) { + System.out.println("Uložena počáteční pozice kurzoru: " + initialMousePosition); + } + if (!findPokemonGoWindow()) { System.err.println("Nepodařilo se najít okno Pokémon GO!"); return; @@ -537,7 +547,8 @@ public class PokemonGoAutomation { int transferredCount = 0; // Transferovat dokud nedosáhneme požadovaného počtu - while (transferredCount < totalPokemonCount) { + try { + while (transferredCount < totalPokemonCount) { // Kontrola přerušení if (Thread.currentThread().isInterrupted()) { System.out.println("\n⚠️ Automatizace byla přerušena!"); @@ -582,11 +593,22 @@ public class PokemonGoAutomation { while (System.currentTimeMillis() < endTime) { if (Thread.currentThread().isInterrupted()) { System.out.println("\n⚠️ Automatizace byla přerušena během přestávky!"); - return; + break; } robot.delay(100); } } + } + } finally { + // Obnovit pozici kurzoru + if (initialMousePosition != null) { + try { + robot.mouseMove(initialMousePosition.x, initialMousePosition.y); + System.out.println("Kurzor vrácen na počáteční pozici: " + initialMousePosition); + } catch (Exception e) { + System.err.println("Chyba při obnovení pozice kurzoru: " + e.getMessage()); + } + } } System.out.println("\n✅ Transfer automatizace dokončena! Transferováno: " + transferredCount + " pokémonů"); @@ -669,6 +691,30 @@ public class PokemonGoAutomation { return new Point(absoluteX, absoluteY); } + /** + * Vyčistí všechny prostředky používané automatizací + * Volat po skončení automatizace + */ + public void cleanup() { + try { + System.out.println("Čištění prostředků automatizace..."); + + // Uvolnit reference na obrázky + t1Template = null; + t2Template = null; + t3Template = null; + pok1Template = null; + includeTemplate = null; + windowBounds = null; + + // Explicitně vyvolat garbage collector + System.gc(); + System.out.println("Prostředky automatizace vyčištěny"); + } catch (Exception e) { + System.err.println("Chyba při čištění prostředků: " + e.getMessage()); + } + } + public static void main(String[] args) { System.out.println("=== Pokémon GO Automatizační Nástroj ==="); System.out.println("Ujistěte se, že je aplikace Pokémon GO spuštěná..."); diff --git a/src/main/java/com/pokemongo/PokemonGoGUI.java b/src/main/java/com/pokemongo/PokemonGoGUI.java index f4e92e7..683911f 100644 --- a/src/main/java/com/pokemongo/PokemonGoGUI.java +++ b/src/main/java/com/pokemongo/PokemonGoGUI.java @@ -31,7 +31,7 @@ public class PokemonGoGUI extends JFrame { private static final String CONFIG_FILE = "pgo-automat-settings.properties"; private static final String VERSION = "1.0.2"; private Properties settings; - private JSpinner countSpinner; + private JComboBox countComboBox; private JSpinner delaySpinner; private static final Font TITLE_FONT = new Font("Segoe UI", Font.BOLD, 18); @@ -330,21 +330,37 @@ public class PokemonGoGUI extends JFrame { centerPanel.setOpaque(true); if (title.contains("TRANSFER")) { - countSpinner = new JSpinner(new SpinnerNumberModel( - Integer.parseInt(settings.getProperty("transfer.count", "9")), - 1, 999, 1 - )); - countSpinner.setPreferredSize(new Dimension(64, 26)); + // Načíst hodnotu a zajistit, že je v platném rozsahu nebo v seznamu povolených hodnot + int savedCount = Integer.parseInt(settings.getProperty("transfer.count", "12")); + // Povolené hodnoty: 1, 3, 6, 12, 24, 36, 48, 60, 72, 84, 96 + int[] validCounts = {1, 3, 6, 12, 24, 36, 48, 60, 72, 84, 96}; + boolean isValid = false; + for (int count : validCounts) { + if (savedCount == count) { + isValid = true; + break; + } + } + if (!isValid) { + savedCount = 12; // Nastavit na výchozí, pokud není v seznamu povolených + } + + // Vytvořit dropdown s hodnotami 1, 3, 6, 12, 24, 36, ..., 96 + Integer[] counts = {1, 3, 6, 12, 24, 36, 48, 60, 72, 84, 96}; + countComboBox = new JComboBox<>(counts); + countComboBox.setSelectedItem(savedCount); + countComboBox.setPreferredSize(new Dimension(70, 26)); + delaySpinner = new JSpinner(new SpinnerNumberModel( Integer.parseInt(settings.getProperty("transfer.delay", "2")), 0, 60, 1 )); delaySpinner.setPreferredSize(new Dimension(64, 26)); - card.putClientProperty("countSpinner", countSpinner); + card.putClientProperty("countComboBox", countComboBox); card.putClientProperty("delaySpinner", delaySpinner); - centerPanel.add(createFieldPanel("Počet:", countSpinner)); + centerPanel.add(createFieldPanel("Počet:", countComboBox)); centerPanel.add(createFieldPanel("Čekání (s):", delaySpinner)); } else if (title.contains("AUTOKLIK")) { JSpinner xSpinner = new JSpinner(new SpinnerNumberModel( @@ -524,10 +540,10 @@ public class PokemonGoGUI extends JFrame { } // Získat počet pokémonů a čekání z GUI - JSpinner countSpinner = (JSpinner) transferCard.getClientProperty("countSpinner"); + JComboBox countComboBox = (JComboBox) transferCard.getClientProperty("countComboBox"); JSpinner delaySpinner = (JSpinner) transferCard.getClientProperty("delaySpinner"); - int pokemonCount = (Integer) countSpinner.getValue(); + int pokemonCount = (Integer) countComboBox.getSelectedItem(); int delaySeconds = (Integer) delaySpinner.getValue(); stopButton.setEnabled(true); @@ -599,6 +615,18 @@ public class PokemonGoGUI extends JFrame { } }); } finally { + // Čistit prostředky po automatizaci + try { + if (automation != null) { + automation.cleanup(); + } + // Také vyčistit WindowFinder resources + WindowFinder.cleanup(); + System.gc(); + } catch (Exception cleanupEx) { + System.err.println("Chyba při čištění: " + cleanupEx.getMessage()); + } + SwingUtilities.invokeLater(new Runnable() { @Override public void run() { @@ -773,7 +801,7 @@ public class PokemonGoGUI extends JFrame { // Výchozí hodnoty, pokud nastavení neexistují if (!settings.containsKey("transfer.count")) { - settings.setProperty("transfer.count", "9"); + settings.setProperty("transfer.count", "12"); } if (!settings.containsKey("transfer.delay")) { settings.setProperty("transfer.delay", "2"); @@ -796,9 +824,9 @@ public class PokemonGoGUI extends JFrame { * Uloží aktuální nastavení do souboru */ private void saveSettings() { - // Uložení hodnot z spinnerů - if (countSpinner != null) { - settings.setProperty("transfer.count", countSpinner.getValue().toString()); + // Uložení hodnot z combo boxu a spinneru + if (countComboBox != null) { + settings.setProperty("transfer.count", countComboBox.getSelectedItem().toString()); } if (delaySpinner != null) { settings.setProperty("transfer.delay", delaySpinner.getValue().toString()); @@ -819,11 +847,32 @@ public class PokemonGoGUI extends JFrame { public static void main(String[] args) { + // Nastavit shutdown hook pro bezpečné ukončení + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + System.out.println("Aplikace se vypíná..."); + // Vyčistit X11 resources + try { + WindowFinder.cleanup(); + } catch (Exception e) { + System.err.println("Chyba při čištění WindowFinder: " + e.getMessage()); + } + })); + SwingUtilities.invokeLater(new Runnable() { @Override public void run() { PokemonGoGUI frame = new PokemonGoGUI(); frame.setVisible(true); + + // Nastavit window listener pro čisté ukončení + frame.addWindowListener(new java.awt.event.WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + System.out.println("Zavírám okno..."); + frame.saveSettings(); + System.exit(0); + } + }); } }); } diff --git a/src/main/java/com/pokemongo/PositionPicker.java b/src/main/java/com/pokemongo/PositionPicker.java index 38c72a2..605efa4 100644 --- a/src/main/java/com/pokemongo/PositionPicker.java +++ b/src/main/java/com/pokemongo/PositionPicker.java @@ -22,20 +22,11 @@ public class PositionPicker extends JWindow { GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); Rectangle screenBounds = gd.getDefaultConfiguration().getBounds(); - // Zjistit insets - offset zp ůsobený OS panelem/dashboardem - Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(gd.getDefaultConfiguration()); - System.out.println("PositionPicker insets: top=" + insets.top + ", left=" + insets.left); + // Pokrýt celou obrazovku bez omezení insets + // (protože vrátíme absolutní globální souřadnice, ne relativní) + setBounds(screenBounds); - // Aplikovat insets na bounds - Rectangle bounds = new Rectangle( - screenBounds.x + insets.left, - screenBounds.y + insets.top, - screenBounds.width - insets.left - insets.right, - screenBounds.height - insets.top - insets.bottom - ); - setBounds(bounds); - - System.out.println("PositionPicker vytvořen: " + bounds); + System.out.println("PositionPicker vytvořen: " + screenBounds); setFocusable(true); setBackground(new Color(0, 0, 0, 0)); @@ -69,7 +60,11 @@ public class PositionPicker extends JWindow { panel.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { - selectedPosition = new Point(e.getX(), e.getY()); + // Vrátit absolutní globální souřadnice na obrazovce + selectedPosition = new Point( + screenBounds.x + e.getX(), + screenBounds.y + e.getY() + ); positionSelected = true; System.out.println("✅ Pozice vybrána: " + selectedPosition); if (listener != null) { diff --git a/src/main/java/com/pokemongo/WindowFinder.java b/src/main/java/com/pokemongo/WindowFinder.java index d496b21..594d95b 100644 --- a/src/main/java/com/pokemongo/WindowFinder.java +++ b/src/main/java/com/pokemongo/WindowFinder.java @@ -16,6 +16,8 @@ import java.util.List; */ public class WindowFinder { + private static Pointer cachedDisplay = null; + /** * X11 native library interface */ @@ -23,7 +25,7 @@ public class WindowFinder { X11 INSTANCE = Native.load("X11", X11.class); /** - * X11 Window Attributes struktura + * X11 Window Attributes struktura - přesná kopie z X11/Xlib.h */ class XWindowAttributes extends Structure { public int x; @@ -32,31 +34,32 @@ public class WindowFinder { public int height; public int border_width; public int depth; - public Pointer visual; - public Pointer root; - public int class_; + public Pointer visual; // Visual* - opaque pointer + public long root; // Window (XID) + public int class_; // int, not pointer public int bit_gravity; public int win_gravity; - public int backing_pixel; - public int backing_planes; public int backing_store; - public long backing_pixel_unused; - public int save_under; - public Pointer colormap; - public int map_installed; + public long backing_planes; + public long backing_pixel; + public boolean save_under; // Bool - should be boolean + public long colormap; // Colormap (XID) - should be long + public boolean map_installed; // Bool - should be boolean public int map_state; public long all_event_masks; public long your_event_mask; public long do_not_propagate_mask; + public boolean override_redirect; // Bool - missing field + public Pointer screen; // Screen* - opaque pointer, missing field @Override protected List getFieldOrder() { return Arrays.asList("x", "y", "width", "height", "border_width", "depth", "visual", "root", "class_", "bit_gravity", "win_gravity", - "backing_pixel", "backing_planes", "backing_store", - "backing_pixel_unused", "save_under", "colormap", - "map_installed", "map_state", "all_event_masks", - "your_event_mask", "do_not_propagate_mask"); + "backing_store", "backing_planes", "backing_pixel", + "save_under", "colormap", "map_installed", "map_state", + "all_event_masks", "your_event_mask", "do_not_propagate_mask", + "override_redirect", "screen"); } } @@ -84,17 +87,24 @@ public class WindowFinder { * @param searchPattern Pattern pro hledání (substring názvu okna) * @return Rectangle s pozicí a velikostí okna, nebo null pokud nenalezeno */ - public static Rectangle findWindowByName(String searchPattern) { + public static synchronized Rectangle findWindowByName(String searchPattern) { Pointer display = null; + try { - display = X11.INSTANCE.XOpenDisplay(null); - if (display == null) { - System.out.println("WindowFinder: Nelze se připojit k X11 displei"); - return null; + // Použít cachedDisplay pokud existuje, nebo otevřít nový + if (cachedDisplay != null) { + display = cachedDisplay; + System.out.println("WindowFinder: Používám cachovaný X11 display"); + } else { + display = X11.INSTANCE.XOpenDisplay(null); + if (display == null) { + System.out.println("WindowFinder: Nelze se připojit k X11 displei"); + return null; + } + cachedDisplay = display; + System.out.println("WindowFinder: Připojen k X11 displayu a uložen v cache"); } - System.out.println("WindowFinder: Připojen k X11 displayu"); - long rootWindow = X11.INSTANCE.XDefaultRootWindow(display); long[] foundWindow = new long[1]; foundWindow[0] = 0; @@ -115,15 +125,16 @@ public class WindowFinder { } catch (Exception e) { System.err.println("WindowFinder - Chyba: " + e.getMessage()); e.printStackTrace(); - return null; - } finally { - if (display != null) { + // Pokud dojde k chybě, vynulovat cache a zavřít display + if (display != null && display == cachedDisplay) { try { X11.INSTANCE.XCloseDisplay(display); - } catch (Exception e) { - System.err.println("WindowFinder - Chyba při zavírání displeje: " + e.getMessage()); + cachedDisplay = null; + } catch (Exception ex) { + System.err.println("WindowFinder - Chyba při zavírání displeje: " + ex.getMessage()); } } + return null; } } @@ -148,11 +159,12 @@ public class WindowFinder { } // Hledat v potomcích + PointerByReference children_return = new PointerByReference(); + IntByReference nchildren_return = new IntByReference(); + try { PointerByReference root_return = new PointerByReference(); PointerByReference parent_return = new PointerByReference(); - PointerByReference children_return = new PointerByReference(); - IntByReference nchildren_return = new IntByReference(); int status = X11.INSTANCE.XQueryTree(display, window, root_return, parent_return, children_return, nchildren_return); @@ -171,8 +183,8 @@ public class WindowFinder { } } - // Uvolnit paměť - X11.INSTANCE.XFree(childrenPtr); + // Don't call XFree - it can cause heap corruption + // X11.INSTANCE.XFree(childrenPtr); } } } catch (Exception e) { @@ -184,17 +196,21 @@ public class WindowFinder { * Získá jméno okna jako String */ private static String getWindowNameString(Pointer display, long window) { + PointerByReference namePtr = new PointerByReference(); + try { - PointerByReference namePtr = new PointerByReference(); int status = X11.INSTANCE.XFetchName(display, window, namePtr); - if (status != 0 && namePtr.getValue() != null) { - String name = namePtr.getValue().getString(0); - if (name != null && !name.isEmpty()) { - X11.INSTANCE.XFree(namePtr.getValue()); - return name; + if (status != 0) { + Pointer actualNamePtr = namePtr.getValue(); + if (actualNamePtr != null) { + String name = actualNamePtr.getString(0); + + // Don't call XFree - it can cause heap corruption + // X11.INSTANCE.XFree(actualNamePtr); + + return (name != null && !name.isEmpty()) ? name : null; } - X11.INSTANCE.XFree(namePtr.getValue()); } } catch (Exception e) { // Ignorovat chyby @@ -228,4 +244,21 @@ public class WindowFinder { return null; } -} \ No newline at end of file + + /** + * Ukončí X11 display connection a vyčistí cache + * Volat při shutdown aplikace + */ + public static synchronized void cleanup() { + if (cachedDisplay != null) { + try { + X11.INSTANCE.XCloseDisplay(cachedDisplay); + System.out.println("WindowFinder: X11 display uzavřen a cache vyčištěn"); + } catch (Exception e) { + System.err.println("WindowFinder - Chyba při zavírání displeje: " + e.getMessage()); + } finally { + cachedDisplay = null; + } + } + } +}