Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/presentation/src/modules/objects/Script.cc @ 8974

Last change on this file since 8974 was 8667, checked in by dafrick, 13 years ago

Possible fix for segfaults due to player being NULL.

  • Property svn:eol-style set to native
File size: 10.8 KB
RevLine 
[7482]1
[1383]2/*
3 *   ORXONOX - the hottest 3D action shooter ever to exist
4 *                    > www.orxonox.net <
5 *
6 *
7 *   License notice:
8 *
9 *   This program is free software; you can redistribute it and/or
10 *   modify it under the terms of the GNU General Public License
11 *   as published by the Free Software Foundation; either version 2
12 *   of the License, or (at your option) any later version.
13 *
14 *   This program is distributed in the hope that it will be useful,
15 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *   GNU General Public License for more details.
18 *
19 *   You should have received a copy of the GNU General Public License
20 *   along with this program; if not, write to the Free Software
21 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
22 *
23 *   Author:
24 *      Benjamin Knecht
25 *   Co-authors:
[7404]26 *      Damian 'Mozork' Frick
[1383]27 *
28 */
29
30#include "Script.h"
[1906]31
[7404]32#include "core/command/CommandExecutor.h"
[1383]33#include "core/CoreIncludes.h"
[7404]34#include "core/EventIncludes.h"
[7463]35#include "core/GameMode.h"
[5695]36#include "core/LuaState.h"
37#include "core/XMLPort.h"
[7474]38#include "network/Host.h"
39#include "network/NetworkFunction.h"
[1383]40
[7474]41#include "PlayerManager.h"
42#include "infos/PlayerInfo.h"
43#include "interfaces/PlayerTrigger.h"
44#include "worldentities/pawns/Pawn.h"
45
[1383]46namespace orxonox
47{
[5695]48    CreateFactory(Script);
[1383]49
[7482]50    registerStaticNetworkFunction(Script::executeHelper);
[7474]51
[7404]52    // Initializing constants.
53    /*static*/ const std::string Script::NORMAL = "normal";
54    /*static*/ const std::string Script::LUA = "lua";
[7406]55    /*static*/ const int Script::INF = -1;
[7404]56
57    /**
58    @brief
59        Constructor. Registers and initializes the object.
60    @param creator
61        The creator of this object.
62    */
[7486]63    Script::Script(BaseObject* creator) : BaseObject(creator)
[5695]64    {
65        RegisterObject(Script);
[1383]66
[7404]67        // Initialize variables.
68        this->remainingExecutions_ = Script::INF;
[7463]69        this->mode_ = ScriptMode::normal;
70        this->onLoad_ = true;
71        this->times_ = Script::INF;
72        this->needsGraphics_ = false;
[5695]73    }
[1383]74
[7404]75    /**
76    @brief
77        Destructor. Cleans up.
78    */
[5695]79    Script::~Script()
80    {
[7486]81
[5695]82    }
[1383]83
[7404]84    /**
85    @brief
86        Method for creating a Script object through XML.
[7407]87    @param xmlelement
[7404]88        The element.
89    @param mode
90        The mode.
91    */
[7407]92    void Script::XMLPort(Element& xmlelement, XMLPort::Mode mode)
[5695]93    {
[7408]94        SUPER(Script, XMLPort, xmlelement, mode);
[1383]95
[7407]96        XMLPortParam(Script, "code", setCode, getCode, xmlelement, mode);
97        XMLPortParamTemplate(Script, "mode", setMode, getMode, xmlelement, mode, const std::string&).defaultValues(Script::NORMAL);
98        XMLPortParam(Script, "onLoad", setOnLoad, isOnLoad, xmlelement, mode).defaultValues(true);
99        XMLPortParam(Script, "times", setTimes, getTimes, xmlelement, mode).defaultValues(Script::INF);
[7463]100        XMLPortParam(Script, "needsGraphics", setNeedsGraphics, getNeedsGraphics, xmlelement, mode).defaultValues(false);
[7474]101        XMLPortParam(Script, "forAll", setForAll, isForAll, xmlelement, mode).defaultValues(false);
[7404]102
[7407]103        XMLPortEventSink(Script, BaseObject, "trigger", trigger, xmlelement, mode);
[7404]104
[7482]105        if(this->isOnLoad()) // If the object is onLoad the code is executed at once for the server.
[7486]106            this->execute(0, true);
[5695]107    }
[1383]108
[7404]109    /**
110    @brief
111        Creates a port that can be used to channel events and react to them.
[7407]112    @param xmlelement
[7404]113        The element.
114    @param mode
115        The mode.
116    */
[7407]117    void Script::XMLEventPort(Element& xmlelement, XMLPort::Mode mode)
[7404]118    {
[7408]119        SUPER(Script, XMLEventPort, xmlelement, mode);
[7404]120
[7407]121        XMLPortEventState(Script, BaseObject, "trigger", trigger, xmlelement, mode);
[7404]122    }
123
124    /**
125    @brief
126        Is called when an event comes in trough the event port.
127    @param triggered
128        Whether the event is triggering or un-triggering.
[7474]129    @param trigger
130        The object that caused the event to be fired.
131    @return
132        Returns true if successful.
[7404]133    */
[7474]134    bool Script::trigger(bool triggered, BaseObject* trigger)
[7404]135    {
[7474]136        if(!triggered || !this->isActive()) // If the Script is inactive it cannot be executed.
137            return false;
138
139        COUT(4) << "Script (&" << this << ") triggered." << std::endl;
140
141        PlayerTrigger* pTrigger = orxonox_cast<PlayerTrigger*>(trigger);
[8667]142        PlayerInfo* player = NULL;
[7474]143
144        // If the trigger is a PlayerTrigger.
145        if(pTrigger != NULL)
146        {
147            if(!pTrigger->isForPlayer())  // The PlayerTrigger is not exclusively for Pawns which means we cannot extract one.
148                return false;
149            else
[8667]150                player = pTrigger->getTriggeringPlayer();
[7474]151        }
152        else
153            return false;
154
[8667]155        if(player == NULL)  //TODO: Will this ever happen? If not, change in NotificationDispatcher as well.
[7474]156        {
157            COUT(4) << "The Script was triggered by an entity other than a Pawn. (" << trigger->getIdentifier()->getName() << ")" << std::endl;
158            return false;
159        }
160
161        this->execute(player->getClientID());
162        return true;
[7404]163    }
164
165    /**
166    @brief
[7474]167        Executes the Scripts code for the input client, depending on the mode.
168    @param clientId
169        The Id of the client the Script should be executed for.
[7486]170    @param onLoad
171        Whether this method is executed as a result of the onLoad parameter being set to true. Default is false.
[7404]172    */
[7486]173    void Script::execute(unsigned int clientId, bool onLoad)
[5695]174    {
[7482]175        // If this is the server or we're in standalone mode we check whether we still want to execute the code and if so decrease the number of remaining executions.
[7486]176        if(GameMode::isMaster())
[7474]177        {
178            // If the number of executions have been used up.
[7493]179            if(this->times_ != Script::INF && this->remainingExecutions_ <= 0)
[7474]180                return;
181        }
[7463]182
[7482]183        // If this is either the standalone mode or we're on the client we want to be.
[7474]184        if(GameMode::isStandalone() || Host::getPlayerID() == clientId)
[7404]185        {
[7486]186            this->executeHelper(this->getCode(), this->getMode(), this->getNeedsGraphics());
187            if(GameMode::isMaster() && !onLoad && this->times_ != Script::INF) // Decrement the number of remaining executions.
188                this->remainingExecutions_--;
[7482]189        }
[7474]190
[7482]191        // If this is the server and we're not on the client we want to be.
[7486]192        if(GameMode::isServer() && Host::getPlayerID() != clientId)
[7474]193        {
[7486]194            // If we want to execute the code for all clients and the server.
195            if(this->isForAll())
[7474]196            {
197                const std::map<unsigned int, PlayerInfo*> clients = PlayerManager::getInstance().getClients();
198                for(std::map<unsigned int, PlayerInfo*>::const_iterator it = clients.begin(); it != clients.end(); it++)
199                {
[7482]200                    callStaticNetworkFunction(Script::executeHelper, it->first, this->getCode(), this->getMode(), this->getNeedsGraphics());
[7483]201                    if(this->times_ != Script::INF) // Decrement the number of remaining executions.
[7493]202                    {
[7483]203                        this->remainingExecutions_--;
[7493]204                        if(this->remainingExecutions_ <= 0)
205                            break;
206                    }
[7474]207                }
208            }
[7482]209            // Else we execute the code just for the specified client.
[7474]210            else
211            {
[7482]212                callStaticNetworkFunction(Script::executeHelper, clientId, this->getCode(), this->getMode(), this->getNeedsGraphics());
[7483]213                if(this->times_ != Script::INF) // Decrement the number of remaining executions.
214                    this->remainingExecutions_--;
[7474]215            }
216        }
217    }
[7404]218
[7482]219    /**
220    @brief
221        Helper method that is used to reach this Script object on other clients.
222    */
223    /*static*/ void Script::executeHelper(const std::string& code, const std::string& mode, bool needsGraphics)
224    {
225        // If the code needs graphics to be executed but the GameMode doesn't show graphics the code isn't executed.
226        if(needsGraphics && !GameMode::showsGraphics())
227            return;
228
229        if(mode == Script::NORMAL) // If the mode is 'normal'.
230            CommandExecutor::execute(code);
231        else if(mode == Script::LUA) // If it's 'lua'.
232        {
[7483]233            LuaState* luaState = new LuaState();
234            luaState->doString(code);
235            delete luaState;
[7482]236        }
237    }
238
239    /**
240    @brief
241        Callback that is called when a new client has connected.
242    @param clientId
243        The clientId of the new client that has connected.
244    */
[7474]245    void Script::clientConnected(unsigned int clientId)
246    {
[7482]247        // If this is the server and the Script is specified as being 'onLoad'.
[7486]248        if(GameMode::isServer() && this->isOnLoad())
[7474]249        {
[7486]250            callStaticNetworkFunction(Script::executeHelper, clientId, this->getCode(), this->getMode(), this->getNeedsGraphics());
[7474]251        }
[5695]252    }
[7404]253
254    /**
255    @brief
256        Sets the mode of the Script.
257    @param mode
258        The mode as a string.
259    */
260    void Script::setMode(const std::string& mode)
261    {
262        if(mode == Script::NORMAL)
[7474]263        {
[7404]264            this->setMode(ScriptMode::normal);
[7474]265            this->modeStr_ = Script::NORMAL;
266        }
[7404]267        else if(mode == Script::LUA)
268        {
269            this->setMode(ScriptMode::lua);
[7474]270            this->modeStr_ = Script::LUA;
[7404]271        }
272        else
273        {
[7474]274            COUT(2) << "Invalid mode '" << mode << "' in Script object. Setting to 'normal'." << std::endl;
[7404]275            this->setMode(ScriptMode::normal);
[7474]276            this->modeStr_ = Script::NORMAL;
[7404]277        }
278    }
279
280    /**
281    @brief
[7482]282        Sets the mode to the mode specified in this->modeStr_.
283        This is used internally for networking purposes.
284    */
285    void Script::modeChanged(void)
286    {
287        this->setMode(this->modeStr_);
288    }
289
290    /**
291    @brief
[7404]292        Get the mode of the Script.
293    @return
294        Returns the mode as a string.
295    */
296    const std::string& Script::getMode(void)
297    {
298        switch(this->mode_)
299        {
300            case ScriptMode::normal:
301                return Script::NORMAL;
302            case ScriptMode::lua:
303                return Script::LUA;
[7410]304            default: // This will never happen...
305                return Script::NORMAL;
[7404]306        }
307    }
308
309    /**
310    @brief
311        Set the number of times this Script is executed at the most.
312        -1 denotes infinity.
313    @param times
314        The number of times to be set.
315    */
316    void Script::setTimes(int times)
317    {
318        if(times >= -1)
319        {
320            this->times_ = times;
321            this->remainingExecutions_ = times;
322        }
323        else
324        {
[7474]325            COUT(2) << "Invalid times '" << times << "' in Script. Setting to infinity." << std::endl;
[7404]326            this->times_ = Script::INF;
[7474]327            this->remainingExecutions_ = Script::INF;
[7404]328        }
329    }
330
[1383]331}
Note: See TracBrowser for help on using the repository browser.