fishyboteso/fishy/engine/common/window_server.py

106 lines
2.6 KiB
Python
Raw Normal View History

import logging
2021-05-09 07:05:51 +00:00
import math
import traceback
from enum import Enum
from threading import Thread
import cv2
2021-05-09 07:05:51 +00:00
import numpy as np
import pywintypes
import win32gui
from PIL import ImageGrab
2021-05-09 07:05:51 +00:00
from win32api import GetSystemMetrics
2020-10-17 19:06:07 +00:00
from fishy.helper.config import config
class Status(Enum):
2020-10-17 22:35:20 +00:00
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
2020-10-17 19:06:07 +00:00
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
2020-10-17 19:06:07 +00:00
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