summaryrefslogtreecommitdiff
path: root/indra/newview/llluamanager.cpp
AgeCommit message (Collapse)Author
2024-07-10Remove ability to reuse a LuaState between LLLUAmanager functions.Nat Goodspeed
Remove LLLUAmanager::mumbleScriptLine() LuaState& parameters. Make startScriptLine(), waitScriptLine() and runScriptLine() exactly parallel to startScriptFile(), waitScriptFile() and runScriptFile(). That means that runScriptLine()'s C++ coroutine instantiates and destroys its own LuaState, which means that LL.atexit() functions will run on the Lua-specific C++ coroutine rather than (say) the viewer's main coroutine. Introduce LLLUAmanager::script_result typedef for std::pair<int, LLSD> and use in method returns. Remove LuaState::initLuaState(); move its logic back into the constructor. Remove initLuaState() calls in the expr() error cases: they're moot now that we won't get subsequent expr() calls on the same LuaState instance. Remove LLFloaterLUADebug "Use clean lua_State" checkbox and the cleanLuaState() method. Remove mState member. Remove explicit LuaState declarations from LLLUAmanager tests. Adapt one test for implicit LuaState: it was directly calling LuaState::obtainListener() to discover the LuaListener's reply-pump name. But since that test also captures two leap.request() calls from the Lua script, it can just look at the "reply" key in either of those requests.
2024-07-02Make require() implementation honor LuaRequirePath setting.Nat Goodspeed
Remove LL_TEST special case from require() code (to search in the viewer's source tree). Instead, make llluamanager_test.cpp append to LuaRequirePath to get the same effect.
2024-07-02Promote LuaRemover from llluamanager.cpp to lua_function.h.Nat Goodspeed
2024-06-28Add LuaAutorunPath, LuaCommandPath and LuaRequirePath settings.Nat Goodspeed
Remove AutorunLuaScriptFile and the LLLUAmanager::runScriptOnLogin() method that checked it. Instead, iterate over LuaAutorunPath directories at viewer startup, iterate over *.lua files in each and implicitly run those. LuaCommandPath and LuaRequirePath are not yet implemented.
2024-06-18Improve diagnostic output from running 'require' module.Nat Goodspeed
2024-06-17Store script's LuaListener in userdata in lua_State's Registry.Nat Goodspeed
Instead of deriving LuaListener from LLInstanceTracker with an int key, generating a unique int key and storing that key in the Registry, use new lua_emplace<LuaState>() to store the LuaListener directly in a Lua userdata object in the Lua Registry. Because lua_emplace<T>() uses LL.atexit() to guarantee that ~LuaState will destroy the T object, we no longer need ~LuaState() to make a special call specifically to destroy the LuaListener, if any. So we no longer need LuaState::getListener() separate from obtainListener(). Since LuaListener is no longer an LLInstanceTracker subclass, make LuaState::obtainListener() return LuaListener& rather than LuaListener::ptr_t.
2024-06-14Move Lua modules for 'require' to indra/newview/scripts/lua/require.Nat Goodspeed
Make viewer_manifest.py copy them into the viewer install image. Make the require() function look for them there.
2024-06-12For a single string concatenation, use operator+().Nat Goodspeed
stringize() constructs, populates and destroys a std::ostringstream, which is actually less efficient than directly allocating a std::string big enough for the result of operator+(). Maybe someday we'll specialize stringize(p0, p1) for the case in which they're both string-like, and invoke operator+() for that situation...
2024-04-18Move {set,check}_interrupts_counter() to lluau namespace.Nat Goodspeed
Use in LuaState::expr() so we can catch a runaway in-memory Lua chunk as well as a script read from a file.
2024-04-17Reintroduce LLCoros::killreq() to request killing a named coroutine.Nat Goodspeed
Make LLCoros constructor echo "LLApp" status-change events on new "LLCoros" event pump. Rename LLCoros::kill() to killreq() because this operation only registers a request for the named coroutine to terminate next time it calls checkStop(). Add a new CoroData member to record the name of the coroutine requesting termination. killreq() sets that and also posts "killreq" to "LLCoros". Add an optional final-cleanup callback to LLCoros::checkStop(). Make checkStop() check for a pending killreq() request as well as viewer termination. Introduce new LLCoros::Killed exception for that case. Introduce LLCoros::getStopListener(), with two overloads, to encapsulate some of the messy logic to listen (perhaps temporarily) for viewer shutdown. Both overloads are for use by code at the source end of a queue or promise or other resource for which coroutines might still be waiting at viewer shutdown time. One overload is specifically for when the caller knows the name of the one and only coroutine that will wait on the resource (e.g. because the caller IS that coroutine). That overload honors killreq(). Use getStopListener() to simplify the four existing places where we set up such a listener. Add a fifth: also make WorkQueue listen for viewer shutdown (resolving a TODO comment). Remove LLLUAmanager::terminateScript(), getTerminationList() and the static sTerminationList. In the Lua interrupt callback, instead of checking sTerminationList, call LLCoros::checkStop(). Change LLFloaterLUAScripts terminate-script logic to call LLCoros::killreq() instead of posting on "LLLua" and calling LLLUAmanager::terminateScript(). Drop LLApp::setStatus() posting to "LLLua" LLEventPump: the above makes that moot.
2024-04-16Call suspend() periodically to avoid viewer freezeMnikolenko Productengine
2024-04-12'Lua Scripts' floater clean upMnikolenko Productengine
2024-04-09mac build fix - remove unused variableMaxim Nikolenko
2024-04-08Add script termination option to 'Lua Scripts' floaterMnikolenko Productengine
2024-04-03Merge pull request #1101 from secondlife/lua-scripts-floaternat-goodspeed
Lua scripts floater
2024-04-03Introduce fsyspath subclass of std::filesystem::path.Nat Goodspeed
Our std::strings are UTF-8 encoded, so conversion from std::string to std::filesystem::path must use UTF-8 decoding. The native Windows std::filesystem::path constructor and assignment operator accepting std::string use "native narrow encoding," which mangles path strings containing UTF-8 encoded non-ASCII characters. fsyspath's std::string constructor and assignment operator explicitly engage std::filesystem::u8path() to handle encoding. u8path() is deprecated in C++20, but once we adapt fsyspath's conversion to C++20 conventions, consuming code need not be modified.
2024-04-03Add RAII class for adding/erasing script entries; code clean upMnikolenko Productengine
2024-04-02Streamline std::filesystem::path conversions in LLRequireResolver.Nat Goodspeed
Make LLRequireResolver capture std::filesystem::path instances, instead of std::strings, for the path to resolve and the source directory. Store the running script's containing directory instead of calling parent_path() over and over. Demote Lua LL.post_on() logging to DEBUG level instead of INFO.
2024-04-01Add 'Lua Scripts' floaterMnikolenko Productengine
2024-03-29Merge branch 'release/luau-scripting' into lua-startupNat Goodspeed
2024-03-29Merge pull request #1071 from secondlife/lua-new-luastatenat-goodspeed
Run each script file with new LuaState
2024-03-28Merge branch 'lua-hangfix' into lua-startup.Nat Goodspeed
2024-03-28Remove rest of prototype UI access.Nat Goodspeed
2024-03-28Remove llluamanager.cpp "FIXME extremely hacky way" cruft.Nat Goodspeed
2024-03-27Run each script file with new LuaStateMnikolenko Productengine
2024-03-27Run loaded `require()` module on Lua's main thread.Nat Goodspeed
The problem with running a `require()` module on a Lua coroutine is that it prohibits calling `leap.request()` at module load time. When a coroutine calls `leap.request()`, it must yield back to Lua's main thread -- but a `require()` module is forbidden from yielding. Running on Lua's main thread means that (after potentially giving time slices to other ready coroutines) `fiber.lua` will request the response event from the viewer, and continue processing the loaded module without having to yield.
2024-03-08Allow build-time Lua tests to require() bundled Lua modules.Nat Goodspeed
2024-02-29Fix caching for loaded Lua require() modules.Nat Goodspeed
The code to save the loaded module was using the wrong key.
2024-02-29Refactor require() to make it easier to reason about Lua stack usage.Nat Goodspeed
Push throwing Lua errors down into LLRequireResolver::findModule() and findModuleImpl() so their callers don't have to handle the error case. That eliminates finishrequire(). require() itself now only retrieves (and pops) the passed module name and calls LLRequireResolver::resolveRequire() to do the actual work. resolveRequire() is now void. It only instantiates LLRequireResolver and calls its findModule(). findModule() is now also void. It's guaranteed to either push the loaded Lua module or throw a Lua error. In particular, when findPathImpl() cannot find the specified module, findModule() throws an error. That replaces ModuleStatus::NotFound. Since std::filesystem::path::append() aka operator/() detects when its right operand is absolute and, in that case, discards the left operand, we no longer need resolveAndStoreDefaultPaths(): we can just invoke that operation inline. When findModule() pushes _MODULES on the Lua stack, it uses LuaRemover (below) to ensure that _MODULES is removed again no matter how findModules() exits. findModuleImpl() now accepts the candidate pathname as its argument. That eliminates mAbsolutePath. findModuleImpl() now returns only bool: true means the module was found and loaded and pushed on the Lua stack, false means not found and nothing was pushed; no return means an error was reported. Push running a newly found module's source file down into findModuleImpl(). That eliminates the distinction between Cached and FileRead, which obviates ModuleStatus: a bool return means either "previously cached" or "we read it, compiled it, loaded it and ran it." That also eliminates the need to store the module's textual content in mSourceCode. Similarly, once loading the module succeeds, findModuleImpl() caches it in _MODULES right away. That eliminates ResolvedRequire since we need not pass the full pathname of the found module (or its contents) back up through the call chain. Move require() code that runs the new module into private runModule() method, called by findModuleImpl() in the not-cached case. runModule() is the only remaining method that can push either a string error message or the desired module, because of its funny stack manipulations. That means the check for a string error message on the stack top can move down to findModuleImpl(). Add LuaRemover class to ensure that on exit from some particular C++ block, the specified Lua stack entry will definitely be removed. This is different from LuaPopper in that it engages lua_remove() rather than lua_pop(). Also ditch obsolete await_event() Lua entry point.
2024-02-27Merge branch 'release/luau-scripting' into luau-require-impl.Nat Goodspeed
2024-02-26Clear the stack after requiring a moduleMnikolenko Productengine
2024-02-26Clean-up and restoring correct pathMnikolenko Productengine
2024-02-23require() code clean-upMnikolenko Productengine
2024-02-22Lua listen_events(), await_event() => get_event_{pumps,next}().Nat Goodspeed
Don't set up a Lua callback to receive incoming events, a la listen_events(). Don't listen on an arbitrary event pump, a la await_event(). Instead, the new get_event_pumps() entry point simply delivers the reply pump and command pump names (as listen_events() did) without storing a Lua callback. Make LuaListener capture incoming events on the reply pump in a queue. This avoids the problem of multiple events arriving too quickly for the Lua script to retrieve. If the queue gets too big, discard the excess instead of blocking the caller of post(). Then the new get_event_next() entry point retrieves the next (pump, data) pair from the queue, blocking the Lua script until a suitable event arrives. This is closer to the use of stdin for a LEAP plugin. It also addresses the question: what should the Lua script's C++ coroutine do while waiting for an incoming reply pump event? Recast llluamanager_test.cpp for this new, more straightforward API. Move LLLeap's and LuaListener's reply LLEventPump into LLLeapListener, which they both use. This simplifies LLLeapListener's API, which was a little convoluted: the caller supplied a connect callback to allow LLLeapListener to connect some listener to the caller's reply pump. Now, instead, the caller simply passes a bool(pumpname, data) callback to receive events incoming on LLLeapListener's own reply pump. Fix a latent bug in LLLeapListener: if a plugin called listen() more than once with the same listener name, the new connection would not have been saved. While at it, replace some older Boost features in LLLeapListener and LLLeap.
2024-02-20Don't accept a full path as arg for require()Mnikolenko Productengine
2024-02-20Initial require implementationMnikolenko Productengine
2024-02-13Add leaphelp() Lua builtin function for help on LEAP operations.Nat Goodspeed
leaphelp() (no argument) shows a list of all LEAP APIs. leaphelp(API) shows further help for a specific API. Both forms query LuaListener's LeapListener and report its responses. In future we might reimplement leaphelp() as a Lua function. Add LuaState::getListener() method, which checks whether there's a LuaListener associated with this LuaState and returns a pointer if so. Add LuaState::obtainListener() method, which finds or creates a LuaListener for this LuaState and returns its pointer. Both the above use logic migrated from the Lua listen_events() entry point, which now calls obtainListener() instead.
2024-02-09Make LLLUAmanager::runScriptFile() use filename as description.Nat Goodspeed
Since the description shows up in the log output, it's better to see just the script filename than to see "runScriptFile('filename')".
2024-02-08Add required helptext parameter to lua_function() macro.Nat Goodspeed
Extend the LuaFunction::Registry map to store helptext as well as the function pointer. Add help text to every existing lua_function() invocation.
2024-02-07Add LLLUAmanager::startScriptFile(), startScriptLine() functions.Nat Goodspeed
Break out for LLLUAmanager consumers the promise/future semantics of waitScriptFile() and waitScriptLine(). startScriptMumble() uses runScriptMumble() to launch a coroutine to run the specified Lua script or chunk, providing an internal adapter callback to set a promise on completion. It then returns to its caller the future obtained from that promise. This allows a caller to call startScriptMumble(), run in parallel with the Lua coroutine for a while and then call get() on the returned future to wait for results. waitScriptMumble() is then trivially implemented using startScriptMumble(). Fix runScriptLine()'s logic to abbreviate the passed Lua chunk for use as the description. We were erroneously assigning back through a string_view of the parameter, which overwrote a temporary string in the argument list. With Lua 5.4, listen_events() tried to discover the main "thread" (Lua coroutine) associated with the current lua_State so we could call async callbacks on that thread. Luau doesn't seem to provide that feature, so run callbacks on whichever thread calls listen_events(). Reinstate original multi-argument lua_print_msg(), tweaked to avoid the Lua 5.4 lua_rotate() function, which is missing from Luau.
2024-02-07Add machinery to capture result of running a Lua script or snippet.Nat Goodspeed
Add LuaState::expr() that evaluates a Lua snippet and reports back any result (or error) left on the stack. Add LLLUAmanager::runScriptFile() and runScriptLine() overloads that accept a callback with an (int count, LLSD result) signature. The count disambiguates (error, no result, one result, array of results). Also add overloads that accept an existing LuaState instance. Also add waitScriptFile() and waitScriptLine() methods that pause the calling coroutine until the Lua script completes, and return its results. Instead of giving LuaState a description to use for all subsequent checkLua() calls, remove description from its constructor and data members. Move to expr() and checkLua() parameters: we want a description specific to each operation, rather than for the LuaState as a whole. This prepares for persistent LuaState instances. For now, the existing script_finished_fn semantics remain: the callback will be called only when the LuaState is destroyed. This may need to change as we migrate towards longer-lasting LuaState instances. Make lua_function(name) macro append suffixes to the name for both the LuaFunction subclass declaration and the instance declaration. This allows publishing a lua_function() name such as sleep(), which already has a different C++ declaration. Move the Lua sleep() entry point to a standalone lua_function(sleep), instead of a lambda in the body of runScriptFile().
2024-02-06Break out lua_function.h,.cpp and lualistener.h,.cpp.Nat Goodspeed
The intention is to decentralize Luau entry points into our C++ code, permitting a given entry point to be added to the .cpp file that already deals with that class or functional area. Continuing to add every such entry point to llluamanager.cpp doesn't scale well. Extract LuaListener class from llluamanager.cpp to its own header and .cpp file. Extract from llluamanager into lua_function.h (and .cpp) declarations useful for adding a lua_function Luau entry point, e.g.: lua_register() lua_rawlen() lua_tostdstring() lua_pushstdstring() lua_tollsd() lua_pushllsd() LuaPopper lua_function() and LuaFunction class LuaState lua_what lua_stack DebugExit
2024-01-31strip lua testing functionsMnikolenko Productengine
2024-01-29DRTVWR-589: get rid of pragma and update windows libsMnikolenko Productengine
2024-01-26DRTVWR-589: update to start using Luau libsMnikolenko Productengine
2023-11-09DRTVWR-589 - don't prevent mangling names as we use C++ libMnikolenko Productengine
2023-11-02DRTVWR-589: Update Lualibs.cmake to use lua54.lib from 3p-lua.Nat Goodspeed
Also remove #pragma comment(lib, "liblua54.a") from relevant source files.
2023-10-19DRTVWR-589: Fix unreferenced LuaListener::mState member.Nat Goodspeed
2023-10-07DRTVWR-589: Solved the bug in traversing nested Lua tables.Nat Goodspeed
When lua_tollsd() makes a recursive call, it passes -1 as the index of the newly-encountered nested table. To traverse the nested table, lua_tollsd() starts by pushing nil as the initial key. But then calling lua_next(-1) finds nil -- NOT the nested table! Converting the index parameter to absolute before pushing nil solves.
2023-10-04DRTVWR-589: Add tests for LLSD-to-Lua round-trip conversions.Nat Goodspeed
Add from_lua() function to run a small Lua script that constructs a specified Lua object and posts it back to the test program via a temporary LLEventPump. Call this with a variety of Lua objects, comparing to the expected LLSD. Add round_trip() function to run another small Lua script that listens for incoming LLEventPump events and, for each, posts the received Lua data back to the test program as LLSD. Call this with a variety of LLSD objects, comparing to the expected LLSD. Also collect these objects into an LLSD array and send that for a round trip; also collect into an LLSD map and send that. Sadly, tests currently drive an access violation when trying to convert a nested Lua table to LLSD. Add verbose debug logging to lua_tollsd() to identify the context at which we hit the access violation. Add comments describing further exceptions to LLSD-to-Lua round trip identity. Add lua_what() iostream manipulator to stream whatever we can readily discover about a value at a specified Lua stack index. Add lua_stack() to report the contents of the Lua stack. Since the stack is created anew for every call to a C function, this shouldn't usually be enormous. Add hexdump.h with iostream manipulators to dump a byte range as hex digits, or to produce readable text from a mix of printing and nonprinting ASCII characters.