Scripting : add ability to use delegates for timeouts (enabling complex timeouts)

This commit is contained in:
Marianne Gagnon 2016-01-02 20:34:39 -05:00
parent bd9f435190
commit 15b35b76ac
3 changed files with 167 additions and 8 deletions

View File

@ -172,6 +172,99 @@ namespace Scripting
//-----------------------------------------------------------------------------
void ScriptEngine::runDelegate(asIScriptFunction* delegate)
{
asIScriptContext *ctx = m_engine->CreateContext();
if (ctx == NULL)
{
Log::error("Scripting", "runMethod: Failed to create the context.");
//m_engine->Release();
return;
}
int r = ctx->Prepare(delegate);
if (r < 0)
{
Log::error("Scripting", "runMethod: Failed to prepare the context.");
ctx->Release();
return;
}
// Execute the function
r = ctx->Execute();
if (r != asEXECUTION_FINISHED)
{
// The execution didn't finish as we had planned. Determine why.
if (r == asEXECUTION_ABORTED)
{
Log::error("Scripting", "The script was aborted before it could finish. Probably it timed out.");
}
else if (r == asEXECUTION_EXCEPTION)
{
Log::error("Scripting", "The script ended with an exception : (line %i) %s",
ctx->GetExceptionLineNumber(),
ctx->GetExceptionString());
}
else
{
Log::error("Scripting", "The script ended for some unforeseen reason (%i)", r);
}
}
ctx->Release();
}
//-----------------------------------------------------------------------------
/*
void ScriptEngine::runMethod(asIScriptObject* obj, std::string methodName)
{
asIObjectType* type = obj->GetObjectType();
asIScriptFunction* method = type->GetMethodByName(methodName.c_str());
if (method == NULL)
Log::error("Scripting", ("runMethod: object does not implement method " + methodName).c_str());
asIScriptContext *ctx = m_engine->CreateContext();
if (ctx == NULL)
{
Log::error("Scripting", "runMethod: Failed to create the context.");
//m_engine->Release();
return;
}
int r = ctx->Prepare(method);
if (r < 0)
{
Log::error("Scripting", "runMethod: Failed to prepare the context.");
ctx->Release();
return;
}
// Execute the function
r = ctx->Execute();
if (r != asEXECUTION_FINISHED)
{
// The execution didn't finish as we had planned. Determine why.
if (r == asEXECUTION_ABORTED)
{
Log::error("Scripting", "The script was aborted before it could finish. Probably it timed out.");
}
else if (r == asEXECUTION_EXCEPTION)
{
Log::error("Scripting", "The script ended with an exception.");
}
else
{
Log::error("Scripting", "The script ended for some unforeseen reason (%i)", r);
}
}
ctx->Release();
}
*/
//-----------------------------------------------------------------------------
/** runs the specified script
* \param string scriptName = name of script to run
*/
@ -415,9 +508,36 @@ namespace Scripting
//-----------------------------------------------------------------------------
PendingTimeout::PendingTimeout(double time, asIScriptFunction* callback_delegate)
: PendingTimeout()
{
m_time = time;
m_callback_delegate = callback_delegate;
}
//-----------------------------------------------------------------------------
PendingTimeout::~PendingTimeout()
{
if (m_callback_delegate != NULL)
{
asIScriptEngine* engine = World::getWorld()->getScriptEngine()->getEngine();
m_callback_delegate->Release();
}
}
//-----------------------------------------------------------------------------
void ScriptEngine::addPendingTimeout(double time, const std::string& callback_name)
{
m_pending_timeouts.push_back(PendingTimeout(time, callback_name));
m_pending_timeouts.push_back(new PendingTimeout(time, callback_name));
}
//-----------------------------------------------------------------------------
void ScriptEngine::addPendingTimeout(double time, asIScriptFunction* delegate)
{
m_pending_timeouts.push_back(new PendingTimeout(time, delegate));
}
//-----------------------------------------------------------------------------
@ -430,8 +550,16 @@ namespace Scripting
curr.m_time -= dt;
if (curr.m_time <= 0.0)
{
runFunction(true, "void " + curr.m_callback_name + "()");
m_pending_timeouts.erase(m_pending_timeouts.begin() + i);
if (curr.m_callback_delegate != NULL)
{
runDelegate(curr.m_callback_delegate);
}
else
{
runFunction(true, "void " + curr.m_callback_name + "()");
}
m_pending_timeouts.erase(i);
}
}
}

View File

@ -23,21 +23,38 @@
#include <angelscript.h>
#include <functional>
#include "scriptengine/script_utils.hpp"
#include "utils/ptr_vector.hpp"
class TrackObjectPresentation;
namespace Scripting
{
/** Represents a scripting function to execute after a given time */
struct PendingTimeout
struct PendingTimeout : NoCopy
{
double m_time;
std::string m_callback_name;
PendingTimeout(double time, const std::string& callback_name)
/** We have two callback types: a string containing the name of the function
* to call (simple callback) or a "TimeoutBase" object (advanced callback)
*/
std::string m_callback_name;
asIScriptFunction* m_callback_delegate;
PendingTimeout()
{
m_callback_delegate = NULL;
}
PendingTimeout(double time, const std::string& callback_name) : PendingTimeout()
{
m_time = time;
m_callback_name = callback_name;
}
PendingTimeout(double time, asIScriptFunction* callback_delegate);
~PendingTimeout();
};
class ScriptEngine
@ -53,6 +70,7 @@ namespace Scripting
void runFunction(bool warn_if_not_found, std::string function_name,
std::function<void(asIScriptContext*)> callback,
std::function<void(asIScriptContext*)> get_return_value);
void runDelegate(asIScriptFunction* delegate_fn);
void evalScript(std::string script_fragment);
void cleanupCache();
@ -60,12 +78,15 @@ namespace Scripting
bool compileLoadedScripts();
void addPendingTimeout(double time, const std::string& callback_name);
void addPendingTimeout(double time, asIScriptFunction* delegate_fn);
void update(double dt);
asIScriptEngine* getEngine() { return m_engine; }
private:
asIScriptEngine *m_engine;
std::map<std::string, asIScriptFunction*> m_functions_cache;
std::vector<PendingTimeout> m_pending_timeouts;
PtrVector<PendingTimeout> m_pending_timeouts;
void configureEngine(asIScriptEngine *engine);
}; // class ScriptEngine

View File

@ -16,7 +16,7 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "script_track.hpp"
#include "script_utils.hpp"
#include "animations/three_d_animation.hpp"
#include "input/device_manager.hpp"
@ -132,6 +132,12 @@ namespace Scripting
World::getWorld()->getScriptEngine()->addPendingTimeout(delay, *callback_name);
}
/** Call a method from the given object after the specified delay */
void setTimeoutDelegate(asIScriptFunction* obj, float delay)
{
World::getWorld()->getScriptEngine()->addPendingTimeout(delay, obj);
}
/** Log to the console */
void logInfo(std::string* log)
{
@ -180,6 +186,7 @@ namespace Scripting
{
int r; // of type asERetCodes
engine->SetDefaultNamespace("Utils");
r = engine->RegisterGlobalFunction("string insertValues(const string &in, const string &in)", asFUNCTION(proxy_insertValues1), asCALL_CDECL); assert(r >= 0);
r = engine->RegisterGlobalFunction("string insertValues(const string &in, const string &in, const string &in)", asFUNCTION(proxy_insertValues2), asCALL_CDECL); assert(r >= 0);
r = engine->RegisterGlobalFunction("string insertValues(const string &in, const string &in, const string &in, const string &in)", asFUNCTION(proxy_insertValues3), asCALL_CDECL); assert(r >= 0);
@ -190,6 +197,9 @@ namespace Scripting
r = engine->RegisterGlobalFunction("int randomInt(int, int)", asFUNCTION(randomInt), asCALL_CDECL); assert(r >= 0);
r = engine->RegisterGlobalFunction("float randomFloat(int, int)", asFUNCTION(randomFloat), asCALL_CDECL); assert(r >= 0);
r = engine->RegisterGlobalFunction("void setTimeout(const string &in, float)", asFUNCTION(setTimeout), asCALL_CDECL); assert(r >= 0);
r = engine->RegisterFuncdef("void TimeoutCallback()"); assert(r >= 0);
r = engine->RegisterGlobalFunction("void setTimeoutDelegate(TimeoutCallback@, float)", asFUNCTION(setTimeoutDelegate), asCALL_CDECL); assert(r >= 0);
r = engine->RegisterGlobalFunction("void logInfo(const string &in)", asFUNCTION(logInfo), asCALL_CDECL); assert(r >= 0);
r = engine->RegisterGlobalFunction("void logWarning(const string &in)", asFUNCTION(logWarning), asCALL_CDECL); assert(r >= 0);