private static Dictionary <string, Dictionary <string, string> > ReadCreatureEntries(BinaryReader bin, wdbCache wdb)
        {
            var entries = new Dictionary <string, Dictionary <string, string> >();

            if (wdb.buildInfo.expansion == 2)
            {
                Console.WriteLine("Classic creature cache, skipping..");
                return(entries);
            }

            while (bin.BaseStream.Position < bin.BaseStream.Length)
            {
                var id     = bin.ReadUInt32().ToString();
                var length = bin.ReadUInt32();

                if (length == 0)
                {
                    break;
                }

                entries.Add(id, new Dictionary <string, string>());

                var ds = new DataStore(bin);

                var TitleLength      = ds.GetIntByBits(11);
                var TitleAltLength   = ds.GetIntByBits(11);
                var CursorNameLength = ds.GetIntByBits(6);
                var Leader           = ds.GetBool();
                var Name0Length      = ds.GetIntByBits(11);
                var NameAlt0Length   = ds.GetIntByBits(11);
                var Name1Length      = ds.GetIntByBits(11);
                var NameAlt1Length   = ds.GetIntByBits(11);
                var Name2Length      = ds.GetIntByBits(11);
                var NameAlt2Length   = ds.GetIntByBits(11);
                var Name3Length      = ds.GetIntByBits(11);
                var NameAlt3Length   = ds.GetIntByBits(11);

                entries[id].Add("Name[0]", ds.GetString(Name0Length).Trim('\0'));
                entries[id].Add("NameAlt[0]", ds.GetString(NameAlt0Length).Trim('\0'));
                entries[id].Add("Name[1]", ds.GetString(Name1Length).Trim('\0'));
                entries[id].Add("NameAlt[1]", ds.GetString(NameAlt1Length).Trim('\0'));
                entries[id].Add("Name[2]", ds.GetString(Name2Length).Trim('\0'));
                entries[id].Add("NameAlt[2]", ds.GetString(NameAlt2Length).Trim('\0'));
                entries[id].Add("Name[3]", ds.GetString(Name3Length).Trim('\0'));
                entries[id].Add("NameAlt[3]", ds.GetString(NameAlt3Length).Trim('\0'));

                entries[id].Add("Flags[0]", bin.ReadUInt32().ToString());
                entries[id].Add("Flags[1]", bin.ReadUInt32().ToString());

                entries[id].Add("CreatureType", bin.ReadUInt32().ToString());
                entries[id].Add("CreatureFamily", bin.ReadUInt32().ToString());
                entries[id].Add("Classification", bin.ReadUInt32().ToString());
                entries[id].Add("ProxyCreatureID[0]", bin.ReadUInt32().ToString());
                entries[id].Add("ProxyCreatureID[1]", bin.ReadUInt32().ToString());

                var numCreatureDisplays = bin.ReadUInt32();
                entries[id].Add("NumCreatureDisplays", numCreatureDisplays.ToString());
                entries[id].Add("TotalProbability", bin.ReadSingle().ToString());

                for (var i = 0; i < numCreatureDisplays; i++)
                {
                    entries[id].Add("CreatureDisplayInfoID[" + i + "]", bin.ReadUInt32().ToString());
                    entries[id].Add("CreatureScale[" + i + "]", bin.ReadSingle().ToString());
                    entries[id].Add("CreatureProbability[" + i + "]", bin.ReadSingle().ToString());
                }

                entries[id].Add("HPMultiplier", bin.ReadSingle().ToString());
                entries[id].Add("EnergyMultiplier", bin.ReadSingle().ToString());

                var numQuestItems = bin.ReadUInt32();
                entries[id].Add("NumQuestItems", numQuestItems.ToString());

                entries[id].Add("CreatureMovementInfoID", bin.ReadInt32().ToString());
                entries[id].Add("RequiredExpansion", bin.ReadUInt32().ToString());
                entries[id].Add("TrackingQuestID", bin.ReadUInt32().ToString());
                entries[id].Add("VignetteID", bin.ReadUInt32().ToString());
                entries[id].Add("CreatureClassMask", bin.ReadUInt32().ToString());

                if (wdb.buildInfo.expansion >= 9 && wdb.buildInfo.major >= 1)
                {
                    entries[id].Add("CreatureDifficultyID", bin.ReadUInt32().ToString());
                }

                entries[id].Add("UIWidgetParentSetID", bin.ReadUInt32().ToString());

                if (wdb.buildInfo.expansion >= 9)
                {
                    entries[id].Add("UIWidgetSetUnitConditionID", bin.ReadUInt32().ToString());
                }

                if (wdb.buildInfo.expansion == 8 && wdb.clientBuild >= 34769)
                {
                    entries[id].Add("BfA_Int_1", bin.ReadUInt32().ToString());
                    entries[id].Add("BfA_Int_2", bin.ReadUInt32().ToString());
                }

                entries[id].Add("Title", ds.GetString(TitleLength).Trim('\0'));
                entries[id].Add("TitleAlt", ds.GetString(TitleAltLength).Trim('\0'));

                if (CursorNameLength != 1)
                {
                    entries[id].Add("CursorName", ds.GetString(CursorNameLength).Trim('\0'));
                }

                for (var i = 0; i < numQuestItems; i++)
                {
                    entries[id].Add("QuestItemID[" + i + "]", bin.ReadUInt32().ToString());
                }
            }

            return(entries);
        }
        private static Dictionary <string, Dictionary <string, string> > ReadQuestEntries(BinaryReader bin, wdbCache wdb)
        {
            var entries = new Dictionary <string, Dictionary <string, string> >();

            while (bin.BaseStream.Position < bin.BaseStream.Length)
            {
                var id     = bin.ReadUInt32().ToString();
                var length = bin.ReadUInt32();

                if (length == 0)
                {
                    break;
                }

                entries.Add(id, new Dictionary <string, string>());
                entries[id].Add("QuestID", bin.ReadUInt32().ToString());
                entries[id].Add("QuestType", bin.ReadUInt32().ToString());

                if (wdb.recordVersion <= 12 && wdb.buildInfo.expansion < 9)
                {
                    // Removed in 9.0.1.33978 - without a RecordVersion change
                    entries[id].Add("QuestLevel", bin.ReadUInt32().ToString());
                }

                if (wdb.recordVersion <= 12 && wdb.buildInfo.expansion < 9)
                {
                    // Removed in 9.0.1.33978 - without a RecordVersion change
                    entries[id].Add("QuestMaxScalingLevel", bin.ReadUInt32().ToString());
                }

                entries[id].Add("QuestPackageID", bin.ReadUInt32().ToString());

                if (wdb.recordVersion >= 11)
                {
                    entries[id].Add("ContentTuningID", bin.ReadUInt32().ToString());
                }

                if (wdb.recordVersion <= 12 && wdb.buildInfo.expansion < 9)
                {
                    // Removed in 9.0.1.33978 - without a RecordVersion change
                    entries[id].Add("QuestMinLevel", bin.ReadUInt32().ToString());
                }

                // If negative, index into QuestSortID, if positive index into AreaTable
                var questSortOrAreaTableID = bin.ReadInt32();
                if (questSortOrAreaTableID < 0)
                {
                    entries[id].Add("QuestSortID", Math.Abs(questSortOrAreaTableID).ToString());
                }
                else
                {
                    entries[id].Add("AreaTableID", questSortOrAreaTableID.ToString());
                }

                entries[id].Add("QuestInfoID", bin.ReadUInt32().ToString());
                entries[id].Add("SuggestedGroupNum", bin.ReadUInt32().ToString());
                entries[id].Add("RewardNextQuest", bin.ReadUInt32().ToString());
                entries[id].Add("RewardXPDifficulty", bin.ReadUInt32().ToString());
                entries[id].Add("RewardXPMultiplier", bin.ReadSingle().ToString());
                entries[id].Add("RewardMoney", bin.ReadUInt32().ToString());
                entries[id].Add("RewardMoneyDifficulty", bin.ReadUInt32().ToString());
                entries[id].Add("RewardMoneyMultiplier", bin.ReadSingle().ToString());
                entries[id].Add("RewardBonusMoney", bin.ReadUInt32().ToString());

                uint rewardDisplaySpellCount = 0;
                if (wdb.clientBuild >= 35078 && wdb.buildInfo.expansion >= 9)
                {
                    rewardDisplaySpellCount = bin.ReadUInt32();
                    entries[id].Add("RewardDisplaySpellCount", rewardDisplaySpellCount.ToString());
                }
                else
                {
                    for (var i = 0; i < 3; i++)
                    {
                        entries[id].Add("RewardDisplaySpell[" + i + "]", bin.ReadUInt32().ToString());
                    }
                }

                entries[id].Add("RewardSpell", bin.ReadUInt32().ToString());
                entries[id].Add("RewardHonorAddition", bin.ReadUInt32().ToString());
                entries[id].Add("RewardHonorMultiplier", bin.ReadSingle().ToString());
                entries[id].Add("RewardArtifactXPDifficulty", bin.ReadUInt32().ToString());
                entries[id].Add("RewardArtifactXPMultiplier", bin.ReadSingle().ToString());
                entries[id].Add("RewardArtifactCategoryID", bin.ReadUInt32().ToString());
                entries[id].Add("ProvidedItem", bin.ReadUInt32().ToString());

                for (var i = 0; i < 3; i++)
                {
                    entries[id].Add("Flags[" + i + "]", bin.ReadUInt32().ToString());
                }

                for (var i = 0; i < 4; i++)
                {
                    entries[id].Add("RewardFixedItemID[" + i + "]", bin.ReadUInt32().ToString());
                    entries[id].Add("RewardFixedItemQuantity[" + i + "]", bin.ReadUInt32().ToString());
                }

                for (var i = 0; i < 4; i++)
                {
                    entries[id].Add("ItemDropItemID[" + i + "]", bin.ReadUInt32().ToString());
                    entries[id].Add("ItemDropItemQuantity[" + i + "]", bin.ReadUInt32().ToString());
                }

                for (var i = 0; i < 6; i++)
                {
                    entries[id].Add("RewardChoiceItemItemID[" + i + "]", bin.ReadUInt32().ToString());
                    entries[id].Add("RewardChoiceItemItemQuantity[" + i + "]", bin.ReadUInt32().ToString());
                    entries[id].Add("RewardChoiceItemItemDisplayID[" + i + "]", bin.ReadUInt32().ToString());
                }

                entries[id].Add("POIContinent", bin.ReadUInt32().ToString());
                entries[id].Add("POIx", bin.ReadSingle().ToString());
                entries[id].Add("POIy", bin.ReadSingle().ToString());
                entries[id].Add("POIPriority", bin.ReadUInt32().ToString());
                entries[id].Add("RewardTitle", bin.ReadUInt32().ToString());
                entries[id].Add("RewardArenaPoints", bin.ReadUInt32().ToString());
                entries[id].Add("RewardSkillLineID", bin.ReadUInt32().ToString());
                entries[id].Add("RewardNumSkillUps", bin.ReadUInt32().ToString());
                entries[id].Add("PortraitGiverDisplayID", bin.ReadUInt32().ToString());
                entries[id].Add("PortraitGiverMountDisplayID", bin.ReadUInt32().ToString());

                // Might be a few fields off, so many 0s
                if (wdb.buildInfo.expansion >= 9 && wdb.buildInfo.major >= 1)
                {
                    entries[id].Add("PortraitModelSceneID", bin.ReadUInt32().ToString());
                }

                // Might be one or two fields off
                entries[id].Add("PortraitTurnInDisplayID", bin.ReadUInt32().ToString());

                for (var i = 0; i < 5; i++)
                {
                    entries[id].Add("FactionID[" + i + "]", bin.ReadUInt32().ToString());
                    entries[id].Add("FactionValue[" + i + "]", bin.ReadUInt32().ToString());
                    entries[id].Add("FactionOverride[" + i + "]", bin.ReadUInt32().ToString());
                    entries[id].Add("FactionGainMaxRank[" + i + "]", bin.ReadUInt32().ToString());
                }

                entries[id].Add("RewardFactionFlags", bin.ReadUInt32().ToString());

                for (var i = 0; i < 4; i++)
                {
                    entries[id].Add("RewardCurrencyID[" + i + "]", bin.ReadUInt32().ToString());
                    entries[id].Add("RewardCurrencyQuantity[" + i + "]", bin.ReadUInt32().ToString());
                }

                entries[id].Add("AcceptedSoundKitID", bin.ReadUInt32().ToString());
                entries[id].Add("CompleteSoundKitID", bin.ReadUInt32().ToString());
                entries[id].Add("AreaGroupID", bin.ReadUInt32().ToString());
                entries[id].Add("TimeAllowed", bin.ReadUInt32().ToString());

                var numObjectives = bin.ReadUInt32();
                entries[id].Add("NumObjectives", numObjectives.ToString());
                entries[id].Add("RaceFlags", bin.ReadUInt64().ToString());
                entries[id].Add("QuestRewardID", bin.ReadUInt32().ToString());
                entries[id].Add("ExpansionID", bin.ReadUInt32().ToString());

                if (wdb.recordVersion > 11)
                {
                    entries[id].Add("ManagedWorldStateID", bin.ReadUInt32().ToString());
                    entries[id].Add("QuestSessionBonus", bin.ReadUInt32().ToString());
                }

                if (wdb.clientBuild >= 35078 && wdb.buildInfo.expansion >= 9)
                {
                    for (var i = 0; i < rewardDisplaySpellCount; i++)
                    {
                        entries[id].Add("RewardDisplaySpellID[" + i + "]", bin.ReadUInt32().ToString());
                        entries[id].Add("RewardDisplayPlayerConditionID[" + i + "]", bin.ReadUInt32().ToString());
                    }
                }

                var ds = new DataStore(bin);

                var LogTitleLength           = ds.GetIntByBits(9);
                var LogDescriptionLength     = ds.GetIntByBits(12);
                var QuestDescriptionLength   = ds.GetIntByBits(12);
                var AreaDescriptionLength    = ds.GetIntByBits(9);
                var PortraitGiverTextLength  = ds.GetIntByBits(10);
                var PortraitGiverNameLength  = ds.GetIntByBits(8);
                var PortraitTurnInTextLength = ds.GetIntByBits(10);
                var PortraitTurnInNameLength = ds.GetIntByBits(8);
                var QuestCompletionLogLength = ds.GetIntByBits(11);

                for (var i = 0; i < numObjectives; i++)
                {
                    entries[id].Add("ObjectiveID[" + i + "]", bin.ReadUInt32().ToString());
                    entries[id].Add("ObjectiveType[" + i + "]", bin.ReadByte().ToString());
                    entries[id].Add("ObjectiveStorageIndex[" + i + "]", bin.ReadByte().ToString());
                    entries[id].Add("ObjectiveObjectID[" + i + "]", bin.ReadUInt32().ToString());
                    entries[id].Add("ObjectiveAmount[" + i + "]", bin.ReadUInt32().ToString());
                    entries[id].Add("ObjectiveFlags[" + i + "]", bin.ReadUInt32().ToString());
                    entries[id].Add("ObjectiveFlags2[" + i + "]", bin.ReadUInt32().ToString());
                    entries[id].Add("ObjectivePercentAmount[" + i + "]", bin.ReadSingle().ToString());

                    var numVisualEffects = bin.ReadUInt32();
                    entries[id].Add("ObjectiveNumVisualEffects[" + i + "]", numVisualEffects.ToString());

                    for (var j = 0; j < numVisualEffects; j++)
                    {
                        entries[id].Add("ObjectiveVisualEffects[" + i + "][" + j + "]", bin.ReadUInt32().ToString());
                    }

                    var descriptionLength = bin.ReadByte();
                    entries[id].Add("ObjectiveDescription[" + i + "]", ds.GetString(descriptionLength).Trim('\0'));
                }

                entries[id].Add("LogTitle", ds.GetString(LogTitleLength).Trim('\0'));
                entries[id].Add("LogDescription", ds.GetString(LogDescriptionLength).Trim('\0'));
                entries[id].Add("QuestDescription", ds.GetString(QuestDescriptionLength).Trim('\0'));
                entries[id].Add("AreaDescription", ds.GetString(AreaDescriptionLength).Trim('\0'));
                entries[id].Add("PortraitGiverText", ds.GetString(PortraitGiverTextLength).Trim('\0'));
                entries[id].Add("PortraitGiverName", ds.GetString(PortraitGiverNameLength).Trim('\0'));
                entries[id].Add("PortraitTurnInText", ds.GetString(PortraitTurnInTextLength).Trim('\0'));
                entries[id].Add("PortraitTurnInName", ds.GetString(PortraitTurnInNameLength).Trim('\0'));
                entries[id].Add("QuestCompletionLog", ds.GetString(QuestCompletionLogLength).Trim('\0'));
            }

            return(entries);
        }
        static void Main(string[] args)
        {
            if (args.Length == 0)
            {
                throw new Exception("Arguments: <wdbpath> (json (default)/mysql)");
            }

            var outputType = "json";

            if (args.Length == 2)
            {
                if (args[1].ToLower() == "mysql")
                {
                    outputType = "mysql";
                }
            }

            var wdb = new wdbCache();

            using (var ms = new MemoryStream(File.ReadAllBytes(args[0])))
                using (var bin = new BinaryReader(ms))
                {
                    wdb.identifier    = Encoding.ASCII.GetString(bin.ReadBytes(4).Reverse().ToArray());
                    wdb.clientBuild   = bin.ReadUInt32();
                    wdb.clientLocale  = Encoding.ASCII.GetString(bin.ReadBytes(4).Reverse().ToArray());
                    wdb.recordSize    = bin.ReadUInt32();
                    wdb.recordVersion = bin.ReadUInt32();
                    wdb.formatVersion = bin.ReadUInt32();
                    wdb.buildInfo     = GetBuildInfoFromDB(wdb.clientBuild);

                    var humanReadableJsonOptions = new JsonSerializerOptions
                    {
                        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
                        WriteIndented        = true
                    };

                    if (wdb.clientLocale != "enUS" && wdb.clientLocale != "enGB")
                    {
                        if (outputType == "json")
                        {
                            var wdbJson = JsonSerializer.Serialize(new Dictionary <string, Dictionary <string, string> >(), humanReadableJsonOptions);
                            Console.WriteLine(wdbJson);
                        }

                        return;
                    }

                    // All WDB structures below are based on Simca's excellent 010 template.

                    switch (wdb.identifier)
                    {
                    case "WMOB": // Creature
                        wdb.entries = ReadCreatureEntries(bin, wdb);
                        break;

                    case "WGOB": // Gameobject
                        wdb.entries = ReadGameObjectEntries(bin);
                        break;

                    case "WPTX": // PageText
                        wdb.entries = ReadPageTextEntries(bin);
                        break;

                    case "WQST": // Quest
                        wdb.entries = ReadQuestEntries(bin, wdb);
                        break;

                    case "WNPC": // NPC
                    case "WPTN": // Petition
                        break;

                    default:
                        Console.WriteLine("Unknown cache file: " + wdb.identifier);
                        break;
                    }


                    var storageJsonOptions = new JsonSerializerOptions
                    {
                        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
                        WriteIndented        = false
                    };

                    if (outputType == "json")
                    {
                        var wdbJson = JsonSerializer.Serialize(wdb.entries, humanReadableJsonOptions);
                        Console.WriteLine(wdbJson);
                    }
                    else if (outputType == "mysql")
                    {
                        using (var connection = new MySqlConnection(File.ReadAllText("connectionstring.txt")))
                        {
                            connection.Open();

                            string targetTable;
                            string nameCol;
                            switch (wdb.identifier)
                            {
                            case "WMOB":
                                targetTable = "creatures";
                                nameCol     = "Name[0]";
                                break;

                            case "WQST":
                                targetTable = "quests";
                                nameCol     = "LogTitle";
                                break;

                            default:
                                return;
                            }

                            var currentEntries = new Dictionary <uint, DBEntry>();
                            using (var currentDataCmd = new MySqlCommand("SELECT id, name, firstseenbuild, lastupdatedbuild, json FROM " + targetTable, connection))
                                using (var reader = currentDataCmd.ExecuteReader())
                                {
                                    while (reader.Read())
                                    {
                                        var entry = new DBEntry()
                                        {
                                            id               = reader.GetUInt32(0),
                                            name             = reader.GetString(1),
                                            firstSeenBuild   = reader.GetUInt32(2),
                                            lastUpdatedBuild = reader.GetUInt32(3),
                                            json             = reader.GetString(4)
                                        };

                                        currentEntries.Add(entry.id, entry);
                                    }
                                }

                            Console.WriteLine(currentEntries.Count + " entries in " + targetTable + " DB");
                            Console.WriteLine(wdb.entries.Count + " entries in WDB file");

                            var newEntries     = 0;
                            var updatedEntries = 0;

                            using (var updateCmd = new MySqlCommand())
                                using (var insertCmd = new MySqlCommand())
                                {
                                    insertCmd.Connection  = connection;
                                    insertCmd.CommandText = "INSERT INTO wowdata." + targetTable + " (id, name, firstseenbuild, lastupdatedbuild, json) VALUES (@id, @name, @firstseenbuild, @lastupdatedbuild, @json)";
                                    insertCmd.Parameters.AddWithValue("id", 0);
                                    insertCmd.Parameters.AddWithValue("name", "");
                                    insertCmd.Parameters.AddWithValue("firstseenbuild", wdb.clientBuild);
                                    insertCmd.Parameters.AddWithValue("lastupdatedbuild", wdb.clientBuild);
                                    insertCmd.Parameters.AddWithValue("json", "");

                                    updateCmd.Connection  = connection;
                                    updateCmd.CommandText = "UPDATE wowdata." + targetTable + " SET name = @name, lastupdatedbuild = @lastupdatedbuild, json = @json WHERE ID = @id";
                                    updateCmd.Parameters.AddWithValue("id", 0);
                                    updateCmd.Parameters.AddWithValue("name", "");
                                    updateCmd.Parameters.AddWithValue("lastupdatedbuild", wdb.clientBuild);
                                    updateCmd.Parameters.AddWithValue("json", "");

                                    foreach (var entry in wdb.entries)
                                    {
                                        var properID       = uint.Parse(entry.Key);
                                        var serializedJson = JsonSerializer.Serialize(entry.Value, storageJsonOptions);

                                        if (!currentEntries.TryGetValue(properID, out DBEntry dbEntry))
                                        {
                                            Console.WriteLine(entry.Key + " is new, adding!");
                                            insertCmd.Parameters["id"].Value   = entry.Key;
                                            insertCmd.Parameters["name"].Value = entry.Value[nameCol];
                                            insertCmd.Parameters["json"].Value = serializedJson;
                                            insertCmd.ExecuteNonQuery();
                                            newEntries++;
                                        }
                                        else
                                        {
                                            // Don't let classic or older builds overwrite existing records, will break classic updates, TODO: Needs proper checking between retail/ptr, maybe DBD build comparison code?
                                            if (wdb.buildInfo.expansion == 1 && wdb.buildInfo.major == 13)
                                            {
                                                continue;
                                            }

                                            if (wdb.buildInfo.expansion == 2 && wdb.buildInfo.major == 5)
                                            {
                                                continue;
                                            }

                                            if (dbEntry.json != serializedJson && wdb.clientBuild > dbEntry.lastUpdatedBuild)
                                            {
                                                Console.WriteLine("JSON for " + entry.Key + " is changed updating! Before: \n " + dbEntry.json + "\n After: \n" + serializedJson);
                                                updateCmd.Parameters["id"].Value   = entry.Key;
                                                updateCmd.Parameters["name"].Value = entry.Value[nameCol];
                                                updateCmd.Parameters["json"].Value = serializedJson;
                                                updateCmd.ExecuteNonQuery();
                                                updatedEntries++;
                                            }
                                        }
                                    }
                                }

                            Console.WriteLine("New entries: " + newEntries);
                            Console.WriteLine("Updated entries: " + updatedEntries);
                        }
                    }
                }
        }
Example #4
0
        public static Dictionary <string, Dictionary <string, string> > ReadGameObjectEntries(BinaryReader bin, wdbCache wdb)
        {
            var entries = new Dictionary <string, Dictionary <string, string> >();

            while (bin.BaseStream.Position < bin.BaseStream.Length)
            {
                var id     = bin.ReadUInt32().ToString();
                var length = bin.ReadUInt32();

                if (length == 0)
                {
                    break;
                }

                var goEntry = new Dictionary <string, string>();
                goEntry.Add("Type", bin.ReadUInt32().ToString());
                goEntry.Add("GameObjectDisplayID", bin.ReadUInt32().ToString());

                var nameSize = 4;
                for (var i = 0; i < nameSize; i++)
                {
                    goEntry.Add("Name[" + i + "]", bin.ReadCString());
                }

                goEntry.Add("Icon", bin.ReadCString());
                goEntry.Add("Action", bin.ReadCString());
                goEntry.Add("Condition", bin.ReadCString());

                var gameDataSize = 34;

                // This change somes in the middle of several branches being worked on at the same time :(
                if (wdb.buildInfo.build > 40120 &&
                    wdb.buildInfo.build != 40140 &&
                    wdb.buildInfo.build != 40179 &&
                    wdb.buildInfo.build != 40203 &&
                    wdb.buildInfo.build != 40237 &&
                    wdb.buildInfo.build != 40260 &&
                    wdb.buildInfo.build != 40347 &&
                    wdb.buildInfo.build != 40422 &&
                    wdb.buildInfo.build != 40441 &&
                    wdb.buildInfo.build != 40443 &&
                    wdb.buildInfo.build != 40488 &&
                    wdb.buildInfo.build != 40593 &&
                    wdb.buildInfo.build != 40617 &&
                    wdb.buildInfo.build != 40618 &&
                    wdb.buildInfo.build != 40725 &&
                    wdb.buildInfo.build != 40892 &&
                    wdb.buildInfo.build != 41446 &&
                    wdb.buildInfo.build != 41510)
                {
                    gameDataSize = 35;
                }

                for (var i = 0; i < gameDataSize; i++)
                {
                    goEntry.Add("GameData[" + i + "]", bin.ReadUInt32().ToString());
                }

                goEntry.Add("Scale", bin.ReadSingle().ToString());

                var numQuestItems = bin.ReadByte();
                goEntry.Add("NumQuestItems", numQuestItems.ToString());

                for (var i = 0; i < numQuestItems; i++)
                {
                    goEntry.Add("QuestItems[" + i + "]", bin.ReadUInt32().ToString());
                }

                goEntry.Add("ContentTuningID", bin.ReadUInt32().ToString());

                entries.TryAdd(id, goEntry);
            }

            return(entries);
        }