Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Ignore:
Timestamp:
Sep 21, 2010, 11:15:44 PM (14 years ago)
Author:
dafrick
Message:

Synchronizing Notifications.
In the course of that, notifications are not longer sent by creating a Notification and the calling notification.send() bur by letting the NotificationManager handle all this: NotificationManager::getInstance().sendNotification(message)
This made QuestNotification obsolete, thus it was removde.

Also did some work on synchronizing the Script class. It should work properly most of the time, but the current solution is unreliable and unsatisfactory. So this will change as soon as I know how.

Location:
code/trunk/src/modules/objects
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • code/trunk/src/modules/objects/Script.cc

    r7463 r7474  
    3535#include "core/LuaState.h"
    3636#include "core/XMLPort.h"
     37#include "network/Host.h"
     38#include "network/NetworkFunction.h"
     39
     40#include "PlayerManager.h"
     41#include "infos/PlayerInfo.h"
     42#include "interfaces/PlayerTrigger.h"
     43#include "worldentities/pawns/Pawn.h"
    3744
    3845namespace orxonox
    3946{
    4047    CreateFactory(Script);
     48
     49    registerMemberNetworkFunction(Script, execute);
    4150
    4251    // Initializing constants.
     
    5160        The creator of this object.
    5261    */
    53     Script::Script(BaseObject* creator) : BaseObject(creator)
     62    Script::Script(BaseObject* creator) : BaseObject(creator), Synchronisable(creator)
    5463    {
    5564        RegisterObject(Script);
     
    6372        this->needsGraphics_ = false;
    6473
     74        this->counter_ = 0.0f;
     75
     76        this->registerVariables();
    6577    }
    6678
     
    92104        XMLPortParam(Script, "times", setTimes, getTimes, xmlelement, mode).defaultValues(Script::INF);
    93105        XMLPortParam(Script, "needsGraphics", setNeedsGraphics, getNeedsGraphics, xmlelement, mode).defaultValues(false);
     106        XMLPortParam(Script, "forAll", setForAll, isForAll, xmlelement, mode).defaultValues(false);
    94107
    95108        XMLPortEventSink(Script, BaseObject, "trigger", trigger, xmlelement, mode);
    96109
    97         if(this->isOnLoad()) // If the object is onLoad the code is executed at once.
    98             this->execute();
     110        if(this->isOnLoad()) // If the object is onLoad the code is executed at once for all clients.
     111            this->execute(0);
    99112    }
    100113
     
    116129    /**
    117130    @brief
     131        Register the variables that need to be synchronized.
     132    */
     133    void Script::registerVariables(void)
     134    {
     135        registerVariable(code_, VariableDirection::ToClient);
     136        registerVariable(needsGraphics_, VariableDirection::ToClient);
     137        registerVariable(modeStr_, VariableDirection::ToClient, new NetworkCallback<Script>(this, &Script::modeChanged));
     138    }
     139
     140    void Script::modeChanged(void)
     141    {
     142        this->setMode(this->modeStr_);
     143    }
     144
     145    void Script::tick(float dt)
     146    {
     147        SUPER(Script, tick, dt);
     148
     149        if(!this->clientCallbacks_.empty())
     150        {
     151            if(this->counter_ < 2.0f)
     152            {
     153                this->counter_ += dt;
     154            }
     155            else
     156            {
     157                for(std::vector<unsigned int>::iterator it = this->clientCallbacks_.begin(); it != this->clientCallbacks_.end(); it++)
     158                {
     159                    this->execute(*it, true);
     160                }
     161                this->clientCallbacks_.clear();
     162                this->counter_ = 0.0f;
     163            }
     164        }
     165    }
     166
     167    /**
     168    @brief
    118169        Is called when an event comes in trough the event port.
    119170    @param triggered
    120171        Whether the event is triggering or un-triggering.
    121     */
    122     void Script::trigger(bool triggered)
    123     {
    124         if(triggered) // If the event is triggering (instead of un-triggering) the code of this Script  is executed.
    125             this->execute();
    126     }
    127 
    128     /**
    129     @brief
    130         Executes the Scripts code, depending on the mode.
    131     */
    132     void Script::execute()
    133     {
    134         if(this->times_ != Script::INF && this->remainingExecutions_ == 0)
    135             return;
    136 
    137         // If the code needs graphics to be executed but the GameMode doesn't show graphics the code isn't executed.
    138         if(this->needsGraphics_ && !GameMode::showsGraphics())
    139             return;
    140 
    141         if(this->mode_ == ScriptMode::normal) // If the mode is 'normal'.
    142             CommandExecutor::execute(this->code_);
    143         else if(this->mode_ == ScriptMode::lua) // If it's 'lua'.
    144         {
    145             assert(this->luaState_);
    146             this->luaState_->doString(this->code_);
    147         }
    148 
    149         if(this->times_ != Script::INF)
    150             this->remainingExecutions_--;
     172    @param trigger
     173        The object that caused the event to be fired.
     174    @return
     175        Returns true if successful.
     176    */
     177    bool Script::trigger(bool triggered, BaseObject* trigger)
     178    {
     179        if(!triggered || !this->isActive()) // If the Script is inactive it cannot be executed.
     180            return false;
     181
     182        COUT(4) << "Script (&" << this << ") triggered." << std::endl;
     183
     184        PlayerTrigger* pTrigger = orxonox_cast<PlayerTrigger*>(trigger);
     185        Pawn* pawn = NULL;
     186
     187        // If the trigger is a PlayerTrigger.
     188        if(pTrigger != NULL)
     189        {
     190            if(!pTrigger->isForPlayer())  // The PlayerTrigger is not exclusively for Pawns which means we cannot extract one.
     191                return false;
     192            else
     193                pawn = pTrigger->getTriggeringPlayer();
     194        }
     195        else
     196            return false;
     197
     198        if(pawn == NULL)  //TODO: Will this ever happen? If not, change in NotificationDispatcher as well.
     199        {
     200            COUT(4) << "The Script was triggered by an entity other than a Pawn. (" << trigger->getIdentifier()->getName() << ")" << std::endl;
     201            return false;
     202        }
     203
     204        // Extract the PlayerInfo from the Pawn.
     205        PlayerInfo* player = pawn->getPlayer();
     206
     207        if(player == NULL)
     208        {
     209            COUT(3) << "The PlayerInfo* is NULL." << std::endl;
     210            return false;
     211        }
     212
     213        this->execute(player->getClientID());
     214        return true;
     215    }
     216
     217    /**
     218    @brief
     219        Executes the Scripts code for the input client, depending on the mode.
     220    @param clientId
     221        The Id of the client the Script should be executed for.
     222    @param fromCallback
     223        Whether this method is executed in response to the connectedCallback().
     224    */
     225    void Script::execute(unsigned int clientId, bool fromCallback)
     226    {
     227        if(GameMode::isServer())
     228        {
     229            // If the number of executions have been used up.
     230            if(this->times_ != Script::INF && this->remainingExecutions_ == 0)
     231                return;
     232
     233            // Decrement the number of remaining executions.
     234            if(this->times_ != Script::INF)
     235                this->remainingExecutions_--;
     236        }
     237
     238        if(GameMode::isStandalone() || Host::getPlayerID() == clientId)
     239        {
     240            // If the code needs graphics to be executed but the GameMode doesn't show graphics the code isn't executed.
     241            if(this->needsGraphics_ && !GameMode::showsGraphics())
     242                return;
     243
     244            if(this->mode_ == ScriptMode::normal) // If the mode is 'normal'.
     245                CommandExecutor::execute(this->code_);
     246            else if(this->mode_ == ScriptMode::lua) // If it's 'lua'.
     247            {
     248                if(this->luaState_ == NULL)
     249                    this->luaState_ = new LuaState();
     250                this->luaState_->doString(this->code_);
     251            }
     252        }
     253        if(!GameMode::isStandalone() && GameMode::isServer() && Host::getPlayerID() != clientId)
     254        {
     255            if(!fromCallback && this->isForAll())
     256            {
     257                const std::map<unsigned int, PlayerInfo*> clients = PlayerManager::getInstance().getClients();
     258                for(std::map<unsigned int, PlayerInfo*>::const_iterator it = clients.begin(); it != clients.end(); it++)
     259                {
     260                    callMemberNetworkFunction(Script, execute, this->getObjectID(), it->first, it->first, false);
     261                }
     262            }
     263            else
     264            {
     265                callMemberNetworkFunction(Script, execute, this->getObjectID(), clientId, clientId, false);
     266            }
     267        }
     268    }
     269
     270    void Script::clientConnected(unsigned int clientId)
     271    {
     272        if(!GameMode::isStandalone() && GameMode::isServer() && this->isOnLoad())
     273        {
     274            if(clientId != 0)
     275                //TODO: Do better. This is only a temporary fix.
     276                this->clientCallbacks_.push_back(clientId);
     277        }
    151278    }
    152279
     
    160287    {
    161288        if(mode == Script::NORMAL)
     289        {
    162290            this->setMode(ScriptMode::normal);
     291            this->modeStr_ = Script::NORMAL;
     292        }
    163293        else if(mode == Script::LUA)
    164294        {
    165295            this->setMode(ScriptMode::lua);
     296            this->modeStr_ = Script::LUA;
    166297            // Creates a new LuaState.
    167298            if(this->luaState_ == NULL)
     
    170301        else
    171302        {
    172             COUT(2) << "Invalid mode '" << mode << "' in Script object." << std::endl;
     303            COUT(2) << "Invalid mode '" << mode << "' in Script object. Setting to 'normal'." << std::endl;
    173304            this->setMode(ScriptMode::normal);
     305            this->modeStr_ = Script::NORMAL;
    174306        }
    175307    }
     
    210342        else
    211343        {
    212             COUT(2) << "Invalid times '" << times << "' in Script." << std::endl;
     344            COUT(2) << "Invalid times '" << times << "' in Script. Setting to infinity." << std::endl;
    213345            this->times_ = Script::INF;
     346            this->remainingExecutions_ = Script::INF;
    214347        }
    215348    }
  • code/trunk/src/modules/objects/Script.h

    r7463 r7474  
    3333
    3434#include <string>
     35#include <vector>
     36
    3537#include "core/BaseObject.h"
     38#include "tools/interfaces/Tickable.h"
     39#include "network/synchronisable/Synchronisable.h"
     40#include "network/ClientConnectionListener.h"
    3641
    3742namespace orxonox
     
    5459        'code': The code that should be executed.
    5560        'mode': The mode, specifying whether the set code should be executed the normal way ('normal') or in lua ('lua'). Default is 'normal'.
    56         'onLoad': Whether the code is executed upon loading (creation) of this object. Default is true.
     61        'onLoad': Whether the code is executed upon loading (creation) of this object. If this is set the code is executed ofr all players, regardless of the value of parameter 'forAll'. Default is true.
    5762        'needsGraphics': Whether the code needs graphics to be executed or not. Default is false.
     63        'forAll': Whether the code is executed for all players each time the Script is triggered or jut for the player triggering the Script. If forAll is false, which is default, the event that triggers the Script must come from a PlayerTrigger.
    5864
    5965        Here are two examples illustrating the usage:
     
    7783        Damian 'Mozork' Frick
    7884    */
    79     class _ObjectsExport Script : public BaseObject
     85    class _ObjectsExport Script : public BaseObject, public Synchronisable, public ClientConnectionListener, public Tickable
    8086    {
    8187        public:
     
    8692            virtual void XMLEventPort(Element& xmlelement, XMLPort::Mode mode); //!< Creates a port that can be used to channel events and react to them.
    8793
    88             void trigger(bool triggered); //!< Is called when an event comes in trough the event port.
    89             void execute(); //!< Executes the Scripts code, depending on the mode.
     94            virtual void tick(float dt);
     95
     96            bool trigger(bool triggered, BaseObject* trigger); //!< Is called when an event comes in trough the event port.
     97            void execute(unsigned int clientId, bool fromCallback = false); //!< Executes the Scripts code for the input client, depending on the mode.
    9098
    9199            /**
     
    139147                { return this->needsGraphics_; }
    140148
     149            /**
     150            @brief Set whether the code is executed for all players or just for the player triggering the Script.
     151            @param forAll If true the code is executed for all players.
     152            */
     153            void setForAll(bool forAll)
     154                { this->forAll_ = forAll; }
     155            /**
     156            @brief Get whether the Script executes its code for all players or just for the player triggering the Script.
     157            @return Returns true if the code is executed for all players, false if not.
     158            */
     159            bool isForAll(void)
     160                { return this->forAll_; }
     161
     162            virtual void clientConnected(unsigned int clientId);
     163            virtual void clientDisconnected(unsigned int clientid) {}
     164
    141165        private:
    142166            //! Static variables to avoid magic strings.
     
    150174            int times_; //!< The number of times the Scripts code is executed at the most. -1 denotes infinity.
    151175            bool needsGraphics_; //!< Whether the code to be executed needs graphics.
     176            bool forAll_; //!< Whether the code is executed for all players (in a multiplayer setup) or just for the one triggering the Script.
     177
     178            std::string modeStr_;
     179
     180            std::vector<unsigned int> clientCallbacks_;
     181            float counter_;
    152182
    153183            LuaState* luaState_; //!< The LuaState to execute the code in lua.
    154184            int remainingExecutions_; //!< The number of remainign executions. -1 denotes infinity.
     185
     186            void registerVariables(void);
     187            void modeChanged();
    155188
    156189            /**
Note: See TracChangeset for help on using the changeset viewer.