LuaFunction LuaFunction::createFromCode(lua_State* L, std::string const& code, std::string const& name) { int err = luaL_loadbuffer(L, code.c_str(), code.length(), name.c_str()); if (!err) { LuaFunction func; func.setReference(LuaReference::create(L)); lua_pop(L, 1); return func; } else { // Get the error message size_t len; const char* err = lua_tolstring(L, -1, &len); lua_pop(L, 1); throw LuaException(std::string(err, len)); } }
/* method: Call of class LuaFunction */ static int tolua_LuaFunction_LuaFunction_Call00(lua_State* tolua_S) { #ifndef TOLUA_RELEASE tolua_Error tolua_err; if ( !tolua_isusertype(tolua_S,1,"LuaFunction",0,&tolua_err) || !tolua_isnoobj(tolua_S,2,&tolua_err) ) goto tolua_lerror; else #endif { LuaFunction* self = (LuaFunction*) tolua_tousertype(tolua_S,1,0); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S,"invalid 'self' in function 'Call'",NULL); #endif { self->Call(); } } return 0; #ifndef TOLUA_RELEASE tolua_lerror: tolua_error(tolua_S,"#ferror in function 'Call'.",&tolua_err); return 0; #endif }
LuaObject LuaGlobalSelector::toLuaObject( void ) const { magicalAssert( !_key.empty(), "key should not be empty!" ); lua_State* L = _L->cPtr(); LuaObject lobj; lua_getglobal( L, _key.c_str() ); switch( lua_type( L, -1 ) ) { case LUA_TNIL: lobj = nullptr; break; case LUA_TBOOLEAN: lobj = (bool) lua_toboolean( L, -1 ); break; case LUA_TNUMBER: lobj = (double) lua_tonumber( L, -1 ); break; case LUA_TSTRING: lobj = lua_tostring( L, -1 ); break; case LUA_TUSERDATA: { int top = lua_gettop( L ); std::string type = tolua_typename( L, top ); lua_pop( L, 1 ); void* userdata = tolua_tousertype( L, top, 0 ); lobj.set( userdata, type.c_str() ); } break; case LUA_TFUNCTION: { LuaFunction lf; int handler = tolua_ext_tofunction( L, lua_gettop( L ), 0 ); if( handler != 0 ) { lf.bind( _L, handler ); } lobj = lf; } break; case LUA_TTABLE: { LuaTable lt; int handler = tolua_ext_totable( L, lua_gettop( L ), 0 ); if( handler != 0 ) { lt.bind( _L, handler ); } lobj = lt; } break; default: lobj = nullptr; break; } lua_pop( L, 1 ); return lobj; }
// - LuaFunction::operator> ------------------------------------------------- bool LuaFunction::operator> (const LuaFunction& rhs) const { if (functionType_ > rhs.functionType_) return true; else if (getSize() > rhs.getSize()) return true; else if (getSize() < rhs.getSize()) return false; else // getSize() == rhs.getSize() return memcmp (getData(), rhs.getData(), getSize()) > 0; }
LuaFunction LuaFunction::createFromCFunction(lua_State* L, lua_CFunction function) { LuaFunction func; lua_pushcfunction(L, function); func.setReference(LuaReference::create(L)); lua_pop(L, 1); return func; }
TEST_F(LuaFunctionTest, Call) { { ScopedLuaStackTest stackTest(L); // Test execution with failure LuaFunction function = LuaFunction::createFromCode(L, "invalid()"); ASSERT_THROW(function.call(), luacpp::LuaException); ASSERT_THROW(function(), luacpp::LuaException); } { ScopedLuaStackTest stackTest(L); // Test execution without failure LuaFunction function = LuaFunction::createFromCode(L, "local a = 1"); ASSERT_NO_THROW(function.call()); ASSERT_NO_THROW(function()); } { ScopedLuaStackTest stackTest(L); // Test execution without failure LuaFunction function = LuaFunction::createFromCode(L, "return 'abc', 5"); LuaValueList returnValues = function(); ASSERT_EQ(luacpp::ValueType::STRING, returnValues[0].getValueType()); ASSERT_EQ(luacpp::ValueType::NUMBER, returnValues[1].getValueType()); ASSERT_STREQ("abc", returnValues[0].getValue<std::string>().c_str()); ASSERT_EQ(5, returnValues[1].getValue<int>()); } { ScopedLuaStackTest stackTest(L); lua_getglobal(L, "type"); LuaFunction func; ASSERT_TRUE(convert::popValue(L, func)); LuaValue arg = LuaValue::createValue(L, "testString"); LuaValueList returnVals = func({ arg }); ASSERT_EQ(1, (int)returnVals.size()); ASSERT_EQ(ValueType::STRING, returnVals[0].getValueType()); ASSERT_STREQ("string", returnVals[0].getValue<std::string>().c_str()); } }
TEST_F(LuaFunctionTest, ErrorFunctionNoReturnValues) { ScopedLuaStackTest stackTest(L); LuaFunction func = LuaFunction::createFromCode(L, "invalid()"); func.setErrorFunction(LuaFunction::createFromCFunction(L, &testErrorFunctionNoRetVals)); try { func(); FAIL(); } catch (const LuaException& err) { ASSERT_STREQ("Invalid lua value on stack!", err.what()); } }
void LuaAiState::onSeeEnemy(IActor *enemy) { LuaType::registerConstant<IBody>(this->script, "body", this->body); LuaFunction luaFunction; luaFunction.readyToRunFunction(this->script, "OnSeeEnemy"); this->script->sendToLua<void*>(enemy); luaFunction.runFunction(1, 0); luaFunction.clearAfterFunction(); this->script->removeSymbol("body"); }
CallbackFunction *CallbackFunction::create_from_stack(lua_State *L, int pos) { if (lua_type(L, pos) == LUA_TUSERDATA) { return checkarg<CallbackFunction>(L, pos); } else if (lua_type(L, pos) == LUA_TNIL) { return NULL; } else { LuaFunction *f = create<LuaFunction>(L); f->hold(pos, "lua_callback"); return f; } }
void LuaAiState::onTakeDamage(IActor* instigator, float damageValue, Vector2D impulse) { LuaType::registerConstant<IBody>(this->script, "body", this->body); LuaFunction luaFunction; luaFunction.readyToRunFunction(this->script, "OnTakeDamage"); this->script->sendToLua<void*>(instigator); this->script->sendToLua<double>(damageValue); luaFunction.runFunction(2, 0); luaFunction.clearAfterFunction(); this->script->removeSymbol("body"); }
LuaFunction LuaFunction::createFromCFunction(lua_State* L, lua_CFunction function, const LuaValueList& upvalues) { LuaFunction func; for (auto& val : upvalues) { val.pushValue(); } lua_pushcclosure(L, function, (int) upvalues.size()); func.setReference(UniqueLuaReference::create(L)); lua_pop(L, 1); return func; }
LuaFunction LuaGlobalSelector::toLuaFunction( void ) const { magicalAssert( !_key.empty(), "key should not be empty!" ); lua_State* L = _L->cPtr(); LuaFunction lf; lua_getglobal( L, _key.c_str() ); int handler = tolua_ext_tofunction( L, lua_gettop( L ), 0 ); if( handler != 0 ) { lf.bind( _L, handler ); } lua_pop( L, 1 ); return lf; }
TEST_F(LuaFunctionTest, SetErrorFunction) { { ScopedLuaStackTest stackTest(L); LuaFunction func = LuaFunction::createFromCode(L, "invalid()"); func.setErrorFunction(LuaFunction::createFromCFunction(L, &testErrorFunction)); try { func(); FAIL(); } catch (const LuaException& err) { ASSERT_STREQ("TestError", err.what()); } } }
// - LuaState::call --------------------------------------------------------- LuaValueList LuaState::call (LuaFunction& func, const LuaValueList& params, const std::string& chunkName) { func.setReaderFlag (false); PushLuaValue (state_, LuaValue (func)); return Impl::CallFunctionOnTop (state_, params); }
TEST_F(LuaFunctionTest, SetReference) { { ScopedLuaStackTest stackTest(L); LuaFunction func = LuaFunction::createFromCode(L, "invalid()"); lua_pushliteral(L, "abc"); ASSERT_THROW(func.setReference(UniqueLuaReference::create(L)), LuaException); lua_pop(L, 1); lua_getglobal(L, "type"); ASSERT_NO_THROW(func.setReference(UniqueLuaReference::create(L))); lua_pop(L, 1); } }
void LuaScriptEventInvoker::HandleLuaScriptEvent(StringHash eventType, VariantMap& eventData) { LuaFunction* function = static_cast<LuaFunction*>(GetEventHandler()->GetUserData()); if (!function) return; // Keep instance alive during invoking SharedPtr<LuaScriptInstance> instance(instance_); if (instance) { 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(); } } }
LuaFunction LuaTableSelector::toLuaFunction( void ) const { magicalAssert( !_key.empty(), "key should not be empty!" ); if( !_L || !_handler ) return nullptr; LuaFunction lf; lua_State* L = _L->cPtr(); tolua_ext_get_table_by_handler( L, _handler ); lua_getfield( L, -1, _key.c_str() ); int handler = tolua_ext_tofunction( L, lua_gettop( L ), 0 ); if( handler != 0 ) { lf.bind( _L, handler ); } lua_pop( L, 2 ); return lf; }
TEST_F(LuaFunctionTest, SetEnvironment) { { ScopedLuaStackTest stackTest(L); // Setup environment table LuaTable envionment = LuaTable::create(L); envionment.addValue("key", "Test"); LuaFunction func = LuaFunction::createFromCode(L, "return key"); func.setEnvironment(envionment); LuaValueList returnVals = func(); ASSERT_EQ(1, (int)returnVals.size()); ASSERT_EQ(ValueType::STRING, returnVals[0].getValueType()); ASSERT_STREQ("Test", returnVals[0].getValue<std::string>().c_str()); } }
bool ::luacpp::convert::popValue(lua_State* luaState, LuaFunction& target, int stackposition, bool remove) { if (!internal::isValidIndex(luaState, stackposition)) { return false; } if (!lua_isfunction(luaState, stackposition)) { return false; } else { target.setReference(UniqueLuaReference::create(luaState, stackposition)); if (remove) { lua_remove(luaState, stackposition); } return true; } }
// - LuaFunction::operator== ------------------------------------------------ bool LuaFunction::operator== (const LuaFunction& rhs) const { return functionType_ == rhs.functionType_ && getSize() == rhs.getSize() && memcmp (getData(), rhs.getData(), getSize()) == 0; }
static int push(lua_State* l, const LuaFunction& ref) { return ref.push(l); }
bool LuaScript::ExecuteFunction(const String& functionName) { LuaFunction* function = GetFunction(functionName); return function && function->BeginCall() && function->EndCall(); }
/** Sets the value of the element as a function value */ void LuaTableElement::set(LuaFunction f) { type = FUNCTION; func_value = f.getFunction(); }
void LuaIntegration::CreateScene() { auto* cache = GetSubsystem<ResourceCache>(); scene_ = new Scene(context_); // Create the Octree component to the scene so that drawable objects can be rendered. Use default volume // (-1000, -1000, -1000) to (1000, 1000, 1000) scene_->CreateComponent<Octree>(); // Create a Zone component into a child scene node. The Zone controls ambient lighting and fog settings. Like the Octree, // it also defines its volume with a bounding box, but can be rotated (so it does not need to be aligned to the world X, Y // and Z axes.) Drawable objects "pick up" the zone they belong to and use it when rendering; several zones can exist Node* zoneNode = scene_->CreateChild("Zone"); auto* zone = zoneNode->CreateComponent<Zone>(); // Set same volume as the Octree, set a close bluish fog and some ambient light zone->SetBoundingBox(BoundingBox(-1000.0f, 1000.0f)); zone->SetAmbientColor(Color(0.05f, 0.1f, 0.15f)); zone->SetFogColor(Color(0.1f, 0.2f, 0.3f)); zone->SetFogStart(10.0f); zone->SetFogEnd(100.0f); auto* scriptFile = cache->GetResource<LuaFile>("LuaScripts/Utilities/Rotator.lua"); if (!scriptFile) return; // Create randomly positioned and oriented box StaticModels in the scene const unsigned NUM_OBJECTS = 2000; for (unsigned i = 0; i < NUM_OBJECTS; ++i) { Node* boxNode = scene_->CreateChild("Box"); boxNode->SetPosition(Vector3(Random(200.0f) - 100.0f, Random(200.0f) - 100.0f, Random(200.0f) - 100.0f)); // Orient using random pitch, yaw and roll Euler angles boxNode->SetRotation(Quaternion(Random(360.0f), Random(360.0f), Random(360.0f))); auto* boxObject = boxNode->CreateComponent<StaticModel>(); boxObject->SetModel(cache->GetResource<Model>("Models/Box.mdl")); boxObject->SetMaterial(cache->GetResource<Material>("Materials/Stone.xml")); // Add our custom Rotator script object (using the LuaScriptInstance C++ component to instantiate / store it) which will // rotate the scene node each frame, when the scene sends its update event auto* instance = boxNode->CreateComponent<LuaScriptInstance>(); instance->CreateObject(scriptFile, "Rotator"); // Call the script object's "SetRotationSpeed" function. LuaFunction* function = instance->GetScriptObjectFunction("SetRotationSpeed"); if (function && function->BeginCall(instance)) { function->PushUserType(Vector3(10.0f, 20.0f, 30.0f), "Vector3"); function->EndCall(); } } // Create the camera. Let the starting position be at the world origin. As the fog limits maximum visible distance, we can // bring the far clip plane closer for more effective culling of distant objects cameraNode_ = scene_->CreateChild("Camera"); auto* camera = cameraNode_->CreateComponent<Camera>(); camera->SetFarClip(100.0f); // Create a point light to the camera scene node auto* light = cameraNode_->CreateComponent<Light>(); light->SetLightType(LIGHT_POINT); light->SetRange(30.0f); }
LuaFunction::LuaFunction (const LuaFunction& other) : functionType_(other.functionType_), size_(other.getSize()), data_(new char[size_]) { memcpy (data_.get(), other.getData(), getSize()); }
// - LuaFunction::operator!= ------------------------------------------------ bool LuaFunction::operator!= (const LuaFunction& rhs) const { return functionType_ != rhs.functionType_ || getSize() != rhs.getSize() || memcmp (getData(), rhs.getData(), getSize()) != 0; }
/** * @brief Sets the function called when an error occurs * This lua_Cfunction will be called by lua if an error occus while executing this function * * @return void */ void setErrorFunction(const LuaFunction& errorFunc) { errorFunction = errorFunc.getReference(); }