- Timestamp:
- Dec 14, 2017, 4:04:14 PM (7 years ago)
- Location:
- code/branches/ScriptableController_HS17/src/orxonox/scriptablecontroller
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
code/branches/ScriptableController_HS17/src/orxonox/scriptablecontroller/is_callable.h
r11519 r11673 4 4 #include <type_traits> 5 5 6 // See https://stackoverflow.com/a/15396757/7421666 6 /** 7 * @brief Implementation of IsCallable 8 */ 7 9 template<typename T> 8 10 struct IsCallableImpl … … 27 29 }; 28 30 29 // Checks if a type is callable (has an 'operator()'). This will not work for 30 // normal functions without modifications, but we don't need that case anyway. 31 /** 32 * @brief Checks if a type is callable 33 * 34 * Callable means here, that it has has an 'operator()'. This will not work for 35 * normal functions without modifications, but we don't need that case anyway. 36 * 37 * See https://stackoverflow.com/a/15396757/7421666 38 */ 31 39 template<typename T> 32 40 struct IsCallable -
code/branches/ScriptableController_HS17/src/orxonox/scriptablecontroller/luatb.h
r11549 r11673 6 6 struct lua_State; 7 7 8 // Makes certain functions visible to lua while staying type-safe on the 9 // C++ side. 8 /** 9 * @brief Makes certain functions visible to lua while staying type-safe 10 * on the C++ side. 11 */ 10 12 template<typename ThisType, typename FunctionType> 11 13 class LuaTB 12 14 { 13 15 public: 14 // Make a function visible to lua. If you want to make a function 'foo' 15 // visible, you should call it like this: 16 // 17 // LuaTB<decltype(foo)>::registerFunction<foo>( ... ); 16 /** 17 * @brief Make a function visible to lua 18 * @param _this Pointer to the object that owns the function 19 * @param lua Pointer to the lua state 20 * @param name Name that will be visible to lua for this function 21 * 22 * Only class functions are supported, because that's all we need at 23 * the moment. Extending it to support normal functions as well should 24 * be fairly easy, though. 25 * 26 * If you want to make a function 'Foo::bar' visible, you should call 27 * it like this (assuming no C++17 support): 28 * 29 * LuaTB<Foo, decltype(&Foo::bar)>::registerFunction<&Foo::bar>( ... ); 30 */ 18 31 template<FunctionType func> 19 32 static void registerFunction(ThisType *_this, lua_State *lua, std::string name); … … 21 34 22 35 // We need to include all type-dependant template implementations, because the 23 // compiler needs to know for which types it has to instantiate those 36 // compiler needs to know for which types it has to instantiate those. 24 37 #include "luatb.ipp" 25 38 -
code/branches/ScriptableController_HS17/src/orxonox/scriptablecontroller/luatb_typed_stack.h
r11552 r11673 8 8 #include "core/CoreIncludes.h" 9 9 10 // We need a separate class for this because we need to specialize the functions 11 // and that's not possible if we didn't specialize the class. And the logical 12 // separation makes sense as well. 10 11 /** 12 * @brief Represents a typed version of the lua stack 13 * 14 * We need a separate class for this because we need to specialize the functions 15 * and that's not possible if we didn't specialize the class. And the logical 16 * separation makes sense as well. 17 */ 13 18 class LuaTBTypedStack 14 19 { 15 20 public: 16 21 17 // Get a non-function argument from the lua stack and convert it to type 'T' 18 // Pops the value from the stack. 22 /** 23 * @brief Get a non-function argument from the lua stack and convert it to type 'T' 24 * @param lua Pointer to the lua state 25 * @return Top element of the lua stack with the appropriate type 26 * 27 * Note: Pops the value from the stack. 28 */ 19 29 template<typename T> 20 30 static typename std::enable_if<!IsCallable<T>::value, T>::type getArgument(lua_State *lua) … … 25 35 } 26 36 27 // Specialization if 'T' is a callable type (std::function). Saves the lua 28 // function in the registry and constructs a function to call it again. 29 // 'decltype(&T::operator())' represents the function signature of the callable 30 // object. 37 /** 38 * @brief Get a function-type argument from the lua stack and convert it to type 'T' 39 * @param lua Pointer to the lua state 40 * @return Top element of the lua stack with the appropriate type 41 * 42 * Specialization if 'T' is a callable type (std::function). Saves the lua 43 * function in the registry and constructs a function to call it again. 44 * 45 * Note: Pops the value from the stack. 46 */ 31 47 template<typename T> 32 48 static typename std::enable_if<IsCallable<T>::value, T>::type getArgument(lua_State *lua) … … 39 55 LuaTBTypedStack::callbackRefs.push_back(std::unique_ptr<int>(ref)); 40 56 57 // 'decltype(&T::operator())' represents the function signature of the callable object. 41 58 return GetLuaCallback<decltype(&T::operator())>::value(lua, ref); 42 59 } … … 47 64 // Gets a value from the top of the lua stack and returns it with the proper type. 48 65 // Does not pop the value! 66 /** 67 * @brief Get a value from the lua stack and convert it to type 'T' 68 * @param lua Pointer to the lua state 69 * @return Top element of the lua stack with the appropriate type 70 * 71 * Note: Does NOT pop the value from the stack. 72 */ 49 73 template<typename T> static T getFromLuaStack(lua_State *lua); 50 74 … … 52 76 // be a normal function signature because it is the signature of 53 77 // std::function<>::operator(), which is also the reason for the 'const'. 78 /** 79 * @brief Needed to get a lambda to call a lua function 80 * 81 * We need this class, becasue we need to specify the signature of the function 82 * before. 83 */ 54 84 template<typename Ret, typename... Args> 55 85 struct GetLuaCallback<void (std::function<Ret(Args...)>::*)(Args...) const> 56 86 { 57 // Returns a lambda that will push the arguments to the lua stack and call 58 // the function afterwards. We can't return 'callLuaFunction' directly, 59 // because we need the additional arguments 'lua' and 'ref' which we would 60 // like to hide from the user. 87 /** 88 * @brief Get a lambda to call a lua function later 89 * @param lua Pointer to the lua state 90 * @param ref Pointer to the lua registry reference where the function is stored 91 * @return Lambda that will call the function specified with ref 92 */ 61 93 static std::function<void (Args...)> value(lua_State *lua, int *ref) 62 94 { 95 // We can't return 'callLuaFunction' directly, because we need the 96 // additional arguments 'lua' and 'ref' which we would like to hide 97 // from the user. 63 98 return [lua, ref](Args... args){callLuaFunction<Ret, Args...>(lua, ref, args...);}; 64 99 } 65 100 }; 66 101 67 // Pushes all arguments to the lua stack and calls a lua function afterwards 102 /** 103 * @brief Pushes all arguments to the lua stack and calls a lua function afterwards 104 * @param lua Pointer to the lua state 105 * @param ref Pointer to the lua registry reference where the function is stored 106 * @param args Arguments for the function 107 */ 68 108 template<typename Ret, typename... Args> 69 109 static void callLuaFunction(lua_State *lua, int *ref, Args... args) … … 85 125 } 86 126 87 // This is needed in case the function has no arguments at all. Otherwise, we 88 // would have a missing argument for such function. This is also why we pass 89 // a dummy argument in 'callLuaFunction', so we have at least one argument. 127 /** 128 * @brief Pushes nothing onto the stack 129 * 130 * This is needed in case the function has no arguments at all. Otherwise, we 131 * would have a missing argument for such a function. This is also why we pass 132 * a dummy argument in 'callLuaFunction', so we have at least one argument. It 133 * is the termination point for the recursive template. 134 */ 90 135 template<typename T> 91 136 static void pushArgumentsToLuaStack(lua_State *, T) 92 137 { } 93 138 94 // Recursively pushes arguments to the lua stack 139 /** 140 * @brief Recursively pushes arguments to the lua stack 141 * @param lua Pointer to the lua state 142 * @param first First argument to push onto the stack 143 * @param args The remaining arguments to push onto the stack 144 */ 95 145 template<typename First, typename... Args> 96 146 static void pushArgumentsToLuaStack(lua_State *lua, First first, Args... args) … … 100 150 } 101 151 102 // Pushes a value to the lua stack. Only the specializations are valid. 152 /** 153 * @brief Pushes a value to the lua stack 154 * @param lua Pointer to the lua state 155 * @param value The value to push 156 * 157 * Note: Only the specializations are valid 158 */ 103 159 template<typename T> 104 160 static void pushToLuaStack(lua_State *lua, T value); -
code/branches/ScriptableController_HS17/src/orxonox/scriptablecontroller/scriptable_controller.cc
r11662 r11673 50 50 } 51 51 52 // Reme ber the api52 // Remember the api 53 53 this->apis_.push_back(std::unique_ptr<ScriptableControllerAPI>(api)); 54 54 … … 73 73 void ScriptableController::registerPawn(std::string id, Pawn *pawn) 74 74 { 75 this->worldEntities_[id] = pawn;76 75 this->pawns_[id] = pawn; 77 76 this->pawnsReverse_[pawn] = id; … … 87 86 } 88 87 89 for(auto &api : this->apis_) 90 api->pawnKilled(pawn_id_iter->second, pawn); 91 88 // The ID of the pawn should already be invalid when we call the callback 89 std::string id = pawn_id_iter->second; 92 90 this->pawns_.erase(pawn_id_iter->second); 93 91 this->pawnsReverse_.erase(pawn_id_iter); 92 93 for(auto &api : this->apis_) 94 api->pawnKilled(id, pawn); 94 95 } 95 96 … … 110 111 } 111 112 112 void ScriptableController::killPawn(std::string id)113 {114 auto pawn = this->getPawnByID(id);115 if(pawn == nullptr)116 {117 orxout(user_warning) << "Tried to destroy unknown pawn " << id << std::endl;118 return;119 }120 121 pawn->kill();122 }123 124 113 WorldEntity *ScriptableController::getWorldEntityByID(std::string id) const 125 114 { … … 138 127 auto entity = this->mobileEntities_.find(id); 139 128 return entity != this->mobileEntities_.end() ? entity->second : nullptr; 140 141 129 } 142 130 -
code/branches/ScriptableController_HS17/src/orxonox/scriptablecontroller/scriptable_controller.h
r11638 r11673 98 98 99 99 /** 100 * @brief Kill a Pawn101 * @param id The Pawn to kill102 */103 void killPawn(std::string id);104 105 /**106 100 * @brief Convert an ID to a WorldEntity pointer 107 101 * @param id The ID of the WorldEntity -
code/branches/ScriptableController_HS17/src/orxonox/scriptablecontroller/scriptable_controller_api.cc
r11662 r11673 18 18 this->controller_ = controller; 19 19 20 // Haven't found a shorter way yet to write that... 20 // Haven't found a shorter way yet to write that... We need C++17! 21 21 LuaTB<ScriptableControllerAPI, decltype(&ScriptableControllerAPI::orxPrint)>::registerFunction<&ScriptableControllerAPI::orxPrint>(this, lua, "orxPrint"); 22 22 … … 101 101 void ScriptableControllerAPI::killPawn(std::string id) 102 102 { 103 // We don't kill the pawn here directly, because this function is called from LUA and thus 104 // runs in a different thread. So we schedule the kill for later in the main thread 105 // (in 'periodic'). 106 this->pawnsToKill_.push_back(id); 103 Pawn *pawn = this->controller_->getPawnByID(id); 104 if(pawn == nullptr) 105 orxout(user_warning) << "Trying to kill an unknown pawn" << std::endl; 106 else 107 pawn->kill(); 107 108 } 108 109 … … 168 169 const Vector3 &old = entity->getPosition(); 169 170 171 // If one of the values is NaN, don't change that value 170 172 x = std::isnan(x) ? old.x : x; 171 173 y = std::isnan(y) ? old.y : y; … … 189 191 entity->getOrientation().ToAngleAxis(old_angle, old_axis); 190 192 193 // If one of the values is NaN, don't change that value 191 194 x = std::isnan(x) ? old_axis.x : x; 192 195 y = std::isnan(y) ? old_axis.y : y; … … 194 197 angle = std::isnan(x) ? old_angle.valueDegrees() : angle; 195 198 199 196 200 entity->setOrientation(Vector3(x, y, z), Degree(angle)); 197 201 } … … 208 212 const Vector3 &old = entity->getVelocity(); 209 213 214 // If one of the values is NaN, don't change that value 210 215 x = std::isnan(x) ? old.x : x; 211 216 y = std::isnan(y) ? old.y : y; … … 226 231 const Vector3 &old = entity->getAngularVelocity(); 227 232 233 // If one of the values is NaN, don't change that value 228 234 x = std::isnan(x) ? old.x : x; 229 235 y = std::isnan(y) ? old.y : y; … … 248 254 else 249 255 near_obj_handler++; 256 } 257 258 auto near_point_handler = this->nearPointHandlers_.begin(); 259 while(near_point_handler != this->nearPointHandlers_.end()) 260 { 261 if(near_point_handler->entity_ == pawn) 262 near_point_handler = this->nearPointHandlers_.erase(near_point_handler); 263 else 264 near_point_handler++; 265 } 266 267 auto area_handler = this->areaHandlers_.begin(); 268 while(area_handler != this->areaHandlers_.end()) 269 { 270 if(area_handler->entity_ == pawn) 271 area_handler = this->areaHandlers_.erase(area_handler); 272 else 273 area_handler++; 250 274 } 251 275 } … … 319 343 } 320 344 } 321 322 // Pawns to kill 323 // TODO Possible race condidtion when the player destroys the pawn 324 // between the callback and the next periodic call. 325 for(auto &pawn : this->pawnsToKill_) 326 this->controller_->killPawn(pawn); 327 328 this->pawnsToKill_.clear(); 329 } 330 331 } 345 } 346 347 } -
code/branches/ScriptableController_HS17/src/orxonox/scriptablecontroller/scriptable_controller_api.h
r11662 r11673 146 146 * @param type Name of the class of the object you want to spawn 147 147 * @param id The newly created ID that can be used to access this object 148 * 149 * IMPORTANT: Do not use this function yet, it only has minimal functionality and is not 150 * really helpful as it is. 148 151 */ 149 152 void spawn(std::string type, std::string id); … … 196 199 197 200 private: 198 /**199 * @brief Called by ScriptableController when a pawn is killed200 * @param id The dead pawn201 *202 * Calls the lua callbacks associated with this event.203 */204 void pawnKilled(std::string id, Pawn *pawn);205 206 /**207 * @brief Called by ScriptableController when a Pawn is hit208 * @param target_id The hit Pawn209 * @param source_id The shooting Pawn210 * @param new_health The new health of the hit Pawn211 * @param new_shield The new shield health of the hit Pawn212 */213 void pawnHit(std::string target_id, std::string source_id, double new_health, double new_shield);214 215 201 /** 216 202 * @brief Groups everything together that is needed to handle a near-object event … … 260 246 }; 261 247 262 263 248 lua_State *lua_; 264 249 ScriptableController *controller_; … … 266 251 std::list<NearPointHandler> nearPointHandlers_; 267 252 std::list<AreaHandler> areaHandlers_; 268 std::list<std::string> pawnsToKill_;269 253 std::map<std::string, std::list<std::function<void (std::string)> > > pawnDestroyedHandlers_; 270 254 std::map<std::string, std::list<std::function<void (std::string, std::string, double, double)> > > pawnHitHandlers_; … … 273 257 274 258 /** 259 * @brief Called by ScriptableController when a pawn is killed 260 * @param id The dead pawn 261 * 262 * Calls the lua callbacks associated with this event. 263 */ 264 void pawnKilled(std::string id, Pawn *pawn); 265 266 /** 267 * @brief Called by ScriptableController when a Pawn is hit 268 * @param target_id The hit Pawn 269 * @param source_id The shooting Pawn 270 * @param new_health The new health of the hit Pawn 271 * @param new_shield The new shield health of the hit Pawn 272 */ 273 void pawnHit(std::string target_id, std::string source_id, double new_health, double new_shield); 274 275 /** 275 276 * @brief Called every 0.5s 276 277 * 277 * This handles things that have to be checked periodically (like area events) and 278 * things that are done by lua that have to synchronize with the main thread (like 279 * killing a pawn). Doing this in every tick would be an overkill. 278 * This handles things that have to be checked periodically (like area events) 279 * but doing this in every tick would be an overkill. 280 280 */ 281 281 void periodic(void);
Note: See TracChangeset
for help on using the changeset viewer.