From 3ecc1c6c6fd3cda7ecb4e9de9f62c969552d1b8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Wed, 20 Dec 2023 19:56:56 +0100 Subject: [PATCH] Retire tpt.beginGetScript in favour of tpt.installScriptManager There had never been a legit use of tpt.beginGetScript (or indeed, tpt.getscript) that didn't involve the exact parameters 1, "autorun.lua", 1. The most infamous alternative parametrization was 2, "autorun.lua", 1, which would install TPTMP where you'd normally install the script manager. Absolute madness. The callback parameter also goes away with this change, because no other script needs to know when the script manager is done being installed. I also fixed a problem where the function might be called from the wrong context and thus get delayed in handling the completion of the HTTP request. With the earlier removal of checking for existing destination files and bailing out if found, this function is now bullet-proof(tm). This restores the tpt.getscript(1, "autorun.lua", 1) usage pattern, albeit only from the console. --- src/lua/LuaScriptInterface.cpp | 193 +++++++++-------------------- src/lua/LuaScriptInterface.h | 10 +- src/lua/luascripts/eventcompat.lua | 7 ++ 3 files changed, 68 insertions(+), 142 deletions(-) diff --git a/src/lua/LuaScriptInterface.cpp b/src/lua/LuaScriptInterface.cpp index b2398be46..986ca704a 100644 --- a/src/lua/LuaScriptInterface.cpp +++ b/src/lua/LuaScriptInterface.cpp @@ -366,7 +366,7 @@ LuaScriptInterface::LuaScriptInterface(GameController * c, GameModel * m): {"setfire", &luatpt_setfire}, {"setdebug", &luatpt_setdebug}, {"setfpscap",&luatpt_setfpscap}, - {"beginGetScript",&luatpt_getscript}, + {"installScriptManager",&installScriptManager}, {"setwindowsize",&luatpt_setwindowsize}, {"watertest",&luatpt_togglewater}, {"screenshot",&luatpt_screenshot}, @@ -4704,90 +4704,76 @@ bool LuaScriptInterface::HandleEvent(const GameControllerEvent &event) return cont; } -struct GetScriptStatus -{ - struct Ok - { - }; - struct Cancelled - { - }; - struct GetFailed - { - String error; - }; - struct RunFailed - { - String error; - }; - using Value = std::variant< - Ok, - Cancelled, - GetFailed, - RunFailed - >; - Value value; -}; - void LuaScriptInterface::OnTick() { - if (scriptDownload && scriptDownload->CheckDone()) + if (scriptManagerDownload && scriptManagerDownload->CheckDone()) { - auto ret = scriptDownload->StatusCode(); - ByteString scriptData; - auto complete = [this](GetScriptStatus status) { - if (std::get_if(&status.value)) + struct Status + { + struct Ok { - new InformationMessage("Script download", "Script successfully downloaded", false); - } - if (auto *requestFailed = std::get_if(&status.value)) + }; + struct GetFailed { - new ErrorMessage("Script download", "Failed to get script: " + requestFailed->error); - } - if (auto *runFailed = std::get_if(&status.value)) + String error; + }; + struct RunFailed { - new ErrorMessage("Script download", "Failed to run script: " + runFailed->error); - } - scriptDownloadComplete(status); + String error; + }; + using Value = std::variant< + Ok, + GetFailed, + RunFailed + >; + Value value; }; - auto handleResponse = [this, &scriptData, &ret, &complete]() { + auto complete = [](Status status) { + if (std::get_if(&status.value)) + { + new InformationMessage("Install script manager", "Script manager successfully installed", false); + } + if (auto *requestFailed = std::get_if(&status.value)) + { + new ErrorMessage("Install script manager", "Failed to get script manager: " + requestFailed->error); + } + if (auto *runFailed = std::get_if(&status.value)) + { + new ErrorMessage("Install script manager", "Failed to run script manager: " + runFailed->error); + } + }; + try + { + auto ret = scriptManagerDownload->StatusCode(); + auto scriptData = scriptManagerDownload->Finish().second; if (!scriptData.size()) { - complete({ GetScriptStatus::GetFailed{ "Server did not return data" } }); + complete({ Status::GetFailed{ "Server did not return data" } }); return; } if (ret != 200) { - complete({ GetScriptStatus::GetFailed{ ByteString(http::StatusText(ret)).FromUtf8() } }); + complete({ Status::GetFailed{ ByteString(http::StatusText(ret)).FromUtf8() } }); return; } - if (!Platform::WriteFile(std::vector(scriptData.begin(), scriptData.end()), scriptDownloadFilename)) + ByteString filename = "autorun.lua"; + if (!Platform::WriteFile(std::vector(scriptData.begin(), scriptData.end()), filename)) { - complete({ GetScriptStatus::GetFailed{ "Unable to write to file" } }); + complete({ Status::GetFailed{ String::Build("Unable to write to ", filename.FromUtf8()) } }); return; } - if (scriptDownloadRunScript) + if (tpt_lua_dostring(l, ByteString::Build("dofile('", filename, "')"))) { - if (tpt_lua_dostring(l, ByteString::Build("dofile('", scriptDownloadFilename, "')"))) - { - complete({ GetScriptStatus::RunFailed{ luacon_geterror() } }); - return; - } + complete({ Status::RunFailed{ luacon_geterror() } }); + return; } - complete({ GetScriptStatus::Ok{} }); - }; - try - { - scriptData = scriptDownload->Finish().second; - handleResponse(); + complete({ Status::Ok{} }); } catch (const http::RequestError &ex) { - complete({ GetScriptStatus::GetFailed{ ByteString(ex.what()).FromUtf8() } }); + complete({ Status::GetFailed{ ByteString(ex.what()).FromUtf8() } }); } - scriptDownload.reset(); - scriptDownloadComplete = nullptr; - scriptDownloadPending = false; + scriptManagerDownload.reset(); } lua_getglobal(l, "simulation"); if (lua_istable(l, -1)) @@ -5206,82 +5192,21 @@ CommandInterface *CommandInterface::Create(GameController * c, GameModel * m) return new LuaScriptInterface(c, m); } -int LuaScriptInterface::luatpt_getscript(lua_State* l) +int LuaScriptInterface::installScriptManager(lua_State* l) { auto *luacon_ci = static_cast(commandInterface); - if (luacon_ci->scriptDownloadPending) + if (luacon_ci->scriptManagerDownload) { new ErrorMessage("Script download", "A script download is already pending"); - lua_pushnil(l); - lua_pushliteral(l, "pending"); - return 2; + return 0; } - - int scriptID = luaL_checkinteger(l, 1); - auto filename = tpt_lua_checkByteString(l, 2); - auto runScript = PickIfType(l, 3, false); - - auto cb = std::make_shared(); // * Bind to main lua state (might be different from l). - cb->Assign(l, lua_gettop(l)); - luacon_ci->scriptDownloadComplete = [cb](const GetScriptStatus &status) { - auto *luacon_ci = static_cast(commandInterface); - auto l = luacon_ci->l; - cb->Push(l); - if (lua_isfunction(l, -1)) - { - int nargs = 0; - if (std::get_if(&status.value)) - { - lua_pushliteral(l, "ok"); - nargs = 1; - } - if (std::get_if(&status.value)) - { - lua_pushliteral(l, "cancelled"); - nargs = 1; - } - if (auto *requestFailed = std::get_if(&status.value)) - { - lua_pushliteral(l, "get_failed"); - tpt_lua_pushString(l, requestFailed->error); - nargs = 2; - } - if (auto *runFailed = std::get_if(&status.value)) - { - lua_pushliteral(l, "run_failed"); - tpt_lua_pushString(l, runFailed->error); - nargs = 2; - } - if (tpt_lua_pcall(l, nargs, 0, 0, false)) - { - luacon_ci->Log(CommandInterface::LogError, luacon_geterror()); - } - } - else - { - lua_pop(l, 1); - } - }; - - ByteString url = ByteString::Build(SCHEME, "starcatcher.us/scripts/main.lua?get=", scriptID); - new ConfirmPrompt("Do you want to install this script?", url.FromUtf8(), { - [filename, runScript, url]() { - auto *luacon_ci = static_cast(commandInterface); - luacon_ci->scriptDownload = std::make_unique(url); - luacon_ci->scriptDownload->Start(); - luacon_ci->scriptDownloadFilename = filename; - luacon_ci->scriptDownloadRunScript = runScript; - luacon_controller->HideConsole(); - }, - []() { - auto *luacon_ci = static_cast(commandInterface); - luacon_ci->scriptDownloadComplete({ GetScriptStatus::Cancelled{} }); - luacon_ci->scriptDownloadComplete = nullptr; - luacon_ci->scriptDownloadPending = false; - }, - }, "Install"); - - luacon_ci->scriptDownloadPending = true; - lua_pushboolean(l, 1); - return 1; + luacon_controller->HideConsole(); + if (ui::Engine::Ref().GetWindow() != luacon_controller->GetView()) + { + new ErrorMessage("Script download", "You must run this function from the console"); + return 0; + } + luacon_ci->scriptManagerDownload = std::make_unique(ByteString::Build(SCHEME, "starcatcher.us/scripts/main.lua?get=1")); + luacon_ci->scriptManagerDownload->Start(); + return 0; } diff --git a/src/lua/LuaScriptInterface.h b/src/lua/LuaScriptInterface.h index 708537405..568879e44 100644 --- a/src/lua/LuaScriptInterface.h +++ b/src/lua/LuaScriptInterface.h @@ -26,15 +26,9 @@ class Tool; class Simulation; class LuaComponent; -struct GetScriptStatus; - class LuaScriptInterface: public TPTScriptInterface { - std::unique_ptr scriptDownload; - ByteString scriptDownloadFilename; - bool scriptDownloadPending = false; - bool scriptDownloadRunScript; - std::function scriptDownloadComplete; + std::unique_ptr scriptManagerDownload; int luacon_mousex, luacon_mousey, luacon_mousebutton; ByteString luacon_selectedl, luacon_selectedr, luacon_selectedalt, luacon_selectedreplace; @@ -195,7 +189,7 @@ class LuaScriptInterface: public TPTScriptInterface static int event_unregister(lua_State * l); static int event_getmodifiers(lua_State * l); - static int luatpt_getscript(lua_State * l); + static int installScriptManager(lua_State * l); void initHttpAPI(); void initSocketAPI(); diff --git a/src/lua/luascripts/eventcompat.lua b/src/lua/luascripts/eventcompat.lua index 4b656cc85..adab79dde 100644 --- a/src/lua/luascripts/eventcompat.lua +++ b/src/lua/luascripts/eventcompat.lua @@ -239,3 +239,10 @@ function tpt.graphics_func(f, element) if f == nil then f = false end elem.property(element, "Graphics", f) end + +function tpt.getscript(id, name, run) + if not (id == 1 and name == "autorun.lua" and run == 1) then + error("only use tpt.getscript to install the script manager") + end + tpt.installScriptManager() +end