diff --git a/include/mgba/core/thread.h b/include/mgba/core/thread.h index deadc36c6..72e9de7b5 100644 --- a/include/mgba/core/thread.h +++ b/include/mgba/core/thread.h @@ -11,6 +11,10 @@ CXX_GUARD_START #include +#ifdef ENABLE_SCRIPTING +#include +#include +#endif struct mCoreThread; struct mCore; @@ -39,6 +43,10 @@ struct mCoreThread { void* userData; void (*run)(struct mCoreThread*); +#ifdef ENABLE_SCRIPTING + struct mScriptContext* scriptContext; +#endif + struct mCoreThreadInternal* impl; }; diff --git a/include/mgba/script/context.h b/include/mgba/script/context.h index 0241cbd8a..bb3b98b78 100644 --- a/include/mgba/script/context.h +++ b/include/mgba/script/context.h @@ -36,6 +36,8 @@ struct mScriptEngineContext { struct mScriptContext* context; void (*destroy)(struct mScriptEngineContext*); + bool (*isScript)(struct mScriptEngineContext*, const char* name, struct VFile* vf); + bool (*setGlobal)(struct mScriptEngineContext*, const char* name, struct mScriptValue*); struct mScriptValue* (*getGlobal)(struct mScriptEngineContext*, const char* name); @@ -48,10 +50,15 @@ void mScriptContextInit(struct mScriptContext*); void mScriptContextDeinit(struct mScriptContext*); struct mScriptEngineContext* mScriptContextRegisterEngine(struct mScriptContext*, struct mScriptEngine2*); +void mScriptContextRegisterEngines(struct mScriptContext*); void mScriptContextSetGlobal(struct mScriptContext*, const char* key, struct mScriptValue* value); void mScriptContextRemoveGlobal(struct mScriptContext*, const char* key); +struct VFile; +bool mScriptContextLoadVF(struct mScriptContext*, const char* name, struct VFile* vf); +bool mScriptContextLoadFile(struct mScriptContext*, const char* path); + bool mScriptInvoke(const struct mScriptValue* fn, struct mScriptFrame* frame); CXX_GUARD_END diff --git a/src/core/thread.c b/src/core/thread.c index 801cf5bb6..2375aea4c 100644 --- a/src/core/thread.c +++ b/src/core/thread.c @@ -219,6 +219,12 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) { mLogFilterLoad(threadContext->logger.d.filter, &core->config); } +#ifdef ENABLE_SCRIPTING + if (threadContext->scriptContext) { + mScriptContextAttachCore(threadContext->scriptContext, core); + } +#endif + mCoreThreadRewindParamsChanged(threadContext); if (threadContext->startCallback) { threadContext->startCallback(threadContext); @@ -337,6 +343,11 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) { if (threadContext->cleanCallback) { threadContext->cleanCallback(threadContext); } +#ifdef ENABLE_SCRIPTING + if (threadContext->scriptContext) { + mScriptContextDetachCore(threadContext->scriptContext); + } +#endif core->clearCoreCallbacks(core); if (threadContext->logger.d.filter == &filter) { diff --git a/src/script/context.c b/src/script/context.c index 9cc8b09b0..44d0fdca6 100644 --- a/src/script/context.c +++ b/src/script/context.c @@ -4,12 +4,21 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include +#ifdef USE_LUA +#include +#endif struct mScriptKVPair { const char* key; struct mScriptValue* value; }; +struct mScriptFileInfo { + const char* name; + struct VFile* vf; + struct mScriptEngineContext* context; +}; + static void _engineContextDestroy(void* ctx) { struct mScriptEngineContext* context = ctx; context->destroy(context); @@ -28,6 +37,18 @@ static void _contextRemoveGlobal(const char* key, void* value, void* user) { context->setGlobal(context, user, NULL); } +static void _contextFindForFile(const char* key, void* value, void* user) { + UNUSED(key); + struct mScriptFileInfo* info = user; + struct mScriptEngineContext* context = value; + if (info->context) { + return; + } + if (context->isScript(context, info->name, info->vf)) { + info->context = context; + } +} + void mScriptContextInit(struct mScriptContext* context) { HashTableInit(&context->rootScope, 0, (void (*)(void*)) mScriptValueDeref); HashTableInit(&context->engines, 0, _engineContextDestroy); @@ -46,6 +67,13 @@ struct mScriptEngineContext* mScriptContextRegisterEngine(struct mScriptContext* return ectx; } +void mScriptContextRegisterEngines(struct mScriptContext* context) { + UNUSED(context); +#ifdef USE_LUA + mScriptContextRegisterEngine(context, mSCRIPT_ENGINE_LUA); +#endif +} + void mScriptContextSetGlobal(struct mScriptContext* context, const char* key, struct mScriptValue* value) { mScriptValueRef(value); HashTableInsert(&context->rootScope, key, value); @@ -65,6 +93,29 @@ void mScriptContextRemoveGlobal(struct mScriptContext* context, const char* key) HashTableRemove(&context->rootScope, key); } +bool mScriptContextLoadVF(struct mScriptContext* context, const char* name, struct VFile* vf) { + struct mScriptFileInfo info = { + .name = name, + .vf = vf, + .context = NULL + }; + HashTableEnumerate(&context->engines, _contextFindForFile, &info); + if (!info.context) { + return false; + } + return info.context->load(info.context, vf, NULL); +} + +bool mScriptContextLoadFile(struct mScriptContext* context, const char* path) { + struct VFile* vf = VFileOpen(path, O_RDONLY); + if (!vf) { + return false; + } + bool ret = mScriptContextLoadVF(context, path, vf); + vf->close(vf); + return ret; +} + bool mScriptInvoke(const struct mScriptValue* val, struct mScriptFrame* frame) { if (val->type->base != mSCRIPT_TYPE_FUNCTION) { return false; diff --git a/src/script/engines/lua.c b/src/script/engines/lua.c index ae34066e7..c002dafc6 100644 --- a/src/script/engines/lua.c +++ b/src/script/engines/lua.c @@ -13,6 +13,7 @@ static struct mScriptEngineContext* _luaCreate(struct mScriptEngine2*, struct mScriptContext*); static void _luaDestroy(struct mScriptEngineContext*); +static bool _luaIsScript(struct mScriptEngineContext*, const char*, struct VFile*); static struct mScriptValue* _luaGetGlobal(struct mScriptEngineContext*, const char* name); static bool _luaSetGlobal(struct mScriptEngineContext*, const char* name, struct mScriptValue*); static bool _luaLoad(struct mScriptEngineContext*, struct VFile*, const char** error); @@ -99,6 +100,7 @@ struct mScriptEngineContext* _luaCreate(struct mScriptEngine2* engine, struct mS luaContext->d = (struct mScriptEngineContext) { .context = context, .destroy = _luaDestroy, + .isScript = _luaIsScript, .getGlobal = _luaGetGlobal, .setGlobal = _luaSetGlobal, .load = _luaLoad, @@ -134,6 +136,15 @@ void _luaDestroy(struct mScriptEngineContext* ctx) { free(luaContext); } +bool _luaIsScript(struct mScriptEngineContext* ctx, const char* name, struct VFile* vf) { + UNUSED(ctx); + UNUSED(vf); + if (!name) { + return false; + } + return endswith(name, ".lua"); +} + struct mScriptValue* _luaGetGlobal(struct mScriptEngineContext* ctx, const char* name) { struct mScriptEngineContextLua* luaContext = (struct mScriptEngineContextLua*) ctx; lua_getglobal(luaContext->lua, name);