Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/modules/objects/Script.cc @ 7482

Last change on this file since 7482 was 7482, checked in by dafrick, 15 years ago

Fixed Script class. Works now without having to rely on guessing how long it is going to take for the object to be synchronized.

  • Property svn:eol-style set to native
File size: 11.3 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/NetworkFunction.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    CreateFactory(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    /*static*/ LuaState* Script::LUA_STATE = NULL;
58
59    /**
60    @brief
61        Constructor. Registers and initializes the object.
62    @param creator
63        The creator of this object.
64    */
65    Script::Script(BaseObject* creator) : BaseObject(creator), Synchronisable(creator)
66    {
67        RegisterObject(Script);
68
69        // Initialize variables.
70        this->remainingExecutions_ = Script::INF;
71        this->mode_ = ScriptMode::normal;
72        this->onLoad_ = true;
73        this->times_ = Script::INF;
74        this->needsGraphics_ = false;
75    }
76
77    /**
78    @brief
79        Destructor. Cleans up.
80    */
81    Script::~Script()
82    {
83        //if(this->isInitialized() && this->luaState_ != NULL)
84        //    delete this->luaState_;
85    }
86
87    /**
88    @brief
89        Method for creating a Script object through XML.
90    @param xmlelement
91        The element.
92    @param mode
93        The mode.
94    */
95    void Script::XMLPort(Element& xmlelement, XMLPort::Mode mode)
96    {
97        SUPER(Script, XMLPort, xmlelement, mode);
98
99        XMLPortParam(Script, "code", setCode, getCode, xmlelement, mode);
100        XMLPortParamTemplate(Script, "mode", setMode, getMode, xmlelement, mode, const std::string&).defaultValues(Script::NORMAL);
101        XMLPortParam(Script, "onLoad", setOnLoad, isOnLoad, xmlelement, mode).defaultValues(true);
102        XMLPortParam(Script, "times", setTimes, getTimes, xmlelement, mode).defaultValues(Script::INF);
103        XMLPortParam(Script, "needsGraphics", setNeedsGraphics, getNeedsGraphics, xmlelement, mode).defaultValues(false);
104        XMLPortParam(Script, "forAll", setForAll, isForAll, xmlelement, mode).defaultValues(false);
105
106        XMLPortEventSink(Script, BaseObject, "trigger", trigger, xmlelement, mode);
107
108        if(this->isOnLoad()) // If the object is onLoad the code is executed at once for the server.
109            this->execute(0);
110    }
111
112    /**
113    @brief
114        Creates a port that can be used to channel events and react to them.
115    @param xmlelement
116        The element.
117    @param mode
118        The mode.
119    */
120    void Script::XMLEventPort(Element& xmlelement, XMLPort::Mode mode)
121    {
122        SUPER(Script, XMLEventPort, xmlelement, mode);
123
124        XMLPortEventState(Script, BaseObject, "trigger", trigger, xmlelement, mode);
125    }
126
127    /**
128    @brief
129        Is called when an event comes in trough the event port.
130    @param triggered
131        Whether the event is triggering or un-triggering.
132    @param trigger
133        The object that caused the event to be fired.
134    @return
135        Returns true if successful.
136    */
137    bool Script::trigger(bool triggered, BaseObject* trigger)
138    {
139        if(!triggered || !this->isActive()) // If the Script is inactive it cannot be executed.
140            return false;
141
142        COUT(4) << "Script (&" << this << ") triggered." << std::endl;
143
144        PlayerTrigger* pTrigger = orxonox_cast<PlayerTrigger*>(trigger);
145        Pawn* pawn = NULL;
146
147        // If the trigger is a PlayerTrigger.
148        if(pTrigger != NULL)
149        {
150            if(!pTrigger->isForPlayer())  // The PlayerTrigger is not exclusively for Pawns which means we cannot extract one.
151                return false;
152            else
153                pawn = pTrigger->getTriggeringPlayer();
154        }
155        else
156            return false;
157
158        if(pawn == NULL)  //TODO: Will this ever happen? If not, change in NotificationDispatcher as well.
159        {
160            COUT(4) << "The Script was triggered by an entity other than a Pawn. (" << trigger->getIdentifier()->getName() << ")" << std::endl;
161            return false;
162        }
163
164        // Extract the PlayerInfo from the Pawn.
165        PlayerInfo* player = pawn->getPlayer();
166
167        if(player == NULL)
168        {
169            COUT(3) << "The PlayerInfo* is NULL." << std::endl;
170            return false;
171        }
172
173        this->execute(player->getClientID());
174        return true;
175    }
176
177    /**
178    @brief
179        Executes the Scripts code for the input client, depending on the mode.
180    @param clientId
181        The Id of the client the Script should be executed for.
182    @param fromCallback
183        Whether this method is executed in response to the connectedCallback().
184    */
185    void Script::execute(unsigned int clientId, bool fromCallback)
186    {
187        COUT(0) << "EXECUTE: " << Host::getPlayerID() << " | " << clientId << std::endl; //TODO: Remove.
188        // 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.
189        if(GameMode::isServer() || GameMode::isStandalone())
190        {
191            // If the number of executions have been used up.
192            if(this->times_ != Script::INF && this->remainingExecutions_ == 0)
193                return;
194
195            // Decrement the number of remaining executions.
196            //TODO: Mode such that this is consistent in any case.
197            if(this->times_ != Script::INF)
198                this->remainingExecutions_--;
199        }
200
201        // If this is either the standalone mode or we're on the client we want to be.
202        if(GameMode::isStandalone() || Host::getPlayerID() == clientId)
203        {
204           this->executeHelper(this->getCode(), this->getMode(), this->getNeedsGraphics());
205        }
206
207        // If this is the server and we're not on the client we want to be.
208        if(!GameMode::isStandalone() && GameMode::isServer() && Host::getPlayerID() != clientId)
209        {
210            COUT(0) << "1" << std::endl; //TODO: Remove.
211            // If this is not the result of a clientConnected callback and we want to execute the code for all clients.
212            //TODO: In this case does the server get executed as well?
213            if(!fromCallback && this->isForAll())
214            {
215                const std::map<unsigned int, PlayerInfo*> clients = PlayerManager::getInstance().getClients();
216                for(std::map<unsigned int, PlayerInfo*>::const_iterator it = clients.begin(); it != clients.end(); it++)
217                {
218                    callStaticNetworkFunction(Script::executeHelper, it->first, this->getCode(), this->getMode(), this->getNeedsGraphics());
219                }
220            }
221            // Else we execute the code just for the specified client.
222            else
223            {
224                COUT(0) << "2" << std::endl; //TODO: Remove.
225                callStaticNetworkFunction(Script::executeHelper, clientId, this->getCode(), this->getMode(), this->getNeedsGraphics());
226            }
227        }
228    }
229
230    /**
231    @brief
232        Helper method that is used to reach this Script object on other clients.
233    */
234    /*static*/ void Script::executeHelper(const std::string& code, const std::string& mode, bool needsGraphics)
235    {
236        COUT(0) << "HELPER: " << code << " | " << mode << " | " << needsGraphics << std::endl; //TODO: Remove.
237
238        // If the code needs graphics to be executed but the GameMode doesn't show graphics the code isn't executed.
239        if(needsGraphics && !GameMode::showsGraphics())
240            return;
241
242        if(mode == Script::NORMAL) // If the mode is 'normal'.
243            CommandExecutor::execute(code);
244        else if(mode == Script::LUA) // If it's 'lua'.
245        {
246            if(Script::LUA_STATE == NULL)
247                Script::LUA_STATE = new LuaState();
248            Script::LUA_STATE->doString(code);
249        }
250    }
251
252    /**
253    @brief
254        Callback that is called when a new client has connected.
255    @param clientId
256        The clientId of the new client that has connected.
257    */
258    void Script::clientConnected(unsigned int clientId)
259    {
260        // If this is the server and the Script is specified as being 'onLoad'.
261        if(!GameMode::isStandalone() && GameMode::isServer() && this->isOnLoad())
262        {
263            if(clientId != 0) //TODO: Remove if not needed.
264                this->execute(clientId, true);
265        }
266    }
267
268    /**
269    @brief
270        Sets the mode of the Script.
271    @param mode
272        The mode as a string.
273    */
274    void Script::setMode(const std::string& mode)
275    {
276        if(mode == Script::NORMAL)
277        {
278            this->setMode(ScriptMode::normal);
279            this->modeStr_ = Script::NORMAL;
280        }
281        else if(mode == Script::LUA)
282        {
283            this->setMode(ScriptMode::lua);
284            this->modeStr_ = Script::LUA;
285        }
286        else
287        {
288            COUT(2) << "Invalid mode '" << mode << "' in Script object. Setting to 'normal'." << std::endl;
289            this->setMode(ScriptMode::normal);
290            this->modeStr_ = Script::NORMAL;
291        }
292    }
293
294    /**
295    @brief
296        Sets the mode to the mode specified in this->modeStr_.
297        This is used internally for networking purposes.
298    */
299    void Script::modeChanged(void)
300    {
301        this->setMode(this->modeStr_);
302    }
303
304    /**
305    @brief
306        Get the mode of the Script.
307    @return
308        Returns the mode as a string.
309    */
310    const std::string& Script::getMode(void)
311    {
312        switch(this->mode_)
313        {
314            case ScriptMode::normal:
315                return Script::NORMAL;
316            case ScriptMode::lua:
317                return Script::LUA;
318            default: // This will never happen...
319                return Script::NORMAL;
320        }
321    }
322
323    /**
324    @brief
325        Set the number of times this Script is executed at the most.
326        -1 denotes infinity.
327    @param times
328        The number of times to be set.
329    */
330    void Script::setTimes(int times)
331    {
332        if(times >= -1)
333        {
334            this->times_ = times;
335            this->remainingExecutions_ = times;
336        }
337        else
338        {
339            COUT(2) << "Invalid times '" << times << "' in Script. Setting to infinity." << std::endl;
340            this->times_ = Script::INF;
341            this->remainingExecutions_ = Script::INF;
342        }
343    }
344
345}
Note: See TracBrowser for help on using the repository browser.