#include "scriptable_controller.h" #include "luatb.h" #include "infos/PlayerInfo.h" namespace orxonox { // Used https://csl.name/post/lua-and-cpp/ as a reference int ScriptableController::runScript(const std::string &file_path) { int ret; // Create a lua object lua_State *lua = luaL_newstate(); if(lua == nullptr) { orxout(internal_warning) << "ScriptableController: Falied to load script " << file_path << std::endl; return LUA_ERRMEM; } // Make standard libraries available in the Lua object luaL_openlibs(lua); // Register the API ScriptableControllerAPI *api = new ScriptableControllerAPI(lua, this); // Load the program; this supports both source code and bytecode files. if((ret = luaL_loadfile(lua, file_path.c_str())) != 0) { this->printLuaError(lua); delete api; return ret; } // Execute the script if((ret = lua_pcall(lua, 0, LUA_MULTRET, 0)) != 0) { this->printLuaError(lua); delete api; return ret; } // Remeber the api this->apis_.push_back(std::unique_ptr(api)); // Only the caller knows, when the end-of-life of the script is reached, // so we give him control over when to destroy it. return 0; } void ScriptableController::setPlayer(PlayerInfo *player) { this->player_ = player; } void ScriptableController::registerWorldEntity(int id, WorldEntity *obj) { orxout(user_info) << "WorldEntity registered (id: " << id << ")" << std::endl; this->worldEntities_[id] = obj; } void ScriptableController::registerControllableEntity(int id, ControllableEntity *obj) { orxout(user_info) << "ControllableEntity registered (id: " << id << ")" << std::endl; this->worldEntities_[id] = obj; } WorldEntity *ScriptableController::getWorldEntityByID(int id) const { if(id == 0) return this->player_->getControllableEntity(); auto obj = this->worldEntities_.find(id); return obj != this->worldEntities_.end() ? obj->second : nullptr; } ControllableEntity *ScriptableController::getControllableEntityByID(int id) const { if(id == 0) return this->player_->getControllableEntity(); auto obj = this->controllabelEntities_.find(id); return obj != this->controllabelEntities_.end() ? obj->second : nullptr; } void ScriptableController::addNearObjectHandler(int obj1, int obj2, double distance, std::function callback) { orxout(user_info) << "NearObject registering (id 1: " << obj1 << ", id 2: " << obj2 << ")" << std::endl; WorldEntity *entity1 = this->getWorldEntityByID(obj1); WorldEntity *entity2 = this->getWorldEntityByID(obj2); NearObjectHandler *handler1 = new NearObjectHandler(entity2, distance, callback); NearObjectHandler *handler2 = new NearObjectHandler(entity1, distance, callback); this->nearObjectHandlers_[entity1].push_front(std::unique_ptr(handler1)); this->nearObjectHandlers_[entity2].push_front(std::unique_ptr(handler2)); handler1->otherHandler_ = this->nearObjectHandlers_[entity2].begin(); handler2->otherHandler_ = this->nearObjectHandlers_[entity1].begin(); } void ScriptableController::objectMoved(WorldEntity *obj) { // Temp return; auto &nearObjectHandlers = this->nearObjectHandlers_[obj]; auto handler = nearObjectHandlers.begin(); while(handler != nearObjectHandlers.end()) { WorldEntity *other = (*handler)->otherObject_; if((obj->getPosition() - other->getPosition()).length() < (*handler)->distance_) { (*handler)->callback_(obj->getID(), other->getID()); auto otherHandler = (*handler)->otherHandler_; handler = nearObjectHandlers.erase(handler); if(nearObjectHandlers.empty()) this->nearObjectHandlers_.erase(obj); this->nearObjectHandlers_[other].erase(otherHandler); if(this->nearObjectHandlers_[other].empty()) this->nearObjectHandlers_.erase(other); } else { handler++; } } } void ScriptableController::printLuaError(lua_State *lua) { // The error message is on top of the stack. // Fetch it, print it and then pop it off the stack. // Yes, this is 'const char*' and not 'std::string' because that's what lua gives us. const char* message = lua_tostring(lua, -1); std::cout << message << std::endl; lua_pop(lua, 1); } }