/* orxonox - the future of 3D-vertical-scrollers Copyright (C) 2004 orx This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. ### File Specific: main-programmer: Silvan Nellen co-programmer: Benjamin Grauer */ #include "script.h" #include "script_class.h" #include "luaincl.h" #include "debug.h" #include "util/loading/resource_manager.h" #include "loading/load_param.h" #include "parser/tinyxml/tinyxml.h" ObjectListDefinition(Script); CREATE_SCRIPTABLE_CLASS(Script, addMethod("addObject", Executor2(&Script::addObject)) ->addMethod("registerClass", Executor1(&Script::registerClass)) ->addMethod("selectFunction", Executor2ret(&Script::selectFunction)) ->addMethod("executeFunction", Executor0ret(&Script::executeFunction)) ); Script::Script(const TiXmlElement* root) { this->registerObject(this, Script::_objectList); returnCount = argumentCount = 0; luaState = lua_open(); luaopen_base(luaState); luaopen_table(luaState); luaopen_io(luaState); luaopen_string(luaState); luaopen_math(luaState); luaopen_debug(luaState); if (root != NULL) this->loadParams(root); } Script::Script(const std::string& filename) { this->registerObject(this, Script::_objectList); returnCount = argumentCount = 0; luaState = lua_open(); luaopen_base(luaState); luaopen_table(luaState); luaopen_io(luaState); luaopen_string(luaState); luaopen_math(luaState); luaopen_debug(luaState); this->loadFile(filename); } Script::~Script() { lua_setgcthreshold(luaState, 0); // collected garbage lua_close(luaState); } void Script::loadParams(const TiXmlElement* root) { //printf(("Loading params for %p \n",this); BaseObject::loadParams(root); LOAD_PARAM_START_CYCLE(root, object); { LoadParam_CYCLE(object, "object", this, Script, addObject) .describe("The name of an object that is needed by a script"); } LOAD_PARAM_END_CYCLE(object); LoadParam(root, "file", this, Script, loadFileNoRet) .describe("the fileName of the script, that should be loaded into this world") .defaultValues(""); } bool Script::loadFile(const std::string& filename) { std::string filedest(ResourceManager::getInstance()->getDataDir()); filedest += "scripts/" + filename; this->addThisScript(); this->registerStandartClasses(); if(currentFile.length() != 0) { printf("SCRIPT %s : ERROR: Could not load %s because an other file is already loaded: %s\n",currentFile.c_str(),filename.c_str(), currentFile.c_str()); return false; } int error = luaL_loadfile (luaState, filedest.c_str()); if(error == 0) { currentFile = filename; error = lua_pcall(luaState, 0, 0, 0); if(error == 0) { return true; } else { printf("SCRIPT %s : ERROR: while loading file %s: \n",currentFile.c_str(),filename.c_str()); reportError(error); } } else { printf("SCRIPT %s : ERROR: while loading file %s: \n",currentFile.c_str(),filename.c_str()); reportError(error); } return false; } void Script::addObject(const std::string& className, const std::string& objectName) { //printf(("Script %s: I am about to add %s of class %s\n",this->getName(),objectName.c_str(),className.c_str()); ScriptClass* scriptClass = ScriptClass::objectList().getObject(className); // printf(("The script class for %s is at %p \n",className.c_str(),scriptClass); WorldObject tmpObj; if (scriptClass != NULL) { tmpObj.type = className; if( !classIsRegistered(className) ) { scriptClass->registerClass(this); } BaseObject* object = ObjectListBase::getBaseObject(className, objectName); // printf(("%s is at %p \n",objectName.c_str(),object); if (object != NULL && !objectIsAdded(objectName)) { scriptClass->insertObject(this, object, false); tmpObj.name = objectName; registeredObjects.push_back(tmpObj); } } } bool Script::executeFile() { PRINTF(2)("script.executeFile is not implemented yet\n"); /*if(currentFile.length() != 0) { int error = lua_pcall(luaState, 0, 0, 0); if( error == 0) return true; else { reportError(error); return false; } }*/ return false; } bool Script::selectFunction(const std::string& functionName, int retCount) { if(returnCount == 0 && currentFunction.length() == 0) //no return values left on the stack and no other function selected { lua_pushlstring(luaState, functionName.c_str(), functionName.size() ); lua_gettable(luaState, LUA_GLOBALSINDEX); if(lua_isfunction( luaState , -1)) { returnCount = retCount; argumentCount = 0; currentFunction = functionName; return true; } else return false; } else printf("SCRIPT %s : ERROR: There is an other function active ( %s ) or there are unremoved return values on the stack. Please remove them first.\n",currentFile.c_str(),currentFunction.c_str()); return false; } //return number of returned values bool Script::executeFunction() { if(currentFunction.length() != 0 ) { int error = lua_pcall(luaState, argumentCount, returnCount,0); if(error != 0) { PRINTF(1)("Script '%s' : Failed to execute function '%s': \n",currentFile.c_str(),currentFunction.c_str()); reportError(error); //clean up currentFunction.assign(""); argumentCount = returnCount = 0; return false; } else { currentFunction.assign("");//a function gets unusable after beeing called for the first time argumentCount = 0; return true; } } else PRINTF(1)("SCRIPT '%s' : no function selected.\n",currentFile.c_str()); return false; } //overload this function to add different types bool Script::pushParam(int param, std::string& toFunction) { if(currentFunction == toFunction) { lua_pushnumber(luaState, (lua_Number) param); argumentCount++; return true; } else { printf("SCRIPT %s : ERROR: Couldn't add parameter because the wrong function is selected: %s instead of %s\n",currentFile.c_str(), currentFunction.c_str(), toFunction.c_str()); return false; } } bool Script::pushParam(float param, std::string& toFunction) { if(currentFunction.compare(toFunction) == 0) { lua_pushnumber(luaState,(lua_Number) param); argumentCount++; return true; } else { printf("SCRIPT %s : ERROR: Couldn't add parameter because the wrong function is selected: %s instead of %s\n",currentFile.c_str(), currentFunction.c_str(), toFunction.c_str()); return false; } } bool Script::pushParam(double param, std::string& toFunction) { if(currentFunction.compare(toFunction) == 0) { lua_pushnumber(luaState,(lua_Number) param); argumentCount++; return true; } else { printf("SCRIPT %s : ERROR: Couldn't add parameter because the wrong function is selected: %s instead of %s\n",currentFile.c_str(), currentFunction.c_str(), toFunction.c_str()); return false; } } int Script::getReturnedInt() { int returnValue = 0; if(returnCount > 0) { if(lua_isnumber(luaState, -1*returnCount)) { returnValue = (int)lua_tonumber(luaState, -1*returnCount); lua_remove(luaState,-1*returnCount); returnCount--; } } return returnValue; } bool Script::getReturnedBool() { bool returnValue = false; if(returnCount > 0) { if(lua_isboolean(luaState, -1*returnCount)) { returnValue = (bool)lua_toboolean(luaState, -1*returnCount); lua_remove(luaState,-1*returnCount); returnCount--; } else printf("SCRIPT %s : ERROR: Trying to retreive non bolean value\n",this->currentFile.c_str()); } return returnValue; } float Script::getReturnedFloat() { float returnValue = 0.0f; if(returnCount > 0) { if(lua_isnumber(luaState, -1*returnCount)) { returnValue = (float)lua_tonumber(luaState, -1*returnCount); lua_remove(luaState,-1*returnCount); returnCount--; } } return returnValue; } void Script::getReturnedString(std::string& string) { const char* returnValue = ""; if(returnCount > 0) { if(lua_isstring(luaState, -1*returnCount)) { returnValue = lua_tostring(luaState, -1*returnCount); lua_remove(luaState,-1*returnCount); returnCount--; } } string.assign(returnValue); } void Script::addThisScript() { ScriptClass* scriptClass = ScriptClass::objectList().getObject("Script"); if (scriptClass != NULL) { scriptClass->registerClass(this); scriptClass->insertObject(this, this,"thisscript", false); } } int Script::reportError(int error) { if(error != 0) { const char *msg = lua_tostring(luaState, -1); if (msg == NULL) msg = "(error with no message)\n"; printf("ERROR: %s\n", msg); lua_pop(luaState, 1); } return error; } bool Script::registerStandartClasses() { bool success = false; //this->registerClass(std::string("Vector")); this->registerClass("ScriptTrigger"); // this->registerClass("AttractorMine"); return success; } void Script::registerClass( const std::string& className) { ScriptClass* scriptClass = ScriptClass::objectList().getObject(className); //printf(("The script class for %s is at %p \n",className.c_str(),scriptClass); WorldObject tmpObj; if (scriptClass != NULL) { tmpObj.type = className; if( !classIsRegistered(className) ) { static_cast(scriptClass)->registerClass(this); tmpObj.name = ""; registeredObjects.push_back(tmpObj); return; } } } bool Script::classIsRegistered(const std::string& type) { for(std::list::const_iterator it = registeredObjects.begin(); it != registeredObjects.end(); it++ ) { if( (*it).type == type) { return true; } } return false; } bool Script::objectIsAdded(const std::string& name) { for(std::list::const_iterator it = registeredObjects.begin(); it != registeredObjects.end(); it++ ) { if( (*it).name == name) { return true; } } return false; }