55 #include <SDL3/SDL_timer.h>
67 #define DBG_LUA LOG_STREAM(debug, log_scripting_lua)
68 #define LOG_LUA LOG_STREAM(info, log_scripting_lua)
69 #define WRN_LUA LOG_STREAM(warn, log_scripting_lua)
70 #define ERR_LUA LOG_STREAM(err, log_scripting_lua)
73 static const char *
Gen =
"name generator";
76 static const char *
Interp =
"lua interpreter";
85 template<VERSION_COMP_OP vop>
91 lua_pushboolean(L, result);
101 if(lua_isinteger(L, 2)) {
102 int n = lua_tointeger(L, 2) - 1;
104 if(
n >= 0 && std::size_t(
n) < components.size()) {
111 char const *m = luaL_checkstring(L, 2);
119 }
else if(strcmp(m,
"sep") == 0) {
128 static const std::vector<std::string> fields{
"major",
"minor",
"revision",
"is_canonical",
"special",
"sep"};
139 vers->~version_info();
159 if(luaL_testudata(L, 1,
Version)) {
165 if(lua_type(L, 1) == LUA_TSTRING) {
168 int major = luaL_checkinteger(L, 1), minor = luaL_optinteger(L, 2, 0), rev = luaL_optinteger(L, 3, 0);
169 std::string sep, special;
170 if(lua_type(L, -1) == LUA_TSTRING) {
171 special = lua_tostring(L, -1);
172 if(!special.empty() && std::isalpha(special[0])) {
175 sep.push_back(special[0]);
176 special = special.substr(1);
181 new(L)
version_info(major, minor, rev, sep[0], special);
183 if(luaL_newmetatable(L,
Version)) {
184 static const luaL_Reg metafuncs[] {
188 {
"__lt", &impl_version_compare<VERSION_COMP_OP::OP_LESS> },
189 {
"__le", &impl_version_compare<VERSION_COMP_OP::OP_LESS_OR_EQUAL> },
190 {
"__eq", &impl_version_compare<VERSION_COMP_OP::OP_EQUAL> },
194 luaL_setfuncs(L, metafuncs, 0);
195 luaW_table_set<std::string>(L, -1,
"__metatable",
Version);
197 lua_setmetatable(L, -2);
222 const int tostring_type = luaL_getmetafield(L, 1,
"__tostring");
223 if(tostring_type != LUA_TNIL
224 || (lua_type(L, 1) != LUA_TTABLE && lua_type(L, 1) != LUA_TUSERDATA)) {
225 if(tostring_type != LUA_TNIL) {
228 luaL_tolstring(L, 1,
nullptr);
233 const int name_type = luaL_getmetafield(L, 1,
"__name");
234 if(name_type == LUA_TSTRING) {
237 if(name_type != LUA_TNIL) {
240 lua_pushstring(L, luaL_typename(L, 1));
250 const int nargs = lua_gettop(L);
251 lua_getglobal(L,
"tostring");
252 for(
int i = 1;
i <= nargs; ++
i) {
253 lua_pushvalue(L, -1);
255 const int status = lua_pcall(L, 1, 1, 0);
258 if(status != LUA_OK) {
262 std::size_t length = 0;
263 const char*
string = luaL_checklstring(L, -1, &length);
265 lua_writestring(
"\t", 1);
267 lua_writestring(
string, length);
281 DBG_LUA <<
"intf_print called:";
282 std::size_t nargs = lua_gettop(L);
284 lua_getglobal(L,
"tostring");
285 for (std::size_t
i = 1;
i <= nargs; ++
i) {
286 lua_pushvalue(L, -1);
289 const char * str = lua_tostring(L, -1);
291 LOG_LUA <<
"'tostring' must return a value to 'print'";
310 static const char*
const prefix =
"Warning:\n ";
311 static std::ostringstream warning(prefix);
312 warning.seekp(0, std::ios::end);
313 warning <<
msg <<
' ';
315 auto L =
reinterpret_cast<lua_State*
>(
p);
318 lua_pushinteger(L, 2);
320 auto& lk = lua_kernel_base::get_lua_kernel<lua_kernel_base>(L);
321 lk.add_log_to_console(luaL_checkstring(L, -1));
337 std::string chunk = luaL_checkstring(L, 1);
338 const char* name = luaL_optstring(L, 2, chunk.c_str());
339 std::string mode = luaL_optstring(L, 3,
"t");
340 bool override_env = !lua_isnone(L, 4);
343 return luaL_argerror(L, 3,
"binary chunks are not allowed for security reasons");
346 int result = luaL_loadbufferx(L, chunk.data(), chunk.length(), name,
"t");
347 if(result != LUA_OK) {
359 const char* upvalue_name = lua_setupvalue(L, -2, 1);
360 if(upvalue_name ==
nullptr) {
374 lua_CFunction function = lua_tocfunction(L, lua_upvalueindex(1));
377 int nRets =
function(L);
389 std::string message =
"There is already an external logger attached to this lua kernel, you cannot open the lua console right now.";
401 lua_pushstring(L, gen->
generate().c_str());
409 lua_pushstring(L,
"%s: %s");
410 lua_pushstring(L,
Gen);
411 lua_pushstring(L, gen->
type().c_str());
425 std::string
type = luaL_checkstring(L, 1);
428 if(
type ==
"markov" ||
type ==
"markov_chain") {
429 std::vector<std::string> input;
430 if(lua_istable(L, 2)) {
431 input = lua_check<std::vector<std::string>>(L, 2);
435 int chain_sz = luaL_optinteger(L, 3, 2);
436 int max_len = luaL_optinteger(L, 4, 12);
440 }
else if(
type ==
"context_free" ||
type ==
"cfg" ||
type ==
"CFG") {
441 if(lua_istable(L, 2)) {
442 std::map<std::string, std::vector<std::string>>
data;
443 for(lua_pushnil(L); lua_next(L, 2); lua_pop(L, 1)) {
444 if(lua_type(L, -2) != LUA_TSTRING) {
445 lua_pushstring(L,
"CFG generator: invalid nonterminal name (must be a string)");
448 if(lua_isstring(L, -1)) {
450 if(productions.size() > 1) {
451 deprecated_message(
"wesnoth.name_generator('cfg', {nonterminal = 'a|b'})",
DEP_LEVEL::INDEFINITE,
"1.17",
"Non-terminals should now be assigned an array of productions instead of a single string containing productions separated by | - but a single string is fine if it's only one production");
453 }
else if(lua_istable(L, -1)) {
454 const auto&
split = lua_check<std::vector<t_string>>(L, -1);
455 auto& productions =
data[lua_tostring(L,-2)];
458 lua_pushstring(L,
"CFG generator: invalid nonterminal value (must be a string or list of strings)");
472 return luaL_argerror(L, 1,
"should be either 'markov_chain' or 'context_free'");
476 lua_pushstring(L, ex.
what());
482 luaL_getmetatable(L,
Gen);
483 lua_setmetatable(L, -2);
494 const std::string& logger = lua_isstring(L, 2) ? luaL_checkstring(L, 1) :
"";
495 std::string
msg = lua_isstring(L, 2) ? luaL_checkstring(L, 2) : luaL_checkstring(L, 1);
496 if(
msg.empty() ||
msg.back() !=
'\n') {
500 if(logger ==
"err" || logger ==
"error") {
502 }
else if(logger ==
"warn" || logger ==
"wrn" || logger ==
"warning") {
504 }
else if((logger ==
"debug" || logger ==
"dbg")) {
520 const std::string elem = luaL_checkstring(L, 1);
523 const std::string ver_str = lua_isnoneornil(L, 3) ?
"" : luaL_checkstring(L, 3);
532 lua_warning(L,
msg.c_str(),
false);
547 if(!lua_istable(L, 1)) {
550 auto names = lua_check<std::vector<std::string>>(L, 2);
552 int len = luaL_checkinteger(L, -1);
554 for(
int i = 1; i <= std::max<int>(len,
names.size());
i++) {
565 temp.
read(luaL_checkstring(L, 1));
566 std::set<map_location> locs;
567 for(
int x = 1; x <= temp.
width(); x++) {
568 for(
int y = 1; y <= temp.
height(); y++) {
569 if(!temp.
value(x, y)) {
583 for(
const auto&
loc : locs) {
595 lua_pushinteger(L, SDL_GetTicks());
607 switch(luaL_getmetafield(L, -1,
"__dir")) {
611 if(lua_pcall(L, 2, 1, 0) == LUA_OK) {
612 keys = lua_check<std::vector<std::string>>(L, -1);
614 lua_warning(L,
"wesnoth.print_attributes: __dir metamethod raised an error",
false);
618 auto dir_keys = lua_check<std::vector<std::string>>(L, -1);
619 std::copy(dir_keys.begin(), dir_keys.end(), std::back_inserter(
keys));
628 auto key = luaL_checkstring(L, 2);
629 auto type = lua_getfield(L, 1, key);
630 if(
type == LUA_TTABLE) {
631 lua_pushliteral(L,
"__deprecated");
632 if(lua_rawget(L, -2) == LUA_TBOOLEAN) {
634 lua_pushboolean(L, deprecated);
639 lua_pushboolean(L,
false);
646 auto key = luaL_checkstring(L, 2);
647 std::string suffix =
" ";
648 auto type = lua_getfield(L, 1, key);
649 if(
type == LUA_TTABLE) {
651 }
else if(
type == LUA_TFUNCTION) {
653 }
else if(
type == LUA_TUSERDATA) {
654 lua_getglobal(L,
"getmetatable");
655 lua_pushvalue(L, -2);
657 if(lua_type(L, -1) == LUA_TSTRING) {
658 auto meta = lua_check<std::string>(L, -1);
659 if(meta ==
"function") {
664 if(suffix.size() == 1) {
666 if(
auto t = luaL_getmetafield(L, -1,
"__dir_tablelike");
t == LUA_TBOOLEAN) {
671 }
else if(
t != LUA_TNIL) {
676 suffix =
" " + suffix;
677 lua_pushlstring(L, suffix.c_str(), suffix.size());
687 if(idx < 0 && idx >= -lua_gettop(L)) {
688 idx = lua_absindex(L, idx);
690 std::vector<std::string>
keys;
691 if(lua_istable(L, idx)) {
694 int save_top = lua_gettop(L);
695 lua_pushvalue(L, idx);
697 lua_settop(L, save_top);
700 int table_idx = lua_absindex(L, -1);
701 for(lua_pushnil(L); lua_next(L, table_idx); lua_pop(L, 1)) {
702 if(lua_type(L, -2) == LUA_TSTRING) {
703 keys.push_back(lua_tostring(L,-2));
711 if(luaL_getmetafield(L, table_idx,
"__index") == LUA_TNIL)
break;
712 }
while(lua_istable(L, -1));
713 if(lua_isfunction(L, -1)) {
717 }
else if(lua_isuserdata(L, idx) && !lua_islightuserdata(L, idx)) {
718 lua_pushvalue(L, idx);
723 std::sort(
keys.begin(),
keys.end());
724 auto new_end = std::unique(
keys.begin(),
keys.end());
725 new_end = std::remove_if(
keys.begin(), new_end, [L, idx](
const std::string& key) {
726 if(key.compare(0, 2,
"__") == 0) {
729 int save_top = lua_gettop(L);
731 lua_settop(L, save_top);
738 lua_pushvalue(L, idx);
740 if(lua_pcall(L, 2, 1, 0) == LUA_OK) {
763 if(lua_isnil(L, 1))
return luaL_argerror(L, 1,
"Can't dir() nil");
764 if(!lua_isfunction(L, 2)) {
767 int fcn_idx = lua_gettop(L);
769 std::size_t max_len = std::accumulate(
keys.begin(),
keys.end(), 0, [](std::size_t max,
const std::string& next) {
770 return std::max(max, next.size());
773 static const std::size_t MAX_WIDTH = 80, COL_PADDING = 3, SUFFIX_PADDING = 2;
774 std::size_t col_width = max_len + COL_PADDING + SUFFIX_PADDING;
775 std::size_t n_cols = (MAX_WIDTH + COL_PADDING) / col_width;
776 std::size_t n_rows = ceil(
keys.size() /
double(n_cols));
777 for(std::size_t
i = 0;
i < n_rows;
i++) {
778 std::ostringstream
line;
780 line.setf(std::ios::left);
781 for(std::size_t j = 0; j < n_cols && j + (
i * n_cols) <
keys.size(); j++) {
782 int save_top = lua_gettop(L);
784 lua_settop(L, save_top);
788 const auto& key =
keys[j +
i * n_cols];
789 lua_pushlstring(L, key.c_str(), key.size());
790 std::string suffix =
" !";
791 if(lua_pcall(L, 2, 1, 0) == LUA_OK) {
792 suffix = luaL_checkstring(L, -1);
796 line.width(col_width - SUFFIX_PADDING + suffix.size());
800 lua_pushvalue(L, fcn_idx);
812 template <member_callback method>
814 return ((lua_kernel_base::get_lua_kernel<lua_kernel_base>(L)).*method)(L);
819 : mState(luaL_newstate())
829 cmd_log_ <<
"Adding boost function proxy...\n";
835 cmd_log_ <<
"Adding standard libs...\n";
837 static const luaL_Reg safe_libs[] {
838 {
"", luaopen_base },
839 {
"table", luaopen_table },
840 {
"string", luaopen_string },
841 {
"math", luaopen_math },
842 {
"coroutine", luaopen_coroutine },
843 {
"debug", luaopen_debug },
844 {
"os", luaopen_os },
845 {
"utf8", luaopen_utf8 },
854 for (luaL_Reg
const *lib = safe_libs; lib->func; ++lib)
856 luaL_requiref(L, lib->name, lib->func, strlen(lib->name));
863 lua_setglobal(L,
"tostring");
866 lua_getglobal(L,
"os");
868 while(lua_next(L, -2) != 0) {
870 char const*
function = lua_tostring(L, -1);
871 if(strcmp(
function,
"clock") == 0 || strcmp(
function,
"date") == 0
872 || strcmp(
function,
"time") == 0 || strcmp(
function,
"difftime") == 0)
continue;
874 lua_setfield(L, -3,
function);
880 lua_setglobal(L,
"dofile");
882 lua_setglobal(L,
"loadfile");
885 cmd_log_ <<
"Adding error handler...\n";
892 cmd_log_ <<
"Registering basic wesnoth API...\n";
894 static luaL_Reg
const callbacks[] {
897 {
"dofile", &dispatch<&lua_kernel_base::intf_dofile> },
898 {
"require", &dispatch<&lua_kernel_base::intf_require> },
899 {
"kernel_type", &dispatch<&lua_kernel_base::intf_kernel_type> },
913 lua_getglobal(L,
"wesnoth");
914 if (!lua_istable(L,-1)) {
917 luaL_setfuncs(L, callbacks, 0);
919 lua_setglobal(L,
"wesnoth");
929 cmd_log_ <<
"Redirecting print function...\n";
932 lua_setglobal(L,
"std_print");
936 lua_pushcfunction(L, &dispatch<&lua_kernel_base::intf_print>);
937 lua_setglobal(L,
"print");
940 lua_setglobal(L,
"load");
942 lua_setglobal(L,
"loadstring");
945 cmd_log_ <<
"Wrapping pcall and xpcall functions...\n";
946 lua_getglobal(L,
"pcall");
948 lua_setglobal(L,
"pcall");
949 lua_getglobal(L,
"xpcall");
951 lua_setglobal(L,
"xpcall");
953 cmd_log_ <<
"Initializing package repository...\n";
955 lua_getglobal(L,
"wesnoth");
957 lua_setfield(L, -2,
"package");
960 lua_pushstring(L,
"lua/package.lua");
963 cmd_log_ <<
"Error: Failed to initialize package repository. Falling back to less flexible C++ implementation.\n";
967 cmd_log_ <<
"Adding map table...\n";
969 static luaL_Reg
const map_callbacks[] {
990 lua_getglobal(L,
"wesnoth");
992 luaL_setfuncs(L, map_callbacks, 0);
993 lua_setfield(L, -2,
"map");
997 cmd_log_ <<
"Adding game_config table...\n";
999 lua_getglobal(L,
"wesnoth");
1000 lua_newuserdatauv(L, 0, 0);
1001 lua_createtable(L, 0, 3);
1002 lua_pushcfunction(L, &dispatch<&lua_kernel_base::impl_game_config_get>);
1003 lua_setfield(L, -2,
"__index");
1004 lua_pushcfunction(L, &dispatch<&lua_kernel_base::impl_game_config_set>);
1005 lua_setfield(L, -2,
"__newindex");
1006 lua_pushcfunction(L, &dispatch<&lua_kernel_base::impl_game_config_dir>);
1007 lua_setfield(L, -2,
"__dir");
1008 lua_pushboolean(L,
true);
1009 lua_setfield(L, -2,
"__dir_tablelike");
1010 lua_pushstring(L,
"game config");
1011 lua_setfield(L, -2,
"__metatable");
1012 lua_setmetatable(L, -2);
1013 lua_setfield(L, -2,
"game_config");
1017 cmd_log_ <<
"Adding rng tables...\n";
1020 cmd_log_ <<
"Adding name generator metatable...\n";
1021 luaL_newmetatable(L,
Gen);
1029 lua_pushstring(L,
Gen);
1030 lua_setfield(L, -2,
"__metatable");
1038 cmd_log_ <<
"Sandboxing Lua interpreter...\nTo make variables visible outside the interpreter, assign to _G.variable.\n";
1039 cmd_log_ <<
"The special variable _ holds the result of the last expression (if any).\n";
1041 lua_createtable(L, 0, 1);
1042 lua_getglobal(L,
"_G");
1043 lua_setfield(L, -2,
"__index");
1044 lua_setmetatable(L, -2);
1046 lua_setfield(L, -2,
"dir");
1047 lua_setfield(L, LUA_REGISTRYINDEX,
Interp);
1054 lua_pushstring(L,
"lua/ilua.lua");
1057 lua_pushstring(L,
"set_strict");
1058 lua_gettable(L, -2);
1060 cmd_log_ <<
"Failed to activate strict mode.\n";
1062 cmd_log_ <<
"Activated strict mode.\n";
1065 lua_setglobal(L,
"ilua");
1067 cmd_log_ <<
"Error: failed to load ilua.\n";
1073 lua_getglobal(L,
"debug");
1075 while(lua_next(L, -2) != 0) {
1077 char const*
function = lua_tostring(L, -1);
1078 if(strcmp(
function,
"traceback") == 0 || strcmp(
function,
"getinfo") == 0)
continue;
1080 lua_setfield(L, -3,
function);
1124 if (errcode != LUA_OK) {
1125 char const *
msg = lua_tostring(L, -1);
1127 std::string context =
"When executing, ";
1128 if (errcode == LUA_ERRRUN) {
1129 context +=
"Lua runtime error: ";
1130 }
else if (errcode == LUA_ERRERR) {
1131 context +=
"Lua error in attached debugger: ";
1132 }
else if (errcode == LUA_ERRMEM) {
1133 context +=
"Lua out of memory error: ";
1135 context +=
"unknown lua error: ";
1137 if(lua_isstring(L, -1)) {
1138 context +=
msg ?
msg :
"null string";
1140 context += lua_typename(L, lua_type(L, -1));
1145 e_h(context.c_str(),
"Lua Error");
1156 int errcode = luaL_loadbufferx(
mState, prog.c_str(), prog.size(), name.empty() ? prog.c_str() : name.c_str(), allow_unsafe ?
"tb" :
"t");
1157 if (errcode != LUA_OK) {
1158 char const *
msg = lua_tostring(
mState, -1);
1159 std::string message =
msg ?
msg :
"null string";
1161 std::string context =
"When parsing a string to lua, ";
1163 if (errcode == LUA_ERRSYNTAX) {
1164 context +=
" a syntax error";
1165 }
else if(errcode == LUA_ERRMEM){
1166 context +=
" a memory error";
1168 context +=
" an unknown error";
1173 e_h(message.c_str(), context.c_str());
1187 this->
run(cfg[
"code"].str().c_str(),
cfg[
"name"].str(), nArgs);
1192 if(lua_iscfunction(L, func)) {
1195 if(!lua_isfunction(L, func)) {
1200 lua_pushvalue(L, func);
1201 lua_getinfo(L,
">u", &
info);
1204 lua_pushvalue(L, func);
1206 data[
"code"] = lua_check<std::string>(L, -1);
1209 for(
int i = 1;
i <=
info.nups;
i++, lua_pop(L, 1)) {
1210 std::string_view name = lua_getupvalue(L, func,
i);
1211 if(name ==
"_ENV") {
1212 upvalues.
add_child(name)[
"upvalue_type"] =
"_ENV";
1215 int idx = lua_absindex(L, -1);
1216 switch(lua_type(L, idx)) {
1217 case LUA_TBOOLEAN:
case LUA_TNUMBER:
case LUA_TSTRING:
1228 for(std::size_t
i = 1;
i <= lua_rawlen(L, -1);
i++, lua_pop(L, 1)) {
1229 lua_rawgeti(L, idx,
i);
1233 cfg[
"upvalue_type"] =
"named tuple";
1238 std::vector<std::string>
names;
1239 int save_top = lua_gettop(L);
1240 if(luaL_getmetafield(L, idx,
"__name") && lua_check<std::string>(L, -1) ==
"named tuple") {
1241 luaL_getmetafield(L, -2,
"__names");
1242 names = lua_check<std::vector<std::string>>(L, -1);
1244 lua_settop(L, save_top);
1245 upvalues.
add_child(name,
cfg)[
"upvalue_type"] =
names.empty() ?
"config" :
"named tuple";
1248 for(std::size_t
i = 1;
i <= lua_rawlen(L, -1);
i++, lua_pop(L, 1)) {
1249 lua_rawgeti(L, idx,
i);
1252 cfg[
"upvalue_type"] =
"array";
1254 bool found_non_array =
false;
1255 for(lua_pushnil(L); lua_next(L, idx); lua_pop(L, 1)) {
1256 if(lua_type(L, -2) != LUA_TNUMBER) {
1257 found_non_array =
true;
1261 if(!found_non_array)
break;
1265 std::ostringstream os;
1266 os <<
"cannot serialize function with upvalue " << name <<
" = ";
1268 lua_pushvalue(L, idx);
1270 os << luaL_checkstring(L, -1);
1271 lua_pushboolean(L,
false);
1275 if(!upvalues.
empty())
data.add_child(
"upvalues", upvalues);
1283 lua_pushvalue(
mState, -1);
1286 int funcindex = lua_absindex(
mState, -1);
1287 for(
int i = 1;
i <=
info.nups;
i++) {
1288 std::string_view name = lua_getupvalue(
mState, funcindex,
i);
1290 if(name ==
"_ENV") {
1291 lua_pushglobaltable(
mState);
1292 }
else if(upvalues->has_attribute(name)) {
1294 }
else if(upvalues->has_child(name)) {
1295 const auto& child = upvalues->mandatory_child(name);
1296 if(child[
"upvalue_type"] ==
"array") {
1297 auto children = upvalues->child_range(name);
1298 lua_createtable(
mState, children.size(), 0);
1299 for(
const auto&
cfg : children) {
1303 }
else if(child[
"upvalue_type"] ==
"config") {
1305 }
else if(child[
"upvalue_type"] ==
"function") {
1307 }
else if(child[
"upvalue_type"] ==
"nil") {
1311 lua_setupvalue(
mState, funcindex,
i);
1319 int top = lua_gettop(
mState);
1323 lua_pushvalue(
mState, -1);
1330 error[
"name"] =
"execute_error";
1331 error[
"error"] =
e.what();
1335 result[
"ref"] =
cfg[
"ref"];
1337 lua_remove(
mState, top + 1);
1338 result[
"name"] =
"execute_result";
1339 for(
int i = top + 1;
i < lua_gettop(
mState);
i++) {
1342 case LUA_TNUMBER:
case LUA_TBOOLEAN:
case LUA_TSTRING:
1359 if(in_interpreter) {
1361 if(lua_setupvalue(
mState, -2, 1) ==
nullptr)
1364 lua_insert(
mState, -nArgs - 1);
1365 this->
protected_call(nArgs, in_interpreter ? LUA_MULTRET : 0, eh);
1381 std::string experiment =
"return ";
1383 int top = lua_gettop(
mState);
1390 this->
load_string(experiment.c_str(),
"interactive", eh);
1392 if(lua_setupvalue(
mState, -2, 1) ==
nullptr)
1396 if(lua_gettop(
mState) == top + 1) {
1406 int nRets = lua_gettop(
mState) - top - 1;
1410 int env_idx = lua_gettop(
mState);
1411 lua_pushvalue(
mState, top + 2);
1412 lua_setfield(
mState, -2,
"_");
1415 for(
int i = top + 2;
i < env_idx;
i++)
1418 lua_setfield(
mState, -2,
"_all");
1431 luaL_checkstring(L, 1);
1432 lua_rotate(L, 1, -1);
1435 lua_rotate(L, 1, 1);
1439 lua_call(L, lua_gettop(L) - 1, LUA_MULTRET);
1440 return lua_gettop(L);
1451 const char * m = luaL_checkstring(L, 1);
1453 return luaL_argerror(L, 1,
"found a null string argument to wesnoth require");
1458 lua_getglobal(L,
"wesnoth");
1459 lua_pushstring(L,
"package");
1461 lua_pushvalue(L, 1);
1467 lua_pushvalue(L, 1);
1475 DBG_LUA <<
"require: loaded a file, now calling it";
1483 lua_pushvalue(L, 1);
1484 lua_pushvalue(L, -2);
1488 lua_settable(L, -4);
1500 lua_createtable(L, palette.size(), 1);
1501 lua_rotate(L, -2, 1);
1502 lua_setfield(L, -2,
"name");
1503 for(std::size_t
i = 0;
i < palette.size();
i++) {
1504 tuple_builder.push(L);
1505 lua_pushinteger(L, palette[
i].r);
1506 lua_rawseti(L, -2, 1);
1507 lua_pushinteger(L, palette[
i].
g);
1508 lua_rawseti(L, -2, 2);
1509 lua_pushinteger(L, palette[
i].
b);
1510 lua_rawseti(L, -2, 3);
1511 lua_pushinteger(L, palette[
i].a);
1512 lua_rawseti(L, -2, 4);
1513 lua_rawseti(L, -2,
i);
1518 char const *m = luaL_checkstring(L, 2);
1519 lua_pushvalue(L, 2);
1532 #define GAME_CONFIG_SIMPLE_GETTER(name) \
1533 GAME_CONFIG_GETTER(#name, decltype(game_config::name), lua_kernel_base) { \
1535 return game_config::name; \
1555 if(luaL_newmetatable(L,
"color palettes")) {
1557 lua_setfield(L, -2,
"__index");
1559 lua_setmetatable(L, -2);
1565 lua_pushstring(L,
"red_green_scale");
1572 lua_pushstring(L,
"red_green_scale_text");
1579 lua_pushstring(L,
"blue_white_scale");
1586 lua_pushstring(L,
"blue_white_scale_text");
1628 lua_pushcfunction(L, luaopen_package);
1629 lua_pushstring(L,
"package");
1639 lua_pushstring(L,
"lua/core");
1641 cmd_log_ <<
"Error: Failed to load core.\n";
1651 std::vector<std::string> ret;
1655 int idx = lua_gettop(L);
1656 lua_getglobal(L,
"_G");
1659 while (lua_next(L, idx+1) != 0) {
1660 if (lua_isstring(L, -2)) {
1661 ret.push_back(lua_tostring(L,-2));
1674 std::vector<std::string> ret;
1675 std::string base_path = input;
1676 std::size_t last_dot = base_path.find_last_of(
'.');
1677 std::string partial_name = base_path.substr(last_dot + 1);
1678 base_path.erase(last_dot);
1679 std::string
load =
"return " + base_path;
1682 int save_stack = lua_gettop(L);
1683 int result = luaL_loadstring(L,
load.c_str());
1684 if(result != LUA_OK) {
1686 LOG_LUA <<
"Error when attempting tab completion:";
1687 LOG_LUA << luaL_checkstring(L, -1);
1689 lua_settop(L, save_stack);
1694 if(lua_istable(L, -1) || lua_isuserdata(L, -1)) {
1695 int top = lua_gettop(L);
1696 int obj = lua_absindex(L, -1);
1697 if(luaL_getmetafield(L, obj,
"__tab_enum") == LUA_TFUNCTION) {
1698 lua_pushvalue(L, obj);
1699 lua_pushlstring(L, partial_name.c_str(), partial_name.size());
1701 ret = lua_check<std::vector<std::string>>(L, -1);
1702 }
else if(lua_type(L, -1) != LUA_TTABLE) {
1703 LOG_LUA <<
"Userdata missing __tab_enum meta-function for tab completion";
1704 lua_settop(L, save_stack);
1709 for(lua_pushnil(L); lua_next(L, obj); lua_pop(L, 1)) {
1710 if(lua_type(L, -2) == LUA_TSTRING) {
1711 std::string attr = lua_tostring(L, -2);
1715 if(!isalpha(attr[0]) && attr[0] !=
'_') {
1718 if(std::any_of(attr.begin(), attr.end(), [](
char c){
1719 return !isalpha(c) && !isdigit(c) && c !=
'_';
1723 if(attr.substr(0, partial_name.size()) == partial_name) {
1724 ret.push_back(base_path +
"." + attr);
1730 lua_settop(L, save_stack);
1737 #pragma GCC diagnostic push
1738 #pragma GCC diagnostic ignored "-Wold-style-cast"
1742 #pragma GCC diagnostic pop
std::vector< std::string > names
A config object defines a single node in a WML file, with access to child nodes.
config & add_child(std::string_view key)
optional_config_impl< config > optional_child(std::string_view key, int n=0)
Equivalent to mandatory_child, but returns an empty optional if the nth child was not found.
static void rethrow()
Rethrows the stored exception.
void load_core()
Loads the "core" library into the Lua environment.
void run(char const *prog, const std::string &name, int nArgs=0)
Runs a plain script.
virtual void log_error(char const *msg, char const *context="Lua error")
Error reporting mechanisms, used by virtual methods protected_call and load_string.
int intf_dofile(lua_State *L)
Loads and executes a Lua file.
int impl_game_config_get(lua_State *L)
Gets some game_config data (__index metamethod).
int intf_require(lua_State *L)
Loads and executes a Lua file, if there is no corresponding entry in wesnoth.package.
void throwing_run(char const *prog, const std::string &name, int nArgs, bool in_interpreter=false)
Runs a plain script, but reports errors by throwing lua_error.
int intf_kernel_type(lua_State *L)
int impl_game_config_set(lua_State *L)
Sets some game_config data (__newindex metamethod).
void load_package()
Loads the package library into lua environment.
bool protected_call(int nArgs, int nRets, const error_handler &)
void add_log_to_console(const std::string &msg)
int impl_game_config_dir(lua_State *L)
Gets a list of game_config data (__dir metamethod).
int intf_show_lua_console(lua_State *L)
bool load_string(const std::string &prog, const std::string &name, const error_handler &, bool allow_unsafe=false)
std::vector< std::tuple< std::string, std::string > > registered_widget_definitions_
static lua_kernel_base *& get_lua_kernel_base_ptr(lua_State *L)
std::vector< std::string > get_global_var_names()
Get tab completion strings.
std::function< void(char const *, char const *)> error_handler
void run_lua_tag(const config &cfg)
Runs a [lua] tag.
bool load_binary(const config &func, const error_handler &)
virtual ~lua_kernel_base()
int intf_print(lua_State *L)
Replacement print function – instead of printing to std::cout, print to the command log.
void interactive_run(char const *prog)
Tests if a program resolves to an expression, and pretty prints it if it is, otherwise it runs it nor...
std::vector< std::string > get_attribute_names(const std::string &var_path)
Gets all attribute names of an extended variable name.
config run_binary_lua_tag(const config &cfg)
Runs a binary [lua] tag.
virtual uint32_t get_random_seed()
virtual void throw_exception(char const *msg, char const *context="Lua error")
virtual std::string my_name()
User-visible name of the lua kernel that they are talking to.
Efficiently creates new LUA "named tuples" with the specified field names.
const char * what() const noexcept
std::string generate(const std::map< std::string, std::string > &variables) const
virtual ~name_generator()
virtual std::string type() const
void read(const std::string &shroud_data)
void set_enabled(bool enabled)
bool value(int x, int y) const
std::string write() const
const std::string & str() const
Represents version numbers.
std::string str() const
Serializes the version number into string form.
unsigned int revision_level() const
Retrieves the revision level (x3 in "x1.x2.x3").
char special_version_separator() const
Retrieves the special version separator (e.g.
const std::string & special_version() const
Retrieves the special version suffix (e.g.
unsigned int minor_version() const
Retrieves the minor version number (x2 in "x1.x2.x3").
unsigned int major_version() const
Retrieves the major version number (x1 in "x1.x2.x3").
const std::vector< unsigned int > & components() const
Read-only access to all numeric components.
bool is_canonical() const
Whether the version number is considered canonical for mainline Wesnoth.
std::string deprecated_message(const std::string &elem_name, DEP_LEVEL level, const version_info &version, const std::string &detail)
DEP_LEVEL
See https://wiki.wesnoth.org/CompatibilityStandards for more info.
int(* lua_CFunction)(lua_State *L)
bool do_version_check(const version_info &a, VERSION_COMP_OP op, const version_info &b)
Interfaces for manipulating version numbers of engine, add-ons, etc.
const language_def & get_language()
Standard logging facilities (interface).
#define LOG_STREAM(level, domain)
void luaW_pushconfig(lua_State *L, const config &cfg)
Converts a config object to a Lua table pushed at the top of the stack.
int luaW_pcall_internal(lua_State *L, int nArgs, int nRets)
void push_error_handler(lua_State *L)
std::set< map_location > luaW_check_locationset(lua_State *L, int idx)
Converts a table of integer pairs to a set of map location objects.
bool luaW_toboolean(lua_State *L, int n)
int luaW_type_error(lua_State *L, int narg, const char *tname)
bool luaW_toscalar(lua_State *L, int index, config::attribute_value &v)
Converts the value at the top of the stack to an attribute value.
void luaW_pushscalar(lua_State *L, const config::attribute_value &v)
Converts an attribute value into a Lua object pushed at the top of the stack.
std::vector< std::string > luaW_to_namedtuple(lua_State *L, int idx)
Get the keys of a "named tuple" from the stack.
bool luaW_pcall(lua_State *L, int nArgs, int nRets, bool allow_wml_error)
Calls a Lua function stored below its nArgs arguments at the top of the stack.
bool luaW_toconfig(lua_State *L, int index, config &cfg)
Converts an optional table or vconfig to a config object.
int luaW_push_locationset(lua_State *L, const std::set< map_location > &locs)
Converts a set of map locations to a Lua table pushed at the top of the stack.
bool luaW_getglobal(lua_State *L, const std::vector< std::string > &path)
Pushes the value found by following the variadic names (char *), if the value is not nil.
t_string luaW_checktstring(lua_State *L, int index)
Converts a scalar to a translatable string.
#define return_string_attrib(name, accessor)
#define return_int_attrib(name, accessor)
#define return_bool_attrib(name, accessor)
static int intf_make_shroud_bitmap(lua_State *L)
static int impl_version_finalize(lua_State *L)
Destroy a version.
int dispatch(lua_State *L)
static int intf_name_generator(lua_State *L)
static lg::log_domain log_user("scripting/lua/user")
static int intf_current_version(lua_State *L)
Returns the current Wesnoth version.
static lg::log_domain log_scripting_lua("scripting/lua")
static int intf_parse_shroud_bitmap(lua_State *L)
static int intf_make_version(lua_State *L)
Builds a version from its component parts, or parses it from a string.
static int impl_version_dir(lua_State *L)
static int impl_version_get(lua_State *L)
Decomposes a version into its component parts.
static int impl_get_dir_suffix(lua_State *L)
static int impl_version_tostring(lua_State *L)
Convert a version to string form.
luaW_Registry & gameConfigReg()
static int intf_deprecated_message(lua_State *L)
Logs a deprecation message.
static int intf_pcall(lua_State *L)
Wrapper for pcall and xpcall functions to rethrow jailbreak exceptions.
static int intf_named_tuple(lua_State *L)
Converts a Lua array to a named tuple.
static void impl_warn(void *p, const char *msg, int tocont)
int(lua_kernel_base::* member_callback)(lua_State *L)
static const char * Version
static int intf_log(lua_State *L)
Logs a message Arg 1: (optional) Logger Arg 2: Message.
static int impl_palette_get(lua_State *L)
static int impl_is_deprecated(lua_State *L)
static const char * Interp
std::vector< std::string > luaW_get_attributes(lua_State *L, int idx)
This function does the actual work of grabbing all the attribute names.
static void push_color_palette(lua_State *L, const std::vector< color_t > &palette)
static int intf_std_print(lua_State *L)
static int intf_load(lua_State *L)
Replacement load function.
static int intf_ms_since_init(lua_State *L)
Returns the time stamp, exactly as [set_variable] time=stamp does.
static int intf_get_language(lua_State *L)
static int impl_name_generator_call(lua_State *L)
static int impl_name_generator_tostring(lua_State *L)
static void dir_meta_helper(lua_State *L, std::vector< std::string > &keys)
static int intf_object_dir(lua_State *L)
Prints out a list of keys available in an object.
static int intf_safe_tostring(lua_State *L)
#define GAME_CONFIG_SIMPLE_GETTER(name)
config luaW_serialize_function(lua_State *L, int func)
static int impl_name_generator_collect(lua_State *L)
static int impl_version_compare(lua_State *L)
Compares two versions.
#define GAME_CONFIG_GETTER(name, type, kernel_type)
void line(int from_x, int from_y, int to_x, int to_y)
Draw a line.
std::vector< color_t > red_green_scale_text
const version_info wesnoth_version(VERSION)
const std::vector< color_t > & tc_info(std::string_view name)
std::vector< color_t > blue_white_scale
std::vector< color_t > red_green_scale
std::vector< color_t > blue_white_scale_text
std::vector< game_tip > load(const config &cfg)
Loads the tips from a config.
void remove_single_widget_definition(const std::string &widget_type, const std::string &definition_id)
Removes a widget definition from the default GUI.
std::string register_metatables(lua_State *L)
int intf_textdomain(lua_State *L)
Creates an interface for gettext.
std::string register_gettext_metatable(lua_State *L)
Adds the gettext metatable.
std::string register_tstring_metatable(lua_State *L)
Adds the tstring metatable.
void register_metatable(lua_State *L)
int luaW_open(lua_State *L)
int load_file(lua_State *L)
Loads a Lua file and pushes the contents on the stack.
int luaW_open(lua_State *L)
int show_lua_console(lua_State *, lua_kernel_base *lk)
int intf_get_relative_dir(lua_State *L)
Expose map_location get_relative_dir.
int intf_vector_negation(lua_State *L)
Expose map_location::vector_negation to lua.
int intf_distance_between(lua_State *L)
Expose map_location distance_between.
int intf_get_in_cubic(lua_State *L)
Expose map_location to_cubic.
int intf_tiles_adjacent(lua_State *L)
Expose map_location tiles_adjacent.
int intf_vector_diff(lua_State *L)
Expose map_location::vector_difference to lua.
int intf_get_from_cubic(lua_State *L)
Expose map_location from_cubic.
int intf_vector_sum(lua_State *L)
Expose map_location::vector_sum to lua.
int intf_get_tile_ring(lua_State *L)
Expose map_location get_tile_ring.
int intf_rotate_right_around_center(lua_State *L)
Expose map_location::rotate_right_around_center to lua.
int intf_get_tiles_in_radius(lua_State *L)
Expose map_location get_tiles_in_radius.
int intf_get_adjacent_tiles(lua_State *L)
Expose map_location get_adjacent_tiles.
int intf_get_direction(lua_State *L)
Expose map_location::get_direction function to lua Arg 1: a location Arg 2: a direction Arg 3: (optio...
int luaW_open(lua_State *L)
void load_tables(lua_State *L)
Creates the metatable for RNG objects, and adds the Rng table which contains the constructor.
int luaW_open(lua_State *L)
int luaW_open(lua_State *L)
rng * generator
This generator is automatically synced during synced context.
std::size_t index(std::string_view str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
std::vector< std::string > parenthetical_split(std::string_view val, const char separator, std::string_view left, std::string_view right, const int flags)
Splits a string based either on a separator, except then the text appears within specified parenthesi...
std::vector< std::string > split(const config_attribute_value &val)
std::string to_string(const Range &range, const Func &op)
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
void lua_push(lua_State *L, const T &val)
static std::string flush(std::ostringstream &s)
#define ON_SCOPE_EXIT(...)
Run some arbitrary code (a lambda) when the current scope exits The lambda body follows this header,...
Error used to report an error in a lua script or in the lua interpreter.
Holds a lookup table for members of one type of object.
int dir(lua_State *L)
Implement __dir metamethod.
int set(lua_State *L)
Implement __newindex metamethod.
int get(lua_State *L)
Implement __index metamethod.
external_log_type external_log_
static map_location::direction n