Browse Source

Move the pieces around for code reuse opportunity.

Yao Wei Tjong 姚伟忠 10 years ago
parent
commit
a0125a19c1

+ 3 - 9
Source/Urho3D/LuaScript/LuaFile.cpp

@@ -47,12 +47,10 @@ LuaFile::LuaFile(Context* context) :
     hasLoaded_(false),
     hasLoaded_(false),
     hasExecuted_(false)
     hasExecuted_(false)
 {
 {
-
 }
 }
 
 
 LuaFile::~LuaFile()
 LuaFile::~LuaFile()
 {
 {
-
 }
 }
 
 
 void LuaFile::RegisterObject(Context* context)
 void LuaFile::RegisterObject(Context* context)
@@ -93,10 +91,7 @@ bool LuaFile::LoadChunk(lua_State* luaState)
     if (hasLoaded_)
     if (hasLoaded_)
         return true;
         return true;
 
 
-    if (size_ == 0)
-        return false;
-
-    if (!luaState)
+    if (size_ == 0 || !luaState)
         return false;
         return false;
 
 
     int top = lua_gettop(luaState);
     int top = lua_gettop(luaState);
@@ -132,16 +127,15 @@ bool LuaFile::LoadAndExecute(lua_State* luaState)
     if (!LoadChunk(luaState))
     if (!LoadChunk(luaState))
         return false;
         return false;
 
 
-    int top = lua_gettop(luaState);
-
     if (lua_pcall(luaState, 0, 0, 0))
     if (lua_pcall(luaState, 0, 0, 0))
     {
     {
         const char* message = lua_tostring(luaState, -1);
         const char* message = lua_tostring(luaState, -1);
         LOGERROR("Lua Execute failed for " + GetName() + ": " + String(message));
         LOGERROR("Lua Execute failed for " + GetName() + ": " + String(message));
-        lua_settop(luaState, top);
+        lua_pop(luaState, 1);
         return false;
         return false;
     }
     }
 
 
+    LOGINFO("Executed Lua script " + GetName());
     hasExecuted_ = true;
     hasExecuted_ = true;
 
 
     return true;
     return true;

+ 18 - 88
Source/Urho3D/LuaScript/LuaFunction.cpp

@@ -54,27 +54,19 @@ bool LuaFunction::IsValid() const
     return functionRef_ != LUA_REFNIL;
     return functionRef_ != LUA_REFNIL;
 }
 }
 
 
-bool LuaFunction::BeginCall()
-{
-    if (!IsValid())
-        return false;
-
-    stackTop_ = lua_gettop(luaState_);
-    numArguments_ = 0;
-    lua_rawgeti(luaState_, LUA_REGISTRYINDEX, functionRef_);
-
-    return true;
-}
-
 bool LuaFunction::BeginCall(const LuaScriptInstance* instance)
 bool LuaFunction::BeginCall(const LuaScriptInstance* instance)
 {
 {
     if (!IsValid())
     if (!IsValid())
         return false;
         return false;
 
 
-    stackTop_ = lua_gettop(luaState_);
-    numArguments_ = 1;
     lua_rawgeti(luaState_, LUA_REGISTRYINDEX, functionRef_);
     lua_rawgeti(luaState_, LUA_REGISTRYINDEX, functionRef_);
-    lua_rawgeti(luaState_, LUA_REGISTRYINDEX, instance->GetScriptObjectRef());
+    if (instance)
+    {
+        lua_rawgeti(luaState_, LUA_REGISTRYINDEX, instance->GetScriptObjectRef());
+        numArguments_ = 1;
+    }
+    else
+        numArguments_ = 0;
 
 
     return true;
     return true;
 }
 }
@@ -85,7 +77,7 @@ bool LuaFunction::EndCall(int numReturns)
     {
     {
         const char* message = lua_tostring(luaState_, -1);
         const char* message = lua_tostring(luaState_, -1);
         LOGERROR("Execute Lua function failed: " + String(message));
         LOGERROR("Execute Lua function failed: " + String(message));
-        lua_settop(luaState_, stackTop_);
+        lua_pop(luaState_, 1);
         return false;
         return false;
     }
     }
 
 
@@ -95,113 +87,51 @@ bool LuaFunction::EndCall(int numReturns)
 void LuaFunction::PushInt(int value)
 void LuaFunction::PushInt(int value)
 {
 {
     ++numArguments_;
     ++numArguments_;
-
     lua_pushinteger(luaState_, value);
     lua_pushinteger(luaState_, value);
 }
 }
 
 
 void LuaFunction::PushBool(bool value)
 void LuaFunction::PushBool(bool value)
 {
 {
     ++numArguments_;
     ++numArguments_;
-
     lua_pushboolean(luaState_, value);
     lua_pushboolean(luaState_, value);
 }
 }
 
 
 void LuaFunction::PushFloat(float value)
 void LuaFunction::PushFloat(float value)
 {
 {
     ++numArguments_;
     ++numArguments_;
+    lua_pushnumber(luaState_, value);
+}
 
 
+void LuaFunction::PushDouble(double value)
+{
+    ++numArguments_;
     lua_pushnumber(luaState_, value);
     lua_pushnumber(luaState_, value);
 }
 }
 
 
 void LuaFunction::PushString(const String& string)
 void LuaFunction::PushString(const String& string)
 {
 {
     ++numArguments_;
     ++numArguments_;
-
     tolua_pushurho3dstring(luaState_, string);
     tolua_pushurho3dstring(luaState_, string);
 }
 }
 
 
 void LuaFunction::PushUserType(void* userType, const char* typeName)
 void LuaFunction::PushUserType(void* userType, const char* typeName)
 {
 {
     ++numArguments_;
     ++numArguments_;
-
     tolua_pushusertype(luaState_, userType, typeName);
     tolua_pushusertype(luaState_, userType, typeName);
 }
 }
 
 
-bool LuaFunction::PushVariant(const Variant& variant)
+void LuaFunction::PushVariant(const Variant& variant, const char* asType)
 {
 {
-    switch (variant.GetType())
-    {
-    case VAR_INT:
-        PushInt(variant.GetInt());
-        return true;
-
-    case VAR_BOOL:
-        PushBool(variant.GetBool());
-        return true;
-
-    case VAR_FLOAT:
-        PushFloat(variant.GetFloat());
-        return true;
-
-    case VAR_VECTOR2:
-        PushUserType(variant.GetVector2(), "Vector2");
-        return true;
-
-    case VAR_VECTOR3:
-        PushUserType(variant.GetVector3(), "Vector3");
-        return true;
-
-    case VAR_VECTOR4:
-        PushUserType(variant.GetVector4(), "Vector4");
-        return true;
-
-    case VAR_QUATERNION:
-        PushUserType(variant.GetQuaternion(), "Quaternion");
-        return true;
-
-    case VAR_COLOR:
-        PushUserType(variant.GetColor(), "Color");
-        return true;
-
-    case VAR_STRING:
-        PushString(variant.GetString());
-        return true;
-
-    case VAR_BUFFER:
-        {
-            VectorBuffer buffer(variant.GetBuffer());
-            PushUserType(buffer, "VectorBuffer");
-        }
-        return true;
-
-    case VAR_RESOURCEREF:
-        PushUserType(variant.GetResourceRef(), "ResourceRef");
-        return true;
-
-    case VAR_INTRECT:
-        PushUserType(variant.GetIntRect(), "IntRect");
-        return true;
-
-    case VAR_INTVECTOR2:
-        PushUserType(variant.GetIntVector2(), "IntVector2");
-        return true;
-
-    default:
-        return false;
-    }
+    ++numArguments_;
+    ToluaPushVariant(luaState_, &variant, asType);
 }
 }
 
 
-bool LuaFunction::PushLuaTable(const String& tableName)
+void LuaFunction::PushLuaTable(const String& tableName)
 {
 {
     ++numArguments_;
     ++numArguments_;
-
     lua_getglobal(luaState_, tableName.CString());
     lua_getglobal(luaState_, tableName.CString());
     if (!lua_istable(luaState_, -1))
     if (!lua_istable(luaState_, -1))
-    {
-        LOGERROR("Could not find lua table " + tableName);
-        return false;
-    }
-    return true;
+        LOGERROR("Could not find lua table " + tableName);      // nil is pushed instead
 }
 }
 
 
 }
 }

+ 8 - 10
Source/Urho3D/LuaScript/LuaFunction.h

@@ -44,10 +44,8 @@ public:
 
 
     /// Check that function is valid.
     /// Check that function is valid.
     bool IsValid() const;
     bool IsValid() const;
-    /// Begin function call.
-    bool BeginCall();
-    /// Begin script object's function call.
-    bool BeginCall(const LuaScriptInstance* instance);
+    /// Begin function call. When a script object is given then pass it as self argument (first parameter) to the function call.
+    bool BeginCall(const LuaScriptInstance* instance = 0);
     /// End call and actually execute the function.
     /// End call and actually execute the function.
     bool EndCall(int numReturns = 0);
     bool EndCall(int numReturns = 0);
     /// Push int to stack.
     /// Push int to stack.
@@ -56,6 +54,8 @@ public:
     void PushBool(bool value);
     void PushBool(bool value);
     /// Push float to stack.
     /// Push float to stack.
     void PushFloat(float value);
     void PushFloat(float value);
+    /// Push double to stack.
+    void PushDouble(double value);
     /// Push string to stack.
     /// Push string to stack.
     void PushString(const String& string);
     void PushString(const String& string);
     /// Push user type to stack.
     /// Push user type to stack.
@@ -86,9 +86,9 @@ public:
     }
     }
 
 
     /// Push variant to stack.
     /// Push variant to stack.
-    bool PushVariant(const Variant& variant);
-    /// Push Lua table to stack.
-    bool PushLuaTable(const String& tableName);
+    void PushVariant(const Variant& variant, const char* asType = 0);
+    /// Push Lua table to stack. When the specified table is not found then a nil is pushed instead.
+    void PushLuaTable(const String& tableName);
 
 
     /// Return function ref.
     /// Return function ref.
     int GetFunctionRef() const { return functionRef_; }
     int GetFunctionRef() const { return functionRef_; }
@@ -100,9 +100,7 @@ private:
     int functionRef_;
     int functionRef_;
     /// Need unref.
     /// Need unref.
     bool needUnref_;
     bool needUnref_;
-    /// Lua stack top.
-    int stackTop_;
-    /// Number of arguments.
+    /// Number of arguments being pushed so far. For internal use only.
     int numArguments_;
     int numArguments_;
 };
 };
 
 

+ 25 - 32
Source/Urho3D/LuaScript/LuaScript.cpp

@@ -127,7 +127,6 @@ LuaScript::LuaScript(Context* context) :
     SetContext(luaState_, context_);
     SetContext(luaState_, context_);
 
 
     eventInvoker_ = new LuaScriptEventInvoker(context_);
     eventInvoker_ = new LuaScriptEventInvoker(context_);
-
     coroutineUpdate_ = GetFunction("coroutine.update");
     coroutineUpdate_ = GetFunction("coroutine.update");
 
 
     // Subscribe to post update
     // Subscribe to post update
@@ -144,14 +143,15 @@ LuaScript::~LuaScript()
 
 
     lua_State* luaState = luaState_;
     lua_State* luaState = luaState_;
     luaState_ = 0;
     luaState_ = 0;
+    coroutineUpdate_ = 0;
 
 
     if (luaState)
     if (luaState)
         lua_close(luaState);
         lua_close(luaState);
 }
 }
 
 
-void LuaScript::AddEventHandler(const String& eventName, int functionIndex)
+void LuaScript::AddEventHandler(const String& eventName, int index)
 {
 {
-    LuaFunction* function = GetFunction(functionIndex);
+    LuaFunction* function = GetFunction(index);
     if (function)
     if (function)
         eventInvoker_->AddEventHandler(0, eventName, function);
         eventInvoker_->AddEventHandler(0, eventName, function);
 }
 }
@@ -163,12 +163,12 @@ void LuaScript::AddEventHandler(const String& eventName, const String& functionN
         eventInvoker_->AddEventHandler(0, eventName, function);
         eventInvoker_->AddEventHandler(0, eventName, function);
 }
 }
 
 
-void LuaScript::AddEventHandler(Object* sender, const String& eventName, int functionIndex)
+void LuaScript::AddEventHandler(Object* sender, const String& eventName, int index)
 {
 {
     if (!sender)
     if (!sender)
         return;
         return;
 
 
-    LuaFunction* function = GetFunction(functionIndex);
+    LuaFunction* function = GetFunction(index);
     if (function)
     if (function)
         eventInvoker_->AddEventHandler(sender, eventName, function);
         eventInvoker_->AddEventHandler(sender, eventName, function);
 }
 }
@@ -309,11 +309,6 @@ bool LuaScript::ExecuteFunction(const String& functionName)
     return function && function->BeginCall() && function->EndCall();
     return function && function->BeginCall() && function->EndCall();
 }
 }
 
 
-void LuaScript::SendEvent(const String& eventName, VariantMap& eventData)
-{
-    Object::SendEvent(StringHash(eventName), eventData);
-}
-
 void LuaScript::SetExecuteConsoleCommands(bool enable)
 void LuaScript::SetExecuteConsoleCommands(bool enable)
 {
 {
     if (enable == executeConsoleCommands_)
     if (enable == executeConsoleCommands_)
@@ -353,8 +348,8 @@ int LuaScript::Loader(lua_State* L)
     String fileName(luaL_checkstring(L, 1));
     String fileName(luaL_checkstring(L, 1));
 
 
 #ifdef URHO3D_LUA_RAW_SCRIPT_LOADER
 #ifdef URHO3D_LUA_RAW_SCRIPT_LOADER
-    // First attempt to load lua script file from the file system.
-    // Attempt to load .luc file first, then fall back to .lua.
+    // First attempt to load lua script file from the file system
+    // Attempt to load .luc file first, then fall back to .lua
     LuaScript* lua = ::GetContext(L)->GetSubsystem<LuaScript>();
     LuaScript* lua = ::GetContext(L)->GetSubsystem<LuaScript>();
     if (lua->LoadRawFile(fileName + ".luc") || lua->LoadRawFile(fileName + ".lua"))
     if (lua->LoadRawFile(fileName + ".luc") || lua->LoadRawFile(fileName + ".lua"))
         return 1;
         return 1;
@@ -362,7 +357,7 @@ int LuaScript::Loader(lua_State* L)
 
 
     ResourceCache* cache = ::GetContext(L)->GetSubsystem<ResourceCache>();
     ResourceCache* cache = ::GetContext(L)->GetSubsystem<ResourceCache>();
 
 
-    // Attempt to get .luc file first.
+    // Attempt to get .luc file first
     LuaFile* lucFile = cache->GetResource<LuaFile>(fileName + ".luc", false);
     LuaFile* lucFile = cache->GetResource<LuaFile>(fileName + ".luc", false);
     if (lucFile)
     if (lucFile)
         return lucFile->LoadChunk(L) ? 1 : 0;
         return lucFile->LoadChunk(L) ? 1 : 0;
@@ -420,12 +415,12 @@ int LuaScript::Print(lua_State* L)
     return 0;
     return 0;
 }
 }
 
 
-LuaFunction* LuaScript::GetFunction(int functionIndex)
+LuaFunction* LuaScript::GetFunction(int index)
 {
 {
-    if (!lua_isfunction(luaState_, functionIndex))
+    if (!lua_isfunction(luaState_, index))
         return 0;
         return 0;
 
 
-    const void* functionPointer = lua_topointer(luaState_, functionIndex);
+    const void* functionPointer = lua_topointer(luaState_, index);
     if (!functionPointer)
     if (!functionPointer)
         return 0;
         return 0;
 
 
@@ -433,7 +428,7 @@ LuaFunction* LuaScript::GetFunction(int functionIndex)
     if (i != functionPointerToFunctionMap_.End())
     if (i != functionPointerToFunctionMap_.End())
         return i->second_;
         return i->second_;
 
 
-    lua_pushvalue(luaState_, functionIndex);
+    lua_pushvalue(luaState_, index);
     int functionRef = luaL_ref(luaState_, LUA_REGISTRYINDEX);
     int functionRef = luaL_ref(luaState_, LUA_REGISTRYINDEX);
 
 
     SharedPtr<LuaFunction> function(new LuaFunction(luaState_, functionRef, false));
     SharedPtr<LuaFunction> function(new LuaFunction(luaState_, functionRef, false));
@@ -489,32 +484,30 @@ void LuaScript::HandleConsoleCommand(StringHash eventType, VariantMap& eventData
 
 
 bool LuaScript::PushScriptFunction(const String& functionName, bool silentIfNotFound)
 bool LuaScript::PushScriptFunction(const String& functionName, bool silentIfNotFound)
 {
 {
-    Vector<String> splitedNames = functionName.Split('.');
+    Vector<String> splitNames = functionName.Split('.');
 
 
-    String currentName = splitedNames.Front();
+    String currentName = splitNames.Front();
     lua_getglobal(luaState_, currentName.CString());
     lua_getglobal(luaState_, currentName.CString());
 
 
-    if (splitedNames.Size() > 1)
+    if (splitNames.Size() > 1)
     {
     {
-        if (!lua_istable(luaState_, -1))
+        for (unsigned i = 0; i < splitNames.Size() - 1; ++i)
         {
         {
-            LOGERROR("Could not find Lua table: Table name = '" + currentName + "'");
-            return false;
-        }
-
-        for (unsigned i = 1; i < splitedNames.Size() - 1; ++i)
-        {
-            currentName = currentName + "." + splitedNames[i];
-            lua_getfield(luaState_, -1, splitedNames[i].CString());
+            if (i)
+            {
+                currentName = currentName + "." + splitNames[i];
+                lua_getfield(luaState_, -1, splitNames[i].CString());
+            }
             if (!lua_istable(luaState_, -1))
             if (!lua_istable(luaState_, -1))
             {
             {
-                LOGERROR("Could not find Lua table: Table name = '" + currentName + "'");
+                if (!silentIfNotFound)
+                    LOGERROR("Could not find Lua table: Table name = '" + currentName + "'");
                 return false;
                 return false;
             }
             }
         }
         }
 
 
-        currentName = currentName + "." + splitedNames.Back().CString();
-        lua_getfield(luaState_, -1, splitedNames.Back().CString());
+        currentName = currentName + "." + splitNames.Back();
+        lua_getfield(luaState_, -1, splitNames.Back().CString());
     }
     }
 
 
     if (!lua_isfunction(luaState_, -1))
     if (!lua_isfunction(luaState_, -1))

+ 10 - 12
Source/Urho3D/LuaScript/LuaScript.h

@@ -48,12 +48,12 @@ public:
     /// Destruct.
     /// Destruct.
     ~LuaScript();
     ~LuaScript();
 
 
-    /// Add a scripted event handler by function.
-    virtual void AddEventHandler(const String& eventName, int functionIndex);
+    /// Add a scripted event handler by function at the given stack index.
+    virtual void AddEventHandler(const String& eventName, int index);
     /// Add a scripted event handler by function name.
     /// Add a scripted event handler by function name.
     virtual void AddEventHandler(const String& eventName, const String& functionName);
     virtual void AddEventHandler(const String& eventName, const String& functionName);
-    /// Add a scripted event handler by function for a specific sender.
-    virtual void AddEventHandler(Object* sender, const String& eventName, int functionIndex);
+    /// Add a scripted event handler by function at the given stack index for a specific sender.
+    virtual void AddEventHandler(Object* sender, const String& eventName, int index);
     /// Add a scripted event handler by function name for a specific sender.
     /// Add a scripted event handler by function name for a specific sender.
     virtual void AddEventHandler(Object* sender, const String& eventName, const String& functionName);
     virtual void AddEventHandler(Object* sender, const String& eventName, const String& functionName);
     /// Remove a scripted event handler.
     /// Remove a scripted event handler.
@@ -77,18 +77,16 @@ public:
     bool ExecuteRawFile(const String& fileName);
     bool ExecuteRawFile(const String& fileName);
     /// Execute script function.
     /// Execute script function.
     bool ExecuteFunction(const String& functionName);
     bool ExecuteFunction(const String& functionName);
-    /// Send event.
-    void SendEvent(const String& eventName, VariantMap& eventData);
     /// Set whether to execute engine console commands as script code.
     /// Set whether to execute engine console commands as script code.
     void SetExecuteConsoleCommands(bool enable);
     void SetExecuteConsoleCommands(bool enable);
 
 
     /// Return Lua state.
     /// Return Lua state.
     lua_State* GetState() const { return luaState_; }
     lua_State* GetState() const { return luaState_; }
 
 
-    /// Return Lua function by function stack index.
-    LuaFunction* GetFunction(int functionIndex);
+    /// Return Lua function at the given stack index.
+    LuaFunction* GetFunction(int index);
     /// Return Lua function by function name.
     /// Return Lua function by function name.
-    LuaFunction* GetFunction(const String& functionName, bool silentIfNotfound = false);
+    LuaFunction* GetFunction(const String& functionName, bool silentIfNotFound = false);
 
 
     /// Return whether is executing engine console commands as script code.
     /// Return whether is executing engine console commands as script code.
     bool GetExecuteConsoleCommands() const { return executeConsoleCommands_; }
     bool GetExecuteConsoleCommands() const { return executeConsoleCommands_; }
@@ -102,8 +100,8 @@ private:
     void HandlePostUpdate(StringHash eventType, VariantMap& eventData);
     void HandlePostUpdate(StringHash eventType, VariantMap& eventData);
     /// Handle a console command event.
     /// Handle a console command event.
     void HandleConsoleCommand(StringHash eventType, VariantMap& eventData);
     void HandleConsoleCommand(StringHash eventType, VariantMap& eventData);
-    /// Push script function.
-    bool PushScriptFunction(const String& functionName, bool silentIfNotfound = false);
+    /// Push script function to stack.
+    bool PushScriptFunction(const String& functionName, bool silentIfNotFound = false);
 
 
     /// At panic.
     /// At panic.
     static int AtPanic(lua_State* L);
     static int AtPanic(lua_State* L);
@@ -114,7 +112,7 @@ private:
 
 
     /// Lua state.
     /// Lua state.
     lua_State* luaState_;
     lua_State* luaState_;
-    /// Event invoker.
+    /// Procedural event invoker.
     SharedPtr<LuaScriptEventInvoker> eventInvoker_;
     SharedPtr<LuaScriptEventInvoker> eventInvoker_;
     /// Coroutine update function.
     /// Coroutine update function.
     LuaFunction* coroutineUpdate_;
     LuaFunction* coroutineUpdate_;

+ 4 - 16
Source/Urho3D/LuaScript/LuaScriptEventInvoker.cpp

@@ -65,23 +65,11 @@ void LuaScriptEventInvoker::HandleLuaScriptEvent(StringHash eventType, VariantMa
 
 
     // Keep instance alive during invoking
     // Keep instance alive during invoking
     SharedPtr<LuaScriptInstance> instance(instance_);
     SharedPtr<LuaScriptInstance> instance(instance_);
-    if (instance)
+    if (function->BeginCall(instance))      // instance may be null when invoking a procedural event handler
     {
     {
-        if (function->BeginCall(instance))
-        {
-            function->PushUserType(eventType, "StringHash");
-            function->PushUserType(eventData, "VariantMap");
-            function->EndCall();
-        }
-    }
-    else
-    {
-        if (function->BeginCall())
-        {
-            function->PushUserType(eventType, "StringHash");
-            function->PushUserType(eventData, "VariantMap");
-            function->EndCall();
-        }
+        function->PushUserType(eventType, "StringHash");
+        function->PushUserType(eventData, "VariantMap");
+        function->EndCall();
     }
     }
 }
 }
 
 

+ 4 - 4
Source/Urho3D/LuaScript/LuaScriptEventListener.h

@@ -34,12 +34,12 @@ public:
     /// Destruct.
     /// Destruct.
     virtual ~LuaScriptEventListener() { };
     virtual ~LuaScriptEventListener() { };
 
 
-    /// Add a scripted event handler by function.
-    virtual void AddEventHandler(const String& eventName, int functionIndex) = 0;
+    /// Add a scripted event handler by function at the given stack index.
+    virtual void AddEventHandler(const String& eventName, int index) = 0;
     /// Add a scripted event handler by function name.
     /// Add a scripted event handler by function name.
     virtual void AddEventHandler(const String& eventName, const String& functionName) = 0;
     virtual void AddEventHandler(const String& eventName, const String& functionName) = 0;
-    /// Add a scripted event handler by function for a specific sender.
-    virtual void AddEventHandler(Object* sender, const String& eventName, int functionIndex) = 0;
+    /// Add a scripted event handler by function at the given stack index for a specific sender.
+    virtual void AddEventHandler(Object* sender, const String& eventName, int index) = 0;
     /// Add a scripted event handler by function name for a specific sender.
     /// Add a scripted event handler by function name for a specific sender.
     virtual void AddEventHandler(Object* sender, const String& eventName, const String& functionName) = 0;
     virtual void AddEventHandler(Object* sender, const String& eventName, const String& functionName) = 0;
     /// Remove a scripted event handler.
     /// Remove a scripted event handler.

+ 254 - 0
Source/Urho3D/LuaScript/ToluaUtils.cpp

@@ -22,6 +22,8 @@
 
 
 #include "../Precompiled.h"
 #include "../Precompiled.h"
 
 
+#include "../IO/VectorBuffer.h"
+
 #include <toluapp/tolua++.h>
 #include <toluapp/tolua++.h>
 
 
 #include "../LuaScript/ToluaUtils.h"
 #include "../LuaScript/ToluaUtils.h"
@@ -125,6 +127,258 @@ template <> int ToluaPushPODVector<bool>(double /*overload*/, lua_State* L, void
     return 1;
     return 1;
 }
 }
 
 
+namespace Urho3D
+{
+
+template <> const VariantValue* Variant::Get<const VariantValue*>() const
+{
+    return &value_;
+}
+
+}
+
+void ToluaToVariant(lua_State* L, int narg, void* def, Variant& variant)
+{
+    switch (lua_type(L, narg))   // Use the type of lua object to determine the final variant type
+    {
+    case LUA_TNIL:
+        variant = Variant::EMPTY;
+        break;
+
+    case LUA_TBOOLEAN:
+        variant = (bool)lua_toboolean(L, narg);     // Still need to cast to bool as Lua/LuaJIT return it as int
+        break;
+
+    case LUA_TNUMBER:
+        {
+            // Use the original variant type to further determine the final variant type
+            // CAVEAT: if lhs has integral data type and double is desired then lhs needs to be reset first before assigning
+            double value = lua_tonumber(L, narg);
+            switch (variant.GetType())
+            {
+            case VAR_INT:
+                variant = (int)value;
+                break;
+
+            case VAR_BOOL:
+                variant = value != 0.0f;
+                break;
+
+            case VAR_FLOAT:
+                variant = (float)value;
+                break;
+
+            default:
+                variant = value;
+            }
+        }
+        break;
+
+    case LUA_TSTRING:
+        variant = lua_tostring(L, narg);
+        break;
+
+    case LUA_TUSERDATA:
+        {
+            if (lua_getmetatable(L, narg))
+            {
+                lua_rawget(L, LUA_REGISTRYINDEX);     // registry[mt]
+                const char* typeName = lua_tostring(L, -1);
+                lua_pop(L, 1);
+
+                void* value = tolua_tousertype(L, narg, def);
+                switch (Variant::GetTypeFromName(typeName))
+                {
+                case VAR_NONE:
+                    // Handle special cases
+                    if (typeName)
+                    {
+                        tolua_Error error;
+                        if (strcmp(typeName, "Variant") == 0)
+                            variant = *static_cast<Variant*>(value);
+                        else if (strcmp(typeName, "VectorBuffer") == 0)
+                            variant = *static_cast<VectorBuffer*>(value);
+                        else if (tolua_isusertype(L, narg, "RefCounted", 0, &error))
+                            variant = static_cast<RefCounted*>(value);
+                        else
+                            variant = value;    // void*
+                    }
+                    break;
+
+                case VAR_VECTOR2:
+                    variant = *static_cast<Vector2*>(value);
+                    break;
+
+                case VAR_VECTOR3:
+                    variant = *static_cast<Vector3*>(value);
+                    break;
+
+                case VAR_VECTOR4:
+                    variant = *static_cast<Vector4*>(value);
+                    break;
+
+                case VAR_QUATERNION:
+                    variant = *static_cast<Quaternion*>(value);
+                    break;
+
+                case VAR_COLOR:
+                    variant = *static_cast<Color*>(value);
+                    break;
+
+                case VAR_INTRECT:
+                    variant = *static_cast<IntRect*>(value);
+                    break;
+
+                case VAR_INTVECTOR2:
+                    variant = *static_cast<IntVector2*>(value);
+                    break;
+
+                case VAR_MATRIX3:
+                    variant = *static_cast<Matrix3*>(value);
+                    break;
+
+                case VAR_MATRIX3X4:
+                    variant = *static_cast<Matrix3x4*>(value);
+                    break;
+
+                case VAR_MATRIX4:
+                    variant = *static_cast<Matrix4*>(value);
+                    break;
+
+                case VAR_RESOURCEREF:
+                    variant = *static_cast<ResourceRef*>(value);
+                    break;
+
+                case VAR_RESOURCEREFLIST:
+                    variant = *static_cast<ResourceRefList*>(value);
+                    break;
+
+                case VAR_VARIANTMAP:
+                    variant = *static_cast<VariantMap*>(value);
+                    break;
+
+                default: break;
+                }
+            };
+        }
+        break;
+
+    case LUA_TTABLE:
+        {
+            tolua_Error error;
+            if (ToluaIsPODVector<unsigned char>(0.f, L, narg, "unsigned char", 0, &error))
+                variant = *static_cast<PODVector<unsigned char>*>(ToluaToPODVector<unsigned char>(0.f, L, narg, def));
+            else if (ToluaIsVector<Variant>(L, narg, "Variant", 0, &error))
+                variant = *static_cast<VariantVector*>(ToluaToVector<Variant>(L, narg, def));
+            else if (ToluaIsVector<String>(L, narg, "String", 0, &error))
+                variant = *static_cast<StringVector*>(ToluaToVector<String>(L, narg, def));
+        }
+        break;
+
+    default: break;
+    }
+}
+
+void ToluaPushVariant(lua_State* L, const Variant* variant, const char* type)
+{
+    String typeName(type);
+    switch (variant->GetType())
+    {
+    case VAR_INT:
+        if (typeName == "unsigned" || typeName == "unsigned int" || typeName == "UInt" || typeName == "uint")
+            tolua_pushnumber(L, (lua_Number)variant->GetUInt());
+        else if (typeName == "StringHash")
+        {
+            // Make a new local copy
+            tolua_pushusertype(L, Mtolua_new(StringHash(variant->GetStringHash())), "StringHash");
+            tolua_register_gc(L, lua_gettop(L));
+        }
+        else
+            tolua_pushnumber(L, (lua_Number)variant->GetInt());
+        break;
+
+    case VAR_BOOL:
+        tolua_pushboolean(L, (int)variant->GetBool());
+        break;
+
+    case VAR_FLOAT:
+        tolua_pushnumber(L, (lua_Number)variant->GetFloat());
+        break;
+
+    case VAR_DOUBLE:
+        tolua_pushnumber(L, (lua_Number)variant->GetDouble());
+        break;
+
+    case VAR_VECTOR2:
+    case VAR_VECTOR3:
+    case VAR_VECTOR4:
+    case VAR_QUATERNION:
+    case VAR_COLOR:
+    case VAR_RESOURCEREF:
+    case VAR_RESOURCEREFLIST:
+    case VAR_VARIANTMAP:
+    case VAR_INTRECT:
+    case VAR_INTVECTOR2:
+        tolua_pushusertype(L, (void*)variant->Get<const VariantValue*>(), variant->GetTypeName().CString());
+        break;
+
+    case VAR_STRING:
+        tolua_pushurho3dstring(L, variant->GetString());
+        break;
+
+    case VAR_BUFFER:
+        if (typeName == "VectorBufer")
+        {
+            tolua_pushusertype(L, Mtolua_new(VectorBuffer(variant->GetVectorBuffer())), "VectorBuffer");
+            tolua_register_gc(L, lua_gettop(L));
+        }
+        else
+            ToluaPushPODVector<unsigned char>(0.f, L, (void*)&variant->GetBuffer(), "unsigned char");
+        break;
+
+    case VAR_VOIDPTR:
+        ToluaPushRegisteredUserType(L, static_cast<void*>(variant->GetVoidPtr()), type);
+        break;
+
+    case VAR_PTR:
+        ToluaPushRegisteredUserType(L, static_cast<void*>(variant->GetPtr()), type);
+        break;
+
+    case VAR_VARIANTVECTOR:
+        ToluaPushVector<Variant>(L, (void*)&variant->GetVariantVector(), "Variant");
+        break;
+
+    case VAR_STRINGVECTOR:
+        ToluaPushVector<String>(L, (void*)&variant->GetStringVector(), "String");
+        break;
+
+    case VAR_MATRIX3:
+    case VAR_MATRIX3X4:
+    case VAR_MATRIX4:
+        tolua_pushusertype(L, variant->Get<const VariantValue*>()->ptr_, variant->GetTypeName().CString());
+        break;
+
+    default:
+        lua_pushnil(L);
+        break;
+    }
+}
+
+void ToluaPushRegisteredUserType(lua_State* L, void* data, const char* type)
+{
+    if (type)
+    {
+        luaL_getmetatable(L, type);
+        if (!lua_isnil(L, -1))
+        {
+            lua_pop(L, 1);
+            tolua_pushusertype(L, data, type);
+        }
+    }
+    else
+        lua_pushnil(L);
+}
+
 void ToluaPushObject(lua_State* L, void* data, const char* type)
 void ToluaPushObject(lua_State* L, void* data, const char* type)
 {
 {
     tolua_pushusertype(L, data, data ? static_cast<Object*>(data)->GetTypeName().CString() : type);
     tolua_pushusertype(L, data, data ? static_cast<Object*>(data)->GetTypeName().CString() : type);

+ 9 - 0
Source/Urho3D/LuaScript/ToluaUtils.h

@@ -185,5 +185,14 @@ template <> int ToluaIsPODVector<bool>(double /*overload*/, lua_State* L, int lo
 template <> void* ToluaToPODVector<bool>(double /*overload*/, lua_State* L, int narg, void* def);
 template <> void* ToluaToPODVector<bool>(double /*overload*/, lua_State* L, int narg, void* def);
 template <> int ToluaPushPODVector<bool>(double /*overload*/, lua_State* L, void* data, const char* type);
 template <> int ToluaPushPODVector<bool>(double /*overload*/, lua_State* L, void* data, const char* type);
 
 
+/// Convert object at the given index and store it in Variant. This function is not thread-safe.
+void ToluaToVariant(lua_State* L, int narg, void* def, Variant& variant);
+
+/// Push object stored in a Variant to stack. Empty variant value is pushed as nil.
+void ToluaPushVariant(lua_State* L, const Variant* variant, const char* type = 0);
+
+/// Push a registered Lua user type to stack. If the specified type is not yet registered, a nil is pushed instead.
+void ToluaPushRegisteredUserType(lua_State* L, void* data, const char* type);
+
 /// Push Object to Lua.
 /// Push Object to Lua.
 void ToluaPushObject(lua_State* L, void* data, const char* type);
 void ToluaPushObject(lua_State* L, void* data, const char* type);

+ 5 - 249
Source/Urho3D/LuaScript/pkgs/Core/Variant.pkg

@@ -343,17 +343,7 @@ static int tolua_CoreLuaAPI_Variant_GetVoidPtr00(lua_State* tolua_S)
  if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetVoidPtr'", NULL);
  if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetVoidPtr'", NULL);
 #endif
 #endif
  {
  {
-     if (type)
-     {
-         luaL_getmetatable(tolua_S, type);
-         if (!lua_isnil(tolua_S, -1))
-         {
-             lua_pop(tolua_S, 1);
-             tolua_pushusertype(tolua_S, static_cast<void*>(self->GetVoidPtr()), type);
-         }
-     }
-     else
-         lua_pushnil(tolua_S);
+     ToluaPushRegisteredUserType(tolua_S, static_cast<void*>(self->GetVoidPtr()), type);
  }
  }
  }
  }
  return 1;
  return 1;
@@ -364,16 +354,6 @@ static int tolua_CoreLuaAPI_Variant_GetVoidPtr00(lua_State* tolua_S)
 #endif
 #endif
 }
 }
 
 
-namespace Urho3D
-{
-
-template <> const VariantValue* Variant::Get<const VariantValue*>() const
-{
-    return &value_;
-}
-
-}
-
 #define TOLUA_DISABLE_tolua_CoreLuaAPI_Variant_GetPtr00
 #define TOLUA_DISABLE_tolua_CoreLuaAPI_Variant_GetPtr00
 static int tolua_CoreLuaAPI_Variant_GetPtr00(lua_State* tolua_S)
 static int tolua_CoreLuaAPI_Variant_GetPtr00(lua_State* tolua_S)
 {
 {
@@ -394,17 +374,7 @@ static int tolua_CoreLuaAPI_Variant_GetPtr00(lua_State* tolua_S)
  if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetPtr'", NULL);
  if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetPtr'", NULL);
 #endif
 #endif
  {
  {
-     if (type)
-     {
-         luaL_getmetatable(tolua_S, type);
-         if (!lua_isnil(tolua_S, -1))
-         {
-             lua_pop(tolua_S, 1);
-             tolua_pushusertype(tolua_S, static_cast<void*>(self->GetPtr()), type);
-         }
-     }
-     else
-         lua_pushnil(tolua_S);
+     ToluaPushRegisteredUserType(tolua_S, static_cast<void*>(self->GetPtr()), type);
  }
  }
  }
  }
  return 1;
  return 1;
@@ -430,89 +400,12 @@ static int tolua_CoreLuaAPI_Variant_Get00(lua_State* tolua_S)
 #endif
 #endif
  {
  {
   const Variant* self = (const Variant*)  tolua_tousertype(tolua_S,1,0);
   const Variant* self = (const Variant*)  tolua_tousertype(tolua_S,1,0);
-  String type = String(tolua_tostring(tolua_S,2,0));
+  const char* type = ((const char*)  tolua_tostring(tolua_S,2,0));
 #ifndef TOLUA_RELEASE
 #ifndef TOLUA_RELEASE
  if (!self) tolua_error(tolua_S,"invalid 'self' in function 'Get'", NULL);
  if (!self) tolua_error(tolua_S,"invalid 'self' in function 'Get'", NULL);
 #endif
 #endif
  {
  {
-    switch (self->GetType())
-    {
-    case VAR_INT:
-        if (type == "UInt" || type == "unsigned" || type == "unsigned int")
-            tolua_pushnumber(tolua_S, (lua_Number)self->GetUInt());
-        else if (type == "StringHash")
-        {
-            // Make a new local copy
-            tolua_pushusertype(tolua_S, Mtolua_new(StringHash(self->GetStringHash())), "StringHash");
-            tolua_register_gc(tolua_S, lua_gettop(tolua_S));
-        }
-        else
-            tolua_pushnumber(tolua_S, (lua_Number)self->GetInt());
-        break;
-
-    case VAR_BOOL:
-        tolua_pushboolean(tolua_S, (int)self->GetBool());
-        break;
-
-    case VAR_FLOAT:
-        tolua_pushnumber(tolua_S, (lua_Number)self->GetFloat());
-        break;
-
-    case VAR_DOUBLE:
-        tolua_pushnumber(tolua_S, (lua_Number)self->GetDouble());
-        break;
-
-    case VAR_VECTOR2:
-    case VAR_VECTOR3:
-    case VAR_VECTOR4:
-    case VAR_QUATERNION:
-    case VAR_COLOR:
-    case VAR_RESOURCEREF:
-    case VAR_RESOURCEREFLIST:
-    case VAR_VARIANTMAP:
-    case VAR_INTRECT:
-    case VAR_INTVECTOR2:
-        tolua_pushusertype(tolua_S, (void*)self->Get<const VariantValue*>(), self->GetTypeName().CString());
-        break;
-
-    case VAR_STRING:
-        tolua_pushurho3dstring(tolua_S, (const char*)self->GetString());
-        break;
-
-    case VAR_BUFFER:
-        if (type == "VectorBufer")
-        {
-            tolua_pushusertype(tolua_S, Mtolua_new(VectorBuffer(self->GetVectorBuffer())), "VectorBuffer");
-            tolua_register_gc(tolua_S, lua_gettop(tolua_S));
-        }
-        else
-            ToluaPushPODVector<unsigned char>(0.f, tolua_S, (void*)&self->GetBuffer(), "unsigned char");
-        break;
-
-    case VAR_VOIDPTR:
-        return tolua_CoreLuaAPI_Variant_GetVoidPtr00(tolua_S);
-
-    case VAR_PTR:
-        return tolua_CoreLuaAPI_Variant_GetPtr00(tolua_S);
-
-    case VAR_VARIANTVECTOR:
-        ToluaPushVector<Variant>(tolua_S, (void*)&self->GetVariantVector(), "Variant");
-        break;
-
-    case VAR_STRINGVECTOR:
-        ToluaPushVector<String>(tolua_S, (void*)&self->GetStringVector(), "String");
-        break;
-
-    case VAR_MATRIX3:
-    case VAR_MATRIX3X4:
-    case VAR_MATRIX4:
-        tolua_pushusertype(tolua_S, (void*)self->Get<const VariantValue*>()->ptr_, self->GetTypeName().CString());
-        break;
-
-    default:
-        lua_pushnil(tolua_S);
-        break;
-    }
+     ToluaPushVariant(tolua_S, self, type);
  }
  }
  }
  }
  return 1;
  return 1;
@@ -582,144 +475,7 @@ static int VariantMapNewIndexEventHandler(lua_State* tolua_S)
     else
     else
         return 0;
         return 0;
     Variant& variant = static_cast<VariantMap*>(tolua_tousertype(tolua_S, 1, 0))->operator [](key);     // autovivification
     Variant& variant = static_cast<VariantMap*>(tolua_tousertype(tolua_S, 1, 0))->operator [](key);     // autovivification
-    switch (lua_type(tolua_S, 3))   // Use the type of lua object to determine the final variant type
-    {
-    case LUA_TNIL:
-        variant = Variant::EMPTY;
-        break;
-
-    case LUA_TBOOLEAN:
-        variant = (bool)lua_toboolean(tolua_S, 3);     // Still need to cast to bool as Lua/LuaJIT return it as int
-        break;
-
-    case LUA_TNUMBER:
-        {
-            // Use the original variant type to further determine the final variant type
-            // CAVEAT: if lhs has integral data type and double is desired then lhs needs to be reset first before assigning
-            double value = lua_tonumber(tolua_S, 3);
-            switch (variant.GetType())
-            {
-            case VAR_INT:
-                variant = (int)value;
-                break;
-
-            case VAR_BOOL:
-                variant = value != 0.0f;
-                break;
-
-            case VAR_FLOAT:
-                variant = (float)value;
-                break;
-
-            default:
-                variant = value;
-            }
-        }
-        break;
-
-    case LUA_TSTRING:
-        variant = lua_tostring(tolua_S, 3);
-        break;
-
-    case LUA_TUSERDATA:
-        {
-            if (lua_getmetatable(tolua_S, 3))
-            {
-                lua_rawget(tolua_S, LUA_REGISTRYINDEX);     // registry[mt]
-                const char* typeName = lua_tostring(tolua_S, -1);
-                lua_pop(tolua_S, 1);
-
-                void* value = tolua_tousertype(tolua_S, 3, 0);
-                switch (Variant::GetTypeFromName(typeName))
-                {
-                case VAR_NONE:
-                    // Handle special cases
-                    if (typeName)
-                    {
-                        tolua_Error error;
-                        if (strcmp(typeName, "Variant") == 0)
-                            variant = *static_cast<Variant*>(value);
-                        else if (strcmp(typeName, "VectorBuffer") == 0)
-                            variant = *static_cast<VectorBuffer*>(value);
-                        else if (tolua_isusertype(tolua_S, 3, "RefCounted", 0, &error))
-                            variant = static_cast<RefCounted*>(value);
-                        else
-                            variant = value;    // void*
-                    }
-                    break;
-
-                case VAR_VECTOR2:
-                    variant = *static_cast<Vector2*>(value);
-                    break;
-
-                case VAR_VECTOR3:
-                    variant = *static_cast<Vector3*>(value);
-                    break;
-
-                case VAR_VECTOR4:
-                    variant = *static_cast<Vector4*>(value);
-                    break;
-
-                case VAR_QUATERNION:
-                    variant = *static_cast<Quaternion*>(value);
-                    break;
-
-                case VAR_COLOR:
-                    variant = *static_cast<Color*>(value);
-                    break;
-
-                case VAR_INTRECT:
-                    variant = *static_cast<IntRect*>(value);
-                    break;
-
-                case VAR_INTVECTOR2:
-                    variant = *static_cast<IntVector2*>(value);
-                    break;
-
-                case VAR_MATRIX3:
-                    variant = *static_cast<Matrix3*>(value);
-                    break;
-
-                case VAR_MATRIX3X4:
-                    variant = *static_cast<Matrix3x4*>(value);
-                    break;
-
-                case VAR_MATRIX4:
-                    variant = *static_cast<Matrix4*>(value);
-                    break;
-
-                case VAR_RESOURCEREF:
-                    variant = *static_cast<ResourceRef*>(value);
-                    break;
-
-                case VAR_RESOURCEREFLIST:
-                    variant = *static_cast<ResourceRefList*>(value);
-                    break;
-
-                case VAR_VARIANTMAP:
-                    variant = *static_cast<VariantMap*>(value);
-                    break;
-
-                default: break;
-                }
-            };
-        }
-        break;
-
-    case LUA_TTABLE:
-        {
-            tolua_Error error;
-            if (ToluaIsPODVector<unsigned char>(0.f, tolua_S, 3, "unsigned char", 0, &error))
-                variant = *static_cast<PODVector<unsigned char>*>(ToluaToPODVector<unsigned char>(0.f, tolua_S, 3, 0));
-            else if (ToluaIsVector<Variant>(tolua_S, 3, "Variant", 0, &error))
-                variant = *static_cast<VariantVector*>(ToluaToVector<Variant>(tolua_S, 3, 0));
-            else if (ToluaIsVector<String>(tolua_S, 3, "String", 0, &error))
-                variant = *static_cast<StringVector*>(ToluaToVector<String>(tolua_S, 3, 0));
-        }
-        break;
-
-    default: break;
-    }
+    ToluaToVariant(tolua_S, 3, 0, variant);
     return 0;
     return 0;
 }
 }