gooブログはじめました!

写真付きで日記や趣味を書くならgooブログ

AngelScript管理クラス更新

2010-01-17 17:55:30 | angelscript
timeSetEventをangelscriptで使う前に、CAngelScriptMgrに結構無駄なソースがあったので整理する。

CAngelScriptMgr.h

CAngelScriptMgr.cpp

<form>

CAngelScriptMgr.h

<textarea rows="8" cols="75" readonly="readonly"> #ifndef _CANGELSCRIPT_MGR_H_ #define _CANGELSCRIPT_MGR_H_ #include <windows.h> #include <iostream> // cout #include <assert.h> // assert() #include <angelscript.h> #include "../angel_incluce_lib/angel_include/add_on/scriptstring/scriptstring.h" #include "../angel_incluce_lib/angel_include/add_on/contextmgr/contextmgr.h" #include "../angel_incluce_lib/angel_include/add_on/scriptstdstring/scriptstdstring.h" #include "../angel_incluce_lib/angel_include/add_on/scriptbuilder/scriptbuilder.h" #include "../angel_incluce_lib/angel_include/add_on/scriptany/scriptany.h" //\angel_incluce_lib\angel_include\add_on #include <crtdbg.h> #include <conio.h> // kbhit(), getch() #include "CMoveObject.h" using namespace std; class CAngelMap { public: //! angelscriptが管理しているfuncID,angelscriptに登録するときのchar* chfuncIDとは別 int iAngelFuncID; //! angelscriptに登録するときのchar *funIDのこと string strFuncName; }; class CAngelScriptMgr { public: CAngelScriptMgr(); ~CAngelScriptMgr(); //! m_mapAngelfunc(map)を取得 /*! \return int m_mapAngelfunc(map)に登録してある関数の数 */ int GetAngelFuncNum(); //! angelscriptのタイムアウト時間の設定 /*! \param imsec angelscriptのタイムアウト時間(ミリ秒単位で設定 1秒だったら1000を指定する) \return void */ void SetScriptTimeOut( DWORD dwMsec ); //! angelscriptのタイムアウト時間の取得 /*! \return DWORD angelscriptのタイムアウト時間 */ DWORD GetScriptTimeOut(); //! angelscriptの関数実行する /*! \param index ファンクション番号 (CAngelScriptMgrのAngelFuncListに登録してある番号) \param fret 戻り値 (この関数はangelscriptの戻り値floatの結果を受け取る) \return int 0:成功(angelscript内の関数呼び出し成功)  -1:失敗 */ int Excute( int index, float &fret); //! angelscriptの関数実行する /*! \param index ファンクション番号 (CAngelScriptMgrのAngelFuncListに登録してある番号) \param dret 戻り値 (この関数はangelscriptの戻り値doubleの結果を受け取る) \return int 0:成功(angelscript内の関数呼び出し成功)  -1:失敗 */ int Excute( int index, double &dret); //! angelscriptの関数実行する /*! \param index ファンクション番号 (CAngelScriptMgrのAngelFuncListに登録してある番号) \param *ret angelscript内で自由に変更するためのパラメータ。c++,angelscriptどちらからでも更新可能。 \return int 0:成功(angelscript内の関数呼び出し成功)  -1:失敗 */ int Excute( int index,CMoveObject *ret); private: int LoadScript( char *ScriptName ); //以下はクラス関数として登録できない。globalにする必要がある。 //void MessageCallback2( const asSMessageInfo *msg, void *param ); //void print2( string &msg ); //void print2( int num ); //void print2( asUINT num ); //void print2( float num ); //void print2( double num ); //! c++,angelscript両方で使用できる変数を登録。(C++側ではグローバル変数にする) /*! \return int 0:成功  -1:失敗 */ int RegisterProperty(); //! c++,angelscript両方で使用できるクラスを登録。(angelscriptに渡す引数はここで登録する) /*! \return int 0:成功  -1:失敗 */ int RegisterMyClass(); //! angelscriptのエンジン初期化 /*! \return int 0:成功  -1:失敗 */ int InitializeAngelEngine(); //! angelscriptのビルド /*! \return int 0:成功  -1:失敗 */ int BuildAngelScript(); //! angelscriptのビルドcheck /*! \return int 0:成功  -1:失敗 */ int CheckBuild(); //! angelscriptがc++の関数を登録したときにできるfuncidをm_mapAngelfunc(マップ)に登録しておく。 //! c++からangelscriptを実行するときにfuncidをすぐ取り出すため /*! \return int 0:成功  -1:失敗 */ int SetAngelFuncMap(); //! angelscriptに失敗したときのangelscriptが出力されるメッセージ /*! \return int 0:成功  -1:失敗 */ void DisplayErrorMsg( int err ); //! angelscriptの関数実行前処理 /*! \param index ファンクション番号 (CAngelScriptMgrのAngelFuncListに登録してある番号) \return int 0:成功(angelscript内の関数呼び出し成功)  -1:失敗 */ int Before_Excute( int index ); //! angelscript内の関数の実行に失敗したときの共通エラーメッセージを表示する。 /*! 表示されるのはangelscriptの名前、モジュール名、ライン番号等 \return void */ void CAngelScriptMgr::CommonErrorMsg(); private: //! angelscript engine asIScriptEngine *m_pasengine; //! angelscript module asIScriptModule *m_pasmod; //! angelscript context asIScriptContext *m_pasctx; //! angelscript contextmgr CContextMgr *m_pcontextMgr; //! angelscript,c++の情報管理のためのマップ map<int,CAngelMap> m_mapAngelfunc; //! angelscriptの実行待ち時間(この時間がすぎればabort()をなげてangelscriptの関数は実行しない default=1000) DWORD m_dwTimeOut; }; #endif //_CANGELSCRIPT_MGR_H_ </textarea>

</form>

<form>

CAngelScriptMgr.cpp

<textarea rows="8" cols="75" readonly="readonly"> #include "CAngelScriptMgr.h" #include "CMoveObject.h" #include <windows.h> // timeGetTime() #include "LogUtility.h" #define OK 0 #define NG -1 //angelscript,c++両方で使用できるグローバル変数を定義する float g_fdata = 0; float g_fx = 0; float g_fy = 0; int g_LogLevel = LOG_WARN; //scriptひとつひとつ読み込み、ビルドに成功した場合bsuccessをtrueに設定しておく struct _ScriptList { char *scriptname; //angel script名 bool bsuccess; //scrptnameのangelscriptがビルドできたか }ScriptList[] = { { "resource/script/test11.as", false }, { "resource/script/test12.as",false }, }; #define ANGEL_SCRIPT_NUM (sizeof(ScriptList)/sizeof(ScriptList[0]) ) //angle scritptないで使用するmethodがふえたらここに追加 //別々のscript(ファイル)にある関数でもここにはすべて記述する。 chDescriptionにはどのファイル名で定義してあるかも記述しておく //asIScriptContextのmethodでangelscriptから戻り値を受け取ることができるのは以下の型のみ //chFuncIDは戻り値の型が違う場合c++側で再コンパイルが必要 //GetReturnAddress(),GetReturnByte(),GetReturnDouble() //GetReturnDWord(),GetReturnFloat(),GetReturnObject() //GetReturnQWord(),GetReturnWord() struct _AngelFuncList { int iID; //index、for,while 用途 char *chFuncID; //angle scriptのasIScriptContext->Prepare(funcId); のfuncIdに指定する文字列 char *chDescription; //angle script用の関数説明用 }AngelFuncList[] = { {0,"float test1()","print test file:test11.as"}, {1,"CMoveObject getscriptreturn()"," file:test11.as"}, {2,"CMoveObject getscriptreturn2( CMoveObject cmove )"," file:test11.as"}, {3,"float test2()"," file:test2.as"}, {4,"float TestCorutine()","corotine test file::test3.as"}, //{3,"int test4()",""}, }; //anglesciprtで使用する関数の数 #define ANGEL_FUNC_NUM (sizeof(AngelFuncList)/sizeof(AngelFuncList[0]) ) //このクラスのコンストラクタで、angelscriptの関数類を使えるようにしておく CAngelScriptMgr::CAngelScriptMgr() : m_pasengine( NULL ),m_pasmod( NULL ),m_pasctx( NULL ), m_pcontextMgr( NULL ), m_dwTimeOut( 1000 ) { int iRet = OK; m_mapAngelfunc.clear(); //angelscriptのengine初期化 iRet = InitializeAngelEngine(); assert( iRet >= 0 ); //c++,angelscript両方で使用する変数登録 iRet = RegisterProperty(); assert( iRet >= 0 ); //angelscriptで使用したいc++のクラスを登録 iRet = RegisterMyClass(); assert( iRet >= 0 ); //angelscriptをひとつひとつ読み込みビルドできるかcheck iRet = CheckBuild(); assert( iRet >= 0 ); SetAngelFuncMap(); } CAngelScriptMgr::~CAngelScriptMgr() { if( m_pasctx != NULL ) { m_pasctx->Release(); } if( m_pasengine != NULL ) { m_pasengine->Release(); } if( m_pcontextMgr != NULL ) { delete m_pcontextMgr; m_pcontextMgr = NULL; } if( m_pasmod != NULL ) { m_pasmod = NULL; } m_mapAngelfunc.clear(); } void CAngelScriptMgr::CommonErrorMsg() { int ifuncid = m_pasctx->GetExceptionFunction(); asIScriptFunction *func = m_pasengine->GetFunctionDescriptorById( ifuncid ); cout << "func: " << func->GetDeclaration() << endl; cout << "modl: " << func->GetModuleName() << endl; cout << "sect: " << func->GetScriptSectionName() << endl; cout << "line: " << m_pasctx->GetExceptionLineNumber() << endl; cout << "desc: " << m_pasctx->GetExceptionString() << endl; PUT_LOG( g_LogLevel,"func:%sn",func->GetDeclaration() ); PUT_LOG( g_LogLevel,"modl:%s\n", func->GetModuleName() ); PUT_LOG( g_LogLevel,"sect:%s\n", func->GetScriptSectionName() ); PUT_LOG( g_LogLevel,"line:%d\n", m_pasctx->GetExceptionLineNumber() ); PUT_LOG( g_LogLevel,"line:%d\n", m_pasctx->GetExceptionString() ); func->Release(); } void CAngelScriptMgr::DisplayErrorMsg( int err ) { int ifuncid = m_pasctx->GetExceptionFunction(); asIScriptFunction *func = m_pasengine->GetFunctionDescriptorById( ifuncid ); //エラー内容によってメッセージを分ける。coutはコマンドライン用、PUT_LOGはOutputDebugPrintを使い //どちらでもメッセージが出力されるようにする switch( err ) { case asEXECUTION_ABORTED: cout << "The script was aborted before it could finish. Probably it timed out." << endl; PUT_LOG( g_LogLevel,"The script was aborted before it could finish. Probably it timed out.n" ); break; case asEXECUTION_EXCEPTION: cout << "The script ended with an exception." << endl; PUT_LOG( g_LogLevel,"The script ended with an exception.n" ); //共通エラーメッセージ CommonErrorMsg(); break; case asEXECUTION_ERROR: cout << "The script ended with an exception error." << endl; PUT_LOG( g_LogLevel,"The script ended with an exception error.n" ); //共通エラーメッセージ CommonErrorMsg(); default: cout << "Unknown error " << endl; PUT_LOG( g_LogLevel,"Unknown error.n" ); break; } } //angelscript内の関数に時間がかかる場合はabortを投げて例外終了させる void LineCallback2( asIScriptContext *ctx, DWORD *timeOut ) { // If the time out is reached we abort the script if( *timeOut < timeGetTime() ) { ctx->Abort(); } // It would also be possible to only suspend the script, // instead of aborting it. That would allow the application // to resume the execution where it left of at a later // time, by simply calling Execute() again. } //angelscript前にタイムアウト時間やmapにあるangelscriptのfuncIDを取得する。 int CAngelScriptMgr::Before_Excute( int index ) { int iRet = OK; CAngelMap mapdata; //int ifuncid = m_mapAngelfunc[string(chFunc)]; mapdata = m_mapAngelfunc[index]; // Create our context, prepare it, and then execute m_pasctx = m_pasengine->CreateContext(); //anglescriptの関数を実行するための準備 m_pasctx->Prepare( mapdata.iAngelFuncID ); // We don't want to allow the script to hang the application, e.g. with an // infinite loop, so we'll use the line callback function to set a timeout // that will abort the script after a certain time. Before executing the // script the timeOut variable will be set to the time when the script must // stop executing. DWORD timeOut; iRet = m_pasctx->SetLineCallback( asFUNCTION( LineCallback2 ), &timeOut, asCALL_CDECL ); if( iRet < 0 ) { cout << "Failed to set the line callback function." << endl; PUT_LOG( g_LogLevel,"Failed to set the line callback function.n" ); return NG; } // Set the timeout before executing the function. Give the function 1 sec // to return before we'll abort it. // timeoutは1秒(1000ミリ秒)にしておく。SetScriptTimeOutで指定されていればその値 timeOut = timeGetTime() + m_dwTimeOut; return iRet; } //この関数では戻り値float,引数なしの関数を実行する //indexにしていするのはAngelFuncList[]のインデックス値 int CAngelScriptMgr::Excute( int index, float &fret ) { int iRet = OK; iRet = Before_Excute( index ); if( iRet != 0 ) { return NG; } //angel scriptの実行 iRet = m_pasctx->Execute(); //angelscript内の関数に実行した場合、エラー表示を行う if( iRet != asEXECUTION_FINISHED ) { DisplayErrorMsg( iRet ); } else { fret = m_pasctx->GetReturnFloat(); } return iRet; } //この関数では戻り値float,引数なしの関数を実行する //indexにしていするのはAngelFuncList[]のインデックス値 int CAngelScriptMgr::Excute( int index,double &dret ) { int iRet = OK; iRet = Before_Excute( index ); if( iRet != 0 ) { return NG; } //angel scriptの実行 iRet = m_pasctx->Execute(); //angelscript内の関数に実行した場合、エラー表示を行う if( iRet != asEXECUTION_FINISHED ) { DisplayErrorMsg( iRet ); } else { dret = m_pasctx->GetReturnDouble(); } return iRet; } //angelscritの引数をセットする int CAngelScriptMgr::Excute( int index,CMoveObject *ret ) { int iRet = OK; iRet = Before_Excute( index ); if( iRet != 0 ) { return NG; } //angelscriptに引数をセット,複数の引数にする場合クラスにまとめた方がよさそう iRet = m_pasctx->SetArgObject( 0,(void*)ret ); if( iRet != 0 ) { return NG; } //angel scriptの実行 iRet = m_pasctx->Execute(); //angelscript内の関数に実行した場合、エラー表示を行う if( iRet != asEXECUTION_FINISHED ) { DisplayErrorMsg( iRet ); } else { *ret = *(CMoveObject*)(void*)m_pasctx->GetReturnObject(); } return iRet; } int CAngelScriptMgr::GetAngelFuncNum() { return m_mapAngelfunc.size(); } int CAngelScriptMgr::SetAngelFuncMap() { int iRet = OK; int iangelfuncnum = 0; for( int i = 0; i < ANGEL_SCRIPT_NUM; i++) { //buildに成功したangelscriptのみ読み込み if( ScriptList[i].bsuccess == true ) { LoadScript( ScriptList[i].scriptname ); iangelfuncnum++; } } //使用できるangelscriptのみモジュールとしてbuild BuildAngelScript(); for( int i = 0; i < ANGEL_FUNC_NUM; i++) { //anglescript内でのc++の関数のfuncidを取得しておく int ifuncid = m_pasmod->GetFunctionIdByDecl( AngelFuncList[i].chFuncID ); if( ifuncid < 0 ) { printf("The script must have the function %s. Please add it and try again.n",AngelFuncList[i].chFuncID ); PUT_LOG( g_LogLevel,"The script must have the function %s. Please add it and try again.n",AngelFuncList[i].chFuncID ); continue; } CAngelMap angeldata; angeldata.iAngelFuncID = ifuncid; angeldata.strFuncName = string( AngelFuncList[i].chFuncID ); m_mapAngelfunc[i] = angeldata; } return iRet; } int CAngelScriptMgr::CheckBuild() { int iRet = OK; for( int i = 0; i < ANGEL_SCRIPT_NUM; i++) { iRet = LoadScript( ScriptList[i].scriptname ); if( iRet == OK ) { iRet = BuildAngelScript(); if( iRet == OK ) { //angelscriptのビルドに成功したらtrueに設定しておく ScriptList[i].bsuccess = true; } else { printf("faile build script name %sn",ScriptList[i].scriptname ); PUT_LOG( g_LogLevel,"faile build script name %sn",ScriptList[i].scriptname ); } } } return iRet; } int CAngelScriptMgr::LoadScript( char *ScriptName ) { int iRet = OK; FILE *f = fopen(ScriptName, "rb"); if ( f == NULL ) { printf(" file not foundn"); PUT_LOG( g_LogLevel,"file not foundn"); return NG; } fseek(f, 0, SEEK_END); //file sizeを取得する int len = ftell( f ); fseek( f, 0, SEEK_SET ); std::string script; script.resize(len); size_t c = fread( &script[0], len, 1, f ); fclose(f); //scriptのファイル名でセクションを登録する。 iRet = m_pasmod->AddScriptSection( ScriptName, &script[0], len ); return iRet; } //この関数はangelscriptひとつひとつチェックした後 //buildに成功したすべてのangelscriptをモジュールとして再Buildする。 int CAngelScriptMgr::BuildAngelScript() { int iRet = OK; iRet = m_pasmod->Build(); if( iRet < 0 ) { printf("angel script build failedn" ); PUT_LOG( g_LogLevel,"angel script build failedn"); return NG; } return iRet; } void MessageCallback2( const asSMessageInfo *msg, void *param ) { const char *type = "ERR "; if( msg->type == asMSGTYPE_WARNING ) { type = "WARN"; } else if( msg->type == asMSGTYPE_INFORMATION ) { type = "INFO"; } printf("%s (%d, %d) : %s : %s\n", msg->section, msg->row, msg->col, type, msg->message); PUT_LOG( g_LogLevel,"%s (%d, %d) : %s : %s\n", msg->section, msg->row, msg->col, type, msg->message ); } void print2( string &msg ) { std::cout << msg << std::endl; } void print2( int num ) { std::cout << num << std::endl; } void print2( asUINT num ) { std::cout << num << std::endl; } void print2( float num ) { std::cout << num << std::endl; } void print2( double num ) { std::cout << num << std::endl; } int CAngelScriptMgr::RegisterProperty() { int iRet = OK; iRet = m_pasengine->RegisterGlobalProperty("int g_fdata", &g_fdata); assert( iRet >= 0 ); iRet = m_pasengine->RegisterGlobalProperty("int g_fx", &g_fx); assert( iRet >= 0 ); iRet = m_pasengine->RegisterGlobalProperty("int g_fy", &g_fy); assert( iRet >= 0 ); return iRet; } int CAngelScriptMgr::RegisterMyClass() { //CMoveObject.hにあるクラスを登録 int iRet = OK; iRet = m_pasengine->RegisterObjectType("CMoveObject", sizeof(CMoveObject), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS); assert( iRet >= 0 ); iRet = m_pasengine->RegisterObjectProperty("CMoveObject", "float fx", offsetof(CMoveObject, fx)); assert( iRet >= 0 ); iRet = m_pasengine->RegisterObjectProperty("CMoveObject", "float fy", offsetof(CMoveObject, fy)); assert( iRet >= 0 ); iRet = m_pasengine->RegisterObjectProperty("CMoveObject", "float fwidth", offsetof(CMoveObject, fwidth)); assert( iRet >= 0 ); iRet = m_pasengine->RegisterObjectProperty("CMoveObject", "float fheight", offsetof(CMoveObject, fheight)); assert( iRet >= 0 ); iRet = m_pasengine->RegisterObjectProperty("CMoveObject", "float fhitradius", offsetof(CMoveObject, fhitradius)); assert( iRet >= 0 ); iRet = m_pasengine->RegisterObjectProperty("CMoveObject", "float facceleration", offsetof(CMoveObject, facceleration)); assert( iRet >= 0 ); iRet = m_pasengine->RegisterObjectProperty("CMoveObject", "float fdirection", offsetof(CMoveObject, fdirection)); assert( iRet >= 0 ); iRet = m_pasengine->RegisterObjectProperty("CMoveObject", "float fspeed", offsetof(CMoveObject, fspeed)); assert( iRet >= 0 ); iRet = m_pasengine->RegisterObjectProperty("CMoveObject", "float fangle", offsetof(CMoveObject, fangle)); assert( iRet >= 0 ); iRet = m_pasengine->RegisterObjectProperty("CMoveObject", "float finterval", offsetof(CMoveObject, finterval)); assert( iRet >= 0 ); iRet = m_pasengine->RegisterObjectProperty("CMoveObject", "float flevel", offsetof(CMoveObject, flevel)); assert( iRet >= 0 ); iRet = m_pasengine->RegisterObjectProperty("CMoveObject", "float fkind", offsetof(CMoveObject, fkind)); assert( iRet >= 0 ); iRet = m_pasengine->RegisterObjectProperty("CMoveObject", "float fcolor", offsetof(CMoveObject, fcolor)); assert( iRet >= 0 ); iRet = m_pasengine->RegisterObjectProperty("CMoveObject", "float falpha", offsetof(CMoveObject, falpha)); assert( iRet >= 0 ); iRet = m_pasengine->RegisterObjectProperty("CMoveObject", "float falive", offsetof(CMoveObject, falive)); assert( iRet >= 0 ); iRet = m_pasengine->RegisterObjectProperty("CMoveObject", "float fscale", offsetof(CMoveObject, fscale)); assert( iRet >= 0 ); return iRet; } int CAngelScriptMgr::InitializeAngelEngine() { PUT_LOG( g_LogLevel,"start\n" ); int iRet = OK; // Create the script engine m_pasengine = asCreateScriptEngine(ANGELSCRIPT_VERSION); //SHIFT-JIS対応 m_pasengine->SetEngineProperty(asEP_SCRIPT_SCANNER ,0); // Set the message callback to receive information on errors in human readable form. // It's recommended to do this right after the creation of the engine, because if // some registration fails the engine may send valuable information to the message // stream. iRet = m_pasengine->SetMessageCallback( asFUNCTION( MessageCallback2 ), 0, asCALL_CDECL ); assert( iRet >= 0 ); if( iRet < 0 ) { printf("failed Message Callbackn" ); PUT_LOG( g_LogLevel,"failed Message Callbackn" ); return NG; } m_pasmod = m_pasengine->GetModule( 0, asGM_ALWAYS_CREATE ); if( iRet < 0 ) { printf("failed GetModulen" ); PUT_LOG( g_LogLevel,"failed GetModulen" ); return NG; } // AngelScript doesn't have a built-in string type, as there is no definite standard // string type for C++ applications. Every developer is free to register it's own string type. // The SDK do however provide a standard add-on for registering a string type, so it's not // necessary to implement the registration yourself if you don't want to. RegisterStdString( m_pasengine ); //anglescript側でprint(string),print(型)でそれぞれの値を表示できるようにする。print系は複数 //GUIやwindow関連では以下のprint関数は使えないため無意味 iRet = m_pasengine->RegisterGlobalFunction( "void print(const string &in)", asFUNCTIONPR(print2, (string &in), void), asCALL_CDECL ); assert( iRet >= 0 ); iRet = m_pasengine->RegisterGlobalFunction( "void print(int)", asFUNCTIONPR(print2, (int), void), asCALL_CDECL ); assert( iRet >= 0 ); iRet = m_pasengine->RegisterGlobalFunction( "void print(float)", asFUNCTIONPR(print2, (float), void), asCALL_CDECL ); assert( iRet >= 0 ); iRet = m_pasengine->RegisterGlobalFunction( "void print(uint)", asFUNCTIONPR(print2, (asUINT), void), asCALL_CDECL ); assert( iRet >= 0 ); iRet = m_pasengine->RegisterGlobalFunction( "void print(double)", asFUNCTIONPR(print2, (double), void), asCALL_CDECL ); assert( iRet >= 0 ); RegisterScriptAny( m_pasengine ); // Add the support for co-routines m_pcontextMgr = new CContextMgr(); m_pcontextMgr->RegisterCoRoutineSupport( m_pasengine ); return iRet; } void CAngelScriptMgr::SetScriptTimeOut( DWORD dwMsec ) { //angelscriptの実行タイムアウト設定 m_dwTimeOut = dwMsec; } DWORD CAngelScriptMgr::GetScriptTimeOut() { //angelscriptのタイムアウト時間 return m_dwTimeOut; } </textarea>

</form>

コメントを投稿