예제 #1
0
        /// <summary>
        /// Read song timer and note data from memory
        /// </summary>
        /// <returns></returns>
        public RSMemoryReadout DoReadout()
        {
            // SONG ID
            //
            // Seems to be a zero terminated string in the format: Song_SONGID_Preview
            //
            //Candidate #1: FollowPointers(0x00F5C494, new int[] { 0xBC, 0x0 })
            //Candidate #2: FollowPointers(0x00F80CEC, new int[] { 0x598, 0x1B8, 0x0 })
            //Candidate #3: FollowPointers(0x00F5DAFC, new int[] { 0x608, 0x1B8, 0x0 })

            string preview_name;
            switch (Environment.OSVersion.Platform)
            {
                case PlatformID.MacOSX:
                case PlatformID.Unix:
                    /* more info in MacOSAPI.cs */
                    preview_name = preview_name = CreateStringFromBytes(FollowPointers(0x018FA000, new int[] { 0xE8, 0x0 }), 128);
                    break;
                default:
                    //bytes = MemoryHelper.ReadBytesFromMemory(PInfo, FollowPointers(0x00F5C80C, new int[] { 0x28, 0x10, 0x140 }), 128);
                    preview_name = CreateStringFromBytes(FollowPointers(0x00F5C494, new int[] { 0xBC, 0x0 }), 128);

                    break;
            }
            //Verify Play_ prefix and _Preview suffix
            if (preview_name.StartsWith("Play_") && preview_name.EndsWith("_Preview"))
            {
                //Remove Play_ prefix and _Preview suffix
                string song_id = preview_name.Substring(5, preview_name.Length - 13);
                //Assign to readout
                readout.songID = song_id;
            }
            else if (preview_name.StartsWith("Song_") && preview_name.EndsWith("_Preview.bnk"))
            {
                string song_id = preview_name.Substring(5, preview_name.Length - 17);
                //Assign to readout
                if (song_id != readout.songID)
                {
                    readout.persistentID = string.Empty;
                    NoteDataMacAddress_LAS = IntPtr.Zero;
                    NoteDataMacAddress_SA = IntPtr.Zero;
                }
                readout.songID = song_id;
            }

            switch (Environment.OSVersion.Platform)
            {
                case PlatformID.MacOSX:
                case PlatformID.Unix:
                    break;
                default:
                    //PID
                    string pid = CreateStringFromBytes(FollowPointers(0x00F5C5AC, new int[] { 0x18, 0x18, 0xC, 0x1C0, 0x0 }), 128);
                    if (!string.IsNullOrEmpty(pid))
                    {
                        readout.persistentID = pid;
                    }
                    break;
            }

            // CURRENT STATE
            switch (Environment.OSVersion.Platform)
            {
                case PlatformID.MacOSX:
                case PlatformID.Unix:
                    string p = CreateStringFromBytes(FollowPointers(0x018FA9B8, new int[] { 0x48, 0xE0, 0 }), 128);
                    if (!string.IsNullOrEmpty(p))
                        readout.gameState = p;
                    break;
                default:
                    string s = CreateStringFromBytes(FollowPointers(0x00F5C5AC, new int[] { 0x28, 0x8C, 0x0 }), 255);
                    if (!string.IsNullOrEmpty(s))
                        readout.gameState = s;
                    break;
            }


            // SONG TIMER
            //
            switch (Environment.OSVersion.Platform)
            {
                case PlatformID.MacOSX:
                case PlatformID.Unix:
                    /* more info in MacOSAPI.cs */
                    ReadSongTimer(FollowPointers(0x018EE728, new int[] { 0x184 }));
                    IntPtr noteDataRoot = IntPtr.Subtract(NoteDataMacAddress_LAS, 0x000C);
                    IntPtr noteDataSARoot = IntPtr.Subtract(NoteDataMacAddress_SA, 0x000C);
                    if (readout.gameState.ToLower().Contains("learnasong"))
                    {
                        if (readout.mode != RSMode.LEARNASONG)
                        {
                            readout.LASData.Clear();
                            readout.SAData.Clear();
                            NoteDataMacAddress_LAS = IntPtr.Zero;
                            NoteDataMacAddress_SA = IntPtr.Zero;
                            NDAddressStack.Clear();
                        }
                        readout.mode = RSMode.LEARNASONG;
                        ReadNoteData(noteDataRoot);
                    }
                    else if (readout.gameState.ToLower().Contains("scoreattack"))
                    {
                        if (readout.mode != RSMode.SCOREATTACK)
                        {
                            readout.LASData.Clear();
                            readout.SAData.Clear();
                            NoteDataMacAddress_LAS = IntPtr.Zero;
                            NoteDataMacAddress_SA = IntPtr.Zero;
                            NDAddressStack.Clear();
                        }
                        readout.mode = RSMode.SCOREATTACK;
                        ReadNoteData(noteDataRoot);
                        readout.SAData.TotalNotesHit = readout.LASData.TotalNotesHit;
                        readout.SAData.CurrentHitStreak = readout.LASData.CurrentHitStreak;
                        readout.SAData.HighestHitStreak = readout.LASData.HighestHitStreak;
                        readout.SAData.TotalNotesMissed = readout.LASData.TotalNotesMissed;
                        readout.SAData.CurrentMissStreak = readout.LASData.CurrentMissStreak;
                        ReadScoreAttackNoteData(noteDataSARoot);
                    }
                    else
                        readout.mode = RSMode.UNKNOWN;
                    break;
                default:
                    //Weird static address: FollowPointers(0x01567AB0, new int[]{ 0x80, 0x20, 0x10C, 0x244 })
                    //Candidate #1: FollowPointers(0x00F5C5AC, new int[] { 0xB0, 0x538, 0x8 })
                    //Candidate #2: FollowPointers(0x00F5C4CC, new int[] { 0x5F0, 0x538, 0x8 })
                    ReadSongTimer(FollowPointers(0x00F5C5AC, new int[] { 0xB0, 0x538, 0x8 }));

                    // NOTE DATA
                    //
                    // For learn a song:
                    //Candidate #1: FollowPointers(0x00F5C5AC, new int[] {0xB0, 0x18, 0x4, 0x84, 0x0})
                    //Candidate #2: FollowPointers(0x00F5C4CC, new int[] {0x5F0, 0x18, 0x4, 0x84, 0x0})
                    //
                    // For score attack:
                    //Candidate #1: FollowPointers(0x00F5C5AC, new int[] { 0xB0, 0x18, 0x4, 0x4C, 0x0 })
                    //Candidate #2: FollowPointers(0x00F5C4CC, new int[] { 0x5F0, 0x18, 0x4, 0x4C, 0x0 })

                    //If note data is not valid, try the next mode
                    //Learn a song
                    if (readout.gameState.ToLower().Contains("learnasong"))
                    {
                        readout.mode = RSMode.LEARNASONG;
                        ReadNoteData(FollowPointers(0x00F5C5AC, new int[] { 0xB0, 0x18, 0x4, 0x84, 0x0 }));
                    }
                    else if (readout.gameState.ToLower().Contains("scoreattack"))
                    {
                        readout.mode = RSMode.SCOREATTACK;
                        ReadScoreAttackNoteData(FollowPointers(0x00F5C5AC, new int[] { 0xB0, 0x18, 0x4, 0x4C, 0x0 }));
                    }
                    else
                        readout.mode = RSMode.UNKNOWN;
                    break;
            }
            //Copy over everything when a song is running
            if (readout.songTimer > 0)
            {
                readout.CopyTo(ref prevReadout);
            }

            //Always copy over important fields
            prevReadout.songID = readout.songID;
            prevReadout.songTimer = readout.songTimer;
            prevReadout.gameState = readout.gameState;
            prevReadout.mode = readout.mode;

            return prevReadout;
        }
예제 #2
0
        /// <summary>
        /// Read song timer and note data from memory
        /// </summary>
        /// <returns></returns>
        public RSMemoryReadout DoReadout()
        {
            // SONG ID
            //
            // Seems to be a zero terminated string in the format: Song_SONGID_Preview
            //
            //Candidate #1: FollowPointers(0x00F5C494, new int[] { 0xBC, 0x0 })
            //Candidate #2: FollowPointers(0x00F80CEC, new int[] { 0x598, 0x1B8, 0x0 })
            //Candidate #3: FollowPointers(0x00F5DAFC, new int[] { 0x608, 0x1B8, 0x0 })
            byte[] bytes = MemoryHelper.ReadBytesFromMemory(rsProcessHandle, FollowPointers(0x00F5C494, new int[] { 0xBC, 0x0 }), 128);

            //Find the first 0 in the array
            int end = Array.IndexOf <byte>(bytes, 0);

            //If there was a 0 in the array
            if (end > 0)
            {
                //Copy into a char array
                char[] chars = new char[end];

                Array.Copy(bytes, chars, end);

                //Create string from char array
                string preview_name = new string(chars);

                //Verify Play_ prefix and _Preview suffix
                if (preview_name.StartsWith("Play_") && preview_name.EndsWith("_Preview"))
                {
                    //Remove Play_ prefix and _Preview suffix
                    string song_id = preview_name.Substring(5, preview_name.Length - 13);

                    //Assign to readout
                    readout.songID = song_id;
                }
            }

            // SONG TIMER
            //
            //Weird static address: FollowPointers(0x01567AB0, new int[]{ 0x80, 0x20, 0x10C, 0x244 })
            //Candidate #1: FollowPointers(0x00F5C5AC, new int[] { 0xB0, 0x538, 0x8 })
            //Candidate #2: FollowPointers(0x00F5C4CC, new int[] { 0x5F0, 0x538, 0x8 })
            ReadSongTimer(FollowPointers(0x00F5C5AC, new int[] { 0xB0, 0x538, 0x8 }));

            // NOTE DATA
            //
            // For learn a song:
            //Candidate #1: FollowPointers(0x00F5C5AC, new int[] {0xB0, 0x18, 0x4, 0x84, 0x0})
            //Candidate #2: FollowPointers(0x00F5C4CC, new int[] {0x5F0, 0x18, 0x4, 0x84, 0x0})
            //
            // For score attack:
            //Candidate #1: FollowPointers(0x00F5C5AC, new int[] { 0xB0, 0x18, 0x4, 0x4C, 0x0 })
            //Candidate #2: FollowPointers(0x00F5C4CC, new int[] { 0x5F0, 0x18, 0x4, 0x4C, 0x0 })

            //If note data is not valid, try the next mode
            //Learn a song
            if (!ReadNoteData(FollowPointers(0x00F5C5AC, new int[] { 0xB0, 0x18, 0x4, 0x84, 0x0 })))
            {
                //Score attack
                if (!ReadScoreAttackNoteData(FollowPointers(0x00F5C5AC, new int[] { 0xB0, 0x18, 0x4, 0x4C, 0x0 })))
                {
                    readout.mode = RSMode.UNKNOWN;
                }
            }

            //Copy over everything when a song is running
            if (readout.songTimer > 0)
            {
                readout.CopyTo(ref prevReadout);
            }

            //Always copy over important fields
            prevReadout.songID    = readout.songID;
            prevReadout.songTimer = readout.songTimer;

            return(prevReadout);
        }
예제 #3
0
        /// <summary>
        /// Read song timer and note data from memory
        /// </summary>
        /// <returns></returns>
        public RSMemoryReadout DoReadout()
        {
            // SONG ID
            //
            // Seems to be a zero terminated string in the format: Song_SONGID_Preview
            //
            //Candidate #1: FollowPointers(0x00F5C494, new int[] { 0xBC, 0x0 })
            //Candidate #2: FollowPointers(0x00F80CEC, new int[] { 0x598, 0x1B8, 0x0 })
            //Candidate #3: FollowPointers(0x00F5DAFC, new int[] { 0x608, 0x1B8, 0x0 })
            string preview_name = MemoryHelper.ReadStringFromMemory(rsProcessHandle, FollowPointers(0x00F5C494, new int[] { 0xBC, 0x0 }));

            //If there was string in memory
            if (preview_name != null)
            {
                //Verify Play_ prefix and _Preview suffix
                if (preview_name.StartsWith("Play_") && preview_name.EndsWith("_Preview"))
                {
                    //Remove Play_ prefix and _Preview suffix
                    string song_id = preview_name.Substring(5, preview_name.Length - 13);

                    //Assign to readout
                    readout.songID = song_id;
                }
            }

            // SONG TIMER
            //
            //Weird static address: FollowPointers(0x01567AB0, new int[]{ 0x80, 0x20, 0x10C, 0x244 })
            //Candidate #1: FollowPointers(0x00F5C5AC, new int[] { 0xB0, 0x538, 0x8 })
            //Candidate #2: FollowPointers(0x00F5C4CC, new int[] { 0x5F0, 0x538, 0x8 })
            ReadSongTimer(FollowPointers(0x00F5C5AC, new int[] { 0xB0, 0x538, 0x8 }));

            // ARRANGEMENT HASH
            //
            // This is set to the arrangement persistent id while playing a song
            string arrangement_hash = MemoryHelper.ReadStringFromMemory(rsProcessHandle, FollowPointers(0x00F5C5AC, new int[] { 0x18, 0x18, 0xC, 0x1C0, 0x0 }));

            if (arrangement_hash != null)
            {
                readout.arrangementID = arrangement_hash;
            }

            // GAME STATE
            //
            // This one popped up while looking for arrangement hash, seems to be a logical string representing the current game stage
            // Can be garbled under unknown circumstances
            // Exists in two (and probably more) locations, where only one may be valid, this tries to get either
            // Prioritizing the one at 0x27C, because it is more human readable
            string game_stage = MemoryHelper.ReadStringFromMemory(rsProcessHandle, FollowPointers(0x00F5C5AC, new int[] { 0x18, 0x18, 0xC, 0x27C }));

            if (game_stage == null)
            {
                game_stage = MemoryHelper.ReadStringFromMemory(rsProcessHandle, FollowPointers(0x00F5C5AC, new int[] { 0x18, 0x18, 0xC, 0x14 }));
            }

            //If we got a game stage
            if (game_stage != null)
            {
                //Verify that it is at least 4 characters long, to filter out more garbage
                if (game_stage.Length > 4)
                {
                    readout.gameStage = game_stage;
                }
            }

            // NOTE DATA
            //
            // For learn a song:
            //Candidate #1: FollowPointers(0x00F5C5AC, new int[] {0xB0, 0x18, 0x4, 0x84, 0x0})
            //Candidate #2: FollowPointers(0x00F5C4CC, new int[] {0x5F0, 0x18, 0x4, 0x84, 0x0})
            //
            // For score attack:
            //Candidate #1: FollowPointers(0x00F5C5AC, new int[] { 0xB0, 0x18, 0x4, 0x4C, 0x0 })
            //Candidate #2: FollowPointers(0x00F5C4CC, new int[] { 0x5F0, 0x18, 0x4, 0x4C, 0x0 })

            //If note data is not valid, try the next mode
            //Learn a song
            if (!ReadNoteData(FollowPointers(0x00F5C5AC, new int[] { 0xB0, 0x18, 0x4, 0x84, 0x0 })))
            {
                //Score attack
                if (!ReadScoreAttackNoteData(FollowPointers(0x00F5C5AC, new int[] { 0xB0, 0x18, 0x4, 0x4C, 0x0 })))
                {
                    readout.mode = RSMode.UNKNOWN;
                }
            }

            //Copy over everything when a song is running
            if (readout.songTimer > 0)
            {
                readout.CopyTo(ref prevReadout);
            }

            //Always copy over important fields
            prevReadout.songID    = readout.songID;
            prevReadout.gameStage = readout.gameStage;
            prevReadout.songTimer = readout.songTimer;

            return(prevReadout);
        }