bool luaval_to_tdga_map(lua_State* L,int lo,EventParamMap* outValue)
{
    if (NULL == L || NULL == outValue)
        return false;
    
    bool ok = true;
    
    tolua_Error tolua_err;
    if (!tolua_istable(L,lo,0,&tolua_err))
    {
#if COCOS2D_DEBUG >=1
        luaval_to_native_err(L,"#ferror:",&tolua_err);
#endif
        ok = false;
    }
    
    if (ok) {
        lua_pushnil(L);
        while (lua_next(L, lo))
        {
            lua_pushvalue(L, -2);
            const char* key = lua_tostring(L, -1);
            const char* value = lua_tostring(L, -2);
            (*outValue).insert(EventParamPair(key, value));
            lua_pop(L, 2);
        }
    }
    
    return ok;
}
bool luaval_to_Physics3DWorld_HitResult(lua_State* L,int lo, cocos2d::Physics3DWorld::HitResult* outValue, const char* funcName)
{
    if (nullptr == L || nullptr == outValue)
        return false;
    
    bool ok = true;
    
    tolua_Error tolua_err;
    if (!tolua_istable(L, lo, 0, &tolua_err) )
    {
#if COCOS2D_DEBUG >=1
        luaval_to_native_err(L,"#ferror:",&tolua_err,funcName);
#endif
        ok = false;
    }
    
    if (ok)
    {
        lua_pushstring(L, "hitPosition");
        lua_gettable(L, lo);
        if (!lua_istable(L, -1))
        {
            outValue->hitPosition = cocos2d::Vec3();
        }
        else
        {
            luaval_to_vec3(L, lua_gettop(L), &(outValue->hitPosition));
        }
        lua_pop(L, 1);
        
        lua_pushstring(L, "hitNormal");
        lua_gettable(L, lo);
        if (!lua_istable(L, -1))
        {
            outValue->hitNormal = cocos2d::Vec3();
        }
        else
        {
            luaval_to_vec3(L, lua_gettop(L), &(outValue->hitNormal));
        }
        lua_pop(L, 1);
        
        lua_pushstring(L, "hitObj");
        lua_gettable(L, lo);
        if (!tolua_isusertype(L, -1, "cc.Physics3DObject", 0, &tolua_err))
        {
            outValue->hitObj = nullptr;
        }
        else
        {
            outValue->hitObj = static_cast<cocos2d::Physics3DObject*>(tolua_tousertype(L, lua_gettop(L), nullptr));
        }
        lua_pop(L, 1);
    }
    return true;
}
bool luaval_to_offmeshlinkdata(lua_State* L, int lo, cocos2d::OffMeshLinkData* outValue , const char* funcName)
{
    if (nullptr == L || nullptr == outValue)
        return false;
    
    bool ok = true;
    
    tolua_Error tolua_err;
    if (!tolua_istable(L, lo, 0, &tolua_err) )
    {
#if COCOS2D_DEBUG >=1
        luaval_to_native_err(L,"#ferror:",&tolua_err,funcName);
#endif
        ok = false;
    }
    
    if (ok)
    {
        lua_pushstring(L, "startPosition");
        lua_gettable(L,lo);
        ok &= luaval_to_vec3(L, lua_gettop(L), &outValue->startPosition);
        if(!ok)
        {
            lua_pop(L, 1);
            return false;
        }
        lua_pop(L,1);

        lua_pushstring(L, "endPosition");
        ok &= luaval_to_vec3(L, lua_gettop(L), &outValue->endPosition);
        if(!ok)
        {
            lua_pop(L, 1);
            return false;
        }
        lua_pop(L,1);
        return true;
    }
    
    return false;
}
bool luaval_to_std_vector_string(lua_State* L, int lo, std::vector<std::string>* ret, const char* funcName)
{
    if (NULL == L || NULL == ret || lua_gettop(L) < lo)
        return false;

    tolua_Error tolua_err;
    bool ok = true;
    if (!tolua_istable(L, lo, 0, &tolua_err))
    {
#if COCOS2D_DEBUG >=1
        luaval_to_native_err(L,"#ferror:",&tolua_err,funcName);
#endif
        ok = false;
    }

    if (ok)
    {
        size_t len = lua_objlen(L, lo);
        std::string value = "";
        for (size_t i = 0; i < len; i++)
        {
            lua_pushnumber(L, i + 1);
            lua_gettable(L,lo);
            if(lua_isstring(L, -1))
            {
                ok = luaval_to_std_string(L, -1, &value);
                if(ok)
                    ret->push_back(value);
            }
            else
            {
                //                CCASSERT(false, "string type is needed");
            }

            lua_pop(L, 1);
        }
    }

    return ok;
}
bool luaval_to_int32(lua_State* L,int lo,int* outValue, const char* funcName)
{
    if (NULL == L || NULL == outValue)
        return false;

    bool ok = true;

    tolua_Error tolua_err;
    if (!tolua_isnumber(L,lo,0,&tolua_err))
    {
#if COCOS2D_DEBUG >=1
        luaval_to_native_err(L,"#ferror:",&tolua_err,funcName);
#endif
        ok = false;
    }

    if (ok)
    {
        /**
         When we want to convert the number value from the Lua to int, we would call lua_tonumber to implement.It would
         experience two phase conversion: int -> double, double->int.But,for the 0x80000000 which the min value of int, the
         int cast may return an undefined result,like 0x7fffffff.So we must use the (int)(unsigned int)lua_tonumber() to get
         predictable results for 0x80000000.In this place,we didn't use lua_tointeger, because it may produce differen results
         depending on the compiler,e.g:for iPhone4s,it also get wrong value for 0x80000000.
         */
        unsigned int estimateValue = (unsigned int)lua_tonumber(L, lo);
        if (estimateValue == std::numeric_limits<int>::min())
        {
            *outValue = (int)estimateValue;
        }
        else
        {
            *outValue = (int)lua_tonumber(L, lo);
        }
    }

    return ok;
}
bool luaval_to_ushort(lua_State* L, int lo, unsigned short* outValue, const char* funcName)
{
    if (NULL == L || NULL == outValue)
        return false;

    bool ok = true;

    tolua_Error tolua_err;
    if (!tolua_isnumber(L,lo,0,&tolua_err))
    {
#if COCOS2D_DEBUG >=1
        luaval_to_native_err(L,"#ferror:",&tolua_err,funcName);
#endif
        ok = false;
    }

    if (ok)
    {
        *outValue = (unsigned short)tolua_tonumber(L, lo, 0);
    }

    return ok;
}
bool luaval_to_std_string(lua_State* L, int lo, std::string* outValue, const char* funcName)
{
    if (NULL == L || NULL == outValue)
        return false;

    bool ok = true;

    tolua_Error tolua_err;
    if (!tolua_iscppstring(L,lo,0,&tolua_err))
    {
#if COCOS2D_DEBUG >=1
        luaval_to_native_err(L,"#ferror:",&tolua_err,funcName);
#endif
        ok = false;
    }

    if (ok)
    {
        *outValue = tolua_tocppstring(L,lo,NULL);
    }

    return ok;
}
bool luaval_to_boolean(lua_State* L,int lo,bool* outValue, const char* funcName)
{
    if (NULL == L || NULL == outValue)
        return false;

    bool ok = true;

    tolua_Error tolua_err;
    if (!tolua_isboolean(L,lo,0,&tolua_err))
    {
#if COCOS2D_DEBUG >=1
        luaval_to_native_err(L,"#ferror:",&tolua_err,funcName);
#endif
        ok = false;
    }

    if (ok)
    {
        *outValue = (bool)tolua_toboolean(L, lo, 0);
    }

    return ok;
}
bool luaval_to_navmeshagentparam(lua_State* L, int lo, cocos2d::NavMeshAgentParam* outValue , const char* funcName)
{
    if (nullptr == L || nullptr == outValue)
        return false;
    
    bool ok = true;
    
    tolua_Error tolua_err;
    if (!tolua_istable(L, lo, 0, &tolua_err) )
    {
#if COCOS2D_DEBUG >=1
        luaval_to_native_err(L,"#ferror:",&tolua_err,funcName);
#endif
        ok = false;
    }
    
    if (ok)
    {
        lua_pushstring(L, "radius");
        lua_gettable(L,lo);
        outValue->radius = lua_isnumber(L, -1)? (float)lua_tonumber(L, -1) : 0.6;
        lua_pop(L,1);
        
        lua_pushstring(L, "height");
        lua_gettable(L,lo);
        outValue->height = lua_isnumber(L, -1)?(float)lua_tonumber(L, -1) : 2.0;
        lua_pop(L,1);
        
        lua_pushstring(L, "maxAcceleration");
        lua_gettable(L, lo);
        outValue->maxAcceleration = lua_isnumber(L, -1)?(float)lua_tonumber(L, -1) : 8.0;
        lua_pop(L, 1);
        

        lua_pushstring(L, "maxSpeed");
        lua_gettable(L, lo);
        outValue->maxSpeed = lua_isnumber(L, -1)?(float)lua_tonumber(L, -1) : 3.5;
        lua_pop(L, 1);

        lua_pushstring(L, "collisionQueryRange");
        lua_gettable(L, lo);
        outValue->collisionQueryRange = lua_isnumber(L, -1)?(float)lua_tonumber(L, -1) : outValue->radius * 12.0;
        lua_pop(L, 1);

        lua_pushstring(L, "pathOptimizationRange");
        lua_gettable(L, lo);
        outValue->pathOptimizationRange = lua_isnumber(L, -1)?(float)lua_tonumber(L, -1) :  outValue->radius * 30.0;
        lua_pop(L, 1);

        lua_pushstring(L, "separationWeight");
        lua_gettable(L, lo);
        outValue->separationWeight = lua_isnumber(L, -1)?(float)lua_tonumber(L, -1) : 2.0;
        lua_pop(L, 1);

        lua_pushstring(L, "updateFlags");
        lua_gettable(L, lo);
        outValue->updateFlags = lua_isnumber(L, -1)?(unsigned char)lua_tonumber(L, -1) : DT_CROWD_ANTICIPATE_TURNS | DT_CROWD_OPTIMIZE_VIS | DT_CROWD_OPTIMIZE_TOPO | DT_CROWD_OBSTACLE_AVOIDANCE;
        lua_pop(L, 1);

        lua_pushstring(L, "obstacleAvoidanceType");
        lua_gettable(L, lo);
        outValue->obstacleAvoidanceType = lua_isnumber(L, -1)?(unsigned char)lua_tonumber(L, -1) : 3;
        lua_pop(L, 1);

        lua_pushstring(L, "queryFilterType");
        lua_gettable(L, lo);
        outValue->queryFilterType = lua_isnumber(L, -1)?(unsigned char)lua_tonumber(L, -1) : 0;
        lua_pop(L, 1);

        return true;
    }
    
    return false;
}
int lua_cocos2dx_physics3d_Physics3DShape_createCompoundShape(lua_State* L)
{
    int argc = 0;
    bool ok  = true;
    
    tolua_Error tolua_err;
    
#if COCOS2D_DEBUG >= 1
    if (!tolua_isusertable(L,1,"cc.Physics3DShape",0,&tolua_err)) goto tolua_lerror;
#endif
    
    argc = lua_gettop(L) - 1;
    
    if (argc == 1)
    {
        
        std::vector<std::pair<cocos2d::Physics3DShape *, cocos2d::Mat4>> shapes;
        if (!tolua_istable(L, 2, 0, &tolua_err) )
        {
#if COCOS2D_DEBUG >=1
            luaval_to_native_err(L,"#ferror:",&tolua_err,"cc.Physics3DShape:createCompoundShape");
#endif
            ok = false;
        }
        
        if (ok)
        {
            size_t len = lua_objlen(L, 2);
            cocos2d::Physics3DShape* shape = nullptr;
            cocos2d::Mat4 mat;
            for (size_t i = 0; i < len; i++)
            {
                lua_pushnumber(L,i + 1);
                lua_gettable(L,2);
                if (lua_istable(L, -1))
                {
                    lua_pushnumber(L, 1);
                    lua_gettable(L, -2);
                    luaval_to_object(L, lua_gettop(L), "cc.Physics3DShape", &shape);
                    lua_pop(L,1);
                    
                    lua_pushnumber(L, 2);
                    lua_gettable(L, -2);
                    luaval_to_mat4(L, lua_gettop(L), &mat);
                    lua_pop(L,1);
                    
                    shapes.push_back(std::make_pair(shape, mat));
                }
                lua_pop(L, 1);
            }
        }

        cocos2d::Physics3DShape* ret = cocos2d::Physics3DShape::createCompoundShape(shapes);
        object_to_luaval<cocos2d::Physics3DShape>(L, "cc.Physics3DShape",(cocos2d::Physics3DShape*)ret);
        return 1;
    }
    luaL_error(L, "%s has wrong number of arguments: %d, was expecting %d\n ", "cc.Physics3DShape:createCompoundShape",argc, 1);
    return 0;
#if COCOS2D_DEBUG >= 1
tolua_lerror:
    tolua_error(L,"#ferror in function 'lua_cocos2dx_physics3d_Physics3DShape_createCompoundShape'.",&tolua_err);
#endif
    return 0;
}
bool luaval_to_Physics3DRigidBodyDes(lua_State* L,int lo,cocos2d::Physics3DRigidBodyDes* outValue, const char* funcName)
{
    if (nullptr == L || nullptr == outValue)
        return false;
    
    bool ok = true;
    
    tolua_Error tolua_err;
    if (!tolua_istable(L, lo, 0, &tolua_err) )
    {
#if COCOS2D_DEBUG >=1
        luaval_to_native_err(L,"#ferror:",&tolua_err,funcName);
#endif
        ok = false;
    }
    
    if (ok)
    {
        lua_pushstring(L, "mass");
        lua_gettable(L, lo);
        outValue->mass = lua_isnil(L, -1) ? 0 : lua_tonumber(L, -1);
        lua_pop(L, 1);
        
        lua_pushstring(L, "localInertia");
        lua_gettable(L, lo);
        if (!lua_istable(L, -1))
        {
            outValue->localInertia = cocos2d::Vec3(0.0, 0.0, 0.0);
        }
        else
        {
            luaval_to_vec3(L, lua_gettop(L), &outValue->localInertia);
        }
        lua_pop(L, 1);
        
        lua_pushstring(L, "shape");
        lua_gettable(L, lo);
        if (!tolua_isusertype(L, -1, "cc.Physics3DShape", 0, &tolua_err))
        {
            outValue->shape = nullptr;
        }
        else
        {
            outValue->shape = static_cast<cocos2d::Physics3DShape*>(tolua_tousertype(L, lua_gettop(L), nullptr));
        }
        lua_pop(L, 1);
        
        lua_pushstring(L, "originalTransform");
        lua_gettable(L, lo);
        if (!lua_istable(L, -1))
        {
            outValue->originalTransform = cocos2d::Mat4();
        }
        else
        {
            luaval_to_mat4(L, lua_gettop(L), &outValue->originalTransform);
        }
        lua_pop(L, 1);
        
        lua_pushstring(L, "disableSleep");
        lua_gettable(L, lo);
        outValue->disableSleep = lua_isnil(L, -1) ? false : lua_toboolean(L, -1);
        lua_pop(L, 1);
    }
    return ok;
}