mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-27 05:32:45 +00:00
381 lines
9.3 KiB
C++
381 lines
9.3 KiB
C++
#define FORBIDDEN_SYMBOL_EXCEPTION_setjmp
|
|
#define FORBIDDEN_SYMBOL_EXCEPTION_longjmp
|
|
|
|
#include "engines/grim/lua/ltask.h"
|
|
#include "engines/grim/lua/lapi.h"
|
|
#include "engines/grim/lua/lauxlib.h"
|
|
#include "engines/grim/lua/lmem.h"
|
|
#include "engines/grim/lua/ldo.h"
|
|
#include "engines/grim/lua/lvm.h"
|
|
#include "engines/grim/grim.h"
|
|
|
|
#include "common/textconsole.h"
|
|
|
|
namespace Grim {
|
|
|
|
void lua_taskinit(lua_Task *task, lua_Task *next, StkId tbase, int results) {
|
|
task->executed = false;
|
|
task->next = next;
|
|
task->initBase = tbase;
|
|
task->initResults = results;
|
|
}
|
|
|
|
void lua_taskresume(lua_Task *task, Closure *closure, TProtoFunc *protofunc, StkId tbase) {
|
|
task->cl = closure;
|
|
task->tf = protofunc;
|
|
task->base = tbase;
|
|
task->pc = task->tf->code;
|
|
task->consts = task->tf->consts;
|
|
task->S = &lua_state->stack;
|
|
}
|
|
|
|
void start_script() {
|
|
lua_Object paramObj = lua_getparam(1);
|
|
lua_Type type = paramObj == LUA_NOOBJECT ? LUA_T_NIL : ttype(Address(paramObj));
|
|
|
|
if (paramObj == LUA_NOOBJECT || (type != LUA_T_CPROTO && type != LUA_T_PROTO)) {
|
|
return;
|
|
}
|
|
|
|
LState *state = luaM_new(LState);
|
|
lua_stateinit(state);
|
|
|
|
state->next = lua_state->next;
|
|
state->prev = lua_state;
|
|
if (state->next)
|
|
state->next->prev = state;
|
|
lua_state->next = state;
|
|
|
|
state->taskFunc.ttype = type;
|
|
state->taskFunc.value = Address(paramObj)->value;
|
|
|
|
int l = 2;
|
|
for (lua_Object object = lua_getparam(l++); object != LUA_NOOBJECT; object = lua_getparam(l++)) {
|
|
TObject ptr;
|
|
ptr.ttype = Address(object)->ttype;
|
|
ptr.value = Address(object)->value;
|
|
LState *tmpState = lua_state;
|
|
lua_state = state;
|
|
luaA_pushobject(&ptr);
|
|
lua_state = tmpState;
|
|
}
|
|
|
|
ttype(lua_state->stack.top) = LUA_T_TASK;
|
|
nvalue(lua_state->stack.top) = (float)state->id;
|
|
incr_top;
|
|
}
|
|
|
|
void next_script() {
|
|
lua_Object paramObj = lua_getparam(1);
|
|
lua_Type type = paramObj == LUA_NOOBJECT ? LUA_T_NIL : ttype(Address(paramObj));
|
|
|
|
if (paramObj == LUA_NOOBJECT || (type != LUA_T_TASK && type != LUA_T_NIL))
|
|
lua_error("Bad argument to next_script");
|
|
|
|
if (type == LUA_T_TASK) {
|
|
uint32 task = (uint32)nvalue(Address(paramObj));
|
|
LState *state;
|
|
for (state = lua_rootState->next; state != nullptr; state = state->next) {
|
|
if (state->id == task) {
|
|
if (state->next) {
|
|
ttype(lua_state->stack.top) = LUA_T_TASK;
|
|
nvalue(lua_state->stack.top) = (float)state->next->id;
|
|
incr_top;
|
|
} else
|
|
lua_pushnil();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (lua_rootState->next) {
|
|
ttype(lua_state->stack.top) = LUA_T_TASK;
|
|
nvalue(lua_state->stack.top) = (float)lua_rootState->next->id;
|
|
incr_top;
|
|
} else
|
|
lua_pushnil();
|
|
}
|
|
|
|
void stop_script() {
|
|
lua_Object paramObj = lua_getparam(1);
|
|
lua_Type type = paramObj == LUA_NOOBJECT ? LUA_T_NIL : ttype(Address(paramObj));
|
|
LState *state;
|
|
|
|
if (paramObj == LUA_NOOBJECT || (type != LUA_T_CPROTO && type != LUA_T_PROTO && type != LUA_T_TASK))
|
|
lua_error("Bad argument to stop_script");
|
|
|
|
if (type == LUA_T_TASK) {
|
|
uint32 task = (uint32)nvalue(Address(paramObj));
|
|
for (state = lua_rootState->next; state != nullptr; state = state->next) {
|
|
if (state->id == task)
|
|
break;
|
|
}
|
|
if (state) {
|
|
if (state != lua_state) {
|
|
lua_statedeinit(state);
|
|
luaM_free(state);
|
|
}
|
|
}
|
|
} else if (type == LUA_T_PROTO || type == LUA_T_CPROTO) {
|
|
for (state = lua_rootState->next; state != nullptr;) {
|
|
bool match;
|
|
if (type == LUA_T_PROTO) {
|
|
match = (state->taskFunc.ttype == type && tfvalue(&state->taskFunc) == tfvalue(Address(paramObj)));
|
|
} else {
|
|
match = (state->taskFunc.ttype == type && fvalue(&state->taskFunc) == fvalue(Address(paramObj)));
|
|
}
|
|
if (match && state != lua_state) {
|
|
LState *tmp = state->next;
|
|
lua_statedeinit(state);
|
|
luaM_free(state);
|
|
state = tmp;
|
|
} else {
|
|
state = state->next;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void identify_script() {
|
|
lua_Object paramObj = lua_getparam(1);
|
|
lua_Type type = paramObj == LUA_NOOBJECT ? LUA_T_NIL : ttype(Address(paramObj));
|
|
|
|
if (paramObj == LUA_NOOBJECT || type != LUA_T_TASK)
|
|
lua_error("Bad argument to identify_script");
|
|
|
|
uint32 task = (uint32)nvalue(Address(paramObj));
|
|
LState *state;
|
|
for (state = lua_rootState->next; state != nullptr; state = state->next) {
|
|
if (state->id == task) {
|
|
luaA_pushobject(&state->taskFunc);
|
|
return;
|
|
}
|
|
}
|
|
|
|
lua_pushnil();
|
|
}
|
|
|
|
void find_script() {
|
|
lua_Object paramObj = lua_getparam(1);
|
|
lua_Type type = paramObj == LUA_NOOBJECT ? LUA_T_NIL : ttype(Address(paramObj));
|
|
|
|
if (type != LUA_T_CPROTO && type != LUA_T_PROTO && type != LUA_T_TASK && type != LUA_T_NIL)
|
|
lua_error("Bad argument to find_script");
|
|
|
|
if (type == LUA_T_NIL) {
|
|
ttype(lua_state->stack.top) = LUA_T_TASK;
|
|
nvalue(lua_state->stack.top) = lua_state->id;
|
|
incr_top;
|
|
lua_pushnumber(1.0f);
|
|
return;
|
|
}
|
|
|
|
if (type == LUA_T_TASK) {
|
|
uint32 task = (uint32)nvalue(Address(paramObj));
|
|
LState *state;
|
|
for (state = lua_rootState->next; state != nullptr; state = state->next) {
|
|
if (state->id == task) {
|
|
lua_pushobject(paramObj);
|
|
lua_pushnumber(1.0f);
|
|
return;
|
|
}
|
|
}
|
|
} else if (type == LUA_T_PROTO || type == LUA_T_CPROTO) {
|
|
int task = -1, countTasks = 0;
|
|
bool match;
|
|
LState *state;
|
|
for (state = lua_rootState->next; state != nullptr; state = state->next) {
|
|
if (type == LUA_T_PROTO) {
|
|
match = (state->taskFunc.ttype == type && tfvalue(&state->taskFunc) == tfvalue(Address(paramObj)));
|
|
} else {
|
|
match = (state->taskFunc.ttype == type && fvalue(&state->taskFunc) == fvalue(Address(paramObj)));
|
|
}
|
|
if (match) {
|
|
task = state->id;
|
|
countTasks++;
|
|
}
|
|
}
|
|
if (countTasks) {
|
|
assert(task != -1);
|
|
ttype(lua_state->stack.top) = LUA_T_TASK;
|
|
nvalue(lua_state->stack.top) = (float)task;
|
|
incr_top;
|
|
lua_pushnumber((float)countTasks);
|
|
return;
|
|
}
|
|
}
|
|
|
|
lua_pushnil();
|
|
lua_pushnumber(0.0f);
|
|
}
|
|
|
|
void pause_script() {
|
|
lua_Object taskObj = lua_getparam(1);
|
|
lua_Type type = taskObj == LUA_NOOBJECT ? LUA_T_NIL : ttype(Address(taskObj));
|
|
if (type != LUA_T_TASK) {
|
|
lua_error("Bad argument to pause_script");
|
|
return;
|
|
}
|
|
|
|
uint32 task = (uint32)nvalue(Address(taskObj));
|
|
LState *state;
|
|
for (state = lua_rootState->next; state != nullptr; state = state->next) {
|
|
if (state->id == task) {
|
|
state->paused = true;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void pause_scripts() {
|
|
LState *t;
|
|
lua_Object boolObj = lua_getparam(1);
|
|
|
|
bool p = false;
|
|
if (!lua_isnil(boolObj))
|
|
p = true;
|
|
|
|
for (t = lua_rootState->next; t != nullptr; t = t->next) {
|
|
if (lua_state != t) {
|
|
if (p) {
|
|
t->all_paused++;
|
|
} else {
|
|
t->all_paused = 1;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void unpause_script() {
|
|
lua_Object taskObj = lua_getparam(1);
|
|
lua_Type type = taskObj == LUA_NOOBJECT ? LUA_T_NIL : ttype(Address(taskObj));
|
|
if (type != LUA_T_TASK) {
|
|
lua_error("Bad argument to unpause_script");
|
|
return;
|
|
}
|
|
|
|
uint32 task = (uint32)nvalue(Address(taskObj));
|
|
LState *state;
|
|
for (state = lua_rootState->next; state != nullptr; state = state->next) {
|
|
if (state->id == task) {
|
|
state->paused = false;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void unpause_scripts() {
|
|
LState *t;
|
|
lua_Object boolObj = lua_getparam(1);
|
|
|
|
bool p = false;
|
|
if (!lua_isnil(boolObj))
|
|
p = true;
|
|
|
|
for (t = lua_rootState->next; t != nullptr; t = t->next) {
|
|
if (lua_state != t) {
|
|
if (p) {
|
|
if (t->all_paused > 0)
|
|
t->all_paused--;
|
|
} else {
|
|
t->all_paused = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void current_script() {
|
|
ttype(lua_state->stack.top) = LUA_T_TASK;
|
|
nvalue(lua_state->stack.top) = (float)lua_state->id;
|
|
incr_top;
|
|
}
|
|
|
|
void break_here() {}
|
|
|
|
void sleep_for() {
|
|
lua_Object msObj = lua_getparam(1);
|
|
|
|
if (lua_isnumber(msObj)) {
|
|
int ms = (int)lua_getnumber(msObj);
|
|
lua_state->sleepFor = ms;
|
|
}
|
|
}
|
|
|
|
void lua_runtasks() {
|
|
if (!lua_state || !lua_state->next) {
|
|
return;
|
|
}
|
|
|
|
// Mark all the states to be updated
|
|
LState *state = lua_state->next;
|
|
do {
|
|
if (state->sleepFor > 0) {
|
|
state->sleepFor -= g_grim->getFrameTime();
|
|
} else {
|
|
state->updated = false;
|
|
}
|
|
state = state->next;
|
|
} while (state);
|
|
|
|
// And run them
|
|
runtasks(lua_state);
|
|
}
|
|
|
|
void runtasks(LState *const rootState) {
|
|
lua_state = lua_state->next;
|
|
while (lua_state) {
|
|
LState *nextState = nullptr;
|
|
bool stillRunning;
|
|
if (!lua_state->all_paused && !lua_state->updated && !lua_state->paused) {
|
|
jmp_buf errorJmp;
|
|
lua_state->errorJmp = &errorJmp;
|
|
if (setjmp(errorJmp)) {
|
|
lua_Task *t, *m;
|
|
for (t = lua_state->task; t != nullptr;) {
|
|
m = t->next;
|
|
luaM_free(t);
|
|
t = m;
|
|
}
|
|
stillRunning = false;
|
|
lua_state->task = nullptr;
|
|
} else {
|
|
if (lua_state->task) {
|
|
stillRunning = luaD_call(lua_state->task->initBase, lua_state->task->initResults);
|
|
} else {
|
|
StkId base = lua_state->Cstack.base;
|
|
luaD_openstack((lua_state->stack.top - lua_state->stack.stack) - base);
|
|
set_normalized(lua_state->stack.stack + lua_state->Cstack.base, &lua_state->taskFunc);
|
|
stillRunning = luaD_call(base + 1, 255);
|
|
}
|
|
}
|
|
nextState = lua_state->next;
|
|
// The state returned. Delete it
|
|
if (!stillRunning) {
|
|
lua_statedeinit(lua_state);
|
|
luaM_free(lua_state);
|
|
} else {
|
|
lua_state->updated = true;
|
|
}
|
|
} else {
|
|
nextState = lua_state->next;
|
|
}
|
|
lua_state = nextState;
|
|
}
|
|
|
|
// Restore the value of lua_state to the main script
|
|
lua_state = rootState;
|
|
// Check for states that may have been created in this run.
|
|
LState *state = lua_state->next;
|
|
while (state) {
|
|
if (!state->all_paused && !state->paused && !state->updated) {
|
|
// New state! Run a new pass.
|
|
runtasks(rootState);
|
|
return;
|
|
}
|
|
state = state->next;
|
|
}
|
|
}
|
|
|
|
} // end of namespace Grim
|