diff --git a/src/luacombat.cpp b/src/luacombat.cpp index 1e4059e..b209007 100644 --- a/src/luacombat.cpp +++ b/src/luacombat.cpp @@ -26,6 +26,10 @@ int luaCombatCreate(lua_State* L) int luaCombatDelete(lua_State* L) { + if (!isType(L, 1)) { + return 0; + } + Combat_ptr& combat = getSharedPtr(L, 1); if (combat) { combat.reset(); @@ -36,9 +40,14 @@ int luaCombatDelete(lua_State* L) int luaCombatSetParameter(lua_State* L) { // combat:setParameter(key, value) + if (!isType(L, 1)) { + reportErrorFunc(L, LuaScriptInterface::getErrorDesc(LuaErrorCode::COMBAT_NOT_FOUND)); + lua_pushnil(L); + return 1; + } + const Combat_ptr& combat = getSharedPtr(L, 1); if (!combat) { - reportErrorFunc(L, LuaScriptInterface::getErrorDesc(LuaErrorCode::COMBAT_NOT_FOUND)); lua_pushnil(L); return 1; } @@ -58,9 +67,14 @@ int luaCombatSetParameter(lua_State* L) int luaCombatGetParameter(lua_State* L) { // combat:getParameter(key) + if (!isType(L, 1)) { + reportErrorFunc(L, LuaScriptInterface::getErrorDesc(LuaErrorCode::COMBAT_NOT_FOUND)); + lua_pushnil(L); + return 1; + } + const Combat_ptr& combat = getSharedPtr(L, 1); if (!combat) { - reportErrorFunc(L, LuaScriptInterface::getErrorDesc(LuaErrorCode::COMBAT_NOT_FOUND)); lua_pushnil(L); return 1; } @@ -78,9 +92,14 @@ int luaCombatGetParameter(lua_State* L) int luaCombatSetFormula(lua_State* L) { // combat:setFormula(type, mina, minb, maxa, maxb) + if (!isType(L, 1)) { + reportErrorFunc(L, LuaScriptInterface::getErrorDesc(LuaErrorCode::COMBAT_NOT_FOUND)); + lua_pushnil(L); + return 1; + } + const Combat_ptr& combat = getSharedPtr(L, 1); if (!combat) { - reportErrorFunc(L, LuaScriptInterface::getErrorDesc(LuaErrorCode::COMBAT_NOT_FOUND)); lua_pushnil(L); return 1; } @@ -111,9 +130,14 @@ int luaCombatSetArea(lua_State* L) return 1; } + if (!isType(L, 1)) { + reportErrorFunc(L, LuaScriptInterface::getErrorDesc(LuaErrorCode::COMBAT_NOT_FOUND)); + lua_pushnil(L); + return 1; + } + const Combat_ptr& combat = getSharedPtr(L, 1); if (!combat) { - reportErrorFunc(L, LuaScriptInterface::getErrorDesc(LuaErrorCode::COMBAT_NOT_FOUND)); lua_pushnil(L); return 1; } @@ -126,9 +150,14 @@ int luaCombatSetArea(lua_State* L) int luaCombatAddCondition(lua_State* L) { // combat:addCondition(condition) + if (!isType(L, 1)) { + reportErrorFunc(L, LuaScriptInterface::getErrorDesc(LuaErrorCode::COMBAT_NOT_FOUND)); + lua_pushnil(L); + return 1; + } + const Combat_ptr& combat = getSharedPtr(L, 1); if (!combat) { - reportErrorFunc(L, LuaScriptInterface::getErrorDesc(LuaErrorCode::COMBAT_NOT_FOUND)); lua_pushnil(L); return 1; } @@ -146,9 +175,14 @@ int luaCombatAddCondition(lua_State* L) int luaCombatClearConditions(lua_State* L) { // combat:clearConditions() + if (!isType(L, 1)) { + reportErrorFunc(L, LuaScriptInterface::getErrorDesc(LuaErrorCode::COMBAT_NOT_FOUND)); + lua_pushnil(L); + return 1; + } + const Combat_ptr& combat = getSharedPtr(L, 1); if (!combat) { - reportErrorFunc(L, LuaScriptInterface::getErrorDesc(LuaErrorCode::COMBAT_NOT_FOUND)); lua_pushnil(L); return 1; } @@ -161,9 +195,14 @@ int luaCombatClearConditions(lua_State* L) int luaCombatSetCallback(lua_State* L) { // combat:setCallback(key, callback) + if (!isType(L, 1)) { + reportErrorFunc(L, LuaScriptInterface::getErrorDesc(LuaErrorCode::COMBAT_NOT_FOUND)); + lua_pushnil(L); + return 1; + } + const Combat_ptr& combat = getSharedPtr(L, 1); if (!combat) { - reportErrorFunc(L, LuaScriptInterface::getErrorDesc(LuaErrorCode::COMBAT_NOT_FOUND)); lua_pushnil(L); return 1; } @@ -182,9 +221,14 @@ int luaCombatSetCallback(lua_State* L) int luaCombatSetOrigin(lua_State* L) { // combat:setOrigin(origin) + if (!isType(L, 1)) { + reportErrorFunc(L, LuaScriptInterface::getErrorDesc(LuaErrorCode::COMBAT_NOT_FOUND)); + lua_pushnil(L); + return 1; + } + const Combat_ptr& combat = getSharedPtr(L, 1); if (!combat) { - reportErrorFunc(L, LuaScriptInterface::getErrorDesc(LuaErrorCode::COMBAT_NOT_FOUND)); lua_pushnil(L); return 1; } @@ -197,9 +241,14 @@ int luaCombatSetOrigin(lua_State* L) int luaCombatExecute(lua_State* L) { // combat:execute(creature, variant) + if (!isType(L, 1)) { + reportErrorFunc(L, LuaScriptInterface::getErrorDesc(LuaErrorCode::COMBAT_NOT_FOUND)); + lua_pushnil(L); + return 1; + } + const Combat_ptr& combat = getSharedPtr(L, 1); if (!combat) { - reportErrorFunc(L, LuaScriptInterface::getErrorDesc(LuaErrorCode::COMBAT_NOT_FOUND)); lua_pushnil(L); return 1; } diff --git a/src/luascript.cpp b/src/luascript.cpp index 641a917..6daf9ca 100644 --- a/src/luascript.cpp +++ b/src/luascript.cpp @@ -2164,22 +2164,11 @@ void LuaScriptInterface::registerClass(const std::string& className, const std:: lua_rawseti(luaState, metatable, 'p'); // className.metatable['t'] = type - if (className == "Item") { - lua_pushinteger(luaState, LuaData_Item); - } else if (className == "Container") { - lua_pushinteger(luaState, LuaData_Container); - } else if (className == "Teleport") { - lua_pushinteger(luaState, LuaData_Teleport); - } else if (className == "Player") { - lua_pushinteger(luaState, LuaData_Player); - } else if (className == "Monster") { - lua_pushinteger(luaState, LuaData_Monster); - } else if (className == "Npc") { - lua_pushinteger(luaState, LuaData_Npc); - } else if (className == "Tile") { - lua_pushinteger(luaState, LuaData_Tile); - } else { + auto luaDataType = LuaDataTypeByClassName.find(className); + if (luaDataType == LuaDataTypeByClassName.end()) { lua_pushinteger(luaState, LuaData_Unknown); + } else { + lua_pushinteger(luaState, luaDataType->second); } lua_rawseti(luaState, metatable, 't'); diff --git a/src/luascript.h b/src/luascript.h index ce6772f..68618d5 100644 --- a/src/luascript.h +++ b/src/luascript.h @@ -19,40 +19,193 @@ #endif #endif +enum LuaDataType +{ + LuaData_Unknown, + + LuaData_Item, + LuaData_Container, + LuaData_Teleport, + LuaData_Creature, + LuaData_Player, + LuaData_Monster, + LuaData_Npc, + LuaData_Tile, + LuaData_Condition, + + LuaData_Combat, + LuaData_Group, + LuaData_Guild, + LuaData_House, + LuaData_ItemType, + LuaData_ModalWindow, + LuaData_MonsterType, + LuaData_NetworkMessage, + LuaData_Party, + LuaData_Vocation, + LuaData_Town, + LuaData_LuaVariant, + LuaData_Position, + + LuaData_Outfit, + LuaData_Loot, + LuaData_MonsterSpell, + LuaData_Spell, + LuaData_Action, + LuaData_TalkAction, + LuaData_CreatureEvent, + LuaData_MoveEvent, + LuaData_GlobalEvent, + LuaData_Weapon, + + LuaData_XMLDocument, + LuaData_XMLNode, +}; + +template +inline constexpr LuaDataType LuaDataTypeByClass = LuaData_Unknown; + +#define NEW_LUA_DATA_TYPE(CLASS) \ + template <> \ + inline constexpr LuaDataType LuaDataTypeByClass = LuaData_##CLASS; \ + template <> \ + inline constexpr LuaDataType LuaDataTypeByClass = LuaData_##CLASS; + +class Action; class AreaCombat; -class SpectatorVec; class Combat; +class Condition; +class Container; class Container; class Creature; +class CreatureEvent; class Cylinder; -class Spell; +class GlobalEvent; +class Guild; +class House; class InstantSpell; class Item; +class ItemType; +class Loot; class LuaScriptInterface; class LuaVariant; +class Monster; +class MonsterSpell; +class MonsterType; +class MoveEvent; +class NetworkMessage; class Npc; +class Party; class Player; +class RuneSpell; +class SpectatorVec; +class Spell; +class TalkAction; +class Teleport; class Thing; +class Tile; +class Town; +class Vocation; +class Weapon; +class WeaponDistance; +class WeaponMelee; +class WeaponWand; + +struct Group; struct LootBlock; +struct ModalWindow; struct Mount; struct Outfit; +struct Position; using Combat_ptr = std::shared_ptr; +using XMLDocument = pugi::xml_document; +using XMLNode = pugi::xml_node; + inline constexpr int32_t EVENT_ID_LOADING = 1; inline constexpr int32_t EVENT_ID_USER = 1000; -enum LuaDataType -{ - LuaData_Unknown, - - LuaData_Item, - LuaData_Container, - LuaData_Teleport, - LuaData_Player, - LuaData_Monster, - LuaData_Npc, - LuaData_Tile, +NEW_LUA_DATA_TYPE(Item); +NEW_LUA_DATA_TYPE(Container); +NEW_LUA_DATA_TYPE(Teleport); +NEW_LUA_DATA_TYPE(Creature); +NEW_LUA_DATA_TYPE(Player); +NEW_LUA_DATA_TYPE(Monster); +NEW_LUA_DATA_TYPE(Npc); +NEW_LUA_DATA_TYPE(Tile); +NEW_LUA_DATA_TYPE(Condition); + +NEW_LUA_DATA_TYPE(Combat); +NEW_LUA_DATA_TYPE(Group); +NEW_LUA_DATA_TYPE(Guild); +NEW_LUA_DATA_TYPE(House); +NEW_LUA_DATA_TYPE(ItemType); +NEW_LUA_DATA_TYPE(ModalWindow); +NEW_LUA_DATA_TYPE(MonsterType); +NEW_LUA_DATA_TYPE(NetworkMessage); +NEW_LUA_DATA_TYPE(Party); +NEW_LUA_DATA_TYPE(Vocation); +NEW_LUA_DATA_TYPE(Town); +NEW_LUA_DATA_TYPE(Position); + +NEW_LUA_DATA_TYPE(LuaVariant); + +NEW_LUA_DATA_TYPE(Outfit); +NEW_LUA_DATA_TYPE(Loot); +NEW_LUA_DATA_TYPE(MonsterSpell); +NEW_LUA_DATA_TYPE(Spell); +NEW_LUA_DATA_TYPE(Action); +NEW_LUA_DATA_TYPE(TalkAction); +NEW_LUA_DATA_TYPE(CreatureEvent); +NEW_LUA_DATA_TYPE(MoveEvent); +NEW_LUA_DATA_TYPE(GlobalEvent); +NEW_LUA_DATA_TYPE(Weapon); + +NEW_LUA_DATA_TYPE(XMLDocument); +NEW_LUA_DATA_TYPE(XMLNode); + +const std::unordered_map LuaDataTypeByClassName = { + {"Item", LuaData_Item}, + {"Container", LuaData_Container}, + {"Teleport", LuaData_Teleport}, + {"Creature", LuaData_Creature}, + {"Player", LuaData_Player}, + {"Monster", LuaData_Monster}, + {"Npc", LuaData_Npc}, + {"Tile", LuaData_Tile}, + {"Condition", LuaData_Condition}, + + {"Combat", LuaData_Combat}, + {"Group", LuaData_Group}, + {"Guild", LuaData_Guild}, + {"House", LuaData_House}, + {"ItemType", LuaData_ItemType}, + {"ModalWindow", LuaData_ModalWindow}, + {"MonsterType", LuaData_MonsterType}, + {"NetworkMessage", LuaData_NetworkMessage}, + {"Party", LuaData_Party}, + {"Vocation", LuaData_Vocation}, + {"Town", LuaData_Town}, + {"LuaVariant", LuaData_LuaVariant}, + {"Position", LuaData_Position}, + + {"Outfit", LuaData_Outfit}, + {"Loot", LuaData_Loot}, + {"MonsterSpell", LuaData_MonsterSpell}, + {"Spell", LuaData_Spell}, + {"InstantSpell", LuaData_Spell}, + {"Action", LuaData_Action}, + {"TalkAction", LuaData_TalkAction}, + {"CreatureEvent", LuaData_CreatureEvent}, + {"MoveEvent", LuaData_MoveEvent}, + {"GlobalEvent", LuaData_GlobalEvent}, + {"Weapon", LuaData_Weapon}, + {"WeaponDistance", LuaData_Weapon}, + {"WeaponWand", LuaData_Weapon}, + {"WeaponMelee", LuaData_Weapon}, + {"XMLDocument", LuaData_XMLDocument}, + {"XMLNode", LuaData_XMLNode}, }; struct LuaTimerEventDesc @@ -537,8 +690,12 @@ inline T* getUserdata(lua_State* L, int32_t arg) template inline T** getRawUserdata(lua_State* L, int32_t arg) { + if (!isType(L, arg)) { + return nullptr; + } return static_cast(lua_touserdata(L, arg)); } + template inline std::shared_ptr& getSharedPtr(lua_State* L, int32_t arg) { @@ -634,6 +791,24 @@ inline void setField(lua_State* L, const char* index, std::string_view value) lua_setfield(L, -2, index); } +template +inline const bool isType(lua_State* L, int32_t arg) +{ + const LuaDataType classType = LuaDataTypeByClass; + if (classType == LuaData_Unknown) { + return false; + } + + const LuaDataType userdataType = getUserdataType(L, arg); + if (classType == LuaData_Creature) { + return userdataType >= LuaData_Creature && userdataType <= LuaData_Npc; + } else if (classType == LuaData_Item) { + return userdataType >= LuaData_Item && userdataType <= LuaData_Teleport; + } + + return userdataType == classType; +} + // Push void pushBoolean(lua_State* L, bool value); void pushCombatDamage(lua_State* L, const CombatDamage& damage); diff --git a/src/luaxml.cpp b/src/luaxml.cpp index 6c1dbdb..3bda16d 100644 --- a/src/luaxml.cpp +++ b/src/luaxml.cpp @@ -19,9 +19,9 @@ int luaCreateXmlDocument(lua_State* L) return 1; } - auto doc = std::make_unique(); + auto doc = std::make_unique(); if (auto result = doc->load_file(filename.c_str())) { - pushUserdata(L, doc.release()); + pushUserdata(L, doc.release()); setMetatable(L, -1, "XMLDocument"); } else { printXMLError("Error - luaCreateXmlDocument", filename, result); @@ -33,7 +33,7 @@ int luaCreateXmlDocument(lua_State* L) int luaDeleteXmlDocument(lua_State* L) { // doc:delete() or doc:__gc() or doc:__close() - pugi::xml_document** document = getRawUserdata(L, 1); + XMLDocument** document = getRawUserdata(L, 1); if (document && *document) { delete *document; *document = nullptr; @@ -44,7 +44,7 @@ int luaDeleteXmlDocument(lua_State* L) int luaXmlDocumentChild(lua_State* L) { // doc:child(name) - pugi::xml_document* document = getUserdata(L, 1); + XMLDocument* document = getUserdata(L, 1); if (!document) { lua_pushnil(L); return 1; @@ -56,8 +56,8 @@ int luaXmlDocumentChild(lua_State* L) return 1; } - auto node = std::make_unique(document->child(name.c_str())); - pushUserdata(L, node.release()); + auto node = std::make_unique(document->child(name.c_str())); + pushUserdata(L, node.release()); setMetatable(L, -1, "XMLNode"); return 1; } @@ -65,7 +65,7 @@ int luaXmlDocumentChild(lua_State* L) int luaDeleteXmlNode(lua_State* L) { // node:delete() or node:__gc() or node:__close() - pugi::xml_node** node = getRawUserdata(L, 1); + XMLNode** node = getRawUserdata(L, 1); if (node && *node) { delete *node; *node = nullptr; @@ -76,7 +76,7 @@ int luaDeleteXmlNode(lua_State* L) int luaXmlNodeAttribute(lua_State* L) { // node:attribute(name) - pugi::xml_node* node = getUserdata(L, 1); + XMLNode* node = getUserdata(L, 1); if (!node) { lua_pushnil(L); return 1; @@ -100,7 +100,7 @@ int luaXmlNodeAttribute(lua_State* L) int luaXmlNodeName(lua_State* L) { // node:name() - pugi::xml_node* node = getUserdata(L, 1); + XMLNode* node = getUserdata(L, 1); if (!node) { lua_pushnil(L); return 1; @@ -113,7 +113,7 @@ int luaXmlNodeName(lua_State* L) int luaXmlNodeFirstChild(lua_State* L) { // node:firstChild() - pugi::xml_node* node = getUserdata(L, 1); + XMLNode* node = getUserdata(L, 1); if (!node) { lua_pushnil(L); return 1; @@ -125,8 +125,8 @@ int luaXmlNodeFirstChild(lua_State* L) return 1; } - auto newNode = std::make_unique(std::move(firstChild)); - pushUserdata(L, newNode.release()); + auto newNode = std::make_unique(std::move(firstChild)); + pushUserdata(L, newNode.release()); setMetatable(L, -1, "XMLNode"); return 1; } @@ -134,7 +134,7 @@ int luaXmlNodeFirstChild(lua_State* L) int luaXmlNodeNextSibling(lua_State* L) { // node:nextSibling() - pugi::xml_node* node = getUserdata(L, 1); + XMLNode* node = getUserdata(L, 1); if (!node) { lua_pushnil(L); return 1; @@ -146,8 +146,8 @@ int luaXmlNodeNextSibling(lua_State* L) return 1; } - auto newNode = std::make_unique(std::move(nextSibling)); - pushUserdata(L, newNode.release()); + auto newNode = std::make_unique(std::move(nextSibling)); + pushUserdata(L, newNode.release()); setMetatable(L, -1, "XMLNode"); return 1; }