openblocks/core/src/objects/script.cpp

128 lines
No EOL
3.8 KiB
C++

#include "script.h"
#include "common.h"
#include "logger.h"
#include "objects/base/instance.h"
#include "objects/base/member.h"
#include "objects/script/scriptcontext.h"
#include "objects/workspace.h"
#include "objects/datamodel.h"
#include "datatypes/ref.h"
#include "lua.h"
#include <algorithm>
#include <memory>
int script_wait(lua_State*);
int script_delay(lua_State*);
Script::Script(): Instance(&TYPE) {
source = "workspace.Part.Touched:Connect(function(otherPart)\n"
" print(\"Touched by: \", otherPart.Name)\n"
"end)\n"
"\n"
"workspace.Part.TouchEnded:Connect(function(otherPart)\n"
" print(\"Touched ended with: \", otherPart.Name)\n"
"end)\n"
"\n"
"error(\"Test\")";
}
Script::~Script() {
}
void Script::Run() {
std::shared_ptr<ScriptContext> scriptContext = dataModel().value()->GetService<ScriptContext>();
lua_State* L = scriptContext->state;
// Create thread
this->thread = lua_newthread(L);
lua_State* Lt = thread;
// Initialize script globals
lua_getglobal(Lt, "_G");
Data::InstanceRef(dataModel().value()).PushLuaValue(Lt);
lua_setfield(Lt, -2, "game");
Data::InstanceRef(dataModel().value()->GetService<Workspace>()).PushLuaValue(Lt);
lua_setfield(Lt, -2, "workspace");
lua_pushlightuserdata(Lt, scriptContext.get());
lua_pushcclosure(Lt, script_wait, 1);
lua_setfield(Lt, -2, "wait");
lua_pushlightuserdata(Lt, scriptContext.get());
lua_pushcclosure(Lt, script_delay, 1);
lua_setfield(Lt, -2, "delay");
lua_pop(Lt, 1); // _G
// Load source and push onto thread stack as function ptr
// luaL_loadstring(Lt, source.c_str());
luaL_loadbuffer(Lt, source.c_str(), source.size(), scriptContext->RegisterScriptSource(shared<Script>()).c_str());
int status = lua_resume(Lt, 0);
if (status > LUA_YIELD) {
lua_Debug dbg;
lua_getstack(Lt, 1, &dbg);
lua_getinfo(Lt, "S", &dbg);
std::weak_ptr<Script> source = scriptContext->GetScriptFromSource(dbg.source);
std::string errorMessage = lua_tostring(Lt, -1);
if (!source.expired())
errorMessage = source.lock()->GetFullName() + errorMessage.substr(errorMessage.find(':'));
Logger::error(errorMessage);
lua_pop(Lt, 1); // Pop return value
Logger::traceStart();
int stack = 1;
while (lua_getstack(Lt, stack++, &dbg)) {
lua_getinfo(Lt, "nlSu", &dbg);
std::weak_ptr<Script> source = scriptContext->GetScriptFromSource(dbg.source);
if (source.expired()) {
Logger::trace(dbg.source, dbg.currentline);
} else {
Logger::trace(source.lock()->GetFullName(), dbg.currentline, &source);
}
}
Logger::traceEnd();
}
lua_pop(L, 1); // Pop the thread
}
void Script::Stop() {
// TODO:
}
int script_wait(lua_State* L) {
ScriptContext* scriptContext = (ScriptContext*)lua_touserdata(L, lua_upvalueindex(1));
float secs = lua_gettop(L) == 0 ? 0.03 : std::max(luaL_checknumber(L, 1), 0.03);
if (lua_gettop(L) > 0) lua_pop(L, 1); // pop secs
scriptContext->PushThreadSleep(L, secs);
// Yield
return lua_yield(L, 0);
}
int script_delay(lua_State* L) {
ScriptContext* scriptContext = (ScriptContext*)lua_touserdata(L, lua_upvalueindex(1));
float secs = std::max(luaL_checknumber(L, 1), 0.03);
luaL_checktype(L, 2, LUA_TFUNCTION);
lua_State* Lt = lua_newthread(L); // Create a new thread
lua_pop(L, 1); // pop the newly created thread so that xmove moves func instead of it into itself
lua_xmove(L, Lt, 1); // move func
lua_pop(L, 1); // pop secs
// Schedule next run
scriptContext->PushThreadSleep(Lt, secs);
return 0;
}