All pastes #676586 Raw Edit

Someone

public text v1 · immutable
#676586 ·published 2007-08-31 06:15 UTC
rendered paste body
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

namespace WoWExtractor
{
    public static class UpdateFieldExtractor
    {
        private static string s_File;
        private static string s_Version;
        private static string s_Build;
        private static long s_stringStartOffset;
        private static long s_dataStartOffset;
        private static int s_fieldCount;

        static int m_objectStart;
        static int m_objectEnd;
        static int m_unitStart;
        static int m_unitEnd;
        static int m_playerStart;
        static int m_playerEnd;
        static int m_gameObjectStart;
        static int m_gameObjectEnd;
        static int m_itemStart;
        static int m_itemEnd;
        static int m_containerStart;
        static int m_containerEnd;
        static int m_corpseStart;
        static int m_corpseEnd;
        static int m_dynamicObjectStart;
        static int m_dynamicObjectEnd;        

        private static List<UpdateField> m_updateFieldList = new List<UpdateField>();

        public static bool Extract(string wowExeName, string outputFileName)
        {
            if (!File.Exists(wowExeName))
                return false;

            using (FileStream fs = new FileStream(wowExeName, FileMode.Open))
            {
                StreamReader sr = new StreamReader(fs, Encoding.ASCII);

                s_File = sr.ReadToEnd();

                FindStringOffset();
                FindDataOffset();

                using (BinaryReader br = new BinaryReader(fs))
                {
                    FindVersionInfo(br);
                    FillList(br);
                }

                FillStartAndEndValues();

                AdjustOffsets();

                WriteToFile(outputFileName);

                sr.Close();
            }

            WritePublicFields();

            return true;
        }

        static void WritePublicFields()
        {
            var query = from field in m_updateFieldList
                        where ((field.Flags & FieldFlag.Public) == FieldFlag.Public)
                        select field;

            foreach (var field in query)
            {
                Console.WriteLine("SetPublicField({0}, {1}); // {2}", field.Offset, field.Size, field.Name);
            }
        }

        static void FlagFinder(FieldFlag toSearch)
        {
            var query = from field in m_updateFieldList
                        where (field.Flags & toSearch) == toSearch
                        select field;

            Console.WriteLine("Flag: {0}", toSearch);
            foreach (var field in query)
            {
                Console.WriteLine(field.Name);
            }
        }

        private static void FindVersionInfo(BinaryReader binReader)
        {
            // Should be 3839016 for 2.1.3
            long startOffset = s_File.IndexOf("RELEASE_BUILD");

            if (startOffset > 0)
            {
                /*
                 * 6898....2.1.3...RELEASE_BUILD
                 * */
                binReader.BaseStream.Position = startOffset - 16;

                s_Build = binReader.ReadCString();
                binReader.BaseStream.Position += 3;
                s_Version = binReader.ReadCString();
            }
            else
            {
                s_Build = "NOTFOUND";
                s_Version = "NOTFOUND";
                Console.WriteLine("Version Info Not Found!");
            }
        }

        private static void FindStringOffset()
        {
            // Should be 3853356 for 2.1.3
            int index = s_File.IndexOf("OBJECT_FIELD_GUID");

            if (index > 0)
            {
                s_stringStartOffset = index;
            }
            else
            {
                Console.WriteLine("String Offset Not Found!");
            }
        }

        private static void FindDataOffset()
        {
            byte[] temp = new byte[16] { 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 };

            StringBuilder sb = new StringBuilder();
            foreach (byte b in temp)
            {
                sb.Append((char)b);
            }
            string toFind = sb.ToString();

            // Should be at 6896020 for 2.1.3
            int index = s_File.IndexOf(toFind);

            if (index > 0)
            {
                s_dataStartOffset = index - 4;
            }
            else
            {
                Console.WriteLine("Data Offset Not Found!");
            }
        }

        private static void FillList(BinaryReader binReader)
        {
            s_fieldCount = 0;

            long stringOffsetDelta = 0x400000;

            string previousField = String.Empty;
            string currentField;

            binReader.BaseStream.Position = s_dataStartOffset;

            while (true)
            {
                UpdateField field = new UpdateField();
                field.NameOffset = binReader.ReadUInt32();

                if (field.NameOffset < 0x9999)
                {
                    uint oldNameOffset = field.NameOffset;
                    field.NameOffset = binReader.ReadUInt32();
                }

                field.Offset = binReader.ReadUInt32();
                field.Size = binReader.ReadUInt32();
                field.Type = (FieldType)binReader.ReadUInt32();
                field.Flags = (FieldFlag)binReader.ReadUInt32();

                if (s_fieldCount == 0)
                    stringOffsetDelta = field.NameOffset - s_stringStartOffset;

                long stringOffset = field.NameOffset - stringOffsetDelta;

                long oldpos = binReader.BaseStream.Position;
                binReader.BaseStream.Position = stringOffset;
                currentField = binReader.ReadCString();
                binReader.BaseStream.Position = oldpos;

                StringBuilder sb = new StringBuilder();
                sb.AppendFormat("Size: {0} - ", field.Size);
                sb.AppendFormat("Type: {0} - ", field.Type);
                sb.AppendFormat("Flags: {0}", field.Flags);
                field.Description = sb.ToString();

                field.Name = currentField;

                m_updateFieldList.Add(field);

                s_fieldCount++;

                if (!previousField.Equals("CORPSE_FIELD_PAD") && currentField.Equals("CORPSE_FIELD_PAD"))
                    break;

                previousField = currentField;
            }            
        }

        private static void FillStartAndEndValues()
        {
            for (int i = 0; i < s_fieldCount; i++)
            {

                if (m_updateFieldList[i].Name.StartsWith("OBJECT"))
                {
                    // workaround for GameObjectFields first field being named OBJECT_FIELD_CREATED_BY
                    if (m_updateFieldList[i].Name == "OBJECT_FIELD_CREATED_BY")
                    {
                        m_gameObjectStart = i;
                        m_gameObjectEnd = m_gameObjectStart;
                        m_gameObjectEnd++;
                        continue;
                    }

                    if (m_updateFieldList[i].Offset == 0)
                    {
                        m_objectStart = i;
                        m_objectEnd = m_objectStart;
                    }
                    m_objectEnd++;
                }

                if (m_updateFieldList[i].Name.StartsWith("ITEM"))
                {
                    if (m_updateFieldList[i].Offset == 0)
                    {
                        m_itemStart = i;
                        m_itemEnd = m_itemStart;
                    }
                    m_itemEnd++;
                    continue;
                }

                if (m_updateFieldList[i].Name.StartsWith("CONTAINER"))
                {
                    if (m_updateFieldList[i].Offset == 0)
                    {
                        m_containerStart = i;
                        m_containerEnd = m_containerStart;
                    }
                    m_containerEnd++;
                    continue;
                }

                if (m_updateFieldList[i].Name.StartsWith("GAMEOBJECT"))
                {
                    // Dont need to check for first because first GameObject field is OBJECT_FIELD_CREATED_BY
                    m_gameObjectEnd++;
                    continue;
                }

                if (m_updateFieldList[i].Name.StartsWith("UNIT"))
                {
                    if (m_updateFieldList[i].Offset == 0)
                    {
                        m_unitStart = i;
                        m_unitEnd = m_unitStart;
                    }
                    m_unitEnd++;
                    continue;
                }

                if (m_updateFieldList[i].Name.StartsWith("PLAYER"))
                {
                    if (m_updateFieldList[i].Offset == 0)
                    {
                        m_playerStart = i;
                        m_playerEnd = m_playerStart;
                    }
                    m_playerEnd++;
                    continue;
                }

                if (m_updateFieldList[i].Name.StartsWith("CORPSE"))
                {
                    if (m_updateFieldList[i].Offset == 0)
                    {
                        m_corpseStart = i;
                        m_corpseEnd = m_corpseStart;
                    }
                    m_corpseEnd++;
                    continue;
                }

                if (m_updateFieldList[i].Name.StartsWith("DYNAMIC"))
                {
                    if (m_updateFieldList[i].Offset == 0)
                    {
                        m_dynamicObjectStart = i;
                        m_dynamicObjectEnd = m_dynamicObjectStart;
                    }
                    m_dynamicObjectEnd++;
                    continue;
                }
            }


        }

        private static void AdjustOffsets()
        {
            uint objectDelta = m_updateFieldList[m_objectEnd - 1].Offset + m_updateFieldList[m_objectEnd - 1].Size;
            uint unitDelta = m_updateFieldList[m_unitEnd - 1].Offset + m_updateFieldList[m_unitEnd - 1].Size;
            uint itemDelta = m_updateFieldList[m_itemEnd - 1].Offset + m_updateFieldList[m_unitEnd - 1].Size;

            UpdateField field;

            for (int i = m_unitStart; i < m_unitEnd; i++)
            {
                field = m_updateFieldList[i];
                field.Offset += objectDelta;
                m_updateFieldList[i] = field;
            }

            for (int i = m_playerStart; i < m_playerEnd; i++)
            {
                field = m_updateFieldList[i];
                field.Offset += objectDelta + unitDelta;
                m_updateFieldList[i] = field;
            }

            for (int i = m_itemStart; i < m_itemEnd; i++)
            {
                field = m_updateFieldList[i];
                field.Offset += objectDelta;
                m_updateFieldList[i] = field;
            }

            for (int i = m_containerStart; i < m_containerEnd; i++)
            {
                field = m_updateFieldList[i];
                field.Offset += objectDelta + itemDelta;
                m_updateFieldList[i] = field;
            }

            for (int i = m_dynamicObjectStart; i < m_dynamicObjectEnd; i++)
            {
                field = m_updateFieldList[i];
                field.Offset += objectDelta;
                m_updateFieldList[i] = field;
            }

            for (int i = m_gameObjectStart; i < m_gameObjectEnd; i++)
            {
                field = m_updateFieldList[i];
                field.Offset += objectDelta;
                m_updateFieldList[i] = field;
            }

            for (int i = m_corpseStart; i < m_corpseEnd; i++)
            {
                field = m_updateFieldList[i];
                field.Offset += objectDelta;
                m_updateFieldList[i] = field;
            }
        }

        private static void WriteToFile(string outputFile)
        {
            using (StreamWriter sw = new StreamWriter(outputFile))
            {
                
                UpdateField field;

                #region Header

                sw.WriteLine();
                sw.WriteLine("// UpdateFields Generated For Build {0}.{1}", s_Version, s_Build);
                sw.WriteLine();

                sw.WriteLine("namespace WCell.Core");
                sw.WriteLine("{");

                #endregion

                #region ObjectFields

                sw.WriteLine("\tpublic enum ObjectFields");
                sw.WriteLine("\t{");
                for (int i = m_objectStart; i < m_objectEnd; i++)
                {
                    field = m_updateFieldList[i];
                    sw.WriteLine("\t\t/// <summary>");
                    sw.WriteLine("\t\t/// {0}", field.Description);
                    sw.WriteLine("\t\t/// </summary>");
                    sw.WriteLine("\t\t{0} = {1},", field.Name, field.Offset);
                    if (i == m_objectEnd - 1)
                    {
                        sw.WriteLine("\t\tOBJECT_END = {0}", field.Offset + field.Size);
                    }

                }
                sw.WriteLine("\t}");
                sw.WriteLine();

                #endregion         

                #region UnitFields
                sw.WriteLine("\tpublic enum UnitFields");
                sw.WriteLine("\t{");
                for (int i = m_unitStart; i < m_unitEnd; i++)
                {
                    field = m_updateFieldList[i];

                    sw.WriteLine("\t\t/// <summary>");
                    sw.WriteLine("\t\t/// {0}", field.Description);
                    sw.WriteLine("\t\t/// </summary>");
                    sw.WriteLine("\t\t{0} = {1},", field.Name, field.Offset);
                    if (i == m_unitEnd - 1)
                    {
                        sw.WriteLine("\t\tUNIT_END = {0}", field.Offset + field.Size);
                        break;
                    }

                }
                sw.WriteLine("\t}");

                sw.WriteLine();
                #endregion

                #region PlayerFields

                sw.WriteLine("\tpublic enum PlayerFields");
                sw.WriteLine("\t{");
                for (int i = m_playerStart; i < m_playerEnd; i++)
                {
                    field = m_updateFieldList[i];

                    sw.WriteLine("\t\t/// <summary>");
                    sw.WriteLine("\t\t/// {0}", field.Description);
                    sw.WriteLine("\t\t/// </summary>");
                    sw.WriteLine("\t\t{0} = {1},", field.Name, field.Offset);
                    if (i == m_playerEnd - 1)
                    {
                        sw.WriteLine("\t\tPLAYER_END = {0}", field.Offset + field.Size);
                        break;
                    }
                }
                sw.WriteLine("}");

                sw.WriteLine();
                #endregion

                #region ItemFields
                sw.WriteLine("\tpublic enum ItemFields");
                sw.WriteLine("\t{");
                for (int i = m_itemStart; i < m_itemEnd; i++)
                {
                    field = m_updateFieldList[i];

                    sw.WriteLine("\t\t/// <summary>");
                    sw.WriteLine("\t\t/// {0}", field.Description);
                    sw.WriteLine("\t\t/// </summary>");
                    sw.WriteLine("\t\t{0} = {1},", field.Name, field.Offset);
                    if (i == m_itemEnd - 1)
                    {
                        sw.WriteLine("\t\tITEM_END = {0}", field.Offset + field.Size);
                        break;
                    }

                }
                sw.WriteLine("\t}");

                sw.WriteLine();
                #endregion

                #region ContainerFields

                sw.WriteLine("\tpublic enum ContainerFields");
                sw.WriteLine("\t{");
                for (int i = m_containerStart; i < m_containerEnd; i++)
                {
                    field = m_updateFieldList[i];

                    sw.WriteLine("\t\t/// <summary>");
                    sw.WriteLine("\t\t/// {0}", field.Description);
                    sw.WriteLine("\t\t/// </summary>");
                    sw.WriteLine("\t\t{0} = {1},", field.Name, field.Offset);
                    if (i == m_containerEnd - 1)
                    {
                        sw.WriteLine("\t\tCONTAINER_END = {0}", field.Offset + field.Size );
                        break;
                    }
                }
                sw.WriteLine("\t}");

                sw.WriteLine();
                #endregion

                #region DynamicObjectFields
                sw.WriteLine("\tpublic enum DynamicObjectFields");
                sw.WriteLine("\t{");
                for (int i = m_dynamicObjectStart; i < m_dynamicObjectEnd; i++)
                {
                    field = m_updateFieldList[i];

                    sw.WriteLine("\t\t/// <summary>");
                    sw.WriteLine("\t\t/// {0}", field.Description);
                    sw.WriteLine("\t\t/// </summary>");
                    sw.WriteLine("\t\t{0} = {1},", field.Name, field.Offset);
                    if (i == m_dynamicObjectEnd - 1)
                    {
                        sw.WriteLine("\t\tDYNAMICOBJECT_END = {0}", field.Offset + field.Size);
                        break;
                    }

                }
                sw.WriteLine("\t}");

                sw.WriteLine();
                #endregion

                #region GameObjectFields
                sw.WriteLine("\tpublic enum GameObjectFields");
                sw.WriteLine("\t{");
                for (int i = m_gameObjectStart; i < m_gameObjectEnd; i++)
                {
                    field = m_updateFieldList[i];

                    sw.WriteLine("\t\t/// <summary>");
                    sw.WriteLine("\t\t/// {0}", field.Description);
                    sw.WriteLine("\t\t/// </summary>");
                    sw.WriteLine("\t\t{0} = {1},", field.Name, field.Offset);
                    if (i == m_gameObjectEnd - 1)
                    {
                        sw.WriteLine("\t\tGAMEOBJECT_END = {0}", field.Offset + field.Size);
                        break;
                    }

                }
                sw.WriteLine("\t}");

                sw.WriteLine();
                #endregion

                #region CorpseFields
                sw.WriteLine("\tpublic enum CorpseFields");
                sw.WriteLine("\t{");
                for (int i = m_corpseStart; i < m_corpseEnd; i++)
                {
                    field = m_updateFieldList[i];

                    sw.WriteLine("\t\t/// <summary>");
                    sw.WriteLine("\t\t/// {0}", field.Description);
                    sw.WriteLine("\t\t/// </summary>");
                    sw.WriteLine("\t\t{0} = {1},", field.Name, field.Offset);
                    if (i == m_corpseEnd - 1)
                    {
                        sw.WriteLine("\t\tCORPSE_END = {0}", field.Offset + field.Size);
                        break;
                    }

                }
                sw.WriteLine("\t}");
                #endregion

                sw.WriteLine("}");
            }
        }
    }

    public struct UpdateField
    {
        public uint NameOffset;
        public uint Offset;
        public uint Size;
        public FieldType Type;
        public FieldFlag Flags;

        public string Name;
        public string Description;
    }

    [Flags]
    public enum FieldFlag
    {
        Public = 0x0001, // Public?
        Private = 0x0002, // Private?
        Flag0x0004 = 0x0004,
        /// <summary>
        /// Unused
        /// </summary>
        Flag0x0008 = 0x0008,
        /// <summary>
        /// ITEM_FIELD_STACK_COUNT
        /// ITEM_FIELD_DURATION
        /// ITEM_FIELD_SPELL_CHARGES
        /// ITEM_FIELD_DURABILITY
        /// ITEM_FIELD_MAXDURABILITY
        /// </summary>
        Flag0x0010 = 0x0010,
        /// <summary>
        /// UNIT_FIELD_MINDAMAGE
        /// UNIT_FIELD_MAXDAMAGE
        /// UNIT_FIELD_MINOFFHANDDAMAGE
        /// UNIT_FIELD_MAXOFFHANDDAMAGE
        /// UNIT_FIELD_RESISTANCES
        /// </summary>
        Flag0x0020 = 0x0020,
        /// <summary>
        /// Only seen in PLAYER_QUEST_LOG_X_1
        /// </summary>
        GroupOnly = 0x40,
        /// <summary>
        /// Unused
        /// </summary>
        Flag0x0080 = 0x0080,
        /// <summary>
        /// Mask?
        /// </summary>
        Flag0x0100 = 0x0100,
    }

    public enum FieldType
    {
        None,
        Int32,
        Unknown,
        Float,
        GUID,
        Bytes,
    }
}