{"id":22400496,"url":"https://github.com/christofsteel/pyautosplit","last_synced_at":"2025-06-12T15:33:57.107Z","repository":{"id":46654435,"uuid":"330490458","full_name":"christofsteel/pyautosplit","owner":"christofsteel","description":"Autosplitter for Linux (for the LiveSplit Server)","archived":false,"fork":false,"pushed_at":"2023-03-22T14:10:05.000Z","size":708,"stargazers_count":44,"open_issues_count":3,"forks_count":6,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-07T04:22:09.754Z","etag":null,"topics":["linux","livesplit-autosplitter","livesplit-component","speedrun-timer"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/christofsteel.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-01-17T21:29:51.000Z","updated_at":"2025-03-21T02:21:37.000Z","dependencies_parsed_at":"2022-09-18T04:20:59.464Z","dependency_job_id":null,"html_url":"https://github.com/christofsteel/pyautosplit","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/christofsteel/pyautosplit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/christofsteel%2Fpyautosplit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/christofsteel%2Fpyautosplit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/christofsteel%2Fpyautosplit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/christofsteel%2Fpyautosplit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/christofsteel","download_url":"https://codeload.github.com/christofsteel/pyautosplit/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/christofsteel%2Fpyautosplit/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259493861,"owners_count":22866405,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["linux","livesplit-autosplitter","livesplit-component","speedrun-timer"],"created_at":"2024-12-05T08:13:10.460Z","updated_at":"2025-06-12T15:33:57.059Z","avatar_url":"https://github.com/christofsteel.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"PyAutoSplit\n===========\n\nThis is a python based autosplitting tool for speedrunning. Currently only Linux is supported, but adding Windows support should be possible, when I come around to do it. In theory MacOS and other Unix systems work, but this is completely untested.\n\n## Why was this done?\n\nWhile LiveSplit does work inside wine, the autosplit component does not work on linux machines. In addition to this, it is not possible to create breakpoints and read values in CPU registers with the autosplit component of LiveSplit. PyAutoSplit can do that. This is especially useful in a game like VVVVVV (2.2 and below), where all relevant information are on the stack, and therefore at nonstatic locations in memory.\n\nCurrent strategies involve scanning the processes memory for specific values, to guess the location of information like gamestate etc. Unfortunately this is rather error prone. With PyAutoSplit one can set a breakpoint at the (static) instruction where the game object is created, and read the cpu registers to get an exact location of the game object.\n\n## Installation\n\nThe program can be installed via pip\n\n```\npip install --user git+https://github.com/christofsteel/pyautosplit.git\n```\n\n## Usage\n\nPyAutoSplit has three different _front-ends_: _console out_, _LiveSplit_ and _LiveSplit One_. You select one or multiple front-end with the `-f`/`--front-end` flag. If no front-end flag is given, _LiveSplit_ is automatically selected.\n\n### LiveSplit\n\nIf you want to connect PyAutoSplit to the server component of LiveSplit, you first have to start LiveSplit, and the LiveSplit server component. After that you can launch PyAutoSplit with\n\n```\npyautosplit -f livesplit -- routefile.json\n```\n\n### LiveSplit One\n\nRun PyAutoSplit with\n\n```\npyautosplit -f livesplitone -- routefile.json\n```\n\nAfter that, go to https://one.livesplit.org and connect to `ws://localhost:5000`.\n\n### Console out\n\nThis is more of a debug output, but you can launch PyAutoSplit with\n\n```\npyautosplit -f console -- routefile.json\n```\n\n## Configuration\n\nTo use PyAutoSplit for a game, you have to have it installed and two files. One specific for the game you are playing and one specific for your route. In this repository, there is an example for the game VVVVVV and a route for glitchless 100%.\n\n### Game file\n\nA game file is a json file with the following fields:\n\n  * `name`, the name of the game\n  * `command`, the launch command to run the game\n  * `cwd`, the working directory of the command (optional)\n  * `env`, additional environment variables for the game (optional)\n  * `frequency`, how many times a second should the memory be read\n  * `time`, how does one calculate the ingame time in seconds (optional). If not present, realtime will be used.\n  * `variables`, variables, that can be used to define other components (see below)\n  * `events`, events, that can trigger splits, resets etc. (see also below)\n\n\n#### Variables\n\nA variable in the `variables` field can be either a the state of the stack pointer at a specific instruction (`rsp`), the state of the base pointer at a specific instruction (`rbp`) or an integer value at an address in memory (`memory`). Addresses of variables can use the values of variables, that were defined prior, and the stack and base pointer can define an offset to be added to the value.\n\n```\n\"game_object\": {\n    \"type\": \"rsp\",\n    \"address\": \"0x416da8\",\n    \"offset\": \"0xe20\"\n}\n```\n\nThis defines the variable `game_object` to be the value of the stack pointer at instruction `0x416da8` incremented by `0xe20`.\n\n```\n\"frames\": {\n    \"type\": \"memory\",\n    \"address\": \"game_object + 0xa8\",\n    \"length\": 4,\n    \"signed\": false,\n    \"byteorder\": \"little\"\n}\n```\n\nThis defines the variable `frames` to be the value in memory at address `game_object + 0xa8`. The variable `game_object` must be defined prior. Optionally it can specify the `length` of the variable, the `signed`ness and the endianess (`byteorder`). The defaults are `4` and `false` for `length` and `signed`. For `byteorder` the native endianess of the system is used (`little` on `x86` machines).\n\nWith the help of the memory access, one can define _multi-level_ variables, meaning variables, whos addresses depend on the value of other variables.\n\n```\n\"some_pointer\": {\n  \"type\": \"memory\",\n  \"address\": \"0x123456\",\n  \"length\": 8,\n}\n\n\"some_variable\": {\n  \"type\": \"memory\",\n  \"address\": \"some_pointer + 0xc3\",\n  \"length\": 4\n}\n```\n\nSince there is no distinction between variables, that are used as pointers, and variables whose value is directly used, one can chain this to arbitrary length. Note: You want to choose a length, that fits your pointer size. For `x86_64`, this is `8`.\n\n#### Events\n\nAn event in the `events` field is a json object with the fields `name` and `trigger`, bound to an identifier.\n\n```\n\"gamestart\": {\n    \"name\": \"Game Start\",\n    \"trigger\": \"state.gamestate == 0\"\n}\n```\n\nThis defines the event `gamestart` with the name `Game Start` to be triggered, if the variable `gamestate` is equal to `0` at the current state.\n\nEvents can access variables of the current state by prefixing them with `state.`. They also can access variables of the state juste before the current state by prefixing them with `oldstate.`. This is useful to track changes in the state.\n\n```\n\"secret_to_nobody\": {\n    \"name\": \"Trinket - It's a Secret to Nobody\",\n    \"trigger\": \"state.trinkets != oldstate.trinkets\"\n}\n```\n\nThis triggers if the variables `trinkets` changes.\n\n### Route file\n\nA route file defines the route for your speedrun. It is also a json file with the following fields:\n\n * `name`, the name of your attemtet category\n * `gamefile`, the location of the respective json file for the game\n * `start`, the event to start the timer\n * `reset`, the event to reset the timer\n * `route`, this defines the triggers for the actual route (see below)\n\nThe field `route` containes the splits. Each split is itself a json object, that can contain subsplits.\n\n```\n'first_level': {},\n'second_level': {\n  'mid_boss' : {}\n}\n```\nIn this example the first split is triggered when the event `first_level` happens. The next split would be the first subsplit of `second_level`, namely `mid_boss`, the next split would be `second_level` itself.\n\nThe names of the splits reference events as defined in the game file.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchristofsteel%2Fpyautosplit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchristofsteel%2Fpyautosplit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchristofsteel%2Fpyautosplit/lists"}