27 #include "formula/callable_objects.hpp" 31 #include <boost/dynamic_bitset.hpp> 32 #include <boost/range/iterator_range.hpp> 33 #include <unordered_map> 38 #define LOG_LMG LOG_STREAM(info, log_scripting_lua_mapgen) 39 #define ERR_LMG LOG_STREAM(err, log_scripting_lua_mapgen) 51 using knows_sets_t = std::map<std::string, std::set<map_location>>;
58 #define LOG_MATCHES(NAME) \ 59 LOG_LMG << #NAME << ":matches(" << l << ") line:" << __LINE__ << "\n"; 70 int res = strtol(&s[0], end, 10);
74 std::pair<int, int> parse_single_range(
string_view s)
76 int dash_pos = s.find(
'-');
77 if(dash_pos ==
int(string_view::npos)) {
84 return {atoi(first), atoi(second)};
92 auto pair = parse_single_range(part);
93 int m = std::max(pair.first, pair.second);
94 if(m >=
int(res.size())) {
96 for(
int i = pair.first;
i <= pair.second; ++
i) {
110 bool last_was_n =
false;
111 while(!str.empty()) {
112 switch(str.front()) {
136 str.remove_prefix(1);
139 odd.emplace_back(se, s + se/2);
140 even.emplace_back(se, s + se/2);
143 odd.emplace_back(se, s + (se - 1)/2);
144 even.emplace_back(se, s + (se + 1)/2);
151 parse_rel(part, even, odd);
166 LOG_LMG <<
"push_locationset\n";
185 std::set<map_location> res;
188 for(
size_t i = 0;
i != len; ++
i) {
216 LOG_LMG <<
"creating con filter\n";
218 for(
size_t i = 1;
i != len; ++
i) {
220 list_.emplace_back(build_filter(L, res_index, ks));
224 std::vector<std::unique_ptr<filter_impl>> list_;
227 class and_filter :
public con_filter
231 : con_filter(L, res_index, ks)
233 LOG_LMG <<
"created and filter\n";
239 for(
const auto& pfilter : list_) {
240 if(!pfilter->matches(m, l)) {
248 class or_filter :
public con_filter
252 : con_filter(L, res_index, ks)
254 LOG_LMG <<
"created or filter\n";
260 for(
const auto& pfilter : list_) {
261 if(pfilter->matches(m, l)) {
269 class nand_filter :
public con_filter
273 : con_filter(L, res_index, ks)
275 LOG_LMG <<
"created nand filter\n";
281 for(
const auto& pfilter : list_) {
282 if(!pfilter->matches(m, l)) {
290 class nor_filter :
public con_filter
294 : con_filter(L, res_index, ks)
296 LOG_LMG <<
"created nor filter\n";
302 for(
const auto& pfilter : list_) {
303 if(pfilter->matches(m, l)) {
318 LOG_LMG <<
"creating cached filter\n";
320 filter_ = build_filter(L, res_index, ks);
330 if(
int(cache_.size()) != cache_size) {
333 if(cache_[loc_index]) {
334 return cache_[loc_index + 1];
337 bool res = filter_->matches(m, l);
338 cache_[loc_index] =
true;
339 cache_[loc_index + 1] = res;
344 std::unique_ptr<filter_impl> filter_;
354 LOG_LMG <<
"creating x filter\n";
362 return l.
x >= 0 && l.
x < int(filter_.size()) && filter_[l.
x];
373 LOG_LMG <<
"creating y filter\n";
382 return l.
y >= 0 && l.
y < int(filter_.size()) && filter_[l.
y];
393 LOG_LMG <<
"creating onborder filter\n";
409 LOG_LMG <<
"creating terrain filter\n";
426 static const offset_list_t even_offsets_default = {{1 , 0}, {1 , 1}, {0 , 1}, {-1 , 1}, {-1 , 0}, {0, -1}};
427 static const offset_list_t odd_offsets_default = {{1 , -1}, {1 , 0}, {0 , 1}, {-1 , 0}, {-1 , -1}, {0, -1}};
435 LOG_LMG <<
"creating adjacent filter\n";
437 parse_rel_sequence(
luaW_tostring(L, -1), even_offsets_, odd_offsets_);
441 even_offsets_ = even_offsets_default;
442 odd_offsets_ = odd_offsets_default;
449 filter_ = build_filter(L, res_index, ks);
459 for(
const auto& offset : offsets) {
461 if(m.
on_map(ad) && filter_->matches(m, ad)) {
462 if(accepted_counts_.size() == 0) {
468 return int(accepted_counts_.size()) > count && accepted_counts_[count];
473 std::unique_ptr<filter_impl> filter_;
482 LOG_LMG <<
"creating findin filter\n";
488 auto insert_res = ks.insert(knows_sets_t::value_type{id, {}});
489 if(insert_res.second && res_index > 0) {
496 set_ = &insert_res.first->second;
502 return set_->find(l) != set_->end();
518 LOG_LMG <<
"creating radius filter\n";
520 filter_radius_ = build_filter(L, res_index, ks);
527 filter_ = build_filter(L, res_index, ks);
534 std::set<map_location> result;
541 return !filter_radius_ || filter_radius_->matches(m, l);
546 if(!filter_ || filter_->matches(m, lr)) {
554 std::unique_ptr<filter_impl> filter_radius_;
555 std::unique_ptr<filter_impl> filter_;
564 LOG_LMG <<
"creating formula filter\n";
570 formula_ = std::make_unique<wfl::formula>(code);
581 return (formula_.get() !=
nullptr) && formula_->evaluate(callable).as_bool();
587 std::unique_ptr<wfl::formula> formula_;
591 enum filter_keys { F_AND, F_OR, F_NAND, F_NOR, F_X, F_Y, F_FIND_IN, F_ADJACENT, F_TERRAIN, F_RADUIS, F_FORMULA, F_CACHED };
594 static const std::unordered_map<std::string, filter_keys> keys {
597 {
"not_all", F_NAND },
601 {
"find_in", F_FIND_IN },
602 {
"adjacent", F_ADJACENT },
603 {
"terrain", F_TERRAIN },
604 {
"cached", F_CACHED },
605 {
"formula", F_FORMULA },
606 {
"radius", F_RADUIS }
611 LOG_LMG <<
"buildfilter: start\n";
617 LOG_LMG <<
"buildfilter: got: " << s <<
"\n";
618 auto it = keys.find(s);
619 if(it == keys.end()) {
623 auto key = it->second;
628 return std::make_unique<and_filter>(L, res_index, ks);
630 return std::make_unique<or_filter>(L, res_index, ks);
632 return std::make_unique<nand_filter>(L, res_index, ks);
634 return std::make_unique<nor_filter>(L, res_index, ks);
636 return std::make_unique<x_filter>(L, res_index, ks);
638 return std::make_unique<y_filter>(L, res_index, ks);
640 return std::make_unique<findin_filter>(L, res_index, ks);
642 return std::make_unique<adjacent_filter>(L, res_index, ks);
644 return std::make_unique<terrain_filter>(L, res_index, ks);
646 return std::make_unique<radius_filter>(L, res_index, ks);
648 return std::make_unique<cached_filter>(L, res_index, ks);
650 return std::make_unique<formula_filter>(L, res_index, ks);
652 throw "invalid filter key enum";
665 filter::filter(
lua_State* L,
int data_index,
int res_index)
667 LOG_LMG <<
"creating filter object\n";
669 impl_ = build_filter(L, res_index, known_sets_);
671 LOG_LMG <<
"finished creating filter object\n";
677 return impl_->matches(m, l);
690 LOG_LMG <<
"map:get_locations vaidargs\n";
692 LOG_LMG <<
"map:get_locations some locations\n";
694 LOG_LMG <<
"map:get_locations #args = " << s.size() <<
"\n";
702 LOG_LMG <<
"map:get_locations all locations\n";
709 LOG_LMG <<
"map:get_locations #res = " << res.size() <<
"\n";
711 LOG_LMG <<
"map:get_locations end\n";
718 LOG_LMG <<
"map:get_locations\n";
772 throw "luaW_type_error didn't throw";
780 template<
typename... T>
783 LOG_LMG <<
"luaW_push_mgfilter\n";
836 std::string err_msg =
"unknown modifiable property of map: ";
865 std::ostringstream cmd_out;
867 cmd_out <<
"Adding terrainmamap metatable...\n";
882 return cmd_out.str();
bool luaW_tableget(lua_State *L, int index, const char *key)
LUA_API void lua_createtable(lua_State *L, int narray, int nrec)
#define lua_pushcfunction(L, f)
utils::string_view luaW_tostring(lua_State *L, int index)
std::pair< int, int > parse_range(const std::string &str)
bool matches(const mapgen_gamemap &m, map_location l)
std::map< std::string, std::set< map_location > > knows_sets_t
int luaW_type_error(lua_State *L, int narg, const char *tname)
static const char terrinfilterKey[]
LUA_API int lua_rawgeti(lua_State *L, int idx, lua_Integer n)
lua_mapgen::filter * luaW_to_mgfilter(lua_State *L, int index)
bool terrain_matches(const terrain_code &src, const terrain_code &dest)
Tests whether a specific terrain matches an expression, for matching rules see above.
std::vector< std::pair< int, int > > offset_list_t
LUA_API void lua_rawseti(lua_State *L, int idx, lua_Integer n)
REMOVE_EMPTY: remove empty elements.
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
std::string register_metatables(lua_State *L)
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
#define lua_tonumber(L, i)
LUALIB_API void luaL_setmetatable(lua_State *L, const char *tname)
map_location luaW_checklocation(lua_State *L, int index)
Converts an optional table or pair of integers to a map location object.
static int luaW_push_locationset(lua_State *L, const std::set< map_location > &locs)
lua_mapgen::filter & luaW_check_mgfilter(lua_State *L, int index)
void split_foreach(string_view s, char sep, const int flags, const F &f)
LUALIB_API int luaL_argerror(lua_State *L, int arg, const char *extramsg)
static int intf_clearcache(lua_State *L)
Clears the cache of a filter.
static lua_mapgen::filter * luaW_push_mgfilter(lua_State *L, T &&... params)
static int intf_mg_get_locations_part2(lua_State *L, mapgen_gamemap &m, lua_mapgen::filter &f)
int intf_mg_get_tiles_radius(lua_State *L)
bool on_map(const map_location &loc) const
static int impl_terainfilter_get(lua_State *L)
Gets some data on a filter (__index metamethod).
boost::dynamic_bitset<> dynamic_bitset
inalid_lua_argument(const std::string &msg)
std::string errormessage_
void for_each_loc(const F &f) const
#define LOG_MATCHES(NAME)
static int impl_terainfilter_collect(lua_State *L)
Destroys a map object before it is collected (__gc metamethod).
static lg::log_domain log_scripting_lua_mapgen("scripting/lua/mapgen")
LUALIB_API void * luaL_testudata(lua_State *L, int ud, const char *tname)
const char * what() const noexcept
static map_location::DIRECTION se
Encapsulates the map of the game.
LUALIB_API int luaL_newmetatable(lua_State *L, const char *tname)
LUA_API void * lua_touserdata(lua_State *L, int idx)
bool luaW_is_mgfilter(lua_State *L, int index)
static std::set< map_location > luaW_to_locationset(lua_State *L, int index)
int intf_terainfilter_create(lua_State *L)
Create a filter.
LUALIB_API lua_Integer luaL_checkinteger(lua_State *L, int arg)
void lua_mgfilter_setmetatable(lua_State *L)
static map_location::DIRECTION s
void get_tiles_radius(const map_location ¢er, std::size_t radius, std::set< map_location > &result)
Function that will add to result all locations within radius tiles of center (including center itself...
#define log_scope(description)
LUA_API void lua_pushvalue(lua_State *L, int idx)
std::size_t index(const std::string &str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
LUA_API size_t lua_rawlen(lua_State *L, int idx)
std::set< map_location > location_set
mapgen_gamemap & luaW_checkterrainmap(lua_State *L, int index)
int total_height() const
Real height of the map, including borders.
#define lua_istable(L, n)
static int impl_terainfilter_set(lua_State *L)
Sets some data on a filter (__newindex metamethod).
Standard logging facilities (interface).
LUA_API int lua_geti(lua_State *L, int idx, lua_Integer n)
bool on_map_noborder(const map_location &loc) const
boost::string_view string_view
int total_width() const
Real width of the map, including borders.
const char * what() const noexcept
LUA_API void lua_pushinteger(lua_State *L, lua_Integer n)
This structure can be used for matching terrain strings.
int intf_mg_get_locations(lua_State *L)
LUA_API const char * lua_pushstring(lua_State *L, const char *s)
LUA_API void lua_setfield(lua_State *L, int idx, const char *k)
#define luaL_checkstring(L, n)