{"id":20139665,"url":"https://github.com/livesplit/livesplit.autosplitters","last_synced_at":"2026-01-28T15:06:01.432Z","repository":{"id":36998249,"uuid":"286118007","full_name":"LiveSplit/LiveSplit.AutoSplitters","owner":"LiveSplit","description":"Auto Splitters for LiveSplit","archived":false,"fork":false,"pushed_at":"2026-01-25T23:36:53.000Z","size":11471,"stargazers_count":176,"open_issues_count":2,"forks_count":713,"subscribers_count":4,"default_branch":"master","last_synced_at":"2026-01-26T14:46:40.617Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/LiveSplit.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2020-08-08T20:55:41.000Z","updated_at":"2026-01-25T23:36:56.000Z","dependencies_parsed_at":"2023-12-28T14:24:44.219Z","dependency_job_id":"0d67b9d7-3ff9-4713-bb7d-772a0c6f58a3","html_url":"https://github.com/LiveSplit/LiveSplit.AutoSplitters","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/LiveSplit/LiveSplit.AutoSplitters","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LiveSplit%2FLiveSplit.AutoSplitters","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LiveSplit%2FLiveSplit.AutoSplitters/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LiveSplit%2FLiveSplit.AutoSplitters/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LiveSplit%2FLiveSplit.AutoSplitters/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LiveSplit","download_url":"https://codeload.github.com/LiveSplit/LiveSplit.AutoSplitters/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LiveSplit%2FLiveSplit.AutoSplitters/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28846109,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-28T13:02:32.985Z","status":"ssl_error","status_checked_at":"2026-01-28T13:02:04.945Z","response_time":57,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":[],"created_at":"2024-11-13T21:46:36.517Z","updated_at":"2026-01-28T15:06:01.426Z","avatar_url":"https://github.com/LiveSplit.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Auto Splitters\n\n[![Build Status](https://github.com/LiveSplit/LiveSplit.AutoSplitters/workflows/CI/badge.svg)](https://github.com/LiveSplit/LiveSplit.AutoSplitters/actions)\n\n\u003c!-- TOC depth:6 withLinks:1 updateOnSave:1 orderedList:0 --\u003e\n\n- [Features of an Auto Splitter](#features-of-an-auto-splitter)\n\t- [Game Time](#game-time)\n\t- [Automatic Splits](#automatic-splits)\n\t- [Automatic Timer Start](#automatic-timer-start)\n\t- [Automatic Resets](#automatic-resets)\n- [How an Auto Splitter works](#how-an-auto-splitter-works)\n\t- [Pointer Paths](#pointer-paths)\n- [The Auto Splitting Language - ASL](#the-auto-splitting-language---asl)\n\t- [State Descriptors](#state-descriptors)\n\t\t- [State objects](#state-objects)\n\t- [Actions](#actions)\n \t\t- [Script Management](#script-management)\n\t\t- [Timer Control](#timer-control)\n    \t- [Order of Execution](#order-of-execution)\n\t- [Action Variables](#action-variables)\n\t\t- [General Variables](#general-variables)\n\t\t- [Game Dependent](#game-dependent)\n\t- [Settings](#settings-1)\n\t\t- [Basic Settings](#basic-settings)\n\t\t- [Custom Settings](#custom-settings)\n\t- [Built-in Functions](#built-in-functions)\n\t- [Testing your Script](#testing-your-script)\n\t\t- [Debugging](#debugging)\n- [Sandboxed Auto Splitters](#sandboxed-auto-splitters)\n- [Adding an Auto Splitter](#adding-an-auto-splitter)\n- [Additional Resources](#additional-resources)\n\n\u003c!-- /TOC --\u003e\n\nLiveSplit has integrated support for Auto Splitters. An Auto Splitter can be one\nof the following:\n* A Script written in the Auto Splitting Language (ASL).\n* A WebAssembly module that uses the new cross-platform, sandboxed Auto\n  Splitting Runtime.\n* A LiveSplit Component written in any .NET compatible language.\n* A third party application communicating with LiveSplit through the LiveSplit\n  Server.\n\nLiveSplit can automatically download and activate Auto Splitters that are\nLiveSplit components, WebAssembly modules, or ASL scripts.\n\nCurrently we recommend writing an ASL script, which has the most extensive\nsupport for all the features you might need. If you are feeling more\nadventurous, you can start looking into writing an auto splitter for the new\ncross-platform, sandboxed Auto Splitting Runtime\n[here](#sandboxed-auto-splitters). Sandboxed auto splitters are currently more\nlimited, but they will become the main way to write auto splitters in the\nfuture.\n\n## Features of an Auto Splitter\n\nAn Auto Splitter can provide any of the following features:\n\n### Game Time\n\nGame Time can either be Real Time without Loads or an actual Game Timer found in the game. This depends on the game and the speedrun community of that game. If the game has been run in Real Time for multiple years already, introducing a new timing method might not be worth it.\n\n### Automatic Splits\n\nAn Auto Splitter, as the name suggests, can also provide automatic splits to increase the accuracy of the individual segment and split times. An Auto Splitter might not necessarily implement Automatic Splits for every single split available since the runner might want to have some additional splits that are not supported by the Auto Splitter used.\n\n### Automatic Timer Start\n\nNot every Auto Splitter automatically starts the timer. For some games, the Auto Splitter can't tell whether the runner just wants to start the game to practice something or actually wants to do a run.\n\n### Automatic Resets\n\nAn Auto Splitter can automatically reset the timer. This might be useful for games where going back to the main menu always means that the run is over. This is a bit dangerous though, as the runner might not have wanted to reset there. Think twice before implementing this functionality into your Auto Splitter.\n\n## How an Auto Splitter works\n\nAuto Splitters can work in one or multiple of the following ways:\n * It can read the RAM, interpret the values, and toggle any of the actions described above based on these values. The RAM addresses might not always be the same. Therefore, the Auto Splitter might need to follow a so called *Pointer Path*. This is what most Auto Splitters do and what is directly supported by the Auto Splitting Language.\n * It can scan the game's RAM to find a value and toggle any of the actions based on these values. Doing a memory scan is slower than following a Pointer Path.\n * It can read the game's log files, parse them, and toggle actions based on those. This works, but is usually fairly delayed, which is why this isn't that great of a solution.\n * It can read the game's standard output stream. This only works if the game actually writes valuable information to the standard output, which is rare. Also, Steam prevents this method since in order to read the standard output, you need to start the game's process through the Auto Splitter, which Steam won't let you do.\n\n### Pointer Paths\n\nA Pointer Path is a list of Offsets + a Base Address. The Auto Splitter reads the value at the base address and interprets the value as yet another address. It adds the first offset to this address and reads the value of the calculated address. It does this over and over until there are no more offsets. At that point, it has found the value it was searching for. This resembles the way objects are stored in memory. Every object has a clearly defined layout where each variable has a consistent offset within the object, so you basically follow these variables from object to object.\n\n*Cheat Engine* is a tool that allows you to easily find Addresses and Pointer Paths for those Addresses, so you don't need to debug the game to figure out the structure of the memory.\n\n## The Auto Splitting Language - ASL\n\nThe Auto Splitting Language is a small scripting language made specifically for LiveSplit Auto Splitters. It has a few advantages and disadvantages over normal Components.\n\n**Advantages:**\n * ASL Scripts are easy to maintain.\n * There's no need to update the Script for new LiveSplit versions.\n * No Visual Studio or any compiler is needed; you can write it in Notepad.\n\n**Disadvantages:**\n * Currently only provides Boolean settings in the GUI for the user to change.\n\nAn ASL Script contains a State Descriptor and multiple [Actions](#actions) which contain C# code.\n\n### State Descriptors\n\nThe State Descriptor is the most important part of the script and describes which game process and which state of the game the script is interested in. This is where all of the Pointer Paths, which the Auto Splitter uses to read values from the game, are described. A State Descriptor looks like this:\n```\nstate(\"PROCESS_NAME\")\n{\n\tPOINTER_PATH\n\tPOINTER_PATH\n\t...\n}\n```\nIf the script needs to support multiple versions of the game, you can specify an optional version identifier:\n```\nstate(\"PROCESS_NAME\", \"VERSION_IDENTIFIER\")\n...\n```\n\nThe `PROCESS_NAME` is the name of the process the Auto Splitter should look for. The Script is inactive while it's not connected to a process. Once a process with that name is found, it automatically connects to that process. A Process Name should not include the `.exe`. Even advanced scripts that use other ways to access the game's memory require a State Descriptor to define which process LiveSplit is supposed to connect to.\n\nThe optional `VERSION_IDENTIFIER` can be any arbitrary string you wish to use. Note that the script can define multiple State Descriptors for different processes/games. These optional features are extremely useful for emulators.\n\n`POINTER_PATH` describes a Pointer Path and has two ways to declare:\n```\nVARIABLE_TYPE VARIABLE_NAME : OFFSET, OFFSET, OFFSET, ...;\nVARIABLE_TYPE VARIABLE_NAME : \"BASE_MODULE\", OFFSET, OFFSET, OFFSET, ...;\n```\n\nThe variable type `VARIABLE_TYPE` describes the type of the value found at the pointer path. It can be one of the following:\n\n| Type             | Description                |\n| ---------------- | -------------------------- |\n| sbyte            | Signed 8-bit integer       |\n| byte             | Unsigned 8-bit integer     |\n| short            | Signed 16-bit integer      |\n| ushort           | Unsigned 16-bit integer    |\n| int              | Signed 32-bit integer      |\n| uint             | Unsigned 32-bit integer    |\n| long             | Signed 64-bit integer      |\n| ulong            | Unsigned 64-bit integer    |\n| float            | 32-bit IEEE floating-point |\n| double           | 64-bit IEEE floating-point |\n| bool             | Boolean                    |\n| string\\\u003clength\\\u003e | String (e.g. string255)    |\n| byte\\\u003clength\\\u003e   | Byte array (e.g. byte255)  |\n\nThe variable name `VARIABLE_NAME` can be any variable name you choose, describing what is found at the pointer path. The naming is up to you, but should be distinct from the other variable names.\n\nThe optional base module name `BASE_MODULE` describes the name of the module the Pointer Path starts at. Every \\*.exe and \\*.dll file loaded into the process has its own base address. Instead of specifying the base address of the Pointer Path, you specify the base module and an offset from there. If this is not defined, it will default to the main (.exe) module.\n\nYou can use as many offsets `OFFSET` as you want. They need to be integer literals, either written as decimal or hexadecimal.\n\n#### State objects\n\nThe State Variables described through the State Descriptor are available through two State objects: `current` and `old`. The `current` object contains the current state of the game with all the up-to-date variables, while the `old` object contains the state of the variables at the last execution of the ASL Script in LiveSplit. These objects are useful for checking for state changes. For example, you could check if the last level of a game was a certain value and is now a certain other value, which might mean that a split needs to happen.\n\nLiveSplit's internal state is also available through the object `timer`. This is an object of the type [`LiveSplitState`](https://github.com/LiveSplit/LiveSplit/blob/master/src/LiveSplit.Core/Model/LiveSplitState.cs) and can be used to interact with LiveSplit in ways that are not directly available through ASL.\n\n### Actions\n\nAfter writing a State Descriptor, you can implement multiple actions such as splitting and starting the timer. These actions define the logic of the Auto Splitter based on the information described by the State Descriptor. An action looks like this:\n```\nACTION_NAME\n{\n\tC# CODE\n}\n```\n\nYou can think of Actions like functions that are automatically called by the ASL Component. These functions can only interact with each other or LiveSplit via the [special variables](#action-variables) the environment provides.\n\nAll of the actions are optional and are declared by their name `ACTION_NAME` followed by a code block `CODE`. You trigger the action by returning a value. Returning a value is optional though; if no value is returned, the action is not triggered. Some actions are only executed while LiveSplit is connected to the process.\n\nActions are implemented in C#. You can use C#'s documentation for any questions you may have regarding the syntax of C#.\n\n#### Script Management\n\n- ##### Script Startup\n\t- The name of this action is `startup`. This action is triggered when the script is first loaded. This is the place where you can put initialization that doesn't depend on being connected to the process and the only place where you can add [Custom Settings](#custom-settings).\n\n- ##### Script Shutdown\n\t- The name of this action is `shutdown`. This action is triggered whenever the script is entirely stopped, for example when the Auto Splitter is disabled, LiveSplit exits, the script path is changed or the script is reloaded (e.g. during development of the ASL script).\n\n- ##### Script Initialization (Game Start)\n\t- The name of this action is `init`. This action is triggered whenever a game process has been found according to the State Descriptors. This can occur more than once during the execution of a script (e.g. when you restart the game). This is the place to do initialization that depends on the game, for example detecting the game version.\n\n- ##### Game Exit\n\t- The name of this action is `exit`. This action is triggered whenever the currently attached game process exits.\n\n#### Timer Control\n\nThese actions are repeatedly triggered while LiveSplit is connected to the game process.\n\n- ##### Generic Update\n\t- The name of this action is `update`. You can use this for generic updating. In each update iteration, this is run before the timer control actions, which e.g. means if you set a value in `vars` in `update` you can then access it in `start` on the same update cycle.\n\t- Explicitly returning `false` will prevent the actions `isLoading`, `gameTime`, `reset`, `split`, and `start` from being run. This can be useful if you want to entirely disable the script under some conditions (e.g. for incompatible game versions). See [Order of Execution](#order-of-execution) for more information.\n\n- ##### Automatic Timer Start\n\t- The name of this action is `start`. Return `true` whenever you want the timer to start. Note that the `start` action will only be run if the timer hasn't been started (right after being reset, for example).\n\n- ##### Automatic Splits\n\t- The name of this action is `split`. Return `true` whenever you want to trigger a split.\n\n- ##### Automatic Resets\n\t- The name of this action is `reset`. Return `true` whenever you want to reset the run. Only run while the timer is running.\n\t- Explicitly returning `true` will prevent the `split` action from being run. This can be useful in some cases, but may also cause issues for some scripts. See [Order of Execution](#order-of-execution) for more information.\n\n- ##### Load Time Removal\n\t- The name of this action is `isLoading`. Return `true` whenever the game is loading. LiveSplit's Game Time Timer will be paused as long as you return `true`.\n\t- **NOTE**: Make sure the timer is set to \"Game Time\" in the layout! Failure to do so will cause the timer to keep running, as if `isLoading` had returned `false` or `isLoading` weren't triggered at all.\n\n- ##### Game Time\n\t- The name of this action is `gameTime`. Return a [`TimeSpan`](https://msdn.microsoft.com/en-us/library/system.timespan(v=vs.110).aspx) object that contains the current time of the game.\n \t- You can also combine this with `isLoading`. If `isLoading` returns false, nothing, or isn't implemented, LiveSplit's Game Time Timer is always running and syncs with the game's Game Time at a constant interval. Everything in between is therefore a Real Time approximation of the Game Time. If you want the Game Time to not run in between the synchronization interval and only ever return the actual Game Time of the game, make sure to implement `isLoading` with a constant return value of `true`.\n\n#### Order of Execution\nUnderstanding the order and conditions under which timer control actions are executed can help you avoid issues in your script where variables appear to be set improperly, actions appear to be skipped, and more.\n\n##### Script - Initialization:\n1. `startup` is run once when the script is loaded.\n2. If a matching process is found, `init` is run. `init` is restarted if stopped by an exception.\n##### Script - Main Loop:\n1. `update` will always be run. If it returns `false`, then all other Timer Control actions will be skipped.\n2. If the timer is currently running, then the `isLoading`, `gameTime`, and `reset` actions will be run.\n\t- If `reset` does not explicitly return `true`, then the `split` action will be run.\n3. If the timer hasn't started, then the `start` action will be run.\n\n##### Events\n\nWhile a broader suite of events exist in LiveSplit, three are also available as ASL actions. The `onStart`, `onSplit` and `onReset` actions will be triggered when the timer is started, split, and reset respectively.\n\n\n### Action Variables\n\nActions have a few hidden variables available.\n\n#### General Variables\n\n##### vars\nA dynamic object which can be used to store variables. Make sure the variables are defined (for example in `startup` or `init`) before trying to access them. This can be used to exchange data between Actions.\n```\ninit { vars.test = 5; }\nupdate { print(vars.test.ToString()); }\n```\nYou can also store variables like this in `current` and the value will be in `old` on the next update.\n\n##### version\nWhen you set `version` in `init`, the corresponding State Descriptor will be activated. When there is no State Descriptor corresponding to the `version`, the default one will be activated.\n\nThe default is the first defined State Descriptor with no version specified, or the first State Descriptor in the file if there is none with no version specified.\n\nThe string you set `version` to will also be displayed in the ASL Settings GUI.\n```\nstate(\"game\", \"v1.2\")\n{\n    byte levelID : 0x9001;\n}\nstate(\"game\", \"v1.3\")\n{\n    byte levelID : 0x9002;\n}\ninit\n{\n    if (modules.First().ModuleMemorySize == 0x123456)\n        version = \"v1.2\";\n    else if (modules.First().ModuleMemorySize == 0x654321)\n        version = \"v1.3\";\n}\nupdate\n{\n    if (version == \"\") return false;\n    print(current.levelID.ToString());\n}\n```\n\n##### refreshRate\nMany actions are triggered repeatedly, by default approximately 60 times per second. You can set this variable lower to reduce CPU usage. This is commonly done in `startup` or `init`.\n```\nrefreshRate = 30;\n```\n\n##### settings\nUsed to add and access [Settings](#settings-1).\n\n#### Game Dependent\n\nThese variables depend on being or having been connected to a game process and are not available in the `startup` or `exit` actions and only partly available in `shutdown` (might be `null`).\n\n##### current / old\nState objects representing the current and previous states.\n```\nsplit { return current.levelID != old.levelID; }\n```\n\n##### game\nThe currently connected [Process](https://msdn.microsoft.com/en-us/library/system.diagnostics.process%28v=vs.110%29.aspx) object.\n```\nupdate { if (game.ProcessName == \"snes9x\") { } }\n```\n\n##### modules\nThe modules of the currently connected process. Please use this instead of game.Modules! Use modules.First() instead of game.MainModule.\n\n##### memory\nProvides a means to read memory from the game without using the State Descriptor.\n```\nvars.exe = memory.ReadBytes(modules.First().BaseAddress, modules.First().ModuleMemorySize);\nvars.test = memory.ReadValue\u003cbyte\u003e(modules.First().BaseAddress + 0x9001);\nvars.test2 = memory.ReadString(modules.First().BaseAddress + 0x9002, 256);\nvars.test3 = new DeepPointer(\"some.dll\", 0x9003, vars.test, 0x02).Deref\u003cint\u003e(game);\nvars.test4 = memory.ReadString(modules.Where(m =\u003e m.ModuleName == \"some.dll\").First().BaseAddress + 0x9002, 256);\n```\n\n### Settings\n\nASL script settings are stored either with the Layout if you are using the Scriptable Auto Splitter component or with the Splits if you activated the script in the Splits Editor (so make sure to save your Layout or Splits accordingly when exiting LiveSplit if you changed settings).\n\n#### Basic Settings\nThe Auto Splitter Settings GUI has some default settings to allow the user to toggle the actions `start`, `reset` and `split`. If the checkbox for an action is unchecked, the return value of that action is ignored (but the code inside the action is still executed). So for example if the checkbox for `start` is unchecked, returning `true` in the `start` action will have no effect.\n\nYou can access the current value of the basic settings through the attributes `settings.StartEnabled`, `settings.ResetEnabled` and `settings.SplitEnabled`. This is only for informational purposes, for example if your script needs to do something depending on whether the action was actually performed or not, ignoring the return value is done automatically.\n\nActions that are not present in the ASL script or empty will have their checkboxes disabled.\n\n#### Custom Settings\n\nYou can define custom boolean settings for your script in the `startup` action and then access the setting values as configured by the user in the other actions. If you have custom settings defined, they will be shown in the GUI for the user to check/uncheck. They will appear in the same order you added them in the ASL script.\n\n##### Basic usage\n\nYou can define settings in the `startup` action by using the `settings.Add(id, default_value = true, description = null, parent = null)` method:\n\n```\n// Add setting 'mission1', enabled by default, with 'First Mission' being displayed in the GUI\nsettings.Add(\"mission1\", true, \"First Mission\");\n\n// Add setting 'mission2', enabled by default, with 'mission2' being displayed in the GUI\nsettings.Add(\"mission2\");\n\n// Add setting 'mission3', disabled by default, with 'mission3' being displayed in the GUI\nsettings.Add(\"mission3\", false);\n```\n\nYou can access the current value of a setting in all actions other than `startup` by accessing `settings`:\n\n````\n// Do something depending on the value of the setting 'mission1'\nif (settings[\"mission1\"]) {  }\n````\n\n##### Grouping settings\nIf you want to organize the settings in a hierarchy, you can specify the `parent` parameter. Note that the `parent` has to be the `id` of a setting that you already added:\n\n```\n// Add setting 'main_missions'\nsettings.Add(\"main_missions\", true, \"Main Missions\");\n\n// Add setting 'mission1', with 'main_missions' as parent\nsettings.Add(\"mission1\", true, \"First Mission\", \"main_missions\");\n```\n\nSettings only return `true` (checked) when their `parent` setting is `true` as well. The user is unable to toggle settings that have their parent unchecked, and they will be grayed out to indicate they are disabled.\n\nAny setting can act as a `parent` setting, so you could for example do the following to go one level deeper (continuing from the last example):\n\n```\n// Add setting 'mission1_part1', with 'mission1' as parent\nsettings.Add(\"mission1_part1\", true, \"First part of Mission 1\", \"mission1\");\n```\n\nThe setting `mission1_part1` will only be enabled, when both `mission1` and `main_missions` are enabled.\n\nWhen the `parent` parameter is null or omitted, the setting will be added as top-level setting, unless `settings.CurrentDefaultParent` is set to something other than `null`:\n\n```\n// Add top-level setting 'main_missions'\nsettings.Add(\"main_missions\");\n\nsettings.CurrentDefaultParent = \"main_missions\";\n\n// Add setting 'mission1', with the parent 'main_missions'\nsettings.Add(\"mission1\");\n\nsettings.CurrentDefaultParent = null;\n\n// Add top-level setting 'side_missions'\nsettings.Add(\"side_missions\");\n```\n\nUsing `settings.CurrentDefaultParent` can be useful when adding several settings with the same parent, without having to specify the parent every time.\n\n##### Tooltips\n\nYou can add a tooltip to settings that appears when hover over the setting in the GUI. This can be useful if you want to add a bit more information. After adding the setting, use `settings.SetToolTip(id, tooltip_text)` to set a tooltip:\n\n```\nsettings.Add(\"main_missions\", true, \"Main Missions\");\nsettings.SetToolTip(\"main_missions\", \"All main story missions, except Mission A and Mission B\");\n```\n\n### Built-in Functions\n\n##### print\nUsed for debug printing. Use [DbgView](https://technet.microsoft.com/en-us/Library/bb896647.aspx) to watch the output.\n```\nprint(\"current level is \" + current.levelID);\n```\n\n##### Other\nThere are some advanced memory utilities not covered here. You can find them [here](https://github.com/LiveSplit/LiveSplit/tree/master/src/LiveSplit.Core/ComponentUtil).\n\n### Testing your Script\n\nYou can test your Script by adding the *Scriptable Auto Splitter* component to your Layout. Right-click on LiveSplit and choose \"Edit Layout...\" to open the Layout Editor, then click on the Plus-sign and choose \"Scriptable Auto Splitter\" from the section \"Control\". You can set the Path of the Script by going into the component settings of the Scriptable Auto Splitter. To get to the settings of the component you can either double click it in the Layout Editor or go into to the Scriptable Auto Splitter Tab of the Layout Settings. Once you've set the Path, the script should automatically load and hopefully work.\n\n#### Debugging\nReading debug output is an integral part of developing ASL scripts, both for your own debug messages which you can output with `print()` and any debug messages or error messages the ASL Component itself provides.\n\nThe program [DebugView](https://technet.microsoft.com/en-us/sysinternals/debugview.aspx) can be used for a live view of debug output from the ASL Component.\n\nFor errors, you can also check the Windows Event Logs, which you can find via:\n\nControl Panel ➞ Search for Event Viewer ➞ Open it ➞ Windows Logs ➞ Application ➞ Find the LiveSplit Errors\n\nSome might be unrelated to the Script, but it'll be fairly obvious which ones are caused by you.\n\n## Sandboxed Auto Splitters\n\nIt is also possible to provide an auto splitter as a WebAssembly module. These\nauto splitters get executed through the new Auto Splitter Runtime, which has\nseveral benefits:\n1. The runtime is cross platform. It can run on Windows, macOS, and Linux.\n2. The runtime is sandboxed. All auto splitters running on the new runtime are\n   fully sandboxed and it's impossible for an auto splitter to harm the user.\n   The user is also protected from the auto splitter crashing, which will not\n   affect the timer itself.\n3. The auto splitters can be written in many different languages, such as Rust,\n   C, C++, JavaScript, TypeScript, Go, and more.\n4. The runtime isn't tied to just LiveSplit and can be used with other timers or\n   even run inside of the [Auto Splitting Runtime\n   Debugger](https://github.com/CryZe/asr-debugger) which allows you to debug\n   the auto splitters more easily.\n\nThere is one downside to auto splitters written for the new runtime however. The\nfact that they are sandboxed and cross platform means that there may be certain\nfunctionality, that you may need for your auto splitter to work, that is not\nsupported yet.\n\nRight now Rust is the language that has the best support. If you want to create\nan auto splitter using the new runtime, you can follow the instructions over\nhere: [Rust Auto Splitter\nTemplate](https://github.com/LiveSplit/auto-splitter-template)\n\nIf you need help writing an auto splitter for the new runtime, make sure to\nvisit the `#auto-splitting-v2` channel in the [Speedrun Tool Development\nDiscord](https://discord.gg/N6wv8pW).\n\n## Adding an Auto Splitter\n\nIf you implemented an Auto Splitter and want to add it to the Auto Splitters that are automatically being downloaded by LiveSplit, feel free to add it to the [Auto Splitters XML](./LiveSplit.AutoSplitters.xml). Just click the link, click the icon for modifying the file and GitHub will automatically create a fork, branch and pull request for you, which we can review and then merge in.\n\n**Any kind of abuse in an Auto Splitter will result in an immediate ban.**\n\n## Additional Resources\n\n- [Speedrun Tool Development Discord](https://discord.gg/N6wv8pW)\n- [List of ASL Scripts](https://fatalis.github.io/livesplit-asl-list/) to learn from, automatically created from the [Auto Splitters XML](./LiveSplit.AutoSplitters.xml) and filterable by different criteria\n- Example: [Simple Autosplitter with Settings](https://raw.githubusercontent.com/tduva/LiveSplit-ASL/master/AlanWake.asl)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flivesplit%2Flivesplit.autosplitters","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flivesplit%2Flivesplit.autosplitters","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flivesplit%2Flivesplit.autosplitters/lists"}