1. using System;
  2. using System.Collections.Generic;
  3. namespace WowDBCExample
  4. {
  5. class DBC<T> : IEnumerable<T> where T : struct
  6. {
  7. private readonly WoWClientDB m_dbInfo;
  8. private readonly DBCFile m_fileHdr;
  9. public int MinIndex { get { return m_dbInfo.MinIndex; } }
  10. public int MaxIndex { get { return m_dbInfo.MaxIndex; } }
  11. public int NumRows { get { return m_dbInfo.NumRows; } }
  12. public T this[int index] { get { return WowMemory.Read<T>(GetRowPtr(index)); } }
  13. public bool HasRow(int index) { return GetRowPtr(index) != IntPtr.Zero; }
  14. /// <summary>
  15. /// Initializes a new instance of DBC class using specified memory address
  16. /// </summary>
  17. /// <param name="dbcBase">DBC memory address</param>
  18. public DBC(IntPtr dbcBase)
  19. {
  20. IntPtr addr = WowMemory.Rebase(dbcBase);
  21. m_dbInfo = WowMemory.Read<WoWClientDB>(addr);
  22. m_fileHdr = WowMemory.Read<DBCFile>(m_dbInfo.Data);
  23. }
  24. private IntPtr GetRowPtr(int index)
  25. {
  26. if (index < MinIndex || index > MaxIndex)
  27. return IntPtr.Zero;
  28. int actualIndex = index - MinIndex;
  29. int v5 = WowMemory.Read<int>(m_dbInfo.Unk1 + (4 * (actualIndex >> 5)));
  30. int a2a = (int)(actualIndex & 0x1Fu);
  31. if (((1 << a2a) & v5) != 0)
  32. {
  33. int bitsSet = CountBitsSet(v5 << (31 - a2a));
  34. int entry = bitsSet + GetArrayEntryBySizeType(m_dbInfo.Unk3, actualIndex >> 5) - 1;
  35. if (m_dbInfo.Unk2 == 0)
  36. {
  37. entry = GetArrayEntryBySizeType(m_dbInfo.Rows, entry);
  38. }
  39. return m_dbInfo.FirstRow + m_fileHdr.RecordSize * entry;
  40. }
  41. return IntPtr.Zero;
  42. }
  43. private int CountBitsSet(int a1)
  44. {
  45. return 0x1010101 *
  46. ((((a1 - ((a1 >> 1) & 0x55555555)) & 0x33333333) +
  47. (((a1 - ((a1 >> 1) & 0x55555555)) >> 2) & 0x33333333) +
  48. ((((a1 - ((a1 >> 1) & 0x55555555)) & 0x33333333) +
  49. (((a1 - ((a1 >> 1) & 0x55555555)) >> 2) & 0x33333333)) >> 4)) & 0x0F0F0F0F) >> 24;
  50. }
  51. private int GetArrayEntryBySizeType(IntPtr arrayPtr, int index)
  52. {
  53. if (m_dbInfo.RowEntrySize == 2)
  54. return WowMemory.Read<short>(arrayPtr + (2 * index));
  55. else
  56. return WowMemory.Read<int>(arrayPtr + (4 * index));
  57. }
  58. public IEnumerator<T> GetEnumerator()
  59. {
  60. for (uint i = 0; i < NumRows; ++i)
  61. yield return WowMemory.Read<T>(m_dbInfo.FirstRow + (int)(i * m_fileHdr.RecordSize));
  62. }
  63. System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
  64. {
  65. return GetEnumerator();
  66. }
  67. }
  68. }