using System; using System.Collections.Generic; using System.Text; using System.Collections; using System.Threading; using System.IO; using System.Runtime.Serialization.Formatters.Binary; using System.Runtime.Serialization; using System.Data; // Work work using Grunt.Library; using Warcraft = Grunt.Library.Warcraft; namespace Grunt.UI { /// /// Best class in the world :-) /// class Program { /// /// Private variables /// private static Warcraft war; private static Hashtable objsById; private static Hashtable untsById; private static Hashtable itemsById; private static Random rnd; /// /// Private constants /// /// /// Used for parsing the /Data/"obj.Type" file /// private const string START = "#START"; // Object start private const string END = "#END"; // Object end private const string CUSTOM_START = "#CUSTOM_START"; private const string CUSTOM_END = "#CUSTOM_END"; private const string GUID = "OBJECT_FIELD_GUID"; // Object guid private static int fileCount; public static Hashtable dbc; /// /// Application Entry /// /// static void Main(string[] args) { Console.Title = "World of Warcraft - 47 72 75 6E 74"; #region Introduction Spam Console.WriteLine(@" _______ ______ _______ _______ _______ | __| __ | | | | |_ _| \___/ | | | < | | | | | cO Oc |_______|___|__|_______|__|____| |___| Moo |_| For World of Warcraft 1.10.2 /valvet"); Console.WriteLine(""); Console.WriteLine(" 00827024 47 52 55 4E 54 5F 48 45 GRUNT_HE\n" + " 0082702C 4C 4C 4F LLO\n"); Console.WriteLine(" Please minimize me after starting, in order to reduce memory usage."); Console.WriteLine(" Starting up..\n"); #endregion // End spam rnd = new Random(); war = new Warcraft(); war.Interval = 125; war.ThreadPriority = ThreadPriority.Normal; Console.WriteLine(" Creating Hashtable."); objsById = new Hashtable(); untsById = new Hashtable(); itemsById = new Hashtable(); DateTime startTime = DateTime.Now; Console.WriteLine(" Parsing files. This might take a while."); string[] dirs = Directory.GetDirectories(@"./Data/"); if (dirs.Length > 0) { Console.WriteLine(" Scanning for Object files in {0} directorie(s).", dirs.Length); foreach (string dir in dirs) { GetDirectories(dir); } TimeSpan resultTime = DateTime.Now - startTime; Console.WriteLine(" Done. Parsed {0} files in {1} sec(s).\n", fileCount, resultTime.TotalSeconds); } try { Console.WriteLine(" Creating new instance of Warcraft object."); if (war.Start()) { Console.WriteLine(" Launching update event.\n"); war.OnUpdateEvent += new WarcraftUpdateEvent(GruntUpdateEvent); Console.WriteLine(" Started. Have a safe journey!\n"); } else { Console.WriteLine(" Unable to start. Please check /Logs/Warcraft.log."); } } catch (Exception E) { Console.WriteLine("\n -- Cut here --"); Console.WriteLine(" Caught exception.\n Please report the following to the developers: "); Console.WriteLine(" Source: {0}", E.Source); Console.WriteLine(" Message: {0}", E.Message); Console.WriteLine(" StrackTrace: {0}", E.StackTrace); Console.WriteLine(" -- Cut here --\n"); } GC.Collect(); // Main thread will exit } #region Parser Specific Functions /// /// Gets all the directories at the specified path /// /// Path to look in private static void GetDirectories(string path) { string[] dirs = Directory.GetDirectories(path); if (dirs.Length > 0) { foreach (string subDir in dirs) { GetDirectories(subDir); } } string[] files = Directory.GetFiles(path); if (files.Length > 0) { foreach (string fileName in files) { FileInfo fileInfo = new FileInfo(fileName); Console.WriteLine(" Parsing file: {0}, size: {1} bytes.", fileName, fileInfo.Length); ParseFile(fileName); fileCount++; } } } /// /// Parses specified file and adds them to the our collection /// /// File to parse private static void ParseFile(string fileName) { bool active = false; StreamReader sr = new StreamReader(fileName); string line; while ((line = sr.ReadLine()) != null) { if (line.StartsWith(START)) { active = true; } else if (line.StartsWith(END)) { active = false; } else { if (active) { int ispace = line.IndexOf(" "); line = line.Insert(ispace, ":"); string[] parts = line.Split(":".ToCharArray()); string key = parts[0].Trim(); string val = parts[1].Trim(); if (key.StartsWith(GUID)) { if (!objsById.Contains(long.Parse(val))) objsById.Add(long.Parse(val), "invalid"); } else { //Console.WriteLine(" Unrecognized line " + line); } } } } sr.Close(); } #endregion /// /// Our callback event for the WarcraftUpdateEvent in the library /// /// /// This will update every 125 ms by default. You can change the interval /// by modifying war.Interval = integer; -- Don't set too high! /// /// Warcraft object private static void GruntUpdateEvent(Warcraft sender) { foreach (War_Object obj in war.Objects.Values) { if (!obj.IsValid) return; switch (obj.Type) { case War_ObjectType.Object: { // TODO break; } case War_ObjectType.Item: { if (!itemsById.Contains(obj.ReadStorageInt(0xC))) { //Console.WriteLine(" Item Name: {0}", obj.Name); itemsById.Add(obj.ReadStorageInt(0xC), obj); ObjectToFile(obj); } break; } case War_ObjectType.Container: { // TODO break; } case War_ObjectType.Unit: { /* if (!untsById.Contains(obj.ReadStorageInt(0x0))) { Console.WriteLine(" Unit Name: {0}", obj.Name); Console.WriteLine(" Unit BasePtr: {0}", obj.BasePtr); untsById.Add(obj.ReadStorageInt(0x0), obj); ObjectToFile(obj); } addUnit(obj); */ //ds.Tables["Units"].WriteXml(@"./XmlData/dsUnitsObjects.xml"); break; } case War_ObjectType.Player: { // TODO break; } case War_ObjectType.AIGroup: { Console.WriteLine("Hello AIGroup."); break; } case War_ObjectType.Areatrigger: { Console.WriteLine("Hello Areatrigger."); break; } case War_ObjectType.GameObject: { // Name was blank, try again later. if (obj.Name.Length < 1) return; if (obj.Name == "Duel Flag") return; // We don't want duel flags // TODO: Do some more checking of bogus objects // like Traps and such. if (!objsById.Contains(obj.GUID.Full)) { Console.WriteLine("Name {0} Type: {1}({2})", obj.Name, (War_GameObjectType)obj.ReadStorageInt(war.Descriptors[obj.Type, "GAMEOBJECT_TYPE_ID"]), obj.ReadStorageInt(war.Descriptors[obj.Type, "GAMEOBJECT_TYPE_ID"])); //Console.WriteLine(" GO Name: {0}", obj.Name); //Console.WriteLine(" GO BasePtr: {0}", obj.BasePtr); objsById.Add(obj.GUID.Full, obj); //ObjectToFile(obj); //Console.WriteLine("Name {0}, padding(id?): {1}, bob: {2}, flags: {3}", obj.Name, obj.ReadStorageInt(0x14), obj.ReadStorageInt(0xE8), obj.ReadStorageInt(0x24)); } break; } case War_ObjectType.Dynamic: { // TODO break; } case War_ObjectType.Corpse: { // TODO break; } default: { Console.WriteLine("\n -- Cut here --"); Console.WriteLine(" Strange.. Unknown Object type returned.\n Please report the following to the developers:"); Console.WriteLine(" Returned Object Type: {0}.", obj.Type); Console.WriteLine(" -- Cut here --\n"); break; } } } // Let's try and sleep a little.. maybe that'll fix the // name returning blank sometimes on objects. Thread.Sleep(1000 + rnd.Next(500)); } /// /// Writes all descriptor fields to a file /// /// War_Object object /// /// We need to check all the ReadStorage functions that they're /// being used correctly. Eg. ReadStorageInt where the return value is /// integer, Long where it's long and so forth. /// private static void ObjectToFile(War_Object obj) { if (!Directory.Exists(@"./Data/" + obj.Type)) Directory.CreateDirectory(@"./Data/" + obj.Type); using (StreamWriter sw = new StreamWriter(@"./Data/" + obj.Type + "/" + obj.Name, true)) { sw.WriteLine("#START"); // Object start sw.WriteLine("OBJECT_FIELD_GUID {0}", obj.ReadStorageLong(0x0)); sw.WriteLine("OBJECT_FIELD_GUID+1 {0}", obj.ReadStorageLong(0x4)); sw.WriteLine("#START_CUSTOM"); // Start custom descriptors sw.WriteLine("OBJECT_FIELD_NAME {0}", obj.Name); // Custom sw.WriteLine("GAMEOBJECT_CONTINENT {0}", obj.Continent); // Custom sw.WriteLine("GAMEOBJECT_CREATED_BY_NAME {0}", obj.CreatedByName); // Custom sw.WriteLine("OBJECT_FIELD_GUID_FULL {0}", obj.GUID.Full); // Custom sw.WriteLine("OBJECT_FIELD_GUID_HIGH {0}", obj.GUID.High); // Custom sw.WriteLine("OBJECT_FIELD_GUID_LOW {0}", obj.GUID.Low); // Custom sw.WriteLine("GAMEOBJECT_SOUND {0}", obj.Sound0); // Custom sw.WriteLine("GAMEOBJECT_SOUND+1 {0}", obj.Sound1); // Custom sw.WriteLine("GAMEOBJECT_SOUND+2 {0}", obj.Sound2); // Custom sw.WriteLine("GAMEOBJECT_SOUND+3 {0}", obj.Sound3); // Custom sw.WriteLine("GAMEOBJECT_SOUND+4 {0}", obj.Sound4); // Custom sw.WriteLine("GAMEOBJECT_SOUND+5 {0}", obj.Sound5); // Custom sw.WriteLine("GAMEOBJECT_SOUND+6 {0}", obj.Sound6); // Custom sw.WriteLine("GAMEOBJECT_SOUND+7 {0}", obj.Sound7); // Custom sw.WriteLine("GAMEOBJECT_SOUND+8 {0}", obj.Sound8); // Custom sw.WriteLine("GAMEOBJECT_SOUND+9 {0}", obj.Sound9); // Custom sw.WriteLine("#END_CUSTOM"); // End custom descriptors sw.WriteLine("OBJECT_FIELD_TYPE {0}", obj.ReadStorageInt(0x8)); sw.WriteLine("OBJECT_FIELD_ENTRY {0}", obj.ReadStorageInt(0xC)); sw.WriteLine("OBJECT_FIELD_SCALE_X {0}", obj.ReadStorageFloat(0x10)); sw.WriteLine("OBJECT_FIELD_PADDING {0}", obj.ReadStorageFloat(0x14)); // TODO: Figure out how this workes // Perhaps the first or second is GUID of the creator. sw.WriteLine("OBJECT_FIELD_CREATED_BY {0}", obj.ReadStorageLong(0x18)); sw.WriteLine("OBJECT_FIELD_CREATED_BY+1 {0}", obj.ReadStorageLong(0x1C)); sw.WriteLine("GAMEOBJECT_DISPLAYID {0}", obj.ReadStorageInt(0x20)); sw.WriteLine("GAMEOBJECT_FLAGS {0}", obj.ReadStorageInt(0x24)); sw.WriteLine("GAMEOBJECT_ROTATION {0}", obj.ReadStorageFloat(0x28)); sw.WriteLine("GAMEOBJECT_ROTATION+1 {0}", obj.ReadStorageFloat(0x2C)); sw.WriteLine("GAMEOBJECT_ROTATION+2 {0}", obj.ReadStorageFloat(0x30)); sw.WriteLine("GAMEOBJECT_ROTATION+3 {0}", obj.ReadStorageFloat(0x34)); // 0x34 sw.WriteLine("GAMEOBJECT_STATE {0}", obj.ReadStorageInt(0x38)); // TODO: Figure out how to calculate to real DateTime sw.WriteLine("GAMEOBJECT_TIMESTAMP {0}", obj.ReadStorageLong(0x3C)); sw.WriteLine("GAMEOBJECT_POS_X {0}", obj.ReadStorageFloat(0x40)); sw.WriteLine("GAMEOBJECT_POS_Y {0}", obj.ReadStorageFloat(0x44)); sw.WriteLine("GAMEOBJECT_POS_Z {0}", obj.ReadStorageFloat(0x48)); sw.WriteLine("GAMEOBJECT_FACING {0}", obj.ReadStorageFloat(0x4C)); sw.WriteLine("GAMEOBJECT_DYN_FLAGS {0}", obj.ReadStorageInt(0x50)); sw.WriteLine("GAMEOBJECT_FACTION {0}", obj.ReadStorageInt(0x54)); sw.WriteLine("GAMEOBJECT_TYPE_ID {0}", obj.ReadStorageInt(0x58)); sw.WriteLine("GAMEOBJECT_LEVEL {0}", obj.ReadStorageInt(0x5C)); sw.WriteLine("#END"); // Object end sw.WriteLine(""); } } /// /// Class destructor /// ~Program() { objsById = null; GC.Collect(); } } }