Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/libraries/core/Loader.cc @ 5929

Last change on this file since 5929 was 5929, checked in by rgrieder, 15 years ago

Merged core5 branch back to the trunk.
Key features include clean level unloading and an extended XML event system.

Two important notes:
Delete your keybindings.ini files! * or you will still get parser errors when loading the key bindings.
Delete build_dir/lib/modules/libgamestates.module! * or orxonox won't start.
Best thing to do is to delete the build folder ;)

  • Property svn:eol-style set to native
File size: 12.2 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Fabian 'x3n' Landau
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29#include "Loader.h"
30
31#include <sstream>
32#include <tinyxml/ticpp.h>
33#include <boost/scoped_ptr.hpp>
34
35#include "util/Debug.h"
36#include "util/Exception.h"
37#include "util/StringUtils.h"
38#include "BaseObject.h"
39#include "Iterator.h"
40#include "ObjectList.h"
41#include "LuaState.h"
42#include "Namespace.h"
43#include "Resource.h"
44#include "XMLFile.h"
45
46namespace orxonox
47{
48    std::vector<std::pair<const XMLFile*, ClassTreeMask> > Loader::files_s;
49    ClassTreeMask Loader::currentMask_s;
50
51    bool Loader::open(const XMLFile* file, const ClassTreeMask& mask)
52    {
53        Loader::add(file, mask);
54        return Loader::load(file, mask);
55    }
56
57    void Loader::close()
58    {
59        Loader::unload();
60        Loader::files_s.clear();
61    }
62
63    void Loader::close(const XMLFile* file)
64    {
65        Loader::unload(file);
66        Loader::remove(file);
67    }
68
69    void Loader::add(const XMLFile* file, const ClassTreeMask& mask)
70    {
71        if (!file)
72            return;
73        Loader::files_s.insert(Loader::files_s.end(), std::pair<const XMLFile*, ClassTreeMask>(file, mask));
74    }
75
76    void Loader::remove(const XMLFile* file)
77    {
78        if (!file)
79            return;
80        for (std::vector<std::pair<const XMLFile*, ClassTreeMask> >::iterator it = Loader::files_s.begin(); it != Loader::files_s.end(); ++it)
81        {
82            if ((*it).first == file)
83            {
84                Loader::files_s.erase(it);
85                break;
86            }
87        }
88    }
89
90    bool Loader::load(const ClassTreeMask& mask)
91    {
92        bool success = true;
93        for (std::vector<std::pair<const XMLFile*, ClassTreeMask> >::iterator it = Loader::files_s.begin(); it != Loader::files_s.end(); ++it)
94            if (!Loader::load((*it).first, (*it).second * mask))
95                success = false;
96
97        return success;
98    }
99
100    void Loader::unload(const ClassTreeMask& mask)
101    {
102        for (ObjectList<BaseObject>::iterator it = ObjectList<BaseObject>::begin(); it != ObjectList<BaseObject>::end(); )
103        {
104            if (mask.isIncluded(it->getIdentifier()))
105                (it++)->destroy();
106            else
107                ++it;
108        }
109    }
110
111    bool Loader::reload(const ClassTreeMask& mask)
112    {
113        Loader::unload(mask);
114        return Loader::load(mask);
115    }
116
117    bool Loader::load(const XMLFile* file, const ClassTreeMask& mask)
118    {
119        if (!file)
120            return false;
121
122        Loader::currentMask_s = file->getMask() * mask;
123
124        std::string xmlInput;
125        if (file->getLuaSupport())
126        {
127            // Use the LuaState to replace the XML tags (calls our function)
128            scoped_ptr<LuaState> luaState(new LuaState());
129            luaState->setIncludeParser(&Loader::replaceLuaTags);
130            luaState->includeFile(file->getFilename(), file->getResourceGroup(), false);
131            xmlInput = luaState->getOutput().str();
132        }
133        else
134        {
135            shared_ptr<ResourceInfo> info = Resource::getInfo(file->getFilename(), file->getResourceGroup());
136            if (info == NULL)
137            {
138                COUT(1) << "Error: Could not find XML file '" << file->getFilename() << "'." << std::endl;
139                return false;
140            }
141            xmlInput = Resource::open(file->getFilename(), file->getResourceGroup())->getAsString();
142        }
143
144        try
145        {
146            COUT(0) << "Start loading " << file->getFilename() << "..." << std::endl;
147            COUT(3) << "Mask: " << Loader::currentMask_s << std::endl;
148
149            ticpp::Document xmlfile(file->getFilename());
150            xmlfile.Parse(xmlInput, true);
151
152            ticpp::Element rootElement;
153            rootElement.SetAttribute("name", "root");
154            rootElement.SetAttribute("bAutogenerated", true);
155
156            for (ticpp::Iterator<ticpp::Element> child = xmlfile.FirstChildElement(false); child != child.end(); child++)
157                rootElement.InsertEndChild(*child);
158
159            COUT(4) << "  creating root-namespace..." << std::endl;
160            Namespace* rootNamespace = new Namespace(0);
161            rootNamespace->setLoaderIndentation("    ");
162            rootNamespace->setFile(file);
163            rootNamespace->setNamespace(rootNamespace);
164            rootNamespace->setRoot(true);
165            rootNamespace->XMLPort(rootElement, XMLPort::LoadObject);
166
167            COUT(0) << "Finished loading " << file->getFilename() << "." << std::endl;
168
169            COUT(4) << "Namespace-tree:" << std::endl << rootNamespace->toString("  ") << std::endl;
170
171            return true;
172        }
173        catch (ticpp::Exception& ex)
174        {
175            COUT(1) << std::endl;
176            COUT(1) << "An XML-error occurred in Loader.cc while loading " << file->getFilename() << ":" << std::endl;
177            COUT(1) << ex.what() << std::endl;
178            COUT(1) << "Loading aborted." << std::endl;
179            return false;
180        }
181        catch (Exception& ex)
182        {
183            COUT(1) << std::endl;
184            COUT(1) << "A loading-error occurred in Loader.cc while loading " << file->getFilename() << ":" << std::endl;
185            COUT(1) << ex.what() << std::endl;
186            COUT(1) << "Loading aborted." << std::endl;
187            return false;
188        }
189        catch (...)
190        {
191            COUT(1) << std::endl;
192            COUT(1) << "An error occurred in Loader.cc while loading " << file->getFilename() << ":" << std::endl;
193            COUT(1) << Exception::handleMessage() << std::endl;
194            COUT(1) << "Loading aborted." << std::endl;
195            return false;
196        }
197    }
198
199    void Loader::unload(const XMLFile* file, const ClassTreeMask& mask)
200    {
201        if (!file)
202            return;
203        for (ObjectList<BaseObject>::iterator it = ObjectList<BaseObject>::begin(); it; )
204        {
205            if ((it->getFile() == file) && mask.isIncluded(it->getIdentifier()))
206                (it++)->destroy();
207            else
208                ++it;
209        }
210    }
211
212    bool Loader::reload(const XMLFile* file, const ClassTreeMask& mask)
213    {
214        Loader::unload(file, mask);
215        return Loader::load(file, mask);
216    }
217
218    std::string Loader::replaceLuaTags(const std::string& text)
219    {
220        // chreate map with all Lua tags
221        std::map<size_t, bool> luaTags;
222        {
223            size_t pos = 0;
224            while ((pos = text.find("<?lua", pos)) != std::string::npos)
225                luaTags[pos++] = true;
226        }
227        {
228            size_t pos = 0;
229            while ((pos = text.find("?>", pos)) != std::string::npos)
230                luaTags[pos++] = false;
231        }
232
233        // erase all tags from the map that are between two quotes
234        {
235            std::map<size_t, bool>::iterator it = luaTags.begin();
236            std::map<size_t, bool>::iterator it2 = it;
237            bool bBetweenQuotes = false;
238            size_t pos = 0;
239            while ((pos = getNextQuote(text, pos)) != std::string::npos)
240            {
241                while ((it != luaTags.end()) && (it->first < pos))
242                {
243                    if (bBetweenQuotes)
244                    {
245                        it2++;
246                        if(it->second && !(it2->second) && it2->first < pos)
247                            it = ++it2;
248                        else
249                            luaTags.erase(it++);
250                    }
251                    else
252                        ++it;
253                }
254                bBetweenQuotes = !bBetweenQuotes;
255                pos++;
256            }
257        }
258
259        // check whether on every opening <?lua tag a closing ?> tag follows
260        {
261            bool expectedValue = true;
262            for (std::map<size_t, bool>::iterator it = luaTags.begin(); it != luaTags.end(); ++it)
263            {
264                if (it->second == expectedValue)
265                    expectedValue = !expectedValue;
266                else
267                {
268                    expectedValue = false;
269                    break;
270                }
271            }
272            if (!expectedValue)
273            {
274                COUT(2) << "Warning: Error in level file" << std::endl;
275                // todo: errorhandling
276                return "";
277            }
278        }
279
280        // Use a stringstream object to speed up the parsing
281        std::ostringstream output;
282
283        // cut the original string into pieces and put them together with print() instead of lua tags
284        {
285            std::map<size_t, bool>::iterator it = luaTags.begin();
286            bool bInPrintFunction = true;
287            size_t start = 0;
288            size_t end = 0;
289
290            do
291            {
292                if (it != luaTags.end())
293                    end = (*(it++)).first;
294                else
295                    end = std::string::npos;
296
297                unsigned int equalSignCounter = 0;
298
299                if (bInPrintFunction)
300                {
301                    // count ['='[ and ]'='] and replace tags with print([[ and ]])
302                    std::string temp = text.substr(start, end - start);
303                    {
304                    size_t pos = 0;
305                    while ((pos = temp.find('[', pos)) != std::string::npos)
306                    {
307                        unsigned int tempCounter = 1;
308                        size_t tempPos = pos++;
309                        while(temp[++tempPos] == '=')
310                        {
311                            tempCounter++;
312                        }
313                        if(temp[tempPos] != '[')
314                        {
315                            tempCounter = 0;
316                        }
317                        else if(tempCounter == 0)
318                        {
319                            tempCounter = 1;
320                        }
321                        if (tempCounter > equalSignCounter)
322                            equalSignCounter = tempCounter;
323                        }
324                    }
325                    {
326                        size_t pos = 0;
327                        while ((pos = temp.find(']', pos)) != std::string::npos)
328                        {
329                            unsigned int tempCounter = 1;
330                            size_t tempPos = pos++;
331                            while(temp[++tempPos] == '=')
332                            {
333                                tempCounter++;
334                            }
335                            if(temp[tempPos] != ']')
336                            {
337                                tempCounter = 0;
338                            }
339                            else if(tempCounter == 0)
340                            {
341                                tempCounter = 1;
342                            }
343                            if (tempCounter > equalSignCounter)
344                                equalSignCounter = tempCounter;
345                        }
346                    }
347                    std::string equalSigns = "";
348                    for(unsigned int i = 0; i < equalSignCounter; i++)
349                    {
350                        equalSigns += "=";
351                    }
352                    output << "print([" + equalSigns + "[" + temp + "]" + equalSigns +"])";
353                    start = end + 5;
354                }
355                else
356                {
357                    output << text.substr(start, end - start);
358                    start = end + 2;
359                }
360
361                bInPrintFunction = !bInPrintFunction;
362            }
363            while (end != std::string::npos);
364        }
365
366        return output.str();
367    }
368}
Note: See TracBrowser for help on using the repository browser.