<reponame>fishyboteso/fishyboteso<gh_stars>10-100
import logging
import math
import traceback
from enum import Enum
from threading import Thread

import cv2
import numpy as np
import pywintypes
import win32gui
from PIL import ImageGrab
from win32api import GetSystemMetrics

from fishy.helper.config import config


class Status(Enum):
    CRASHED = -1
    STOPPED = 0
    RUNNING = 1


class WindowServer:
    """
    Records the game window, and allows to create instance to process it
    """
    Screen = None
    windowOffset = None
    hwnd = None
    status = Status.STOPPED


def init():
    """
    Executed once before the main loop,
    Finds the game window, and calculates the offset to remove the title bar
    """
    try:
        WindowServer.hwnd = win32gui.FindWindow(None, "Elder Scrolls Online")
        rect = win32gui.GetWindowRect(WindowServer.hwnd)
        client_rect = win32gui.GetClientRect(WindowServer.hwnd)
        WindowServer.windowOffset = math.floor(((rect[2] - rect[0]) - client_rect[2]) / 2)
        WindowServer.status = Status.RUNNING
    except pywintypes.error:
        logging.error("Game window not found")
        WindowServer.status = Status.CRASHED


def loop():
    """
    Executed in the start of the main loop
    finds the game window location and captures it
    """
    bbox = (0, 0, GetSystemMetrics(0), GetSystemMetrics(1))

    temp_screen = np.array(ImageGrab.grab(bbox=bbox))

    rect = win32gui.GetWindowRect(WindowServer.hwnd)
    client_rect = win32gui.GetClientRect(WindowServer.hwnd)

    fullscreen = GetSystemMetrics(1) == (rect[3] - rect[1])
    titleOffset = ((rect[3] - rect[1]) - client_rect[3]) - WindowServer.windowOffset if not fullscreen else 0

    crop = (
        rect[0] + WindowServer.windowOffset, rect[1] + titleOffset, rect[2] - WindowServer.windowOffset,
        rect[3] - WindowServer.windowOffset)

    WindowServer.Screen = temp_screen[crop[1]:crop[3], crop[0]:crop[2]]

    if WindowServer.Screen.size == 0:
        logging.error("Don't minimize or drag game window outside the screen")
        WindowServer.status = Status.CRASHED


def loop_end():
    cv2.waitKey(25)


# noinspection PyBroadException
def run():
    # todo use config
    while WindowServer.status == Status.RUNNING:
        try:
            loop()
        except Exception:
            traceback.print_exc()
            WindowServer.status = Status.CRASHED
    loop_end()


def start():
    if WindowServer.status == Status.RUNNING:
        return

    init()
    if WindowServer.status == Status.RUNNING:
        Thread(target=run).start()


def screen_ready():
    return WindowServer.Screen is not None or WindowServer.status == Status.CRASHED


def stop():
    WindowServer.status = Status.STOPPED

import logging
import math
import traceback
from enum import Enum
from threading import Thread

import cv2
import numpy as np
import pywintypes
import win32gui
from PIL import ImageGrab
from win32api import GetSystemMetrics

from fishy.helper.config import config


class Status(Enum):
    CRASHED = -1
    STOPPED = 0
    RUNNING = 1


class WindowServer:
    """
    Records the game window, and allows to create instance to process it
    """
    Screen = None
    windowOffset = None
    hwnd = None
    status = Status.STOPPED


def init():
    """
    Executed once before the main loop,
    Finds the game window, and calculates the offset to remove the title bar
    """
    try:
        WindowServer.hwnd = win32gui.FindWindow(None, "Elder Scrolls Online")
        rect = win32gui.GetWindowRect(WindowServer.hwnd)
        client_rect = win32gui.GetClientRect(WindowServer.hwnd)
        WindowServer.windowOffset = math.floor(((rect[2] - rect[0]) - client_rect[2]) / 2)
        WindowServer.status = Status.RUNNING
    except pywintypes.error:
        logging.error("Game window not found")
        WindowServer.status = Status.CRASHED


def loop():
    """
    Executed in the start of the main loop
    finds the game window location and captures it
    """
    bbox = (0, 0, GetSystemMetrics(0), GetSystemMetrics(1))

    temp_screen = np.array(ImageGrab.grab(bbox=bbox))

    rect = win32gui.GetWindowRect(WindowServer.hwnd)
    client_rect = win32gui.GetClientRect(WindowServer.hwnd)

    fullscreen = GetSystemMetrics(1) == (rect[3] - rect[1])
    titleOffset = ((rect[3] - rect[1]) - client_rect[3]) - WindowServer.windowOffset if not fullscreen else 0

    crop = (
        rect[0] + WindowServer.windowOffset, rect[1] + titleOffset, rect[2] - WindowServer.windowOffset,
        rect[3] - WindowServer.windowOffset)

    WindowServer.Screen = temp_screen[crop[1]:crop[3], crop[0]:crop[2]]

    if WindowServer.Screen.size == 0:
        logging.error("Don't minimize or drag game window outside the screen")
        WindowServer.status = Status.CRASHED


def loop_end():
    cv2.waitKey(25)


# noinspection PyBroadException
def run():
    # todo use config
    while WindowServer.status == Status.RUNNING:
        try:
            loop()
        except Exception:
            traceback.print_exc()
            WindowServer.status = Status.CRASHED
    loop_end()


def start():
    if WindowServer.status == Status.RUNNING:
        return

    init()
    if WindowServer.status == Status.RUNNING:
        Thread(target=run).start()


def screen_ready():
    return WindowServer.Screen is not None or WindowServer.status == Status.CRASHED


def stop():
    WindowServer.status = Status.STOPPED
Records the game window, and allows to create instance to process it Executed once before the main loop,     Finds the game window, and calculates the offset to remove the title bar Executed in the start of the main loop     finds the game window location and captures it # noinspection PyBroadException # todo use config