From 9e6a490ea11acc9f270e6bbf415039e356907278 Mon Sep 17 00:00:00 2001 From: Mobin <99535731+MobinYengejehi@users.noreply.github.com> Date: Mon, 3 Apr 2023 14:37:28 +0330 Subject: [PATCH 1/4] read function as argument add function type to read and write method define static `CallFunction` method and `CleanupFunction` method --- .../deathmatch/logic/lua/CLuaArgument.cpp | 245 +++++++++++++++++- 1 file changed, 238 insertions(+), 7 deletions(-) diff --git a/Server/mods/deathmatch/logic/lua/CLuaArgument.cpp b/Server/mods/deathmatch/logic/lua/CLuaArgument.cpp index 6c2f02c3778..2d17c11746d 100644 --- a/Server/mods/deathmatch/logic/lua/CLuaArgument.cpp +++ b/Server/mods/deathmatch/logic/lua/CLuaArgument.cpp @@ -17,6 +17,7 @@ #include "CElementIDs.h" #include "CScriptDebugging.h" #include "CResourceManager.h" +#include "CScriptArgReader.h" extern CGame* g_pGame; @@ -24,6 +25,11 @@ extern CGame* g_pGame; #define VERIFY_ELEMENT(element) (g_pGame->GetMapManager()->GetRootElement ()->IsMyChild(element,true)&&!element->IsBeingDeleted()) #endif +#ifndef lua_toresource + #define lua_toresource(luaVM, index) \ + (g_pGame->GetResourceManager()->GetResourceFromScriptID(reinterpret_cast((CResource*)lua_touserdata(luaVM, index)))) +#endif + using namespace std; CLuaArgument::CLuaArgument() @@ -31,12 +37,16 @@ CLuaArgument::CLuaArgument() m_iType = LUA_TNIL; m_pTableData = NULL; m_pUserData = NULL; + m_pResource = nullptr; + m_iFunctionRef = -1; } CLuaArgument::CLuaArgument(const CLuaArgument& Argument, CFastHashMap* pKnownTables) { // Initialize and call our = on the argument m_pTableData = NULL; + m_pResource = nullptr; + m_iFunctionRef = -1; CopyRecursive(Argument, pKnownTables); } @@ -44,6 +54,8 @@ CLuaArgument::CLuaArgument(lua_State* luaVM, int iArgument, CFastHashMapReadTable(luaVM, iArgument, pKnownTables); - m_bWeakTableRef = false; + if (pKnownTables && (m_pTableData = MapFindRef(*pKnownTables, lua_topointer(luaVM, iArgument)))) + { + m_bWeakTableRef = true; + } + else + { + m_pTableData = new CLuaArguments(); + m_pTableData->ReadTable(luaVM, iArgument, pKnownTables); + m_bWeakTableRef = false; + } } break; } @@ -218,8 +284,11 @@ void CLuaArgument::Read(lua_State* luaVM, int iArgument, CFastHashMap* pKn lua_pushlstring(luaVM, m_strString.c_str(), m_strString.length()); break; } + + case LUA_TFUNCTION: + { + if (m_pResource) + { + lua_newtable(luaVM); // create callable + + lua_pushresource(luaVM, m_pResource); // push function inside callable + lua_setfield(luaVM, -2, "resource"); + + lua_pushnumber(luaVM, m_iFunctionRef); // push function ref inside callable + lua_setfield(luaVM, -2, "reference"); + + lua_pushcfunction(luaVM, CleanupFunction); // push cleanup function + lua_setfield(luaVM, -2, "free"); + + lua_newtable(luaVM); // create metatable + lua_pushcfunction(luaVM, CallFunction); + lua_setfield(luaVM, -2, "__call"); + lua_setmetatable(luaVM, -2); + } + break; + } } } } @@ -963,6 +1055,10 @@ bool CLuaArgument::IsEqualTo(const CLuaArgument& compareTo, std::setGetName().c_str(); + if (resource->IsActive()) + { + lua_getfield(luaVM, 1, "reference"); + int reference = 0; + if (lua_type(luaVM, -1) == LUA_TNUMBER) + { + reference = (int)lua_tonumber(luaVM, -1); + } + lua_pop(luaVM, 1); + if (reference != 0) + { + lua_State* resourceVM = resource->GetVirtualMachine()->GetVM(); + if (resourceVM) + { + lua_getref(resourceVM, reference); + if (lua_type(resourceVM, -1) == LUA_TFUNCTION) + { + lua_pop(resourceVM, 1); // pop function after type checked + + CLuaArguments arguments; + + CScriptArgReader argReader(luaVM); + argReader.Skip(1); + argReader.ReadLuaArguments(arguments); + + int top = lua_gettop(resourceVM); + argReader.m_luaVM = resourceVM; + argReader.m_iIndex = top + 1; + + lua_getref(resourceVM, reference); + arguments.PushArguments(resourceVM); + lua_call(resourceVM, arguments.Count(), LUA_MULTRET); + + arguments.DeleteArguments(); + + int returnCount = lua_gettop(resourceVM) - top; + if (returnCount > 0) + { + argReader.ReadLuaArguments(arguments); + arguments.PushArguments(luaVM); + } + + return returnCount; + } + else + { + g_pGame->GetScriptDebugging()->LogError(NULL, "calling to a none function value on resource[%s]", resourceName); + } + lua_pop(resourceVM, 1); // pop function + } + else + { + g_pGame->GetScriptDebugging()->LogError(NULL, "couldn't find resource virutal machine"); + } + } + else + { + g_pGame->GetScriptDebugging()->LogError(NULL, "invalid reference id while calling to resource[%s]", resourceName); + } + } + else + { + g_pGame->GetScriptDebugging()->LogError(NULL, "calling to a none running resource[%s]", resourceName); + } + } + else + { + g_pGame->GetScriptDebugging()->LogError(NULL, "couldn't find the resource of function"); + } + return 0; + } +} + +int CLuaArgument::CleanupFunction(lua_State* luaVM) +{ + if (lua_type(luaVM, 1) == LUA_TTABLE) + { + lua_getfield(luaVM, 1, "resource"); + CResource* resource = nullptr; + if (lua_type(luaVM, -1) == LUA_TLIGHTUSERDATA) + { + resource = lua_toresource(luaVM, -1); + } + lua_pop(luaVM, 1); + if (resource) + { + const char* resourceName = resource->GetName().c_str(); + if (resource->IsActive()) + { + lua_getfield(luaVM, 1, "reference"); + int reference = 0; + if (lua_type(luaVM, -1) == LUA_TNUMBER) + { + reference = (int)lua_tonumber(luaVM, -1); + } + lua_pop(luaVM, 1); + if (reference != 0) + { + lua_State* resourceVM = resource->GetVirtualMachine()->GetVM(); + if (resourceVM) + { + lua_getref(resourceVM, reference); + if (lua_type(resourceVM, -1) != LUA_TNIL) + { + lua_pop(resourceVM, 1); + + lua_unref(resourceVM, reference); + + lua_pushboolean(luaVM, true); + return 1; + } + lua_pop(resourceVM, 1); + } + } + } + } + } + lua_pushboolean(luaVM, false); + return 1; +} From e24010341febe9fd5a4517d149e045bf570f2e47 Mon Sep 17 00:00:00 2001 From: Mobin <99535731+MobinYengejehi@users.noreply.github.com> Date: Mon, 3 Apr 2023 14:39:15 +0330 Subject: [PATCH 2/4] function as argument define methods --- Server/mods/deathmatch/logic/lua/CLuaArgument.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Server/mods/deathmatch/logic/lua/CLuaArgument.h b/Server/mods/deathmatch/logic/lua/CLuaArgument.h index bb6c8581f8b..57d0a61adcd 100644 --- a/Server/mods/deathmatch/logic/lua/CLuaArgument.h +++ b/Server/mods/deathmatch/logic/lua/CLuaArgument.h @@ -22,6 +22,8 @@ extern "C" class CElement; class CLuaArguments; +class CLuaMain; +class CResource; #define LUA_TTABLEREF 9 #define LUA_TSTRING_LONG 10 @@ -48,13 +50,15 @@ class CLuaArgument void ReadElementID(ElementID ID); void ReadScriptID(uint uiScriptID); void ReadTable(class CLuaArguments* table); - + int GetType() const { return m_iType; }; bool GetBoolean() const { return m_bBoolean; }; lua_Number GetNumber() const { return m_Number; }; const std::string& GetString() { return m_strString; }; void* GetUserData() const { return m_pUserData; }; + CResource* GetFunctionResource() const { return m_pResource; }; + int GetFunctionReference() const { return m_iFunctionRef; }; CElement* GetElement() const; bool GetAsString(SString& strBuffer); @@ -66,6 +70,9 @@ class CLuaArgument bool IsEqualTo(const CLuaArgument& compareTo, std::set* knownTables = nullptr) const; + static int CallFunction(lua_State* luaVM); + static int CleanupFunction(lua_State* luaVM); + private: void LogUnableToPacketize(const char* szMessage) const; @@ -75,6 +82,8 @@ class CLuaArgument std::string m_strString; void* m_pUserData; CLuaArguments* m_pTableData; + CResource* m_pResource; + int m_iFunctionRef; bool m_bWeakTableRef; #ifdef MTA_DEBUG From 963cf1944ec38b3cdca46391d40eb64133af30a2 Mon Sep 17 00:00:00 2001 From: Mobin <99535731+MobinYengejehi@users.noreply.github.com> Date: Mon, 3 Apr 2023 14:41:20 +0330 Subject: [PATCH 3/4] function as argument define methods --- Client/mods/deathmatch/logic/lua/CLuaArgument.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Client/mods/deathmatch/logic/lua/CLuaArgument.h b/Client/mods/deathmatch/logic/lua/CLuaArgument.h index a0b8a416edb..f9496f6e7b4 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaArgument.h +++ b/Client/mods/deathmatch/logic/lua/CLuaArgument.h @@ -55,6 +55,8 @@ class CLuaArgument lua_Number GetNumber() const { return m_Number; }; const SString& GetString() { return m_strString; }; void* GetUserData() const { return m_pUserData; }; + CResource* GetFunctionResource() const { return m_pResource; }; + int GetFunctionReference() const { return m_iFunctionRef; }; CClientEntity* GetElement() const; bool ReadFromBitStream(NetBitStreamInterface& bitStream, std::vector* pKnownTables = NULL); @@ -63,6 +65,9 @@ class CLuaArgument bool ReadFromJSONObject(json_object* object, std::vector* pKnownTables = NULL); char* WriteToString(char* szBuffer, int length); + static int CallFunction(lua_State* luaVM); + static int CleanupFunction(lua_State* luaVM); + private: void LogUnableToPacketize(const char* szMessage) const; @@ -73,6 +78,8 @@ class CLuaArgument SString m_strString; void* m_pUserData; CLuaArguments* m_pTableData; + CResource* m_pResource; + int m_iFunctionRef; bool m_bWeakTableRef; #ifdef MTA_DEBUG From 7d3a6c2b692cdc6457564be8fcde7b58c93a5e1f Mon Sep 17 00:00:00 2001 From: Mobin <99535731+MobinYengejehi@users.noreply.github.com> Date: Mon, 3 Apr 2023 14:42:11 +0330 Subject: [PATCH 4/4] function as argument define methods --- .../deathmatch/logic/lua/CLuaArgument.cpp | 243 +++++++++++++++++- 1 file changed, 236 insertions(+), 7 deletions(-) diff --git a/Client/mods/deathmatch/logic/lua/CLuaArgument.cpp b/Client/mods/deathmatch/logic/lua/CLuaArgument.cpp index 3a5f50df3f6..3e8e89398c8 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaArgument.cpp +++ b/Client/mods/deathmatch/logic/lua/CLuaArgument.cpp @@ -10,6 +10,7 @@ #include "StdInc.h" #include "net/SyncStructures.h" +#include "CScriptArgReader.h" #define ARGUMENT_TYPE_INT 9 #define ARGUMENT_TYPE_FLOAT 10 @@ -24,6 +25,11 @@ extern CClientGame* g_pClientGame; +#ifndef lua_toresource + #define lua_toresource(luaVM, index) \ + (g_pClientGame->GetResourceManager()->GetResourceFromScriptID(reinterpret_cast((CResource*)lua_touserdata(luaVM, index)))) +#endif + using namespace std; // Prevent the warning issued when doing unsigned short -> void* @@ -35,18 +41,24 @@ CLuaArgument::CLuaArgument() m_iIndex = -1; m_pTableData = NULL; m_pUserData = NULL; + m_pResource = nullptr; + m_iFunctionRef = -1; } CLuaArgument::CLuaArgument(const CLuaArgument& Argument, CFastHashMap* pKnownTables) { // Initialize and call our = on the argument m_pTableData = NULL; + m_pResource = nullptr; + m_iFunctionRef = -1; CopyRecursive(Argument, pKnownTables); } CLuaArgument::CLuaArgument(NetBitStreamInterface& bitStream, std::vector* pKnownTables) { m_pTableData = NULL; + m_pResource = nullptr; + m_iFunctionRef = -1; ReadFromBitStream(bitStream, pKnownTables); } @@ -54,6 +66,8 @@ CLuaArgument::CLuaArgument(lua_State* luaVM, int iArgument, CFastHashMapReadTable(luaVM, iArgument, pKnownTables); - m_bWeakTableRef = false; + if (pKnownTables && (m_pTableData = MapFindRef(*pKnownTables, lua_topointer(luaVM, iArgument)))) + { + m_bWeakTableRef = true; + } + else + { + m_pTableData = new CLuaArguments(); + m_pTableData->ReadTable(luaVM, iArgument, pKnownTables); + m_bWeakTableRef = false; + } } break; } @@ -284,8 +352,11 @@ void CLuaArgument::Read(lua_State* luaVM, int iArgument, CFastHashMap* pKn lua_pushlstring(luaVM, m_strString.c_str(), m_strString.length()); break; } + + case LUA_TFUNCTION: + { + if (m_pResource) + { + lua_newtable(luaVM); // create callable + + lua_pushresource(luaVM, m_pResource); // push function inside callable + lua_setfield(luaVM, -2, "resource"); + + lua_pushnumber(luaVM, m_iFunctionRef); // push function ref inside callable + lua_setfield(luaVM, -2, "reference"); + + lua_pushcfunction(luaVM, CleanupFunction); // push cleanup function + lua_setfield(luaVM, -2, "free"); + + lua_newtable(luaVM); // create metatable + lua_pushcfunction(luaVM, CallFunction); + lua_setfield(luaVM, -2, "__call"); + lua_setmetatable(luaVM, -2); + } + break; + } } } } @@ -1073,3 +1167,138 @@ bool CLuaArgument::ReadFromJSONObject(json_object* object, std::vectorGetName(); + if (resource->IsActive() || resource->GetState() == "starting") + { + lua_getfield(luaVM, 1, "reference"); + int reference = 0; + if (lua_type(luaVM, -1) == LUA_TNUMBER) + { + reference = (int)lua_tonumber(luaVM, -1); + } + lua_pop(luaVM, 1); + if (reference != 0) + { + lua_State* resourceVM = resource->GetVM()->GetVirtualMachine(); + if (resourceVM) + { + lua_getref(resourceVM, reference); + if (lua_type(resourceVM, -1) == LUA_TFUNCTION) + { + lua_pop(resourceVM, 1); // pop function after type checked + + CLuaArguments arguments; + + CScriptArgReader argReader(luaVM); + argReader.Skip(1); + argReader.ReadLuaArguments(arguments); + + int top = lua_gettop(resourceVM); + argReader.m_luaVM = resourceVM; + argReader.m_iIndex = top + 1; + + lua_getref(resourceVM, reference); + arguments.PushArguments(resourceVM); + lua_call(resourceVM, arguments.Count(), LUA_MULTRET); + + arguments.DeleteArguments(); + + int returnCount = lua_gettop(resourceVM) - top; + if (returnCount > 0) + { + argReader.ReadLuaArguments(arguments); + arguments.PushArguments(luaVM); + } + + return returnCount; + } + else + { + g_pClientGame->GetScriptDebugging()->LogError(NULL, "calling to a none function value on resource[%s]", resourceName); + } + lua_pop(resourceVM, 1); // pop function + } + else + { + g_pClientGame->GetScriptDebugging()->LogError(NULL, "couldn't find resource virutal machine"); + } + } + else + { + g_pClientGame->GetScriptDebugging()->LogError(NULL, "invalid reference id while calling to resource[%s]", resourceName); + } + } + else + { + g_pClientGame->GetScriptDebugging()->LogError(NULL, "calling to a none running resource[%s]", resourceName); + } + } + else + { + g_pClientGame->GetScriptDebugging()->LogError(NULL, "couldn't find the resource of function"); + } + return 0; + } +} + +int CLuaArgument::CleanupFunction(lua_State* luaVM) +{ + if (lua_type(luaVM, 1) == LUA_TTABLE) + { + lua_getfield(luaVM, 1, "resource"); + CResource* resource = nullptr; + if (lua_type(luaVM, -1) == LUA_TLIGHTUSERDATA) + { + resource = lua_toresource(luaVM, -1); + } + lua_pop(luaVM, 1); + if (resource) + { + const char* resourceName = resource->GetName(); + if (resource->IsActive() || resource->GetState() == "starting") + { + lua_getfield(luaVM, 1, "reference"); + int reference = 0; + if (lua_type(luaVM, -1) == LUA_TNUMBER) + { + reference = (int)lua_tonumber(luaVM, -1); + } + lua_pop(luaVM, 1); + if (reference != 0) + { + lua_State* resourceVM = resource->GetVM()->GetVirtualMachine(); + if (resourceVM) + { + lua_getref(resourceVM, reference); + if (lua_type(resourceVM, -1) != LUA_TNIL) + { + lua_pop(resourceVM, 1); + + lua_unref(resourceVM, reference); + + lua_pushboolean(luaVM, true); + return 1; + } + lua_pop(resourceVM, 1); + } + } + } + } + } + lua_pushboolean(luaVM, false); + return 1; +}