private dynamic GetValue(Process p, String type, DeepPointer pointer)
 {
     if (type == "int")
         return pointer.Deref<int>(p);
     else if (type == "uint")
         return pointer.Deref<uint>(p);
     else if (type == "float")
         return pointer.Deref<float>(p);
     else if (type == "double")
         return pointer.Deref<double>(p);
     else if (type == "byte")
         return pointer.Deref<byte>(p);
     else if (type == "sbyte")
         return pointer.Deref<sbyte>(p);
     else if (type == "short")
         return pointer.Deref<short>(p);
     else if (type == "ushort")
         return pointer.Deref<ushort>(p);
     else if (type == "bool")
         return pointer.Deref<bool>(p);
     else if (type.StartsWith("string"))
     {
         var length = Int32.Parse(type.Substring("string".Length));
         return pointer.DerefString(p, length);
     }
     else if (type.StartsWith("byte"))
     {
         var length = Int32.Parse(type.Substring("byte".Length));
         return pointer.DerefBytes(p, length);
     }
     throw new ArgumentException(string.Format("The provided type, '{0}', is not supported", type));
 }
示例#2
0
        private bool IsLegendOfZelda()
        {
            if (RomName == null)
            {
                return(false);
            }

            // Try and see what game version we're using
            string romName;

            RomName.DerefString(Emulator, 21, out romName);
            if (romName == "ZELDANODENSETSU      " || romName == "THE LEGEND OF ZELDA  ")
            {
                IsRandomized = false;
                return(true);
            }
            else if (romName.StartsWith("Z3Rv") || romName.StartsWith("VT"))
            {
                // The normal randomizer is Z3Rv<version> <difficulty><seed>
                // VT are randomized seeds created by Veetorp, VT<difficulty><seed>v<version>
                IsRandomized = true;
                return(true);
            }
            return(false);
        }
示例#3
0
        /// <summary>
        /// Get the name of an entity using a pointer.
        /// </summary>
        /// <param name="ptr">The pointer.</param>
        /// <param name="isTargetName">Whether the supplied name is the entity's name or its class name.</param>
        /// <returns></returns>
        private static string GetNameFromPtr(IntPtr ptr, bool isTargetName = false)
        {
            DeepPointer nameptr = new DeepPointer(ptr, 0x10, (isTargetName) ? 0x18 : 0x20, 0x0);
            string      name    = "";

            nameptr.DerefString(game, 128, out name);
            return(name);
        }
示例#4
0
        private int GetCommandTextLength()
        {
            if (!consoleTextPointer.DerefOffsets(this.process, out _))
            {
                return(0);
            }

            var str = consoleTextPointer.DerefString(process, ReadStringType.UTF16, MaxCommandLength);

            return(string.IsNullOrEmpty(str) ? 0 : str.Length);
        }
示例#5
0
        private static dynamic GetValue(Process p, string type, DeepPointer pointer)
        {
            switch (type)
            {
            case "int":
                return(pointer.Deref <int>(p));

            case "uint":
                return(pointer.Deref <uint>(p));

            case "long":
                return(pointer.Deref <long>(p));

            case "ulong":
                return(pointer.Deref <ulong>(p));

            case "float":
                return(pointer.Deref <float>(p));

            case "double":
                return(pointer.Deref <double>(p));

            case "byte":
                return(pointer.Deref <byte>(p));

            case "sbyte":
                return(pointer.Deref <sbyte>(p));

            case "short":
                return(pointer.Deref <short>(p));

            case "ushort":
                return(pointer.Deref <ushort>(p));

            case "bool":
                return(pointer.Deref <bool>(p));

            default:
                if (type.StartsWith("string"))
                {
                    var length = int.Parse(type.Substring("string".Length));
                    return(pointer.DerefString(p, length));
                }
                else if (type.StartsWith("byte"))
                {
                    var length = int.Parse(type.Substring("byte".Length));
                    return(pointer.DerefBytes(p, length));
                }
                break;
            }

            throw new ArgumentException($"The provided type, '{type}', is not supported");
        }
        public GameState GetGameState()
        {
            try
            {
                if (GameProcess == null || GameProcess.HasExited)
                {
                    return(GameState.None);
                }
                CurrentMap.Deref(GameProcess, out int rawMapAddr);
                var cm = new DeepPointer(new IntPtr(rawMapAddr));
                cm.DerefString(GameProcess, 1024, out string rawMap);

                if (string.IsNullOrWhiteSpace(rawMap))
                {
                    return(GameState.None);
                }
                rawMap = rawMap.ToLower();

                string formattedMap = rawMap.Replace(".unr", "").Replace(".UNR", "");

                if (OldMap == "DEFAULT")
                {
                    OldMap = formattedMap;
                }

                if (formattedMap != OldMap)
                {
                    OldMap = formattedMap;

                    if (formattedMap == "book_frontend")
                    {
                        return(GameState.Reset);
                    }
                    if (formattedMap == "book_story_1")
                    {
                        return(GameState.NewGame);
                    }

                    if (Shrek2Variables.ExcludedSplitMaps.Any(p => p == formattedMap))
                    {
                        return(GameState.None);
                    }
                    return(GameState.Split);
                }

                return(GameState.None);
            }
            catch
            {
                return(GameState.None);
            }
        }
示例#7
0
        public bool ReadCurrentRoomId(out int roomId)
        {
            StringBuilder sb = new StringBuilder();

            if (DPMainManagerCurrentRoomName.DerefString(BfGameProcess, ReadStringType.ASCII, sb))
            {
                string roomName = sb.ToString();
                if (!int.TryParse(roomName, out roomId))
                {
                    roomId = -1;
                    return(false);
                }
                return(true);
            }

            roomId = -1;
            return(false);
        }
示例#8
0
        public override bool IsLoaded()
        {
            if (!emulator.IsRunning())
            {
                return(false);
            }

            try
            {
                romName = new DeepPointer(emulator.GetOffsets().ROM, 0x7FC0);
                string name;
                romName.DerefString(emulator.emulatorProcess, 21, out name);
                GameModule currentModule = Get <GameModule>("Main Module");

                //tourney = name?.Substring(3, 7).Equals("TOURNEY") ?? false;

                if (name?.StartsWith(gameName) ?? false)
                {
                    region = REGION.NTSC_U;
                    return(currentModule < GameModule.MAX);
                }

                else if (name?.StartsWith("ZELDANODENSETSU") ?? false)
                {
                    region = REGION.NTSC_J;
                    return(currentModule < GameModule.MAX);
                }

                else if (name?.StartsWith("VT") ?? false)
                {
                    region     = REGION.NTSC_J;
                    randomized = true;
                    return(currentModule < GameModule.MAX);
                }
            }

            catch (Exception)
            { }

            return(false);
        }
        private static dynamic GetValue(Process p, string type, DeepPointer pointer)
        {
            switch (type)
            {
                case "int":
                    return pointer.Deref<int>(p);
                case "uint":
                    return pointer.Deref<uint>(p);
                case "float":
                    return pointer.Deref<float>(p);
                case "double":
                    return pointer.Deref<double>(p);
                case "byte":
                    return pointer.Deref<byte>(p);
                case "sbyte":
                    return pointer.Deref<sbyte>(p);
                case "short":
                    return pointer.Deref<short>(p);
                case "ushort":
                    return pointer.Deref<ushort>(p);
                case "bool":
                    return pointer.Deref<bool>(p);
                default:
                    if (type.StartsWith("string"))
                    {
                        var length = int.Parse(type.Substring("string".Length));
                        return pointer.DerefString(p, length);
                    }
                    else if (type.StartsWith("byte"))
                    {
                        var length = int.Parse(type.Substring("byte".Length));
                        return pointer.DerefBytes(p, length);
                    }
                    break;
            }

            throw new ArgumentException($"The provided type, '{type}', is not supported");
        }
示例#10
0
        public override bool IsLoaded()
        {
            if (!emulator.IsRunning())
            {
                return(false);
            }

            try
            {
                romName = new DeepPointer(emulator.GetOffsets().ROM, 0x7FC0);
                string name;
                romName.DerefString(emulator.emulatorProcess, 21, out name);
                if (name?.StartsWith(gameName) ?? false)
                {
                    ushort state = Get <ushort>("Game State");
                    if (state < 0x2A)
                    {
                        return(true);
                    }
                }

                else if (name?.StartsWith("SMRv") ?? false)
                {
                    randomized = true;
                    ushort state = Get <ushort>("Game State");
                    if (state < 0x2A)
                    {
                        return(true);
                    }
                }
            }

            catch (Exception)
            { }

            return(false);
        }
示例#11
0
        void MemoryReadThread()
        {
            Debug.WriteLine("[NoLoads] MemoryReadThread");

            while (!_cancelSource.IsCancellationRequested)
            {
                try
                {
                    Debug.WriteLine("[NoLoads] Waiting for HMA.exe...");
                    uint frameCounter = 0;

                    Process game;
                    while ((game = GetGameProcess()) == null)
                    {
                        Thread.Sleep(250);
                        if (_cancelSource.IsCancellationRequested)
                        {
                            return;
                        }
                    }

                    Debug.WriteLine("[NoLoads] Got games process!");

                    float prevMenuLoadingScreenProgress = -1;
                    float prevIsInGameOrMenu            = -1;
                    float prevIsNotLoading      = -1;
                    float prevIsSavingOrLoading = -1;
                    int   prevTimer             = -1;


                    string prevCurrentScene = null;

                    float menuLoadingScreenProgress = -1;
                    float isInGameOrMenu            = -1;
                    float isNotLoading      = -1;
                    float isSavingOrLoading = -1;
                    int   timer             = -1;

                    string currentScene   = "";
                    bool   finalSplitFlag = false;
                    Stats  stats;

                    while (!game.HasExited && !_cancelSource.IsCancellationRequested)
                    {
                        currentScene = "";

                        bool isMenuLoadingScreenProgressValid = _MenuLoadingScreenProgress.Deref(game, out menuLoadingScreenProgress);
                        bool isIsNotLoadingValid      = _IsNotLoading.Deref(game, out isNotLoading);
                        bool isIsSavingOrLoadingValid = _IsSavingOrLoading.Deref(game, out isSavingOrLoading);
                        bool isCurrentSceneValid      = _CurrentScene.DerefString(game, 50, out currentScene);
                        bool isTimerValid             = _Timer.Deref(game, out timer);
                        bool isStatsValid             = _Stats.Deref <Stats>(game, out stats);
                        var  scene = currentScene?.ToLower();

                        if (isCurrentSceneValid && currentScene != prevCurrentScene)
                        {
                            Debug.WriteLine($"Scene changed to {currentScene}");
                            if (scene.Contains("premission") || scene.Contains("intro"))
                            {
                                try
                                {
                                    CurrentLevel = (SplitArea)Int32.Parse(Regex.Match(scene, "m(\\d+)\\\\").Groups[1].Value);
                                    Debug.WriteLine($"Current level changed to {CurrentLevel}");
                                    if (_settings.FirstLevel.HasValue && CurrentLevel == _settings.FirstLevel)
                                    {
                                        Debug.WriteLine($"First level loaded");
                                        _uiThread.Post(d =>
                                        {
                                            OnFirstLevelLoaded?.Invoke(this, EventArgs.Empty);
                                        }, null);
                                    }
                                }
                                catch (Exception ex)
                                {
                                    CurrentLevel = null;
                                    Debug.WriteLine(ex.ToString());
                                }
                            }
                            else if (CurrentLevel.HasValue && ((PostMissionSceneNames.ContainsKey(CurrentLevel.Value) && scene.Contains(PostMissionSceneNames[CurrentLevel.Value])) || scene.Contains("postmission")))
                            {
                                Debug.WriteLine($"Splitting {CurrentLevel.Value}");
                                Split(CurrentLevel.Value, frameCounter);
                            }
                            finalSplitFlag = false;
                        }

                        if (isStatsValid && CurrentLevel.HasValue && CurrentLevel.Value == SplitArea.Requiem && isCurrentSceneValid && currentScene.ToLower().Contains("main") && !finalSplitFlag && stats.m_TargetsKilled == 13)
                        {
                            finalSplitFlag = true;
                            Split(CurrentLevel.Value, frameCounter);
                        }


                        if ((isIsNotLoadingValid && isNotLoading == 0 && (scene.Contains("main") || scene.Contains("premission"))) ||
                            (isIsSavingOrLoadingValid && isSavingOrLoading != 0 && scene.Contains("saveandcontinue")) ||
                            (isMenuLoadingScreenProgressValid && menuLoadingScreenProgress != 1)
                            )
                        {
                            IsLoading = true;
                        }
                        else
                        {
                            IsLoading = false;
                        }

                        prevMenuLoadingScreenProgress = isMenuLoadingScreenProgressValid ? menuLoadingScreenProgress : prevMenuLoadingScreenProgress;
                        prevIsInGameOrMenu            = isMenuLoadingScreenProgressValid ? isInGameOrMenu : prevIsInGameOrMenu;
                        prevIsNotLoading      = isIsNotLoadingValid ? isNotLoading : prevIsNotLoading;
                        prevIsSavingOrLoading = isIsSavingOrLoadingValid ? isSavingOrLoading : prevIsSavingOrLoading;
                        prevTimer             = isTimerValid ? timer : prevTimer;
                        prevCurrentScene      = isCurrentSceneValid ? currentScene : prevCurrentScene;

                        frameCounter++;

                        Thread.Sleep(15);
                    }
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex.ToString());
                    Thread.Sleep(1000);
                }
            }
        }
示例#12
0
        void GameMemoryReadThread()
        {
            Trace.WriteLine("[NoLoads] MemoryReadThread");

            while (!ListenGameCancelSource.IsCancellationRequested)
            {
                try
                {
                    Trace.WriteLine("[NoLoads] Waiting for game.exe...");

                    Process game;
                    while ((game = GetGameProcess()) == null)
                    {
                        Thread.Sleep(250);
                        if (ListenGameCancelSource.IsCancellationRequested)
                        {
                            return;
                        }
                    }

                    Trace.WriteLine("[NoLoads] Got game.exe!");

                    FrameCounter = 0;
                    int    prevBufCursor  = 0;
                    string prevBuf        = String.Empty;
                    string currentMap     = String.Empty;
                    string prevCurrentMap = String.Empty;
                    bool   prevIsLoading  = false;

                    while (!game.HasExited)
                    {
                        LogBufferPtr.DerefString(game, 4096, out string buf);
                        LogBufferCursorPtr.Deref(game, out int bufCursor);
                        IsLoadingPtr.Deref(game, out int ret);
                        IsSavingPtr.Deref(game, out int isSaving);

                        bool isLoading = (ret == 2 || isSaving == 256);

                        string log = String.Empty;

                        if ((!buf.Equals(prevBuf) && !prevBuf.Equals(String.Empty)))
                        {
                            int length = (prevBufCursor > bufCursor) ? 4096 - prevBufCursor : bufCursor - prevBufCursor;
                            log = buf.Substring(prevBufCursor, length);
                            if (prevBufCursor > bufCursor)
                            {
                                log += buf.Substring(0, bufCursor);
                            }

                            string[] logLines = Regex.Split(log, @"(?<=\r\n)");

                            Debug.WriteLine(String.Format("------bufCursor: {0} prevBufCursor: {1}-------", bufCursor, prevBufCursor));
                            Debug.WriteLine("--------------------" + FrameCounter + "---------------------");
                            Debug.Write(log);

                            int  cursor = prevBufCursor;
                            uint i      = 0;
                            foreach (string line in logLines)
                            {
                                Match validLine      = Regex.Match(line, @"^(?:Log:|Init:|ScriptLog:|CutLog:|DevSound:|Localization:|Warning:|ScriptWarning:|Exit:|Uninitialized:).+\r\n");
                                Match loadMapRegex   = Regex.Match(line, @"LoadMap: ([^?]+)\?");
                                Match splitRegex     = Regex.Match(line, @"Bringing Level ([^ ?]+)\.MyLevel up for play");
                                Match loadTimeRegex  = Regex.Match(line, @"Load time (?:.+\\)?([^?]+): (\d+\.\d+) seconds total, (\d+\.\d+) app");
                                Match saveStartRegex = Regex.Match(line, @"Saving game\.\.\. filename: .+\.usa");
                                Match saveEndRegex   = Regex.Match(line, @"Log: Moving '.+\.tmp' to '.+\.usa'");

                                if (line.Equals(""))
                                {
                                    continue;
                                }

                                // If the line is incorrect, read again from there next frame
                                if (!validLine.Success && i > 0)
                                {
                                    Debug.WriteLine("\n[Invalid line] " + line);
                                    bufCursor = cursor;
                                    if (bufCursor >= 4096)
                                    {
                                        bufCursor -= 4096;
                                    }
                                    break;
                                }
                                cursor += line.Length;

                                if (loadMapRegex.Success)
                                {
                                    currentMap = loadMapRegex.Groups[1].Value.ToLower();
                                    if (Shrek2Splits.Splits.Any(p => p.Name == currentMap))
                                    {
                                        Split(Shrek2Splits.Splits.First(p => p.Name == currentMap).ID, FrameCounter);
                                    }
                                }
                                else if (line.Contains(Shrek2Splits.NewGame_MemoryLine))
                                {
                                    ListenGameUIThread.Post(d =>
                                    {
                                        OnNewGame?.Invoke(this, EventArgs.Empty);
                                    }, null);
                                }
                                else
                                {
                                    if (Shrek2Splits.Splits.Any(p => p.CutSceneTriggers.Any(x => line.Contains(x))))
                                    {
                                        var splitValue = Shrek2Splits.Splits.FirstOrDefault(p => p.CutSceneTriggers.Any(x => line.Contains(x)));
                                        Split(splitValue.ID, FrameCounter);
                                    }
                                }

                                i++;
                            }
                        }

                        if (currentMap != prevCurrentMap)
                        {
                            Debug.WriteLine(String.Format("[NoLoads] Detected map change from \"{0}\" to \"{1}\" - {2}", prevCurrentMap, currentMap, FrameCounter));

                            if (currentMap == "book_frontend.unr")
                            {
                                ListenGameUIThread.Post(d =>
                                {
                                    if (this.OnMainMenuLoad != null)
                                    {
                                        this.OnMainMenuLoad(this, EventArgs.Empty);
                                    }
                                }, null);
                            }
                        }

                        if (isLoading != prevIsLoading)
                        {
                            if (isLoading)
                            {
                                Trace.WriteLine("[NoLoads] Loading started - " + FrameCounter);
                                ListenGameUIThread.Post(d =>
                                {
                                    if (this.OnLoadStart != null)
                                    {
                                        this.OnLoadStart(this, EventArgs.Empty);
                                    }
                                }, null);
                            }
                            else
                            {
                                Trace.WriteLine("[NoLoads] Loading ended - " + FrameCounter);
                                ListenGameUIThread.Post(d =>
                                {
                                    if (this.OnLoadEnd != null)
                                    {
                                        this.OnLoadEnd(this, EventArgs.Empty);
                                    }
                                }, null);
                            }
                        }

                        FrameCounter++;
                        prevBuf        = buf;
                        prevBufCursor  = bufCursor;
                        prevCurrentMap = currentMap;
                        prevIsLoading  = isLoading;

                        Thread.Sleep(Shrek2Variables.GameLogic_SleepTime);

                        if (ListenGameCancelSource.IsCancellationRequested)
                        {
                            return;
                        }
                    }
                }
                catch (Exception ex)
                {
                    Trace.WriteLine(ex.ToString());
                    Thread.Sleep(1000);
                }
            }
        }
示例#13
0
        void MemoryReadThread()
        {
            Debug.WriteLine("[NoLoads] MemoryReadThread");

            while (!_cancelSource.IsCancellationRequested)
            {
                try
                {
                    Debug.WriteLine("[NoLoads] Waiting for quake4.exe...");

                    Process game;
                    while ((game = GetGameProcess()) == null)
                    {
                        Thread.Sleep(250);
                        if (_cancelSource.IsCancellationRequested)
                        {
                            return;
                        }
                    }

                    Debug.WriteLine("[NoLoads] Got games process!");

                    uint frameCounter = 0;

                    bool   prevIsLoading     = false;
                    bool   prevIsCutscene    = false;
                    string prevStreamGroupId = String.Empty;


                    bool loadingStarted = false;

                    while (!game.HasExited)
                    {
                        bool   isLoading;
                        bool   isCutscene;
                        string streamGroupId = String.Empty;
                        _levelNamePtr.DerefString(game, 30, out streamGroupId);
                        streamGroupId = streamGroupId.ToLower();
                        _isLoadingPtr.Deref(game, out isLoading);
                        _isCutscenePtr.Deref(game, out isCutscene);

                        if (streamGroupId != prevStreamGroupId && streamGroupId != null || prevIsCutscene != isCutscene)
                        {
                            if (prevStreamGroupId == LevelName.l01_airDefence1 && streamGroupId == LevelName.l02_airDefence2)
                            {
                                Split(SplitArea.l01, frameCounter);
                            }
                            else if (prevStreamGroupId == LevelName.l02_airDefence2 && streamGroupId == LevelName.l03_hangar1)
                            {
                                Split(SplitArea.l02, frameCounter);
                            }
                            else if (prevStreamGroupId == LevelName.l03_hangar1 && streamGroupId == LevelName.l04_hangar2)
                            {
                                Split(SplitArea.l03, frameCounter);
                            }
                            else if (prevStreamGroupId == LevelName.l04_hangar2 && streamGroupId == LevelName.l05_mcclanding)
                            {
                                Split(SplitArea.l04, frameCounter);
                            }
                            else if (prevStreamGroupId == LevelName.l05_mcclanding && streamGroupId == LevelName.l06_mcc1)
                            {
                                Split(SplitArea.l05, frameCounter);
                            }
                            else if (prevStreamGroupId == LevelName.l06_mcc1 && streamGroupId == LevelName.l07_convoy1)
                            {
                                Split(SplitArea.l06, frameCounter);
                            }
                            else if (prevStreamGroupId == LevelName.l07_convoy1 && streamGroupId == LevelName.l08_buildingb)
                            {
                                Split(SplitArea.l07, frameCounter);
                            }
                            else if (prevStreamGroupId == LevelName.l08_buildingb && streamGroupId == LevelName.l09_convoy2)
                            {
                                Split(SplitArea.l08, frameCounter);
                            }
                            else if (prevStreamGroupId == LevelName.l09_convoy2 && streamGroupId == LevelName.l10_convoy2b)
                            {
                                Split(SplitArea.l09, frameCounter);
                            }
                            else if (prevStreamGroupId == LevelName.l10_convoy2b && streamGroupId == LevelName.l11_hub1)
                            {
                                Split(SplitArea.l10, frameCounter);
                            }
                            else if (prevStreamGroupId == LevelName.l11_hub1 && streamGroupId == LevelName.l12_hub2)
                            {
                                Split(SplitArea.l11, frameCounter);
                            }
                            else if (prevStreamGroupId == LevelName.l12_hub2 && streamGroupId == LevelName.l13_medlabs)
                            {
                                Split(SplitArea.l12, frameCounter);
                            }
                            else if (prevStreamGroupId == LevelName.l13_medlabs && streamGroupId == LevelName.l14_walker)
                            {
                                Split(SplitArea.l13, frameCounter);
                            }
                            else if (prevStreamGroupId == LevelName.l14_walker && streamGroupId == LevelName.l15_dispersal)
                            {
                                Split(SplitArea.l14, frameCounter);
                            }
                            else if (prevStreamGroupId == LevelName.l15_dispersal && streamGroupId == LevelName.l16_recomp)
                            {
                                Split(SplitArea.l15, frameCounter);
                            }
                            else if (prevStreamGroupId == LevelName.l16_recomp && streamGroupId == LevelName.l17_purification)
                            {
                                Split(SplitArea.l16, frameCounter);
                            }
                            else if (prevStreamGroupId == LevelName.l17_purification && streamGroupId == LevelName.l18_wasteDisposal)
                            {
                                Split(SplitArea.l17, frameCounter);
                            }
                            else if (prevStreamGroupId == LevelName.l18_wasteDisposal && streamGroupId == LevelName.l19_mcc2)
                            {
                                Split(SplitArea.l18, frameCounter);
                            }
                            else if (prevStreamGroupId == LevelName.l19_mcc2 && streamGroupId == LevelName.l20_storage1)
                            {
                                Split(SplitArea.l19, frameCounter);
                            }
                            else if (prevStreamGroupId == LevelName.l20_storage1 && streamGroupId == LevelName.l21_storage2)
                            {
                                Split(SplitArea.l20, frameCounter);
                            }
                            else if (prevStreamGroupId == LevelName.l21_storage2 && streamGroupId == LevelName.l22_storage1)
                            {
                                Split(SplitArea.l21, frameCounter);
                            }
                            else if (prevStreamGroupId == LevelName.l22_storage1 && streamGroupId == LevelName.l23_tram1)
                            {
                                Split(SplitArea.l22, frameCounter);
                            }
                            else if (prevStreamGroupId == LevelName.l23_tram1 && streamGroupId == LevelName.l24_tram1b)
                            {
                                Split(SplitArea.l23, frameCounter);
                            }
                            else if (prevStreamGroupId == LevelName.l24_tram1b && streamGroupId == LevelName.l25_process1)
                            {
                                Split(SplitArea.l24, frameCounter);
                            }
                            else if (prevStreamGroupId == LevelName.l25_process1 && streamGroupId == LevelName.l26_process2)
                            {
                                Split(SplitArea.l25, frameCounter);
                            }
                            else if (prevStreamGroupId == LevelName.l26_process2 && streamGroupId == LevelName.l27_process1)
                            {
                                Split(SplitArea.l26, frameCounter);
                            }
                            else if (prevStreamGroupId == LevelName.l27_process1 && streamGroupId == LevelName.l28_network1)
                            {
                                Split(SplitArea.l27, frameCounter);
                            }
                            else if (prevStreamGroupId == LevelName.l28_network1 && streamGroupId == LevelName.l29_network2)
                            {
                                Split(SplitArea.l28, frameCounter);
                            }
                            else if (prevStreamGroupId == LevelName.l29_network2 && streamGroupId == LevelName.l30_core1)
                            {
                                Split(SplitArea.l29, frameCounter);
                            }
                            else if (prevStreamGroupId == LevelName.l30_core1 && streamGroupId == LevelName.l31_core2)
                            {
                                Split(SplitArea.l30, frameCounter);
                            }
                            else if (streamGroupId == LevelName.l31_core2 && isCutscene)
                            {
                                Split(SplitArea.l31, frameCounter);
                            }
                            else if (streamGroupId == LevelName.l01_airDefence1 && isCutscene == true && prevIsCutscene == false)
                            {
                                //Reset in game timer
                                _uiThread.Post(d =>
                                {
                                    if (this.OnFirstLevelLoading != null)
                                    {
                                        this.OnFirstLevelLoading(this, EventArgs.Empty);
                                    }
                                }, null);

                                // And instantly start it
                                _uiThread.Post(d =>
                                {
                                    if (this.OnPlayerGainedControl != null)
                                    {
                                        this.OnPlayerGainedControl(this, EventArgs.Empty);
                                    }
                                }, null);
                            }
                        }

                        _isLoadingPtr.Deref(game, out isLoading);

                        if (isLoading != prevIsLoading)
                        {
                            if (isLoading)
                            {
                                Debug.WriteLine(String.Format("[NoLoads] Load Start - {0}", frameCounter));

                                loadingStarted = true;

                                // pause game timer
                                _uiThread.Post(d =>
                                {
                                    if (this.OnLoadStarted != null)
                                    {
                                        this.OnLoadStarted(this, EventArgs.Empty);
                                    }
                                }, null);
                            }
                            else
                            {
                                Debug.WriteLine(String.Format("[NoLoads] Load End - {0}", frameCounter));
                                if (loadingStarted)
                                {
                                    loadingStarted = false;

                                    // unpause game timer
                                    _uiThread.Post(d =>
                                    {
                                        if (this.OnLoadFinished != null)
                                        {
                                            this.OnLoadFinished(this, EventArgs.Empty);
                                        }
                                    }, null);
                                }
                            }
                        }


                        Debug.WriteLineIf(streamGroupId != prevStreamGroupId, String.Format("[NoLoads] streamGroupId changed from {0} to {1} - {2}", prevStreamGroupId, streamGroupId, frameCounter));
                        prevStreamGroupId = streamGroupId;
                        prevIsLoading     = isLoading;
                        prevIsCutscene    = isCutscene;

                        frameCounter++;

                        Thread.Sleep(15);

                        if (_cancelSource.IsCancellationRequested)
                        {
                            return;
                        }
                    }
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex.ToString());
                    Thread.Sleep(1000);
                }
            }
        }