// // Created by pmacc on 1/8/2025. // #pragma once #include "main.hpp" #include "lua_refs.hpp" #include #include #include namespace Nampower { // Field type enumeration enum class FieldType { INT32, UINT32, FLOAT, STRING, UINT64, UINT8 }; // Field descriptor for simple fields struct FieldDescriptor { const char* name; size_t offset; FieldType type; }; // Field descriptor for array fields struct ArrayFieldDescriptor { const char* name; size_t offset; FieldType type; size_t count; }; // ItemStats_C field descriptors extern const FieldDescriptor itemStatsFields[]; extern const size_t itemStatsFieldsCount; extern const ArrayFieldDescriptor itemStatsArrayFields[]; extern const size_t itemStatsArrayFieldsCount; // SpellRec field descriptors extern const FieldDescriptor spellRecFields[]; extern const size_t spellRecFieldsCount; extern const ArrayFieldDescriptor spellRecArrayFields[]; extern const size_t spellRecArrayFieldsCount; // Hash tables for O(1) field lookups extern std::unordered_map itemStatsFieldMap; extern std::unordered_map itemStatsArrayFieldMap; extern std::unordered_map spellRecFieldMap; extern std::unordered_map spellRecArrayFieldMap; // Initialize field maps (call once before using field lookups) void InitializeFieldMaps(); // Forward declarations for Lua functions (defined in offsets.hpp/misc_scripts.cpp/spell_scripts.cpp) using lua_pushnumberT = void (__fastcall *)(uintptr_t *, double); using lua_pushstringT = void (__fastcall *)(uintptr_t *, char *); using lua_newtableT = void (__fastcall *)(uintptr_t *); using lua_settableT = void (__fastcall *)(uintptr_t *, int); extern lua_pushnumberT lua_pushnumber; extern lua_pushstringT lua_pushstring; extern lua_newtableT lua_newtable; extern lua_settableT lua_settable; // Helper template functions to push fields to Lua (inline for performance) template inline void PushFieldsToLua(uintptr_t* luaState, const T* obj, const FieldDescriptor* fields, size_t fieldCount) { for (size_t i = 0; i < fieldCount; ++i) { const auto& field = fields[i]; lua_pushstring(luaState, const_cast(field.name)); const char* fieldPtr = reinterpret_cast(obj) + field.offset; switch (field.type) { case FieldType::INT32: lua_pushnumber(luaState, *reinterpret_cast(fieldPtr)); break; case FieldType::UINT32: lua_pushnumber(luaState, *reinterpret_cast(fieldPtr)); break; case FieldType::FLOAT: lua_pushnumber(luaState, *reinterpret_cast(fieldPtr)); break; case FieldType::UINT64: lua_pushnumber(luaState, static_cast(*reinterpret_cast(fieldPtr))); break; case FieldType::UINT8: lua_pushnumber(luaState, *reinterpret_cast(fieldPtr)); break; case FieldType::STRING: { const char* str = *reinterpret_cast(fieldPtr); lua_pushstring(luaState, str ? const_cast(str) : const_cast("")); break; } } lua_settable(luaState, -3); } } template inline void PushArrayFieldsToLua(uintptr_t* luaState, const T* obj, const ArrayFieldDescriptor* fields, size_t fieldCount) { for (size_t i = 0; i < fieldCount; ++i) { const auto& field = fields[i]; lua_pushstring(luaState, const_cast(field.name)); lua_newtable(luaState); const char* fieldPtr = reinterpret_cast(obj) + field.offset; for (size_t j = 0; j < field.count; ++j) { lua_pushnumber(luaState, j + 1); // Lua is 1-indexed switch (field.type) { case FieldType::INT32: lua_pushnumber(luaState, reinterpret_cast(fieldPtr)[j]); break; case FieldType::UINT32: lua_pushnumber(luaState, reinterpret_cast(fieldPtr)[j]); break; case FieldType::FLOAT: lua_pushnumber(luaState, reinterpret_cast(fieldPtr)[j]); break; case FieldType::UINT64: lua_pushnumber(luaState, static_cast(reinterpret_cast(fieldPtr)[j])); break; case FieldType::UINT8: lua_pushnumber(luaState, reinterpret_cast(fieldPtr)[j]); break; case FieldType::STRING: { const char* str = reinterpret_cast(fieldPtr)[j]; lua_pushstring(luaState, str ? const_cast(str) : const_cast("")); break; } } lua_settable(luaState, -3); } lua_settable(luaState, -3); } } // Version that uses reusable table references for each array field template inline void PushArrayFieldsToLuaWithRefs(uintptr_t* luaState, const T* obj, const ArrayFieldDescriptor* fields, size_t fieldCount, std::unordered_map& refMap) { for (size_t i = 0; i < fieldCount; ++i) { const auto& field = fields[i]; lua_pushstring(luaState, const_cast(field.name)); // Get or create reusable table for this specific field name GetTableRef(luaState, refMap[field.name]); const char* fieldPtr = reinterpret_cast(obj) + field.offset; for (size_t j = 0; j < field.count; ++j) { lua_pushnumber(luaState, j + 1); // Lua is 1-indexed switch (field.type) { case FieldType::INT32: lua_pushnumber(luaState, reinterpret_cast(fieldPtr)[j]); break; case FieldType::UINT32: lua_pushnumber(luaState, reinterpret_cast(fieldPtr)[j]); break; case FieldType::FLOAT: lua_pushnumber(luaState, reinterpret_cast(fieldPtr)[j]); break; case FieldType::UINT64: lua_pushnumber(luaState, static_cast(reinterpret_cast(fieldPtr)[j])); break; case FieldType::UINT8: lua_pushnumber(luaState, reinterpret_cast(fieldPtr)[j]); break; case FieldType::STRING: { const char* str = reinterpret_cast(fieldPtr)[j]; lua_pushstring(luaState, str ? const_cast(str) : const_cast("")); break; } } lua_settable(luaState, -3); } lua_settable(luaState, -3); } } }