#include #include #include // strstr() #include #include #include #include "../../../add_on/scriptstdstring/scriptstdstring.h" #include "../../../add_on/scripthelper/scripthelper.h" #include "../../../add_on/scriptarray/scriptarray.h" using namespace std; // Function prototypes void PrintHelp(); void ExecString(asIScriptEngine *engine, string &arg); void AddVariable(asIScriptEngine *engine, string &arg); void DeleteVariable(asIScriptEngine *engine, string &arg); void AddFunction(asIScriptEngine *engine, string &arg); void DeleteFunction(asIScriptEngine *engine, string &arg); void ListVariables(asIScriptEngine *engine); void ListFunctions(asIScriptEngine *engine); void ConfigureEngine(asIScriptEngine *engine); void print(const string &s); void grab(int); void grab(asUINT); void grab(bool); void grab(float); void grab(double); void grab(const string&); void grab(void); // Some global variables that the script can access float g_gravity; asUINT p_health; asUINT r_fov; bool r_shadow; string p_name = "player"; int main(int argc, char **argv) { // Create the script engine asIScriptEngine *engine = asCreateScriptEngine(); if( engine == 0 ) { cout << "Failed to create script engine." << endl; return -1; } // Configure the script engine with all the functions, // and variables that the script should be able to use. ConfigureEngine(engine); // Print some useful information and start the input loop cout << "Sample console using AngelScript " << asGetLibraryVersion() << " to perform scripted tasks." << endl; cout << "Type 'help' for more information." << endl; // TODO: Allow multiple lines per command by ending each line with a backslash. for(;;) { string input; input.resize(256); string cmd, arg; cout << "> "; cin.getline(&input[0], 256); // Trim unused characters input.resize(strlen(input.c_str())); size_t pos; if( (pos = input.find(" ")) != string::npos ) { cmd = input.substr(0, pos); arg = input.substr(pos+1); } else { cmd = input; arg = ""; } // Interpret the command if( cmd == "exec" ) ExecString(engine, arg); else if( cmd == "addfunc" ) AddFunction(engine, arg); else if( cmd == "delfunc" ) DeleteFunction(engine, arg); else if( cmd == "addvar" ) AddVariable(engine, arg); else if( cmd == "delvar" ) DeleteVariable(engine, arg); else if( cmd == "help" ) PrintHelp(); else if( cmd == "listfuncs" ) ListFunctions(engine); else if( cmd == "listvars" ) ListVariables(engine); else if( cmd == "quit" ) break; else cout << "Unknown command." << endl; } // Shut down the engine engine->ShutDownAndRelease(); return 0; } void PrintHelp() { cout << "Commands:" << endl; cout << " addfunc [decl] - adds a user function" << endl; cout << " addvar [decl] - adds a user variable" << endl; cout << " delfunc [name] - removes a user function" << endl; cout << " delvar [name] - removes a user variable" << endl; cout << " exec [script] - executes script statement and prints the result" << endl; cout << " help - this command" << endl; cout << " listfuncs - list functions" << endl; cout << " listvars - list variables" << endl; cout << " quit - end application" << endl; } void print(const string &s) { cout << s << endl; } void MessageCallback(const asSMessageInfo *msg, void *param) { const char *type = "ERR "; if( msg->type == asMSGTYPE_WARNING ) type = "WARN"; else if( msg->type == asMSGTYPE_INFORMATION ) type = "INFO"; cout << msg->section << " (" << msg->row << ", " << msg->col << ") : " << type << " : " << msg->message << endl; } void ConfigureEngine(asIScriptEngine *engine) { int r; // Tell the engine to output any error messages to printf engine->SetMessageCallback(asFUNCTION(MessageCallback), 0, asCALL_CDECL); // Register the script string type // Look at the implementation for this function for more information // on how to register a custom string type, and other object types. RegisterStdString(engine); // Register the script array type RegisterScriptArray(engine, false); // Register the global variables r = engine->RegisterGlobalProperty("float g_gravity", &g_gravity); assert( r >= 0 ); r = engine->RegisterGlobalProperty("uint p_health", &p_health); assert( r >= 0 ); r = engine->RegisterGlobalProperty("uint r_fov", &r_fov); assert( r >= 0 ); r = engine->RegisterGlobalProperty("bool r_shadow", &r_shadow); assert( r >= 0 ); r = engine->RegisterGlobalProperty("string p_name", &p_name); assert( r >= 0 ); // Register some useful functions r = engine->RegisterGlobalFunction("float sin(float)", asFUNCTION(sinf), asCALL_CDECL); assert( r >= 0 ); r = engine->RegisterGlobalFunction("float cos(float)", asFUNCTION(cosf), asCALL_CDECL); assert( r >= 0 ); r = engine->RegisterGlobalFunction("void print(const string &in)", asFUNCTION(print), asCALL_CDECL); assert( r >= 0 ); // Register special function with overloads to catch any type. // This is used by the exec command to output the resulting value from the statement. r = engine->RegisterGlobalFunction("void _grab(bool)", asFUNCTIONPR(grab, (bool), void), asCALL_CDECL); assert( r >= 0 ); r = engine->RegisterGlobalFunction("void _grab(int)", asFUNCTIONPR(grab, (int), void), asCALL_CDECL); assert( r >= 0 ); r = engine->RegisterGlobalFunction("void _grab(uint)", asFUNCTIONPR(grab, (asUINT), void), asCALL_CDECL); assert( r >= 0 ); r = engine->RegisterGlobalFunction("void _grab(float)", asFUNCTIONPR(grab, (float), void), asCALL_CDECL); assert( r >= 0 ); r = engine->RegisterGlobalFunction("void _grab(double)", asFUNCTIONPR(grab, (double), void), asCALL_CDECL); assert( r >= 0 ); r = engine->RegisterGlobalFunction("void _grab()", asFUNCTIONPR(grab, (void), void), asCALL_CDECL); assert( r >= 0 ); r = engine->RegisterGlobalFunction("void _grab(const string &in)", asFUNCTIONPR(grab, (const string&), void), asCALL_CDECL); assert( r >= 0 ); // Do not output anything else to printf engine->ClearMessageCallback(); } void ExecString(asIScriptEngine *engine, string &arg) { string script; // Wrap the expression in with a call to _grab, which allow us to print the resulting value script = "_grab(" + arg + ")"; // TODO: Add a time out to the script, so that never ending scripts doesn't freeze the application int r = ExecuteString(engine, script.c_str(), engine->GetModule("console")); if( r < 0 ) cout << "Invalid script statement. " << endl; else if( r == asEXECUTION_EXCEPTION ) cout << "A script exception was raised." << endl; } void AddVariable(asIScriptEngine *engine, string &arg) { asIScriptModule *mod = engine->GetModule("console", asGM_CREATE_IF_NOT_EXISTS); // Add a semi-colon to end the statement (if not already there) if( arg.length() > 0 && arg[arg.length()-1] != ';' ) arg += ";"; int r = mod->CompileGlobalVar("addvar", arg.c_str(), 0); if( r < 0 ) { // TODO: Add better description of error (invalid declaration, name conflict, etc) cout << "Failed to add variable. " << endl; } else cout << "Variable added. " << endl; } void DeleteVariable(asIScriptEngine *engine, string &arg) { asIScriptModule *mod = engine->GetModule("console"); if( mod == 0 || mod->GetGlobalVarCount() == 0 ) { cout << "No variables have been added. " << endl; return; } // trim the string to find the variable name size_t p1 = arg.find_first_not_of(" \n\r\t"); if( p1 != string::npos ) arg = arg.substr(p1, -1); size_t p2 = arg.find_last_not_of(" \n\r\t"); if( p2 != string::npos ) arg = arg.substr(0, p2+1); int index = mod->GetGlobalVarIndexByName(arg.c_str()); if( index >= 0 ) { mod->RemoveGlobalVar(index); cout << "Variable removed. " << endl; } else cout << "No such variable. " << endl; } void AddFunction(asIScriptEngine *engine, string &arg) { asIScriptModule *mod = engine->GetModule("console", asGM_CREATE_IF_NOT_EXISTS); asIScriptFunction *func = 0; int r = mod->CompileFunction("addfunc", arg.c_str(), 0, asCOMP_ADD_TO_MODULE, &func); if( r < 0 ) { // TODO: Add better description of error (invalid declaration, name conflict, etc) cout << "Failed to add function. " << endl; } else { // The script engine supports function overloads, but to simplify the // console we'll disallow multiple functions with the same name. // We know the function was added, so if GetFunctionByName() fails it is // because there already was another function with the same name. if( mod->GetFunctionByName(func->GetName()) == 0 ) { mod->RemoveFunction(func); cout << "Another function with that name already exists." << endl; } else cout << "Function added. " << endl; } // We must release the function object if( func ) func->Release(); } void DeleteFunction(asIScriptEngine *engine, string &arg) { asIScriptModule *mod = engine->GetModule("console"); if( mod == 0 || mod->GetFunctionCount() == 0 ) { cout << "No functions have been added. " << endl; return; } // trim the string to find the variable name size_t p1 = arg.find_first_not_of(" \n\r\t"); if( p1 != string::npos ) arg = arg.substr(p1, -1); size_t p2 = arg.find_last_not_of(" \n\r\t"); if( p2 != string::npos ) arg = arg.substr(0, p2+1); asIScriptFunction *func = mod->GetFunctionByName(arg.c_str()); if( func ) { mod->RemoveFunction(func); cout << "Function removed. " << endl; } else cout << "No such function. " << endl; // Since functions can be recursive, we'll call the garbage // collector to make sure the object is really freed engine->GarbageCollect(); } void ListVariables(asIScriptEngine *engine) { asUINT n; // List the application registered variables cout << "Application variables:" << endl; for( n = 0; n < (asUINT)engine->GetGlobalPropertyCount(); n++ ) { const char *name; int typeId; bool isConst; engine->GetGlobalPropertyByIndex(n, &name, 0, &typeId, &isConst); string decl = isConst ? " const " : " "; decl += engine->GetTypeDeclaration(typeId); decl += " "; decl += name; cout << decl << endl; } // List the user variables in the module asIScriptModule *mod = engine->GetModule("console"); if( mod ) { cout << endl; cout << "User variables:" << endl; for( n = 0; n < (asUINT)mod->GetGlobalVarCount(); n++ ) { cout << " " << mod->GetGlobalVarDeclaration(n) << endl; } } } void ListFunctions(asIScriptEngine *engine) { asUINT n; // List the application registered functions cout << "Application functions:" << endl; for( n = 0; n < (asUINT)engine->GetGlobalFunctionCount(); n++ ) { asIScriptFunction *func = engine->GetGlobalFunctionByIndex(n); // Skip the functions that start with _ as these are not meant to be called explicitly by the user if( func->GetName()[0] != '_' ) cout << " " << func->GetDeclaration() << endl; } // List the user functions in the module asIScriptModule *mod = engine->GetModule("console"); if( mod ) { cout << endl; cout << "User functions:" << endl; for( n = 0; n < (asUINT)mod->GetFunctionCount(); n++ ) { asIScriptFunction *func = mod->GetFunctionByIndex(n); cout << " " << func->GetDeclaration() << endl; } } } void grab(int v) { cout << v << endl; } void grab(asUINT v) { cout << v << endl; } void grab(bool v) { cout << boolalpha << v << endl; } void grab(float v) { cout << v << endl; } void grab(double v) { cout << v << endl; } void grab(const string &v) { cout << v << endl; } void grab() { // There is no value }