在游戏顶部绘制覆盖图的库

game-overlay-sdk的Python项目详细描述


游戏覆盖sdk

在游戏窗口顶部写入文本消息的库。

支持的图形api:

  • DirectX 11
  • DirectX 12
  • 瓦肯

支持的体系结构:

  • x86
  • x64

用法

要为全屏游戏绘制覆盖图,在初始化图形api之前,您必须钩住游戏进程,因此有两个选项可以实现它:

  • 创建挂起的进程,安装挂钩并恢复线程
  • 如果创建了目标进程,请为createprocess事件注册回调-挂起所有线程,安装挂钩并恢复所有线程(我使用WMI来实现它)

这两个选项都已实现,因此有:

run_process (exe_path, exe_args = "", steam_app_id = None)
start_monitor (process_name)

重要提示:对于启动监视器,您需要提供与taskmanager中完全相同的可执行文件名,并自行运行目标进程,而对于运行进程,您需要提供可执行文件的完整路径,sdk将为您运行它

在游戏进程中加载dll后,您就可以调用

send_message (message)

发送消息并将其呈现在游戏进程窗口的顶部 对于进程间的通信,我使用Memory Mapped Files,所以send_message方法只是将数据发送到这个内存映射文件,然后注入游戏进程的dll读取它。

重要提示:当游戏显示新帧时,将立即显示消息,但我不能确保显示所有消息,例如,如果您发送消息的速度快于游戏绘制帧,则只显示最新消息,同时,游戏进程每200毫秒读取一次数据(但我在python代码中使用queue缓冲消息,因此实际速率可能更高)

还有几种方法可以控制cpp代码的日志级别:

set_log_level (level) # level here is not related to python's log levels!
enable_monitor_logger ()
disble_monitor_logger ():
enable_dev_logger ()

我建议默认使用enable_monitor_logger

最后应该调用的方法:

release_resources ()

我还添加了python日志处理程序,以便在游戏窗口顶部编写日志消息

overlay_log_handler = game_overlay_sdk.injector.OvelrayLogHandler ()

蒸汽游戏使用

默认情况下,steam forks游戏进程有两个进程,不可能区分它们,并且它会中断dll注入,因为run_processdll将加载到错误的进程,因此不会绘制覆盖,而对于start_monitor它几乎是随机的,如果选择了错误的进程,它可能会挂起,或者工作正常

幸运的是,有一种方法可以强制steam只创建一个进程,我们只需要在game文件夹中创建文件steam app id.txt,而且每个游戏应该只创建一次,这就是为什么在run-process方法中有steam app\u id参数的原因。您可以获取应用程序idhere

示例

看上去怎么样?

Demo

如何实现它?

代码:

import argparse
import time
import game_overlay_sdk
import game_overlay_sdk.injector
import threading
import logging


logging.basicConfig (filename = 'test.log', level = logging.WARNING)

logger = logging.getLogger (__name__)
logger.setLevel (logging.INFO)
overlay_log_handler = game_overlay_sdk.injector.OvelrayLogHandler ()
formatter = logging.Formatter ('%(levelname)s:%(message)s')
overlay_log_handler.setFormatter (formatter)
logger.addHandler (overlay_log_handler)


class MessageThread (threading.Thread):

    def __init__ (self):
        super (MessageThread, self).__init__ ()
        self.need_quit = False

    def run (self):
        i = 0
        while not self.need_quit:
            logger.info ('Hi from python OverlayLogHandler %d' % i)
            i = i + 1
            time.sleep (1)


def main ():
    parser = argparse.ArgumentParser ()
    parser.add_argument ('--exe_path', type = str, help = 'exe path', required = True)
    parser.add_argument ('--exe_args', type = str, help = 'exe args', default = '')
    parser.add_argument ('--steam_app_id', type = int, help = 'for steam games please provide app_id', required = False)
    args = parser.parse_args ()

    game_overlay_sdk.injector.enable_monitor_logger ()
    game_overlay_sdk.injector.run_process (args.exe_path, args.exe_args, args.steam_app_id)

    # start sending messages to overlay
    thread = MessageThread ()
    thread.start ()
    input ("Press Enter to stop...")
    thread.need_quit = True
    thread.join ()

    game_overlay_sdk.injector.release_resources ()


if __name__ == "__main__":
    main ()

命令行(我使用古墓丽影的试用演示,对于另一个需要更改蒸汽应用程序ID的蒸汽游戏):

python examples\overlay_log_handler.py --exe_path "D:\Steam\steamapps\common\Shadow of the Tomb Raider Trial\SOTTR.exe" --steam_app_id 974630

使用start_monitor而不是run_process的示例:

代码:

import argparse
import time
import game_overlay_sdk
import game_overlay_sdk.injector
import threading
import logging


class MessageThread (threading.Thread):

    def __init__ (self):
        super (MessageThread, self).__init__ ()
        self.need_quit = False

    def run (self):
        i = 0
        while not self.need_quit:
            try:
                game_overlay_sdk.injector.send_message ('Hi from python %d' % i)
                i = i + 1
                time.sleep (1)
            except game_overlay_sdk.injector.InjectionError as err:
                if err.exit_code == game_overlay_sdk.injector.CustomExitCodes.TARGET_PROCESS_IS_NOT_CREATED_ERROR.value:
                    logging.warning ('target process is not created')
                    time.sleep (5)
                elif err.exit_code == game_overlay_sdk.injector.CustomExitCodes.TARGET_PROCESS_WAS_TERMINATED_ERROR.value:
                    logging.warning ('target process was stopped')
                    # in monitor mode we can run process several times so dont need to stop this thread here
                    i = 0
                    time.sleep (5)
                else:
                    raise err


def main ():
    logging.basicConfig (level = logging.DEBUG)
    parser = argparse.ArgumentParser ()
    parser.add_argument ('--name', type = str, help  = 'process name', required = True)
    args = parser.parse_args ()

    game_overlay_sdk.injector.enable_monitor_logger ()
    game_overlay_sdk.injector.start_monitor (args.name)

    # start sending messages to overlay
    thread = MessageThread ()
    thread.start ()
    input ("Press Enter to stop...")
    thread.need_quit = True
    thread.join ()

    game_overlay_sdk.injector.release_resources ()


if __name__ == "__main__":
    main ()

命令行:

python examples\monitor.py --name SOTTR.exe

重要提示:使用start_monitor可以按顺序运行目标进程多次这里唯一的要求是:不要同时运行多个进程

要获取更多示例,请转到github页面

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
java ParsePushReceiver参数   java如何从设备读取完整数据?   java将java_设置为home,但忽略错误   java如何从歌曲中对专辑进行排序?   java libnaude+windows 10 x64+Eclipse   java如何将maven目标更改为如图所示的想法中的quickicon?   java swing布局中心面板,可滚动显示多个窗口窗格   使用MOSQUITO代理的mqtt中的java SSL   java如何通过属性值获取XML字符串   java在服务器每次启动时停止GWT编译   java如何让javac搜索类路径的子目录?   可以比较java中的两个不同类吗?   JAVAAndroid活动内部类中的lang.NoClassDefFoundError   java HttpServletRequest获取请求头参数块   C++socket与java客户端的连接   java如何在Apache commons http客户端上使用SSL客户端证书   使用预编译正则表达式模式提高java速度   JavaRhino将两个已编译脚本合并为一个脚本