Skip to content

Instantly share code, notes, and snippets.

@preshing
Last active March 2, 2020 18:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save preshing/28e9450f73461c39fef9580bc6c79b91 to your computer and use it in GitHub Desktop.
Save preshing/28e9450f73461c39fef9580bc6c79b91 to your computer and use it in GitHub Desktop.
Manifold Garden AutoSplit script
// AutoSplit script for Manifold Garden 1.0.30.13294
//
// Automatically starts the timer ~2.4 seconds after starting a new game, and splits the timer
// when transitioning between game levels. You must still reset the timer manually between runs.
// If you accidentally backtrack through a portal, causing an unwanted split, you'll have
// to undo it manually (default NumPad8 in LiveSplit).
//
// To compensate for the late start, you should delay your start timer by 2.4 seconds in LiveSplit.
// (Right-click -> Edit Splits -> Start timer at:)
//
// A split is also triggered after being in "World_905_EndingCollapseCutscene" for 1.1 seconds,
// since this is when the kaleidoscope appears.
//
// If you check "All God Cubes waypoints" in the script's Advanced settings (below), the script
// will only split at mandala scenes. This is useful when running "All God Cubes" categories.
//
// To install in LiveSplit: https://github.com/LiveSplit/LiveSplit/releases
// - Right-click -> Edit Layout
// - Add a "Scriptable Auto Splitter" entry if you don't have one
// - Layout Settings
// - Scriptable Auto Splitter tab
// - Enter the path to this script
// - Advanced settings are also found here
//
// Make sure to save your layout and that you don't have another autosplitter enabled
// (for example, in the "Splits Editor" dialog box).
//
// The pointer path to the current level often changes when a new version of Manifold Garden is
// released. When that happens, a new pointer path must be found using CheatEngine. If the
// current pointer path stops working (even for a frame or two), a message is logged to the
// debug output.
//
// To view debug output (print statements from this script), use DebugView:
// https://technet.microsoft.com/en-us/Library/bb896647.aspx
state("ManifoldGarden") {
// This pointer path seems to work with Manifold Garden 1.0.30.13294 (2020-02-25):
int level: "UnityPlayer.dll", 0x014BE300, 0x60, 0xA8, 0x38, 0x30, 0xB0, 0x118, 0x5C;
// These ones also seem to work with version 13294, and can be tried as backups in case
// the one above stops working:
//int level: "UnityPlayer.dll", 0x01552858, 0x8, 0x0, 0xB8, 0x80, 0x80, 0x28, 0x5C;
//int level: "UnityPlayer.dll", 0x01552858, 0x28, 0x8, 0xB8, 0x80, 0x80, 0x28, 0x5C;
// This pointer path worked with Manifold Garden 1.0.29.12904 (2020-02-??)
// & Manifold Garden 1.0.29.12830 (2019-12-18)
// & Manifold Garden 1.0.29.12781 (2019-12-11):
//int level: "UnityPlayer.dll", 0x01507BE0, 0x0, 0x928, 0x38, 0x30, 0xB0, 0x118, 0x5C;
// This pointer path worked with older versions:
//int level: "UnityPlayer.dll", 0x01507C68, 0x8, 0x38, 0xA8, 0x58, 0x118, 0x5C;
}
startup {
settings.Add("allGodCubes", false, "All God Cubes waypoints");
settings.Add("low", false, "Low% waypoints");
vars.waypoints = null;
vars.prevLevel = 0;
vars.seqIndex = 0;
vars.stopwatch = null; // Used for the final split
}
init {
print(String.Format("**** AUTOSPLIT: Game found, pointer path {0} ****",
current.level == 0 ? "DOESN'T work (this is normal at startup)" : "works"));
}
update {
// Log a message when the pointer path starts/stops working:
if (current.level == 0 && old.level != 0) {
print("**** AUTOSPLIT: Pointer path STOPPED working ****");
} else if (current.level != 0 && old.level == 0) {
print("**** AUTOSPLIT: Pointer path STARTED working ****");
}
}
start {
if (current.level == 64 && old.level == -1) {
print(String.Format("Level changed from {0} to {1}: START", old.level, current.level));
if (settings["low"]) {
vars.waypoints = new List<int>{17, 66, 22, 49, 37, 100, 88};
} else {
vars.waypoints = null;
}
vars.prevLevel = 64;
vars.seqIndex = 0;
vars.stopwatch = Stopwatch.StartNew();
return true;
}
}
split {
// Split when level index changes, but avoid splitting during a loading screen
// or when the pointer path stops working:
if (current.level > 0 && current.level != vars.prevLevel) {
string action = "NO SPLIT";
// Ignore the split rules when script is reloaded mid-game:
if (vars.prevLevel != 0) {
// Split rules:
if (vars.waypoints == null) {
if (settings["allGodCubes"]) {
if (current.level >= 9 && current.level <= 15) {
action = "SPLIT";
}
} else {
action = "SPLIT";
}
} else if (vars.seqIndex < vars.waypoints.Count) {
if (current.level == vars.waypoints[vars.seqIndex]) {
vars.seqIndex++;
action = String.Format("SPLIT (new seqIndex = {0})", vars.seqIndex);
} else {
action = String.Format("NO SPLIT (seqIndex = {0}, {1} expected)",
vars.seqIndex, vars.waypoints[vars.seqIndex]);
}
} else {
action = String.Format("NO SPLIT (seqIndex = {0}, end of waypoint sequence)", vars.seqIndex);
}
print(String.Format("Level changed from {0} to {1}: {2}", vars.prevLevel, current.level, action));
}
vars.prevLevel = current.level;
vars.stopwatch = Stopwatch.StartNew();
return action.StartsWith("SPLIT");
}
// Final split of the game:
// Split after being in "World_905_EndingCollapseCutscene" for 1.1 seconds.
if (current.level == 110
&& vars.stopwatch != null
&& vars.stopwatch.ElapsedMilliseconds >= 1100) {
vars.stopwatch = null;
return true;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment