package com.pokemongo; import java.awt.AWTException; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.Point; import java.awt.Rectangle; import java.awt.Robot; import java.awt.event.InputEvent; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.ArrayList; import java.util.List; import javax.imageio.ImageIO; /** * Automatizační nástroj pro Pokémon GO. * Najde běžící aplikaci, označí všechny Pokémony a stiskne tlačítko Transfer. */ public class PokemonGoAutomation { private Robot robot; private Rectangle windowBounds; private BufferedImage t1Template; // TRANSFER button template private BufferedImage t2Template; // Confirmation button template private BufferedImage t3Template; private BufferedImage pok1Template; // Pokemon detection template private BufferedImage includeTemplate; // Include button template 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ů public PokemonGoAutomation() throws AWTException { this.robot = new Robot(); this.robot.setAutoDelay(50); this.robot.setAutoWaitForIdle(true); loadButtonTemplates(); } /** * Vrátí počet dosud transfernutých pokémonů */ public int getTransferredCount() { return transferredPokemonCount; } /** * Resetuje počítadlo transfernutých pokémonů */ public void resetTransferredCount() { transferredPokemonCount = 0; } /** * Pořídí screenshot oblasti okna */ private BufferedImage captureScreen(Rectangle area) { return robot.createScreenCapture(area); } /** * Načte templaty pro tlačítka TRANSFER (t1.png) a confirmation (t2.png) */ private void loadButtonTemplates() { try { String t1Paths = "/t1.png"; t1Template = ImageIO.read(getClass().getResourceAsStream(t1Paths)); System.out.println("✅ Template TRANSFER načten z: " + t1Paths); String t2Paths = "/t2.png"; t2Template = ImageIO.read(getClass().getResourceAsStream(t2Paths)); System.out.println("✅ Template Potvrzení načten z: " + t2Paths); String t3Paths = "/t3.png"; t3Template = ImageIO.read(getClass().getResourceAsStream(t3Paths)); System.out.println("✅ Template Potvrzení načten z: " + t3Paths); String pok1Paths = "/pok1.png"; pok1Template = ImageIO.read(getClass().getResourceAsStream(pok1Paths)); System.out.println("✅ Template Pokémon načten z: " + pok1Paths); String includePaths = "/include.png"; includeTemplate = ImageIO.read(getClass().getResourceAsStream(includePaths)); System.out.println("✅ Template INCLUDE načten z: " + includePaths); if (t1Template == null) { System.out.println("⚠️ Template t1.png nebyl nalezen"); } if (t2Template == null) { System.out.println("⚠️ Template t2.png nebyl nalezen"); } if (pok1Template == null) { System.out.println("⚠️ Template pok1.png nebyl nalezen"); } if (includeTemplate == null) { System.out.println("⚠️ Template include.png nebyl nalezen"); } } catch (IOException e) { System.err.println("⚠️ Chyba při načítání templates: " + e.getMessage()); } } /** * Porovnává template s oblastí v obrázku - jednoduché pixelové porovnání s * optimalizací */ private double templateMatch(BufferedImage screenshot, int startX, int startY, BufferedImage template, int tolerance) { if (template == null) return 0.0; int tWidth = template.getWidth(); int tHeight = template.getHeight(); // Kontrola hranic if (startX + tWidth > screenshot.getWidth() || startY + tHeight > screenshot.getHeight()) { return 0.0; } if (startX < 0 || startY < 0) { return 0.0; } int matchingPixels = 0; int totalPixels = tWidth * tHeight; int requiredMatch = (int) (totalPixels * 0.75); // 75% shody for (int y = 0; y < tHeight; y++) { for (int x = 0; x < tWidth; x++) { int templateRGB = template.getRGB(x, y); int screenRGB = screenshot.getRGB(startX + x, startY + y); // Rozdělit RGB hodnoty int tR = (templateRGB >> 16) & 0xFF; int tG = (templateRGB >> 8) & 0xFF; int tB = templateRGB & 0xFF; int sR = (screenRGB >> 16) & 0xFF; int sG = (screenRGB >> 8) & 0xFF; int sB = screenRGB & 0xFF; // Porovnat barvy - zvýšená tolerance pro lepší detekci int rDiff = Math.abs(tR - sR); int gDiff = Math.abs(tG - sG); int bDiff = Math.abs(tB - sB); if (rDiff < tolerance && gDiff < tolerance && bDiff < tolerance) { matchingPixels++; // Early exit - pokud jsme nedosáhli minima, skončit if (matchingPixels < requiredMatch / 2 && (y * tWidth + x) > (totalPixels / 2)) { return 0.0; } } } } // Vrátit procentuální shodu (0.0-1.0) return (double) matchingPixels / totalPixels; } /** * Detekuje pozice Pokémonů pomocí template matchingu s pok1.png * Hledá v oblasti od vrchu obrazovky do 75% výšky * Může najít až 9 Pokémonů */ private List detectPokemonsByTemplateMatching2() { List positions = new ArrayList<>(); System.out.println("\n=== Detekce Pokémonů pomocí template matchingu (pok1.png) ==="); if (pok1Template == null) { System.out.println("⚠️ Template pok1.png není dostupný"); return positions; } BufferedImage screenshot = captureScreen(windowBounds); int tWidth = pok1Template.getWidth(); int tHeight = pok1Template.getHeight(); System.out.println("Template velikost: " + tWidth + "x" + tHeight); // Grid parametry - 3x3 (9 Pokémonů) - pevné pozice podle layoutu aplikace int gridStartY = (int) (windowBounds.height * 0.15); int gridEndY = (int) (windowBounds.height * 0.75); int gridHeight = gridEndY - gridStartY; int gridMargin = (int) (windowBounds.width * 0.05); int gridStartX = gridMargin; int gridWidth = windowBounds.width - (2 * gridMargin); int columns = 3; int rows = 3; // 3x3 grid = 9 Pokémonů int columnWidth = gridWidth / columns; int rowHeight = gridHeight / rows; System.out.println("Hledám Pokémony v gridu 3x3 (9 pozic)"); // Pro každou buňku v gridu hledat template for (int row = 0; row < rows; row++) { for (int col = 0; col < columns; col++) { int cellX = gridStartX + (col * columnWidth); int cellY = gridStartY + (row * rowHeight); double bestScore = 0.0; int bestX = cellX + columnWidth / 2; int bestY = cellY + rowHeight / 2; // Skenovat buňku s jemností for (int sy = cellY; sy < cellY + rowHeight - tHeight; sy += 3) { for (int sx = cellX; sx < cellX + columnWidth - tWidth; sx += 3) { double score = templateMatch(screenshot, sx, sy, pok1Template, 115); // Zvýšená tolerance if (score > bestScore) { bestScore = score; bestX = sx + tWidth / 2; bestY = sy + tHeight / 2; } } } // Pokud jsme našli match (skóre > 75%), považovat za Pokémona if (bestScore > 0.98) { int x = windowBounds.x + bestX; int y = windowBounds.y + bestY; positions.add(new Point(x, y)); System.out.println(" Detekován Pokémon na [" + row + "," + col + "] -> (" + x + ", " + y + ") skóre=" + String.format("%.1f", bestScore * 100) + "%"); } } } System.out.println("Celkem detekováno: " + positions.size() + " Pokémonů"); System.out.println("=================================\n"); return positions; } /** * Najde a vrátí pozici transferu tlačítka bez kliknutí */ private Point findTransferButtonPosition() { System.out.println("Hledám tlačítko TRANSFER pomocí template matchingu (t1.png)..."); BufferedImage screenshot = captureScreen(windowBounds); int tWidth = t1Template.getWidth(); int tHeight = t1Template.getHeight(); // Template je celý řádek - zkusíme matchovat od 75% do 95% (kde by měl být // TRANSFER řádek) int searchStartY = (int) (windowBounds.height * 0.75); int searchEndY = (int) (windowBounds.height * 0.95); double bestScore = 0.0; int bestX = 0; int bestY = 0; // Skenovat Y-ové pozice s větším krokem - 15px místo 5px pro zrychlení for (int y = searchStartY; y <= searchEndY - tHeight; y += 15) { // Skenovat také X pozice pro nalezení středu shody for (int x = 0; x <= windowBounds.width - tWidth; x += 30) { double score = templateMatch(screenshot, x, y, t1Template, 90); if (score > bestScore) { bestScore = score; bestX = x; bestY = y; } } } if (bestScore > 0.92) { Point bestMatch = new Point( windowBounds.x + bestX + (tWidth / 2), windowBounds.y + bestY + (tHeight / 2)); System.out.println("✅ Nalezeno TRANSFER tlačítko (template match) na: " + bestMatch + " (shoda: " + String.format("%.1f", bestScore * 100) + "%)"); return bestMatch; } System.out.println("Template nenalezen"); return null; } /** * Najde a vrátí pozici potvrzovacího tlačítka bez kliknutí */ private Point findConfirmTransferButtonPosition(BufferedImage template, int tolerance) { System.out.println("Hledám potvrzovací TRANSFER tlačítko pomocí template matchingu..."); BufferedImage screenshot = captureScreen(windowBounds); int tWidth = template.getWidth(); int tHeight = template.getHeight(); // Dialog je obvykle v horní polovině po TRANSFER kliknutí int searchStartY = (int) (windowBounds.height * 0.40); int searchEndY = (int) (windowBounds.height * 0.75); double bestScore = 0.0; int bestX = 0; int bestY = 0; // Skenovat Y-ové pozice s větším krokem - 15px místo 5px pro zrychlení for (int y = searchStartY; y <= searchEndY - tHeight; y += 15) { // Skenovat také X pozice pro nalezení středu shody for (int x = 0; x <= windowBounds.width - tWidth; x += 30) { double score = templateMatch(screenshot, x, y, template, tolerance); if (score > bestScore) { bestScore = score; bestX = x; bestY = y; } } } if (bestScore > 0.85) { Point bestMatch = new Point( windowBounds.x + bestX + (tWidth / 2), windowBounds.y + bestY + (tHeight / 2)); System.out.println("✅ Nalezeno potvrzovací tlačítko (template match) na: " + bestMatch + " (shoda: " + String.format("%.1f", bestScore * 100) + "%)"); return bestMatch; } System.out.println("Template nenalezen"); return null; } private Point findIncludeButtonPosition(int tolerance) { System.out.println("Hledám tlačítko INCLUDE pomocí template matchingu (include.png)..."); BufferedImage screenshot = captureScreen(windowBounds); int tWidth = includeTemplate.getWidth(); int tHeight = includeTemplate.getHeight(); // Dialog je obvykle v horní polovině po TRANSFER kliknutí int searchStartY = (int) (windowBounds.height * 0.40); int searchEndY = (int) (windowBounds.height * 0.75); double bestScore = 0.0; int bestX = 0; int bestY = 0; // Skenovat Y-ové pozice s větším krokem - 15px místo 5px pro zrychlení for (int y = searchStartY; y <= searchEndY - tHeight; y += 15) { // Skenovat také X pozice pro nalezení středu shody for (int x = 0; x <= windowBounds.width - tWidth; x += 30) { double score = templateMatch(screenshot, x, y, includeTemplate, tolerance); if (score > bestScore) { bestScore = score; bestX = x; bestY = y; } } } if (bestScore > 0.80) { Point bestMatch = new Point( windowBounds.x + bestX + (tWidth / 2), windowBounds.y + bestY + (tHeight / 2)); System.out.println("✅ Nalezeno tlačítko INCLUDE (template match) na: " + bestMatch + " (shoda: " + String.format("%.1f", bestScore * 100) + "%)"); return bestMatch; } System.out.println("Template nenalezen"); return null; } /** * Najde okno s názvem obsahujícím "Pokémon" nebo "Pokemon" */ public boolean findPokemonGoWindow() { try { // Pro Linux - hledání okna pomocí xdotool // Nejdříve najít ID okna, pak získat jeho geometrii Process searchProcess = Runtime.getRuntime().exec( new String[] { "bash", "-c", "xdotool search --name \"Lenovo|L78032\" | head -1" }); java.io.BufferedReader searchReader = new java.io.BufferedReader( new java.io.InputStreamReader(searchProcess.getInputStream())); String windowId = searchReader.readLine(); searchProcess.waitFor(); if (windowId != null && !windowId.trim().isEmpty()) { System.out.println("Nalezeno okno s ID: " + windowId); // Získat geometrii okna Process geomProcess = Runtime.getRuntime().exec( new String[] { "bash", "-c", "xdotool getwindowgeometry " + windowId.trim() }); java.io.BufferedReader geomReader = new java.io.BufferedReader( new java.io.InputStreamReader(geomProcess.getInputStream())); String line; int x = 0, y = 0, width = 0, height = 0; while ((line = geomReader.readLine()) != null) { System.out.println("xdotool výstup: " + line); if (line.contains("Position:")) { String[] parts = line.split("Position: ")[1].split(","); x = Integer.parseInt(parts[0].trim()); y = Integer.parseInt(parts[1].trim().split(" ")[0]); } else if (line.contains("Geometry:")) { String[] parts = line.split("Geometry: ")[1].split("x"); width = Integer.parseInt(parts[0].trim()); height = Integer.parseInt(parts[1].trim()); } } geomProcess.waitFor(); if (width > 0 && height > 0) { windowBounds = new Rectangle(x, y, width, height); System.out.println("Nalezeno okno: " + windowBounds); return true; } } // Fallback - použití celé obrazovky System.out.println("Okno nenalezeno, použiji celou obrazovku"); GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); windowBounds = gd.getDefaultConfiguration().getBounds(); return true; } catch (Exception e) { System.err.println("Chyba při hledání okna: " + e.getMessage()); e.printStackTrace(); // Použití celé obrazovky jako záložní varianta GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); windowBounds = gd.getDefaultConfiguration().getBounds(); return true; } } /** * Aktivuje okno aplikace */ public void activateWindow() { try { // Kliknutí na horní panel okna (title bar) pro aktivaci // Title bar je obvykle 30-40px vysoký v horní části okna int centerX = windowBounds.x + windowBounds.width / 2; int titleBarY = windowBounds.y + 15; // 15px od vrcholu okna = horní panel System.out.println("Aktivuji okno kliknutím na title bar: (" + centerX + ", " + titleBarY + ")"); robot.mouseMove(centerX, titleBarY); robot.delay(200); robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); robot.delay(DELAY_AFTER_ACTION); System.out.println("Okno aktivováno"); } catch (Exception e) { System.err.println("Chyba při aktivaci okna: " + e.getMessage()); } } /** * Stiskne tlačítko Transfer na spodní části obrazovky */ public void clickTransferButton() { // Použít detekci tlačítka // Point buttonPos = findTransferButtonPosition(); Point buttonPos = getAbsolutePoint(307, 1100); if (buttonPos == null) { System.err.println("Tlačítko TRANSFER nebylo nalezeno!"); return; } robot.mouseMove(buttonPos.x, buttonPos.y); robot.delay(DELAY_AFTER_ACTION); robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); System.out.println("Tlačítko TRANSFER stisknuto!"); robot.delay(DELAY_AFTER_ACTION); } /** * Potvrdí transfer (pokud je potřeba potvrzovací dialog) */ public void clickConfirmTransferButton(BufferedImage template, int tolerance) { System.out.println("Potvrzuji transfer - hledám confirmation button..."); robot.delay(100); // Počkat na zobrazení dialogu // Najít zelené TRANSFER tlačítko v potvrzovacím dialogu Point buttonPos = findConfirmTransferButtonPosition(template, tolerance); if (buttonPos == null) { System.out.println("Potvrzovací tlačítko nebylo nalezeno, přeskočím potvrzení."); return; } robot.mouseMove(buttonPos.x, buttonPos.y); robot.delay(DELAY_BETWEEN_CLICKS); robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); System.out.println("Transfer finálně potvrzen!"); robot.delay(DELAY_AFTER_ACTION); } public boolean clickIncludeButton(int tolerance) { System.out.println("Potvrzuji transfer - hledám include.png (confirmation button)..."); robot.delay(100); // Počkat na zobrazení dialogu // Najít zelené INCLUDE tlačítko v potvrzovacím dialogu Point buttonPos = findIncludeButtonPosition(tolerance); if (buttonPos == null) { System.out.println("INCLUDE tlačítko nebylo nalezeno, přeskočím potvrzení."); return false; } robot.mouseMove(buttonPos.x, buttonPos.y); robot.delay(DELAY_BETWEEN_CLICKS); robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); System.out.println("Transfer finálně potvrzen!"); robot.delay(DELAY_AFTER_ACTION); return true; } /** * Spustí Transfer automatizaci s konkrétním počtem pokémonů * * @param totalPokemonCount Celkový počet pokémonů k transferu * @param delaySeconds Čekání mezi iteracemi (v sekundách) */ public void runWithCount(int totalPokemonCount, int delaySeconds) { System.out.println("Spouštím Transfer automatizaci - Počet pokémonů: " + totalPokemonCount + ", Čekání: " + delaySeconds + "s"); if (!findPokemonGoWindow()) { System.err.println("Nepodařilo se najít okno Pokémon GO!"); return; } activateWindow(); System.out.println("Čekám 1 sekundu před začátkem..."); robot.delay(1000); int transferredCount = 0; // Transferovat dokud nedosáhneme požadovaného počtu while (transferredCount < totalPokemonCount) { // Kontrola přerušení if (Thread.currentThread().isInterrupted()) { System.out.println("\n⚠️ Automatizace byla přerušena!"); return; } int pokemonThisRound = Math.min(12, totalPokemonCount - transferredCount); System.out.println( "\n=== Iterace " + (transferredCount / 9 + 1) + " - Transferuji maximálně " + pokemonThisRound + " pokémonů ==="); // Vybrat pokémony a získat skutečný počet vybraných int actualTransferredCount = selectAllPokemonCount(pokemonThisRound); System.out.println("Čekám na TRANSFER..."); clickTransferButton(); System.out.println("Čekám na INCLUDE dialog..."); robot.delay(100); if (clickIncludeButton(110)) { System.out.println("Čekám na potvrzovací dialog t3..."); robot.delay(100); clickConfirmTransferButton(t3Template, 70); } else { System.out.println("Čekám na potvrzovací dialog t2..."); robot.delay(100); clickConfirmTransferButton(t2Template, 70); } transferredCount += actualTransferredCount; transferredPokemonCount += actualTransferredCount; System.out.println("Transferováno v této iteraci: " + actualTransferredCount + " pokémonů (celkem: " + transferredCount + ")"); // Pokud ještě zbývá co transferovat, počkat if (transferredCount < totalPokemonCount) { System.out.println("Přestávka: " + delaySeconds + " sekund..."); // Čekat s kontrolou přerušení long endTime = System.currentTimeMillis() + (delaySeconds * 1000L); while (System.currentTimeMillis() < endTime) { if (Thread.currentThread().isInterrupted()) { System.out.println("\n⚠️ Automatizace byla přerušena během přestávky!"); return; } robot.delay(100); } } } System.out.println("\n✅ Transfer automatizace dokončena! Transferováno: " + transferredCount + " pokémonů"); } /** * Označí konkrétní počet pokémonů * * @return Skutečný počet vybraných pokémonů */ private int selectAllPokemonCount(int count) { System.out.println("Začínám označovat " + count + " pokémonů (pouze template matching)..."); List positions = getPossitionsAbsolute(); int maxPokemon = Math.min(count, positions.size()); System.out.println("Budu označovat " + maxPokemon + " pokémonů..."); for (int i = 0; i < maxPokemon; i++) { Point pos = positions.get(i); System.out.println("Klikám na Pokémona " + (i + 1) + "/" + maxPokemon + " na pozici: " + pos); robot.mouseMove(pos.x, pos.y); if (i == 0) { System.out.println(" -> Dlouhé podržení (aktivace multi-select)"); robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); robot.delay(700); robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); robot.delay(DELAY_AFTER_ACTION); } else { System.out.println(" -> Normální klik"); robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); } robot.delay(DELAY_BETWEEN_CLICKS); } System.out.println("Označeno " + maxPokemon + " pokémonů!"); System.out.println("Čekám před kliknutím na TRANSFER..."); robot.delay(800); return maxPokemon; } private List getPossitionsAbsolute() { List possitions = new ArrayList<>(); possitions.add(getAbsolutePoint(115, 240)); possitions.add(getAbsolutePoint(307, 240)); possitions.add(getAbsolutePoint(496, 240)); possitions.add(getAbsolutePoint(115, 460)); possitions.add(getAbsolutePoint(307, 460)); possitions.add(getAbsolutePoint(496, 460)); possitions.add(getAbsolutePoint(115, 680)); possitions.add(getAbsolutePoint(307, 680)); possitions.add(getAbsolutePoint(496, 680)); possitions.add(getAbsolutePoint(115, 900)); possitions.add(getAbsolutePoint(307, 900)); possitions.add(getAbsolutePoint(496, 900)); return possitions; } /** * Převede relativní pozici v okně (0.0-1.0) na absolutní souřadnice obrazovky * * @param relativeX Relativní X pozice (0.0 = levý okraj, 1.0 = pravý okraj) * @param relativeY Relativní Y pozice (0.0 = horní okraj, 1.0 = dolní okraj) * @return Absolutní pozice na obrazovce */ private Point getAbsolutePoint(int relativeX, int relativeY) { int absoluteX = windowBounds.x + relativeX; int absoluteY = windowBounds.y + relativeY; return new Point(absoluteX, absoluteY); } 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á..."); } }