Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Ignore:
Timestamp:
Dec 14, 2017, 4:04:14 PM (6 years ago)
Author:
kohlia
Message:

The ScriptableController should work now. A demo level called scriptableControllerTest exists as well.

Location:
code/branches/ScriptableController_HS17/src/orxonox
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • code/branches/ScriptableController_HS17/src/orxonox/infos/GametypeInfo.cc

    r11662 r11673  
    7878        this->spawned_ = false;
    7979        this->readyToSpawn_ = false;
     80        this->isFirstSpawn_ = true;
    8081
    8182        this->registerVariables();
     
    315316        }
    316317
    317         if(player->isHumanPlayer() && player->isLocalPlayer())
    318         {
     318        // TODO We might want to handle the subsequent spawns as well somehow
     319        if(player->isHumanPlayer() && player->isLocalPlayer() && this->isFirstSpawn_)
     320        {
     321            this->isFirstSpawn_ = false;
    319322            this->getLevel()->getScriptableController()->setPlayer(player);
    320323
     324            // This handles paths relative to the 'level' directory
    321325            std::string script = this->getLevel()->getScript();
    322326            if(script.at(0) != '/')
  • code/branches/ScriptableController_HS17/src/orxonox/infos/GametypeInfo.h

    r11358 r11673  
    8383            inline bool isStartCountdownRunning() const
    8484                { return this->bStartCountdownRunning_; }
    85            
     85
    8686            void changedStartCountdownRunning(void); // Is called when the start countdown has been either started or stopped.
    8787
     
    168168            bool spawned_; //!< Whether the local Player is currently spawned.
    169169            bool readyToSpawn_; //!< Whether the local Player is ready to spawn.
     170            bool isFirstSpawn_;
    170171    };
    171172}
  • code/branches/ScriptableController_HS17/src/orxonox/scriptablecontroller/is_callable.h

    r11519 r11673  
    44#include <type_traits>
    55
    6 // See https://stackoverflow.com/a/15396757/7421666
     6/**
     7 * @brief Implementation of IsCallable
     8 */
    79template<typename T>
    810struct IsCallableImpl
     
    2729};
    2830
    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 */
    3139template<typename T>
    3240struct IsCallable
  • code/branches/ScriptableController_HS17/src/orxonox/scriptablecontroller/luatb.h

    r11549 r11673  
    66struct lua_State;
    77
    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 */
    1012template<typename ThisType, typename FunctionType>
    1113class LuaTB
    1214{
    1315public:
    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     */
    1831    template<FunctionType func>
    1932    static void registerFunction(ThisType *_this, lua_State *lua, std::string name);
     
    2134
    2235// 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.
    2437#include "luatb.ipp"
    2538
  • code/branches/ScriptableController_HS17/src/orxonox/scriptablecontroller/luatb_typed_stack.h

    r11552 r11673  
    88#include "core/CoreIncludes.h"
    99
    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 */
    1318class LuaTBTypedStack
    1419{
    1520public:
    1621
    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     */
    1929    template<typename T>
    2030    static typename std::enable_if<!IsCallable<T>::value, T>::type getArgument(lua_State *lua)
     
    2535    }
    2636
    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     */
    3147    template<typename T>
    3248    static typename std::enable_if<IsCallable<T>::value, T>::type getArgument(lua_State *lua)
     
    3955        LuaTBTypedStack::callbackRefs.push_back(std::unique_ptr<int>(ref));
    4056
     57        // 'decltype(&T::operator())' represents the function signature of the callable object.
    4158        return GetLuaCallback<decltype(&T::operator())>::value(lua, ref);
    4259    }
     
    4764    // Gets a value from the top of the lua stack and returns it with the proper type.
    4865    // 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     */
    4973    template<typename T> static T getFromLuaStack(lua_State *lua);
    5074
     
    5276    // be a normal function signature because it is the signature of
    5377    // 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     */
    5484    template<typename Ret, typename... Args>
    5585    struct GetLuaCallback<void (std::function<Ret(Args...)>::*)(Args...) const>
    5686    {
    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         */
    6193        static std::function<void (Args...)> value(lua_State *lua, int *ref)
    6294        {
     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.
    6398            return [lua, ref](Args... args){callLuaFunction<Ret, Args...>(lua, ref, args...);};
    6499        }
    65100    };
    66101
    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     */
    68108    template<typename Ret, typename... Args>
    69109    static void callLuaFunction(lua_State *lua, int *ref, Args... args)
     
    85125    }
    86126
    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     */
    90135    template<typename T>
    91136    static void pushArgumentsToLuaStack(lua_State *, T)
    92137    { }
    93138
    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     */
    95145    template<typename First, typename... Args>
    96146    static void pushArgumentsToLuaStack(lua_State *lua, First first, Args... args)
     
    100150    }
    101151
    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     */
    103159    template<typename T>
    104160    static void pushToLuaStack(lua_State *lua, T value);
  • code/branches/ScriptableController_HS17/src/orxonox/scriptablecontroller/scriptable_controller.cc

    r11662 r11673  
    5050    }
    5151
    52     // Remeber the api
     52    // Remember the api
    5353    this->apis_.push_back(std::unique_ptr<ScriptableControllerAPI>(api));
    5454
     
    7373void ScriptableController::registerPawn(std::string id, Pawn *pawn)
    7474{
    75     this->worldEntities_[id] = pawn;
    7675    this->pawns_[id] = pawn;
    7776    this->pawnsReverse_[pawn] = id;
     
    8786    }
    8887
    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;
    9290    this->pawns_.erase(pawn_id_iter->second);
    9391    this->pawnsReverse_.erase(pawn_id_iter);
     92
     93    for(auto &api : this->apis_)
     94        api->pawnKilled(id, pawn);
    9495}
    9596
     
    110111}
    111112
    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 
    124113WorldEntity *ScriptableController::getWorldEntityByID(std::string id) const
    125114{
     
    138127    auto entity = this->mobileEntities_.find(id);
    139128    return entity != this->mobileEntities_.end() ? entity->second : nullptr;
    140 
    141129}
    142130
  • code/branches/ScriptableController_HS17/src/orxonox/scriptablecontroller/scriptable_controller.h

    r11638 r11673  
    9898
    9999    /**
    100      * @brief Kill a Pawn
    101      * @param id The Pawn to kill
    102      */
    103     void killPawn(std::string id);
    104 
    105     /**
    106100     * @brief Convert an ID to a WorldEntity pointer
    107101     * @param id The ID of the WorldEntity
  • code/branches/ScriptableController_HS17/src/orxonox/scriptablecontroller/scriptable_controller_api.cc

    r11662 r11673  
    1818    this->controller_ = controller;
    1919
    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!
    2121    LuaTB<ScriptableControllerAPI, decltype(&ScriptableControllerAPI::orxPrint)>::registerFunction<&ScriptableControllerAPI::orxPrint>(this, lua, "orxPrint");
    2222
     
    101101void ScriptableControllerAPI::killPawn(std::string id)
    102102{
    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();
    107108}
    108109
     
    168169    const Vector3 &old = entity->getPosition();
    169170
     171    // If one of the values is NaN, don't change that value
    170172    x = std::isnan(x) ? old.x : x;
    171173    y = std::isnan(y) ? old.y : y;
     
    189191    entity->getOrientation().ToAngleAxis(old_angle, old_axis);
    190192
     193    // If one of the values is NaN, don't change that value
    191194    x = std::isnan(x) ? old_axis.x : x;
    192195    y = std::isnan(y) ? old_axis.y : y;
     
    194197    angle = std::isnan(x) ? old_angle.valueDegrees() : angle;
    195198
     199
    196200    entity->setOrientation(Vector3(x, y, z), Degree(angle));
    197201}
     
    208212    const Vector3 &old = entity->getVelocity();
    209213
     214    // If one of the values is NaN, don't change that value
    210215    x = std::isnan(x) ? old.x : x;
    211216    y = std::isnan(y) ? old.y : y;
     
    226231    const Vector3 &old = entity->getAngularVelocity();
    227232
     233    // If one of the values is NaN, don't change that value
    228234    x = std::isnan(x) ? old.x : x;
    229235    y = std::isnan(y) ? old.y : y;
     
    248254        else
    249255            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++;
    250274    }
    251275}
     
    319343        }
    320344    }
    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  
    146146     * @param type Name of the class of the object you want to spawn
    147147     * @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.
    148151     */
    149152    void spawn(std::string type, std::string id);
     
    196199
    197200private:
    198     /**
    199      * @brief Called by ScriptableController when a pawn is killed
    200      * @param id The dead pawn
    201      *
    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 hit
    208      * @param target_id The hit Pawn
    209      * @param source_id The shooting Pawn
    210      * @param new_health The new health of the hit Pawn
    211      * @param new_shield The new shield health of the hit Pawn
    212      */
    213     void pawnHit(std::string target_id, std::string source_id, double new_health, double new_shield);
    214 
    215201    /**
    216202     * @brief Groups everything together that is needed to handle a near-object event
     
    260246    };
    261247
    262 
    263248    lua_State *lua_;
    264249    ScriptableController *controller_;
     
    266251    std::list<NearPointHandler> nearPointHandlers_;
    267252    std::list<AreaHandler> areaHandlers_;
    268     std::list<std::string> pawnsToKill_;
    269253    std::map<std::string, std::list<std::function<void (std::string)> > > pawnDestroyedHandlers_;
    270254    std::map<std::string, std::list<std::function<void (std::string, std::string, double, double)> > > pawnHitHandlers_;
     
    273257
    274258    /**
     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    /**
    275276     * @brief Called every 0.5s
    276277     *
    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.
    280280     */
    281281    void periodic(void);
Note: See TracChangeset for help on using the changeset viewer.