コード例 #1
0
        /// <summary>
        /// Get the gear entries list, optionally with a substring filter.
        /// </summary>
        /// <param name="substring"></param>
        /// <returns></returns>
        public async Task <List <XivGear> > GetCachedGearList(string substring = null)
        {
            WhereClause where = null;
            if (substring != null)
            {
                where          = new WhereClause();
                where.Comparer = WhereClause.ComparisonType.Like;
                where.Column   = "name";
                where.Value    = "%" + substring + "%";
            }

            List <XivGear> mainHands = new List <XivGear>();
            List <XivGear> offHands  = new List <XivGear>();
            var            list      = await BuildListFromTable("items", where, async (reader) =>
            {
                var primaryMi = new XivGearModelInfo();

                var item = new XivGear
                {
                    ExdID             = reader.GetInt32("exd_id"),
                    PrimaryCategory   = XivStrings.Gear,
                    SecondaryCategory = reader.GetString("slot_full"),
                    ModelInfo         = primaryMi,
                };

                item.Name             = reader.GetString("name");
                item.IconNumber       = (uint)reader.GetInt32("icon_id");
                primaryMi.IsWeapon    = reader.GetBoolean("is_weapon");
                primaryMi.PrimaryID   = reader.GetInt32("primary_id");
                primaryMi.SecondaryID = reader.GetInt32("secondary_id");
                primaryMi.ImcSubsetID = reader.GetInt32("imc_variant");

                if (item.Name.Contains(XivStrings.Main_Hand))
                {
                    mainHands.Add(item);
                }
                else if (item.Name.Contains(XivStrings.Off_Hand))
                {
                    offHands.Add(item);
                }

                return(item);
            });

            // Assign pairs based on items that came out of the same EXD row.
            foreach (var item in mainHands)
            {
                var pair = offHands.FirstOrDefault(x => x.ExdID == item.ExdID);
                if (pair != null)
                {
                    pair.PairedItem = item;
                    item.PairedItem = pair;
                }
            }
            return(list);
        }
コード例 #2
0
ファイル: Gear.cs プロジェクト: ufx/xivModdingFramework
        /// <summary>
        /// Gets any missing gear that must be added manualy as it does not exist in the items exd
        /// </summary>
        /// <returns>The list of missing gear</returns>
        private List <XivGear> GetMissingGear()
        {
            var xivGearList = new List <XivGear>();

            var xivGear = new XivGear
            {
                Name         = "SmallClothes Body",
                Category     = XivStrings.Gear,
                ItemCategory = _slotNameDictionary[4],
                ModelInfo    = new XivModelInfo {
                    ModelID = 0, Variant = 1, Body = 0
                }
            };

            xivGearList.Add(xivGear);

            xivGear = new XivGear
            {
                Name         = "SmallClothes Legs",
                Category     = XivStrings.Gear,
                ItemCategory = _slotNameDictionary[7],
                ModelInfo    = new XivModelInfo {
                    ModelID = 0, Variant = 1, Body = 0
                }
            };

            xivGearList.Add(xivGear);

            xivGear = new XivGear
            {
                Name         = "SmallClothes Feet",
                Category     = XivStrings.Gear,
                ItemCategory = _slotNameDictionary[8],
                ModelInfo    = new XivModelInfo {
                    ModelID = 0, Variant = 1, Body = 0
                }
            };

            xivGearList.Add(xivGear);

            return(xivGearList);
        }
コード例 #3
0
        /// <summary>
        /// Gets the Icon info for a specific gear item
        /// </summary>
        /// <param name="gearItem">The gear item</param>
        /// <returns>A list of TexTypePath containing Icon Info</returns>
        public async Task <List <TexTypePath> > GetIconInfo(XivGear gearItem)
        {
            var ttpList = new List <TexTypePath>();

            var iconString = gearItem.IconNumber.ToString();

            var iconBaseNum  = iconString.Substring(0, 2).PadRight(iconString.Length, '0');
            var iconFolder   = $"ui/icon/{iconBaseNum.PadLeft(6, '0')}";
            var iconHQFolder = $"{iconFolder}/hq";
            var iconFile     = $"{iconString.PadLeft(6, '0')}.tex";

            if (await _index.FileExists(HashGenerator.GetHash(iconFile), HashGenerator.GetHash(iconFolder),
                                        XivDataFile._06_Ui))
            {
                ttpList.Add(new TexTypePath
                {
                    Name     = "Icon",
                    Path     = $"{iconFolder}/{iconFile}",
                    Type     = XivTexType.Icon,
                    DataFile = XivDataFile._06_Ui
                });
            }


            if (await _index.FileExists(HashGenerator.GetHash(iconFile), HashGenerator.GetHash(iconHQFolder),
                                        XivDataFile._06_Ui))
            {
                ttpList.Add(new TexTypePath
                {
                    Name     = "HQ Icon",
                    Path     = $"{iconHQFolder}/{iconFile}",
                    Type     = XivTexType.Icon,
                    DataFile = XivDataFile._06_Ui
                });
            }

            return(ttpList);
        }
コード例 #4
0
        /// <summary>
        /// A getter for available gear in the Item exd files
        /// </summary>
        /// <returns>A list containing XivGear data</returns>
        public async Task <List <XivGear> > GetUnCachedGearList()
        {
            // These are the offsets to relevant data
            // These will need to be changed if data gets added or removed with a patch
            const int modelDataCheckOffset = 30;
            int       dataLength           = 160;
            const int nameDataOffset       = 14;
            const int modelDataOffset      = 24;
            const int iconDataOffset       = 136;
            int       slotDataOffset       = 154;

            if (_xivLanguage == XivLanguage.Chinese)
            {
                dataLength     = 168;
                slotDataOffset = 156;
            }

            if (_xivLanguage == XivLanguage.Korean)
            {
                dataLength     = 160;
                slotDataOffset = 154;
            }

            var xivGearList = new List <XivGear>();

            xivGearList.AddRange(GetMissingGear());

            var ex             = new Ex(_gameDirectory, _xivLanguage);
            var itemDictionary = await ex.ReadExData(XivEx.item);

            // Loops through all the items in the item exd files
            // Item files start at 0 and increment by 500 for each new file
            // Item_0, Item_500, Item_1000, etc.
            await Task.Run(() => Parallel.ForEach(itemDictionary, (item) =>
            {
                try
                {
                    // This checks whether there is any model data present in the current item
                    if (item.Value[modelDataCheckOffset] <= 0 && item.Value[modelDataCheckOffset + 1] <= 0)
                    {
                        return;
                    }

                    var primaryMi    = new XivGearModelInfo();
                    var secondaryMi  = new XivGearModelInfo();
                    var hasSecondary = false;

                    var xivGear = new XivGear
                    {
                        ExdID           = item.Key,
                        PrimaryCategory = XivStrings.Gear,
                        ModelInfo       = primaryMi,
                    };

                    /* Used to determine if the given model is a weapon
                     * This is important because the data is formatted differently
                     * The model data is a 16 byte section separated into two 8 byte parts (primary model, secondary model)
                     * Format is 8 bytes in length with 2 bytes per data point [short, short, short, short]
                     * Gear: primary model [blank, blank, variant, ID] nothing in secondary model
                     * Weapon: primary model [blank, variant, body, ID] secondary model [blank, variant, body, ID]
                     */
                    var isWeapon = false;

                    // Big Endian Byte Order
                    using (var br = new BinaryReaderBE(new MemoryStream(item.Value)))
                    {
                        br.BaseStream.Seek(nameDataOffset, SeekOrigin.Begin);
                        var nameOffset = br.ReadInt16();

                        // Model Data
                        br.BaseStream.Seek(modelDataOffset, SeekOrigin.Begin);

                        // Primary Model Key
                        primaryMi.ModelKey = Quad.Read(br.ReadBytes(8), 0);
                        br.BaseStream.Seek(-8, SeekOrigin.Current);

                        // Primary Blank
                        var unused = br.ReadInt16();

                        // Primary Variant for weapon, blank otherwise
                        var weaponVariant = br.ReadInt16();

                        if (weaponVariant != 0)
                        {
                            primaryMi.ImcSubsetID = weaponVariant;
                            primaryMi.IsWeapon    = true;
                            isWeapon = true;
                        }

                        // Primary Body if weapon, Variant otherwise
                        if (isWeapon)
                        {
                            primaryMi.SecondaryID = br.ReadInt16();
                        }
                        else
                        {
                            primaryMi.ImcSubsetID = br.ReadInt16();
                        }

                        // Primary Model ID
                        primaryMi.PrimaryID = br.ReadInt16();

                        // Secondary Model Key
                        isWeapon             = false;
                        secondaryMi.ModelKey = Quad.Read(br.ReadBytes(8), 0);
                        br.BaseStream.Seek(-8, SeekOrigin.Current);

                        // Secondary Blank
                        var unused2 = br.ReadInt16();

                        // Secondary Variant for weapon, blank otherwise
                        weaponVariant = br.ReadInt16();

                        if (weaponVariant != 0)
                        {
                            secondaryMi.ImcSubsetID = weaponVariant;
                            secondaryMi.IsWeapon    = true;
                            isWeapon = true;
                        }

                        // Secondary Body if weapon, Variant otherwise
                        if (isWeapon)
                        {
                            secondaryMi.SecondaryID = br.ReadInt16();
                        }
                        else
                        {
                            secondaryMi.ImcSubsetID = br.ReadInt16();
                        }

                        // Secondary Model ID
                        secondaryMi.PrimaryID = br.ReadInt16();

                        // Icon
                        br.BaseStream.Seek(iconDataOffset, SeekOrigin.Begin);
                        xivGear.IconNumber = br.ReadUInt16();

                        // Gear Slot/Category
                        br.BaseStream.Seek(slotDataOffset, SeekOrigin.Begin);
                        int slotNum = br.ReadByte();

                        // Waist items do not have texture or model data
                        if (slotNum == 6)
                        {
                            return;
                        }

                        xivGear.EquipSlotCategory = slotNum;
                        xivGear.SecondaryCategory = _slotNameDictionary.ContainsKey(slotNum) ? _slotNameDictionary[slotNum] : "Unknown";

                        // Gear Name
                        var gearNameOffset = dataLength + nameOffset;
                        var gearNameLength = item.Value.Length - gearNameOffset;
                        br.BaseStream.Seek(gearNameOffset, SeekOrigin.Begin);
                        var nameString = Encoding.UTF8.GetString(br.ReadBytes(gearNameLength)).Replace("\0", "");
                        xivGear.Name   = new string(nameString.Where(c => !char.IsControl(c)).ToArray());
                        xivGear.Name   = xivGear.Name.Trim();

                        // If we have a secondary model

                        XivGear secondaryItem = null;
                        if (secondaryMi.PrimaryID != 0)
                        {
                            // Make a new item for it.
                            secondaryItem                   = (XivGear)xivGear.Clone();
                            secondaryItem.ModelInfo         = secondaryMi;
                            xivGear.Name                   += " - " + XivStrings.Main_Hand;
                            secondaryItem.Name             += " - " + XivStrings.Off_Hand;
                            xivGear.PairedItem              = secondaryItem;
                            secondaryItem.PairedItem        = xivGear;
                            xivGear.SecondaryCategory       = XivStrings.Dual_Wield;
                            secondaryItem.SecondaryCategory = XivStrings.Dual_Wield;
                        }

                        lock (_gearLock)
                        {
                            xivGearList.Add(xivGear);
                            if (secondaryItem != null)
                            {
                                xivGearList.Add(secondaryItem);
                            }
                        }
                    }
                } catch (Exception ex)
                {
                    throw;
                }
            }));

            xivGearList.Sort();

            return(xivGearList);
        }
コード例 #5
0
        /// <summary>
        /// Gets the available races that contain model data for the given gear
        /// </summary>
        /// <remarks>
        /// This checks to see if the mdl file for each race exists in the mdl folder
        /// It creates a list of the races which do have an available mdl file
        /// </remarks>
        /// <param name="xivGear">A gear item</param>
        /// <returns>A list of XivRace data</returns>
        public async Task <List <XivRace> > GetRacesForModels(XivGear xivGear, XivDataFile dataFile)
        {
            var itemType = xivGear.GetPrimaryItemType();

            var modelID = xivGear.ModelInfo.PrimaryID.ToString().PadLeft(4, '0');

            var raceList = new List <XivRace>();

            if (itemType == XivItemType.weapon)
            {
                return(new List <XivRace> {
                    XivRace.All_Races
                });
            }

            string mdlFolder;
            var    id = xivGear.ModelInfo.PrimaryID.ToString().PadLeft(4, '0');

            switch (itemType)
            {
            case XivItemType.equipment:
                mdlFolder = $"chara/{itemType}/e{id}/model";
                break;

            case XivItemType.accessory:
                mdlFolder = $"chara/{itemType}/a{id}/model";
                break;

            default:
                mdlFolder = "";
                break;
            }

            var testFilesDictionary = new Dictionary <int, string>();

            // loop through each race ID to create a dictionary containing [Hashed file name, race ID]
            foreach (var ID in IDRaceDictionary.Keys)
            {
                string mdlFile;

                switch (itemType)
                {
                case XivItemType.equipment:
                    mdlFile = $"c{ID}e{modelID}_{xivGear.GetItemSlotAbbreviation()}.mdl";
                    break;

                case XivItemType.accessory:
                    mdlFile = $"c{ID}a{modelID}_{xivGear.GetItemSlotAbbreviation()}.mdl";
                    break;

                default:
                    mdlFile = "";
                    break;
                }

                testFilesDictionary.Add(HashGenerator.GetHash(mdlFile), ID);
            }

            // get the list of hashed file names from the mtrl folder
            var files = await _index.GetAllHashedFilesInFolder(HashGenerator.GetHash(mdlFolder), dataFile);

            // Loop through each entry in the dictionary
            foreach (var testFile in testFilesDictionary)
            {
                // if the file in the dictionary entry is contained in the list of files from the folder
                // add that race to the race list
                if (files.Contains(testFile.Key))
                {
                    raceList.Add(IDRaceDictionary[testFile.Value]);
                }
            }

            return(raceList);
        }
コード例 #6
0
        /// <summary>
        /// Gets any missing gear that must be added manualy as it does not exist in the items exd
        /// </summary>
        /// <returns>The list of missing gear</returns>
        private List <XivGear> GetMissingGear()
        {
            var xivGearList = new List <XivGear>();

            var xivGear = new XivGear
            {
                Name              = "SmallClothes Body",
                PrimaryCategory   = XivStrings.Gear,
                SecondaryCategory = _slotNameDictionary[4],
                ModelInfo         = new XivGearModelInfo {
                    PrimaryID = 0, ImcSubsetID = 1, SecondaryID = 0
                }
            };

            xivGearList.Add(xivGear);

            xivGear = new XivGear
            {
                Name              = "SmallClothes Hands",
                PrimaryCategory   = XivStrings.Gear,
                SecondaryCategory = _slotNameDictionary[5],
                ModelInfo         = new XivGearModelInfo {
                    PrimaryID = 0, ImcSubsetID = 1, SecondaryID = 0
                }
            };

            xivGearList.Add(xivGear);

            xivGear = new XivGear
            {
                Name              = "SmallClothes Legs",
                PrimaryCategory   = XivStrings.Gear,
                SecondaryCategory = _slotNameDictionary[7],
                ModelInfo         = new XivGearModelInfo {
                    PrimaryID = 0, ImcSubsetID = 1, SecondaryID = 0
                }
            };

            xivGearList.Add(xivGear);

            xivGear = new XivGear
            {
                Name              = "SmallClothes Feet",
                PrimaryCategory   = XivStrings.Gear,
                SecondaryCategory = _slotNameDictionary[8],
                ModelInfo         = new XivGearModelInfo {
                    PrimaryID = 0, ImcSubsetID = 1, SecondaryID = 0
                }
            };

            xivGearList.Add(xivGear);

            xivGear = new XivGear
            {
                Name              = "SmallClothes Body (NPC)",
                PrimaryCategory   = XivStrings.Gear,
                SecondaryCategory = _slotNameDictionary[4],
                ModelInfo         = new XivGearModelInfo {
                    PrimaryID = 9903, ImcSubsetID = 1, SecondaryID = 0
                }
            };

            xivGearList.Add(xivGear);

            xivGear = new XivGear
            {
                Name              = "SmallClothes Hands (NPC)",
                PrimaryCategory   = XivStrings.Gear,
                SecondaryCategory = _slotNameDictionary[5],
                ModelInfo         = new XivGearModelInfo {
                    PrimaryID = 9903, ImcSubsetID = 1, SecondaryID = 0
                }
            };

            xivGearList.Add(xivGear);

            xivGear = new XivGear
            {
                Name              = "SmallClothes Legs (NPC)",
                PrimaryCategory   = XivStrings.Gear,
                SecondaryCategory = _slotNameDictionary[7],
                ModelInfo         = new XivGearModelInfo {
                    PrimaryID = 9903, ImcSubsetID = 1, SecondaryID = 0
                }
            };

            xivGearList.Add(xivGear);

            xivGear = new XivGear
            {
                Name              = "SmallClothes Feet (NPC)",
                PrimaryCategory   = XivStrings.Gear,
                SecondaryCategory = _slotNameDictionary[8],
                ModelInfo         = new XivGearModelInfo {
                    PrimaryID = 9903, ImcSubsetID = 1, SecondaryID = 0
                }
            };

            xivGearList.Add(xivGear);

            xivGear = new XivGear
            {
                Name              = "SmallClothes Feet 2 (NPC)",
                PrimaryCategory   = XivStrings.Gear,
                SecondaryCategory = _slotNameDictionary[8],
                ModelInfo         = new XivGearModelInfo {
                    PrimaryID = 9901, ImcSubsetID = 1, SecondaryID = 0
                }
            };

            xivGearList.Add(xivGear);

            return(xivGearList);
        }
コード例 #7
0
ファイル: Gear.cs プロジェクト: ufx/xivModdingFramework
        /// <summary>
        /// Gets the available races that contain texture data for the given gear
        /// </summary>
        /// <remarks>
        /// This checks to see if the mtrl file for each race exists in the mtrl folder
        /// It creates a list of the races which do have an available mtrl folder
        /// </remarks>
        /// <param name="xivGear">A gear item</param>
        /// <returns>A list of XivRace data</returns>
        public async Task <List <XivRace> > GetRacesForTextures(XivGear xivGear, XivDataFile dataFile)
        {
            // Get the material version for the item from the imc file
            var imc         = new Imc(_gameDirectory, dataFile);
            var gearVersion = (await imc.GetImcInfo(xivGear, xivGear.ModelInfo)).Version.ToString().PadLeft(4, '0');

            var modelID = xivGear.ModelInfo.ModelID.ToString().PadLeft(4, '0');

            var raceList = new List <XivRace>();

            var    itemType = ItemType.GetItemType(xivGear);
            string mtrlFolder;

            if (itemType == XivItemType.weapon)
            {
                return(new List <XivRace> {
                    XivRace.All_Races
                });
            }

            switch (itemType)
            {
            case XivItemType.equipment:
                mtrlFolder = $"chara/{itemType}/e{modelID}/material/v{gearVersion}";
                break;

            case XivItemType.accessory:
                mtrlFolder = $"chara/{itemType}/a{modelID}/material/v{gearVersion}";
                break;

            default:
                mtrlFolder = "";
                break;
            }

            var testFilesDictionary = new Dictionary <int, string>();

            // loop through each race ID to create a dictionary containing [Hashed file name, race ID]
            foreach (var ID in IDRaceDictionary.Keys)
            {
                string mtrlFile;

                switch (itemType)
                {
                case XivItemType.equipment:
                    mtrlFile = $"mt_c{ID}e{modelID}_{SlotAbbreviationDictionary[xivGear.ItemCategory]}_a.mtrl";
                    break;

                case XivItemType.accessory:
                    mtrlFile = $"mt_c{ID}a{modelID}_{SlotAbbreviationDictionary[xivGear.ItemCategory]}_a.mtrl";
                    break;

                default:
                    mtrlFile = "";
                    break;
                }

                testFilesDictionary.Add(HashGenerator.GetHash(mtrlFile), ID);
            }

            // get the list of hashed file names from the mtrl folder
            var files = await _index.GetAllHashedFilesInFolder(HashGenerator.GetHash(mtrlFolder), dataFile);

            // Loop through each entry in the dictionary
            foreach (var testFile in testFilesDictionary)
            {
                // if the file in the dictionary entry is contained in the list of files from the folder
                // add that race to the race list
                if (files.Contains(testFile.Key))
                {
                    raceList.Add(IDRaceDictionary[testFile.Value]);
                }
            }

            return(raceList);
        }
コード例 #8
0
ファイル: Gear.cs プロジェクト: goaaats/xivModdingFramework
        /// <summary>
        /// A getter for available gear in the Item exd files
        /// </summary>
        /// <returns>A list containing XivGear data</returns>
        public List <XivGear> GetGearList()
        {
            // These are the offsets to relevant data
            // These will need to be changed if data gets added or removed with a patch
            const int modelDataCheckOffset = 31;
            const int dataLength           = 152;
            const int nameDataOffset       = 14;
            const int modelDataOffset      = 24;
            const int iconDataOffset       = 128;
            const int slotDataOffset       = 146;

            var xivGearList = new List <XivGear>();

            var ex             = new Ex(_gameDirectory, _xivLanguage);
            var itemDictionary = ex.ReadExData(XivEx.item);

            // Loops through all the items in the item exd files
            // Item files start at 0 and increment by 500 for each new file
            // Item_0, Item_500, Item_1000, etc.
            foreach (var item in itemDictionary.Values)
            {
                // This checks whether there is any model data present in the current item
                if (item[modelDataCheckOffset] <= 0)
                {
                    continue;
                }

                // Gear can have 2 separate models (MNK weapons for example)
                var primaryMi   = new XivModelInfo();
                var secondaryMi = new XivModelInfo();

                var xivGear = new XivGear
                {
                    Category           = XivStrings.Gear,
                    PrimaryModelInfo   = primaryMi,
                    SecondaryModelInfo = secondaryMi
                };

                /* Used to determine if the given model is a weapon
                 * This is important because the data is formated differently
                 * The model data is a 16 byte section separated into two 8 byte parts (primary model, secondary model)
                 * Format is 8 bytes in length with 2 bytes per data point [short, short, short, short]
                 * Gear: primary model [blank, blank, variant, ID] nothing in secondary model
                 * Weapon: primary model [blank, variant, body, ID] secondary model [blank, variant, body, ID]
                 */
                var isWeapon = false;

                // Big Endian Byte Order
                using (var br = new BinaryReaderBE(new MemoryStream(item)))
                {
                    br.BaseStream.Seek(nameDataOffset, SeekOrigin.Begin);
                    var nameOffset = br.ReadInt16();

                    // Model Data
                    br.BaseStream.Seek(modelDataOffset, SeekOrigin.Begin);

                    // Primary Blank
                    primaryMi.Unused = br.ReadInt16();

                    // Primary Variant for weapon, blank otherwise
                    var weaponVariant = br.ReadInt16();

                    if (weaponVariant != 0)
                    {
                        primaryMi.Variant = weaponVariant;
                        isWeapon          = true;
                    }

                    // Primary Body if weapon, Variant otherwise
                    if (isWeapon)
                    {
                        primaryMi.Body = br.ReadInt16();
                    }
                    else
                    {
                        primaryMi.Variant = br.ReadInt16();
                    }

                    // Primary Model ID
                    primaryMi.ModelID = br.ReadInt16();

                    // Secondary Blank
                    secondaryMi.Unused = br.ReadInt16();

                    // Secondary Variant for weapon, blank otherwise
                    weaponVariant = br.ReadInt16();

                    if (weaponVariant != 0)
                    {
                        secondaryMi.Variant = weaponVariant;
                        isWeapon            = true;
                    }

                    // Secondary Body if weapon, Variant otherwise
                    if (isWeapon)
                    {
                        secondaryMi.Body = br.ReadInt16();
                    }
                    else
                    {
                        secondaryMi.Variant = br.ReadInt16();
                    }

                    // Secondary Model ID
                    secondaryMi.ModelID = br.ReadInt16();

                    // Icon
                    br.BaseStream.Seek(iconDataOffset, SeekOrigin.Begin);
                    xivGear.IconNumber = br.ReadUInt16();

                    // Gear Slot/Category
                    br.BaseStream.Seek(slotDataOffset, SeekOrigin.Begin);
                    int slotNum = br.ReadByte();

                    // Waist items do not have texture or model data
                    if (slotNum == 6)
                    {
                        continue;
                    }

                    xivGear.ItemCategory = _slotNameDictionary.ContainsKey(slotNum) ? _slotNameDictionary[slotNum] : "Unknown";

                    // Gear Name
                    var gearNameOffset = dataLength + nameOffset;
                    var gearNameLength = item.Length - gearNameOffset;
                    br.BaseStream.Seek(gearNameOffset, SeekOrigin.Begin);
                    var nameString = Encoding.UTF8.GetString(br.ReadBytes(gearNameLength)).Replace("\0", "");
                    xivGear.Name = new string(nameString.Where(c => !char.IsControl(c)).ToArray());

                    xivGearList.Add(xivGear);
                }
            }
            xivGearList.Sort();

            return(xivGearList);
        }