Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/libraries/core/LuaState.cc @ 8538

Last change on this file since 8538 was 8351, checked in by rgrieder, 14 years ago

Merged kicklib2 branch back to trunk (includes former branches ois_update, mac_osx and kicklib).

Notes for updating

Linux:
You don't need an extra package for CEGUILua and Tolua, it's already shipped with CEGUI.
However you do need to make sure that the OgreRenderer is installed too with CEGUI 0.7 (may be a separate package).
Also, Orxonox now recognises if you install the CgProgramManager (a separate package available on newer Ubuntu on Debian systems).

Windows:
Download the new dependency packages versioned 6.0 and use these. If you have problems with that or if you don't like the in game console problem mentioned below, you can download the new 4.3 version of the packages (only available for Visual Studio 2005/2008).

Key new features:

  • *Support for Mac OS X*
  • Visual Studio 2010 support
  • Bullet library update to 2.77
  • OIS library update to 1.3
  • Support for CEGUI 0.7 —> Support for Arch Linux and even SuSE
  • Improved install target
  • Compiles now with GCC 4.6
  • Ogre Cg Shader plugin activated for Linux if available
  • And of course lots of bug fixes

There are also some regressions:

  • No support for CEGUI 0.5, Ogre 1.4 and boost 1.35 - 1.39 any more
  • In game console is not working in main menu for CEGUI 0.7
  • Tolua (just the C lib, not the application) and CEGUILua libraries are no longer in our repository. —> You will need to get these as well when compiling Orxonox
  • And of course lots of new bugs we don't yet know about
  • Property svn:eol-style set to native
File size: 11.5 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
[5654]24 *      Reto Grieder
[1959]25 *   Co-authors:
26 *      ...
27 *
28 */
29
[5654]30#include "LuaState.h"
[1959]31
[8351]32#include <tolua++.h>
[2710]33extern "C" {
[5654]34#include <lua.h>
[2710]35#include <lualib.h>
36}
[7266]37#include <loki/ScopeGuard.h>
[2710]38
[3196]39#include "util/Debug.h"
[6746]40#include "util/Exception.h"
[5781]41#include "Resource.h"
[5655]42#include "ToluaBindCore.h"
[7284]43#include "command/IOConsole.h"
[1959]44
45namespace orxonox
46{
[5654]47    LuaState::ToluaInterfaceMap LuaState::toluaInterfaces_s;
48    std::vector<LuaState*> LuaState::instances_s;
[1959]49
[6763]50    const std::string LuaState::ERROR_HANDLER_NAME = "errorHandler";
51
[5655]52    // Do this after declaring toluaInterfaces_s and instances_s to avoid larger problems
53    DeclareToluaInterface(Core);
54
[5654]55    LuaState::LuaState()
56        : bIsRunning_(false)
57        , includeParseFunction_(NULL)
58    {
59        // Create new lua state and configure it
60        luaState_ = lua_open();
[6746]61        Loki::ScopeGuard luaStateGuard = Loki::MakeGuard(&lua_close, luaState_);
[5654]62        luaL_openlibs(luaState_);
[3370]63
[5654]64        // Open all available tolua interfaces
65        this->openToluaInterfaces(luaState_);
[3370]66
[5654]67        // Create dummy file info
68        sourceFileInfo_.reset(new ResourceInfo());
[5781]69        sourceFileInfo_->group = "General";
70        sourceFileInfo_->size = 0;
[1959]71
[5759]72        // Push 'this' pointer
[5654]73        tolua_pushusertype(luaState_, static_cast<void*>(this), "orxonox::LuaState");
74        lua_setglobal(luaState_, "luaState");
[3370]75
[5654]76        // Parse init script
[6746]77        if (!this->doFile("LuaStateInit.lua"))
78            ThrowException(InitialisationFailed, "Running LuaStateInit.lua failed");
79
80        luaStateGuard.Dismiss();
[5654]81    }
[1959]82
[5654]83    LuaState::~LuaState()
84    {
85        lua_close(luaState_);
86    }
[2710]87
[6417]88    shared_ptr<ResourceInfo> LuaState::getFileInfo(const std::string& filename)
[5654]89    {
[6417]90        // Look in the current directory first
91        shared_ptr<ResourceInfo> sourceInfo = Resource::getInfo(sourceFileInfo_->path + filename);
92        // Continue search in root directories
93        if (sourceInfo == NULL && !sourceFileInfo_->path.empty())
94            sourceInfo = Resource::getInfo(filename);
[5654]95        return sourceInfo;
96    }
97
[6746]98    bool LuaState::includeFile(const std::string& filename)
[1959]99    {
[6417]100        shared_ptr<ResourceInfo> sourceInfo = this->getFileInfo(filename);
[5654]101        if (sourceInfo != NULL)
[6746]102            return this->includeString(Resource::open(sourceInfo)->getAsString(), sourceInfo);
[5654]103        else
[6746]104        {
105            COUT(2) << "LuaState: Cannot include file '" << filename << "' (not found)." << std::endl;
106            return false;
107        }
[1959]108    }
109
[6746]110    bool LuaState::includeString(const std::string& code, const shared_ptr<ResourceInfo>& sourceFileInfo)
[5654]111    {
112        // Parse string with provided include parser (otherwise don't preparse at all)
113        std::string luaInput;
114        if (includeParseFunction_ != NULL)
115            luaInput = (*includeParseFunction_)(code);
116        else
117            luaInput = code;
[1959]118
[6746]119        if (sourceFileInfo != NULL)
120        {
121            // Also fill a map with the actual source code. This is just for the include* commands
122            // where the content of sourceFileInfo->filename doesn't match 'code'
123            this->sourceCodeMap_[sourceFileInfo->filename] = code;
124        }
125
126        bool returnValue = this->doString(luaInput, sourceFileInfo);
127
128        if (sourceFileInfo != NULL)
129        {
130            // Delete source code entry
131            if (sourceFileInfo != NULL)
132                this->sourceCodeMap_.erase(sourceFileInfo->filename);
133        }
134
135        return returnValue;
[5654]136    }
137
[6746]138    bool LuaState::doFile(const std::string& filename)
[1959]139    {
[6417]140        shared_ptr<ResourceInfo> sourceInfo = this->getFileInfo(filename);
[5654]141        if (sourceInfo != NULL)
[6746]142            return this->doString(Resource::open(sourceInfo)->getAsString(), sourceInfo);
[5654]143        else
[6746]144        {
145            COUT(2) << "LuaState: Cannot do file '" << filename << "' (not found)." << std::endl;
146            return false;
147        }
[1959]148    }
149
[6746]150    bool LuaState::doString(const std::string& code, const shared_ptr<ResourceInfo>& sourceFileInfo)
[5654]151    {
[6417]152        // Save the old source file info
[5654]153        shared_ptr<ResourceInfo> oldSourceFileInfo = sourceFileInfo_;
154        // Only override if sourceFileInfo provides useful information
155        if (sourceFileInfo != NULL)
156            sourceFileInfo_ = sourceFileInfo;
[1959]157
[6746]158        std::string chunkname;
159        if (sourceFileInfo != NULL)
160        {
161            // Provide lua_load with the filename for debug purposes
162            // The '@' is a Lua convention to identify the chunk name as filename
163            chunkname = '@' + sourceFileInfo->filename;
164        }
165        else
166        {
167            // Use the code string to identify the chunk
168            chunkname = code;
169        }
170
171        // Push custom error handler that uses the debugger
[6763]172        lua_getglobal(this->luaState_, ERROR_HANDLER_NAME.c_str());
[6746]173        int errorHandler = lua_gettop(luaState_);
174        if (lua_isnil(this->luaState_, -1))
175        {
176            lua_pop(this->luaState_, 1);
177            errorHandler = 0;
178        }
179
180        int error = luaL_loadbuffer(luaState_, code.c_str(), code.size(), chunkname.c_str());
[5654]181
[6746]182        switch (error)
183        {
184        case LUA_ERRSYNTAX: // Syntax error
185            COUT(1) << "Lua syntax error: " << lua_tostring(luaState_, -1) << std::endl;
186            break;
187        case LUA_ERRMEM:    // Memory allocation error
188            COUT(1) << "Lua memory allocation error: Consult your dentist immediately!" << std::endl;
189            break;
190        }
191
[5654]192        if (error == 0)
[6746]193        {
194            // Execute the chunk in protected mode with an error handler function (stack index)
195            error = lua_pcall(luaState_, 0, 1, errorHandler);
196
197            switch (error)
198            {
199            case LUA_ERRRUN: // Runtime error
200                if (errorHandler)
201                {
202                    // Do nothing (we already display the error in the
203                    // 'errorHandler' Lua function in LuaStateInit.lua)
204                }
205                else
206                {
207                    std::string errorString = lua_tostring(this->luaState_, -1);
208                    if (errorString.find("Error propagation") == std::string::npos)
209                        COUT(1) << "Lua runtime error: " << errorString << std::endl;
210                }
211                break;
212            case LUA_ERRERR: // Error in the error handler
213                COUT(1) << "Lua error in error handler. No message available." << std::endl;
214                break;
215            case LUA_ERRMEM: // Memory allocation error
216                COUT(1) << "Lua memory allocation error: Consult your dentist immediately!" << std::endl;
217                break;
218            }
219        }
220
[5654]221        if (error != 0)
222        {
[6746]223            lua_pop(luaState_, 1);  // Remove error message
224            lua_pushnil(luaState_); // Push a nil return value
[5654]225        }
[6746]226
227        if (errorHandler != 0)
228            lua_remove(luaState_, errorHandler); // Remove error handler from stack
229
230        // Set return value to a global variable because we cannot return a table in this function
231        // here. It would work for numbers, pointers and strings, but certainly not for Lua tables.
[5661]232        lua_setglobal(luaState_, "LuaStateReturnValue");
[5654]233
234        // Load the old info again
235        sourceFileInfo_ = oldSourceFileInfo;
[6746]236
237        return (error == 0);
[1959]238    }
[5654]239
240    void LuaState::luaPrint(const std::string& str)
[1959]241    {
[5654]242        output_ << str;
[1959]243    }
244
[5654]245    void LuaState::luaLog(unsigned int level, const std::string& message)
[1959]246    {
[6105]247        OutputHandler::getOutStream(level) << message << std::endl;
[1959]248    }
[5654]249
[6417]250    bool LuaState::fileExists(const std::string& filename)
[5661]251    {
[6417]252        shared_ptr<ResourceInfo> info = this->getFileInfo(filename);
[5661]253        if (info == NULL)
254            return false;
255        else
256            return true;
257    }
258
[6746]259    //! Returns the content of a file
260    std::string LuaState::getSourceCode(const std::string& filename)
261    {
262        // Try the internal map first to get the actual Lua code
263        // and not just some pseudo Lua-XML code when using include* commands
264        std::map<std::string, std::string>::const_iterator it = this->sourceCodeMap_.find(filename);
265        if (it != this->sourceCodeMap_.end())
266            return it->second;
267        shared_ptr<ResourceInfo> info = Resource::getInfo(filename);
268        if (info == NULL)
269            return "";
270        else
271            return Resource::open(info)->getAsString();
272    }
273
274    bool LuaState::usingIOConsole() const
275    {
276        return IOConsole::exists();
277    }
278
[5654]279    /*static*/ bool LuaState::addToluaInterface(int (*function)(lua_State*), const std::string& name)
[1959]280    {
[5654]281        for (ToluaInterfaceMap::const_iterator it = toluaInterfaces_s.begin(); it != toluaInterfaces_s.end(); ++it)
[1959]282        {
[5654]283            if (it->first == name || it->second == function)
284            {
285                COUT(2) << "Warning: Trying to add a Tolua interface with the same name or function." << std::endl;
286                return true;
287            }
[1959]288        }
[5654]289        toluaInterfaces_s[name] = function;
290
291        // Open interface in all LuaStates
292        for (std::vector<LuaState*>::const_iterator it = instances_s.begin(); it != instances_s.end(); ++it)
293            (*function)((*it)->luaState_);
294
295        // Return dummy bool
296        return true;
[1959]297    }
298
[5654]299    /*static*/ bool LuaState::removeToluaInterface(const std::string& name)
[1959]300    {
[5654]301        ToluaInterfaceMap::iterator it = toluaInterfaces_s.find(name);
302        if (it == toluaInterfaces_s.end())
[1959]303        {
[5654]304            COUT(2) << "Warning: Cannot remove Tolua interface '" << name << "': Not found" << std::endl;
305            return true;
[1959]306        }
307
[5654]308        // Close interface in all LuaStates
309        for (std::vector<LuaState*>::const_iterator itState = instances_s.begin(); itState != instances_s.end(); ++itState)
[1959]310        {
[5654]311            lua_pushnil((*itState)->luaState_);
312            lua_setglobal((*itState)->luaState_, it->first.c_str());
[1959]313        }
314
[5654]315        // Remove entry
316        toluaInterfaces_s.erase(it);
317
318        // Return dummy bool
319        return true;
[1959]320    }
321
[5654]322    /*static*/ void LuaState::openToluaInterfaces(lua_State* state)
323    {
324        for (ToluaInterfaceMap::const_iterator it = toluaInterfaces_s.begin(); it != toluaInterfaces_s.end(); ++it)
325            (*it->second)(state);
326    }
[1959]327
[5654]328    /*static*/ void LuaState::closeToluaInterfaces(lua_State* state)
[3370]329    {
[5654]330        for (ToluaInterfaceMap::const_iterator it = toluaInterfaces_s.begin(); it != toluaInterfaces_s.end(); ++it)
331        {
332            lua_pushnil(state);
333            lua_setglobal(state, it->first.c_str());
334        }
[3370]335    }
[6417]336
337
338    LuaFunctor::LuaFunctor(const std::string& code, LuaState* luaState)
339    {
340        this->code_ = code;
341        this->lua_ = luaState;
342    }
343
[7284]344    void LuaFunctor::operator()()
[6417]345    {
346        lua_->doString(this->code_);
347    }
[1959]348}
Note: See TracBrowser for help on using the repository browser.