2020-10-17 10:52:04 +00:00
|
|
|
import logging
|
2021-05-09 07:05:51 +00:00
|
|
|
import math
|
2020-10-17 10:52:04 +00:00
|
|
|
from enum import Enum
|
|
|
|
from threading import Thread
|
|
|
|
|
2022-01-30 14:28:17 +00:00
|
|
|
import d3dshot
|
2020-10-17 10:52:04 +00:00
|
|
|
import pywintypes
|
2022-01-30 14:28:17 +00:00
|
|
|
import win32api
|
2020-10-17 10:52:04 +00:00
|
|
|
import win32gui
|
2022-01-30 14:28:17 +00:00
|
|
|
from ctypes import windll
|
2020-10-17 10:52:04 +00:00
|
|
|
|
2022-02-01 16:50:57 +00:00
|
|
|
from fishy.helper.helper import print_exc
|
2020-10-17 10:52:04 +00:00
|
|
|
|
|
|
|
|
|
|
|
class Status(Enum):
|
2020-10-17 22:35:20 +00:00
|
|
|
CRASHED = -1
|
|
|
|
STOPPED = 0
|
2020-10-17 10:52:04 +00:00
|
|
|
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
|
2022-02-03 00:21:03 +00:00
|
|
|
d3: d3dshot.D3DShot = d3dshot.create(capture_output="numpy")
|
2022-01-30 14:28:17 +00:00
|
|
|
monitor_top_left = None
|
2020-10-17 10:52:04 +00:00
|
|
|
|
|
|
|
|
2020-10-17 19:06:07 +00:00
|
|
|
def init():
|
2020-10-17 10:52:04 +00:00
|
|
|
"""
|
|
|
|
Executed once before the main loop,
|
|
|
|
Finds the game window, and calculates the offset to remove the title bar
|
|
|
|
"""
|
2022-02-02 23:59:10 +00:00
|
|
|
# noinspection PyUnresolvedReferences
|
2020-10-17 10:52:04 +00:00
|
|
|
try:
|
|
|
|
WindowServer.hwnd = win32gui.FindWindow(None, "Elder Scrolls Online")
|
2022-01-30 14:28:17 +00:00
|
|
|
|
|
|
|
monitor_id = windll.user32.MonitorFromWindow(WindowServer.hwnd, 2)
|
|
|
|
WindowServer.monitor_top_left = win32api.GetMonitorInfo(monitor_id)["Monitor"][:2]
|
|
|
|
|
2020-10-17 10:52:04 +00:00
|
|
|
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
|
2022-01-30 14:28:17 +00:00
|
|
|
|
2022-02-03 00:21:03 +00:00
|
|
|
WindowServer.d3.display = next((m for m in WindowServer.d3.displays if m.hmonitor == monitor_id), None)
|
2022-01-30 14:28:17 +00:00
|
|
|
|
2020-10-17 10:52:04 +00:00
|
|
|
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
|
|
|
|
"""
|
|
|
|
|
2022-01-30 14:28:17 +00:00
|
|
|
temp_screen = WindowServer.d3.screenshot()
|
2020-10-17 10:52:04 +00:00
|
|
|
|
|
|
|
rect = win32gui.GetWindowRect(WindowServer.hwnd)
|
2021-05-16 00:24:21 +00:00
|
|
|
client_rect = win32gui.GetClientRect(WindowServer.hwnd)
|
|
|
|
|
2022-01-30 14:28:17 +00:00
|
|
|
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
|
2020-10-17 10:52:04 +00:00
|
|
|
crop = (
|
2022-01-30 14:28:17 +00:00
|
|
|
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]
|
|
|
|
)
|
2020-10-17 10:52:04 +00:00
|
|
|
|
2022-01-30 14:28:17 +00:00
|
|
|
WindowServer.Screen = temp_screen[crop[1]:crop[3], crop[0]:crop[2]] if not fullscreen else temp_screen
|
2020-10-17 10:52:04 +00:00
|
|
|
|
|
|
|
if WindowServer.Screen.size == 0:
|
|
|
|
logging.error("Don't minimize or drag game window outside the screen")
|
|
|
|
WindowServer.status = Status.CRASHED
|
|
|
|
|
|
|
|
|
2021-11-21 07:12:14 +00:00
|
|
|
# noinspection PyBroadException
|
2020-10-17 10:52:04 +00:00
|
|
|
def run():
|
|
|
|
# todo use config
|
2022-02-01 11:51:58 +00:00
|
|
|
logging.debug("window server started")
|
2020-10-17 10:52:04 +00:00
|
|
|
while WindowServer.status == Status.RUNNING:
|
2021-11-21 07:12:14 +00:00
|
|
|
try:
|
|
|
|
loop()
|
|
|
|
except Exception:
|
2022-02-01 16:50:57 +00:00
|
|
|
print_exc()
|
2021-11-21 07:12:14 +00:00
|
|
|
WindowServer.status = Status.CRASHED
|
2022-02-01 11:51:58 +00:00
|
|
|
|
|
|
|
if WindowServer.status == Status.CRASHED:
|
|
|
|
logging.debug("window server crashed")
|
|
|
|
elif WindowServer.status == Status.STOPPED:
|
|
|
|
logging.debug("window server stopped")
|
2020-10-17 10:52:04 +00:00
|
|
|
|
|
|
|
|
|
|
|
def start():
|
|
|
|
if WindowServer.status == Status.RUNNING:
|
|
|
|
return
|
|
|
|
|
2020-10-17 19:06:07 +00:00
|
|
|
init()
|
2020-10-17 10:52:04 +00:00
|
|
|
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
|