state("LastHalfOfDarkness-Win64-Shipping") { int levelTransition : 0x6631BB8; } startup { { if (timer.CurrentTimingMethod == TimingMethod.RealTime) // Asks user to change to game time if LiveSplit is currently set to Real Time. { var timingMessage = MessageBox.Show ( "This game uses Time without Loads (Game Time) as the main timing method.\n"+ "LiveSplit is currently set to show Real Time (RTA).\n"+ "Would you like to set the timing method to Game Time?", "LiveSplit | Last Half of Darkness", MessageBoxButtons.YesNo,MessageBoxIcon.Question ); if (timingMessage == DialogResult.Yes) { timer.CurrentTimingMethod = TimingMethod.GameTime; } } } //creates text components for variable information vars.SetTextComponent = (Action<string, string>)((id, text) => { var textSettings = timer.Layout.Components.Where(x => x.GetType().Name == "TextComponent").Select(x => x.GetType().GetProperty("Settings").GetValue(x, null)); var textSetting = textSettings.FirstOrDefault(x => (x.GetType().GetProperty("Text1").GetValue(x, null) as string) == id); if (textSetting == null) { var textComponentAssembly = Assembly.LoadFrom("Components\\LiveSplit.Text.dll"); var textComponent = Activator.CreateInstance(textComponentAssembly.GetType("LiveSplit.UI.Components.TextComponent"), timer); timer.Layout.LayoutComponents.Add(new LiveSplit.UI.Components.LayoutComponent("LiveSplit.Text.dll", textComponent as LiveSplit.UI.Components.IComponent)); textSetting = textComponent.GetType().GetProperty("Settings", BindingFlags.Instance | BindingFlags.Public).GetValue(textComponent, null); textSetting.GetType().GetProperty("Text1").SetValue(textSetting, id); } if (textSetting != null) textSetting.GetType().GetProperty("Text2").SetValue(textSetting, text); }); //Parent setting settings.Add("Variable Information", true, "Variable Information"); //Child settings that will sit beneath Parent setting settings.Add("Camera", true, "Current Camera Target", "Variable Information"); settings.Add("Map", true, "Current Map", "Variable Information"); settings.Add("Loading", false, "Current Loading", "Variable Information"); } init { // Scanning the MainModule for static pointers to GSyncLoadCount, UWorld, UEngine and FNamePool var scn = new SignatureScanner(game, game.MainModule.BaseAddress, game.MainModule.ModuleMemorySize); //var LoadingTrg = new SigScanTarget(2, "89 05 ?? ?? ?? ?? e8 ?? ?? ?? ?? 84 c0 75 ?? e8 ?? ?? ?? ?? 84 c0 48 8b c3 74 ?? 48 8b c5 f3 0f 10 04 06 f3 0f 11 05 ?? ?? ?? ?? e9") { OnFound = (p, s, ptr) => ptr + 0x4 + game.ReadValue<int>(ptr) }; //var Loading1 = scn.Scan(LoadingTrg); var uWorldTrg = new SigScanTarget(3, "48 8b 1d ?? ?? ?? ?? 48 85 db 74 ?? 41 b0") { OnFound = (p, s, ptr) => ptr + 0x4 + game.ReadValue<int>(ptr) }; var uWorld = scn.Scan(uWorldTrg); var gameEngineTrg = new SigScanTarget(3, "48 89 05 ?? ?? ?? ?? 48 85 c9 74 ?? e8 ?? ?? ?? ?? 48 8d 4d") { OnFound = (p, s, ptr) => ptr + 0x4 + game.ReadValue<int>(ptr) }; var gameEngine = scn.Scan(gameEngineTrg); var fNamePoolTrg = new SigScanTarget(3, "48 8d 05 ?? ?? ?? ?? eb ?? 48 8d 0d ?? ?? ?? ?? e8 ?? ?? ?? ?? c6 05 ?? ?? ?? ?? ?? 0f 10 07") { OnFound = (p, s, ptr) => ptr + 0x4 + game.ReadValue<int>(ptr) }; var fNamePool = scn.Scan(fNamePoolTrg); // Throwing in case any base pointers can't be found (yet, hopefully) if(uWorld == IntPtr.Zero || gameEngine == IntPtr.Zero || fNamePool == IntPtr.Zero) { throw new Exception("One or more base pointers not found - retrying"); } vars.Watchers = new MemoryWatcherList { //new MemoryWatcher<int>(new DeepPointer(Loading1)) { Name = "Loading"}, // UWorld.Name new MemoryWatcher<ulong>(new DeepPointer(uWorld, 0x18)) { Name = "worldFName"}, // GameEngine.GameInstance.LocalPlayers[0].PlayerController.PlayerCameraManager.ViewTarget.Target.Name new MemoryWatcher<ulong>(new DeepPointer(gameEngine, 0xFC0, 0x38, 0x0, 0x30, 0x348, 0x12C0, 0x18)) { Name = "camViewTargetFName"}, }; // Translating FName to String, this *could* be cached vars.FNameToString = (Func<ulong, string>)(fName => { var number = (fName & 0xFFFFFFFF00000000) >> 0x20; var chunkIdx = (fName & 0x00000000FFFF0000) >> 0x10; var nameIdx = (fName & 0x000000000000FFFF) >> 0x00; var chunk = game.ReadPointer(fNamePool + 0x10 + (int)chunkIdx * 0x8); var nameEntry = chunk + (int)nameIdx * 0x2; var length = game.ReadValue<short>(nameEntry) >> 6; var name = game.ReadString(nameEntry + 0x2, length); return number == 0 ? name : name; }); vars.Watchers.UpdateAll(game); //sets the var world from the memory watcher current.world = old.world = vars.FNameToString(vars.Watchers["worldFName"].Current); //helps with null values throwing errors - i dont exactly know why, but thanks to Nikoheart for this current.camTarget = ""; current.world = ""; } update { vars.Watchers.UpdateAll(game); // Get the current world name as string, only if *UWorld isnt null var worldFName = vars.Watchers["worldFName"].Current; current.world = worldFName != 0x0 ? vars.FNameToString(worldFName) : old.world; // Get the Name of the current target for the CameraManager current.camTarget = vars.FNameToString(vars.Watchers["camViewTargetFName"].Current); //current.LevelTransition = vars.Watchers["Loading"].Current; //Prints the camera target to the Livesplit layout if the setting is enabled if(settings["Camera"]) { vars.SetTextComponent("Camera Target:",current.camTarget.ToString()); if (old.camTarget != current.camTarget) print("Camera Target:" + current.camTarget.ToString()); } //Prints the current map to the Livesplit layout if the setting is enabled if(settings["Map"]) { vars.SetTextComponent("Map:",current.world.ToString()); if (old.world != current.world) print("Map:" + current.world.ToString()); } //Prints the camera target to the Livesplit layout if the setting is enabled if(settings["Loading"]) { vars.SetTextComponent("Loading:",current.levelTransition.ToString()); } //DEBUG CODE print("isLoading? " + current.levelTransition.ToString()); //print("Loaded Map = " + current.world.ToString()); //print("Camera Target = " + current.camTarget.ToString()); //print("Horizontal Position:" + current.horizontalPos.ToString()); //print(modules.First().ModuleMemorySize.ToString()); } start { return old.world == "BeachMenu" && current.world != "BeachMenu" || old.world != "Beach" && current.world == "Beach"; } split { return old.world != current.world || old.camTarget == "LastHalfCharacter_C" && current.camTarget == "CineCameraActor"; } isLoading { return current.levelTransition == 0; }