Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core7/src/modules/objects/Script.cc @ 10513

Last change on this file since 10513 was 10478, checked in by landauf, 10 years ago

callStaticNetworkFunction() and callMemberNetworkFunction() are now template functions instead of macros.
simplified function call interface: always pass five MultiType-references. Check if MultiType.null() evaluates to true to see if the argument was defined.
moved references to NetworkFunctionManager to NetworkFunctionIncludes.cc.
this also fixed a linker error in MSVC by including NetworkFunctionIncludes.h in a build-unit inside the network library.

  • Property svn:eol-style set to native
File size: 10.9 KB
Line 
1
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:
26 *      Damian 'Mozork' Frick
27 *
28 */
29
30#include "Script.h"
31
32#include "core/command/CommandExecutor.h"
33#include "core/CoreIncludes.h"
34#include "core/EventIncludes.h"
35#include "core/GameMode.h"
36#include "core/LuaState.h"
37#include "core/XMLPort.h"
38#include "network/Host.h"
39#include "network/NetworkFunctionIncludes.h"
40
41#include "PlayerManager.h"
42#include "infos/PlayerInfo.h"
43#include "interfaces/PlayerTrigger.h"
44#include "worldentities/pawns/Pawn.h"
45
46namespace orxonox
47{
48    RegisterClass(Script);
49
50    registerStaticNetworkFunction(Script::executeHelper);
51
52    // Initializing constants.
53    /*static*/ const std::string Script::NORMAL = "normal";
54    /*static*/ const std::string Script::LUA = "lua";
55    /*static*/ const int Script::INF = -1;
56
57    /**
58    @brief
59        Constructor. Registers and initializes the object.
60    @param creator
61        The creator of this object.
62    */
63    Script::Script(Context* context) : BaseObject(context)
64    {
65        RegisterObject(Script);
66
67        // Initialize variables.
68        this->remainingExecutions_ = Script::INF;
69        this->mode_ = ScriptMode::normal;
70        this->onLoad_ = true;
71        this->times_ = Script::INF;
72        this->needsGraphics_ = false;
73    }
74
75    /**
76    @brief
77        Destructor. Cleans up.
78    */
79    Script::~Script()
80    {
81
82    }
83
84    /**
85    @brief
86        Method for creating a Script object through XML.
87    @param xmlelement
88        The element.
89    @param mode
90        The mode.
91    */
92    void Script::XMLPort(Element& xmlelement, XMLPort::Mode mode)
93    {
94        SUPER(Script, XMLPort, xmlelement, mode);
95
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);
100        XMLPortParam(Script, "needsGraphics", setNeedsGraphics, getNeedsGraphics, xmlelement, mode).defaultValues(false);
101        XMLPortParam(Script, "forAll", setForAll, isForAll, xmlelement, mode).defaultValues(false);
102
103        XMLPortEventSink(Script, BaseObject, "trigger", trigger, xmlelement, mode);
104
105        if(this->isOnLoad()) // If the object is onLoad the code is executed at once for the server.
106            this->execute(0, true);
107    }
108
109    /**
110    @brief
111        Creates a port that can be used to channel events and react to them.
112    @param xmlelement
113        The element.
114    @param mode
115        The mode.
116    */
117    void Script::XMLEventPort(Element& xmlelement, XMLPort::Mode mode)
118    {
119        SUPER(Script, XMLEventPort, xmlelement, mode);
120
121        XMLPortEventState(Script, BaseObject, "trigger", trigger, xmlelement, mode);
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.
129    @param trigger
130        The object that caused the event to be fired.
131    @return
132        Returns true if successful.
133    */
134    bool Script::trigger(bool triggered, BaseObject* trigger)
135    {
136        if(!triggered || !this->isActive()) // If the Script is inactive it cannot be executed.
137            return false;
138
139        orxout(verbose, context::misc::script) << "Script (&" << this << ") triggered." << endl;
140
141        PlayerTrigger* pTrigger = orxonox_cast<PlayerTrigger*>(trigger);
142        PlayerInfo* player = NULL;
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
150                player = pTrigger->getTriggeringPlayer();
151        }
152        else
153            return false;
154
155        if(player == NULL)  //TODO: Will this ever happen? If not, change in NotificationDispatcher as well.
156        {
157            orxout(internal_warning) << "The Script was triggered by an entity other than a Pawn. (" << trigger->getIdentifier()->getName() << ")" << endl;
158            return false;
159        }
160
161        this->execute(player->getClientID());
162        return true;
163    }
164
165    /**
166    @brief
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.
170    @param onLoad
171        Whether this method is executed as a result of the onLoad parameter being set to true. Default is false.
172    */
173    void Script::execute(unsigned int clientId, bool onLoad)
174    {
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.
176        if(GameMode::isMaster())
177        {
178            // If the number of executions have been used up.
179            if(this->times_ != Script::INF && this->remainingExecutions_ <= 0)
180                return;
181        }
182
183        // If this is either the standalone mode or we're on the client we want to be.
184        if(GameMode::isStandalone() || Host::getPlayerID() == clientId)
185        {
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_--;
189        }
190
191        // If this is the server and we're not on the client we want to be.
192        if(GameMode::isServer() && Host::getPlayerID() != clientId)
193        {
194            // If we want to execute the code for all clients and the server.
195            if(this->isForAll())
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                {
200                    callStaticNetworkFunction(&Script::executeHelper, it->first, this->getCode(), this->getMode(), this->getNeedsGraphics());
201                    if(this->times_ != Script::INF) // Decrement the number of remaining executions.
202                    {
203                        this->remainingExecutions_--;
204                        if(this->remainingExecutions_ <= 0)
205                            break;
206                    }
207                }
208            }
209            // Else we execute the code just for the specified client.
210            else
211            {
212                callStaticNetworkFunction(&Script::executeHelper, clientId, this->getCode(), this->getMode(), this->getNeedsGraphics());
213                if(this->times_ != Script::INF) // Decrement the number of remaining executions.
214                    this->remainingExecutions_--;
215            }
216        }
217    }
218
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        {
233            LuaState* luaState = new LuaState();
234            luaState->doString(code);
235            delete luaState;
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    */
245    void Script::clientConnected(unsigned int clientId)
246    {
247        // If this is the server and the Script is specified as being 'onLoad'.
248        if(GameMode::isServer() && this->isOnLoad())
249        {
250            callStaticNetworkFunction(&Script::executeHelper, clientId, this->getCode(), this->getMode(), this->getNeedsGraphics());
251        }
252    }
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)
263        {
264            this->setMode(ScriptMode::normal);
265            this->modeStr_ = Script::NORMAL;
266        }
267        else if(mode == Script::LUA)
268        {
269            this->setMode(ScriptMode::lua);
270            this->modeStr_ = Script::LUA;
271        }
272        else
273        {
274            orxout(internal_warning) << "Invalid mode '" << mode << "' in Script object. Setting to 'normal'." << endl;
275            this->setMode(ScriptMode::normal);
276            this->modeStr_ = Script::NORMAL;
277        }
278    }
279
280    /**
281    @brief
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
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;
304            default: // This will never happen...
305                return Script::NORMAL;
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        {
325            orxout(internal_warning) << "Invalid times '" << times << "' in Script. Setting to infinity." << endl;
326            this->times_ = Script::INF;
327            this->remainingExecutions_ = Script::INF;
328        }
329    }
330
331}
Note: See TracBrowser for help on using the repository browser.