The Battle for Wesnoth  1.19.10+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 <SDL2/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 && 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 /**
212  * Replacement print function -- instead of printing to std::cout, print to the command log.
213  * Intended to be bound to this' command_log at registration time.
214  */
216 {
217  DBG_LUA << "intf_print called:";
218  std::size_t nargs = lua_gettop(L);
219 
220  lua_getglobal(L, "tostring");
221  for (std::size_t i = 1; i <= nargs; ++i) {
222  lua_pushvalue(L, -1); // function to call: "tostring"
223  lua_pushvalue(L, i); // value to pass through tostring() before printing
224  lua_call(L, 1, 1);
225  const char * str = lua_tostring(L, -1);
226  if (!str) {
227  LOG_LUA << "'tostring' must return a value to 'print'";
228  str = "";
229  }
230  if (i > 1) {
231  cmd_log_ << "\t"; //separate multiple args with tab character
232  }
233  cmd_log_ << str;
234  DBG_LUA << "'" << str << "'";
235  lua_pop(L, 1); // Pop the output of tostrring()
236  }
237  lua_pop(L, 1); // Pop 'tostring' global
238 
239  cmd_log_ << "\n";
240  DBG_LUA;
241 
242  return 0;
243 }
244 
245 static void impl_warn(void* p, const char* msg, int tocont) {
246  static const char*const prefix = "Warning:\n ";
247  static std::ostringstream warning(prefix);
248  warning.seekp(0, std::ios::end);
249  warning << msg << ' ';
250  if(!tocont) {
251  auto L = reinterpret_cast<lua_State*>(p);
252  luaW_getglobal(L, "debug", "traceback");
253  lua_push(L, warning.str());
254  lua_pushinteger(L, 2);
255  lua_call(L, 2, 1);
256  auto& lk = lua_kernel_base::get_lua_kernel<lua_kernel_base>(L);
257  lk.add_log_to_console(luaL_checkstring(L, -1));
258  warning.str(prefix);
259  }
260 }
261 
262 void lua_kernel_base::add_log_to_console(const std::string& msg) {
263  cmd_log_ << msg << "\n";
264  DBG_LUA << "'" << msg << "'";
265 }
266 
267 /**
268  * Replacement load function. Mostly the same as regular load, but disallows loading binary chunks
269  * due to CVE-2018-1999023.
270  */
271 static int intf_load(lua_State* L)
272 {
273  std::string chunk = luaL_checkstring(L, 1);
274  const char* name = luaL_optstring(L, 2, chunk.c_str());
275  std::string mode = luaL_optstring(L, 3, "t");
276  bool override_env = !lua_isnone(L, 4);
277 
278  if(mode != "t") {
279  return luaL_argerror(L, 3, "binary chunks are not allowed for security reasons");
280  }
281 
282  int result = luaL_loadbufferx(L, chunk.data(), chunk.length(), name, "t");
283  if(result != LUA_OK) {
284  lua_pushnil(L);
285  // Move the nil as the first return value, like Lua's own load() does.
286  lua_insert(L, -2);
287 
288  return 2;
289  }
290 
291  if(override_env) {
292  // Copy "env" to the top of the stack.
293  lua_pushvalue(L, 4);
294  // Set "env" as the first upvalue.
295  const char* upvalue_name = lua_setupvalue(L, -2, 1);
296  if(upvalue_name == nullptr) {
297  // lua_setupvalue() didn't remove the copy of "env" from the stack, so we need to do it ourselves.
298  lua_pop(L, 1);
299  }
300  }
301 
302  return 1;
303 }
304 
305 /**
306  * Wrapper for pcall and xpcall functions to rethrow jailbreak exceptions
307  */
308 static int intf_pcall(lua_State *L)
309 {
310  lua_CFunction function = lua_tocfunction(L, lua_upvalueindex(1));
311  assert(function); // The upvalue should be Lua's pcall or xpcall, or else something is very wrong.
312 
313  int nRets = function(L);
314 
315  // If a jailbreak exception was stored while running (x)pcall, rethrow it so Lua doesn't continue.
317 
318  return nRets;
319 }
320 
321 // The show lua console callback is similarly a method of lua kernel
323 {
324  if (cmd_log_.external_log_) {
325  std::string message = "There is already an external logger attached to this lua kernel, you cannot open the lua console right now.";
326  log_error(message.c_str());
327  cmd_log_ << message << "\n";
328  return 0;
329  }
330 
331  return lua_gui2::show_lua_console(L, this);
332 }
333 
334 static int impl_name_generator_call(lua_State *L)
335 {
336  name_generator* gen = static_cast<name_generator*>(lua_touserdata(L, 1));
337  lua_pushstring(L, gen->generate().c_str());
338  return 1;
339 }
340 
341 static int impl_name_generator_collect(lua_State *L)
342 {
343  name_generator* gen = static_cast<name_generator*>(lua_touserdata(L, 1));
344  gen->~name_generator();
345  return 0;
346 }
347 
348 static int intf_name_generator(lua_State *L)
349 {
350  std::string type = luaL_checkstring(L, 1);
351  name_generator* gen = nullptr;
352  try {
353  if(type == "markov" || type == "markov_chain") {
354  std::vector<std::string> input;
355  if(lua_istable(L, 2)) {
356  input = lua_check<std::vector<std::string>>(L, 2);
357  } else {
358  input = utils::parenthetical_split(luaW_checktstring(L, 2).str(), ',');
359  }
360  int chain_sz = luaL_optinteger(L, 3, 2);
361  int max_len = luaL_optinteger(L, 4, 12);
362  gen = new(L) markov_generator(input, chain_sz, max_len);
363  // Ensure the pointer didn't change when cast
364  assert(static_cast<void*>(gen) == dynamic_cast<markov_generator*>(gen));
365  } else if(type == "context_free" || type == "cfg" || type == "CFG") {
366  if(lua_istable(L, 2)) {
367  std::map<std::string, std::vector<std::string>> data;
368  for(lua_pushnil(L); lua_next(L, 2); lua_pop(L, 1)) {
369  if(lua_type(L, -2) != LUA_TSTRING) {
370  lua_pushstring(L, "CFG generator: invalid nonterminal name (must be a string)");
371  return lua_error(L);
372  }
373  if(lua_isstring(L, -1)) {
374  auto& productions = data[lua_tostring(L,-2)] = utils::split(luaW_checktstring(L,-1).str(), '|');
375  if(productions.size() > 1) {
376  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");
377  }
378  } else if(lua_istable(L, -1)) {
379  const auto& split = lua_check<std::vector<t_string>>(L, -1);
380  auto& productions = data[lua_tostring(L,-2)];
381  std::transform(split.begin(), split.end(), std::back_inserter(productions), std::mem_fn(&t_string::str));
382  } else {
383  lua_pushstring(L, "CFG generator: invalid nonterminal value (must be a string or list of strings)");
384  return lua_error(L);
385  }
386  }
387  if(!data.empty()) {
388  gen = new(L) context_free_grammar_generator(data);
389  }
390  } else {
392  }
393  if(gen) {
394  assert(static_cast<void*>(gen) == dynamic_cast<context_free_grammar_generator*>(gen));
395  }
396  } else {
397  return luaL_argerror(L, 1, "should be either 'markov_chain' or 'context_free'");
398  }
399  }
400  catch (const name_generator_invalid_exception& ex) {
401  lua_pushstring(L, ex.what());
402  return lua_error(L);
403  }
404 
405  // We set the metatable now, even if the generator is invalid, so that it
406  // will be properly collected if it was invalid.
407  luaL_getmetatable(L, Gen);
408  lua_setmetatable(L, -2);
409 
410  return 1;
411 }
412 
413 /**
414 * Logs a message
415 * Arg 1: (optional) Logger
416 * Arg 2: Message
417 */
418 static int intf_log(lua_State *L) {
419  const std::string& logger = lua_isstring(L, 2) ? luaL_checkstring(L, 1) : "";
420  std::string msg = lua_isstring(L, 2) ? luaL_checkstring(L, 2) : luaL_checkstring(L, 1);
421  if(msg.empty() || msg.back() != '\n') {
422  msg += '\n';
423  }
424 
425  if(logger == "err" || logger == "error") {
426  LOG_STREAM(err, log_user) << msg;
427  } else if(logger == "warn" || logger == "wrn" || logger == "warning") {
429  } else if((logger == "debug" || logger == "dbg")) {
431  } else {
433  }
434  return 0;
435 }
436 
437 /**
438  * Logs a deprecation message. See deprecation.cpp for details
439  * Arg 1: Element to be deprecated.
440  * Arg 2: Deprecation level.
441  * Arg 3: Version when element may be removed.
442  * Arg 4: Additional detail message.
443  */
444 static int intf_deprecated_message(lua_State* L) {
445  const std::string elem = luaL_checkstring(L, 1);
446  // This could produce an invalid deprecation level, but that possibility is handled in deprecated_message()
447  const DEP_LEVEL level = DEP_LEVEL(luaL_checkinteger(L, 2));
448  const std::string ver_str = lua_isnoneornil(L, 3) ? "" : luaL_checkstring(L, 3);
449  const std::string detail = luaW_checktstring(L, 4);
450  const version_info ver = ver_str.empty() ? game_config::wesnoth_version.str() : ver_str;
451  const std::string msg = deprecated_message(elem, level, ver, detail);
452  if(level < DEP_LEVEL::INDEFINITE || level >= DEP_LEVEL::REMOVED) {
453  // Invalid deprecation level or level 4 deprecation should raise an interpreter error
454  lua_push(L, msg);
455  return lua_error(L);
456  }
457  lua_warning(L, msg.c_str(), false);
458  return 0;
459 }
460 
461 /**
462  * Converts a Lua array to a named tuple.
463  * Arg 1: A Lua array
464  * Arg 2: An array of strings
465  * Ret: A copy of arg 1 that's now a named tuple with the names in arg 2.
466  * The copy will only include the array portion of the input array.
467  * Any non-integer keys or non-consecutive keys will be gone.
468  * Note: This exists so that wml.tag can use it but is not really intended as a public API.
469  */
470 static int intf_named_tuple(lua_State* L)
471 {
472  if(!lua_istable(L, 1)) {
473  return luaW_type_error(L, 1, lua_typename(L, LUA_TTABLE));
474  }
475  auto names = lua_check<std::vector<std::string>>(L, 2);
476  lua_len(L, 1);
477  int len = luaL_checkinteger(L, -1);
479  for(int i = 1; i <= std::max<int>(len, names.size()); i++) {
480  lua_geti(L, 1, i);
481  lua_seti(L, -2, i);
482  }
483  return 1;
484 }
485 
486 static int intf_parse_shroud_bitmap(lua_State* L)
487 {
488  shroud_map temp;
489  temp.set_enabled(true);
490  temp.read(luaL_checkstring(L, 1));
491  std::set<map_location> locs;
492  for(int x = 1; x <= temp.width(); x++) {
493  for(int y = 1; y <= temp.height(); y++) {
494  if(!temp.value(x, y)) {
495  locs.emplace(x, y, wml_loc());
496  }
497  }
498  }
499  luaW_push_locationset(L, locs);
500  return 1;
501 }
502 
503 static int intf_make_shroud_bitmap(lua_State* L)
504 {
505  shroud_map temp;
506  temp.set_enabled(true);
507  auto locs = luaW_check_locationset(L, 1);
508  for(const auto& loc : locs) {
509  temp.clear(loc.wml_x(), loc.wml_y());
510  }
511  lua_push(L, temp.write());
512  return 1;
513 }
514 
515 /**
516 * Returns the time stamp, exactly as [set_variable] time=stamp does.
517 * - Ret 1: integer
518 */
519 static int intf_ms_since_init(lua_State *L) {
520  lua_pushinteger(L, SDL_GetTicks());
521  return 1;
522 }
523 
524 static int intf_get_language(lua_State* L)
525 {
526  lua_push(L, get_language().localename);
527  return 1;
528 }
529 
530 static void dir_meta_helper(lua_State* L, std::vector<std::string>& keys)
531 {
532  switch(luaL_getmetafield(L, -1, "__dir")) {
533  case LUA_TFUNCTION:
534  lua_pushvalue(L, 1);
535  lua_push(L, keys);
536  if(lua_pcall(L, 2, 1, 0) == LUA_OK) {
537  keys = lua_check<std::vector<std::string>>(L, -1);
538  } else {
539  lua_warning(L, "wesnoth.print_attributes: __dir metamethod raised an error", false);
540  }
541  break;
542  case LUA_TTABLE:
543  auto dir_keys = lua_check<std::vector<std::string>>(L, -1);
544  std::copy(dir_keys.begin(), dir_keys.end(), std::back_inserter(keys));
545  break;
546  }
547  lua_pop(L, 1);
548 }
549 
550 // This is a separate function so I can use a protected call on it to catch errors.
551 static int impl_is_deprecated(lua_State* L)
552 {
553  auto key = luaL_checkstring(L, 2);
554  auto type = lua_getfield(L, 1, key);
555  if(type == LUA_TTABLE) {
556  lua_pushliteral(L, "__deprecated");
557  if(lua_rawget(L, -2) == LUA_TBOOLEAN) {
558  auto deprecated = luaW_toboolean(L, -1);
559  lua_pushboolean(L, deprecated);
560  return 1;
561  }
562  lua_pop(L, 1);
563  }
564  lua_pushboolean(L, false);
565  return 1;
566 }
567 
568 // This is also a separate function so I can use a protected call on it to catch errors.
569 static int impl_get_dir_suffix(lua_State*L)
570 {
571  auto key = luaL_checkstring(L, 2);
572  std::string suffix = " ";
573  auto type = lua_getfield(L, 1, key);
574  if(type == LUA_TTABLE) {
575  suffix = "†";
576  } else if(type == LUA_TFUNCTION) {
577  suffix = "Æ’";
578  } else if(type == LUA_TUSERDATA) {
579  lua_getglobal(L, "getmetatable");
580  lua_pushvalue(L, -2);
581  lua_call(L, 1, 1);
582  if(lua_type(L, -1) == LUA_TSTRING) {
583  auto meta = lua_check<std::string>(L, -1);
584  if(meta == "function") {
585  suffix = "Æ’";
586  }
587  }
588  lua_pop(L, 1);
589  if(suffix.size() == 1) {
590  // ie, the above block didn't identify it as a function
591  if(auto t = luaL_getmetafield(L, -1, "__dir_tablelike"); t == LUA_TBOOLEAN) {
592  if(luaW_toboolean(L, -1)) {
593  suffix = "†";
594  }
595  lua_pop(L, 1);
596  } else if(t != LUA_TNIL) {
597  lua_pop(L, 1);
598  }
599  }
600  }
601  suffix = " " + suffix;
602  lua_pushlstring(L, suffix.c_str(), suffix.size());
603  return 1;
604 }
605 
606 /**
607  * This function does the actual work of grabbing all the attribute names.
608  * It's a separate function so that it can be used by tab-completion as well.
609  */
610 std::vector<std::string> luaW_get_attributes(lua_State* L, int idx)
611 {
612  if(idx < 0 && idx >= -lua_gettop(L)) {
613  idx = lua_absindex(L, idx);
614  }
615  std::vector<std::string> keys;
616  if(lua_istable(L, idx)) {
617  // Walk the metatable chain (as long as __index is a table)...
618  // If we reach an __index that's a function, check for a __dir metafunction.
619  int save_top = lua_gettop(L);
620  lua_pushvalue(L, idx);
621  ON_SCOPE_EXIT(&) {
622  lua_settop(L, save_top);
623  };
624  do {
625  int table_idx = lua_absindex(L, -1);
626  for(lua_pushnil(L); lua_next(L, table_idx); lua_pop(L, 1)) {
627  if(lua_type(L, -2) == LUA_TSTRING) {
628  keys.push_back(lua_tostring(L,-2));
629  }
630  }
631  // Two possible exit cases:
632  // 1. getmetafield returns TNIL because there is no __index
633  // In this case, the stack is unchanged, so the while condition is still true.
634  // 2. The __index is not a table
635  // In this case, obviously the while condition fails
636  if(luaL_getmetafield(L, table_idx, "__index") == LUA_TNIL) break;
637  } while(lua_istable(L, -1));
638  if(lua_isfunction(L, -1)) {
639  lua_pop(L, 1);
640  dir_meta_helper(L, keys);
641  }
642  } else if(lua_isuserdata(L, idx) && !lua_islightuserdata(L, idx)) {
643  lua_pushvalue(L, idx);
644  dir_meta_helper(L, keys);
645  lua_pop(L, 1);
646  }
647  // Sort and remove any duplicates
648  std::sort(keys.begin(), keys.end());
649  auto new_end = std::unique(keys.begin(), keys.end());
650  new_end = std::remove_if(keys.begin(), new_end, [L, idx](const std::string& key) {
651  if(key.compare(0, 2, "__") == 0) {
652  return true;
653  }
654  int save_top = lua_gettop(L);
655  ON_SCOPE_EXIT(&) {
656  lua_settop(L, save_top);
657  };
658  // Exclude deprecated elements
659  // Some keys may be write-only, which would raise an exception here
660  // In that case we just ignore it and assume not deprecated
661  // (the __dir metamethod would be responsible for excluding deprecated write-only keys)
662  lua_pushcfunction(L, impl_is_deprecated);
663  lua_pushvalue(L, idx);
664  lua_push(L, key);
665  if(lua_pcall(L, 2, 1, 0) == LUA_OK) {
666  return luaW_toboolean(L, -1);
667  }
668  return false;
669  });
670  keys.erase(new_end, keys.end());
671  return keys;
672 }
673 
674 /**
675  * Prints out a list of keys available in an object.
676  * A list of keys is gathered from the following sources:
677  * - For a table, all keys defined in the table
678  * - Any keys accessible through the metatable chain (if __index on the metatable is a table)
679  * - The output of the __dir metafunction
680  * - Filtering out any keys beginning with two underscores
681  * - Filtering out any keys for which object[key].__deprecated exists and is true
682  * The list is then sorted alphabetically and formatted into columns.
683  * - Arg 1: Any object
684  * - Arg 2: (optional) Function to use for output; defaults to _G.print
685  */
686 static int intf_object_dir(lua_State* L)
687 {
688  if(lua_isnil(L, 1)) return luaL_argerror(L, 1, "Can't dir() nil");
689  if(!lua_isfunction(L, 2)) {
690  luaW_getglobal(L, "print");
691  }
692  int fcn_idx = lua_gettop(L);
693  auto keys = luaW_get_attributes(L, 1);
694  size_t max_len = std::accumulate(keys.begin(), keys.end(), 0, [](size_t max, const std::string& next) {
695  return std::max(max, next.size());
696  });
697  // Let's limit to about 80 characters of total width with minimum 3 characters padding between columns
698  static const size_t MAX_WIDTH = 80, COL_PADDING = 3, SUFFIX_PADDING = 2;
699  size_t col_width = max_len + COL_PADDING + SUFFIX_PADDING;
700  size_t n_cols = (MAX_WIDTH + COL_PADDING) / col_width;
701  size_t n_rows = ceil(keys.size() / double(n_cols));
702  for(size_t i = 0; i < n_rows; i++) {
703  std::ostringstream line;
704  line.fill(' ');
705  line.setf(std::ios::left);
706  for(size_t j = 0; j < n_cols && j + (i * n_cols) < keys.size(); j++) {
707  int save_top = lua_gettop(L);
708  ON_SCOPE_EXIT(&) {
709  lua_settop(L, save_top);
710  };
711  lua_pushcfunction(L, impl_get_dir_suffix);
712  lua_pushvalue(L, 1);
713  const auto& key = keys[j + i * n_cols];
714  lua_pushlstring(L, key.c_str(), key.size());
715  std::string suffix = " !"; // Exclamation mark to indicate an error
716  if(lua_pcall(L, 2, 1, 0) == LUA_OK) {
717  suffix = luaL_checkstring(L, -1);
718  }
719  // This weird calculation is because width counts in bytes, not code points
720  // Since the suffix is a Unicode character, that messes up the alignment
721  line.width(col_width - SUFFIX_PADDING + suffix.size());
722  // Concatenate key and suffix beforehand so they share the same field width.
723  line << (key + suffix) << std::flush;
724  }
725  lua_pushvalue(L, fcn_idx);
726  lua_push(L, line.str());
727  lua_call(L, 1, 0);
728  }
729  return 0;
730 }
731 
732 // End Callback implementations
733 
734 // Template which allows to push member functions to the lua kernel base into lua as C functions, using a shim
735 typedef int (lua_kernel_base::*member_callback)(lua_State *L);
736 
737 template <member_callback method>
738 int dispatch(lua_State *L) {
739  return ((lua_kernel_base::get_lua_kernel<lua_kernel_base>(L)).*method)(L);
740 }
741 
742 // Ctor, initialization
744  : mState(luaL_newstate())
745  , cmd_log_()
746 {
748  lua_State *L = mState;
749 
750  cmd_log_ << "Initializing " << my_name() << "...\n";
751 
752  // Define the CPP_function metatable ( so we can override print to point to a C++ member function, add certain functions for this kernel, etc. )
753  // Do it first of all in case C++ functions are ever used in the core Wesnoth libs loaded in the next step
754  cmd_log_ << "Adding boost function proxy...\n";
755 
757 
758  // Open safe libraries.
759  // Debug and OS are not, but most of their functions will be disabled below.
760  cmd_log_ << "Adding standard libs...\n";
761 
762  static const luaL_Reg safe_libs[] {
763  { "", luaopen_base },
764  { "table", luaopen_table },
765  { "string", luaopen_string },
766  { "math", luaopen_math },
767  { "coroutine", luaopen_coroutine },
768  { "debug", luaopen_debug },
769  { "os", luaopen_os },
770  { "utf8", luaopen_utf8 }, // added in Lua 5.3
771  // Wesnoth libraries
772  { "stringx",lua_stringx::luaW_open },
773  { "mathx", lua_mathx::luaW_open },
774  { "wml", lua_wml::luaW_open },
775  { "gui", lua_gui2::luaW_open },
776  { "filesystem", lua_fileops::luaW_open },
777  { nullptr, nullptr }
778  };
779  for (luaL_Reg const *lib = safe_libs; lib->func; ++lib)
780  {
781  luaL_requiref(L, lib->name, lib->func, strlen(lib->name));
782  lua_pop(L, 1); /* remove lib */
783  }
784 
785  // Disable functions from os which we don't want.
786  lua_getglobal(L, "os");
787  lua_pushnil(L);
788  while(lua_next(L, -2) != 0) {
789  lua_pop(L, 1);
790  char const* function = lua_tostring(L, -1);
791  if(strcmp(function, "clock") == 0 || strcmp(function, "date") == 0
792  || strcmp(function, "time") == 0 || strcmp(function, "difftime") == 0) continue;
793  lua_pushnil(L);
794  lua_setfield(L, -3, function);
795  }
796  lua_pop(L, 1);
797 
798  // Delete dofile and loadfile.
799  lua_pushnil(L);
800  lua_setglobal(L, "dofile");
801  lua_pushnil(L);
802  lua_setglobal(L, "loadfile");
803 
804  // Store the error handler.
805  cmd_log_ << "Adding error handler...\n";
807 
808 
809  lua_settop(L, 0);
810 
811  // Add some callback from the wesnoth lib
812  cmd_log_ << "Registering basic wesnoth API...\n";
813 
814  static luaL_Reg const callbacks[] {
815  { "deprecated_message", &intf_deprecated_message },
816  { "textdomain", &lua_common::intf_textdomain },
817  { "dofile", &dispatch<&lua_kernel_base::intf_dofile> },
818  { "require", &dispatch<&lua_kernel_base::intf_require> },
819  { "kernel_type", &dispatch<&lua_kernel_base::intf_kernel_type> },
820  { "compile_formula", &lua_formula_bridge::intf_compile_formula},
821  { "eval_formula", &lua_formula_bridge::intf_eval_formula},
822  { "name_generator", &intf_name_generator },
823  { "named_tuple", &intf_named_tuple },
824  { "log", &intf_log },
825  { "ms_since_init", &intf_ms_since_init },
826  { "get_language", &intf_get_language },
827  { "version", &intf_make_version },
828  { "current_version", &intf_current_version },
829  { "print_attributes", &intf_object_dir },
830  { nullptr, nullptr }
831  };
832 
833  lua_getglobal(L, "wesnoth");
834  if (!lua_istable(L,-1)) {
835  lua_newtable(L);
836  }
837  luaL_setfuncs(L, callbacks, 0);
838  //lua_cpp::set_functions(L, cpp_callbacks, 0);
839  lua_setglobal(L, "wesnoth");
840 
841  // Create the gettext metatable.
843  // Create the tstring metatable.
845 
847 
848  // Override the print function
849  cmd_log_ << "Redirecting print function...\n";
850 
851  lua_getglobal(L, "print");
852  lua_setglobal(L, "std_print"); //storing original impl as 'std_print'
853  lua_settop(L, 0); //clear stack, just to be sure
854 
855  lua_setwarnf(L, &::impl_warn, L);
856  lua_pushcfunction(L, &dispatch<&lua_kernel_base::intf_print>);
857  lua_setglobal(L, "print");
858 
859  lua_pushcfunction(L, intf_load);
860  lua_setglobal(L, "load");
861  lua_pushnil(L);
862  lua_setglobal(L, "loadstring");
863 
864  // Wrap the pcall and xpcall functions
865  cmd_log_ << "Wrapping pcall and xpcall functions...\n";
866  lua_getglobal(L, "pcall");
867  lua_pushcclosure(L, intf_pcall, 1);
868  lua_setglobal(L, "pcall");
869  lua_getglobal(L, "xpcall");
870  lua_pushcclosure(L, intf_pcall, 1);
871  lua_setglobal(L, "xpcall");
872 
873  cmd_log_ << "Initializing package repository...\n";
874  // Create the package table.
875  lua_getglobal(L, "wesnoth");
876  lua_newtable(L);
877  lua_setfield(L, -2, "package");
878  lua_pop(L, 1);
879  lua_settop(L, 0);
880  lua_pushstring(L, "lua/package.lua");
881  int res = intf_require(L);
882  if(res != 1) {
883  cmd_log_ << "Error: Failed to initialize package repository. Falling back to less flexible C++ implementation.\n";
884  }
885 
886  // Get some callbacks for map locations
887  cmd_log_ << "Adding map table...\n";
888 
889  static luaL_Reg const map_callbacks[] {
890  { "get_direction", &lua_map_location::intf_get_direction },
891  { "hex_vector_sum", &lua_map_location::intf_vector_sum },
892  { "hex_vector_diff", &lua_map_location::intf_vector_diff },
893  { "hex_vector_negation", &lua_map_location::intf_vector_negation },
894  { "rotate_right_around_center", &lua_map_location::intf_rotate_right_around_center },
895  { "are_hexes_adjacent", &lua_map_location::intf_tiles_adjacent },
896  { "get_adjacent_hexes", &lua_map_location::intf_get_adjacent_tiles },
897  { "get_hexes_in_radius", &lua_map_location::intf_get_tiles_in_radius },
898  { "get_hexes_at_radius", &lua_map_location::intf_get_tile_ring },
899  { "distance_between", &lua_map_location::intf_distance_between },
900  { "get_cubic", &lua_map_location::intf_get_in_cubic },
901  { "from_cubic", &lua_map_location::intf_get_from_cubic },
902  { "get_relative_dir", &lua_map_location::intf_get_relative_dir },
903  // Shroud bitmaps
904  {"parse_bitmap", intf_parse_shroud_bitmap},
905  {"make_bitmap", intf_make_shroud_bitmap},
906  { nullptr, nullptr }
907  };
908 
909  // Create the map_location table.
910  lua_getglobal(L, "wesnoth");
911  lua_newtable(L);
912  luaL_setfuncs(L, map_callbacks, 0);
913  lua_setfield(L, -2, "map");
914  lua_pop(L, 1);
915 
916  // Create the game_config variable with its metatable.
917  cmd_log_ << "Adding game_config table...\n";
918 
919  lua_getglobal(L, "wesnoth");
920  lua_newuserdatauv(L, 0, 0);
921  lua_createtable(L, 0, 3);
922  lua_pushcfunction(L, &dispatch<&lua_kernel_base::impl_game_config_get>);
923  lua_setfield(L, -2, "__index");
924  lua_pushcfunction(L, &dispatch<&lua_kernel_base::impl_game_config_set>);
925  lua_setfield(L, -2, "__newindex");
926  lua_pushcfunction(L, &dispatch<&lua_kernel_base::impl_game_config_dir>);
927  lua_setfield(L, -2, "__dir");
928  lua_pushboolean(L, true);
929  lua_setfield(L, -2, "__dir_tablelike");
930  lua_pushstring(L, "game config");
931  lua_setfield(L, -2, "__metatable");
932  lua_setmetatable(L, -2);
933  lua_setfield(L, -2, "game_config");
934  lua_pop(L, 1);
935 
936  // Add mersenne twister rng wrapper
937  cmd_log_ << "Adding rng tables...\n";
939 
940  cmd_log_ << "Adding name generator metatable...\n";
941  luaL_newmetatable(L, Gen);
942  static luaL_Reg const generator[] {
943  { "__call", &impl_name_generator_call},
944  { "__gc", &impl_name_generator_collect},
945  { nullptr, nullptr}
946  };
947  luaL_setfuncs(L, generator, 0);
948 
949  // Create formula bridge metatables
951 
953 
954  // Create the Lua interpreter table
955  cmd_log_ << "Sandboxing Lua interpreter...\nTo make variables visible outside the interpreter, assign to _G.variable.\n";
956  cmd_log_ << "The special variable _ holds the result of the last expression (if any).\n";
957  lua_newtable(L);
958  lua_createtable(L, 0, 1);
959  lua_getglobal(L, "_G");
960  lua_setfield(L, -2, "__index");
961  lua_setmetatable(L, -2);
962  lua_pushcfunction(L, intf_object_dir);
963  lua_setfield(L, -2, "dir");
964  lua_setfield(L, LUA_REGISTRYINDEX, Interp);
965 
966  // Loading ilua:
967  cmd_log_ << "Loading ilua...\n";
968 
969  lua_settop(L, 0);
970  luaW_getglobal(L, "wesnoth", "require");
971  lua_pushstring(L, "lua/ilua.lua");
972  if(protected_call(1, 1)) {
973  //run "ilua.set_strict()"
974  lua_pushstring(L, "set_strict");
975  lua_gettable(L, -2);
976  if (!this->protected_call(0,0, std::bind(&lua_kernel_base::log_error, this, std::placeholders::_1, std::placeholders::_2))) {
977  cmd_log_ << "Failed to activate strict mode.\n";
978  } else {
979  cmd_log_ << "Activated strict mode.\n";
980  }
981 
982  lua_setglobal(L, "ilua"); //save ilua table as a global
983  } else {
984  cmd_log_ << "Error: failed to load ilua.\n";
985  }
986  lua_settop(L, 0);
987 
988  // Disable functions from debug which we don't want.
989  // We do this last because ilua needs to be able to use debug.getmetatable
990  lua_getglobal(L, "debug");
991  lua_pushnil(L);
992  while(lua_next(L, -2) != 0) {
993  lua_pop(L, 1);
994  char const* function = lua_tostring(L, -1);
995  if(strcmp(function, "traceback") == 0 || strcmp(function, "getinfo") == 0) continue; //traceback is needed for our error handler
996  lua_pushnil(L); //getinfo is needed for ilua strict mode
997  lua_setfield(L, -3, function);
998  }
999  lua_pop(L, 1);
1000 }
1001 
1003 {
1004  for (const auto& pair : this->registered_widget_definitions_) {
1005  gui2::remove_single_widget_definition(std::get<0>(pair), std::get<1>(pair));
1006  }
1007  lua_close(mState);
1008 }
1009 
1010 void lua_kernel_base::log_error(char const * msg, char const * context)
1011 {
1012  ERR_LUA << context << ": " << msg;
1013 }
1014 
1015 void lua_kernel_base::throw_exception(char const * msg, char const * context)
1016 {
1017  throw game::lua_error(msg, context);
1018 }
1019 
1020 bool lua_kernel_base::protected_call(int nArgs, int nRets)
1021 {
1022  error_handler eh = std::bind(&lua_kernel_base::log_error, this, std::placeholders::_1, std::placeholders::_2 );
1023  return this->protected_call(nArgs, nRets, eh);
1024 }
1025 
1026 bool lua_kernel_base::load_string(char const * prog, const std::string& name)
1027 {
1028  error_handler eh = std::bind(&lua_kernel_base::log_error, this, std::placeholders::_1, std::placeholders::_2 );
1029  return this->load_string(prog, name, eh);
1030 }
1031 
1032 bool lua_kernel_base::protected_call(int nArgs, int nRets, const error_handler& e_h)
1033 {
1034  return this->protected_call(mState, nArgs, nRets, e_h);
1035 }
1036 
1037 bool lua_kernel_base::protected_call(lua_State * L, int nArgs, int nRets, const error_handler& e_h)
1038 {
1039  int errcode = luaW_pcall_internal(L, nArgs, nRets);
1040 
1041  if (errcode != LUA_OK) {
1042  char const * msg = lua_tostring(L, -1);
1043 
1044  std::string context = "When executing, ";
1045  if (errcode == LUA_ERRRUN) {
1046  context += "Lua runtime error: ";
1047  } else if (errcode == LUA_ERRERR) {
1048  context += "Lua error in attached debugger: ";
1049  } else if (errcode == LUA_ERRMEM) {
1050  context += "Lua out of memory error: ";
1051  } else {
1052  context += "unknown lua error: ";
1053  }
1054  if(lua_isstring(L, -1)) {
1055  context += msg ? msg : "null string";
1056  } else {
1057  context += lua_typename(L, lua_type(L, -1));
1058  }
1059 
1060  lua_pop(L, 1);
1061 
1062  e_h(context.c_str(), "Lua Error");
1063 
1064  return false;
1065  }
1066 
1067  return true;
1068 }
1069 
1070 bool lua_kernel_base::load_string(const std::string& prog, const std::string& name, const error_handler& e_h, bool allow_unsafe)
1071 {
1072  // pass 't' to prevent loading bytecode which is unsafe and can be used to escape the sandbox.
1073  int errcode = luaL_loadbufferx(mState, prog.c_str(), prog.size(), name.empty() ? prog.c_str() : name.c_str(), allow_unsafe ? "tb" : "t");
1074  if (errcode != LUA_OK) {
1075  char const * msg = lua_tostring(mState, -1);
1076  std::string message = msg ? msg : "null string";
1077 
1078  std::string context = "When parsing a string to lua, ";
1079 
1080  if (errcode == LUA_ERRSYNTAX) {
1081  context += " a syntax error";
1082  } else if(errcode == LUA_ERRMEM){
1083  context += " a memory error";
1084  } else {
1085  context += " an unknown error";
1086  }
1087 
1088  lua_pop(mState, 1);
1089 
1090  e_h(message.c_str(), context.c_str());
1091 
1092  return false;
1093  }
1094  return true;
1095 }
1096 
1098 {
1099  int nArgs = 0;
1100  if (auto args = cfg.optional_child("args")) {
1101  luaW_pushconfig(this->mState, *args);
1102  ++nArgs;
1103  }
1104  this->run(cfg["code"].str().c_str(), cfg["name"].str(), nArgs);
1105 }
1106 
1107 config luaW_serialize_function(lua_State* L, int func)
1108 {
1109  if(lua_iscfunction(L, func)) {
1110  throw luafunc_serialize_error("cannot serialize C function");
1111  }
1112  if(!lua_isfunction(L, func)) {
1113  throw luafunc_serialize_error("cannot serialize callable non-function");
1114  }
1115  config data;
1116  lua_Debug info;
1117  lua_pushvalue(L, func); // push copy of function because lua_getinfo will pop it
1118  lua_getinfo(L, ">u", &info);
1119  data["params"] = info.nparams;
1120  luaW_getglobal(L, "string", "dump");
1121  lua_pushvalue(L, func);
1122  lua_call(L, 1, 1);
1123  data["code"] = lua_check<std::string>(L, -1);
1124  lua_pop(L, 1);
1125  config upvalues;
1126  for(int i = 1; i <= info.nups; i++, lua_pop(L, 1)) {
1127  std::string_view name = lua_getupvalue(L, func, i);
1128  if(name == "_ENV") {
1129  upvalues.add_child(name)["upvalue_type"] = "_ENV";
1130  continue;
1131  }
1132  int idx = lua_absindex(L, -1);
1133  switch(lua_type(L, idx)) {
1134  case LUA_TBOOLEAN: case LUA_TNUMBER: case LUA_TSTRING:
1135  luaW_toscalar(L, idx, upvalues[name]);
1136  break;
1137  case LUA_TFUNCTION:
1138  upvalues.add_child(name, luaW_serialize_function(L, idx))["upvalue_type"] = "function";
1139  break;
1140  case LUA_TNIL:
1141  upvalues.add_child(name, config{"upvalue_type", "nil"});
1142  break;
1143  case LUA_TTABLE:
1144  if(std::vector<std::string> names = luaW_to_namedtuple(L, idx); !names.empty()) {
1145  for(size_t i = 1; i <= lua_rawlen(L, -1); i++, lua_pop(L, 1)) {
1146  lua_rawgeti(L, idx, i);
1147  config& cfg = upvalues.add_child(name);
1148  luaW_toscalar(L, -1, cfg["value"]);
1149  cfg["name"] = names[0];
1150  cfg["upvalue_type"] = "named tuple";
1151  names.erase(names.begin());
1152  }
1153  break;
1154  } else if(config cfg; luaW_toconfig(L, idx, cfg)) {
1155  std::vector<std::string> names;
1156  int save_top = lua_gettop(L);
1157  if(luaL_getmetafield(L, idx, "__name") && lua_check<std::string>(L, -1) == "named tuple") {
1158  luaL_getmetafield(L, -2, "__names");
1159  names = lua_check<std::vector<std::string>>(L, -1);
1160  }
1161  lua_settop(L, save_top);
1162  upvalues.add_child(name, cfg)["upvalue_type"] = names.empty() ? "config" : "named tuple";
1163  break;
1164  } else {
1165  for(size_t i = 1; i <= lua_rawlen(L, -1); i++, lua_pop(L, 1)) {
1166  lua_rawgeti(L, idx, i);
1167  config& cfg = upvalues.add_child(name);
1168  luaW_toscalar(L, -1, cfg["value"]);
1169  cfg["upvalue_type"] = "array";
1170  }
1171  bool found_non_array = false;
1172  for(lua_pushnil(L); lua_next(L, idx); lua_pop(L, 1)) {
1173  if(lua_type(L, -2) != LUA_TNUMBER) {
1174  found_non_array = true;
1175  break;
1176  }
1177  }
1178  if(!found_non_array) break;
1179  }
1180  [[fallthrough]];
1181  default:
1182  std::ostringstream os;
1183  os << "cannot serialize function with upvalue " << name << " = ";
1184  luaW_getglobal(L, "wesnoth", "as_text");
1185  lua_pushvalue(L, idx);
1186  lua_call(L, 1, 1);
1187  os << luaL_checkstring(L, -1);
1188  lua_pushboolean(L, false);
1189  throw luafunc_serialize_error(os.str());
1190  }
1191  }
1192  if(!upvalues.empty()) data.add_child("upvalues", upvalues);
1193  return data;
1194 }
1195 
1197 {
1198  if(!load_string(cfg["code"].str(), cfg["name"], eh, true)) return false;
1199  if(auto upvalues = cfg.optional_child("upvalues")) {
1200  lua_pushvalue(mState, -1); // duplicate function because lua_getinfo will pop it
1201  lua_Debug info;
1202  lua_getinfo(mState, ">u", &info);
1203  int funcindex = lua_absindex(mState, -1);
1204  for(int i = 1; i <= info.nups; i++) {
1205  std::string_view name = lua_getupvalue(mState, funcindex, i);
1206  lua_pop(mState, 1); // we only want the upvalue's name, not its value
1207  if(name == "_ENV") {
1208  lua_pushglobaltable(mState);
1209  } else if(upvalues->has_attribute(name)) {
1210  luaW_pushscalar(mState, (*upvalues)[name]);
1211  } else if(upvalues->has_child(name)) {
1212  const auto& child = upvalues->mandatory_child(name);
1213  if(child["upvalue_type"] == "array") {
1214  auto children = upvalues->child_range(name);
1215  lua_createtable(mState, children.size(), 0);
1216  for(const auto& cfg : children) {
1217  luaW_pushscalar(mState, cfg["value"]);
1218  lua_rawseti(mState, -2, lua_rawlen(mState, -2) + 1);
1219  }
1220  } else if(child["upvalue_type"] == "config") {
1221  luaW_pushconfig(mState, child);
1222  } else if(child["upvalue_type"] == "function") {
1223  if(!load_binary(child, eh)) return false;
1224  } else if(child["upvalue_type"] == "nil") {
1225  lua_pushnil(mState);
1226  }
1227  } else continue;
1228  lua_setupvalue(mState, funcindex, i);
1229  }
1230  }
1231  return true;
1232 }
1233 
1235 {
1236  int top = lua_gettop(mState);
1237  try {
1238  error_handler eh = std::bind(&lua_kernel_base::throw_exception, this, std::placeholders::_1, std::placeholders::_2 );
1239  if(load_binary(cfg, eh)) {
1240  lua_pushvalue(mState, -1);
1241  protected_call(0, LUA_MULTRET, eh);
1242  }
1243  } catch (const game::lua_error & e) {
1244  cmd_log_ << e.what() << "\n";
1245  lua_kernel_base::log_error(e.what(), "In function lua_kernel::run()");
1246  config error;
1247  error["name"] = "execute_error";
1248  error["error"] = e.what();
1249  return error;
1250  }
1251  config result;
1252  result["ref"] = cfg["ref"];
1253  result.add_child("executed") = luaW_serialize_function(mState, top + 1);
1254  lua_remove(mState, top + 1);
1255  result["name"] = "execute_result";
1256  for(int i = top + 1; i < lua_gettop(mState); i++) {
1257  std::string index = std::to_string(i - top);
1258  switch(lua_type(mState, i)) {
1259  case LUA_TNUMBER: case LUA_TBOOLEAN: case LUA_TSTRING:
1260  luaW_toscalar(mState, i, result[index]);
1261  break;
1262  case LUA_TTABLE:
1263  luaW_toconfig(mState, i, result.add_child(index));
1264  break;
1265  }
1266  }
1267  return result;
1268 }
1269 // Call load_string and protected call. Make them throw exceptions.
1270 //
1271 void lua_kernel_base::throwing_run(const char * prog, const std::string& name, int nArgs, bool in_interpreter)
1272 {
1273  cmd_log_ << "$ " << prog << "\n";
1274  error_handler eh = std::bind(&lua_kernel_base::throw_exception, this, std::placeholders::_1, std::placeholders::_2 );
1275  this->load_string(prog, name, eh);
1276  if(in_interpreter) {
1277  lua_getfield(mState, LUA_REGISTRYINDEX, Interp);
1278  if(lua_setupvalue(mState, -2, 1) == nullptr)
1279  lua_pop(mState, 1);
1280  }
1281  lua_insert(mState, -nArgs - 1);
1282  this->protected_call(nArgs, in_interpreter ? LUA_MULTRET : 0, eh);
1283 }
1284 
1285 // Do a throwing run, but if we catch a lua_error, reformat it with signature for this function and log it.
1286 void lua_kernel_base::run(const char * prog, const std::string& name, int nArgs)
1287 {
1288  try {
1289  this->throwing_run(prog, name, nArgs);
1290  } catch (const game::lua_error & e) {
1291  cmd_log_ << e.what() << "\n";
1292  lua_kernel_base::log_error(e.what(), "In function lua_kernel::run()");
1293  }
1294 }
1295 
1296 // Tests if a program resolves to an expression, and pretty prints it if it is, otherwise it runs it normally. Throws exceptions.
1297 void lua_kernel_base::interactive_run(char const * prog) {
1298  std::string experiment = "return ";
1299  experiment += prog;
1300  int top = lua_gettop(mState);
1301 
1302  error_handler eh = std::bind(&lua_kernel_base::throw_exception, this, std::placeholders::_1, std::placeholders::_2 );
1303  luaW_getglobal(mState, "ilua", "_pretty_print");
1304 
1305  try {
1306  // Try to load the experiment without syntax errors
1307  this->load_string(experiment.c_str(), "interactive", eh);
1308  lua_getfield(mState, LUA_REGISTRYINDEX, Interp);
1309  if(lua_setupvalue(mState, -2, 1) == nullptr)
1310  lua_pop(mState, 1);
1311  } catch (const game::lua_error &) {
1312  this->throwing_run(prog, "interactive", 0, true); // Since it failed, fall back to the usual throwing_run, on the original input.
1313  if(lua_gettop(mState) == top + 1) {
1314  // Didn't return anything
1315  lua_settop(mState, top);
1316  return;
1317  } else goto PRINT;
1318  }
1319  // experiment succeeded, now run but log normally.
1320  cmd_log_ << "$ " << prog << "\n";
1321  this->protected_call(0, LUA_MULTRET, eh);
1322 PRINT:
1323  int nRets = lua_gettop(mState) - top - 1;
1324  {
1325  // Assign first result to _
1326  lua_getfield(mState, LUA_REGISTRYINDEX, Interp);
1327  int env_idx = lua_gettop(mState);
1328  lua_pushvalue(mState, top + 2);
1329  lua_setfield(mState, -2, "_");
1330  // Now duplicate EVERY result and pass it to table.pack, assigning to _all
1331  luaW_getglobal(mState, "table", "pack");
1332  for(int i = top + 2; i < env_idx; i++)
1333  lua_pushvalue(mState, i);
1334  this->protected_call(nRets, 1, eh);
1335  lua_setfield(mState, -2, "_all");
1336  lua_pop(mState, 1);
1337  }
1338  // stack is now ilua._pretty_print followed by any results of prog
1339  this->protected_call(lua_gettop(mState) - top - 1, 0, eh);
1340 }
1341 /**
1342  * Loads and executes a Lua file.
1343  * - Arg 1: string containing the file name.
1344  * - Ret *: values returned by executing the file body.
1345  */
1347 {
1348  luaL_checkstring(L, 1);
1349  lua_rotate(L, 1, -1);
1350  if (lua_fileops::load_file(L) != 1) return 0;
1351  //^ should end with the file contents loaded on the stack. actually it will call lua_error otherwise, the return 0 is redundant.
1352  lua_rotate(L, 1, 1);
1353  // Using a non-protected call here appears to fix an issue in plugins.
1354  // The protected call isn't technically necessary anyway, because this function is called from Lua code,
1355  // which should already be in a protected environment.
1356  lua_call(L, lua_gettop(L) - 1, LUA_MULTRET);
1357  return lua_gettop(L);
1358 }
1359 
1360 /**
1361  * Loads and executes a Lua file, if there is no corresponding entry in wesnoth.package.
1362  * Stores the result of the script in wesnoth.package and returns it.
1363  * - Arg 1: string containing the file name.
1364  * - Ret 1: value returned by the script.
1365  */
1367 {
1368  const char * m = luaL_checkstring(L, 1);
1369  if(!m) {
1370  return luaL_argerror(L, 1, "found a null string argument to wesnoth require");
1371  }
1372 
1373  // Check if there is already an entry.
1374 
1375  lua_getglobal(L, "wesnoth");
1376  lua_pushstring(L, "package");
1377  lua_rawget(L, -2);
1378  lua_pushvalue(L, 1);
1379  lua_rawget(L, -2);
1380  if(!lua_isnil(L, -1) && !game_config::debug_lua) {
1381  return 1;
1382  }
1383  lua_pop(L, 1);
1384  lua_pushvalue(L, 1);
1385  // stack is now [packagename] [wesnoth] [package] [packagename]
1386 
1387  if(lua_fileops::load_file(L) != 1) {
1388  // should end with the file contents loaded on the stack. actually it will call lua_error otherwise, the return 0 is redundant.
1389  // stack is now [packagename] [wesnoth] [package] [chunk]
1390  return 0;
1391  }
1392  DBG_LUA << "require: loaded a file, now calling it";
1393 
1394  if (!this->protected_call(L, 0, 1, std::bind(&lua_kernel_base::log_error, this, std::placeholders::_1, std::placeholders::_2))) {
1395  // historically if wesnoth.require fails it just yields nil and some logging messages, not a lua error
1396  return 0;
1397  }
1398  // stack is now [packagename] [wesnoth] [package] [results]
1399 
1400  lua_pushvalue(L, 1);
1401  lua_pushvalue(L, -2);
1402  // stack is now [packagename] [wesnoth] [package] [results] [packagename] [results]
1403  // Add the return value to the table.
1404 
1405  lua_settable(L, -4);
1406  // stack is now [packagename] [wesnoth] [package] [results]
1407  return 1;
1408 }
1410 {
1411  lua_push(L, my_name());
1412  return 1;
1413 }
1414 static void push_color_palette(lua_State* L, const std::vector<color_t>& palette) {
1415  lua_createtable(L, palette.size(), 1);
1416  lua_rotate(L, -2, 1); // swap new table with previous element on stack
1417  lua_setfield(L, -2, "name");
1418  for(size_t i = 0; i < palette.size(); i++) {
1419  luaW_push_namedtuple(L, {"r", "g", "b", "a"});
1420  lua_pushinteger(L, palette[i].r);
1421  lua_rawseti(L, -2, 1);
1422  lua_pushinteger(L, palette[i].g);
1423  lua_rawseti(L, -2, 2);
1424  lua_pushinteger(L, palette[i].b);
1425  lua_rawseti(L, -2, 3);
1426  lua_pushinteger(L, palette[i].a);
1427  lua_rawseti(L, -2, 4);
1428  lua_rawseti(L, -2, i);
1429  }
1430 }
1431 static int impl_palette_get(lua_State* L)
1432 {
1433  char const *m = luaL_checkstring(L, 2);
1434  lua_pushvalue(L, 2);
1436  return 1;
1437 }
1438 
1439 // suppress missing prototype warning (not static because game_lua_kernel referenes it);
1442  static luaW_Registry gameConfigReg{"game config"};
1443  return gameConfigReg;
1444 }
1445 static auto& dummy = gameConfigReg(); // just to ensure it's constructed.
1446 
1447 #define GAME_CONFIG_SIMPLE_GETTER(name) \
1448 GAME_CONFIG_GETTER(#name, decltype(game_config::name), lua_kernel_base) { \
1449  (void) k; \
1450  return game_config::name; \
1451 }
1452 
1453 namespace {
1466 
1468  (void)k;
1469  lua_newtable(L);
1470  if(luaL_newmetatable(L, "color palettes")) {
1471  lua_pushcfunction(L, impl_palette_get);
1472  lua_setfield(L, -2, "__index");
1473  }
1474  lua_setmetatable(L, -2);
1475  return lua_index_raw(L);
1476 }
1477 
1478 GAME_CONFIG_GETTER("red_green_scale", lua_index_raw, lua_kernel_base) {
1479  (void)k;
1480  lua_pushstring(L, "red_green_scale");
1482  return lua_index_raw(L);
1483 }
1484 
1485 GAME_CONFIG_GETTER("red_green_scale_text", lua_index_raw, lua_kernel_base) {
1486  (void)k;
1487  lua_pushstring(L, "red_green_scale_text");
1489  return lua_index_raw(L);
1490 }
1491 
1492 GAME_CONFIG_GETTER("blue_white_scale", lua_index_raw, lua_kernel_base) {
1493  (void)k;
1494  lua_pushstring(L, "blue_white_scale");
1496  return lua_index_raw(L);
1497 }
1498 
1499 GAME_CONFIG_GETTER("blue_white_scale_text", lua_index_raw, lua_kernel_base) {
1500  (void)k;
1501  lua_pushstring(L, "blue_white_scale_text");
1503  return lua_index_raw(L);
1504 }
1505 }
1506 
1507 /**
1508  * Gets some game_config data (__index metamethod).
1509  * - Arg 1: userdata (ignored).
1510  * - Arg 2: string containing the name of the property.
1511  * - Ret 1: something containing the attribute.
1512  */
1514 {
1515  return gameConfigReg().get(L);
1516 }
1517 /**
1518  * Sets some game_config data (__newindex metamethod).
1519  * - Arg 1: userdata (ignored).
1520  * - Arg 2: string containing the name of the property.
1521  * - Arg 3: something containing the attribute.
1522  */
1524 {
1525  return gameConfigReg().set(L);
1526 }
1527 /**
1528  * Gets a list of game_config data (__dir metamethod).
1529  */
1531 {
1532  return gameConfigReg().dir(L);
1533 }
1534 /**
1535  * Loads the "package" package into the Lua environment.
1536  * This action is inherently unsafe, as Lua scripts will now be able to
1537  * load C libraries on their own, hence granting them the same privileges
1538  * as the Wesnoth binary itself.
1539  */
1541 {
1542  lua_State *L = mState;
1543  lua_pushcfunction(L, luaopen_package);
1544  lua_pushstring(L, "package");
1545  lua_call(L, 1, 0);
1546 }
1547 
1549 {
1550  lua_State* L = mState;
1551  lua_settop(L, 0);
1552  cmd_log_ << "Loading core...\n";
1553  luaW_getglobal(L, "wesnoth", "require");
1554  lua_pushstring(L, "lua/core");
1555  if(!protected_call(1, 1)) {
1556  cmd_log_ << "Error: Failed to load core.\n";
1557  }
1558  lua_settop(L, 0);
1559 }
1560 
1561 /**
1562  * Gets all the global variable names in the Lua environment. This is useful for tab completion.
1563  */
1564 std::vector<std::string> lua_kernel_base::get_global_var_names()
1565 {
1566  std::vector<std::string> ret;
1567 
1568  lua_State *L = mState;
1569 
1570  int idx = lua_gettop(L);
1571  lua_getglobal(L, "_G");
1572  lua_pushnil(L);
1573 
1574  while (lua_next(L, idx+1) != 0) {
1575  if (lua_isstring(L, -2)) {
1576  ret.push_back(lua_tostring(L,-2));
1577  }
1578  lua_pop(L,1);
1579  }
1580  lua_settop(L, idx);
1581  return ret;
1582 }
1583 
1584 /**
1585  * Gets all attribute names of an extended variable name. This is useful for tab completion.
1586  */
1587 std::vector<std::string> lua_kernel_base::get_attribute_names(const std::string & input)
1588 {
1589  std::vector<std::string> ret;
1590  std::string base_path = input;
1591  std::size_t last_dot = base_path.find_last_of('.');
1592  std::string partial_name = base_path.substr(last_dot + 1);
1593  base_path.erase(last_dot);
1594  std::string load = "return " + base_path;
1595 
1596  lua_State* L = mState;
1597  int save_stack = lua_gettop(L);
1598  int result = luaL_loadstring(L, load.c_str());
1599  if(result != LUA_OK) {
1600  // 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.
1601  LOG_LUA << "Error when attempting tab completion:";
1602  LOG_LUA << luaL_checkstring(L, -1);
1603  // Just return an empty list; no matches were found
1604  lua_settop(L, save_stack);
1605  return ret;
1606  }
1607 
1608  luaW_pcall(L, 0, 1);
1609  if(lua_istable(L, -1) || lua_isuserdata(L, -1)) {
1610  int top = lua_gettop(L);
1611  int obj = lua_absindex(L, -1);
1612  if(luaL_getmetafield(L, obj, "__tab_enum") == LUA_TFUNCTION) {
1613  lua_pushvalue(L, obj);
1614  lua_pushlstring(L, partial_name.c_str(), partial_name.size());
1615  luaW_pcall(L, 2, 1);
1616  ret = lua_check<std::vector<std::string>>(L, -1);
1617  } else if(lua_type(L, -1) != LUA_TTABLE) {
1618  LOG_LUA << "Userdata missing __tab_enum meta-function for tab completion";
1619  lua_settop(L, save_stack);
1620  return ret;
1621  } else {
1622  lua_settop(L, top);
1623  // Metafunction not found, so use lua_next to enumerate the table
1624  for(lua_pushnil(L); lua_next(L, obj); lua_pop(L, 1)) {
1625  if(lua_type(L, -2) == LUA_TSTRING) {
1626  std::string attr = lua_tostring(L, -2);
1627  if(attr.empty()) {
1628  continue;
1629  }
1630  if(!isalpha(attr[0]) && attr[0] != '_') {
1631  continue;
1632  }
1633  if(std::any_of(attr.begin(), attr.end(), [](char c){
1634  return !isalpha(c) && !isdigit(c) && c != '_';
1635  })) {
1636  continue;
1637  }
1638  if(attr.substr(0, partial_name.size()) == partial_name) {
1639  ret.push_back(base_path + "." + attr);
1640  }
1641  }
1642  }
1643  }
1644  }
1645  lua_settop(L, save_stack);
1646  return ret;
1647 }
1648 
1650 {
1651  #ifdef __GNUC__
1652  #pragma GCC diagnostic push
1653  #pragma GCC diagnostic ignored "-Wold-style-cast"
1654  #endif
1655  return *reinterpret_cast<lua_kernel_base**>(lua_getextraspace(L));
1656  #ifdef __GNUC__
1657  #pragma GCC diagnostic pop
1658  #endif
1659 }
1660 
1662 {
1663  return seed_rng::next_seed();
1664 }
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:67
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:158
bool empty() const
Definition: config.cpp:845
optional_config_impl< config > optional_child(config_key_type key, int n=0)
Equivalent to mandatory_child, but returns an empty optional if the nth child was not found.
Definition: config.cpp:380
config & add_child(config_key_type key)
Definition: config.cpp:436
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.
const char * what() const noexcept
std::string generate(const std::map< std::string, std::string > &variables) const
virtual ~name_generator()
int height() const
Definition: team.cpp:762
void read(const std::string &shroud_data)
Definition: team.cpp:877
void set_enabled(bool enabled)
Definition: team.hpp:61
int width() const
Definition: team.cpp:757
bool value(int x, int y) const
Definition: team.cpp:820
std::string write() const
Definition: team.cpp:861
bool clear(int x, int y)
Definition: team.cpp:770
const std::string & str() const
Definition: tstring.hpp:199
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::vector< color_t > palette(const color_range &cr)
Creates a reference color palette from a color range.
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
std::size_t i
Definition: function.cpp:1030
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:327
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:905
int luaW_pcall_internal(lua_State *L, int nArgs, int nRets)
void push_error_handler(lua_State *L)
void luaW_push_namedtuple(lua_State *L, const std::vector< std::string > &names)
Push an empty "named tuple" onto the stack.
Definition: lua_common.cpp:763
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:888
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:583
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:578
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:795
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:934
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:876
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:635
#define return_string_attrib(name, accessor)
Definition: lua_common.hpp:266
#define return_int_attrib(name, accessor)
Definition: lua_common.hpp:277
#define return_bool_attrib(name, accessor)
Definition: lua_common.hpp:297
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_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 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.
#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:189
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:306
logger & warn()
Definition: log.cpp:312
logger & info()
Definition: log.cpp:318
std::string register_metatables(lua_State *L)
Definition: lua_color.cpp:155
int intf_textdomain(lua_State *L)
Creates an interface for gettext.
Definition: lua_common.cpp:93
std::string register_gettext_metatable(lua_State *L)
Adds the gettext metatable.
Definition: lua_common.cpp:421
std::string register_tstring_metatable(lua_State *L)
Adds the tstring metatable.
Definition: lua_common.cpp:441
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:79
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:241
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:41
constexpr auto keys
Definition: ranges.hpp:39
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)
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:178
void lua_push(lua_State *L, const T &val)
Definition: push_check.hpp:425
static std::string flush(std::ostringstream &s)
Definition: reports.cpp:96
#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:218
int wml_x() const
Definition: location.hpp:217
mock_char c
mock_party p
static map_location::direction n
#define e
#define b