Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 7944 was 7493, checked in by dafrick, 14 years ago

Fixing small bug in Script (regarding number of executions).
Fixed bug in WorldEntity, that caused the visibility and activity to be synchronized incorrectly (since bVisibleMem and bActiveMem are not synchronized).
Some small changed in documentation.
Started "synchronizing" pickups. Seems to work (except GUI), but haven't done any extensive testing yet.

  • Property svn:eol-style set to native
File size: 11.0 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    /**
58    @brief
59        Constructor. Registers and initializes the object.
60    @param creator
61        The creator of this object.
62    */
63    Script::Script(BaseObject* creator) : BaseObject(creator)
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        COUT(4) << "Script (&" << this << ") triggered." << std::endl;
140
141        PlayerTrigger* pTrigger = orxonox_cast<PlayerTrigger*>(trigger);
142        Pawn* pawn = 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                pawn = pTrigger->getTriggeringPlayer();
151        }
152        else
153            return false;
154
155        if(pawn == NULL)  //TODO: Will this ever happen? If not, change in NotificationDispatcher as well.
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        // Extract the PlayerInfo from the Pawn.
162        PlayerInfo* player = pawn->getPlayer();
163
164        if(player == NULL)
165        {
166            COUT(3) << "The PlayerInfo* is NULL." << std::endl;
167            return false;
168        }
169
170        this->execute(player->getClientID());
171        return true;
172    }
173
174    /**
175    @brief
176        Executes the Scripts code for the input client, depending on the mode.
177    @param clientId
178        The Id of the client the Script should be executed for.
179    @param onLoad
180        Whether this method is executed as a result of the onLoad parameter being set to true. Default is false.
181    */
182    void Script::execute(unsigned int clientId, bool onLoad)
183    {
184        // 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.
185        if(GameMode::isMaster())
186        {
187            // If the number of executions have been used up.
188            if(this->times_ != Script::INF && this->remainingExecutions_ <= 0)
189                return;
190        }
191
192        // If this is either the standalone mode or we're on the client we want to be.
193        if(GameMode::isStandalone() || Host::getPlayerID() == clientId)
194        {
195            this->executeHelper(this->getCode(), this->getMode(), this->getNeedsGraphics());
196            if(GameMode::isMaster() && !onLoad && this->times_ != Script::INF) // Decrement the number of remaining executions.
197                this->remainingExecutions_--;
198        }
199
200        // If this is the server and we're not on the client we want to be.
201        if(GameMode::isServer() && Host::getPlayerID() != clientId)
202        {
203            // If we want to execute the code for all clients and the server.
204            if(this->isForAll())
205            {
206                const std::map<unsigned int, PlayerInfo*> clients = PlayerManager::getInstance().getClients();
207                for(std::map<unsigned int, PlayerInfo*>::const_iterator it = clients.begin(); it != clients.end(); it++)
208                {
209                    callStaticNetworkFunction(Script::executeHelper, it->first, this->getCode(), this->getMode(), this->getNeedsGraphics());
210                    if(this->times_ != Script::INF) // Decrement the number of remaining executions.
211                    {
212                        this->remainingExecutions_--;
213                        if(this->remainingExecutions_ <= 0)
214                            break;
215                    }
216                }
217            }
218            // Else we execute the code just for the specified client.
219            else
220            {
221                callStaticNetworkFunction(Script::executeHelper, clientId, this->getCode(), this->getMode(), this->getNeedsGraphics());
222                if(this->times_ != Script::INF) // Decrement the number of remaining executions.
223                    this->remainingExecutions_--;
224            }
225        }
226    }
227
228    /**
229    @brief
230        Helper method that is used to reach this Script object on other clients.
231    */
232    /*static*/ void Script::executeHelper(const std::string& code, const std::string& mode, bool needsGraphics)
233    {
234        // If the code needs graphics to be executed but the GameMode doesn't show graphics the code isn't executed.
235        if(needsGraphics && !GameMode::showsGraphics())
236            return;
237
238        if(mode == Script::NORMAL) // If the mode is 'normal'.
239            CommandExecutor::execute(code);
240        else if(mode == Script::LUA) // If it's 'lua'.
241        {
242            LuaState* luaState = new LuaState();
243            luaState->doString(code);
244            delete luaState;
245        }
246    }
247
248    /**
249    @brief
250        Callback that is called when a new client has connected.
251    @param clientId
252        The clientId of the new client that has connected.
253    */
254    void Script::clientConnected(unsigned int clientId)
255    {
256        // If this is the server and the Script is specified as being 'onLoad'.
257        if(GameMode::isServer() && this->isOnLoad())
258        {
259            callStaticNetworkFunction(Script::executeHelper, clientId, this->getCode(), this->getMode(), this->getNeedsGraphics());
260        }
261    }
262
263    /**
264    @brief
265        Sets the mode of the Script.
266    @param mode
267        The mode as a string.
268    */
269    void Script::setMode(const std::string& mode)
270    {
271        if(mode == Script::NORMAL)
272        {
273            this->setMode(ScriptMode::normal);
274            this->modeStr_ = Script::NORMAL;
275        }
276        else if(mode == Script::LUA)
277        {
278            this->setMode(ScriptMode::lua);
279            this->modeStr_ = Script::LUA;
280        }
281        else
282        {
283            COUT(2) << "Invalid mode '" << mode << "' in Script object. Setting to 'normal'." << std::endl;
284            this->setMode(ScriptMode::normal);
285            this->modeStr_ = Script::NORMAL;
286        }
287    }
288
289    /**
290    @brief
291        Sets the mode to the mode specified in this->modeStr_.
292        This is used internally for networking purposes.
293    */
294    void Script::modeChanged(void)
295    {
296        this->setMode(this->modeStr_);
297    }
298
299    /**
300    @brief
301        Get the mode of the Script.
302    @return
303        Returns the mode as a string.
304    */
305    const std::string& Script::getMode(void)
306    {
307        switch(this->mode_)
308        {
309            case ScriptMode::normal:
310                return Script::NORMAL;
311            case ScriptMode::lua:
312                return Script::LUA;
313            default: // This will never happen...
314                return Script::NORMAL;
315        }
316    }
317
318    /**
319    @brief
320        Set the number of times this Script is executed at the most.
321        -1 denotes infinity.
322    @param times
323        The number of times to be set.
324    */
325    void Script::setTimes(int times)
326    {
327        if(times >= -1)
328        {
329            this->times_ = times;
330            this->remainingExecutions_ = times;
331        }
332        else
333        {
334            COUT(2) << "Invalid times '" << times << "' in Script. Setting to infinity." << std::endl;
335            this->times_ = Script::INF;
336            this->remainingExecutions_ = Script::INF;
337        }
338    }
339
340}
Note: See TracBrowser for help on using the repository browser.