fishyboteso/fishy/engine/common/window_server.py
Adam Saudagar 4ea27ae7da added a null check in get_coords
changed print_exec to print in both console and fishy
fixed engine couldn't be stoped with toggle
fixed full auto stop getting called multiple times due to inactive stop
set logging for d3dshot to info, to remove debug logs caused by it
2022-02-01 22:20:57 +05:30

120 lines
3.4 KiB
Python

import logging
import math
import traceback
from enum import Enum
from threading import Thread
import cv2
import d3dshot
import pywintypes
import win32api
import win32gui
from ctypes import windll
from fishy.helper.config import config
from fishy.helper.helper import print_exc
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
d3: d3dshot.D3DShot = None
monitor_top_left = None
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")
monitor_id = windll.user32.MonitorFromWindow(WindowServer.hwnd, 2)
WindowServer.monitor_top_left = win32api.GetMonitorInfo(monitor_id)["Monitor"][:2]
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
d3 = d3dshot.create(capture_output="numpy")
d3.display = next((m for m in d3.displays if m.hmonitor == monitor_id), None)
WindowServer.d3 = d3
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
"""
temp_screen = WindowServer.d3.screenshot()
rect = win32gui.GetWindowRect(WindowServer.hwnd)
client_rect = win32gui.GetClientRect(WindowServer.hwnd)
fullscreen = WindowServer.d3.display.resolution[1] == (rect[3] - rect[1])
title_offset = ((rect[3] - rect[1]) - client_rect[3]) - WindowServer.windowOffset if not fullscreen else 0
crop = (
rect[0] + WindowServer.windowOffset - WindowServer.monitor_top_left[0],
rect[1] + title_offset - WindowServer.monitor_top_left[1],
rect[2] - WindowServer.windowOffset - WindowServer.monitor_top_left[0],
rect[3] - WindowServer.windowOffset - WindowServer.monitor_top_left[1]
)
WindowServer.Screen = temp_screen[crop[1]:crop[3], crop[0]:crop[2]] if not fullscreen else temp_screen
if WindowServer.Screen.size == 0:
logging.error("Don't minimize or drag game window outside the screen")
WindowServer.status = Status.CRASHED
# noinspection PyBroadException
def run():
# todo use config
logging.debug("window server started")
while WindowServer.status == Status.RUNNING:
try:
loop()
except Exception:
print_exc()
WindowServer.status = Status.CRASHED
if WindowServer.status == Status.CRASHED:
logging.debug("window server crashed")
elif WindowServer.status == Status.STOPPED:
logging.debug("window server stopped")
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