public void SerializeStore(HotfixStore <T> store, StringBuilder hotfixBuilder, StringBuilder localeBuilder)
        {
            if (store.Records.Count == 0)
            {
                return;
            }

            bool isLocale = false;
            var  hotfixStructureAttribute = typeof(T).GetCustomAttribute <HotfixStructureAttribute>();

            Debug.Assert(hotfixStructureAttribute != null);

            var propertiesInfos = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public);
            // Synch with TC
            var normalizedTableHashString = hotfixStructureAttribute.Hash.ToString()
                                            .Replace("GameObject", "Gameobject")
                                            .Replace("PvP", "Pvp")
                                            .Replace("PVP", "Pvp")
                                            .Replace("QuestXP", "QuestXp")
                                            .Replace("WMO", "Wmo")
                                            .Replace("AddOn", "Addon")
                                            .Replace("LFG", "Lfg")
                                            .Replace("_", "");

            var tableName = Regex.Replace(normalizedTableHashString, @"(?<=[a-z])([A-Z])|(?<=[A-Z])([A-Z][a-z])",
                                          @"_$1$2", RegexOptions.Compiled).ToLower();

            if (localeBuilder != null && propertiesInfos.Any(
                    propInfo => propInfo.PropertyType == typeof(string) || propInfo.PropertyType == typeof(string[])))
            {
                switch (tableName)
                {
                case "achievement":
                case "area_table":
                case "artifact_appearance":
                case "artifact_appearance_set":
                case "artifact":
                case "auction_house":
                case "azerite_essence":
                case "azerite_essence_power":
                case "barber_shop_style":
                case "battlemaster_list":
                case "battle_pet_species":
                case "broadcast_text":
                case "char_titles":
                case "chat_channels":
                case "chr_classes":
                case "chr_races":
                case "chr_specialization":
                case "creature_family":
                case "creature_type":
                case "criteria_tree":
                case "currency_types":
                case "difficulty":
                case "dungeon_encounter":
                case "faction":
                case "gameobjects":
                case "garr_ability":
                case "garr_building":
                case "garr_class_spec":
                case "garr_follower":
                case "heirloom":
                case "item_bag_family":
                case "item_class":
                case "item_limit_category":
                case "item_name_description":
                case "item_search_name":
                case "item_set":
                case "item_sparse":
                case "lfg_dungeons":
                case "mail_template":
                case "map_difficulty":
                case "map":
                case "mount":
                case "names_reserved":
                case "player_condition":
                case "prestige_level_info":
                case "pvp_talent":
                case "quest_sort":
                case "scenario":
                case "scenario_step":
                case "skill_line":
                case "specialization_spells":
                case "spell_category":
                case "spell_focus_object":
                case "spell_item_enchantment":
                case "spell_name":
                case "spell_range":
                case "spell_shapeshift_form":
                case "talent":
                case "taxi_nodes":
                case "totem_category":
                case "toy":
                case "transmog_set_group":
                case "transmog_set":
                case "ui_map":
                case "unit_power_bar":
                case "wmo_area_table":
                    break;

                default:
                    return;
                }

                if (tableName == "broadcast_text")
                {
                    var remainingCountDelete = store.Records.Count - 1;

                    localeBuilder.Append($"DELETE FROM `{tableName}_locale` WHERE `locale` = '{ClientLocale.PacketLocale}' AND `ID` IN (");
                    foreach (var kv in store.Records)
                    {
                        localeBuilder?.Append($"{kv.Key}");
                        localeBuilder?.Append(remainingCountDelete > 0 ? $", " : $");" + Environment.NewLine);
                        --remainingCountDelete;
                    }
                }
                else
                {
                    localeBuilder.AppendLine($"DELETE FROM `{tableName}_locale` WHERE `locale` = '{ClientLocale.PacketLocale}' AND `VerifiedBuild`>0;");
                }
                localeBuilder.Append($"INSERT INTO `{tableName}_locale` (");
                localeBuilder.Append("`ID`, ");
                localeBuilder.Append("`locale`, ");
                isLocale = true;
            }

            if (tableName == "broadcast_text")
            {
                var remainingCountDelete = store.Records.Count - 1;

                hotfixBuilder.Append($"DELETE FROM `{tableName}` WHERE `VerifiedBuild`>0 AND `ID` IN (");
                foreach (var kv in store.Records)
                {
                    hotfixBuilder.Append($"{kv.Key}");
                    hotfixBuilder.Append(remainingCountDelete > 0 ? $", " : $");" + Environment.NewLine);
                    --remainingCountDelete;
                }
            }
            else
            {
                hotfixBuilder.AppendLine($"DELETE FROM `{tableName}` WHERE `VerifiedBuild`>0;");
            }

            hotfixBuilder.Append($"INSERT INTO `{tableName}` (");
            if (!hotfixStructureAttribute.HasIndexInData)
            {
                hotfixBuilder.Append("`ID`, ");
            }

            foreach (var propInfo in propertiesInfos)
            {
                if (!ShouldRead(propInfo))
                {
                    continue;
                }

                if (propInfo.PropertyType.IsArray)
                {
                    var isString = propInfo.PropertyType.GetElementType() == typeof(string);

                    var arraySizeAttribute = propInfo.GetCustomAttribute <HotfixArrayAttribute>();
                    for (var i = 0; i < arraySizeAttribute.Size; ++i)
                    {
                        if (arraySizeAttribute.IsPosition)
                        {
                            hotfixBuilder.Append($"`{propInfo.Name}{ PosLetters[i] }`, ");
                            if (localeBuilder != null && isString)
                            {
                                localeBuilder.Append($"{propInfo.Name}{ PosLetters[i] }_lang`, ");
                            }
                        }
                        else
                        {
                            hotfixBuilder.Append($"`{propInfo.Name}{ i + 1 }`, ");
                            if (localeBuilder != null && isString)
                            {
                                localeBuilder.Append($"{propInfo.Name}{ i + 1 }_lang`, ");
                            }
                        }
                    }
                }
                else
                {
                    hotfixBuilder.Append($"`{propInfo.Name}`, ");
                    if (localeBuilder != null && propInfo.PropertyType == typeof(string))
                    {
                        localeBuilder.Append($"`{propInfo.Name}_lang`, ");
                    }
                }
            }

            hotfixBuilder.AppendLine("`VerifiedBuild`) VALUES");
            if (isLocale)
            {
                localeBuilder?.AppendLine("`VerifiedBuild`) VALUES");
            }

            var remainingCount = store.Records.Count - 1;

            foreach (var kv in store.Records)
            {
                hotfixBuilder.Append("(");
                if (isLocale)
                {
                    localeBuilder?.Append("(");
                }

                if (!hotfixStructureAttribute.HasIndexInData)
                {
                    hotfixBuilder.Append($"{kv.Key}, ");
                }

                if (isLocale)
                {
                    localeBuilder?.Append($"{kv.Key}, ");
                }

                if (isLocale)
                {
                    localeBuilder?.Append($"'{ClientLocale.PacketLocale}', ");
                }
                _serializer((T)kv.Value, hotfixBuilder, localeBuilder);

                hotfixBuilder.AppendLine(remainingCount > 0 ? $"{ClientVersion.BuildInt})," : $"{ClientVersion.BuildInt});");
                if (isLocale)
                {
                    localeBuilder?.AppendLine(remainingCount > 0 ? $"{ClientVersion.BuildInt})," : $"{ClientVersion.BuildInt});");
                }
                --remainingCount;
            }

            hotfixBuilder.AppendLine();
            if (isLocale)
            {
                localeBuilder?.AppendLine();
            }
        }
        public void SerializeStore(HotfixStore <T> store, StringBuilder hotfixBuilder, StringBuilder localeBuilder)
        {
            if (store.Records.Count == 0)
            {
                return;
            }

            var hotfixStructureAttribute = typeof(T).GetCustomAttribute <HotfixStructureAttribute>();

            Debug.Assert(hotfixStructureAttribute != null);

            var propertiesInfos = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public);
            var tableName       = Regex.Replace(hotfixStructureAttribute.Hash.ToString(), @"(?<=[a-z])([A-Z])|(?<=[A-Z])([A-Z][a-z])",
                                                @"_$1$2", RegexOptions.Compiled).ToLower();

            if (localeBuilder != null && propertiesInfos.Any(
                    propInfo => propInfo.PropertyType == typeof(string) || propInfo.PropertyType == typeof(string[])))
            {
                localeBuilder.AppendLine($"TRUNCATE `{tableName}_locale`;");
                localeBuilder.Append($"INSERT INTO `{tableName}_locale` (");
                if (!hotfixStructureAttribute.HasIndexInData)
                {
                    localeBuilder.Append("`ID`, ");
                }
                localeBuilder.Append("`locale`, ");
            }

            hotfixBuilder.AppendLine($"TRUNCATE `{tableName}`;");
            hotfixBuilder.Append($"INSERT INTO `{tableName}` (");
            if (!hotfixStructureAttribute.HasIndexInData)
            {
                hotfixBuilder.Append("`ID`, ");
            }

            foreach (var propInfo in propertiesInfos)
            {
                if (!ShouldRead(propInfo))
                {
                    continue;
                }

                if (propInfo.PropertyType.IsArray)
                {
                    var isString = propInfo.PropertyType.GetElementType() == typeof(string);

                    var arraySizeAttribute = propInfo.GetCustomAttribute <HotfixArrayAttribute>();
                    for (var i = 0; i < arraySizeAttribute.Size; ++i)
                    {
                        hotfixBuilder.Append($"`{propInfo.Name}{ i + 1 }`, ");
                        if (localeBuilder != null && isString)
                        {
                            localeBuilder.Append($"{propInfo.Name}{ i + 1 }_lang`, ");
                        }
                    }
                }
                else
                {
                    hotfixBuilder.Append($"`{propInfo.Name}`, ");
                    if (localeBuilder != null && propInfo.PropertyType == typeof(string))
                    {
                        localeBuilder.Append($"`{propInfo.Name}_lang`, ");
                    }
                }
            }

            hotfixBuilder.AppendLine("`VerifiedBuild`) VALUES");
            localeBuilder?.AppendLine("`VerifiedBuild`) VALUES");

            var remainingCount = store.Records.Count - 1;

            foreach (var kv in store.Records)
            {
                hotfixBuilder.Append("(");
                localeBuilder?.Append("(");
                if (!hotfixStructureAttribute.HasIndexInData)
                {
                    hotfixBuilder.Append($"{kv.Key}, ");
                    localeBuilder?.Append($"{kv.Key}, ");
                }

                localeBuilder?.Append($"'{ClientLocale.PacketLocale}', ");
                _serializer((T)kv.Value, hotfixBuilder, localeBuilder);

                hotfixBuilder.AppendLine(remainingCount > 0 ? $"{ClientVersion.BuildInt})," : $"{ClientVersion.BuildInt});");
                localeBuilder?.AppendLine(remainingCount > 0 ? $"{ClientVersion.BuildInt})," : $"{ClientVersion.BuildInt});");
                --remainingCount;
            }

            hotfixBuilder.AppendLine();
            localeBuilder?.AppendLine();
        }