chore(lua): refactor addon Lua engine API + progress docs

- Refactor Lua addon integration:
  - Update CMakeLists.txt for addon build paths
  - Enhance addons API headers and Lua engine interface
  - Add new Lua API addon modules (`lua_api_helpers`, `lua_api_registrations`, `lua_services`, `lua_action_api`, `lua_inventory_api`, `lua_quest_api`, `lua_social_api`, `lua_spell_api`, `lua_system_api`, `lua_unit_api`)
  - Update implementation in addon_manager.cpp, lua_engine.cpp, application.cpp, game_handler.cpp
This commit is contained in:
Paul 2026-04-03 07:31:06 +03:00
parent 6e02b4451c
commit a916270a13
21 changed files with 6183 additions and 6700 deletions

View file

@ -13,7 +13,7 @@ public:
AddonManager();
~AddonManager();
bool initialize(game::GameHandler* gameHandler);
bool initialize(game::GameHandler* gameHandler, const LuaServices& services = {});
void scanAddons(const std::string& addonsPath);
void loadAllAddons();
bool runScript(const std::string& code);
@ -35,6 +35,7 @@ private:
LuaEngine luaEngine_;
std::vector<TocFile> addons_;
game::GameHandler* gameHandler_ = nullptr;
LuaServices luaServices_;
std::string addonsPath_;
bool loadAddon(const TocFile& addon);

View file

@ -0,0 +1,166 @@
// lua_api_helpers.hpp — Shared helpers, lookup tables, and utility functions
// used by all lua_*_api.cpp domain files.
// Extracted from lua_engine.cpp as part of §5.1 (Tame LuaEngine).
#pragma once
#include <string>
#include <chrono>
#include <cstring>
#include <algorithm>
#include "addons/lua_services.hpp"
#include "game/game_handler.hpp"
#include "game/entity.hpp"
#include "game/update_field_table.hpp"
#include "core/logger.hpp"
extern "C" {
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
}
namespace wowee::addons {
// ---- String helper ----
inline void toLowerInPlace(std::string& s) {
for (char& c : s) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
}
// ---- Lua return helpers — used 200+ times as guard/fallback returns ----
inline int luaReturnNil(lua_State* L) { lua_pushnil(L); return 1; }
inline int luaReturnZero(lua_State* L) { lua_pushnumber(L, 0); return 1; }
inline int luaReturnFalse(lua_State* L){ lua_pushboolean(L, 0); return 1; }
// ---- Shared GetTime() epoch ----
// All time-returning functions must use this same origin
// so that addon calculations like (start + duration - GetTime()) are consistent.
inline const auto& luaTimeEpoch() {
static const auto epoch = std::chrono::steady_clock::now();
return epoch;
}
inline double luaGetTimeNow() {
return std::chrono::duration<double>(std::chrono::steady_clock::now() - luaTimeEpoch()).count();
}
// ---- Shared WoW class/race/power name tables (indexed by ID, element 0 = unknown) ----
inline constexpr const char* kLuaClasses[] = {
"","Warrior","Paladin","Hunter","Rogue","Priest",
"Death Knight","Shaman","Mage","Warlock","","Druid"
};
inline constexpr const char* kLuaRaces[] = {
"","Human","Orc","Dwarf","Night Elf","Undead",
"Tauren","Gnome","Troll","","Blood Elf","Draenei"
};
inline constexpr const char* kLuaPowerNames[] = {
"MANA","RAGE","FOCUS","ENERGY","HAPPINESS","","RUNIC_POWER"
};
// ---- Quality hex strings ----
// No alpha prefix — for item links
inline constexpr const char* kQualHexNoAlpha[] = {
"9d9d9d","ffffff","1eff00","0070dd","a335ee","ff8000","e6cc80","e6cc80"
};
// With ff alpha prefix — for Lua color returns
inline constexpr const char* kQualHexAlpha[] = {
"ff9d9d9d","ffffffff","ff1eff00","ff0070dd","ffa335ee","ffff8000","ffe6cc80","ff00ccff"
};
// ---- Retrieve GameHandler pointer stored in Lua registry ----
inline game::GameHandler* getGameHandler(lua_State* L) {
lua_getfield(L, LUA_REGISTRYINDEX, "wowee_game_handler");
auto* gh = static_cast<game::GameHandler*>(lua_touserdata(L, -1));
lua_pop(L, 1);
return gh;
}
// ---- Retrieve LuaServices pointer stored in Lua registry ----
inline LuaServices* getLuaServices(lua_State* L) {
lua_getfield(L, LUA_REGISTRYINDEX, "wowee_lua_services");
auto* svc = static_cast<LuaServices*>(lua_touserdata(L, -1));
lua_pop(L, 1);
return svc;
}
// ---- Unit resolution helpers ----
// Read UNIT_FIELD_TARGET_LO/HI from an entity's update fields to get what it's targeting
inline uint64_t getEntityTargetGuid(game::GameHandler* gh, uint64_t guid) {
if (guid == 0) return 0;
// If asking for the player's target, use direct accessor
if (guid == gh->getPlayerGuid()) return gh->getTargetGuid();
auto entity = gh->getEntityManager().getEntity(guid);
if (!entity) return 0;
const auto& fields = entity->getFields();
auto loIt = fields.find(game::fieldIndex(game::UF::UNIT_FIELD_TARGET_LO));
if (loIt == fields.end()) return 0;
uint64_t targetGuid = loIt->second;
auto hiIt = fields.find(game::fieldIndex(game::UF::UNIT_FIELD_TARGET_HI));
if (hiIt != fields.end())
targetGuid |= (static_cast<uint64_t>(hiIt->second) << 32);
return targetGuid;
}
// Resolve WoW unit IDs to GUID
inline uint64_t resolveUnitGuid(game::GameHandler* gh, const std::string& uid) {
if (uid == "player") return gh->getPlayerGuid();
if (uid == "target") return gh->getTargetGuid();
if (uid == "focus") return gh->getFocusGuid();
if (uid == "mouseover") return gh->getMouseoverGuid();
if (uid == "pet") return gh->getPetGuid();
// Compound unit IDs: targettarget, focustarget, pettarget, mouseovertarget
if (uid == "targettarget") return getEntityTargetGuid(gh, gh->getTargetGuid());
if (uid == "focustarget") return getEntityTargetGuid(gh, gh->getFocusGuid());
if (uid == "pettarget") return getEntityTargetGuid(gh, gh->getPetGuid());
if (uid == "mouseovertarget") return getEntityTargetGuid(gh, gh->getMouseoverGuid());
// party1-party4, raid1-raid40
if (uid.rfind("party", 0) == 0 && uid.size() > 5) {
int idx = 0;
try { idx = std::stoi(uid.substr(5)); } catch (...) { return 0; }
if (idx < 1 || idx > 4) return 0;
const auto& pd = gh->getPartyData();
// party members exclude self; index 1-based
int found = 0;
for (const auto& m : pd.members) {
if (m.guid == gh->getPlayerGuid()) continue;
if (++found == idx) return m.guid;
}
return 0;
}
if (uid.rfind("raid", 0) == 0 && uid.size() > 4 && uid[4] != 'p') {
int idx = 0;
try { idx = std::stoi(uid.substr(4)); } catch (...) { return 0; }
if (idx < 1 || idx > 40) return 0;
const auto& pd = gh->getPartyData();
if (idx <= static_cast<int>(pd.members.size()))
return pd.members[idx - 1].guid;
return 0;
}
return 0;
}
// Resolve unit IDs (player, target, focus, mouseover, pet, targettarget, etc.) to entity
inline game::Unit* resolveUnit(lua_State* L, const char* unitId) {
auto* gh = getGameHandler(L);
if (!gh || !unitId) return nullptr;
std::string uid(unitId);
toLowerInPlace(uid);
uint64_t guid = resolveUnitGuid(gh, uid);
if (guid == 0) return nullptr;
auto entity = gh->getEntityManager().getEntity(guid);
if (!entity) return nullptr;
return dynamic_cast<game::Unit*>(entity.get());
}
// Find GroupMember data for a GUID (for party members out of entity range)
inline const game::GroupMember* findPartyMember(game::GameHandler* gh, uint64_t guid) {
if (!gh || guid == 0) return nullptr;
for (const auto& m : gh->getPartyData().members) {
if (m.guid == guid && m.hasPartyStats) return &m;
}
return nullptr;
}
} // namespace wowee::addons

View file

@ -0,0 +1,18 @@
// lua_api_registrations.hpp — Forward declarations for per-domain Lua API
// registration functions. Called from LuaEngine::registerCoreAPI().
// Extracted from lua_engine.cpp as part of §5.1 (Tame LuaEngine).
#pragma once
struct lua_State;
namespace wowee::addons {
void registerUnitLuaAPI(lua_State* L);
void registerSpellLuaAPI(lua_State* L);
void registerInventoryLuaAPI(lua_State* L);
void registerQuestLuaAPI(lua_State* L);
void registerSocialLuaAPI(lua_State* L);
void registerSystemLuaAPI(lua_State* L);
void registerActionLuaAPI(lua_State* L);
} // namespace wowee::addons

View file

@ -1,5 +1,6 @@
#pragma once
#include "addons/lua_services.hpp"
#include <functional>
#include <string>
#include <vector>
@ -27,6 +28,7 @@ public:
bool executeString(const std::string& code);
void setGameHandler(game::GameHandler* handler);
void setLuaServices(const LuaServices& services);
// Fire a WoW event to all registered Lua handlers.
void fireEvent(const std::string& eventName,
@ -55,6 +57,7 @@ public:
private:
lua_State* L_ = nullptr;
game::GameHandler* gameHandler_ = nullptr;
LuaServices luaServices_;
LuaErrorCallback luaErrorCallback_;
void registerCoreAPI();

View file

@ -0,0 +1,17 @@
// lua_services.hpp — Dependency-injected services for Lua bindings.
// Replaces Application::getInstance() calls in domain API files (§5.2).
#pragma once
namespace wowee::core { class Window; }
namespace wowee::audio { class AudioCoordinator; }
namespace wowee::game { class ExpansionRegistry; }
namespace wowee::addons {
struct LuaServices {
core::Window* window = nullptr;
audio::AudioCoordinator* audioCoordinator = nullptr;
game::ExpansionRegistry* expansionRegistry = nullptr;
};
} // namespace wowee::addons