00001 /*************************************************************************** 00002 * * 00003 * (c) Art Tevs, MPI Informatik Saarbruecken * 00004 * mailto: <tevs@mpi-sb.mpg.de> * 00005 * * 00006 * This program is free software; you can redistribute it and/or modify * 00007 * it under the terms of the GNU General Public License as published by * 00008 * the Free Software Foundation; either version 2 of the License, or * 00009 * (at your option) any later version. * 00010 * * 00011 ***************************************************************************/ 00012 00013 00014 #ifndef _NR_SCRIPT_INTERFACE_RESOURCE__H_ 00015 #define _NR_SCRIPT_INTERFACE_RESOURCE__H_ 00016 00017 00018 //---------------------------------------------------------------------------------- 00019 // Includes 00020 //---------------------------------------------------------------------------------- 00021 #include "Prerequisities.h" 00022 #include "Resource.h" 00023 #include "ITask.h" 00024 00025 /*! 00026 * \defgroup script Engine Scripting 00027 * 00028 * Scripting is our form of data driven design of our engine. Scripts 00029 * are also resources that are loaded through specified loader. Scripts are 00030 * used to program the engine from the outside of the source code. You are 00031 * able to program the engine in the runtime by executing the scripts through 00032 * a console provided by the engine. To understand what the scripts are good for 00033 * use appropriate literature from the internet. 00034 * 00035 * Our engine is designed to be very expandable and generic, so we are not use 00036 * specific kind of script language. nrEngine does only provide an interface 00037 * for a script classes that are implemented by plugins. The main idea of such 00038 * an interface is to create a binding between the script language and the engine. 00039 * 00040 * The plugins classes have to know how to bind the specific script language with 00041 * the script interface of the engine. The console will acquire a script object to 00042 * be used for the console scripting. This script object is provided by the plugins 00043 * so it uses that language which is implemented in the plugin. 00044 * 00045 * If there no plugins providing a scripting language so the default one is used. 00046 * The default scripting language does not support anything except of some function calls. 00047 * This very simple languge can be used to load another script language or 00048 * to setup some properties of the engine. 00049 * 00050 * Because there is thousands of scripting languages outside and they can be bounded 00051 * on different ways we do not provide any bounding routine. If you using any scripting 00052 * language in your application, than you have to bind your code with the script code by your 00053 * self. Mostly this is done through metaprogramming or through preproccessing 00054 * routines on the scripting language. Therefor providing such an interface through 00055 * plugins for the engine seems not to be managable. Therefor all default functions used 00056 * in our engine are registered by the script engine. By adding or deleting any 00057 * script function there will be an event. Your glue-code has to catch this event to 00058 * take care off registering or derigistering this function in your scripting language. 00059 * 00060 * For example you want to use lua in your application. You use some 3rd party tools 00061 * like tolua which does generate a c++ code form pkg files. This newly generated files 00062 * can be used to provide your c++ classes in lua. Now to provide the engine's scripting 00063 * functions, which are registered by the ScriptEngine you have to write a wrapper which will 00064 * call ScriptEngine::call() method if appropriate function was called from lua. 00065 * 00066 * Probalby in later version we can provide some binding to you (loadtime plugins), which 00067 * does provide this functionality. But at now there is no other way to do this. 00068 **/ 00069 00070 namespace nrEngine{ 00071 00072 00073 //! Script interface for any kind of script languages 00074 /** 00075 * This is an interface for any kind of scripting language provided by the plugins. 00076 * This interface is used to executed strings typed in the console or readed from 00077 * the scripting files. 00078 * 00079 * We also define each script as an task in the kernel. So the script will be 00080 * updated in each tick by the kernel and will be unloaded from the task queue as soon 00081 * as the script ends his execution. Using of scripts as a task has the advantage, that 00082 * we are able to run scripts with a certain priority/order number. So the script_Task can 00083 * run before certain application task or after them. 00084 * 00085 * Each script can not only be executed, but if specify any functions or routines, 00086 * so this routines could be explicitely called. You can also specify arguments 00087 * for such a routine. Therefor the IScript interface does only store 00088 * the arguments and their type as a string. Derived class should read this 00089 * and pass the parameters in the right way. If a derived script language 00090 * does not support any arguments or function calling so just ignore them. 00091 * Passed parameters will be automaticaly removed from the waiting list as 00092 * soon as the function from the script will be called. 00093 * 00094 * @see IResource, ITask 00095 * \ingroup script 00096 **/ 00097 class _NRExport IScript : public IResource, public ITask{ 00098 public: 00099 //! You can also push a list of arguments to the function directly 00100 typedef std::list<std::pair<std::string, std::string> > ArgumentList; 00101 00102 /** 00103 * Returns the content of the script file 00104 **/ 00105 NR_FORCEINLINE const std::string& getContent() const { return mContent; } 00106 00107 /** 00108 * Load a script from string. The given string should contain 00109 * the script in the appropriate language, so it can be executed. 00110 * 00111 * @param str String containing the script 00112 * @return either OK or: 00113 * - SCRIPT_PARSE_ERROR 00114 **/ 00115 virtual Result loadFromString(const std::string& str) = 0; 00116 00117 /** 00118 * Get short description of the last error. 00119 **/ 00120 std::string popLastError(); 00121 00122 /** 00123 * Execute the script. The script will be executed completely, before 00124 * go back to the system run. Execution is done by adding the script to 00125 * the kernel's pipeline. In the next cycle the script will be then executed. 00126 * 00127 * @param runOnce If true, so the script method run() will be called only 00128 * once. If you specify false, so run() will be called in each 00129 * kernel cycle. 00130 * 00131 * NOTE: If you want to execute script immidiately, use forceExecute() instead 00132 **/ 00133 Result execute(bool runOnce = true); 00134 00135 /** 00136 * Force starting the script. Script will be added to the kernel 00137 * and started immeiately after that, by calling the run() method. 00138 * Afer that the script will be updated in each cycle if not otherwise 00139 * specified. 00140 * 00141 * @see execute() 00142 **/ 00143 Result forceExecute(bool runOnce = true); 00144 00145 /** 00146 * By calling the execute() method you will execute the whole script completely. 00147 * This is usefull if you do not interested in the results of the scripts, but 00148 * in its handling. However if you wish to call a certain function from the script 00149 * (only if function calling is supported by the scripting language), so you 00150 * have to use this method. 00151 * 00152 * Here a certain function from the script will be called. The result of this function 00153 * will be given back in a generic type ScriptResult. You have to know how 00154 * to interpret the results given back by the script. If any error occurs the 00155 * error message will be logged and an exception will be thrown. Catch 00156 * the exception to handle the errors. 00157 * 00158 * @param funcName Name of the function to call 00159 * 00160 * @return result from the script execution converted into generic 00161 * ScriptResult object. 00162 * 00163 * NOTE: To pass parameters to function use pushArgument() 00164 **/ 00165 ScriptResult call(const std::string& funcName); 00166 00167 /** 00168 * User application can also specify certain arguments for functions 00169 * in the script. The derived class implementing specific script 00170 * language must read out this values before starting the script. 00171 * The derived class should also know how to pass them to the script 00172 * language and how to parse them. If a script does not support function 00173 * calling or argument binding, so this values can be ignored. 00174 * 00175 * @param funcName Name of the function/routine in the script for which one 00176 * the parameters are specified 00177 * @param type String containing the name of the type of the argument 00178 * @param value String containing the value of the argument. 00179 * 00180 * @return Number of arguments currently stored for the given function including 00181 * the new argument. 00182 * 00183 * NOTE: Push arguments from the first to the last. 00184 **/ 00185 uint32 pushArgument(const std::string& funcName, const std::string& type, const std::string& value); 00186 00187 /** 00188 * Same as pushArgument() but set argument from the list. Already pushed 00189 * arguments will be removed ! 00190 **/ 00191 uint32 setArguments(const std::string& funcName, const ArgumentList& args); 00192 00193 /** 00194 * Derived class should use this function to pop the first parameter 00195 * from the list. The argument type and the value will be stored in 00196 * the given variables. The function does return the number of 00197 * remaining parameters. If function returns 0, so no parameters are 00198 * available. 00199 * 00200 * @param funcName Name of the function for which the arguments are retrieved 00201 * @param type Here the type of the argument will be stored 00202 * @param value Here the value of the argument will be stored 00203 * 00204 * @return Number of remaining arguments for the function. If the resulting 00205 * value is -1, so no parameters for the function exists 00206 * 00207 * NOTE: The arguments are returned from the first to the last 00208 **/ 00209 int32 popArgument(const std::string& funcName, std::string& type, std::string& value); 00210 00211 protected: 00212 00213 /** 00214 * Run the script. This method must be overriden by the derived classes. 00215 * run will be called by the execution of the script. However you can not 00216 * be sure if the script executed completely or only stepwise by this method, 00217 * this depends only on the implementation. Read appropriate documentation of 00218 * script language implementation. 00219 **/ 00220 virtual Result run() = 0; 00221 00222 /** 00223 * Derived class can overload this method if a implemented script language 00224 * does support function calling. Default behaviour of this method 00225 * is not to call any function or to execute a script. Overload 00226 * this if you wish to have another behaviour. 00227 * 00228 * @param funcName name of the function to call 00229 * @param result Store here the result of a call of a function 00230 * @return OK if no error during the execution occurs or an error code. 00231 * If any error code will be returned so an exception will 00232 * be thrown. 00233 **/ 00234 virtual Result callfunc(const std::string& funcName, ScriptResult& result); 00235 00236 /** 00237 * If any error occurs stor here the error messages. 00238 * The base class will deliver them to the user. Also the base 00239 * class does implement error message stack, so returned messages are 00240 * automaticaly removed from the message stack. 00241 **/ 00242 void pushErrorMessage(const std::string& msg); 00243 00244 /** 00245 * Initialize the script interface 00246 * Specify also the script type name, so we know of which 00247 * type is the given script 00248 **/ 00249 IScript(const std::string&); 00250 00251 /** 00252 * Virtual destructor 00253 **/ 00254 virtual ~IScript(); 00255 00256 /** 00257 * Run one step from the script. This method will be automaticaly 00258 * called from the engine's kernel. 00259 **/ 00260 Result updateTask(); 00261 00262 /** 00263 * Method is called from kernel, when script starts its execution 00264 **/ 00265 Result onStartTask(); 00266 00267 //! Here we store the whole script as a string 00268 std::string mContent; 00269 00270 /** 00271 * Bypass the IResource::unloadRes() function, so that derived 00272 * class can overload them 00273 **/ 00274 virtual Result unloadResource() {return OK;} 00275 virtual Result reloadResource(PropertyList* params) {return OK;} 00276 00277 //! Check if script should only run once 00278 bool shouldRunOnce() const { return mbRunOnce; } 00279 00280 //! Should the script run only once (no loop) 00281 void setRunOnce(bool b) { mbRunOnce = b; } 00282 00283 /** 00284 * This method will be called to check from base class to 00285 * check if run completes. If derived class returns false, 00286 * so script will be removed from the kernel 00287 **/ 00288 virtual bool hasCommands() = 0; 00289 00290 /** 00291 * This method will be called if a script is gonna be executed. 00292 * Override this method to make some initializations for example. 00293 **/ 00294 virtual void onStartScript() {}; 00295 00296 /** 00297 * Call this method to manually specify, that a script is 00298 * loaded and can be executed. The method should be called 00299 * from loadFromString() method by derived classes 00300 **/ 00301 void notifyLoaded(); 00302 00303 private: 00304 00305 //! Should this script run once 00306 bool mbRunOnce; 00307 00308 //! Store here error messages 00309 std::list<std::string> mErrorMsg; 00310 00311 typedef std::map<std::string, ArgumentList> ArgumentDatabase; 00312 00313 //! Here we store the arguments for the script 00314 ArgumentDatabase mArguments; 00315 00316 }; 00317 00318 00319 //! Empty script object that just do nothing(idle). 00320 /** 00321 * Empty script objects do nothing. They idle. 00322 * \ingroup script 00323 **/ 00324 class _NRExport EmptyScript : public IScript{ 00325 public: 00326 00327 //! Constructor does not call anything 00328 EmptyScript(const std::string& typeName); 00329 00330 //! Release used memory 00331 ~EmptyScript(); 00332 00333 //! Loading an empty script from file does not affect anything 00334 Result loadFromString(const std::string& str); 00335 00336 //! Executing of empty script does return immideately 00337 Result run(); 00338 private: 00339 bool hasCommands() { return false; } 00340 }; 00341 00342 }; 00343 00344 #endif