state("SongOfNunu-Win64-Shipping") { } startup { Assembly.Load(File.ReadAllBytes("Components/asl-help")).CreateInstance("Basic"); vars.Helper.GameName = "Song of Nunu"; vars.Helper.AlertLoadless(); #region setting creation dynamic[,] _settings = { { "Chapter Splits", true, "Chapter Splits", null }, { "02_Shore_P", true, "Shore", "Chapter Splits" }, { "03_Plains_P", true, "Plains", "Chapter Splits" }, { "04_Chasm_P", true, "Chasm", "Chapter Splits" }, { "05_Ramshara_P", true, "Ramshara", "Chapter Splits" }, { "06_FrostguardCitadel_P", true, "Citadel Start", "Chapter Splits" }, { "08_HallOfTheNine_P", true, "Hall of the Nine", "Chapter Splits" }, { "09_Ending_P", true, "Ending Area", "Chapter Splits" }, {"GameInfo", true, "Print Various Game Info", null}, {"World", false, "Current World", "GameInfo"}, {"camTarget", false, "Current Camera Target", "GameInfo"}, {"playerPos", false, "playerPos", "GameInfo"}, {"PlayerVelDisplay", true, "Print Player Speed", null}, {"playerVel", true,"Combined & Simplified", "PlayerVelDisplay"}, {"playerVelCombinedRaw", false, "Combined Raw", "PlayerVelDisplay"}, {"playerVelTrueRaw", false, "True Raw", "PlayerVelDisplay"}, {"Debug", false, "Print Debug Info", null}, {"placeholder", false, "placeholder", "Debug"}, }; vars.Helper.Settings.Create(_settings); #endregion #region TextComponent vars.lcCache = new Dictionary(); vars.SetText = (Action)((text1, text2) => { const string FileName = "LiveSplit.Text.dll"; LiveSplit.UI.Components.ILayoutComponent lc; if (!vars.lcCache.TryGetValue(text1, out lc)) { lc = timer.Layout.LayoutComponents.Reverse().Cast() .FirstOrDefault(llc => llc.Path.EndsWith(FileName) && llc.Component.Settings.Text1 == text1) ?? LiveSplit.UI.Components.ComponentManager.LoadLayoutComponent(FileName, timer); vars.lcCache.Add(text1, lc); } if (!timer.Layout.LayoutComponents.Contains(lc)) timer.Layout.LayoutComponents.Add(lc); dynamic tc = lc.Component; tc.Settings.Text1 = text1; tc.Settings.Text2 = text2.ToString(); }); vars.RemoveText = (Action)(text1 => { LiveSplit.UI.Components.ILayoutComponent lc; if (vars.lcCache.TryGetValue(text1, out lc)) { timer.Layout.LayoutComponents.Remove(lc); vars.lcCache.Remove(text1); } }); #endregion vars.CompletedSplits = new HashSet(); } init { //UE5.01 IntPtr gWorld = vars.Helper.ScanRel(3, "48 8B 1D ???????? 48 85 DB 74 ?? 41 B0 01"); vars.hasGWorldPTR = true; IntPtr gEngine = vars.Helper.ScanRel(3, "48 8B 0D ???????? 66 0F 5A C9 E8"); vars.hasGEnginePTR = true; IntPtr fNamePool = vars.Helper.ScanRel(7, "8B D9 74 ?? 48 8D 15 ???????? EB"); vars.hasFnamePoolPTR = true; //IntPtr gSyncLoadCount = vars.Helper.ScanRel(3, "48 89 35 ???????? 48 89 74 24 ?? e8 ???????? 48 8b 4c 24 ?? 8d 7e"); vars.hasGSyncPTR = true; vars.Log("hasWorldPtr = " + vars.hasGWorldPTR); vars.Log("hasGEnginePTR = " + vars.hasGEnginePTR); vars.Log("hasFnamePoolPTR = " + vars.hasFnamePoolPTR); vars.FNameToString = (Func)(fName => { var nameIdx = (fName & 0x000000000000FFFF) >> 0x00; var chunkIdx = (fName & 0x00000000FFFF0000) >> 0x10; var number = (fName & 0xFFFFFFFF00000000) >> 0x20; // IntPtr chunk = vars.Helper.Read(fNamePool + 0x10 + (int)chunkIdx * 0x8); IntPtr chunk = vars.Helper.Read(fNamePool + 0x10 + (int)chunkIdx * 0x8); IntPtr entry = chunk + (int)nameIdx * sizeof(short); int length = vars.Helper.Read(entry) >> 6; string name = vars.Helper.ReadString(length, ReadStringType.UTF8, entry + sizeof(short)); return number == 0 ? name : name + "_" + number; }); vars.FNameToShortString2 = (Func)(fName => { string name = vars.FNameToString(fName); int under = name.LastIndexOf('_'); return name.Substring(0, under); }); vars.Chop2 = (Func)(v => { if (double.IsNaN(v) || double.IsInfinity(v)) return "—"; var s = v.ToString(); int i = s.IndexOf('.'); if (i < 0) i = s.IndexOf(','); if (i < 0) return s; int end = Math.Min(i + 3, s.Length); // keep 2 after separator return s.Substring(0, end); }); #region Text Component vars.SetTextIfEnabled = (Action)((text1, text2) => { if (settings[text1]) vars.SetText(text1, text2); else vars.RemoveText(text1); }); #endregion // gEngine - GameViewport(9A0) - World(078) - FName vars.Helper["GWorldName"] = vars.Helper.Make(gEngine, 0x9A0, 0x078, 0x18); // gEngine -> GameInstance(1058) ->LocalPlayers[0](38) -> Dereference(0) -> PlayerController(30) -> Character(2E0) - CapsuleComponent(328) - RelativeLocationX(128) vars.Helper["playerPosX"] = vars.Helper.Make(gEngine, 0x1058, 0x38, 0x0, 0x30, 0x2E0, 0x328, 0x128); vars.Helper["playerPosY"] = vars.Helper.Make(gEngine, 0x1058, 0x38, 0x0, 0x30, 0x2E0, 0x328, 0x130); vars.Helper["playerPosZ"] = vars.Helper.Make(gEngine, 0x1058, 0x38, 0x0, 0x30, 0x2E0, 0x328, 0x138); // gEngine -> GameInstance(1210) -> LocalPlayers[0](38) -> Dereference(0) -> PlayerController(30) -> Character(2E0) -> CharacterMovement(320) -> Velocity(0B8) vars.Helper["playerVelVector"] = vars.Helper.Make(gEngine, 0x1058, 0x38, 0x0, 0x30, 0x2E0, 0x320, 0x08); vars.Helper["playerVelX"] = vars.Helper.Make(gEngine, 0x1058, 0x38, 0x0, 0x30, 0x2E0, 0x320, 0xB8); vars.Helper["playerVelY"] = vars.Helper.Make(gEngine, 0x1058, 0x38, 0x0, 0x30, 0x2E0, 0x320, 0xC0); vars.Helper["playerVelZ"] = vars.Helper.Make(gEngine, 0x1058, 0x38, 0x0, 0x30, 0x2E0, 0x320, 0xC8); // gEngine -> GameInstance(1058) -> LocalPlayers[0](38) -> Dereference(0) -> PlayerController(30) -> PlayerCameraManager(348) -> ViewTarget.Target(12C0) -> FNameIndex vars.Helper["camTargetName"] = vars.Helper.Make(gEngine, 0x1058, 0x38, 0x0, 0x30, 0x348, 0x12C0, 0x18); // gEngine.TransitionType vars.Helper["Pause"] = vars.Helper.Make(gEngine, 0xADA); // gEngine -> GameInstance(1058) -> m_GameStage(314) vars.Helper["GameStage"] = vars.Helper.Make(gEngine, 0x1058, 0x314); current.World = ""; current.camTarget = ""; current.placeholderTest = ""; current.playerPosXPretty = ""; current.playerPosYPretty = ""; current.playerPosZPretty = ""; current.playerVelRaw = 0; current.playerVelDisplay = 0; current.autostartReady = false; } update { vars.Helper.Update(); vars.Helper.MapPointers(); var World = vars.FNameToString(current.GWorldName); if (!string.IsNullOrEmpty(World) && World != "None") current.World = World; if (old.World != current.World) vars.Log("World: " + old.World + " -> " + current.World); var camTarget = vars.FNameToString(current.camTargetName); if (!string.IsNullOrEmpty(camTarget) && camTarget != "None") current.camTarget = camTarget; if (old.camTarget != current.camTarget) vars.Log("camTarget: " + old.camTarget + " -> " + current.camTarget); var placeholder = vars.FNameToString(current.GWorldName); if (!string.IsNullOrEmpty(placeholder) && placeholder != "None") current.placeholderTest = placeholder; if (old.placeholderTest != current.placeholderTest) vars.Log("placeholderTest: " + old.placeholderTest + " -> " + current.placeholderTest); double velMath = current.playerVelX*current.playerVelX + current.playerVelY*current.playerVelY; current.playerVelRaw = (double)System.Math.Sqrt(velMath); current.playerVelDisplay = (double)(current.playerVelRaw / 10f); current.playerPosXPretty = ((Func)vars.Chop2)(current.playerPosX); current.playerPosYPretty = ((Func)vars.Chop2)(current.playerPosY); current.playerPosZPretty = ((Func)vars.Chop2)(current.playerPosZ); current.playerVelRawPretty = ((Func)vars.Chop2)(current.playerVelRaw); current.playerVelDisplayPretty = ((Func)vars.Chop2)(current.playerVelDisplay); vars.SetTextIfEnabled("placeholder",current.playerPosXPretty); vars.SetTextIfEnabled("playerPos",current.playerPosXPretty + " " + current.playerPosYPretty + " " + current.playerPosZPretty); vars.SetTextIfEnabled("World",current.World); vars.SetTextIfEnabled("camTarget",current.camTarget); vars.SetTextIfEnabled("playerVel",current.playerVelDisplayPretty); vars.SetTextIfEnabled("playerVelCombinedRaw",current.playerVelRawPretty); vars.SetTextIfEnabled("playerVelTrueRaw", current.playerVelVector); vars.Log("playerVelTrueRaw = " + current.World); } start { if (current.camTarget != "CameraMainMenu" && old.camTarget == "CameraMainMenu") {current.autostartReady = true;} if (current.World == "04_Chasm_P" || current.World == "05_Ramshara_P") { if (current.autostartReady == true && current.camTarget.Contains("BP_Nunu_C")) { current.autostartReady = false; return true; } } if (current.World == "03_Plains_P") { if (current.autostartReady == true && current.camTarget.Contains("CAM_Plains") && old.camTarget.Contains("BP_Nunu_C")) { current.autostartReady = false; return true; } } if (current.World != "04_Chasm_P" && current.World != "05_Ramshara_P" && current.World != "03_Plains_P") { if (current.autostartReady == true && !current.camTarget.Contains("BP_Nunu_C") && old.camTarget.Contains("BP_Nunu_C")) { current.autostartReady = false; return true; } } } onStart { vars.CompletedSplits.Clear(); } isLoading { return current.GameStage != 2 && current.GameStage != 1 || current.camTarget == "LoadingCamera"; } split { if (settings.ContainsKey(current.World) && settings[current.World] && !vars.CompletedSplits.Contains(current.World)) { vars.CompletedSplits.Add(current.World); return true; } if (current.World == "09_Ending_P" && current.camTarget == "CineCameraActor5" && old.camTarget != "CineCameraActor5") { return true; } } exit { timer.IsGameTimePaused = true; } onReset { vars.CompletedSplits.Clear(); }