示例#1
0
        /// <summary>
        /// Reads a UnitObject from the internal serialised byte array.
        /// </summary>
        private void _ReadUnit()
        {
            //// start of header
            // unit object versions
            _version = _bitBuffer.ReadInt16();
            _context = (ObjectContext)_bitBuffer.ReadByte();
            if (_version != 0x00BF && _version != 0x00CD && _version != 0x00CF) throw new Exceptions.NotSupportedVersionException("0x00BF or 0x00CD or 0x00CF", "0x" + _version.ToString("X4"));
            if (_context != ObjectContext.Save && _context != ObjectContext.CharSelect &&
                _context != ObjectContext.CharStats && _context != ObjectContext.ItemDrop)
            {
                throw new Exceptions.NotSupportedVersionException("0x00 or 0x02 or 0x03 or 0x04", "0x" + _context.ToString("X2"));
            }
            if (_debugOutputLoadingProgress)
            {
                Debug.WriteLine(String.Format("Version = {0} (0x{0:X4}), Context = {1} (0x{2:X2})", _version, _context, (int)_context));
            }

            // content bit fields
            _bitFieldCount = _bitBuffer.ReadBits(8);
            if (_bitFieldCount == 1) _bitField = _bitBuffer.ReadUInt32();
            if (_bitFieldCount == 2) _bitField = _bitBuffer.ReadUInt64();
            if (_debugOutputLoadingProgress)
            {
                Debug.WriteLine(String.Format("BitField = {0} (0x{1:X16})", _DebugBinaryFormat(_bitField), _bitField));
            }

            // total bit count
            if (_TestBit(Bits.Bit1DBitCountEof))
            {
                _bitCount = _bitBuffer.ReadBits(32);
                if (_debugOutputLoadingProgress)
                {
                    Debug.WriteLine(String.Format("Total BitCount = {0}", _bitCount));
                }
            }

            // begin data magic word
            if (_TestBit(Bits.Bit00FlagAlignment))
            {
                _beginFlag = (uint)_bitBuffer.ReadBits(32);
                if (_debugOutputLoadingProgress)
                {
                    Debug.WriteLine(String.Format("BeginFlag = 0x{0}", _beginFlag.ToString("X8")));
                }
                if (_beginFlag != ObjectMagicWord && _beginFlag != ItemMagicWord) throw new Exceptions.UnexpectedTokenException(ObjectMagicWord, _beginFlag);
            }

            // dunno what these are exactly
            if (_TestBit(Bits.Bit1CTimeStamps))
            {
                _timeStamp1 = _bitBuffer.ReadBits(32);
                _timeStamp2 = _bitBuffer.ReadBits(32);
                _timeStamp3 = _bitBuffer.ReadBits(32);
                if (_debugOutputLoadingProgress)
                {
                    Debug.WriteLine(String.Format("TimeStamp1 = {0}, TimeStamp2 = {1}, TimeStamp3 = {2}", _timeStamp1, _timeStamp2, _timeStamp3));
                }
            }

            // last station visited save/respawn location
            if (_TestBit(Bits.Bit1FSaveLocations))
            {
                int saveLocationsCount = _bitBuffer.ReadBitsShift(4);
                if (_debugOutputLoadingProgress)
                {
                    Debug.WriteLine(String.Format("SaveLocationsCount = {0}", saveLocationsCount));
                }

                for (int i = 0; i < saveLocationsCount; i++)
                {
                    ushort levelCode = _bitBuffer.ReadUInt16(); // table 0x6D (LEVEL)
                    ushort difficultyCode = _bitBuffer.ReadUInt16();  // table 0xB2 (DIFFICULTY)

                    SaveLocation saveLocation = new SaveLocation
                    {
                        Level = (LevelRow)FileManager.GetRowFromCode(Xls.TableCodes.LEVEL, (short)levelCode),
                        Difficulty = (DifficultyRow)FileManager.GetRowFromCode(Xls.TableCodes.DIFFICULTY, (short)difficultyCode)
                    };
                    SaveLocations.Add(saveLocation);

                    if ((SaveLocations[i].Level == null && SaveLocations[i].Difficulty != null) || (SaveLocations[i].Level != null && SaveLocations[i].Difficulty == null))
                    {
                        throw new Exceptions.UnitObjectException(String.Format("Invalid SaveLocation encountered. Level = {0:X4}, Difficulty = {1:X4}", levelCode, difficultyCode));
                    }

                    if (!_debugOutputLoadingProgress) continue;
                    if (SaveLocations[i].Level == null || SaveLocations[i].Difficulty == null)
                    {
                        Debug.WriteLine(String.Format("SaveLocations[{0}].LevelCode = {1} (0x{1:X4}), SaveLocations[{0}].DifficultyCode = {2} (0x{2:X4})",
                                                      i, levelCode, difficultyCode));
                    }
                    else
                    {
                        Debug.WriteLine(String.Format("SaveLocations[{0}].Level = {1}, SaveLocations[{0}].Difficulty = {2}",
                                                      i, SaveLocations[i].Level.levelName, SaveLocations[i].Difficulty.name));
                    }
                }
            }

            // character flags
            if (_TestBit(Bits.Bit20States1))
            {
                int statCount = _bitBuffer.ReadBits(8);
                if (_debugOutputLoadingProgress)
                {
                    Debug.WriteLine(String.Format("StateCode1Count = {0}", statCount));
                }

                for (int i = 0; i < statCount; i++)
                {
                    int state = _bitBuffer.ReadInt16();
                    AddState1(state); // table 0x4B (STATES)
                    if (_debugOutputLoadingProgress)
                    {
                        Debug.WriteLine(String.Format("StateCodes1[{0}] = {1}({2:X})", i, StateCodes1[i], (short)(StateCodes1[i])));
                    }
                }
            }
            //// end of header

            // bit offsets to bookmarks (only 1 bookmark though - "hotkeys")
            if (_TestBit(Bits.Bit1BBookmarks))
            {
                BookmarkCount = _bitBuffer.ReadBits(5);
                if (_debugOutputLoadingProgress)
                {
                    Debug.WriteLine(String.Format("BookmarkCount = {0}", BookmarkCount));
                }
                if (BookmarkCount > 1)
                {
                    throw new Exceptions.UnitObjectNotImplementedException("Unexpected BookmarkCount (> 1)!\nNot-Implemented cases. Please report this error and supply the offending file.");
                }

                for (int i = 0; i < BookmarkCount; i++)
                {
                    Bookmark bookmark = new Bookmark
                    {
                        Code = _bitBuffer.ReadUInt16(),
                        Offset = _bitBuffer.ReadInt32()
                    };
                    if (_debugOutputLoadingProgress)
                    {
                        Debug.WriteLine(String.Format("Bookmarks[{0}].Code = {1} (0x{1:X4}), Bookmarks[{0}].Offset = {2}", i, bookmark.Code, bookmark.Offset));
                    }

                    Bookmarks.Add(bookmark);
                }
            }

            // dunno...
            if (_TestBit(Bits.Bit05Unknown))
            {
                UnitObjectId = _bitBuffer.ReadInt32();
                if (_debugOutputLoadingProgress)
                {
                    Debug.WriteLine(String.Format("UnitObjectId = {0} (0x{0:X4})", UnitObjectId));
                }
            }

            // unit type/code
            // if unit type == 1, table = 0x91 (PLAYERS)
            //                 2, table = 0x77 (MONSTERS)
            //                 3? (table = 0x72; MISSILES at a guess. For memory, MISSILES doesn't use code values - probably why not seen in ASM)
            //                 4, table = 0x67 (ITEMS)
            //                 5, table = 0x7B (OBJECTS)
            UnitType = (UnitTypes)_bitBuffer.ReadBits(4);
            if (_debugOutputLoadingProgress)
            {
                Debug.WriteLine(String.Format("UnitType = {0}", UnitType));
            }
            UnitCode = _bitBuffer.ReadUInt16();
            if (_debugOutputLoadingProgress)
            {
                Debug.Write(String.Format("UnitCode = {0} (0x{0:X4}), ", UnitCode));
            }
            Xls.TableCodes tableCode = Xls.TableCodes.Null;
            switch (UnitType)
            {
                case UnitTypes.Player:  tableCode = Xls.TableCodes.PLAYERS;  break;
                case UnitTypes.Monster: tableCode = Xls.TableCodes.MONSTERS; break;
                case UnitTypes.Missile: tableCode = Xls.TableCodes.MISSILES; break;
                case UnitTypes.Item:    tableCode = Xls.TableCodes.ITEMS;    break;
                case UnitTypes.Object:  tableCode = Xls.TableCodes.OBJECTS;  break;
            }
            if (tableCode == Xls.TableCodes.Null) throw new Exceptions.UnitObjectException("The unit object data has an unknown UnitType.");
            UnitData = FileManager.GetUnitDataRowFromCode(tableCode, (short)UnitCode);
            if (UnitData == null) Debug.WriteLine(String.Format("Warning: UnitCode {0} (0x{0:X4}) not found!", UnitCode));
            if (_debugOutputLoadingProgress && UnitData != null)
            {
                ExcelFile unitDataTable = FileManager.GetExcelTableFromCode(tableCode);
                String rowName = unitDataTable.ReadStringTable(UnitData.name);
                Debug.WriteLine(String.Format("UnitDataName = " + rowName));
            }

            // unit object id
            if (_TestBit(Bits.Bit17ObjectId))
            {
                if (_version > 0xB2)
                {
                    ObjectId = _bitBuffer.ReadUInt64();
                    if (_debugOutputLoadingProgress)
                    {
                        Debug.WriteLine(String.Format("ObjectId = {0} (0x{0:X16})", ObjectId));
                    }

                    if (ObjectId == 0)
                    {
                        throw new Exceptions.UnitObjectNotImplementedException("if (ObjectId == 0)");
                    }
                }
            }

            // item positioning stuff
            if (_TestBit(Bits.Bit01Unknown) || _TestBit(Bits.Bit03Unknown))
            {
                IsInventory = _bitBuffer.ReadBool();
                if (_debugOutputLoadingProgress)
                {
                    Debug.WriteLine(String.Format("IsInventory = {0}, Bits.Bit01Unknown = {1}, Bits.Bit03Unknown = {2}", IsInventory, _TestBit(Bits.Bit01Unknown), _TestBit(Bits.Bit03Unknown)));
                }

                if (IsInventory) // item is in inventory
                {
                    if (_TestBit(Bits.Bit02Unknown))
                    {
                        Unknown02 = _bitBuffer.ReadBits(32);
                        if (_debugOutputLoadingProgress)
                        {
                            Debug.WriteLine(String.Format("Unknown02 = {0}", Unknown02));
                        }
                    }

                    InventoryLocationIndex = _bitBuffer.ReadBits(12);
                    InventoryPositionX = _bitBuffer.ReadBits(12);
                    InventoryPositionY = _bitBuffer.ReadBits(12);
                    Unknown04 = _bitBuffer.ReadBits(4);
                    if (_debugOutputLoadingProgress)
                    {
                        Debug.WriteLine(String.Format("InventoryLocationIndex = {0}, InventoryPositionX = {1}, InventoryPositionY = {2}, Unknown04 = {3}",
                            InventoryLocationIndex, InventoryPositionX, InventoryPositionY, Unknown04));
                    }

                    Unknown0103Int64 = _bitBuffer.ReadNonStandardFunc();
                    if (_debugOutputLoadingProgress)
                    {
                        Debug.WriteLine(String.Format("Unknown0103Int64 = {0} (0x{0:X16})", Unknown0103Int64));
                    }
                }
                else // item is a "world drop"
                {
                    RoomId = _bitBuffer.ReadInt32();

                    Position.X = _bitBuffer.ReadFloat();
                    Position.Y = _bitBuffer.ReadFloat();
                    Position.Z = _bitBuffer.ReadFloat();

                    Unknown0103Float21 = _bitBuffer.ReadFloat();
                    Unknown0103Float22 = _bitBuffer.ReadFloat();
                    Unknown0103Float23 = _bitBuffer.ReadFloat();

                    Normal.X = _bitBuffer.ReadFloat();
                    Normal.Y = _bitBuffer.ReadFloat();
                    Normal.Z = _bitBuffer.ReadFloat();

                    Unknown0103Int2 = _bitBuffer.ReadBits(10);

                    Unknown0103Float4 = _bitBuffer.ReadFloat();

                    Unknown0103Float5 = _bitBuffer.ReadFloat();

                    if (_debugOutputLoadingProgress)
                    {
                        Debug.WriteLine(String.Format("RoomId = {0}", RoomId));
                        Debug.WriteLine(String.Format("Position.X = {0}, Position.Y = {1}, Position.Z = {2}", Position.X, Position.Y, Position.Z));
                        Debug.WriteLine(String.Format("Unknown0103Float21 = {0}, Unknown0103Float22 = {1}, Unknown0103Float23 = {2}", Unknown0103Float21, Unknown0103Float22, Unknown0103Float23));
                        Debug.WriteLine(String.Format("NormalX = {0}, NormalY = {1}, NormalZ = {2}", Normal.X, Normal.Y, Normal.Z));
                        Debug.WriteLine(String.Format("Unknown0103Int2 = {0}", Unknown0103Int2));
                        Debug.WriteLine(String.Format("Unknown0103Float4 = {0}", Unknown0103Float4));
                        Debug.WriteLine(String.Format("Unknown0103Float5 = {0}", Unknown0103Float5));
                    }
                }
            }

            // I think this has something to do with the Monsters table +46Ch, bit 0x55 = 4 bits or bit 0x47 = 2 bits. Or Objects table +46Ch, bit 0x55 = 2 bits... Something like that
            if (_TestBit(Bits.Bit06Unknown))
            {
                UnknownBool06 = _bitBuffer.ReadBool();
                if (_debugOutputLoadingProgress)
                {
                    Debug.WriteLine(String.Format("UnknownBool06 = {0}", UnknownBool06));
                }
                if (!UnknownBool06)
                {
                    throw new Exceptions.UnitObjectNotImplementedException("if (UnknownBool06 != 1)");
                }
            }

            if (_TestBit(Bits.Bit09ItemLookGroup))
            {
                ItemLookGroupCode = _bitBuffer.ReadBits(8);
                if (_debugOutputLoadingProgress)
                {
                    Debug.WriteLine(String.Format("ItemLookGroupCode = {0} (0x{0:X2})", ItemLookGroupCode));
                }
            }

            // on character only
            if (_TestBit(Bits.Bit07CharacterShape))
            {
                CharacterHeight = _bitBuffer.ReadByte();
                CharacterBulk = _bitBuffer.ReadByte();
                if (_debugOutputLoadingProgress)
                {
                    Debug.WriteLine(String.Format("CharacterHeight = {0}, CharacterBulk = {1}", CharacterHeight, CharacterBulk));
                }
            }

            // object id for older versions - they moved it?
            if (_TestBit(Bits.Bit17ObjectId))
            {
                if (_version <= 0xB2)
                {
                    throw new Exceptions.UnitObjectNotImplementedException("if (_TestBit(0x17) && Version <= 0xB2)");
                }
            }

            // on character only
            if (_TestBit(Bits.Bit08CharacterName))
            {
                int unicodeCharCount = _bitBuffer.ReadBits(8);
                if (unicodeCharCount > 0)
                {
                    int byteCount = unicodeCharCount * 2; // is Unicode string without \0
                    _charNameBytes = new byte[byteCount];
                    for (int i = 0; i < byteCount; i++)
                    {
                        _charNameBytes[i] = _bitBuffer.ReadByte();
                    }
                    Name = Encoding.Unicode.GetString(_charNameBytes, 0, byteCount);
                    if (_debugOutputLoadingProgress)
                    {
                        Debug.WriteLine(String.Format("Name = {0}", Name));
                    }
                }
            }

            // on both character and items - appears to be always zero for items
            if (_TestBit(Bits.Bit0AStates2))
            {
                int stateCount = _bitBuffer.ReadBits(8);
                if (_debugOutputLoadingProgress)
                {
                    Debug.WriteLine(String.Format("StateCode2Count = {0}", stateCount));
                }

                for (int i = 0; i < stateCount; i++)
                {
                    int state = _bitBuffer.ReadInt16();
                    AddState2(state);
                    if (_debugOutputLoadingProgress)
                    {
                        Debug.WriteLine(String.Format("StateCodes2[{0}] = {1}({2:X})", i, StateCodes2[i], (short)(StateCodes2[i])));
                    }

                    // this section looks like it has more reading if Bit14 is flagged (CharSelectStats)
                }
            }

            if (_context > ObjectContext.CharSelect && (_context <= ObjectContext.Unknown6 || _context != ObjectContext.Unknown7)) // so if == 0, 1, 2, 7, then *don't* do this
            {
                ContextBool = _bitBuffer.ReadBool();
                if (ContextBool)
                {
                    ContextBoolValue = _bitBuffer.ReadBits(4); // invlocidx??
                }

                if (_debugOutputLoadingProgress)
                {
                    Debug.WriteLine(String.Format("UsageBool = {0}, UsageBoolValue = {1}", ContextBool, ContextBoolValue));
                }
            }

            // <unknown bitfield 0x11th bit> - only seen as false anyways

            IsDead = _bitBuffer.ReadBool();
            if (_debugOutputLoadingProgress)
            {
                Debug.WriteLine(String.Format("IsDead = {0}", IsDead));
            }

            // unit stats
            if (_TestBit(Bits.Bit0DStats))
            {
                Stats.ReadStats(_bitBuffer, true);
            }
            else if (_TestBit(Bits.Bit14CharSelectStats))
            {
                int characterLevel = _bitBuffer.ReadByte(); // stats row 0x000 (level)
                Stats.SetStat("level", characterLevel);

                int characterPvpRankRowIndex = _bitBuffer.ReadByte(); // stats row 0x347 (player_rank)
                Stats.SetStat("player_rank", characterPvpRankRowIndex);

                if (_debugOutputLoadingProgress)
                {
                    Debug.WriteLine(String.Format("LevelRowIndex = {0}, PlayerRankRowIndex = {1}", characterLevel, characterPvpRankRowIndex));
                }

                if (_TestBit(Bits.Bit1ECharSelectStatsMaxDifficulty))
                {
                    int maxDifficultyRowIndex = _bitBuffer.ReadBits(3); // stats row 0x347 (difficulty_max)
                    Stats.SetStat("difficulty_max", maxDifficultyRowIndex);

                    if (_debugOutputLoadingProgress)
                    {
                        Debug.WriteLine(String.Format("MaxDifficultyRowIndex = {0}, ", maxDifficultyRowIndex));
                    }
                }
            }

            HasAppearanceDetails = _bitBuffer.ReadBool();
            if (_debugOutputLoadingProgress)
            {
                Debug.WriteLine(String.Format("HasAppearanceDetails = {0}", HasAppearanceDetails));
            }
            if (HasAppearanceDetails)
            {
                _ReadAppearance();
            }

            if (_TestBit(Bits.Bit12Items))
            {
                ItemEndBitOffset = _bitBuffer.ReadInt32();
                ItemCount = _bitBuffer.ReadBits(10);
                if (_debugOutputLoadingProgress)
                {
                    Debug.WriteLine(String.Format("ItemEndBitOffset = {0}, ItemCount = {1}", ItemEndBitOffset, ItemCount));
                }

                for (int i = 0; i < ItemCount; i++)
                {
                    UnitObject item = new UnitObject(_bitBuffer, _debugOutputLoadingProgress);
                    item._ReadUnit();
                    Items.Add(item);
                }
            }

            if (_TestBit(Bits.Bit1AHotkeys))
            {
                HotkeyFlag = _bitBuffer.ReadUInt32();
                if (_debugOutputLoadingProgress)
                {
                    Debug.WriteLine(String.Format("HotkeyFlag = {0} (0x{0:X8})", HotkeyFlag));
                }
                if (HotkeyFlag != HotkeysMagicWord)
                {
                    throw new Exceptions.UnexpectedTokenException(HotkeysMagicWord, HotkeyFlag);
                }

                EndFlagBitOffset = _bitBuffer.ReadBits(32);     // to end flag
                if (_debugOutputLoadingProgress)
                {
                    Debug.WriteLine(String.Format("EndFlagBitOffset = {0}", EndFlagBitOffset));
                }

                HotkeyCount = _bitBuffer.ReadBits(6);
                if (_debugOutputLoadingProgress)
                {
                    Debug.WriteLine(String.Format("HotkeyCount = {0}", HotkeyCount));
                }
                for (int i = 0; i < HotkeyCount; i++)
                {
                    Hotkey hotkey = new Hotkey
                    {
                        Code = _bitBuffer.ReadUInt16(), // code from TAG table
                    };
                    Hotkeys.Add(hotkey);
                    if (_debugOutputLoadingProgress)
                    {
                        Debug.WriteLine(String.Format("hotkey.Code = 0x{0:X4}", hotkey.Code));
                    }

                    hotkey.UnknownCount = _bitBuffer.ReadBits(4);
                    if (_debugOutputLoadingProgress)
                    {
                        Debug.WriteLine(String.Format("hotkey.UnknownCount = " + hotkey.UnknownCount));
                    }
                    if (hotkey.UnknownCount > 0x02)
                    {
                        throw new Exceptions.UnitObjectNotImplementedException("if (hotkey.UnknownCount > 0x02)");
                    }

                    hotkey.UnknownExists = new bool[hotkey.UnknownCount];
                    hotkey.UnknownValues = new int[hotkey.UnknownCount];
                    for (int j = 0; j < hotkey.UnknownCount; j++)
                    {
                        hotkey.UnknownExists[j] = _bitBuffer.ReadBool();
                        if (hotkey.UnknownExists[j])
                        {
                            hotkey.UnknownValues[j] = _bitBuffer.ReadBits(32); // under some condition this will be ReadFromOtherFunc thingy
                        }
                        if (_debugOutputLoadingProgress)
                        {
                            Debug.WriteLine(String.Format("hotkey.UnknownExists[{0}] = {1}, hotkey.UnknownValues[{0}] = 0x{2:X8}", j, hotkey.UnknownExists[j], hotkey.UnknownValues[j]));
                        }
                    }

                    hotkey.SkillCount = _bitBuffer.ReadBits(4);
                    hotkey.SkillExists = new bool[hotkey.SkillCount];
                    hotkey.SkillCode = new int[hotkey.SkillCount];
                    for (int j = 0; j < hotkey.SkillCount; j++)
                    {
                        hotkey.SkillExists[j] = _bitBuffer.ReadBool();
                        if (hotkey.SkillExists[j])
                        {
                            hotkey.SkillCode[j] = _bitBuffer.ReadBits(32); // code from SKILLS table
                        }
                        if (_debugOutputLoadingProgress)
                        {
                            Debug.WriteLine(String.Format("hotkey.SkillExists[{0}] = {1}, hotkey.SkillCode[{0}] = 0x{2:X8}", j, hotkey.SkillExists[j], hotkey.SkillCode[j]));
                        }
                    }

                    hotkey.UnitTypeCode = _bitBuffer.ReadBits(32); // code from UNITTYPES table
                    if (_debugOutputLoadingProgress)
                    {
                        Debug.WriteLine(String.Format("hotkey.UnitTypeCode = 0x{0:X8}", hotkey.UnitTypeCode));
                    }
                }
            }

            // end flag
            EndFlag = _bitBuffer.ReadBits(32);
            if (_debugOutputLoadingProgress)
            {
                Debug.WriteLine(String.Format("EndFlag = {0} (0x{0:X8})", EndFlag));
            }

            if (EndFlag != _beginFlag && EndFlag != ItemMagicWord)
            {
                int bitOffset = _bitCount - _bitBuffer.BitOffset;
                int byteOffset = (_bitBuffer.Length - _bitBuffer.Offset) - (_bitBuffer.BytesUsed);
                throw new Exceptions.InvalidFileException("Flags not aligned!\nBit Offset: " + _bitBuffer.BitOffset + "\nExpected: " + _bitCount + " (+" + bitOffset +
                                                          ")\nBytes Used: " + (_bitBuffer.BytesUsed) + "\nExpected: " + (_bitBuffer.Length - _bitBuffer.Offset) + " (+" + byteOffset + ")");
            }

            if (_TestBit(Bits.Bit1DBitCountEof)) // no reading is done in here
            {
                // todo: do check that we're at the EoF bit count etc
            }
        }