Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/resource/src/core/LuaBind.cc @ 3358

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

Generalised use of tolua interfaces a bit: GSRoot now adds the interface functions to LuaBind which supports two new functions: openToluaInterfaces and closeToluaInterfaces. Both accept a lua state and can therefore be used to inject our own tolua bindings (the GUIManager makes use of that).
There's also something new: When loading a level, you could now use the tolua bindings from Orxonox as well (not just those from Core).

  • Property svn:eol-style set to native
File size: 9.1 KB
RevLine 
[1959]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 *      Benjamin Knecht
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29#include "LuaBind.h"
30
31#include <fstream>
32#include <map>
[2710]33extern "C" {
34#include <lualib.h>
35}
36#include <tolua/tolua++.h>
37#include <boost/filesystem.hpp>
38
[3196]39#include "util/Debug.h"
[3280]40#include "util/StringUtils.h"
[2710]41#include "Core.h"
[1959]42
43namespace orxonox
44{
[2662]45  LuaBind* LuaBind::singletonRef_s = NULL;
[1959]46
47  LuaBind::LuaBind()
48  {
[2662]49    assert(LuaBind::singletonRef_s == 0);
50    LuaBind::singletonRef_s = this;
51
[2759]52    this->includePath_ = Core::getMediaPathString();
[2710]53
[1959]54    luaState_ = lua_open();
55    luaSource_ = "";
56#if LUA_VERSION_NUM == 501
57    luaL_openlibs(luaState_);
58#else
59    luaopen_base(luaState_);
60    luaopen_string(luaState_);
61    luaopen_table(luaState_);
62    luaopen_math(luaState_);
63    luaopen_io(luaState_);
64    luaopen_debug(luaState_);
65#endif
[3340]66
67    // Open all available tolua interfaces
68    this->openToluaInterfaces(luaState_);
69
[1959]70    output_ = "";
71    isRunning_ = false;
72  }
73
[3340]74  LuaBind::~LuaBind()
75  {
76    this->closeToluaInterfaces(luaState_);
77
78    assert(singletonRef_s);
79    LuaBind::singletonRef_s = NULL;
80  };
81
[3196]82  void LuaBind::luaPrint(const std::string& str)
[1959]83  {
84    output_ += str;
85//    COUT(4) << "Lua_output!:" << std::endl << str << std::endl << "***" << std::endl;
86    COUT(5) << str;
87  }
88
89  /**
90      @brief Loads the specified file line by line
91      @param filename The filename of the file
92      @param luaTags if true, the loaded file gets stripped off luaTags
93  */
[3196]94  void LuaBind::loadFile(const std::string& filename, bool luaTags)
[1959]95  {
[2710]96    boost::filesystem::path filepath(filename);
97
[1959]98    output_ = "";
99    std::ifstream file;
[2759]100    file.open(filepath.string().c_str(), std::fstream::in);
[1959]101
102    if (!file.is_open())
103    {
104      // some error msg
105    }
106
107    std::string levelString = "";
108
109    while (file.good() && !file.eof())
110    {
[3198]111      std::string line;
112      std::getline(file, line);
[1959]113      levelString += line;
114      levelString += "\n";
115    }
116
117    file.close();
118    //std::string output;
119
[2508]120    if (luaTags)
121      luaSource_ = replaceLuaTags(levelString);
122    else
123      luaSource_ = levelString;
[1959]124    COUT(5) << "ParsedSourceCode: " << luaSource_ << std::endl;
125  }
126
[3196]127  void LuaBind::loadString(const std::string& code)
[1959]128  {
129    luaSource_ = code;
130    output_ = "";
131  }
132
133#if LUA_VERSION_NUM != 501
134  const char * LuaBind::lua_Chunkreader(lua_State *L, void *data, size_t *size)
135  {
[3301]136    LoadS* ls = static_cast<LoadS*>(data);
[1959]137    if (ls->size == 0) return NULL;
138    *size = ls->size;
139    ls->size = 0;
140    return ls->s;
141  }
142#endif
143  void LuaBind::run()
144  {
145    if (!isRunning_)
146    {
147      isRunning_ = true;
148      int error = 0;
[2508]149      std::string init =
150         "local scr = orxonox.LuaBind:getInstance()\n \
151          local debug = print\n \
152          print = function(s)\n \
153              scr:luaPrint(s)\n \
154          end\n \
155          include = function(f)\n \
156              file = assert(io.open(\"" + this->includePath_ + "\"..\"/\"..f))\n \
157              content = file:read(\"*a\")\n \
158              file:close()\n \
159              source = scr:replaceLuaTags(content)\n \
160              assert(loadstring(source))()\n \
161          end\n";
[1959]162      init += luaSource_;
163  #if LUA_VERSION_NUM == 501
164      error = luaL_loadstring(luaState_, init.c_str());
165  #else
166      LoadS ls;
167      ls.s = init.c_str();
168      ls.size = init.size();
169      error = lua_load(luaState_, &orxonox::LuaBind::lua_Chunkreader, &ls, init.c_str());
170  #endif
171      if (error == 0)
172      {
173        error = lua_pcall(luaState_, 0, 0, 0);
174      }
175      if (error != 0)
176      {
177        COUT(2) << "Error in Lua-script: " << lua_tostring(luaState_, -1) << std::endl;
178      }
179      isRunning_ = false;
180    }
181    else
182    {
183      COUT(2) << "Warning: Lua's run is called while running!" << std::endl;
184    }
185  }
186
187  std::string LuaBind::replaceLuaTags(const std::string& text)
188  {
189    // chreate map with all Lua tags
190    std::map<size_t, bool> luaTags;
191    {
192      size_t pos = 0;
193      while ((pos = text.find("<?lua", pos)) != std::string::npos)
194        luaTags[pos++] = true;
195    }
196    {
197      size_t pos = 0;
198      while ((pos = text.find("?>", pos)) != std::string::npos)
199        luaTags[pos++] = false;
200    }
201
202    // erase all tags from the map that are between two quotes
203    {
204      std::map<size_t, bool>::iterator it = luaTags.begin();
205      std::map<size_t, bool>::iterator it2 = it;
206      bool bBetweenQuotes = false;
207      size_t pos = 0;
208      while ((pos = getNextQuote(text, pos)) != std::string::npos)
209      {
210        while ((it != luaTags.end()) && (it->first < pos))
211        {
212          if (bBetweenQuotes) {
213            it2++;
214            if(it->second && !(it2->second) && it2->first < pos)
215              it = ++it2;
216            else
217              luaTags.erase(it++);
218          }
219          else
220            ++it;
221        }
222        bBetweenQuotes = !bBetweenQuotes;
223        pos++;
224      }
225    }
226
227    // check whether on every opening <?lua tag a closing ?> tag follows
228    {
229      bool expectedValue = true;
230      for (std::map<size_t, bool>::iterator it = luaTags.begin(); it != luaTags.end(); ++it)
231      {
232        if (it->second == expectedValue)
233          expectedValue = !expectedValue;
234        else
235        {
236          expectedValue = false;
237          break;
238        }
239      }
240      if (!expectedValue) {
241        COUT(2) << "Warning: Error in level file" << std::endl;
242        // todo: errorhandling
243        return "";
244      }
245    }
246
247    // cut the original string into pieces and put them together with print() instead of lua tags
248    std::string output;
249    {
250      std::map<size_t, bool>::iterator it = luaTags.begin();
251      bool bInPrintFunction = true;
252      size_t start = 0;
[1961]253      size_t end = 0;
[1959]254
255      do
256      {
257        if (it != luaTags.end())
258          end = (*(it++)).first;
259        else
260          end = std::string::npos;
261
262        unsigned int equalSignCounter = 0;
263
264        if (bInPrintFunction)
265        {
266          // count ['='[ and ]'='] and replace tags with print([[ and ]])
267          std::string temp = text.substr(start, end - start);
268          {
269            size_t pos = 0;
270            while ((pos = temp.find('[', pos)) != std::string::npos)
271            {
272              unsigned int tempCounter = 1;
273              size_t tempPos = pos++;
274              while(temp[++tempPos] == '=') {
275                tempCounter++;
276              }
277              if(temp[tempPos] != '[') {
278                tempCounter = 0;
279              }
280              else if(tempCounter == 0) {
281                tempCounter = 1;
282              }
283              if (tempCounter > equalSignCounter)
284                equalSignCounter = tempCounter;
285            }
286          }
287          {
288            size_t pos = 0;
289            while ((pos = temp.find(']', pos)) != std::string::npos)
290            {
291              unsigned int tempCounter = 1;
292              size_t tempPos = pos++;
293              while(temp[++tempPos] == '=') {
294                tempCounter++;
295              }
296              if(temp[tempPos] != ']') {
297                tempCounter = 0;
298              }
299              else if(tempCounter == 0) {
300                tempCounter = 1;
301              }
302              if (tempCounter > equalSignCounter)
303                equalSignCounter = tempCounter;
304            }
305          }
306          std::string equalSigns = "";
307          for(unsigned int i = 0; i < equalSignCounter; i++) {
308            equalSigns += "=";
309          }
310          output += "print([" + equalSigns + "[" + temp + "]" + equalSigns +"])";
311          start = end + 5;
312        }
313        else
314        {
315          output += text.substr(start, end - start);
316          start = end + 2;
317        }
318
319        bInPrintFunction = !bInPrintFunction;
320      }
321      while (end != std::string::npos);
322    }
323
324    return output;
325  }
326
[3340]327  void LuaBind::addToluaInterface(int (*function)(lua_State*), const std::string& name)
328  {
329    toluaInterfaces_.push_back(std::make_pair(name, function));
330    // Apply changes to our own lua state as well
331    (*function)(luaState_);
332  }
333
334  void LuaBind::openToluaInterfaces(lua_State* state)
335  {
336    for (unsigned int i = 0; i < toluaInterfaces_.size(); ++i)
337      (*toluaInterfaces_[i].second)(state);
338  }
339
340  void LuaBind::closeToluaInterfaces(lua_State* state)
341  {
342    for (unsigned int i = 0; i < toluaInterfaces_.size(); ++i)
343    {
344      lua_pushnil(state);
345      lua_setglobal(state, toluaInterfaces_[i].first.c_str());
346    }
347  }
348
[1959]349}
Note: See TracBrowser for help on using the repository browser.