The Battle for Wesnoth  1.15.1+dev
mapgen_lua_kernel.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2018 by Chris Beck <render787@gmail.com>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
16 
17 #include "config.hpp"
18 #include "game_errors.hpp"
19 #include "log.hpp"
20 #include "scripting/lua_common.hpp"
21 #include "scripting/lua_rng.hpp"
25 
26 #include <ostream>
27 #include <string>
28 #include "utils/functional.hpp"
29 
30 #include "lua/lauxlib.h"
31 #include "lua/lua.h"
32 #include "scripting/push_check.hpp"
34 
35 static lg::log_domain log_mapgen("mapgen");
36 #define ERR_NG LOG_STREAM(err, log_mapgen)
37 #define LOG_NG LOG_STREAM(info, log_mapgen)
38 #define DBG_NG LOG_STREAM(debug, log_mapgen)
39 
40 struct lua_State;
41 
42 
43 // Template which allows to push member functions to the lua kernel into lua as C functions, using a shim
45 
46 template <member_callback method>
48  return ((lua_kernel_base::get_lua_kernel<mapgen_lua_kernel>(L)).*method)(L);
49 }
50 
51 /**
52  * Returns a random numer, same interface as math.random.
53  */
54 static int intf_random(lua_State *L)
55 {
56  std::mt19937& rng = lua_kernel_base::get_lua_kernel<mapgen_lua_kernel>(L).get_default_rng();
57  if(lua_isnoneornil(L, 1)) {
58  double r = double (rng());
59  double r_max = double (rng.max());
60  lua_push(L, r / (r_max + 1));
61  return 1;
62  }
63  else {
64  int32_t min;
65  int32_t max;
66  if(lua_isnumber(L, 2)) {
67  min = lua_check<int32_t>(L, 1);
68  max = lua_check<int32_t>(L, 2);
69  }
70  else {
71  min = 1;
72  max = lua_check<int32_t>(L, 1);
73  }
74  if(min > max) {
75  return luaL_argerror(L, 1, "min > max");
76  }
77  lua_push(L, min + static_cast<int>(rng() % (max - min + 1)));
78  return 1;
79  }
80 }
81 
82 /**
83  * calls the default mapgenerator.
84  */
86 {
87  std::mt19937& rng = lua_kernel_base::get_lua_kernel<mapgen_lua_kernel>(L).get_default_rng();
88 
89  int width = luaL_checkinteger(L, 1);
90  int height = luaL_checkinteger(L, 2);
91 
92  config cfg = luaW_checkconfig(L, 3);
93 
94  generator_data arg;
95  arg.width = width;
96  arg.height = height;
97  arg.nplayers = cfg["nplayers"].to_int(2);
98  arg.nvillages = cfg["nvillages"].to_int(0);
99  arg.iterations = cfg["iterations"].to_int(0);
100  arg.hill_size = cfg["hill_size"].to_int(0);
101  arg.castle_size = cfg["castle_size"].to_int(0);
102  arg.island_size = cfg["island_size"].to_int(0);
103  arg.island_off_center = cfg["island_off_center"].to_int(0);
104  arg.max_lakes = cfg["max_lakes"].to_int(0);
105  arg.link_castles = cfg["link_castles"].to_bool();
106  arg.show_labels = cfg["show_labels"].to_bool(0);
107 
108  uint32_t seed = cfg["seed"].to_int(0);
109  if(!cfg.has_attribute("seed")) {
110  seed = rng();
111  }
112 
113  default_map_generator_job job(seed);
114  std::string res = job.default_generate_map(arg, nullptr, cfg);
115 
116  lua_push(L, res);
117  return 1;
118 }
119 
120 /**
121  * calls the default mapgenerator.
122  */
124 {
125  std::mt19937& rng = lua_kernel_base::get_lua_kernel<mapgen_lua_kernel>(L).get_default_rng();
126 
127  int width = luaL_checkinteger(L, 1);
128  int height = luaL_checkinteger(L, 2);
129 
130  config cfg = luaW_checkconfig(L, 3);
131 
132  int iterations = cfg["iterations"].to_int(1);
133  int hill_size = cfg["hill_size"].to_int(1);
134  int island_size = cfg["island_size"].to_int(width/2);
135  int center_x = cfg["center_x"].to_int(width/2);
136  int center_y = cfg["center_y"].to_int(height/2);
137  bool flip_layout = cfg["flip_format"].to_bool();
138  uint32_t seed = cfg["seed"].to_int(0);
139 
140  if(!cfg.has_attribute("seed")) {
141  seed = rng();
142  }
143  default_map_generator_job job(seed);
144  default_map_generator_job::height_map res = job.generate_height_map(width, height, iterations, hill_size, island_size, center_x, center_y);
145  lua_createtable (L, width * height, 0);
146  assert(int(res.size()) == width);
147  assert((width == 0 || int(res[0].size()) == height));
148  for(int x = 0; x != width; ++x) {
149  for(int y = 0; y != height; ++y) {
150  int h = res[x][y];
151  int i = flip_layout ? (y + x * height) : (x + y * width);
152  lua_pushinteger (L, h);
153  lua_rawseti(L, -2, i);
154  }
155  }
156  return 1;
157 }
158 /**
159  * Finds a path between two locations.
160  * - Args 1,2: source location.
161  * - Args 3,4: destination.
162  * - Arg 5: cost function
163  * - Args 6,7 size of map.
164  * - Arg 8 include border.
165  * - Ret 1: array of pairs containing path steps.
166  * - Ret 2: path cost.
167  */
168 static int intf_find_path(lua_State *L)
169 {
170  int arg = 1;
171  map_location src, dst;
172  src.set_wml_x(luaL_checkinteger(L, 1));
173  src.set_wml_y(luaL_checkinteger(L, 2));
174  dst.set_wml_x(luaL_checkinteger(L, 3));
175  dst.set_wml_y(luaL_checkinteger(L, 4));
176  if(lua_isfunction(L, arg)) {
177  const char *msg = lua_pushfstring(L, "%s expected, got %s", lua_typename(L, LUA_TFUNCTION), luaL_typename(L, 5));
178  return luaL_argerror(L, 5, msg);
179  }
180  lua_pathfind_cost_calculator calc(L, 5);
181  int width = luaL_checkinteger(L, 6);
182  int height = luaL_checkinteger(L, 7);
183  bool border = false;
184  if(lua_isboolean(L, 8)) {
185  border = luaW_toboolean(L, 8);
186  }
187  pathfind::plain_route res = pathfind::a_star_search(src, dst, 10000, calc, width, height, nullptr, border);
188 
189  int nb = res.steps.size();
190  lua_createtable(L, nb, 0);
191  for (int i = 0; i < nb; ++i)
192  {
193  lua_createtable(L, 2, 0);
194  lua_pushinteger(L, res.steps[i].wml_x());
195  lua_rawseti(L, -2, 1);
196  lua_pushinteger(L, res.steps[i].wml_y());
197  lua_rawseti(L, -2, 2);
198  lua_rawseti(L, -2, i + 1);
199  }
200  lua_pushinteger(L, res.move_cost);
201 
202  return 2;
203 }
204 
205 
207  : lua_kernel_base()
208  , random_seed_()
209  , default_rng_()
210  , vars_(vars)
211 {
212  lua_State *L = mState;
213 
214  // Unset wesnoth.random. This guarantees that the mapgen_lua_kernel version
215  // of wesnoth.random overrides the lua_kernel_base version.
216  lua_getglobal(L, "wesnoth");
217  lua_pushnil(L);
218  lua_setfield(L, -2, "random");
219 
220  lua_settop(L, 0);
221 
222  static luaL_Reg const callbacks[] {
223  { "find_path", &intf_find_path },
224  { "random", &intf_random },
225  { "create_filter", &intf_terainfilter_create },
226  { "create_map", &intf_terainmap_create },
227  { "default_generate_height_map", &intf_default_generate_height_map },
228  { "generate_default_map", &intf_default_generate },
229  { "get_variable", &dispatch<&mapgen_lua_kernel::intf_get_variable> },
230  { nullptr, nullptr }
231  };
232 
233  lua_getglobal(L, "wesnoth");
234  assert(lua_istable(L,-1));
235  luaL_setfuncs(L, callbacks, 0);
236  lua_pop(L, 1);
237  assert(lua_gettop(L) == 0);
238 
239 
242 }
243 
244 void mapgen_lua_kernel::run_generator(const char * prog, const config & generator)
245 {
246  load_string(prog, "", std::bind(&lua_kernel_base::throw_exception, this, _1, _2));
247  luaW_pushconfig(mState, generator);
248  protected_call(1, 1, std::bind(&lua_kernel_base::throw_exception, this, _1, _2));
249 }
250 
251 void mapgen_lua_kernel::user_config(const char * prog, const config & generator)
252 {
253  run_generator(prog, generator);
254 }
255 
257 {
258  static const config empty_cfg;
259 
260  char const *m = luaL_checkstring(L, 1);
261  variable_access_const v(m, vars_ ? *vars_ : empty_cfg);
262  return luaW_pushvariable(L, v) ? 1 : 0;
263 }
264 std::string mapgen_lua_kernel::create_map(const char * prog, const config & generator, boost::optional<uint32_t> seed) // throws game::lua_error
265 {
266  random_seed_ = seed;
267  default_rng_ = std::mt19937(get_random_seed());
268  run_generator(prog, generator);
269 
270  if (!lua_isstring(mState,-1)) {
271  std::string msg = "expected a string, found a ";
272  msg += lua_typename(mState, lua_type(mState, -1));
273  lua_pop(mState, 1);
274  throw game::lua_error(msg.c_str(),"bad return value");
275  }
276 
277  return lua_tostring(mState, -1);
278 }
279 
280 config mapgen_lua_kernel::create_scenario(const char * prog, const config & generator, boost::optional<uint32_t> seed) // throws game::lua_error
281 {
282  random_seed_ = seed;
283  default_rng_ = std::mt19937(get_random_seed());
284  run_generator(prog, generator);
285 
286  if (!lua_istable(mState, -1)) {
287  std::string msg = "expected a config (table), found a ";
288  msg += lua_typename(mState, lua_type(mState, -1));
289  lua_pop(mState, 1);
290  throw game::lua_error(msg.c_str(),"bad return value");
291  }
292  config result;
293  if (!luaW_toconfig(mState, -1, result)) {
294  std::string msg = "expected a config, but it is malformed ";
295  lua_pop(mState, 1);
296  throw game::lua_error(msg.c_str(),"bad return value");
297  }
298  return result;
299 }
300 
302 {
303  if(uint32_t* pint = random_seed_.get_ptr()) {
304  return (*pint)++;
305  }
306  else {
308  }
309 }
310 
312 {
313  if(!default_rng_) {
314  default_rng_ = std::mt19937(get_random_seed());
315  }
316  return *default_rng_;
317 }
void set_wml_y(int v)
Definition: location.hpp:161
#define lua_isnoneornil(L, n)
Definition: lua.h:359
LUA_API void lua_createtable(lua_State *L, int narray, int nrec)
Definition: lapi.cpp:684
static int intf_random(lua_State *L)
Returns a random numer, same interface as math.random.
boost::optional< std::mt19937 > default_rng_
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:712
LUA_API void lua_settop(lua_State *L, int idx)
Definition: lapi.cpp:172
LUA_API int lua_type(lua_State *L, int idx)
Definition: lapi.cpp:251
std::string create_map(const char *prog, const config &generator, boost::optional< uint32_t > seed)
config create_scenario(const char *prog, const config &generator, boost::optional< uint32_t > seed)
bool has_attribute(config_key_type key) const
Definition: config.cpp:213
static int intf_default_generate(lua_State *L)
calls the default mapgenerator.
LUA_API void lua_rawseti(lua_State *L, int idx, lua_Integer n)
Definition: lapi.cpp:817
LUA_API int lua_gettop(lua_State *L)
Definition: lapi.cpp:167
boost::optional< uint32_t > random_seed_
bool luaW_pushvariable(lua_State *L, variable_access_const &v)
Definition: lua_common.cpp:875
LUA_API int lua_getglobal(lua_State *L, const char *name)
Definition: lapi.cpp:605
std::string register_metatables(lua_State *L)
void set_wml_x(int v)
Definition: location.hpp:160
const config * vars_
#define h
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:109
#define luaL_typename(L, i)
Definition: lauxlib.h:127
#define LUA_TFUNCTION
Definition: lua.h:70
void lua_push(lua_State *L, const T &val)
Definition: push_check.hpp:371
Definitions for the interface to Wesnoth Markup Language (WML).
#define lua_pop(L, n)
Definition: lua.h:344
int intf_terainmap_create(lua_State *L)
Create a map.
LUALIB_API int luaL_argerror(lua_State *L, int arg, const char *extramsg)
Definition: lauxlib.cpp:164
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:86
std::vector< map_location > steps
Definition: pathfind.hpp:134
LUA_API int lua_isstring(lua_State *L, int idx)
Definition: lapi.cpp:283
bool luaW_toboolean(lua_State *L, int n)
Definition: lua_common.cpp:870
Structure which holds a single route between one location and another.
Definition: pathfind.hpp:131
void user_config(const char *prog, const config &generator)
int intf_get_variable(lua_State *L)
int dispatch(lua_State *L)
bool protected_call(int nArgs, int nRets, error_handler)
std::string register_metatables(lua_State *L)
LUA_API void lua_pushnil(lua_State *L)
Definition: lapi.cpp:450
int move_cost
Movement cost for reaching the end of the route.
Definition: pathfind.hpp:136
Encapsulates the map of the game.
Definition: location.hpp:42
std::string default_generate_map(generator_data data, std::map< map_location, std::string > *labels, const config &cfg)
Generate the map.
#define lua_isboolean(L, n)
Definition: lua.h:356
bool luaW_toconfig(lua_State *L, int index, config &cfg)
Converts an optional table or vconfig to a config object.
Definition: lua_common.cpp:724
int intf_terainfilter_create(lua_State *L)
Create a filter.
Cost function object relying on a Lua function.
std::size_t i
Definition: function.cpp:933
LUALIB_API lua_Integer luaL_checkinteger(lua_State *L, int arg)
Definition: lauxlib.cpp:430
int(mapgen_lua_kernel::* member_callback)(lua_State *)
config luaW_checkconfig(lua_State *L, int index)
Converts an optional table or vconfig to a config object.
Definition: lua_common.cpp:799
#define lua_isfunction(L, n)
Definition: lua.h:352
virtual uint32_t get_random_seed()
#define lua_tostring(L, i)
Definition: lua.h:366
LUA_API int lua_isnumber(lua_State *L, int idx)
Definition: lapi.cpp:276
virtual uint32_t get_random_seed()
rng * generator
This generator is automatically synced during synced context.
Definition: random.cpp:60
bool load_string(char const *prog, const std::string &name, error_handler)
command_log cmd_log_
LUA_API int lua_error(lua_State *L)
Definition: lapi.cpp:1114
Information on a WML variable.
#define lua_istable(L, n)
Definition: lua.h:353
static int intf_find_path(lua_State *L)
Finds a path between two locations.
virtual void throw_exception(char const *msg, char const *context="Lua error")
std::mt19937 & get_default_rng()
static lg::log_domain log_mapgen("mapgen")
Standard logging facilities (interface).
height_map generate_height_map(size_t width, size_t height, size_t iterations, size_t hill_size, size_t island_size, size_t island_off_center)
static int intf_default_generate_height_map(lua_State *L)
calls the default mapgenerator.
LUA_API const char * lua_pushfstring(lua_State *L, const char *fmt,...)
Definition: lapi.cpp:519
mapgen_lua_kernel(const config *vars)
LUALIB_API void luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup)
Definition: lauxlib.cpp:934
void run_generator(const char *prog, const config &generator)
plain_route a_star_search(const map_location &src, const map_location &dst, double stop_at, const cost_calculator &calc, const std::size_t width, const std::size_t height, const teleport_map *teleports, bool border)
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:92
lua_State * mState
LUA_API void lua_pushinteger(lua_State *L, lua_Integer n)
Definition: lapi.cpp:466
LUA_API void lua_setfield(lua_State *L, int idx, const char *k)
Definition: lapi.cpp:777
LUA_API const char * lua_typename(lua_State *L, int t)
Definition: lapi.cpp:257
std::vector< std::vector< int > > height_map
#define luaL_checkstring(L, n)
Definition: lauxlib.h:124