Browse Source

Cleaned up Lua event subscription code (do not register C++ handler before Lua function is found successfully.)
Moved Lua script object destruction to a function.
Destroy the old Lua script object before creating new.
Unref the object specific event handler functions when destroying Lua script object.

Lasse Öörni 12 years ago
parent
commit
6f78838b5c

+ 10 - 10
Source/Extras/LuaScript/LuaScript.cpp

@@ -172,15 +172,15 @@ void LuaScript::ScriptSubscribeToEvent(const String& eventName, const String& fu
 {
 {
     StringHash eventType(eventName);
     StringHash eventType(eventName);
 
 
-    HashSet<Object*>* receivers = context_->GetEventReceivers(eventType);
-    if (!receivers || !receivers->Contains(this))
-        SubscribeToEvent(eventType, HANDLER(LuaScript, HandleEvent));
-
     int functionRef = LUA_REFNIL;
     int functionRef = LUA_REFNIL;
     if (FindFunction(functionName))
     if (FindFunction(functionName))
         functionRef = luaL_ref(luaState_, LUA_REGISTRYINDEX);
         functionRef = luaL_ref(luaState_, LUA_REGISTRYINDEX);
 
 
-    eventTypeToFunctionRefMap_[eventType] = functionRef;
+    if (functionRef != LUA_REFNIL)
+    {
+        SubscribeToEvent(eventType, HANDLER(LuaScript, HandleEvent));
+        eventTypeToFunctionRefMap_[eventType] = functionRef;
+    }
 }
 }
 
 
 void LuaScript::ScriptSubscribeToEvent(void* object, const String& eventName, const String& functionName)
 void LuaScript::ScriptSubscribeToEvent(void* object, const String& eventName, const String& functionName)
@@ -188,15 +188,15 @@ void LuaScript::ScriptSubscribeToEvent(void* object, const String& eventName, co
     StringHash eventType(eventName);
     StringHash eventType(eventName);
     Object* sender = (Object*)object;
     Object* sender = (Object*)object;
 
 
-    HashSet<Object*>* receivers = context_->GetEventReceivers(sender, eventType);
-    if (!receivers || !receivers->Contains(this))
-        SubscribeToEvent(sender, eventType, HANDLER(LuaScript, HandleObjectEvent));
-
     int functionRef = LUA_REFNIL;
     int functionRef = LUA_REFNIL;
     if (FindFunction(functionName))
     if (FindFunction(functionName))
         functionRef = luaL_ref(luaState_, LUA_REGISTRYINDEX);
         functionRef = luaL_ref(luaState_, LUA_REGISTRYINDEX);
 
 
-    objectToEventTypeToFunctionRefMap_[sender][eventType] = functionRef;
+    if (functionRef != LUA_REFNIL)
+    {
+        SubscribeToEvent(sender, eventType, HANDLER(LuaScript, HandleObjectEvent));
+        objectToEventTypeToFunctionRefMap_[sender][eventType] = functionRef;
+    }
 }
 }
 
 
 void LuaScript::RegisterLoader()
 void LuaScript::RegisterLoader()

+ 55 - 41
Source/Extras/LuaScript/LuaScriptInstance.cpp

@@ -41,7 +41,7 @@ namespace Urho3D
 {
 {
 
 
 LuaScriptInstance::LuaScriptInstance(Context* context) : 
 LuaScriptInstance::LuaScriptInstance(Context* context) : 
-    Component(context), 
+    Component(context),
     scriptObjectRef_(LUA_REFNIL)
     scriptObjectRef_(LUA_REFNIL)
 {
 {
     luaScript_ = GetSubsystem<LuaScript>();
     luaScript_ = GetSubsystem<LuaScript>();
@@ -50,35 +50,7 @@ LuaScriptInstance::LuaScriptInstance(Context* context) :
 
 
 LuaScriptInstance::~LuaScriptInstance()
 LuaScriptInstance::~LuaScriptInstance()
 {
 {
-    // Unref script object.
-    if (scriptObjectRef_ != LUA_REFNIL)
-        luaL_unref(luaState_, LUA_REGISTRYINDEX, scriptObjectRef_);
-
-    // Unref Lua function.
-    for (HashMap<StringHash, int>::Iterator i = eventTypeToFunctionRefMap_.Begin(); i != eventTypeToFunctionRefMap_.End(); ++i)
-        luaL_unref(luaState_, LUA_REGISTRYINDEX, i->second_);
-    
-    int top = lua_gettop(luaState_);
-
-    lua_getglobal(luaState_, "DestroyScriptObjectInstance");
-    if (!lua_isfunction(luaState_, -1))
-    {
-        LOGERROR("Can not find lua function DestroyScriptObjectInstance.");
-        lua_settop(luaState_, top);
-        return;
-    }
-
-    // Push this as second parameter.
-    tolua_pushusertype(luaState_, (void*)this, "LuaScriptInstance");
-
-    // Call ObjectType:new function.
-    if (lua_pcall(luaState_, 1, 0, 0) != 0)
-    {
-        const char* message = lua_tostring(luaState_, -1);
-        LOGERROR("Execute Lua function failed: " + String(message));
-        lua_settop(luaState_, top);
-        return;
-    }
+    ReleaseObject();
 }
 }
 
 
 void LuaScriptInstance::RegisterObject(Context* context)
 void LuaScriptInstance::RegisterObject(Context* context)
@@ -91,6 +63,8 @@ bool LuaScriptInstance::CreateObject(const String& objectType)
     if (objectType_ == objectType)
     if (objectType_ == objectType)
         return true;
         return true;
 
 
+    ReleaseObject();
+
     int top = lua_gettop(luaState_);
     int top = lua_gettop(luaState_);
 
 
     lua_getglobal(luaState_, "CreateScriptObjectInstance");
     lua_getglobal(luaState_, "CreateScriptObjectInstance");
@@ -147,15 +121,15 @@ void LuaScriptInstance::ScriptSubscribeToEvent(const String& eventName, const St
     StringHash eventType(eventName);
     StringHash eventType(eventName);
     String realFunctionName = functionName.Replaced(":", ".");
     String realFunctionName = functionName.Replaced(":", ".");
 
 
-    HashSet<Object*>* receivers = context_->GetEventReceivers(eventType);
-    if (!receivers || !receivers->Contains(this))
-        SubscribeToEvent(eventType, HANDLER(LuaScriptInstance, HandleEvent));
-
     int functionRef = LUA_REFNIL;
     int functionRef = LUA_REFNIL;
     if (luaScript_->FindFunction(realFunctionName))
     if (luaScript_->FindFunction(realFunctionName))
         functionRef = luaL_ref(luaState_, LUA_REGISTRYINDEX);
         functionRef = luaL_ref(luaState_, LUA_REGISTRYINDEX);
 
 
-    eventTypeToFunctionRefMap_[eventType] = functionRef;
+    if (functionRef != LUA_REFNIL)
+    {
+        SubscribeToEvent(eventType, HANDLER(LuaScriptInstance, HandleEvent));
+        eventTypeToFunctionRefMap_[eventType] = functionRef;
+    }
 }
 }
 
 
 void LuaScriptInstance::ScriptSubscribeToEvent(void* object, const String& eventName, const String& functionName)
 void LuaScriptInstance::ScriptSubscribeToEvent(void* object, const String& eventName, const String& functionName)
@@ -163,16 +137,16 @@ void LuaScriptInstance::ScriptSubscribeToEvent(void* object, const String& event
     StringHash eventType(eventName);
     StringHash eventType(eventName);
     String realFunctionName = functionName.Replaced(":", ".");
     String realFunctionName = functionName.Replaced(":", ".");
     Object* sender = (Object*)object;
     Object* sender = (Object*)object;
-    
-    HashSet<Object*>* receivers = context_->GetEventReceivers(sender, eventType);
-    if (!receivers || !receivers->Contains(this))
-        SubscribeToEvent(sender, eventType, HANDLER(LuaScriptInstance, HandleObjectEvent));
 
 
     int functionRef = LUA_REFNIL;
     int functionRef = LUA_REFNIL;
     if (luaScript_->FindFunction(realFunctionName))
     if (luaScript_->FindFunction(realFunctionName))
         functionRef = luaL_ref(luaState_, LUA_REGISTRYINDEX);
         functionRef = luaL_ref(luaState_, LUA_REGISTRYINDEX);
 
 
-    objectToEventTypeToFunctionRefMap_[sender][eventType] = functionRef;
+    if (functionRef != LUA_REFNIL)
+    {
+        SubscribeToEvent(sender, eventType, HANDLER(LuaScriptInstance, HandleObjectEvent));
+        objectToEventTypeToFunctionRefMap_[sender][eventType] = functionRef;
+    }
 }
 }
 
 
 void LuaScriptInstance::HandleEvent(StringHash eventType, VariantMap& eventData)
 void LuaScriptInstance::HandleEvent(StringHash eventType, VariantMap& eventData)
@@ -205,7 +179,7 @@ void LuaScriptInstance::CallEventHandler(int functionRef, StringHash eventType,
     int top = lua_gettop(luaState_);
     int top = lua_gettop(luaState_);
 
 
     // Push function.
     // Push function.
-    lua_rawgeti(luaState_, LUA_REGISTRYINDEX, functionRef);  
+    lua_rawgeti(luaState_, LUA_REGISTRYINDEX, functionRef);
 
 
     // Push script object.
     // Push script object.
     lua_rawgeti(luaState_, LUA_REGISTRYINDEX, scriptObjectRef_);
     lua_rawgeti(luaState_, LUA_REGISTRYINDEX, scriptObjectRef_);
@@ -223,7 +197,47 @@ void LuaScriptInstance::CallEventHandler(int functionRef, StringHash eventType,
         lua_settop(luaState_, top);
         lua_settop(luaState_, top);
         return;
         return;
     }
     }
+}
+
+void LuaScriptInstance::ReleaseObject()
+{
+    if (scriptObjectRef_ == LUA_REFNIL)
+        return;
+    
+    // Unref script object.
+    luaL_unref(luaState_, LUA_REGISTRYINDEX, scriptObjectRef_);
+    scriptObjectRef_ = LUA_REFNIL;
+    
+    // Unref Lua function.
+    for (HashMap<StringHash, int>::Iterator i = eventTypeToFunctionRefMap_.Begin(); i != eventTypeToFunctionRefMap_.End(); ++i)
+        luaL_unref(luaState_, LUA_REGISTRYINDEX, i->second_);
+    for (HashMap<Object*, HashMap<StringHash, int> >::Iterator i = objectToEventTypeToFunctionRefMap_.Begin(); 
+        i != objectToEventTypeToFunctionRefMap_.End(); ++i)
+    {
+        for (HashMap<StringHash, int>::Iterator j = i->second_.Begin(); j != i->second_.End(); ++j)
+            luaL_unref(luaState_, LUA_REGISTRYINDEX, j->second_);
+    }
+    
+    int top = lua_gettop(luaState_);
 
 
+    lua_getglobal(luaState_, "DestroyScriptObjectInstance");
+    if (!lua_isfunction(luaState_, -1))
+    {
+        LOGERROR("Can not find lua function DestroyScriptObjectInstance.");
+        lua_settop(luaState_, top);
+        return;
+    }
+
+    // Push this as second parameter.
+    tolua_pushusertype(luaState_, (void*)this, "LuaScriptInstance");
+
+    if (lua_pcall(luaState_, 1, 0, 0) != 0)
+    {
+        const char* message = lua_tostring(luaState_, -1);
+        LOGERROR("Execute Lua function failed: " + String(message));
+        lua_settop(luaState_, top);
+        return;
+    }
 }
 }
 
 
 }
 }

+ 4 - 2
Source/Extras/LuaScript/LuaScriptInstance.h

@@ -56,7 +56,7 @@ public:
     /// Script subscribe object's event.
     /// Script subscribe object's event.
     void ScriptSubscribeToEvent(void* object, const String& eventName, const String& functionName);
     void ScriptSubscribeToEvent(void* object, const String& eventName, const String& functionName);
     
     
-protected:
+private:
     /// Handle event.
     /// Handle event.
     void HandleEvent(StringHash eventType, VariantMap& eventData);
     void HandleEvent(StringHash eventType, VariantMap& eventData);
 
 
@@ -66,7 +66,9 @@ protected:
     /// Call event handler.
     /// Call event handler.
     void CallEventHandler(int functionRef, StringHash eventType, VariantMap& eventData);
     void CallEventHandler(int functionRef, StringHash eventType, VariantMap& eventData);
 
 
-private:
+    /// Release the script object.
+    void ReleaseObject();
+    
     // Lua Script.
     // Lua Script.
     LuaScript* luaScript_;
     LuaScript* luaScript_;