private Stat _ReadStat(BitBuffer bitBuffer, UnitObjectStats statBlock) { Stat stat = new Stat(); int statIndex = statBlock.Stats.Count; int valueShift = 0; int valueOffset = 0; bool isOffset = false; StatsRow statData; int valueBitCount; int[] paramsBitCounts = new int[MaxParams]; if (statBlock.Context == StatContext.UseRows) { int rowIndex = bitBuffer.ReadBits(11); // todo: make this a static value - this bit count is determined by FileManager._GetTableRowBitMax() of the Stats row count statData = stat.StatRow = _fileManager.GetStatRowFromIndex(rowIndex); if (statData == null) throw new Exceptions.UnitObjectException(String.Format("Error stats[{0}].RowIndex = {1} not found.\nCannot have null stat - not known param count will break bit offset.", statIndex, rowIndex)); valueBitCount = statData.valbits; if (statData.ParamCount > 0 && bitBuffer.ReadBool()) paramsBitCounts[0] = statData.param1Bits; if (statData.ParamCount > 1 && bitBuffer.ReadBool()) paramsBitCounts[1] = statData.param2Bits; if (statData.ParamCount > 2 && bitBuffer.ReadBool()) paramsBitCounts[2] = statData.param3Bits; if (statData.ParamCount > 3 && bitBuffer.ReadBool()) paramsBitCounts[3] = statData.param4Bits; if (_debugOutputLoadingProgress) { Debug.WriteLine(String.Format("stats[{0}].Name = {1}, .Code = {2} (0x{3:X4}), .ParamCount = {4}", statIndex, stat.Name, stat.Code, (uint)stat.Code, statData.ParamCount)); Xls.TableCodes tableCode = (stat.ValueTable == null) ? Xls.TableCodes.Null : stat.ValueTable.TableCode; int noValueTableCode = (stat.ValueTable == null) ? 1 : 0; Debug.WriteLine(String.Format("stats[{0}].NoValueTableCode = {1}, .ValueTableCode = 0x{2:X4}, .ValueTable = {3}", statIndex, noValueTableCode, (uint)tableCode, tableCode)); if (statData.ParamCount >= 1) Debug.WriteLine(String.Format("stats[{0}].Param1.BitCount = {1}, .Table = {2}", statIndex, paramsBitCounts[0], stat.Param1TableCode)); if (statData.ParamCount >= 2) Debug.WriteLine(String.Format("stats[{0}].Param2.BitCount = {1}, .Table = {2}", statIndex, paramsBitCounts[1], stat.Param2TableCode)); if (statData.ParamCount >= 3) Debug.WriteLine(String.Format("stats[{0}].Param3.BitCount = {1}, .Table = {2}", statIndex, paramsBitCounts[2], stat.Param3TableCode)); if (statData.ParamCount >= 4) Debug.WriteLine(String.Format("stats[{0}].Param4.BitCount = {1}, .Table = {2}", statIndex, paramsBitCounts[3], stat.Param4TableCode)); } } else { ushort code = bitBuffer.ReadUInt16(); statData = stat.StatRow = _fileManager.GetStatRowFromCode((short)code); if (stat.StatRow == null) throw new Exceptions.UnitObjectException(String.Format("Error: stat.Code = {0} (0x{0:X4}) not found.\nCannot have null stat - not known param count will break bit offset.", code)); int paramsCount = bitBuffer.ReadBits(2); if (_debugOutputLoadingProgress) { Debug.WriteLine(String.Format("stats[{0}].Name = {1}, stat.Code = {2} (0x{3:X4}), stat.ParamCount = {4}", statIndex, stat.Name, code, (uint)code, paramsCount)); } if (paramsCount > statData.ParamCount) Debug.WriteLine(String.Format("Unexpected large params count of {0}. Expecting count <= {1}", paramsCount, statData.ParamCount)); for (int i = 0; i < paramsCount; i++) { bool exists = bitBuffer.ReadBool(); if (!exists) continue; paramsBitCounts[i] = bitBuffer.ReadBits(6); int paramOperationsFlags = bitBuffer.ReadBits(2); int paramShift = 0; bool paramIsOffset = false; if ((paramOperationsFlags & 0x01) != 0) { paramShift = bitBuffer.ReadBits(3); } if ((paramOperationsFlags & 0x02) != 0) { paramIsOffset = bitBuffer.ReadBool(); } bool hasTableCode = !bitBuffer.ReadBool(); Xls.TableCodes paramTableCode = Xls.TableCodes.Null; if (hasTableCode) { paramTableCode = (Xls.TableCodes)bitBuffer.ReadUInt16(); Xls.TableCodes expetedTableCode = Xls.TableCodes.Null; switch (i) { case 0: expetedTableCode = stat.Param1TableCode; break; case 1: expetedTableCode = stat.Param2TableCode; break; case 2: expetedTableCode = stat.Param3TableCode; break; case 3: expetedTableCode = stat.Param4TableCode; break; } if (expetedTableCode != paramTableCode) throw new Exceptions.UnitObjectException(String.Format("Unexpected param value table supplied. Expecting {0}, got {1}", expetedTableCode, paramTableCode)); } if (_debugOutputLoadingProgress) { Debug.WriteLine(String.Format("stats[{0}].Param{1}.BitCount = {2}, .ParamOperationsFlags = {3}, .ParamShift = {4}, .ParamIsOffset = {5}, .HasTableCode = {6}, .TableCode = {7}, .Table = {8}", statIndex, i, paramsBitCounts[i], paramOperationsFlags, paramShift, paramIsOffset, hasTableCode, (uint)paramTableCode, paramTableCode)); } } valueBitCount = bitBuffer.ReadBits(6); int valueOperationsFlags = bitBuffer.ReadBits(3); if ((valueOperationsFlags & 0x01) != 0) { valueShift = bitBuffer.ReadBits(4); // valShift } if ((valueOperationsFlags & 0x02) != 0) { valueOffset = bitBuffer.ReadBits(12); // valOffset } if ((valueOperationsFlags & 0x04) != 0) { isOffset = bitBuffer.ReadBool(); } if (_debugOutputLoadingProgress) { Debug.WriteLine(String.Format("stats[{0}].BitCount = {1}, .ValueOperationsFlags = {2}, .ValueShift = {3}, .ValueOffset = {4}, .IsOffset = {5}", statIndex, valueBitCount, valueOperationsFlags, valueShift, valueOffset, isOffset)); } int noValueTableCode = bitBuffer.ReadBits(2); Debug.Assert(noValueTableCode != 2); // never seen... seen in stats column in Monsters table Xls.TableCodes tableCode = Xls.TableCodes.Null; if (noValueTableCode == 0) { tableCode = (Xls.TableCodes)bitBuffer.ReadUInt16(); Xls.TableCodes expectedTableCode = stat.ValueTableCode; if (expectedTableCode != tableCode) throw new Exceptions.UnitObjectException(String.Format("Unexpected stat value table supplied. Expecting {0}, got {1}", expectedTableCode, tableCode)); } if (_debugOutputLoadingProgress) { Debug.WriteLine(String.Format("stats[{0}].NoValueTableCode = {1}, .ValueTableCode = 0x{2:X4}, .ValueTable = {3}", statIndex, noValueTableCode, (uint)tableCode, tableCode)); } } bool hasMultipleValues = bitBuffer.ReadBool(); int valueCount = 1; if (hasMultipleValues) { int valueCountBits = (statBlock._version <= 7) ? 8 : 10; valueCount = bitBuffer.ReadBits(valueCountBits); } if (_debugOutputLoadingProgress) { Debug.WriteLine(String.Format("stats[{0}].HasMultipleValues = {1}, .ValueCount = {2}", statIndex, hasMultipleValues, valueCount)); } for (int i = 0; i < valueCount; i++) { Stat.StatValue statValue = new Stat.StatValue(); _ReadStatValue(bitBuffer, paramsBitCounts[0], ref statValue.Param1, stat.Param1Table, ref statValue.Param1Row, statBlock.Context); _ReadStatValue(bitBuffer, paramsBitCounts[1], ref statValue.Param2, stat.Param2Table, ref statValue.Param2Row, statBlock.Context); _ReadStatValue(bitBuffer, paramsBitCounts[2], ref statValue.Param3, stat.Param3Table, ref statValue.Param3Row, statBlock.Context); _ReadStatValue(bitBuffer, paramsBitCounts[3], ref statValue.Param4, stat.Param4Table, ref statValue.Param4Row, statBlock.Context); _ReadStatValue(bitBuffer, valueBitCount, ref statValue.Value, stat.ValueTable, ref statValue.ValueRow, statBlock.Context); // this seems to work // todo: do this for writing stats if (valueOffset == 0) valueOffset = (stat.StatRow.valOffs + stat.StatRow.offset); if (valueShift == 0) valueShift = (stat.StatRow.valShift - stat.StatRow.shift); statValue.Value -= valueOffset; // not going to bother with this for now statValue.Value <<= valueShift; // not sure what this is for either - possibly server-side to increase accuracy/value range I guess - but values aren't saved with it... //if (value.IsOffset) statValue.Value--; // do this to *row index* though, not code - not sure about non-table relations values... stat.Values.Add(statValue); if (_debugOutputLoadingProgress) { if (paramsBitCounts[0] > 0) Debug.WriteLine(String.Format("stats[{0}].Param1 = {1}", statIndex, statValue.Param1)); if (paramsBitCounts[1] > 0) Debug.WriteLine(String.Format("stats[{0}].Param2 = {1}", statIndex, statValue.Param2)); if (paramsBitCounts[2] > 0) Debug.WriteLine(String.Format("stats[{0}].Param3 = {1}", statIndex, statValue.Param3)); if (paramsBitCounts[3] > 0) Debug.WriteLine(String.Format("stats[{0}].Param4 = {1}", statIndex, statValue.Param4)); Debug.WriteLine(String.Format("stats[{0}].Value = {1}", statIndex, statValue.Value)); } } return stat; }
/// <summary> /// Read stats from a serialised byte array /// </summary> /// <param name="bitBuffer">The current buffer state.</param> /// <param name="stats">The stats block to populate.</param> /// <param name="readNameCount">TODO</param> public void ReadStats(BitBuffer bitBuffer, UnitObjectStats stats, bool readNameCount = false) { stats._version = bitBuffer.ReadBits(16); stats.Context = (StatContext)bitBuffer.ReadBits(3); if (_debugOutputLoadingProgress) { Debug.WriteLine(String.Format("stats.Version = {0}, stats.Context = {1} (0x{2:X2})", stats._version, stats.Context, (int)stats.Context)); } if (stats._version != 0x0A) { throw new Exceptions.NotSupportedVersionException("0x0A", "0x" + stats._version.ToString("X2")); } int statSelectorCount = bitBuffer.ReadBits(6); if (_debugOutputLoadingProgress) { Debug.WriteLine(String.Format("stats.StatSelectorCount = {0}", statSelectorCount)); } for (int i = 0; i < statSelectorCount; i++) { StatSelector statSelector = new StatSelector(); if (stats.Context == StatContext.UseRows) { statSelector.RowIndex = bitBuffer.ReadBits(5); statSelector.StatSelectorRow = (ExcelTablesRow)_fileManager.GetRowFromIndex(Xls.TableCodes.STATS_SELECTOR, statSelector.RowIndex); // StatsSelector table } else { statSelector.Code = bitBuffer.ReadUInt16(); statSelector.StatSelectorRow = (ExcelTablesRow)_fileManager.GetRowFromCode(Xls.TableCodes.STATS_SELECTOR, (short)statSelector.Code); // StatsSelector table } int selectorStatCount = bitBuffer.ReadInt16(); if (_debugOutputLoadingProgress) { Debug.WriteLine(String.Format("StatSelectors[{0}].Name = {1}, .Code = 0x{2:X4}, .RowIndex = {3}, .StatCount = {4}", i, statSelector.Name, statSelector.Code, statSelector.RowIndex, selectorStatCount)); } for (int j = 0; j < selectorStatCount; j++) { Stat stat = _ReadStat(bitBuffer, stats); statSelector.Stats.Add(stat); } stats.StatSelectors.Add(statSelector); } int statCount = bitBuffer.ReadBits(16); if (_debugOutputLoadingProgress) { Debug.WriteLine(String.Format("stats.StatCount = {0}", statCount)); } for (int i = 0; i < statCount; i++) { Stat stat = _ReadStat(bitBuffer, stats); stats.Stats[stat.StatRow.code] = stat; } if (!readNameCount) return; stats.NameCount = bitBuffer.ReadBits(8); if (_debugOutputLoadingProgress) { Debug.WriteLine(String.Format("stats.NameCount = {0}", stats.NameCount)); } for (int i = 0; i < stats.NameCount; i++) { StatName name = new StatName { Unknown1 = (short)bitBuffer.ReadBits(5), Stats = new UnitObjectStats(_fileManager, _version) }; if (_debugOutputLoadingProgress) { Debug.WriteLine(String.Format("stats.Unknown1 = {0}", name.Unknown1)); } ReadStats(bitBuffer, name.Stats, false); stats.Names.Add(name); } }