Kelsidavis-WoWee/include/pipeline/dbc_loader.hpp
Kelsi b0466e9029 perf: eliminate ~70 unnecessary sqrt ops per frame, optimize caches and threading
Squared distance optimizations across 30 files:
- Convert glm::length() comparisons to glm::dot() (no sqrt)
- Use glm::inversesqrt() for check-then-normalize patterns (1 rsqrt vs 2 sqrt)
- Defer sqrt to after early-out checks in collision/movement code
- Hottest paths: camera_controller (21), weather particles, WMO collision,
  transport movement, creature interpolation, nameplate culling

Container and algorithm improvements:
- std::map<string> → std::unordered_map for asset/DBC/MPQ/warden caches
- std::mutex → std::shared_mutex for asset_manager and mpq_manager caches
- std::sort → std::partial_sort in lighting_manager (top-2 of N volumes)
- Double-lookup find()+operator[] → insert_or_assign in game_handler
- Add reserve() for per-frame vectors: weather, swim_effects, WMO/M2 collision

Threading and synchronization:
- Replace 1ms busy-wait polling with condition_variable in character_renderer
- Move timestamp capture before mutex in logger
- Use memory_order_acquire/release for normal map completion signaling

API additions:
- DBC getStringView()/getStringViewByOffset() for zero-copy string access
- Parse creature display IDs from SMSG_CREATURE_QUERY_SINGLE_RESPONSE
2026-03-27 16:33:16 -07:00

153 lines
4.1 KiB
C++

#pragma once
#include <vector>
#include <map>
#include <string>
#include <string_view>
#include <cstdint>
#include <memory>
namespace wowee {
namespace pipeline {
/**
* DBC File - WoW Database Client file
*
* DBC files store game database tables (spells, items, maps, creatures, etc.)
* Format: Fixed header + fixed-size records + string block
* Format specification: https://wowdev.wiki/DBC
*/
class DBCFile {
public:
DBCFile();
~DBCFile();
/**
* Load DBC file from byte data
* @param dbcData Raw DBC file data
* @return true if loaded successfully
*/
[[nodiscard]] bool load(const std::vector<uint8_t>& dbcData);
/**
* Check if DBC is loaded
*/
bool isLoaded() const { return loaded; }
/**
* Get record count
*/
uint32_t getRecordCount() const { return recordCount; }
/**
* Get field count (number of 32-bit fields per record)
*/
uint32_t getFieldCount() const { return fieldCount; }
/**
* Get record size in bytes
*/
uint32_t getRecordSize() const { return recordSize; }
/**
* Get string block size
*/
uint32_t getStringBlockSize() const { return stringBlockSize; }
/**
* Get a record by index
* @param index Record index (0 to recordCount-1)
* @return Pointer to record data (recordSize bytes) or nullptr
*/
const uint8_t* getRecord(uint32_t index) const;
/**
* Get a 32-bit integer field from a record
* @param recordIndex Record index
* @param fieldIndex Field index (0 to fieldCount-1)
* @return Field value
*/
uint32_t getUInt32(uint32_t recordIndex, uint32_t fieldIndex) const;
/**
* Get a 32-bit signed integer field from a record
* @param recordIndex Record index
* @param fieldIndex Field index
* @return Field value
*/
int32_t getInt32(uint32_t recordIndex, uint32_t fieldIndex) const;
/**
* Get a float field from a record
* @param recordIndex Record index
* @param fieldIndex Field index
* @return Field value
*/
float getFloat(uint32_t recordIndex, uint32_t fieldIndex) const;
/**
* Get a string field from a record
* @param recordIndex Record index
* @param fieldIndex Field index (contains string offset)
* @return String value
*/
std::string getString(uint32_t recordIndex, uint32_t fieldIndex) const;
/**
* Get a string field as a view (no allocation; valid while this DBCFile lives)
*/
std::string_view getStringView(uint32_t recordIndex, uint32_t fieldIndex) const;
/**
* Get string by offset in string block
* @param offset Offset into string block
* @return String value
*/
std::string getStringByOffset(uint32_t offset) const;
/**
* Get string by offset as a view (no allocation; valid while this DBCFile lives)
*/
std::string_view getStringViewByOffset(uint32_t offset) const;
/**
* Find a record by ID (assumes first field is ID)
* @param id Record ID to find
* @return Record index or -1 if not found
*/
int32_t findRecordById(uint32_t id) const;
private:
// DBC file header (20 bytes)
struct DBCHeader {
char magic[4]; // 'WDBC'
uint32_t recordCount; // Number of records
uint32_t fieldCount; // Number of fields per record
uint32_t recordSize; // Size of each record in bytes
uint32_t stringBlockSize; // Size of string block
};
bool loaded = false;
uint32_t recordCount = 0;
uint32_t fieldCount = 0;
uint32_t recordSize = 0;
uint32_t stringBlockSize = 0;
std::vector<uint8_t> recordData; // All record data
std::vector<uint8_t> stringBlock; // String block
// Cache for record ID -> index lookup
mutable std::map<uint32_t, uint32_t> idToIndexCache;
mutable bool idCacheBuilt = false;
void buildIdCache() const;
/**
* Load from CSV text format (produced by dbc_to_csv tool).
* Rebuilds the same in-memory layout as binary load.
*/
bool loadCSV(const std::vector<uint8_t>& csvData);
};
} // namespace pipeline
} // namespace wowee