The Battle for Wesnoth  1.19.27+dev
lua_kernel_base.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2025
3  by Chris Beck <render787@gmail.com>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
17 
18 #include "game_config.hpp"
19 #include "game_errors.hpp"
20 #include "gui/core/gui_definition.hpp" // for remove_single_widget_definition
21 #include "log.hpp"
22 #include "lua_jailbreak_exception.hpp" // for lua_jailbreak_exception
23 #include "seed_rng.hpp"
24 #include "deprecation.hpp"
25 #include "language.hpp" // for get_language
26 #include "team.hpp" // for shroud_map
27 
28 #ifdef DEBUG_LUA
29 #include "scripting/debug_lua.hpp"
30 #endif
31 
33 #include "scripting/lua_color.hpp"
34 #include "scripting/lua_common.hpp"
38 #include "scripting/lua_gui2.hpp"
39 #include "scripting/lua_wml.hpp"
42 #include "scripting/lua_mathx.hpp"
43 #include "scripting/lua_rng.hpp"
44 #include "scripting/lua_widget.hpp"
45 #include "scripting/push_check.hpp"
46 
47 #include "game_version.hpp" // for do_version_check, etc
48 
49 #include <functional>
50 #include "utils/name_generator.hpp"
53 #include "utils/scope_exit.hpp"
54 
55 #include <SDL3/SDL_timer.h>
56 
57 #include <cstring>
58 #include <string>
59 #include <sstream>
60 #include <vector>
61 #include <numeric>
62 
63 #include "lua/wrapper_lualib.h"
64 
65 static lg::log_domain log_scripting_lua("scripting/lua");
66 static lg::log_domain log_user("scripting/lua/user");
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)
71 
72 // Registry key for metatable
73 static const char * Gen = "name generator";
74 static const char * Version = "version";
75 // Registry key for lua interpreter environment
76 static const char * Interp = "lua interpreter";
77 
78 // Callback implementations
79 
80 /**
81  * Compares two versions.
82  * - Args 1,2: version strings
83  * - Ret 1: comparison result
84  */
85 template<VERSION_COMP_OP vop>
86 static int impl_version_compare(lua_State* L)
87 {
88  version_info& v1 = *static_cast<version_info*>(luaL_checkudata(L, 1, Version));
89  version_info& v2 = *static_cast<version_info*>(luaL_checkudata(L, 2, Version));
90  const bool result = do_version_check(v1, vop, v2);
91  lua_pushboolean(L, result);
92  return 1;
93 }
94 
95 /**
96  * Decomposes a version into its component parts
97  */
98 static int impl_version_get(lua_State* L)
99 {
100  version_info& vers = *static_cast<version_info*>(luaL_checkudata(L, 1, Version));
101  if(lua_isinteger(L, 2)) {
102  int n = lua_tointeger(L, 2) - 1;
103  auto& components = vers.components();
104  if(n >= 0 && std::size_t(n) < components.size()) {
105  lua_pushinteger(L, vers.components()[n]);
106  } else {
107  lua_pushnil(L);
108  }
109  return 1;
110  }
111  char const *m = luaL_checkstring(L, 2);
112  return_int_attrib("major", vers.major_version());
113  return_int_attrib("minor", vers.minor_version());
114  return_int_attrib("revision", vers.revision_level());
115  return_bool_attrib("is_canonical", vers.is_canonical());
116  return_string_attrib("special", vers.special_version());
117  if(char sep = vers.special_version_separator()) {
118  return_string_attrib("sep", std::string(1, sep));
119  } else if(strcmp(m, "sep") == 0) {
120  lua_pushnil(L);
121  return 1;
122  }
123  return 0;
124 }
125 
126 static int impl_version_dir(lua_State* L)
127 {
128  static const std::vector<std::string> fields{"major", "minor", "revision", "is_canonical", "special", "sep"};
129  lua_push(L, fields);
130  return 1;
131 }
132 
133 /**
134  * Destroy a version
135  */
136 static int impl_version_finalize(lua_State* L)
137 {
138  version_info* vers = static_cast<version_info*>(luaL_checkudata(L, 1, Version));
139  vers->~version_info();
140  return 0;
141 }
142 
143 /**
144  * Convert a version to string form
145  */
146 static int impl_version_tostring(lua_State* L)
147 {
148  version_info& vers = *static_cast<version_info*>(luaL_checkudata(L, 1, Version));
149  lua_push(L, vers.str());
150  return 1;
151 }
152 
153 /**
154  * Builds a version from its component parts, or parses it from a string
155  */
156 static int intf_make_version(lua_State* L)
157 {
158  // If passed a version, just return it unchanged
159  if(luaL_testudata(L, 1, Version)) {
160  lua_settop(L, 1);
161  return 1;
162  }
163  // If it's a string, parse it; otherwise build from components
164  // The components method only supports canonical versions
165  if(lua_type(L, 1) == LUA_TSTRING) {
166  new(L) version_info(lua_check<std::string>(L, 1));
167  } else {
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])) {
173  sep.push_back('+');
174  } else {
175  sep.push_back(special[0]);
176  special = special.substr(1);
177  }
178  } else {
179  sep.push_back(0);
180  }
181  new(L) version_info(major, minor, rev, sep[0], special);
182  }
183  if(luaL_newmetatable(L, Version)) {
184  static const luaL_Reg metafuncs[] {
185  { "__index", &impl_version_get },
186  { "__dir", &impl_version_dir },
187  { "__tostring", &impl_version_tostring },
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> },
191  { "__gc", &impl_version_finalize },
192  { nullptr, nullptr }
193  };
194  luaL_setfuncs(L, metafuncs, 0);
195  luaW_table_set<std::string>(L, -1, "__metatable", Version);
196  }
197  lua_setmetatable(L, -2);
198  return 1;
199 }
200 
201 /**
202  * Returns the current Wesnoth version
203  */
204 static int intf_current_version(lua_State* L) {
205  lua_settop(L, 0);
208  return 1;
209 }
210 
211 static int intf_safe_tostring(lua_State* L)
212 {
213  // tostring requires one argument. Report an error when the stack has no first value.
214  luaL_checkany(L, 1);
215 
216  // Shared __tostring methods make Lua's standard conversion safe for functions,
217  // threads, and light userdata. Tables and full userdata use individual metatables,
218  // so values without __tostring are handled below instead of passed to luaL_tolstring.
219 
220  // If the value defines __tostring, use it exactly as Lua normally would.
221  // The generic type name below is only for values without their own string representation.
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) {
226  lua_pop(L, 1);
227  }
228  luaL_tolstring(L, 1, nullptr);
229  return 1;
230  }
231 
232  // Named metatables already provide base descriptions. Reuse them for stringification.
233  const int name_type = luaL_getmetafield(L, 1, "__name");
234  if(name_type == LUA_TSTRING) {
235  return 1;
236  }
237  if(name_type != LUA_TNIL) {
238  lua_pop(L, 1);
239  }
240  lua_pushstring(L, luaL_typename(L, 1));
241  return 1;
242 }
243 
244 static int intf_std_print(lua_State* L)
245 {
246  // Lua's print calls luaL_tolstring directly instead of the global
247  // tostring function. Tables and userdata without __tostring would therefore
248  // include memory addresses. Use Wesnoth's replacement without changing the
249  // order in which arguments are converted and written.
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);
254  lua_pushvalue(L, i);
255  const int status = lua_pcall(L, 1, 1, 0);
256  // A jailbreak exception must not be returned as a normal Lua error.
258  if(status != LUA_OK) {
259  return lua_error(L);
260  }
261 
262  std::size_t length = 0;
263  const char* string = luaL_checklstring(L, -1, &length);
264  if(i > 1) {
265  lua_writestring("\t", 1);
266  }
267  lua_writestring(string, length);
268  lua_pop(L, 1);
269  }
270  lua_pop(L, 1);
271  lua_writeline();
272  return 0;
273 }
274 
275 /**
276  * Replacement print function -- instead of printing to std::cout, print to the command log.
277  * Intended to be bound to this' command_log at registration time.
278  */
280 {
281  DBG_LUA << "intf_print called:";
282  std::size_t nargs = lua_gettop(L);
283 
284  lua_getglobal(L, "tostring");
285  for (std::size_t i = 1; i <= nargs; ++i) {
286  lua_pushvalue(L, -1); // function to call: "tostring"
287  lua_pushvalue(L, i); // value to pass through tostring() before printing
288  lua_call(L, 1, 1);
289  const char * str = lua_tostring(L, -1);
290  if (!str) {
291  LOG_LUA << "'tostring' must return a value to 'print'";
292  str = "";
293  }
294  if (i > 1) {
295  cmd_log_ << "\t"; //separate multiple args with tab character
296  }
297  cmd_log_ << str;
298  DBG_LUA << "'" << str << "'";
299  lua_pop(L, 1); // Pop the output of tostrring()
300  }
301  lua_pop(L, 1); // Pop 'tostring' global
302 
303  cmd_log_ << "\n";
304  DBG_LUA;
305 
306  return 0;
307 }
308 
309 static void impl_warn(void* p, const char* msg, int tocont) {
310  static const char*const prefix = "Warning:\n ";
311  static std::ostringstream warning(prefix);
312  warning.seekp(0, std::ios::end);
313  warning << msg << ' ';
314  if(!tocont) {
315  auto L = reinterpret_cast<lua_State*>(p);
316  luaW_getglobal(L, "debug", "traceback");
317  lua_push(L, warning.str());
318  lua_pushinteger(L, 2);
319  lua_call(L, 2, 1);
320  auto& lk = lua_kernel_base::get_lua_kernel<lua_kernel_base>(L);
321  lk.add_log_to_console(luaL_checkstring(L, -1));
322  warning.str(prefix);
323  }
324 }
325 
326 void lua_kernel_base::add_log_to_console(const std::string& msg) {
327  cmd_log_ << msg << "\n";
328  DBG_LUA << "'" << msg << "'";
329 }
330 
331 /**
332  * Replacement load function. Mostly the same as regular load, but disallows loading binary chunks
333  * due to CVE-2018-1999023.
334  */
335 static int intf_load(lua_State* L)
336 {
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);
341 
342  if(mode != "t") {
343  return luaL_argerror(L, 3, "binary chunks are not allowed for security reasons");
344  }
345 
346  int result = luaL_loadbufferx(L, chunk.data(), chunk.length(), name, "t");
347  if(result != LUA_OK) {
348  lua_pushnil(L);
349  // Move the nil as the first return value, like Lua's own load() does.
350  lua_insert(L, -2);
351 
352  return 2;
353  }
354 
355  if(override_env) {
356  // Copy "env" to the top of the stack.
357  lua_pushvalue(L, 4);
358  // Set "env" as the first upvalue.
359  const char* upvalue_name = lua_setupvalue(L, -2, 1);
360  if(upvalue_name == nullptr) {
361  // lua_setupvalue() didn't remove the copy of "env" from the stack, so we need to do it ourselves.
362  lua_pop(L, 1);
363  }
364  }
365 
366  return 1;
367 }
368 
369 /**
370  * Wrapper for pcall and xpcall functions to rethrow jailbreak exceptions
371  */
372 static int intf_pcall(lua_State *L)
373 {
374  lua_CFunction function = lua_tocfunction(L, lua_upvalueindex(1));
375  assert(function); // The upvalue should be Lua's pcall or xpcall, or else something is very wrong.
376 
377  int nRets = function(L);
378 
379  // If a jailbreak exception was stored while running (x)pcall, rethrow it so Lua doesn't continue.
381 
382  return nRets;
383 }
384 
385 // The show lua console callback is similarly a method of lua kernel
387 {
388  if (cmd_log_.external_log_) {
389  std::string message = "There is already an external logger attached to this lua kernel, you cannot open the lua console right now.";
390  log_error(message.c_str());
391  cmd_log_ << message << "\n";
392  return 0;
393  }
394 
395  return lua_gui2::show_lua_console(L, this);
396 }
397 
398 static int impl_name_generator_call(lua_State *L)
399 {
400  name_generator* gen = static_cast<name_generator*>(luaL_checkudata(L, 1, Gen));
401  lua_pushstring(L, gen->generate().c_str());
402  return 1;
403 }
404 
405 static int impl_name_generator_tostring(lua_State *L)
406 {
407  name_generator* gen = static_cast<name_generator*>(luaL_checkudata(L, 1, Gen));
408  luaW_getglobal(L, "string", "format");
409  lua_pushstring(L, "%s: %s");
410  lua_pushstring(L, Gen);
411  lua_pushstring(L, gen->type().c_str());
412  lua_call(L, 2, 1);
413  return 1;
414 }
415 
416 static int impl_name_generator_collect(lua_State *L)
417 {
418  name_generator* gen = static_cast<name_generator*>(luaL_checkudata(L, 1, Gen));
419  gen->~name_generator();
420  return 0;
421 }
422 
423 static int intf_name_generator(lua_State *L)
424 {
425  std::string type = luaL_checkstring(L, 1);
426  name_generator* gen = nullptr;
427  try {
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);
432  } else {
433  input = utils::parenthetical_split(luaW_checktstring(L, 2).str(), ',');
434  }
435  int chain_sz = luaL_optinteger(L, 3, 2);
436  int max_len = luaL_optinteger(L, 4, 12);
437  gen = new(L) markov_generator(input, chain_sz, max_len);
438  // Ensure the pointer didn't change when cast
439  assert(static_cast<void*>(gen) == dynamic_cast<markov_generator*>(gen));
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)");
446  return lua_error(L);
447  }
448  if(lua_isstring(L, -1)) {
449  auto& productions = data[lua_tostring(L,-2)] = utils::split(luaW_checktstring(L,-1).str(), '|');
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");
452  }
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)];
456  std::transform(split.begin(), split.end(), std::back_inserter(productions), std::mem_fn(&t_string::str));
457  } else {
458  lua_pushstring(L, "CFG generator: invalid nonterminal value (must be a string or list of strings)");
459  return lua_error(L);
460  }
461  }
462  if(!data.empty()) {
463  gen = new(L) context_free_grammar_generator(data);
464  }
465  } else {
467  }
468  if(gen) {
469  assert(static_cast<void*>(gen) == dynamic_cast<context_free_grammar_generator*>(gen));
470  }
471  } else {
472  return luaL_argerror(L, 1, "should be either 'markov_chain' or 'context_free'");
473  }
474  }
475  catch (const name_generator_invalid_exception& ex) {
476  lua_pushstring(L, ex.what());
477  return lua_error(L);
478  }
479 
480  // We set the metatable now, even if the generator is invalid, so that it
481  // will be properly collected if it was invalid.
482  luaL_getmetatable(L, Gen);
483  lua_setmetatable(L, -2);
484 
485  return 1;
486 }
487 
488 /**
489 * Logs a message
490 * Arg 1: (optional) Logger
491 * Arg 2: Message
492 */
493 static int intf_log(lua_State *L) {
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') {
497  msg += '\n';
498  }
499 
500  if(logger == "err" || logger == "error") {
501  LOG_STREAM(err, log_user) << msg;
502  } else if(logger == "warn" || logger == "wrn" || logger == "warning") {
504  } else if((logger == "debug" || logger == "dbg")) {
506  } else {
508  }
509  return 0;
510 }
511 
512 /**
513  * Logs a deprecation message. See deprecation.cpp for details
514  * Arg 1: Element to be deprecated.
515  * Arg 2: Deprecation level.
516  * Arg 3: Version when element may be removed.
517  * Arg 4: Additional detail message.
518  */
519 static int intf_deprecated_message(lua_State* L) {
520  const std::string elem = luaL_checkstring(L, 1);
521  // This could produce an invalid deprecation level, but that possibility is handled in deprecated_message()
522  const DEP_LEVEL level = DEP_LEVEL(luaL_checkinteger(L, 2));
523  const std::string ver_str = lua_isnoneornil(L, 3) ? "" : luaL_checkstring(L, 3);
524  const std::string detail = luaW_checktstring(L, 4);
525  const version_info ver = ver_str.empty() ? game_config::wesnoth_version.str() : ver_str;
526  const std::string msg = deprecated_message(elem, level, ver, detail);
527  if(level < DEP_LEVEL::INDEFINITE || level >= DEP_LEVEL::REMOVED) {
528  // Invalid deprecation level or level 4 deprecation should raise an interpreter error
529  lua_push(L, msg);
530  return lua_error(L);
531  }
532  lua_warning(L, msg.c_str(), false);
533  return 0;
534 }
535 
536 /**
537  * Converts a Lua array to a named tuple.
538  * Arg 1: A Lua array
539  * Arg 2: An array of strings
540  * Ret: A copy of arg 1 that's now a named tuple with the names in arg 2.
541  * The copy will only include the array portion of the input array.
542  * Any non-integer keys or non-consecutive keys will be gone.
543  * Note: This exists so that wml.tag can use it but is not really intended as a public API.
544  */
545 static int intf_named_tuple(lua_State* L)
546 {
547  if(!lua_istable(L, 1)) {
548  return luaW_type_error(L, 1, lua_typename(L, LUA_TTABLE));
549  }
550  auto names = lua_check<std::vector<std::string>>(L, 2);
551  lua_len(L, 1);
552  int len = luaL_checkinteger(L, -1);
553  lua_named_tuple_builder{ names }.push(L);
554  for(int i = 1; i <= std::max<int>(len, names.size()); i++) {
555  lua_geti(L, 1, i);
556  lua_seti(L, -2, i);
557  }
558  return 1;
559 }
560 
561 static int intf_parse_shroud_bitmap(lua_State* L)
562 {
563  shroud_map temp;
564  temp.set_enabled(true);
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)) {
570  locs.emplace(x, y, wml_loc());
571  }
572  }
573  }
574  luaW_push_locationset(L, locs);
575  return 1;
576 }
577 
578 static int intf_make_shroud_bitmap(lua_State* L)
579 {
580  shroud_map temp;
581  temp.set_enabled(true);
582  auto locs = luaW_check_locationset(L, 1);
583  for(const auto& loc : locs) {
584  temp.clear(loc.wml_x(), loc.wml_y());
585  }
586  lua_push(L, temp.write());
587  return 1;
588 }
589 
590 /**
591 * Returns the time stamp, exactly as [set_variable] time=stamp does.
592 * - Ret 1: integer
593 */
594 static int intf_ms_since_init(lua_State *L) {
595  lua_pushinteger(L, SDL_GetTicks());
596  return 1;
597 }
598 
599 static int intf_get_language(lua_State* L)
600 {
601  lua_push(L, get_language().localename);
602  return 1;
603 }
604 
605 static void dir_meta_helper(lua_State* L, std::vector<std::string>& keys)
606 {
607  switch(luaL_getmetafield(L, -1, "__dir")) {
608  case LUA_TFUNCTION:
609  lua_pushvalue(L, 1);
610  lua_push(L, keys);
611  if(lua_pcall(L, 2, 1, 0) == LUA_OK) {
612  keys = lua_check<std::vector<std::string>>(L, -1);
613  } else {
614  lua_warning(L, "wesnoth.print_attributes: __dir metamethod raised an error", false);
615  }
616  break;
617  case LUA_TTABLE:
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));
620  break;
621  }
622  lua_pop(L, 1);
623 }
624 
625 // This is a separate function so I can use a protected call on it to catch errors.
626 static int impl_is_deprecated(lua_State* L)
627 {
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) {
633  auto deprecated = luaW_toboolean(L, -1);
634  lua_pushboolean(L, deprecated);
635  return 1;
636  }
637  lua_pop(L, 1);
638  }
639  lua_pushboolean(L, false);
640  return 1;
641 }
642 
643 // This is also a separate function so I can use a protected call on it to catch errors.
644 static int impl_get_dir_suffix(lua_State*L)
645 {
646  auto key = luaL_checkstring(L, 2);
647  std::string suffix = " ";
648  auto type = lua_getfield(L, 1, key);
649  if(type == LUA_TTABLE) {
650  suffix = "†";
651  } else if(type == LUA_TFUNCTION) {
652  suffix = "Æ’";
653  } else if(type == LUA_TUSERDATA) {
654  lua_getglobal(L, "getmetatable");
655  lua_pushvalue(L, -2);
656  lua_call(L, 1, 1);
657  if(lua_type(L, -1) == LUA_TSTRING) {
658  auto meta = lua_check<std::string>(L, -1);
659  if(meta == "function") {
660  suffix = "Æ’";
661  }
662  }
663  lua_pop(L, 1);
664  if(suffix.size() == 1) {
665  // ie, the above block didn't identify it as a function
666  if(auto t = luaL_getmetafield(L, -1, "__dir_tablelike"); t == LUA_TBOOLEAN) {
667  if(luaW_toboolean(L, -1)) {
668  suffix = "†";
669  }
670  lua_pop(L, 1);
671  } else if(t != LUA_TNIL) {
672  lua_pop(L, 1);
673  }
674  }
675  }
676  suffix = " " + suffix;
677  lua_pushlstring(L, suffix.c_str(), suffix.size());
678  return 1;
679 }
680 
681 /**
682  * This function does the actual work of grabbing all the attribute names.
683  * It's a separate function so that it can be used by tab-completion as well.
684  */
685 std::vector<std::string> luaW_get_attributes(lua_State* L, int idx)
686 {
687  if(idx < 0 && idx >= -lua_gettop(L)) {
688  idx = lua_absindex(L, idx);
689  }
690  std::vector<std::string> keys;
691  if(lua_istable(L, idx)) {
692  // Walk the metatable chain (as long as __index is a table)...
693  // If we reach an __index that's a function, check for a __dir metafunction.
694  int save_top = lua_gettop(L);
695  lua_pushvalue(L, idx);
696  ON_SCOPE_EXIT(&) {
697  lua_settop(L, save_top);
698  };
699  do {
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));
704  }
705  }
706  // Two possible exit cases:
707  // 1. getmetafield returns TNIL because there is no __index
708  // In this case, the stack is unchanged, so the while condition is still true.
709  // 2. The __index is not a table
710  // In this case, obviously the while condition fails
711  if(luaL_getmetafield(L, table_idx, "__index") == LUA_TNIL) break;
712  } while(lua_istable(L, -1));
713  if(lua_isfunction(L, -1)) {
714  lua_pop(L, 1);
715  dir_meta_helper(L, keys);
716  }
717  } else if(lua_isuserdata(L, idx) && !lua_islightuserdata(L, idx)) {
718  lua_pushvalue(L, idx);
719  dir_meta_helper(L, keys);
720  lua_pop(L, 1);
721  }
722  // Sort and remove any duplicates
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) {
727  return true;
728  }
729  int save_top = lua_gettop(L);
730  ON_SCOPE_EXIT(&) {
731  lua_settop(L, save_top);
732  };
733  // Exclude deprecated elements
734  // Some keys may be write-only, which would raise an exception here
735  // In that case we just ignore it and assume not deprecated
736  // (the __dir metamethod would be responsible for excluding deprecated write-only keys)
737  lua_pushcfunction(L, impl_is_deprecated);
738  lua_pushvalue(L, idx);
739  lua_push(L, key);
740  if(lua_pcall(L, 2, 1, 0) == LUA_OK) {
741  return luaW_toboolean(L, -1);
742  }
743  return false;
744  });
745  keys.erase(new_end, keys.end());
746  return keys;
747 }
748 
749 /**
750  * Prints out a list of keys available in an object.
751  * A list of keys is gathered from the following sources:
752  * - For a table, all keys defined in the table
753  * - Any keys accessible through the metatable chain (if __index on the metatable is a table)
754  * - The output of the __dir metafunction
755  * - Filtering out any keys beginning with two underscores
756  * - Filtering out any keys for which object[key].__deprecated exists and is true
757  * The list is then sorted alphabetically and formatted into columns.
758  * - Arg 1: Any object
759  * - Arg 2: (optional) Function to use for output; defaults to _G.print
760  */
761 static int intf_object_dir(lua_State* L)
762 {
763  if(lua_isnil(L, 1)) return luaL_argerror(L, 1, "Can't dir() nil");
764  if(!lua_isfunction(L, 2)) {
765  luaW_getglobal(L, "print");
766  }
767  int fcn_idx = lua_gettop(L);
768  auto keys = luaW_get_attributes(L, 1);
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());
771  });
772  // Let's limit to about 80 characters of total width with minimum 3 characters padding between columns
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;
779  line.fill(' ');
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);
783  ON_SCOPE_EXIT(&) {
784  lua_settop(L, save_top);
785  };
786  lua_pushcfunction(L, impl_get_dir_suffix);
787  lua_pushvalue(L, 1);
788  const auto& key = keys[j + i * n_cols];
789  lua_pushlstring(L, key.c_str(), key.size());
790  std::string suffix = " !"; // Exclamation mark to indicate an error
791  if(lua_pcall(L, 2, 1, 0) == LUA_OK) {
792  suffix = luaL_checkstring(L, -1);
793  }
794  // This weird calculation is because width counts in bytes, not code points
795  // Since the suffix is a Unicode character, that messes up the alignment
796  line.width(col_width - SUFFIX_PADDING + suffix.size());
797  // Concatenate key and suffix beforehand so they share the same field width.
798  line << (key + suffix) << std::flush;
799  }
800  lua_pushvalue(L, fcn_idx);
801  lua_push(L, line.str());
802  lua_call(L, 1, 0);
803  }
804  return 0;
805 }
806 
807 // End Callback implementations
808 
809 // Template which allows to push member functions to the lua kernel base into lua as C functions, using a shim
810 typedef int (lua_kernel_base::*member_callback)(lua_State *L);
811 
812 template <member_callback method>
813 int dispatch(lua_State *L) {
814  return ((lua_kernel_base::get_lua_kernel<lua_kernel_base>(L)).*method)(L);
815 }
816 
817 // Ctor, initialization
819  : mState(luaL_newstate())
820  , cmd_log_()
821 {
823  lua_State *L = mState;
824 
825  cmd_log_ << "Initializing " << my_name() << "...\n";
826 
827  // Define the CPP_function metatable ( so we can override print to point to a C++ member function, add certain functions for this kernel, etc. )
828  // Do it first of all in case C++ functions are ever used in the core Wesnoth libs loaded in the next step
829  cmd_log_ << "Adding boost function proxy...\n";
830 
832 
833  // Open safe libraries.
834  // Debug and OS are not, but most of their functions will be disabled below.
835  cmd_log_ << "Adding standard libs...\n";
836 
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 }, // added in Lua 5.3
846  // Wesnoth libraries
847  { "stringx",lua_stringx::luaW_open },
848  { "mathx", lua_mathx::luaW_open },
849  { "wml", lua_wml::luaW_open },
850  { "gui", lua_gui2::luaW_open },
851  { "filesystem", lua_fileops::luaW_open },
852  { nullptr, nullptr }
853  };
854  for (luaL_Reg const *lib = safe_libs; lib->func; ++lib)
855  {
856  luaL_requiref(L, lib->name, lib->func, strlen(lib->name));
857  lua_pop(L, 1); /* remove lib */
858  }
859 
860  // luaopen_base installs the standard tostring function, so install the replacement
861  // after library initialization and before any core or scenario Lua code can run.
862  lua_pushcfunction(L, intf_safe_tostring);
863  lua_setglobal(L, "tostring");
864 
865  // Disable functions from os which we don't want.
866  lua_getglobal(L, "os");
867  lua_pushnil(L);
868  while(lua_next(L, -2) != 0) {
869  lua_pop(L, 1);
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;
873  lua_pushnil(L);
874  lua_setfield(L, -3, function);
875  }
876  lua_pop(L, 1);
877 
878  // Delete dofile and loadfile.
879  lua_pushnil(L);
880  lua_setglobal(L, "dofile");
881  lua_pushnil(L);
882  lua_setglobal(L, "loadfile");
883 
884  // Store the error handler.
885  cmd_log_ << "Adding error handler...\n";
887 
888 
889  lua_settop(L, 0);
890 
891  // Add some callback from the wesnoth lib
892  cmd_log_ << "Registering basic wesnoth API...\n";
893 
894  static luaL_Reg const callbacks[] {
895  { "deprecated_message", &intf_deprecated_message },
896  { "textdomain", &lua_common::intf_textdomain },
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> },
900  { "compile_formula", &lua_formula_bridge::intf_compile_formula},
901  { "eval_formula", &lua_formula_bridge::intf_eval_formula},
902  { "name_generator", &intf_name_generator },
903  { "named_tuple", &intf_named_tuple },
904  { "log", &intf_log },
905  { "ms_since_init", &intf_ms_since_init },
906  { "get_language", &intf_get_language },
907  { "version", &intf_make_version },
908  { "current_version", &intf_current_version },
909  { "print_attributes", &intf_object_dir },
910  { nullptr, nullptr }
911  };
912 
913  lua_getglobal(L, "wesnoth");
914  if (!lua_istable(L,-1)) {
915  lua_newtable(L);
916  }
917  luaL_setfuncs(L, callbacks, 0);
918  //lua_cpp::set_functions(L, cpp_callbacks, 0);
919  lua_setglobal(L, "wesnoth");
920 
921  // Create the gettext metatable.
923  // Create the tstring metatable.
925 
927 
928  // Override the print function
929  cmd_log_ << "Redirecting print function...\n";
930 
931  lua_pushcfunction(L, intf_std_print);
932  lua_setglobal(L, "std_print");
933  lua_settop(L, 0); //clear stack, just to be sure
934 
935  lua_setwarnf(L, &::impl_warn, L);
936  lua_pushcfunction(L, &dispatch<&lua_kernel_base::intf_print>);
937  lua_setglobal(L, "print");
938 
939  lua_pushcfunction(L, intf_load);
940  lua_setglobal(L, "load");
941  lua_pushnil(L);
942  lua_setglobal(L, "loadstring");
943 
944  // Wrap the pcall and xpcall functions
945  cmd_log_ << "Wrapping pcall and xpcall functions...\n";
946  lua_getglobal(L, "pcall");
947  lua_pushcclosure(L, intf_pcall, 1);
948  lua_setglobal(L, "pcall");
949  lua_getglobal(L, "xpcall");
950  lua_pushcclosure(L, intf_pcall, 1);
951  lua_setglobal(L, "xpcall");
952 
953  cmd_log_ << "Initializing package repository...\n";
954  // Create the package table.
955  lua_getglobal(L, "wesnoth");
956  lua_newtable(L);
957  lua_setfield(L, -2, "package");
958  lua_pop(L, 1);
959  lua_settop(L, 0);
960  lua_pushstring(L, "lua/package.lua");
961  int res = intf_require(L);
962  if(res != 1) {
963  cmd_log_ << "Error: Failed to initialize package repository. Falling back to less flexible C++ implementation.\n";
964  }
965 
966  // Get some callbacks for map locations
967  cmd_log_ << "Adding map table...\n";
968 
969  static luaL_Reg const map_callbacks[] {
970  { "get_direction", &lua_map_location::intf_get_direction },
971  { "hex_vector_sum", &lua_map_location::intf_vector_sum },
972  { "hex_vector_diff", &lua_map_location::intf_vector_diff },
973  { "hex_vector_negation", &lua_map_location::intf_vector_negation },
974  { "rotate_right_around_center", &lua_map_location::intf_rotate_right_around_center },
975  { "are_hexes_adjacent", &lua_map_location::intf_tiles_adjacent },
976  { "get_adjacent_hexes", &lua_map_location::intf_get_adjacent_tiles },
977  { "get_hexes_in_radius", &lua_map_location::intf_get_tiles_in_radius },
978  { "get_hexes_at_radius", &lua_map_location::intf_get_tile_ring },
979  { "distance_between", &lua_map_location::intf_distance_between },
980  { "get_cubic", &lua_map_location::intf_get_in_cubic },
981  { "from_cubic", &lua_map_location::intf_get_from_cubic },
982  { "get_relative_dir", &lua_map_location::intf_get_relative_dir },
983  // Shroud bitmaps
984  {"parse_bitmap", intf_parse_shroud_bitmap},
985  {"make_bitmap", intf_make_shroud_bitmap},
986  { nullptr, nullptr }
987  };
988 
989  // Create the map_location table.
990  lua_getglobal(L, "wesnoth");
991  lua_newtable(L);
992  luaL_setfuncs(L, map_callbacks, 0);
993  lua_setfield(L, -2, "map");
994  lua_pop(L, 1);
995 
996  // Create the game_config variable with its metatable.
997  cmd_log_ << "Adding game_config table...\n";
998 
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");
1014  lua_pop(L, 1);
1015 
1016  // Add mersenne twister rng wrapper
1017  cmd_log_ << "Adding rng tables...\n";
1019 
1020  cmd_log_ << "Adding name generator metatable...\n";
1021  luaL_newmetatable(L, Gen);
1022  static luaL_Reg const generator[] {
1023  { "__call", &impl_name_generator_call},
1024  { "__tostring", &impl_name_generator_tostring},
1025  { "__gc", &impl_name_generator_collect},
1026  { nullptr, nullptr}
1027  };
1028  luaL_setfuncs(L, generator, 0);
1029  lua_pushstring(L, Gen);
1030  lua_setfield(L, -2, "__metatable");
1031 
1032  // Create formula bridge metatables
1034 
1036 
1037  // Create the Lua interpreter table
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";
1040  lua_newtable(L);
1041  lua_createtable(L, 0, 1);
1042  lua_getglobal(L, "_G");
1043  lua_setfield(L, -2, "__index");
1044  lua_setmetatable(L, -2);
1045  lua_pushcfunction(L, intf_object_dir);
1046  lua_setfield(L, -2, "dir");
1047  lua_setfield(L, LUA_REGISTRYINDEX, Interp);
1048 
1049  // Loading ilua:
1050  cmd_log_ << "Loading ilua...\n";
1051 
1052  lua_settop(L, 0);
1053  luaW_getglobal(L, "wesnoth", "require");
1054  lua_pushstring(L, "lua/ilua.lua");
1055  if(protected_call(1, 1)) {
1056  //run "ilua.set_strict()"
1057  lua_pushstring(L, "set_strict");
1058  lua_gettable(L, -2);
1059  if (!this->protected_call(0,0, std::bind(&lua_kernel_base::log_error, this, std::placeholders::_1, std::placeholders::_2))) {
1060  cmd_log_ << "Failed to activate strict mode.\n";
1061  } else {
1062  cmd_log_ << "Activated strict mode.\n";
1063  }
1064 
1065  lua_setglobal(L, "ilua"); //save ilua table as a global
1066  } else {
1067  cmd_log_ << "Error: failed to load ilua.\n";
1068  }
1069  lua_settop(L, 0);
1070 
1071  // Disable functions from debug which we don't want.
1072  // We do this last because ilua needs to be able to use debug.getmetatable
1073  lua_getglobal(L, "debug");
1074  lua_pushnil(L);
1075  while(lua_next(L, -2) != 0) {
1076  lua_pop(L, 1);
1077  char const* function = lua_tostring(L, -1);
1078  if(strcmp(function, "traceback") == 0 || strcmp(function, "getinfo") == 0) continue; //traceback is needed for our error handler
1079  lua_pushnil(L); //getinfo is needed for ilua strict mode
1080  lua_setfield(L, -3, function);
1081  }
1082  lua_pop(L, 1);
1083 }
1084 
1086 {
1087  for (const auto& pair : this->registered_widget_definitions_) {
1088  gui2::remove_single_widget_definition(std::get<0>(pair), std::get<1>(pair));
1089  }
1090  lua_close(mState);
1091 }
1092 
1093 void lua_kernel_base::log_error(char const * msg, char const * context)
1094 {
1095  ERR_LUA << context << ": " << msg;
1096 }
1097 
1098 void lua_kernel_base::throw_exception(char const * msg, char const * context)
1099 {
1100  throw game::lua_error(msg, context);
1101 }
1102 
1103 bool lua_kernel_base::protected_call(int nArgs, int nRets)
1104 {
1105  error_handler eh = std::bind(&lua_kernel_base::log_error, this, std::placeholders::_1, std::placeholders::_2 );
1106  return this->protected_call(nArgs, nRets, eh);
1107 }
1108 
1109 bool lua_kernel_base::load_string(char const * prog, const std::string& name)
1110 {
1111  error_handler eh = std::bind(&lua_kernel_base::log_error, this, std::placeholders::_1, std::placeholders::_2 );
1112  return this->load_string(prog, name, eh);
1113 }
1114 
1115 bool lua_kernel_base::protected_call(int nArgs, int nRets, const error_handler& e_h)
1116 {
1117  return this->protected_call(mState, nArgs, nRets, e_h);
1118 }
1119 
1120 bool lua_kernel_base::protected_call(lua_State * L, int nArgs, int nRets, const error_handler& e_h)
1121 {
1122  int errcode = luaW_pcall_internal(L, nArgs, nRets);
1123 
1124  if (errcode != LUA_OK) {
1125  char const * msg = lua_tostring(L, -1);
1126 
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: ";
1134  } else {
1135  context += "unknown lua error: ";
1136  }
1137  if(lua_isstring(L, -1)) {
1138  context += msg ? msg : "null string";
1139  } else {
1140  context += lua_typename(L, lua_type(L, -1));
1141  }
1142 
1143  lua_pop(L, 1);
1144 
1145  e_h(context.c_str(), "Lua Error");
1146 
1147  return false;
1148  }
1149 
1150  return true;
1151 }
1152 
1153 bool lua_kernel_base::load_string(const std::string& prog, const std::string& name, const error_handler& e_h, bool allow_unsafe)
1154 {
1155  // pass 't' to prevent loading bytecode which is unsafe and can be used to escape the sandbox.
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";
1160 
1161  std::string context = "When parsing a string to lua, ";
1162 
1163  if (errcode == LUA_ERRSYNTAX) {
1164  context += " a syntax error";
1165  } else if(errcode == LUA_ERRMEM){
1166  context += " a memory error";
1167  } else {
1168  context += " an unknown error";
1169  }
1170 
1171  lua_pop(mState, 1);
1172 
1173  e_h(message.c_str(), context.c_str());
1174 
1175  return false;
1176  }
1177  return true;
1178 }
1179 
1181 {
1182  int nArgs = 0;
1183  if (auto args = cfg.optional_child("args")) {
1184  luaW_pushconfig(this->mState, *args);
1185  ++nArgs;
1186  }
1187  this->run(cfg["code"].str().c_str(), cfg["name"].str(), nArgs);
1188 }
1189 
1190 config luaW_serialize_function(lua_State* L, int func)
1191 {
1192  if(lua_iscfunction(L, func)) {
1193  throw luafunc_serialize_error("cannot serialize C function");
1194  }
1195  if(!lua_isfunction(L, func)) {
1196  throw luafunc_serialize_error("cannot serialize callable non-function");
1197  }
1198  config data;
1199  lua_Debug info;
1200  lua_pushvalue(L, func); // push copy of function because lua_getinfo will pop it
1201  lua_getinfo(L, ">u", &info);
1202  data["params"] = info.nparams;
1203  luaW_getglobal(L, "string", "dump");
1204  lua_pushvalue(L, func);
1205  lua_call(L, 1, 1);
1206  data["code"] = lua_check<std::string>(L, -1);
1207  lua_pop(L, 1);
1208  config upvalues;
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";
1213  continue;
1214  }
1215  int idx = lua_absindex(L, -1);
1216  switch(lua_type(L, idx)) {
1217  case LUA_TBOOLEAN: case LUA_TNUMBER: case LUA_TSTRING:
1218  luaW_toscalar(L, idx, upvalues[name]);
1219  break;
1220  case LUA_TFUNCTION:
1221  upvalues.add_child(name, luaW_serialize_function(L, idx))["upvalue_type"] = "function";
1222  break;
1223  case LUA_TNIL:
1224  upvalues.add_child(name, config{"upvalue_type", "nil"});
1225  break;
1226  case LUA_TTABLE:
1227  if(std::vector<std::string> names = luaW_to_namedtuple(L, idx); !names.empty()) {
1228  for(std::size_t i = 1; i <= lua_rawlen(L, -1); i++, lua_pop(L, 1)) {
1229  lua_rawgeti(L, idx, i);
1230  config& cfg = upvalues.add_child(name);
1231  luaW_toscalar(L, -1, cfg["value"]);
1232  cfg["name"] = names[0];
1233  cfg["upvalue_type"] = "named tuple";
1234  names.erase(names.begin());
1235  }
1236  break;
1237  } else if(config cfg; luaW_toconfig(L, idx, cfg)) {
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);
1243  }
1244  lua_settop(L, save_top);
1245  upvalues.add_child(name, cfg)["upvalue_type"] = names.empty() ? "config" : "named tuple";
1246  break;
1247  } else {
1248  for(std::size_t i = 1; i <= lua_rawlen(L, -1); i++, lua_pop(L, 1)) {
1249  lua_rawgeti(L, idx, i);
1250  config& cfg = upvalues.add_child(name);
1251  luaW_toscalar(L, -1, cfg["value"]);
1252  cfg["upvalue_type"] = "array";
1253  }
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;
1258  break;
1259  }
1260  }
1261  if(!found_non_array) break;
1262  }
1263  [[fallthrough]];
1264  default:
1265  std::ostringstream os;
1266  os << "cannot serialize function with upvalue " << name << " = ";
1267  luaW_getglobal(L, "wesnoth", "as_text");
1268  lua_pushvalue(L, idx);
1269  lua_call(L, 1, 1);
1270  os << luaL_checkstring(L, -1);
1271  lua_pushboolean(L, false);
1272  throw luafunc_serialize_error(os.str());
1273  }
1274  }
1275  if(!upvalues.empty()) data.add_child("upvalues", upvalues);
1276  return data;
1277 }
1278 
1280 {
1281  if(!load_string(cfg["code"].str(), cfg["name"], eh, true)) return false;
1282  if(auto upvalues = cfg.optional_child("upvalues")) {
1283  lua_pushvalue(mState, -1); // duplicate function because lua_getinfo will pop it
1284  lua_Debug info;
1285  lua_getinfo(mState, ">u", &info);
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);
1289  lua_pop(mState, 1); // we only want the upvalue's name, not its value
1290  if(name == "_ENV") {
1291  lua_pushglobaltable(mState);
1292  } else if(upvalues->has_attribute(name)) {
1293  luaW_pushscalar(mState, (*upvalues)[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) {
1300  luaW_pushscalar(mState, cfg["value"]);
1301  lua_rawseti(mState, -2, lua_rawlen(mState, -2) + 1);
1302  }
1303  } else if(child["upvalue_type"] == "config") {
1304  luaW_pushconfig(mState, child);
1305  } else if(child["upvalue_type"] == "function") {
1306  if(!load_binary(child, eh)) return false;
1307  } else if(child["upvalue_type"] == "nil") {
1308  lua_pushnil(mState);
1309  }
1310  } else continue;
1311  lua_setupvalue(mState, funcindex, i);
1312  }
1313  }
1314  return true;
1315 }
1316 
1318 {
1319  int top = lua_gettop(mState);
1320  try {
1321  error_handler eh = std::bind(&lua_kernel_base::throw_exception, this, std::placeholders::_1, std::placeholders::_2 );
1322  if(load_binary(cfg, eh)) {
1323  lua_pushvalue(mState, -1);
1324  protected_call(0, LUA_MULTRET, eh);
1325  }
1326  } catch (const game::lua_error & e) {
1327  cmd_log_ << e.what() << "\n";
1328  lua_kernel_base::log_error(e.what(), "In function lua_kernel::run()");
1329  config error;
1330  error["name"] = "execute_error";
1331  error["error"] = e.what();
1332  return error;
1333  }
1334  config result;
1335  result["ref"] = cfg["ref"];
1336  result.add_child("executed") = luaW_serialize_function(mState, top + 1);
1337  lua_remove(mState, top + 1);
1338  result["name"] = "execute_result";
1339  for(int i = top + 1; i < lua_gettop(mState); i++) {
1340  std::string index = std::to_string(i - top);
1341  switch(lua_type(mState, i)) {
1342  case LUA_TNUMBER: case LUA_TBOOLEAN: case LUA_TSTRING:
1343  luaW_toscalar(mState, i, result[index]);
1344  break;
1345  case LUA_TTABLE:
1346  luaW_toconfig(mState, i, result.add_child(index));
1347  break;
1348  }
1349  }
1350  return result;
1351 }
1352 // Call load_string and protected call. Make them throw exceptions.
1353 //
1354 void lua_kernel_base::throwing_run(const char * prog, const std::string& name, int nArgs, bool in_interpreter)
1355 {
1356  cmd_log_ << "$ " << prog << "\n";
1357  error_handler eh = std::bind(&lua_kernel_base::throw_exception, this, std::placeholders::_1, std::placeholders::_2 );
1358  this->load_string(prog, name, eh);
1359  if(in_interpreter) {
1360  lua_getfield(mState, LUA_REGISTRYINDEX, Interp);
1361  if(lua_setupvalue(mState, -2, 1) == nullptr)
1362  lua_pop(mState, 1);
1363  }
1364  lua_insert(mState, -nArgs - 1);
1365  this->protected_call(nArgs, in_interpreter ? LUA_MULTRET : 0, eh);
1366 }
1367 
1368 // Do a throwing run, but if we catch a lua_error, reformat it with signature for this function and log it.
1369 void lua_kernel_base::run(const char * prog, const std::string& name, int nArgs)
1370 {
1371  try {
1372  this->throwing_run(prog, name, nArgs);
1373  } catch (const game::lua_error & e) {
1374  cmd_log_ << e.what() << "\n";
1375  lua_kernel_base::log_error(e.what(), "In function lua_kernel::run()");
1376  }
1377 }
1378 
1379 // Tests if a program resolves to an expression, and pretty prints it if it is, otherwise it runs it normally. Throws exceptions.
1380 void lua_kernel_base::interactive_run(char const * prog) {
1381  std::string experiment = "return ";
1382  experiment += prog;
1383  int top = lua_gettop(mState);
1384 
1385  error_handler eh = std::bind(&lua_kernel_base::throw_exception, this, std::placeholders::_1, std::placeholders::_2 );
1386  luaW_getglobal(mState, "ilua", "_pretty_print");
1387 
1388  try {
1389  // Try to load the experiment without syntax errors
1390  this->load_string(experiment.c_str(), "interactive", eh);
1391  lua_getfield(mState, LUA_REGISTRYINDEX, Interp);
1392  if(lua_setupvalue(mState, -2, 1) == nullptr)
1393  lua_pop(mState, 1);
1394  } catch (const game::lua_error &) {
1395  this->throwing_run(prog, "interactive", 0, true); // Since it failed, fall back to the usual throwing_run, on the original input.
1396  if(lua_gettop(mState) == top + 1) {
1397  // Didn't return anything
1398  lua_settop(mState, top);
1399  return;
1400  } else goto PRINT;
1401  }
1402  // experiment succeeded, now run but log normally.
1403  cmd_log_ << "$ " << prog << "\n";
1404  this->protected_call(0, LUA_MULTRET, eh);
1405 PRINT:
1406  int nRets = lua_gettop(mState) - top - 1;
1407  {
1408  // Assign first result to _
1409  lua_getfield(mState, LUA_REGISTRYINDEX, Interp);
1410  int env_idx = lua_gettop(mState);
1411  lua_pushvalue(mState, top + 2);
1412  lua_setfield(mState, -2, "_");
1413  // Now duplicate EVERY result and pass it to table.pack, assigning to _all
1414  luaW_getglobal(mState, "table", "pack");
1415  for(int i = top + 2; i < env_idx; i++)
1416  lua_pushvalue(mState, i);
1417  this->protected_call(nRets, 1, eh);
1418  lua_setfield(mState, -2, "_all");
1419  lua_pop(mState, 1);
1420  }
1421  // stack is now ilua._pretty_print followed by any results of prog
1422  this->protected_call(lua_gettop(mState) - top - 1, 0, eh);
1423 }
1424 /**
1425  * Loads and executes a Lua file.
1426  * - Arg 1: string containing the file name.
1427  * - Ret *: values returned by executing the file body.
1428  */
1430 {
1431  luaL_checkstring(L, 1);
1432  lua_rotate(L, 1, -1);
1433  if (lua_fileops::load_file(L) != 1) return 0;
1434  //^ should end with the file contents loaded on the stack. actually it will call lua_error otherwise, the return 0 is redundant.
1435  lua_rotate(L, 1, 1);
1436  // Using a non-protected call here appears to fix an issue in plugins.
1437  // The protected call isn't technically necessary anyway, because this function is called from Lua code,
1438  // which should already be in a protected environment.
1439  lua_call(L, lua_gettop(L) - 1, LUA_MULTRET);
1440  return lua_gettop(L);
1441 }
1442 
1443 /**
1444  * Loads and executes a Lua file, if there is no corresponding entry in wesnoth.package.
1445  * Stores the result of the script in wesnoth.package and returns it.
1446  * - Arg 1: string containing the file name.
1447  * - Ret 1: value returned by the script.
1448  */
1450 {
1451  const char * m = luaL_checkstring(L, 1);
1452  if(!m) {
1453  return luaL_argerror(L, 1, "found a null string argument to wesnoth require");
1454  }
1455 
1456  // Check if there is already an entry.
1457 
1458  lua_getglobal(L, "wesnoth");
1459  lua_pushstring(L, "package");
1460  lua_rawget(L, -2);
1461  lua_pushvalue(L, 1);
1462  lua_rawget(L, -2);
1463  if(!lua_isnil(L, -1) && !game_config::debug_lua) {
1464  return 1;
1465  }
1466  lua_pop(L, 1);
1467  lua_pushvalue(L, 1);
1468  // stack is now [packagename] [wesnoth] [package] [packagename]
1469 
1470  if(lua_fileops::load_file(L) != 1) {
1471  // should end with the file contents loaded on the stack. actually it will call lua_error otherwise, the return 0 is redundant.
1472  // stack is now [packagename] [wesnoth] [package] [chunk]
1473  return 0;
1474  }
1475  DBG_LUA << "require: loaded a file, now calling it";
1476 
1477  if (!this->protected_call(L, 0, 1, std::bind(&lua_kernel_base::log_error, this, std::placeholders::_1, std::placeholders::_2))) {
1478  // historically if wesnoth.require fails it just yields nil and some logging messages, not a lua error
1479  return 0;
1480  }
1481  // stack is now [packagename] [wesnoth] [package] [results]
1482 
1483  lua_pushvalue(L, 1);
1484  lua_pushvalue(L, -2);
1485  // stack is now [packagename] [wesnoth] [package] [results] [packagename] [results]
1486  // Add the return value to the table.
1487 
1488  lua_settable(L, -4);
1489  // stack is now [packagename] [wesnoth] [package] [results]
1490  return 1;
1491 }
1493 {
1494  lua_push(L, my_name());
1495  return 1;
1496 }
1497 static void push_color_palette(lua_State* L, const std::vector<color_t>& palette) {
1498  static const lua_named_tuple_builder tuple_builder{ {"r", "g", "b", "a"} };
1499 
1500  lua_createtable(L, palette.size(), 1);
1501  lua_rotate(L, -2, 1); // swap new table with previous element on stack
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);
1514  }
1515 }
1516 static int impl_palette_get(lua_State* L)
1517 {
1518  char const *m = luaL_checkstring(L, 2);
1519  lua_pushvalue(L, 2);
1521  return 1;
1522 }
1523 
1524 // suppress missing prototype warning (not static because game_lua_kernel referenes it);
1527  static luaW_Registry gameConfigReg{"game config"};
1528  return gameConfigReg;
1529 }
1530 static auto& dummy = gameConfigReg(); // just to ensure it's constructed.
1531 
1532 #define GAME_CONFIG_SIMPLE_GETTER(name) \
1533 GAME_CONFIG_GETTER(#name, decltype(game_config::name), lua_kernel_base) { \
1534  (void) k; \
1535  return game_config::name; \
1536 }
1537 
1538 namespace {
1551 
1553  (void)k;
1554  lua_newtable(L);
1555  if(luaL_newmetatable(L, "color palettes")) {
1556  lua_pushcfunction(L, impl_palette_get);
1557  lua_setfield(L, -2, "__index");
1558  }
1559  lua_setmetatable(L, -2);
1560  return lua_index_raw(L);
1561 }
1562 
1563 GAME_CONFIG_GETTER("red_green_scale", lua_index_raw, lua_kernel_base) {
1564  (void)k;
1565  lua_pushstring(L, "red_green_scale");
1567  return lua_index_raw(L);
1568 }
1569 
1570 GAME_CONFIG_GETTER("red_green_scale_text", lua_index_raw, lua_kernel_base) {
1571  (void)k;
1572  lua_pushstring(L, "red_green_scale_text");
1574  return lua_index_raw(L);
1575 }
1576 
1577 GAME_CONFIG_GETTER("blue_white_scale", lua_index_raw, lua_kernel_base) {
1578  (void)k;
1579  lua_pushstring(L, "blue_white_scale");
1581  return lua_index_raw(L);
1582 }
1583 
1584 GAME_CONFIG_GETTER("blue_white_scale_text", lua_index_raw, lua_kernel_base) {
1585  (void)k;
1586  lua_pushstring(L, "blue_white_scale_text");
1588  return lua_index_raw(L);
1589 }
1590 }
1591 
1592 /**
1593  * Gets some game_config data (__index metamethod).
1594  * - Arg 1: userdata (ignored).
1595  * - Arg 2: string containing the name of the property.
1596  * - Ret 1: something containing the attribute.
1597  */
1599 {
1600  return gameConfigReg().get(L);
1601 }
1602 /**
1603  * Sets some game_config data (__newindex metamethod).
1604  * - Arg 1: userdata (ignored).
1605  * - Arg 2: string containing the name of the property.
1606  * - Arg 3: something containing the attribute.
1607  */
1609 {
1610  return gameConfigReg().set(L);
1611 }
1612 /**
1613  * Gets a list of game_config data (__dir metamethod).
1614  */
1616 {
1617  return gameConfigReg().dir(L);
1618 }
1619 /**
1620  * Loads the "package" package into the Lua environment.
1621  * This action is inherently unsafe, as Lua scripts will now be able to
1622  * load C libraries on their own, hence granting them the same privileges
1623  * as the Wesnoth binary itself.
1624  */
1626 {
1627  lua_State *L = mState;
1628  lua_pushcfunction(L, luaopen_package);
1629  lua_pushstring(L, "package");
1630  lua_call(L, 1, 0);
1631 }
1632 
1634 {
1635  lua_State* L = mState;
1636  lua_settop(L, 0);
1637  cmd_log_ << "Loading core...\n";
1638  luaW_getglobal(L, "wesnoth", "require");
1639  lua_pushstring(L, "lua/core");
1640  if(!protected_call(1, 1)) {
1641  cmd_log_ << "Error: Failed to load core.\n";
1642  }
1643  lua_settop(L, 0);
1644 }
1645 
1646 /**
1647  * Gets all the global variable names in the Lua environment. This is useful for tab completion.
1648  */
1649 std::vector<std::string> lua_kernel_base::get_global_var_names()
1650 {
1651  std::vector<std::string> ret;
1652 
1653  lua_State *L = mState;
1654 
1655  int idx = lua_gettop(L);
1656  lua_getglobal(L, "_G");
1657  lua_pushnil(L);
1658 
1659  while (lua_next(L, idx+1) != 0) {
1660  if (lua_isstring(L, -2)) {
1661  ret.push_back(lua_tostring(L,-2));
1662  }
1663  lua_pop(L,1);
1664  }
1665  lua_settop(L, idx);
1666  return ret;
1667 }
1668 
1669 /**
1670  * Gets all attribute names of an extended variable name. This is useful for tab completion.
1671  */
1672 std::vector<std::string> lua_kernel_base::get_attribute_names(const std::string & input)
1673 {
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;
1680 
1681  lua_State* L = mState;
1682  int save_stack = lua_gettop(L);
1683  int result = luaL_loadstring(L, load.c_str());
1684  if(result != LUA_OK) {
1685  // This isn't at error level because it's a really low priority error; it just means the user tried to tab-complete something that doesn't exist.
1686  LOG_LUA << "Error when attempting tab completion:";
1687  LOG_LUA << luaL_checkstring(L, -1);
1688  // Just return an empty list; no matches were found
1689  lua_settop(L, save_stack);
1690  return ret;
1691  }
1692 
1693  luaW_pcall(L, 0, 1);
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());
1700  luaW_pcall(L, 2, 1);
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);
1705  return ret;
1706  } else {
1707  lua_settop(L, top);
1708  // Metafunction not found, so use lua_next to enumerate the table
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);
1712  if(attr.empty()) {
1713  continue;
1714  }
1715  if(!isalpha(attr[0]) && attr[0] != '_') {
1716  continue;
1717  }
1718  if(std::any_of(attr.begin(), attr.end(), [](char c){
1719  return !isalpha(c) && !isdigit(c) && c != '_';
1720  })) {
1721  continue;
1722  }
1723  if(attr.substr(0, partial_name.size()) == partial_name) {
1724  ret.push_back(base_path + "." + attr);
1725  }
1726  }
1727  }
1728  }
1729  }
1730  lua_settop(L, save_stack);
1731  return ret;
1732 }
1733 
1735 {
1736  #ifdef __GNUC__
1737  #pragma GCC diagnostic push
1738  #pragma GCC diagnostic ignored "-Wold-style-cast"
1739  #endif
1740  return *reinterpret_cast<lua_kernel_base**>(lua_getextraspace(L));
1741  #ifdef __GNUC__
1742  #pragma GCC diagnostic pop
1743  #endif
1744 }
1745 
1747 {
1748  return seed_rng::next_seed();
1749 }
map_location loc
Definition: move.cpp:172
double t
Definition: astarsearch.cpp:63
double g
Definition: astarsearch.cpp:63
#define debug(x)
std::vector< std::string > names
Definition: build_info.cpp:74
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:157
config & add_child(std::string_view key)
Definition: config.cpp:436
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.
Definition: config.cpp:380
bool empty() const
Definition: config.cpp:823
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.
command_log cmd_log_
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.
lua_State * mState
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.
Definition: lua_common.hpp:85
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
int height() const
Definition: team.cpp:756
void read(const std::string &shroud_data)
Definition: team.cpp:871
void set_enabled(bool enabled)
Definition: team.hpp:60
int width() const
Definition: team.cpp:751
bool value(int x, int y) const
Definition: team.cpp:814
std::string write() const
Definition: team.cpp:855
bool clear(int x, int y)
Definition: team.cpp:764
const std::string & str() const
Definition: tstring.hpp:204
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)
Definition: deprecation.cpp:29
DEP_LEVEL
See https://wiki.wesnoth.org/CompatibilityStandards for more info.
Definition: deprecation.hpp:21
const config * cfg
std::size_t i
Definition: function.cpp:1031
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()
Definition: language.cpp:317
Standard logging facilities (interface).
#define LOG_STREAM(level, domain)
Definition: log.hpp:278
void luaW_pushconfig(lua_State *L, const config &cfg)
Converts a config object to a Lua table pushed at the top of the stack.
Definition: lua_common.cpp:883
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.
Definition: lua_common.cpp:867
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.
Definition: lua_common.cpp:545
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.
Definition: lua_common.cpp:540
std::vector< std::string > luaW_to_namedtuple(lua_State *L, int idx)
Get the keys of a "named tuple" from the stack.
Definition: lua_common.cpp:772
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.
Definition: lua_common.cpp:912
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.
Definition: lua_common.cpp:855
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.
Definition: lua_common.cpp:597
#define return_string_attrib(name, accessor)
Definition: lua_common.hpp:324
#define return_int_attrib(name, accessor)
Definition: lua_common.hpp:335
#define return_bool_attrib(name, accessor)
Definition: lua_common.hpp:355
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")
#define ERR_LUA
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.
#define LOG_LUA
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 auto & dummy
static int impl_is_deprecated(lua_State *L)
static const char * Interp
#define DBG_LUA
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 const char * Gen
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.
Definition: draw.cpp:203
int rest_heal_amount
Definition: game_config.cpp:48
int village_income
Definition: game_config.cpp:41
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
int kill_experience
Definition: game_config.cpp:44
int combat_experience
Definition: game_config.cpp:45
std::vector< color_t > red_green_scale
std::vector< color_t > blue_white_scale_text
int village_support
Definition: game_config.cpp:42
std::vector< game_tip > load(const config &cfg)
Loads the tips from a config.
Definition: tips.cpp:37
void remove_single_widget_definition(const std::string &widget_type, const std::string &definition_id)
Removes a widget definition from the default GUI.
logger & err()
Definition: log.cpp:339
logger & warn()
Definition: log.cpp:345
logger & info()
Definition: log.cpp:351
std::string register_metatables(lua_State *L)
Definition: lua_color.cpp:146
int intf_textdomain(lua_State *L)
Creates an interface for gettext.
Definition: lua_common.cpp:92
std::string register_gettext_metatable(lua_State *L)
Adds the gettext metatable.
Definition: lua_common.cpp:372
std::string register_tstring_metatable(lua_State *L)
Adds the tstring metatable.
Definition: lua_common.cpp:392
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.
std::string register_metatables(lua_State *)
int intf_compile_formula(lua_State *)
int intf_eval_formula(lua_State *)
Evaluates a formula in the formula engine.
int luaW_open(lua_State *L)
Definition: lua_gui2.cpp:398
int show_lua_console(lua_State *, lua_kernel_base *lk)
Definition: lua_gui2.cpp:250
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)
Definition: lua_mathx.cpp:61
void load_tables(lua_State *L)
Creates the metatable for RNG objects, and adds the Rng table which contains the constructor.
Definition: lua_rng.cpp:97
int luaW_open(lua_State *L)
void register_metatable(lua_State *L)
Definition: lua_widget.cpp:212
int luaW_open(lua_State *L)
Definition: lua_wml.cpp:240
rng * generator
This generator is automatically synced during synced context.
Definition: random.cpp:60
uint32_t next_seed()
Definition: seed_rng.cpp:32
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.
Definition: unicode.cpp:70
constexpr auto transform
Definition: ranges.hpp:45
constexpr auto keys
Definition: ranges.hpp:43
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="")
Definition: debugger.cpp:109
std::string_view data
Definition: picture.cpp:188
void lua_push(lua_State *L, const T &val)
Definition: push_check.hpp:425
static std::string flush(std::ostringstream &s)
Definition: reports.cpp:97
#define ON_SCOPE_EXIT(...)
Run some arbitrary code (a lambda) when the current scope exits The lambda body follows this header,...
Definition: scope_exit.hpp:43
Error used to report an error in a lua script or in the lua interpreter.
Definition: game_errors.hpp:54
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.
int wml_y() const
Definition: location.hpp:187
int wml_x() const
Definition: location.hpp:186
mock_char c
mock_party p
static map_location::direction n
#define e
#define b