mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-24 07:23:51 +00:00
OpcodeTable::toWire was an unordered_map<uint16_t, uint16_t>::find() called from ~300 sites (some per-frame on movement opcode construction). LogicalOpcode is a dense uint16_t enum, so back the mapping with a plain std::vector<uint16_t> sized to max-seen and indexed directly. toWire() becomes a bounds check + one array read instead of hash + bucket walk. Loading still goes through an unordered_map scratch to let the recursive _extends/_remove loader work unchanged; the result is baked into the flat vector once at load time. fromWire stays a map since wire values are sparse across the 0..0xFFFF range.
90 lines
2.8 KiB
C++
90 lines
2.8 KiB
C++
#pragma once
|
|
|
|
#include <cstdint>
|
|
#include <string>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
#include <optional>
|
|
|
|
namespace wowee {
|
|
namespace game {
|
|
|
|
/**
|
|
* Logical opcode identifiers (expansion-agnostic).
|
|
*
|
|
* These are compile-time enum values used in switch statements.
|
|
* The actual wire values depend on the active expansion and are
|
|
* loaded from JSON at runtime via OpcodeTable.
|
|
*/
|
|
enum class LogicalOpcode : uint16_t {
|
|
// Generated from Data/opcodes/canonical.json
|
|
#include "game/opcode_enum_generated.inc"
|
|
|
|
// Sentinel
|
|
COUNT
|
|
};
|
|
|
|
/**
|
|
* Maps LogicalOpcode ↔ expansion-specific wire values.
|
|
*
|
|
* Loaded from JSON (e.g. Data/expansions/wotlk/opcodes.json).
|
|
* Used for sending packets (toWire) and receiving them (fromWire).
|
|
*/
|
|
class OpcodeTable {
|
|
public:
|
|
/**
|
|
* Load opcode mappings from a JSON file.
|
|
* Format:
|
|
* { "CMSG_PING": "0x1DC", "SMSG_AUTH_CHALLENGE": "0x1EC", ... }
|
|
* or a delta file with:
|
|
* { "_extends": "../classic/opcodes.json", "_remove": ["MSG_FOO"], ...overrides }
|
|
*/
|
|
bool loadFromJson(const std::string& path);
|
|
|
|
/** LogicalOpcode → wire value for sending packets. Returns 0xFFFF if unknown. */
|
|
uint16_t toWire(LogicalOpcode op) const;
|
|
|
|
/** Wire value → LogicalOpcode for receiving packets. Returns nullopt if unknown. */
|
|
std::optional<LogicalOpcode> fromWire(uint16_t wireValue) const;
|
|
|
|
/** Check if a logical opcode has a wire mapping. */
|
|
bool hasOpcode(LogicalOpcode op) const;
|
|
|
|
/** Number of mapped opcodes. */
|
|
size_t size() const { return logicalToWireSize_; }
|
|
|
|
/** Get canonical enum name for a logical opcode. */
|
|
static const char* logicalToName(LogicalOpcode op);
|
|
|
|
private:
|
|
// LogicalOpcode → wire. Flat dense vector indexed by LogicalOpcode value;
|
|
// toWire() then becomes a bounds check + array read instead of a hash lookup
|
|
// (wireOpcode() is called from ~300 sites, several per-frame on movement).
|
|
// Entries default to 0xFFFF meaning "unmapped".
|
|
std::vector<uint16_t> logicalToWire_;
|
|
size_t logicalToWireSize_ = 0; // count of mapped entries
|
|
|
|
std::unordered_map<uint16_t, uint16_t> wireToLogical_; // wire → LogicalOpcode (sparse)
|
|
|
|
static std::optional<LogicalOpcode> nameToLogical(const std::string& name);
|
|
};
|
|
|
|
/**
|
|
* Global active opcode table pointer (set by GameHandler at startup).
|
|
* Used by world_packets.cpp and other code that needs to send packets
|
|
* without direct access to a GameHandler instance.
|
|
*/
|
|
void setActiveOpcodeTable(const OpcodeTable* table);
|
|
const OpcodeTable* getActiveOpcodeTable();
|
|
|
|
/**
|
|
* Get the wire value for a logical opcode using the active table.
|
|
* Convenience helper for packet construction code.
|
|
*/
|
|
inline uint16_t wireOpcode(LogicalOpcode op) {
|
|
const auto* table = getActiveOpcodeTable();
|
|
return table ? table->toWire(op) : 0xFFFF;
|
|
}
|
|
|
|
} // namespace game
|
|
} // namespace wowee
|