Exemplo n.º 1
0
        static public Dictionary <uint, FFXI_Item> ReadItemListFromDatFile(uint DatFileId)
        {
            Dictionary <uint, FFXI_Item> res = new Dictionary <uint, FFXI_Item>();

            if (!FFXI_FTable.TryGetValue(DatFileId, out var FileDatInfo))
            {
                return(res);
            }

            if (!File.Exists(FileDatInfo.FullFileName))
            {
                return(res);
            }

            var FS = new FileStream(FileDatInfo.FullFileName, FileMode.Open, FileAccess.Read);

            // needs to be in 3072 byte block size, and a minimum of 16 entries
            if (((FS.Length % 0x0C00) != 0) || (FS.Length < 0xC000))
            {
                return(res);
            }
            var BR = new BinaryReader(FS);

            FFXI_DeduceItemType(BR, out var ExpectedItemType);

            var itemCount = BR.BaseStream.Length / 0x0C00;

            for (var i = 0; i < itemCount; i++)
            {
                BR.BaseStream.Seek(i * 0x0C00, SeekOrigin.Begin);
                byte[] ItemBytes = BR.ReadBytes(0xC00);
                FFXIEncryption.Rotate(ItemBytes, 5);
                var MemBR = new BinaryReader(new MemoryStream(ItemBytes, false));

                FFXI_Item item = new FFXI_Item();
                // Common Fields (14 bytes)
                item.Id        = MemBR.ReadUInt32();
                item.Flags     = (FFXI_ItemFlags)MemBR.ReadUInt16();
                item.StackSize = MemBR.ReadUInt16(); // 0xe0ff for Currency, which kinda suggests this is really 2 separate bytes
                item.Type      = (FFXI_ItemType)MemBR.ReadUInt16();
                MemBR.ReadUInt16();                  // item.ResourceID_ = MemBR.ReadUInt16();
                MemBR.ReadUInt16();                  // item.ValidTargets_ = (ValidTarget)MemBR.ReadUInt16();
                // Extra Fields (22/30/10/6/2 bytes for Armor/Weapon/Puppet/Item/UsableItem)

                if (item.Type == FFXI_ItemType.Nothing)
                {
                    continue;
                }

                switch (ExpectedItemType)
                {
                case FFXI_ItemDatFileTypes.Armor:
                case FFXI_ItemDatFileTypes.Weapon:
                    MemBR.ReadUInt16();     // item.Level_ = MemBR.ReadUInt16();
                    MemBR.ReadUInt16();     // item.Slots_ = (EquipmentSlot)MemBR.ReadUInt16();
                    MemBR.ReadUInt16();     // item.Races_ = (Race)MemBR.ReadUInt16();
                    MemBR.ReadUInt32();     // item.Jobs_ = (Job)MemBR.ReadUInt32();
                    MemBR.ReadUInt16();     //item.SuperiorLevel_ = MemBR.ReadUInt16();
                    if (ExpectedItemType == FFXI_ItemDatFileTypes.Armor)
                    {
                        MemBR.ReadUInt16();     // item.ShieldSize_ = MemBR.ReadUInt16();
                    }
                    else
                    {
                        // Weapon
                        MemBR.ReadUInt16(); // item.Unknown4_ = MemBR.ReadUInt16();
                        MemBR.ReadUInt16(); // item.Damage_ = MemBR.ReadUInt16();
                        MemBR.ReadInt16();  // item.Delay_ = MemBR.ReadInt16();
                        MemBR.ReadUInt16(); // item.DPS_ = MemBR.ReadUInt16();
                        MemBR.ReadByte();   // item.Skill_ = (Skill)MemBR.ReadByte();
                        MemBR.ReadByte();   // item.JugSize_ = MemBR.ReadByte();
                        MemBR.ReadUInt32(); // item.Unknown1_ = MemBR.ReadUInt32();
                    }
                    MemBR.ReadByte();       // item.MaxCharges_ = MemBR.ReadByte();
                    MemBR.ReadByte();       // item.CastingTime_ = MemBR.ReadByte();
                    MemBR.ReadUInt16();     // item.UseDelay_ = MemBR.ReadUInt16();
                    MemBR.ReadUInt32();     // item.ReuseDelay_ = MemBR.ReadUInt32();
                    MemBR.ReadUInt16();     // item.Unknown2_ = MemBR.ReadUInt16();
                    MemBR.ReadUInt16();     // item.iLevel_ = MemBR.ReadUInt16();
                    MemBR.ReadUInt32();     // item.Unknown3_ = MemBR.ReadUInt32();
                    break;

                case FFXI_ItemDatFileTypes.PuppetItem:
                    MemBR.ReadUInt16();     // item.PuppetSlot_ = (PuppetSlot)MemBR.ReadUInt16();
                    MemBR.ReadUInt32();     // item.ElementCharge_ = MemBR.ReadUInt32();
                    MemBR.ReadUInt32();     // item.Unknown3_ = MemBR.ReadUInt32();
                    break;

                case FFXI_ItemDatFileTypes.Instinct:
                    MemBR.ReadUInt32();
                    MemBR.ReadUInt32();
                    MemBR.ReadUInt16();
                    MemBR.ReadUInt16();     // item.InstinctCost_ = MemBR.ReadUInt16();
                    MemBR.ReadUInt16();
                    MemBR.ReadUInt32();
                    MemBR.ReadUInt32();
                    MemBR.ReadUInt32();
                    break;

                case FFXI_ItemDatFileTypes.Item:
                    switch (item.Type)
                    {
                    case FFXI_ItemType.Flowerpot:
                    case FFXI_ItemType.Furnishing:
                    case FFXI_ItemType.Mannequin:
                        MemBR.ReadUInt16();        // item.Element_ = (Element)MemBR.ReadUInt16();
                        MemBR.ReadInt32();         // item.StorageSlots_ = MemBR.ReadInt32();
                        MemBR.ReadUInt32();        // item.Unknown3_ = MemBR.ReadUInt32();
                        break;

                    default:
                        MemBR.ReadUInt16();         // item.Unknown2_ = MemBR.ReadUInt16();
                        MemBR.ReadUInt32();         // item.Unknown3_ = MemBR.ReadUInt32();
                        MemBR.ReadUInt32();         // item.Unknown3_ = MemBR.ReadUInt32();
                        break;
                    }
                    break;

                case FFXI_ItemDatFileTypes.UsableItem:
                    MemBR.ReadUInt16();     // item.ActivationTime_ = MemBR.ReadUInt16();
                    MemBR.ReadUInt32();     // item.Unknown1_ = MemBR.ReadUInt32();
                    MemBR.ReadUInt32();     // item.Unknown3_ = MemBR.ReadUInt32();
                    MemBR.ReadUInt32();     // item.Unknown4_ = MemBR.ReadUInt32();
                    break;

                case FFXI_ItemDatFileTypes.Currency:
                    MemBR.ReadUInt16();     // item.Unknown2_ = MemBR.ReadUInt16();
                    break;

                case FFXI_ItemDatFileTypes.ItemSlip:
                    MemBR.ReadUInt16();     // item.Unknown1_ = MemBR.ReadUInt16();
                    for (int counter = 0; counter < 17; counter++)
                    {
                        MemBR.ReadUInt32();
                    }
                    break;

                case FFXI_ItemDatFileTypes.Monipulator:
                    MemBR.ReadUInt16();     // item.Unknown1_ = MemBR.ReadUInt16();
                    for (int counter = 0; counter < 24; counter++)
                    {
                        MemBR.ReadInt32();
                    }
                    break;

                default:
                    // If this is a unknown expected file type, ignore and exit
                    return(res);
                }

                if (item.Type > FFXI_ItemType.Max)
                {
                    // Invalid item type ?
                    continue;
                }

                // Next Up: Strings (variable size)
                long StringBase  = MemBR.BaseStream.Position;
                uint StringCount = MemBR.ReadUInt32();
                if (StringCount > 9)
                {
                    // Sanity check, for safety - 0 strings is fine for now
                    // item.Clear();
                    continue;
                }
                FFXIEncoding E       = new FFXIEncoding();
                string[]     Strings = new string[StringCount];
                for (byte iStrings = 0; iStrings < StringCount; iStrings++)
                {
                    long Offset = StringBase + MemBR.ReadUInt32();
                    uint Flag   = MemBR.ReadUInt32();
                    if (Offset < 0 || Offset + 0x20 > 0x280 || (Flag != 0 && Flag != 1))
                    {
                        // item.Clear();
                        StringCount = 0;
                        break;
                    }
                    // Flag seems to be 1 if the offset is not actually an offset. Could just be padding to make StringCount unique per language, or it could be an indication
                    // of the pronoun to use (a/an/the/...). The latter makes sense because of the increased number of such flags for french and german.
                    if (Flag == 0)
                    {
                        MemBR.BaseStream.Position = Offset;
                        Strings[iStrings]         = FFXI_ReadString(MemBR, E);
                        if (Strings[iStrings] == null)
                        {
                            // item.Clear();
                            StringCount = 0;
                            break;
                        }
                        MemBR.BaseStream.Position = StringBase + 4 + 8 * (iStrings + 1);
                    }
                }
                // Assign the strings to the proper fields
                switch (StringCount)
                {
                case 0:
                    // Temporary hack until I can figure out what the hell is wrong with reading the strings
                    if ((Strings.Length > 1) && (Strings[0] != null))
                    {
                        item.Name = Strings[0];
                    }
                    else
                    {
                        item.Name = "<no name found>";
                    }
                    // item.Name = item.Type.ToString() + " - " + item.Id.ToString();
                    break;

                case 1:
                    item.Name = Strings[0];
                    break;

                case 2:     // Japanese
                    item.Name        = Strings[0];
                    item.Description = Strings[1];
                    break;

                case 5:     // English
                    item.Name = Strings[0];
                    // unused:              Strings[1]
                    item.NameSingle   = Strings[2];
                    item.NameMultiple = Strings[3];
                    item.Description  = Strings[4];
                    break;

                case 6:     // French
                    item.Name = Strings[0];
                    // unused:              Strings[1]
                    // unused:              Strings[2]
                    item.NameSingle   = Strings[3];
                    item.NameMultiple = Strings[4];
                    item.Description  = Strings[5];
                    break;

                case 9:     // German
                    item.Name = Strings[0];
                    // unused:              Strings[1]
                    // unused:              Strings[2]
                    // unused:              Strings[3]
                    item.NameSingle = Strings[4];
                    // unused:              Strings[5]
                    // unused:              Strings[6]
                    item.NameMultiple = Strings[7];
                    item.Description  = Strings[8];
                    break;
                }
                MemBR.Close();

                if ((item.Name != null) && (item.Name != string.Empty) && (item.Name != "."))
                {
                    res.Add(item.Id, item);
                }
            }
            return(res);
        }
Exemplo n.º 2
0
        static public List <FFXI_Item> ReadItemListFromXML(string ItemXmlFile)
        {
            List <FFXI_Item> res = new List <FFXI_Item>();

            XmlDocument D = new XmlDocument();

            D.Load(ItemXmlFile);

            foreach (XmlNode itemNode in D.DocumentElement.ChildNodes)
            {
                if (itemNode.Name == "thing")
                {
                    var newItem = new FFXI_Item();
                    foreach (XmlNode itemElement in itemNode.ChildNodes)
                    {
                        if (itemElement.Name == "field")
                        {
                            var fieldName      = itemElement.Attributes["name"]?.Value.ToLower();
                            var fieldValueText = itemElement?.InnerText;
                            uint.TryParse(fieldValueText, out uint fieldValueUInt);
                            uint.TryParse(fieldValueText, System.Globalization.NumberStyles.HexNumber, CultureInfo.InvariantCulture, out uint fieldValueUIntHex);

                            switch (fieldName)
                            {
                            case "id":
                                newItem.Id = fieldValueUInt;
                                break;

                            case "flags":
                                newItem.Flags = (FFXI_ItemFlags)fieldValueUIntHex;
                                break;

                            case "stack-size":
                                newItem.StackSize = fieldValueUInt;
                                break;

                            case "type":
                                newItem.Type = (FFXI_ItemType)fieldValueUIntHex;
                                break;

                            case "name":
                                newItem.Name = fieldValueText;
                                break;

                            case "description":
                                newItem.Description = fieldValueText;
                                break;

                            case "log-name-singular":
                                newItem.NameSingle = fieldValueText;
                                break;

                            case "log-name-plural":
                                newItem.NameMultiple = fieldValueText;
                                break;
                            }
                        }
                    }

                    // Only add a item if it has some usefull info in it
                    if ((newItem.Id > 0) && (newItem.Name != null) && (newItem.Name != string.Empty) && (newItem.Name != "."))
                    {
                        res.Add(newItem);
                    }
                }
            }

            return(res);
        }