Cruising the spell cache from memory menu

User Tag List

Results 1 to 6 of 6
  1. #1
    amadmonk's Avatar Active Member
    Reputation
    124
    Join Date
    Apr 2008
    Posts
    772
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Cruising the spell cache from memory

    Sorry for first post, lil problem with my marshalling (ooopsy). Here's working code.

    If folks can contribute to the layout of the SpellInfo struct, that would be very helpful.

    Code:
        [StructLayout(LayoutKind.Explicit, Size = (int)ObjectOffsets.DBSpellCache_BlockSize)]
        public class SpellInfo
        {
            [FieldOffset(0x238)]
            IntPtr _nameBytes;
    
            // note that I should decode these as UTF-8 since they're not technically ANSI, but that's a ton more work.  Why doesn't Marshal.PtrToString take a Text.Encoding object??
            public string Name
            {
                get
                {
                    return Marshal.PtrToStringAnsi(_nameBytes);
                }
            }
    
            [FieldOffset(0x23c)]
            public IntPtr _secondaryNameBytes;
    
            public string SecondaryName
            {
                get
                {
                    return Marshal.PtrToStringAnsi(_secondaryNameBytes);
                }
            }
    
            [UnmanagedFunctionPointer(CallingConvention.ThisCall)]
            delegate bool GetCachedSpellInfo(IntPtr spellCache, int spellID, IntPtr buffer);
            static GetCachedSpellInfo s_getCachedSpellInfo = null;
    
            public static SpellInfo GetSpellInfo(int spellID)
            {
                if (s_getCachedSpellInfo == null)
                {
                    s_getCachedSpellInfo = Utilities.RegisterDelegate<GetCachedSpellInfo>((IntPtr)GlobalOffsets.DBSpellCache_GetInfoBlockByID);
                }
    
                IntPtr DBSpellCache = (IntPtr)GlobalOffsets.DBSpellCache;
                IntPtr buffer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SpellInfo)));
                try
                {
                    if (s_getCachedSpellInfo(DBSpellCache, spellID, buffer))
                    {
                        return (SpellInfo)Marshal.PtrToStructure(buffer, typeof(SpellInfo));
                    }
                    else
                    {
                        return null;
                    }
                }
                finally
                {
                    Marshal.FreeHGlobal(buffer);
                }
            }
        }
    Relevant offsets:

    Code:
            CGSpell__CreateSpellLink = 0x005B4280, // 3.3.0 (RE: look for the spell link string (aSHspellDHSHS)
            DBSpellCache_GetInfoBlockByID = 0x00476630, // 3.3.0 (RE: second call in CGSpell__CreateSpellLink)
            DBSpellCache = 0x00A751FC, // 3.3.0 (RE: move ecx, [static] right before GetInfoBlockByID in CreateSpellLink above)
            DBSpellCache_BlockSize = 0x2c0, // see DBSpellCache_GetInfoBlockByID, the only call, 2nd param)
    Last edited by amadmonk; 12-08-2009 at 08:17 PM.
    Don't believe everything you think.

    Cruising the spell cache from memory
  2. #2
    Apoc's Avatar Angry Penguin
    Reputation
    1387
    Join Date
    Jan 2008
    Posts
    2,750
    Thanks G/R
    0/12
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by amadmonk View Post
    Sorry for first post, lil problem with my marshalling (ooopsy). Here's working code.

    If folks can contribute to the layout of the SpellInfo struct, that would be very helpful.

    Code:
        [StructLayout(LayoutKind.Explicit, Size = (int)ObjectOffsets.DBSpellCache_BlockSize)]
        public class SpellInfo
        {
            [FieldOffset(0x238)]
            IntPtr _nameBytes;
    
            // note that I should decode these as UTF-8 since they're not technically ANSI, but that's a ton more work.  Why doesn't Marshal.PtrToString take a Text.Encoding object??
            public string Name
            {
                get
                {
                    return Marshal.PtrToStringAnsi(_nameBytes);
                }
            }
    
            [FieldOffset(0x23c)]
            public IntPtr _secondaryNameBytes;
    
            public string SecondaryName
            {
                get
                {
                    return Marshal.PtrToStringAnsi(_secondaryNameBytes);
                }
            }
    
            [UnmanagedFunctionPointer(CallingConvention.ThisCall)]
            delegate bool GetCachedSpellInfo(IntPtr spellCache, int spellID, IntPtr buffer);
            static GetCachedSpellInfo s_getCachedSpellInfo = null;
    
            public static SpellInfo GetSpellInfo(int spellID)
            {
                if (s_getCachedSpellInfo == null)
                {
                    s_getCachedSpellInfo = Utilities.RegisterDelegate<GetCachedSpellInfo>((IntPtr)GlobalOffsets.DBSpellCache_GetInfoBlockByID);
                }
    
                IntPtr DBSpellCache = (IntPtr)GlobalOffsets.DBSpellCache;
                IntPtr buffer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SpellInfo)));
                try
                {
                    if (s_getCachedSpellInfo(DBSpellCache, spellID, buffer))
                    {
                        return (SpellInfo)Marshal.PtrToStructure(buffer, typeof(SpellInfo));
                    }
                    else
                    {
                        return null;
                    }
                }
                finally
                {
                    Marshal.FreeHGlobal(buffer);
                }
            }
        }
    Relevant offsets:

    Code:
            CGSpell__CreateSpellLink = 0x005B4280, // 3.3.0 (RE: look for the spell link string (aSHspellDHSHS)
            DBSpellCache_GetInfoBlockByID = 0x00476630, // 3.3.0 (RE: second call in CGSpell__CreateSpellLink)
            DBSpellCache = 0x00A751FC, // 3.3.0 (RE: move ecx, [static] right before GetInfoBlockByID in CreateSpellLink above)
            DBSpellCache_BlockSize = 0x2c0, // see DBSpellCache_GetInfoBlockByID, the only call, 2nd param)
    Edit; I just noticed. That's not the cache. That's the DBC stuff.

    Lol.

    You're actually calling ClientDb_GetLocalizedRow and passing the [pSpellDbc-0x18] pointer to it.

    I think I posted DBC stuff before; if not; I'll post it in elite.

  3. #3
    amadmonk's Avatar Active Member
    Reputation
    124
    Join Date
    Apr 2008
    Posts
    772
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by Apoc View Post
    Edit; I just noticed. That's not the cache. That's the DBC stuff.

    Lol.

    You're actually calling ClientDb_GetLocalizedRow and passing the [pSpellDbc-0x18] pointer to it.

    I think I posted DBC stuff before; if not; I'll post it in elite.
    Erm, yeah, naming mismatch there. I'll use the search for the DBC info.

    Cache is just for net-dynamic stuff (player names, etc.), right? As you can tell, I've gone a long time without needing to touch anything in the MPQ's...
    Don't believe everything you think.

  4. #4
    Apoc's Avatar Angry Penguin
    Reputation
    1387
    Join Date
    Jan 2008
    Posts
    2,750
    Thanks G/R
    0/12
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by amadmonk View Post
    Erm, yeah, naming mismatch there. I'll use the search for the DBC info.

    Cache is just for net-dynamic stuff (player names, etc.), right? As you can tell, I've gone a long time without needing to touch anything in the MPQ's...
    Yes; cache is for net-dynamic stuff.

    You're looking at the Spell.dbc, which needs to be 'localized' in WoW. (It's the only one with that treatment as far as I can tell)

    I'll post my current stuff in elite so you can get a head start.

  5. #5
    amadmonk's Avatar Active Member
    Reputation
    124
    Join Date
    Apr 2008
    Posts
    772
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Cool, thanks. Feel free to lock this if it's a dupe. If I'd have scanned the info thread for my "newly discovered" offset at 0x00476630, I could have saved myself some time...
    Don't believe everything you think.

  6. #6
    Apoc's Avatar Angry Penguin
    Reputation
    1387
    Join Date
    Jan 2008
    Posts
    2,750
    Thanks G/R
    0/12
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Posted it in elite; I'll leave this thread open for people who want to figure it out for themselves.

Similar Threads

  1. [C#] Read the angle a player is facing from memory
    By wowhackz0r in forum WoW Memory Editing
    Replies: 35
    Last Post: 01-01-2010, 11:27 AM
  2. Remove no-cache from the headers.
    By Apoc in forum Suggestions
    Replies: 18
    Last Post: 08-28-2008, 05:19 PM
  3. Death Knight spell footage from the alpha!
    By Patchumz in forum World of Warcraft General
    Replies: 5
    Last Post: 05-23-2008, 04:44 PM
  4. All the spells from the PTR
    By Fishy80 in forum World of Warcraft Model Editing
    Replies: 0
    Last Post: 04-20-2007, 02:32 PM
  5. WOW the gold standard (FROM RED GUIDES)
    By Elites360 in forum World of Warcraft Guides
    Replies: 4
    Last Post: 10-24-2006, 12:50 PM
All times are GMT -5. The time now is 05:46 PM. Powered by vBulletin® Version 4.2.3
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved. User Alert System provided by Advanced User Tagging (Pro) - vBulletin Mods & Addons Copyright © 2024 DragonByte Technologies Ltd.
Digital Point modules: Sphinx-based search