tutorial: quick 'n' dirty ========================= These are all the things. Use your browser's search to find things you want. You'll need to ``#include ``/``#include "sol.hpp"`` somewhere in your code. Sol is header-only, so you don't need to compile anything. opening a state --------------- .. code-block:: cpp int main (int argc, char* argv[]) { sol::state lua; // open some common libraries lua.open_libraries(sol::lib::base, sol::lib::package); lua.script( "print('bark bark bark!')" ); } sol::state on lua_State* ------------------------ For your system/game that already has lua, but you'd like something nice: .. code-block:: cpp int pre_existing_system( lua_State* L ) { sol::state_view lua(L); lua.script( "print('bark bark bark!')" ); return 0; } running lua code ---------------- .. code-block:: cpp sol::state lua; // load and execute from string lua.script("a = 'test'"); // load and execute from file lua.script_file("path/to/luascript.lua"); // load file without execute sol::load_result script1 = state.load_file("path/to/luascript.lua"); script1(); //execute // load string without execute sol::load_result script2 = state.load("a = 'test'"); script2(); //execute set and get variables --------------------- You can set/get everything. .. code-block:: cpp sol::lua_state lua; lua.open_libraries(sol::lib::base); // integer types lua.set("number", 24); // floating point numbers lua["number2"] = 24.5; // string types lua["important_string"] = "woof woof"; // non-recognized types is stored as userdata // is callable, therefore gets stored as a function lua["a_function"] = [](){ return 100; }; // make a table lua["some_table"] = lua.create_table_wth("value", 24); Equivalent to loading a lua file with: .. code-block:: lua number = 24 number2 = 24.5 important_string = "woof woof" a_function = function () return 100 end some_table = { value = 24 } Retrieve these variables using this syntax: .. code-block:: cpp // implicit conversion int number = lua["number"]; // explicit get auto number2 = lua.get("number2"); // strings too std::string important_string = lua["important_string"]; // dig into a table int value = lua["value"]["value"]; // get a function sol::function a_function = lua["a_function"]; int value_is_100 = a_function(); // get a std::function std::function a_std_function = lua["a_function"]; int value_is_still_100 = a_std_function(); Retrieve Lua types using ``object`` and other ``sol::`` types. .. code-block:: cpp sol::state lua; // ... everything from before sol::object number_obj = lua.get( "number" ); // sol::type::number sol::type t1 = number_obj.get_type(); sol::object function_obj = lua[ "a_function" ]; // sol::type::function sol::type t2 = function_obj.get_type(); bool is_it_really = function_obj.is(); // true // will not contain data sol::optional check_for_me = lua["a_function"]; You can erase things by setting it to ``nullptr`` or ``sol::nil``. .. code-block:: cpp sol::state lua; lua.script("exists = 250"); int first_try = lua.get_or( 322 ); // first_try == 250 lua.set("exists", sol::nil); int second_try = lua.get_or( 322 ); // second_try == 322 Note that if its a :doc:`userdata/usertype<../doc/usertype>` for a C++ type, the destructor will run only when the garbage collector deems it appropriate to destroy the memory. If you are relying on the destructor being run when its set to ``sol::nil``, you're probably committing a mistake. tables ------ :doc:`sol::state<../api/state>` is a table too. .. code-block:: cpp sol::state lua; // Raw string literal for easy multiline lua.script( R"( abc = { [0] = 24 } def = { ghi = { bark = 50, woof = abc } } )" ); sol::table abc = lua["abc"]; sol::state def = lua["def"]; sol::table ghi = lua["def"]["ghi"]; int bark1 = def["ghi"]["bark"]; int bark2 = lua["def"]["ghi"]["bark"]; // bark1 == bark2 == 50 int abcval1 = abc[0]; int abcval2 = ghi["woof"][0]; // abcval1 == abcval2 == 24 If you're going deep, be safe: .. code-block:: cpp sol::state lua; sol::optional will_not_error = lua["abc"]["DOESNOTEXIST"]["ghi"]; // will_not_error == sol::nullopt int will_not_error2 = lua["abc"]["def"]["ghi"]["jklm"].get_or(25); // is 25 // if you don't go safe, // will throw (or do at_panic if no exceptions) int aaaahhh = lua["abc"]["hope_u_liek_crash"]; make tables ----------- Make some: .. code-block:: cpp lua["abc"] = lua.create_table_with( 0, 24 ); lua.create_named_table("def", "ghi", lua.create_table_with( "bark", 50, // can reference other existing stuff too "woof", lua["abc"] ) ); Equivalent Lua code: .. code-block:: lua abc = { [0] = 24 } def = { ghi = { bark = 50, woof = abc } } You can put anything you want in tables as values or keys, including strings, numbers, functions, other tables. functions --------- They're great. Use them: .. code-block:: cpp sol::state lua; lua.script("function f (a, b, c, d) return 1 end"); lua.script("function g (a, b) return a + b end"); // fixed signature std::function<...> std::function stdfx = lua["f"]; // sol::function is often easier: // takes a variable number/types of arguments... sol::function fx = lua["f"]; int is_one = stdfx(1, 34.5, 3, "bark"); int is_also_one = fx(1, "boop", 3, "bark"); // call through operator[] int is_three = lua["g"](1, 2); // is_three == 3 double is_4_8 = lua["g"](2.4, 2.4); // is_4_8 == 4.8 If you need to protect against errors and parser problems and you're not ready to deal with Lua's `longjmp` problems (if you compiled with C), use :doc:`sol::protected_function<../api/protected_function>`. You can bind member variables as functions too, as well as all KINDS of function-like things: .. code-block:: cpp void some_function () { std::cout << "some function!" << std::endl; } void some_other_function () { std::cout << "some other function!" << std::endl; } struct some_class { int variable = 30; double member_function () { return 24.5; } }; sol::state lua; lua.open_libraries(sol::lib::base); // put an instance of "some_class" into lua // (we'll go into more detail about this later // just know here that it works and is // put into lua as a userdata lua.set("sc", some_class()); // binds a plain function lua["f1"] = some_function; lua.set_function("f2", &some_other_function); // binds just the member function lua["m1"] = &some_class::member_function; // binds the class to the type lua.set_function("m2", &some_class::member_function, some_class{}); // binds just the member variable as a function lua["v1"] = &some_class::variable; // binds class with member variable as function lua.set_function("v2", &some_class::variable, some_class{}); The lua code to call these things is: .. code-block:: lua f1() -- some function! f2() -- some other function! -- need class instance if you don't bind it with the function print(m1(sc)) -- 24.5 -- does not need class instance: was made with one print(m2()) -- 24.5 -- need class instance if you -- don't bind it with the function print(v1(sc)) -- 30 -- does not need class instance: -- it was bound with one print(v2()) -- 30 -- can set, still -- requires instance v1(sc, 212) -- can set, does not need -- class instance: was bound with one v2(254) print(v1(sc)) -- 212 print(v2()) -- 254 Can use ``sol::readonly( &some_class::variable )`` to make a variable readonly and error if someone tries to write to it. multiple returns from lua ------------------------- .. code-block:: cpp sol::state lua; lua.script("function f (a, b, c) return a, b, c end"); std::tuple result; result = lua["f"](100, 200, 300); // result == { 100, 200, 300 } int a, int b; std::string c; sol::tie( a, b, c ) = lua["f"](100, 200, "bark"); // a == 100 // b == 200 // c == "bark" multiple returns to lua ----------------------- .. code-block:: cpp sol::state lua; lua["f"] = [](int a, int b, sol::object c) { // sol::object can be anything here: just pass it through return std::make_tuple( a, b, c ); }; std::tuple result = lua["f"](100, 200, 300); // result == { 100, 200, 300 } std::tuple result2; result2 = lua["f"](100, 200, "BARK BARK BARK!") // result2 == { 100, 200, "BARK BARK BARK!" } int a, int b; std::string c; sol::tie( a, b, c ) = lua["f"](100, 200, "bark"); // a == 100 // b == 200 // c == "bark" C++ classes from C++ -------------------- Everything that is not a: * primitive type: ``bool``, ``char/short/int/long/long long``, ``float/double`` * string type: ``std::string``, ``const char*`` * function type: function pointers, ``lua_CFunction``, ``std::function``, :doc:`sol::function/sol::protected_function<../api/function>`, :doc:`sol::coroutine<../api/coroutine>`, member variable, member function * designated sol type: :doc:`sol::table<../api/table>`, :doc:`sol::thread<../api/thread>`, :doc:`sol::error<../api/error>`, :doc:`sol::object<../api/object>` * transparent argument type: :doc:`sol::variadic_arg<../api/variadic_args>`, :doc:`sol::this_state<../api/this_state>` * usertype class: :doc:`sol::usertype<../api/usertype>` Is set as a :doc:`userdata + usertype<../api/usertype>`. .. code-block:: cpp struct Doge { int tailwag = 50; } Doge dog{}; // Copy into lua: destroyed by Lua VM during garbage collection lua["dog"] = dog; // OR: move semantics - will call move constructor if present instead // Again, owned by Lua lua["dog"] = std::move( dog ); lua["dog"] = Doge{}; lua["dog"] = std::make_unique(); lua["dog"] = std::make_shared(); // Identical to above Doge dog2{}; lua.set("dog", dog2); lua.set("dog", std::move(dog2)); lua.set("dog", Doge{}); lua.set("dog", std::unique_ptr(new Doge())); lua.set("dog", std::shared_ptr(new Doge())); ``std::unique_ptr``/``std::shared_ptr``'s reference counts / deleters will :doc:`be respected<../api/unique_usertype_traits>`. If you want it to refer to something, whose memory you know won't die in C++, do the following: .. code-block:: cpp struct Doge { int tailwag = 50; } sol::state lua; lua.open_libraries(sol::lib::base); Doge dog{}; // Kept alive somehow // Later... // The following stores a reference, and does not copy/move // lifetime is same as dog in C++ // (access after it is destroyed is bad) lua["dog"] = &dog; // Same as above: respects std::reference_wrapper lua["dog"] = std::ref(dog); // These two are identical to above lua.set( "dog", &dog ); lua.set( "dog", std::ref( dog ) ); Get userdata in the same way as everything else: .. code-block:: cpp struct Doge { int tailwag = 50; } sol::state lua; lua.open_libraries(sol::lib::base); Doge& dog = lua["dog"]; // References Lua memory Doge* dog_pointer = lua["dog"]; // References Lua memory Doge dog_copy = lua["dog"]; // Copies, will not affect lua Note that you can change the data of usertype variables and it will affect things in lua if you get a pointer or a reference from Sol: .. code-block:: cpp struct Doge { int tailwag = 50; } sol::state lua; lua.open_libraries(sol::lib::base); Doge& dog = lua["dog"]; // References Lua memory Doge* dog_pointer = lua["dog"]; // References Lua memory Doge dog_copy = lua["dog"]; // Copies, will not affect lua dog_copy.tailwag = 525; // Still 50 lua.script("assert(dog.tailwag == 50)"); dog.tailwag = 100; // Now 100 lua.script("assert(dog.tailwag == 100)"); C++ classes put into Lua ------------------------ See this :doc:`section here`. advanced -------- Some more advanced things you can do/read about: * :doc:`metatable manipulations<../api/metatable_key>` allow a user to change how indexing, function calls, and other things work on a single type. * :doc:`ownership semantics` are described for how lua deals with (raw) pointers. * :doc:`stack manipulation<../api/stack>` to safely play with the stack. You can also define customization points for ``stack::get``/``stack::check``/``stack::push`` for your type. * :doc:`make_reference/make_object convenience function<../api/make_reference>` to get the same benefits and conveniences as the low-level stack API but put into objects you can specify. * :doc:`stack references<../api/stack_reference>` to have zero-overhead Sol abstractions while not copying to the Lua registry. * :doc:`unique usertype traits<../api/unique_usertype_traits>` allows you to specialize handle/RAII types from other frameworks, like boost, and Unreal, to work with Sol. * :doc:`variadic arguments<../api/variadic_args>` in functions with ``sol::variadic_args``. * :doc:`this_state<../api/this_state>` to get the current ``lua_State*``. * :doc:`resolve<../api/resolve>` overloads in case you have overloaded functions; a cleaner casting utility.