Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/core/LuaBind.cc @ 3731

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

Merged resource branch back to the trunk. Changes:

  • Automated graphics loading by evaluating whether a GameState requires it
  • Using native Tcl library (x3n)

Windows users: Update your dependency package!

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