rendered paste bodyusing 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,
}
}