Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

LuaState Class Reference

#include <celx.h>

Collaboration diagram for LuaState:

Collaboration graph
List of all members.

Public Types

enum  IOMode { NoIO = 1, Asking = 2, IOAllowed = 4, IODenied = 8 }

Public Member Functions

bool charEntered (const char *)
void cleanup ()
bool createThread ()
std::string getErrorMessage ()
lua_State * getState () const
double getTime () const
bool init (CelestiaCore *)
bool isAlive () const
int loadScript (const std::string &)
int loadScript (std::istream &, const std::string &streamname)
 LuaState ()
void requestIO ()
int resume ()
bool tick (double)
bool timesliceExpired ()
 ~LuaState ()

Public Attributes

int screenshotCount
double timeout

Private Attributes

bool alive
lua_State * costate
IOMode ioMode
double scriptAwakenTime
lua_State * state
Timertimer

Member Enumeration Documentation

enum LuaState::IOMode
 

Enumeration values:
NoIO 
Asking 
IOAllowed 
IODenied 

Definition at line 53 of file celx.h.

00053                 {
00054         NoIO = 1,
00055         Asking = 2,
00056         IOAllowed = 4,
00057         IODenied = 8
00058     };


Constructor & Destructor Documentation

LuaState::LuaState  ) 
 

Definition at line 372 of file celx.cpp.

References CreateTimer(), MaxTimeslice, screenshotCount, state, and timer.

00372                    :
00373     timeout(MaxTimeslice),
00374     state(NULL),
00375     costate(NULL),
00376     alive(false),
00377     timer(NULL),
00378     scriptAwakenTime(0.1),
00379     ioMode(NoIO)
00380 {
00381     state = lua_open();
00382     timer = CreateTimer();
00383     screenshotCount = 0;
00384 }

LuaState::~LuaState  ) 
 

Definition at line 386 of file celx.cpp.

References costate, state, and timer.

00387 {
00388     delete timer;
00389     if (state != NULL)
00390         lua_close(state);
00391 #if 0
00392     if (costate != NULL)
00393         lua_close(costate);
00394 #endif
00395 }


Member Function Documentation

bool LuaState::charEntered const char *   ) 
 

Definition at line 594 of file celx.cpp.

References Asking, costate, getAppCore(), CelestiaCore::getRenderer(), CelestiaCore::getTextEnterMode(), getTime(), IOAllowed, IODenied, ioMode, KbdCallback, NoErrors, Renderer::setRenderFlags(), CelestiaCore::setTextEnterMode(), CelestiaCore::showText(), and timeout.

00595 {
00596     if (ioMode == Asking && getTime() > timeout)
00597     {
00598         int stackTop = lua_gettop(costate);
00599         if (strcmp(c_p, "y") == 0)
00600         {
00601             lua_iolibopen(costate);
00602             ioMode = IOAllowed;
00603         }
00604         else
00605         {
00606             ioMode = IODenied;
00607         }
00608         CelestiaCore* appCore = getAppCore(costate, NoErrors);
00609         if (appCore == NULL)
00610         {
00611             cerr << "ERROR: appCore not found\n";
00612             return true;
00613         }
00614         appCore->setTextEnterMode(appCore->getTextEnterMode() & ~CelestiaCore::KbPassToScript);
00615         appCore->showText("", 0, 0, 0, 0);
00616         // Restore renderflags:
00617         lua_pushstring(costate, "celestia-savedrenderflags");
00618         lua_gettable(costate, LUA_REGISTRYINDEX);
00619         if (lua_isuserdata(costate, -1))
00620         {
00621             int* savedrenderflags = static_cast<int*>(lua_touserdata(costate, -1));
00622             appCore->getRenderer()->setRenderFlags(*savedrenderflags);
00623             // now delete entry:
00624             lua_pushstring(costate, "celestia-savedrenderflags");
00625             lua_pushnil(costate);
00626             lua_settable(costate, LUA_REGISTRYINDEX);
00627         }
00628         else
00629         {
00630             cerr << "Oops, expected savedrenderflags to be userdata\n";
00631         }
00632         lua_settop(costate,stackTop);
00633         return true;
00634     }
00635     int stack_top = lua_gettop(costate);
00636     bool result = true;
00637     lua_pushstring(costate, KbdCallback);
00638     lua_gettable(costate, LUA_GLOBALSINDEX);
00639     lua_pushstring(costate, c_p);
00640     timeout = getTime() + 1.0;
00641     if (lua_pcall(costate, 1, 1, 0) != 0)
00642     {
00643         cerr << "Error while executing keyboard-callback: " << lua_tostring(costate, -1) << "\n";
00644         result = false;
00645     }
00646     else
00647     {
00648         if (lua_isboolean(costate, -1))
00649         {
00650             result = static_cast<bool>(lua_toboolean(costate, -1));
00651         }
00652     }
00653     // cleanup stack - is this necessary?
00654     lua_settop(costate, stack_top);
00655     return result;
00656 }

void LuaState::cleanup  ) 
 

Definition at line 439 of file celx.cpp.

References Asking, CleanupCallback, costate, getAppCore(), CelestiaCore::getRenderer(), getTime(), ioMode, NoErrors, Renderer::setRenderFlags(), state, and timeout.

00440 {
00441     if (ioMode == Asking)
00442     {
00443         // Restore renderflags:
00444         CelestiaCore* appCore = getAppCore(costate, NoErrors);
00445         if (appCore != NULL)
00446         {
00447             lua_pushstring(state, "celestia-savedrenderflags");
00448             lua_gettable(state, LUA_REGISTRYINDEX);
00449             if (lua_isuserdata(state, -1))
00450             {
00451                 int* savedrenderflags = static_cast<int*>(lua_touserdata(state, -1));
00452                 appCore->getRenderer()->setRenderFlags(*savedrenderflags);
00453                 // now delete entry:
00454                 lua_pushstring(state, "celestia-savedrenderflags");
00455                 lua_pushnil(state);
00456                 lua_settable(state, LUA_REGISTRYINDEX);
00457             }
00458             lua_pop(state,1);
00459         }
00460     }
00461     lua_pushstring(costate, CleanupCallback);
00462     lua_gettable(costate, LUA_GLOBALSINDEX);
00463     if (lua_isnil(costate, -1))
00464     {
00465         return;
00466     }
00467     timeout = getTime() + 1.0;
00468     if (lua_pcall(costate, 0, 0, 0) != 0)
00469     {
00470         cerr << "Error while executing cleanup-callback: " << lua_tostring(costate, -1) << "\n";
00471     }
00472 }

bool LuaState::createThread  ) 
 

Definition at line 475 of file celx.cpp.

References alive, checkTimeslice(), costate, and state.

00476 {
00477     // Initialize the coroutine which wraps the script
00478     if (!(lua_isfunction(state, -1) && !lua_iscfunction(state, -1)))
00479     {
00480         // Should never happen; we manually set up the stack in C++
00481         assert(0);
00482         return false;
00483     }
00484     else
00485     {
00486         costate = lua_newthread(state);
00487         if (costate == NULL)
00488             return false;
00489         lua_sethook(costate, checkTimeslice, LUA_MASKCOUNT, 1000);
00490         lua_pushvalue(state, -2);
00491         lua_xmove(state, costate, 1);  /* move function from L to NL */
00492         alive = true;
00493         return true;
00494     }
00495 }

string LuaState::getErrorMessage  ) 
 

Definition at line 498 of file celx.cpp.

References state.

00499 {
00500     if (lua_gettop(state) > 0)
00501     {
00502         if (lua_isstring(state, -1))
00503             return lua_tostring(state, -1);
00504     }
00505     return "";
00506 }

lua_State * LuaState::getState  )  const
 

Definition at line 397 of file celx.cpp.

References state.

Referenced by tick().

00398 {
00399     return state;
00400 }

double LuaState::getTime  )  const
 

Definition at line 403 of file celx.cpp.

References Timer::getTime(), and timer.

Referenced by celestia_getscripttime(), celestia_takescreenshot(), celscript_tick(), charEntered(), cleanup(), object_preloadtexture(), resume(), tick(), and timesliceExpired().

00404 {
00405     return timer->getTime();
00406 }

bool LuaState::init CelestiaCore  ) 
 

Definition at line 4575 of file celx.cpp.

References alerter, celestia_new(), CreateCelestiaMetaTable(), CreateCelscriptMetaTable(), CreateFrameMetaTable(), CreateObjectMetaTable(), CreateObserverMetaTable(), CreatePositionMetaTable(), CreateRotationMetaTable(), CreateVectorMetaTable(), KdeAlerter::fatalError(), initMaps(), KM_PER_LY, loadScript(), and state.

04576 {
04577     initMaps();
04578 
04579     // Import the base and math libraries
04580     lua_baselibopen(state);
04581     lua_mathlibopen(state);
04582     lua_tablibopen(state);
04583     lua_strlibopen(state);
04584 
04585     // Add an easy to use wait function, so that script writers can
04586     // live in ignorance of coroutines.  There will probably be a significant
04587     // library of useful functions that can be defined purely in Lua.
04588     // At that point, we'll want something a bit more robust than just
04589     // parsing the whole text of the library every time a script is launched
04590     if (loadScript("wait = function(x) coroutine.yield(x) end") != 0)
04591         return false;
04592     lua_pcall(state, 0, 0, 0); // execute it
04593 
04594     lua_pushstring(state, "KM_PER_MICROLY");
04595     lua_pushnumber(state, (lua_Number)KM_PER_LY/1e6);
04596     lua_settable(state, LUA_GLOBALSINDEX);
04597 
04598     CreateObjectMetaTable(state);
04599     CreateObserverMetaTable(state);
04600     CreateCelestiaMetaTable(state);
04601     CreatePositionMetaTable(state);
04602     CreateVectorMetaTable(state);
04603     CreateRotationMetaTable(state);
04604     CreateFrameMetaTable(state);
04605     CreateCelscriptMetaTable(state);
04606 
04607     // Create the celestia object
04608     lua_pushstring(state, "celestia");
04609     celestia_new(state, appCore);
04610     lua_settable(state, LUA_GLOBALSINDEX);
04611     // add reference to appCore in the registry
04612     lua_pushstring(state, "celestia-appcore");
04613     lua_pushlightuserdata(state, static_cast<void*>(appCore));
04614     lua_settable(state, LUA_REGISTRYINDEX);
04615     // add a reference to the LuaState-object in the registry
04616     lua_pushstring(state, "celestia-luastate");
04617     lua_pushlightuserdata(state, static_cast<void*>(this));
04618     lua_settable(state, LUA_REGISTRYINDEX);
04619 
04620 #if 0
04621     lua_pushstring(state, "dofile");
04622     lua_gettable(state, LUA_GLOBALSINDEX); // function "dofile" on stack
04623     lua_pushstring(state, "luainit.celx"); // parameter
04624     if (lua_pcall(state, 1, 0, 0) != 0) // execute it
04625     {
04626         CelestiaCore::Alerter* alerter = appCore->getAlerter();
04627         // copy string?!
04628         const char* errorMessage = lua_tostring(state, -1);
04629         cout << errorMessage << '\n'; cout.flush();
04630         alerter->fatalError(errorMessage);
04631         return false;
04632     }
04633 #endif
04634 
04635     return true;
04636 }

bool LuaState::isAlive  )  const
 

Definition at line 552 of file celx.cpp.

References alive.

Referenced by tick().

00553 {
00554     return alive;
00555 }

int LuaState::loadScript const std::string  ) 
 

Definition at line 681 of file celx.cpp.

References loadScript().

00682 {
00683 #ifdef HAVE_SSTREAM
00684     istringstream in(s);
00685 #else
00686     istrstream in(s.c_str());
00687 #endif
00688     return loadScript(in, "string");
00689 }

int LuaState::loadScript std::istream &  ,
const std::string streamname
 

Definition at line 659 of file celx.cpp.

References ReadChunkInfo::buf, ReadChunkInfo::bufSize, ReadChunkInfo::in, readStreamChunk(), and state.

Referenced by init(), and loadScript().

00660 {
00661     char buf[4096];
00662     ReadChunkInfo info;
00663     info.buf = buf;
00664     info.bufSize = sizeof(buf);
00665     info.in = &in;
00666 
00667     if (streamname != "string")
00668     {
00669         lua_pushstring(state, "celestia-scriptpath");
00670         lua_pushstring(state, streamname.c_str());
00671         lua_settable(state, LUA_REGISTRYINDEX);
00672     }
00673 
00674     int status = lua_load(state, readStreamChunk, &info, streamname.c_str());
00675     if (status != 0)
00676         cout << "Error loading script: " << lua_tostring(state, -1) << '\n';
00677 
00678     return status;
00679 }

void LuaState::requestIO  ) 
 

Definition at line 852 of file celx.cpp.

References AllErrors, Asking, costate, getAppCore(), CelestiaCore::getConfig(), IOAllowed, IODenied, ioMode, NoIO, CelestiaConfig::scriptSystemAccessPolicy, and state.

Referenced by celestia_requestsystemaccess().

00853 {
00854     // the script requested IO, set the mode
00855     // so we display the warning during tick
00856     // and can request keyboard. We can't do this now
00857     // because the script is still active and could
00858     // disable keyboard again.
00859     if (ioMode == NoIO)
00860     {
00861         CelestiaCore* appCore = getAppCore(state, AllErrors);
00862         string policy = appCore->getConfig()->scriptSystemAccessPolicy;
00863         if (policy == "allow")
00864         {
00865             //lua_iolibopen(costate);
00866             luaopen_io(costate);
00867             ioMode = IOAllowed;
00868         }
00869         else if (policy == "deny")
00870         {
00871             ioMode = IODenied;
00872         }
00873         else
00874         {
00875             ioMode = Asking;
00876         }
00877     }
00878 }

int LuaState::resume  ) 
 

Definition at line 691 of file celx.cpp.

References alerter, alive, Asking, auxresume(), costate, KdeAlerter::fatalError(), CelestiaCore::getAlerter(), getAppCore(), getTime(), ioMode, MaxTimeslice, state, and timeout.

Referenced by tick().

00692 {
00693     assert(costate != NULL);
00694     if (costate == NULL)
00695         return false;
00696 
00697     lua_State* co = lua_tothread(state, -1);
00698     //assert(co == costate); // co can be NULL after error (top stack is errorstring)
00699     if (co != costate)
00700         return false;
00701 
00702     timeout = getTime() + MaxTimeslice;
00703     int nArgs = auxresume(state, co, 0);
00704     if (nArgs < 0)
00705     {
00706         alive = false;
00707 
00708         const char* errorMessage = lua_tostring(state, -1);
00709 
00710         // This is a nasty and hopefully temporary hack . . .  We continue
00711         // to resume the script until we get an error.  The
00712         // 'cannot resume dead coroutine' error appears when there were
00713         // no other errors, and execution terminates normally.  There
00714         // should be a better way to figure out whether the script ended
00715         // normally . . .
00716         if (strcmp(errorMessage, "cannot resume dead coroutine") != 0)
00717         {
00718             cout << "Error: " << errorMessage << '\n';
00719             CelestiaCore* appCore = getAppCore(co);
00720             if (appCore != NULL)
00721             {
00722                 CelestiaCore::Alerter* alerter = appCore->getAlerter();
00723                 alerter->fatalError(errorMessage);
00724             }
00725         }
00726 
00727         return 1; // just the error string
00728     }
00729     else
00730     {
00731         if (ioMode == Asking)
00732         {
00733             // timeout now is used to first only display warning, and 1s
00734             // later allow response to avoid accidental activation
00735             timeout = getTime() + 1.0;
00736         }
00737 
00738         return nArgs; // arguments from yield
00739     }
00740 }

bool LuaState::tick double   ) 
 

Definition at line 763 of file celx.cpp.

References Asking, costate, getAppCore(), CelestiaCore::getRenderer(), Renderer::getRenderFlags(), getState(), CelestiaCore::getTextEnterMode(), getTime(), ioMode, isAlive(), NoErrors, resume(), scriptAwakenTime, Renderer::setRenderFlags(), CelestiaCore::setTextEnterMode(), CelestiaCore::showText(), state, and timeout.

00764 {
00765     // Due to the way CelestiaCore::tick is called (at least for KDE),
00766     // this method may be entered a second time when we show the error-alerter
00767     // Workaround: check if we are alive, return true(!) when we aren't anymore
00768     // this way the script isn't deleted after the second enter, but only
00769     // when we return from the first enter. OMG.
00770     
00771     // better Solution: defer showing the error-alterter to CelestiaCore, using
00772     // getErrorMessage()
00773     if (!isAlive())
00774         return false;
00775     
00776     if (ioMode == Asking)
00777     {
00778         CelestiaCore* appCore = getAppCore(costate, NoErrors);
00779         if (appCore == NULL)
00780         {
00781             cerr << "ERROR: appCore not found\n";
00782             return true;
00783         }
00784         lua_pushstring(state, "celestia-savedrenderflags");
00785         lua_gettable(state, LUA_REGISTRYINDEX);
00786         if (lua_isnil(state, -1))
00787         {
00788             lua_pushstring(state, "celestia-savedrenderflags");
00789             int* savedrenderflags = static_cast<int*>(lua_newuserdata(state, sizeof(int)));
00790             *savedrenderflags = appCore->getRenderer()->getRenderFlags();
00791             lua_settable(state, LUA_REGISTRYINDEX);
00792             appCore->getRenderer()->setRenderFlags(0);
00793         }
00794         // now pop result of gettable
00795         lua_pop(state, 1);
00796 
00797         if (getTime() > timeout)
00798         {
00799             appCore->showText("WARNING:\n\nThis script requests permission to read/write files\n"
00800                               "and execute external programs. Allowing this can be\n"
00801                               "dangerous.\n"
00802                               "Do you trust the script and want to allow this?\n\n"
00803                               "y = yes, ESC = cancel script, any other key = no",
00804                               0, 0,
00805                               -15, 5, 5);
00806             appCore->setTextEnterMode(appCore->getTextEnterMode() | CelestiaCore::KbPassToScript);
00807         }
00808         else
00809         {
00810             appCore->showText("WARNING:\n\nThis script requests permission to read/write files\n"
00811                               "and execute external programs. Allowing this can be\n"
00812                               "dangerous.\n"
00813                               "Do you trust the script and want to allow this?",
00814                               0, 0,
00815                               -15, 5, 5);
00816             appCore->setTextEnterMode(appCore->getTextEnterMode() & ~CelestiaCore::KbPassToScript);
00817         }
00818 
00819         return false;
00820     }
00821 
00822     if (dt == 0 || scriptAwakenTime > getTime())
00823         return false;
00824    
00825     int nArgs = resume();
00826     if (!isAlive())
00827     {
00828         // The script is complete
00829         return true;
00830     }
00831     else
00832     {
00833         // The script has returned control to us, but it is not completed.
00834         lua_State* state = getState();
00835 
00836         // The values on the stack indicate what event will wake up the
00837         // script.  For now, we just support wait()
00838         double delay;
00839         if (nArgs == 1 && lua_isnumber(state, -1))
00840             delay = lua_tonumber(state, -1);
00841         else
00842             delay = 0.0;
00843         scriptAwakenTime = getTime() + delay;
00844 
00845         // Clean up the stack
00846         lua_pop(state, nArgs);
00847         return false;
00848     }
00849 }

bool LuaState::timesliceExpired  ) 
 

Definition at line 509 of file celx.cpp.

References checkTimeslice(), costate, getTime(), and timeout.

Referenced by checkTimeslice().

00510 {
00511     if (timeout < getTime())
00512     {
00513         // timeslice expired, make every instruction (including pcall) fail: 
00514         lua_sethook(costate, checkTimeslice, LUA_MASKCOUNT, 1);
00515         return true;
00516     }
00517     else
00518     {
00519         return false;
00520     }
00521 }


Member Data Documentation

bool LuaState::alive [private]
 

Definition at line 63 of file celx.h.

Referenced by createThread(), isAlive(), and resume().

lua_State* LuaState::costate [private]
 

Definition at line 62 of file celx.h.

Referenced by charEntered(), cleanup(), createThread(), requestIO(), resume(), tick(), timesliceExpired(), and ~LuaState().

IOMode LuaState::ioMode [private]
 

Definition at line 66 of file celx.h.

Referenced by charEntered(), cleanup(), requestIO(), resume(), and tick().

int LuaState::screenshotCount
 

Definition at line 50 of file celx.h.

Referenced by celestia_takescreenshot(), and LuaState().

double LuaState::scriptAwakenTime [private]
 

Definition at line 65 of file celx.h.

Referenced by tick().

lua_State* LuaState::state [private]
 

Definition at line 61 of file celx.h.

Referenced by cleanup(), createThread(), getErrorMessage(), getState(), init(), loadScript(), LuaState(), requestIO(), resume(), tick(), and ~LuaState().

double LuaState::timeout
 

Definition at line 51 of file celx.h.

Referenced by celestia_takescreenshot(), charEntered(), cleanup(), object_preloadtexture(), resume(), tick(), and timesliceExpired().

Timer* LuaState::timer [private]
 

Definition at line 64 of file celx.h.

Referenced by getTime(), LuaState(), and ~LuaState().


The documentation for this class was generated from the following files:
Generated on Sat Jan 14 22:33:26 2006 for Celestia by  doxygen 1.4.1