{ "info": { "author": "Andrey Parfenov", "author_email": "a1994ndrey@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 2 - Pre-Alpha", "Topic :: Utilities" ], "description": "# Game Overlay SDK\nLibrary to write text messages on top of game window.\n\n### Supported Graphical APIs:\n* DirectX 11\n* DirectX 12\n* Vulkan\n\n### Supported Architectures:\n* x86\n* x64\n\n## Usage\nTo draw overlay for fullscreen game you have to hook inside game process before initializing of graphical API, so there are two options to achive it:\n\n* Create suspended process, install hooks and resume threads\n* Register a callback for CreateProcess Event, if target process was created - suspend all threads, install hooks and resume all threads( I use [WMI](https://docs.microsoft.com/en-us/windows/desktop/wmisdk/using-wmi) to achive it)\n\nBoth of these options are implemented, so there are:\n```\nrun_process (exe_path, exe_args = \"\", steam_app_id = None)\nstart_monitor (process_name)\n```\n*Important note: for start_monitor you need to provide executable name exactly like in TaskManager and run target process by yourself while for run_process you need to provide full path to the executable and SDK will run it for you*\n\nAs soon as DLL was loaded inside game process you are able to call\n```\nsend_message (message)\n```\nTo send message and render it on top of game process window\nFor Inter Process Communication I use [Memory Mapped Files](https://docs.microsoft.com/en-us/windows/desktop/memory/creating-named-shared-memory), so send_message method just sends data to this Memory Mapped File and DLL which was injected to game process reads it.\n\n*Important note: message will be showed as soon as game presents new frame and I don't ensure that all your messages will be displayed, for example if you send messages faster than game draws frames only the latest message will be displayed, also game process reads data one time per 200ms(but I use queue in python code to buffer messages, so real rate could be bigger)*\n\nAlso, there are several methods to control log level of Cpp code:\n```\nset_log_level (level) # level here is not related to python's log levels!\nenable_monitor_logger ()\ndisble_monitor_logger ():\nenable_dev_logger ()\n```\nI recommend to use *enable_monitor_logger* by default\n\nAnd method which should be called in the end:\n```\nrelease_resources ()\n```\nAnd I've added python logging handler to write log messages on top of game window\n```\noverlay_log_handler = game_overlay_sdk.injector.OvelrayLogHandler ()\n```\n\n### Usage with Steam Games\nSteam forks game process by default so there are two process and it's impossible to distinguish them and it breaks DLL injection, for *run_process* DLL will be loaded to the wrong process so no overlay will be drawed while for *start_monitor* it's almost random, it may hangs if wrong process was selected or may works well\n\nFortunately there is a way to force Steam to create only one process, we just need to create file *steam_appid.txt* in game folder, and it should be done only once per game, that's why there is steam_app_id argument in *run_process* method. You can get app_id [here](https://steamdb.info/search/)\n\n\n### Examples\n#### How does it look?\n![Demo](https://live.staticflickr.com/65535/47939286276_08fbb08c45_h.jpg)\n#### How to achive it?\n**Code:**\n```\nimport argparse\nimport time\nimport game_overlay_sdk\nimport game_overlay_sdk.injector\nimport threading\nimport logging\n\n\nlogging.basicConfig (filename = 'test.log', level = logging.WARNING)\n\nlogger = logging.getLogger (__name__)\nlogger.setLevel (logging.INFO)\noverlay_log_handler = game_overlay_sdk.injector.OvelrayLogHandler ()\nformatter = logging.Formatter ('%(levelname)s:%(message)s')\noverlay_log_handler.setFormatter (formatter)\nlogger.addHandler (overlay_log_handler)\n\n\nclass MessageThread (threading.Thread):\n\n def __init__ (self):\n super (MessageThread, self).__init__ ()\n self.need_quit = False\n\n def run (self):\n i = 0\n while not self.need_quit:\n logger.info ('Hi from python OverlayLogHandler %d' % i)\n i = i + 1\n time.sleep (1)\n\n\ndef main ():\n parser = argparse.ArgumentParser ()\n parser.add_argument ('--exe_path', type = str, help = 'exe path', required = True)\n parser.add_argument ('--exe_args', type = str, help = 'exe args', default = '')\n parser.add_argument ('--steam_app_id', type = int, help = 'for steam games please provide app_id', required = False)\n args = parser.parse_args ()\n\n game_overlay_sdk.injector.enable_monitor_logger ()\n game_overlay_sdk.injector.run_process (args.exe_path, args.exe_args, args.steam_app_id)\n\n # start sending messages to overlay\n thread = MessageThread ()\n thread.start ()\n input (\"Press Enter to stop...\")\n thread.need_quit = True\n thread.join ()\n\n game_overlay_sdk.injector.release_resources ()\n\n\nif __name__ == \"__main__\":\n main ()\n```\n**Command line(I use trial demo of Tomb Raider, for another Steam game you need to change steam_app_id):**\n```\npython examples\\overlay_log_handler.py --exe_path \"D:\\Steam\\steamapps\\common\\Shadow of the Tomb Raider Trial\\SOTTR.exe\" --steam_app_id 974630\n```\n\n#### Example with *start_monitor* instead *run_process*:\n**Code:**\n```\nimport argparse\nimport time\nimport game_overlay_sdk\nimport game_overlay_sdk.injector\nimport threading\nimport logging\n\n\nclass MessageThread (threading.Thread):\n\n def __init__ (self):\n super (MessageThread, self).__init__ ()\n self.need_quit = False\n\n def run (self):\n i = 0\n while not self.need_quit:\n try:\n game_overlay_sdk.injector.send_message ('Hi from python %d' % i)\n i = i + 1\n time.sleep (1)\n except game_overlay_sdk.injector.InjectionError as err:\n if err.exit_code == game_overlay_sdk.injector.CustomExitCodes.TARGET_PROCESS_IS_NOT_CREATED_ERROR.value:\n logging.warning ('target process is not created')\n time.sleep (5)\n elif err.exit_code == game_overlay_sdk.injector.CustomExitCodes.TARGET_PROCESS_WAS_TERMINATED_ERROR.value:\n logging.warning ('target process was stopped')\n # in monitor mode we can run process several times so dont need to stop this thread here\n i = 0\n time.sleep (5)\n else:\n raise err\n\n\ndef main ():\n logging.basicConfig (level = logging.DEBUG)\n parser = argparse.ArgumentParser ()\n parser.add_argument ('--name', type = str, help = 'process name', required = True)\n args = parser.parse_args ()\n\n game_overlay_sdk.injector.enable_monitor_logger ()\n game_overlay_sdk.injector.start_monitor (args.name)\n\n # start sending messages to overlay\n thread = MessageThread ()\n thread.start ()\n input (\"Press Enter to stop...\")\n thread.need_quit = True\n thread.join ()\n\n game_overlay_sdk.injector.release_resources ()\n\n\nif __name__ == \"__main__\":\n main ()\n```\n**Command Line:**\n```\npython examples\\monitor.py --name SOTTR.exe\n```\n*Important note: with *start_monitor* you can run target process several times sequentially the only requirement here: dont run several processes at the same time*\n\n#### To get more examples please go to github page\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/Andrey1994/game_overlay_sdk", "keywords": "", "license": "", "maintainer": "", "maintainer_email": "", "name": "game-overlay-sdk", "package_url": "https://pypi.org/project/game-overlay-sdk/", "platform": "", "project_url": "https://pypi.org/project/game-overlay-sdk/", "project_urls": { "Homepage": "https://github.com/Andrey1994/game_overlay_sdk" }, "release_url": "https://pypi.org/project/game-overlay-sdk/1.0.1/", "requires_dist": [ "numpy" ], "requires_python": ">=3", "summary": "Library to draw overlay on top of game", "version": "1.0.1" }, "last_serial": 5436006, "releases": { "1.0.0": [ { "comment_text": "", "digests": { "md5": "d1b7dd977518cd54ca5861adf76b0618", "sha256": "caa15a8597d31da7304f7ad085d36e6746ebcb06dd401e1123e8415e1ed5a3bb" }, "downloads": -1, "filename": "game_overlay_sdk-1.0.0-py3-none-any.whl", "has_sig": false, "md5_digest": "d1b7dd977518cd54ca5861adf76b0618", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3", "size": 2451571, "upload_time": "2019-05-27T00:35:39", "url": "https://files.pythonhosted.org/packages/f8/5b/fb311476012e6ec6de19d8e863cb09bb16f54eb648d40edf30af1629c88f/game_overlay_sdk-1.0.0-py3-none-any.whl" } ], "1.0.1": [ { "comment_text": "", "digests": { "md5": "119c0f9c112cf313e689d232cf1a42ce", "sha256": "67971ae5b3bcc0336c8a10373ed46c2f808d71dd6f7b8d0660efc76493aeb7c8" }, "downloads": -1, "filename": "game_overlay_sdk-1.0.1-py3-none-any.whl", "has_sig": false, "md5_digest": "119c0f9c112cf313e689d232cf1a42ce", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3", "size": 2451748, "upload_time": "2019-06-23T00:59:46", "url": "https://files.pythonhosted.org/packages/cd/96/a3a139dfbd08a75e6b7459ba909ef2a76a1a080b93cce617c516a4cd3f2d/game_overlay_sdk-1.0.1-py3-none-any.whl" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "119c0f9c112cf313e689d232cf1a42ce", "sha256": "67971ae5b3bcc0336c8a10373ed46c2f808d71dd6f7b8d0660efc76493aeb7c8" }, "downloads": -1, "filename": "game_overlay_sdk-1.0.1-py3-none-any.whl", "has_sig": false, "md5_digest": "119c0f9c112cf313e689d232cf1a42ce", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3", "size": 2451748, "upload_time": "2019-06-23T00:59:46", "url": "https://files.pythonhosted.org/packages/cd/96/a3a139dfbd08a75e6b7459ba909ef2a76a1a080b93cce617c516a4cd3f2d/game_overlay_sdk-1.0.1-py3-none-any.whl" } ] }