• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!
  • New resources must be posted under Resources tab. A discussion thread will be created automatically, you can't open threads manually anymore.

Feature OTServ using 1 lua_State

Baxnie

Active Member
Senator
Joined
Oct 5, 2007
Messages
90
Reaction score
47
Location
Brazil
This is a solution to a well known problem in otserv which we cannot share variables across lua scripts in actions, creaturescripts, talkactions...
Its idea consists of combining all lua_State in one static variable in LuaInterface, then making the events system compatible and changes npc/movements registerEvents function. The diff was made on TFS rev. 3777

Here's the git diff file:
http://pastebin.com/K44Fchf7
 
Last edited:
Baxnie you are rly one of the best scripter we have in the community, i was wondering if this can cause crash by having a stack overflow and how can we reload the state?
 
well, i'vent tested reload. it didnt work on my server even before these changes.
i've started using this 2 days ago, neither crashs or bugs experienced yet, but its too soon to say its stable.
 
This file is gone? Any chance you could Reupload it, it basically gives alooot of extra functionality!
Since global tables are gone from otfans, this is the onlything working it seems :(
 
Here it is

PHP:
diff --git a/src/luascript.cpp b/src/luascript.cpp
index 5eeb6d8..8cde298 100644
--- a/src/luascript.cpp
+++ b/src/luascript.cpp
@@ -72,6 +72,8 @@ ScriptEnviroment::ThingMap ScriptEnviroment::m_globalMap;
 ScriptEnviroment::StorageMap ScriptEnviroment::m_storageMap;
 ScriptEnviroment::TempItemListMap ScriptEnviroment::m_tempItems;
 
+lua_State *LuaInterface::m_luaState = NULL;
+
 ScriptEnviroment::ScriptEnviroment()
 {
 	m_lastUID = 70000;
@@ -637,7 +639,6 @@ int32_t LuaInterface::m_scriptEnvIndex = -1;
 
 LuaInterface::LuaInterface(std::string interfaceName)
 {
-	m_luaState = NULL;
 	m_interfaceName = interfaceName;
 	m_lastTimer = 1000;
 	m_errors = true;
@@ -749,8 +750,7 @@ bool LuaInterface::loadDirectory(const std::string& dir, Npc* npc/* = NULL*/)
 
 int32_t LuaInterface::getEvent(const std::string& eventName)
 {
-	//get our events table
-	lua_getfield(m_luaState, LUA_REGISTRYINDEX, "EVENTS");
+    lua_rawgeti(m_luaState, LUA_REGISTRYINDEX, m_eventTableRef);
 	if(!lua_istable(m_luaState, -1))
 	{
 		lua_pop(m_luaState, 1);
@@ -831,7 +831,7 @@ void LuaInterface::error(const char* function, const std::string& desc)
 
 bool LuaInterface::pushFunction(int32_t function)
 {
-	lua_getfield(m_luaState, LUA_REGISTRYINDEX, "EVENTS");
+    lua_rawgeti(m_luaState, LUA_REGISTRYINDEX, m_eventTableRef);
 	if(lua_istable(m_luaState, -1))
 	{
 		lua_pushnumber(m_luaState, function);
@@ -847,9 +847,8 @@ bool LuaInterface::pushFunction(int32_t function)
 
 bool LuaInterface::initState()
 {
+    if(!m_luaState) {
 	m_luaState = luaL_newstate();
-	if(!m_luaState)
-		return false;
 
 	luaL_openlibs(m_luaState);
 #ifdef __LUAJIT__
@@ -859,9 +858,10 @@ bool LuaInterface::initState()
 	registerFunctions();
 	if(!loadDirectory(getFilePath(FILE_TYPE_OTHER, "lib/"), NULL))
 		std::cout << "[Warning - LuaInterface::initState] Cannot load " << getFilePath(FILE_TYPE_OTHER, "lib/") << std::endl;
+    }
 
 	lua_newtable(m_luaState);
-	lua_setfield(m_luaState, LUA_REGISTRYINDEX, "EVENTS");
+    m_eventTableRef = luaL_ref(m_luaState, LUA_REGISTRYINDEX);
 	m_runningEvent = EVENT_ID_USER;
 	return true;
 }
@@ -883,6 +883,8 @@ bool LuaInterface::closeState()
 
 	m_timerEvents.clear();
 	lua_close(m_luaState);
+    m_luaState = NULL;
+    std::cout << "[LuaInterface::closeState]: This must be watched, never tested." << std::endl;
 	return true;
 }
 
diff --git a/src/luascript.h b/src/luascript.h
index 92de902..50b3366 100644
--- a/src/luascript.h
+++ b/src/luascript.h
@@ -737,7 +737,8 @@ class LuaInterface
 		static int32_t luaStdSHA512(lua_State* L);
 		static int32_t luaStdVAHash(lua_State* L);
 
-		lua_State* m_luaState;
+        int m_eventTableRef;
+        static lua_State* m_luaState;
 		bool m_errors;
 		std::string m_lastError;
 
diff --git a/src/movement.cpp b/src/movement.cpp
index cbc4f4c..41962c3 100644
--- a/src/movement.cpp
+++ b/src/movement.cpp
@@ -35,9 +35,20 @@ extern MoveEvents* g_moveEvents;
 
 MoveEvent* MoveEventScript::event = NULL;
 
+MoveEventScript::MoveEventScript() :
+    LuaInterface("MoveEvents Interface")
+{
+    initState();
+
+    static bool registerLuaFunctions = false;
+    if(!registerLuaFunctions) { // only 1 luastate now, no need to register functions more than once.
+        registerFunctions();
+        registerLuaFunctions = true;
+    }
+}
+
 void MoveEventScript::registerFunctions()
 {
-	LuaInterface::registerFunctions();
 	lua_register(m_luaState, "callFunction", MoveEventScript::luaCallFunction);
 }
 
@@ -126,7 +137,6 @@ int32_t MoveEventScript::luaCallFunction(lua_State* L)
 MoveEvents::MoveEvents():
 	m_lastCacheTile(NULL)
 {
-	m_interface.initState();
 }
 
 inline void MoveEvents::clearMap(MoveListMap& map)
diff --git a/src/movement.h b/src/movement.h
index 9d32a54..46ee781 100644
--- a/src/movement.h
+++ b/src/movement.h
@@ -25,7 +25,7 @@ class MoveEvent;
 class MoveEventScript : public LuaInterface
 {
 	public:
-		MoveEventScript() : LuaInterface("MoveEvents Interface") {}
+        MoveEventScript();
 		virtual ~MoveEventScript() {}
 
 		static MoveEvent* event;
diff --git a/src/npc.cpp b/src/npc.cpp
index b167665..8eb3a3c 100644
--- a/src/npc.cpp
+++ b/src/npc.cpp
@@ -93,11 +93,7 @@ bool Npc::load()
 
 	reset();
 	if(!m_interface)
-	{
 		m_interface = new NpcScript();
-		m_interface->loadFile(getFilePath(FILE_TYPE_OTHER, "npc/lib/npc.lua"));
-		m_interface->loadFile(getFilePath(FILE_TYPE_OTHER, "npc/lib/npcsystem/main.lua"));
-	}
 
 	loaded = loadFromXml(m_filename);
 	return isLoaded();
@@ -2400,11 +2396,18 @@ NpcScript::NpcScript() :
 	LuaInterface("NpcScript Interface")
 {
 	initState();
+
+    static bool registerLuaFunctions = false;
+    if(!registerLuaFunctions) { // only 1 luastate now, no need to register functions more than once.
+        registerFunctions();
+        loadFile(getFilePath(FILE_TYPE_OTHER, "npc/lib/npc.lua"));
+        loadFile(getFilePath(FILE_TYPE_OTHER, "npc/lib/npcsystem/main.lua"));
+        registerLuaFunctions = true;
+    }
 }
 
 void NpcScript::registerFunctions()
 {
-	LuaInterface::registerFunctions();
 	lua_register(m_luaState, "selfFocus", NpcScript::luaActionFocus);
 	lua_register(m_luaState, "selfSay", NpcScript::luaActionSay);
 
@Baxnie I dont know if this code was related to create static lua state in initState method, but I discovered problems with it after I started using it. Reloading was damaged, and I had some bad issues with it back then. I guess its better to implement luaengine from otclient. Its way better XD
 
I only found one bug with this.
stopEvent wont work if addEvent was created from another LuaInterface.

The fix is to make LuaInterface static and luaState back to what it was.
However the rework became too big so I didn't post it here.

Implementing otclient's lua engine would take ages. So it's something i wouldnt do now.
 
In total This is pretty good solution to exchange variables between scripts.
Congratulations idea.
 
In total This is pretty good solution to exchange variables between scripts.
Congratulations idea.

Was posted somewhere in feature section 2 or 3 years ago - Elf have proven that it's not right approach to solve sharing of variables.
 
Was posted somewhere in feature section 2 or 3 years ago - Elf have proven that it's not right approach to solve sharing of variables.
Everything has its pros and cons. You can always create "sandbox", if you know what I mean.
 
Heh commenting on otc lua engine, I just think its a masterpiece : D
 
Back
Top